014. Lower homogeneous scalar membership directly

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

Problem and mechanism

Membership over native scalar values can pass through JSON encoding and decoding even when the receiver and every non-null candidate already share one HFF scalar type. Two paths address this shape: a direct filter predicate for literal candidates on eligible native columns, and a native same-type membership expression that avoids JSON conversion when values are dynamic. The literal path can also bypass projections when composed with other eligible scalar predicates.

The candidate lowers eligible homogeneous membership to SQL IN. It preserves the string COLLATE "C" rule and treats null candidates as non-matches. A nullable receiver remains null as a method result; in filter context, the predicate remains false for a null receiver. Mixed numeric membership and other ineligible expressions retain the general path so cross-type exact comparison and presence behavior remain unchanged.

Applicability

Execution profile Applied / Partial / Not applied / Not applicable Reason
Directly bound native Int, String, or Bool field with same-type literal candidates at the filter root Applied Eligible membership composes directly with simple scalar predicates.
Same-type native scalar membership expression Partial Bool, Int, Float, String, and Bytes values can avoid JSON conversion while retaining receiver and candidate null/no-value behavior.
Mixed Int/Float membership Not applied Exact cross-subtype comparison retains the general lowering.
Ineligible root predicate or unsupported scalar shape Not applied The general lowering retains expression, type, and presence semantics.

Reproduction

The root-predicate comparison uses age:in(18,21) over a directly bound native integer column. It distinguishes the prior JSON-based lowering, an intermediate native-IN lowering that retained projection barriers, and the direct root-predicate path. SQL text lengths and projection-barrier counts are structural measurements, not database execution measurements.

The baseline is commit 3116dfa; the implementation is commit 88d1bb8. The code is in backends/sql/scalar_where.go and backends/sql/json_membership.go. Correctness fixtures compare local and PostgreSQL results for nullable Int, String, Bool, Float, and Bytes receivers, including null candidates, computed or guarded needles, and mixed-numeric fallback.

The eligible root filter generates this predicate:

("records"."age" IS NOT NULL AND "records"."age" IN (($1::bigint),($2::bigint)))

With an index on records(age), plain EXPLAIN on the temporary empty fixture selected a Bitmap Index Scan on records_age_idx, represented as age = ANY ('{18,21}'::bigint[]). This is a plan observation for that fixture only.

Results

Lowering of age:in(18,21) WHERE length Projection barriers Parameters
Prior JSON-based expression 1,627 characters 3 2
Native IN with general root lowering 399 characters 3 2
Direct literal-root predicate 80 characters 0 2

No execution timing or allocation comparison is reported. Plain EXPLAIN was inspected only for the direct-predicate candidate; that fixture-specific plan observation is not evidence of general index use or speed.

Correctness and tradeoffs

The optimized paths are restricted to same-type scalar membership. Null candidates never match a non-null receiver. Nullable receiver behavior and argument presence remain governed by the ordinary HFF method contract. String membership continues to use byte-lexical COLLATE "C". Mixed Int/Float equality still needs the exact general comparison path. The generic root path retained three barriers for the measured literal filter; dynamic expressions vary by shape. Only the eligible literal-root path removes those barriers.

Decision and limits

This candidate demonstrates smaller generated membership SQL for one literal-root filter, with projection removal limited to eligible literal-root predicates. It does not establish faster PostgreSQL execution or reduced planning time. Retain the general lowering for ineligible or mixed-type shapes and validate each supported form against local evaluation and PostgreSQL.

Explore HFF
Search documentation

Search the language specification and guides.