Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -401,7 +401,7 @@ public void testInsertUnsupportedTimeExpressions() throws SQLException {
statement.execute(
"CREATE TABLE rejected_custom_time_expression "
+ "(device_id STRING TAG, event_time TIMESTAMP TIME, value INT64 FIELD)");
String[] expressions = {"1735660800000 + 1000", "?", "1.5", "true", "abs(1)"};
String[] expressions = {"?", "1.5", "true", "abs(1)"};
for (String expression : expressions) {
for (String columns : new String[] {" (time, device_id, value)", ""}) {
assertUnsupportedInsertExpression(
Expand Down Expand Up @@ -453,7 +453,10 @@ private static void assertUnsupportedInsertExpression(Statement statement, Strin
SQLException exception = assertThrows(SQLException.class, () -> statement.execute(sql));
assertEquals(sql, TSStatusCode.SEMANTIC_ERROR.getStatusCode(), exception.getErrorCode());
String message = exception.getMessage();
assertTrue(message, message.contains("Unsupported expression:"));
assertTrue(
message,
message.contains("Unsupported expression:")
|| message.contains("Insert expression must be constant after constant folding:"));
assertFalse(message, message.contains("ClassCastException"));
assertFalse(message, message.contains("cannot be cast"));
assertFalse(message, message.contains("org.apache.iotdb"));
Expand All @@ -467,7 +470,12 @@ public void testInsertSupportedTimeValues() throws SQLException {
statement.execute(
"CREATE TABLE supported_time_expression (device_id STRING TAG, value INT64 FIELD)");
String[] expressions = {
"1735660800000", "'2025-01-01T00:00:00+08:00'", "NOW()", "NOW() + 1d", "NOW() - 1d"
"1735660800000",
"'2025-01-01T00:00:00+08:00'",
"1735660799000 + 1000",
"NOW()",
"NOW() + 1d",
"NOW() - 1d"
};
for (boolean explicitColumns : new boolean[] {true, false}) {
for (int i = 0; i < expressions.length; i++) {
Expand All @@ -491,10 +499,10 @@ public void testInsertSupportedTimeValues() throws SQLException {
+ "'")) {
assertTrue(resultSet.next());
long timestamp = resultSet.getLong(1);
if (i < 2) {
if (i < 3) {
assertEquals(1735660800000L, timestamp);
} else {
long offset = i == 3 ? 86400000L : i == 4 ? -86400000L : 0;
long offset = i == 4 ? 86400000L : i == 5 ? -86400000L : 0;
// Allow clock skew between the test client and cluster nodes.
assertTrue(timestamp >= before + offset - 10000);
assertTrue(timestamp <= after + offset + 10000);
Expand All @@ -507,6 +515,44 @@ public void testInsertSupportedTimeValues() throws SQLException {
}
}

@Test
public void testInsertFoldedPredicates() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getTableConnection();
Statement statement = connection.createStatement()) {
statement.execute("USE test");
statement.execute("CREATE TABLE folded_predicates (device_id STRING TAG, value INT32 FIELD)");
String[] predicates = {
"1 + 1 IN (2, 3)",
"2 IN (1 + 1, 3)",
"1 + 1 IN (2.0, 3.0)",
"1.0 < (0.0 / 0.0)",
"(0.0 / 0.0) >= 1.0",
"(0.0 / 0.0) = (0.0 / 0.0)",
"(0.0 / 0.0) <> 1.0"
};
for (boolean explicitColumns : new boolean[] {true, false}) {
for (int i = 0; i < predicates.length; i++) {
String deviceId = "d" + explicitColumns + i;
statement.execute(
"INSERT INTO folded_predicates"
+ (explicitColumns ? " (time, device_id, value)" : "")
+ " VALUES (1, '"
+ deviceId
+ "', if("
+ predicates[i]
+ ", 11, 22))");
try (ResultSet resultSet =
statement.executeQuery(
"SELECT value FROM folded_predicates WHERE device_id = '" + deviceId + "'")) {
assertTrue(resultSet.next());
assertEquals(predicates[i], i < 3 ? 11 : 22, resultSet.getInt(1));
assertFalse(resultSet.next());
}
}
}
}
}

@Test
public void testInsertNaN() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@ public void insertWrongTimeSqlTest()
session.executeNonQueryStatement("USE \"db1\"");
// Include a FIELD column so schema validation does not mask invalid timestamps.
session.executeNonQueryStatement(
"create table wrong_time(color string tag, device_id string tag,city string attribute, value int32 field)");
"create table wrong_time(color string tag, device_id string tag,city string attribute,"
+ " value int32 field)");
try {
session.executeNonQueryStatement("insert into wrong_time values('aa','bb','cc','dd',1)");
fail("No exception thrown");
Expand All @@ -281,11 +282,17 @@ public void insertWrongTimeSqlTest()
"701: Input time format aa error. Input like yyyy-MM-dd HH:mm:ss, yyyy-MM-ddTHH:mm:ss or refer to user document for more info.",
e.getMessage());
}
try {
session.executeNonQueryStatement("insert into wrong_time values(1+1,'bb','cc','dd',1)");
fail("No exception thrown");
} catch (StatementExecutionException e) {
assertEquals("701: Unsupported expression: (1 + 1)", e.getMessage());
session.executeNonQueryStatement("insert into wrong_time values(1+1,'bb','cc','dd',1)");
try (SessionDataSet dataSet =
session.executeQueryStatement("select * from wrong_time where time = 2")) {
assertTrue(dataSet.hasNext());
RowRecord rowRecord = dataSet.next();
assertEquals(2L, rowRecord.getFields().get(0).getLongV());
assertEquals("bb", rowRecord.getFields().get(1).getBinaryV().toString());
assertEquals("cc", rowRecord.getFields().get(2).getBinaryV().toString());
assertEquals("dd", rowRecord.getFields().get(3).getBinaryV().toString());
assertEquals(1, rowRecord.getFields().get(4).getIntV());
assertFalse(dataSet.hasNext());
}
try {
session.executeNonQueryStatement("insert into wrong_time values(1.0,'bb','cc','dd',1)");
Expand Down Expand Up @@ -347,6 +354,14 @@ public void insertRelationalSqlTest()
row, "tag:" + row, "attr:" + row, row));
}

session.executeNonQueryStatement(
"INSERT INTO table1 (time, tag1, attr1, m1) "
+ "VALUES (if(true, 50, 0), if(true, 'tag:50', 'x'), "
+ "if(false, 'x', 'attr:50'), if(true, 50.0, 0.0))");
session.executeNonQueryStatement(
"INSERT INTO table1 VALUES (if(true, 51, 0), if(true, 'tag:51', 'x'), "
+ "if(true, 'attr:51', 'x'), if(false, 0, 51))");

SessionDataSet dataSet = session.executeQueryStatement("select * from table1 order by time");
int cnt = 0;
while (dataSet.hasNext()) {
Expand All @@ -357,7 +372,7 @@ public void insertRelationalSqlTest()
assertEquals(timestamp * 1.0, rowRecord.getFields().get(3).getDoubleV(), 0.0001);
cnt++;
}
assertEquals(50, cnt);
assertEquals(52, cnt);

// sql cannot create column
assertThrows(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4037,6 +4037,39 @@ private DataNodeQueryMessages() {}
public static final String EXCEPTION_LOAD_CONSENSUS_INVALID_PIECE_REF_F3498507 =
"Invalid LOAD consensus piece ref: path %s, offset %d, size %d";


public static final String EXCEPTION_DATABASENAME_IS_NULL_A811DE1B =
"databaseName is null";

public static final String EXCEPTION_VALUES_IS_NULL_A580EDAA =
"values is null";

public static final String EXCEPTION_ZONEID_IS_NULL_7DAA5E2C =
"zoneId is null";

public static final String EXCEPTION_INSERT_TARGET_TABLE_DOES_NOT_EXIST_ARG_ARG_78F05787 =
"Insert target table does not exist: %s.%s";

public static final String EXCEPTION_EXPRESSIONS_AND_COLUMNS_DO_NOT_MATCH_EXPRESSIONS_SIZE_ARG_COLUMNS_SIZE_ARG_F933A8C1 =
"expressions and columns do not match, expressions size: %s, columns size: %s";

public static final String EXCEPTION_INSERT_EXPRESSION_MUST_BE_CONSTANT_AFTER_CONSTANT_FOLDING_ARG_FOLDED_TO_ARG_D9EE1433 =
"Insert expression must be constant after constant folding: %s (folded to %s)";

public static final String EXCEPTION_CANNOT_EVALUATE_INSERT_EXPRESSION_AS_A_CONSTANT_ARG_ARG_F478C134 =
"Cannot evaluate insert expression as a constant: %s. %s";

public static final String EXCEPTION_THE_ARG_IS_OUT_OF_RANGE_OF_INT_F8E58471 =
"The %s is out of range of int.";

public static final String EXCEPTION_THE_ARG_IS_OUT_OF_RANGE_OF_LONG_9B1C872A =
"The %s is out of range of long.";

public static final String EXCEPTION_INT_OVERFLOW_ARG_ARG_BB287017 =
"int overflow: %s / %s";

public static final String EXCEPTION_LONG_OVERFLOW_ARG_ARG_46CC95E2 =
"long overflow: %s / %s";
public static final String EXCEPTION_CHUNKDATA_CONTAINS_NO_PHYSICAL_CHUNK_607BCFC8 =
"ChunkData contains no physical chunk";
public static final String EXCEPTION_DEVICE_CANNOT_BE_NULL_F1EB20B6 = "device cannot be null";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4793,6 +4793,39 @@ private DataNodeQueryMessages() {}
public static final String EXCEPTION_LOAD_CONSENSUS_INVALID_PIECE_REF_F3498507 =
"无效的 LOAD 共识分片引用:路径 %s,偏移 %d,大小 %d";


public static final String EXCEPTION_DATABASENAME_IS_NULL_A811DE1B =
"databaseName 为空";

public static final String EXCEPTION_VALUES_IS_NULL_A580EDAA =
"values 为空";

public static final String EXCEPTION_ZONEID_IS_NULL_7DAA5E2C =
"zoneId 为空";

public static final String EXCEPTION_INSERT_TARGET_TABLE_DOES_NOT_EXIST_ARG_ARG_78F05787 =
"写入目标表不存在:%s.%s";

public static final String EXCEPTION_EXPRESSIONS_AND_COLUMNS_DO_NOT_MATCH_EXPRESSIONS_SIZE_ARG_COLUMNS_SIZE_ARG_F933A8C1 =
"表达式与列不匹配,表达式数量:%s,列数量:%s";

public static final String EXCEPTION_INSERT_EXPRESSION_MUST_BE_CONSTANT_AFTER_CONSTANT_FOLDING_ARG_FOLDED_TO_ARG_D9EE1433 =
"写入表达式在常量折叠后必须为常量:%s(折叠结果为 %s)";

public static final String EXCEPTION_CANNOT_EVALUATE_INSERT_EXPRESSION_AS_A_CONSTANT_ARG_ARG_F478C134 =
"无法将写入表达式计算为常量:%s。%s";

public static final String EXCEPTION_THE_ARG_IS_OUT_OF_RANGE_OF_INT_F8E58471 =
"%s 超出 int 的范围。";

public static final String EXCEPTION_THE_ARG_IS_OUT_OF_RANGE_OF_LONG_9B1C872A =
"%s 超出 long 的范围。";

public static final String EXCEPTION_INT_OVERFLOW_ARG_ARG_BB287017 =
"int 溢出:%s / %s";

public static final String EXCEPTION_LONG_OVERFLOW_ARG_ARG_46CC95E2 =
"long 溢出:%s / %s";
public static final String EXCEPTION_CHUNKDATA_CONTAINS_NO_PHYSICAL_CHUNK_607BCFC8 =
"ChunkData 中不包含任何物理 chunk";
public static final String EXCEPTION_DEVICE_CANNOT_BE_NULL_F1EB20B6 = "device 不能为 null";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,17 @@ public List<WritePlanNode> splitByPartition(IAnalysis analysis) {
List<WritePlanNode> writePlanNodeList = new ArrayList<>();
Map<TRegionReplicaSet, RelationalInsertRowsNode> splitMap = new HashMap<>();
List<TEndPoint> redirectInfo = new ArrayList<>();
String databaseName = getDatabaseName(analysis);
for (int i = 0; i < getInsertRowNodeList().size(); i++) {
InsertRowNode insertRowNode = getInsertRowNodeList().get(i);
// Data region for insert row node
// each row may belong to different database, pass null for auto-detection
TRegionReplicaSet dataRegionReplicaSet =
analysis
.getDataPartitionInfo()
.getDataRegionReplicaSetForWriting(
insertRowNode.getDeviceID(),
TimePartitionUtils.getTimePartitionSlot(insertRowNode.getTime()),
analysis.getDatabaseName());
databaseName);

// Collect redirectInfo
redirectInfo.add(dataRegionReplicaSet.getDataNodeLocations().get(0).getClientRpcEndPoint());
Expand All @@ -230,6 +230,14 @@ public List<WritePlanNode> splitByPartition(IAnalysis analysis) {
return writePlanNodeList;
}

private String getDatabaseName(IAnalysis analysis) {
if (analysis.getDataPartitionInfo() != null
&& analysis.getDataPartitionInfo().getDataPartitionMap().size() == 1) {
return analysis.getDataPartitionInfo().getDataPartitionMap().keySet().iterator().next();
}
return analysis.getDatabaseName();
}

public RelationalInsertRowsNode emptyClone() {
return new RelationalInsertRowsNode(this.getPlanNodeId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertRow;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertRows;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertTablet;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.InsertValues;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadTsFile;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.PipeEnriched;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Property;
Expand Down Expand Up @@ -1335,13 +1336,18 @@
}

private Scope visitInsert(WrappedInsertStatement insert, Optional<Scope> scope) {
if (insert instanceof InsertValues) {
((InsertValues) insert)
.materialize(new PlannerContext(metadata, typeManager), sessionContext);
}

final Scope ret = Scope.create();

final MPPQueryContext context = insert.getContext();
InsertBaseStatement innerInsert = insert.getInnerTreeStatement();
innerInsert.toLowerCaseForDevicePath();

innerInsert =

Check warning on line 1350 in iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this instanceof check and cast with 'instanceof InsertValues insertvalues'

See more on https://sonarcloud.io/project/issues?id=apache_iotdb&issues=AaGv4TAUbXXvKWQwlP99&open=AaGv4TAUbXXvKWQwlP99&pullRequest=17850
AnalyzeUtils.analyzeInsert(
context,
innerInsert,
Expand Down
Loading
Loading