Skip to content

refactor(r13): WHERE BETWEEN / IN delegate to the value evaluator (R13 slice 4, part 1) - #87

Merged
TimelordUK merged 6 commits into
mainfrom
refactor/r13-slice4-where-arms-delegate
Sep 15, 2026
Merged

TimelordUK merged 6 commits into
mainfrom
refactor/r13-slice4-where-arms-delegate

Conversation

@TimelordUK

Copy link
Copy Markdown
Owner

R13 slice 4, first part: WHERE's BETWEEN, IN and NOT IN arms now delegate to the value evaluator and cross back once, in evaluate_delegated (Trilean::from_value). WHERE's own copies of those rules are deleted.

Commits

  1. Pins. The P15 raw-window-operand error in every BETWEEN / IN / NOT IN position (kept on WHERE's side, since the value evaluator would evaluate a window function quietly). Also five recorded divergences in alias-qualified column resolution.
  2. Fix column resolution. WHERE resolved i.a to the right index, then looked the bare name up again and got the first a. The inner value evaluator was also built without aliases. Latent: join output renames duplicate columns before WHERE runs, so no SQL probe reached it. Flips the five pins.
  3. perf: drop per-node logging from the value evaluator. Non-interactive mode records TRACE to a file, and evaluate formatted the expression at every node of every row. Over trades_100000.csv (~2.4 s load): WHERE price + 0 > quantity 5.5 → 3.0 s, SELECT price * quantity 4.8 → 2.6 s, GROUP BY UPPER(trader) 4.3 → 2.6 s.
  4. BETWEEN delegates (3.1 → 2.5 s).
  5. IN / NOT IN delegate (3.6 → 3.0 s, 3.0 → 2.5 s).
  6. Docs: R13 entry in docs/ENGINE_REFACTORING.md.

Verification

  • Parity report byte-identical to baseline after every commit (204 cases, contract holds).
  • Evaluator matrix green in both runs (default and case-insensitive).
  • ./run_all_tests.sh passes: Rust, Python, all FORMAL examples. One SMOKE failure (expander_rewriters query 7) also fails the same way on main.

Next (slice 4 part 2)

Comparison arms, then LIKE and IS NULL, each pinned first. The operand readers still differ: TODAY local vs UTC, DATETIME date vs string, 5.0 integer vs float, left-side legacy method calls (slice 5), and the LIKE regex cache.

🤖 Generated with Claude Code

TimelordUK and others added 6 commits September 15, 2026 20:45
…/ IN (R13 slice 4)

Before WHERE's BETWEEN and IN arms delegate to the value evaluator:

- the P15 raw-window-operand error in every BETWEEN / IN / NOT IN operand
  position, which the value evaluator would otherwise evaluate quietly;
- alias-qualified operands over two columns sharing a name. Latent (join
  output disambiguates before WHERE, so not reachable from SQL as probed),
  but WHERE's column fast path throws the resolved index away and looks the
  bare name up again, and the inner value evaluator has no aliases. Five
  divergences recorded; the next commit is expected to flip them.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…uator gets aliases (R13 slice 4)

WHERE's column fast path resolved an alias-qualified operand to an index
through the ExecutionContext, turned it back into a bare name, and looked
that up again - finding the first column of the name, not the one the
qualifier picked. The value evaluator WHERE hands expression operands to was
built with no aliases, so `i.a + 0` had the same fault from the other side.

Now the index is used directly, and the inner evaluator is given the
context's aliases, so a column means the same thing whichever of the two
resolves it - the precondition for BETWEEN / IN delegating. Latent (join
output disambiguates duplicate names first); flips the five recorded
divergences. Parity report byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Non-interactive mode installs a TRACE subscriber writing to a ring buffer
and a log file, so every `debug!` in `ArithmeticEvaluator::evaluate` - once
per expression node per row, formatting the whole expression with `{:?}` -
was paid in full. It was most of the evaluator's cost: with the filter lowered
(`RUST_LOG=warn`) `WHERE price + 0 > quantity` over trades_100000.csv ran in
load time.

Removed the entry log, the binary-op log (and its now-unused format_value),
column resolution, method proxy and CASE branch logs. Best of 3, ~2.4 s load:

  WHERE price + 0 > quantity      5.5 s -> 3.0 s
  SELECT price * quantity         4.8 s -> 2.6 s
  GROUP BY UPPER(trader)          4.3 s -> 2.6 s
  GROUP BY trader                 3.7 s -> 2.5 s

Found measuring slice 4: WHERE arms that delegate to this evaluator must not
cost more than the arms they replace. Parity report byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…slice 4)

The BETWEEN arm now evaluates through `ArithmeticEvaluator` and reads the
answer back with `Trilean::from_value`; `evaluate_between` and its own copy of
the AND-over-two-comparisons rule are gone. `evaluate_delegated` is the one
crossing every delegated arm will use.

The P15 raw-window-operand check stays on WHERE's side
(`reject_unlifted_window`, now shared with `evaluate_operand_value`), since
the value evaluator would evaluate one quietly.

Parity report byte-identical, matrix green (both runs), pins from the first
commit hold. `WHERE price BETWEEN 100 AND 500` over trades_100000.csv
3.0-3.2 s -> 2.5-2.7 s.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…13 slice 4)

Both arms now evaluate through `ArithmeticEvaluator` via
`evaluate_delegated`; `evaluate_in_list` - WHERE's copy of the OR-over-
equalities rule, with an unused `_ignore_case` parameter - is gone. The raw
window check covers the probe and every list item, as before.

Parity report byte-identical, matrix green (both runs). Over
trades_100000.csv: IN 3.6 s -> 3.0 s, NOT IN 3.0 s -> 2.5 s.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@TimelordUK
TimelordUK merged commit d9a468b into main Sep 15, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant