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

shuwenwei pushed a commit to branch fixBug-0713
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 9b315588b44be010d999a3eee38d4e1a7b1773b0
Author: shuwenwei <[email protected]>
AuthorDate: Mon Jul 13 14:33:26 2026 +0800

    Fix tag index misalignment in read_tsfile when projection pruning removes 
tag columns
    
    When projection pruning removes tag columns from the scan node's
    assignments, constructExternalTsFileDeviceFilter builds a TsTable
    from the pruned assignments and recomputes tag indices via
    getTagColumnIndex. This causes tag2 to be assigned index 0 instead
    of 1, and ExternalTsFileDeviceFilterVisitor reads the wrong deviceID
    segment (tag1 instead of tag2), effectively evaluating the wrong tag.
    
    Fix: Use ExternalTsFileQueryResource.getTableColumnSchema() which
    always holds the complete, unpruned column schema with correct tag
    ordering, instead of the pruned scan node assignments.
---
 .../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