This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 187e4547c0c Fix table delete with renamed time column (#17841)
187e4547c0c is described below

commit 187e4547c0ccd9b8ff88e4b1ae243ba4846a3d7d
Author: Jiang Tian <[email protected]>
AuthorDate: Thu Jun 4 10:33:43 2026 +0800

    Fix table delete with renamed time column (#17841)
    
    * reviewed AnalyzeUtils
    
    * Fix delete with non-default time column
---
 .../relational/it/db/it/IoTDBDeletionTableIT.java  | 21 +++++++++
 .../iotdb/db/i18n/DataNodeQueryMessages.java       |  2 +
 .../iotdb/db/i18n/DataNodeQueryMessages.java       |  2 +
 .../db/queryengine/plan/analyze/AnalyzeUtils.java  | 14 +++++-
 .../plan/relational/planner/PredicateUtils.java    | 28 +++++++----
 .../queryengine/plan/analyze/AnalyzeUtilsTest.java | 55 ++++++++++++++++++++++
 .../relational/planner/PredicateUtilsTest.java     | 13 +++++
 7 files changed, 126 insertions(+), 9 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBDeletionTableIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBDeletionTableIT.java
index e6939c5226a..66d0e3a6a0d 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBDeletionTableIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBDeletionTableIT.java
@@ -414,6 +414,27 @@ public class IoTDBDeletionTableIT {
     }
   }
 
+  @Test
+  public void testDeleteWithRenamedTimeColumn() throws SQLException {
+    try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE DATABASE time_column_rename");
+      statement.execute("use time_column_rename");
+      statement.execute("CREATE TABLE vehicle(ts time, deviceId STRING TAG, s0 
INT32 FIELD)");
+      statement.execute("INSERT INTO vehicle(ts, deviceId, s0) VALUES(1, 'd0', 
1)");
+      statement.execute("INSERT INTO vehicle(ts, deviceId, s0) VALUES(2, 'd0', 
2)");
+
+      statement.execute("DELETE FROM vehicle WHERE ts <= 1");
+
+      try (ResultSet resultSet = statement.executeQuery("SELECT ts, s0 FROM 
vehicle")) {
+        assertTrue(resultSet.next());
+        assertEquals(2, resultSet.getLong("ts"));
+        assertEquals(2, resultSet.getInt("s0"));
+        assertFalse(resultSet.next());
+      }
+    }
+  }
+
   @Test
   public void testRangeDelete() throws SQLException {
     prepareData(4, 1);
diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
index c1c26550f9d..2c4978618a6 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
@@ -259,6 +259,8 @@ public final class DataNodeQueryMessages {
       "Left hand expression is not an identifier: ";
   public static final String THE_LEFT_HAND_VALUE_MUST_BE_AN_IDENTIFIER =
       "The left hand value must be an identifier: ";
+  public static final String THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN =
+      "The table '%s' does not contain a time column";
   public static final String THE_OPERATOR_OF_TAG_PREDICATE_MUST_BE_FOR =
       "The operator of tag predicate must be '=' for ";
   public static final String ONLY_TIME_FILTERS_ARE_SUPPORTED_IN_LAST_QUERY =
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
index 3d2783c81b6..7a7de06471b 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
@@ -258,6 +258,8 @@ public final class DataNodeQueryMessages {
       "左侧表达式不是标识符:";
   public static final String THE_LEFT_HAND_VALUE_MUST_BE_AN_IDENTIFIER =
       "左侧值必须是标识符:";
+  public static final String THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN =
+      "表 '%s' 不包含时间列";
   public static final String THE_OPERATOR_OF_TAG_PREDICATE_MUST_BE_FOR =
       "标签谓词的运算符必须为 '=',目标:";
   public static final String ONLY_TIME_FILTERS_ARE_SUPPORTED_IN_LAST_QUERY =
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
index c9cf278051f..d00ee54428b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
 import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.NullLiteral;
 import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.StringLiteral;
 import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
 import org.apache.iotdb.confignode.rpc.thrift.TRegionRouteMapResp;
 import org.apache.iotdb.db.i18n.DataNodeQueryMessages;
@@ -520,7 +521,7 @@ public class AnalyzeUtils {
     }
     Identifier identifier = (Identifier) left;
     // time predicate
-    if (identifier.getValue().equalsIgnoreCase("time")) {
+    if (identifier.getValue().equalsIgnoreCase(getTimeColumnName(table))) {
       long rightHandValue;
       if (right instanceof LongLiteral) {
         rightHandValue = ((LongLiteral) right).getParsedValue();
@@ -567,6 +568,17 @@ public class AnalyzeUtils {
     return combinePredicates(oldPredicate, newPredicate);
   }
 
+  private static String getTimeColumnName(final TsTable table) {
+    final TsTableColumnSchema timeColumnSchema = table.getTimeColumnSchema();
+    if (Objects.isNull(timeColumnSchema)) {
+      throw new SemanticException(
+          String.format(
+              DataNodeQueryMessages.THE_TABLE_S_DOES_NOT_CONTAIN_A_TIME_COLUMN,
+              table.getTableName()));
+    }
+    return timeColumnSchema.getColumnName();
+  }
+
   private static IDPredicate getTagPredicate(
       ComparisonExpression comparisonExpression, Expression right, int 
tagColumnOrdinal) {
     if (comparisonExpression.getOperator() != 
ComparisonExpression.Operator.EQUAL) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
index d7748e2347d..041be454c92 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtils.java
@@ -57,14 +57,25 @@ public class PredicateUtils {
    */
   public static Pair<Expression, Boolean> extractGlobalTimePredicate(
       Expression predicate, boolean canRewrite, boolean isFirstOr) {
+    return extractGlobalTimePredicate(predicate, canRewrite, isFirstOr, TIME);
+  }
+
+  public static Pair<Expression, Boolean> extractGlobalTimePredicate(
+      Expression predicate, boolean canRewrite, boolean isFirstOr, String 
timeColumnName) {
     if (predicate instanceof LogicalExpression
         && ((LogicalExpression) predicate).getOperator().equals(AND)) {
       Pair<Expression, Boolean> leftResultPair =
           extractGlobalTimePredicate(
-              ((LogicalExpression) predicate).getTerms().get(0), canRewrite, 
isFirstOr);
+              ((LogicalExpression) predicate).getTerms().get(0),
+              canRewrite,
+              isFirstOr,
+              timeColumnName);
       Pair<Expression, Boolean> rightResultPair =
           extractGlobalTimePredicate(
-              ((LogicalExpression) predicate).getTerms().get(1), canRewrite, 
isFirstOr);
+              ((LogicalExpression) predicate).getTerms().get(1),
+              canRewrite,
+              isFirstOr,
+              timeColumnName);
 
       // rewrite predicate to avoid duplicate calculation on time filter
       // If Left-child or Right-child does not contain value filter
@@ -104,10 +115,10 @@ public class PredicateUtils {
         && ((LogicalExpression) predicate).getOperator().equals(OR)) {
       Pair<Expression, Boolean> leftResultPair =
           extractGlobalTimePredicate(
-              ((LogicalExpression) predicate).getTerms().get(0), false, false);
+              ((LogicalExpression) predicate).getTerms().get(0), false, false, 
timeColumnName);
       Pair<Expression, Boolean> rightResultPair =
           extractGlobalTimePredicate(
-              ((LogicalExpression) predicate).getTerms().get(1), false, false);
+              ((LogicalExpression) predicate).getTerms().get(1), false, false, 
timeColumnName);
 
       if (leftResultPair.left != null && rightResultPair.left != null) {
         if (Boolean.TRUE.equals(isFirstOr && !leftResultPair.right && 
!rightResultPair.right)) {
@@ -132,8 +143,8 @@ public class PredicateUtils {
     else if (predicate instanceof ComparisonExpression) {
       Expression leftExpression = ((ComparisonExpression) predicate).getLeft();
       Expression rightExpression = ((ComparisonExpression) 
predicate).getRight();
-      if (checkIsTimeFilter(leftExpression, rightExpression)
-          || checkIsTimeFilter(rightExpression, leftExpression)) {
+      if (checkIsTimeFilter(leftExpression, rightExpression, timeColumnName)
+          || checkIsTimeFilter(rightExpression, leftExpression, 
timeColumnName)) {
         return new Pair<>(predicate, false);
       }
       return new Pair<>(null, true);
@@ -190,9 +201,10 @@ public class PredicateUtils {
     }
   }
 
-  private static boolean checkIsTimeFilter(Expression timeExpression, 
Expression valueExpression) {
+  private static boolean checkIsTimeFilter(
+      Expression timeExpression, Expression valueExpression, String 
timeColumnName) {
     return timeExpression instanceof Identifier
-        && ((Identifier) timeExpression).getValue().equalsIgnoreCase(TIME)
+        && ((Identifier) 
timeExpression).getValue().equalsIgnoreCase(timeColumnName)
         && valueExpression instanceof LongLiteral;
   }
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtilsTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtilsTest.java
new file mode 100644
index 00000000000..5d0ccd74f45
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtilsTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.analyze;
+
+import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ComparisonExpression;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
+import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.column.TimeColumnSchema;
+import 
org.apache.iotdb.db.storageengine.dataregion.modification.TableDeletionEntry;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class AnalyzeUtilsTest {
+
+  @Test
+  public void testParseDeletePredicateWithRenamedTimeColumn() {
+    TsTable table = new TsTable("table1");
+    table.addColumnSchema(new TimeColumnSchema("ts", TSDataType.TIMESTAMP));
+    Expression expression =
+        new ComparisonExpression(
+            ComparisonExpression.Operator.LESS_THAN_OR_EQUAL,
+            new Identifier("ts"),
+            new LongLiteral("100"));
+
+    List<TableDeletionEntry> entries = 
AnalyzeUtils.parseExpressions2ModEntries(expression, table);
+
+    assertEquals(1, entries.size());
+    assertEquals(Long.MIN_VALUE, entries.get(0).getStartTime());
+    assertEquals(100, entries.get(0).getEndTime());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
index 51df25a68d0..48a012a21ca 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PredicateUtilsTest.java
@@ -22,7 +22,10 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.planner;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.queryengine.common.SessionInfo;
 import org.apache.iotdb.commons.queryengine.common.SqlDialect;
+import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.ComparisonExpression;
 import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Expression;
+import org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Identifier;
+import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.LongLiteral;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.QueryId;
 import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis;
@@ -36,6 +39,7 @@ import java.time.ZoneId;
 
 import static 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.AnalyzerTest.analyzeSQL;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.PredicateUtils.extractGlobalTimePredicate;
+import static org.junit.Assert.assertNotNull;
 
 public class PredicateUtilsTest {
   @Test
@@ -69,4 +73,13 @@ public class PredicateUtilsTest {
             actualAnalysis.getWhereMap().values().iterator().next(), true, 
true);
     System.out.println(ret.getLeft());
   }
+
+  @Test
+  public void extractGlobalTimePredicateWithCustomTimeColumnTest() {
+    Expression expression =
+        new ComparisonExpression(
+            ComparisonExpression.Operator.GREATER_THAN, new Identifier("ts"), 
new LongLiteral("1"));
+    Pair<Expression, Boolean> ret = extractGlobalTimePredicate(expression, 
true, true, "ts");
+    assertNotNull(ret.getLeft());
+  }
 }

Reply via email to