diff --git a/core/trino-main/src/main/java/io/trino/execution/CommentTask.java b/core/trino-main/src/main/java/io/trino/execution/CommentTask.java index 1b8dfde93ae3..663149382cb2 100644 --- a/core/trino-main/src/main/java/io/trino/execution/CommentTask.java +++ b/core/trino-main/src/main/java/io/trino/execution/CommentTask.java @@ -15,12 +15,15 @@ import com.google.common.util.concurrent.ListenableFuture; import io.trino.Session; +import io.trino.connector.CatalogName; import io.trino.execution.warnings.WarningCollector; import io.trino.metadata.Metadata; +import io.trino.metadata.MetadataUtil; import io.trino.metadata.QualifiedObjectName; import io.trino.metadata.RedirectionAwareTableHandle; import io.trino.metadata.TableHandle; import io.trino.security.AccessControl; +import io.trino.spi.TrinoException; import io.trino.spi.connector.ColumnHandle; import io.trino.sql.tree.Comment; import io.trino.sql.tree.Expression; @@ -38,6 +41,7 @@ import static io.trino.spi.StandardErrorCode.MISSING_TABLE; import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; +import static io.trino.spi.connector.ConnectorCapabilities.COMMENT_ON_TABLE; import static io.trino.sql.analyzer.SemanticExceptions.semanticException; import static java.util.Objects.requireNonNull; @@ -76,6 +80,11 @@ public ListenableFuture execute( throw semanticException(TABLE_NOT_FOUND, statement, "Table does not exist: %s", originalTableName); } + CatalogName catalogName = MetadataUtil.getRequiredCatalogHandle(metadata, session, statement, originalTableName.getCatalogName()); + if (statement.getComment().isPresent() && !metadata.getConnectorCapabilities(session, catalogName).contains(COMMENT_ON_TABLE)) { + throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting table comments"); + } + accessControl.checkCanSetTableComment(session.toSecurityContext(), redirectionAwareTableHandle.getRedirectedTableName().orElse(originalTableName)); TableHandle tableHandle = redirectionAwareTableHandle.getTableHandle().get(); metadata.setTableComment(session, tableHandle, statement.getComment()); diff --git a/core/trino-main/src/main/java/io/trino/execution/CreateTableTask.java b/core/trino-main/src/main/java/io/trino/execution/CreateTableTask.java index 955b1cff695c..1f145889fe8d 100644 --- a/core/trino-main/src/main/java/io/trino/execution/CreateTableTask.java +++ b/core/trino-main/src/main/java/io/trino/execution/CreateTableTask.java @@ -71,6 +71,7 @@ import static io.trino.spi.StandardErrorCode.TABLE_ALREADY_EXISTS; import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; import static io.trino.spi.StandardErrorCode.TYPE_NOT_FOUND; +import static io.trino.spi.connector.ConnectorCapabilities.COMMENT_ON_TABLE; import static io.trino.spi.connector.ConnectorCapabilities.NOT_NULL_COLUMN_CONSTRAINT; import static io.trino.sql.ParameterUtils.parameterExtractor; import static io.trino.sql.analyzer.SemanticExceptions.semanticException; @@ -135,6 +136,10 @@ ListenableFuture internalExecute(CreateTable statement, Session session, L CatalogName catalogName = getRequiredCatalogHandle(plannerContext.getMetadata(), session, statement, tableName.getCatalogName()); + if (statement.getComment().isPresent() && !plannerContext.getMetadata().getConnectorCapabilities(session, catalogName).contains(COMMENT_ON_TABLE)) { + throw new TrinoException(NOT_SUPPORTED, "This connector does not support setting table comments"); + } + LinkedHashMap columns = new LinkedHashMap<>(); Map inheritedProperties = ImmutableMap.of(); boolean includingProperties = false; diff --git a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorCapabilities.java b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorCapabilities.java index b45d48ccd89d..9802a37e0721 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorCapabilities.java +++ b/core/trino-spi/src/main/java/io/trino/spi/connector/ConnectorCapabilities.java @@ -16,4 +16,5 @@ public enum ConnectorCapabilities { NOT_NULL_COLUMN_CONSTRAINT, + COMMENT_ON_TABLE, } diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveConnector.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveConnector.java index d44cd4140132..d27b0ca2e571 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveConnector.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/HiveConnector.java @@ -20,6 +20,7 @@ import io.trino.plugin.base.session.SessionPropertiesProvider; import io.trino.spi.connector.Connector; import io.trino.spi.connector.ConnectorAccessControl; +import io.trino.spi.connector.ConnectorCapabilities; import io.trino.spi.connector.ConnectorMetadata; import io.trino.spi.connector.ConnectorNodePartitioningProvider; import io.trino.spi.connector.ConnectorPageSinkProvider; @@ -39,6 +40,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.Sets.immutableEnumSet; +import static io.trino.spi.connector.ConnectorCapabilities.COMMENT_ON_TABLE; import static io.trino.spi.transaction.IsolationLevel.READ_UNCOMMITTED; import static io.trino.spi.transaction.IsolationLevel.checkConnectorSupports; import static java.util.Objects.requireNonNull; @@ -219,6 +222,12 @@ public final void shutdown() lifeCycleManager.stop(); } + @Override + public Set getCapabilities() + { + return immutableEnumSet(COMMENT_ON_TABLE); + } + @Override public Set getTableProcedures() { diff --git a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergConnector.java b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergConnector.java index 8b8a9e069a4c..d2d1bc9074d1 100644 --- a/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergConnector.java +++ b/plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergConnector.java @@ -40,6 +40,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Sets.immutableEnumSet; +import static io.trino.spi.connector.ConnectorCapabilities.COMMENT_ON_TABLE; import static io.trino.spi.connector.ConnectorCapabilities.NOT_NULL_COLUMN_CONSTRAINT; import static io.trino.spi.transaction.IsolationLevel.SERIALIZABLE; import static io.trino.spi.transaction.IsolationLevel.checkConnectorSupports; @@ -94,7 +95,7 @@ public IcebergConnector( @Override public Set getCapabilities() { - return immutableEnumSet(NOT_NULL_COLUMN_CONSTRAINT); + return immutableEnumSet(NOT_NULL_COLUMN_CONSTRAINT, COMMENT_ON_TABLE); } @Override diff --git a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java index d19911c49f6f..b83b43000e05 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java @@ -2001,6 +2001,23 @@ public void testRenameTable() assertFalse(getQueryRunner().tableExists(getSession(), renamedTable)); } + @Test + public void testCreateTableWithComment() + { + String tableName = "test_create_" + randomTableSuffix(); + String createTable = "CREATE TABLE " + tableName + " (a bigint) COMMENT 'foo'"; + + if (!hasBehavior(SUPPORTS_COMMENT_ON_TABLE)) { + assertThatThrownBy(() -> + assertUpdate(createTable)) + .hasMessage("This connector does not support setting table comments"); + } + else { + assertUpdate(createTable); + assertThat(getTableComment(tableName)).isEqualTo("foo"); + } + } + @Test public void testCommentTable() {