feat(v3/sem): pin ORE comparators IMMUTABLE + regression test#263
Conversation
The three compare_ore_block_u64_8_256_term(s) overloads (term×term, term[]×term[], composite×composite) are now IMMUTABLE, diverging from the v2 originals which default to VOLATILE. The comparison is deterministic — its only crypto call, pgcrypto encrypt(), is IMMUTABLE — so the planner can fold/cache in ordering and index contexts. NOT STRICT: the NULL-handling branches are load-bearing. T8 (family::sem::ore_comparators_are_immutable) asserts exactly 3 overloads exist and all have provolatile = 'i', so a silent regression to VOLATILE fails CI.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| let rows: Vec<(String, String)> = sqlx::query_as( | ||
| r#" | ||
| SELECT pg_catalog.pg_get_function_arguments(p.oid) AS args, | ||
| p.provolatile::text AS provolatile |
There was a problem hiding this comment.
Lopsided catalog pin: T8 pins provolatile but not proisstrict. The function's own doc note flags two catalog-level invariants as load-bearing — IMMUTABLE and "NOT STRICT: the NULL-handling branches below are load-bearing for the array overload." T8 turns the volatility marker into a CI-enforced pin (good), but the equally-documented non-STRICT property is guarded only behaviourally (T3). T3 would catch a stray STRICT on the term comparator, but the symmetric catalog pin is one extra column and states the intent at the same layer T8 already queries — and it also covers the array/composite overloads, whose non-STRICT-ness T3 doesn't directly assert.
Widen the existing query rather than add a test:
let rows: Vec<(String, String, bool)> = sqlx::query_as(
r#"
SELECT pg_catalog.pg_get_function_arguments(p.oid) AS args,
p.provolatile::text AS provolatile,
p.proisstrict AS isstrict
FROM pg_catalog.pg_proc p
WHERE p.pronamespace = 'eql_v3'::regnamespace
AND p.proname IN (
'compare_ore_block_u64_8_256_term',
'compare_ore_block_u64_8_256_terms'
)
ORDER BY args
"#,
).fetch_all(&pool).await?;
assert_eq!(rows.len(), 3, "expected exactly 3 compare overloads, found: {rows:?}");
for (args, provolatile, isstrict) in &rows {
assert_eq!(provolatile, "i", "{args} must be IMMUTABLE, got {provolatile}");
assert!(!isstrict, "{args} must NOT be STRICT (NULL branches are load-bearing)");
}Expected: passes today (all three are provolatile='i', proisstrict=false); fails the moment a future edit adds STRICT to any of the three — at the same catalog layer T8 already enforces, instead of relying solely on T3's behavioural check.
auxesis
left a comment
There was a problem hiding this comment.
Test coverage needs fixing, will re-review afterwards.
Widen the existing T8 catalog query to also assert all three compare_ore_block_u64_8_256_term(s) overloads are NOT STRICT, closing the lopsided pin where the equally load-bearing non-STRICT property was only guarded behaviourally (T3, term overload only). Now pinned at the same catalog layer T8 already queries, covering the array/composite overloads T3 does not directly assert.
What
Mark the three
eql_v3.compare_ore_block_u64_8_256_term(s)overloadsIMMUTABLE(term×term, term[]×term[], composite×composite). They previously had no volatility marker and defaulted toVOLATILE.Why
The comparison is deterministic — its only crypto call, pgcrypto
encrypt(), is itselfIMMUTABLE STRICT PARALLEL SAFE— so marking the comparatorsIMMUTABLElets the planner fold/cache them in ordering and index contexts.CREATE FUNCTION eql_v3.compare_ore_block_u64_8_256_term(a …, b …) RETURNS integer + IMMUTABLE SET search_path = pg_catalog, extensions, publicNOT
STRICT: the NULL-handling branches in the array overload are load-bearing — aSTRICTmarker would let PostgreSQL skip the body on a NULL argument.Test
family::sem::ore_comparators_are_immutable(T8) asserts exactly 3 overloads exist and all carryprovolatile = 'i', so a silent regression toVOLATILEfails CI.Summary by CodeRabbit
Release Notes
Improvements
Tests