indexpredicate

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package indexpredicate classifies stored index predicates the way Java's IndexPredicate.toPredicate constructors would (record.metadata.IndexPredicate).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConstantArmIsTrue

func ConstantArmIsTrue(p *gen.Predicate) bool

ConstantArmIsTrue is the narrow classifier Java's QueryPredicate.isTautology() is: only ConstantPredicate.TRUE overrides the default `false` (ConstantPredicate.java:98 vs QueryPredicate.java:311). It answers about the message AS GIVEN and folds nothing — callers normalize first.

The arm-presence test is not redundant with the value test: ConstantPredicate.value is a proto2 field whose declared DEFAULT is TRUE, so GetValue() on an ABSENT arm returns TRUE. The nil-safe getters fail OPEN here, not closed, which is why the arm is checked explicitly — and why normalization above must only fold children that carry the arm.

func IsTautology

func IsTautology(p *gen.Predicate) bool

IsTautology reports whether a stored index predicate provably rejects no record — i.e. whether the index it guards holds an entry for every record. Normalize the way Java's constructors do, then apply Java's narrow tautology test to the result.

func Normalize

func Normalize(p *gen.Predicate) *gen.Predicate

THE INVARIANT, for this function and every caller of it: normalization may only ERASE a predicate it can PROVE accepts every record. Anything it cannot prove — an arm it does not understand, a malformed message, a child it cannot compile — must stay VISIBLE to the sparseness gates, because those gates read absence as "this index holds everything". Erasing on doubt turns a partial index into a full one and a scan of it into wrong rows; keeping a predicate that was in fact harmless costs at worst a declined candidate.

Normalize applies Java's predicate CONSTRUCTION rules to a stored index predicate, returning the equivalent predicate Java would have built. It is the single authority on that question: the planner (deciding whether a candidate carries a predicate to account for) and the executor (deciding whether an index is complete enough to scan) both classify through it, so they cannot answer differently about the same stored bytes.

Java never classifies a conjunction of tautologies, because it never constructs one. IndexPredicate.AndPredicate.toPredicate delegates to AndPredicate.and (IndexPredicate.java:344-345), and that constructor drops every tautological conjunct, returns ConstantPredicate.TRUE when none remain, and unwraps a lone survivor (AndPredicate.java:188-206). `TRUE AND TRUE` has therefore already become the constant before anything asks whether it filters.

OR IS NOT THE DUAL, and deliberately so. OrPredicate.or delegates to OrPredicate.of (OrPredicate.java:417-445), which only collapses a single-element disjunction — it does no tautology folding — and OrPredicate never overrides QueryPredicate.isTautology (default false, QueryPredicate.java:311). So `TRUE OR x` is NOT a tautology to Java, and folding it here would make Go's completeness proof WIDER than Java's: Go would scan an index Java treats as filtering. The asymmetry is Java's, not an oversight to be tidied up.

A ROW-NUMBER WINDOW arm is likewise never folded, and that is a DIVERGENCE from Java's conversion, taken deliberately. Java's RowNumberWindowPredicate.toPredicate returns ConstantPredicate.TRUE (IndexPredicate.java:770-772) — but that states only that the constraint is not expressible as a QueryPredicate over a record, NOT that it filters nothing. It filters maximally: `QualifyRowNumber(score, DESC) <= 100` "keeps the 100 records with the highest score values in the index" (IndexPredicate.java:608-619). Folding it to the constant here would classify a top-N index as COMPLETE and let a scan serve it as the whole table.

Leaving it unfolded keeps it VISIBLE to the sparseness gates, and that alone turned out not to be enough: the flat expansion converts the predicate and omits a tautological result, so a row-window arm that reached indexPredicateToQueryPredicate was mapped to TRUE and dropped, and the candidate matched as full whether the arm arrived bare or wrapped in an AND. The conversion therefore REFUSES the arm outright, which excludes the candidate.

That refusal is LOAD-BEARING rather than belt-and-braces: a store can carry such an index, because the record layer maintains one — a vector index whose stored predicate declares the window is decorated by slidingWindowIndexMaintainer, which keeps only the qualifying records in the wrapped HNSW graph. The arm's compiled per-record evaluator answers `true` for every record (Java's shouldIndexThisRecord), and it is exactly that answer which must never reach the completeness question here.

The result is always a deep clone; the input is never mutated and the two trees share no nodes.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL