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