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


##########
be/src/format_v2/table_reader.cpp:
##########
@@ -790,6 +790,15 @@ Status 
TableReader::_evaluate_partition_prune_conjuncts(const VExprContextSPtrs&
     for (const auto& conjunct : conjuncts) {
         DORIS_CHECK(conjunct != nullptr);
         DORIS_CHECK(conjunct->root() != nullptr);
+        const auto root = conjunct->root();
+        const auto impl = root->get_impl();
+        const auto predicate = impl != nullptr ? impl : root;
+        // Split pruning evaluates a predicate once before any file rows are 
read. Reordering
+        // non-deterministic or error-preserving expressions can change their 
row-level semantics,
+        // even when every referenced slot is a partition column.
+        if (!predicate->is_safe_to_execute_on_selected_rows()) {
+            continue;

Review Comment:
   The `continue` here still changes evaluation order when there are multiple 
conjuncts. `_build_table_conjuncts()` preserves `_conjuncts` order, and the 
normal `execute_conjuncts()` path evaluates each context in order and only 
stops once a context filters all rows. With this loop, an earlier unsafe 
predicate is dropped but a later safe partition predicate can still be added to 
`partition_conjuncts` and prune the split before the unsafe predicate ever 
reaches the row-level `Scanner::_filter_output_block()` path. For example, on a 
`part=7` split, `[assert_true(part != 7), part = 0]` should raise from the 
first conjunct in the normal path, but this code skips it and lets `part = 0` 
prune the file. Once a conjunct is not safe to move, split pruning should stop 
considering later conjuncts for that split, or disable this pruning pass 
entirely, rather than just skipping that one predicate.



##########
be/src/format_v2/table_reader.cpp:
##########
@@ -790,6 +790,15 @@ Status 
TableReader::_evaluate_partition_prune_conjuncts(const VExprContextSPtrs&
     for (const auto& conjunct : conjuncts) {
         DORIS_CHECK(conjunct != nullptr);
         DORIS_CHECK(conjunct->root() != nullptr);
+        const auto root = conjunct->root();
+        const auto impl = root->get_impl();
+        const auto predicate = impl != nullptr ? impl : root;
+        // Split pruning evaluates a predicate once before any file rows are 
read. Reordering
+        // non-deterministic or error-preserving expressions can change their 
row-level semantics,
+        // even when every referenced slot is a partition column.
+        if (!predicate->is_safe_to_execute_on_selected_rows()) {

Review Comment:
   This guard also needs to cover the other split-level pre-execution path. 
After `open_reader()` builds mappings, `_evaluate_constant_filters()` still 
executes any table filter whose referenced entries are constants, and partition 
columns become constant filter entries. It only skips runtime-filter wrappers; 
it does not check the unwrapped predicate's 
`is_safe_to_execute_on_selected_rows()` contract. A non-runtime conjunct such 
as `part = 7 OR random() < 0.5` is skipped by this new runtime-filter pruning 
guard, but can still be evaluated once in `_evaluate_constant_filters()` and 
close the split based on a single random/error-preserving result. Please apply 
the same safety gate before constant-filter pruning, leaving unsafe 
constant-only predicates for the normal row-level filter path.



##########
be/src/format_v2/table_reader.cpp:
##########
@@ -790,6 +790,15 @@ Status 
TableReader::_evaluate_partition_prune_conjuncts(const VExprContextSPtrs&
     for (const auto& conjunct : conjuncts) {
         DORIS_CHECK(conjunct != nullptr);
         DORIS_CHECK(conjunct->root() != nullptr);
+        const auto root = conjunct->root();
+        const auto impl = root->get_impl();
+        const auto predicate = impl != nullptr ? impl : root;
+        // Split pruning evaluates a predicate once before any file rows are 
read. Reordering

Review Comment:
   This fixes the v2 TableReader pruning path, but the same runtime-filter 
partition-pruning feature is still reachable through the legacy `FileScanner` 
fallback. `FileScanOperator` falls back to `FileScanner` when 
`enable_file_scanner_v2` is false, during loads, or when a range is not 
supported by v2. That path builds `_runtime_filter_partition_prune_ctxs()` by 
checking only whether the unwrapped expression references partition slots, then 
executes those contexts on the synthetic partition block. There is no 
`is_safe_to_execute_on_selected_rows()` check there, so the same 
non-deterministic/error-preserving partition-only runtime filter can still 
prune a whole split once v1 is selected. Please mirror the safety check in the 
legacy partition-prune setup, or otherwise keep the behavior consistent across 
the v1/v2 scanner selection.



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