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


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/PercentileReservoir.java:
##########
@@ -67,21 +69,38 @@ private PercentileReservoir(NullableAggregateFunctionParams 
functionParams) {
 
     @Override
     public void checkLegalityBeforeTypeCoercion() {
+        checkLevel();
+    }
+
+    @Override
+    public void checkLegalityAfterRewrite() {
+        checkLevel();
+    }
+
+    /**
+     * The level must be a constant that folds to a literal in [0, 1]. It is 
folded here instead of
+     * waiting for the rewrite phase because a constant expression such as 
0.25 + 0.25 is only a
+     * literal after folding, some plans (INSERT ... VALUES, load column 
mappings) never run the
+     * rewrite phase, and constant folding can be turned off by 
debug_skip_fold_constant.
+     */
+    private void checkLevel() {
         Expression levelArgument = getArgument(1);
-        if (!levelArgument.isConstant()) {
+        Expression level = levelArgument.isConstant()
+                ? FoldConstantRuleOnFE.evaluateWithoutContext(levelArgument) : 
levelArgument;
+        if (!(level instanceof Literal)) {
             throw new AnalysisException(
                     "percentile_reservoir requires second parameter must be a 
constant : " + this.toSql());
         }
-        if (levelArgument instanceof Literal) {
-            double value = ((Literal) levelArgument).getDouble();
-            // Negate the valid range to reject NaN, which makes both < 0 and 
> 1 false.
-            if (!(value >= 0 && value <= 1)) {
-                throw new AnalysisException(
-                        "percentile_reservoir level must be in [0, 1], but got 
" + value + ": " + this.toSql());
-            }
-        } else {
+        // a NULL level is skipped by the null-ignoring BE implementation and 
yields a NULL result
+        if (level instanceof NullLiteral) {
+            return;
+        }
+        // the literal may still carry its own type here, for example DECIMAL 
or VARCHAR
+        double value = ((Literal) ((Literal) 
level).checkedCastTo(DoubleType.INSTANCE)).getDouble();

Review Comment:
   [P2] Preserve non-strict implicit-cast semantics here. With the default 
`enable_strict_cast=false`, this direct `checkedCastTo(DOUBLE)` makes 
`percentile_reservoir(number, '')` throw before signature coercion. In the base 
code the empty string passed the old range check and the ordinary 
VARCHAR-to-DOUBLE cast then produced NULL; the equivalent explicit `cast('' as 
double)` still produces NULL and is accepted above. This therefore introduces a 
syntax-dependent regression for equivalent implicit and explicit casts. Please 
range-check the result of the same session-aware DOUBLE cast/fold used by 
normal coercion (so non-strict failures become `NullLiteral` and strict 
failures still throw), and cover both forms in both cast modes.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/PercentileReservoir.java:
##########
@@ -67,21 +69,38 @@ private PercentileReservoir(NullableAggregateFunctionParams 
functionParams) {
 
     @Override
     public void checkLegalityBeforeTypeCoercion() {
+        checkLevel();
+    }
+
+    @Override
+    public void checkLegalityAfterRewrite() {
+        checkLevel();
+    }
+
+    /**
+     * The level must be a constant that folds to a literal in [0, 1]. It is 
folded here instead of
+     * waiting for the rewrite phase because a constant expression such as 
0.25 + 0.25 is only a
+     * literal after folding, some plans (INSERT ... VALUES, load column 
mappings) never run the
+     * rewrite phase, and constant folding can be turned off by 
debug_skip_fold_constant.
+     */
+    private void checkLevel() {
         Expression levelArgument = getArgument(1);
-        if (!levelArgument.isConstant()) {
+        Expression level = levelArgument.isConstant()
+                ? FoldConstantRuleOnFE.evaluateWithoutContext(levelArgument) : 
levelArgument;

Review Comment:
   [P1] Do not validate this level against a different DECIMALV2 result than 
BE. For `percentile_reservoir(number, cast(0 as decimalv2(27,9)) / cast(2 as 
decimalv2(27,9)))`, this helper calls `NumericArithmetic.divideDecimal`, whose 
zero guard checks the numerator and folds `0 / 2` to NULL. Normal rewrite 
repeats that fold, so the aggregate returns NULL; with 
`debug_skip_fold_constant=true`, this check still accepts NULL but the original 
expression reaches BE, whose denominator check computes level 0, so the 
aggregate returns the minimum value. The setting therefore changes query 
results and the legality check validates a value BE does not execute. Please 
fix the FE DECIMALV2 denominator check (including `1 / 0`) or otherwise avoid 
relying on the mismatched fold, and cover both folding modes.



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