Skip to content
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

Iceberg: Use table schema corresponding to snapshot in snapshot queries #12786

Merged
merged 3 commits into from Aug 2, 2022

Conversation

findinpath
Copy link
Contributor

Description

When performing a snapshot/time travel query, use the table schema corresponding to the snapshot.

Is this change a fix, improvement, new feature, refactoring, or other?

Bugfix

Is this a change to the core query engine, a connector, client library, or the SPI interfaces? (be specific)

How would you describe this change to a non-technical end user or system administrator?

In the context of the dealing with an Iceberg table with a structure which evolves over time (columns are added / dropped) in case of performing a snapshot/time travel query, the schema of the output should match the corresponding schema of the table snapshot queried.

Related issues, pull requests, and links

Fixes #12743

Documentation

(x) No documentation is needed.
( ) Sufficient documentation is included in this PR.
( ) Documentation PR is available with #prnumber.
( ) Documentation issue #issuenumber is filed, and can be handled later.

Release notes

( ) No release notes entries required.
(x) Release notes entries required with the following suggested text:

# Iceberg
* Use table schema corresponding to snapshot in snapshot queries

@cla-bot cla-bot bot added the cla-signed label Jun 10, 2022
private Schema getSchema(ConnectorSession session, IcebergTableHandle table)
{
Table icebergTable = catalog.loadTable(session, table.getSchemaTableName());
if (table.getSnapshotId().isEmpty() || table.getSnapshotId().get() == icebergTable.currentSnapshot().snapshotId()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

table.getSnapshotId() is always filled even when not doing snapshot queries because it is the way to see whether the table has or not data in IcebergSplitManager or TableStatisticsMaker.

With this value always filled, there is currently no way to know whether a specific snapshot of the table is being queried.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is desired behavior (explained here: #12786 (comment))

what you discovered is that snapshot-id doesn't describe table's state fully, in case there was ADD COLUMN (and no further INSERT yet).
We just need to capture what identifies the table state. I assume this is (snapshot-id, schema-id) pair. The table handle should therefore carry both.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've modified the logic of getTableHandle() method so that the correct tableSchemaJson and partitionSpecJson are transported over the IcebergTableHandle.
Thank you @findepi for hinting me towards this path.

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 5 times, most recently from 4327df3 to e28fab9 Compare June 13, 2022 09:59

return new ConnectorTableMetadata(table, columns.build(), getIcebergTableProperties(icebergTable), getTableComment(icebergTable));
return new ConnectorTableMetadata(table, columns, getIcebergTableProperties(icebergTable), getTableComment(icebergTable));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do table comments / properties also have a history we should be looking through during TT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are to be very puristic about time travelling, then yes.

The table metadata(s) corresponding to a snapshot contain the properties as well.

The table properties would need to be probably transported along the IcebergTableHandle (in order to avoid obtaining them on the fly by going through the table metadata files and causing unnecessary I/O operations).

cc @findepi @electrum


ImmutableList.Builder<ColumnMetadata> columns = ImmutableList.builder();
columns.addAll(getColumnMetadatas(icebergTable));
columns.add(pathColumnMetadata());
Copy link
Member

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.

Copy link
Contributor Author

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?

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 2 times, most recently from 489a3d5 to ee3a5b0 Compare June 14, 2022 12:56
@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch from ee3a5b0 to cd5782a Compare June 22, 2022 08:01
@findinpath findinpath requested a review from electrum June 22, 2022 08:10
@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 2 times, most recently from 9e778d2 to 741f4d1 Compare June 27, 2022 06:09
@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch from 741f4d1 to e362c8d Compare July 6, 2022 11:56
Copy link
Member

@ebyhr ebyhr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left initial comments.

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 2 times, most recently from 0b9e6ce to 279413c Compare July 8, 2022 05:35
@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch from 279413c to ae09364 Compare July 22, 2022 03:31
@findepi findepi requested a review from ebyhr July 22, 2022 13:17
Copy link
Member

@findepi findepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Retrieve schema and partition spec depending on the table snapshot"

{
return snapshotIds.computeIfAbsent(
table.name() + "@" + id,
ignored -> IcebergUtil.resolveSnapshotId(table, id, allowLegacySnapshotSyntax));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allowLegacySnapshotSyntax should be part of the cache key

(pre-existing, but still sth to fix)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public static long resolveSnapshotId(Table table, long snapshotId, boolean allowLegacySnapshotSyntax)
{
if (!allowLegacySnapshotSyntax) {
throw new TrinoException(
NOT_SUPPORTED,
format(
"Failed to access snapshot %s for table %s. This syntax for accessing Iceberg tables is not "
+ "supported. Use the AS OF syntax OR set the catalog session property "
+ "allow_legacy_snapshot_syntax=true for temporarily restoring previous behavior.",
snapshotId,
table.name()));
}

In case that allowLegacySnapshotSyntax is false we'd get a Trino exception.

I don't see the purpose behind this request.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case that allowLegacySnapshotSyntax is false we'd get a Trino exception.

only if snapshotIds entry doesn't exist yet.
cc @phd3

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch from ae09364 to 3270605 Compare July 25, 2022 05:17
@findepi
Copy link
Member

findepi commented Jul 25, 2022

ACK the small change (https://github.com/trinodb/trino/compare/ae09364cc7eae9e7dc13a4b8e9f84e5fcbc4a6de..3270605c060f415edcdf0a2579a312323e296a18)

The CI didn't run due to a merge conflict.
Can you please rebase (just rebase) before making further changes?

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 2 times, most recently from daa59bb to 641cc85 Compare July 26, 2022 15:21
@findinpath
Copy link
Contributor Author

Followed up on your hint @alexjo2144 #12786 (comment) and made the partitionSpecJson field in the IcebergTableHandle as optional.

Copy link
Member

@alexjo2144 alexjo2144 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me. Just take a look at the conflicts

@@ -338,7 +351,7 @@ public IcebergTableHandle getTableHandle(
Optional.empty());
}

private static long getSnapshotIdFromVersion(Table table, ConnectorTableVersion version)
private long getSnapshotIdFromVersion(Table table, ConnectorTableVersion version)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary?

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 3 times, most recently from 824b41b to 9c4ade2 Compare July 28, 2022 06:40
Copy link
Member

@findepi findepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Retrieve table schema depending on the table snapshot"

{
return snapshotIds.computeIfAbsent(
table.name() + "@" + id,
ignored -> IcebergUtil.resolveSnapshotId(table, id, allowLegacySnapshotSyntax));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case that allowLegacySnapshotSyntax is false we'd get a Trino exception.

only if snapshotIds entry doesn't exist yet.
cc @phd3

verify(table.getPartitionSpecJson().isPresent(), "The table handle must contain the partion spec definition");
return new IcebergPageSink(
tableSchema,
PartitionSpecParser.fromJson(tableSchema, table.getPartitionSpecJson().get()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

table.getPartitionSpecJson()
  .orElseThrow(() -> new VerifyException("Partition spec missing in the table handle")

and revert other changes here (addition of { ... })

@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch 2 times, most recently from 4d3fd06 to 4bb99a3 Compare July 29, 2022 11:10
@findinpath findinpath requested a review from findepi July 29, 2022 11:11
In the context of dealing with time travel queries, the
partition spec is intentionally not retrieved because it
would involve going through the all the metadata files of
the table and finding out which is the initial metadata file
(containing the partition spec) corresponding to the specified
table snapshot.
In the context of the dealing with an Iceberg table with a structure
which evolves over time (columns are added / dropped) in case of performing a
snapshot/time travel query, the schema of the output should match the
corresponding schema of the table snapshot queried.
@findinpath findinpath force-pushed the iceberg-snaphsot-query-schema branch from 4bb99a3 to c30d109 Compare July 30, 2022 15:05
@findepi findepi requested a review from alexjo2144 August 1, 2022 16:12
@findepi findepi requested review from electrum and removed request for electrum August 1, 2022 16:19
@findepi findepi merged commit ee3fd2f into trinodb:master Aug 2, 2022
@github-actions github-actions bot added this to the 392 milestone Aug 2, 2022
@findepi findepi mentioned this pull request Aug 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Iceberg snapshot queries use the latest schema of the table
7 participants