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

JackieTien97 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 ce74949268e Fix tag index misalignment in read_tsfile when projection 
pruning removes tag columns (#18191)
ce74949268e is described below

commit ce74949268ec18f8e4b894b5bbc4373defe993a0
Author: shuwenwei <[email protected]>
AuthorDate: Mon Jul 13 15:15:44 2026 +0800

    Fix tag index misalignment in read_tsfile when projection pruning removes 
tag columns (#18191)
---
 .../recent/IoTDBReadTsFileTableFunctionIT.java     | 50 ++++++++++++++++++++++
 .../optimizations/PushPredicateIntoTableScan.java  |  3 +-
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBReadTsFileTableFunctionIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBReadTsFileTableFunctionIT.java
index 0b5abc38a62..33c562b3c6d 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBReadTsFileTableFunctionIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBReadTsFileTableFunctionIT.java
@@ -129,6 +129,56 @@ public class IoTDBReadTsFileTableFunctionIT {
         DATABASE_NAME);
   }
 
+  @Test
+  public void testReadTsFileWithTagFilterAndProjectionPruning() throws 
Exception {
+    // Reproduces a bug where projection pruning removes tag columns from the 
scan node's
+    // assignments, and the subsequent device filter construction rebuilds tag 
indices from the
+    // pruned list, causing tag index misalignment in 
ExternalTsFileDeviceFilterVisitor.
+    // The TsFile has tag columns [tag1, tag2]. When SELECT projects only time 
and s1 (omitting
+    // both tag columns), the old code would assign tag2 an index of 0 instead 
of 1, and
+    // deviceID.segment(1) would read tag1 instead of tag2.
+    File tsFile = new File(tmpDir, "tag-projection-pruning.tsfile");
+    try (TsFileWriter writer = new TsFileWriter(tsFile)) {
+      generateTable(
+          writer, "table1", Arrays.asList("tag1", "tag2"), Arrays.asList("s1", 
"s2"), 1, 2);
+    }
+
+    // tag2 = 'tag2_1' should match only the device whose tag2 is tag2_1
+    // Before fix: read deviceID.segment(1)=tag1 instead of tag2, so this 
actually evaluated
+    // tag1 = 'tag2_1' and returned empty
+    tableResultSetEqualTest(
+        "SELECT time, s1 FROM read_tsfile(PATHS => '"
+            + toSqlPath(tsFile)
+            + "', TABLE_NAME => 'table1') WHERE tag2 = 'tag2_1' ORDER BY time",
+        new String[] {"time", "s1"},
+        new String[] {
+          "1970-01-01T00:00:00.001Z,1,", "1970-01-01T00:00:00.002Z,2,",
+        },
+        DATABASE_NAME);
+
+    // tag2 = 'tag1_1' should match nothing: no device has tag2 = tag1_1
+    // Before fix: read deviceID.segment(1)=tag1, so this actually evaluated 
tag1 = 'tag1_1'
+    // and returned 2 rows (the device with tag1_1)
+    tableResultSetEqualTest(
+        "SELECT time, s1 FROM read_tsfile(PATHS => '"
+            + toSqlPath(tsFile)
+            + "', TABLE_NAME => 'table1') WHERE tag2 = 'tag1_1'",
+        new String[] {"time", "s1"},
+        new String[] {},
+        DATABASE_NAME);
+
+    // Verify: select tag2 as well to confirm correct matching
+    tableResultSetEqualTest(
+        "SELECT time, tag2, s1 FROM read_tsfile(PATHS => '"
+            + toSqlPath(tsFile)
+            + "', TABLE_NAME => 'table1') WHERE tag2 = 'tag2_2' ORDER BY time",
+        new String[] {"time", "tag2", "s1"},
+        new String[] {
+          "1970-01-01T00:00:00.001Z,tag2_2,1,", 
"1970-01-01T00:00:00.002Z,tag2_2,2,",
+        },
+        DATABASE_NAME);
+  }
+
   @Test
   public void testReadTsFileAggregationWithNoMatchedDevice() throws Exception {
     File tsFile = new File(tmpDir, "empty-device-aggregation.tsfile");
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
index 44730de6d3f..1ceb4c86f6c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushPredicateIntoTableScan.java
@@ -558,7 +558,8 @@ public class PushPredicateIntoTableScan implements 
PlanOptimizer {
         return null;
       }
       TsTable table = new 
TsTable(tableScanNode.getQualifiedObjectName().getObjectName());
-      for (Map.Entry<Symbol, ColumnSchema> entry : 
tableScanNode.getAssignments().entrySet()) {
+      for (Map.Entry<Symbol, ColumnSchema> entry :
+          
tableScanNode.getExternalTsFileQueryResource().getTableColumnSchema().entrySet())
 {
         ColumnSchema columnSchema = entry.getValue();
         if (TAG.equals(columnSchema.getColumnCategory())) {
           table.addColumnSchema(

Reply via email to