github-actions[bot] commented on code in PR #65682:
URL: https://github.com/apache/doris/pull/65682#discussion_r3674210931


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraphv2/receiver/PlanReceiver.java:
##########
@@ -291,29 +300,64 @@ public Group getBestPlan(long bitmap) {
 
     private LogicalPlan proposeProject(LogicalPlan join, List<Edge> edges, 
long left, long right) {
         Set<Slot> outputSet = join.getOutputSet();
-        // calculate required columns by all parents
-        Set<Slot> requireSlots = calculateRequiredSlots(left, right, edges);
+        // calculate required columns by all parents (final outputs + unused 
edges)
+        Set<Slot> parentRequireSlots = calculateRequiredSlots(left, right, 
edges);
+        // Pending projected aliases may reference input slots (e.g., A.v, B.v 
for
+        // s=A.v+B.v) that are not in finalRequiredSlots or unused edges. 
Preserve
+        // them so the join output still contains the base columns needed to 
evaluate
+        // the alias expressions, both for aliases emitted at this stage and 
those
+        // deferred to a later join whose bitmap is a superset.
+        Set<Slot> aliasInputSlots = hyperGraph.getAllAliasInputSlotsForNodes(
+                LongBitmap.newBitmapUnion(left, right));
+        Set<Slot> requireSlots = new HashSet<>(parentRequireSlots);
+        requireSlots.addAll(aliasInputSlots);
         List<NamedExpression> allProjects = new ArrayList<>(outputSet.size());
         for (Slot slot : outputSet) {
             if (requireSlots.contains(slot)) {
                 allProjects.add(slot);
             }
         }
-        if (hyperGraph.hasLiteralAlias()) {
-            allProjects.addAll(hyperGraph.getLiteralAlias(left, right));
-        }
 
         if (allProjects.isEmpty()) {
             allProjects.add(new Alias(new ExprId(-1), new 
TinyIntLiteral((byte) 1)));
         }
 
-        // propose logical project
+        // propose logical project for the slot pass-through
         LogicalPlan logicalPlan;
         if (outputSet.equals(new HashSet<>(allProjects))) {
             logicalPlan = join;
         } else {
             logicalPlan = new LogicalProject<>(allProjects, join);
         }
+
+        // Emit projected aliases as a single LogicalProject node.
+        // Cross-layer references (e.g., z = x + 1 referencing x = COALESCE(v, 
0))
+        // were already resolved at graph-build time, so only one Project is 
needed.
+        // Carry forward child slots still required by parents (e.g., join 
keys)
+        // or by deferred alias layers (e.g., B.w for a later y=B.w+1).
+        // Use the full requireSlots so that deferred-layer inputs survive
+        // through intermediate layers.
+        if (hyperGraph.hasProjectedAliases()) {
+            List<NamedExpression> aliases = 
hyperGraph.getProjectedAliases(left, right);
+            if (!aliases.isEmpty()) {
+                Set<ExprId> aliasExprIds = new HashSet<>();
+                for (NamedExpression a : aliases) {
+                    aliasExprIds.add(a.getExprId());
+                }
+                List<NamedExpression> mergedLayer = new ArrayList<>(aliases);
+                Set<Slot> emittedAliasSlots = 
hyperGraph.getAliasInputSlotsForSubsetNodes(
+                        left, right);
+                for (Slot childSlot : logicalPlan.getOutputSet()) {
+                    if (requireSlots.contains(childSlot)
+                            && !aliasExprIds.contains(childSlot.getExprId())
+                            && !emittedAliasSlots.contains(childSlot)) {

Review Comment:
   [P1] Keep alias inputs that are still required by parents
   
   A reduced input is:
   
   ```text
   LeftOuterJoin(A.k = B.k)
     A
     Project(B.k, B.k + 1 AS x)
       B
   ```
   
   While building leaf `{B}`, `parentRequireSlots` contains `B.k` for the 
unused outer-join edge, and the alias also consumes `B.k`. 
`getAliasInputSlotsForSubsetNodes(B,B)` therefore puts `B.k` in 
`emittedAliasSlots`, and this condition removes it even though the parent still 
needs it. The rebuilt right child becomes `Project[x]`, so the later 
`LeftOuterJoin(A.k = B.k)` references an ExprId its child no longer outputs and 
`CheckAfterRewrite` rejects the plan. Please distinguish why a slot is live and 
remove an emitted alias input only when no parent edge, final output, or 
pending layer still requires it; add a plan-shape/slot-validity test where the 
alias consumes its parent join key.
   



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to