yifan-c commented on code in PR #4411:
URL: https://github.com/apache/cassandra/pull/4411#discussion_r2463049669


##########
doc/modules/cassandra/pages/developing/cql/ddl.adoc:
##########
@@ -801,3 +801,195 @@ statements.
 However, tables are the only object that can be truncated currently, and the 
`TABLE` keyword can be omitted.
 
 Truncating a table permanently removes all existing data from the table, but 
without removing the table itself.
+
+[[comment-statement]]
+== COMMENT ON
+
+The `COMMENT ON` statement allows you to add descriptive comments to schema 
elements for documentation purposes.
+Comments are stored in the schema metadata and displayed when using `DESCRIBE` 
statements.
+
+=== COMMENT ON KEYSPACE
+
+Add or modify a comment on a keyspace:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE keyspace_name IS 'comment text';
+COMMENT ON KEYSPACE keyspace_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE cycling IS 'Keyspace for cycling application data';
+----
+
+=== COMMENT ON TABLE
+
+Add or modify a comment on a table:
+
+[source,cql]
+----
+COMMENT ON TABLE [keyspace_name.]table_name IS 'comment text';
+COMMENT ON TABLE [keyspace_name.]table_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TABLE cycling.cyclist_name IS 'Table storing cyclist names and 
basic information';
+----
+
+=== COMMENT ON COLUMN
+
+Add or modify a comment on a column:
+
+[source,cql]
+----
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS 'comment text';
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON COLUMN cycling.cyclist_name.id IS 'Unique identifier for each 
cyclist';
+----
+
+=== COMMENT ON TYPE
+
+Add or modify a comment on a user-defined type:
+
+[source,cql]
+----
+COMMENT ON TYPE [keyspace_name.]type_name IS 'comment text';
+COMMENT ON TYPE [keyspace_name.]type_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TYPE cycling.address IS 'User-defined type for storing address 
information';
+----
+
+=== COMMENT ON FIELD
+
+Add or modify a comment on a field within a user-defined type:
+
+[source,cql]
+----
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS 'comment text';
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+include::cassandra:example$CQL/comment_on_field.cql[]

Review Comment:
   I have two comments:
   
   1. Some examples include inline CQL statements, while others link to 
external files. Since those external files only contain a single line of CQL, 
is it necessary to reference them externally?
   
   2. The `[keyspace_name.]` notation might be confusing. I assume the intent 
is to indicate that `keyspace_name` can be omitted when a `USE` statement has 
been issued earlier. However, it might not be necessary to mention that 
scenario here. It’s probably clearer to focus on demonstrating the full syntax 
of the new CQL.



##########
doc/modules/cassandra/pages/developing/cql/ddl.adoc:
##########
@@ -801,3 +801,195 @@ statements.
 However, tables are the only object that can be truncated currently, and the 
`TABLE` keyword can be omitted.
 
 Truncating a table permanently removes all existing data from the table, but 
without removing the table itself.
+
+[[comment-statement]]
+== COMMENT ON
+
+The `COMMENT ON` statement allows you to add descriptive comments to schema 
elements for documentation purposes.
+Comments are stored in the schema metadata and displayed when using `DESCRIBE` 
statements.
+
+=== COMMENT ON KEYSPACE
+
+Add or modify a comment on a keyspace:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE keyspace_name IS 'comment text';
+COMMENT ON KEYSPACE keyspace_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE cycling IS 'Keyspace for cycling application data';
+----
+
+=== COMMENT ON TABLE
+
+Add or modify a comment on a table:
+
+[source,cql]
+----
+COMMENT ON TABLE [keyspace_name.]table_name IS 'comment text';
+COMMENT ON TABLE [keyspace_name.]table_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TABLE cycling.cyclist_name IS 'Table storing cyclist names and 
basic information';
+----
+
+=== COMMENT ON COLUMN
+
+Add or modify a comment on a column:
+
+[source,cql]
+----
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS 'comment text';
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON COLUMN cycling.cyclist_name.id IS 'Unique identifier for each 
cyclist';
+----
+
+=== COMMENT ON TYPE
+
+Add or modify a comment on a user-defined type:
+
+[source,cql]
+----
+COMMENT ON TYPE [keyspace_name.]type_name IS 'comment text';
+COMMENT ON TYPE [keyspace_name.]type_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TYPE cycling.address IS 'User-defined type for storing address 
information';
+----
+
+=== COMMENT ON FIELD
+
+Add or modify a comment on a field within a user-defined type:
+
+[source,cql]
+----
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS 'comment text';
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+include::cassandra:example$CQL/comment_on_field.cql[]
+----
+
+NOTE: Comments can be removed by setting them to `NULL`. Comments are 
displayed when using `DESCRIBE` statements
+and are useful for documenting the purpose and structure of your schema 
elements.
+
+[[security-label-statement]]
+== SECURITY LABEL ON

Review Comment:
   Should this be `SECURITY LABEL`? I thought the correct term was “security 
label statement.” Similarly, I believe it’s “comment statement,” not “comment 
on statement.”



##########
src/java/org/apache/cassandra/cql3/statements/schema/CommentOnTableStatement.java:
##########
@@ -0,0 +1,140 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.schema.TableParams;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+/**
+ * Handles the execution of COMMENT ON TABLE CQL statements.
+ * <p>
+ * This statement allows users to add descriptive comments to tables for 
documentation purposes.
+ * Comments are stored in the table metadata and displayed when using DESCRIBE 
TABLE.
+ * </p>
+ * <p>
+ * Syntax: {@code COMMENT ON TABLE [keyspace_name.]table_name IS 'comment 
text';}
+ * </p>
+ * <p>
+ * Comments can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see CommentOnKeyspaceStatement
+ * @see CommentOnColumnStatement
+ * @see CommentOnTypeStatement
+ */
+public final class CommentOnTableStatement extends AlterSchemaStatement
+{
+    private final String tableName;
+    private final String comment;
+
+    public CommentOnTableStatement(String keyspaceName, String tableName, 
String comment)
+    {
+        super(keyspaceName);
+        this.tableName = tableName;
+        this.comment = comment;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateComment(comment);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        TableMetadata table = keyspace.getTableOrViewNullable(tableName);
+        if (null == table)
+            throw ire("Table '%s.%s' doesn't exist", keyspaceName, tableName);
+
+        if (table.isView())
+            throw ire("Cannot set comment on materialized view '%s.%s'. 
Comments should be set on the base table.", keyspaceName, tableName);
+

Review Comment:
   To @smiklosovic 's point, I think you only want to allow comment on regular 
table, i.e. reject if `table.kind != TableMetadata.Kind.REGULAR`



##########
src/java/org/apache/cassandra/cql3/statements/schema/CopyTableStatement.java:
##########
@@ -305,17 +335,19 @@ public CQLStatement prepare(ClientState state)
         {
             String oldKeyspace = oldName.hasKeyspace() ? oldName.getKeyspace() 
: state.getKeyspace();
             String newKeyspace = newName.hasKeyspace() ? newName.getKeyspace() 
: state.getKeyspace();
-            return new CopyTableStatement(oldKeyspace, newKeyspace, 
oldName.getName(), newName.getName(), ifNotExists, createLikeOption, attrs);
+            return new CopyTableStatement(oldKeyspace, newKeyspace, 
oldName.getName(), newName.getName(), ifNotExists, createLikeOptions, attrs);
         }
 
-        public void withLikeOption(CreateLikeOption option)
+        public void addLikeOption(CreateLikeOption option)
         {
-            this.createLikeOption = option;
+            this.createLikeOptions.add(option);
         }
     }
 
     public enum CreateLikeOption
     {
-        INDEXES;
+        INDEXES,
+        COMMENTS,
+        SECURITY_LABELS;

Review Comment:
   Not a fan of the if-else logic in the `maybeCopyComments` method and others. 
I would like to suggest a refactoring that follows OOP. The callsites would be 
simplified. 
   
   ```java
       interface CreateLikeHandler
       {
           // TODO: add javadoc please
           void copy(TableMetadata.Builder tagetTableBuilder, String 
targetKeyspace, String targetTableName, TableMetadata sourceTableMeta);
       }
       public enum CreateLikeOption implements CreateLikeHandler
       {
           INDEXES
           {
               @Override
               public void copy(TableMetadata.Builder tagetTableBuilder, String 
targetKeyspace, String targetTableName, TableMetadata sourceTableMeta)
               {
                   String sourceTableName = sourceTableMeta.name;
                   String sourceKeyspace = sourceTableMeta.keyspace;
                   KeyspaceMetadata targetKeyspaceMeta = 
Schema.instance.getKeyspaceMetadata(targetKeyspace);
                   Set<String> customIndexes = Sets.newTreeSet();
                   List<IndexMetadata> indexesToCopy = new ArrayList<>();
                   for (IndexMetadata indexMetadata : sourceTableMeta.indexes)
                   {
                       // only sai and legacy secondary index is supported
                       if (indexMetadata.isCustom() && 
!StorageAttachedIndex.class.getCanonicalName().equals(indexMetadata.getIndexClassName()))
                       {
                           customIndexes.add(indexMetadata.name);
                           continue;
                       }
   
                       ColumnMetadata targetColumn = 
sourceTableMeta.getColumn(UTF8Type.instance.decompose(indexMetadata.options.get("target")));
                       String indexName;
                       // The rules for generating the index names of the 
target table are:
                       // (1) If the source table's index names follow the 
pattern sourcetablename_columnname_idx_number, the index names are considered 
to be generated by the system,
                       //     then we directly replace the name of source table 
with the name of target table, and increment the number after idx to avoid 
index name conflicts.
                       // (2) Index names that do not follow the above pattern 
are considered user-defined, so the index names are retained and increment the 
number after idx to avoid conflicts.
                       if (indexMetadata.name.startsWith(sourceTableName + "_" 
+ targetColumn.name + "_idx"))
                       {
                           String baseName = 
IndexMetadata.generateDefaultIndexName(targetTableName, targetColumn.name);
                           indexName = 
targetKeyspaceMeta.findAvailableIndexName(baseName, indexesToCopy, 
targetKeyspaceMeta);
                       }
                       else
                       {
                           indexName = 
targetKeyspaceMeta.findAvailableIndexName(indexMetadata.name, indexesToCopy, 
targetKeyspaceMeta);
                       }
                       
indexesToCopy.add(IndexMetadata.fromSchemaMetadata(indexName, 
indexMetadata.kind, indexMetadata.options));
                   }
   
                   if (!indexesToCopy.isEmpty())
                       
tagetTableBuilder.indexes(Indexes.builder().add(indexesToCopy).build());
   
                   if (!customIndexes.isEmpty())
                       ClientWarn.instance.warn(String.format("Source table 
%s.%s to copy indexes from to %s.%s has custom indexes. These indexes were not 
copied: %s",
                                                              sourceKeyspace,
                                                              sourceTableName,
                                                              targetKeyspace,
                                                              targetTableName,
                                                              customIndexes));
               }
           },
           COMMENTS
           {
               @Override
               public void copy(TableMetadata.Builder tagetTableBuilder, String 
targetKeyspace, String targetTableName, TableMetadata sourceTableMeta)
               {
                   if (!StringUtils.isEmpty(sourceTableMeta.params.comment))
                       
tagetTableBuilder.comment(sourceTableMeta.params.comment);
   
                   for (ColumnMetadata columnMetadata : 
sourceTableMeta.columns())
                       
tagetTableBuilder.alterColumnComment(columnMetadata.name, 
columnMetadata.comment);
               }
           },
           SECURITY_LABELS
           {
               @Override
               public void copy(TableMetadata.Builder tagetTableBuilder, String 
targetKeyspace, String targetTableName, TableMetadata sourceTableMeta)
               {
                   if 
(!StringUtils.isEmpty(sourceTableMeta.params.securityLabel))
                       
tagetTableBuilder.securityLabel(sourceTableMeta.params.securityLabel);
   
                   for (ColumnMetadata columnMetadata : 
sourceTableMeta.columns())
                       
tagetTableBuilder.alterColumnSecurityLabel(columnMetadata.name, 
columnMetadata.securityLabel);
               }
           }
       }
   ```



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnTableStatement.java:
##########
@@ -0,0 +1,150 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.schema.TableParams;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+/**
+ * Handles the execution of SECURITY LABEL ON TABLE CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to tables.
+ * Security labels are stored in the table metadata and displayed when using 
DESCRIBE TABLE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON TABLE [keyspace_name.]table_name IS 
'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnKeyspaceStatement
+ * @see SecurityLabelOnColumnStatement
+ * @see SecurityLabelOnTypeStatement
+ */
+public final class SecurityLabelOnTableStatement extends AlterSchemaStatement
+{
+    private final String tableName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnTableStatement(String keyspaceName, String 
tableName, String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.tableName = tableName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        TableMetadata table = keyspace.getTableOrViewNullable(tableName);
+        if (null == table)
+            throw ire("Table '%s.%s' doesn't exist", keyspaceName, tableName);
+
+        if (table.isView())
+            throw ire("Cannot set security label on materialized view '%s.%s'. 
Security labels should be set on the base table.", keyspaceName, tableName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");
+
+        TableParams newParams = 
table.params.unbuild().securityLabel(securityLabel).build();
+        TableMetadata newTable = table.withSwapped(newParams);
+        KeyspaceMetadata newKeyspace = 
keyspace.withSwapped(keyspace.tables.withSwapped(newTable));
+
+        return schema.withAddedOrUpdated(newKeyspace);
+    }
+
+    @Override
+    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
+    {
+        return new SchemaChange(Change.UPDATED, Target.TABLE, keyspaceName, 
tableName);
+    }
+
+    @Override
+    public void authorize(ClientState client)
+    {
+        client.ensureTablePermission(keyspaceName, tableName, 
Permission.ALTER);
+    }
+
+    @Override
+    public AuditLogContext getAuditLogContext()
+    {
+        return new AuditLogContext(AuditLogEntryType.SECURITY_LABEL_TABLE, 
keyspaceName, tableName);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s (%s.%s, %s)", getClass().getSimpleName(), 
keyspaceName, tableName, securityLabel);
+    }
+
+    public static final class Raw extends CQLStatement.Raw
+    {
+        private final QualifiedName tableName;
+        private final String securityLabel;
+        private final String provider;
+
+        public Raw(QualifiedName tableName, String securityLabel, String 
provider)
+        {
+            this.tableName = tableName;
+            this.securityLabel = securityLabel;
+            this.provider = provider;
+        }
+
+        @Override
+        public SecurityLabelOnTableStatement prepare(ClientState state)
+        {
+            String keyspaceName = tableName.hasKeyspace() ? 
tableName.getKeyspace() : state.getKeyspace();
+            return new SecurityLabelOnTableStatement(keyspaceName,
+                                                   tableName.getName(),
+                                                   securityLabel,
+                                                   provider);

Review Comment:
   not aligned; please check the other files. I am not going to making more 
comments about alignment :p



##########
src/java/org/apache/cassandra/cql3/statements/SchemaDescriptionsUtil.java:
##########
@@ -0,0 +1,292 @@
+/*
+ * 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.cassandra.cql3.statements;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+
+/**
+ * Utility class for appending COMMENT and SECURITY LABEL statements to schema 
element descriptions.
+ * <p>
+ * This class provides methods to append CQL statements for comments and 
security labels on various
+ * schema elements (keyspaces, tables, columns, and types) to their CREATE 
statement output.
+ * These are typically used by DESCRIBE statements to show the complete schema 
definition including
+ * any associated metadata.
+ * </p>
+ */
+public class SchemaDescriptionsUtil
+{
+    private static final String COMMENT_DESCRIPTION_TYPE = "COMMENT";
+    private static final String SECURITY_LABEL_DESCRIPTION_TYPE = "SECURITY 
LABEL";
+    private static final String KEYSPACE_SCHEMA_ELEMENT = "KEYSPACE";
+    private static final String TABLE_SCHEMA_ELEMENT = "TABLE";
+    private static final String COLUMN_SCHEMA_ELEMENT = "COLUMN";
+    private static final String TYPE_SCHEMA_ELEMENT = "TYPE";
+    private static final String FIELD_SCHEMA_ELEMENT = "FIELD";
+
+    /**
+     * Maximum length for comments and security labels.
+     * This limit helps prevent excessive memory usage and storage overhead.
+     */
+    public static final int MAX_METADATA_LENGTH = 1024;

Review Comment:
   1024 is a lot for free-text. I think a label or comment length limit should 
be similar to Keyspace name, which is 48, see 
`org.apache.cassandra.schema.SchemaConstants#NAME_LENGTH`. 
   If you are concerned with it being too short, maybe make it configurable and 
change the default to 48? 
   
   Besides the length, the name `MAX_METADATA_LENGTH` is too general.. All the 
schema things are "metadata". Please rename. 



##########
src/java/org/apache/cassandra/cql3/statements/SchemaDescriptionsUtil.java:
##########
@@ -0,0 +1,292 @@
+/*
+ * 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.cassandra.cql3.statements;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+
+/**
+ * Utility class for appending COMMENT and SECURITY LABEL statements to schema 
element descriptions.
+ * <p>
+ * This class provides methods to append CQL statements for comments and 
security labels on various
+ * schema elements (keyspaces, tables, columns, and types) to their CREATE 
statement output.
+ * These are typically used by DESCRIBE statements to show the complete schema 
definition including
+ * any associated metadata.
+ * </p>
+ */
+public class SchemaDescriptionsUtil
+{
+    private static final String COMMENT_DESCRIPTION_TYPE = "COMMENT";
+    private static final String SECURITY_LABEL_DESCRIPTION_TYPE = "SECURITY 
LABEL";
+    private static final String KEYSPACE_SCHEMA_ELEMENT = "KEYSPACE";
+    private static final String TABLE_SCHEMA_ELEMENT = "TABLE";
+    private static final String COLUMN_SCHEMA_ELEMENT = "COLUMN";
+    private static final String TYPE_SCHEMA_ELEMENT = "TYPE";
+    private static final String FIELD_SCHEMA_ELEMENT = "FIELD";
+
+    /**
+     * Maximum length for comments and security labels.
+     * This limit helps prevent excessive memory usage and storage overhead.
+     */
+    public static final int MAX_METADATA_LENGTH = 1024;
+
+    private SchemaDescriptionsUtil()
+    {
+    }
+
+    /**
+     * Validates that a comment does not exceed the maximum allowed length.
+     *
+     * @param comment the comment to validate (can be null)
+     * @throws InvalidRequestException if the comment exceeds the maximum 
length
+     */
+    public static void validateComment(String comment)
+    {
+        if (comment != null && comment.length() > MAX_METADATA_LENGTH)
+        {
+            String msg = String.format("Comment length (%d) exceeds maximum 
allowed length (%d)",
+                                       comment.length(),
+                                       MAX_METADATA_LENGTH);
+            throw new InvalidRequestException(msg);
+        }
+    }
+
+    /**
+     * Validates that a security label does not exceed the maximum allowed 
length.
+     *
+     * @param securityLabel the security label to validate (can be null)
+     * @throws InvalidRequestException if the security label exceeds the 
maximum length
+     */
+    public static void validateSecurityLabel(String securityLabel)
+    {
+        if (securityLabel != null && securityLabel.length() > 
MAX_METADATA_LENGTH)
+        {
+            throw new InvalidRequestException(String.format("Security label 
length (%d) exceeds maximum allowed length (%d)",
+                                                           
securityLabel.length(),
+                                                           
MAX_METADATA_LENGTH));
+        }
+    }
+
+    /**
+     * Appends a COMMENT ON KEYSPACE statement to the builder if the keyspace 
has a comment.
+     *
+     * @param builder the StringBuilder to append to
+     * @param keyspaceMetadata the keyspace metadata containing the comment
+     */
+    public static void appendCommentOnKeyspace(StringBuilder builder, 
KeyspaceMetadata keyspaceMetadata)
+    {
+        addDescription(builder, COMMENT_DESCRIPTION_TYPE, 
KEYSPACE_SCHEMA_ELEMENT, keyspaceMetadata.name, 
keyspaceMetadata.params.comment);
+    }
+
+    /**
+     * Appends a SECURITY LABEL ON KEYSPACE statement to the builder if the 
keyspace has a security label.
+     *
+     * @param builder the StringBuilder to append to
+     * @param keyspaceMetadata the keyspace metadata containing the security 
label
+     */
+    public static void appendSecurityLabelOnKeyspace(StringBuilder builder, 
KeyspaceMetadata keyspaceMetadata)
+    {
+        addDescription(builder, SECURITY_LABEL_DESCRIPTION_TYPE, 
KEYSPACE_SCHEMA_ELEMENT, keyspaceMetadata.name, 
keyspaceMetadata.params.securityLabel);
+    }
+
+    /**
+     * Appends a COMMENT ON TABLE statement to the builder if the table has a 
comment.
+     *
+     * @param builder the StringBuilder to append to
+     * @param tableMetadata the table metadata containing the comment
+     */
+    public static void appendCommentOnTable(StringBuilder builder, 
TableMetadata tableMetadata)
+    {
+        String schemaElement = String.format("%s.%s", tableMetadata.keyspace, 
tableMetadata.name);
+        addDescription(builder, COMMENT_DESCRIPTION_TYPE, 
TABLE_SCHEMA_ELEMENT, schemaElement, tableMetadata.params.comment);
+    }
+
+    /**
+     * Appends SECURITY LABEL ON TABLE statement and COMMENT/SECURITY LABEL ON 
COLUMN statements
+     * to the builder if the table or any of its columns have security labels 
or comments.
+     *
+     * @param builder the StringBuilder to append to
+     * @param tableMetadata the table metadata containing the security label 
and columns
+     */
+    public static void appendSecurityLabelOnTable(StringBuilder builder, 
TableMetadata tableMetadata)
+    {
+        String schemaElement = String.format("%s.%s", tableMetadata.keyspace, 
tableMetadata.name);
+        addDescription(builder, SECURITY_LABEL_DESCRIPTION_TYPE, 
TABLE_SCHEMA_ELEMENT, schemaElement, tableMetadata.params.securityLabel);

Review Comment:
   From architecture's perspective, those should be interface methods in 
`SchemaElement` or a new interface that the relevant metadata classes 
implement, instead of having the utility methods per type. 
   Two interface methods are needed,
   ```
   void appendSecurityLabel(StringBuilder builder);
   void appendComment(StringBuilder builder);
   ```



##########
doc/modules/cassandra/pages/developing/cql/ddl.adoc:
##########
@@ -801,3 +801,195 @@ statements.
 However, tables are the only object that can be truncated currently, and the 
`TABLE` keyword can be omitted.
 
 Truncating a table permanently removes all existing data from the table, but 
without removing the table itself.
+
+[[comment-statement]]
+== COMMENT ON
+
+The `COMMENT ON` statement allows you to add descriptive comments to schema 
elements for documentation purposes.
+Comments are stored in the schema metadata and displayed when using `DESCRIBE` 
statements.
+
+=== COMMENT ON KEYSPACE
+
+Add or modify a comment on a keyspace:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE keyspace_name IS 'comment text';
+COMMENT ON KEYSPACE keyspace_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON KEYSPACE cycling IS 'Keyspace for cycling application data';
+----
+
+=== COMMENT ON TABLE
+
+Add or modify a comment on a table:
+
+[source,cql]
+----
+COMMENT ON TABLE [keyspace_name.]table_name IS 'comment text';
+COMMENT ON TABLE [keyspace_name.]table_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TABLE cycling.cyclist_name IS 'Table storing cyclist names and 
basic information';
+----
+
+=== COMMENT ON COLUMN
+
+Add or modify a comment on a column:
+
+[source,cql]
+----
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS 'comment text';
+COMMENT ON COLUMN [keyspace_name.]table_name.column_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON COLUMN cycling.cyclist_name.id IS 'Unique identifier for each 
cyclist';
+----
+
+=== COMMENT ON TYPE
+
+Add or modify a comment on a user-defined type:
+
+[source,cql]
+----
+COMMENT ON TYPE [keyspace_name.]type_name IS 'comment text';
+COMMENT ON TYPE [keyspace_name.]type_name IS NULL;  -- Remove comment
+----
+
+Example:
+
+[source,cql]
+----
+COMMENT ON TYPE cycling.address IS 'User-defined type for storing address 
information';
+----
+
+=== COMMENT ON FIELD
+
+Add or modify a comment on a field within a user-defined type:
+
+[source,cql]
+----
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS 'comment text';
+COMMENT ON FIELD [keyspace_name.]type_name.field_name IS NULL;  -- Remove 
comment
+----
+
+Example:
+
+[source,cql]
+----
+include::cassandra:example$CQL/comment_on_field.cql[]
+----
+
+NOTE: Comments can be removed by setting them to `NULL`. Comments are 
displayed when using `DESCRIBE` statements
+and are useful for documenting the purpose and structure of your schema 
elements.
+
+[[security-label-statement]]
+== SECURITY LABEL ON
+
+The `SECURITY LABEL ON` statement allows you to add security classification 
labels to schema elements.
+Security labels are stored in the schema metadata and displayed when using 
`DESCRIBE` statements.
+These labels can be used to mark data sensitivity levels or compliance 
requirements.
+
+=== SECURITY LABEL ON KEYSPACE
+
+Add or modify a security label on a keyspace:
+
+[source,cql]
+----
+SECURITY LABEL ON KEYSPACE keyspace_name IS 'label';
+SECURITY LABEL ON KEYSPACE keyspace_name IS NULL;  -- Remove label
+----
+
+Example:
+
+[source,cql]
+----
+SECURITY LABEL ON KEYSPACE cycling IS 'CONFIDENTIAL';
+----
+
+=== SECURITY LABEL ON TABLE
+
+Add or modify a security label on a table:
+
+[source,cql]
+----
+SECURITY LABEL ON TABLE [keyspace_name.]table_name IS 'label';
+SECURITY LABEL ON TABLE [keyspace_name.]table_name IS NULL;  -- Remove label
+----
+
+Example:
+
+[source,cql]
+----
+SECURITY LABEL ON TABLE cycling.cyclist_name IS 'PII';
+----
+
+=== SECURITY LABEL ON COLUMN
+
+Add or modify a security label on a column:
+
+[source,cql]
+----
+SECURITY LABEL ON COLUMN [keyspace_name.]table_name.column_name IS 'label';
+SECURITY LABEL ON COLUMN [keyspace_name.]table_name.column_name IS NULL;  -- 
Remove label
+----
+
+Example:
+
+[source,cql]
+----
+SECURITY LABEL ON COLUMN cycling.cyclist_name.email IS 'PII-EMAIL';
+----
+
+=== SECURITY LABEL ON TYPE
+
+Add or modify a security label on a user-defined type:
+
+[source,cql]
+----
+SECURITY LABEL ON TYPE [keyspace_name.]type_name IS 'label';
+SECURITY LABEL ON TYPE [keyspace_name.]type_name IS NULL;  -- Remove label
+----
+
+Example:
+
+[source,cql]
+----
+SECURITY LABEL ON TYPE cycling.address IS 'SENSITIVE';
+----
+
+=== SECURITY LABEL ON FIELD
+
+Add or modify a security label on a field within a user-defined type:
+
+[source,cql]
+----
+SECURITY LABEL ON FIELD [keyspace_name.]type_name.field_name IS 'label';
+SECURITY LABEL ON FIELD [keyspace_name.]type_name.field_name IS NULL;  -- 
Remove label
+----
+
+Example:
+
+[source,cql]
+----
+include::cassandra:example$CQL/security_label_on_field.cql[]
+----
+
+NOTE: Security labels can be removed by setting them to `NULL`. Security 
labels are displayed when using `DESCRIBE` statements
+and can be used in conjunction with custom authorization plugins or audit 
systems to enforce data access policies.
+
+IMPORTANT: `COMMENT ON` and `SECURITY LABEL ON` statements require schema 
version V8 or higher.

Review Comment:
   The `schema version V8` information is database-internal and not exposed to 
application developers or database users. Including it in a customer-facing 
document may lead to unnecessary confusion.
   You can probably mention the Cassandra version. But I guess it is 
unnecessary still. It is a new feature in Cassandra 6.0.



##########
pylib/cqlshlib/test/test_cqlsh_completion.py:
##########
@@ -238,7 +238,7 @@ def test_complete_in_insert(self):
         self.trycompletions('INSERT INTO twenty_rows_composite_table',
                             immediate=' ')
         self.trycompletions('INSERT INTO twenty_rows_composite_table ',
-                            choices=['(', 'JSON'])
+                            choices=['(', 'JSON', 'COMMENT', 'SECURITY'])

Review Comment:
   It is surprising to see `comment` and `security` in the insert statements.



##########
src/java/org/apache/cassandra/cql3/statements/schema/CommentOnFieldStatement.java:
##########
@@ -0,0 +1,145 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.FieldIdentifier;
+import org.apache.cassandra.cql3.UTName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+/**
+ * Handles the execution of COMMENT ON FIELD CQL statements.
+ * <p>
+ * This statement allows users to add descriptive comments to individual 
fields of user-defined types
+ * for documentation purposes. Comments are stored in the type metadata and 
displayed when using DESCRIBE TYPE.
+ * </p>
+ * <p>
+ * Syntax: {@code COMMENT ON FIELD [keyspace_name.]type_name.field_name IS 
'comment text';}
+ * </p>
+ * <p>
+ * Comments can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see CommentOnTypeStatement
+ * @see CommentOnColumnStatement
+ */
+public final class CommentOnFieldStatement extends AlterSchemaStatement

Review Comment:
   nit: `CommentOnUserTypeFieldStatement`. 
   Reason: field is not a term specific to user type, so better clarify in the 
name. 👍  on the excellent documentation. 



##########
src/java/org/apache/cassandra/cql3/statements/schema/CopyTableStatement.java:
##########
@@ -83,7 +86,8 @@ public CopyTableStatement(String sourceKeyspace,
         this.sourceTableName = sourceTableName;
         this.targetTableName = targetTableName;
         this.ifNotExists = ifNotExists;
-        this.createLikeOption = createLikeOption;
+        this.createLikeOptions = createLikeOptions != null ?
+            EnumSet.copyOf(createLikeOptions) : 
EnumSet.noneOf(CreateLikeOption.class);

Review Comment:
   nit: codestyle for ternary operator
   ```suggestion
           this.createLikeOptions = createLikeOptions != null
                                    ? EnumSet.copyOf(createLikeOptions)
                                    : EnumSet.noneOf(CreateLikeOption.class);
   ```



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnColumnStatement.java:
##########
@@ -0,0 +1,159 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+/**
+ * Handles the execution of SECURITY LABEL ON COLUMN CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
individual columns.
+ * Security labels are stored in the column metadata and displayed when using 
DESCRIBE TABLE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON COLUMN 
[keyspace_name.]table_name.column_name IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnKeyspaceStatement
+ * @see SecurityLabelOnTableStatement
+ * @see SecurityLabelOnTypeStatement
+ */
+public final class SecurityLabelOnColumnStatement extends AlterSchemaStatement
+{
+    private final String tableName;
+    private final ColumnIdentifier columnName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnColumnStatement(String keyspaceName, String 
tableName, ColumnIdentifier columnName, String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.tableName = tableName;
+        this.columnName = columnName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        TableMetadata table = keyspace.getTableOrViewNullable(tableName);
+        if (null == table)
+            throw ire("Table '%s.%s' doesn't exist", keyspaceName, tableName);
+
+        if (table.isView())
+            throw ire("Cannot set security label on column in materialized 
view '%s.%s'. Security labels should be set on the base table.", keyspaceName, 
tableName);
+
+        ColumnMetadata column = table.getColumn(columnName);
+        if (null == column)
+            throw ire("Column '%s' doesn't exist in table '%s.%s'", 
columnName, keyspaceName, tableName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");

Review Comment:
   The warning reads confusing. Can you clarify that no provider will be loaded 
into the process and will not be invoked for the security label? 



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnFieldStatement.java:
##########
@@ -0,0 +1,155 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.FieldIdentifier;
+import org.apache.cassandra.cql3.UTName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+/**
+ * Handles the execution of SECURITY LABEL ON FIELD CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
individual fields of user-defined types.
+ * Security labels are stored in the type metadata and displayed when using 
DESCRIBE TYPE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON FIELD [keyspace_name.]type_name.field_name 
IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnTypeStatement
+ * @see SecurityLabelOnColumnStatement
+ */
+public final class SecurityLabelOnFieldStatement extends AlterSchemaStatement
+{
+    private final String typeName;
+    private final FieldIdentifier fieldName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnFieldStatement(String keyspaceName, String typeName, 
FieldIdentifier fieldName, String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.typeName = typeName;
+        this.fieldName = fieldName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        UserType type = keyspace.types.getNullable(bytes(typeName));
+        if (null == type)
+            throw ire("Type '%s.%s' doesn't exist", keyspaceName, typeName);
+
+        if (type.fieldPosition(fieldName) == -1)
+            throw ire("Field '%s' doesn't exist in type '%s.%s'", fieldName, 
keyspaceName, typeName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");

Review Comment:
   The code is duplicating. Could you have a base class for security labels to 
provides the common utilities? 
   Similarly, please check for code duplication in comment statements. 



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnColumnStatement.java:
##########
@@ -0,0 +1,159 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+/**
+ * Handles the execution of SECURITY LABEL ON COLUMN CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
individual columns.
+ * Security labels are stored in the column metadata and displayed when using 
DESCRIBE TABLE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON COLUMN 
[keyspace_name.]table_name.column_name IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnKeyspaceStatement
+ * @see SecurityLabelOnTableStatement
+ * @see SecurityLabelOnTypeStatement
+ */
+public final class SecurityLabelOnColumnStatement extends AlterSchemaStatement
+{
+    private final String tableName;
+    private final ColumnIdentifier columnName;
+    private final String securityLabel;
+    private final String provider;

Review Comment:
   Can you add a comment regarding `provider`? It is not functional, not 
implemented. 



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnColumnStatement.java:
##########
@@ -0,0 +1,159 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QualifiedName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+/**
+ * Handles the execution of SECURITY LABEL ON COLUMN CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
individual columns.
+ * Security labels are stored in the column metadata and displayed when using 
DESCRIBE TABLE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON COLUMN 
[keyspace_name.]table_name.column_name IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnKeyspaceStatement
+ * @see SecurityLabelOnTableStatement
+ * @see SecurityLabelOnTypeStatement
+ */
+public final class SecurityLabelOnColumnStatement extends AlterSchemaStatement
+{
+    private final String tableName;
+    private final ColumnIdentifier columnName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnColumnStatement(String keyspaceName, String 
tableName, ColumnIdentifier columnName, String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.tableName = tableName;
+        this.columnName = columnName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        TableMetadata table = keyspace.getTableOrViewNullable(tableName);
+        if (null == table)
+            throw ire("Table '%s.%s' doesn't exist", keyspaceName, tableName);
+
+        if (table.isView())
+            throw ire("Cannot set security label on column in materialized 
view '%s.%s'. Security labels should be set on the base table.", keyspaceName, 
tableName);
+
+        ColumnMetadata column = table.getColumn(columnName);
+        if (null == column)
+            throw ire("Column '%s' doesn't exist in table '%s.%s'", 
columnName, keyspaceName, tableName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");
+
+        TableMetadata newTable = 
table.unbuild().alterColumnSecurityLabel(columnName, securityLabel).build();
+        KeyspaceMetadata newKeyspace = 
keyspace.withSwapped(keyspace.tables.withSwapped(newTable));
+
+        return schema.withAddedOrUpdated(newKeyspace);
+    }
+
+    @Override
+    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
+    {
+        return new SchemaChange(Change.UPDATED, Target.TABLE, keyspaceName, 
tableName);
+    }
+
+    @Override
+    public void authorize(ClientState client)
+    {
+        client.ensureTablePermission(keyspaceName, tableName, 
Permission.ALTER);
+    }
+
+    @Override
+    public AuditLogContext getAuditLogContext()
+    {
+        return new AuditLogContext(AuditLogEntryType.SECURITY_LABEL_COLUMN, 
keyspaceName, tableName);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s (%s.%s.%s, %s)", getClass().getSimpleName(), 
keyspaceName, tableName, columnName, securityLabel);
+    }
+
+    public static final class Raw extends CQLStatement.Raw
+    {
+        private final QualifiedName tableName;
+        private final ColumnIdentifier columnName;
+        private final String securityLabel;
+        private final String provider;
+
+        public Raw(QualifiedName tableName, ColumnIdentifier columnName, 
String securityLabel, String provider)
+        {
+            this.tableName = tableName;
+            this.columnName = columnName;
+            this.securityLabel = securityLabel;
+            this.provider = provider;
+        }
+
+        @Override
+        public SecurityLabelOnColumnStatement prepare(ClientState state)
+        {
+            String keyspaceName = tableName.hasKeyspace() ? 
tableName.getKeyspace() : state.getKeyspace();
+            return new SecurityLabelOnColumnStatement(keyspaceName,
+                                                    tableName.getName(),
+                                                    columnName,
+                                                    securityLabel,
+                                                    provider);
+        }

Review Comment:
   lines are not aligned



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnTypeStatement.java:
##########
@@ -0,0 +1,147 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.UTName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+/**
+ * Handles the execution of SECURITY LABEL ON TYPE CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
user-defined types.
+ * Security labels are stored in the type metadata and displayed when using 
DESCRIBE TYPE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON TYPE [keyspace_name.]type_name IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnKeyspaceStatement
+ * @see SecurityLabelOnTableStatement
+ * @see SecurityLabelOnColumnStatement
+ */
+public final class SecurityLabelOnTypeStatement extends AlterSchemaStatement
+{
+    private final String typeName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnTypeStatement(String keyspaceName, String typeName, 
String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.typeName = typeName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        UserType type = keyspace.types.getNullable(bytes(typeName));
+        if (null == type)
+            throw ire("Type '%s.%s' doesn't exist", keyspaceName, typeName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");
+
+        UserType newType = type.withSecurityLabel(securityLabel);
+        KeyspaceMetadata newKeyspace = 
keyspace.withSwapped(keyspace.types.withUpdatedUserType(newType));
+
+        return schema.withAddedOrUpdated(newKeyspace);
+    }
+
+    @Override
+    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
+    {
+        return new SchemaChange(Change.UPDATED, Target.TYPE, keyspaceName, 
typeName);
+    }
+
+    @Override
+    public void authorize(ClientState client)
+    {
+        client.ensureKeyspacePermission(keyspaceName, Permission.ALTER);

Review Comment:
   I think the permission scope should be similar to create user type. It 
should be the following. Please also check the other security label and comment 
statements.
   
   ```
   client.ensureAllTablesPermission(...)
   ```



##########
src/java/org/apache/cassandra/cql3/statements/DescribeStatement.java:
##########
@@ -618,6 +619,69 @@ public String toCqlString(boolean withWarnings, boolean 
withInternals, boolean i
         };
     }
 
+    /**
+     * Wraps a schema element to append its associated comments and security 
labels.
+     * <p>
+     * This method creates a wrapper around schema elements (keyspaces, 
tables, types) that
+     * augments their CQL string representation with any defined comments or 
security labels.
+     * The wrapper delegates all SchemaElement interface methods to the 
wrapped element,
+     * but overrides toCqlString() to append COMMENT and SECURITY LABEL 
statements.
+     * </p>
+     *
+     * @param element the schema element to wrap
+     * @return a wrapped schema element that includes comments and security 
labels in its CQL output
+     */
+    private static SchemaElement descriptions(SchemaElement element)
+    {
+        return new SchemaElement()
+        {
+            @Override
+            public SchemaElementType elementType()
+            {
+                return element.elementType();
+            }
+
+            @Override
+            public String elementKeyspace()
+            {
+                return element.elementKeyspace();
+            }
+
+            @Override
+            public String elementName()
+            {
+                return element.elementName();
+            }
+
+            @Override
+            public String toCqlString(boolean withWarnings, boolean 
withInternals, boolean ifNotExists)
+            {
+                String baseStatement = element.toCqlString(withWarnings, 
withInternals, ifNotExists);
+                StringBuilder result = new StringBuilder(baseStatement);
+                if (element instanceof KeyspaceMetadata)
+                {
+                    KeyspaceMetadata ksm = (KeyspaceMetadata) element;
+                    SchemaDescriptionsUtil.appendCommentOnKeyspace(result, 
ksm);
+                    
SchemaDescriptionsUtil.appendSecurityLabelOnKeyspace(result, ksm);
+                }
+                else if (element instanceof TableMetadata)
+                {
+                    TableMetadata tbm = (TableMetadata) element;
+                    SchemaDescriptionsUtil.appendCommentOnTable(result, tbm);
+                    SchemaDescriptionsUtil.appendSecurityLabelOnTable(result, 
tbm);
+                }
+                else if (element instanceof UserType)
+                {
+                    UserType userType = (UserType) element;
+                    SchemaDescriptionsUtil.appendCommentOnType(result, 
userType);
+                    SchemaDescriptionsUtil.appendSecurityLabelOnType(result, 
userType);
+                }

Review Comment:
   Hmmm... why comparing the types.. Could you move the handling to be part of 
each `SchemaElement` concrete implementations? 



##########
src/java/org/apache/cassandra/cql3/statements/schema/SecurityLabelOnFieldStatement.java:
##########
@@ -0,0 +1,155 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.FieldIdentifier;
+import org.apache.cassandra.cql3.UTName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.ClientWarn;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+/**
+ * Handles the execution of SECURITY LABEL ON FIELD CQL statements.
+ * <p>
+ * This statement allows users to add security classification labels to 
individual fields of user-defined types.
+ * Security labels are stored in the type metadata and displayed when using 
DESCRIBE TYPE.
+ * </p>
+ * <p>
+ * Syntax: {@code SECURITY LABEL ON FIELD [keyspace_name.]type_name.field_name 
IS 'label';}
+ * </p>
+ * <p>
+ * Security labels can be used to mark data sensitivity levels or compliance 
requirements.
+ * Labels can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see SecurityLabelOnTypeStatement
+ * @see SecurityLabelOnColumnStatement
+ */
+public final class SecurityLabelOnFieldStatement extends AlterSchemaStatement
+{
+    private final String typeName;
+    private final FieldIdentifier fieldName;
+    private final String securityLabel;
+    private final String provider;
+
+    public SecurityLabelOnFieldStatement(String keyspaceName, String typeName, 
FieldIdentifier fieldName, String securityLabel, String provider)
+    {
+        super(keyspaceName);
+        this.typeName = typeName;
+        this.fieldName = fieldName;
+        this.securityLabel = securityLabel;
+        this.provider = provider;
+    }
+
+    @Override
+    public void validate(ClientState state)
+    {
+        super.validate(state);
+        SchemaDescriptionsUtil.validateSecurityLabel(securityLabel);
+    }
+
+    @Override
+    public Keyspaces apply(ClusterMetadata metadata)
+    {
+        Keyspaces schema = metadata.schema.getKeyspaces();
+        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
+
+        if (null == keyspace)
+            throw ire("Keyspace '%s' doesn't exist", keyspaceName);
+
+        UserType type = keyspace.types.getNullable(bytes(typeName));
+        if (null == type)
+            throw ire("Type '%s.%s' doesn't exist", keyspaceName, typeName);
+
+        if (type.fieldPosition(fieldName) == -1)
+            throw ire("Field '%s' doesn't exist in type '%s.%s'", fieldName, 
keyspaceName, typeName);
+
+        if (provider != null)
+            ClientWarn.instance.warn("Provider is not yet implemented but will 
proceed with adding the security label");
+
+        UserType newType = type.withFieldSecurityLabel(fieldName, 
securityLabel);
+        KeyspaceMetadata newKeyspace = 
keyspace.withSwapped(keyspace.types.withUpdatedUserType(newType));
+
+        return schema.withAddedOrUpdated(newKeyspace);
+    }
+
+    @Override
+    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
+    {
+        return new SchemaChange(Change.UPDATED, Target.TYPE, keyspaceName, 
typeName);
+    }
+
+    @Override
+    public void authorize(ClientState client)
+    {
+        client.ensureKeyspacePermission(keyspaceName, Permission.ALTER);
+    }
+
+    @Override
+    public AuditLogContext getAuditLogContext()
+    {
+        return new AuditLogContext(AuditLogEntryType.SECURITY_LABEL_TYPE, 
keyspaceName, typeName);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s (%s.%s.%s, %s)", getClass().getSimpleName(), 
keyspaceName, typeName, fieldName, securityLabel);
+    }
+
+    public static final class Raw extends CQLStatement.Raw
+    {
+        private final UTName typeName;
+        private final FieldIdentifier fieldName;
+        private final String securityLabel;
+        private final String provider;
+
+        public Raw(UTName typeName, FieldIdentifier fieldName, String 
securityLabel, String provider)
+        {
+            this.typeName = typeName;
+            this.fieldName = fieldName;
+            this.securityLabel = securityLabel;
+            this.provider = provider;
+        }
+
+        @Override
+        public SecurityLabelOnFieldStatement prepare(ClientState state)
+        {
+            String keyspaceName = typeName.hasKeyspace() ? 
typeName.getKeyspace() : state.getKeyspace();
+            return new SecurityLabelOnFieldStatement(keyspaceName,
+                                                    
typeName.getStringTypeName(),
+                                                    fieldName,
+                                                    securityLabel,
+                                                    provider);

Review Comment:
   not aligned.



##########
src/java/org/apache/cassandra/db/marshal/UserType.java:
##########
@@ -384,15 +412,19 @@ private boolean equalsWithoutTypes(UserType other)
         return name.equals(other.name)
             && fieldNames.equals(other.fieldNames)
             && keyspace.equals(other.keyspace)
-            && isMultiCell == other.isMultiCell;
+            && isMultiCell == other.isMultiCell
+            && comment.equals(other.comment)
+            && securityLabel.equals(other.securityLabel);

Review Comment:
   Similar reasoning with `ColumnSpec`, I do not think comment and 
securityLabel should be part of equals. 



##########
src/java/org/apache/cassandra/db/virtual/SchemaCommentsTable.java:
##########
@@ -0,0 +1,91 @@
+/*
+ * 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.cassandra.db.virtual;
+
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.db.marshal.UserType;
+
+/**
+ * Virtual table that exposes all comments on schema elements.
+ * <p>
+ * This table provides a unified view of documentation metadata across:
+ * <ul>
+ *   <li>Keyspaces - comments on keyspaces</li>
+ *   <li>Tables - comments on tables</li>
+ *   <li>Columns - comments on columns</li>
+ *   <li>User-Defined Types (UDTs) - comments on UDTs</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The table automatically reflects the current state of schema metadata 
without requiring
+ * explicit updates. Data is read directly from {@link 
org.apache.cassandra.schema.Schema#instance} on each query.
+ * </p>
+ * <p>
+ * Example queries:
+ * <pre>
+ * -- All comments in the system
+ * SELECT * FROM system_views.schema_comments;
+ *
+ * -- All table comments in a specific keyspace
+ * SELECT * FROM system_views.schema_comments
+ * WHERE object_type = 'TABLE' AND keyspace_name = 'my_keyspace';
+ *
+ * -- All column comments across all keyspaces
+ * SELECT * FROM system_views.schema_comments WHERE object_type = 'COLUMN';

Review Comment:
   Partition key is `(object_type, keyspace_name)`, I do not think this query 
would work, although I have not tried. Please double check and update the 
javadoc (here and in SchemaSecurityLabelsTable) if needed. 



##########
src/java/org/apache/cassandra/cql3/statements/schema/CommentOnTypeStatement.java:
##########
@@ -0,0 +1,137 @@
+/*
+ * 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.cassandra.cql3.statements.schema;
+
+import org.apache.cassandra.audit.AuditLogContext;
+import org.apache.cassandra.audit.AuditLogEntryType;
+import org.apache.cassandra.auth.Permission;
+import org.apache.cassandra.cql3.CQLStatement;
+import org.apache.cassandra.cql3.UTName;
+import org.apache.cassandra.cql3.statements.SchemaDescriptionsUtil;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Keyspaces;
+import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.transport.Event.SchemaChange;
+import org.apache.cassandra.transport.Event.SchemaChange.Change;
+import org.apache.cassandra.transport.Event.SchemaChange.Target;
+
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
+
+/**
+ * Handles the execution of COMMENT ON TYPE CQL statements.
+ * <p>
+ * This statement allows users to add descriptive comments to user-defined 
types for documentation purposes.
+ * Comments are stored in the type metadata and displayed when using DESCRIBE 
TYPE.
+ * </p>
+ * <p>
+ * Syntax: {@code COMMENT ON TYPE [keyspace_name.]type_name IS 'comment text';}
+ * </p>
+ * <p>
+ * Comments can be removed by setting them to an empty string or null.
+ * </p>
+ *
+ * @see CommentOnKeyspaceStatement
+ * @see CommentOnTableStatement
+ * @see CommentOnColumnStatement
+ */
+public final class CommentOnTypeStatement extends AlterSchemaStatement

Review Comment:
   nit: `CommentOnUserTypeStatement`, user type is the more common term



##########
src/java/org/apache/cassandra/db/virtual/AbstractSchemaMetadataTable.java:
##########
@@ -0,0 +1,311 @@
+/*
+ * 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.cassandra.db.virtual;
+
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.marshal.CompositeType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.dht.LocalPartitioner;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.Schema;
+import org.apache.cassandra.schema.SchemaProvider;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.db.marshal.UserType;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.google.common.base.Strings;
+
+/**
+ * Abstract base class for virtual tables that expose metadata on schema 
elements.
+ * <p>
+ * This class provides a unified implementation for tables that expose 
metadata across:
+ * <ul>
+ *   <li>Keyspaces - metadata on keyspaces</li>
+ *   <li>Tables - metadata on tables</li>
+ *   <li>Columns - metadata on columns</li>
+ *   <li>User-Defined Types (UDTs) - metadata on UDTs</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses must implement methods to extract the specific metadata field
+ * (e.g., comment, security label) from each schema element type.
+ * </p>
+ */
+abstract class AbstractSchemaMetadataTable extends AbstractVirtualTable
+{
+    /*
+        As clustering keys cannot be null, using an EMPTY_VALUE in the results 
for non-existent
+        columns in query results.
+    */
+    private static final String EMPTY_VALUE = "";
+
+    private static final String OBJECT_TYPE = "object_type";
+    private static final String KEYSPACE_NAME = "keyspace_name";
+    private static final String TABLE_NAME = "table_name";
+    private static final String COLUMN_NAME = "column_name";
+    private static final String UDT_NAME = "udt_name";
+    private static final String FIELD_NAME = "field_name";
+
+    private final SchemaTableType schemaTableType;
+
+    /**
+     * Schema object types that can have metadata.
+     */
+    protected enum ObjectType
+    {
+        KEYSPACE,
+        TABLE,
+        COLUMN,
+        UDT,
+        FIELD;
+
+        @Override
+        public String toString()
+        {
+            return name();
+        }
+
+        /**
+         * Parse object type string to enum.
+         * @param objectType the string representation of the object type
+         * @return ObjectType enum value or null if invalid
+         */
+        static ObjectType parse(String objectType)
+        {
+            try
+            {
+                return ObjectType.valueOf(objectType);
+            }
+            catch (IllegalArgumentException e)
+            {
+                return null;
+            }
+        }
+    }
+
+    protected enum SchemaTableType
+    {
+        COMMENT("schema_comments", "comment"),
+        SECURITY_LABEL("schema_security_labels", "security_label");
+
+        private final String tableName;
+        private final String columnName;
+
+        SchemaTableType(String tableName, String columnName)
+        {
+            this.tableName = tableName;
+            this.columnName = columnName;
+        }
+    }
+
+    protected AbstractSchemaMetadataTable(String keyspace, SchemaTableType 
schemaTableType)
+    {
+        super(TableMetadata.builder(keyspace, schemaTableType.tableName)
+                           .kind(TableMetadata.Kind.VIRTUAL)
+                           .partitioner(new 
LocalPartitioner(CompositeType.getInstance(UTF8Type.instance, 
UTF8Type.instance)))
+                           .addPartitionKeyColumn(OBJECT_TYPE, 
UTF8Type.instance)
+                           .addPartitionKeyColumn(KEYSPACE_NAME, 
UTF8Type.instance)
+                           .addClusteringColumn(TABLE_NAME, UTF8Type.instance)
+                           .addClusteringColumn(COLUMN_NAME, UTF8Type.instance)
+                           .addClusteringColumn(UDT_NAME, UTF8Type.instance)
+                           .addClusteringColumn(FIELD_NAME, UTF8Type.instance)
+                           .addRegularColumn(schemaTableType.columnName, 
UTF8Type.instance)
+                           .build());
+        this.schemaTableType = schemaTableType;
+    }
+
+    /**
+     * Extract metadata from a keyspace.
+     * @param keyspace the keyspace metadata
+     * @return the metadata value, or null if not present
+     */
+    protected abstract String extractKeyspaceMetadata(KeyspaceMetadata 
keyspace);
+
+    /**
+     * Extract metadata from a table.
+     * @param table the table metadata
+     * @return the metadata value, or null if not present
+     */
+    protected abstract String extractTableMetadata(TableMetadata table);
+
+    /**
+     * Extract metadata from a column.
+     * @param column the column metadata
+     * @return the metadata value, or null if not present
+     */
+    protected abstract String extractColumnMetadata(ColumnMetadata column);
+
+    /**
+     * Extract metadata from a UDT.
+     * @param udt the user-defined type
+     * @return the metadata value, or null if not present
+     */
+    protected abstract String extractUdtMetadata(UserType udt);
+
+    /**
+     * Extract metadata from a UDT field.
+     * @param udt the user-defined type
+     * @param fieldName the field name
+     * @return the metadata value, or null if not present
+     */
+    protected abstract String extractFieldMetadata(UserType udt, String 
fieldName);
+
+    @Override
+    public DataSet data()
+    {
+        SimpleDataSet result = new SimpleDataSet(metadata());
+        SchemaProvider schemaProvider = Schema.instance;
+
+        for (String keyspaceName : schemaProvider.getKeyspaces())
+        {
+            KeyspaceMetadata keyspace = 
schemaProvider.getKeyspaceMetadata(keyspaceName);
+            if (keyspace == null)
+            {
+                continue;
+            }
+            addKeyspaceRow(result, keyspace);
+
+            for (TableMetadata table : keyspace.tables)
+            {
+                addTableRow(result, keyspace, table);
+
+                for (ColumnMetadata column : table.columns())
+                    addColumnRow(result, keyspace, table, column);
+            }
+
+            for (UserType udt : keyspace.types)
+            {
+                addUdtRow(result, keyspace, udt);
+
+                for (org.apache.cassandra.cql3.FieldIdentifier field : 
udt.fieldNames())

Review Comment:
   Why using the full qualified name here?!



##########
src/java/org/apache/cassandra/cql3/ColumnSpecification.java:
##########
@@ -86,12 +97,14 @@ public boolean equals(Object other)
         return this.ksName.equals(that.ksName) &&
                this.cfName.equals(that.cfName) &&
                this.name.equals(that.name) &&
-               this.type.equals(that.type);
+               this.type.equals(that.type) &&
+               Objects.equal(this.comment, that.comment) &&
+               Objects.equal(this.securityLabel, that.securityLabel);
     }
 
     public int hashCode()
     {
-        return Objects.hashCode(ksName, cfName, name, type);
+        return Objects.hashCode(ksName, cfName, name, type, comment, 
securityLabel);

Review Comment:
   I do not think `comment` and `securirtyLabel` should be part of hashcode and 
equals for `ColumnSpecification`. Each column should be uniquely identified by 
its name already. 
   
   FYI, those 2 methods in `ColumnSpecification` will only be examined in 
`SelectionColumnMapping` where colSpec is used as key. 



##########
src/java/org/apache/cassandra/db/marshal/UserType.java:
##########
@@ -384,15 +412,19 @@ private boolean equalsWithoutTypes(UserType other)
         return name.equals(other.name)
             && fieldNames.equals(other.fieldNames)
             && keyspace.equals(other.keyspace)
-            && isMultiCell == other.isMultiCell;
+            && isMultiCell == other.isMultiCell
+            && comment.equals(other.comment)
+            && securityLabel.equals(other.securityLabel);
     }
 
     public boolean equalsWithOutKs(UserType other)
     {
         return name.equals(other.name)
             && fieldNames.equals(other.fieldNames)
             && types.equals(other.types)
-            && isMultiCell == other.isMultiCell;
+            && isMultiCell == other.isMultiCell
+            && comment.equals(other.comment)
+            && securityLabel.equals(other.securityLabel);

Review Comment:
   The method is used in table-copy feature. Operators have to create the UDT 
with the same comments and securtiy label first in order for the table-copy to 
be successful. It is surprising since table-copy allows to avoid copying the 
comments and the security labels. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to