Skip to content

feat(v3/sem): pin ORE comparators IMMUTABLE + regression test#263

Merged
tobyhede merged 2 commits into
eql_v3from
v3-sem-ore-immutable
Jun 9, 2026
Merged

feat(v3/sem): pin ORE comparators IMMUTABLE + regression test#263
tobyhede merged 2 commits into
eql_v3from
v3-sem-ore-immutable

Conversation

@tobyhede

@tobyhede tobyhede commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What

Mark the three eql_v3.compare_ore_block_u64_8_256_term(s) overloads IMMUTABLE (term×term, term[]×term[], composite×composite). They previously had no volatility marker and defaulted to VOLATILE.

Why

The comparison is deterministic — its only crypto call, pgcrypto encrypt(), is itself IMMUTABLE STRICT PARALLEL SAFE — so marking the comparators IMMUTABLE lets 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, public

NOT STRICT: the NULL-handling branches in the array overload are load-bearing — a STRICT marker 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 carry provolatile = 'i', so a silent regression to VOLATILE fails CI.

Summary by CodeRabbit

Release Notes

  • Improvements

    • Encrypted data comparison functions now explicitly declared as immutable for enhanced query optimization and performance.
    • Enhanced documentation clarifying deterministic comparison behavior and NULL-handling expectations.
  • Tests

    • Added test coverage to validate immutability declarations and prevent future regressions.

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.
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0bdafad-9577-4660-9162-4caa038d69f9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v3-sem-ore-immutable

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@auxesis auxesis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude caught one gap in test coverage of changed code.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 auxesis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@tobyhede tobyhede requested a review from auxesis June 9, 2026 09:24
@tobyhede tobyhede merged commit a0af113 into eql_v3 Jun 9, 2026
11 checks passed
@tobyhede tobyhede deleted the v3-sem-ore-immutable branch June 9, 2026 23:20
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.

2 participants