-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Avoid re-resolving column names after analysis #25240
base: master
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 |
---|---|---|
|
@@ -34,6 +34,8 @@ | |
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
import static io.trino.spi.StandardErrorCode.EXPRESSION_NOT_SCALAR; | ||
import static io.trino.sql.analyzer.ExpressionTreeUtils.extractAggregateFunctions; | ||
|
@@ -105,7 +107,10 @@ public Analysis analyze(Statement statement, QueryType queryType) | |
accessControlInfo.getAccessControl().checkCanSelectFromColumns( | ||
accessControlInfo.getSecurityContext(session.getRequiredTransactionId(), session.getQueryId(), session.getStart()), | ||
tableName, | ||
columns))); | ||
columns.stream() | ||
.map(Field::getOriginColumnName) | ||
.map(Optional::get) | ||
.collect(Collectors.toSet())))); | ||
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, immutableSet? |
||
} | ||
|
||
return analysis; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -886,12 +886,24 @@ protected Scope visitAnalyze(Analyze node, Optional<Scope> scope) | |
|
||
analysis.setAnalyzeMetadata(metadata.getStatisticsCollectionMetadata(session, tableHandle, analyzeProperties)); | ||
|
||
Set<Field> fields = metadata.getTableSchema(session, tableHandle) | ||
.columns().stream() | ||
.map(column -> Field.newQualified( | ||
node.getTableName(), | ||
Optional.of(column.getName()), | ||
column.getType(), | ||
column.isHidden(), | ||
Optional.of(tableName), | ||
Optional.of(column.getName()), | ||
false)) | ||
.collect(Collectors.toSet()); | ||
Comment on lines
+889
to
+899
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. In general, that PR is what I started doing, but this is the place where I got into trouble, because I didn't know where to get a 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. immutable set and static import? 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. It seems this is a convention is this class, not sure we should be changing that (at this time) |
||
|
||
// user must have read and insert permission in order to analyze stats of a table | ||
analysis.addTableColumnReferences( | ||
accessControl, | ||
session.getIdentity(), | ||
ImmutableMultimap.<QualifiedObjectName, String>builder() | ||
.putAll(tableName, metadata.getColumnHandles(session, tableHandle).keySet()) | ||
ImmutableMultimap.<QualifiedObjectName, Field>builder() | ||
.putAll(tableName, fields) | ||
.build()); | ||
try { | ||
accessControl.checkCanInsertIntoTable(session.toSecurityContext(), tableName); | ||
|
@@ -3856,7 +3868,7 @@ private void recordColumnAccess(Field field) | |
analysis.addTableColumnReferences( | ||
accessControl, | ||
session.getIdentity(), | ||
ImmutableMultimap.of(field.getOriginTable().get(), field.getOriginColumnName().get())); | ||
ImmutableMultimap.of(field.getOriginTable().get(), field)); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import io.trino.spi.Unstable; | ||
|
||
import java.util.Objects; | ||
import java.util.Optional; | ||
|
||
/** | ||
|
@@ -46,4 +47,19 @@ public Optional<String> getMask() | |
{ | ||
return mask; | ||
} | ||
|
||
@Override | ||
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. Should we migrate this class to record? 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. This is an SPI class, although marked as |
||
public boolean equals(Object o) | ||
{ | ||
if (!(o instanceof ColumnInfo that)) { | ||
return false; | ||
} | ||
return Objects.equals(column, that.column) && Objects.equals(mask, that.mask); | ||
} | ||
|
||
@Override | ||
public int hashCode() | ||
{ | ||
return Objects.hash(column, mask); | ||
} | ||
} |
Unchanged files with check annotations Beta
assertAccessDenied("SHOW STATS FOR (SELECT *, nationkey FROM nation)", "Cannot select from columns \\[nationkey, regionkey, name, comment] in table or view .*.nation", privilege("nation.nationkey", SELECT_COLUMN)); | ||
assertAccessDenied("SHOW STATS FOR (SELECT *, * FROM nation)", "Cannot select from columns \\[nationkey, regionkey, name, comment] in table or view .*.nation", privilege("nation.nationkey", SELECT_COLUMN)); | ||
assertAccessDenied("SHOW STATS FOR (SELECT linenumber, orderkey FROM lineitem)", "Cannot select from columns \\[linenumber, orderkey] in table or view .*.lineitem.*", privilege("lineitem", SELECT_COLUMN)); | ||
assertAccessDenied("SHOW STATS FOR (SELECT linenumber, orderkey, quantity FROM lineitem)", "Cannot select from columns \\[linenumber, orderkey, quantity] in table or view .*.lineitem.*", privilege("lineitem.linenumber", SELECT_COLUMN), privilege("lineitem.orderkey", SELECT_COLUMN)); | ||
Check failure on line 366 in testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java
|
||
assertAccessDenied("SHOW STATS FOR (SELECT nationkey FROM nation)", "Cannot select from columns \\[nationkey] in table or view .*.nation.*", privilege("nation", SELECT_COLUMN)); | ||
assertAccessDenied("SHOW STATS FOR (SELECT * FROM nation)", "Cannot select from columns \\[nationkey, regionkey, name, comment] in table or view .*.nation.*", privilege("nation", SELECT_COLUMN)); | ||
} |
.hasCatalogSchemaTable("tpch", "tiny", "nation") | ||
.hasAuthorization("alice") | ||
.isNotDirectlyReferenced() | ||
.hasColumnsWithoutMasking("nationkey", "regionkey", "name", "comment") | ||
Check failure on line 513 in testing/trino-tests/src/test/java/io/trino/execution/TestEventListenerBasic.java
|
||
.hasNoRowFilters() | ||
.hasTableReferencesSatisfying(tableRef -> assertThat(tableRef).asMaterializedViewInfo().hasCatalogSchemaView("mock", "default", "test_materialized_view_fresh")); | ||
.hasCatalogSchemaTable("tpch", "tiny", "nation") | ||
.hasAuthorization("user") | ||
.isDirectlyReferenced() | ||
.hasColumnsWithoutMasking("nationkey", "regionkey", "name", "comment") | ||
Check failure on line 581 in testing/trino-tests/src/test/java/io/trino/execution/TestEventListenerBasic.java
|
||
.hasNoRowFilters() | ||
.hasNoTableReferences(); | ||
} | ||
.hasCatalogSchemaTable("tpch", "tiny", "nation") | ||
.hasAuthorization("user") | ||
.isDirectlyReferenced() | ||
.hasColumnsWithoutMasking("nationkey", "regionkey", "name", "comment") | ||
Check failure on line 609 in testing/trino-tests/src/test/java/io/trino/execution/TestEventListenerBasic.java
|
||
.hasNoRowFilters() | ||
.hasNoTableReferences(); | ||
} | ||
.hasCatalogSchemaTable("mock", "default", "test_table_with_column_mask") | ||
.hasAuthorization("user") | ||
.isDirectlyReferenced() | ||
.hasColumnNames("test_varchar", "test_bigint") | ||
Check failure on line 799 in testing/trino-tests/src/test/java/io/trino/execution/TestEventListenerBasic.java
|
||
.hasColumnMasks("(SELECT CAST(max(orderkey) AS varchar(15)) FROM orders)", null) | ||
.hasNoRowFilters() | ||
.hasNoTableReferences(); |
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 distinct was moved?
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.
Previously
.distinct()
worked onString
, so it made sense to do it early. Now we're processingField
instances, which are not comparable, so.distinct()
is moved to a later stage, where we convert them toColumnInfo
, which are comparable.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.
This
distinct
is actually pretty important and is the reason this test is failing:Previously we got the
test_varchar
field twice, but it was just a name, so it could easily be disambiguated. Now it's aField
, andField
instances are always distinct. Thing is that this field is referenced once as a target ofSELECT
and another time as the field that has a column mask. InStatementAnalyzer
we create a new distinctField
instance each time and it makes it a distinct instance to the one used to register a column mask. So when we are processing the references, only one registeredField
instance has a column mask associated, so of the resultingColumnInfo
objects only one has a column mask and the two objects for the field are distinct as well and are not disambiguated.