diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/join/FullOuterTimeJoinNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/join/FullOuterTimeJoinNode.java index f692e0867ff1..936be8f6a6e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/join/FullOuterTimeJoinNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/join/FullOuterTimeJoinNode.java @@ -131,11 +131,30 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - if (!super.equals(o)) { + // Don't call super.equals() to avoid order-sensitive children comparison + FullOuterTimeJoinNode that = (FullOuterTimeJoinNode) o; + // For FullOuterTimeJoinNode, the order of children doesn't matter semantically + // since all children are merged based on timestamps. Compare children as sets. + if (mergeOrder != that.mergeOrder + || !Objects.equals(this.getPlanNodeId(), that.getPlanNodeId()) + || this.children.size() != that.children.size()) { return false; } - FullOuterTimeJoinNode that = (FullOuterTimeJoinNode) o; - return mergeOrder == that.mergeOrder; + // Compare children in an order-independent way by checking if each child in this + // has a corresponding equal child in that + for (PlanNode child : this.children) { + boolean found = false; + for (PlanNode thatChild : that.children) { + if (Objects.equals(child, thatChild)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; } @Override diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/ColumnInjectionPushDownTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/ColumnInjectionPushDownTest.java index 06140fddafcf..e69a2d24a1ba 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/ColumnInjectionPushDownTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/ColumnInjectionPushDownTest.java @@ -31,7 +31,6 @@ import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -295,7 +294,7 @@ public void testPushDownAggregationSourceAlignByDevice() { List outputColumnNames = Arrays.asList("Device", "__endTime", "count(s1)"); List devices = Arrays.asList("root.sg.d1", "root.sg.d2.a"); - Map> deviceToMeasurementIndexesMap = new HashMap<>(); + Map> deviceToMeasurementIndexesMap = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.put("root.sg.d1", Arrays.asList(1, 2)); deviceToMeasurementIndexesMap.put("root.sg.d2.a", Arrays.asList(1, 2)); @@ -373,7 +372,7 @@ public void testPushDownSlidingWindowAlignByDevice() { List outputColumnNames = Arrays.asList("Device", "__endTime", "count(s1)"); List devices = Arrays.asList("root.sg.d1", "root.sg.d2.a"); - Map> deviceToMeasurementIndexesMap = new HashMap<>(); + Map> deviceToMeasurementIndexesMap = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.put("root.sg.d1", Arrays.asList(1, 2)); deviceToMeasurementIndexesMap.put("root.sg.d2.a", Arrays.asList(1, 2)); @@ -453,7 +452,7 @@ public void testPushDownRawDataAggregationAlignByDevice() { List outputColumnNames = Arrays.asList("Device", "__endTime", "count(s1)"); List devices = Arrays.asList("root.sg.d1", "root.sg.d2.a"); - Map> deviceToMeasurementIndexesMap = new HashMap<>(); + Map> deviceToMeasurementIndexesMap = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.put("root.sg.d1", Arrays.asList(1, 2)); deviceToMeasurementIndexesMap.put("root.sg.d2.a", Arrays.asList(1, 2)); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/OptimizationTestUtil.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/OptimizationTestUtil.java index b2e13e277741..e94145853040 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/OptimizationTestUtil.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/OptimizationTestUtil.java @@ -44,7 +44,7 @@ import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -54,7 +54,7 @@ private OptimizationTestUtil() { // util class } - public static final Map schemaMap = new HashMap<>(); + public static final Map schemaMap = new LinkedHashMap<>(); static { try { @@ -159,6 +159,6 @@ public static AggregationDescriptor getAggregationDescriptor(AggregationStep ste TAggregationType.COUNT.name().toLowerCase(), step, Collections.singletonList(new TimeSeriesOperand(schemaMap.get(path))), - new HashMap<>()); + new LinkedHashMap<>()); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/TestPlanBuilder.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/TestPlanBuilder.java index 9b25ae7787fe..7ad0bc49f66b 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/TestPlanBuilder.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/optimization/TestPlanBuilder.java @@ -62,7 +62,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -353,7 +353,7 @@ public TestPlanBuilder fill(String id, String intValue) { public TestPlanBuilder singleDeviceView(String id, String device, String measurement) { IDeviceID deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create(device); - Map> deviceToMeasurementIndexesMap = new HashMap<>(); + Map> deviceToMeasurementIndexesMap = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.put(deviceID, Collections.singletonList(1)); DeviceViewNode deviceViewNode = new DeviceViewNode( @@ -389,7 +389,7 @@ public TestPlanBuilder topK( public TestPlanBuilder singleOrderedDeviceView( String id, String device, OrderByParameter orderByParameter, String... measurement) { IDeviceID deviceID = IDeviceID.Factory.DEFAULT_FACTORY.create(device); - Map> deviceToMeasurementIndexesMap = new HashMap<>(); + Map> deviceToMeasurementIndexesMap = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.put( deviceID, measurement.length == 1 ? Collections.singletonList(1) : Arrays.asList(1, 2)); DeviceViewNode deviceViewNode = @@ -456,7 +456,7 @@ public TestPlanBuilder deviceView( List devices, Map> deviceToMeasurementIndexesMap, List children) { - Map> map = new HashMap<>(); + Map> map = new LinkedHashMap<>(); deviceToMeasurementIndexesMap.forEach( (key, value) -> map.put(IDeviceID.Factory.DEFAULT_FACTORY.create(key), value)); DeviceViewNode deviceViewNode =