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

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

commit f22906edede6f473259dd36ede237a1ae5d705f6
Merge: 7617259da03 607339cbeae
Author: Tian Jiang <[email protected]>
AuthorDate: Tue Jan 20 09:58:11 2026 +0800

    Merge branch 'master' into force_ci/support_schema_evolution
    
    # Conflicts:
    #       .gitignore
    #       
integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
    #       
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/FileLoaderUtils.java
    #       pom.xml

 .gitignore                                         |   3 +
 integration-test/pom.xml                           |   2 +-
 .../treemodel/manual/IoTDBPipePermissionIT.java    |  36 +-
 .../pipe/it/single/IoTDBPipePermissionIT.java      |  51 ++
 .../it/query/object/IoTDBObjectQuery2IT.java       | 326 -------------
 .../it/query/object/IoTDBObjectQueryIT.java        | 309 ------------
 .../it/query/old/IoTDBSimpleQueryTableIT.java      |  63 +--
 .../relational/it/query/recent/IoTDBCteIT.java     |  27 +
 .../recent/informationschema/IoTDBServicesIT.java  | 118 +++++
 .../relational/it/schema/IoTDBDatabaseIT.java      |  12 +-
 .../iotdb/relational/it/schema/IoTDBTableIT.java   | 541 ++++++++-------------
 .../relational/it/session/IoTDBObjectDeleteIT.java | 363 --------------
 .../relational/it/session/IoTDBObjectInsertIT.java | 339 -------------
 .../it/session/IoTDBObjectInsertIT2.java           | 170 -------
 iotdb-api/external-service-api/pom.xml             |  60 +++
 .../externalservice/api/IExternalService.java      |  33 ++
 iotdb-api/pom.xml                                  |   1 +
 .../src/test/cpp/sessionRelationalIT.cpp           |  12 +-
 iotdb-client/client-py/README.md                   |   2 +
 .../client-py/iotdb/tsfile/utils/tsblock_serde.py  |   4 +-
 iotdb-client/client-py/session_example_date.py     | 109 +++++
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |   8 +
 iotdb-core/ainode/build_binary.py                  |  54 +-
 iotdb-core/ainode/iotdb/ainode/core/ai_node.py     |  11 +-
 iotdb-core/ainode/iotdb/ainode/core/constant.py    |   2 +-
 .../ainode/core/inference/batcher/basic_batcher.py |  27 +-
 .../ainode/core/inference/inference_request.py     |  15 +-
 .../core/inference/inference_request_pool.py       |   2 +-
 .../pool_scheduler/basic_pool_scheduler.py         |  11 +-
 .../iotdb/ainode/core/manager/inference_manager.py |   2 +-
 .../ainode/iotdb/ainode/core/manager/utils.py      |  28 +-
 iotdb-core/ainode/iotdb/ainode/core/rpc/service.py |   2 +-
 .../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 |   3 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |  24 +
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |  13 +
 .../client/async/CnToDnAsyncRequestType.java       |   3 +
 .../CnToDnInternalServiceAsyncRequestManager.java  |   5 +
 .../rpc/DataNodeAsyncRequestRPCHandler.java        |   9 +
 .../rpc/GetBuiltInExternalServiceRPCHandler.java   |  82 ++++
 .../confignode/conf/SystemPropertiesUtils.java     |  15 -
 .../consensus/request/ConfigPhysicalPlan.java      |  16 +
 .../consensus/request/ConfigPhysicalPlanType.java  |   6 +
 .../exernalservice/ShowExternalServicePlan.java    |  58 +++
 .../externalservice/CreateExternalServicePlan.java |  89 ++++
 .../externalservice/DropExternalServicePlan.java   |  87 ++++
 .../externalservice/StartExternalServicePlan.java  |  87 ++++
 .../externalservice/StopExternalServicePlan.java   |  87 ++++
 .../externalservice/ShowExternalServiceResp.java   |  53 ++
 .../iotdb/confignode/manager/ConfigManager.java    |  64 +++
 .../apache/iotdb/confignode/manager/IManager.java  |  15 +
 .../externalservice/ExternalServiceInfo.java       | 312 ++++++++++++
 .../externalservice/ExternalServiceManager.java    | 215 ++++++++
 .../iotdb/confignode/manager/node/NodeManager.java |  13 +-
 .../persistence/executor/ConfigPlanExecutor.java   |  22 +
 .../thrift/ConfigNodeRPCServiceProcessor.java      |  27 +
 .../persistence/ExternalServiceInfoTest.java       |  93 ++++
 .../persistence/schema/ConfigMTreeTest.java        |  58 +++
 .../test/resources/oldsnapshot/cluster_schema.bin  | Bin 0 -> 121 bytes
 .../resources/oldsnapshot/table_cluster_schema.bin | Bin 0 -> 5177 bytes
 iotdb-core/datanode/pom.xml                        |   5 +
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |   9 +
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |   9 -
 .../subtask/processor/PipeProcessorSubtask.java    |  21 +-
 .../db/pipe/event/common/PipeInsertionEvent.java   |   4 +
 .../common/tsfile/PipeTsFileInsertionEvent.java    |   4 -
 .../scan/TsFileInsertionEventScanParser.java       |   3 +-
 .../table/TsFileInsertionEventTableParser.java     |  16 +-
 .../sink/protocol/writeback/WriteBackSink.java     |  14 +-
 .../iotdb/db/protocol/client/ConfigNodeClient.java |  35 ++
 .../iotdb/db/protocol/mqtt/MPPPublishHandler.java  |   7 +-
 .../impl/DataNodeInternalRPCServiceImpl.java       |  20 +-
 .../common/header/DatasetHeaderFactory.java        |   4 +
 .../execution/operator/source/FileLoaderUtils.java |   3 +-
 .../execution/operator/source/SeriesScanUtil.java  |  40 +-
 .../InformationSchemaContentSupplierFactory.java   |  37 ++
 .../relational/ColumnTransformerBuilder.java       |  36 --
 .../iotdb/db/queryengine/plan/Coordinator.java     |   8 +
 .../execution/config/TableConfigTaskVisitor.java   |  40 ++
 .../execution/config/TreeConfigTaskVisitor.java    |  41 ++
 .../config/executor/ClusterConfigTaskExecutor.java | 114 +++++
 .../config/executor/IConfigTaskExecutor.java       |  10 +
 .../externalservice/CreateExternalServiceTask.java |  52 ++
 .../externalservice/DropExternalServiceTask.java   |  45 ++
 .../externalservice/ShowExternalServiceTask.java   |  56 +++
 .../externalservice/StartExternalServiceTask.java  |  33 +-
 .../externalservice/StopExternalServiceTask.java   |  33 +-
 .../db/queryengine/plan/parser/ASTVisitor.java     |  34 ++
 .../plan/relational/analyzer/Scope.java            |   3 +-
 .../relational/analyzer/StatementAnalyzer.java     |  18 +-
 .../function/tvf/ClassifyTableFunction.java        |   2 +-
 .../function/tvf/ForecastTableFunction.java        |   2 +-
 .../relational/metadata/TableMetadataImpl.java     |  18 -
 .../fetcher/TableDeviceSchemaValidator.java        |  13 +-
 .../DataNodeLocationSupplierFactory.java           |   1 +
 .../security/TreeAccessCheckVisitor.java           |  42 ++
 .../plan/relational/sql/ast/AstVisitor.java        |  20 +
 .../relational/sql/ast/CreateExternalService.java  |  97 ++++
 .../relational/sql/ast/DropExternalService.java    |  91 ++++
 .../relational/sql/ast/ShowExternalService.java    |  34 +-
 .../relational/sql/ast/StartExternalService.java   |  85 ++++
 .../relational/sql/ast/StopExternalService.java    |  85 ++++
 .../plan/relational/sql/parser/AstBuilder.java     |  44 ++
 .../plan/relational/sql/parser/ErrorHandler.java   |  31 +-
 .../plan/relational/sql/rewrite/ShowRewrite.java   |  15 +
 .../plan/relational/sql/util/AstUtil.java          |  30 --
 .../queryengine/plan/statement/StatementType.java  |   6 +
 .../plan/statement/StatementVisitor.java           |  31 ++
 .../CreateExternalServiceStatement.java            |  76 +++
 .../DropExternalServiceStatement.java              |  76 +++
 .../ShowExternalServiceStatement.java              |  68 +++
 .../StartExternalServiceStatement.java             |  67 +++
 .../StopExternalServiceStatement.java              |  67 +++
 .../db/queryengine/plan/udf/UDTFForecast.java      |   3 +-
 .../binary/ReadObject2ColumnTransformer.java       |  78 ---
 .../ternary/ReadObject3ColumnTransformer.java      |  99 ----
 .../unary/scalar/ReadObjectColumnTransformer.java  | 126 -----
 .../schemaregion/utils/ResourceByPathUtils.java    |  15 +-
 .../java/org/apache/iotdb/db/service/DataNode.java |  30 ++
 .../db/service/ResourcesInformationHolder.java     |  11 +
 .../externalservice/BuiltinExternalServices.java   |  57 +++
 .../ExternalServiceClassLoader.java                |  57 +++
 .../ExternalServiceManagementException.java        |  30 ++
 .../ExternalServiceManagementService.java          | 379 +++++++++++++++
 .../storageengine/dataregion/Base32ObjectPath.java | 169 -------
 .../db/storageengine/dataregion/DataRegion.java    |   4 +-
 .../db/storageengine/dataregion/IObjectPath.java   |   9 +-
 .../storageengine/dataregion/PlainObjectPath.java  | 126 -----
 .../dataregion/tsfile/TsFileResource.java          |   6 +-
 .../apache/iotdb/db/tools/TsFileSketchTool.java    |  30 ++
 .../org/apache/iotdb/db/utils/ObjectTypeUtils.java |  26 +-
 .../org/apache/iotdb/db/utils/SchemaUtils.java     |   5 +-
 .../org/apache/iotdb/db/utils/TabletDecoder.java   |   2 +-
 .../plan/function/RecordObjectTypeTest.java        | 156 ------
 .../plan/relational/planner/CteSubqueryTest.java   |   2 -
 .../sql/ast/SqlParserErrorHandlerTest.java         |  76 +++
 .../unary/scalar/ObjectTypeFunctionTest.java       | 186 -------
 .../object/ObjectTypeCompactionTest.java           | 459 -----------------
 iotdb-core/node-commons/pom.xml                    |   5 +
 .../conf/iotdb-system.properties.template          |  10 -
 .../iotdb/commons/conf/CommonDescriptor.java       |   5 -
 .../apache/iotdb/commons/conf/IoTDBConstant.java   |   1 +
 .../iotdb/commons/externalservice/ServiceInfo.java | 170 +++++++
 .../schema/column/ColumnHeaderConstant.java        |  13 +
 .../commons/schema/table/InformationSchema.java    |  11 +
 .../apache/iotdb/commons/schema/table/TsTable.java |  37 +-
 .../relational/TableBuiltinScalarFunction.java     |   1 -
 .../db/relational/grammar/sql/RelationalSql.g4     |  35 +-
 .../thrift-ainode/src/main/thrift/ainode.thrift    |   2 +-
 .../thrift-commons/src/main/thrift/common.thrift   |  14 +
 .../src/main/thrift/confignode.thrift              |  23 +
 .../src/main/thrift/datanode.thrift                |   5 +
 151 files changed, 4690 insertions(+), 3737 deletions(-)

diff --cc .gitignore
index e4c7c982393,2c19b1b3a2c..3dcc328829a
--- a/.gitignore
+++ b/.gitignore
@@@ -124,4 -124,6 +124,7 @@@ iotdb-core/tsfile/src/main/antlr4/org/a
  .mvn/.gradle-enterprise/
  .mvn/.develocity/
  .run/
 +*.sevo
+ 
+ # Relational Grammar ANTLR
+ 
iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/.antlr/
diff --cc 
integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
index c70342a8cfa,0923877d977..25666f8181f
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
@@@ -33,9 -31,6 +31,8 @@@ import org.apache.iotdb.rpc.StatementEx
  
  import org.apache.tsfile.enums.ColumnCategory;
  import org.apache.tsfile.enums.TSDataType;
- import org.apache.tsfile.external.commons.lang3.SystemUtils;
 +import org.apache.tsfile.file.metadata.ColumnSchema;
 +import org.apache.tsfile.file.metadata.TableSchema;
  import org.apache.tsfile.write.record.Tablet;
  import org.apache.tsfile.write.schema.IMeasurementSchema;
  import org.apache.tsfile.write.schema.MeasurementSchema;
@@@ -60,6 -52,6 +54,7 @@@ import java.util.Collections
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
++import java.util.stream.Collectors;
  
  import static 
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.describeTableColumnHeaders;
  import static 
org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.describeTableDetailsColumnHeaders;
@@@ -1240,802 -1113,4 +1099,834 @@@ public class IoTDBTableIT 
        }
      }
    }
 +
 +  @Test
 +  public void testAlterTableName() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      try {
 +        statement.execute(
 +            "CREATE TABLE IF NOT EXISTS alter_table_name_disabled () WITH 
(allow_alter_name=1)");
 +        fail("allow_alter_name must be boolean");
 +      } catch (SQLException e) {
 +        assertEquals(
 +            "701: allow_alter_name value must be a BooleanLiteral, but now is 
LongLiteral, value: 1",
 +            e.getMessage());
 +      }
 +
 +      statement.execute(
 +          "CREATE TABLE IF NOT EXISTS alter_table_name_disabled () WITH 
(allow_alter_name=false)");
 +
 +      try {
 +        statement.execute(
 +            "ALTER TABLE alter_table_name_disabled SET PROPERTIES 
allow_alter_name=true");
 +        fail("allow_alter_name cannot be altered");
 +      } catch (SQLException e) {
 +        assertEquals("701: The property allow_alter_name cannot be altered.", 
e.getMessage());
 +      }
 +
 +      try {
 +        statement.execute("ALTER TABLE alter_table_name_disabled RENAME TO 
alter_table_named");
 +        fail("the table cannot be renamed");
 +      } catch (SQLException e) {
 +        assertEquals(
 +            "701: Table 'testdb.alter_table_name_disabled' is created in a 
old version and cannot be renamed, please migrate its data to a new table 
manually",
 +            e.getMessage());
 +      }
 +
 +      // alter once
 +      statement.execute("CREATE TABLE IF NOT EXISTS alter_table_name (s1 
int32)");
 +      statement.execute("INSERT INTO alter_table_name (time, s1) VALUES (1, 
1)");
 +      statement.execute("ALTER TABLE alter_table_name RENAME TO 
alter_table_named");
 +      try {
 +        statement.execute("INSERT INTO alter_table_name (time, s1) VALUES (0, 
0)");
 +        fail();
 +      } catch (SQLException e) {
 +        assertEquals("550: Table 'testdb.alter_table_name' does not exist.", 
e.getMessage());
 +      }
 +      statement.execute("INSERT INTO alter_table_named (time, s1) VALUES (2, 
2)");
 +
 +      ResultSet resultSet = statement.executeQuery("SELECT * FROM 
alter_table_named");
 +      assertTrue(resultSet.next());
 +      assertEquals(1, resultSet.getLong(1));
 +      assertEquals(1, resultSet.getLong(2));
 +      assertTrue(resultSet.next());
 +      assertEquals(2, resultSet.getLong(1));
 +      assertEquals(2, resultSet.getLong(2));
 +      assertFalse(resultSet.next());
 +
 +      // alter twice
 +      statement.execute("ALTER TABLE alter_table_named RENAME TO 
alter_table_named2");
 +      try {
 +        statement.execute("INSERT INTO alter_table_named (time, s1) VALUES 
(0, 0)");
 +        fail();
 +      } catch (SQLException e) {
 +        assertEquals("550: Table 'testdb.alter_table_named' does not exist.", 
e.getMessage());
 +      }
 +      statement.execute("INSERT INTO alter_table_named2 (time, s1) VALUES (3, 
3)");
 +
 +      resultSet = statement.executeQuery("SELECT * FROM alter_table_named2");
 +      for (int i = 1; i <= 3; i++) {
 +        assertTrue(resultSet.next());
 +        assertEquals(i, resultSet.getLong(1));
 +        assertEquals(i, resultSet.getLong(2));
 +      }
 +      assertFalse(resultSet.next());
 +
 +      // alter back
 +      statement.execute("ALTER TABLE alter_table_named2 RENAME TO 
alter_table_name");
 +      try {
 +        statement.execute("INSERT INTO alter_table_named2 (time, s1) VALUES 
(0, 0)");
 +        fail();
 +      } catch (SQLException e) {
 +        assertEquals("550: Table 'testdb.alter_table_named2' does not 
exist.", e.getMessage());
 +      }
 +      statement.execute("INSERT INTO alter_table_name (time, s1) VALUES (4, 
4)");
 +
 +      resultSet = statement.executeQuery("SELECT * FROM alter_table_name");
 +      for (int i = 1; i <= 4; i++) {
 +        assertTrue(resultSet.next());
 +        assertEquals(i, resultSet.getLong(1));
 +        assertEquals(i, resultSet.getLong(2));
 +      }
 +      assertFalse(resultSet.next());
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterColumnName() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS alter_column_name (s1 
int32)");
 +      statement.execute("INSERT INTO alter_column_name (time, s1) VALUES (1, 
1)");
 +      // alter once
 +      statement.execute("ALTER TABLE alter_column_name RENAME COLUMN s1 TO 
s2");
 +      try {
 +        statement.execute("INSERT INTO alter_column_name (time, s1) VALUES 
(0, 0)");
 +        fail();
 +      } catch (SQLException e) {
 +        assertEquals(
 +            "616: Unknown column category for s1. Cannot auto create 
column.", e.getMessage());
 +      }
 +      statement.execute("INSERT INTO alter_column_name (time, s2) VALUES (2, 
2)");
 +
 +      ResultSet resultSet = statement.executeQuery("SELECT * FROM 
alter_column_name");
 +      ResultSetMetaData metaData = resultSet.getMetaData();
 +      assertEquals(2, metaData.getColumnCount());
 +      assertEquals("s2", metaData.getColumnName(2));
 +
 +      for (int i = 1; i <= 2; i++) {
 +        assertTrue(resultSet.next());
 +        assertEquals(i, resultSet.getLong(1));
 +        assertEquals(i, resultSet.getInt(2));
 +      }
 +      assertFalse(resultSet.next());
 +    }
 +  }
 +
 +  @Test
 +  public void testTableRenameConflict() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS table_a ()");
 +      statement.execute("CREATE TABLE IF NOT EXISTS table_b ()");
 +
 +      try {
 +        statement.execute("ALTER TABLE table_a RENAME TO table_b");
 +        fail();
 +      } catch (final SQLException e) {
 +        // expect table already exists (use code 551)
 +        assertTrue(
 +            e.getMessage().startsWith("551") && 
e.getMessage().toLowerCase().contains("already"));
 +      }
 +    }
 +  }
 +
 +  @Test
 +  public void testColumnRenameConflict() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS tconf (c1 int32, c2 
int32)");
 +
 +      try {
 +        statement.execute("ALTER TABLE tconf RENAME COLUMN c1 TO c2");
 +        fail();
 +      } catch (final SQLException e) {
 +        // expect column already exist error (code 552)
 +        assertTrue(
 +            e.getMessage().startsWith("552") && 
e.getMessage().toLowerCase().contains("exist"));
 +      }
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterTableRenameToSameName() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS rename_same (s1 int32)");
 +      statement.execute("INSERT INTO rename_same (time, s1) VALUES (1, 1)");
 +
 +      // Renaming to the same name should be a no-op and not lose data
 +      try {
 +        statement.execute("ALTER TABLE rename_same RENAME TO rename_same");
 +        fail();
 +      } catch (SQLException e) {
 +        assertEquals(
 +            "701: The table's old name shall not be equal to the new one.", 
e.getMessage());
 +      }
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterTableRenameToQuotedSpecialName() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS rename_special (s1 
int32)");
 +      statement.execute("INSERT INTO rename_special (time, s1) VALUES (1, 
1)");
 +
 +      // rename to a quoted name containing hyphen and unicode
 +      statement.execute("ALTER TABLE rename_special RENAME TO \"rename-特殊\"");
 +
 +      // old name should not exist
 +      try {
 +        statement.execute("INSERT INTO rename_special (time, s1) VALUES (2, 
2)");
 +        fail();
 +      } catch (final SQLException e) {
 +        assertTrue(
 +            e.getMessage().startsWith("550")
 +                || e.getMessage().toLowerCase().contains("does not exist"));
 +      }
 +
 +      // insert into new quoted name and verify
 +      statement.execute("INSERT INTO \"rename-特殊\" (time, s1) VALUES (2, 2)");
 +      ResultSet rs = statement.executeQuery("SELECT * FROM \"rename-特殊\"");
 +      for (int i = 1; i <= 2; i++) {
 +        assertTrue(rs.next());
 +        assertEquals(i, rs.getLong(1));
 +        assertEquals(i, rs.getInt(2));
 +      }
 +      assertFalse(rs.next());
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterTableRenameWithDots() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS db1");
 +      statement.execute("DROP DATABASE IF EXISTS db2");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS db1");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS db2");
 +      statement.execute("USE db1");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS t1 (s1 int32)");
 +      statement.execute("INSERT INTO t1 (time, s1) VALUES (1, 1)");
 +
 +      statement.execute("ALTER TABLE t1 RENAME TO \"db2.t1\"");
 +
 +      ResultSet rs = statement.executeQuery("SELECT * FROM \"db2.t1\"");
 +      assertTrue(rs.next());
 +      assertEquals(1, rs.getLong(1));
 +      assertEquals(1, rs.getInt(2));
 +      assertFalse(rs.next());
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterColumnRenameCaseSensitivity() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS tcase (c1 int32)");
 +      statement.execute("INSERT INTO tcase (time, c1) VALUES (1, 1)");
 +
 +      statement.execute("ALTER TABLE tcase RENAME COLUMN c1 TO C1");
 +
 +      ResultSet rs = statement.executeQuery("SELECT * FROM tcase");
 +      ResultSetMetaData md = rs.getMetaData();
 +      assertEquals(2, md.getColumnCount());
 +      // server may normalize column names; accept either exact case or 
normalized lower-case
 +      String colName = md.getColumnName(2);
 +      assertTrue(colName.equals("C1") || colName.equals("c1"));
 +
 +      // ensure data still accessible via the new identifier (try using the 
new name in insert)
 +      try {
 +        statement.execute("INSERT INTO tcase (time, c1) VALUES (2, 2)");
 +        // if server treats identifiers case-insensitively this may succeed
 +      } catch (final SQLException ignored) {
 +        // ignore - the purpose is to assert existence/behavior, not enforce 
one model here
 +      }
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterColumnRenameToQuotedSpecialChars() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS tcolspecial (s1 int32)");
 +      statement.execute("INSERT INTO tcolspecial (time, s1) VALUES (1, 1)");
 +
 +      statement.execute("ALTER TABLE tcolspecial RENAME COLUMN s1 TO 
\"s-特\"");
 +
 +      try {
 +        statement.execute("INSERT INTO tcolspecial (time, s1) VALUES (2, 2)");
 +        fail();
 +      } catch (final SQLException e) {
 +        assertTrue(
 +            e.getMessage().startsWith("616") || 
e.getMessage().toLowerCase().contains("unknown"));
 +      }
 +
 +      statement.execute("INSERT INTO tcolspecial (time, \"s-特\") VALUES (2, 
2)");
 +      ResultSet rs = statement.executeQuery("SELECT * FROM tcolspecial");
 +      ResultSetMetaData md = rs.getMetaData();
 +      assertEquals(2, md.getColumnCount());
 +      String colName = md.getColumnName(2);
 +      // accept either exact quoted name or normalized variant
 +      assertTrue(colName.equals("s-特") || colName.equals("s特") || 
colName.equals("s_特"));
 +    }
 +  }
 +
 +  @Test
 +  public void testAlterColumnMultipleRenamesAndBack() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS tmulti (a int32)");
 +      statement.execute("INSERT INTO tmulti (time, a) VALUES (1, 1)");
 +
 +      statement.execute("ALTER TABLE tmulti RENAME COLUMN a TO b");
 +      statement.execute("INSERT INTO tmulti (time, b) VALUES (2, 2)");
 +
 +      statement.execute("ALTER TABLE tmulti RENAME COLUMN b TO c");
 +      statement.execute("INSERT INTO tmulti (time, c) VALUES (3, 3)");
 +
 +      statement.execute("ALTER TABLE tmulti RENAME COLUMN c TO a");
 +      statement.execute("INSERT INTO tmulti (time, a) VALUES (4, 4)");
 +
 +      ResultSet rs = statement.executeQuery("SELECT * FROM tmulti");
 +      for (int i = 1; i <= 4; i++) {
 +        assertTrue(rs.next());
 +        assertEquals(i, rs.getLong(1));
 +        assertEquals(i, rs.getInt(2));
 +      }
 +      assertFalse(rs.next());
 +    }
 +  }
 +
 +  @Test
 +  public void testRenameNonExistentColumn() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      statement.execute("CREATE TABLE IF NOT EXISTS tnonexist (x int32)");
 +
 +      try {
 +        statement.execute("ALTER TABLE tnonexist RENAME COLUMN y TO z");
 +        fail();
 +      } catch (final SQLException e) {
 +        // error should indicate column does not exist (use code 616 + 
contains)
 +        assertTrue(e.getMessage().startsWith("616"));
 +        assertTrue(
 +            e.getMessage().toLowerCase().contains("does not exist")
 +                || e.getMessage().toLowerCase().contains("cannot be 
resolved"));
 +      }
 +    }
 +  }
 +
 +  @Test
 +  public void testRenameTimeColumnForbidden() throws Exception {
 +    try (final Connection connection =
 +            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement statement = connection.createStatement()) {
 +      statement.execute("DROP DATABASE IF EXISTS testdb");
 +      statement.execute("CREATE DATABASE IF NOT EXISTS testdb");
 +      statement.execute("USE testdb");
 +
 +      // create a table with explicit time column
 +      statement.execute("CREATE TABLE IF NOT EXISTS ttime (time TIMESTAMP 
TIME, a INT32)");
 +
 +      try {
 +        statement.execute("ALTER TABLE ttime RENAME COLUMN time TO newtime");
 +        fail();
 +      } catch (final SQLException e) {
 +        // renaming time column should be forbidden (code 701 or similar)
 +        assertTrue(
 +            (e.getMessage().startsWith("701") && 
e.getMessage().toLowerCase().contains("time")));
 +      }
 +    }
 +  }
 +
-     // Helper: recognize SQLExceptions that mean the target table/device 
cannot be found.
-     private static boolean isTableNotFound(final SQLException e) {
-       if (e == null) return false;
-       final String msg = e.getMessage();
-       if (msg == null) return false;
-       final String lm = msg.toLowerCase();
-       // code 550 is commonly used for 'does not exist' in this project; also 
match textual phrases
-       return msg.startsWith("550") || lm.contains("not exist");
-     }
++  // Helper: recognize SQLExceptions that mean the target table/device cannot 
be found.
++  private static boolean isTableNotFound(final SQLException e) {
++    if (e == null) return false;
++    final String msg = e.getMessage();
++    if (msg == null) return false;
++    final String lm = msg.toLowerCase();
++    // code 550 is commonly used for 'does not exist' in this project; also 
match textual phrases
++    return msg.startsWith("550") || lm.contains("not exist");
++  }
 +
-     @Test(timeout = 120000)
-     @SuppressWarnings("resource")
-     public void testConcurrentRenameVsQueries() throws Throwable {
-     try (final Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++  @Test(timeout = 120000)
++  @SuppressWarnings("resource")
++  public void testConcurrentRenameVsQueries() throws Throwable {
++    try (final Connection connection =
++            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement stmt = connection.createStatement()) {
 +      final String db = "concrenamedb";
 +      final int tableCount = 6;
 +      final int rows = 50;
 +      stmt.execute("DROP DATABASE IF EXISTS " + db);
 +      stmt.execute("CREATE DATABASE IF NOT EXISTS " + db);
 +      stmt.execute("USE " + db);
 +
 +      final String[] names = new String[tableCount];
 +      for (int i = 0; i < tableCount; i++) {
 +        names[i] = "crtable" + i;
 +        stmt.execute(String.format("CREATE TABLE IF NOT EXISTS %s (v int32)", 
names[i]));
 +        for (int r = 1; r <= rows; r++) {
 +          stmt.execute(String.format("INSERT INTO %s (time, v) VALUES (%d, 
%d)", names[i], r, r));
 +        }
 +      }
 +
-       final java.util.concurrent.atomic.AtomicReference<Throwable> err = new 
java.util.concurrent.atomic.AtomicReference<>();
-       final java.util.concurrent.CountDownLatch startLatch = new 
java.util.concurrent.CountDownLatch(1);
-       final java.util.concurrent.CountDownLatch doneLatch = new 
java.util.concurrent.CountDownLatch(4);
++      final java.util.concurrent.atomic.AtomicReference<Throwable> err =
++          new java.util.concurrent.atomic.AtomicReference<>();
++      final java.util.concurrent.CountDownLatch startLatch =
++          new java.util.concurrent.CountDownLatch(1);
++      final java.util.concurrent.CountDownLatch doneLatch =
++          new java.util.concurrent.CountDownLatch(4);
 +
 +      java.util.concurrent.ExecutorService exec = null;
 +      try {
 +        exec = java.util.concurrent.Executors.newFixedThreadPool(8);
 +
 +        // Renamer task: rotate rename a subset of tables repeatedly
-         exec.submit(() -> {
-           try (final Connection c = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-               final Statement s = c.createStatement()) {
-             startLatch.await();
-             // ensure this thread's connection uses the test database
-             try {
-               s.execute("USE " + db);
-             } catch (final SQLException ignore) {
-             }
-             for (int round = 0; round < 20 && err.get() == null; round++) {
-               for (int i = 0; i < tableCount / 2; i++) {
-                 final String oldName = names[i];
-                 final String newName = oldName + "_r" + round;
++        exec.submit(
++            () -> {
++              try (final Connection c =
++                      
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++                  final Statement s = c.createStatement()) {
++                startLatch.await();
++                // ensure this thread's connection uses the test database
 +                try {
-                   s.execute(String.format("ALTER TABLE %s RENAME TO %s", 
oldName, newName));
-                   // reflect change locally so queries target updated names
-                   names[i] = newName;
-                 } catch (final SQLException ex) {
-                   // Only ignore if the failure is due to table not existing; 
otherwise record the error
-                   if (isTableNotFound(ex)) {
-                     // table not found: likely a transient race with 
concurrent rename — ignore and log
-                     System.out.println("Ignored table-not-found during 
rename: " + ex.getMessage());
-                   } else {
-                     err.compareAndSet(null, ex);
++                  s.execute("USE " + db);
++                } catch (final SQLException ignore) {
++                }
++                for (int round = 0; round < 20 && err.get() == null; round++) 
{
++                  for (int i = 0; i < tableCount / 2; i++) {
++                    final String oldName = names[i];
++                    final String newName = oldName + "_r" + round;
++                    try {
++                      s.execute(String.format("ALTER TABLE %s RENAME TO %s", 
oldName, newName));
++                      // reflect change locally so queries target updated 
names
++                      names[i] = newName;
++                    } catch (final SQLException ex) {
++                      // Only ignore if the failure is due to table not 
existing; otherwise record
++                      // the error
++                      if (isTableNotFound(ex)) {
++                        // table not found: likely a transient race with 
concurrent rename — ignore
++                        // and log
++                        System.out.println(
++                            "Ignored table-not-found during rename: " + 
ex.getMessage());
++                      } else {
++                        err.compareAndSet(null, ex);
++                      }
++                    }
++                  }
++                  try {
++                    Thread.sleep(50);
++                  } catch (final InterruptedException ie) {
++                    Thread.currentThread().interrupt();
++                    break;
 +                  }
 +                }
++              } catch (final Throwable t) {
++                err.compareAndSet(null, t);
++              } finally {
++                doneLatch.countDown();
 +              }
-               try {
-                 Thread.sleep(50);
-               } catch (final InterruptedException ie) {
-                 Thread.currentThread().interrupt();
-                 break;
-               }
-             }
-           } catch (final Throwable t) {
-             err.compareAndSet(null, t);
-           } finally {
-             doneLatch.countDown();
-           }
-         });
++            });
 +
 +        // Queryer tasks: continuously query random tables
 +        for (int q = 0; q < 2; q++) {
-           exec.submit(() -> {
-             try (final Connection c = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-                 final Statement s = c.createStatement()) {
-               final java.util.Random rnd = new java.util.Random();
-               startLatch.await();
-               // ensure this thread's connection uses the test database
-               try {
-                 s.execute("USE " + db);
-               } catch (final SQLException ignore) {
-               }
-               for (int iter = 0; iter < 200 && err.get() == null; iter++) {
-                 final int idx = rnd.nextInt(tableCount);
-                 final String tname = names[idx];
-                 try (final ResultSet rs = s.executeQuery("SELECT count(*) 
FROM " + tname)) {
-                   if (rs.next()) {
-                     rs.getLong(1);
++          exec.submit(
++              () -> {
++                try (final Connection c =
++                        
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++                    final Statement s = c.createStatement()) {
++                  final java.util.Random rnd = new java.util.Random();
++                  startLatch.await();
++                  // ensure this thread's connection uses the test database
++                  try {
++                    s.execute("USE " + db);
++                  } catch (final SQLException ignore) {
 +                  }
-                 } catch (final SQLException ex) {
-                   // Only ignore table-not-found; otherwise surface the error 
to fail the test
-                   if (!isTableNotFound(ex)) {
-                     err.compareAndSet(null, ex);
-                     break;
++                  for (int iter = 0; iter < 200 && err.get() == null; iter++) 
{
++                    final int idx = rnd.nextInt(tableCount);
++                    final String tname = names[idx];
++                    try (final ResultSet rs = s.executeQuery("SELECT count(*) 
FROM " + tname)) {
++                      if (rs.next()) {
++                        rs.getLong(1);
++                      }
++                    } catch (final SQLException ex) {
++                      // Only ignore table-not-found; otherwise surface the 
error to fail the test
++                      if (!isTableNotFound(ex)) {
++                        err.compareAndSet(null, ex);
++                        break;
++                      }
++                    }
 +                  }
++                } catch (final Throwable t) {
++                  err.compareAndSet(null, t);
++                } finally {
++                  doneLatch.countDown();
 +                }
-               }
-             } catch (final Throwable t) {
-               err.compareAndSet(null, t);
-             } finally {
-               doneLatch.countDown();
-             }
-           });
++              });
 +        }
 +
 +        // Another queryer to trigger more parallel access
-         exec.submit(() -> {
-           try (final Connection c = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-               final Statement s = c.createStatement()) {
-             startLatch.await();
-             // ensure this thread's connection uses the test database
-             try {
-               s.execute("USE " + db);
-             } catch (final SQLException ignore) {
-             }
-             for (int iter = 0; iter < 200 && err.get() == null; iter++) {
-               for (int i = 0; i < tableCount; i++) {
-                 try (final ResultSet rs = s.executeQuery("SELECT * FROM " + 
names[i] + " LIMIT 1")) {
-                   // consume
-                   while (rs.next()) {
-                     rs.getLong(1);
-                   }
-                 } catch (final SQLException ex) {
-                   if (!isTableNotFound(ex)) {
-                     err.compareAndSet(null, ex);
-                     break;
++        exec.submit(
++            () -> {
++              try (final Connection c =
++                      
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++                  final Statement s = c.createStatement()) {
++                startLatch.await();
++                // ensure this thread's connection uses the test database
++                try {
++                  s.execute("USE " + db);
++                } catch (final SQLException ignore) {
++                }
++                for (int iter = 0; iter < 200 && err.get() == null; iter++) {
++                  for (int i = 0; i < tableCount; i++) {
++                    try (final ResultSet rs =
++                        s.executeQuery("SELECT * FROM " + names[i] + " LIMIT 
1")) {
++                      // consume
++                      while (rs.next()) {
++                        rs.getLong(1);
++                      }
++                    } catch (final SQLException ex) {
++                      if (!isTableNotFound(ex)) {
++                        err.compareAndSet(null, ex);
++                        break;
++                      }
++                    }
 +                  }
 +                }
++              } catch (final Throwable t) {
++                err.compareAndSet(null, t);
++              } finally {
++                doneLatch.countDown();
 +              }
-             }
-           } catch (final Throwable t) {
-             err.compareAndSet(null, t);
-           } finally {
-             doneLatch.countDown();
-           }
-         });
++            });
 +
 +        // start
 +        startLatch.countDown();
 +        // wait for tasks
 +        doneLatch.await();
 +
 +        if (err.get() != null) {
 +          throw err.get();
 +        }
 +      } finally {
 +        if (exec != null) {
 +          exec.shutdownNow();
 +        }
 +      }
 +    }
-     }
++  }
 +
-     @Test
-     public void testMultiTableCrossCheckAfterRenames() throws Exception {
-     try (final Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++  @Test
++  public void testMultiTableCrossCheckAfterRenames() throws Exception {
++    try (final Connection connection =
++            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement stmt = connection.createStatement()) {
 +      final String db = "multicheckdb";
 +      stmt.execute("DROP DATABASE IF EXISTS " + db);
 +      stmt.execute("CREATE DATABASE IF NOT EXISTS " + db);
 +      stmt.execute("USE " + db);
 +
 +      // create two related tables
 +      stmt.execute("CREATE TABLE IF NOT EXISTS mta (k int32)");
 +      stmt.execute("CREATE TABLE IF NOT EXISTS mtb (k int32)");
 +
 +      for (int i = 1; i <= 10; i++) {
 +        stmt.execute(String.format("INSERT INTO mta (time, k) VALUES (%d, 
%d)", i, i));
 +        stmt.execute(String.format("INSERT INTO mtb (time, k) VALUES (%d, 
%d)", i, i));
 +      }
 +
 +      // baseline: read aggregates
 +      long aCount = 0, bCount = 0;
 +      try (final ResultSet ra = stmt.executeQuery("SELECT count(*) FROM 
mta")) {
-         if (ra.next())  {
++        if (ra.next()) {
 +          aCount = ra.getLong(1);
 +        }
 +      }
 +      try (final ResultSet rb = stmt.executeQuery("SELECT count(*) FROM 
mtb")) {
-         if (rb.next())  {
++        if (rb.next()) {
 +          bCount = rb.getLong(1);
 +        }
 +      }
 +
 +      // rename one table and verify cross results remain consistent when 
queried separately
 +      stmt.execute("ALTER TABLE mtb RENAME TO mtb_renamed");
 +
 +      long bCountAfter = 0;
 +      try (final ResultSet rb2 = stmt.executeQuery("SELECT count(*) FROM 
mtb_renamed")) {
 +        if (rb2.next()) {
 +          bCountAfter = rb2.getLong(1);
 +        }
 +      }
 +
 +      // assert counts unchanged
 +      assertEquals(bCount, bCountAfter);
 +      assertEquals(10, aCount);
 +
 +      // rename the other table and verify again
 +      stmt.execute("ALTER TABLE mta RENAME TO mta_renamed");
 +      long aCountAfter = 0;
 +      try (final ResultSet ra2 = stmt.executeQuery("SELECT count(*) FROM 
mta_renamed")) {
 +        if (ra2.next()) {
 +          aCountAfter = ra2.getLong(1);
 +        }
 +      }
 +      assertEquals(aCount, aCountAfter);
 +    }
-     }
++  }
 +
-     @Test
-     public void testPerformanceWithQuotedSpecialNameRenames() throws 
Exception {
-     try (final Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++  @Test
++  public void testPerformanceWithQuotedSpecialNameRenames() throws Exception {
++    try (final Connection connection =
++            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
 +        final Statement stmt = connection.createStatement();
 +        final ITableSession session = 
EnvFactory.getEnv().getTableSessionConnection()) {
 +      final String db = "perfquotedb";
-       final int tables = 3200;
++      final int colPerTable = 1;
++      final int tables = 8;
 +      final int rows = 100;
 +      final int numFile = 5;
-       final int colPerTable = 100;
 +      stmt.execute("DROP DATABASE IF EXISTS " + db);
 +      stmt.execute("CREATE DATABASE IF NOT EXISTS " + db);
 +      stmt.execute("USE " + db);
++      //stmt.execute("set configuration enable_seq_space_compaction='false'");
 +      session.executeNonQueryStatement("USE " + db);
 +
 +      final String[] names = new String[tables];
 +      StringBuilder createTableTemplate = new StringBuilder("CREATE TABLE IF 
NOT EXISTS %s (");
 +      for (int c = 0; c < colPerTable; c++) {
 +        createTableTemplate.append(String.format("v%d int32,", c));
 +      }
-       createTableTemplate = new StringBuilder(
-           createTableTemplate.substring(0, createTableTemplate.length() - 1) 
+ ")");
++      createTableTemplate =
++          new StringBuilder(
++              createTableTemplate.substring(0, createTableTemplate.length() - 
1) + ")");
 +      List<ColumnSchema> columns = new ArrayList<>();
 +      for (int i = 0; i < colPerTable; i++) {
 +        columns.add(new ColumnSchema("v" + i, TSDataType.INT32, 
ColumnCategory.FIELD));
 +      }
-       TableSchema tableSchema = new TableSchema(
-           "", // place holder
-           columns
-       );
++      TableSchema tableSchema =
++          new TableSchema(
++              "", // place holder
++              columns);
 +
 +      System.out.println("Start data preparation...");
 +      for (int i = 0; i < tables; i++) {
 +        names[i] = "qtable" + i;
 +        stmt.execute(String.format(createTableTemplate.toString(), names[i]));
 +        tableSchema.setTableName(names[i]);
-         Tablet tablet = new Tablet(tableSchema.getTableName(), 
tableSchema.getColumnSchemas().stream().map(IMeasurementSchema::getMeasurementName).collect(
-             Collectors.toList()), 
tableSchema.getColumnSchemas().stream().map(IMeasurementSchema::getType).collect(
-             Collectors.toList()), tableSchema.getColumnTypes(), rows);
++        Tablet tablet =
++            new Tablet(
++                tableSchema.getTableName(),
++                tableSchema.getColumnSchemas().stream()
++                    .map(IMeasurementSchema::getMeasurementName)
++                    .collect(Collectors.toList()),
++                tableSchema.getColumnSchemas().stream()
++                    .map(IMeasurementSchema::getType)
++                    .collect(Collectors.toList()),
++                tableSchema.getColumnTypes(),
++                rows);
 +        for (int j = 0; j < numFile; j++) {
 +          tablet.reset();
 +          for (int r = 1; r <= rows; r++) {
 +            tablet.addTimestamp(r - 1, r + j * rows);
 +            for (int c = 0; c < colPerTable; c++) {
 +              tablet.addValue(r - 1, c, r + j * rows);
 +            }
 +          }
 +          session.insert(tablet);
 +          stmt.execute("FLUSH");
 +        }
 +      }
 +      System.out.println("Data preparation done.");
 +
 +      // baseline measurement: simple average over a few runs
 +      final int runs = 100;
 +      double totalMs = 0.0;
 +      for (int run = 0; run < runs; run++) {
 +        final long start = System.nanoTime();
 +        for (int i = 0; i < tables; i++) {
 +          try (final ResultSet rs = stmt.executeQuery("SELECT count(*) FROM " 
+ names[i])) {
 +            if (rs.next()) {
 +              rs.getLong(1);
 +            }
 +          }
 +        }
 +        final long end = System.nanoTime();
 +        if (run > runs * 0.1) {
 +          totalMs += (end - start) / 1_000_000.0;
 +        }
 +      }
 +      final double baseline = totalMs / (runs * 0.9);
 +      System.out.println("baseline_total_ms=" + String.format("%.3f", 
baseline));
 +
 +      // rename half of them to quoted special names and measure again
 +      for (int i = 0; i < tables / 2; i++) {
 +        final String oldName = names[i];
 +        final String newName = "\"" + oldName + "-特\""; // quoted name
 +        stmt.execute(String.format("ALTER TABLE %s RENAME TO %s", oldName, 
newName));
 +        names[i] = newName;
 +      }
 +
 +      totalMs = 0.0;
 +      for (int run = 0; run < runs; run++) {
 +        final long start = System.nanoTime();
 +        for (int i = 0; i < tables; i++) {
 +          try (final ResultSet rs = stmt.executeQuery("SELECT count(*) FROM " 
+ names[i])) {
 +            if (rs.next()) {
 +              rs.getLong(1);
 +            }
 +          }
 +        }
 +        final long end = System.nanoTime();
 +        if (run > runs * 0.1) {
 +          totalMs += (end - start) / 1_000_000.0;
 +        }
 +      }
 +      final double after = totalMs / (runs * 0.9);
 +      System.out.println("after_quoted_total_ms=" + String.format("%.3f", 
after));
 +
 +      // basic sanity: ensure queries still return counts
 +      for (int i = 0; i < tables; i++) {
 +        try (final ResultSet rs = stmt.executeQuery("SELECT count(*) FROM " + 
names[i])) {
 +          assertTrue(rs.next());
 +          assertEquals(rows * numFile, rs.getLong(1));
 +        }
 +      }
 +    }
-     }
++  }
 +
-     @Test
-     public void testAlterTableAndColumnTogether() throws Exception {
-       try (final Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-           final Statement stmt = connection.createStatement()) {
-         final String db = "dualalterdb";
-         stmt.execute("DROP DATABASE IF EXISTS " + db);
-         stmt.execute("CREATE DATABASE IF NOT EXISTS " + db);
-         stmt.execute("USE " + db);
- 
-         stmt.execute("CREATE TABLE IF NOT EXISTS tab1 (c1 int32, c2 int32)");
-         stmt.execute("INSERT INTO tab1 (time, c1, c2) VALUES (1, 1, 10)");
- 
-         // rename column first and then rename table
-         stmt.execute("ALTER TABLE tab1 RENAME COLUMN c1 TO c1_new");
-         stmt.execute("ALTER TABLE tab1 RENAME TO tab1_new");
- 
-         // old table name should not exist
-         try {
-           stmt.execute("INSERT INTO tab1 (time, c1_new) VALUES (2, 2)");
-           fail();
-         } catch (final SQLException e) {
-           assertTrue(e.getMessage().startsWith("550") || 
e.getMessage().toLowerCase().contains("does not exist"));
-         }
++  @Test
++  public void testAlterTableAndColumnTogether() throws Exception {
++    try (final Connection connection =
++            EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
++        final Statement stmt = connection.createStatement()) {
++      final String db = "dualalterdb";
++      stmt.execute("DROP DATABASE IF EXISTS " + db);
++      stmt.execute("CREATE DATABASE IF NOT EXISTS " + db);
++      stmt.execute("USE " + db);
 +
-         // inserting using new table and new column names should succeed
-         stmt.execute("INSERT INTO tab1_new (time, c1_new, c2) VALUES (2, 2, 
20)");
++      stmt.execute("CREATE TABLE IF NOT EXISTS tab1 (c1 int32, c2 int32)");
++      stmt.execute("INSERT INTO tab1 (time, c1, c2) VALUES (1, 1, 10)");
 +
-         // verify data
-         try (final ResultSet rs = stmt.executeQuery("SELECT * FROM tab1_new 
ORDER BY time")) {
-           assertTrue(rs.next());
-           assertEquals(1, rs.getLong(1));
-           assertEquals(1, rs.getInt("c1_new"));
-           assertEquals(10, rs.getInt("c2"));
++      // rename column first and then rename table
++      stmt.execute("ALTER TABLE tab1 RENAME COLUMN c1 TO c1_new");
++      stmt.execute("ALTER TABLE tab1 RENAME TO tab1_new");
 +
-           assertTrue(rs.next());
-           assertEquals(2, rs.getLong(1));
-           assertEquals(2, rs.getInt("c1_new"));
-           assertEquals(20, rs.getInt("c2"));
++      // old table name should not exist
++      try {
++        stmt.execute("INSERT INTO tab1 (time, c1_new) VALUES (2, 2)");
++        fail();
++      } catch (final SQLException e) {
++        assertTrue(
++            e.getMessage().startsWith("550")
++                || e.getMessage().toLowerCase().contains("does not exist"));
++      }
 +
-           assertFalse(rs.next());
-         }
++      // inserting using new table and new column names should succeed
++      stmt.execute("INSERT INTO tab1_new (time, c1_new, c2) VALUES (2, 2, 
20)");
 +
-         // rename column again on the renamed table and verify
-         stmt.execute("ALTER TABLE tab1_new RENAME COLUMN c1_new TO c1_final");
-         try {
-           // old column identifier should fail
-           stmt.execute("INSERT INTO tab1_new (time, c1_new) VALUES (3, 3)");
-           fail();
-         } catch (final SQLException e) {
-           assertTrue(e.getMessage().startsWith("616") || 
e.getMessage().toLowerCase().contains("unknown") || 
e.getMessage().toLowerCase().contains("cannot be resolved"));
-         }
++      // verify data
++      try (final ResultSet rs = stmt.executeQuery("SELECT * FROM tab1_new 
ORDER BY time")) {
++        assertTrue(rs.next());
++        assertEquals(1, rs.getLong(1));
++        assertEquals(1, rs.getInt("c1_new"));
++        assertEquals(10, rs.getInt("c2"));
 +
-         // use final name
-         stmt.execute("INSERT INTO tab1_new (time, c1_final, c2) VALUES (3, 3, 
30)");
-         try (final ResultSet rs = stmt.executeQuery("SELECT count(*) FROM 
tab1_new")) {
-           if (rs.next()) {
-             assertEquals(3L, rs.getLong(1));
-           } else {
-             fail();
-           }
++        assertTrue(rs.next());
++        assertEquals(2, rs.getLong(1));
++        assertEquals(2, rs.getInt("c1_new"));
++        assertEquals(20, rs.getInt("c2"));
++
++        assertFalse(rs.next());
++      }
++
++      // rename column again on the renamed table and verify
++      stmt.execute("ALTER TABLE tab1_new RENAME COLUMN c1_new TO c1_final");
++      try {
++        // old column identifier should fail
++        stmt.execute("INSERT INTO tab1_new (time, c1_new) VALUES (3, 3)");
++        fail();
++      } catch (final SQLException e) {
++        assertTrue(
++            e.getMessage().startsWith("616")
++                || e.getMessage().toLowerCase().contains("unknown")
++                || e.getMessage().toLowerCase().contains("cannot be 
resolved"));
++      }
++
++      // use final name
++      stmt.execute("INSERT INTO tab1_new (time, c1_final, c2) VALUES (3, 3, 
30)");
++      try (final ResultSet rs = stmt.executeQuery("SELECT count(*) FROM 
tab1_new")) {
++        if (rs.next()) {
++          assertEquals(3L, rs.getLong(1));
++        } else {
++          fail();
 +        }
 +      }
 +    }
++  }
  }
diff --cc 
iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index d85caa47dbc,e51d1a43299..582ffd16220
--- 
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
@@@ -111,9 -108,10 +112,11 @@@ import org.apache.iotdb.confignode.cons
  import 
org.apache.iotdb.confignode.consensus.response.template.TemplateSetInfoResp;
  import org.apache.iotdb.confignode.consensus.response.ttl.ShowTTLResp;
  import 
org.apache.iotdb.confignode.consensus.statemachine.ConfigRegionStateMachine;
 +import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
  import org.apache.iotdb.confignode.manager.consensus.ConsensusManager;
  import org.apache.iotdb.confignode.manager.cq.CQManager;
+ import 
org.apache.iotdb.confignode.manager.externalservice.ExternalServiceInfo;
+ import 
org.apache.iotdb.confignode.manager.externalservice.ExternalServiceManager;
  import org.apache.iotdb.confignode.manager.load.LoadManager;
  import 
org.apache.iotdb.confignode.manager.load.cache.node.NodeHeartbeatSample;
  import org.apache.iotdb.confignode.manager.node.ClusterNodeStartUtils;
diff --cc 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/FileLoaderUtils.java
index ec8b73d1c4f,70f3ce5e0e6..dc79dc560cc
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/FileLoaderUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/FileLoaderUtils.java
@@@ -124,8 -116,10 +124,9 @@@ public class FileLoaderUtils 
            SchemaUtils.changeMetadataModified(timeSeriesMetadata, 
seriesPath.getSeriesType());
            long t2 = System.nanoTime();
            List<ModEntry> pathModifications =
 -              context.getPathModifications(
 -                  resource, seriesPath.getDeviceId(), 
seriesPath.getMeasurement());
 +              context.getPathModifications(resource, deviceId, measurement);
-           timeSeriesMetadata.setModified(!pathModifications.isEmpty());
+           timeSeriesMetadata.setModified(
+               timeSeriesMetadata.isModified() || 
!pathModifications.isEmpty());
            timeSeriesMetadata.setChunkMetadataLoader(
                new DiskChunkMetadataLoader(resource, context, 
globalTimeFilter, pathModifications));
            int modificationCount = pathModifications.size();
diff --cc 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
index 7bbf1964d90,b8101fbd443..ebcfd0c040a
--- 
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
@@@ -3496,13 -3249,17 +3496,15 @@@ public class DataRegion implements IDat
          continue;
        }
  
 -      // the tsfile may not be closed here, it should not be added in 
deletedByFiles
 -      if (!sealedTsFile.isClosed()) {
 -        deletedByMods.add(sealedTsFile);
 -        continue;
 -      }
 -
        ITimeIndex timeIndex = sealedTsFile.getTimeIndex();
 +      EvolvedSchema evolvedSchema = sealedTsFile.getMergedEvolvedSchema();
  
++      // the tsfile may not be closed here, it should not be added in 
deletedByFiles
        if ((timeIndex instanceof ArrayDeviceTimeIndex)
-           && (deletion.getType() == ModType.TABLE_DELETION)) {
 -          && (deletion.getType() == ModEntry.ModType.TABLE_DELETION)) {
++          && (deletion.getType() == ModType.TABLE_DELETION)
++          && sealedTsFile.isClosed()) {
          ArrayDeviceTimeIndex deviceTimeIndex = (ArrayDeviceTimeIndex) 
timeIndex;
 +
          Set<IDeviceID> devicesInFile = deviceTimeIndex.getDevices();
          boolean onlyOneTable = false;
  

Reply via email to