-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exclude with statement names from tables #532
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,7 @@ | |
import io.trino.sql.tree.Statement; | ||
import io.trino.sql.tree.Table; | ||
import io.trino.sql.tree.TableFunctionInvocation; | ||
import io.trino.sql.tree.WithQuery; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.ws.rs.HttpMethod; | ||
|
||
|
@@ -74,6 +75,7 @@ | |
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import static com.google.common.collect.ImmutableSet.toImmutableSet; | ||
import static com.google.common.io.BaseEncoding.base64Url; | ||
import static io.airlift.json.JsonCodec.jsonCodec; | ||
import static java.lang.Math.toIntExact; | ||
|
@@ -194,13 +196,25 @@ else if (statement instanceof ExecuteImmediate executeImmediate) { | |
|
||
queryType = statement.getClass().getSimpleName(); | ||
resourceGroupQueryType = StatementUtils.getQueryType(statement).toString(); | ||
ImmutableSet.Builder<QualifiedName> tableBuilder = ImmutableSet.builder(); | ||
List<QualifiedName> allQUalifiedNames = new ArrayList<>(); | ||
ImmutableSet.Builder<String> catalogBuilder = ImmutableSet.builder(); | ||
ImmutableSet.Builder<String> schemaBuilder = ImmutableSet.builder(); | ||
ImmutableSet.Builder<String> catalogSchemaBuilder = ImmutableSet.builder(); | ||
|
||
getNames(statement, tableBuilder, catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
tables = tableBuilder.build(); | ||
ImmutableSet.Builder<Identifier> withQueryNameBuilder = ImmutableSet.builder(); | ||
|
||
getNames(statement, allQUalifiedNames, catalogBuilder, schemaBuilder, catalogSchemaBuilder, withQueryNameBuilder); | ||
ImmutableSet<Identifier> withQueryNames = withQueryNameBuilder.build(); | ||
tables = allQUalifiedNames.stream() | ||
.filter(n -> (n.getOriginalParts().size() > 1 || !withQueryNames.contains(n.getOriginalParts().getFirst()))) | ||
.map(t -> { | ||
try { | ||
return qualifyName(t); | ||
} | ||
catch (RequestParsingException e) { | ||
throw new RuntimeException(e); | ||
} | ||
}) | ||
.collect(toImmutableSet()); | ||
catalogBuilder.addAll(tables.stream().map(q -> q.getParts().getFirst()).iterator()); | ||
catalogs = catalogBuilder.build(); | ||
schemaBuilder.addAll(tables.stream().map(q -> q.getParts().get(1)).iterator()); | ||
|
@@ -260,27 +274,30 @@ private String decodePreparedStatementFromHeader(String headerValue) | |
return new String(preparedStatement, UTF_8); | ||
} | ||
|
||
private void getNames(Node node, ImmutableSet.Builder<QualifiedName> tableBuilder, | ||
private void getNames( | ||
Node node, | ||
List<QualifiedName> allQualifiedNames, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand the difference between |
||
ImmutableSet.Builder<String> catalogBuilder, | ||
ImmutableSet.Builder<String> schemaBuilder, | ||
ImmutableSet.Builder<String> catalogSchemaBuilder) | ||
ImmutableSet.Builder<String> catalogSchemaBuilder, | ||
ImmutableSet.Builder<Identifier> withQueryNamesBuilder) | ||
throws RequestParsingException | ||
{ | ||
switch (node) { | ||
case AddColumn s -> tableBuilder.add(qualifyName(s.getName())); | ||
case Analyze s -> tableBuilder.add(qualifyName(s.getTableName())); | ||
case AddColumn s -> allQualifiedNames.add(s.getName()); | ||
case Analyze s -> allQualifiedNames.add(s.getTableName()); | ||
case CreateCatalog s -> catalogBuilder.add(s.getCatalogName().getValue()); | ||
case CreateMaterializedView s -> tableBuilder.add(qualifyName(s.getName())); | ||
case CreateMaterializedView s -> allQualifiedNames.add(s.getName()); | ||
case CreateSchema s -> setCatalogAndSchemaNameFromSchemaQualifiedName(Optional.of(s.getSchemaName()), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
case CreateTable s -> tableBuilder.add(qualifyName(s.getName())); | ||
case CreateView s -> tableBuilder.add(qualifyName(s.getName())); | ||
case CreateTableAsSelect s -> tableBuilder.add(qualifyName(s.getName())); | ||
case CreateTable s -> allQualifiedNames.add(s.getName()); | ||
case CreateView s -> allQualifiedNames.add(s.getName()); | ||
case CreateTableAsSelect s -> allQualifiedNames.add(s.getName()); | ||
case DropCatalog s -> catalogBuilder.add(s.getCatalogName().getValue()); | ||
case DropSchema s -> setCatalogAndSchemaNameFromSchemaQualifiedName(Optional.of(s.getSchemaName()), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
case DropTable s -> tableBuilder.add(qualifyName(s.getTableName())); | ||
case DropTable s -> allQualifiedNames.add(s.getTableName()); | ||
case RenameMaterializedView s -> { | ||
tableBuilder.add(qualifyName(s.getSource())); | ||
tableBuilder.add(qualifyName(s.getTarget())); | ||
allQualifiedNames.add(s.getSource()); | ||
allQualifiedNames.add(s.getTarget()); | ||
} | ||
case RenameSchema s -> { | ||
setCatalogAndSchemaNameFromSchemaQualifiedName(Optional.of(s.getSource()), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
|
@@ -301,48 +318,49 @@ private void getNames(Node node, ImmutableSet.Builder<QualifiedName> tableBuilde | |
} | ||
case RenameTable s -> { | ||
QualifiedName qualifiedSource = qualifyName(s.getSource()); | ||
tableBuilder.add(qualifiedSource); | ||
allQualifiedNames.add(qualifiedSource); | ||
QualifiedName target = s.getTarget(); | ||
if (target.getParts().size() == 1) { | ||
tableBuilder.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), qualifiedSource.getParts().get(1), target.getParts().getFirst())); | ||
allQualifiedNames.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), qualifiedSource.getParts().get(1), target.getParts().getFirst())); | ||
} | ||
else { | ||
tableBuilder.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), target.getParts().getFirst(), target.getParts().get(1))); | ||
allQualifiedNames.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), target.getParts().getFirst(), target.getParts().get(1))); | ||
} | ||
} | ||
case RenameView s -> { | ||
QualifiedName qualifiedSource = qualifyName(s.getSource()); | ||
tableBuilder.add(qualifiedSource); | ||
allQualifiedNames.add(qualifiedSource); | ||
QualifiedName target = s.getTarget(); | ||
if (target.getParts().size() == 1) { | ||
tableBuilder.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), qualifiedSource.getParts().get(1), target.getParts().getFirst())); | ||
allQualifiedNames.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), qualifiedSource.getParts().get(1), target.getParts().getFirst())); | ||
} | ||
else { | ||
tableBuilder.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), target.getParts().getFirst(), target.getParts().get(1))); | ||
allQualifiedNames.add(QualifiedName.of(qualifiedSource.getParts().getFirst(), target.getParts().getFirst(), target.getParts().get(1))); | ||
} | ||
} | ||
case SetProperties s -> tableBuilder.add(qualifyName(s.getName())); | ||
case ShowColumns s -> tableBuilder.add(qualifyName(s.getTable())); | ||
case SetProperties s -> allQualifiedNames.add(s.getName()); | ||
case ShowColumns s -> allQualifiedNames.add(s.getTable()); | ||
case ShowCreate s -> { | ||
if (s.getType() == ShowCreate.Type.SCHEMA) { | ||
setCatalogAndSchemaNameFromSchemaQualifiedName(Optional.of(s.getName()), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
} | ||
else { | ||
tableBuilder.add(qualifyName(s.getName())); | ||
allQualifiedNames.add(s.getName()); | ||
} | ||
} | ||
case ShowSchemas s -> catalogBuilder.add(s.getCatalog().map(Identifier::getValue).or(() -> defaultCatalog).orElseThrow(this::unsetDefaultExceptionSupplier)); | ||
case ShowTables s -> setCatalogAndSchemaNameFromSchemaQualifiedName(s.getSchema(), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
case SetSchemaAuthorization s -> setCatalogAndSchemaNameFromSchemaQualifiedName(Optional.of(s.getSource()), catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
case SetTableAuthorization s -> tableBuilder.add(qualifyName(s.getSource())); | ||
case SetViewAuthorization s -> tableBuilder.add(qualifyName(s.getSource())); | ||
case Table s -> tableBuilder.add(qualifyName(s.getName())); | ||
case TableFunctionInvocation s -> tableBuilder.add(qualifyName(s.getName())); | ||
case SetTableAuthorization s -> allQualifiedNames.add(s.getSource()); | ||
case SetViewAuthorization s -> allQualifiedNames.add(s.getSource()); | ||
case Table s -> allQualifiedNames.add(s.getName()); | ||
case TableFunctionInvocation s -> allQualifiedNames.add(s.getName()); | ||
case WithQuery withQuery -> withQueryNamesBuilder.add(withQuery.getName()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. didn't know you could do this directly, i thought withQuery comes with Query. |
||
default -> {} | ||
} | ||
|
||
for (Node child : node.getChildren()) { | ||
getNames(child, tableBuilder, catalogBuilder, schemaBuilder, catalogSchemaBuilder); | ||
getNames(child, allQualifiedNames, catalogBuilder, schemaBuilder, catalogSchemaBuilder, withQueryNamesBuilder); | ||
} | ||
} | ||
|
||
|
@@ -386,7 +404,8 @@ private QualifiedName qualifyName(QualifiedName table) | |
{ | ||
List<String> tableParts = table.getParts(); | ||
return switch (tableParts.size()) { | ||
case 1 -> QualifiedName.of(defaultCatalog.orElseThrow(this::unsetDefaultExceptionSupplier), defaultSchema.orElseThrow(this::unsetDefaultExceptionSupplier), tableParts.getFirst()); | ||
case 1 -> | ||
QualifiedName.of(defaultCatalog.orElseThrow(this::unsetDefaultExceptionSupplier), defaultSchema.orElseThrow(this::unsetDefaultExceptionSupplier), tableParts.getFirst()); | ||
case 2 -> QualifiedName.of(defaultCatalog.orElseThrow(this::unsetDefaultExceptionSupplier), tableParts.getFirst(), tableParts.get(1)); | ||
case 3 -> QualifiedName.of(tableParts.getFirst(), tableParts.get(1), tableParts.get(2)); | ||
default -> throw new RequestParsingException("Unexpected table name: " + table.getParts()); | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -404,6 +404,36 @@ void testTrinoQueryPropertiesTableExtraction(String query, Set<String> catalogs, | |||||||||||||
assertThat(trinoQueryProperties.getCatalogs()).isEqualTo(catalogs); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
@Test | ||||||||||||||
void testWithQueryNameExcluded() | ||||||||||||||
throws IOException | ||||||||||||||
{ | ||||||||||||||
String query = """ | ||||||||||||||
WITH dos (c1) as (select c1 from uno), | ||||||||||||||
uno(c1) as (select c1 from cat.schem.tbl1) | ||||||||||||||
SELECT c1 from uno, dos | ||||||||||||||
Comment on lines
+412
to
+414
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uppercase as, select, from. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't think this is valid SQL. You cannot use uno as it is defined after dos.
Suggested change
you can test this in trino via simple sql // works fine
WITH dos AS (SELECT node_id FROM system.runtime.nodes),
uno AS (SELECT node_id as node_id2 FROM dos)
SELECT node_id, node_id2
FROM uno, dos
// doesn't work as uno is not defined before dos.
// Query 20241023_021715_04215_f8xaz failed: line 1:34: Table 'system.runtime.uno' does not exist
WITH dos AS (SELECT node_id FROM uno),
uno AS (SELECT node_id as node_id2 FROM system.runtime.nodes)
SELECT node_id, node_id2
FROM uno, dos |
||||||||||||||
"""; | ||||||||||||||
BufferedReader bufferedReader = new BufferedReader(new StringReader(query)); | ||||||||||||||
HttpServletRequest mockRequestWithDefaults = prepareMockRequest(); | ||||||||||||||
when(mockRequestWithDefaults.getReader()).thenReturn(bufferedReader); | ||||||||||||||
when(mockRequestWithDefaults.getHeader(TrinoQueryProperties.TRINO_CATALOG_HEADER_NAME)).thenReturn(DEFAULT_CATALOG); | ||||||||||||||
when(mockRequestWithDefaults.getHeader(TrinoQueryProperties.TRINO_SCHEMA_HEADER_NAME)).thenReturn(DEFAULT_SCHEMA); | ||||||||||||||
|
||||||||||||||
TrinoQueryProperties trinoQueryPropertiesWithDefaults = new TrinoQueryProperties(mockRequestWithDefaults, requestAnalyzerConfig); | ||||||||||||||
|
||||||||||||||
assertThat(trinoQueryPropertiesWithDefaults.tablesContains(String.format("%s.%s.%s", DEFAULT_CATALOG, DEFAULT_SCHEMA, "uno"))).isFalse(); | ||||||||||||||
assertThat(trinoQueryPropertiesWithDefaults.tablesContains(String.format("%s.%s.%s", DEFAULT_CATALOG, DEFAULT_SCHEMA, "does"))).isFalse(); | ||||||||||||||
Comment on lines
+424
to
+425
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Static import |
||||||||||||||
assertThat(trinoQueryPropertiesWithDefaults.tablesContains("cat.schem.tbl1")).isTrue(); | ||||||||||||||
|
||||||||||||||
HttpServletRequest mockRequestNoDefaults = prepareMockRequest(); | ||||||||||||||
bufferedReader = new BufferedReader(new StringReader(query)); | ||||||||||||||
when(mockRequestNoDefaults.getReader()).thenReturn(bufferedReader); | ||||||||||||||
|
||||||||||||||
TrinoQueryProperties trinoQueryPropertiesNoDefaults = new TrinoQueryProperties(mockRequestNoDefaults, requestAnalyzerConfig); | ||||||||||||||
assertThat(trinoQueryPropertiesNoDefaults.getTables().size()).isEqualTo(1); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AssertJ provides There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you consider temporary tables (with clause) as non-tables? |
||||||||||||||
assertThat(trinoQueryPropertiesNoDefaults.tablesContains("cat.schem.tbl1")).isTrue(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
private HttpServletRequest prepareMockRequest() | ||||||||||||||
{ | ||||||||||||||
HttpServletRequest mockRequest = mock(HttpServletRequest.class); | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you change to ArrayList? #Also, the new name has a typo.
U
should be a lowercase.