RelNode tree and consumed by the optimizer
and planner.
This first increment carries distinctness — whether the relation is guaranteed free of duplicate rows — backed by a key model:
wholeRowDistinct()— the entire row is unique (the relation is a set), without enumerating the columns. Produced by operators whose output is a set regardless of input (δ, ∪, ∩, −, ∆, ÷, transitive closure).keys()— explicit candidate keys, each a set of column names on which rows are unique (an empty key set means "at most one row"). Produced where the unique columns are known structurally (a grouping aggregation's keys, a group-wise ∀'s keys).
A relation is duplicate-free iff its whole row
is distinct or it has any candidate key — the question
DIST-001 (redundant δ elimination) asks.
The carrier also records boundedness. The
distinctness factories default it to Boundedness.BOUNDED (every relation
in the language is finite today); the boundedness-aware
PropertyDeriver.derive(com.darkcollective.relix.ast.RelNode, BoundednessSource) overlays the derived value via withBoundedness(com.darkcollective.relix.cost.Boundedness). A
physical ordering descriptor is the remaining Phase-C extension. Column names
are compared case-insensitively (stored lowercased), matching
Schema.
Instances are immutable value objects.
-
Method Summary
Modifier and TypeMethodDescriptionThe relation's boundedness — whether it is provably finite.booleaninthashCode()booleanWhether the relation is guaranteed to contain no duplicate rows — it is whole-row distinct or has at least one candidate key.static RelationPropertieskey(Collection<String> columns) Properties of a relation unique on exactly the given key columns (an empty collection denotes a relation of at most one row).keys()The known candidate keys — each an immutable set of lowercased column names on which rows are unique.static RelationPropertiesnone()Properties of a relation about which nothing is known — not duplicate-free, no candidate keys.toString()static RelationPropertieswholeRow()Properties of a relation whose entire row is guaranteed unique (a set), without enumerating its columns — e.g.booleanWhether the entire row is known to be unique without an enumerated key.withBoundedness(Boundedness newBoundedness) Returns a copy of these properties with the boundedness replaced — used by the boundedness-aware derivation to overlay the structurally-derived distinctness with a source-derived boundedness.
-
Method Details
-
none
Properties of a relation about which nothing is known — not duplicate-free, no candidate keys. The conservative default for leaves and operators that may introduce duplicates.- Returns:
- the empty properties; never null
-
wholeRow
Properties of a relation whose entire row is guaranteed unique (a set), without enumerating its columns — e.g. the output ofδor a set operation.- Returns:
- whole-row-distinct properties; never null
-
key
Properties of a relation unique on exactly the given key columns (an empty collection denotes a relation of at most one row).- Parameters:
columns- the key columns; must not be null (may be empty)- Returns:
- properties carrying that single candidate key; never null
-
withBoundedness
Returns a copy of these properties with the boundedness replaced — used by the boundedness-aware derivation to overlay the structurally-derived distinctness with a source-derived boundedness.- Parameters:
newBoundedness- the boundedness to set; must not be null- Returns:
- a copy carrying
newBoundedness; never null
-
isDuplicateFree
public boolean isDuplicateFree()Whether the relation is guaranteed to contain no duplicate rows — it is whole-row distinct or has at least one candidate key.- Returns:
trueif the relation is provably duplicate-free
-
wholeRowDistinct
public boolean wholeRowDistinct()Whether the entire row is known to be unique without an enumerated key.- Returns:
trueif the relation is whole-row distinct
-
keys
The known candidate keys — each an immutable set of lowercased column names on which rows are unique.Staged, not dead. Today the keys are read only through
isDuplicateFree(), whose sole caller asks the yes/no questionDIST-001needs; which columns form the key is derived on every derivation and never inspected. That is deliberate rather than accidental: the rules that would consume the column sets — candidate-key survival through π, key propagation through a join, and the set-op idempotence laws — are filed and unshipped, and deriving the keys is what makes writing them a rule rather than a rule plus a new derivation. Dropping the detail to a boolean now would have to be undone by the first of them.The key model that is load-bearing today is the separate
RelationStatistics.keys()— read byStatisticsDistinctnessSource(a keyed base relation is duplicate-free) and byPlanner.indexBacked(a merge key that prefixes a candidate key is index-backed). The two are not interchangeable: those are declared keys of a base table, these are keys derived through the operator tree.- Returns:
- an immutable set of candidate keys; never null, possibly empty
-
boundedness
The relation's boundedness — whether it is provably finite.- Returns:
- the boundedness; never null
-
equals
-
hashCode
public int hashCode() -
toString
-