Skip to content

Commit 187e454

Browse files
authored
Fix table delete with renamed time column (#17841)
* reviewed AnalyzeUtils * Fix delete with non-default time column
1 parent 99bf6d4 commit 187e454

7 files changed

Lines changed: 126 additions & 9 deletions

File tree

integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBDeletionTableIT.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,27 @@ public void testDelAfterFlush() throws SQLException {
414414
}
415415
}
416416

417+
@Test
418+
public void testDeleteWithRenamedTimeColumn() throws SQLException {
419+
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
420+
Statement statement = connection.createStatement()) {
421+
statement.execute("CREATE DATABASE time_column_rename");
422+
statement.execute("use time_column_rename");
423+
statement.execute("CREATE TABLE vehicle(ts time, deviceId STRING TAG, s0 INT32 FIELD)");
424+
statement.execute("INSERT INTO vehicle(ts, deviceId, s0) VALUES(1, 'd0', 1)");
425+
statement.execute("INSERT INTO vehicle(ts, deviceId, s0) VALUES(2, 'd0', 2)");
426+
427+
statement.execute("DELETE FROM vehicle WHERE ts <= 1");
428+
429+
try (ResultSet resultSet = statement.executeQuery("SELECT ts, s0 FROM vehicle")) {
430+
assertTrue(resultSet.next());
431+
assertEquals(2, resultSet.getLong("ts"));
432+
assertEquals(2, resultSet.getInt("s0"));
433+
assertFalse(resultSet.next());
434+
}
435+
}
436+
}
437+
417438
@Test
418439
public void testRangeDelete() throws SQLException {
419440
prepareData(4, 1);

iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ public final class DataNodeQueryMessages {
259259
"Left hand expression is not an identifier: ";
260260
public static final String THE_LEFT_HAND_VALUE_MUST_BE_AN_IDENTIFIER =
261261
"The left hand value must be an identifier: ";
262+
public static final String THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN =
263+
"The table '%s' does not contain a time column";
262264
public static final String THE_OPERATOR_OF_TAG_PREDICATE_MUST_BE_FOR =
263265
"The operator of tag predicate must be '=' for ";
264266
public static final String ONLY_TIME_FILTERS_ARE_SUPPORTED_IN_LAST_QUERY =

iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ public final class DataNodeQueryMessages {
258258
"左侧表达式不是标识符:";
259259
public static final String THE_LEFT_HAND_VALUE_MUST_BE_AN_IDENTIFIER =
260260
"左侧值必须是标识符:";
261+
public static final String THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN =
262+
"表 '%s' 不包含时间列";
261263
public static final String THE_OPERATOR_OF_TAG_PREDICATE_MUST_BE_FOR =
262264
"标签谓词的运算符必须为 '=',目标:";
263265
public static final String ONLY_TIME_FILTERS_ARE_SUPPORTED_IN_LAST_QUERY =

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullLiteral;
3838
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
3939
import org.apache.iotdb.commons.schema.table.TsTable;
40+
import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
4041
import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
4142
import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp;
4243
import org.apache.iotdb.db.i18n.DataNodeQueryMessages;
@@ -520,7 +521,7 @@ private static IDPredicate parseComparison(
520521
}
521522
Identifier identifier = (Identifier) left;
522523
// time predicate
523-
if (identifier.getValue().equalsIgnoreCase("time")) {
524+
if (identifier.getValue().equalsIgnoreCase(getTimeColumnName(table))) {
524525
long rightHandValue;
525526
if (right instanceof LongLiteral) {
526527
rightHandValue = ((LongLiteral) right).getParsedValue();
@@ -567,6 +568,17 @@ private static IDPredicate parseComparison(
567568
return combinePredicates(oldPredicate, newPredicate);
568569
}
569570

571+
private static String getTimeColumnName(final TsTable table) {
572+
final TsTableColumnSchema timeColumnSchema = table.getTimeColumnSchema();
573+
if (Objects.isNull(timeColumnSchema)) {
574+
throw new SemanticException(
575+
String.format(
576+
DataNodeQueryMessages.THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN,
577+
table.getTableName()));
578+
}
579+
return timeColumnSchema.getColumnName();
580+
}
581+
570582
private static IDPredicate getTagPredicate(
571583
ComparisonExpression comparisonExpression, Expression right, int tagColumnOrdinal) {
572584
if (comparisonExpression.getOperator() != ComparisonExpression.Operator.EQUAL) {

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,25 @@ private PredicateUtils() {
5757
*/
5858
public static Pair<Expression, Boolean> extractGlobalTimePredicate(
5959
Expression predicate, boolean canRewrite, boolean isFirstOr) {
60+
return extractGlobalTimePredicate(predicate, canRewrite, isFirstOr, TIME);
61+
}
62+
63+
public static Pair<Expression, Boolean> extractGlobalTimePredicate(
64+
Expression predicate, boolean canRewrite, boolean isFirstOr, String timeColumnName) {
6065
if (predicate instanceof LogicalExpression
6166
&& ((LogicalExpression) predicate).getOperator().equals(AND)) {
6267
Pair<Expression, Boolean> leftResultPair =
6368
extractGlobalTimePredicate(
64-
((LogicalExpression) predicate).getTerms().get(0), canRewrite, isFirstOr);
69+
((LogicalExpression) predicate).getTerms().get(0),
70+
canRewrite,
71+
isFirstOr,
72+
timeColumnName);
6573
Pair<Expression, Boolean> rightResultPair =
6674
extractGlobalTimePredicate(
67-
((LogicalExpression) predicate).getTerms().get(1), canRewrite, isFirstOr);
75+
((LogicalExpression) predicate).getTerms().get(1),
76+
canRewrite,
77+
isFirstOr,
78+
timeColumnName);
6879

6980
// rewrite predicate to avoid duplicate calculation on time filter
7081
// If Left-child or Right-child does not contain value filter
@@ -104,10 +115,10 @@ public static Pair<Expression, Boolean> extractGlobalTimePredicate(
104115
&& ((LogicalExpression) predicate).getOperator().equals(OR)) {
105116
Pair<Expression, Boolean> leftResultPair =
106117
extractGlobalTimePredicate(
107-
((LogicalExpression) predicate).getTerms().get(0), false, false);
118+
((LogicalExpression) predicate).getTerms().get(0), false, false, timeColumnName);
108119
Pair<Expression, Boolean> rightResultPair =
109120
extractGlobalTimePredicate(
110-
((LogicalExpression) predicate).getTerms().get(1), false, false);
121+
((LogicalExpression) predicate).getTerms().get(1), false, false, timeColumnName);
111122

112123
if (leftResultPair.left != null && rightResultPair.left != null) {
113124
if (Boolean.TRUE.equals(isFirstOr && !leftResultPair.right && !rightResultPair.right)) {
@@ -132,8 +143,8 @@ public static Pair<Expression, Boolean> extractGlobalTimePredicate(
132143
else if (predicate instanceof ComparisonExpression) {
133144
Expression leftExpression = ((ComparisonExpression) predicate).getLeft();
134145
Expression rightExpression = ((ComparisonExpression) predicate).getRight();
135-
if (checkIsTimeFilter(leftExpression, rightExpression)
136-
|| checkIsTimeFilter(rightExpression, leftExpression)) {
146+
if (checkIsTimeFilter(leftExpression, rightExpression, timeColumnName)
147+
|| checkIsTimeFilter(rightExpression, leftExpression, timeColumnName)) {
137148
return new Pair<>(predicate, false);
138149
}
139150
return new Pair<>(null, true);
@@ -190,9 +201,10 @@ else if (predicate instanceof InPredicate) {
190201
}
191202
}
192203

193-
private static boolean checkIsTimeFilter(Expression timeExpression, Expression valueExpression) {
204+
private static boolean checkIsTimeFilter(
205+
Expression timeExpression, Expression valueExpression, String timeColumnName) {
194206
return timeExpression instanceof Identifier
195-
&& ((Identifier) timeExpression).getValue().equalsIgnoreCase(TIME)
207+
&& ((Identifier) timeExpression).getValue().equalsIgnoreCase(timeColumnName)
196208
&& valueExpression instanceof LongLiteral;
197209
}
198210
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.db.queryengine.plan.analyze;
21+
22+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ComparisonExpression;
23+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
24+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
25+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
26+
import org.apache.iotdb.commons.schema.table.TsTable;
27+
import org.apache.iotdb.commons.schema.table.column.TimeColumnSchema;
28+
import org.apache.iotdb.db.storageengine.dataregion.modification.TableDeletionEntry;
29+
30+
import org.apache.tsfile.enums.TSDataType;
31+
import org.junit.Test;
32+
33+
import java.util.List;
34+
35+
import static org.junit.Assert.assertEquals;
36+
37+
public class AnalyzeUtilsTest {
38+
39+
@Test
40+
public void testParseDeletePredicateWithRenamedTimeColumn() {
41+
TsTable table = new TsTable("table1");
42+
table.addColumnSchema(new TimeColumnSchema("ts", TSDataType.TIMESTAMP));
43+
Expression expression =
44+
new ComparisonExpression(
45+
ComparisonExpression.Operator.LESS_THAN_OR_EQUAL,
46+
new Identifier("ts"),
47+
new LongLiteral("100"));
48+
49+
List<TableDeletionEntry> entries = AnalyzeUtils.parseExpressions2ModEntries(expression, table);
50+
51+
assertEquals(1, entries.size());
52+
assertEquals(Long.MIN_VALUE, entries.get(0).getStartTime());
53+
assertEquals(100, entries.get(0).getEndTime());
54+
}
55+
}

iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
import org.apache.iotdb.commons.conf.IoTDBConstant;
2323
import org.apache.iotdb.commons.queryengine.common.SessionInfo;
2424
import org.apache.iotdb.commons.queryengine.common.SqlDialect;
25+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ComparisonExpression;
2526
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
27+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
28+
import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
2629
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
2730
import org.apache.iotdb.db.queryengine.common.QueryId;
2831
import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
@@ -36,6 +39,7 @@
3639

3740
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.AnalyzerTest.analyzeSQL;
3841
import static org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate;
42+
import static org.junit.Assert.assertNotNull;
3943

4044
public class PredicateUtilsTest {
4145
@Test
@@ -69,4 +73,13 @@ public void extractGlobalTimePredicateTest() {
6973
actualAnalysis.getWhereMap().values().iterator().next(), true, true);
7074
System.out.println(ret.getLeft());
7175
}
76+
77+
@Test
78+
public void extractGlobalTimePredicateWithCustomTimeColumnTest() {
79+
Expression expression =
80+
new ComparisonExpression(
81+
ComparisonExpression.Operator.GREATER_THAN, new Identifier("ts"), new LongLiteral("1"));
82+
Pair<Expression, Boolean> ret = extractGlobalTimePredicate(expression, true, true, "ts");
83+
assertNotNull(ret.getLeft());
84+
}
7285
}

0 commit comments

Comments
 (0)