Weijun-H opened a new pull request, #27281:
URL: https://github.com/apache/datafusion/pull/27281

   ## Which issue does this PR close?
   
   - Closes #27280.
   
   ## Rationale for this change
   
   In `CASE WHEN f(x) = 'a' THEN 'b' ELSE f(x) END`, `f(x)` runs for all rows 
in the first WHEN and again for the ELSE rows. Logical CSE can remove it (for 
example for an immutable UDF) only for plans that pass through the logical 
optimizer, and does so by moving `f(x)` into a lower projection. This API lets 
a producer that builds physical plans directly reuse the result while still 
evaluating `f(x)` at its original position in the first WHEN.
   
   ## What changes are included in this PR?
   
   - `RequiredOperandReusePolicy`: the caller says which child an expression 
evaluates first (`None` when unknown) and whether a rewritten call is still the 
authorized one.
   - `CaseExpr::with_required_operand_reuse(&operand, policy)`: takes effect 
only for `CASE WHEN … ELSE operand` without a base expression, when the policy 
leads from the first WHEN to a node equal to ELSE. Otherwise the CASE is 
unchanged.
   - The operand is evaluated once at its first-WHEN position and reused for 
ELSE. All existing CASE fast paths still apply. The operand must produce an 
array.
   - `with_new_children` re-checks the permission against the previous ELSE and 
drops it if either use changes to a different call or different arguments.
   - The permission is part of `Eq`/`Hash`; `try_to_proto` returns `Ok(None)` 
for a CASE carrying one.
   
   ## What is the testing strategy for this PR?
   
   The API is only reachable from physical plans, so the tests are Rust unit 
tests rather than `sqllogictest`:
   
   - `expressions::case::required_operand_tests` (5 tests, counting stand-in 
expression): single evaluation and correct values across 
all-true/all-false/null/mixed batches; skipped THEN on uniform predicates; 
permission kept across column rewrites and revoked when the call or its 
arguments change; nested CASE and ineligible operand positions; `Eq`/`Hash`.
   - `projection::case_operand_reuse_tests`: on one batch where an earlier 
column and the operand fail on different rows, the plain and the reusing CASE 
surface the same error, while a lower projection surfaces the other one. This 
documents the producer's requirement, not a general DataFusion error-order 
guarantee.
   
   Local checks: on `c8265b68` (this branch's base), the two test modules 
above, `cargo clippy -p datafusion-physical-expr -p datafusion-physical-plan 
--all-targets --all-features -- -D warnings` and `cargo fmt --all -- --check`. 
On the earlier base `14b3edd9` (same patch): workspace `cargo clippy 
--all-targets --all-features -- -D warnings`, the AGENTS.md extended `cargo 
test --profile ci … --workspace` command, and `./dev/rust_lint.sh`.
   
   Benchmark: the existing `case_when` benchmark does not opt in, so it only 
shows the patch's cost on unchanged CASE paths. For its 9 single-condition 
cases (8192 rows × 3/50/100 columns), 3 alternating rounds of `14b3edd9` versus 
the same base plus this patch gave per-case median changes of −1.05% to +1.64%. 
Cases that moved in the same direction in all three rounds: slower — `8192x3 … 
THEN 1 ELSE 0` (+0.40%, +1.65%, +1.64%) and `8192x3 … THEN c2 ELSE c3` (+0.53%, 
+0.01%, +0.79%); faster — `8192x50 … THEN c2 ELSE c3` (−0.71%, −1.05%, −1.88%) 
and `8192x100 … THEN c2 ELSE c3` (−0.11%, −0.81%, −0.59%). These are observed 
values from one short run, not a significance test. No benchmark of the opt-in 
path is included.
   
   ## Are there any user-facing changes?
   
   New public API: `RequiredOperandReusePolicy` and 
`CaseExpr::with_required_operand_reuse`. No behaviour change unless a caller 
opts in.
   


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