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


##########
be/src/exprs/aggregate/aggregate_function_percentile.h:
##########
@@ -201,7 +213,7 @@ class AggregateFunctionPercentileApproxBase
 
     void check_input_columns_type(const IColumn** columns) const override {
         for (size_t i = 0; i < this->argument_types.size(); ++i) {
-            this->template 
check_argument_column_type<ColumnFloat64>(columns[i]);
+            this->template 
check_const_argument_column_type<ColumnFloat64>(columns[i]);

Review Comment:
   `check_input_columns_type()` now calls `check_const_argument_column_type()` 
for every `percentile_approx` argument, but `get_const_argument_indexes()` only 
marks the quantile/compression positions as required constants. In the normal 
aggregate path `_calc_argument_columns()` wraps only those indexes, so 
`percentile_approx(col_double, 0.5)` still reaches this checker with 
`columns[0]` as a plain `ColumnFloat64`; the weighted forms likewise pass 
non-const value/weight columns at indexes 0/1. The helper then assert-casts 
those ordinary columns to `ColumnConst` before `add()` can run. Please keep 
source/weight inputs on `check_argument_column_type()` and apply the 
const-column check only to the required constant positions.



##########
be/src/exprs/aggregate/aggregate_function_percentile.h:
##########
@@ -654,30 +682,33 @@ class AggregateFunctionPercentile final
 
     DataTypePtr get_return_type() const override { return 
std::make_shared<DataTypeFloat64>(); }
 
+    const std::vector<size_t>& get_const_argument_indexes() const override {
+        static const std::vector<size_t> indexes {1};
+        return indexes;
+    }
+
     void add(AggregateDataPtr __restrict place, const IColumn** columns, 
ssize_t row_num,
              Arena&) const override {
         const auto& sources =
                 assert_cast<const ColVecType&, 
TypeCheckOnRelease::DISABLE>(*columns[0]);
-        const auto& quantile =
-                assert_cast<const ColumnFloat64&, 
TypeCheckOnRelease::DISABLE>(*columns[1]);
+        const auto& quantile_column = 
*check_and_get_column_with_const<ColumnFloat64>(*columns[1]);
         
AggregateFunctionPercentile::data(place).add(sources.get_data()[row_num],
-                                                     quantile.get_data(), 
NullMap(1, 0), 1);
+                                                     
quantile_column.get_data()[0]);
     }
 
     void add_batch_single_place(size_t batch_size, AggregateDataPtr place, 
const IColumn** columns,
                                 Arena&) const override {
         const auto& sources =
                 assert_cast<const ColVecType&, 
TypeCheckOnRelease::DISABLE>(*columns[0]);
-        const auto& quantile =
-                assert_cast<const ColumnFloat64&, 
TypeCheckOnRelease::DISABLE>(*columns[1]);
         DCHECK_EQ(sources.get_data().size(), batch_size);
+        const auto& quantile_column = 
*check_and_get_column_with_const<ColumnFloat64>(*columns[1]);
         AggregateFunctionPercentile::data(place).add_batch(sources.get_data(),
-                                                           
quantile.get_data()[0]);
+                                                           
quantile_column.get_data()[0]);
     }
 
     void check_input_columns_type(const IColumn** columns) const override {
         this->template check_argument_column_type<ColVecType>(columns[0]);
-        this->template check_argument_column_type<ColumnFloat64>(columns[1]);
+        this->template 
check_const_argument_column_type<ColumnFloat64>(columns[1]);

Review Comment:
   The ordinary aggregate path now re-wraps required constants in 
`_calc_argument_columns()`, but analytic/window aggregation never uses that 
path. `AnalyticSinkOperatorX::_insert_range_column()` executes each aggregate 
argument, immediately calls `convert_to_full_column_if_const()`, stores the 
full mutable column, and `_execute_for_function()` later passes those stored 
columns into `AggFnEvaluator::add_range_single_place()`. This new const-only 
check therefore breaks existing window calls such as `percentile(b, 0.5) 
over(...)` (and the same shape applies to `percentile_reservoir(..., 0.5)` and 
the added EMA window case), because the quantile reaches this checker as 
`ColumnFloat64`, not `ColumnConst`. Please preserve/re-create const columns for 
required-const window aggregate arguments, or relax the window 
checker/add-range path to accept the materialized constant value.



##########
regression-test/suites/query_p0/aggregate/support_type/percentile/percentile.groovy:
##########
@@ -103,4 +103,21 @@ suite("percentile") {
     qt_percentile_all_nan """select percentile(v_double, 0.5) from 
percentile_all_nan_t;"""
     qt_percentile_array_all_nan """select percentile_array(v_double, [0.25, 
0.5, 0.75]) from percentile_all_nan_t;"""
     qt_percentile_approx_all_nan """select percentile_approx(v_double, 0.5) 
from percentile_all_nan_t;"""
-}
\ No newline at end of file
+
+    test {
+        sql """select percentile(col_double, -0.1) from d_table;"""
+        exception "percentile quantile must be in [0, 1]"
+    }
+    test {
+        sql """select percentile(col_double, 1.1) from d_table;"""
+        exception "percentile quantile must be in [0, 1]"
+    }
+    test {
+        sql """select percentile_state(col_double, 1.1) from d_table;"""
+        exception "percentile quantile must be in [0, 1]"
+        check { result, exception, startTime, endTime ->

Review Comment:
   These `_state` tests set an `exception` string, but adding a custom `check` 
closure means `TestAction.run()` skips the built-in exception substring 
assertion and calls only the closure. As written, any non-`INTERNAL_ERROR` 
exception would pass, including a stale-nested/runtime failure instead of the 
intended percentile legality error. Please either remove these custom `check` 
blocks or also assert that `exception.toString()` contains the expected 
percentile error in each new `_state` case.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/combinator/StateCombinator.java:
##########
@@ -144,4 +144,9 @@ public boolean canRollUp() {
     public void checkLegalityBeforeTypeCoercion() {
         nested.checkLegalityBeforeTypeCoercion();
     }
+
+    @Override
+    public void checkLegalityAfterRewrite() {
+        nested.checkLegalityAfterRewrite();

Review Comment:
   `StateCombinator.withChildren()` rebuilds the wrapper with rewritten 
children but keeps the original `nested` aggregate. `CheckLegalityAfterRewrite` 
rewrites children before calling this method, so for a call like 
`percentile_state(k, 0.5 + 0.6)` the wrapper child can be folded to `1.1` while 
`nested` still holds the old arithmetic expression. This delegation then checks 
that stale nested aggregate; `Percentile.checkLegalityAfterRewrite()` returns 
for a non-`Literal` quantile, so the invalid `_state` call bypasses the FE 
error that direct `percentile(k, 1.1)` now gets. Please rebuild the nested 
aggregate from the current `StateCombinator` children, or otherwise keep 
`nested` synchronized before delegating legality checks.



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