pub enum Node {
Show 13 variants
Get {
catalog: StrRef,
schema: StrRef,
table: StrRef,
alias: StrRef,
index: u32,
columns: Slice,
},
Dummy,
Values {
index: u32,
columns: Slice,
rows: Slice,
},
TableFunction {
index: u32,
function: StrRef,
args: Slice,
columns: Slice,
},
Filter {
input: NodeRef,
predicate: ExprRef,
},
Project {
input: NodeRef,
index: u32,
exprs: Slice,
names: Slice,
},
Aggregate {
input: NodeRef,
index: u32,
groups: Slice,
aggregates: Slice,
},
Sort {
input: NodeRef,
keys: Slice,
},
Limit {
input: NodeRef,
count: Option<u64>,
offset: u64,
},
Distinct {
input: NodeRef,
on: Slice,
},
Join {
left: NodeRef,
right: NodeRef,
kind: JoinKind,
conditions: Slice,
},
CrossProduct {
left: NodeRef,
right: NodeRef,
},
SetOp {
left: NodeRef,
right: NodeRef,
kind: SetOpKind,
all: bool,
index: u32,
},
}Expand description
One logical operator.
Children are the inputs, in the order Node::children returns them, which is the order they
print in and the order the reader expects.
Variants§
Get
A base table scan.
The projection is in columns, so a scan of two columns of a 105-column table is a two
column scan in the plan and not a filter over a wide one. spec/09-optimizer.md section
9.2 calls projection pushdown the difference between 20 GB and 200 MB on ClickBench, and
this is the field it pushes into.
Fields
Dummy
One row and no columns.
What SELECT 1 sits on top of. Not an empty result: an empty result produces no rows and
SELECT 1 produces one, and conflating them is how a scalar subquery starts returning
nothing instead of null.
Values
Literal rows.
Every row has the same length as columns, which Plan::validate
checks, because a ragged VALUES is a wrong answer rather than a crash.
Fields
TableFunction
A function call where a table goes, such as range(10).
The arguments are expressions rather than numbers, because range(2 + 3) is a legal call
and folding it here would mean the plan could not be printed back as what was written. They
cannot refer to a column: a table function that sees the row on its left is LATERAL, which
is a different node and is not here yet.
A separate node from Node::Values even though range(3) and VALUES (0), (1), (2)
produce the same rows, because the one that produces three million rows should be three
numbers in the plan rather than three million expressions in it.
Fields
Filter
A predicate over the input, keeping the rows where it is true.
True, not “not false”. A null predicate drops the row, which is SQL’s rule and is the
difference between WHERE and CHECK.
Project
A projection, producing a new set of columns from the input’s.
Fields
Aggregate
A grouped or ungrouped aggregation.
The output is the group expressions followed by the aggregates, in that order, and that is
what a binding into index means. An ungrouped aggregate has an empty groups and still
produces exactly one row, including over an empty input.
Fields
aggregates: SliceThe aggregate expressions, into the expression list pool. Every element is an
Expr::Aggregate and this is the only place one may appear.
Sort
An ordering.
Limit
A row count limit and an offset.
Both are constants. LIMIT over an expression is legal SQL and DuckDB evaluates it before
the plan runs, so by the time it is here it is a number or the query did not bind.
Fields
Distinct
Duplicate elimination, over the whole row or over named expressions.
Fields
Join
A join with a condition.
Fields
CrossProduct
An unconditional cross product.
Separate from a Node::Join with no conditions because join ordering treats them
differently: a cross product has no edge in the join graph and section 9.4’s dynamic
program enumerates connected subgraphs.
SetOp
UNION, EXCEPT or INTERSECT.
Implementations§
Source§impl Node
impl Node
Sourcepub fn keyword(&self) -> &'static str
pub fn keyword(&self) -> &'static str
The keyword this operator prints as, which is also what the reader dispatches on.
Sourcepub fn children(&self) -> [Option<NodeRef>; 2]
pub fn children(&self) -> [Option<NodeRef>; 2]
The inputs, in printing order.
Two slots rather than a Vec, because no logical operator in this set has three inputs and
the printer walks this on every node of every dump. A caller wants
node.children().into_iter().flatten().
Sourcepub fn table_index(&self) -> Option<u32>
pub fn table_index(&self) -> Option<u32>
The table index this operator introduces, if it introduces one.