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


##########
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:
   Confirmed with actual SQL execution on a local native cluster. I kept the 
same ASAN BE, table, data and query settings, and swapped only the FE packages 
built from the commits below.
   
   **Reproduction**
   
   ```sql
   CREATE DATABASE IF NOT EXISTS pr68503_ab;
   USE pr68503_ab;
   DROP TABLE IF EXISTS t;
   CREATE TABLE t (k1 INT NOT NULL)
   DUPLICATE KEY(k1)
   DISTRIBUTED BY HASH(k1) BUCKETS 1
   PROPERTIES ("replication_num" = "1");
   
   INSERT INTO t VALUES (1), (1), (2), (2), (3), (3);
   
   SELECT 2 AS two, k1, RAND() AS r
   FROM t
   ORDER BY NTILE(2) OVER (ORDER BY k1), r + r;
   ```
   
   **Observed results**
   
   | FE source commit | Original query | `EXPLAIN VERBOSE` of the same query |
   |---|---|---|
   | PR merge-base on master: `44da2ee105878448b40705e1029861d4b9f71a8c` | 
Success, 6 rows | Success |
   | Master fetched for this experiment: 
`1f3cd9092fbc9151a3cc038d36e32aef68bd8357` | Success, 6 rows | Success |
   | PR head: `758ca77863596f098dd0bd5e2ae5564f106112b1` | Fails during FE 
planning | Same failure |
   
   The PR error is:
   
   ```text
   ERROR 1105 (HY000): errCode = 2, detailMessage =
   The bucket parameter of NTILE must be a constant positive integer: ntile(two)
   ```
   
   Both master plans contain:
   
   ```text
   VANALYTIC
     functions: [ntile(two[#4])]
   ```
   
   Thus the slot representation already exists on master and executes 
successfully; the new literal-only guard introduces the rejection. Restoring 
the PR FE package reproduced the same error.
   
   As controls, changing only `2 AS two` to `3 AS three` makes the query 
succeed on the PR with 6 rows, and a plain `NTILE(2)` query succeeds with 
bucket values `1,1,1,2,2,2`. The random values themselves naturally differ 
between executions. FE package identities were checked using source commits and 
the JAR bytecode/class fingerprints; the generated build-version display string 
was reused across checkouts.
   
   **Suggested change**
   
   Preserve already-validated constant NTILE arguments during ORDER BY alias 
substitution, or restore proven constants at the window-normalization boundary 
before the final legality check. Keep the unconditional positive-integer 
validation, including the translation guard when rewrite rules are disabled. Do 
not allow arbitrary slot arguments or force projection merging across repeated 
uses of `RAND()`. Please add the reproduction above as a regression test 
covering the matching selected constant and repeatedly used volatile projection.
   
   This confirms a P2 query-planning regression: previously valid SQL is 
rejected in FE. The observed path does not return incorrect rows or reach a BE 
crash. These are manual end-to-end SQL runs; I did not run the UT/regression 
suites.



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