JackieTien97 commented on code in PR #15735:
URL: https://github.com/apache/iotdb/pull/15735#discussion_r2176498997


##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;

Review Comment:
   add some comments about this field to describe its life cycle, like when 
will this field be set to null



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;
+  // All LastSeriesSourceNode share this structure
+  private List<IMeasurementSchema> globalMeasurementSchemaList;
+
   public LastQueryNode(
       PlanNodeId id, @Nullable Ordering timeseriesOrdering, boolean 
containsLastTransformNode) {
     super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.measurementSchema2IdxMap = new HashMap<>();
+    this.globalMeasurementSchemaList = new ArrayList<>();
   }
 
   public LastQueryNode(
       PlanNodeId id,
-      List<PlanNode> children,
       @Nullable Ordering timeseriesOrdering,
-      boolean containsLastTransformNode) {
-    super(id, children);
+      boolean containsLastTransformNode,
+      List<IMeasurementSchema> globalMeasurementSchemaList) {
+    super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public long addDeviceLastQueryScanNode(
+      PlanNodeId id,
+      PartialPath devicePath,
+      boolean aligned,
+      List<IMeasurementSchema> measurementSchemas,
+      String outputViewPath) {
+    List<Integer> idxList = new ArrayList<>(measurementSchemas.size());
+    for (IMeasurementSchema measurementSchema : measurementSchemas) {
+      int idx =
+          measurementSchema2IdxMap.computeIfAbsent(
+              measurementSchema,
+              key -> {
+                this.globalMeasurementSchemaList.add(key);
+                return globalMeasurementSchemaList.size() - 1;
+              });
+      idxList.add(idx);
+    }
+    LastQueryScanNode scanNode =
+        new LastQueryScanNode(
+            id, devicePath, aligned, idxList, outputViewPath, 
globalMeasurementSchemaList);
+    children.add(scanNode);
+    return scanNode.getMemorySize();
+  }
+
+  public void sort() {
+    if (timeseriesOrdering == null) {
+      return;
+    }
+    children.sort(
+        Comparator.comparing(
+            child -> {
+              String sortKey = "";
+              if (child instanceof LastQueryScanNode) {
+                sortKey = ((LastQueryScanNode) child).getOutputSymbolForSort();
+              } else if (child instanceof LastQueryTransformNode) {
+                sortKey = ((LastQueryTransformNode) 
child).getOutputSymbolForSort();
+              }
+              return sortKey;
+            }));
+    if (timeseriesOrdering.equals(Ordering.DESC)) {
+      Collections.reverse(children);
+    }
+  }
+
+  public void setGlobalMeasurementSchemaList(List<IMeasurementSchema> 
globalMeasurementSchemaList) {
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public List<IMeasurementSchema> getGlobalMeasurementSchemaList() {
+    return globalMeasurementSchemaList;
+  }

Review Comment:
   ```suggestion
   ```
   never used



##########
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/LastQueryOperatorTest.java:
##########
@@ -192,7 +192,7 @@ public void testLastQueryOperator1() throws Exception {
       LastQueryOperator lastQueryOperator =
           new LastQueryOperator(
               driverContext.getOperatorContexts().get(4),
-              ImmutableList.of(updateLastCacheOperator1, 
updateLastCacheOperator2),
+              Arrays.asList(updateLastCacheOperator1, 
updateLastCacheOperator2),

Review Comment:
   why we need to change it into a mutable list?



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;
+  // All LastSeriesSourceNode share this structure
+  private List<IMeasurementSchema> globalMeasurementSchemaList;
+
   public LastQueryNode(
       PlanNodeId id, @Nullable Ordering timeseriesOrdering, boolean 
containsLastTransformNode) {
     super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.measurementSchema2IdxMap = new HashMap<>();
+    this.globalMeasurementSchemaList = new ArrayList<>();
   }
 
   public LastQueryNode(
       PlanNodeId id,
-      List<PlanNode> children,
       @Nullable Ordering timeseriesOrdering,
-      boolean containsLastTransformNode) {
-    super(id, children);
+      boolean containsLastTransformNode,
+      List<IMeasurementSchema> globalMeasurementSchemaList) {
+    super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public long addDeviceLastQueryScanNode(
+      PlanNodeId id,
+      PartialPath devicePath,
+      boolean aligned,
+      List<IMeasurementSchema> measurementSchemas,
+      String outputViewPath) {
+    List<Integer> idxList = new ArrayList<>(measurementSchemas.size());
+    for (IMeasurementSchema measurementSchema : measurementSchemas) {
+      int idx =
+          measurementSchema2IdxMap.computeIfAbsent(
+              measurementSchema,
+              key -> {
+                this.globalMeasurementSchemaList.add(key);
+                return globalMeasurementSchemaList.size() - 1;
+              });
+      idxList.add(idx);
+    }
+    LastQueryScanNode scanNode =
+        new LastQueryScanNode(
+            id, devicePath, aligned, idxList, outputViewPath, 
globalMeasurementSchemaList);
+    children.add(scanNode);
+    return scanNode.getMemorySize();

Review Comment:
   ```suggestion
       return scanNode.ramBytesUsed();
   ```



##########
iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/partition/DataPartition.java:
##########
@@ -155,6 +158,31 @@ public List<TRegionReplicaSet> 
getDataRegionReplicaSetWithTimeFilter(
         .collect(toList());
   }
 
+  public List<TRegionReplicaSet> getDataRegionReplicaSetWithTimeFilter(
+      String db, TSeriesPartitionSlot tSeriesPartitionSlot, Filter timeFilter) 
{
+    Map<TTimePartitionSlot, List<TRegionReplicaSet>> regionReplicaSetMap =
+        dataPartitionMap
+            .getOrDefault(db, Collections.emptyMap())
+            .getOrDefault(tSeriesPartitionSlot, Collections.emptyMap());
+    if (regionReplicaSetMap.isEmpty()) {
+      return Collections.singletonList(NOT_ASSIGNED);
+    }
+    List<TRegionReplicaSet> replicaSets = new ArrayList<>();
+    Set<TRegionReplicaSet> uniqueValues = new HashSet<>();
+    for (Entry<TTimePartitionSlot, List<TRegionReplicaSet>> entry :
+        regionReplicaSetMap.entrySet()) {
+      if (!TimePartitionUtils.satisfyPartitionStartTime(timeFilter, 
entry.getKey().startTime)) {
+        continue;
+      }
+      for (TRegionReplicaSet tRegionReplicaSet : entry.getValue()) {
+        if (uniqueValues.add(tRegionReplicaSet)) {
+          replicaSets.add(tRegionReplicaSet);
+        }
+      }
+    }
+    return replicaSets;
+  }
+

Review Comment:
   never used



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;
+  // All LastSeriesSourceNode share this structure
+  private List<IMeasurementSchema> globalMeasurementSchemaList;
+
   public LastQueryNode(
       PlanNodeId id, @Nullable Ordering timeseriesOrdering, boolean 
containsLastTransformNode) {
     super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.measurementSchema2IdxMap = new HashMap<>();
+    this.globalMeasurementSchemaList = new ArrayList<>();
   }
 
   public LastQueryNode(
       PlanNodeId id,
-      List<PlanNode> children,
       @Nullable Ordering timeseriesOrdering,
-      boolean containsLastTransformNode) {
-    super(id, children);
+      boolean containsLastTransformNode,
+      List<IMeasurementSchema> globalMeasurementSchemaList) {
+    super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public long addDeviceLastQueryScanNode(
+      PlanNodeId id,
+      PartialPath devicePath,
+      boolean aligned,
+      List<IMeasurementSchema> measurementSchemas,
+      String outputViewPath) {
+    List<Integer> idxList = new ArrayList<>(measurementSchemas.size());
+    for (IMeasurementSchema measurementSchema : measurementSchemas) {
+      int idx =
+          measurementSchema2IdxMap.computeIfAbsent(
+              measurementSchema,
+              key -> {
+                this.globalMeasurementSchemaList.add(key);
+                return globalMeasurementSchemaList.size() - 1;
+              });
+      idxList.add(idx);
+    }
+    LastQueryScanNode scanNode =
+        new LastQueryScanNode(
+            id, devicePath, aligned, idxList, outputViewPath, 
globalMeasurementSchemaList);
+    children.add(scanNode);
+    return scanNode.getMemorySize();
+  }
+
+  public void sort() {
+    if (timeseriesOrdering == null) {
+      return;
+    }
+    children.sort(
+        Comparator.comparing(
+            child -> {
+              String sortKey = "";
+              if (child instanceof LastQueryScanNode) {
+                sortKey = ((LastQueryScanNode) child).getOutputSymbolForSort();
+              } else if (child instanceof LastQueryTransformNode) {
+                sortKey = ((LastQueryTransformNode) 
child).getOutputSymbolForSort();
+              }
+              return sortKey;
+            }));
+    if (timeseriesOrdering.equals(Ordering.DESC)) {
+      Collections.reverse(children);
+    }
+  }
+
+  public void setGlobalMeasurementSchemaList(List<IMeasurementSchema> 
globalMeasurementSchemaList) {
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public List<IMeasurementSchema> getGlobalMeasurementSchemaList() {
+    return globalMeasurementSchemaList;
+  }
+
+  public void setMeasurementSchema2IdxMap(
+      Map<IMeasurementSchema, Integer> measurementSchema2IdxMap) {
+    this.measurementSchema2IdxMap = measurementSchema2IdxMap;
+  }
+
+  public long getMemorySizeOfSharedStructures() {
+    return RamUsageEstimator.shallowSizeOf(this.globalMeasurementSchemaList)
+        + 
RamUsageEstimator.sizeOfObjectArray(globalMeasurementSchemaList.size());
   }
 
   @Override
-  public List<PlanNode> getChildren() {
-    return children;
+  public void serialize(DataOutputStream stream) throws IOException {
+    super.serialize(stream);
   }
 
   @Override
-  public void addChild(PlanNode child) {
-    children.add(child);
+  public void serialize(ByteBuffer byteBuffer) {
+    super.serialize(byteBuffer);
   }

Review Comment:
   don't need to override it?



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;
+  // All LastSeriesSourceNode share this structure
+  private List<IMeasurementSchema> globalMeasurementSchemaList;
+
   public LastQueryNode(
       PlanNodeId id, @Nullable Ordering timeseriesOrdering, boolean 
containsLastTransformNode) {
     super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.measurementSchema2IdxMap = new HashMap<>();
+    this.globalMeasurementSchemaList = new ArrayList<>();
   }
 
   public LastQueryNode(
       PlanNodeId id,
-      List<PlanNode> children,
       @Nullable Ordering timeseriesOrdering,
-      boolean containsLastTransformNode) {
-    super(id, children);
+      boolean containsLastTransformNode,
+      List<IMeasurementSchema> globalMeasurementSchemaList) {
+    super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public long addDeviceLastQueryScanNode(
+      PlanNodeId id,
+      PartialPath devicePath,
+      boolean aligned,
+      List<IMeasurementSchema> measurementSchemas,
+      String outputViewPath) {
+    List<Integer> idxList = new ArrayList<>(measurementSchemas.size());
+    for (IMeasurementSchema measurementSchema : measurementSchemas) {
+      int idx =
+          measurementSchema2IdxMap.computeIfAbsent(
+              measurementSchema,
+              key -> {
+                this.globalMeasurementSchemaList.add(key);
+                return globalMeasurementSchemaList.size() - 1;
+              });
+      idxList.add(idx);
+    }
+    LastQueryScanNode scanNode =
+        new LastQueryScanNode(
+            id, devicePath, aligned, idxList, outputViewPath, 
globalMeasurementSchemaList);
+    children.add(scanNode);
+    return scanNode.getMemorySize();
+  }
+
+  public void sort() {
+    if (timeseriesOrdering == null) {
+      return;
+    }
+    children.sort(
+        Comparator.comparing(
+            child -> {
+              String sortKey = "";
+              if (child instanceof LastQueryScanNode) {
+                sortKey = ((LastQueryScanNode) child).getOutputSymbolForSort();
+              } else if (child instanceof LastQueryTransformNode) {
+                sortKey = ((LastQueryTransformNode) 
child).getOutputSymbolForSort();
+              }
+              return sortKey;
+            }));
+    if (timeseriesOrdering.equals(Ordering.DESC)) {
+      Collections.reverse(children);
+    }
+  }
+
+  public void setGlobalMeasurementSchemaList(List<IMeasurementSchema> 
globalMeasurementSchemaList) {
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public List<IMeasurementSchema> getGlobalMeasurementSchemaList() {
+    return globalMeasurementSchemaList;
+  }
+
+  public void setMeasurementSchema2IdxMap(
+      Map<IMeasurementSchema, Integer> measurementSchema2IdxMap) {
+    this.measurementSchema2IdxMap = measurementSchema2IdxMap;
+  }
+
+  public long getMemorySizeOfSharedStructures() {
+    return RamUsageEstimator.shallowSizeOf(this.globalMeasurementSchemaList)
+        + 
RamUsageEstimator.sizeOfObjectArray(globalMeasurementSchemaList.size());

Review Comment:
   ```suggestion
       return RamUsageEstimator.sizeOfCollection(globalMeasurementSchemaList);
   ```



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java:
##########
@@ -597,48 +598,81 @@ private Analysis analyzeLastQuery(
     for (ResultColumn resultColumn : 
queryStatement.getSelectComponent().getResultColumns()) {
       selectExpressions.add(resultColumn.getExpression());
     }
-    analyzeLastSource(analysis, selectExpressions, schemaTree, context);
-
     analysis.setRespDatasetHeader(DatasetHeaderFactory.getLastQueryHeader());
 
-    // fetch partition information
-    analyzeDataPartition(analysis, queryStatement, schemaTree, context);
-
-    return analysis;
+    return analyzeLastSourceAndDataPartition(analysis, selectExpressions, 
schemaTree, context);
   }
 
-  private void analyzeLastSource(
+  private Analysis analyzeLastSourceAndDataPartition(
       Analysis analysis,
       List<Expression> selectExpressions,
       ISchemaTree schemaTree,
       MPPQueryContext context) {
-    Set<Expression> sourceExpressions = new LinkedHashSet<>();
-    Set<Expression> lastQueryBaseExpressions = new LinkedHashSet<>();
+
+    // For fetch data partition
+    Set<IDeviceID> allDeviceSet = new HashSet<>();
+
+    // For LogicalPlan
+    Set<IDeviceID> deviceExistViewSet = new HashSet<>();
+    Map<IDeviceID, Map<String, Expression>> outputPathToSourceExpressionMap = 
new LinkedHashMap<>();
     Map<Expression, List<Expression>> 
lastQueryNonWritableViewSourceExpressionMap = null;
 
+    Ordering timeseriesOrdering = analysis.getTimeseriesOrderingForLastQuery();
+
     for (Expression selectExpression : selectExpressions) {
       for (Expression lastQuerySourceExpression :
           bindSchemaForExpression(selectExpression, schemaTree, context)) {
         if (lastQuerySourceExpression instanceof TimeSeriesOperand) {
-          lastQueryBaseExpressions.add(lastQuerySourceExpression);
-          sourceExpressions.add(lastQuerySourceExpression);
-        } else {
-          if (lastQueryNonWritableViewSourceExpressionMap == null) {
-            lastQueryNonWritableViewSourceExpressionMap = new HashMap<>();
+          TimeSeriesOperand timeSeriesOperand = (TimeSeriesOperand) 
lastQuerySourceExpression;
+          MeasurementPath outputPath =
+              (MeasurementPath)
+                  (timeSeriesOperand.isViewExpression()
+                      ? timeSeriesOperand.getViewPath()
+                      : timeSeriesOperand.getPath());
+          IDeviceID outputDevice =
+              
ExpressionAnalyzer.getDeviceNameInSourceExpression(timeSeriesOperand);
+          outputPathToSourceExpressionMap
+              .computeIfAbsent(
+                  outputDevice,
+                  k ->
+                      timeseriesOrdering != null
+                          ? new 
TreeMap<>(timeseriesOrdering.getStringComparator())
+                          : new LinkedHashMap<>())
+              .put(outputPath.getMeasurement(), timeSeriesOperand);
+
+          if (timeSeriesOperand.isViewExpression()) {
+            deviceExistViewSet.add(outputDevice);
           }
+        } else {
+          lastQueryNonWritableViewSourceExpressionMap =
+              lastQueryNonWritableViewSourceExpressionMap == null
+                  ? new HashMap<>()
+                  : lastQueryNonWritableViewSourceExpressionMap;
           List<Expression> sourceExpressionsOfNonWritableView =
               searchSourceExpressions(lastQuerySourceExpression);
           lastQueryNonWritableViewSourceExpressionMap.putIfAbsent(
               lastQuerySourceExpression, sourceExpressionsOfNonWritableView);
-          sourceExpressions.addAll(sourceExpressionsOfNonWritableView);
+          for (Expression expression : sourceExpressionsOfNonWritableView) {
+            
allDeviceSet.add(ExpressionAnalyzer.getDeviceNameInSourceExpression(expression));
+          }
         }
       }
     }
+    if (allDeviceSet.isEmpty()) {
+      allDeviceSet = outputPathToSourceExpressionMap.keySet();
+    } else {
+      allDeviceSet.addAll(outputPathToSourceExpressionMap.keySet());
+    }
 
-    analysis.setSourceExpressions(sourceExpressions);
-    analysis.setLastQueryBaseExpressions(lastQueryBaseExpressions);
+    analysis.setShouldHaveSourceExpression(!allDeviceSet.isEmpty());
+    
analysis.setLastQueryOutputPathToSourceExpressionMap(outputPathToSourceExpressionMap);
+    analysis.setDeviceExistViewSet(deviceExistViewSet);

Review Comment:
   ```suggestion
           analysis.setDeviceExistViewSet(deviceExistViewSet.isEmpty() ? 
Collections.emptySet() : deviceExistViewSet);
   ```



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/LastQueryOperator.java:
##########
@@ -116,6 +116,7 @@ public TsBlock next() throws Exception {
           return null;
         } else if (!tsBlock.isEmpty()) {
           LastQueryUtil.appendLastValue(tsBlockBuilder, tsBlock);
+          continue;

Review Comment:
   child.hasNext and next can only be called once in parent's next call



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java:
##########
@@ -46,31 +59,100 @@ public class LastQueryNode extends MultiChildProcessNode {
   // if children contains LastTransformNode, this variable is only used in 
distribute plan
   private boolean containsLastTransformNode;
 
+  private Map<IMeasurementSchema, Integer> measurementSchema2IdxMap;
+  // All LastSeriesSourceNode share this structure
+  private List<IMeasurementSchema> globalMeasurementSchemaList;
+
   public LastQueryNode(
       PlanNodeId id, @Nullable Ordering timeseriesOrdering, boolean 
containsLastTransformNode) {
     super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.measurementSchema2IdxMap = new HashMap<>();
+    this.globalMeasurementSchemaList = new ArrayList<>();
   }
 
   public LastQueryNode(
       PlanNodeId id,
-      List<PlanNode> children,
       @Nullable Ordering timeseriesOrdering,
-      boolean containsLastTransformNode) {
-    super(id, children);
+      boolean containsLastTransformNode,
+      List<IMeasurementSchema> globalMeasurementSchemaList) {
+    super(id);
     this.timeseriesOrdering = timeseriesOrdering;
     this.containsLastTransformNode = containsLastTransformNode;
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public long addDeviceLastQueryScanNode(
+      PlanNodeId id,
+      PartialPath devicePath,
+      boolean aligned,
+      List<IMeasurementSchema> measurementSchemas,
+      String outputViewPath) {
+    List<Integer> idxList = new ArrayList<>(measurementSchemas.size());
+    for (IMeasurementSchema measurementSchema : measurementSchemas) {
+      int idx =
+          measurementSchema2IdxMap.computeIfAbsent(
+              measurementSchema,
+              key -> {
+                this.globalMeasurementSchemaList.add(key);
+                return globalMeasurementSchemaList.size() - 1;
+              });
+      idxList.add(idx);
+    }
+    LastQueryScanNode scanNode =
+        new LastQueryScanNode(
+            id, devicePath, aligned, idxList, outputViewPath, 
globalMeasurementSchemaList);
+    children.add(scanNode);
+    return scanNode.getMemorySize();
+  }
+
+  public void sort() {
+    if (timeseriesOrdering == null) {
+      return;
+    }
+    children.sort(
+        Comparator.comparing(
+            child -> {
+              String sortKey = "";
+              if (child instanceof LastQueryScanNode) {
+                sortKey = ((LastQueryScanNode) child).getOutputSymbolForSort();
+              } else if (child instanceof LastQueryTransformNode) {
+                sortKey = ((LastQueryTransformNode) 
child).getOutputSymbolForSort();
+              }
+              return sortKey;
+            }));
+    if (timeseriesOrdering.equals(Ordering.DESC)) {
+      Collections.reverse(children);
+    }
+  }
+
+  public void setGlobalMeasurementSchemaList(List<IMeasurementSchema> 
globalMeasurementSchemaList) {
+    this.globalMeasurementSchemaList = globalMeasurementSchemaList;
+  }
+
+  public List<IMeasurementSchema> getGlobalMeasurementSchemaList() {
+    return globalMeasurementSchemaList;
+  }
+
+  public void setMeasurementSchema2IdxMap(
+      Map<IMeasurementSchema, Integer> measurementSchema2IdxMap) {
+    this.measurementSchema2IdxMap = measurementSchema2IdxMap;
+  }

Review Comment:
   ```suggestion
     public void clearMeasurementSchema2IdxMap() {
       this.measurementSchema2IdxMap = null;
     }
   ```



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java:
##########
@@ -1251,20 +1257,21 @@ private PlanNode processRawMultiChildNode(
       // At last, we can use the parameter `addParent` to judge whether to 
create new
       // MultiChildNode.
       boolean appendToRootDirectly =
-          sourceGroup.size() == 1 || (!addParent && 
!context.isForceAddParent());
+          !isLastQueryWithTransformNode

Review Comment:
   update the above comments



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/LastQuerySortOperator.java:
##########
@@ -179,21 +180,20 @@ private boolean keepGoing(long start, long maxRuntime, 
int endIndex) {
         && !tsBlockBuilder.isFull();
   }
 
-  private boolean prepareData() throws Exception {
+  private void prepareData() throws Exception {
     if (previousTsBlock == null || previousTsBlock.getPositionCount() <= 
previousTsBlockIndex) {
       if (children.get(currentIndex).hasNextWithTimer()) {
         previousTsBlock = children.get(currentIndex).nextWithTimer();
         previousTsBlockIndex = 0;
-        if (previousTsBlock == null) {
-          return true;
+        if (previousTsBlock == null || 
children.get(currentIndex).hasNextWithTimer()) {

Review Comment:
   we should only call hasNextWithTimer once



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java:
##########
@@ -1225,12 +1228,15 @@ public List<PlanNode> visitFullOuterTimeJoin(
     if (containsAggregationSource(node)) {
       return planAggregationWithTimeJoin(node, context);
     }
-    return Collections.singletonList(processRawMultiChildNode(node, context, 
true));
+    return Collections.singletonList(processRawMultiChildNode(node, context, 
true, false));
   }
 
   // Only `visitFullOuterTimeJoin` and `visitLastQuery` invoke this method
   private PlanNode processRawMultiChildNode(
-      MultiChildProcessNode node, DistributionPlanContext context, boolean 
isTimeJoin) {
+      MultiChildProcessNode node,
+      DistributionPlanContext context,
+      boolean isTimeJoin,
+      boolean isLastQueryWithTransformNode) {

Review Comment:
   why we need this parameter?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to