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


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PullUpProjectUnderTopN.java:
##########
@@ -48,7 +48,10 @@ public Rule build() {
         return logicalTopN(
                 logicalProject(logicalJoin().when(j -> 
j.getJoinType().isLeftRightOuterOrCrossJoin()
                     || j.getJoinType().isAsofOuterJoin()))
-                    .whenNot(p -> p.isAllSlots()))
+                    // a project computing a NoneMovableFunction (e.g. 
assert_true) or a volatile
+                    // expression must not be pulled above the top-N: rows 
pruned by the top-N
+                    // would stop evaluating the expression, changing its 
error behavior or results.
+                    .whenNot(p -> p.isAllSlots() || 
p.containsNoneMovableOrVolatile()))

Review Comment:
   **[P1] Fence row pruning before it is synthesized below this project**
   
   This guard runs after the project-bearing 
`PushDownTopNThroughJoin`/`PushDownTopNThroughWindow` rules. For `TopN(1,k 
DESC) -> Project(k, assert_true(k>0) AS ok) -> CrossJoin(left k={1,0}, right 
one)`, the earlier Join rule keeps the outer `TopN -> Project` but inserts 
`TopN(1,k DESC)` in the left child. The original Project evaluates 
`assert_true` on `k=0` and errors; the rewritten plan drops that row before the 
Project and returns. Because the Project never moves, the pull-up fences from 
the prior thread cannot prevent this. Please gate every project-bearing 
row-pruning pushdown with `containsNoneMovableOrVolatile()` (including the 
analogous Limit and scan-level TopN paths) and add a full-stage regression 
proving no child pruning is synthesized.



##########
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PushDownFilterThroughJoinTest.java:
##########
@@ -226,4 +228,24 @@ private void bothSideToRight(JoinType joinType) {
                         )
                 );
     }
+
+    @Test
+    void testNotPushNoneMovableFunctionThroughJoin() {
+        // assert_true(student.id > 18) references only the left side but must 
NOT be pushed
+        // to the left child: the child evaluates it on a superset of rows 
(before the join),
+        // changing its error behavior.
+        Expression assertTrueExpr = new AssertTrue(

Review Comment:
   **[P2] Exercise the join-condition conversion guard**
   
   This predicate is a top-level `GreaterThan`, so `convertJoinCondition` 
returns at its existing non-`EqualTo` check and this test reaches only the 
later child-push guard. The patch also adds a separate guard inside 
`convertJoinCondition`; please add a cross-side `EqualTo` containing 
`AssertTrue` and assert the exact `Filter -> Join` tree, so the base 
implementation moves it into `otherJoinConjuncts` while this head retains it 
above the join.



##########
fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/PushProjectIntoUnionTest.java:
##########
@@ -118,6 +122,42 @@ public void 
testConstantExprIdsDistinctFromUnionOutputAndAcrossRows() {
         }
     }
 
+    /**
+     * A constant UNION row holding a NoneMovableFunction (assert_true(false)) 
must never be
+     * dropped by pushing a parent project that does not reference it: the 
push-down would turn a
+     * required assertion/error into plain returned rows. the rule must not 
fire.
+     */
+    @Test
+    public void testDoNotPushProjectIntoUnionWithNoneMovableConst() {
+        SlotReference s = new SlotReference(new ExprId(10), "s",
+                IntegerType.INSTANCE, true, ImmutableList.of());
+        SlotReference x = new SlotReference(new ExprId(11), "x",
+                BooleanType.INSTANCE, true, ImmutableList.of());
+        // constant row: s = 1, x = assert_true(false) — a required assertion 
that throws.
+        NamedExpression rowS = new Alias(new ExprId(1), new IntegerLiteral(1), 
"1");
+        NamedExpression rowX = new Alias(new ExprId(2), new AssertTrue(
+                BooleanLiteral.of(false), new StringLiteral("msg")), "x");
+        LogicalUnion union = new LogicalUnion(Qualifier.ALL,
+                ImmutableList.of(s, x),
+                ImmutableList.of(),
+                ImmutableList.of(ImmutableList.of(rowS, rowX)),
+                false,
+                ImmutableList.of());
+        // parent project selects only s, dropping x: pushing it into the 
union would drop the assertion.

Review Comment:
   **[P2] Cover the newly guarded duplication branch**
   
   This project never references `x`, so it proves only the final 
unreferenced-NoneMovable check. It cannot reach the other changed branch where 
`guardedSlots` rejects a second syntactic reference. Please add a direct case 
that projects the assertion-backed UNION slot twice and verifies the `Project 
-> Union` boundary remains; that case fails on the base volatile-only 
implementation and protects the new no-duplication contract.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Project.java:
##########
@@ -154,4 +154,14 @@ default boolean containsNoneMovableFunction() {
         }
         return false;
     }
+
+    /** containsNoneMovableOrVolatile */
+    default boolean containsNoneMovableOrVolatile() {

Review Comment:
   **[P1] Apply this boundary to join-exploration project moves**
   
   Registered `PushDownProjectThroughInnerOuterJoin` and 
`PushDownProjectThroughSemiJoin` still move arbitrary side-local Projects below 
joins. For `TopJoin(Project(A.k, assert_true(A.k > 0) AS ok, A LEFT SEMI JOIN 
B), C)`, let A contain a failing row with no B match: originally the semi join 
removes it before the Project, but the exploration alternative copies the 
Project into A, so the assertion now runs and turns returned rows into an 
error. The inner-join factory has the same unmatched-row failure, and both are 
active before/after DPHyper. Please reject these moves when the Project 
`containsNoneMovableOrVolatile()`, audit `TransposeAggSemiJoinProject`, and add 
exploration/runtime regressions.



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