diff --git 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 index e88b04d824870..3104a7cd9327b 100644 --- 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 @@ -51,6 +51,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Set; import static org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.describeTableColumnHeaders; import static org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.describeTableDetailsColumnHeaders; @@ -761,14 +762,55 @@ public void testTreeViewTable() throws Exception { try (final Connection connection = EnvFactory.getEnv().getConnection(); final Statement statement = connection.createStatement()) { statement.execute("create database root.a.b"); - statement.execute("create timeSeries root.a.b.c.s1 int32"); + statement.execute("create timeSeries root.a.b.c.S1 int32"); statement.execute("create timeSeries root.a.b.c.s2 string"); - statement.execute("create timeSeries root.a.b.s1 int32"); - statement.execute("create timeSeries root.a.b.d.s1 boolean"); - statement.execute("create timeSeries root.a.b.c.f.g.h.s1 int32"); + statement.execute("create timeSeries root.a.b.S1 int32"); + } catch (SQLException e) { + fail(e.getMessage()); + } + + try (final Connection connection = + EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + final Statement statement = connection.createStatement()) { + statement.execute("create database tree_view_db"); + statement.execute("use tree_view_db"); + statement.execute("create table view tree_table (tag1 tag, tag2 tag) as root.a.**"); + statement.execute("drop view tree_table"); + } + + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { + statement.execute("create timeSeries root.a.b.d.s1 int32"); + } catch (SQLException e) { + fail(e.getMessage()); + } + + try (final Connection connection = + EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + final Statement statement = connection.createStatement()) { + statement.execute("use tree_view_db"); + + try { + statement.execute("create table view tree_table (tag1 tag, tag2 tag) as root.a.**"); + fail(); + } catch (final SQLException e) { + final Set result = + new HashSet<>( + Arrays.asList( + "617: The measurements s1 and S1 share the same lower case when auto detecting type, please check", + "617: The measurements S1 and s1 share the same lower case when auto detecting type, please check")); + assertTrue(result.contains(e.getMessage())); + } + } + + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { + statement.execute("drop timeSeries root.a.b.d.s1"); + statement.execute("create timeSeries root.a.b.d.S1 boolean"); + statement.execute("create timeSeries root.a.b.c.f.g.h.S1 int32"); // Put schema cache - statement.execute("select s1, s2 from root.a.b.c"); + statement.execute("select S1, s2 from root.a.b.c"); } catch (SQLException e) { fail(e.getMessage()); } @@ -776,18 +818,52 @@ public void testTreeViewTable() throws Exception { try (final Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); final Statement statement = connection.createStatement()) { - statement.execute("create database tree_view_db"); statement.execute("use tree_view_db"); + try { statement.execute("create table view tree_table (tag1 tag, tag2 tag) as root.a.**"); fail(); } catch (final SQLException e) { assertEquals( - "614: Multiple types encountered when auto detecting type of measurement 's1', please check", + "614: Multiple types encountered when auto detecting type of measurement 'S1', please check", e.getMessage()); } + + try { + statement.execute( + "create table view tree_table (tag1 tag, tag2 tag, S1 field) as root.a.**"); + fail(); + } catch (final SQLException e) { + assertEquals( + "614: Multiple types encountered when auto detecting type of measurement 'S1', please check", + e.getMessage()); + } + } + + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { + statement.execute("create timeSeries root.a.b.e.s1 int32"); + } catch (SQLException e) { + fail(e.getMessage()); + } + + try (final Connection connection = + EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + final Statement statement = connection.createStatement()) { + statement.execute("use tree_view_db"); + + // Temporary + try { + statement.execute( + "create or replace table view tree_table (tag1 tag, tag2 tag, S1 int32 field, s3 boolean from S1) as root.a.**"); + fail(); + } catch (final SQLException e) { + assertEquals( + "701: The duplicated source measurement S1 is unsupported yet.", e.getMessage()); + } + statement.execute( - "create or replace table view tree_table (tag1 tag, tag2 tag, s1 int32 field, s3 from s2) as root.a.**"); + "create or replace table view tree_table (tag1 tag, tag2 tag, S1 int32 field, s3 from s2) as root.a.**"); statement.execute("alter view tree_table rename to view_table"); statement.execute("alter view view_table rename column s1 to s11"); statement.execute("alter view view_table set properties ttl=100"); @@ -808,13 +884,13 @@ public void testTreeViewTable() throws Exception { "tag2,STRING,TAG,", "s11,INT32,FIELD,", "s3,STRING,FIELD,"))); - // Currently we show the device even if all of its measurements does not match the type, + // Currently we show the device even if all of its measurements does not match, // the handling logic at query because validate it at fetching will potentially cause a // lot of time TestUtils.assertResultSetEqual( statement.executeQuery("show devices from view_table where tag1 = 'b'"), "tag1,tag2,", - new HashSet<>(Arrays.asList("b,c,", "b,null,", "b,d,"))); + new HashSet<>(Arrays.asList("b,c,", "b,null,", "b,d,", "b,e,"))); TestUtils.assertResultSetEqual( statement.executeQuery("show devices from view_table where tag1 = 'b' and tag2 is null"), "tag1,tag2,", @@ -822,7 +898,7 @@ public void testTreeViewTable() throws Exception { TestUtils.assertResultSetEqual( statement.executeQuery("count devices from view_table"), "count(devices),", - Collections.singleton("3,")); + Collections.singleton("4,")); } // Test tree session diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java index a3114333bcc92..25afac6797445 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java @@ -111,6 +111,8 @@ public enum TSStatusCode { DATA_TYPE_MISMATCH(614), COLUMN_CATEGORY_MISMATCH(615), COLUMN_NOT_EXISTS(616), + MEASUREMENT_NAME_CONFLICT(617), + WAL_ENTRY_TOO_LARGE(620), // Query Engine diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 index fca3fb47cffbb..4ba4196dad668 100644 --- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 +++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 @@ -60,6 +60,7 @@ keyWords | CLEAR | CLUSTER | CLUSTERID + | COMMENT | CONCAT | CONDITION | CONFIGNODE @@ -87,6 +88,7 @@ keyWords | DATASET | DEACTIVATE | DEBUG + | DEFAULT | DELETE | DESC | DESCRIBE @@ -105,6 +107,7 @@ keyWords | EXPLAIN | EXTRACTOR | FALSE + | FIELD | FILL | FILE | FIRST @@ -198,6 +201,7 @@ keyWords | RESOURCE | REPAIR | REPLACE + | RESTRICT | REVOKE | ROLE | ROUND @@ -229,6 +233,7 @@ keyWords | SUBSTRING | SYSTEM | TABLE + | TAG | TAGS | TAIL | TASK diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 index 5ffc89370bc42..2dfd93e5b3931 100644 --- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 +++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 @@ -789,7 +789,8 @@ createTableView ; viewColumnDefinition - : identifier (type)? (columnCategory=(TAG | TIME | FIELD))? comment? + : identifier columnCategory=(TAG | TIME | FIELD) comment? + | identifier type (columnCategory=(TAG | TIME | FIELD))? comment? | identifier (type)? (columnCategory=FIELD)? FROM original_measurement=identifier comment? ; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/TreeDeviceViewFieldDetector.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/TreeDeviceViewFieldDetector.java index 3f5aec7fba238..3527e62e7a34c 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/TreeDeviceViewFieldDetector.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/TreeDeviceViewFieldDetector.java @@ -28,6 +28,7 @@ import org.apache.iotdb.commons.schema.table.TreeViewSchema; import org.apache.iotdb.commons.schema.table.TsTable; import org.apache.iotdb.commons.schema.table.column.FieldColumnSchema; +import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema; import org.apache.iotdb.commons.utils.StatusUtils; import org.apache.iotdb.confignode.client.async.CnToDnAsyncRequestType; import org.apache.iotdb.confignode.manager.ConfigManager; @@ -44,28 +45,30 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; public class TreeDeviceViewFieldDetector { private static final Logger LOGGER = LoggerFactory.getLogger(TreeDeviceViewFieldDetector.class); - private static final int MEASUREMENT_TRIMMING_THRESHOLD = 1000; private final ConfigManager configManager; private final PartialPath path; private final TsTable table; - private final Map fields; + private final Map> fields; private TDeviceViewResp result = new TDeviceViewResp(StatusUtils.OK, new ConcurrentHashMap<>()); + private final Map lowerCase2OriginalMap = new HashMap<>(); public TreeDeviceViewFieldDetector( final ConfigManager configManager, final TsTable table, - final Map fields) { + final Map> fields) { this.configManager = configManager; this.path = TreeViewSchema.getPrefixPattern(table); this.table = table; @@ -77,7 +80,7 @@ public TSStatus detectMissingFieldTypes() { new TreeDeviceViewFieldDetectionTaskExecutor( configManager, getLatestSchemaRegionMap(), - table.getIdNums(), + table.getTagNum(), TreeViewSchema.isRestrict(table)) .execute(); if (result.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -86,47 +89,56 @@ public TSStatus detectMissingFieldTypes() { result .getDeviewViewFieldTypeMap() .forEach( - (field, type) -> - table.addColumnSchema( - new FieldColumnSchema(field, TSDataType.getTsDataType(type)))); + (field, type) -> { + final FieldColumnSchema columnSchema = + new FieldColumnSchema(field, TSDataType.getTsDataType(type)); + if (!field.equals(lowerCase2OriginalMap.get(field))) { + TreeViewSchema.setOriginalName(columnSchema, lowerCase2OriginalMap.get(field)); + } + table.addColumnSchema(columnSchema); + }); } else { - final Map unknownFields = - Objects.isNull(fields) - ? table.getColumnList().stream() - .filter( - columnSchema -> - columnSchema instanceof FieldColumnSchema - && columnSchema.getDataType() == TSDataType.UNKNOWN) - .collect( - Collectors.toMap( - fieldColumnSchema -> - Objects.nonNull(TreeViewSchema.getOriginalName(fieldColumnSchema)) - ? TreeViewSchema.getOriginalName(fieldColumnSchema) - : fieldColumnSchema.getColumnName(), - FieldColumnSchema.class::cast)) - : fields; + final Map> unknownFields; + if (Objects.isNull(fields)) { + unknownFields = new HashMap<>(); + for (final TsTableColumnSchema schema : table.getColumnList()) { + if (!(schema instanceof FieldColumnSchema) + || schema.getDataType() != TSDataType.UNKNOWN) { + continue; + } + final String key = TreeViewSchema.getSourceName(schema); + if (!unknownFields.containsKey(key)) { + unknownFields.put(key, new HashSet<>()); + } + unknownFields.get(key).add((FieldColumnSchema) schema); + } + } else { + unknownFields = fields; + } + if (unknownFields.isEmpty()) { return StatusUtils.OK; } new TreeDeviceViewFieldDetectionTaskExecutor( configManager, getLatestSchemaRegionMap(), - table.getIdNums(), + table.getTagNum(), TreeViewSchema.isRestrict(table), - unknownFields.size() <= MEASUREMENT_TRIMMING_THRESHOLD - ? unknownFields.keySet() - : null) + unknownFields.keySet()) .execute(); if (result.getStatus().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { return result.getStatus(); } - for (final Map.Entry unknownField : unknownFields.entrySet()) { + for (final Map.Entry> unknownField : + unknownFields.entrySet()) { if (result.getDeviewViewFieldTypeMap().containsKey(unknownField.getKey())) { unknownField .getValue() - .setDataType( - TSDataType.getTsDataType( - result.getDeviewViewFieldTypeMap().get(unknownField.getKey()))); + .forEach( + field -> + field.setDataType( + TSDataType.getTsDataType( + result.getDeviewViewFieldTypeMap().get(unknownField.getKey())))); } else { return new TSStatus(TSStatusCode.TYPE_NOT_FOUND.getStatusCode()) .setMessage( @@ -226,9 +238,13 @@ private void mergeDeviceViewResp(final TDeviceViewResp resp) { resp.getDeviewViewFieldTypeMap() .forEach( (measurement, type) -> { - if (!result.getDeviewViewFieldTypeMap().containsKey(measurement)) { - result.getDeviewViewFieldTypeMap().put(measurement, type); - } else { + final String fieldName = measurement.toLowerCase(Locale.ENGLISH); + + // Field type collection + if (!result.getDeviewViewFieldTypeMap().containsKey(fieldName)) { + result.getDeviewViewFieldTypeMap().put(fieldName, type); + } else if (!Objects.equals( + result.getDeviewViewFieldTypeMap().get(fieldName), type)) { result.setStatus( RpcUtils.getStatus( TSStatusCode.DATA_TYPE_MISMATCH, @@ -236,6 +252,18 @@ private void mergeDeviceViewResp(final TDeviceViewResp resp) { "Multiple types encountered when auto detecting type of measurement '%s', please check", measurement))); } + + // Field name detection + if (!lowerCase2OriginalMap.containsKey(fieldName)) { + lowerCase2OriginalMap.put(fieldName, measurement); + } else if (!Objects.equals(lowerCase2OriginalMap.get(fieldName), measurement)) { + result.setStatus( + RpcUtils.getStatus( + TSStatusCode.MEASUREMENT_NAME_CONFLICT, + String.format( + "The measurements %s and %s share the same lower case when auto detecting type, please check", + lowerCase2OriginalMap.get(fieldName), measurement))); + } }); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/AddViewColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/AddViewColumnProcedure.java index 84e4025548def..5418822aafb99 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/AddViewColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/AddViewColumnProcedure.java @@ -23,7 +23,6 @@ import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.schema.table.TreeViewSchema; import org.apache.iotdb.commons.schema.table.column.FieldColumnSchema; -import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory; import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema; import org.apache.iotdb.confignode.persistence.schema.TreeDeviceViewFieldDetector; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; @@ -36,10 +35,11 @@ import java.io.DataOutputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.Set; public class AddViewColumnProcedure extends AddTableColumnProcedure { public AddViewColumnProcedure(final boolean isGeneratedByPipe) { @@ -58,19 +58,19 @@ public AddViewColumnProcedure( @Override protected void columnCheck(final ConfigNodeProcedureEnv env) { super.columnCheck(env); - final Map fields2Detect = - addedColumnList.stream() - .filter( - columnSchema -> - columnSchema.getColumnCategory() == TsTableColumnCategory.FIELD - && columnSchema.getDataType() == TSDataType.UNKNOWN) - .collect( - Collectors.toMap( - fieldColumnSchema -> - Objects.nonNull(TreeViewSchema.getOriginalName(fieldColumnSchema)) - ? TreeViewSchema.getOriginalName(fieldColumnSchema) - : fieldColumnSchema.getColumnName(), - FieldColumnSchema.class::cast)); + + final Map> fields2Detect = new HashMap<>(); + for (final TsTableColumnSchema schema : addedColumnList) { + if (!(schema instanceof FieldColumnSchema) || schema.getDataType() != TSDataType.UNKNOWN) { + continue; + } + final String key = TreeViewSchema.getSourceName(schema); + if (!fields2Detect.containsKey(key)) { + fields2Detect.put(key, new HashSet<>()); + } + fields2Detect.get(key).add((FieldColumnSchema) schema); + } + if (!fields2Detect.isEmpty()) { final TSStatus status = new TreeDeviceViewFieldDetector(env.getConfigManager(), table, fields2Detect) diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java index 451b820269a28..1505640ff90b5 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java @@ -1248,7 +1248,7 @@ public void preCreateTablePlanTest() throws IOException { preCreateTablePlan0.getTable().getColumnNum(), preCreateTablePlan1.getTable().getColumnNum()); Assert.assertEquals( - preCreateTablePlan0.getTable().getIdNums(), preCreateTablePlan1.getTable().getIdNums()); + preCreateTablePlan0.getTable().getTagNum(), preCreateTablePlan1.getTable().getTagNum()); } @Test @@ -1272,7 +1272,7 @@ public void preCreateTableViewPlanTest() throws IOException { preCreateTableViewPlan0.getTable().getColumnNum(), preCreateTablePlan1.getTable().getColumnNum()); Assert.assertEquals( - preCreateTableViewPlan0.getTable().getIdNums(), preCreateTablePlan1.getTable().getIdNums()); + preCreateTableViewPlan0.getTable().getTagNum(), preCreateTablePlan1.getTable().getTagNum()); Assert.assertEquals(preCreateTableViewPlan0.getStatus(), preCreateTablePlan1.getStatus()); } @@ -1929,8 +1929,8 @@ public void pipeCreateTablePlanTest() throws IOException { pipeCreateTableOrViewPlan0.getTable().getColumnNum(), pipeCreateTableOrViewPlan1.getTable().getColumnNum()); Assert.assertEquals( - pipeCreateTableOrViewPlan0.getTable().getIdNums(), - pipeCreateTableOrViewPlan1.getTable().getIdNums()); + pipeCreateTableOrViewPlan0.getTable().getTagNum(), + pipeCreateTableOrViewPlan1.getTable().getTagNum()); } @Test diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java index 2ea3a0bc434d6..73fe77e40e7ca 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTreeTest.java @@ -385,7 +385,7 @@ public void testTableSerialization() throws Exception { assertEquals(1, tables.size()); final TsTable table = tables.get(0); assertEquals("table" + i, table.getTableName()); - assertEquals(1, table.getIdNums()); + assertEquals(1, table.getTagNum()); assertEquals(4, table.getColumnNum()); } } diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/pipe/receiver/PipeEnrichedProcedureTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/pipe/receiver/PipeEnrichedProcedureTest.java index ff5b07821668d..53d025d6b2fcb 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/pipe/receiver/PipeEnrichedProcedureTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/pipe/receiver/PipeEnrichedProcedureTest.java @@ -414,7 +414,7 @@ public void createTableTest() throws IOException { createTableProcedure.getTable().getColumnNum(), deserializedProcedure.getTable().getColumnNum()); Assert.assertEquals( - createTableProcedure.getTable().getIdNums(), deserializedProcedure.getTable().getIdNums()); + createTableProcedure.getTable().getTagNum(), deserializedProcedure.getTable().getTagNum()); } @Test @@ -617,8 +617,8 @@ public void createTableViewTest() throws IOException { createTableViewProcedure.getTable().getColumnNum(), deserializedProcedure.getTable().getColumnNum()); Assert.assertEquals( - createTableViewProcedure.getTable().getIdNums(), - deserializedProcedure.getTable().getIdNums()); + createTableViewProcedure.getTable().getTagNum(), + deserializedProcedure.getTable().getTagNum()); } @Test diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedureTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedureTest.java index 2126f41f7041e..fab1bfb266013 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedureTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedureTest.java @@ -68,6 +68,6 @@ public void serializeDeserializeTest() throws IllegalPathException, IOException createTableProcedure.getTable().getColumnNum(), deserializedProcedure.getTable().getColumnNum()); Assert.assertEquals( - createTableProcedure.getTable().getIdNums(), deserializedProcedure.getTable().getIdNums()); + createTableProcedure.getTable().getTagNum(), deserializedProcedure.getTable().getTagNum()); } } diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableViewProcedureTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableViewProcedureTest.java index cf7372386e3f5..8d89fe58df5dd 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableViewProcedureTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableViewProcedureTest.java @@ -69,7 +69,7 @@ public void serializeDeserializeTest() throws IllegalPathException, IOException createTableViewProcedure.getTable().getColumnNum(), deserializedProcedure.getTable().getColumnNum()); Assert.assertEquals( - createTableViewProcedure.getTable().getIdNums(), - deserializedProcedure.getTable().getIdNums()); + createTableViewProcedure.getTable().getTagNum(), + deserializedProcedure.getTable().getTagNum()); } } diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedureTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedureTest.java index 4a20d65befb9b..0fb0d344356cb 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedureTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/view/CreateTableViewProcedureTest.java @@ -70,7 +70,7 @@ public void serializeDeserializeTest() throws IllegalPathException, IOException createTableViewProcedure.getTable().getColumnNum(), deserializedProcedure.getTable().getColumnNum()); Assert.assertEquals( - createTableViewProcedure.getTable().getIdNums(), - deserializedProcedure.getTable().getIdNums()); + createTableViewProcedure.getTable().getTagNum(), + deserializedProcedure.getTable().getTagNum()); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java index a23ce8bb8e3f4..b3d0cd80be2a5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TableDeviceQuerySource.java @@ -218,7 +218,7 @@ public void close() throws Exception { !TreeViewSchema.isTreeViewTable(table) ? new String[] {PATH_ROOT, database, tableName} : DataNodeTreeViewSchemaUtils.getPatternNodes(table), - DataNodeTableCache.getInstance().getTable(database, tableName).getIdNums(), + DataNodeTableCache.getInstance().getTable(database, tableName).getTagNum(), tagDeterminedPredicateList, TreeViewSchema.isRestrict(table)); } 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 eccfc71006971..610da9375b82e 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 @@ -213,11 +213,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import static org.apache.iotdb.commons.conf.IoTDBConstant.MAX_DATABASE_NAME_LENGTH; @@ -500,6 +502,7 @@ private Pair parseTable4CreateTableOrView( // TODO: Place the check at statement analyzer boolean hasTimeColumn = false; + final Set sourceNameSet = new HashSet<>(); for (final ColumnDefinition columnDefinition : node.getElements()) { final TsTableColumnCategory category = columnDefinition.getColumnCategory(); final String columnName = columnDefinition.getName().getValue(); @@ -514,7 +517,7 @@ private Pair parseTable4CreateTableOrView( throw new SemanticException( String.format("Columns in table shall not share the same name %s.", columnName)); } - table.addColumnSchema( + final TsTableColumnSchema schema = TableHeaderSchemaValidator.generateColumnSchema( category, columnName, @@ -523,7 +526,14 @@ private Pair parseTable4CreateTableOrView( columnDefinition instanceof ViewFieldDefinition && Objects.nonNull(((ViewFieldDefinition) columnDefinition).getFrom()) ? ((ViewFieldDefinition) columnDefinition).getFrom().getValue() - : null)); + : null); + if (!sourceNameSet.add(TreeViewSchema.getSourceName(schema))) { + throw new SemanticException( + String.format( + "The duplicated source measurement %s is unsupported yet.", + TreeViewSchema.getSourceName(schema))); + } + table.addColumnSchema(schema); } return new Pair<>(database, table); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java index 451e64ca0852f..0d2c719373c75 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java @@ -4627,10 +4627,22 @@ public Statement visitCreateTableView(final IoTDBSqlParser.CreateTableViewContex public ColumnDefinition parseViewColumnDefinition( final IoTDBSqlParser.ViewColumnDefinitionContext ctx) { - return Objects.nonNull(ctx.FROM()) + final Identifier rawColumnName = + new Identifier(parseIdentifier(ctx.identifier().get(0).getText())); + final Identifier columnName = lowerIdentifier(rawColumnName); + final TsTableColumnCategory columnCategory = getColumnCategory(ctx.columnCategory); + Identifier originalMeasurement = null; + + if (Objects.nonNull(ctx.FROM())) { + originalMeasurement = new Identifier(parseIdentifier(ctx.original_measurement.getText())); + } else if (columnCategory == FIELD && !columnName.equals(rawColumnName)) { + originalMeasurement = rawColumnName; + } + + return columnCategory == FIELD ? new ViewFieldDefinition( null, - lowerIdentifier(new Identifier(parseIdentifier(ctx.identifier().get(0).getText()))), + columnName, Objects.nonNull(ctx.type()) ? parseGenericType((IoTDBSqlParser.GenericTypeContext) ctx.type()) : null, @@ -4638,14 +4650,14 @@ public ColumnDefinition parseViewColumnDefinition( ctx.comment() == null ? null : parseStringLiteral(ctx.comment().STRING_LITERAL().getText()), - lowerIdentifier(new Identifier(parseIdentifier(ctx.original_measurement.getText())))) + originalMeasurement) : new ColumnDefinition( null, - lowerIdentifier(new Identifier(parseIdentifier(ctx.identifier().get(0).getText()))), + columnName, Objects.nonNull(ctx.type()) ? parseGenericType((IoTDBSqlParser.GenericTypeContext) ctx.type()) : null, - getColumnCategory(ctx.columnCategory), + columnCategory, null, ctx.comment() == null ? null diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java index 99fabf4cd60ff..0620f3b53839b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/SchemaPredicateUtil.java @@ -223,7 +223,7 @@ static List extractTagSingleMatchExpressionCases( final List>> index2FilterMapList, final TsTable tableInstance) { final List selectedExpressionCases = new ArrayList<>(); - final int idCount = tableInstance.getIdNums(); + final int idCount = tableInstance.getTagNum(); for (int i = 0; i < index2FilterMapList.size(); i++) { final Map> filterMap = index2FilterMapList.get(i); if (filterMap.size() == idCount diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java index 468ab424c858a..61f8689e7ecd3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java @@ -133,7 +133,7 @@ Map> fetchMissingDeviceSchemaForDataInsertion( final List columnHeaderList = coordinator.getQueryExecution(queryId).getDatasetHeader().getColumnHeaders(); - final int idLength = DataNodeTableCache.getInstance().getTable(database, table).getIdNums(); + final int idLength = DataNodeTableCache.getInstance().getTable(database, table).getTagNum(); final Map> fetchedDeviceSchema = new HashMap<>(); while (coordinator.getQueryExecution(queryId).hasNextResult()) { @@ -347,7 +347,7 @@ private boolean tryGetDeviceInCache( final List fetchPaths, final boolean isDirectDeviceQuery, final MPPQueryContext queryContext) { - final String[] idValues = new String[tableInstance.getIdNums()]; + final String[] idValues = new String[tableInstance.getTagNum()]; for (final List schemaFilters : idFilters.values()) { final TagFilter tagFilter = (TagFilter) schemaFilters.get(0); final SchemaFilter childFilter = tagFilter.getChild(); @@ -534,7 +534,7 @@ private void constructTableResults( final List deviceEntryList) { final Column[] columns = tsBlock.getValueColumns(); for (int i = 0; i < tsBlock.getPositionCount(); i++) { - final String[] nodes = new String[tableInstance.getIdNums() + 1]; + final String[] nodes = new String[tableInstance.getTagNum() + 1]; final Map attributeMap = new HashMap<>(); constructNodsArrayAndAttributeMap( attributeMap, @@ -566,7 +566,7 @@ private void constructTreeResults( final Map> deviceEntryMap) { final Column[] columns = tsBlock.getValueColumns(); for (int i = 0; i < tsBlock.getPositionCount(); i++) { - final String[] nodes = new String[tableInstance.getIdNums()]; + final String[] nodes = new String[tableInstance.getTagNum()]; constructNodsArrayAndAttributeMap( Collections.emptyMap(), nodes, null, columnHeaderList, columns, tableInstance, i); final IDeviceID deviceID = diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ViewFieldDefinition.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ViewFieldDefinition.java index f23144b7f2b46..376a8634f8bf7 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ViewFieldDefinition.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/ViewFieldDefinition.java @@ -36,7 +36,7 @@ public ViewFieldDefinition( final DataType type, final @Nullable String charsetName, final @Nullable String comment, - final Identifier from) { + final @Nullable Identifier from) { super(location, name, type, TsTableColumnCategory.FIELD, charsetName, comment); this.from = from; } 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 2a9988c34c107..6e0f789b76780 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 @@ -616,23 +616,32 @@ public Node visitSetTableViewProperties( @Override public Node visitViewColumnDefinition(final RelationalSqlParser.ViewColumnDefinitionContext ctx) { - return Objects.nonNull(ctx.FROM()) || Objects.nonNull(ctx.FIELD()) + final Identifier rawColumnName = (Identifier) visit(ctx.identifier().get(0)); + final Identifier columnName = lowerIdentifier(rawColumnName); + final TsTableColumnCategory columnCategory = getColumnCategory(ctx.columnCategory); + Identifier originalMeasurement = null; + + if (Objects.nonNull(ctx.FROM())) { + originalMeasurement = (Identifier) visit(ctx.original_measurement); + } else if (columnCategory == FIELD && !columnName.equals(rawColumnName)) { + originalMeasurement = rawColumnName; + } + + return columnCategory == FIELD ? new ViewFieldDefinition( getLocation(ctx), - lowerIdentifier((Identifier) visit(ctx.identifier().get(0))), + columnName, Objects.nonNull(ctx.type()) ? (DataType) visit(ctx.type()) : null, null, ctx.comment() == null ? null : ((StringLiteral) visit(ctx.comment().string())).getValue(), - Objects.nonNull(ctx.FROM()) - ? lowerIdentifier((Identifier) visit(ctx.original_measurement)) - : null) + originalMeasurement) : new ColumnDefinition( getLocation(ctx), - lowerIdentifier((Identifier) visit(ctx.identifier().get(0))), + columnName, Objects.nonNull(ctx.type()) ? (DataType) visit(ctx.type()) : null, - getColumnCategory(ctx.columnCategory), + columnCategory, null, ctx.comment() == null ? null diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java index 39fc5d5e23c5f..eea48fd2aeef7 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/TreeViewSchema.java @@ -26,6 +26,8 @@ import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema; import org.apache.iotdb.rpc.TSStatusCode; +import java.util.Objects; + public class TreeViewSchema { public static final String ORIGINAL_NAME = "__original_name"; public static final String TREE_PATH_PATTERN = "__tree_path_pattern"; @@ -61,6 +63,12 @@ public static PartialPath forceSeparateStringToPartialPath(final String string) return partialPath; } + public static String getSourceName(final TsTableColumnSchema schema) { + return Objects.nonNull(TreeViewSchema.getOriginalName(schema)) + ? TreeViewSchema.getOriginalName(schema) + : schema.getColumnName(); + } + public static String getOriginalName(final TsTableColumnSchema schema) { return schema.getProps().get(ORIGINAL_NAME); } 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 5a89192971d48..aa29ea6d42766 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 @@ -218,7 +218,7 @@ public int getColumnNum() { } } - public int getIdNums() { + public int getTagNum() { readWriteLock.readLock().lock(); try { return idNums;