diff --git a/core/trino-main/src/main/java/io/trino/execution/RenameTableTask.java b/core/trino-main/src/main/java/io/trino/execution/RenameTableTask.java index 7f36d84cb1ca..3cbcbfec9d9a 100644 --- a/core/trino-main/src/main/java/io/trino/execution/RenameTableTask.java +++ b/core/trino-main/src/main/java/io/trino/execution/RenameTableTask.java @@ -100,6 +100,12 @@ public ListenableFuture execute( if (metadata.getCatalogHandle(session, target.getCatalogName()).isEmpty()) { throw semanticException(CATALOG_NOT_FOUND, statement, "Target catalog '%s' does not exist", target.getCatalogName()); } + if (metadata.isMaterializedView(session, target)) { + throw semanticException(GENERIC_USER_ERROR, statement, "Target table '%s' does not exist, but a materialized view with that name exists.", target); + } + if (metadata.isView(session, target)) { + throw semanticException(GENERIC_USER_ERROR, statement, "Target table '%s' does not exist, but a view with that name exists.", target); + } if (metadata.getTableHandle(session, target).isPresent()) { throw semanticException(TABLE_ALREADY_EXISTS, statement, "Target table '%s' already exists", target); } diff --git a/core/trino-main/src/main/java/io/trino/execution/RenameViewTask.java b/core/trino-main/src/main/java/io/trino/execution/RenameViewTask.java index b488902cea1d..b93f8892eb04 100644 --- a/core/trino-main/src/main/java/io/trino/execution/RenameViewTask.java +++ b/core/trino-main/src/main/java/io/trino/execution/RenameViewTask.java @@ -29,6 +29,7 @@ import static com.google.common.util.concurrent.Futures.immediateVoidFuture; import static io.trino.metadata.MetadataUtil.createQualifiedObjectName; import static io.trino.spi.StandardErrorCode.CATALOG_NOT_FOUND; +import static io.trino.spi.StandardErrorCode.GENERIC_USER_ERROR; import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; import static io.trino.spi.StandardErrorCode.TABLE_ALREADY_EXISTS; import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; @@ -85,8 +86,14 @@ public ListenableFuture execute( if (metadata.getCatalogHandle(session, target.getCatalogName()).isEmpty()) { throw semanticException(CATALOG_NOT_FOUND, statement, "Target catalog '%s' does not exist", target.getCatalogName()); } + if (metadata.isMaterializedView(session, target)) { + throw semanticException(GENERIC_USER_ERROR, statement, "Target view '%s' does not exist, but a materialized view with that name exists.", target); + } if (metadata.isView(session, target)) { - throw semanticException(TABLE_ALREADY_EXISTS, statement, "Target view '%s' already exists", target); + throw semanticException(GENERIC_USER_ERROR, statement, "Target view '%s' already exists", target); + } + if (metadata.getTableHandle(session, target).isPresent()) { + throw semanticException(TABLE_ALREADY_EXISTS, statement, "Target view '%s' does not exist, but a table with that name exists.", target); } if (!viewName.getCatalogName().equals(target.getCatalogName())) { throw semanticException(NOT_SUPPORTED, statement, "View rename across catalogs is not supported"); diff --git a/core/trino-main/src/test/java/io/trino/execution/TestRenameTableTask.java b/core/trino-main/src/test/java/io/trino/execution/TestRenameTableTask.java index 4233b467591d..3a67d90a36e2 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestRenameTableTask.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestRenameTableTask.java @@ -107,6 +107,32 @@ public void testRenameTableOnMaterializedViewIfExists() .hasMessage("Table '%s' does not exist, but a materialized view with that name exists. Did you mean ALTER MATERIALIZED VIEW catalog.schema.existing_materialized_view RENAME TO ...?", viewName); } + @Test + public void testRenameTableTargetViewExists() + { + QualifiedObjectName tableName = qualifiedObjectName("existing_table"); + metadata.createTable(testSession, CATALOG_NAME, someTable(tableName), false); + QualifiedName viewName = qualifiedName("existing_view"); + metadata.createView(testSession, QualifiedObjectName.valueOf(viewName.toString()), someView(), false); + + assertTrinoExceptionThrownBy(() -> getFutureValue(executeRenameTable(asQualifiedName(tableName), viewName, false))) + .hasErrorCode(GENERIC_USER_ERROR) + .hasMessage("Target table '%s' does not exist, but a view with that name exists.", viewName); + } + + @Test + public void testRenameTableTargetMaterializedViewExists() + { + QualifiedObjectName tableName = qualifiedObjectName("existing_table"); + metadata.createTable(testSession, CATALOG_NAME, someTable(tableName), false); + QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view"); + metadata.createMaterializedView(testSession, materializedViewName, someMaterializedView(), false, false); + + assertTrinoExceptionThrownBy(() -> getFutureValue(executeRenameTable(asQualifiedName(tableName), asQualifiedName(materializedViewName), false))) + .hasErrorCode(GENERIC_USER_ERROR) + .hasMessage("Target table '%s' does not exist, but a materialized view with that name exists.", materializedViewName); + } + private ListenableFuture executeRenameTable(QualifiedName source, QualifiedName target, boolean exists) { return new RenameTableTask(metadata, new AllowAllAccessControl()) diff --git a/core/trino-main/src/test/java/io/trino/execution/TestRenameViewTask.java b/core/trino-main/src/test/java/io/trino/execution/TestRenameViewTask.java index ccc929e59dd0..e38091983583 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestRenameViewTask.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestRenameViewTask.java @@ -23,6 +23,8 @@ import org.testng.annotations.Test; import static io.airlift.concurrent.MoreFutures.getFutureValue; +import static io.trino.spi.StandardErrorCode.GENERIC_USER_ERROR; +import static io.trino.spi.StandardErrorCode.TABLE_ALREADY_EXISTS; import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; import static io.trino.testing.assertions.TrinoExceptionAssert.assertTrinoExceptionThrownBy; import static org.assertj.core.api.Assertions.assertThat; @@ -75,6 +77,43 @@ public void testRenameViewOnMaterializedView() .hasMessage("View '%s' does not exist, but a materialized view with that name exists. Did you mean ALTER MATERIALIZED VIEW catalog.schema.existing_materialized_view RENAME TO ...?", viewName); } + @Test + public void testRenameViewTargetTableExists() + { + QualifiedName viewName = qualifiedName("existing_view"); + metadata.createView(testSession, QualifiedObjectName.valueOf(viewName.toString()), someView(), false); + QualifiedObjectName tableName = qualifiedObjectName("existing_table"); + metadata.createTable(testSession, CATALOG_NAME, someTable(tableName), false); + + assertTrinoExceptionThrownBy(() -> getFutureValue(executeRenameView(viewName, asQualifiedName(tableName)))) + .hasErrorCode(TABLE_ALREADY_EXISTS) + .hasMessage("Target view '%s' does not exist, but a table with that name exists.", tableName); + } + + @Test + public void testRenameViewTargetMaterializedViewExists() + { + QualifiedName viewName = qualifiedName("existing_view"); + metadata.createView(testSession, QualifiedObjectName.valueOf(viewName.toString()), someView(), false); + QualifiedObjectName materializedViewName = qualifiedObjectName("existing_materialized_view"); + metadata.createMaterializedView(testSession, materializedViewName, someMaterializedView(), false, false); + + assertTrinoExceptionThrownBy(() -> getFutureValue(executeRenameView(viewName, asQualifiedName(materializedViewName)))) + .hasErrorCode(GENERIC_USER_ERROR) + .hasMessage("Target view '%s' does not exist, but a materialized view with that name exists.", materializedViewName); + } + + @Test + public void testRenameViewTargetViewExists() + { + QualifiedName viewName = qualifiedName("existing_view"); + metadata.createView(testSession, QualifiedObjectName.valueOf(viewName.toString()), someView(), false); + + assertTrinoExceptionThrownBy(() -> getFutureValue(executeRenameView(viewName, viewName))) + .hasErrorCode(GENERIC_USER_ERROR) + .hasMessage("Target view '%s' already exists", viewName); + } + private ListenableFuture executeRenameView(QualifiedName source, QualifiedName target) { return new RenameViewTask(metadata, new AllowAllAccessControl())