diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java index d1e8f670a9594..9d7b04b4694a0 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java @@ -113,7 +113,6 @@ import org.apache.iceberg.UpdatePartitionSpec; import org.apache.iceberg.UpdateProperties; import org.apache.iceberg.exceptions.NoSuchTableException; -import org.apache.iceberg.exceptions.NoSuchViewException; import org.apache.iceberg.exceptions.ValidationException; import org.apache.iceberg.types.Type; import org.apache.iceberg.types.TypeUtil; @@ -193,7 +192,6 @@ import static com.facebook.presto.iceberg.IcebergUtil.getSnapshotIdTimeOperator; import static com.facebook.presto.iceberg.IcebergUtil.getSortFields; import static com.facebook.presto.iceberg.IcebergUtil.getTableComment; -import static com.facebook.presto.iceberg.IcebergUtil.getViewComment; import static com.facebook.presto.iceberg.IcebergUtil.resolveSnapshotIdByName; import static com.facebook.presto.iceberg.IcebergUtil.toHiveColumns; import static com.facebook.presto.iceberg.IcebergUtil.tryGetLocation; @@ -320,7 +318,7 @@ protected final Table getIcebergTable(ConnectorSession session, SchemaTableName protected abstract Table getRawIcebergTable(ConnectorSession session, SchemaTableName schemaTableName); - protected abstract View getIcebergView(ConnectorSession session, SchemaTableName schemaTableName); + protected abstract Optional getViewMetadata(ConnectorSession session, SchemaTableName viewName); protected abstract void createIcebergView( ConnectorSession session, @@ -540,13 +538,9 @@ protected ConnectorTableMetadata getTableOrViewMetadata(ConnectorSession session // Considering that the Iceberg library does not provide an efficient way to determine whether // it's a view or a table without loading it, we first try to load it as a table directly, and then // try to load it as a view when getting an `NoSuchTableException`. This will be more efficient. - try { - View icebergView = getIcebergView(session, schemaTableName); - return new ConnectorTableMetadata(table, getColumnMetadata(session, icebergView), createViewMetadataProperties(icebergView), getViewComment(icebergView)); - } - catch (NoSuchViewException noSuchViewException) { - throw new TableNotFoundException(schemaTableName); - } + return getViewMetadata(session, schemaTableName) + .map(IcebergViewMetadata::getTableMetadata) + .orElseThrow(() -> new TableNotFoundException(schemaTableName)); } } @@ -1613,112 +1607,98 @@ public void createMaterializedView( @Override public List listMaterializedViews(ConnectorSession session, String schemaName) { - ImmutableList.Builder materializedViews = ImmutableList.builder(); - List views = listViews(session, Optional.of(schemaName)); - for (SchemaTableName viewName : views) { - View icebergView = getIcebergView(session, viewName); - Map properties = icebergView.properties(); - if (properties.containsKey(PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION)) { - materializedViews.add(viewName); - } - } - - return materializedViews.build(); + return views.stream() + .filter(viewName -> getViewMetadata(session, viewName) + .map(IcebergViewMetadata::isMaterializedView) + .orElse(false)) + .collect(toImmutableList()); } @Override public Optional getMaterializedView(ConnectorSession session, SchemaTableName viewName) { - try { - View icebergView = getIcebergView(session, viewName); + Optional viewMetadata = getViewMetadata(session, viewName); + if (!viewMetadata.isPresent() || !viewMetadata.get().isMaterializedView()) { + return Optional.empty(); + } - Map viewProperties = icebergView.properties(); - String originalSql = viewProperties.get(PRESTO_MATERIALIZED_VIEW_ORIGINAL_SQL); + Map viewProperties = viewMetadata.get().getProperties(); + String originalSql = viewProperties.get(PRESTO_MATERIALIZED_VIEW_ORIGINAL_SQL); - if (originalSql == null) { - return Optional.empty(); - } + if (originalSql == null) { + return Optional.empty(); + } - // Validate format version - String formatVersion = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION); - int version; - try { - version = Integer.parseInt(formatVersion); - } - catch (NumberFormatException e) { - throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, - format("Invalid materialized view format version: %s", formatVersion)); - } + // Validate format version + String formatVersion = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION); + int version; + try { + version = Integer.parseInt(formatVersion); + } + catch (NumberFormatException e) { + throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, + format("Invalid materialized view format version: %s", formatVersion)); + } - if (version != CURRENT_MATERIALIZED_VIEW_FORMAT_VERSION) { - throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, - format("Materialized view format version %d is not supported by this version of Presto (current version: %d). Please upgrade Presto.", - version, CURRENT_MATERIALIZED_VIEW_FORMAT_VERSION)); - } + if (version != CURRENT_MATERIALIZED_VIEW_FORMAT_VERSION) { + throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, + format("Materialized view format version %d is not supported by this version of Presto (current version: %d). Please upgrade Presto.", + version, CURRENT_MATERIALIZED_VIEW_FORMAT_VERSION)); + } - String baseTablesStr = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_BASE_TABLES); - List baseTables; - if (baseTablesStr.isEmpty()) { - baseTables = ImmutableList.of(); - } - else { - baseTables = deserializeSchemaTableNames(baseTablesStr); - } + String baseTablesStr = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_BASE_TABLES); + List baseTables; + if (baseTablesStr.isEmpty()) { + baseTables = ImmutableList.of(); + } + else { + baseTables = deserializeSchemaTableNames(baseTablesStr); + } - String columnMappingsJson = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_COLUMN_MAPPINGS); - List columnMappings = deserializeColumnMappings(columnMappingsJson); + String columnMappingsJson = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_COLUMN_MAPPINGS); + List columnMappings = deserializeColumnMappings(columnMappingsJson); - String storageSchema = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STORAGE_SCHEMA); - String storageTableName = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STORAGE_TABLE_NAME); + String storageSchema = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STORAGE_SCHEMA); + String storageTableName = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STORAGE_TABLE_NAME); - String owner = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_OWNER); - ViewSecurity securityMode; - try { - securityMode = ViewSecurity.valueOf(getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_SECURITY_MODE)); - } - catch (IllegalArgumentException | NullPointerException e) { - throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, "Invalid or missing materialized view security mode"); - } + String owner = getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_OWNER); + ViewSecurity securityMode; + try { + securityMode = ViewSecurity.valueOf(getRequiredMaterializedViewProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_SECURITY_MODE)); + } + catch (IllegalArgumentException | NullPointerException e) { + throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, "Invalid or missing materialized view security mode"); + } - // Parse staleness config - staleness window defaults to 0s if behavior is set - Optional staleReadBehavior = getOptionalEnumProperty( - viewProperties, PRESTO_MATERIALIZED_VIEW_STALE_READ_BEHAVIOR, MaterializedViewStaleReadBehavior.class); - Optional stalenessWindow = getOptionalDurationProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STALENESS_WINDOW); + // Parse staleness config - staleness window defaults to 0s if behavior is set + Optional staleReadBehavior = getOptionalEnumProperty( + viewProperties, PRESTO_MATERIALIZED_VIEW_STALE_READ_BEHAVIOR, MaterializedViewStaleReadBehavior.class); + Optional stalenessWindow = getOptionalDurationProperty(viewProperties, PRESTO_MATERIALIZED_VIEW_STALENESS_WINDOW); - Optional stalenessConfig = Optional.empty(); - if (staleReadBehavior.isPresent()) { - stalenessConfig = Optional.of(new MaterializedViewStalenessConfig( - staleReadBehavior.get(), - stalenessWindow.orElse(new Duration(0, TimeUnit.SECONDS)))); - } + Optional stalenessConfig = Optional.empty(); + if (staleReadBehavior.isPresent()) { + stalenessConfig = Optional.of(new MaterializedViewStalenessConfig( + staleReadBehavior.get(), + stalenessWindow.orElse(new Duration(0, TimeUnit.SECONDS)))); + } - Optional refreshType = getOptionalEnumProperty( - viewProperties, PRESTO_MATERIALIZED_VIEW_REFRESH_TYPE, MaterializedViewRefreshType.class); + Optional refreshType = getOptionalEnumProperty( + viewProperties, PRESTO_MATERIALIZED_VIEW_REFRESH_TYPE, MaterializedViewRefreshType.class); - return Optional.of(new MaterializedViewDefinition( - originalSql, - storageSchema, - storageTableName, - baseTables, - Optional.of(owner), - Optional.of(securityMode), - columnMappings, - ImmutableList.of(), - Optional.empty(), - stalenessConfig, - refreshType)); - } - catch (NoSuchViewException e) { - return Optional.empty(); - } - catch (PrestoException e) { - if (e.getErrorCode() == NOT_SUPPORTED.toErrorCode()) { - return Optional.empty(); - } - throw e; - } + return Optional.of(new MaterializedViewDefinition( + originalSql, + storageSchema, + storageTableName, + baseTables, + Optional.of(owner), + Optional.of(securityMode), + columnMappings, + ImmutableList.of(), + Optional.empty(), + stalenessConfig, + refreshType)); } @Override @@ -1749,8 +1729,12 @@ public MaterializedViewStatus getMaterializedViewStatus( return new MaterializedViewStatus(NOT_MATERIALIZED, ImmutableMap.of()); } - View icebergView = getIcebergView(session, materializedViewName); - Map props = icebergView.properties(); + Optional viewMetadata = getViewMetadata(session, materializedViewName); + if (!viewMetadata.isPresent()) { + throw new PrestoException(ICEBERG_INVALID_MATERIALIZED_VIEW, + format("Materialized view metadata not found for %s", materializedViewName)); + } + Map props = viewMetadata.get().getProperties(); String lastRefreshSnapshotStr = props.get(PRESTO_MATERIALIZED_VIEW_LAST_REFRESH_SNAPSHOT_ID); if (lastRefreshSnapshotStr == null) { return new MaterializedViewStatus(NOT_MATERIALIZED, ImmutableMap.of()); @@ -1967,12 +1951,6 @@ private static Optional getOptionalDurationProperty(Map getViewMetadata(ConnectorSession session, SchemaTableName viewName) { - throw new PrestoException(NOT_SUPPORTED, "Iceberg Hive catalog does not support native Iceberg views."); + Optional hiveTable = getHiveTable(session, viewName); + if (!hiveTable.isPresent()) { + return Optional.empty(); + } + + Table table = hiveTable.get(); + if (!isPrestoView(table)) { + return Optional.empty(); + } + + List columns = table.getDataColumns().stream() + .map(column -> ColumnMetadata.builder() + .setName(column.getName()) + .setType(column.getType().getType(typeManager)) + .setComment(column.getComment().orElse(null)) + .build()) + .collect(toImmutableList()); + + Map tableProperties = table.getParameters().entrySet().stream() + .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); + Optional comment = Optional.ofNullable(table.getParameters().get(TABLE_COMMENT)); + + ConnectorTableMetadata tableMetadata = new ConnectorTableMetadata( + viewName, + columns, + tableProperties, + comment); + + return Optional.of(new IcebergViewMetadata(table.getParameters(), tableMetadata)); } @Override @@ -240,6 +270,9 @@ protected boolean tableExists(ConnectorSession session, SchemaTableName schemaTa if (!hiveTable.isPresent()) { return false; } + if (isPrestoView(hiveTable.get())) { + return false; + } if (!isIcebergTable(hiveTable.get())) { throw new UnknownTableTypeException("Not an Iceberg table: " + schemaTableName); } @@ -448,7 +481,7 @@ public void createView(ConnectorSession session, ConnectorTableMetadata viewMeta Optional
existing = getHiveTable(session, viewName); if (existing.isPresent()) { - if (!replace || !isPrestoView(existing.get())) { + if (!replace || !isPrestoView(existing.get()) || isIcebergMaterializedView(existing.get())) { throw new ViewAlreadyExistsException(viewName); } @@ -471,7 +504,11 @@ public List listViews(ConnectorSession session, Optional table = getHiveTable(session, schemaTableName); + if (table.isPresent() && !isIcebergMaterializedView(table.get())) { + tableNames.add(schemaTableName); + } } } return tableNames.build(); @@ -480,7 +517,23 @@ public List listViews(ConnectorSession session, Optional listMaterializedViews(ConnectorSession session, String schemaName) { - return ImmutableList.of(); + MetastoreContext metastoreContext = getMetastoreContext(session); + ImmutableList.Builder materializedViews = ImmutableList.builder(); + + Optional> viewNames = metastore.getAllViews(metastoreContext, schemaName); + if (!viewNames.isPresent()) { + return ImmutableList.of(); + } + + for (String viewName : viewNames.get()) { + SchemaTableName schemaTableName = new SchemaTableName(schemaName, viewName); + Optional
table = getHiveTable(session, schemaTableName); + if (table.isPresent() && isIcebergMaterializedView(table.get())) { + materializedViews.add(schemaTableName); + } + } + + return materializedViews.build(); } @Override @@ -496,7 +549,7 @@ public Map getViews(ConnectorSession s } for (SchemaTableName schemaTableName : tableNames) { Optional
table = getHiveTable(session, schemaTableName); - if (table.isPresent() && isPrestoView(table.get())) { + if (table.isPresent() && isPrestoView(table.get()) && !isIcebergMaterializedView(table.get())) { verifyAndPopulateViews(table.get(), schemaTableName, decodeViewData(table.get().getViewOriginalText().get()), views); } } @@ -714,13 +767,51 @@ protected void createIcebergView( String viewSql, Map properties) { - throw new PrestoException(NOT_SUPPORTED, "Iceberg Hive catalog does not support native Iceberg views for materialized views."); + MetastoreContext metastoreContext = getMetastoreContext(session); + + ImmutableMap.Builder tableProperties = ImmutableMap.builder(); + tableProperties.putAll(properties); + tableProperties.putAll(createIcebergViewProperties(session, nodeVersion.toString())); + + ConnectorTableMetadata viewMetadata = new ConnectorTableMetadata(viewName, columns); + + Table table = createTableObjectForViewCreation( + session, + viewMetadata, + tableProperties.build(), + new HiveTypeTranslator(), + metastoreContext, + encodeViewData(viewSql)); + + PrincipalPrivileges privileges = buildInitialPrivilegeSet(session.getUser()); + + try { + metastore.createTable(metastoreContext, table, privileges, emptyList()); + } + catch (TableAlreadyExistsException e) { + throw new PrestoException(ALREADY_EXISTS, "Materialized view already exists: " + viewName); + } + + tableCache.invalidate(viewName); } @Override protected void dropIcebergView(ConnectorSession session, SchemaTableName schemaTableName) { - throw new PrestoException(NOT_SUPPORTED, "Iceberg Hive catalog does not support native Iceberg views for materialized views."); + MetastoreContext metastoreContext = getMetastoreContext(session); + + try { + metastore.dropTable( + metastoreContext, + schemaTableName.getSchemaName(), + schemaTableName.getTableName(), + true); + } + catch (TableNotFoundException e) { + throw new PrestoException(NOT_FOUND, "Materialized view not found: " + schemaTableName); + } + + tableCache.invalidate(schemaTableName); } @Override @@ -729,6 +820,36 @@ protected void updateIcebergViewProperties( SchemaTableName viewName, Map properties) { - throw new PrestoException(NOT_SUPPORTED, "Iceberg Hive catalog does not support native Iceberg views for materialized views."); + MetastoreContext metastoreContext = getMetastoreContext(session); + + Optional
existingTable = getHiveTable(session, viewName); + if (!existingTable.isPresent() || !isIcebergMaterializedView(existingTable.get())) { + throw new PrestoException(NOT_FOUND, "Materialized view not found: " + viewName); + } + + Table table = existingTable.get(); + + ImmutableMap.Builder mergedProperties = ImmutableMap.builder(); + mergedProperties.putAll(table.getParameters()); + mergedProperties.putAll(properties); + + Table updatedTable = Table.builder(table) + .setParameters(mergedProperties.buildKeepingLast()) + .build(); + + PrincipalPrivileges privileges = buildInitialPrivilegeSet(table.getOwner()); + metastore.replaceTable( + metastoreContext, + viewName.getSchemaName(), + viewName.getTableName(), + updatedTable, + privileges); + + tableCache.invalidate(viewName); + } + + private static boolean isIcebergMaterializedView(Table table) + { + return table.getParameters().containsKey(PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION); } } diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java index 9202be8e4d5c4..6100583f33566 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java @@ -75,6 +75,7 @@ import static com.facebook.presto.iceberg.IcebergUtil.getColumnsForWrite; import static com.facebook.presto.iceberg.IcebergUtil.getNativeIcebergTable; import static com.facebook.presto.iceberg.IcebergUtil.getNativeIcebergView; +import static com.facebook.presto.iceberg.IcebergUtil.getViewComment; import static com.facebook.presto.iceberg.IcebergUtil.populateTableProperties; import static com.facebook.presto.iceberg.PartitionFields.parsePartitionFields; import static com.facebook.presto.iceberg.PartitionSpecConverter.toPrestoPartitionSpec; @@ -135,8 +136,7 @@ protected Table getRawIcebergTable(ConnectorSession session, SchemaTableName sch return getNativeIcebergTable(catalogFactory, session, schemaTableName); } - @Override - protected View getIcebergView(ConnectorSession session, SchemaTableName schemaTableName) + private View getIcebergView(ConnectorSession session, SchemaTableName schemaTableName) { try { return icebergViews.computeIfAbsent( @@ -152,6 +152,27 @@ protected View getIcebergView(ConnectorSession session, SchemaTableName schemaTa } } + @Override + protected Optional getViewMetadata(ConnectorSession session, SchemaTableName viewName) + { + Catalog catalog = catalogFactory.getCatalog(session); + if (!(catalog instanceof ViewCatalog)) { + return Optional.empty(); + } + try { + View view = getIcebergView(session, viewName); + ConnectorTableMetadata tableMetadata = new ConnectorTableMetadata( + viewName, + getColumnMetadata(session, view), + createViewMetadataProperties(view), + getViewComment(view)); + return Optional.of(new IcebergViewMetadata(view.properties(), tableMetadata)); + } + catch (NoSuchViewException e) { + return Optional.empty(); + } + } + @Override protected boolean tableExists(ConnectorSession session, SchemaTableName schemaTableName) { diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergViewMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergViewMetadata.java new file mode 100644 index 0000000000000..9990f1ce11513 --- /dev/null +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergViewMetadata.java @@ -0,0 +1,49 @@ +/* + * Licensed 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 com.facebook.presto.iceberg; + +import com.facebook.presto.spi.ConnectorTableMetadata; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +import static com.facebook.presto.iceberg.IcebergAbstractMetadata.PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION; +import static java.util.Objects.requireNonNull; + +public class IcebergViewMetadata +{ + private final Map properties; + private final ConnectorTableMetadata tableMetadata; + + public IcebergViewMetadata(Map properties, ConnectorTableMetadata tableMetadata) + { + this.properties = ImmutableMap.copyOf(requireNonNull(properties, "properties is null")); + this.tableMetadata = requireNonNull(tableMetadata, "tableMetadata is null"); + } + + public Map getProperties() + { + return properties; + } + + public ConnectorTableMetadata getTableMetadata() + { + return tableMetadata; + } + + public boolean isMaterializedView() + { + return properties.containsKey(PRESTO_MATERIALIZED_VIEW_FORMAT_VERSION); + } +} diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViews.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViewsBase.java similarity index 97% rename from presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViews.java rename to presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViewsBase.java index 0f28075e33898..4cf946701bc31 100644 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViews.java +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergMaterializedViewsBase.java @@ -13,71 +13,18 @@ */ package com.facebook.presto.iceberg; -import com.facebook.airlift.http.server.testing.TestingHttpServer; import com.facebook.presto.Session; -import com.facebook.presto.testing.QueryRunner; import com.facebook.presto.tests.AbstractTestQueryFramework; -import com.google.common.collect.ImmutableMap; -import org.assertj.core.util.Files; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.File; -import java.util.Optional; - -import static com.facebook.presto.iceberg.CatalogType.REST; -import static com.facebook.presto.iceberg.rest.IcebergRestTestUtil.getRestServer; -import static com.facebook.presto.iceberg.rest.IcebergRestTestUtil.restConnectorProperties; -import static com.google.common.io.MoreFiles.deleteRecursively; -import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; @Test(singleThreaded = true) -public class TestIcebergMaterializedViews +public abstract class TestIcebergMaterializedViewsBase extends AbstractTestQueryFramework { - private File warehouseLocation; - private TestingHttpServer restServer; - private String serverUri; - - @BeforeClass - @Override - public void init() - throws Exception - { - warehouseLocation = Files.newTemporaryFolder(); - - restServer = getRestServer(warehouseLocation.getAbsolutePath()); - restServer.start(); - - serverUri = restServer.getBaseUrl().toString(); - super.init(); - } - - @AfterClass(alwaysRun = true) - public void tearDown() - throws Exception - { - if (restServer != null) { - restServer.stop(); - } - deleteRecursively(warehouseLocation.toPath(), ALLOW_INSECURE); - } - - @Override - protected QueryRunner createQueryRunner() - throws Exception - { - return IcebergQueryRunner.builder() - .setCatalogType(REST) - .setExtraConnectorProperties(restConnectorProperties(serverUri)) - .setDataDirectory(Optional.of(warehouseLocation.toPath())) - .setSchemaName("test_schema") - .setCreateTpchTables(false) - .setExtraProperties(ImmutableMap.of("experimental.legacy-materialized-views", "false")) - .build().getQueryRunner(); - } + protected File warehouseLocation; @Test public void testCreateMaterializedView() diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/hive/TestIcebergMaterializedViewsHive.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/hive/TestIcebergMaterializedViewsHive.java new file mode 100644 index 0000000000000..e8b32c8201968 --- /dev/null +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/hive/TestIcebergMaterializedViewsHive.java @@ -0,0 +1,64 @@ +/* + * Licensed 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 com.facebook.presto.iceberg.hive; + +import com.facebook.presto.iceberg.TestIcebergMaterializedViewsBase; +import com.facebook.presto.testing.QueryRunner; +import com.google.common.collect.ImmutableMap; +import org.assertj.core.util.Files; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static com.facebook.presto.iceberg.CatalogType.HIVE; +import static com.facebook.presto.iceberg.IcebergQueryRunner.builder; +import static com.google.common.io.MoreFiles.deleteRecursively; +import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; + +@Test(singleThreaded = true) +public class TestIcebergMaterializedViewsHive + extends TestIcebergMaterializedViewsBase +{ + @BeforeClass + @Override + public void init() + throws Exception + { + warehouseLocation = Files.newTemporaryFolder(); + super.init(); + getQueryRunner().execute("CREATE SCHEMA IF NOT EXISTS test_schema"); + } + + @AfterClass(alwaysRun = true) + public void tearDown() + throws Exception + { + deleteRecursively(warehouseLocation.toPath(), ALLOW_INSECURE); + } + + @Override + protected QueryRunner createQueryRunner() + throws Exception + { + return builder() + .setCatalogType(HIVE) + .setDataDirectory(Optional.of(warehouseLocation.toPath())) + .setSchemaName("test_schema") + .setCreateTpchTables(false) + .setExtraProperties(ImmutableMap.of("experimental.legacy-materialized-views", "false")) + .build().getQueryRunner(); + } +} diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/rest/TestIcebergMaterializedViewsRest.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/rest/TestIcebergMaterializedViewsRest.java new file mode 100644 index 0000000000000..176ac06664df8 --- /dev/null +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/rest/TestIcebergMaterializedViewsRest.java @@ -0,0 +1,79 @@ +/* + * Licensed 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 com.facebook.presto.iceberg.rest; + +import com.facebook.airlift.http.server.testing.TestingHttpServer; +import com.facebook.presto.iceberg.TestIcebergMaterializedViewsBase; +import com.facebook.presto.testing.QueryRunner; +import com.google.common.collect.ImmutableMap; +import org.assertj.core.util.Files; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static com.facebook.presto.iceberg.CatalogType.REST; +import static com.facebook.presto.iceberg.IcebergQueryRunner.builder; +import static com.facebook.presto.iceberg.rest.IcebergRestTestUtil.getRestServer; +import static com.facebook.presto.iceberg.rest.IcebergRestTestUtil.restConnectorProperties; +import static com.google.common.io.MoreFiles.deleteRecursively; +import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; + +@Test(singleThreaded = true) +public class TestIcebergMaterializedViewsRest + extends TestIcebergMaterializedViewsBase +{ + private TestingHttpServer restServer; + private String serverUri; + + @BeforeClass + @Override + public void init() + throws Exception + { + warehouseLocation = Files.newTemporaryFolder(); + + restServer = getRestServer(warehouseLocation.getAbsolutePath()); + restServer.start(); + + serverUri = restServer.getBaseUrl().toString(); + super.init(); + getQueryRunner().execute("CREATE SCHEMA IF NOT EXISTS test_schema"); + } + + @AfterClass(alwaysRun = true) + public void tearDown() + throws Exception + { + if (restServer != null) { + restServer.stop(); + } + deleteRecursively(warehouseLocation.toPath(), ALLOW_INSECURE); + } + + @Override + protected QueryRunner createQueryRunner() + throws Exception + { + return builder() + .setCatalogType(REST) + .setExtraConnectorProperties(restConnectorProperties(serverUri)) + .setDataDirectory(Optional.of(warehouseLocation.toPath())) + .setSchemaName("test_schema") + .setCreateTpchTables(false) + .setExtraProperties(ImmutableMap.of("experimental.legacy-materialized-views", "false")) + .build().getQueryRunner(); + } +}