This is an automated email from the ASF dual-hosted git repository. yuqi4733 pushed a commit to branch internal-main in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit a3cc5cebdc0c619f3a1bf9f176d8994c335d73d3 Author: Joseph Perez <[email protected]> AuthorDate: Fri Dec 12 01:15:05 2025 -0800 [#9414] fix(trino-connector) Add support for querying iceberg metadata tables (#9415) <!-- 1. Title: [#<issue>] <type>(<scope>): <subject> Examples: - "[#123] feat(operator): support xxx" - "[#233] fix: check null before access result in xxx" - "[MINOR] refactor: fix typo in variable name" - "[MINOR] docs: fix typo in README" - "[#255] test: fix flaky test NameOfTheTest" Reference: https://www.conventionalcommits.org/en/v1.0.0/ 2. If the PR is unfinished, please mark this PR as draft. --> ### What changes were proposed in this pull request? Added `getSystemTable()` override in `GravitinoMetadata` to delegate system table lookups to internal connector. This enables querying Iceberg metadata tables like `$snapshots` and `$manifests`, with trino connector. ### Why are the changes needed? For a bug fix - as of right now iceberg metadata tables are not queryable with the gravitino trino connector. Fix: #9414 ### Does this PR introduce _any_ user-facing change? Yes, users will now be able to query iceberg metatables. ### How was this patch tested? Without fix, unit test fails: ``` TestGravitinoMetadataGetSystemTable > testGetSystemTableDelegatesToInternalMetadata() FAILED org.opentest4j.AssertionFailedError: expected: <true> but was: <false> at app//org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151) at app//org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132) at app//org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63) at app//org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36) at app//org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:31) at app//org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:179) at app//org.apache.gravitino.trino.connector.TestGravitinoMetadataGetSystemTable.testGetSystemTableDelegatesToInternalMetadata(TestGravitinoMetadataGetSystemTable.java:58) ``` Also, made a targz of the change with ```./gradlew assembleTrinoConnector ``` and added trino deployment, then querying snapshots worked. --------- Co-authored-by: Yuhui <[email protected]> --- .../lakehouse-iceberg/00012_system_tables.sql | 38 ++++++++++ .../lakehouse-iceberg/00012_system_tables.txt | 13 ++++ .../trino/connector/GravitinoMetadata.java | 6 ++ .../TestGravitinoMetadataGetSystemTable.java | 83 ++++++++++++++++++++++ 4 files changed, 140 insertions(+) diff --git a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.sql b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.sql new file mode 100644 index 0000000000..9e4f286c15 --- /dev/null +++ b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.sql @@ -0,0 +1,38 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +-- Test Iceberg system tables are accessible through Gravitino connector + +CREATE SCHEMA IF NOT EXISTS gt_system_test; + +CREATE TABLE gt_system_test.test_table ( + id int, + name varchar +); + +INSERT INTO gt_system_test.test_table VALUES (1, 'test'); + +-- Query $snapshots system table - should have at least 1 snapshot from INSERT +SELECT count(*) >= 1 FROM "gt_system_test"."test_table$snapshots"; + +-- Query $history system table - should have at least 1 history entry +SELECT count(*) >= 1 FROM "gt_system_test"."test_table$history"; + +-- Cleanup +DROP TABLE gt_system_test.test_table; + +DROP SCHEMA gt_system_test; diff --git a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.txt b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.txt new file mode 100644 index 0000000000..5c492839a2 --- /dev/null +++ b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/lakehouse-iceberg/00012_system_tables.txt @@ -0,0 +1,13 @@ +CREATE SCHEMA + +CREATE TABLE + +INSERT: 1 row + +"true" + +"true" + +DROP TABLE + +DROP SCHEMA diff --git a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java index 36ad9bcdf4..eadb9d5bde 100644 --- a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java +++ b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java @@ -52,6 +52,7 @@ import io.trino.spi.connector.RowChangeParadigm; import io.trino.spi.connector.SaveMode; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.SortItem; +import io.trino.spi.connector.SystemTable; import io.trino.spi.connector.TopNApplicationResult; import io.trino.spi.expression.ConnectorExpression; import io.trino.spi.expression.Constant; @@ -152,6 +153,11 @@ public class GravitinoMetadata implements ConnectorMetadata { return metadataAdapter.getTableMetadata(table); } + @Override + public Optional<SystemTable> getSystemTable(ConnectorSession session, SchemaTableName tableName) { + return internalMetadata.getSystemTable(session, tableName); + } + @Override public SchemaTableName getTableName(ConnectorSession session, ConnectorTableHandle table) { return getTableName(table); diff --git a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoMetadataGetSystemTable.java b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoMetadataGetSystemTable.java new file mode 100644 index 0000000000..cfd846b05b --- /dev/null +++ b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/TestGravitinoMetadataGetSystemTable.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.trino.connector; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.trino.spi.connector.ConnectorMetadata; +import io.trino.spi.connector.ConnectorSession; +import io.trino.spi.connector.SchemaTableName; +import io.trino.spi.connector.SystemTable; +import java.util.Optional; +import org.apache.gravitino.trino.connector.catalog.CatalogConnectorMetadata; +import org.apache.gravitino.trino.connector.catalog.CatalogConnectorMetadataAdapter; +import org.junit.jupiter.api.Test; + +public class TestGravitinoMetadataGetSystemTable { + + @Test + public void testGetSystemTableDelegatesToInternalMetadata() { + CatalogConnectorMetadata catalogConnectorMetadata = mock(CatalogConnectorMetadata.class); + CatalogConnectorMetadataAdapter metadataAdapter = mock(CatalogConnectorMetadataAdapter.class); + ConnectorMetadata internalMetadata = mock(ConnectorMetadata.class); + ConnectorSession session = mock(ConnectorSession.class); + + SystemTable mockSystemTable = mock(SystemTable.class); + SchemaTableName tableName = new SchemaTableName("test_schema", "test_table$snapshots"); + + when(internalMetadata.getSystemTable(any(ConnectorSession.class), any(SchemaTableName.class))) + .thenReturn(Optional.of(mockSystemTable)); + + GravitinoMetadata gravitinoMetadata = + new GravitinoMetadata(catalogConnectorMetadata, metadataAdapter, internalMetadata); + + Optional<SystemTable> result = gravitinoMetadata.getSystemTable(session, tableName); + + assertTrue(result.isPresent()); + assertEquals(mockSystemTable, result.get()); + verify(internalMetadata).getSystemTable(session, tableName); + } + + @Test + public void testGetSystemTableReturnsEmptyWhenInternalReturnsEmpty() { + CatalogConnectorMetadata catalogConnectorMetadata = mock(CatalogConnectorMetadata.class); + CatalogConnectorMetadataAdapter metadataAdapter = mock(CatalogConnectorMetadataAdapter.class); + ConnectorMetadata internalMetadata = mock(ConnectorMetadata.class); + ConnectorSession session = mock(ConnectorSession.class); + + SchemaTableName tableName = new SchemaTableName("test_schema", "test_table$invalid"); + + when(internalMetadata.getSystemTable(any(ConnectorSession.class), any(SchemaTableName.class))) + .thenReturn(Optional.empty()); + + GravitinoMetadata gravitinoMetadata = + new GravitinoMetadata(catalogConnectorMetadata, metadataAdapter, internalMetadata); + + Optional<SystemTable> result = gravitinoMetadata.getSystemTable(session, tableName); + + assertFalse(result.isPresent()); + verify(internalMetadata).getSystemTable(session, tableName); + } +}
