This is the full catalog of operators in the unified algebra. Each entry gives you:
what it does, in plain language;
its signature: the arguments and their types, and what it returns;
its semantics: the precise definition.
Notation used throughout: V is the domain of items, T the set of tuples, A the set of attribute names, ⊕ is tuple concatenation, and Γ is the operator context. inst… marks an argument that is re-instantiated per row (a horizontal input). Each operator's formal definition abbreviates its arguments to single letters; the argument list under every entry gives that letter in parentheses, e.g. attrs (A).
The tables below are a per-group index; the operator name links down to its full entry.
Item operators produce streams of opaque values. Most are calculation intermediaries: building blocks assembled inside a Calculation rather than standalone plan nodes.
Represents the result of a single aggregate (such as count or sum) applied to a partition produced by an upstream GroupBy. It's a placeholder that the GroupBy fills in for each group.
A CASE / if-then-else expression. It scans the whenthens pairs and returns the value of the first one whose condition matches, falling back to default. With an expr, each branch is compared against that value (a switch); without one, each branch condition is tested for truth (an if/elif chain).
Signature: cond(expr,whenthens,default)
expr (e): Stream01(V)
whenthens (w): Seq((Stream01(V),Stream01(V)))
default (d): Stream01(V)
returns: Stream1(V)
cond(e,w,d)=⎩⎨⎧⟨wi,1⟩ where i is the first index with wi,0=e, else d,⟨wi,1⟩ where i is the first index with wi,0=⟨true⟩, else d,if e is providedotherwise
Calls a scalar function on its arguments and yields a single value. It's the building block for ordinary expressions inside a Calculation (arithmetic, comparisons, string functions, and so on).
A SQL-style quantified comparison, for example x > ALL(SELECT y FROM t) or x = ANY(...). The type says how the comparison is quantified over the subquery query.
The general "compute a value" operator, and the only item operator that routinely appears as a real plan node. It wraps an expression (function calls, literals, attribute references, even whole subqueries) and evaluates it against the current row and context. Projection attributes and Selection conditions are all Calculations. When its expression contains a subquery, it tracks whether that subquery yields at most one value or many.
Turns a tuple stream into an item stream by pulling the key attribute out of each tuple. If key is the allAttrs symbol *, the whole tuple becomes the item. The bridge from the tuple world back to the item world.
A cross product kept only where all conditions hold. Set leftOuter or rightOuter to also emit unmatched rows from that side, padded with nulls. Conditions are kept as a set (rather than one combined predicate) so the optimizer can reason about each separately; a join with no conditions is legal and useful purely for its outer-join behavior.
Computes a new set of named attributes for each row: the algebra's SELECT list. Each output attribute is a Calculation evaluated against the row and context.
The depend-join. For each source row, it re-evaluates the mapping subquery (which may reference that row through the context) and joins each resulting row back onto the source row. This is how correlated subqueries and LATERAL joins are expressed. With outer set, source rows that produce no mapping rows are still emitted, padded with nulls.
Partitions rows by their keys and computes one or more aggregates per partition. Each entry in aggs is an aggregate function paired with the attribute it writes; the output of each group is its key values concatenated with its aggregate results.
Signature: γ(keys,aggs,source)
keys (K): Seq(instStream1(V)×A)
aggs (A): Seq((Stream(T)→V)×A)
source (S): Stream(T)
returns: Stream(T)
The helper group selects the rows belonging to one partition (those whose key values equal V):
Wraps each opaque item into a single-attribute row named key, the inverse of MapToItem. The original item is stored as-is; it is not reinterpreted as a tuple.
Repeatedly self-joins source, breadth-first, building up paths of length min to max while condition holds. It backs variable-length graph paths and recursive CTEs. Each output attribute accumulates an array of values across the iterations, and condition sees, for every attribute, the array accumulated so far together with the candidate next value.
Signature: ϕ(min,max,condition,source)
min: N
max: N
condition (C): instStream1(V)
source (S): Stream(T)
returns: Stream(T)
Base case, a single step wraps each attribute value in a one-element array:
ϕ(0,1,C,S,Γ)=⟨{a↦⟨s.a⟩∣a∈s}∣s∈S⟩
Inductive case, extend each accumulated path by one more matching row:
Implements an XQuery path step such as a/b/c. For each source row it evaluates expr and, for every produced item, emits a row carrying the XQuery focus: the current item ($fs:dot), its position ($fs:position), and the total count ($fs:last). It rolls ProjectionConcat, ProjectionIndex, and ProjectionSize into one, but unlike ProjectionConcat, its expr is a Calculation, not a tuple operator.
These operators are not part of the theoretical algebra; a plan is complete and correct without them. They exist only to give the optimizer better targets, enabling substantial speedups. Two of them enable secondary indices; the third is a faster variant of Recursion.
Replaces a filtered TupleSource (or an ItemSource paired with a MapFromItem) with a lookup into a registered index. Instead of scanning the whole source, it holds an accessCalculation that feeds the matching values straight into the underlying index structure. When it stands in for the item-source case, fromItemKey carries the MapFromItem key so the result is still a single-attribute row stream.
Signature: indexScan(name,access,fromItemKey)
name: the indexed source's name
access: Calculation, the index accessor
fromItemKey: A (optional, only for the ItemSource case)
A variant of Recursion that behaves like a recursive depend-join: instead of self-joining a fixed source, it re-evaluates mapping against each accumulated path, so every step can be driven by an index. This is what makes indexed graph traversal possible.
Signature: →ϕ(min,max,mapping,source)
min: N
max: N
mapping (M): instStream(T)
source (S): Stream(T)
returns: Stream(T)
Base case, a single step wraps each attribute value in a one-element array:
→ϕ(0,1,M,S,Γ)=⟨{a↦⟨s.a⟩∣a∈s}∣s∈S⟩
Inductive case, extend each accumulated path by re-instantiating the mapping against it:
Searches a recursive path from both ends at once, expanding mappingFwd from the source side and mappingRev from the target side until the two frontiers meet. It is more work to set up than IndexedRecursion, but offers large asymptotic improvements in both time and memory. Its result combines the schemas of both ends, source⊕target.
Union, Intersection, and Difference are the standard set operations over two streams. Each takes left (L) and right (R) of type Stream(V∪T) and returns the same type.