predicates

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: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

RelOpComparisonType is the predicate comparison a RelOpValue's comparison becomes (RelOpValue.toQueryPredicate).

Functions

func CollectCorrelatedToOfPredicate

func CollectCorrelatedToOfPredicate(p QueryPredicate, out map[CorrelationIdentifier]struct{}) map[CorrelationIdentifier]struct{}

CollectCorrelatedToOfPredicate unions p's correlations into out, allocating out when nil. Callers folding several predicates can share one result set.

func ConstantAgnosticHashCode

func ConstantAgnosticHashCode(p QueryPredicate) uint64

ConstantAgnosticHashCode is SemanticHashCode with constants hashed by type.

func ContainsExistentialPredicate

func ContainsExistentialPredicate(p QueryPredicate) bool

ContainsExistentialPredicate finds structural existential markers, including their residual QOV IS NOT NULL form, anywhere in the predicate tree.

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

func GetCorrelatedToOfPredicate

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

GetCorrelatedToOfPredicate returns transitive correlations as a fresh map. Nil input returns nil; an uncorrelated predicate returns a non-nil empty map.

func IsAtomic

func IsAtomic(p QueryPredicate) bool

IsAtomic reports whether boolean normalization must treat this subtree as a leaf.

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 normalization rules (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 ReadsConstantPool

func ReadsConstantPool(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. ReadsConstantPool reports whether p embeds a statement constant reference.

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
	// contains filtered or unexported fields
}

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

	// 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.

A LIKE's Operand is its values.PatternForLikeValue, which carries the pattern and the escape (Java's ValueComparison(LIKE, patternValue)).

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}`. A LIKE comparand is always a PatternForLikeValue, so a LIKE literal is wrapped as a pattern with no escape.

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 comparison's collector includes its query vector as well as its operand; reading only Operand would silently drop DistanceRank 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 (Java's ComparisonRange.merge, arm for arm):

  • A NONE-type comparison (NOT_EQUALS, IN, LIKE, TEXT_*, …) never enters a range; it comes back as a residual and the range is untouched.
  • Adding any scan-range comparison to an Empty range produces a non-empty range of the corresponding type.
  • Adding an equality to an Equality range is a no-op when the two are the same comparison, and leaves the incoming one as a residual when they differ (the planner scans the first and re-checks the second; a contradiction reads zero rows).
  • Adding an inequality to an Equality range leaves it as a residual.
  • Adding an inequality to an Inequality range appends it, unless it is already present.
  • Adding an equality to an Inequality range makes the equality the range and every accumulated inequality a residual.

The merge is TOTAL: it never fails. MergeResult carries the range plus the residual comparisons, and a caller that cannot carry residuals reads len(Residuals) > 0 as its rejection.

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 adds a comparison to the range. Total: the outcome is always a range plus the residual comparisons that did not fit — see the type comment for the arm table (Java's ComparisonRange.merge(Comparison)).

func (*ComparisonRange) MergeRange

func (r *ComparisonRange) MergeRange(other *ComparisonRange) MergeResult

MergeRange merges every comparison another range carries into this one, accumulating the residuals — Java's ComparisonRange.merge(ComparisonRange).

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, not-equals and the null-safe IS [NOT] DISTINCT FROM are symmetric (unchanged); the binary inequalities flip direction, as Java's RelOpValue.swapBinaryComparisonOperator (RelOpValue.java:297-312). Unary operators (IS NULL / IS NOT NULL) and non-commutable operators (IN, STARTS_WITH, LIKE) 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).

IN is deliberately NOT an equality, matching Java's `IN,` — declared with the no-arg constructor, which chains to `this(false)`. It reads like one, and that is the trap: `x IN (1,2,3)` is a DISJUNCTION of equalities, so a caller acting on a true here would bind a single point-lookup key for a predicate that needs three. Java agrees twice over — `ScanComparisons.getComparisonType(IN)` falls to the `default: NONE` arm, so IN is not a scan bound at all.

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. Used by the NOT-over-Comparison rewrite rule when pushing a NOT down past a leaf comparison.

It is Java's Comparisons.invertComparisonType (Comparisons.java:705-723) and nothing more, which means the DECLINES are the interesting half and they are enumerated rather than characterised:

EQUALS                 -> NOT_EQUALS       inverted
LESS_THAN              -> GREATER_THAN_OR_EQUALS
LESS_THAN_OR_EQUALS    -> GREATER_THAN
GREATER_THAN           -> LESS_THAN_OR_EQUALS
GREATER_THAN_OR_EQUALS -> LESS_THAN

Everything else declines, and four of those declines are worth naming because a negation plainly EXISTS for them and is still not returned:

  • IS NULL / IS NOT NULL. Java's first line is `if (type.isUnary()) return null;`, so the unary null tests are refused before the switch is reached — even though each is the other's exact negation.
  • NOT_EQUALS. EQUALS inverts to it and it does not invert back; Java's switch simply has no NOT_EQUALS arm.
  • IS DISTINCT FROM / IS NOT DISTINCT FROM, likewise absent from the switch.

These are not oversights to be closed here. This function is a 1:1 port and its result feeds a rewrite that changes what the planner's downstream rules see; widening it beyond Java would make Go's canonical predicate shape differ from Java's for the same query.

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().

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. Never nil.
	Range *ComparisonRange
	// Residuals are the comparisons the range could not carry, in the order
	// they were offered. Empty when everything merged.
	Residuals []*Comparison
}

MergeResult carries the outcome of a Merge call: the merged range and the comparisons that could not be pushed into it. Java's ComparisonRange.MergeResult.

func MergeAll

func MergeAll(comparisons []*Comparison) MergeResult

MergeAll folds a list of comparisons into one range from the empty range, accumulating the residuals — Java's ComparisonRange.mergeAll.

func (MergeResult) Complete

func (m MergeResult) Complete() bool

Complete reports whether every offered comparison merged into the range.

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
	// contains filtered or unexported fields
}

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
	// contains filtered or unexported fields
}

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) 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 EvaluatePredicateComparands

func EvaluatePredicateComparands(p QueryPredicate) QueryPredicate

EvaluatePredicateComparands is SimplifyPredicateValues with values.EvaluateConstantComparand at the leaves: every constant composite becomes a literal. It is for a predicate STORED with literal comparands -- the sparse-index predicate, Java's IndexComparison taking `comparison.getComparand(null, null)` -- never for a query plan.

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 FlattenConjunction

func FlattenConjunction(preds []QueryPredicate) []QueryPredicate

FlattenConjunction lifts every top-level AndPredicate in preds into the list, recursively, so the list IS the conjunction: `[And(a, And(b, c)), d]` is `[a, b, c, d]`. An AND under an OR or a NOT is that node's child and is left alone. Java's SelectExpression constructor applies this (SelectExpression.partitionPredicates → flattenPredicate(AndPredicate.class)), which is why a Java rule can read a Select's predicate list as its conjuncts; the expression constructors here establish the same invariant. Returns preds itself when nothing needed lifting, so an already-flat list keeps its identity and a constructor call allocates nothing.

func FoldComparisonMaybe

func FoldComparisonMaybe(lhsValue values.Value, comp Comparison) QueryPredicate

FoldComparisonMaybe is Java's ConstantPredicateFoldingUtil.foldComparisonMaybe: the constant a comparison of lhsValue folds to over EFFECTIVE constants, or nil when it does not fold. IS [NOT] NULL is decided by a NULL or a NOT NULL operand; a binary comparison with a NULL side is NULL; EQUALS and NOT_EQUALS over two known literals (TRUE, FALSE, NULL) compare them; anything else, including a comparison of two non-boolean literals, does not fold.

func PartitionPredicates

func PartitionPredicates(predicates []QueryPredicate) []QueryPredicate

PartitionPredicates ports SelectExpression.partitionPredicates: opaque predicates precede stable, value-equivalent groups of residuals and ranges.

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?".

It is the value half of Java's ValuePredicateSimplificationRule, which cascades.ConstantFoldingRules applies to each leaf inside the QueryPredicate-level fixpoint: `name = 1+2` becomes `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 TransformEmbeddedValues

func TransformEmbeddedValues(p QueryPredicate, transform func(values.Value) values.Value) QueryPredicate

TransformEmbeddedValues applies transform once per complete embedded Value tree, not per interior node. An identity transform rebuilds no predicate nodes.

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.

func WithAtomicity

func WithAtomicity(p QueryPredicate, atomic bool) QueryPredicate

WithAtomicity copies a connective's optimization barrier; leaves are unchanged.

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, bool)

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

It returns false when the constraints cannot be expressed as ONE ComparisonRange: the merge is total and reports what did not fit as residuals (Java's asMergedComparisonRange returns the range plus that list), but this signature has nowhere to hand them on, so `x = 5 AND x > 7` is refused rather than answered with the WEAKER `x = 5` — a caller filtering on the weaker range would return rows the constraints excluded. A caller that can carry residuals should call MergeAll on GetComparisons directly.

LATENT, and said so deliberately: this function has no non-test callers.

func (*RangeConstraints) Encloses

func (r *RangeConstraints) Encloses(other *RangeConstraints) bool

Encloses proves containment of literal-bound ranges. As in Java RangeConstraints.encloses, deferred candidate constraints prevent a proof; deferred query constraints may only narrow its known range. Runtime-bound parameters are deliberately not evaluated here: their values would require a captured plan-cache constraint, not an unconditional implication proof.

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) Add

Add intersects a range without reclassifying its compiled/deferred lanes.

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 TemporalCarrierError

type TemporalCarrierError struct {
	Operand string
	Value   time.Time
}

TemporalCarrierError is a comparison operand that evaluated to a time.Time. DATE and TIMESTAMP values are canonical text, so this is an internal error: a time.Time compared as text or skipped would answer silently wrong.

func (*TemporalCarrierError) Error

func (e *TemporalCarrierError) Error() string

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