Skip to content

docs: equality on ordering domains splits on term injectivity#418

Merged
coderdan merged 1 commit into
mainfrom
docs/database-indexes-ord-equality
Jul 23, 2026
Merged

docs: equality on ordering domains splits on term injectivity#418
coderdan merged 1 commit into
mainfrom
docs/database-indexes-ord-equality

Conversation

@coderdan

Copy link
Copy Markdown
Contributor

Problem

docs/reference/database-indexes.md claims equality rides eq_term / the hm term on the _ord domains generally:

  • the Creating Indexes recipe comment: "Equality (hash index on the eq_term extractor) — public.<T>_eq / _ord / text_search"
  • requirement 1: "Equality needs an hm (hmac_256) term — public.<T>_eq, public.<T>_ord, …"
  • the Equality Queries pattern: "A column typed public.<T>_eq (or _ord, or text_search)"
  • two troubleshooting entries repeating the same rule.

The shipped 3.0.2 bundle disagrees for the numeric-and-time types. Verified against cipherstash-encrypt.sql at this release:

-- integer_ord / date_ord / timestamp_ord / numeric_ord / double_ord / …:
CREATE FUNCTION eql_v3.eq(a public.eql_v3_integer_ord, b public.eql_v3_integer_ord) …
AS $$ SELECT eql_v3.ord_term(a) = eql_v3.ord_term(b) $$;
-- and NO eql_v3.eq_term overload exists for these domains at all.

-- text_ord / text_ord_ore / text_search / text_search_ore:
CREATE FUNCTION eql_v3.eq(a public.eql_v3_text_ord, b public.eql_v3_text_ord) …
AS $$ SELECT eql_v3.eq_term(a) = eql_v3.eq_term(b) $$;

The underlying design: numeric-and-time ordering terms (OPE and ORE alike) are injective, so equality can ride the ordering term — those domains carry no hm. Text ordering terms are non-injective and cannot be relied on for equality, so the text ordering domains carry hm as well.

As written, the doc recommends an eq_term index for a numeric _ord column — DDL that fails outright (no overload) — and implies _ord typing is an equality-via-hm path, when the index that actually serves = on those columns is the ordering btree.

Change

Docs-only, five spots corrected + one new note stating the injectivity rule once:

  • Creating Indexes recipe comment → the hm-carrying domain list (_eq / text_ord / text_ord_ore / text_search / text_search_ore).
  • New blockquote after the ORE note: the injectivity split, including "do not create an eq_term index on a numeric _ord column; the overload does not exist."
  • Index Usage Requirements §1 → equality needs the domain's equality-serving term, split by domain family.
  • Equality Queries → correct domain list, plus the numeric-_ord engagement example (Index Cond: (eql_v3.ord_term(…) = eql_v3.ord_term($1)) against the range-recipe index).
  • Troubleshooting term-check item and the =-returns-zero-rows entry → same split.

How this was found

Porting this guide into the stash agent skill (cipherstash/stack#753, cipherstash/stack#773): a Drizzle helper that derives index DDL from the per-domain capability records emitted no eq_term index for IntegerOrd/DateOrd columns, which disagreed with this page — the bundle turned out to be the one telling the truth.

https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R

The database-indexes page claimed equality rides eq_term/hm on the _ord
domains generally. The shipped 3.0.2 bundle disagrees for the
numeric-and-time types: their ordering terms (OPE and ORE alike) are
injective, so those _ord/_ord_ore domains carry no hm, define no eq_term
overload, and eql_v3.eq inlines to an ordering-term comparison — one
ordering btree serves = and range. Text ordering terms are non-injective
and cannot be relied on for equality, so text_ord/text_ord_ore (and the
text_search variants) carry hm and answer = via eq_term.

Corrected in five places (the recipe comment, requirement 1, the
equality query pattern — now with the numeric-_ord engagement example —
the term-check troubleshooting item, and the zero-rows note), plus a new
note stating the injectivity rule once.

Found while porting this guide into the stash agent skill
(cipherstash/stack#753 / cipherstash/stack#773): an eq_term index
recommended for a numeric _ord column doesn't compile (no overload), and
the "type the column as _ord for equality" guidance pointed users at an
index that can't exist.

Claude-Session: https://claude.ai/code/session_01BkEpKJC3975NHsKgMrCT8R
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@coderdan, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c9ff8cd2-d169-478d-ba73-f8a24fa13ed3

📥 Commits

Reviewing files that changed from the base of the PR and between 52e8cdb and 73b81da.

📒 Files selected for processing (1)
  • docs/reference/database-indexes.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/database-indexes-ord-equality

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.

Copilot AI 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.

Pull request overview

Updates the database indexing guide to accurately document how equality predicates are served for ordering-capable encrypted domains, reflecting the current shipped eql_v3 SQL surface (numeric/time _ord equality via ordering terms; text ordering domains via hm/eq_term due to non-injective ordering terms).

Changes:

  • Corrects the “Equality” index recipe and all affected references to list only the hm-carrying domains as eligible for eql_v3.eq_term(...) indexes.
  • Adds an explicit note explaining the injectivity split: numeric/time ordering terms are injective (so = uses ord_term / ordering btree), while text ordering terms are not (so = relies on eq_term / hm + equality index).
  • Updates “Index Usage Requirements”, “Equality Queries”, and “Troubleshooting” to match the above behavior and avoid recommending DDL that cannot work (missing overloads).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderdan

Copy link
Copy Markdown
Contributor Author

Docs only change.

@coderdan
coderdan merged commit 031eb47 into main Jul 23, 2026
18 checks passed
@coderdan
coderdan deleted the docs/database-indexes-ord-equality branch July 23, 2026 08:50
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