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

shuwenwei pushed a commit to branch fix/copy-to-tsfile-unordered-results
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 30517b1cf9b0543e24892675929153c5108ec62d
Author: shuwenwei <[email protected]>
AuthorDate: Tue Oct 20 12:14:33 2026 +0800

    Add integration coverage for unordered COPY TO TsFile results
    
    Cover descending time, field ordering, LIMIT and OFFSET, aliased timestamps 
and reordered tags, and exports without tags. Read back all rows and use small 
TsBlocks to exercise multiple write batches.
    
    Set MEMORY_THRESHOLD to 1000000 for the new cases. All five integration 
tests passed according to user validation; tests and compilation were not rerun 
by the agent.
---
 .../query/recent/copyto/IoTDBCopyToTsFileIT.java   | 125 +++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/copyto/IoTDBCopyToTsFileIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/copyto/IoTDBCopyToTsFileIT.java
index 388d833f700..7092bc265c6 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/copyto/IoTDBCopyToTsFileIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/copyto/IoTDBCopyToTsFileIT.java
@@ -32,6 +32,9 @@ import org.apache.tsfile.file.metadata.IDeviceID;
 import org.apache.tsfile.file.metadata.StringArrayDeviceID;
 import org.apache.tsfile.file.metadata.TimeseriesMetadata;
 import org.apache.tsfile.read.TsFileSequenceReader;
+import org.apache.tsfile.read.query.dataset.ResultSet;
+import org.apache.tsfile.read.v4.ITsFileReader;
+import org.apache.tsfile.read.v4.TsFileReaderBuilder;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -45,6 +48,10 @@ import org.slf4j.LoggerFactory;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -76,6 +83,7 @@ public class IoTDBCopyToTsFileIT {
 
   @BeforeClass
   public static void setUp() throws Exception {
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setMaxTsBlockLineNumber(2);
     EnvFactory.getEnv().initClusterEnvironment();
     prepareTableData(createSqls);
   }
@@ -743,6 +751,123 @@ public class IoTDBCopyToTsFileIT {
     }
   }
 
+  @Test
+  public void testCopyWithDescendingTime() throws Exception {
+    assertCopyToRows(
+        "COPY (SELECT time, tag1, tag2, s1, s2 FROM table1 ORDER BY time DESC, 
tag1)"
+            + " TO 'copy_descending_time.tsfile' WITH (MEMORY_THRESHOLD 
1000000)",
+        List.of("tag1", "tag2"),
+        "1,t1_1,t2,1,1",
+        "2,t1_1,t2,2,2",
+        "3,t1_1,t2,3,3",
+        "1,t1_2,t2,1,1",
+        "2,t1_2,t2,2,2",
+        "3,t1_2,t2,3,3");
+  }
+
+  @Test
+  public void testCopyWithUnorderedTimeByField() throws Exception {
+    assertCopyToRows(
+        "COPY (SELECT time, tag1, tag2, s1, s2 FROM table1 ORDER BY s1 % 2, 
time DESC, tag1)"
+            + " TO 'copy_field_order.tsfile' WITH (MEMORY_THRESHOLD 1000000)",
+        List.of("tag1", "tag2"),
+        "1,t1_1,t2,1,1",
+        "2,t1_1,t2,2,2",
+        "3,t1_1,t2,3,3",
+        "1,t1_2,t2,1,1",
+        "2,t1_2,t2,2,2",
+        "3,t1_2,t2,3,3");
+  }
+
+  @Test
+  public void testCopyWithDescendingTimeAndLimitOffset() throws Exception {
+    assertCopyToRows(
+        "COPY (SELECT time, tag1, tag2, s1, s2 FROM table1"
+            + " ORDER BY time DESC, tag1 OFFSET 1 LIMIT 3) TO 
'copy_descending_limit.tsfile'"
+            + " WITH (MEMORY_THRESHOLD 1000000)",
+        List.of("tag1", "tag2"),
+        "2,t1_1,t2,2,2",
+        "2,t1_2,t2,2,2",
+        "3,t1_2,t2,3,3");
+  }
+
+  @Test
+  public void testCopyWithDescendingAliasedTimeAndReorderedTags() throws 
Exception {
+    assertCopyToRows(
+        "COPY (SELECT time AS t, tag1 AS renamed_tag1, tag2 AS renamed_tag2, 
s1, s2"
+            + " FROM table1 ORDER BY t DESC, renamed_tag1)"
+            + " TO 'copy_descending_alias.tsfile'"
+            + " WITH (TIME t, TAGS(renamed_tag2, renamed_tag1), 
MEMORY_THRESHOLD 1000000)",
+        List.of("renamed_tag2", "renamed_tag1"),
+        "1,t2,t1_1,1,1",
+        "2,t2,t1_1,2,2",
+        "3,t2,t1_1,3,3",
+        "1,t2,t1_2,1,1",
+        "2,t2,t1_2,2,2",
+        "3,t2,t1_2,3,3");
+  }
+
+  @Test
+  public void testCopyWithDescendingTimeWithoutTags() throws Exception {
+    assertCopyToRows(
+        "COPY (SELECT time, s1, s2 FROM table1 WHERE tag1 = 't1_1' ORDER BY 
time DESC)"
+            + " TO 'copy_descending_no_tags.tsfile' WITH (MEMORY_THRESHOLD 
1000000)",
+        Collections.emptyList(),
+        "1,1,1",
+        "2,2,2",
+        "3,3,3");
+  }
+
+  private void assertCopyToRows(String sql, List<String> tagColumns, String... 
expectedRows)
+      throws Exception {
+    long deviceCount;
+    try (ITableSession session =
+            EnvFactory.getEnv().getTableSessionConnectionWithDB(DATABASE_NAME);
+        SessionDataSet dataSet = session.executeQueryStatement(sql)) {
+      SessionDataSet.DataIterator iterator = dataSet.iterator();
+      Assert.assertTrue(iterator.next());
+      targetFilePath = iterator.getString(1);
+      Assert.assertTrue(new File(targetFilePath).isFile());
+      Assert.assertEquals(expectedRows.length, iterator.getLong(2));
+      deviceCount = iterator.getLong(3);
+      Assert.assertTrue(iterator.getLong(4) > 0);
+      Assert.assertEquals("table1", iterator.getString(5));
+      Assert.assertEquals(tagColumns.toString(), iterator.getString(7));
+      Assert.assertFalse(iterator.next());
+    }
+
+    List<String> columns = new ArrayList<>(tagColumns);
+    columns.add("s1");
+    columns.add("s2");
+    List<String> actualRows = new ArrayList<>();
+    Map<List<String>, Long> lastTimeByDevice = new HashMap<>();
+    try (ITsFileReader reader = new TsFileReaderBuilder().file(new 
File(targetFilePath)).build();
+        ResultSet result = reader.query("table1", columns, Long.MIN_VALUE, 
Long.MAX_VALUE)) {
+      while (result.next()) {
+        long time = result.getLong(1);
+        StringBuilder row = new StringBuilder(Long.toString(time));
+        List<String> tags = new ArrayList<>();
+        for (int i = 0; i < tagColumns.size(); i++) {
+          String tag = result.isNull(i + 2) ? null : result.getString(i + 2);
+          tags.add(tag);
+          row.append(',').append(tag);
+        }
+        Long lastTime = lastTimeByDevice.put(tags, time);
+        if (lastTime != null) {
+          Assert.assertTrue(time > lastTime);
+        }
+        row.append(',').append(result.getInt(tagColumns.size() + 2));
+        row.append(',').append(result.getInt(tagColumns.size() + 3));
+        actualRows.add(row.toString());
+      }
+    }
+    Assert.assertEquals(deviceCount, lastTimeByDevice.size());
+    List<String> expected = new ArrayList<>(Arrays.asList(expectedRows));
+    Collections.sort(expected);
+    Collections.sort(actualRows);
+    Assert.assertEquals(expected, actualRows);
+  }
+
   @Test
   public void testFindTimeColumn()
       throws IoTDBConnectionException, StatementExecutionException, 
IOException {

Reply via email to