015. Emit direct predicates for native String operations

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

Problem and mechanism

String predicates and length comparisons on a directly bound native String column were lowered through several LATERAL projections with OFFSET 0 barriers. The candidate emits contains(), startswith(), and endswith() directly when the receiver is that column and every argument is a literal String or null. It also compares len() directly with an integer literal. String predicates retain PostgreSQL's COLLATE "C" behavior and explicit null handling. These forms avoid materializing intermediate HFF values.

For example, the supported source shapes include:

name:contains("Ali")
name:startswith("Al")
name:endswith("ce")
age>18 name:contains("Ali")
name:len>3
age>18 name:len>3

Computed receivers, dynamic or Any values, JSON fields, and nonliteral arguments retain the general lowering.

Applicability

Execution profile Status Reason
Direct native String column with literal String/null method arguments Applied String method predicates avoid projection barriers.
Direct native String len() compared with an integer literal Applied Length comparison avoids projection barriers.
Eligible operation composed with scalar predicates Applied The measured conjunction lowers directly.
Computed, dynamic/Any, JSON, nonliteral arguments Not applied General lowering preserves presence.

Reproduction

The SQL-shape comparison uses a directly bound records.name text column, literal String/null method arguments, and integer literals for len() comparisons. Combined queries add a directly bound records.age integer column. Baseline revision is 88d1bb8; the implementation is commit a498cde. The code is in backends/sql/scalar_where.go and its focused tests. The reported lengths are the generated WHERE expression lengths; barriers count OFFSET 0 projections in those expressions.

Targeted unit tests and local/PostgreSQL result-parity tests passed for the eligible forms, including nullable values, empty strings, null arguments, negation, and conjunctions. The direct len() comparison was also covered by targeted unit and local/PostgreSQL parity tests. After the len() addition, GOCACHE=/private/tmp/hff-go-cache GOTOOLCHAIN=go1.27.1 go test ./... and GOTOOLCHAIN=go1.27.1 go vet ./... both passed.

Results

HFF filter Prior WHERE length / barriers Direct WHERE length / barriers
name:contains("Ali") 449 characters / 3 101 characters / 0
name:startswith("Al") 394 characters / 3 121 characters / 0
name:endswith("ce") 395 characters / 3 122 characters / 0
age>18 name:contains("Ali") 740 characters / 6 172 characters / 0
name:len>3 338 characters / 3 87 characters / 0
age>18 name:len>3 629 characters / 6 158 characters / 0

These are SQL-shape observations only. No PostgreSQL plan comparison or execution timing was collected, so the smaller predicates do not establish a runtime speedup or index use.

Correctness and tradeoffs

Eligibility is deliberately narrow: method receivers must resolve directly to a native String column, and method arguments must be literal String or null values. The len() comparison must use an integer literal. The general path remains in use for computed receivers, JSON/JSONB, dynamic values, and expressions as arguments. Targeted parity checks cover nullable inputs, null arguments, empty strings, negation, length comparisons, and composition with another eligible scalar predicate. String matching retains the existing UTF-8 and C-collation semantics.

Decision and limits

The candidate shortens generated predicates for the listed native-column shapes while preserving the general lowering elsewhere. This record contains no runtime or query-plan evidence. Any claim about index selection or database execution requires a separate measurement on a representative schema and data set.

Explore HFF
Search documentation

Search the language specification and guides.