Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4b3bb97
bug fix
Caideyipi May 8, 2025
d0abb0a
Update IoTDBTableIT.java
Caideyipi May 8, 2025
5b4ff41
Update IoTDBTableIT.java
Caideyipi May 8, 2025
e21aa55
Update IoTDBTableIT.java
Caideyipi May 8, 2025
0d80e38
Update IoTDBSqlParser.g4
Caideyipi May 8, 2025
be42160
Case -> From
Caideyipi May 8, 2025
b91f759
Bug fix & Refactor
Caideyipi May 8, 2025
365a919
Fix on CN
Caideyipi May 8, 2025
79df682
partial
Caideyipi May 8, 2025
78b883b
partial
Caideyipi May 8, 2025
1fe75b4
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 8, 2025
3c17bd3
Partial
Caideyipi May 9, 2025
5e6a8b0
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 9, 2025
fd2effa
Update IoTDBTableIT.java
Caideyipi May 9, 2025
4180701
Update IoTDBTableIT.java
Caideyipi May 9, 2025
881fd75
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 9, 2025
f7d4969
Update IoTDBTableIT.java
Caideyipi May 9, 2025
2854cf6
Fix
Caideyipi May 9, 2025
dea91f0
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 9, 2025
62a370d
Update IoTDBTableIT.java
Caideyipi May 9, 2025
e46d8d0
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 9, 2025
8d457b4
Update IoTDBTableIT.java
Caideyipi May 12, 2025
53af4fb
Update IoTDBTableIT.java
Caideyipi May 12, 2025
d9657da
Merge branch 'master' of https://github.com/apache/iotdb into may-add…
Caideyipi May 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -761,33 +762,108 @@ 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<String> 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());
}

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");
Expand All @@ -808,21 +884,21 @@ 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,",
Collections.singleton("b,null,"));
TestUtils.assertResultSetEqual(
statement.executeQuery("count devices from view_table"),
"count(devices),",
Collections.singleton("3,"));
Collections.singleton("4,"));
}

// Test tree session
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ keyWords
| CLEAR
| CLUSTER
| CLUSTERID
| COMMENT
| CONCAT
| CONDITION
| CONFIGNODE
Expand Down Expand Up @@ -87,6 +88,7 @@ keyWords
| DATASET
| DEACTIVATE
| DEBUG
| DEFAULT
| DELETE
| DESC
| DESCRIBE
Expand All @@ -105,6 +107,7 @@ keyWords
| EXPLAIN
| EXTRACTOR
| FALSE
| FIELD
| FILL
| FILE
| FIRST
Expand Down Expand Up @@ -198,6 +201,7 @@ keyWords
| RESOURCE
| REPAIR
| REPLACE
| RESTRICT
| REVOKE
| ROLE
| ROUND
Expand Down Expand Up @@ -229,6 +233,7 @@ keyWords
| SUBSTRING
| SYSTEM
| TABLE
| TAG
| TAGS
| TAIL
| TASK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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?
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, FieldColumnSchema> fields;
private final Map<String, Set<FieldColumnSchema>> fields;

private TDeviceViewResp result = new TDeviceViewResp(StatusUtils.OK, new ConcurrentHashMap<>());
private final Map<String, String> lowerCase2OriginalMap = new HashMap<>();

public TreeDeviceViewFieldDetector(
final ConfigManager configManager,
final TsTable table,
final Map<String, FieldColumnSchema> fields) {
final Map<String, Set<FieldColumnSchema>> fields) {
this.configManager = configManager;
this.path = TreeViewSchema.getPrefixPattern(table);
this.table = table;
Expand All @@ -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()) {
Expand All @@ -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<String, FieldColumnSchema> 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<String, Set<FieldColumnSchema>> 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<String, FieldColumnSchema> unknownField : unknownFields.entrySet()) {
for (final Map.Entry<String, Set<FieldColumnSchema>> 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(
Expand Down Expand Up @@ -226,16 +238,32 @@ 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,
String.format(
"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)));
}
});
}

Expand Down
Loading
Loading