-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Iceberg: Use table schema corresponding to snapshot in snapshot queries #12786
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
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 | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -316,18 +316,31 @@ public IcebergTableHandle getTableHandle( | |||||||||||||||||||||||||
| throw new TrinoException(GENERIC_USER_ERROR, "Cannot specify end version both in table name and FOR clause"); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Optional<Long> snapshotId = endVersion.map(version -> getSnapshotIdFromVersion(table, version)) | ||||||||||||||||||||||||||
| .or(() -> getSnapshotId(table, name.getSnapshotId(), isAllowLegacySnapshotSyntax(session))); | ||||||||||||||||||||||||||
| Optional<Long> tableSnapshotId; | ||||||||||||||||||||||||||
| Schema tableSchema; | ||||||||||||||||||||||||||
| Optional<PartitionSpec> partitionSpec; | ||||||||||||||||||||||||||
| if (endVersion.isPresent() || name.getSnapshotId().isPresent()) { | ||||||||||||||||||||||||||
| long snapshotId = endVersion.map(connectorTableVersion -> getSnapshotIdFromVersion(table, connectorTableVersion)) | ||||||||||||||||||||||||||
| .orElseGet(() -> resolveSnapshotId(table, name.getSnapshotId().get(), isAllowLegacySnapshotSyntax(session))); | ||||||||||||||||||||||||||
| tableSnapshotId = Optional.of(snapshotId); | ||||||||||||||||||||||||||
| tableSchema = table.schemas().get(table.snapshot(snapshotId).schemaId()); | ||||||||||||||||||||||||||
| partitionSpec = Optional.empty(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| else { | ||||||||||||||||||||||||||
| tableSnapshotId = Optional.ofNullable(table.currentSnapshot()).map(Snapshot::snapshotId); | ||||||||||||||||||||||||||
| tableSchema = table.schema(); | ||||||||||||||||||||||||||
| partitionSpec = Optional.of(table.spec()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Map<String, String> tableProperties = table.properties(); | ||||||||||||||||||||||||||
| String nameMappingJson = tableProperties.get(TableProperties.DEFAULT_NAME_MAPPING); | ||||||||||||||||||||||||||
| return new IcebergTableHandle( | ||||||||||||||||||||||||||
| tableName.getSchemaName(), | ||||||||||||||||||||||||||
| name.getTableName(), | ||||||||||||||||||||||||||
| name.getTableType(), | ||||||||||||||||||||||||||
| snapshotId, | ||||||||||||||||||||||||||
| SchemaParser.toJson(table.schema()), | ||||||||||||||||||||||||||
| PartitionSpecParser.toJson(table.spec()), | ||||||||||||||||||||||||||
| tableSnapshotId, | ||||||||||||||||||||||||||
| SchemaParser.toJson(tableSchema), | ||||||||||||||||||||||||||
| partitionSpec.map(PartitionSpecParser::toJson), | ||||||||||||||||||||||||||
| table.operations().current().formatVersion(), | ||||||||||||||||||||||||||
| TupleDomain.all(), | ||||||||||||||||||||||||||
| TupleDomain.all(), | ||||||||||||||||||||||||||
|
|
@@ -508,7 +521,10 @@ public ConnectorTableProperties getTableProperties(ConnectorSession session, Con | |||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
| public ConnectorTableMetadata getTableMetadata(ConnectorSession session, ConnectorTableHandle table) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return getTableMetadata(session, ((IcebergTableHandle) table).getSchemaTableName()); | ||||||||||||||||||||||||||
| IcebergTableHandle tableHandle = (IcebergTableHandle) table; | ||||||||||||||||||||||||||
| Table icebergTable = catalog.loadTable(session, tableHandle.getSchemaTableName()); | ||||||||||||||||||||||||||
| List<ColumnMetadata> columns = getColumnMetadatas(SchemaParser.fromJson(tableHandle.getTableSchemaJson())); | ||||||||||||||||||||||||||
| return new ConnectorTableMetadata(tableHandle.getSchemaTableName(), columns, getIcebergTableProperties(icebergTable), getTableComment(icebergTable)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
|
|
@@ -566,7 +582,10 @@ public Iterator<TableColumnsMetadata> streamTableColumns(ConnectorSession sessio | |||||||||||||||||||||||||
| if (redirectTable(session, tableName).isPresent()) { | ||||||||||||||||||||||||||
| return Stream.of(TableColumnsMetadata.forRedirectedTable(tableName)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| return Stream.of(TableColumnsMetadata.forTable(tableName, getTableMetadata(session, tableName).getColumns())); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Table icebergTable = catalog.loadTable(session, tableName); | ||||||||||||||||||||||||||
| List<ColumnMetadata> columns = getColumnMetadatas(icebergTable.schema()); | ||||||||||||||||||||||||||
| return Stream.of(TableColumnsMetadata.forTable(tableName, columns)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| catch (TableNotFoundException e) { | ||||||||||||||||||||||||||
| // Table disappeared during listing operation | ||||||||||||||||||||||||||
|
|
@@ -1282,13 +1301,12 @@ private void scanAndDeleteInvalidFiles(Table table, ConnectorSession session, Sc | |||||||||||||||||||||||||
| public Optional<Object> getInfo(ConnectorTableHandle tableHandle) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| IcebergTableHandle icebergTableHandle = (IcebergTableHandle) tableHandle; | ||||||||||||||||||||||||||
| PartitionSpec partitionSpec = PartitionSpecParser.fromJson( | ||||||||||||||||||||||||||
| SchemaParser.fromJson(icebergTableHandle.getTableSchemaJson()), | ||||||||||||||||||||||||||
| icebergTableHandle.getPartitionSpecJson()); | ||||||||||||||||||||||||||
| Optional<Boolean> partitioned = icebergTableHandle.getPartitionSpecJson() | ||||||||||||||||||||||||||
| .map(partitionSpecJson -> PartitionSpecParser.fromJson(SchemaParser.fromJson(icebergTableHandle.getTableSchemaJson()), partitionSpecJson).isPartitioned()); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return Optional.of(new IcebergInputInfo( | ||||||||||||||||||||||||||
| icebergTableHandle.getSnapshotId(), | ||||||||||||||||||||||||||
| partitionSpec.isPartitioned(), | ||||||||||||||||||||||||||
| partitioned, | ||||||||||||||||||||||||||
| getFileFormat(icebergTableHandle.getStorageProperties()).name())); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -1409,24 +1427,11 @@ public void renameColumn(ConnectorSession session, ConnectorTableHandle tableHan | |||||||||||||||||||||||||
| icebergTable.updateSchema().renameColumn(columnHandle.getName(), target).commit(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * @throws TableNotFoundException when table cannot be found | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| private ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table) | ||||||||||||||||||||||||||
| private List<ColumnMetadata> getColumnMetadatas(Schema schema) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| Table icebergTable = catalog.loadTable(session, table); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ImmutableList.Builder<ColumnMetadata> columns = ImmutableList.builder(); | ||||||||||||||||||||||||||
| columns.addAll(getColumnMetadatas(icebergTable)); | ||||||||||||||||||||||||||
| columns.add(pathColumnMetadata()); | ||||||||||||||||||||||||||
| columns.add(fileModifiedTimeColumnMetadata()); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return new ConnectorTableMetadata(table, columns.build(), getIcebergTableProperties(icebergTable), getTableComment(icebergTable)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private List<ColumnMetadata> getColumnMetadatas(Table table) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return table.schema().columns().stream() | ||||||||||||||||||||||||||
| List<ColumnMetadata> schemaColumns = schema.columns().stream() | ||||||||||||||||||||||||||
| .map(column -> | ||||||||||||||||||||||||||
| ColumnMetadata.builder() | ||||||||||||||||||||||||||
| .setName(column.name()) | ||||||||||||||||||||||||||
|
|
@@ -1435,6 +1440,10 @@ private List<ColumnMetadata> getColumnMetadatas(Table table) | |||||||||||||||||||||||||
| .setComment(Optional.ofNullable(column.doc())) | ||||||||||||||||||||||||||
| .build()) | ||||||||||||||||||||||||||
| .collect(toImmutableList()); | ||||||||||||||||||||||||||
| columns.addAll(schemaColumns); | ||||||||||||||||||||||||||
| columns.add(pathColumnMetadata()); | ||||||||||||||||||||||||||
| columns.add(fileModifiedTimeColumnMetadata()); | ||||||||||||||||||||||||||
| return columns.build(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||
|
|
@@ -1958,13 +1967,17 @@ private Optional<Long> getSnapshotId(Table table, Optional<Long> snapshotId, boo | |||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| // table.name() is an encoded version of SchemaTableName | ||||||||||||||||||||||||||
| return snapshotId | ||||||||||||||||||||||||||
| .map(id -> | ||||||||||||||||||||||||||
| snapshotIds.computeIfAbsent( | ||||||||||||||||||||||||||
| table.name() + "@" + id, | ||||||||||||||||||||||||||
| ignored -> IcebergUtil.resolveSnapshotId(table, id, allowLegacySnapshotSyntax))) | ||||||||||||||||||||||||||
| .map(id -> resolveSnapshotId(table, id, allowLegacySnapshotSyntax)) | ||||||||||||||||||||||||||
| .or(() -> Optional.ofNullable(table.currentSnapshot()).map(Snapshot::snapshotId)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private long resolveSnapshotId(Table table, long id, boolean allowLegacySnapshotSyntax) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return snapshotIds.computeIfAbsent( | ||||||||||||||||||||||||||
| table.name() + "@" + id, | ||||||||||||||||||||||||||
| ignored -> IcebergUtil.resolveSnapshotId(table, id, allowLegacySnapshotSyntax)); | ||||||||||||||||||||||||||
|
Member
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.
(pre-existing, but still sth to fix)
Contributor
Author
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. trino/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergUtil.java Lines 221 to 232 in 9b7c1b9
In case that I don't see the purpose behind this request.
Member
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.
only if |
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Table getIcebergTable(ConnectorSession session, SchemaTableName schemaTableName) | ||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||
| return catalog.loadTable(session, schemaTableName); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
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.
Nit, personally I think it make sense to add the path column to the list here. The other method is responsible for columns that come from the Iceberg schema.
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.
I did this refactor with the intention of not having code duplication in the methods where the column metadatas are built.
Should I try a better naming for the method?