predicates

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ContainsExistentialPredicate

func ContainsExistentialPredicate(p QueryPredicate) bool

ContainsExistentialPredicate reports whether the predicate tree rooted at p contains an existential semi-join predicate ANYWHERE in its subtree — an *ExistentialValuePredicate, or the bare QuantifiedObjectValue-IS-NOT-NULL *ComparisonPredicate it lowers to (the same shape IsExistentialPredicate recognises). A structural (typed-node) walk, not text matching.

This is the RFC-141 R4 convergence backstop primitive. EXISTS can appear at any depth in a WHERE predicate tree, and only a TOP-LEVEL (or single-NOT-wrapped) existential is a directly-handled semi-join shape that the NLJ rule lowers to a FirstOrDefault + residual filter. An existential buried under any OTHER wrapper — `NOT (NOT EXISTS(...))`, `EXISTS(...) OR p`, arbitrary AND/OR/NOT nesting that is not the direct/single-NOT shape — falls into the regular-predicate bucket where the empty FirstOrDefault's NULL default is never removed and every outer row silently passes. The guard uses this to DETECT any such buried existential and REJECT the query cleanly rather than mis-evaluate it.

func CountConjuncts

func CountConjuncts(preds []QueryPredicate) int

CountConjuncts returns the number of independent AND-conjuncts in preds, flattening AndPredicate nodes (recursively, so a nested AND(AND(a,b),c) counts as 3) — the same logical residual predicate SET produces the same count regardless of whether the CONSTRUCTING rule happened to combine conjuncts into one AndPredicate or leave them as separate top-level list entries. Every non-AND predicate (including OR/NOT, treated as one opaque unit — this is a conjunct count, not full CNF expansion) counts as exactly 1. An empty result floors at 1, matching FilterCost's "a zero-predicate filter still pays one selectivity factor" convention.

Exists because NestedLoopJoinCost and PredicatesFilter's own numPreds (both a per-conjunct selectivity-compounding cost, cost_formulas.go) otherwise disagree on a residual that reaches one path as N separate QueryPredicate list entries and the other as one AndPredicate combining the same N conditions — a representation artifact, not a difference in the true selectivity, so the SAME logical join was costed two different ways depending on which physical shape happened to receive which packaging.

func DependsOnStatementClock

func DependsOnStatementClock(p QueryPredicate) bool

DependsOnStatementClock reports whether any Value tree embedded in the predicate contains a CURRENT_TIMESTAMP-family function (see values.DependsOnStatementClock). It probes through the SAME spine the value-rewrite families walk (transformEmbeddedValues), so a predicate shape that carries values cannot be visible to rewrites yet invisible to the statement-clock need check. The probe transform returns every value unchanged, so the pointer-stable spine rebuilds nothing.

func GetCorrelatedToOfPredicate

func GetCorrelatedToOfPredicate(p QueryPredicate) map[CorrelationIdentifier]struct{}

GetCorrelatedToOfPredicate is a nil-safe wrapper around QueryPredicate.GetCorrelatedTo: the transitive set of correlations p and its descendants reference, as a fresh map. Returns nil for nil input, and a non-nil empty map for a tree without correlations.

It asks each predicate rather than inspecting it. This used to be a manual type switch over the predicate shapes that were known when it was written, which silently reported NOTHING for every shape added since — PredicateWithValueAndRanges in particular, whose correlations can live entirely in its range comparands. Callers used the result to decide which quantifiers a compensation still needs, so an unseen correlation became a dangling alias in a rebuilt expression. Delegation is complete, including for shapes not yet invented, as long as each QueryPredicate implementation honors the interface's transitive contract by reporting its own carried Values/comparisons and the union of its children.

func IsContradiction

func IsContradiction(p QueryPredicate) bool

IsContradiction reports whether the predicate always evaluates to FALSE.

func IsExistentialPredicate

func IsExistentialPredicate(p QueryPredicate) (values.CorrelationIdentifier, bool)

IsExistentialPredicate reports whether p is the existential semi-join shape — an ExistentialValuePredicate (a QuantifiedObjectValue operand with a NOT_NULL comparison) — and if so returns the existential alias. This is the single detection point all EXISTS call sites use, instead of type-switching on a dedicated leaf type (RFC-141: one mechanism).

It also recognises a bare ComparisonPredicate with the same shape (QOV operand + ComparisonIsNotNull), which is what ExistentialValuePredicate lowers to as a residual predicate (Java's toResidualPredicate).

func IsLeafQueryPredicate

func IsLeafQueryPredicate(p QueryPredicate) bool

IsLeafQueryPredicate reports whether `p` is a leaf in the predicate tree (no children). Mirrors Java's `com.apple.foundationdb.record.query.plan.cascades.predicates. LeafQueryPredicate` marker interface — Go expresses this via a runtime function on the existing Children() method instead of a per-type marker mixin (Go-idiomatic).

Use case: a rule that matches only leaf predicates checks IsLeafQueryPredicate(p) before recursing into Children(); avoids tight coupling to specific concrete types (ConstantPredicate / ValuePredicate / ComparisonPredicate / ExistentialValuePredicate / etc.).

func IsNotExistentialPredicate

func IsNotExistentialPredicate(p QueryPredicate) (values.CorrelationIdentifier, bool)

IsNotExistentialPredicate reports whether p is NotPredicate wrapping an existential predicate (the NOT EXISTS shape), returning the alias.

func IsTautology

func IsTautology(p QueryPredicate) bool

IsTautology reports whether the predicate always evaluates to TRUE. Only ConstantPredicate(TRUE) is a tautology; all other predicates return false. Mirrors Java's QueryPredicate.isTautology().

func PredicateEquals

func PredicateEquals(a, b QueryPredicate) bool

PredicateEquals reports structural equality between two QueryPredicates. Two predicates are equal when their concrete Go types match AND their children + carried data match recursively. Constants compare by TriBool identity; ComparisonPredicate compares by operand Name + Comparison (Type + Operand literal); ValuePredicate compares by wrapped Value Name.

Used by the dedup / normalization rules (AndDedupRule / OrDedupRule / the absorption rules in rule_simplify.go, NormalizePredicatesRule); the equality helper belongs with the predicate types themselves so rule authors don't roll their own.

func PredicateSize

func PredicateSize(p QueryPredicate) int

PredicateSize returns the total node count in p (p + all descendants). Rule authors use this to gate expensive transformations (e.g. De Morgan expansion that would double the size). Constant-time-per-node; cycle-free by construction.

func SemanticEqualsUnderAliasMap

func SemanticEqualsUnderAliasMap(a, b QueryPredicate, aliases values.AliasMap) bool

SemanticEqualsUnderAliasMap is the ALIAS-AWARE, bool counterpart of PredicateEquals: predicates differing only in the quantifier alias their Values reference are equal when those aliases correspond in `aliases`. Operand/child Values compare via values.SemanticEqualsUnderAliasMap.

Lives in the predicates package (RFC-040 040.1b) so expressions' relational EqualsWithoutChildren (040.2) can call it without an import cycle. Consistent with predicates.SemanticHashCode (equal-under-aliases ⟹ equal hash).

func SemanticHashCode

func SemanticHashCode(p QueryPredicate) uint64

SemanticHashCode returns an ALIAS-INVARIANT structural hash of a QueryPredicate, consistent with alias-aware predicate equality (SemanticEqualsUnderAliasMap). Value-bearing predicates fold their Values via the alias-invariant values.SemanticHashCode; ExistentialValuePredicate's operand alias is EXCLUDED; compound predicates recurse via Children() (NOT alias-bearing Explain() text).

Lives in the predicates package (RFC-040 040.1b relocation) so expressions (relational HashCodeWithoutChildren, 040.2) and cascades (memoEqual) can use it without an import cycle.

func StructuralHash

func StructuralHash(p QueryPredicate) uint64

StructuralHash is the hash analog of StructurallyEqual: two predicates that are StructurallyEqual produce the same hash (the equal⟹same-hash invariant the memo relies on). It mirrors StructurallyEqual's comparison exactly — the same discriminators, values.SemanticHashCode for operand Values (itself the hash analog of values.ValuesStructurallyEqual), recursion for And/Or/Not, and the Explain() fallback StructurallyEqual uses in its own default arm.

KEEP IN SYNC with StructurallyEqual (structural_equal.go): any new case there needs the matching case here, or equal predicates could hash differently.

func StructurallyEqual

func StructurallyEqual(a, b QueryPredicate) bool

StructurallyEqual reports whether two predicates are structurally equal: same concrete type, same non-child attributes, and recursively equal children. Mirrors Java's QueryPredicate.semanticEquals for the same-scope case.

func WalkPredicate

func WalkPredicate(p QueryPredicate, visit func(QueryPredicate) bool)

WalkPredicate applies visit to every node in p's subtree, pre-order. If visit returns false, descent into that node's children is skipped (but siblings + ancestors continue). Rule authors use this for tree-wide searches (e.g. "does any descendant reference the discarded correlation ID?").

Safe on nil: returns immediately. Safe on cyclic trees: predicate construction is non-cyclic by contract, so cycle detection is unnecessary.

Types

type AndPredicate

type AndPredicate struct {
	SubPredicates []QueryPredicate
}

AndPredicate is the Kleene AND of children. Empty children yields TRUE (identity). A single FALSE child short-circuits to FALSE. An UNKNOWN + no-FALSE yields UNKNOWN.

func NewAnd

func NewAnd(preds ...QueryPredicate) *AndPredicate

NewAnd constructs an AndPredicate.

func (*AndPredicate) Children

func (p *AndPredicate) Children() []QueryPredicate

func (*AndPredicate) Eval

func (p *AndPredicate) Eval(evalCtx any) (TriBool, error)

func (*AndPredicate) Explain

func (p *AndPredicate) Explain() string

func (*AndPredicate) GetCorrelatedTo

func (p *AndPredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the union of all children's correlations.

type Comparison

type Comparison struct {
	Type    ComparisonType
	Operand values.Value
	Escape  rune

	// ParameterName is set for parameter-bound comparisons (Java's
	// ParameterComparison). Non-empty means the RHS is resolved at
	// runtime from EvaluationContext.getBinding(ParameterName).
	ParameterName string

	// TextTokenizerName and TextAnalyzerName are set for text-search
	// comparisons (Java's TextComparison). Empty = default tokenizer.
	TextTokenizerName string
	TextAnalyzerName  string

	// TextMaxDistance is set for TEXT_CONTAINS_ALL_WITHIN comparisons
	// (Java's TextWithMaxDistanceComparison).
	TextMaxDistance int

	// TextStrictPrefix is set for TEXT_CONTAINS_ALL_PREFIXES comparisons
	// (Java's TextContainsAllPrefixesComparison).
	TextStrictPrefix bool

	// --- DistanceRank fields (Java's DistanceRankValueComparison) ---
	// Set only for ComparisonDistanceRank* types — the vector K-NN
	// "top-K by distance" comparison produced from
	// ROW_NUMBER() OVER (... ORDER BY <distance>(field, q)) {<,<=,=} K.
	// Operand carries the K (top-K) comparand; QueryVector is the search
	// vector; EfSearch / IsReturningVectors are the HNSW runtime knobs
	// threaded from the ROW_NUMBER() OPTIONS clause (nil = index default).
	QueryVector        values.Value
	EfSearch           *int
	IsReturningVectors *bool
}

Comparison pairs a ComparisonType with a right-hand side `Value`. The LHS lives on the parent ComparisonPredicate; each Comparison carries its own (Type, RHS-Value) pair. Unary comparisons (IS [NOT] NULL) leave Operand nil — Eval ignores it.

The RHS is a Value (not a raw literal) so non-constant RHS shapes — `a = b`, `a < b + 1`, `a = CAST(col AS INT)` — compose uniformly with the LHS. Constant-RHS callers wrap via NewLiteralComparison / LiteralValue. IN-list RHS is carried as a ConstantValue whose Value is a `[]any` of evaluated literals.

Escape is the LIKE-pattern escape rune (`LIKE 'a\%b' ESCAPE '\'`). Zero (the default) means "no escape" — `%` and `_` retain their SQL wildcard meaning everywhere in the pattern. Non-zero values flip the next character after the escape from wildcard to literal. Only Type==ComparisonLike consults Escape; other types ignore it.

func NewDistanceRankComparison

func NewDistanceRankComparison(typ ComparisonType, queryVector, comparand values.Value, efSearch *int, isReturningVectors *bool) (Comparison, bool)

NewDistanceRankComparison builds the vector K-NN distance-rank comparison (Java's Comparisons.DistanceRankValueComparison). comparand is the K (top-K) value and queryVector is the search vector.

Returns ok=false when typ is not a *scannable* distance-rank type. Java's DistanceRankValueComparison constructor asserts `type == DISTANCE_RANK_LESS_THAN || type == DISTANCE_RANK_LESS_THAN_OR_EQUAL` (Comparisons.java) — DISTANCE_RANK_EQUALS is mapped by RowNumberValue.transformComparisonMaybe but then REJECTED at construction, so `ROW_NUMBER() = K` is not expressible as a vector scan. We mirror that here (no panic): the caller treats ok=false as "not lowerable", leaving the row-number comparison unmatched so the query fails to plan, exactly as Java's assertion failure aborts planning.

func NewLiteralComparison

func NewLiteralComparison(typ ComparisonType, lit any) Comparison

NewLiteralComparison is the common-case constructor for a binary Comparison whose RHS is a plan-time literal. Wraps lit in the appropriate Value subtype (NullValue for nil, BooleanValue for bool, ConstantValue otherwise). For unary types callers should set Operand to nil directly: `Comparison{Type: ComparisonIsNull}`.

func (Comparison) Eval

func (c Comparison) Eval(left any) (TriBool, error)

Eval compares left against c's (plan-time-evaluated) RHS per c's ComparisonType. The RHS is produced by c.Operand.Evaluate(nil) — i.e. RHS evaluation without a row context. Constant-RHS callers (the common case, and the only shape that can fold at plan time) get their literal back. Non-constant RHS — a FieldValue or an ArithmeticValue over row columns — evaluates to nil here and degrades to UNKNOWN, which is the right answer when no row is in scope. For row-aware evaluation use ComparisonPredicate.Eval, which evaluates both sides against the given eval context.

NULL (nil) on either side returns UNKNOWN per SQL 3VL for binary comparators; unary (IS [NOT] NULL) and null-safe (IS [NOT] DISTINCT FROM) types resolve even on NULL. Numeric operands promote via cmpAny so mixed-width int/float pairs don't degrade to UNKNOWN.

func (Comparison) EvalAgainst

func (c Comparison) EvalAgainst(left, right any) (TriBool, error)

EvalAgainst is the pure dispatch: given already-evaluated LHS and RHS Go-natives, return the Kleene truth value. ComparisonPredicate evaluates both sides against the row's eval context and calls EvalAgainst — separating eval from dispatch is what lets a non-constant RHS (`a = b + 1`) work row-by-row.

func (Comparison) GetCorrelatedTo

func (c Comparison) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the set of correlation identifiers referenced by every Value this comparison carries: its RHS operand and, for distance-rank comparisons, its query vector. Used by ordering-aware rules to match comparison bindings to explode aliases.

type ComparisonPredicate

type ComparisonPredicate struct {
	Operand    values.Value
	Comparison Comparison
}

ComparisonPredicate applies a Comparison to an operand `Value`. The operand is evaluated against a row (the eval context) via Value.Evaluate to produce the left-hand side; the comparison's literal is the right-hand side. Returns UNKNOWN when either side is NULL (SQL 3VL).

func NewComparisonPredicate

func NewComparisonPredicate(operand values.Value, cmp Comparison) *ComparisonPredicate

NewComparisonPredicate builds a ComparisonPredicate.

func TransformRowNumberDistanceRankMaybe

func TransformRowNumberDistanceRankMaybe(rn *values.RowNumberValue, cmpType ComparisonType, comparand values.Value) (*ComparisonPredicate, bool)

TransformRowNumberDistanceRankMaybe ports Java RowNumberValue.transformComparisonMaybe.

A comparison of the shape

ROW_NUMBER() OVER (PARTITION BY ... ORDER BY <distance>(field, queryVec)) {<,<=,=} K

is rewritten into a ComparisonPredicate (Java's ValuePredicate) whose LHS is the distance-specialized row-number value (Euclidean / EuclideanSquare / Cosine / DotProduct) and whose RHS is a DistanceRank comparison capturing the query vector + K (+ the HNSW ef_search / return-vectors knobs). This is the shape the vector index match candidate recognizes and lowers to an HNSW K-NN scan.

Returns (nil, false) when the pattern doesn't match — the ROW_NUMBER argument is not a single distance function, or the comparison is not one of =, <, <= — in which case the caller keeps the original comparison (Java returns Optional.empty()).

Layering note: Java places this method on RowNumberValue itself; in Go the `values` package cannot import `predicates` (predicates depends on values), so the transform lives here as a function over a *values.RowNumberValue.

func (*ComparisonPredicate) Children

func (*ComparisonPredicate) Children() []QueryPredicate

func (*ComparisonPredicate) Eval

func (p *ComparisonPredicate) Eval(evalCtx any) (TriBool, error)

func (*ComparisonPredicate) Explain

func (p *ComparisonPredicate) Explain() string

func (*ComparisonPredicate) GetCorrelatedTo

func (p *ComparisonPredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the union of correlations from the LHS operand Value and everything the RHS Comparison carries.

The RHS goes through Comparison.GetCorrelatedTo rather than reading its Operand directly: a comparison can carry more than one Value — a DistanceRank comparison also holds a query vector — and reading only Operand silently drops those correlations.

type ComparisonRange

type ComparisonRange struct {
	// contains filtered or unexported fields
}

ComparisonRange represents a contiguous range of values for a single column. Mirrors Java's `com.apple.foundationdb.record.query.plan.cascades.ComparisonRange`.

A range is one of three types:

  • Empty: full universe (any value matches).
  • Equality: a single equals comparison (col = X).
  • Inequality: a set of one or more inequality comparisons (col > X, col < Y, etc.) defining a contiguous range.

Used by index-pushdown rules: when matching predicates against a candidate index, each indexed column gets a ComparisonRange derived from the predicate set. The planner then converts the list of per-column ranges into an index scan key range.

Range type discipline (mirrors Java):

  • Adding any comparison to an Empty range produces a non-empty range of the corresponding type.
  • Adding an equality to an Equality range only succeeds if the two equality values are SAME (otherwise the merge is rejected — the planner knows the predicate set is unsatisfiable).
  • Adding an inequality to an Equality range is rejected (the planner can't combine equality + inequality on the same col).
  • Adding any comparison to an Inequality range merges into the existing list.

Returned MergeResult carries either the merged range or a "merge failed" indicator with the rejected comparison.

func EmptyComparisonRange

func EmptyComparisonRange() *ComparisonRange

EmptyComparisonRange returns the universe-range singleton. Each call returns a fresh struct so callers can safely mutate via Merge without aliasing.

func (*ComparisonRange) GetComparisons

func (r *ComparisonRange) GetComparisons() []*Comparison

GetComparisons returns every Comparison this range carries, whichever shape it has: the single equality, or all the inequalities. It returns an empty slice for an empty or nil range. The returned slice is read-only. Callers that need to inspect the range as a whole should use this rather than branching on the range type and risking one of the shapes going unhandled.

func (*ComparisonRange) GetEqualityComparison

func (r *ComparisonRange) GetEqualityComparison() *Comparison

GetEqualityComparison returns the single equality comparison. Panics if the range isn't an equality range — callers should guard with IsEquality first.

func (*ComparisonRange) GetInequalityComparisons

func (r *ComparisonRange) GetInequalityComparisons() []*Comparison

GetInequalityComparisons returns the inequality comparison list. Panics if the range isn't an inequality range — callers should guard with IsInequality first. Returns a read-only slice.

func (*ComparisonRange) GetRangeType

func (r *ComparisonRange) GetRangeType() ComparisonRangeType

GetRangeType returns the discriminator.

func (*ComparisonRange) IsEmpty

func (r *ComparisonRange) IsEmpty() bool

IsEmpty reports whether the range is the universe.

func (*ComparisonRange) IsEquality

func (r *ComparisonRange) IsEquality() bool

IsEquality reports whether the range is a single = comparison.

func (*ComparisonRange) IsInequality

func (r *ComparisonRange) IsInequality() bool

IsInequality reports whether the range is a set of inequalities.

func (*ComparisonRange) Merge

func (r *ComparisonRange) Merge(c *Comparison) MergeResult

Merge attempts to add a comparison to the range. Returns a MergeResult capturing success / failure.

Rules (per Java):

  • Empty + EQUALS → Equality
  • Empty + INEQ → Inequality
  • Equality + EQUALS (same value) → Equality (idempotent)
  • Equality + EQUALS (different value) → Failed (unsatisfiable)
  • Equality + INEQ → Failed (planner doesn't combine = + range on the same column)
  • Inequality + INEQ → Inequality (extended)
  • Inequality + EQUALS → Failed (similar reasoning)

type ComparisonRangeType

type ComparisonRangeType int

ComparisonRangeType discriminates the three range shapes.

const (
	// ComparisonRangeEmpty is the universe range — any value matches.
	ComparisonRangeEmpty ComparisonRangeType = iota
	// ComparisonRangeEquality is a single = comparison.
	ComparisonRangeEquality
	// ComparisonRangeInequality is a set of inequalities.
	ComparisonRangeInequality
)

type ComparisonType

type ComparisonType int

ComparisonType is the operator carried by a Comparison. Enum values match Java's `com.apple.foundationdb.record.query.expressions.Comparisons.Type` ordering so serialised plans round-trip (once we have plan serialisation).

const (
	ComparisonEquals                   ComparisonType = iota // =
	ComparisonNotEquals                                      // !=, <>
	ComparisonLessThan                                       // <
	ComparisonLessThanOrEq                                   // <=
	ComparisonGreaterThan                                    // >
	ComparisonGreaterThanEq                                  // >=
	ComparisonIsNull                                         // IS NULL (unary, LHS-only)
	ComparisonIsNotNull                                      // IS NOT NULL (unary, LHS-only)
	ComparisonStartsWith                                     // STARTS_WITH (string LHS, string RHS prefix)
	ComparisonIn                                             // IN (LHS any, RHS is a []any membership list)
	ComparisonIsDistinctFrom                                 // IS DISTINCT FROM (null-safe !=)
	ComparisonNotDistinctFrom                                // IS NOT DISTINCT FROM (null-safe =)
	ComparisonLike                                           // LIKE (string LHS, SQL pattern RHS: % / _)
	ComparisonTextContainsAll                                // TEXT_CONTAINS_ALL (full-text: all terms must match)
	ComparisonTextContainsAllWithin                          // TEXT_CONTAINS_ALL_WITHIN (full-text: all terms within distance)
	ComparisonTextContainsAny                                // TEXT_CONTAINS_ANY (full-text: any term matches)
	ComparisonTextContainsPhrase                             // TEXT_CONTAINS_PHRASE (full-text: exact phrase match)
	ComparisonTextContainsPrefix                             // TEXT_CONTAINS_PREFIX (full-text: prefix of any term)
	ComparisonTextContainsAllPrefixes                        // TEXT_CONTAINS_ALL_PREFIXES (full-text: all prefixes match)
	ComparisonTextContainsAnyPrefix                          // TEXT_CONTAINS_ANY_PREFIX (full-text: any prefix matches)
	ComparisonSort                                           // SORT (ordering comparison, not a filter)
	ComparisonDistanceRankEquals                             // DISTANCE_RANK_EQUALS (vector distance rank equality)
	ComparisonDistanceRankLessThan                           // DISTANCE_RANK_LESS_THAN (vector distance rank bound)
	ComparisonDistanceRankLessThanOrEq                       // DISTANCE_RANK_LESS_THAN_OR_EQUAL (vector distance rank bound)
)

func (ComparisonType) Commute

func (c ComparisonType) Commute() (ComparisonType, bool)

Commute returns the operator that holds when the two operands are swapped: `a OP b` is equivalent to `b Commute(OP) a`. Equality and not-equals are symmetric (unchanged); the binary inequalities flip direction. Unary operators (IS NULL / IS NOT NULL) and non-commutable operators (IN, STARTS_WITH, LIKE, the DISTINCT variants) return (c, false). Used by index/PK matching, which is commutative: a join predicate `outer.fk = inner.pk` constrains inner.pk exactly as `inner.pk = outer.fk` does.

func (ComparisonType) IsEquality

func (c ComparisonType) IsEquality() bool

IsEquality reports whether the comparison semantically tests for (null-safe or null-aware) equality. Mirrors Java's `Comparisons.Type.isEquality()` — useful for index-pushdown decisions (equality predicates can use point-lookups; inequality needs ranges).

func (ComparisonType) IsUnary

func (c ComparisonType) IsUnary() bool

IsUnary reports whether the comparison takes no RHS operand (IS NULL / IS NOT NULL). Callers use this to skip Operand-based folding / plumbing for unary predicates.

func (ComparisonType) Negate

func (c ComparisonType) Negate() (ComparisonType, bool)

Negate returns the comparison type whose truth table is the logical negation of this one, plus a flag indicating whether a negation is known. `!(a = b)` → `a <> b`, `!(a IS NULL)` → `a IS NOT NULL`, etc. Used by the NOT-over-Comparison rewrite rules when pushing NOTs down past a leaf comparison.

IN / STARTS_WITH have no direct negation operator — the caller should wrap in NotPredicate. Negate returns the logical negation of the comparison operator, matching Java's Comparisons.invertComparisonType(). Only binary inequality/equality operators are invertible. Unary operators (IS_NULL, IS_NOT_NULL), NOT_EQUALS, and DISTINCT variants return (c, false) — Java explicitly rejects these.

func (ComparisonType) Symbol

func (c ComparisonType) Symbol() string

Symbol returns the SQL-text form of the operator.

type CompatibleTypeEvolutionPredicate

type CompatibleTypeEvolutionPredicate struct {
	// RecordTypeNameFieldAccessMap maps record type names to their
	// field access trie roots. Each trie encodes which fields of
	// that record type are accessed by the plan.
	RecordTypeNameFieldAccessMap map[string]*FieldAccessTrieNode
}

CompatibleTypeEvolutionPredicate is a leaf predicate used by the plan cache to verify that a cached plan is still valid under the current schema. It carries a list of (recordTypeName, fieldAccessTrieNode) pairs describing which record type fields the plan accesses.

Ports Java's com.apple.foundationdb.record.query.plan.cascades.predicates.CompatibleTypeEvolutionPredicate

At eval time in Java, this checks that the current schema's record types are compatible with the cached plan's field access patterns. In Go, the plan cache is not yet ported, so Eval returns TriTrue unconditionally. The type exists for structural conformance: it can be round-tripped through serialization and participates in predicate equality.

func NewCompatibleTypeEvolutionPredicate

func NewCompatibleTypeEvolutionPredicate(m map[string]*FieldAccessTrieNode) *CompatibleTypeEvolutionPredicate

NewCompatibleTypeEvolutionPredicate constructs the predicate from the given record type -> field access trie mapping.

func (*CompatibleTypeEvolutionPredicate) Children

Children returns nil -- this is a leaf predicate.

func (*CompatibleTypeEvolutionPredicate) Eval

Eval returns TriTrue. Plan-cache schema validation is not yet ported; this predicate exists for structural conformance.

func (*CompatibleTypeEvolutionPredicate) Explain

Explain renders the predicate in a human-readable form matching Java's explain output: compatibleTypeEvolution(<record types>).

func (*CompatibleTypeEvolutionPredicate) GetCorrelatedTo

func (*CompatibleTypeEvolutionPredicate) GetCorrelatedTo() map[CorrelationIdentifier]struct{}

GetCorrelatedTo returns the empty set — type evolution predicates reference no quantifier aliases.

type ConstantPredicate

type ConstantPredicate struct {
	Value TriBool
}

ConstantPredicate is a literal truth value (true / false / UNKNOWN). Useful for simplification rules that reduce a subtree to a constant.

func NewConstantPredicate

func NewConstantPredicate(v TriBool) *ConstantPredicate

NewConstantPredicate wraps a TriBool as a ConstantPredicate.

func (*ConstantPredicate) Children

func (*ConstantPredicate) Children() []QueryPredicate

func (*ConstantPredicate) Eval

func (p *ConstantPredicate) Eval(any) (TriBool, error)

func (*ConstantPredicate) Explain

func (p *ConstantPredicate) Explain() string

func (*ConstantPredicate) GetCorrelatedTo

func (*ConstantPredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the empty set — constants reference no quantifier aliases.

type CorrelationIdentifier

type CorrelationIdentifier = values.CorrelationIdentifier

CorrelationIdentifier is re-exported as a type alias so package consumers don't need to import values just for the map key type.

type DatabaseObjectDependenciesPredicate

type DatabaseObjectDependenciesPredicate struct {
	// UsedIndexes is the set of indexes this plan depends on,
	// each carrying its name and the lastModifiedVersion at plan
	// creation time.
	UsedIndexes []UsedIndex
}

DatabaseObjectDependenciesPredicate is a leaf predicate carrying the indexes a plan depends on. It answers one question: may this plan still be executed against the store in front of it?

Ports Java's com.apple.foundationdb.record.query.plan.cascades.predicates.DatabaseObjectDependenciesPredicate. Java attaches it to every planned query as the CONTINUATION plan constraint (QueryPlan.java:667,726-735) and re-evaluates it on every execution, so a resumed page is gated too, not only a first execution.

A dependency is any index whose availability the plan's CORRECTNESS rests on: the indexes it scans, and any index whose metadata property licensed a transformation without being scanned. The second kind is why this cannot be derived from the plan tree alone at evaluation time.

func NewDatabaseObjectDependenciesPredicate

func NewDatabaseObjectDependenciesPredicate(indexes []UsedIndex) *DatabaseObjectDependenciesPredicate

NewDatabaseObjectDependenciesPredicate constructs the predicate from the given set of used indexes.

func (*DatabaseObjectDependenciesPredicate) Children

Children returns nil -- this is a leaf predicate.

func (*DatabaseObjectDependenciesPredicate) Eval

Eval reports whether this plan can still be executed against the store described by evalCtx. Port of Java's eval (DatabaseObjectDependenciesPredicate.java:87-105): every used index must still exist, carry the same lastModifiedVersion, and be readable.

evalCtx MUST implement IndexAvailability. Java takes a non-null store and dereferences it (`Objects.requireNonNull(store)`), so a context that cannot answer is a programming error, not a case to be lenient about: returning TriTrue there would silently pass every dependency check ever made through the wrong call site. An asserted bridge, never a quiet fallback.

A predicate with no dependencies is vacuously TriTrue and needs no context — that is a real absence of dependencies, not an inability to check them.

func (*DatabaseObjectDependenciesPredicate) Explain

Explain renders the predicate in a human-readable form matching Java's explain output: databaseObjectDependencies(<index names>).

func (*DatabaseObjectDependenciesPredicate) GetCorrelatedTo

func (*DatabaseObjectDependenciesPredicate) GetCorrelatedTo() map[CorrelationIdentifier]struct{}

GetCorrelatedTo returns the empty set — database object dependency predicates reference no quantifier aliases.

func (*DatabaseObjectDependenciesPredicate) UnavailableDependency

func (p *DatabaseObjectDependenciesPredicate) UnavailableDependency(
	avail IndexAvailability,
) (name string, reason string, ok bool)

UnavailableDependency returns the first used index that fails against avail, and why — the diagnostic Eval's TriFalse deliberately does not carry, since a predicate's job is a truth value. ok=false when every dependency holds.

type ExistentialValuePredicate

type ExistentialValuePredicate struct {
	// Value is the operand — always a QuantifiedObjectValue over the
	// existential quantifier. Kept as values.Value to mirror Java's
	// ValuePredicate.getValue() and because helpers expect the interface.
	Value values.Value
	// Comparison is always ComparisonIsNotNull (the NullComparison(NOT_NULL)).
	Comparison Comparison
}

ExistentialValuePredicate is the QueryPredicate-layer SQL EXISTS, ported from Java 4.12's `com.apple.foundationdb.record.query.plan.cascades.predicates. ExistentialValuePredicate`. It is "the existential quantifier's object is non-null ⇒ the subplan yielded ≥1 row".

In Java it `extends ValuePredicate(value, comparison)` where value is a QuantifiedObjectValue and comparison is NullComparison(NOT_NULL). Go's ValuePredicate is a bare boolean-Value wrapper (no comparison), so the Java (value, comparison) pair maps to the same shape Go's ComparisonPredicate uses: an operand Value + a Comparison. This type carries exactly that, constrained to a QuantifiedObjectValue operand and a ComparisonIsNotNull comparison.

EXISTS (SELECT ... FROM t WHERE ...)
  ↔  ExistentialValuePredicate{Value: QOV{αsubq}, NOT_NULL}

This is the SINGLE EXISTS predicate representation (RFC-141): it replaces the deleted leaf-alias ExistsPredicate. A NOT-EXISTS is NotPredicate(ExistentialValuePredicate).

Eval is a per-row UNKNOWN at this layer — actual EXISTS evaluation requires running the subplan, which the planner's semi-join rules (ImplementNestedLoopJoinRule) handle structurally. The QOV operand would eval to the bound existential row only inside the FlatMap/ semi-join cursor, not in the generic per-row predicate eval.

func MustNewExistentialValuePredicate

func MustNewExistentialValuePredicate(value values.Value, comparison Comparison) *ExistentialValuePredicate

MustNewExistentialValuePredicate constructs the predicate. The value MUST be a QuantifiedObjectValue; the `Must` prefix is the documented panic contract (Go's regexp.MustCompile convention, mapping to Java's Verify.verify(value instanceof QuantifiedObjectValue)) — a non-QOV operand is a programming error, not a runtime condition. Every call site holds a QOV by construction (a rebased / mapped / decorrelated QOV stays a QOV, and ExistsValueToQueryPredicate passes the ExistsValue's QOV child), so the precondition is a caller-guaranteed structural invariant, not input validation — which is why this asserts rather than returns an error.

func NewExistentialAlias

func NewExistentialAlias(
	alias values.CorrelationIdentifier,
	flowed values.Type,
) (*ExistentialValuePredicate, error)

NewExistentialAlias is the convenience constructor over an existential alias and its exact flowed type: it wraps them in a QuantifiedObjectValue with a NOT_NULL comparison. Invalid aliases or unresolved/malformed types are returned to the caller; this boundary never fabricates an untyped QOV.

func (*ExistentialValuePredicate) Children

Children returns the empty slice — leaf in the predicate tree (the QuantifiedObjectValue operand is a carried Value, not a child predicate).

func (*ExistentialValuePredicate) Eval

Eval returns TriUnknown — EXISTS isn't evaluated at the per-row predicate level; the planner's semi-join rules do the row-level test.

func (*ExistentialValuePredicate) Explain

func (p *ExistentialValuePredicate) Explain() string

Explain renders the SQL-ish form.

func (*ExistentialValuePredicate) GetCorrelatedTo

func (p *ExistentialValuePredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the correlations of the operand Value — the existential alias — together with those its Comparison carries.

The comparison is IS NOT NULL in every construction the planner performs, which correlates to nothing, but the struct permits any comparison. Reading only the operand would silently under-report the moment one appears, and an under-reported correlation is invisible: it does not fail, it produces an expression referencing an alias nothing supplies.

func (*ExistentialValuePredicate) GetExistentialAlias

func (p *ExistentialValuePredicate) GetExistentialAlias() values.CorrelationIdentifier

GetExistentialAlias returns the QuantifiedObjectValue operand's correlation — the alias bound to the subquery. Mirrors Java's getQuantifierAlias().

func (*ExistentialValuePredicate) HashCodeWithoutChildren

func (p *ExistentialValuePredicate) HashCodeWithoutChildren() uint64

HashCodeWithoutChildren hashes the predicate kind. The operand alias is EXCLUDED (alias-invariant), consistent with the alias-invariant SemanticHashCode for the carried QuantifiedObjectValue.

type FieldAccessTrieNode

type FieldAccessTrieNode struct {
	// FieldName is the name of the field this node represents.
	FieldName string
	// Ordinal is the protobuf field ordinal.
	Ordinal int
	// Children, if non-nil, are the child trie nodes keyed by
	// field name. A nil map means this is a terminal node.
	Children map[string]*FieldAccessTrieNode
	// TypeName is the terminal type string. Set only when
	// Children is nil (leaf of the trie).
	TypeName string
}

FieldAccessTrieNode is one node in the field-access trie that CompatibleTypeEvolutionPredicate carries. Each node either has children (keyed by field accessor) or a terminal type value.

Ports Java's CompatibleTypeEvolutionPredicate.FieldAccessTrieNode.

type IndexAvailability

type IndexAvailability interface {
	// IndexLastModifiedVersion reports the index's current
	// lastModifiedVersion, and whether the store's metadata names it.
	IndexLastModifiedVersion(name string) (version int, present bool)
	// IsIndexReadable reports whether the index is strictly READABLE —
	// Java's isReadable, which excludes READABLE_UNIQUE_PENDING even though
	// it is scannable.
	IsIndexReadable(name string) bool
}

IndexAvailability answers, for one live record store, the two questions a plan's index dependency turns on. Eval's context is opaque by interface (predicates.go:229-237), so this is how a caller that HAS a store supplies one — the record-store types live in a package this one cannot import.

present=false means the store's metadata does not name the index at all, which is Java's `!recordMetaData.hasIndex` leg (DatabaseObjectDependenciesPredicate.java:91-93).

type MergeResult

type MergeResult struct {
	// Range is the merged range when Ok is true.
	Range *ComparisonRange
	// Ok reports merge success.
	Ok bool
	// Residual is the comparison that couldn't be merged when Ok is
	// false. Nil otherwise.
	Residual *Comparison
}

MergeResult carries the outcome of a Merge call.

type NonResidualPredicateError

type NonResidualPredicateError struct {
	Detail string
}

NonResidualPredicateError reports a predicate that cannot be converted into an executable filter. Java expresses the same condition as a `Verify.verify(!disjuncts.isEmpty())` inside `OrPredicate.of` (OrPredicate.java:439) — a thrown assertion, not a value — so the Go mapping is an error rather than a degenerate predicate. It matters that this is loud: the whole point of the conversion is that a predicate which cannot answer for a row must never reach a filter, and returning `OR()` here would hand the caller a predicate whose Eval is an unconditional FALSE.

func (*NonResidualPredicateError) Error

func (e *NonResidualPredicateError) Error() string

type NotPredicate

type NotPredicate struct {
	Child QueryPredicate
}

NotPredicate is the Kleene NOT of a single child. NOT UNKNOWN = UNKNOWN.

func NewNot

func NewNot(child QueryPredicate) *NotPredicate

NewNot constructs a NotPredicate.

func (*NotPredicate) Children

func (p *NotPredicate) Children() []QueryPredicate

func (*NotPredicate) Eval

func (p *NotPredicate) Eval(evalCtx any) (TriBool, error)

func (*NotPredicate) Explain

func (p *NotPredicate) Explain() string

func (*NotPredicate) GetCorrelatedTo

func (p *NotPredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the child's correlations.

type OrPredicate

type OrPredicate struct {
	SubPredicates []QueryPredicate
}

OrPredicate is the Kleene OR of children. Empty children yields FALSE (identity). A single TRUE child short-circuits to TRUE.

func NewOr

func NewOr(preds ...QueryPredicate) *OrPredicate

NewOr constructs an OrPredicate.

func (*OrPredicate) Children

func (p *OrPredicate) Children() []QueryPredicate

func (*OrPredicate) Eval

func (p *OrPredicate) Eval(evalCtx any) (TriBool, error)

func (*OrPredicate) Explain

func (p *OrPredicate) Explain() string

func (*OrPredicate) GetCorrelatedTo

func (p *OrPredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the union of all children's correlations.

type Placeholder

type Placeholder struct {
	// ParameterAlias uniquely identifies this placeholder in the
	// candidate's parameter list.
	ParameterAlias values.CorrelationIdentifier

	// Value is the value expression being constrained (e.g. a
	// FieldValue representing a column).
	Value values.Value

	// CompRange is the comparison range constraint on this
	// placeholder. Empty range = unconstrained.
	CompRange *ComparisonRange
}

Placeholder is a QueryPredicate representing a sargable parameter slot in a candidate expression tree. During index matching, the matching rules check whether query predicates can "fill" a placeholder. Mirrors Java's `com.apple.foundationdb.record.query.plan.cascades.predicates.Placeholder`.

A Placeholder carries:

  • ParameterAlias: uniquely identifies this slot in the candidate's parameter list (maps to MatchCandidate.GetSargableAliases()).
  • Value: the value expression being constrained (e.g. a FieldValue representing a column).
  • CompRange: the comparison range constraint on this placeholder. An empty range means unconstrained.

Placeholder is a leaf predicate — it has no children.

func NewPlaceholder

func NewPlaceholder(parameterAlias values.CorrelationIdentifier, value values.Value) *Placeholder

NewPlaceholder constructs a Placeholder with the given alias and value, and an initially empty ComparisonRange.

func (*Placeholder) Children

func (*Placeholder) Children() []QueryPredicate

Children returns an empty slice — Placeholder is a leaf predicate.

func (*Placeholder) Eval

func (*Placeholder) Eval(_ any) (TriBool, error)

Eval returns TriUnknown — placeholders are planning-time constructs and are never evaluated at runtime.

func (*Placeholder) Explain

func (p *Placeholder) Explain() string

Explain renders a textual form: "Placeholder(alias, value)".

func (*Placeholder) GetComparisonRange

func (p *Placeholder) GetComparisonRange() *ComparisonRange

GetComparisonRange returns the comparison range constraint.

func (*Placeholder) GetCorrelatedTo

func (p *Placeholder) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the set of correlation identifiers this placeholder references: its parameter alias, the correlations of the constrained Value, and those of every comparison in its range.

The range comparisons count. A placeholder bound to a range whose comparand is itself correlated (a parameter compared against another quantifier's column) references that quantifier, and a caller that cannot see it will treat the placeholder as independent of a quantifier it actually needs.

func (*Placeholder) GetParameterAlias

func (p *Placeholder) GetParameterAlias() values.CorrelationIdentifier

GetParameterAlias returns the alias that identifies this placeholder in the candidate's parameter list.

func (*Placeholder) GetValue

func (p *Placeholder) GetValue() values.Value

GetValue returns the value expression being constrained.

func (*Placeholder) IsConstraining

func (p *Placeholder) IsConstraining() bool

IsConstraining reports whether this placeholder has a non-empty range — i.e. whether it actually constrains the value.

func (*Placeholder) Negate

func (p *Placeholder) Negate() QueryPredicate

Negate returns the placeholder itself — placeholders don't negate. They are structural slots, not boolean expressions.

func (*Placeholder) WithRange

func (p *Placeholder) WithRange(cr *ComparisonRange) *Placeholder

WithRange returns a new Placeholder with the given comparison range. The original is not modified.

type PredicateWithValueAndRanges

type PredicateWithValueAndRanges struct {
	// contains filtered or unexported fields
}

PredicateWithValueAndRanges associates a Value with a set of RangeConstraints. The set represents a disjunction of range conjunctions — effectively a boolean predicate in DNF form on the associated Value.

Used primarily for index matching: on the query side to represent a sargable (search-argument-able) predicate, on the candidate side to represent column constraints.

Ports Java's `com.apple.foundationdb.record.query.plan.cascades.predicates.PredicateWithValueAndRanges`.

func NewPredicateWithValueAndRanges

func NewPredicateWithValueAndRanges(value values.Value, ranges []*RangeConstraints) *PredicateWithValueAndRanges

NewPredicateWithValueAndRanges constructs a PredicateWithValueAndRanges.

func (*PredicateWithValueAndRanges) Children

func (*PredicateWithValueAndRanges) Eval

func (*PredicateWithValueAndRanges) Explain

func (p *PredicateWithValueAndRanges) Explain() string

Explain returns a human-readable representation.

func (*PredicateWithValueAndRanges) GetComparisons

func (p *PredicateWithValueAndRanges) GetComparisons() []Comparison

GetComparisons returns all comparisons from all ranges, flattened.

func (*PredicateWithValueAndRanges) GetCorrelatedTo

func (p *PredicateWithValueAndRanges) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the union of correlation identifiers from the value and all range constraints.

func (*PredicateWithValueAndRanges) GetRanges

GetRanges returns the set of RangeConstraints (disjunction of range conjunctions).

func (*PredicateWithValueAndRanges) GetValue

GetValue returns the Value associated with the range constraints.

func (*PredicateWithValueAndRanges) HashCodeWithoutChildren

func (p *PredicateWithValueAndRanges) HashCodeWithoutChildren() uint64

func (*PredicateWithValueAndRanges) IsCompileTime

func (p *PredicateWithValueAndRanges) IsCompileTime() bool

IsCompileTime reports whether all range constraints are compile-time evaluable.

func (*PredicateWithValueAndRanges) WithRanges

WithRanges returns a new PredicateWithValueAndRanges with the given ranges, keeping the same Value.

func (*PredicateWithValueAndRanges) WithValue

WithValue returns a new PredicateWithValueAndRanges with the given Value, keeping the same ranges.

type QueryPredicate

type QueryPredicate interface {
	// Children returns the immediate sub-predicates. Leaf
	// predicates (ConstantPredicate, ComparisonPredicate, …)
	// return an empty slice.
	Children() []QueryPredicate

	// Eval returns the predicate's truth value given an
	// opaque evaluation context. Concrete eval context is
	// impl-defined: ValuePredicate / ComparisonPredicate thread it
	// into their operand Values' Evaluate; the boolean connectives
	// thread it to their children; ConstantPredicate ignores it. A
	// non-nil error signals a runtime evaluation failure (e.g. a
	// type-mismatch comparison or an erroring child Value); the
	// returned TriBool is TriUnknown in that case.
	Eval(evalCtx any) (TriBool, error)

	// Explain renders a parenthesised textual form suitable for
	// debug + plan-diff output.
	Explain() string

	// GetCorrelatedTo returns the transitive set of CorrelationIdentifiers
	// this predicate and all its descendants reference. Each concrete
	// type contributes its own correlations (Values, existential aliases,
	// parameter aliases) plus the union of all children's correlations.
	// Mirrors Java's QueryPredicate.getCorrelatedTo() which is transitive.
	GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}
}

QueryPredicate is the root of the predicate hierarchy. A QueryPredicate is a tree of boolean expressions with 3-valued logic semantics.

func ExistsValueToQueryPredicate

func ExistsValueToQueryPredicate(ev *values.ExistsValue) QueryPredicate

ExistsValueToQueryPredicate is the bridge from the value-layer EXISTS (values.ExistsValue) to the predicate-layer EXISTS, mirroring Java's ExistsValue.toQueryPredicate() → ExistentialValuePredicate(child, NullComparison(NOT_NULL)). It lives in the predicates package because the values package cannot import predicates (import cycle: predicates imports values). The child must be a QuantifiedObjectValue.

func FindStructuralPredicate

func FindStructuralPredicate(p QueryPredicate) (QueryPredicate, bool)

FindStructuralPredicate returns the first predicate in p's tree that is STRUCTURAL — an instruction to the planner's matching machinery rather than a test a row can answer — and reports whether one was found.

The three types are exactly the ones ToResidualPredicate converts, and they share a tell: each has an unconditional non-answer as its Eval, so none of them can ever contribute a TRUE.

  • *ExistentialValuePredicate names the existential quantifier's alias. Once its subplan has been lowered to a FirstOrDefault, no physical row carries that alias.
  • *PredicateWithValueAndRanges is an index search argument; its Eval is an unconditional TriUnknown.
  • *Placeholder is a matching-time marker; its Eval is an unconditional TriUnknown. Java makes this a subtype of the sargable (Placeholder.java:48); Go's is a standalone struct, which is precisely why it has to be named here rather than caught by the sargable case.

This exists as an INVARIANT rather than as a fix in each rule because the failure it guards is invisible: a structural predicate in a RecordQueryPredicatesFilterPlan makes the filter reject every row and report success, which is indistinguishable from an empty table. Three separate rules build physical filters, and requiring each to remember the conversion is how two of them came to forget it.

func RebasePredicateChecked

func RebasePredicateChecked(p QueryPredicate, aliases values.AliasMap) (QueryPredicate, error)

RebasePredicateChecked replaces correlation references in every embedded Value tree through the checked rewrite authority, then rebases the one correlation stored outside a Value (Placeholder.ParameterAlias). The whole predicate graph is invocation-local and atomic: an invalid FieldValue reconstruction returns an error and no partial predicate.

func ReplaceValues

func ReplaceValues(p QueryPredicate, fn func(values.Value) values.Value) QueryPredicate

ReplaceValues applies a Value replacement function to all Value trees embedded in a predicate, rebuilding only the spine that changed. Ports Java's QueryPredicate.replaceValuesMaybe. Pointer-equality stable: returns p itself when nothing changed.

This is the EXPORTED home of the walk (the cascades package's replacePredicateValues delegates here): the translator bakes gated-join leg references at the seed with it, and the planner's rule-side callers share the identical spine so predicate-value rewrites can never diverge between the two layers.

func SimplifyPredicateValues

func SimplifyPredicateValues(p QueryPredicate) QueryPredicate

SimplifyPredicateValues walks a QueryPredicate tree and returns a new tree with SimplifyValue applied to every Value operand reachable inside ComparisonPredicate / ValuePredicate leaves. Boolean connectives (AND / OR / NOT) recurse into their children.

Returns the input pointer unchanged when nothing folded — callers can rely on the pointer-equality short-circuit (`if out != p { ... }`) to detect "did anything change?".

Why a separate pass from Simplify: Simplify drives the QueryPredicate- level rule fixpoint (ComparisonConstantSimplifyRule, AndFlatten, …); it doesn't fold expression-level constants inside ComparisonPredicate operands. `name = 1+2` survives Simplify with the `1+2` ArithmeticValue intact; SimplifyPredicateValues collapses it to `name = 3`.

func ToResidualPredicate

func ToResidualPredicate(p QueryPredicate) (QueryPredicate, error)

ToResidualPredicate returns a predicate equivalent to p that can be evaluated as a RESIDUAL — a filter applied to rows that have already been produced — rather than as an index search argument or an instruction to the matching machinery.

Ports Java's `QueryPredicate.toResidualPredicate()`: the interface default (`QueryPredicate.java:252-260`) and its overrides on the existential predicate (`ExistentialValuePredicate.java:107-109`) and the sargable (`PredicateWithValueAndRanges.java:483-492`). Java spells it as a default method; Go has no interface defaults, so it is a package-level function over the interface — the shape `IsTautology` and `ReplaceValues` already use.

Three predicate types cannot answer for a row, and all three have an unconditional non-answer as their Eval: `ExistentialValuePredicate` names an alias no physical row carries once its subplan is a FirstOrDefault, `PredicateWithValueAndRanges` is an index search argument (`Eval` → TriUnknown), and `Placeholder` is a matching-time marker (`Eval` → TriUnknown). Leaving any of them in a filter is not a slower plan, it is a wrong one: the filter drops the entire stream while reporting success.

Pointer-stable: a predicate needing no rewrite is returned as itself.

func ToResidualPredicates

func ToResidualPredicates(preds []QueryPredicate) ([]QueryPredicate, error)

ToResidualPredicates converts a whole predicate list, the shape every filter-building rule needs. Java writes this as `predicates.stream().map(QueryPredicate::toResidualPredicate)` at each of its three filter sites (ImplementFilterRule.java:90, ImplementSimpleSelectRule.java:169, ImplementNestedLoopJoinRule.java:157); having one helper keeps Go from growing three spellings of it.

It is atomic: a failure returns no list rather than a partially converted one.

func TransformEmbeddedValuesChecked

func TransformEmbeddedValuesChecked(
	p QueryPredicate,
	transform func(values.Value) (values.Value, error),
) (QueryPredicate, error)

TransformEmbeddedValuesChecked applies transform once to every complete Value tree owned by p. It does not independently revisit interior Value nodes: callers that need a recursive Value rewrite perform that recursion inside transform. Predicate rebuilding is invocation-local and atomic; the first error returns no predicate graph.

func TranslateLeafPredicates

func TranslateLeafPredicates(p QueryPredicate, m values.TranslationMap) QueryPredicate

TranslateLeafPredicates applies a TranslationMap to every Value tree embedded in a predicate — the Go analog of Java's QueryPredicate.translateLeafPredicate (ValuePredicate.java:149: each predicate's embedded Value goes through Value.translateCorrelations). LEAF-ONLY by construction: the map fires on correlation-bearing leaves via values.TranslateCorrelations — never on interior nodes — and shares the exact predicate spine ReplaceValues uses, so the two rewrite families cannot diverge. Pointer-stable.

func TranslateLeafPredicatesChecked

func TranslateLeafPredicatesChecked(p QueryPredicate, m values.TranslationMap) (QueryPredicate, error)

TranslateLeafPredicatesChecked is the atomic, error-bearing translation authority. A failed Value reconstruction returns no predicate graph; it never embeds a nil Value in an otherwise valid predicate or publishes a partially translated conjunction.

type RangeConstraints

type RangeConstraints struct {
	// contains filtered or unexported fields
}

RangeConstraints represents a conjunction of a compile-time evaluable range and a set of deferred (non-compile-time) ranges. Used during index matching to represent constraints on a single indexed column.

Ports Java's `com.apple.foundationdb.record.query.plan.cascades.predicates.RangeConstraints`.

The compile-time range is represented as a list of Comparisons that can be evaluated against literal values. Deferred ranges are Comparisons that reference correlation variables and can only be evaluated at runtime (but can still form part of an index scan prefix).

RangeConstraints can be converted to a ComparisonRange via AsComparisonRange() for backward compatibility with existing matching infrastructure.

func EmptyRangeConstraints

func EmptyRangeConstraints() *RangeConstraints

EmptyRangeConstraints returns a RangeConstraints with no comparisons (matches everything).

func NewRangeConstraints

func NewRangeConstraints(compilable []Comparison, deferred []Comparison) *RangeConstraints

NewRangeConstraints constructs a RangeConstraints from compile-time and deferred comparisons.

func (*RangeConstraints) AsComparisonRange

func (r *RangeConstraints) AsComparisonRange() *ComparisonRange

AsComparisonRange converts this RangeConstraints to a ComparisonRange by merging all comparisons. This is for backward compatibility with existing matching infrastructure that uses ComparisonRange.

func (*RangeConstraints) GetComparisons

func (r *RangeConstraints) GetComparisons() []Comparison

GetComparisons returns all comparisons (compilable + deferred), cached after first computation.

func (*RangeConstraints) GetCompilableComparisons

func (r *RangeConstraints) GetCompilableComparisons() []Comparison

GetCompilableComparisons returns the compile-time evaluable comparisons.

func (*RangeConstraints) GetCorrelatedTo

func (r *RangeConstraints) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the set of correlation identifiers referenced by all comparisons in this RangeConstraints.

func (*RangeConstraints) GetDeferredRanges

func (r *RangeConstraints) GetDeferredRanges() []Comparison

GetDeferredRanges returns the deferred (non-compile-time) comparisons.

func (*RangeConstraints) IsCompileTime

func (r *RangeConstraints) IsCompileTime() bool

IsCompileTime reports whether all comparisons in this RangeConstraints can be evaluated at compile time (no deferred ranges, no correlation references).

func (*RangeConstraints) IsConstraining

func (r *RangeConstraints) IsConstraining() bool

IsConstraining reports whether this RangeConstraints has any comparisons (compilable or deferred).

type RangeConstraintsBuilder

type RangeConstraintsBuilder struct {
	// contains filtered or unexported fields
}

RangeConstraintsBuilder builds a RangeConstraints incrementally.

func NewRangeConstraintsBuilder

func NewRangeConstraintsBuilder() *RangeConstraintsBuilder

NewRangeConstraintsBuilder creates a new builder.

func (*RangeConstraintsBuilder) AddComparisonMaybe

func (b *RangeConstraintsBuilder) AddComparisonMaybe(c Comparison) bool

AddComparisonMaybe adds a comparison to the builder. Returns true if the comparison was added successfully; false when the comparison kind cannot bound a scan prefix (Java's Builder.addComparisonMaybe, RangeConstraints.java:787-797, gated on canBeUsedInScanPrefix).

func (*RangeConstraintsBuilder) Build

Build creates the RangeConstraints from accumulated comparisons.

type TriBool

type TriBool *bool

TriBool is the SQL 3-valued logic result. A nil pointer is UNKNOWN; otherwise the bool value is true or false. Chose a pointer over a dedicated enum so downstream eval code can use `if result != nil && *result { ... }` without a custom type.

var (
	TriTrue    TriBool = &triTrueVal
	TriFalse   TriBool = &triFalseVal
	TriUnknown TriBool = nil
)

TriTrue / TriFalse / TriUnknown are the canonical tri-state constants. Matchers compare against these rather than constructing fresh pointers.

func AsConstant

func AsConstant(p QueryPredicate) (TriBool, bool)

AsConstant returns (value, true) if p is a ConstantPredicate; (_, false) otherwise. Rule bodies use this as the canonical "is this a fold-able constant?" check, instead of open-coding type assertions.

type TypeMismatchError

type TypeMismatchError struct {
	Left  any
	Right any
}

TypeMismatchError is returned when a comparison encounters incompatible types (e.g., int64 vs string). The executor surfaces it as SQLSTATE 22000 (CANNOT_CONVERT_TYPE), matching Java's SemanticException.

func (*TypeMismatchError) Error

func (e *TypeMismatchError) Error() string

type UsedIndex

type UsedIndex struct {
	// Name is the index name.
	Name string
	// LastModifiedVersion is the metadata version at which the
	// index was last modified, captured at plan creation time.
	LastModifiedVersion int
}

UsedIndex captures the name and lastModifiedVersion of an index that a plan depends on. Ports Java's DatabaseObjectDependenciesPredicate.UsedIndex.

type ValuePredicate

type ValuePredicate struct {
	Value values.Value
}

ValuePredicate wraps a boolean-typed Value as a predicate. The Value evaluates to bool (or nil for UNKNOWN); ValuePredicate.Eval maps that straight to TriBool. `SELECT ... WHERE is_active` where `is_active` is a boolean column or expression goes through this node after semantic analysis.

Returns UNKNOWN when the Value evaluates to nil (NULL) or to any non-bool type — the latter is a type-checking responsibility the semantic analyzer should have already caught; falling through to UNKNOWN keeps the runtime safe against analyzer gaps.

func NewValuePredicate

func NewValuePredicate(v values.Value) *ValuePredicate

NewValuePredicate constructs a ValuePredicate.

func (*ValuePredicate) Children

func (*ValuePredicate) Children() []QueryPredicate

func (*ValuePredicate) Eval

func (p *ValuePredicate) Eval(evalCtx any) (TriBool, error)

func (*ValuePredicate) Explain

func (p *ValuePredicate) Explain() string

func (*ValuePredicate) GetCorrelatedTo

func (p *ValuePredicate) GetCorrelatedTo() map[values.CorrelationIdentifier]struct{}

GetCorrelatedTo returns the correlations from the carried Value.

Jump to

Keyboard shortcuts

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