This is an automated email from the ASF dual-hosted git repository. jiangtian pushed a commit to branch fix_false_positive_deletion in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 0c4f8cb0ad2fb85e3dd6132e3a054ca1733b06f0 Author: Tian Jiang <[email protected]> AuthorDate: Thu Nov 28 18:11:05 2024 +0800 Fix that queries may retrieve false positive deletion --- .../relational/it/db/it/IoTDBDeletionTableIT.java | 36 ++++++++++++++++++++-- .../execution/fragment/QueryContext.java | 15 +++++++-- 2 files changed, 46 insertions(+), 5 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 3dd9672187b..6d2d591fed1 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 @@ -604,20 +604,50 @@ public class IoTDBDeletionTableIT { statement.execute("flush"); statement.execute("delete from t" + testNum + " where id1 is NULL and time <= 1"); - try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum)) { + try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum + " order by time")) { assertTrue(set.next()); + assertEquals(2, set.getLong("time")); assertTrue(set.next()); + assertEquals(3, set.getLong("time")); assertFalse(set.next()); } statement.execute("delete from t" + testNum + " where id2 is NULL"); - try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum)) { + try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum + " order by time")) { assertTrue(set.next()); + assertEquals(2, set.getLong("time")); assertFalse(set.next()); } statement.execute("delete from t" + testNum); - try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum)) { + try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum + " order by time")) { + assertFalse(set.next()); + } + + statement.execute("drop table t" + testNum); + } + } + + @Test + public void testEmptyString() throws SQLException { + int testNum = 15; + try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + Statement statement = connection.createStatement()) { + statement.execute("use test"); + statement.execute( + "create table t" + testNum + " (id1 string id, id2 string id, s1 int32 measurement)"); + // id1 is null for this record + statement.execute("insert into t" + testNum + " (time, id2, s1) values (1, '1', 1)"); + statement.execute("insert into t" + testNum + " (time, id2, s1) values (2, '', 2)"); + statement.execute("insert into t" + testNum + " (time, id2, s1) values (3, NULL, 3)"); + statement.execute("flush"); + + statement.execute("delete from t" + testNum + " where id2 is null"); + try (ResultSet set = statement.executeQuery("SELECT * FROM t" + testNum + " order by time")) { + assertTrue(set.next()); + assertEquals(1, set.getLong("time")); + assertTrue(set.next()); + assertEquals(3, set.getLong("time")); assertFalse(set.next()); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/QueryContext.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/QueryContext.java index 28d4e14703b..566e998d2c4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/QueryContext.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/QueryContext.java @@ -40,6 +40,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; /** QueryContext contains the shared information with in a query. */ public class QueryContext { @@ -117,8 +118,18 @@ public class QueryContext { return Collections.emptyList(); } - return ModificationUtils.sortAndMerge( - getAllModifications(tsFileResource).getOverlapped(deviceID, measurement)); + List<ModEntry> modEntries = + ModificationUtils.sortAndMerge( + getAllModifications(tsFileResource).getOverlapped(deviceID, measurement)); + if (deviceID.isTableModel()) { + // the pattern tree has false-positive for table model deletion, so we do a further + // filtering + modEntries = + modEntries.stream() + .filter(mod -> mod.affects(deviceID) && mod.affects(measurement)) + .collect(Collectors.toList()); + } + return modEntries; } public List<ModEntry> getPathModifications(TsFileResource tsFileResource, IDeviceID deviceID)
