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

jiangtian pushed a commit to branch force_ci/alter_column_datatype
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit e6aee9a083d7d86cce2a18f5f092a45f9163578e
Author: Tian Jiang <[email protected]>
AuthorDate: Tue Jan 7 15:49:23 2025 +0800

    init
---
 .../client/async/CnToDnAsyncRequestType.java       |   1 +
 .../rpc/DataNodeAsyncRequestRPCHandler.java        |   1 +
 .../consensus/request/ConfigPhysicalPlan.java      |   4 +
 .../consensus/request/ConfigPhysicalPlanType.java  |   2 +
 .../write/table/AlterColumnDataTypePlan.java       |  44 +++++
 .../consensus/response/table/DescTableResp.java    |  21 ++-
 .../iotdb/confignode/manager/ConfigManager.java    |   5 +-
 .../iotdb/confignode/manager/ProcedureManager.java |  23 ++-
 .../manager/schema/ClusterSchemaManager.java       |  34 +++-
 .../persistence/executor/ConfigPlanExecutor.java   |   4 +
 .../persistence/schema/ClusterSchemaInfo.java      |  47 ++++-
 .../confignode/persistence/schema/ConfigMTree.java |  79 +++++++-
 .../schema/mnode/impl/ConfigTableNode.java         |  15 ++
 .../schema/mnode/info/ConfigTableInfo.java         |  16 ++
 .../table/AlterTableColumnDataTypeProcedure.java   | 210 +++++++++++++++++++++
 .../schema/table/DropTableColumnProcedure.java     |   2 +-
 .../schema/AlterTableColumnDataTypeState.java      |  27 +++
 .../procedure/store/ProcedureFactory.java          |   4 +
 .../confignode/procedure/store/ProcedureType.java  |   1 +
 .../impl/DataNodeInternalRPCServiceImpl.java       |   1 +
 .../iotdb/db/queryengine/plan/Coordinator.java     |   2 +
 .../execution/config/TableConfigTaskVisitor.java   |  21 +++
 .../config/executor/ClusterConfigTaskExecutor.java |  41 +++-
 .../config/executor/IConfigTaskExecutor.java       |  10 +
 .../relational/AlterColumnDataTypeTask.java        |  53 ++++++
 .../relational/DescribeTableDetailsTask.java       |  17 +-
 .../relational/sql/ast/AlterColumnDataType.java    |  91 +++++++++
 .../plan/relational/sql/ast/AstVisitor.java        |   4 +
 .../plan/relational/sql/parser/AstBuilder.java     |  21 +++
 .../db/storageengine/dataregion/DataRegion.java    |   2 +-
 .../table/AlterOrDropTableOperationType.java       |   4 +-
 .../apache/iotdb/commons/schema/table/TsTable.java |  21 +--
 .../schema/table/column/AttributeColumnSchema.java |   7 +
 .../schema/table/column/FieldColumnSchema.java     |   7 +
 .../schema/table/column/TagColumnSchema.java       |   6 +
 .../schema/table/column/TimeColumnSchema.java      |   6 +
 .../schema/table/column/TsTableColumnSchema.java   |   2 +
 .../table/column/TsTableColumnSchemaUtil.java      |  12 ++
 .../db/relational/grammar/sql/RelationalSql.g4     |   1 +
 .../src/main/thrift/confignode.thrift              |   1 +
 .../src/main/thrift/datanode.thrift                |   1 -
 41 files changed, 830 insertions(+), 41 deletions(-)

diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnAsyncRequestType.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnAsyncRequestType.java
index a27be4e6025..d982b3886e2 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnAsyncRequestType.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnAsyncRequestType.java
@@ -120,4 +120,5 @@ public enum CnToDnAsyncRequestType {
   INVALIDATE_MATCHED_TABLE_DEVICE_CACHE,
   DELETE_DATA_FOR_TABLE_DEVICE,
   DELETE_TABLE_DEVICE_IN_BLACK_LIST,
+  ALTER_COLUMN_DATATYPE
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java
index b1e8753ab49..1419482e895 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java
@@ -89,6 +89,7 @@ public abstract class DataNodeAsyncRequestRPCHandler<Response>
       case ROLLBACK_VIEW_SCHEMA_BLACK_LIST:
       case DELETE_VIEW:
       case ALTER_VIEW:
+      case ALTER_COLUMN_DATATYPE:
         return new SchemaUpdateRPCHandler(
             requestType,
             requestId,
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
index cc1aaee0555..806a4033a24 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
@@ -97,6 +97,7 @@ import 
org.apache.iotdb.confignode.consensus.request.write.sync.PreCreatePipePla
 import 
org.apache.iotdb.confignode.consensus.request.write.sync.RecordPipeMessagePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.sync.SetPipeStatusPlanV1;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.AddTableColumnPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.AlterColumnDataTypePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitCreateTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteColumnPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteTablePlan;
@@ -368,6 +369,9 @@ public abstract class ConfigPhysicalPlan implements 
IConsensusRequest {
         case PreDeleteColumn:
           plan = new PreDeleteColumnPlan();
           break;
+        case AlterColumnDataType:
+          plan = new AlterColumnDataTypePlan();
+          break;
         case CommitDeleteColumn:
           plan = new CommitDeleteColumnPlan();
           break;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
index 5d3bdcc6710..e3857b1f03c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
@@ -171,6 +171,8 @@ public enum ConfigPhysicalPlanType {
   PreDeleteColumn((short) 860),
   CommitDeleteColumn((short) 861),
   DescTable((short) 862),
+  AlterColumnDataType((short) 863),
+  CommitAlterColumnDataType((short) 864),
 
   /** Deprecated types for sync, restored them for upgrade. */
   @Deprecated
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/table/AlterColumnDataTypePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/table/AlterColumnDataTypePlan.java
new file mode 100644
index 00000000000..4b5350c22d0
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/table/AlterColumnDataTypePlan.java
@@ -0,0 +1,44 @@
+package org.apache.iotdb.confignode.consensus.request.write.table;
+
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
+
+import org.apache.tsfile.enums.TSDataType;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class AlterColumnDataTypePlan extends AbstractTableColumnPlan {
+
+  private TSDataType newType;
+
+  public AlterColumnDataTypePlan() {
+    super(ConfigPhysicalPlanType.AlterColumnDataType);
+  }
+
+  public AlterColumnDataTypePlan(
+      String database, String tableName, String columnName, TSDataType 
newType) {
+    super(ConfigPhysicalPlanType.AlterColumnDataType, database, tableName, 
columnName);
+    this.newType = newType;
+  }
+
+  @Override
+  protected void serializeImpl(DataOutputStream stream) throws IOException {
+    super.serializeImpl(stream);
+    stream.writeInt(newType.serialize());
+  }
+
+  @Override
+  protected void deserializeImpl(ByteBuffer buffer) throws IOException {
+    super.deserializeImpl(buffer);
+    newType = TSDataType.deserializeFrom(buffer);
+  }
+
+  public void setNewType(TSDataType newType) {
+    this.newType = newType;
+  }
+
+  public TSDataType getNewType() {
+    return newType;
+  }
+}
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/table/DescTableResp.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/table/DescTableResp.java
index fe09d00d251..7808c068899 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/table/DescTableResp.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/table/DescTableResp.java
@@ -25,6 +25,10 @@ import 
org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil;
 import org.apache.iotdb.confignode.rpc.thrift.TDescTableResp;
 import org.apache.iotdb.consensus.common.DataSet;
 
+import org.apache.tsfile.enums.TSDataType;
+
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
@@ -32,12 +36,17 @@ public class DescTableResp implements DataSet {
   private final TSStatus status;
   private final TsTable table;
   private final Set<String> preDeletedColumns;
+  private final Map<String, TSDataType> preAlteredColumns;
 
   public DescTableResp(
-      final TSStatus status, final TsTable table, final Set<String> 
preDeletedColumns) {
+      final TSStatus status,
+      final TsTable table,
+      final Set<String> preDeletedColumns,
+      final Map<String, TSDataType> preAlteredColumns) {
     this.status = status;
     this.table = table;
     this.preDeletedColumns = preDeletedColumns;
+    this.preAlteredColumns = preAlteredColumns;
   }
 
   public TDescTableResp convertToTDescTableResp() {
@@ -47,6 +56,14 @@ public class DescTableResp implements DataSet {
                 Objects.nonNull(table)
                     ? TsTableInternalRPCUtil.serializeSingleTsTable(table)
                     : null);
-    return Objects.nonNull(preDeletedColumns) ? 
resp.setPreDeletedColumns(preDeletedColumns) : resp;
+    if (Objects.nonNull(preDeletedColumns)) {
+      resp.setPreDeletedColumns(preDeletedColumns);
+    }
+    if (Objects.nonNull(preAlteredColumns)) {
+      Map<String, Byte> preAlteredColumnsMap = new HashMap<>();
+      preAlteredColumns.forEach((col, type) -> preAlteredColumnsMap.put(col, 
type.serialize()));
+      resp.setPreAlteredColumns(preAlteredColumnsMap);
+    }
+    return resp;
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index d1006aaba6f..be0f1dc85fe 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -2626,8 +2626,11 @@ public class ConfigManager implements IManager {
           return procedureManager.alterTableDropColumn(req);
         case DROP_TABLE:
           return procedureManager.dropTable(req);
+        case ALTER_COLUMN_DATA_TYPE:
+          return procedureManager.alterTableColumnDataType(req);
         default:
-          throw new IllegalArgumentException();
+          throw new IllegalArgumentException(
+              
AlterOrDropTableOperationType.getType(req.operationType).toString());
       }
     } else {
       return status;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
index b26b8c6b3be..f79cff952a9 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
@@ -87,10 +87,10 @@ import 
org.apache.iotdb.confignode.procedure.impl.schema.SetTemplateProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.UnsetTemplateProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.AbstractAlterOrDropTableProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.AddTableColumnProcedure;
+import 
org.apache.iotdb.confignode.procedure.impl.schema.table.AlterTableColumnDataTypeProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.CreateTableProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.DeleteDevicesProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.DropTableColumnProcedure;
-import 
org.apache.iotdb.confignode.procedure.impl.schema.table.DropTableProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.RenameTableColumnProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.SetTablePropertiesProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.subscription.consumer.CreateConsumerProcedure;
@@ -135,6 +135,7 @@ import org.apache.iotdb.db.schemaengine.template.Template;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.Pair;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
@@ -1539,14 +1540,30 @@ public class ProcedureManager {
             req.database, req.tableName, req.queryId, 
ReadWriteIOUtils.readString(req.updateInfo)));
   }
 
+  public TSStatus alterTableColumnDataType(TAlterOrDropTableReq req) {
+    return executeWithoutDuplicate(
+        req.database,
+        null,
+        req.tableName,
+        req.queryId,
+        ProcedureType.ALTER_TABLE_COLUMN_DATATYPE_PROCEDURE,
+        new AlterTableColumnDataTypeProcedure(
+            req.database,
+            req.tableName,
+            req.queryId,
+            ReadWriteIOUtils.readVarIntString(req.updateInfo),
+            TSDataType.deserialize(req.updateInfo.get())));
+  }
+
   public TSStatus dropTable(final TAlterOrDropTableReq req) {
     return executeWithoutDuplicate(
         req.database,
         null,
         req.tableName,
         req.queryId,
-        ProcedureType.DROP_TABLE_PROCEDURE,
-        new DropTableProcedure(req.database, req.tableName, req.queryId));
+        ProcedureType.DROP_TABLE_COLUMN_PROCEDURE,
+        new DropTableColumnProcedure(
+            req.database, req.tableName, req.queryId, 
ReadWriteIOUtils.readString(req.updateInfo)));
   }
 
   public TDeleteTableDeviceResp deleteDevices(final TDeleteTableDeviceReq req) 
{
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 353d97995b0..7ce0176c2ec 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
@@ -99,6 +99,7 @@ import org.apache.iotdb.mpp.rpc.thrift.TUpdateTemplateReq;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.utils.Pair;
 import org.slf4j.Logger;
@@ -1180,7 +1181,7 @@ public class ClusterSchemaManager {
           null);
     }
 
-    final TsTable expandedTable = 
TsTable.deserialize(ByteBuffer.wrap(originalTable.serialize()));
+    final TsTable expandedTable = new TsTable(originalTable);
 
     final String errorMsg =
         String.format(
@@ -1203,6 +1204,33 @@ public class ClusterSchemaManager {
     return new Pair<>(RpcUtils.SUCCESS_STATUS, expandedTable);
   }
 
+  public synchronized Pair<TSStatus, TsTable> 
tableColumnCheckForColumnAltering(
+      final String database,
+      final String tableName,
+      final String columnName,
+      final TSDataType dataType)
+      throws MetadataException {
+    final TsTable originalTable = getTableIfExists(database, 
tableName).orElse(null);
+
+    if (Objects.isNull(originalTable)) {
+      return new Pair<>(
+          RpcUtils.getStatus(
+              TSStatusCode.TABLE_NOT_EXISTS,
+              String.format("Table '%s.%s' does not exist", database, 
tableName)),
+          null);
+    }
+    TSStatus tsStatus =
+        clusterSchemaInfo.preAlterColumnDataType(database, tableName, 
columnName, dataType);
+    if (tsStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      return new Pair<>(tsStatus, null);
+    }
+
+    final TsTable alteredTable = new TsTable(originalTable);
+    alteredTable.getColumnSchema(columnName).setDataType(dataType);
+
+    return new Pair<>(RpcUtils.SUCCESS_STATUS, alteredTable);
+  }
+
   public synchronized Pair<TSStatus, TsTable> 
tableColumnCheckForColumnRenaming(
       final String database, final String tableName, final String oldName, 
final String newName)
       throws MetadataException {
@@ -1216,7 +1244,7 @@ public class ClusterSchemaManager {
           null);
     }
 
-    final TsTable expandedTable = 
TsTable.deserialize(ByteBuffer.wrap(originalTable.serialize()));
+    final TsTable expandedTable = new TsTable(originalTable);
 
     final TsTableColumnSchema schema = originalTable.getColumnSchema(oldName);
     if (Objects.isNull(schema)) {
@@ -1318,7 +1346,7 @@ public class ClusterSchemaManager {
       return new Pair<>(RpcUtils.SUCCESS_STATUS, null);
     }
 
-    final TsTable updatedTable = 
TsTable.deserialize(ByteBuffer.wrap(originalTable.serialize()));
+    final TsTable updatedTable = new TsTable(originalTable);
     updatedProperties.forEach(
         (k, v) -> {
           originalProperties.put(k, 
originalTable.getPropValue(k).orElse(null));
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index 712d8e3bf4c..cb912794343 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -119,6 +119,7 @@ import 
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.Cr
 import 
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.DropTopicPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.subscription.topic.runtime.TopicHandleMetaChangePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.AddTableColumnPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.AlterColumnDataTypePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitCreateTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteColumnPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteTablePlan;
@@ -541,6 +542,9 @@ public class ConfigPlanExecutor {
         return clusterSchemaInfo.preDeleteTable((PreDeleteTablePlan) 
physicalPlan);
       case CommitDeleteTable:
         return clusterSchemaInfo.dropTable((CommitDeleteTablePlan) 
physicalPlan);
+      case AlterColumnDataType:
+        return clusterSchemaInfo.commitAlterColumnDataType(
+            ((AlterColumnDataTypePlan) physicalPlan));
       case CreatePipeV2:
         return pipeInfo.createPipe((CreatePipePlanV2) physicalPlan);
       case SetPipeStatusV2:
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 069c5d99400..8c03e76a2d1 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
@@ -49,6 +49,7 @@ import 
org.apache.iotdb.confignode.consensus.request.write.database.SetDataRepli
 import 
org.apache.iotdb.confignode.consensus.request.write.database.SetSchemaReplicationFactorPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.database.SetTimePartitionIntervalPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.AddTableColumnPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.AlterColumnDataTypePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitCreateTablePlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteColumnPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.table.CommitDeleteTablePlan;
@@ -77,6 +78,7 @@ import 
org.apache.iotdb.confignode.consensus.response.template.AllTemplateSetInf
 import 
org.apache.iotdb.confignode.consensus.response.template.TemplateInfoResp;
 import 
org.apache.iotdb.confignode.consensus.response.template.TemplateSetInfoResp;
 import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
+import 
org.apache.iotdb.confignode.persistence.schema.ConfigMTree.TableSchemaDetails;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.confignode.rpc.thrift.TTableInfo;
 import org.apache.iotdb.db.exception.metadata.SchemaQuotaExceededException;
@@ -87,6 +89,7 @@ import 
org.apache.iotdb.db.schemaengine.template.alter.TemplateExtendInfo;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -1226,16 +1229,19 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
     try {
       final PartialPath databasePath = 
getQualifiedDatabasePartialPath(plan.getDatabase());
       if (plan.isDetails()) {
-        final Pair<TsTable, Set<String>> pair =
+        final TableSchemaDetails details =
             tableModelMTree.getTableSchemaDetails(databasePath, 
plan.getTableName());
-        return new DescTableResp(StatusUtils.OK, pair.getLeft(), 
pair.getRight());
+        return new DescTableResp(
+            StatusUtils.OK, details.table, details.preDeletedColumns, 
details.preAlteredColumns);
       }
       return new DescTableResp(
           StatusUtils.OK,
           tableModelMTree.getUsingTableSchema(databasePath, 
plan.getTableName()),
+          null,
           null);
     } catch (final MetadataException e) {
-      return new DescTableResp(RpcUtils.getStatus(e.getErrorCode(), 
e.getMessage()), null, null);
+      return new DescTableResp(
+          RpcUtils.getStatus(e.getErrorCode(), e.getMessage()), null, null, 
null);
     } finally {
       databaseReadWriteLock.readLock().unlock();
     }
@@ -1363,6 +1369,41 @@ public class ClusterSchemaInfo implements 
SnapshotProcessor {
     }
   }
 
+  public TSStatus preAlterColumnDataType(
+      String databaseName, String tableName, String columnName, TSDataType 
dataType) {
+    databaseReadWriteLock.writeLock().lock();
+    try {
+      final TSStatus status = new 
TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
+      tableModelMTree.preAlterColumnDataType(
+          getQualifiedDatabasePartialPath(databaseName), tableName, 
columnName, dataType);
+      return status;
+    } catch (final MetadataException e) {
+      LOGGER.warn(e.getMessage(), e);
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
+    } catch (final SemanticException e) {
+      return RpcUtils.getStatus(TSStatusCode.SEMANTIC_ERROR.getStatusCode(), 
e.getMessage());
+    } finally {
+      databaseReadWriteLock.writeLock().unlock();
+    }
+  }
+
+  public TSStatus commitAlterColumnDataType(AlterColumnDataTypePlan plan) {
+    databaseReadWriteLock.writeLock().lock();
+    try {
+      tableModelMTree.commitAlterColumnDataType(
+          getQualifiedDatabasePartialPath(plan.getDatabase()),
+          plan.getTableName(),
+          plan.getColumnName(),
+          plan.getNewType());
+      return RpcUtils.SUCCESS_STATUS;
+    } catch (final MetadataException e) {
+      LOGGER.warn(e.getMessage(), e);
+      return RpcUtils.getStatus(e.getErrorCode(), e.getMessage());
+    } finally {
+      databaseReadWriteLock.writeLock().unlock();
+    }
+  }
+
   // endregion
 
   @TestOnly
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 bb6474258bd..5c6babfea32 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
@@ -53,7 +53,9 @@ import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.traverser.counter.Dat
 import org.apache.iotdb.db.schemaengine.schemaregion.utils.MetaFormatUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.Pair;
+import org.apache.tsfile.utils.ReadWriteForEncodingUtils;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,7 +63,6 @@ import org.slf4j.LoggerFactory;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.ByteBuffer;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -71,6 +72,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
@@ -850,7 +852,7 @@ public class ConfigMTree {
     }
     if (columnSchema.getColumnCategory() == TsTableColumnCategory.TAG
         || columnSchema.getColumnCategory() == TsTableColumnCategory.TIME) {
-      throw new SemanticException("Dropping id or time column is not 
supported.");
+      throw new SemanticException("Dropping tag or time column is not 
supported.");
     }
 
     node.addPreDeletedColumn(columnName);
@@ -868,21 +870,70 @@ public class ConfigMTree {
     }
   }
 
+  public void preAlterColumnDataType(
+      PartialPath database, String tableName, String columnName, TSDataType 
dataType)
+      throws MetadataException {
+    final ConfigTableNode node = getTableNode(database, tableName);
+    final TsTableColumnSchema columnSchema = 
node.getTable().getColumnSchema(columnName);
+    if (Objects.isNull(columnSchema)) {
+      throw new ColumnNotExistsException(
+          PathUtils.unQualifyDatabaseName(database.getFullPath()), tableName, 
columnName);
+    }
+    if (columnSchema.getColumnCategory() != TsTableColumnCategory.FIELD) {
+      throw new SemanticException("Can only alter datatype of FIELD columns");
+    }
+    if (!dataType.isCompatible(columnSchema.getDataType())) {
+      throw new SemanticException(
+          String.format(
+              "New type %s is not compatible with the existing one %s",
+              dataType, columnSchema.getDataType()));
+    }
+
+    node.addPreAlteredColumn(columnName, dataType);
+  }
+
+  public void commitAlterColumnDataType(
+      PartialPath database, String tableName, String columnName, TSDataType 
dataType)
+      throws MetadataException {
+    final ConfigTableNode node = getTableNode(database, tableName);
+    final TsTable table = getTable(database, tableName);
+    if (Objects.nonNull(table.getColumnSchema(columnName))) {
+      table.getColumnSchema(columnName).setDataType(dataType);
+      node.removePreAlteredColumn(columnName);
+    }
+  }
+
   public TsTable getUsingTableSchema(final PartialPath database, final String 
tableName)
       throws MetadataException {
     final ConfigTableNode node = getTableNode(database, tableName);
-    if (node.getPreDeletedColumns().isEmpty()) {
+    if (node.getPreDeletedColumns().isEmpty() && 
node.getPreAlteredColumns().isEmpty()) {
       return node.getTable();
     }
-    final TsTable newTable = 
TsTable.deserialize(ByteBuffer.wrap(node.getTable().serialize()));
-    node.getPreDeletedColumns().forEach(newTable::removeColumnSchema);
+    final TsTable newTable = new TsTable(node.getTable());
+    if (!node.getPreDeletedColumns().isEmpty()) {
+      node.getPreDeletedColumns().forEach(newTable::removeColumnSchema);
+    }
+    if (!node.getPreAlteredColumns().isEmpty()) {
+      node.getPreAlteredColumns()
+          .forEach((col, type) -> 
newTable.getColumnSchema(col).setDataType(type));
+    }
     return newTable;
   }
 
-  public Pair<TsTable, Set<String>> getTableSchemaDetails(
+  public TableSchemaDetails getTableSchemaDetails(
       final PartialPath database, final String tableName) throws 
MetadataException {
     final ConfigTableNode node = getTableNode(database, tableName);
-    return new Pair<>(node.getTable(), node.getPreDeletedColumns());
+    TableSchemaDetails tableSchemaDetails = new TableSchemaDetails();
+    tableSchemaDetails.table = node.getTable();
+    tableSchemaDetails.preDeletedColumns = node.getPreDeletedColumns();
+    tableSchemaDetails.preAlteredColumns = node.getPreAlteredColumns();
+    return tableSchemaDetails;
+  }
+
+  public static class TableSchemaDetails {
+    public TsTable table;
+    public Set<String> preDeletedColumns;
+    public Map<String, TSDataType> preAlteredColumns;
   }
 
   private TsTable getTable(final PartialPath database, final String tableName)
@@ -964,6 +1015,11 @@ public class ConfigMTree {
     for (final String column : preDeletedColumns) {
       ReadWriteIOUtils.write(column, outputStream);
     }
+    
ReadWriteForEncodingUtils.writeVarInt(tableNode.getPreAlteredColumns().size(), 
outputStream);
+    for (Entry<String, TSDataType> entry : 
tableNode.getPreAlteredColumns().entrySet()) {
+      ReadWriteIOUtils.writeVar(entry.getKey(), outputStream);
+      ReadWriteIOUtils.write(entry.getValue(), outputStream);
+    }
   }
 
   public void deserialize(final InputStream inputStream) throws IOException {
@@ -1057,10 +1113,17 @@ public class ConfigMTree {
         new ConfigTableNode(null, ReadWriteIOUtils.readString(inputStream));
     tableNode.setTable(TsTable.deserialize(inputStream));
     tableNode.setStatus(TableNodeStatus.deserialize(inputStream));
-    final int size = ReadWriteIOUtils.readInt(inputStream);
+    int size = ReadWriteIOUtils.readInt(inputStream);
     for (int i = 0; i < size; ++i) {
       tableNode.addPreDeletedColumn(ReadWriteIOUtils.readString(inputStream));
     }
+
+    size = ReadWriteForEncodingUtils.readVarInt(inputStream);
+    for (int i = 0; i < size; i++) {
+      tableNode.addPreAlteredColumn(
+          ReadWriteIOUtils.readVarIntString(inputStream),
+          ReadWriteIOUtils.readDataType(inputStream));
+    }
     return tableNode;
   }
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/impl/ConfigTableNode.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/impl/ConfigTableNode.java
index 0bb306e3f3f..b95b50ff0be 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/impl/ConfigTableNode.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/impl/ConfigTableNode.java
@@ -31,8 +31,11 @@ import 
org.apache.iotdb.confignode.persistence.schema.mnode.IConfigMNode;
 import 
org.apache.iotdb.confignode.persistence.schema.mnode.container.ConfigMNodeContainer;
 import 
org.apache.iotdb.confignode.persistence.schema.mnode.info.ConfigTableInfo;
 
+import org.apache.tsfile.enums.TSDataType;
+
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import static org.apache.iotdb.commons.schema.SchemaConstant.NON_TEMPLATE;
@@ -70,6 +73,10 @@ public class ConfigTableNode implements IConfigMNode {
     return tableNodeInfo.getPreDeletedColumns();
   }
 
+  public Map<String, TSDataType> getPreAlteredColumns() {
+    return tableNodeInfo.getPreAlteredColumns();
+  }
+
   public void addPreDeletedColumn(final String column) {
     tableNodeInfo.addPreDeletedColumn(column);
   }
@@ -78,6 +85,14 @@ public class ConfigTableNode implements IConfigMNode {
     tableNodeInfo.removePreDeletedColumn(column);
   }
 
+  public void addPreAlteredColumn(final String column, TSDataType dataType) {
+    tableNodeInfo.addPreAlteredColumn(column, dataType);
+  }
+
+  public void removePreAlteredColumn(final String column) {
+    tableNodeInfo.removePreAlteredColumn(column);
+  }
+
   @Override
   public String getName() {
     return tableNodeInfo.getName();
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/info/ConfigTableInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/info/ConfigTableInfo.java
index 5e0fdfba7fd..23b988101df 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/info/ConfigTableInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/mnode/info/ConfigTableInfo.java
@@ -23,9 +23,12 @@ import org.apache.iotdb.commons.schema.table.TableNodeStatus;
 import org.apache.iotdb.commons.schema.table.TsTable;
 import 
org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.info.BasicMNodeInfo;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.RamUsageEstimator;
 
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 public class ConfigTableInfo extends BasicMNodeInfo {
@@ -37,6 +40,7 @@ public class ConfigTableInfo extends BasicMNodeInfo {
 
   // This shall be only one because concurrent modifications of one table is 
not allowed
   private final Set<String> preDeletedColumns = new HashSet<>();
+  private final Map<String, TSDataType> preAlteredColumns = new HashMap<>();
 
   public ConfigTableInfo(final String name) {
     super(name);
@@ -62,6 +66,10 @@ public class ConfigTableInfo extends BasicMNodeInfo {
     return preDeletedColumns;
   }
 
+  public Map<String, TSDataType> getPreAlteredColumns() {
+    return preAlteredColumns;
+  }
+
   public void addPreDeletedColumn(final String column) {
     preDeletedColumns.add(column);
   }
@@ -81,4 +89,12 @@ public class ConfigTableInfo extends BasicMNodeInfo {
             .map(column -> (int) RamUsageEstimator.sizeOf(column))
             .reduce(0, Integer::sum);
   }
+
+  public void addPreAlteredColumn(String column, TSDataType dataType) {
+    preAlteredColumns.put(column, dataType);
+  }
+
+  public void removePreAlteredColumn(String column) {
+    preAlteredColumns.remove(column);
+  }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AlterTableColumnDataTypeProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AlterTableColumnDataTypeProcedure.java
new file mode 100644
index 00000000000..24ab17f8266
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AlterTableColumnDataTypeProcedure.java
@@ -0,0 +1,210 @@
+/*
+ * 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.confignode.procedure.impl.schema.table;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.exception.IoTDBException;
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.AlterColumnDataTypePlan;
+import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureException;
+import 
org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureYieldException;
+import org.apache.iotdb.confignode.procedure.impl.schema.SchemaUtils;
+import 
org.apache.iotdb.confignode.procedure.state.schema.AlterTableColumnDataTypeState;
+import org.apache.iotdb.confignode.procedure.store.ProcedureType;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.utils.Pair;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+public class AlterTableColumnDataTypeProcedure
+    extends AbstractAlterOrDropTableProcedure<AlterTableColumnDataTypeState> {
+  private static final Logger LOGGER =
+      LoggerFactory.getLogger(AlterTableColumnDataTypeProcedure.class);
+
+  private String columnName;
+  private TSDataType dataType;
+
+  public AlterTableColumnDataTypeProcedure() {
+    super();
+  }
+
+  public AlterTableColumnDataTypeProcedure(
+      final String database,
+      final String tableName,
+      final String queryId,
+      final String columnName,
+      final TSDataType dataType) {
+    super(database, tableName, queryId);
+    this.columnName = columnName;
+    this.dataType = dataType;
+  }
+
+  @Override
+  protected String getActionMessage() {
+    return "Alter table column data type";
+  }
+
+  @Override
+  protected Flow executeFromState(
+      final ConfigNodeProcedureEnv env, final AlterTableColumnDataTypeState 
state)
+      throws ProcedureSuspendedException, ProcedureYieldException, 
InterruptedException {
+    final long startTime = System.currentTimeMillis();
+    try {
+      switch (state) {
+        case CHECK_AND_INVALIDATE_COLUMN:
+          LOGGER.info(
+              "Check and invalidate column {} in {}.{} when altering column 
data type",
+              columnName,
+              database,
+              tableName);
+          checkAndPreAlterColumn(env);
+          break;
+        case PRE_RELEASE:
+          LOGGER.info("Pre-release info of table {}.{} when altering column", 
database, tableName);
+          preRelease(env);
+          break;
+        case ALTER_TABLE_COLUMN_DATA_TYPE:
+          LOGGER.info("Altering column {} in {}.{} on configNode", columnName, 
database, tableName);
+          alterColumnDataType(env);
+          break;
+        case COMMIT_RELEASE:
+          LOGGER.info(
+              "Commit release info of table {}.{} when altering column", 
database, tableName);
+          commitRelease(env);
+          return Flow.NO_MORE_STATE;
+        default:
+          setFailure(
+              new ProcedureException("Unrecognized 
AlterTableColumnDataTypeProcedure " + state));
+          return Flow.NO_MORE_STATE;
+      }
+      return Flow.HAS_MORE_STATE;
+    } finally {
+      LOGGER.info(
+          "AlterTableColumnDataType-{}.{}-{} costs {}ms",
+          database,
+          tableName,
+          state,
+          (System.currentTimeMillis() - startTime));
+    }
+  }
+
+  @Override
+  protected void preRelease(ConfigNodeProcedureEnv env) {
+    super.preRelease(env);
+    setNextState(AlterTableColumnDataTypeState.ALTER_TABLE_COLUMN_DATA_TYPE);
+  }
+
+  private void checkAndPreAlterColumn(final ConfigNodeProcedureEnv env) {
+    try {
+      final Pair<TSStatus, TsTable> result =
+          env.getConfigManager()
+              .getClusterSchemaManager()
+              .tableColumnCheckForColumnAltering(database, tableName, 
columnName, dataType);
+      final TSStatus status = result.getLeft();
+      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        setFailure(
+            new ProcedureException(new IoTDBException(status.getMessage(), 
status.getCode())));
+        return;
+      }
+      table = result.getRight();
+      setNextState(AlterTableColumnDataTypeState.PRE_RELEASE);
+    } catch (final MetadataException e) {
+      setFailure(new ProcedureException(e));
+    }
+  }
+
+  private void alterColumnDataType(final ConfigNodeProcedureEnv env) {
+    final TSStatus status =
+        SchemaUtils.executeInConsensusLayer(
+            new AlterColumnDataTypePlan(database, tableName, columnName, 
dataType), env, LOGGER);
+    if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      setFailure(new ProcedureException(new 
IoTDBException(status.getMessage(), status.getCode())));
+    }
+    setNextState(AlterTableColumnDataTypeState.COMMIT_RELEASE);
+  }
+
+  @Override
+  protected boolean isRollbackSupported(final AlterTableColumnDataTypeState 
state) {
+    return false;
+  }
+
+  @Override
+  protected void rollbackState(
+      final ConfigNodeProcedureEnv configNodeProcedureEnv,
+      final AlterTableColumnDataTypeState alterTableColumnDataTypeState)
+      throws IOException, InterruptedException, ProcedureException {
+    // Do nothing
+  }
+
+  @Override
+  protected AlterTableColumnDataTypeState getState(final int stateId) {
+    return AlterTableColumnDataTypeState.values()[stateId];
+  }
+
+  @Override
+  protected int getStateId(final AlterTableColumnDataTypeState 
alterTableColumnDataTypeState) {
+    return alterTableColumnDataTypeState.ordinal();
+  }
+
+  @Override
+  protected AlterTableColumnDataTypeState getInitialState() {
+    return AlterTableColumnDataTypeState.CHECK_AND_INVALIDATE_COLUMN;
+  }
+
+  @Override
+  public void serialize(final DataOutputStream stream) throws IOException {
+    
stream.writeShort(ProcedureType.ALTER_TABLE_COLUMN_DATATYPE_PROCEDURE.getTypeCode());
+    super.serialize(stream);
+
+    ReadWriteIOUtils.write(columnName, stream);
+    ReadWriteIOUtils.write(dataType, stream);
+  }
+
+  @Override
+  public void deserialize(final ByteBuffer byteBuffer) {
+    super.deserialize(byteBuffer);
+
+    this.columnName = ReadWriteIOUtils.readString(byteBuffer);
+    this.dataType = ReadWriteIOUtils.readDataType(byteBuffer);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    return super.equals(o)
+        && Objects.equals(columnName, ((AlterTableColumnDataTypeProcedure) 
o).columnName)
+        && Objects.equals(dataType, ((AlterTableColumnDataTypeProcedure) 
o).dataType);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(super.hashCode(), columnName, dataType);
+  }
+}
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java
index 42523cd02a8..764ee61ee0f 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java
@@ -114,7 +114,7 @@ public class DropTableColumnProcedure
           dropColumn(env);
           return Flow.NO_MORE_STATE;
         default:
-          setFailure(new ProcedureException("Unrecognized CreateTableState " + 
state));
+          setFailure(new ProcedureException("Unrecognized DropTableColumnState 
" + state));
           return Flow.NO_MORE_STATE;
       }
       return Flow.HAS_MORE_STATE;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/AlterTableColumnDataTypeState.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/AlterTableColumnDataTypeState.java
new file mode 100644
index 00000000000..736e9fa4918
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/AlterTableColumnDataTypeState.java
@@ -0,0 +1,27 @@
+/*
+ * 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.confignode.procedure.state.schema;
+
+public enum AlterTableColumnDataTypeState {
+  CHECK_AND_INVALIDATE_COLUMN,
+  PRE_RELEASE,
+  ALTER_TABLE_COLUMN_DATA_TYPE,
+  COMMIT_RELEASE
+}
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
index 42ef4a1b806..3805db28be4 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureFactory.java
@@ -51,6 +51,7 @@ import 
org.apache.iotdb.confignode.procedure.impl.schema.SetTTLProcedure;
 import org.apache.iotdb.confignode.procedure.impl.schema.SetTemplateProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.UnsetTemplateProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.AddTableColumnProcedure;
+import 
org.apache.iotdb.confignode.procedure.impl.schema.table.AlterTableColumnDataTypeProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.CreateTableProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.DeleteDevicesProcedure;
 import 
org.apache.iotdb.confignode.procedure.impl.schema.table.DropTableColumnProcedure;
@@ -207,6 +208,9 @@ public class ProcedureFactory implements IProcedureFactory {
       case DROP_TABLE_COLUMN_PROCEDURE:
         procedure = new DropTableColumnProcedure();
         break;
+      case ALTER_TABLE_COLUMN_DATATYPE_PROCEDURE:
+        procedure = new AlterTableColumnDataTypeProcedure();
+        break;
       case DROP_TABLE_PROCEDURE:
         procedure = new DropTableProcedure();
         break;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java
index 9928a214b75..3135fd30561 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/store/ProcedureType.java
@@ -70,6 +70,7 @@ public enum ProcedureType {
   RENAME_TABLE_COLUMN_PROCEDURE((short) 754),
   DROP_TABLE_COLUMN_PROCEDURE((short) 755),
   DELETE_DEVICES_PROCEDURE((short) 756),
+  ALTER_TABLE_COLUMN_DATATYPE_PROCEDURE((short) 757),
 
   /** AI Model */
   CREATE_MODEL_PROCEDURE((short) 800),
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
index 4bd5f675c32..cfdcdd2ec77 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
@@ -164,6 +164,7 @@ import org.apache.iotdb.db.service.DataNode;
 import org.apache.iotdb.db.service.RegionMigrateService;
 import org.apache.iotdb.db.service.metrics.FileMetrics;
 import org.apache.iotdb.db.storageengine.StorageEngine;
+import org.apache.iotdb.db.storageengine.dataregion.DataRegion;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.repair.RepairTaskStatus;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.schedule.CompactionScheduleTaskManager;
 import 
org.apache.iotdb.db.storageengine.dataregion.compaction.schedule.CompactionTaskManager;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
index 9151ca14cba..fb0980fff19 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
@@ -58,6 +58,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.Pla
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import 
org.apache.iotdb.db.queryengine.plan.relational.security.AllowAllAccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterColumnDataType;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ClearCache;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
@@ -390,6 +391,7 @@ public class Coordinator {
         || statement instanceof DescribeTable
         || statement instanceof ShowTables
         || statement instanceof AddColumn
+        || statement instanceof AlterColumnDataType
         || statement instanceof SetProperties
         || statement instanceof DropColumn
         || statement instanceof DropTable
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index 8abe782d5fd..acd70459748 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -42,6 +42,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowFuncti
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowPipePluginsTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowRegionTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.ShowVariablesTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterColumnDataTypeTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterDBTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterTableAddColumnTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterTableDropColumnTask;
@@ -87,6 +88,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableHeaderSchemaValidator;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterColumnDataType;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
@@ -404,6 +406,25 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
     return new CreateTableTask(table, databaseTablePair.getLeft(), 
node.isIfNotExists());
   }
 
+  @Override
+  protected IConfigTask visitAlterColumnDataType(
+      AlterColumnDataType node, MPPQueryContext context) {
+    context.setQueryType(QueryType.WRITE);
+    final Pair<String, String> databaseTablePair = 
splitQualifiedName(node.getTableName(), true);
+    final String columnName = node.getColumnName().getValue();
+    final DataType dataType = node.getDataType();
+    final boolean ifTableExists = node.isIfTableExists();
+    final boolean ifColumnExists = node.isIfColumnExists();
+    return new AlterColumnDataTypeTask(
+        databaseTablePair.getLeft(),
+        databaseTablePair.getRight(),
+        context.getQueryId().getId(),
+        ifTableExists,
+        ifColumnExists,
+        columnName,
+        getDataType(dataType));
+  }
+
   private boolean checkTimeColumnIdempotent(
       final TsTableColumnCategory category, final String columnName, final 
TSDataType dataType) {
     if (category == TsTableColumnCategory.TIME || 
columnName.equals(TsTable.TIME_COLUMN_NAME)) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index 4a14c71a3d3..42f99f63407 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -286,6 +286,7 @@ import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransportException;
 import org.apache.tsfile.common.conf.TSFileDescriptor;
 import org.apache.tsfile.common.constant.TsFileConstant;
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -3262,7 +3263,8 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
       }
       final TsTable table = 
TsTableInternalRPCUtil.deserializeSingleTsTable(resp.getTableInfo());
       if (isDetails) {
-        DescribeTableDetailsTask.buildTsBlock(table, 
resp.getPreDeletedColumns(), future);
+        DescribeTableDetailsTask.buildTsBlock(
+            table, resp.getPreDeletedColumns(), resp.preAlteredColumns, 
future);
       } else {
         DescribeTableTask.buildTsBlock(table, future);
       }
@@ -3393,6 +3395,43 @@ public class ClusterConfigTaskExecutor implements 
IConfigTaskExecutor {
     return future;
   }
 
+  @Override
+  public SettableFuture<ConfigTaskResult> alterColumnDataType(
+      String database,
+      String tableName,
+      String columnName,
+      TSDataType newType,
+      String queryId,
+      boolean ifTableExists,
+      boolean ifColumnExists) {
+    final SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    try (final ConfigNodeClient client =
+        
CLUSTER_DELETION_CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID))
 {
+
+      final TSStatus tsStatus =
+          sendAlterReq2ConfigNode(
+              database,
+              tableName,
+              queryId,
+              AlterOrDropTableOperationType.ALTER_COLUMN_DATA_TYPE,
+              TsTableColumnSchemaUtil.serialize(columnName, newType),
+              client);
+
+      if (TSStatusCode.SUCCESS_STATUS.getStatusCode() == tsStatus.getCode()
+          || (TSStatusCode.TABLE_NOT_EXISTS.getStatusCode() == 
tsStatus.getCode() && ifTableExists)
+          || (TSStatusCode.COLUMN_NOT_EXISTS.getStatusCode() == 
tsStatus.getCode()
+              && ifColumnExists)) {
+        future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS));
+      } else {
+        future.setException(
+            new IoTDBException(getTableErrorMessage(tsStatus, database), 
tsStatus.getCode()));
+      }
+    } catch (final ClientManagerException | TException e) {
+      future.setException(e);
+    }
+    return future;
+  }
+
   @Override
   public SettableFuture<ConfigTaskResult> alterTableRenameColumn(
       final String database,
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
index 179d2455037..3ab2dd11df4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -91,6 +91,7 @@ import org.apache.iotdb.service.rpc.thrift.TPipeTransferReq;
 import org.apache.iotdb.service.rpc.thrift.TPipeTransferResp;
 
 import com.google.common.util.concurrent.SettableFuture;
+import org.apache.tsfile.enums.TSDataType;
 
 import javax.annotation.Nullable;
 
@@ -323,6 +324,15 @@ public interface IConfigTaskExecutor {
       final boolean tableIfExists,
       final boolean columnIfExists);
 
+  SettableFuture<ConfigTaskResult> alterColumnDataType(
+      final String database,
+      final String tableName,
+      final String columnName,
+      final TSDataType newType,
+      final String queryId,
+      final boolean tableIfExists,
+      boolean ifColumnExists);
+
   SettableFuture<ConfigTaskResult> alterTableRenameColumn(
       final String database,
       final String tableName,
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AlterColumnDataTypeTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AlterColumnDataTypeTask.java
new file mode 100644
index 00000000000..fc769020f07
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/AlterColumnDataTypeTask.java
@@ -0,0 +1,53 @@
+/*
+ * 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.db.queryengine.plan.execution.config.metadata.relational;
+
+import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.IConfigTaskExecutor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.apache.tsfile.enums.TSDataType;
+
+public class AlterColumnDataTypeTask extends AbstractAlterOrDropTableTask {
+  private final String columnName;
+  private final TSDataType newType;
+  private final boolean ifColumnExists;
+
+  public AlterColumnDataTypeTask(
+      String database,
+      String tableName,
+      String queryId,
+      boolean tableIfExists,
+      boolean ifColumnExists,
+      String columnName,
+      TSDataType newType) {
+    super(database, tableName, queryId, tableIfExists);
+    this.columnName = columnName;
+    this.newType = newType;
+    this.ifColumnExists = ifColumnExists;
+  }
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(IConfigTaskExecutor 
configTaskExecutor)
+      throws InterruptedException {
+    return configTaskExecutor.alterColumnDataType(
+        database, tableName, columnName, newType, queryId, tableIfExists, 
ifColumnExists);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/DescribeTableDetailsTask.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/DescribeTableDetailsTask.java
index ad6220ffc1a..c2cfe8ce310 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/DescribeTableDetailsTask.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/metadata/relational/DescribeTableDetailsTask.java
@@ -37,6 +37,7 @@ import org.apache.tsfile.read.common.block.TsBlockBuilder;
 import org.apache.tsfile.utils.Binary;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -54,6 +55,7 @@ public class DescribeTableDetailsTask extends 
AbstractTableTask {
   public static void buildTsBlock(
       final TsTable table,
       final Set<String> preDeletedColumns,
+      final Map<String, Byte> preAlteredColumns,
       final SettableFuture<ConfigTaskResult> future) {
     final List<TSDataType> outputDataTypes =
         ColumnHeaderConstant.describeTableDetailsColumnHeaders.stream()
@@ -63,22 +65,27 @@ public class DescribeTableDetailsTask extends 
AbstractTableTask {
     final TsBlockBuilder builder = new TsBlockBuilder(outputDataTypes);
     for (final TsTableColumnSchema columnSchema : table.getColumnList()) {
       builder.getTimeColumnBuilder().writeLong(0L);
+      String columnStatus = "USING";
+      String dataTypeName = columnSchema.getDataType().name();
+      if (preDeletedColumns.contains(columnSchema.getColumnName())) {
+        columnStatus = "PRE_DELETE";
+      } else if (preAlteredColumns.containsKey(columnSchema.getColumnName())) {
+        columnStatus = "PRE_ALTER";
+        dataTypeName += "->" + 
preAlteredColumns.get(columnSchema.getColumnName());
+      }
       builder
           .getColumnBuilder(0)
           .writeBinary(new Binary(columnSchema.getColumnName(), 
TSFileConfig.STRING_CHARSET));
       builder
           .getColumnBuilder(1)
-          .writeBinary(new Binary(columnSchema.getDataType().name(), 
TSFileConfig.STRING_CHARSET));
+          .writeBinary(new Binary(dataTypeName, TSFileConfig.STRING_CHARSET));
       builder
           .getColumnBuilder(2)
           .writeBinary(
               new Binary(columnSchema.getColumnCategory().name(), 
TSFileConfig.STRING_CHARSET));
       builder
           .getColumnBuilder(3)
-          .writeBinary(
-              new Binary(
-                  preDeletedColumns.contains(columnSchema.getColumnName()) ? 
"PRE_DELETE" : "USING",
-                  TSFileConfig.STRING_CHARSET));
+          .writeBinary(new Binary(columnStatus, TSFileConfig.STRING_CHARSET));
       builder.declarePosition();
     }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AlterColumnDataType.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AlterColumnDataType.java
new file mode 100644
index 00000000000..a427d2342ba
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AlterColumnDataType.java
@@ -0,0 +1,91 @@
+package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
+
+import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+public class AlterColumnDataType extends Statement {
+  private final QualifiedName tableName;
+  private final Identifier columnName;
+  private final DataType dataType;
+  private final boolean ifTableExists;
+  private final boolean ifColumnExists;
+
+  public AlterColumnDataType(
+      @Nullable NodeLocation location,
+      QualifiedName tableName,
+      Identifier columnName,
+      DataType dataType,
+      boolean ifTableExists,
+      boolean ifColumnExists) {
+    super(location);
+    this.tableName = tableName;
+    this.columnName = columnName;
+    this.dataType = dataType;
+    this.ifTableExists = ifTableExists;
+    this.ifColumnExists = ifColumnExists;
+  }
+
+  @Override
+  public List<? extends Node> getChildren() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    AlterColumnDataType that = (AlterColumnDataType) o;
+    return Objects.equals(tableName, that.tableName)
+        && Objects.equals(columnName, that.columnName)
+        && Objects.equals(dataType, that.dataType);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(tableName, columnName, dataType);
+  }
+
+  @Override
+  public String toString() {
+    return "AlterColumnDataType{"
+        + "tableName="
+        + tableName
+        + ", columnName="
+        + columnName
+        + ", dataType="
+        + dataType
+        + '}';
+  }
+
+  @Override
+  public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
+    return visitor.visitAlterColumnDataType(this, context);
+  }
+
+  public QualifiedName getTableName() {
+    return tableName;
+  }
+
+  public Identifier getColumnName() {
+    return columnName;
+  }
+
+  public DataType getDataType() {
+    return dataType;
+  }
+
+  public boolean isIfTableExists() {
+    return ifTableExists;
+  }
+
+  public boolean isIfColumnExists() {
+    return ifColumnExists;
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
index 43bc9223b11..80cad24934f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java
@@ -616,4 +616,8 @@ public abstract class AstVisitor<R, C> {
   protected R visitKillQuery(KillQuery node, C context) {
     return visitStatement(node, context);
   }
+
+  protected R visitAlterColumnDataType(AlterColumnDataType node, C context) {
+    return visitStatement(node, context);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index d3b38af0f58..9e0db8fc2be 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AddColumn;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AliasedRelation;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AllColumns;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AllRows;
+import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterColumnDataType;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterDB;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AlterPipe;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ArithmeticBinaryExpression;
@@ -184,6 +185,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.sys.SetConfigurationStatem
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlBaseVisitor;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlLexer;
 import org.apache.iotdb.db.relational.grammar.sql.RelationalSqlParser;
+import 
org.apache.iotdb.db.relational.grammar.sql.RelationalSqlParser.AlterColumnDataTypeContext;
 import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 import org.apache.iotdb.db.storageengine.load.config.LoadTsFileConfigurator;
 import org.apache.iotdb.db.utils.DateTimeUtils;
@@ -443,6 +445,25 @@ public class AstBuilder extends 
RelationalSqlBaseVisitor<Node> {
         Objects.nonNull(ctx.EXISTS()));
   }
 
+  @Override
+  public Node visitAlterColumnDataType(AlterColumnDataTypeContext ctx) {
+    QualifiedName tableName = getQualifiedName(ctx.tableName);
+    Identifier columnName = lowerIdentifier((Identifier) 
visit(ctx.identifier()));
+    DataType dataType = (DataType) visit(ctx.new_type);
+    boolean ifTableExists =
+        ctx.EXISTS().stream()
+            .anyMatch(
+                node ->
+                    node.getSymbol().getTokenIndex() < 
ctx.COLUMN().getSymbol().getTokenIndex());
+    boolean ifColumnExists =
+        ctx.EXISTS().stream()
+            .anyMatch(
+                node ->
+                    node.getSymbol().getTokenIndex() > 
ctx.COLUMN().getSymbol().getTokenIndex());
+    return new AlterColumnDataType(
+        getLocation(ctx), tableName, columnName, dataType, ifTableExists, 
ifColumnExists);
+  }
+
   @Override
   public Node 
visitCreateIndexStatement(RelationalSqlParser.CreateIndexStatementContext ctx) {
     return new CreateIndex(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
index 2efc10e0851..794ece53842 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
@@ -1883,7 +1883,7 @@ public class DataRegion implements IDataRegionForQuery {
   }
 
   /** close all working tsfile processors */
-  private List<Future<?>> asyncCloseAllWorkingTsFileProcessors() {
+  public List<Future<?>> asyncCloseAllWorkingTsFileProcessors() {
     writeLock("asyncCloseAllWorkingTsFileProcessors");
     List<Future<?>> futures = new ArrayList<>();
     int count = 0;
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/AlterOrDropTableOperationType.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/AlterOrDropTableOperationType.java
index bdae8196a5d..b22575f5c46 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/AlterOrDropTableOperationType.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/AlterOrDropTableOperationType.java
@@ -25,7 +25,9 @@ public enum AlterOrDropTableOperationType {
   RENAME_COLUMN((byte) 2),
   DROP_COLUMN((byte) 3),
   RENAME_TABLE((byte) 4),
-  DROP_TABLE((byte) 5);
+  DROP_TABLE((byte) 5),
+  ALTER_COLUMN_DATA_TYPE((byte) 6),
+  ;
 
   private final byte type;
 
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
index 905620f4613..e37ee361da0 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TsTable.java
@@ -33,7 +33,6 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
 
 import javax.annotation.concurrent.ThreadSafe;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -87,6 +86,16 @@ public class TsTable {
         columnSchema -> columnSchemaMap.put(columnSchema.getColumnName(), 
columnSchema));
   }
 
+  public TsTable(TsTable origin) {
+    this.tableName = origin.tableName;
+    origin.columnSchemaMap.forEach((col, schema) -> 
this.columnSchemaMap.put(col, schema.copy()));
+    this.idColumnIndexMap.putAll(origin.idColumnIndexMap);
+    this.props = origin.props == null ? null : new HashMap<>(origin.props);
+    this.ttlValue = origin.ttlValue;
+    this.idNums = origin.idNums;
+    this.measurementNum = origin.measurementNum;
+  }
+
   public String getTableName() {
     return tableName;
   }
@@ -263,16 +272,6 @@ public class TsTable {
     }
   }
 
-  public byte[] serialize() {
-    ByteArrayOutputStream stream = new ByteArrayOutputStream();
-    try {
-      serialize(stream);
-    } catch (IOException ignored) {
-      // won't happen
-    }
-    return stream.toByteArray();
-  }
-
   public void serialize(final OutputStream stream) throws IOException {
     ReadWriteIOUtils.write(tableName, stream);
     ReadWriteIOUtils.write(columnSchemaMap.size(), stream);
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/AttributeColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/AttributeColumnSchema.java
index 8a3f21930d2..513aecdf61c 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/AttributeColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/AttributeColumnSchema.java
@@ -25,6 +25,7 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
 import java.util.Map;
 
 public class AttributeColumnSchema extends TsTableColumnSchema {
@@ -55,4 +56,10 @@ public class AttributeColumnSchema extends 
TsTableColumnSchema {
     final Map<String, String> props = ReadWriteIOUtils.readMap(buffer);
     return new AttributeColumnSchema(columnName, dataType, props);
   }
+
+  @Override
+  public TsTableColumnSchema copy() {
+    return new AttributeColumnSchema(
+        columnName, dataType, props == null ? null : new HashMap<>(props));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/FieldColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/FieldColumnSchema.java
index c2728fb47e8..4cb78ab41ce 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/FieldColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/FieldColumnSchema.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
 import java.util.Map;
 
 public class FieldColumnSchema extends TsTableColumnSchema {
@@ -109,4 +110,10 @@ public class FieldColumnSchema extends TsTableColumnSchema 
{
     final Map<String, String> props = ReadWriteIOUtils.readMap(buffer);
     return new FieldColumnSchema(columnName, dataType, encoding, compressor, 
props);
   }
+
+  @Override
+  public TsTableColumnSchema copy() {
+    return new FieldColumnSchema(
+        columnName, dataType, encoding, compressor, props == null ? null : new 
HashMap<>(props));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TagColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TagColumnSchema.java
index 83c7bde36b1..8ba20a146f9 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TagColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TagColumnSchema.java
@@ -25,6 +25,7 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
 import java.util.Map;
 
 public class TagColumnSchema extends TsTableColumnSchema {
@@ -55,4 +56,9 @@ public class TagColumnSchema extends TsTableColumnSchema {
     Map<String, String> props = ReadWriteIOUtils.readMap(buffer);
     return new TagColumnSchema(columnName, dataType, props);
   }
+
+  @Override
+  public TsTableColumnSchema copy() {
+    return new TagColumnSchema(columnName, dataType, props == null ? null : 
new HashMap<>(props));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TimeColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TimeColumnSchema.java
index 4349d3e134a..597cf51b53c 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TimeColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TimeColumnSchema.java
@@ -25,6 +25,7 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
 import java.util.Map;
 
 public class TimeColumnSchema extends TsTableColumnSchema {
@@ -55,4 +56,9 @@ public class TimeColumnSchema extends TsTableColumnSchema {
     final Map<String, String> props = ReadWriteIOUtils.readMap(buffer);
     return new TimeColumnSchema(columnName, dataType, props);
   }
+
+  @Override
+  public TsTableColumnSchema copy() {
+    return new TimeColumnSchema(columnName, dataType, props == null ? null : 
new HashMap<>(props));
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
index 2bbb1562fe8..9ad6114aea9 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
@@ -76,4 +76,6 @@ public abstract class TsTableColumnSchema {
   public void setDataType(final TSDataType dataType) {
     this.dataType = dataType;
   }
+
+  public abstract TsTableColumnSchema copy();
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchemaUtil.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchemaUtil.java
index 2c2f2340fde..ab6bbe2ac8a 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchemaUtil.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchemaUtil.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.commons.schema.table.column;
 
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.utils.ReadWriteIOUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -103,6 +104,17 @@ public class TsTableColumnSchemaUtil {
     }
   }
 
+  public static byte[] serialize(String columnName, TSDataType dataType) {
+    ByteArrayOutputStream stream = new ByteArrayOutputStream();
+    try {
+      ReadWriteIOUtils.writeVar(columnName, stream);
+      stream.write(dataType.serialize());
+    } catch (IOException ignored) {
+
+    }
+    return stream.toByteArray();
+  }
+
   public static List<TsTableColumnSchema> 
deserializeColumnSchemaList(ByteBuffer buffer) {
     int size = ReadWriteIOUtils.readInt(buffer);
     if (size == -1) {
diff --git 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index fa599b9178f..794dff013a2 100644
--- 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -197,6 +197,7 @@ alterTableStatement
     | ALTER TABLE (IF EXISTS)? tableName=qualifiedName DROP COLUMN (IF 
EXISTS)? column=identifier                     #dropColumn
     // set TTL can use this
     | ALTER TABLE (IF EXISTS)? tableName=qualifiedName SET PROPERTIES 
propertyAssignments                #setTableProperties
+    | ALTER TABLE (IF EXISTS)? tableName=qualifiedName ALTER COLUMN 
column=identifier (IF EXISTS)? SET DATA TYPE new_type=type #alterColumnDataType
     ;
 
 
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift 
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index f2e6c140091..cbca5db7c4a 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -1075,6 +1075,7 @@ struct TDescTableResp {
    1: required common.TSStatus status
    2: optional binary tableInfo
    3: optional set<string> preDeletedColumns
+   4: optional map<string, byte> preAlteredColumns
 }
 
 struct TFetchTableResp {
diff --git a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift 
b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
index cfdd634a92f..e02505d51a7 100644
--- a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
+++ b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift
@@ -1139,7 +1139,6 @@ service IDataNodeRPCService {
    */
   common.TSStatus deleteColumnData(TDeleteColumnDataReq req)
 
-
   /**
    * Construct table device black list
    */

Reply via email to