This is an automated email from the ASF dual-hosted git repository. Caideyipi pushed a commit to branch hotfix/2.0.9.4-sjzt in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 23d560096388799b7c893d8d0edbcc5dcdea5b4c Author: 罗振羽 <[email protected]> AuthorDate: Wed Apr 29 08:26:27 2026 +0000 [TIMECHODB]Fix object file timestamp parsing (cherry picked from commit 92aa3a4bc7088cc0f31e230c18b7ccb8cc91d4b0) --- .../relational/it/session/IoTDBObjectDeleteIT.java | 147 +++++++++++++++++++++ .../db/storageengine/dataregion/DataRegion.java | 4 +- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBObjectDeleteIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBObjectDeleteIT.java index 0c697424873..e2c7fe73359 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBObjectDeleteIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/session/IoTDBObjectDeleteIT.java @@ -262,6 +262,40 @@ public class IoTDBObjectDeleteIT { Assert.assertFalse(success); } + @Test + public void dropObjectTableWithMultipleRowsTest() + throws IoTDBConnectionException, StatementExecutionException, IOException { + byte[] objectBytes = readTestObjectBytes(); + + try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) { + session.executeNonQueryStatement("USE \"db1\""); + insertTwoRowsWithObjects(session, objectBytes); + assertObjectRowsReadable(session, objectBytes); + + session.executeNonQueryStatement("drop table object_table"); + } + + Assert.assertFalse(objectFileExists("object_table", "1", "5", "3", "file", "1.bin")); + Assert.assertFalse(objectFileExists("object_table", "1", "5", "3", "file", "2.bin")); + } + + @Test + public void dropObjectDatabaseTest() + throws IoTDBConnectionException, StatementExecutionException, IOException { + byte[] objectBytes = readTestObjectBytes(); + + try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) { + session.executeNonQueryStatement("USE \"db1\""); + insertTwoRowsWithObjects(session, objectBytes); + assertObjectRowsReadable(session, objectBytes); + + session.executeNonQueryStatement("drop database db1"); + } + + Assert.assertFalse(objectFileExists("object_table", "1", "5", "3", "file", "1.bin")); + Assert.assertFalse(objectFileExists("object_table", "1", "5", "3", "file", "2.bin")); + } + @Test public void deleteObjectSegmentsTest() throws IoTDBConnectionException, StatementExecutionException, IOException { @@ -360,4 +394,117 @@ public class IoTDBObjectDeleteIT { protected String convertPathString(String path) { return BaseEncoding.base32().omitPadding().encode(path.getBytes(StandardCharsets.UTF_8)); } + + private byte[] readTestObjectBytes() throws IOException { + String testObject = + System.getProperty("user.dir") + + File.separator + + "target" + + File.separator + + "test-classes" + + File.separator + + "object-example.pt"; + return Files.readAllBytes(Paths.get(testObject)); + } + + private void insertTwoRowsWithObjects(ITableSession session, byte[] objectBytes) + throws IoTDBConnectionException, StatementExecutionException { + List<String> columnNameList = + Arrays.asList("region_id", "plant_id", "device_id", "temperature", "file"); + List<TSDataType> dataTypeList = + Arrays.asList( + TSDataType.STRING, + TSDataType.STRING, + TSDataType.STRING, + TSDataType.FLOAT, + TSDataType.OBJECT); + List<ColumnCategory> columnTypeList = + new ArrayList<>( + Arrays.asList( + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.TAG, + ColumnCategory.FIELD, + ColumnCategory.FIELD)); + Tablet tablet = new Tablet("object_table", columnNameList, dataTypeList, columnTypeList, 2); + + int rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, 1); + tablet.addValue(rowIndex, 0, "1"); + tablet.addValue(rowIndex, 1, "5"); + tablet.addValue(rowIndex, 2, "3"); + tablet.addValue(rowIndex, 3, 37.6F); + tablet.addValue(rowIndex, 4, true, 0, objectBytes); + + rowIndex = tablet.getRowSize(); + tablet.addTimestamp(rowIndex, 2); + tablet.addValue(rowIndex, 0, "1"); + tablet.addValue(rowIndex, 1, "5"); + tablet.addValue(rowIndex, 2, "3"); + tablet.addValue(rowIndex, 3, 38.6F); + tablet.addValue(rowIndex, 4, true, 0, objectBytes); + + session.insert(tablet); + tablet.reset(); + session.executeNonQueryStatement("flush"); + } + + private void assertObjectRowsReadable(ITableSession session, byte[] objectBytes) + throws IoTDBConnectionException, StatementExecutionException { + try (SessionDataSet dataSet = + session.executeQueryStatement( + "select time, READ_OBJECT(file) as file_content from object_table order by time")) { + SessionDataSet.DataIterator iterator = dataSet.iterator(); + Assert.assertTrue(iterator.next()); + Assert.assertEquals(1L, iterator.getLong("time")); + Assert.assertArrayEquals(objectBytes, iterator.getBlob("file_content").getValues()); + Assert.assertTrue(iterator.next()); + Assert.assertEquals(2L, iterator.getLong("time")); + Assert.assertArrayEquals(objectBytes, iterator.getBlob("file_content").getValues()); + Assert.assertFalse(iterator.next()); + } + } + + private boolean objectFileExists( + String tableName, + String regionId, + String plantId, + String deviceId, + String measurement, + String fileName) { + for (DataNodeWrapper dataNodeWrapper : EnvFactory.getEnv().getDataNodeWrapperList()) { + String objectDirStr = dataNodeWrapper.getDataNodeObjectDir(); + File objectDir = new File(objectDirStr); + if (!objectDir.exists() || !objectDir.isDirectory()) { + continue; + } + File[] regionDirs = objectDir.listFiles(); + if (regionDirs == null) { + continue; + } + for (File regionDir : regionDirs) { + if (!regionDir.isDirectory()) { + continue; + } + File objectFile = + new File( + regionDir, + convertPathString(tableName) + + File.separator + + convertPathString(regionId) + + File.separator + + convertPathString(plantId) + + File.separator + + convertPathString(deviceId) + + File.separator + + convertPathString(measurement) + + File.separator + + fileName); + if (objectFile.exists() && objectFile.isFile()) { + return true; + } + } + } + return false; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java index a4dcbcd9f3b..ca7fe6e663b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java @@ -3031,7 +3031,9 @@ public class DataRegion implements IDataRegionForQuery { TimePartitionUtils.getTimePartitionId( Long.parseLong( name.substring( - -ObjectTypeUtils.OBJECT_FILE_SUFFIX.length()))); + 0, + name.length() + - ObjectTypeUtils.OBJECT_FILE_SUFFIX.length()))); TableDiskUsageIndex.getInstance() .writeObjectDelta( databaseName,
