Skip to main content

Operator Reference

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\mathcal{V} is the domain of items, T\mathcal{T} the set of tuples, A\mathcal{A} the set of attribute names, \oplus is tuple concatenation, and Γ\Gamma is the operator context. inst\mathrm{inst}_{\dots} 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 (AA).

The tables below are a per-group index; the operator name links down to its full entry.


Item operators

Item operators produce streams of opaque values. Most are calculation intermediaries: building blocks assembled inside a Calculation rather than standalone plan nodes.

OperatorNotationResult schema
Calculation intermediaries
AggregateCallagg(args)\mathrm{agg}(\texttt{args})n/a
Conditionalcond(expr,whenthens,default)\mathrm{cond}(\texttt{expr}, \texttt{whenthens}, \texttt{default})n/a
FnCallfn(impl,args)\mathrm{fn}(\texttt{impl}, \texttt{args})n/a
Literalliteral(value)\mathrm{literal}(\texttt{value})n/a
Quantifierquant(type,query)\mathrm{quant}(\texttt{type}, \texttt{query})n/a
Other
Calculationcalc(impl,args)\mathrm{calc}(\texttt{impl}, \texttt{args})n/a
ItemSourcename\textit{name}n/a
ItemFnSourcename(impl,params)\textit{name}(\texttt{impl}, \texttt{params})n/a
MapToItemtoItem(key,source)\mathrm{toItem}(\texttt{key}, \texttt{source})n/a

AggregateCall

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.

Signature: agg(args)\mathrm{agg}(\texttt{args})

Conditional

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)\mathrm{cond}(\texttt{expr}, \texttt{whenthens}, \texttt{default})

  • expr (ee): Stream01(V)\mathrm{Stream}_{01}(\mathcal{V})
  • whenthens (ww): Seq((Stream01(V),Stream01(V)))\mathrm{Seq}((\mathrm{Stream}_{01}(\mathcal{V}), \mathrm{Stream}_{01}(\mathcal{V})))
  • default (dd): Stream01(V)\mathrm{Stream}_{01}(\mathcal{V})
  • returns: Stream1(V)\mathrm{Stream}_{1}(\mathcal{V})
cond(e,w,d)={wi,1 where i is the first index with wi,0=e, else d,if e is providedwi,1 where i is the first index with wi,0=true, else d,otherwise\mathrm{cond}(e, w, d) = \begin{cases} \langle w_{i,1}\rangle \text{ where } i \text{ is the first index with } w_{i,0} = e, \text{ else } d, & \text{if } e \text{ is provided} \\[6pt] \langle w_{i,1}\rangle \text{ where } i \text{ is the first index with } w_{i,0} = \langle\textbf{true}\rangle, \text{ else } d, & \text{otherwise} \end{cases}

FnCall

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

Signature: fn(impl,args)\mathrm{fn}(\texttt{impl}, \texttt{args})

  • impl (ii): Seq(Stream(V))Stream1(V)\mathrm{Seq}(\mathrm{Stream}(\mathcal{V})) \rightarrow \mathrm{Stream}_1(\mathcal{V})
  • args (AA): Seq(Stream(V))\mathrm{Seq}(\mathrm{Stream}(\mathcal{V}))
  • returns: Stream1(V)\mathrm{Stream}_{1}(\mathcal{V})
fn(i,A)=i(A)\mathrm{fn}(i, A) = \langle i(A) \rangle

Literal

A constant value embedded directly in the plan, such as the 3 in x + 3.

Signature: literal(value)\mathrm{literal}(\texttt{value})

Quantifier

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.

Signature: quant(type,query)\mathrm{quant}(\texttt{type}, \texttt{query})

Calculation

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.

Signature: calc(impl,args)\mathrm{calc}(\texttt{impl}, \texttt{args})

  • impl (ii): Seq(Stream(V))Stream1(V)\mathrm{Seq}(\mathrm{Stream}(\mathcal{V})) \rightarrow \mathrm{Stream}_1(\mathcal{V})
  • args (AA): Seq(Stream(V))\mathrm{Seq}(\mathrm{Stream}(\mathcal{V}))
  • returns: Stream1(V)\mathrm{Stream}_{1}(\mathcal{V})
calc(i,A)=i(A)\mathrm{calc}(i, A) = \langle i(A) \rangle

ItemSource

A named source that emits opaque items, for example a graph's nodes or edges, or a registered JSON array. The leaf of an item pipeline.

Signature: name\textit{name}

ItemFnSource

Like ItemSource, but the items come from calling a function with parameters rather than from a named registration. Cypher's UNWIND lowers to this.

Signature: name(impl,params)\textit{name}(\texttt{impl}, \texttt{params})

  • impl (ii): Seq(Stream1(V))Stream(V)\mathrm{Seq}(\mathrm{Stream}_1(\mathcal{V})) \rightarrow \mathrm{Stream}(\mathcal{V})
  • params (AA): Seq(Stream1(V))\mathrm{Seq}(\mathrm{Stream}_1(\mathcal{V}))
  • returns: Stream(V)\mathrm{Stream}(\mathcal{V})
name(i,A)=i(A)\textit{name}(i, A) = i(A)

MapToItem

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.

Signature: toItem(key,source)\mathrm{toItem}(\texttt{key}, \texttt{source})

  • key (kk): A\mathcal{A}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T}), where keyschema(source)\texttt{key} \in \mathrm{schema}(\texttt{source})
  • returns: Stream(V)\mathrm{Stream}(\mathcal{V})
toItem(k,S)=t.ktS\mathrm{toItem}(k, S) = \langle t.k \mid t \in S \rangle

Tuple operators: SPJ and other

Tuple operators produce streams of named rows. These are the relational core of the algebra.

OperatorNotationResult schema
Select / Project / Join
CartesianProduct×(left,right)\times(\texttt{left},\texttt{right})leftright\texttt{left} \oplus \texttt{right}
Join(left,right,leftOuter,rightOuter,conditions)\bowtie(\texttt{left},\texttt{right}, \texttt{leftOuter}, \texttt{rightOuter},\texttt{conditions})leftright\texttt{left} \oplus \texttt{right}
Projectionπ(attrs,source)\pi(\texttt{attrs},\texttt{source})attrs\texttt{attrs}
ProjectionConcat(mapping,outer,source)\stackrel{\bowtie}{\rightarrow}(\texttt{mapping}, \texttt{outer}, \texttt{source})sourcemapping\texttt{source} \oplus \texttt{mapping}
ProjectionIndexindex(key,source)\mathrm{index}(\texttt{key}, \texttt{source})source(key)\texttt{source} \oplus (\texttt{key})
Selectionσ(expression,source)\sigma(\texttt{expression}, \texttt{source})source\texttt{source}
Other
Distinctδ(attributes,source)\delta(\texttt{attributes}, \texttt{source})source\texttt{source}
GroupByγ(keys,aggs,source)\gamma(\texttt{keys},\texttt{aggs},\texttt{source})keysaggs\texttt{keys} \oplus \texttt{aggs}
MapFromItemfromItem(key,source)\mathrm{fromItem}(\texttt{key}, \texttt{source})(key)(\texttt{key})
OrderByτ(orders,source)\tau(\texttt{orders},\texttt{source})source\texttt{source}
Recursionϕ(min,max,condition,source)\phi(\texttt{min}, \texttt{max}, \texttt{condition}, \texttt{source})source\texttt{source}
TupleSourcename\textbf{name}unknown
TupleFnSourcename(impl,params)\textbf{name}(\texttt{impl}, \texttt{params})possibly unknown

CartesianProduct

Pairs every row on the left with every row on the right: the unfiltered cross product.

Signature: ×(left,right)\times(\texttt{left}, \texttt{right})

  • left (LL): Stream(T)\mathrm{Stream}(\mathcal{T})
  • right (RR): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
×(L,R)=lrlL,rR\times(L, R) = \langle l \oplus r \mid l \in L, r \in R \rangle

Join

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.

Signature: (left,right,leftOuter,rightOuter,conditions)\bowtie(\texttt{left}, \texttt{right}, \texttt{leftOuter}, \texttt{rightOuter}, \texttt{conditions})

  • left (LL): Stream(T)\mathrm{Stream}(\mathcal{T})
  • right (RR): Stream(T)\mathrm{Stream}(\mathcal{T})
  • leftOuter: Boolean
  • rightOuter: Boolean
  • conditions (CC): Set(instStream1(V))\mathrm{Set}(\mathrm{inst}_{\mathrm{Stream}_1(\mathcal{V})})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
(L,R,false,false,C,Γ)=lrlL,rR,cC:c(Γlr)=true\bowtie(L, R, \textbf{false}, \textbf{false}, C, \Gamma) = \langle l \oplus r \mid l \in L, r \in R, \forall c \in C: c(\Gamma \cup l \cup r) = \langle\textbf{true}\rangle \rangle

When leftOuter (or rightOuter) is true, unmatched left (or right) rows are also returned, padded with nulls.

Projection

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.

Signature: π(attrs,source)\pi(\texttt{attrs}, \texttt{source})

  • attrs (AA): Seq(instStream1(V)×A)\mathrm{Seq}(\mathrm{inst}_{\mathrm{Stream}_1(\mathcal{V})} \times \mathcal{A})
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
π(A,S,Γ)={ac(Γs)(c,a)A}sS\pi(A, S, \Gamma) = \langle \left\{ a \mapsto c(\Gamma \oplus s) \mid (c, a) \in A \right\} \mid s \in S \rangle

ProjectionConcat

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.

Signature: (mapping,outer,source)\stackrel{\bowtie}{\rightarrow}(\texttt{mapping}, \texttt{outer}, \texttt{source})

  • mapping (MM): instStream(T)\mathrm{inst}_{\mathrm{Stream}(\mathcal{T})}
  • outer: Boolean
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
(M,false,S,Γ)=smmM(Γs),sS\stackrel{\bowtie}{\rightarrow}(M, \textbf{false}, S, \Gamma) = \langle s \oplus m \mid m \in M(\Gamma \oplus s), s \in S \rangle

ProjectionIndex

Adds an attribute holding each row's ordinal position in the stream (its row number).

Signature: index(key,source)\mathrm{index}(\texttt{key}, \texttt{source})

  • key (kk): A\mathcal{A}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
index(k,S)=si{ki}siS\mathrm{index}(k, S) = \langle s_i \oplus \left\{ k \mapsto i \right\} \mid s_i \in S \rangle

Selection

Keeps only the rows for which the condition is true: the algebra's WHERE.

Signature: σ(expression,source)\sigma(\texttt{expression}, \texttt{source})

  • expression (EE): instStream1(V)\mathrm{inst}_{\mathrm{Stream}_1(\mathcal{V})}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
σ(E,S,Γ)=ssS,E(Γs)=true\sigma(E, S, \Gamma) = \langle s \mid s \in S, E(\Gamma \oplus s) = \langle\textbf{true}\rangle \rangle

Distinct

Removes duplicate rows. Duplicates are compared on attributes, which may be the allAttrs symbol * to compare whole rows.

Signature: δ(attributes,source)\delta(\texttt{attributes}, \texttt{source})

GroupBy

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)\gamma(\texttt{keys}, \texttt{aggs}, \texttt{source})

  • keys (KK): Seq(instStream1(V)×A)\mathrm{Seq}(\mathrm{inst}_{\mathrm{Stream}_1(\mathcal{V})} \times \mathcal{A})
  • aggs (AA): Seq((Stream(T)V)×A)\mathrm{Seq}((\mathrm{Stream}(\mathcal{T}) \rightarrow \mathcal{V}) \times \mathcal{A})
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})

The helper group\mathrm{group} selects the rows belonging to one partition (those whose key values equal VV):

group(K,V,S,Γ)=ssS,i:Ki(Γs)=Vi\mathrm{group}(K, V, S, \Gamma) = \langle s \mid s \in S, \forall i : K_i(\Gamma \oplus s) = V_i \rangle γ(K,A,S,Γ)= {ak(Γs)(k,a)K} {af(group(K, k(Γs)(k,_)K, S, Γ))(f,a)A}sS unique\begin{aligned} \gamma(K, A, S, \Gamma) = \langle\ & \{ a \mapsto k(\Gamma \oplus s) \mid (k, a) \in K \}\ \oplus \\ & \{ a \mapsto f(\mathrm{group}(K,\ \langle k(\Gamma \oplus s) \mid (k, \_) \in K \rangle,\ S,\ \Gamma)) \mid (f, a) \in A \} \\ & \mid s \in S\ \rangle_{unique} \end{aligned}

MapFromItem

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.

Signature: fromItem(key,source)\mathrm{fromItem}(\texttt{key}, \texttt{source})

  • key (kk): A\mathcal{A}
  • source (SS): Stream(V)\mathrm{Stream}(\mathcal{V})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
fromItem(k,S)={ks}sS\mathrm{fromItem}(k, S) = \langle \left\{ k \mapsto s \right\} \mid s \in S \rangle

OrderBy

Sorts the row stream by the given orders (ordering keys with directions). Schema is unchanged.

Signature: τ(orders,source)\tau(\texttt{orders}, \texttt{source})

Recursion

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)\phi(\texttt{min}, \texttt{max}, \texttt{condition}, \texttt{source})

  • min: N\mathbb{N}
  • max: N\mathbb{N}
  • condition (CC): instStream1(V)\mathrm{inst}_{\mathrm{Stream}_1(\mathcal{V})}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})

Base case, a single step wraps each attribute value in a one-element array:

ϕ(0,1,C,S,Γ)={as.aas}sS\phi(0, 1, C, S, \Gamma) = \langle \left\{ a \mapsto \langle s.a \rangle \mid a \in s \right\} \mid s \in S \rangle

Inductive case, extend each accumulated path by one more matching row:

ϕ(0,max,C,S,Γ)= {aacc.acurr.aaacc}currS,accϕ(0,max1,C,S,Γ),C(Γzip(curr,acc))=true \begin{aligned} \phi(0, \mathrm{max}, C, S, \Gamma) = \langle\ & \{ a \mapsto \mathrm{acc}.a \cup \langle\mathrm{curr}.a\rangle \mid a \in \mathrm{acc} \} \\ & \mid \mathrm{curr} \in S, \\ & \quad \mathrm{acc} \in \phi(0, \mathrm{max} - 1, C, S, \Gamma), \\ & \quad C(\Gamma \oplus \mathrm{zip}(\mathrm{curr}, \mathrm{acc})) = \langle\textbf{true}\rangle\ \rangle \end{aligned}

Finally, keep only paths of at least min length:

ϕ(min,max,C,S,Γ)=ppϕ(0,max,C,S,Γ),ap:p.amin\phi(\mathrm{min}, \mathrm{max}, C, S, \Gamma) = \langle p \mid p \in \phi(0, \mathrm{max}, C, S, \Gamma), \forall a \in p: |p.a| \geq \mathrm{min} \rangle

TupleSource

A named source that emits rows, for example a registered relational table. Its schema is generally not known until planning resolves it.

Signature: name\textbf{name}

TupleFnSource

Like TupleSource, but the rows come from calling a function with parameters.

Signature: name(impl,params)\textbf{name}(\texttt{impl}, \texttt{params})

  • impl (ii): Seq(Stream1(V))Stream(T)\mathrm{Seq}(\mathrm{Stream}_1(\mathcal{V})) \rightarrow \mathrm{Stream}(\mathcal{T})
  • params (AA): Seq(Stream1(V))\mathrm{Seq}(\mathrm{Stream}_1(\mathcal{V}))
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
name(i,A)=i(A)\mathrm{name}(i, A) = i(A)

Tuple operators: XQuery

These two operators are provided by the XQuery package, not the core. They demonstrate that the algebra is extensible.

OperatorNotationResult schema
ProjectionSizesize(key,source)\mathrm{size}(\texttt{key}, \texttt{source})source(key)\texttt{source} \oplus (\texttt{key})
TreeJointreeJoin(expr,source)\mathrm{treeJoin}(\texttt{expr}, \texttt{source})source(fs.dot,fs.position,fs.last)\texttt{source} \oplus (\texttt{fs.dot}, \texttt{fs.position}, \texttt{fs.last})

ProjectionSize

Adds an attribute holding the total number of rows in the stream. XQuery needs this to expose $fs:last during path navigation.

Signature: size(key,source)\mathrm{size}(\texttt{key}, \texttt{source})

  • key (kk): A\mathcal{A}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
size(k,S)=s{kS}sS\mathrm{size}(k, S) = \langle s \oplus \left\{ k \mapsto |S| \right\} \mid s \in S \rangle

TreeJoin

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.

Signature: treeJoin(expr,source)\mathrm{treeJoin}(\texttt{expr}, \texttt{source})

  • expr (EE): instStream(V)\mathrm{inst}_{\mathrm{Stream}(\mathcal{V})}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})
treeJoin(E,S,Γ)= si{fs,dote, fs,positioni, fs,lasttreeJoin(E,S,Γ)}siS,eE(Γsi) \begin{aligned} \mathrm{treeJoin}(E, S, \Gamma) = \langle\ & s_i \oplus \{ \\ & \quad \langle\mathrm{fs}, \mathrm{dot}\rangle \mapsto e,\ \\ & \quad \langle\mathrm{fs}, \mathrm{position}\rangle \mapsto i,\ \\ & \quad \langle\mathrm{fs}, \mathrm{last}\rangle \mapsto |\mathrm{treeJoin}(E, S, \Gamma)| \\ & \} \mid s_i \in S, e \in E(\Gamma \oplus s_i)\ \rangle \end{aligned}

Tuple operators: Optimizer

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.

OperatorNotationResult schema
IndexScanindexScan(name,access,fromItemKey)\mathrm{indexScan}(\texttt{name}, \texttt{access}, \texttt{fromItemKey})unknown
IndexedRecursionϕ(min,max,mapping,source)\stackrel{\phi}{\rightarrow}(\texttt{min}, \texttt{max}, \texttt{mapping}, \texttt{source})source\texttt{source}
BidirectionalRecursionϕ(min,max,mappingFwd,mappingRev,target,source)\stackrel{\phi}{\leftrightarrow}(\texttt{min}, \texttt{max}, \texttt{mappingFwd}, \texttt{mappingRev}, \texttt{target}, \texttt{source})sourcetarget\texttt{source} \oplus \texttt{target}

IndexScan

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 access Calculation 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)\mathrm{indexScan}(\texttt{name}, \texttt{access}, \texttt{fromItemKey})

  • name: the indexed source's name
  • access: Calculation\mathrm{Calculation}, the index accessor
  • fromItemKey: A\mathcal{A} (optional, only for the ItemSource case)
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})

IndexedRecursion

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)\stackrel{\phi}{\rightarrow}(\texttt{min}, \texttt{max}, \texttt{mapping}, \texttt{source})

  • min: N\mathbb{N}
  • max: N\mathbb{N}
  • mapping (MM): instStream(T)\mathrm{inst}_{\mathrm{Stream}(\mathcal{T})}
  • source (SS): Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})

Base case, a single step wraps each attribute value in a one-element array:

ϕ(0,1,M,S,Γ)={as.aas}sS\stackrel{\phi}{\rightarrow}(0, 1, M, S, \Gamma) = \langle \left\{ a \mapsto \langle s.a \rangle \mid a \in s \right\} \mid s \in S \rangle

Inductive case, extend each accumulated path by re-instantiating the mapping against it:

ϕ(0,max,M,S,Γ)= {aacc.acurr.aaacc}accϕ(0,max1,M,S,Γ),currM(Γacc) \begin{aligned} \stackrel{\phi}{\rightarrow}(0, \mathrm{max}, M, S, \Gamma) = \langle\ & \{ a \mapsto \mathrm{acc}.a \cup \langle\mathrm{curr}.a\rangle \mid a \in \mathrm{acc} \} \\ & \mid \mathrm{acc} \in \stackrel{\phi}{\rightarrow}(0, \mathrm{max} - 1, M, S, \Gamma), \\ & \quad \mathrm{curr} \in M(\Gamma \oplus \mathrm{acc})\ \rangle \end{aligned}

Finally, keep only paths of at least min length:

ϕ(min,max,M,S,Γ)=ppϕ(0,max,M,S,Γ),ap:p.amin\stackrel{\phi}{\rightarrow}(\mathrm{min}, \mathrm{max}, M, S, \Gamma) = \langle p \mid p \in \stackrel{\phi}{\rightarrow}(0, \mathrm{max}, M, S, \Gamma), \forall a \in p: |p.a| \geq \mathrm{min} \rangle

BidirectionalRecursion

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, sourcetarget\texttt{source} \oplus \texttt{target}.

Signature: ϕ(min,max,mappingFwd,mappingRev,target,source)\stackrel{\phi}{\leftrightarrow}(\texttt{min}, \texttt{max}, \texttt{mappingFwd}, \texttt{mappingRev}, \texttt{target}, \texttt{source})

  • min: N\mathbb{N}
  • max: N\mathbb{N}
  • mappingFwd: instStream(T)\mathrm{inst}_{\mathrm{Stream}(\mathcal{T})}
  • mappingRev: instStream(T)\mathrm{inst}_{\mathrm{Stream}(\mathcal{T})}
  • target: Stream(T)\mathrm{Stream}(\mathcal{T})
  • source: Stream(T)\mathrm{Stream}(\mathcal{T})
  • returns: Stream(T)\mathrm{Stream}(\mathcal{T})

Universal operators

Universal operators accept either tuples or items.

OperatorNotation
NullSource\square
Limitlimit(offset,limit,source)\mathrm{limit}(\texttt{offset}, \texttt{limit}, \texttt{source})
Set
Union(left,right)\cup(\texttt{left}, \texttt{right})
Intersection(left,right)\cap(\texttt{left}, \texttt{right})
Difference(left,right)\setminus(\texttt{left}, \texttt{right})

NullSource

Emits exactly one empty row. It gives constant queries like SELECT 1 AS one something to project from.

Signature: \square

  • returns: Stream1(VT)\mathrm{Stream}_1(\mathcal{V} \cup \mathcal{T})
=\square = \langle \varnothing \rangle

Limit

Skips the first offset results, then passes through at most limit of them: OFFSET plus LIMIT.

Signature: limit(offset,limit,source)\mathrm{limit}(\texttt{offset}, \texttt{limit}, \texttt{source})

  • offset (oo): N\mathbb{N}
  • limit (ll): N\mathbb{N}
  • source (SS): Stream(VT)\mathrm{Stream}(\mathcal{V} \cup \mathcal{T})
  • returns: Stream(VT)\mathrm{Stream}(\mathcal{V} \cup \mathcal{T})
limit(o,l,S)=sisiS,o<io+l\mathrm{limit}(o, l, S) = \langle s_i \mid s_i \in S, o < i \leq o + l \rangle

Set operators

Union, Intersection, and Difference are the standard set operations over two streams. Each takes left (LL) and right (RR) of type Stream(VT)\mathrm{Stream}(\mathcal{V} \cup \mathcal{T}) and returns the same type.

(L,R)=LR\cup(L, R) = L \cup R (L,R)=xxRxL\cap(L, R) = \langle x \mid x \in R \wedge x \in L \rangle (L,R)=xxLxR\setminus(L, R) = \langle x \mid x \in L \wedge x \notin R \rangle