Skip to content

Conversation

codluca
Copy link
Member

@codluca codluca commented Oct 3, 2025

Fix support for system tables for Lakehouse.
The $files and $history system tables for Iceberg tables are not handled properly.

Fixes #26751

Description

For system tables, the handle will be an instance of io.trino.connector.system.SystemTableHandle.
Some Iceberg system tables ($files and $history) use special splits (FilesTableSplit).

io.trino.connector.system.SystemTableHandle is part of trino-main, which is a test dependency for trino-lakehouse.
The dependency to trino-main is not changed.

Release notes

## Lakehouse
* Fix failure when reading metadata tables. ({issue}`26751`)

@cla-bot cla-bot bot added the cla-signed label Oct 3, 2025
@wendigo wendigo requested a review from chenjian2664 October 3, 2025 09:14
@ebyhr ebyhr self-requested a review October 3, 2025 09:21
@codluca codluca force-pushed the 26751-lakehouse-system-tables branch from 7356018 to 3ad2a43 Compare October 3, 2025 16:09
@github-actions github-actions bot added the iceberg Iceberg connector label Oct 3, 2025
@codluca codluca force-pushed the 26751-lakehouse-system-tables branch from 3b04a7b to 07fce46 Compare October 3, 2025 17:50
@martint martint requested a review from electrum October 3, 2025 17:52
}

@Test
public void testSelectDeltaMetaTables()
Copy link
Member

Choose a reason for hiding this comment

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

https://trino.io/docs/current/develop/tests.html#conventions-and-recommendations

  • Test methods should be defined as package-private.

This test can be renamed to testSelectMetadataTable.

Copy link
Member Author

Choose a reason for hiding this comment

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

"Test classes should be defined as package-private and final."
"Test methods should be defined as package-private."
Should I change the class to be package private and final, and the other methods to be package private?
Or just the new methods?

Copy link
Member

Choose a reason for hiding this comment

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

You can change existing visibility, but I recommend handling in a separate PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, fixed

{
computeActual(
"""
CREATE TABLE delta_table
Copy link
Member

@ebyhr ebyhr Oct 3, 2025

Choose a reason for hiding this comment

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

Please avoid a static table name. Use TestTable with try-with-resources instead. Or please consider using the existing table.

Copy link
Member Author

Choose a reason for hiding this comment

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

Used existing table

AS SELECT * FROM tpch.tiny.region
""");

assertQuery("SELECT count(*) FROM \"delta_table$history\"", "VALUES 1");
Copy link
Member

Choose a reason for hiding this comment

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

assertQuery method isn't recommend. Please use assertThat(query(...)) instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to using assertThat(query(...))

@Test
public void testSelectDeltaMetaTables()
{
computeActual(
Copy link
Member

Choose a reason for hiding this comment

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

We usually use assertUpdate for DDL.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to use existing table

default -> {
// For system tables, the handle will be an instance of io.trino.connector.system.SystemTableHandle
// Some Iceberg system tables ($files and $history) use special splits (FilesTableSplit)
if (split instanceof FilesTableSplit) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the handle in this case? it should be the FilesTable right?

Copy link
Member Author

@codluca codluca Oct 4, 2025

Choose a reason for hiding this comment

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

No, it's of io.trino.connector.system.SystemTableHandle type.
And the split is of io.trino.plugin.iceberg.system.files.FilesTableSplit type.

io.trino.connector.system.SystemTableHandle is from trino-main module, which is only a test dependency. That's why I didn't add a new switch case for SystemTableHandle.

Copy link
Contributor

@chenjian2664 chenjian2664 Oct 12, 2025

Choose a reason for hiding this comment

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

Thanks.
In this case we could add a case branch instead of putting it in the default, and raise nice error message to mention which kind of split we are not support yet with the SystemTableHandle

Copy link
Member Author

Choose a reason for hiding this comment

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

io.trino.connector.system.SystemTableHandle is from trino-main module, which is only a test dependency.
What should be the new scope of the trino-main module?

Copy link
Contributor

Choose a reason for hiding this comment

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

Make that scope to compile should be fine in this case

Copy link
Member

@ebyhr ebyhr Oct 12, 2025

Choose a reason for hiding this comment

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

Disagree. Please don't include trino-main as a dependency. The module isn't supposed to be depended on by connectors.

Copy link
Member

Choose a reason for hiding this comment

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

It wouldn't work anyway, as the class is in a different class loader.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks @ebyhr @electrum , just got to know

@codluca codluca force-pushed the 26751-lakehouse-system-tables branch from 2aeb63e to 10fecac Compare October 4, 2025 13:11
Comment on lines 71 to 74
assertThatThrownBy(() -> computeScalar("SELECT count(*) FROM lakehouse.tpch.\"region$files\""))
.hasMessageMatching(".* Table .* does not exist");
assertThatThrownBy(() -> computeScalar("SELECT count(*) FROM lakehouse.tpch.\"region$timeline\""))
.hasMessageMatching(".* Table .* does not exist");
Copy link
Member

Choose a reason for hiding this comment

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

Please use assertThat(query(...)).failure() so we can ensure that the exception class is TrinoException.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not able to get the assertion to work. I can't find an example either.
TrinoException is wrapped in a QueryFailedException, which has a cause of FailureException.
The TrinoException is stored as FailureInfo in FailureException.

        assertThat(query("SELECT count(*) FROM lakehouse.tpch.\"region$history\""))
                .failure().isInstanceOf(TrinoException.class).hasMessage(".* Table .* does not exist");
- fails with ->
java.lang.AssertionError: 
Expecting actual throwable to be an instance of:
  io.trino.spi.TrinoException
but was:
  io.trino.testing.QueryFailedException: line 1:22: Table 'lakehouse.tpch."region$history"' does not exist
        assertThat(query("SELECT count(*) FROM lakehouse.tpch.\"region$history\""))
                .failure().hasCauseInstanceOf(TrinoException.class).hasMessage(".* Table .* does not exist");
- fails with ->
java.lang.AssertionError: 
Expecting a throwable with cause being an instance of:
  io.trino.spi.TrinoException
but was an instance of:
  io.trino.client.FailureException
Throwable that failed the check:
io.trino.testing.QueryFailedException: line 1:22: Table 'lakehouse.tpch."region$history"' does not exist

        assertThatThrownBy(() -> computeScalar("SELECT count(*) FROM lakehouse.tpch.\"region$history\""))
                .isInstanceOf(TrinoException.class).hasMessageMatching(".* Table .* does not exist";
   assertThatThrownBy(() -> computeScalar("SELECT count(*) FROM lakehouse.tpch.\"region$history\""))
            .isInstanceOf(TrinoException.class).hasMessageMatching(".* Table .* does not exist";
  • fails like the first example above

@codluca codluca force-pushed the 26751-lakehouse-system-tables branch from 8376952 to 7eee45e Compare October 5, 2025 19:23
For system tables, the handle will be an instance of io.trino.connector.system.SystemTableHandle.
Some Iceberg system tables ($files and $history) use special splits (FilesTableSplit).
@codluca codluca force-pushed the 26751-lakehouse-system-tables branch from 7eee45e to a83442b Compare October 7, 2025 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

Lakehouse connector throws exception when reading system tables

4 participants