mrhhsg commented on code in PR #68503:
URL: https://github.com/apache/doris/pull/68503#discussion_r4269573708


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Ntile.java:
##########
@@ -80,12 +82,27 @@ public void checkLegalityBeforeTypeCoercion() {
             throw new AnalysisException(
                 "The bucket of NTILE must be a constant value: " + 
this.toSql());
         }
-        if (buckets instanceof Literal) {
-            if (((Literal) buckets).getDouble() <= 0) {
-                throw new AnalysisException(
-                    "The bucket parameter of NTILE must be a constant positive 
integer: " + this.toSql());
-            }
-        } else {
+        // The bucket may be a constant expression such as `1 + 1`, which is 
folded to a literal only by the
+        // rewrite phase after this check runs. Reject early a bucket that FE 
already evaluates to a non-positive
+        // or NULL value. A bucket FE can not evaluate, e.g. `3 % 2`, may 
still be folded by BE when
+        // enable_fold_constant_by_be is set, so it is left to 
checkLegalityAfterRewrite.
+        Expression evaluated = ExpressionUtils.foldConstantArgument(buckets);
+        if (evaluated instanceof Literal) {
+            checkPositiveBucket(evaluated);
+        }
+    }
+
+    @Override
+    public void checkLegalityAfterRewrite() {
+        // The backend reads the bucket from the argument column and registers 
ntile only for a non-nullable
+        // integer argument, so the bucket must have been folded to a literal 
before the plan is translated.
+        // That does not happen when constant folding is skipped, e.g. with 
debug_skip_fold_constant=true, or
+        // when the configured folding can not evaluate the bucket.
+        checkPositiveBucket(getArgument(0));

Review Comment:
   Fixed in 215f9102acb.
   
   - `ReplaceExpressionByChildOutput.buildOutputAliasMap` now skips every 
constant alias (`!alias.child().isConstant()`) instead of only `Literal` ones, 
so `1 + 1 AS two` and `CAST(5 - 2 AS BIGINT) AS three` no longer put 
`Add`/`Cast` into the replacement map and the NTILE bucket stays a constant 
expression that the configured folding turns into a literal. Replacing a 
constant with a slot never saves work (it is folded once anyway), so 
non-constant aliases such as `RAND() AS r` or `k1 + 1 AS x` keep being reused 
exactly as before. The positive-bucket checks after rewrite and at translation 
are unchanged, and project merging across the repeated `RAND()` is not touched.
   - Tests:
     - 
`ReplaceExpressionByChildOutputTest.testSortProjectDoesNotReplaceConstantSubExpression`
 covers both a literal alias and a `1 + 1` alias.
     - `test_ntile_function` adds the ORDER-BY-only reproduction with a 
matching selected constant and a repeatedly used volatile projection for `2`, 
`1 + 1` and `CAST(5 - 2 AS BIGINT)`: `select <const> as two, k1, k2, k3, 
floor(rand()) as r from t order by ntile(<const>) over (order by k1,k2,k3), r + 
r, k1, k2, k3`. `floor(rand())` is still volatile (it contains `rand()`, so 
`canMergeWithProjections` still refuses to merge the projection) but is always 
0, which keeps the generated `.out` stable. The window is no longer selected, 
so whole-window substitution cannot short-circuit the bucket visit.
   - Verified locally: both targeted FE UTs pass (16/16), the regression suite 
passes with regenerated output, and your two original SQL statements with a 
real `RAND()` return all rows on a local cluster; `EXPLAIN` shows `functions: 
[ntile(2)]` with `floor(random())` left in the projection below the window.
   



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