diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java index f1bfe5923fbb0..448ccbf3ca792 100644 --- a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java +++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java @@ -353,6 +353,16 @@ default void createView(Identifier identifier, View view, boolean ignoreIfExists throw new UnsupportedOperationException(); } + /** + * Get names of all views under this database. An empty list is returned if none exists. + * + * @return a list of the names of all views in this database + * @throws DatabaseNotExistException if the database does not exist + */ + default List listViews(String databaseName) throws DatabaseNotExistException { + throw new UnsupportedOperationException(); + } + /** Return a boolean that indicates whether this catalog allow upper case. */ boolean allowUpperCase(); diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java index a2bbf97676cd6..37b96877c8971 100644 --- a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java +++ b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java @@ -153,6 +153,11 @@ public void createView(Identifier identifier, View view, boolean ignoreIfExists) wrapped.createView(identifier, view, ignoreIfExists); } + @Override + public List listViews(String databaseName) throws DatabaseNotExistException { + return wrapped.listViews(databaseName); + } + @Override public Path getTableLocation(Identifier identifier) { return wrapped.getTableLocation(identifier); diff --git a/paimon-core/src/main/java/org/apache/paimon/view/ViewImpl.java b/paimon-core/src/main/java/org/apache/paimon/view/ViewImpl.java index 6207f9d576ead..1cd48d4ce4457 100644 --- a/paimon-core/src/main/java/org/apache/paimon/view/ViewImpl.java +++ b/paimon-core/src/main/java/org/apache/paimon/view/ViewImpl.java @@ -89,8 +89,12 @@ public View copy(Map dynamicOptions) { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ViewImpl view = (ViewImpl) o; return Objects.equals(identifier, view.identifier) && Objects.equals(rowType, view.rowType) diff --git a/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java index 58f5a52a5ae0f..9bb643c9e60bc 100644 --- a/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java +++ b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java @@ -862,6 +862,9 @@ public void testView() throws Exception { assertThatThrownBy(() -> catalog.createView(identifier, view, false)) .isInstanceOf(Catalog.DatabaseNotExistException.class); + assertThatThrownBy(() -> catalog.listViews(identifier.getDatabaseName())) + .isInstanceOf(Catalog.DatabaseNotExistException.class); + catalog.createDatabase(identifier.getDatabaseName(), false); assertThatThrownBy(() -> catalog.getView(identifier)) @@ -878,6 +881,9 @@ public void testView() throws Exception { assertThat(catalogView.comment()).isEqualTo(view.comment()); assertThat(catalogView.options()).containsAllEntriesOf(view.options()); + List views = catalog.listViews(identifier.getDatabaseName()); + assertThat(views).containsOnly(identifier.getObjectName()); + catalog.createView(identifier, view, true); assertThatThrownBy(() -> catalog.createView(identifier, view, false)) .isInstanceOf(Catalog.ViewAlreadyExistException.class); diff --git a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkCatalog.java b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkCatalog.java index ab0abeed99455..ddb960c6bae99 100644 --- a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkCatalog.java +++ b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkCatalog.java @@ -284,7 +284,6 @@ public CatalogBaseTable getTable(ObjectPath tablePath, long timestamp) private CatalogBaseTable getTable(ObjectPath tablePath, @Nullable Long timestamp) throws TableNotExistException { - Identifier identifier = toIdentifier(tablePath); Table table; try { table = catalog.getTable(toIdentifier(tablePath)); @@ -387,41 +386,15 @@ public void createTable(ObjectPath tablePath, CatalogBaseTable table, boolean ig "Creating table in default database is disabled, please specify a database name."); } - Identifier identifier = toIdentifier(tablePath); - // the returned value of "table.getOptions" may be unmodifiable (for example from - // TableDescriptor) - Map options = new HashMap<>(table.getOptions()); - if (table instanceof CatalogView) { - ResolvedCatalogView viewTable = (ResolvedCatalogView) table; - org.apache.paimon.types.RowType.Builder builder = - org.apache.paimon.types.RowType.builder(); - viewTable - .getResolvedSchema() - .getColumns() - .forEach( - column -> - builder.field( - column.getName(), - toDataType(column.getDataType().getLogicalType()), - column.getComment().orElse(null))); - View view = - new ViewImpl( - identifier, - builder.build(), - viewTable.getExpandedQuery(), - viewTable.getComment(), - viewTable.getOptions()); - try { - catalog.createView(identifier, view, ignoreIfExists); - } catch (Catalog.ViewAlreadyExistException e) { - throw new TableAlreadyExistException(getName(), tablePath); - } catch (Catalog.DatabaseNotExistException e) { - throw new DatabaseNotExistException(getName(), tablePath.getDatabaseName()); - } + createView(tablePath, (ResolvedCatalogView) table, ignoreIfExists); return; } + Identifier identifier = toIdentifier(tablePath); + // the returned value of "table.getOptions" may be unmodifiable (for example from + // TableDescriptor) + Map options = new HashMap<>(table.getOptions()); if (table instanceof CatalogMaterializedTable) { fillOptionsForMaterializedTable((CatalogMaterializedTable) table, options); } @@ -443,6 +416,34 @@ public void createTable(ObjectPath tablePath, CatalogBaseTable table, boolean ig } } + private void createView(ObjectPath tablePath, ResolvedCatalogView table, boolean ignoreIfExists) + throws TableAlreadyExistException, DatabaseNotExistException { + Identifier identifier = toIdentifier(tablePath); + org.apache.paimon.types.RowType.Builder builder = org.apache.paimon.types.RowType.builder(); + table.getResolvedSchema() + .getColumns() + .forEach( + column -> + builder.field( + column.getName(), + toDataType(column.getDataType().getLogicalType()), + column.getComment().orElse(null))); + View view = + new ViewImpl( + identifier, + builder.build(), + table.getOriginalQuery(), + table.getComment(), + table.getOptions()); + try { + catalog.createView(identifier, view, ignoreIfExists); + } catch (Catalog.ViewAlreadyExistException e) { + throw new TableAlreadyExistException(getName(), tablePath); + } catch (Catalog.DatabaseNotExistException e) { + throw new DatabaseNotExistException(getName(), tablePath.getDatabaseName()); + } + } + private static void fillOptionsForMaterializedTable( CatalogMaterializedTable mt, Map options) { Options mtOptions = new Options(); @@ -1096,8 +1097,13 @@ public final void renameTable( } @Override - public final List listViews(String databaseName) throws CatalogException { - return Collections.emptyList(); + public final List listViews(String databaseName) + throws DatabaseNotExistException, CatalogException { + try { + return catalog.listViews(databaseName); + } catch (Catalog.DatabaseNotExistException e) { + throw new DatabaseNotExistException(getName(), databaseName); + } } @Override diff --git a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java index 0c2e2f3825287..365ea5dd9a07d 100644 --- a/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java +++ b/paimon-hive/paimon-hive-catalog/src/main/java/org/apache/paimon/hive/HiveCatalog.java @@ -576,6 +576,33 @@ public void dropView(Identifier identifier, boolean ignoreIfNotExists) } } + @Override + public List listViews(String databaseName) throws DatabaseNotExistException { + if (isSystemDatabase(databaseName)) { + return Collections.emptyList(); + } + if (!databaseExists(databaseName)) { + throw new DatabaseNotExistException(databaseName); + } + + try { + List tables = clients.run(client -> client.getAllTables(databaseName)); + List views = new ArrayList<>(); + for (String tableName : tables) { + Table table = clients.run(client -> client.getTable(databaseName, tableName)); + if (TableType.valueOf(table.getTableType()) == TableType.VIRTUAL_VIEW) { + views.add(tableName); + } + } + return views; + } catch (TException e) { + throw new RuntimeException("Failed to list all tables in database " + databaseName, e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted in call to listTables " + databaseName, e); + } + } + @Override public FormatTable getFormatTable(Identifier identifier) throws TableNotExistException { if (!formatTableEnabled()) { diff --git a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java index f34e1344f9aa2..cca044f0438ab 100644 --- a/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java +++ b/paimon-hive/paimon-hive-connector-common/src/test/java/org/apache/paimon/hive/HiveCatalogITCaseBase.java @@ -1921,9 +1921,8 @@ public void testView() throws Exception { tEnv.executeSql("CREATE VIEW flink_v AS SELECT a + 1, b FROM t").await(); assertThat(collect("SELECT * FROM flink_v")) .containsExactlyInAnyOrder(Row.of(2, "Hi"), Row.of(3, "Hello")); - - // hive cannot query flink view, flink view will expand table name to - // `my_hive`.`test_db`.`t` + assertThat(hiveShell.executeQuery("SELECT * FROM flink_v")) + .containsExactlyInAnyOrder("2\tHi", "3\tHello"); // test hive view hiveShell.executeQuery("CREATE VIEW hive_v AS SELECT a + 1, b FROM t"); @@ -1932,6 +1931,9 @@ public void testView() throws Exception { assertThat(hiveShell.executeQuery("SELECT * FROM hive_v")) .containsExactlyInAnyOrder("2\tHi", "3\tHello"); + assertThat(collect("SHOW VIEWS")) + .containsExactlyInAnyOrder(Row.of("flink_v"), Row.of("hive_v")); + collect("DROP VIEW flink_v"); collect("DROP VIEW hive_v"); }