This is an automated email from the ASF dual-hosted git repository.

JackieTien97 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 80d16007436 Reject column changes that conflict with a pending column 
deletion or data type change (#18776)
80d16007436 is described below

commit 80d16007436a94e763a8c0d8db66b7e7cbd87ca2
Author: alpass163 <[email protected]>
AuthorDate: Thu Oct 22 13:56:41 2026 +0800

    Reject column changes that conflict with a pending column deletion or data 
type change (#18776)
---
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |   2 +
 .../manager/schema/ClusterSchemaManager.java       | 120 +++++++++++++++++++--
 .../persistence/schema/ClusterSchemaInfo.java      |  12 +++
 .../confignode/persistence/schema/ConfigMTree.java |  11 ++
 .../manager/ClusterSchemaManagerTest.java          | 111 +++++++++++++++++++
 .../persistence/schema/ConfigMTreeTest.java        |  36 +++++++
 .../apache/iotdb/commons/i18n/CommonMessages.java  |  16 ++-
 .../apache/iotdb/commons/i18n/CommonMessages.java  |   6 ++
 .../exception/table/ColumnInAlterException.java    |  40 +++++++
 .../exception/table/ColumnInDeletionException.java |  40 +++++++
 10 files changed, 381 insertions(+), 13 deletions(-)

diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index da9b4388691..6df31101e47 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -100,6 +100,8 @@ public enum TSStatusCode {
   TABLE_IS_LOST(553),
   TABLE_INCOMPATIBLE(554),
   TABLE_IN_PRE_DELETE(555),
+  COLUMN_IN_PRE_DELETE(556),
+  COLUMN_IN_PRE_ALTER(557),
   ONLY_LOGICAL_VIEW(560),
 
   // Storage Engine
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
index e7f96322a53..d85e2e81013 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
@@ -24,6 +24,8 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.exception.table.ColumnInAlterException;
+import org.apache.iotdb.commons.exception.table.ColumnInDeletionException;
 import org.apache.iotdb.commons.exception.table.TableInDeletionException;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
@@ -100,6 +102,7 @@ import 
org.apache.iotdb.confignode.manager.partition.PartitionMetrics;
 import 
org.apache.iotdb.confignode.manager.partition.RegionGroupExtensionPolicy;
 import org.apache.iotdb.confignode.persistence.schema.ClusterSchemaInfo;
 import org.apache.iotdb.confignode.persistence.schema.ConfigSchemaStatistics;
+import 
org.apache.iotdb.confignode.persistence.schema.mnode.impl.ConfigTableNode;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.confignode.rpc.thrift.TDescTable4InformationSchemaResp;
@@ -1541,17 +1544,113 @@ public class ClusterSchemaManager {
     return clusterSchemaInfo.getTsTableIfExists(database, tableName);
   }
 
+  /**
+   * The table must exist and must not be in the pre-delete status.
+   *
+   * @return the table node, or empty when the table does not exist
+   */
+  private Optional<ConfigTableNode> getTableNodeForModification(
+      final String database, final String tableName) throws MetadataException {
+    final Optional<ConfigTableNode> tableNodeOptional =
+        clusterSchemaInfo.getTableNodeIfExists(database, tableName);
+    if (tableNodeOptional.isPresent()
+        && TableNodeStatus.PRE_DELETE == tableNodeOptional.get().getStatus()) {
+      throw new TableInDeletionException(database, tableName);
+    }
+    return tableNodeOptional;
+  }
+
   public Optional<TsTable> getTableWithUsingStatusIfExists(
       final String database, final String tableName) throws MetadataException {
-    final Optional<Pair<TsTable, TableNodeStatus>> tableAndStatus =
-        getTableAndStatusIfExists(database, tableName);
-    if (tableAndStatus.isEmpty()) {
+    return getTableNodeForModification(database, 
tableName).map(ConfigTableNode::getTable);
+  }
+
+  /**
+   * The new column names must not belong to a column whose deletion or data 
type change has not
+   * finished, otherwise the column being added would collide with it.
+   *
+   * @return the table, or empty when the table does not exist
+   */
+  public Optional<TsTable> checkTableAndColumnsForAddition(
+      final String database,
+      final String tableName,
+      final List<TsTableColumnSchema> columnSchemaList)
+      throws MetadataException {
+    final Optional<ConfigTableNode> tableNodeOptional =
+        getTableNodeForModification(database, tableName);
+    if (tableNodeOptional.isEmpty()) {
       return Optional.empty();
     }
-    if (TableNodeStatus.PRE_DELETE == tableAndStatus.get().getRight()) {
-      throw new TableInDeletionException(database, tableName);
+    final ConfigTableNode tableNode = tableNodeOptional.get();
+    for (final TsTableColumnSchema columnSchema : columnSchemaList) {
+      final String columnName = columnSchema.getColumnName();
+      checkColumnNotDeleting(tableNode, database, tableName, columnName);
+      checkColumnNotAltering(tableNode, database, tableName, columnName);
+    }
+    return Optional.of(tableNode.getTable());
+  }
+
+  /**
+   * The column must not be one whose deletion has not finished. A pending 
data type change is
+   * allowed here: the new type replaces the pending one.
+   *
+   * @return the table, or empty when the table does not exist
+   */
+  public Optional<TsTable> checkTableAndColumnForAltering(
+      final String database, final String tableName, final String columnName)
+      throws MetadataException {
+    final Optional<ConfigTableNode> tableNodeOptional =
+        getTableNodeForModification(database, tableName);
+    if (tableNodeOptional.isEmpty()) {
+      return Optional.empty();
+    }
+    final ConfigTableNode tableNode = tableNodeOptional.get();
+    checkColumnNotDeleting(tableNode, database, tableName, columnName);
+    return Optional.of(tableNode.getTable());
+  }
+
+  /**
+   * Neither the old nor the new column name may belong to a column whose 
deletion or data type
+   * change has not finished.
+   *
+   * @return the table, or empty when the table does not exist
+   */
+  public Optional<TsTable> checkTableAndColumnsForRenaming(
+      final String database, final String tableName, final String oldName, 
final String newName)
+      throws MetadataException {
+    final Optional<ConfigTableNode> tableNodeOptional =
+        getTableNodeForModification(database, tableName);
+    if (tableNodeOptional.isEmpty()) {
+      return Optional.empty();
+    }
+    final ConfigTableNode tableNode = tableNodeOptional.get();
+    checkColumnNotDeleting(tableNode, database, tableName, oldName);
+    checkColumnNotAltering(tableNode, database, tableName, oldName);
+    checkColumnNotDeleting(tableNode, database, tableName, newName);
+    checkColumnNotAltering(tableNode, database, tableName, newName);
+    return Optional.of(tableNode.getTable());
+  }
+
+  private void checkColumnNotDeleting(
+      final ConfigTableNode tableNode,
+      final String database,
+      final String tableName,
+      final String columnName)
+      throws ColumnInDeletionException {
+    if (tableNode.getPreDeletedColumns().contains(columnName)) {
+      throw new ColumnInDeletionException(database, tableName, columnName);
+    }
+  }
+
+  private void checkColumnNotAltering(
+      final ConfigTableNode tableNode,
+      final String database,
+      final String tableName,
+      final String columnName)
+      throws ColumnInAlterException {
+    if (tableNode.getPreAlteredColumns().containsKey(columnName)) {
+      throw new ColumnInAlterException(database, tableName, columnName);
     }
-    return Optional.of(tableAndStatus.get().getLeft());
   }
 
   public synchronized Pair<TSStatus, TsTable> 
tableColumnCheckForColumnExtension(
@@ -1560,7 +1659,8 @@ public class ClusterSchemaManager {
       final List<TsTableColumnSchema> columnSchemaList,
       final boolean isTableView)
       throws MetadataException {
-    final TsTable originalTable = getTableWithUsingStatusIfExists(database, 
tableName).orElse(null);
+    final TsTable originalTable =
+        checkTableAndColumnsForAddition(database, tableName, 
columnSchemaList).orElse(null);
 
     if (Objects.isNull(originalTable)) {
       return new Pair<>(
@@ -1615,7 +1715,8 @@ public class ClusterSchemaManager {
       final TSDataType dataType,
       final boolean isGeneratedByPipe)
       throws MetadataException {
-    final TsTable originalTable = getTableWithUsingStatusIfExists(database, 
tableName).orElse(null);
+    final TsTable originalTable =
+        checkTableAndColumnForAltering(database, tableName, 
columnName).orElse(null);
 
     if (Objects.isNull(originalTable)) {
       return new Pair<>(
@@ -1652,7 +1753,8 @@ public class ClusterSchemaManager {
       final String newName,
       final boolean isTableView)
       throws MetadataException {
-    final TsTable originalTable = getTableWithUsingStatusIfExists(database, 
tableName).orElse(null);
+    final TsTable originalTable =
+        checkTableAndColumnsForRenaming(database, tableName, oldName, 
newName).orElse(null);
 
     if (Objects.isNull(originalTable)) {
       return new Pair<>(
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index 6bae27bc7f2..94fc65e8ba2 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -99,6 +99,7 @@ import 
org.apache.iotdb.confignode.consensus.response.template.TemplateSetInfoRe
 import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.i18n.ConfigNodeMessages;
 import 
org.apache.iotdb.confignode.persistence.schema.ConfigMTree.TableSchemaDetails;
+import 
org.apache.iotdb.confignode.persistence.schema.mnode.impl.ConfigTableNode;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.confignode.rpc.thrift.TTableColumnInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TTableInfo;
@@ -1560,6 +1561,17 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
     }
   }
 
+  public Optional<ConfigTableNode> getTableNodeIfExists(
+      final String database, final String tableName) throws MetadataException {
+    databaseReadWriteLock.readLock().lock();
+    try {
+      return tableModelMTree.getTableNodeIfExists(
+          getQualifiedDatabasePartialPath(database), tableName);
+    } finally {
+      databaseReadWriteLock.readLock().unlock();
+    }
+  }
+
   public TSStatus addTableColumn(final AddTableColumnPlan plan) {
     return executeWithLock(
         () -> {
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
index ddb16660498..f31454b7b4c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
@@ -1027,6 +1027,8 @@ public class ConfigMTree {
       throw new 
SemanticException(ConfigNodeMessages.DROPPING_TAG_OR_TIME_COLUMN_IS_NOT_SUPPORTED);
     }
 
+    // Dropping the column makes a pending data type change moot.
+    node.removePreAlteredColumn(columnName);
     node.addPreDeletedColumn(columnName);
     return columnSchema.getColumnCategory() == TsTableColumnCategory.ATTRIBUTE;
   }
@@ -1181,6 +1183,15 @@ public class ConfigMTree {
     return ((ConfigTableNode) databaseNode.getChild(tableName));
   }
 
+  public Optional<ConfigTableNode> getTableNodeIfExists(
+      final PartialPath database, final String tableName) throws 
MetadataException {
+    final IConfigMNode databaseNode = 
getDatabaseNodeByDatabasePath(database).getAsMNode();
+    if (!databaseNode.hasChild(tableName)) {
+      return Optional.empty();
+    }
+    return Optional.of((ConfigTableNode) databaseNode.getChild(tableName));
+  }
+
   /**
    * A table in the pre-delete status is about to be dropped, pre-create 
status is a temporary
    * status, ignore it.
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
index 1be38df602a..c63ea9a98d6 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java
@@ -18,13 +18,19 @@
  */
 package org.apache.iotdb.confignode.manager;
 
+import org.apache.iotdb.commons.exception.table.ColumnInAlterException;
+import org.apache.iotdb.commons.exception.table.ColumnInDeletionException;
 import org.apache.iotdb.commons.exception.table.TableInDeletionException;
 import org.apache.iotdb.commons.schema.table.TsTable;
 import org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil;
+import org.apache.iotdb.commons.schema.table.column.FieldColumnSchema;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
 import 
org.apache.iotdb.confignode.consensus.request.write.database.DatabaseSchemaPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitCreateTablePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.PreAlterColumnDataTypePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.PreCreateTablePlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.PreDeleteColumnPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.PreDeleteTablePlan;
 import org.apache.iotdb.confignode.manager.schema.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.schema.ClusterSchemaQuotaStatistics;
@@ -33,6 +39,8 @@ import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.tsfile.utils.Pair;
 import org.junit.Assert;
 import org.junit.Test;
@@ -46,6 +54,9 @@ import java.util.Map;
 
 public class ClusterSchemaManagerTest {
 
+  private static final String DATABASE = "root.pending_column_test";
+  private static final String TABLE = "table1";
+
   @Test
   public void testCalcMaxRegionGroupNum() {
 
@@ -172,6 +183,106 @@ public class ClusterSchemaManagerTest {
                 database, table, new HashMap<>(), new HashMap<>(), false));
   }
 
+  @Test
+  public void testAddColumnRejectsPendingColumnNames() throws Exception {
+    final ClusterSchemaManager clusterSchemaManager = 
prepareTableWithPendingColumns();
+
+    // A name whose deletion has not finished, and a name whose data type 
change has not finished,
+    // are both rejected by the entry point the ADD COLUMN procedure uses.
+    Assert.assertThrows(
+        ColumnInDeletionException.class,
+        () ->
+            clusterSchemaManager.tableColumnCheckForColumnExtension(
+                DATABASE, TABLE, columns("deleting"), false));
+    Assert.assertThrows(
+        ColumnInAlterException.class,
+        () ->
+            clusterSchemaManager.tableColumnCheckForColumnExtension(
+                DATABASE, TABLE, columns("altering"), false));
+    // A name that no pending column takes can still be added.
+    Assert.assertEquals(
+        TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+        clusterSchemaManager
+            .tableColumnCheckForColumnExtension(DATABASE, TABLE, 
columns("added"), false)
+            .getLeft()
+            .getCode());
+  }
+
+  @Test
+  public void testAlterColumnTypeRejectsDeletingColumn() throws Exception {
+    final ClusterSchemaManager clusterSchemaManager = 
prepareTableWithPendingColumns();
+
+    // Changing the data type of a column whose deletion has not finished is 
rejected.
+    Assert.assertThrows(
+        ColumnInDeletionException.class,
+        () ->
+            clusterSchemaManager.tableColumnCheckForColumnAltering(
+                DATABASE, TABLE, "deleting", TSDataType.INT64, false));
+    // A column that already has a pending data type change may be changed 
again. Only the check is
+    // used here, because the entry point above writes the new pending type 
through the consensus
+    // layer, which a unit test does not provide.
+    Assert.assertTrue(
+        clusterSchemaManager
+            .checkTableAndColumnForAltering(DATABASE, TABLE, "altering")
+            .isPresent());
+  }
+
+  @Test
+  public void testRenameColumnRejectsPendingNames() throws Exception {
+    final ClusterSchemaManager clusterSchemaManager = 
prepareTableWithPendingColumns();
+
+    // The entry point the RENAME COLUMN procedure uses rejects an old name 
that is being deleted,
+    // and a new name that a pending column already takes.
+    Assert.assertThrows(
+        ColumnInDeletionException.class,
+        () ->
+            clusterSchemaManager.tableColumnCheckForColumnRenaming(
+                DATABASE, TABLE, "deleting", "renamed", false));
+    Assert.assertThrows(
+        ColumnInAlterException.class,
+        () ->
+            clusterSchemaManager.tableColumnCheckForColumnRenaming(
+                DATABASE, TABLE, "live", "altering", false));
+    // Renaming between two names that no pending column takes is allowed.
+    Assert.assertEquals(
+        TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+        clusterSchemaManager
+            .tableColumnCheckForColumnRenaming(DATABASE, TABLE, "live", 
"added", false)
+            .getLeft()
+            .getCode());
+  }
+
+  /** A table whose {@code deleting} column is being deleted and {@code 
altering} column altered. */
+  private static ClusterSchemaManager prepareTableWithPendingColumns() throws 
Exception {
+    final ClusterSchemaInfo clusterSchemaInfo = new ClusterSchemaInfo();
+    clusterSchemaInfo.createDatabase(
+        new DatabaseSchemaPlan(
+            ConfigPhysicalPlanType.CreateDatabase,
+            new TDatabaseSchema(DATABASE).setIsTableModel(true)));
+    final TsTable table = new TsTable(TABLE);
+    table.addColumnSchema(field("live"));
+    table.addColumnSchema(field("deleting"));
+    table.addColumnSchema(field("altering"));
+    clusterSchemaInfo.preCreateTable(new PreCreateTablePlan(DATABASE, table));
+    clusterSchemaInfo.commitCreateTable(new CommitCreateTablePlan(DATABASE, 
TABLE));
+    clusterSchemaInfo.preDeleteColumn(new PreDeleteColumnPlan(DATABASE, TABLE, 
"deleting"));
+    clusterSchemaInfo.preAlterColumnDataType(
+        new PreAlterColumnDataTypePlan(DATABASE, TABLE, "altering", 
TSDataType.INT64));
+    return managerOf(clusterSchemaInfo);
+  }
+
+  private static List<TsTableColumnSchema> columns(final String... 
columnNames) {
+    final List<TsTableColumnSchema> columnSchemaList = new ArrayList<>();
+    for (final String columnName : columnNames) {
+      columnSchemaList.add(field(columnName));
+    }
+    return columnSchemaList;
+  }
+
+  private static FieldColumnSchema field(final String columnName) {
+    return new FieldColumnSchema(columnName, TSDataType.INT32, TSEncoding.RLE, 
CompressionType.LZ4);
+  }
+
   private static ClusterSchemaManager managerOf(final ClusterSchemaInfo 
clusterSchemaInfo) {
     return new ClusterSchemaManager(
         Mockito.mock(IManager.class),
diff --git 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
index f66edecbbcc..29ea80f9dd9 100644
--- 
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
+++ 
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java
@@ -484,6 +484,42 @@ public class ConfigMTreeTest {
         root.getUsingTableSchema(database, 
table.getTableName()).getColumnSchema("measurement"));
   }
 
+  @Test
+  public void testDropColumnClearsPendingDataTypeChange() throws Exception {
+    root = new ConfigMTree(true);
+
+    final PartialPath database = new PartialPath("root.sg");
+    root.setStorageGroup(database);
+    final IDatabaseMNode<IConfigMNode> databaseNode = 
root.getDatabaseNodeByDatabasePath(database);
+    databaseNode
+        .getAsMNode()
+        .getDatabaseSchema()
+        .setName(PathUtils.unQualifyDatabaseName(database.getFullPath()));
+    databaseNode.getAsMNode().getDatabaseSchema().setIsTableModel(true);
+
+    final TsTable table = new TsTable("table1");
+    table.addColumnSchema(new TagColumnSchema("id", TSDataType.STRING));
+    table.addColumnSchema(
+        new FieldColumnSchema(
+            "measurement", TSDataType.DOUBLE, TSEncoding.GORILLA, 
CompressionType.SNAPPY));
+    root.preCreateTable(database, table);
+    root.commitCreateTable(database, table.getTableName());
+
+    root.preAlterColumnDataType(database, table.getTableName(), "measurement", 
TSDataType.STRING);
+    Assert.assertTrue(
+        root.getTableSchemaDetails(database, table.getTableName())
+            .preAlteredColumns
+            .containsKey("measurement"));
+
+    root.preDeleteColumn(database, table.getTableName(), "measurement", false);
+
+    ConfigMTree.TableSchemaDetails tableSchemaDetails =
+        root.getTableSchemaDetails(database, table.getTableName());
+    
Assert.assertTrue(tableSchemaDetails.preDeletedColumns.contains("measurement"));
+    // The pending data type change is moot once the column is dropped.
+    
Assert.assertFalse(tableSchemaDetails.preAlteredColumns.containsKey("measurement"));
+  }
+
   @Test
   public void testSetTemplate() throws MetadataException {
     root.setStorageGroup(new PartialPath("root.a"));
diff --git 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/CommonMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/CommonMessages.java
index a0bcb6078e2..df88f4dbb18 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/CommonMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/en/org/apache/iotdb/commons/i18n/CommonMessages.java
@@ -124,10 +124,12 @@ public final class CommonMessages {
   public static final String REPAIR_SYSTEM_PROPERTIES = "repair 
system.properties, lack {}";
   public static final String 
PARAMETER_CANNOT_BE_MODIFIED_AFTER_FIRST_STARTUP_FMT =
       "%s can't be modified after first startup";
-  public static final String 
MISC_LOG_SERIALIZE_MUTABLE_SYSTEM_PROPERTIES_SUCCESSFULLY_WHICH_TAKES_4656A206 =
-      "Serialize mutable system properties successfully, which takes {} ms.";
-  public static final String 
MISC_LOG_DO_NOT_UPGRADE_IOTDB_FROM_V0_9_OR_LOWER_VERSION_TO_V1_0_9878EC88 =
-      "DO NOT UPGRADE IoTDB from v0.9 or lower version to v1.0! Please upgrade 
to v0.10 first";
+  public static final String
+      
MISC_LOG_SERIALIZE_MUTABLE_SYSTEM_PROPERTIES_SUCCESSFULLY_WHICH_TAKES_4656A206 =
+          "Serialize mutable system properties successfully, which takes {} 
ms.";
+  public static final String
+      
MISC_LOG_DO_NOT_UPGRADE_IOTDB_FROM_V0_9_OR_LOWER_VERSION_TO_V1_0_9878EC88 =
+          "DO NOT UPGRADE IoTDB from v0.9 or lower version to v1.0! Please 
upgrade to v0.10 first";
 
   private CommonMessages() {}
 
@@ -341,6 +343,12 @@ public final class CommonMessages {
   public static final String
       
EXCEPTION_THE_TABLE_ARG_ARG_IS_IN_THE_PRE_DELETE_STATE_PLEASE_WAIT_A_FEW_SECONDS_IF_THE_TABLE_IS_STILL_IN_THIS_STATE_PLEASE_DROP_IT_AGAIN_13B9D39F
 =
           "The table %s.%s is in the pre-delete state. Please wait a few 
seconds. If the table is still in this state, please drop it again.";
+  public static final String
+      
EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_DELETED_PLEASE_WAIT_FOR_DELETION_TO_FINISH_OR_RETRY_DROPPING_THE_COLUMN_IF_IT_IS_STUCK_875DAFFE
 =
+          "Column '%s' in table '%s.%s' is being deleted. Please wait for 
deletion to finish, or retry dropping the column if it is stuck.";
+  public static final String
+      
EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_ALTERED_PLEASE_WAIT_FOR_ALTERATION_TO_FINISH_OR_RETRY_ALTERING_THE_COLUMN_IF_IT_IS_STUCK_11155B55
 =
+          "Column '%s' in table '%s.%s' is being altered. Please wait for 
alteration to finish, or retry altering the column if it is stuck.";
   public static final String EXCEPTION_MEMORY_BLOCK_ARG_IS_READ_ONLY_D10B3340 =
       "Memory block %s is read-only";
   public static final String 
EXCEPTION_MEMORY_BLOCK_ARG_ALREADY_USES_MUTABLE_ACCOUNTING_6F7DCB3F =
diff --git 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/CommonMessages.java
 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/CommonMessages.java
index 75873a97671..25be984f2d1 100644
--- 
a/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/CommonMessages.java
+++ 
b/iotdb-core/node-commons/src/main/i18n/zh/org/apache/iotdb/commons/i18n/CommonMessages.java
@@ -241,4 +241,10 @@ public final class CommonMessages {
   public static final String EXCEPTION_MEMORY_BLOCK_ARG_IS_READ_ONLY_D10B3340 
= "内存块 %s 为只读";
   public static final String 
EXCEPTION_MEMORY_BLOCK_ARG_ALREADY_USES_MUTABLE_ACCOUNTING_6F7DCB3F =
       "内存块 %s 已使用可变计量";
+  public static final String
+      
EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_DELETED_PLEASE_WAIT_FOR_DELETION_TO_FINISH_OR_RETRY_DROPPING_THE_COLUMN_IF_IT_IS_STUCK_875DAFFE
 =
+          "列 '%s'(位于表 '%s.%s')正在删除中。请等待删除完成;如果删除一直未完成,请重试删除该列。";
+  public static final String
+      
EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_ALTERED_PLEASE_WAIT_FOR_ALTERATION_TO_FINISH_OR_RETRY_ALTERING_THE_COLUMN_IF_IT_IS_STUCK_11155B55
 =
+          "列 '%s'(位于表 '%s.%s')正在修改中。请等待修改完成;如果修改一直未完成,请重试修改该列。";
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInAlterException.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInAlterException.java
new file mode 100644
index 00000000000..ee08f2f0a58
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInAlterException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.iotdb.commons.exception.table;
+
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.i18n.CommonMessages;
+import org.apache.iotdb.commons.utils.PathUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class ColumnInAlterException extends MetadataException {
+
+  public ColumnInAlterException(
+      final String database, final String tableName, final String columnName) {
+    super(
+        String.format(
+            CommonMessages
+                
.EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_ALTERED_PLEASE_WAIT_FOR_ALTERATION_TO_FINISH_OR_RETRY_ALTERING_THE_COLUMN_IF_IT_IS_STUCK_11155B55,
+            columnName,
+            PathUtils.unQualifyDatabaseName(database),
+            tableName),
+        TSStatusCode.COLUMN_IN_PRE_ALTER.getStatusCode());
+  }
+}
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInDeletionException.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInDeletionException.java
new file mode 100644
index 00000000000..93bdbc305df
--- /dev/null
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/exception/table/ColumnInDeletionException.java
@@ -0,0 +1,40 @@
+/*
+ * 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.iotdb.commons.exception.table;
+
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.i18n.CommonMessages;
+import org.apache.iotdb.commons.utils.PathUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class ColumnInDeletionException extends MetadataException {
+
+  public ColumnInDeletionException(
+      final String database, final String tableName, final String columnName) {
+    super(
+        String.format(
+            CommonMessages
+                
.EXCEPTION_COLUMN_ARG_IN_TABLE_ARG_ARG_IS_BEING_DELETED_PLEASE_WAIT_FOR_DELETION_TO_FINISH_OR_RETRY_DROPPING_THE_COLUMN_IF_IT_IS_STUCK_875DAFFE,
+            columnName,
+            PathUtils.unQualifyDatabaseName(database),
+            tableName),
+        TSStatusCode.COLUMN_IN_PRE_DELETE.getStatusCode());
+  }
+}

Reply via email to