multiple refactors
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
index 50312a4..a432bca 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
@@ -48,14 +48,9 @@
 import org.apache.iotdb.commons.queryengine.common.SqlDialect;
 import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNodeId;
 import org.apache.iotdb.commons.queryengine.plan.planner.plan.parameter.InputLocation;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BinaryLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BooleanLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.DoubleLiteral;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Literal;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullLiteral;
-import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.parser.ParsingException;
 import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.db.audit.DNAuditLogger;
@@ -143,6 +138,7 @@
 import org.apache.iotdb.db.utils.QueryDataSetUtils;
 import org.apache.iotdb.db.utils.SchemaUtils;
 import org.apache.iotdb.db.utils.SetThreadName;
+import org.apache.iotdb.db.utils.TypeServices;
 import org.apache.iotdb.rpc.RpcUtils;
 import org.apache.iotdb.rpc.TSStatusCode;
 import org.apache.iotdb.rpc.stmt.PreparedParameterSerde;
@@ -216,6 +212,7 @@
 import org.apache.tsfile.read.common.block.TsBlock;
 import org.apache.tsfile.read.common.block.TsBlockBuilder;
 import org.apache.tsfile.read.common.block.column.TsBlockSerde;
+import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.filter.basic.Filter;
 import org.apache.tsfile.read.filter.factory.TimeFilterApi;
 import org.apache.tsfile.utils.Binary;
@@ -699,34 +696,9 @@
         return new Pair<>(new NullLiteral(), "NULL");
       }
 
-      switch (param.type) {
-        case BOOLEAN:
-          String boolStr = (Boolean) param.value ? "true" : "false";
-          return new Pair<>(new BooleanLiteral(boolStr), boolStr);
-        case INT32:
-        case INT64:
-          String numStr = String.valueOf(param.value);
-          return new Pair<>(new LongLiteral(numStr), numStr);
-        case FLOAT:
-          String floatStr = String.valueOf(param.value);
-          return new Pair<>(new DoubleLiteral((Float) param.value), floatStr);
-        case DOUBLE:
-          String doubleStr = String.valueOf(param.value);
-          return new Pair<>(new DoubleLiteral((Double) param.value), doubleStr);
-        case TEXT:
-        case STRING:
-          String strVal = (String) param.value;
-          // Escape single quotes for SQL
-          String escapedStr = "'" + strVal.replace("'", "''") + "'";
-          return new Pair<>(new StringLiteral(strVal), escapedStr);
-        case BLOB:
-          byte[] bytes = (byte[]) param.value;
-          String hexStr = "X'" + PreparedParameterSerde.bytesToHex(bytes) + "'";
-          return new Pair<>(new BinaryLiteral(bytes), hexStr);
-        default:
-          throw new IllegalArgumentException(
-              DataNodeMiscMessages.UNKNOWN_PARAMETER_TYPE + param.type);
-      }
+      return TypeServices.ValueConversion.PREPARED_PARAMETER_LITERAL_SERVICE
+          .call(Type.fromTsDataType(param.type))
+          .apply(param.value);
     }
   }
 
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanUtil.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanUtil.java
index 26dfcc6..dfb615b 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanUtil.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanUtil.java
@@ -41,6 +41,7 @@
 import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
 import org.apache.iotdb.db.utils.CommonUtils;
 import org.apache.iotdb.db.utils.SchemaUtils;
+import org.apache.iotdb.db.utils.TypeServices;
 import org.apache.iotdb.db.utils.datastructure.MemPointIterator;
 
 import org.apache.tsfile.block.column.Column;
@@ -57,12 +58,6 @@
 import org.apache.tsfile.read.common.block.TsBlock;
 import org.apache.tsfile.read.common.block.TsBlockBuilder;
 import org.apache.tsfile.read.common.block.TsBlockUtil;
-import org.apache.tsfile.read.common.block.column.BinaryColumn;
-import org.apache.tsfile.read.common.block.column.BooleanColumn;
-import org.apache.tsfile.read.common.block.column.DoubleColumn;
-import org.apache.tsfile.read.common.block.column.FloatColumn;
-import org.apache.tsfile.read.common.block.column.IntColumn;
-import org.apache.tsfile.read.common.block.column.LongColumn;
 import org.apache.tsfile.read.common.type.Type;
 import org.apache.tsfile.read.controller.IChunkLoader;
 import org.apache.tsfile.read.filter.basic.Filter;
@@ -72,7 +67,6 @@
 import org.apache.tsfile.read.reader.page.TablePageReader;
 import org.apache.tsfile.read.reader.series.PaginationController;
 import org.apache.tsfile.utils.Accountable;
-import org.apache.tsfile.utils.Binary;
 import org.apache.tsfile.utils.RamUsageEstimator;
 import org.apache.tsfile.utils.TsPrimitiveType;
 import org.slf4j.Logger;
@@ -80,7 +74,6 @@
 
 import java.io.IOException;
 import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.LinkedList;
@@ -962,439 +955,11 @@
     int positionCount = tsBlock.getPositionCount();
     Column[] newValueColumns = new Column[length];
     for (int i = 0; i < length; i++) {
-      TSDataType sourceType = valueColumns[i].getDataType();
       TSDataType finalDataType = getTsDataTypeList().get(i);
-      switch (finalDataType) {
-        case BOOLEAN:
-          if (sourceType == TSDataType.BOOLEAN) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new BooleanColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new boolean[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case INT32:
-          if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new IntColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new int[positionCount],
-                    TSDataType.INT32);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case INT64:
-          if (sourceType == TSDataType.INT64) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new LongColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new long[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getLongs()[j] =
-                    ((Number) valueColumns[i].getInts()[j]).longValue();
-              }
-            }
-          } else if (sourceType == TSDataType.TIMESTAMP) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new LongColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new long[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case FLOAT:
-          if (sourceType == TSDataType.FLOAT) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new FloatColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new float[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getFloats()[j] =
-                    ((Number) valueColumns[i].getInts()[j]).floatValue();
-              }
-            }
-          } else {
-            newValueColumns[i] =
-                new FloatColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new float[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case DOUBLE:
-          if (sourceType == TSDataType.DOUBLE) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new DoubleColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new double[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getDoubles()[j] =
-                    ((Number) valueColumns[i].getInts()[j]).doubleValue();
-              }
-            }
-          } else if (sourceType == TSDataType.INT64) {
-            newValueColumns[i] =
-                new DoubleColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new double[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getDoubles()[j] =
-                    ((Number) valueColumns[i].getLongs()[j]).doubleValue();
-              }
-            }
-          } else if (sourceType == TSDataType.FLOAT) {
-            newValueColumns[i] =
-                new DoubleColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new double[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getDoubles()[j] =
-                    ((Number) valueColumns[i].getFloats()[j]).doubleValue();
-              }
-            }
-          } else if (sourceType == TSDataType.TIMESTAMP) {
-            newValueColumns[i] =
-                new DoubleColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new double[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getDoubles()[j] =
-                    ((Number) valueColumns[i].getLongs()[j]).doubleValue();
-              }
-            }
-          } else {
-            newValueColumns[i] =
-                new DoubleColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new double[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case TEXT:
-          if (SchemaUtils.isUsingSameColumn(sourceType, TSDataType.TEXT)) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getInts()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.DATE) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        TSDataType.getDateStringValue(valueColumns[i].getInts()[j]),
-                        StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.INT64 || sourceType == TSDataType.TIMESTAMP) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getLongs()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.FLOAT) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getFloats()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.DOUBLE) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getDoubles()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.BOOLEAN) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getBooleans()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case TIMESTAMP:
-          if (SchemaUtils.isUsingSameColumn(sourceType, TSDataType.TIMESTAMP)) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new LongColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new long[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getLongs()[j] =
-                    ((Number) valueColumns[i].getInts()[j]).longValue();
-              }
-            }
-          } else if (sourceType == TSDataType.INT64) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new LongColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new long[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case DATE:
-          if (SchemaUtils.isUsingSameColumn(sourceType, TSDataType.DATE)) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new IntColumn(
-                    positionCount, Optional.of(new boolean[positionCount]), new int[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case BLOB:
-          if (SchemaUtils.isUsingSameColumn(sourceType, TSDataType.BLOB)) {
-            newValueColumns[i] = valueColumns[i];
-          } else {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case STRING:
-          if (SchemaUtils.isUsingSameColumn(sourceType, TSDataType.STRING)) {
-            newValueColumns[i] = valueColumns[i];
-          } else if (sourceType == TSDataType.INT32) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getInts()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.DATE) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        TSDataType.getDateStringValue(valueColumns[i].getInts()[j]),
-                        StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.INT64 || sourceType == TSDataType.TIMESTAMP) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getLongs()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.FLOAT) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getFloats()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.DOUBLE) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getDoubles()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else if (sourceType == TSDataType.BOOLEAN) {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = valueColumns[i].isNull()[j];
-              if (!valueColumns[i].isNull()[j]) {
-                newValueColumns[i].getBinaries()[j] =
-                    new Binary(
-                        String.valueOf(valueColumns[i].getBooleans()[j]), StandardCharsets.UTF_8);
-              }
-            }
-          } else {
-            newValueColumns[i] =
-                new BinaryColumn(
-                    positionCount,
-                    Optional.of(new boolean[positionCount]),
-                    new Binary[positionCount]);
-            for (int j = 0; j < valueColumns[i].getPositionCount(); j++) {
-              newValueColumns[i].isNull()[j] = true;
-            }
-          }
-          break;
-        case OBJECT:
-          newValueColumns[i] = valueColumns[i];
-        case VECTOR:
-        case UNKNOWN:
-        default:
-          break;
-      }
+      newValueColumns[i] =
+          TypeServices.Transformation.ALTERED_DATA_TYPE_COLUMN_TRANSFORMER_SERVICE
+              .call(Type.fromTsDataType(finalDataType))
+              .transform(valueColumns[i], positionCount);
     }
 
     tsBlock = new TsBlock(tsBlock.getTimeColumn(), newValueColumns);
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeServices.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeServices.java
index 43e7d9e..c81d0d1 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeServices.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeServices.java
@@ -290,6 +290,41 @@
                   };
             };
 
+    // Schema evolution keeps physically compatible columns, widens supported values, and exposes
+    // incompatible historical values as nulls instead of interpreting their raw storage.
+    public static final TypeService<AlteredDataTypeColumnTransformer>
+        ALTERED_DATA_TYPE_COLUMN_TRANSFORMER_SERVICE =
+            type ->
+                switch (type.getTypeEnum()) {
+                  case BOOLEAN,
+                      INT32,
+                      INT64,
+                      FLOAT,
+                      DOUBLE,
+                      TEXT,
+                      STRING,
+                      TIMESTAMP,
+                      DATE,
+                      BLOB -> {
+                    final TSDataType targetType = TSDataType.valueOf(type.getTypeEnum().name());
+                    yield (source, positionCount) -> {
+                      final TSDataType sourceType = source.getDataType();
+                      // DATE shares INT32's physical column but was historically incompatible with
+                      // a schema change to INT32, while the other shared-column pairs are reusable.
+                      if (sourceType == targetType
+                          || (targetType != TSDataType.INT32
+                              && SchemaUtils.isUsingSameColumn(sourceType, targetType))) {
+                        return source;
+                      }
+                      return targetType.isCompatible(sourceType)
+                          ? source.convertTo(targetType)
+                          : type.createNullColumn(positionCount);
+                    };
+                  }
+                  case OBJECT -> (source, positionCount) -> source;
+                  case ROW, UNKNOWN, VECTOR -> (source, positionCount) -> null;
+                };
+
     public static final TypeService<RoundTransformer> ROUND_TRANSFORMER_SERVICE =
         type ->
             switch (type.getTypeEnum()) {
@@ -813,6 +848,11 @@
     }
 
     @FunctionalInterface
+    public interface AlteredDataTypeColumnTransformer {
+      Column transform(Column source, int positionCount);
+    }
+
+    @FunctionalInterface
     public interface RoundTransformer {
       void transform(RoundFunctionTransformer transformer, Column[] columns, ColumnBuilder builder)
           throws QueryProcessException, IOException;
@@ -853,6 +893,7 @@
       COLUMN_BUILDER_SERVICE.check();
       VALUE_TO_DOUBLE_SERVICE.check();
       TRANSFORM_COLUMN_VALUE_WRITER_SERVICE.check();
+      ALTERED_DATA_TYPE_COLUMN_TRANSFORMER_SERVICE.check();
       ROUND_TRANSFORMER_SERVICE.check();
       DIFF_TRANSFORMER_SERVICE.check();
       NEGATION_TRANSFORMER_SERVICE.check();
@@ -1634,10 +1675,47 @@
                   };
             };
 
+    public static final TypeService<Function<Object, Pair<Literal, String>>>
+        PREPARED_PARAMETER_LITERAL_SERVICE =
+            type ->
+                switch (type.getTypeEnum()) {
+                  case BOOLEAN ->
+                      value -> {
+                        final String text = Boolean.toString((Boolean) value);
+                        return new Pair<>(new BooleanLiteral(text), text);
+                      };
+                  case INT32, INT64 ->
+                      value -> {
+                        final String text = String.valueOf(value);
+                        return new Pair<>(new LongLiteral(text), text);
+                      };
+                  case FLOAT ->
+                      value -> new Pair<>(new DoubleLiteral((Float) value), String.valueOf(value));
+                  case DOUBLE ->
+                      value -> new Pair<>(new DoubleLiteral((Double) value), String.valueOf(value));
+                  case TEXT, STRING ->
+                      value -> {
+                        final String text = (String) value;
+                        return new Pair<>(
+                            new StringLiteral(text), "'" + text.replace("'", "''") + "'");
+                      };
+                  case BLOB ->
+                      value -> {
+                        final BinaryLiteral literal = new BinaryLiteral((byte[]) value);
+                        return new Pair<>(literal, "X'" + literal.toHexString() + "'");
+                      };
+                  case DATE, TIMESTAMP, OBJECT, ROW, UNKNOWN, VECTOR ->
+                      value -> {
+                        throw new IllegalArgumentException(
+                            DataNodeMiscMessages.UNKNOWN_PARAMETER_TYPE + type.getTypeEnum());
+                      };
+                };
+
     static {
       VALUE_PARSER_NO_EXCEPTION_SERVICE.check();
       VALUE_PARSER_SERVICE.check();
       AUTO_CAST_SERVICE.check();
+      PREPARED_PARAMETER_LITERAL_SERVICE.check();
     }
 
     private static NumberFormatException inconsistentValueException(
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/TypeServicesTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/TypeServicesTest.java
new file mode 100644
index 0000000..cd0b8a4
--- /dev/null
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/TypeServicesTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.utils;
+
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.BinaryLiteral;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Literal;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
+
+import org.apache.tsfile.block.column.Column;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.read.common.block.column.BinaryColumn;
+import org.apache.tsfile.read.common.block.column.BooleanColumn;
+import org.apache.tsfile.read.common.block.column.FloatColumn;
+import org.apache.tsfile.read.common.block.column.IntColumn;
+import org.apache.tsfile.read.common.block.column.LongColumn;
+import org.apache.tsfile.read.common.type.Type;
+import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.DateUtils;
+import org.apache.tsfile.utils.Pair;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class TypeServicesTest {
+
+  @Test
+  public void testAlteredDataTypeNumericConversion() {
+    final Column intSource =
+        new IntColumn(
+            3,
+            Optional.of(new boolean[] {false, true, false}),
+            new int[] {1, 0, -2},
+            TSDataType.INT32);
+    final Column longSource = new LongColumn(1, Optional.of(new boolean[] {false}), new long[] {3});
+    final Column floatSource =
+        new FloatColumn(1, Optional.of(new boolean[] {false}), new float[] {4.5F});
+
+    final Column int64Result = transform(intSource, TSDataType.INT64);
+    final Column floatResult = transform(intSource, TSDataType.FLOAT);
+    final Column doubleResult = transform(intSource, TSDataType.DOUBLE);
+
+    assertEquals(1L, int64Result.getLong(0));
+    assertTrue(int64Result.isNull(1));
+    assertEquals(-2L, int64Result.getLong(2));
+    assertEquals(1.0F, floatResult.getFloat(0), 0.0F);
+    assertTrue(floatResult.isNull(1));
+    assertEquals(-2.0F, floatResult.getFloat(2), 0.0F);
+    assertEquals(1.0, doubleResult.getDouble(0), 0.0);
+    assertTrue(doubleResult.isNull(1));
+    assertEquals(-2.0, doubleResult.getDouble(2), 0.0);
+    assertEquals(3.0, transform(longSource, TSDataType.DOUBLE).getDouble(0), 0.0);
+    assertEquals(4.5, transform(floatSource, TSDataType.DOUBLE).getDouble(0), 0.0);
+  }
+
+  @Test
+  public void testAlteredDataTypeTextConversion() {
+    final int date = DateUtils.parseDateExpressionToInt(LocalDate.of(2026, 8, 12));
+    final Column dateColumn =
+        new IntColumn(1, Optional.of(new boolean[] {false}), new int[] {date}, TSDataType.DATE);
+    final Column booleanColumn =
+        new BooleanColumn(1, Optional.of(new boolean[] {false}), new boolean[] {true});
+
+    assertEquals("2026-08-12", transform(dateColumn, TSDataType.TEXT).getBinary(0).toString());
+    assertEquals("true", transform(booleanColumn, TSDataType.STRING).getBinary(0).toString());
+  }
+
+  @Test
+  public void testAlteredDataTypeIncompatibleValuesBecomeNull() {
+    final Column source =
+        new BinaryColumn(
+            2,
+            Optional.of(new boolean[] {false, false}),
+            new Binary[] {
+              new Binary("1", StandardCharsets.UTF_8), new Binary("2", StandardCharsets.UTF_8)
+            });
+
+    final Column result = transform(source, TSDataType.INT32);
+
+    assertTrue(result.isNull(0));
+    assertTrue(result.isNull(1));
+  }
+
+  @Test
+  public void testAlteredDataTypeCompatibleColumnIsReused() {
+    final Column intSource =
+        new IntColumn(1, Optional.of(new boolean[] {false}), new int[] {1}, TSDataType.INT32);
+    final Column dateSource =
+        new IntColumn(1, Optional.of(new boolean[] {false}), new int[] {1}, TSDataType.DATE);
+
+    final Column sameTypeResult = transform(intSource, TSDataType.INT32);
+    final Column intToDateResult = transform(intSource, TSDataType.DATE);
+    final Column dateToIntResult = transform(dateSource, TSDataType.INT32);
+
+    assertSame(intSource, sameTypeResult);
+    assertSame(intSource, intToDateResult);
+    assertFalse(sameTypeResult.isNull(0));
+    assertTrue(dateToIntResult.isNull(0));
+  }
+
+  @Test
+  public void testPreparedParameterLiteralConversion() {
+    final Pair<Literal, String> stringResult = convertPreparedParameter(TSDataType.STRING, "it's");
+    final Pair<Literal, String> blobResult =
+        convertPreparedParameter(TSDataType.BLOB, new byte[] {(byte) 0xAB, 0x01});
+
+    assertEquals("it's", ((StringLiteral) stringResult.left).getValue());
+    assertEquals("'it''s'", stringResult.right);
+    assertEquals("AB01", ((BinaryLiteral) blobResult.left).toHexString());
+    assertEquals("X'AB01'", blobResult.right);
+  }
+
+  private static Column transform(final Column source, final TSDataType targetType) {
+    return TypeServices.Transformation.ALTERED_DATA_TYPE_COLUMN_TRANSFORMER_SERVICE
+        .call(Type.fromTsDataType(targetType))
+        .transform(source, source.getPositionCount());
+  }
+
+  private static Pair<Literal, String> convertPreparedParameter(
+      final TSDataType type, final Object value) {
+    return TypeServices.ValueConversion.PREPARED_PARAMETER_LITERAL_SERVICE
+        .call(Type.fromTsDataType(type))
+        .apply(value);
+  }
+}