032. Reuse numeric comparison kernels within a scope

  • Status: Applied
  • Date: 2026-10-14

Problem and mechanism

Repeated mixed Int/Float comparisons could rebuild the same Float floor and the same numeric ordering projection. A JSON-backed scalar pair could also repeat decoding the same stored text as the same numeric family. Within a projection scope, the translator now reuses these kernels:

  • Native comparisons share a Float floor projection by Float expression and an ordering projection by the ordered Int/Float expression pair. The raw numeric values are shared; each comparison still applies its own operator, operand direction, and presence handling.
  • A scalar JSON pair shares decoding only for identical text and numeric family within its isolated pair subquery. The cache key retains ambiguity checks and any predecoded Float override, so different representation requirements do not alias.

JSON pairs with multiple numeric-family branches or mixed Int/Float comparisons already project their guarded casts. The decode cache reuses those projections; single-family pairs retain their existing inline casts.

Callback, fold, relation, equality, and filter scope boundaries remain in force. The JSON pair cache is not hoisted out of its subquery. Stored-value representability, schema, and JSONB metadata checks still run before numeric comparison. This changes generated SQL shape, not comparison semantics.

Applicability

Workload Status Reason
Repeated native mixed Int/Float comparisons in one projection Applied Reuse the Float floor and ordered numeric result while retaining per-comparison operators and presence.
Identical Float operand compared with multiple Int operands Applied Share the Float floor; keep separate order projections for distinct typed operand pairs.
Identical text decoded as the same numeric family within one scalar JSON pair Applied Reuse the text/family decode while retaining ambiguity and Float-override identity.
Distinct JSON operands or independently required decode variants Not applied Keep separate projections when text, family, ambiguity, or Float override differs.
Independent callback, fold, relation, JSON-pair, and filter scopes Not applied Preserve existing cache resets and evaluation scope.
Single native comparison, distinct JSON pair, and unconstrained Any pair controls Not applied No repeated eligible kernel exists, or the generic path remains required.

Reproduction

The shape baseline is commit 0a435fd. The candidate implementation accompanies this record. The temporary shape fixture used Go 1.27.1 and PostgreSQL 18.6 on aarch64 with extra_float_digits=1; correctness parity also ran with extra_float_digits set to 3. Native bindings included nullable Int fields i and j, and a nullable Float field f. The SQL-shape fixture bound nullable String|Int|Float|Null fields choice and other, an Any field data, a list of the same union as items, and a nullable-Float list floats to native PostgreSQL json columns. The parity fixture covered both JSON and JSONB, with numeric metadata where its schema could not recover subtype or representation.

Representative filters were:

i<f i!=f f>i
i<f j<f
(i<f | j<f) !(i=f)
choice=choice
items:any(x=>x=x)
floats:any(x=>i<x j<x)
floats:any(f=>i<f j<f)
floats:any(x=>floats:any(x=>i<x j<x))

Durable fixtures are the unit tests, PostgreSQL parity tests, and cache-identity controls. The shape generator and raw SQL/plans were temporary files outside the repository. For the plain-plan fixture, the temporary table had columns i bigint, j bigint, f double precision, and choice, other, data, items, and floats as json; each generated filter was compiled and explained with EXPLAIN (COSTS OFF) against the empty table. The durable tests cover 171 rows across 24 queries, JSON/JSONB formats, and Float settings 1 and 3, including captures, shadowing, nested callbacks, guards, null and empty values, signed zero, subnormals, the int64 limits, and values around 2^53.

The focused checks were:

GOTOOLCHAIN=go1.27.1 go test ./backends/sql -run '^(TestNumericKernelReuse.*|TestMixedNumericOrderKeepsPresenceOutsideCache|TestJSONNumericFamiliesKeepGuardAndOverrideIdentity)$' -count=1
HFF_POSTGRES_CONTAINER=<container> GOTOOLCHAIN=go1.27.1 go test -tags=integration ./backends/sql -run '^(TestPostgreSQLNumericKernelReuseMatchesLocal|TestPostgreSQLJSONNumericFamilyCacheIdentity)$' -count=1

Results

Generated WHERE bytes and OFFSET 0 barriers were counted for the same filters on baseline and candidate. The validation column is the number of pg_input_is_valid() calls in the generated expression.

Filter Baseline bytes / barriers / validations Candidate bytes / barriers / validations
i<f i!=f f>i 2,443 / 12 / 0 1,205 / 8 / 0
i<f j<f 1,763 / 10 / 0 1,534 / 9 / 0
(i<f | j<f) !(i=f) 2,688 / 15 / 0 1,838 / 12 / 0
choice=choice 3,431 / 14 / 2 2,339 / 9 / 1
items:any(x=>x=x) 3,956 / 18 / 2 2,853 / 13 / 1
floats:any(x=>i<x j<x) 2,641 / 15 / 1 2,411 / 14 / 1
floats:any(f=>i<f j<f) 2,641 / 15 / 1 2,411 / 14 / 1
floats:any(x=>floats:any(x=>i<x j<x)) 3,159 / 19 / 1 2,931 / 18 / 1
Single comparison i<f control 867 / 5 / 0 unchanged
Guarded comparisons i!<f i<f! control 1,930 / 11 / 0 unchanged
Distinct JSON pair choice=other control 3,649 / 16 / 2 unchanged
Generic Any pair data=data control 8,270 / 26 / 4 unchanged

Plain EXPLAIN (COSTS OFF) on the empty temporary-table fixture showed Nested Loop and Result node counts changing from 11 to 7 and 12 to 8 for i<f i!=f f>i, from 9 to 8 and 10 to 9 for i<f j<f, from 12 to 7 and 14 to 9 for choice=choice, and from 16 to 11 and 18 to 13 for items:any(x=>x=x). The single, distinct-pair, and Any controls were unchanged. Plain-plan structure is fixture-specific; no EXPLAIN ANALYZE, timing, or benchmark was collected.

Correctness and tradeoffs

The integration fixture passed 16,416 local/PostgreSQL result comparisons on both the pinned baseline and candidate across JSON and JSONB at Float settings 1 and 3. Three additional cache-key cases verified that equal input text does not share across different ambiguity requirements, Float overrides, or predecoded Float values. Existing dynamic pair, schema dispatch, arithmetic, scope, and Float controls passed. Unit tests, go vet, integration-tagged vet, SQL race checks, and independent review passed.

The generated SQL and sampled plan trees shrink for repeated kernels, but this does not establish lower planning or execution time. These caches retain only scope-local projections and must not merge work across callback or filter boundaries.

Decision and limits

Reuse repeated numeric comparison work only when the typed SQL expressions and representation requirements match within the existing projection scope. Further reuse of constructed containers, normalized JSON, or shared dispatch requires its own representation and scope proofs.

Explore HFF
Search documentation

Search the language specification and guides.