pub struct Prepared { /* private fields */ }Expand description
One or more bound expressions, flattened and resolved against a schema.
Built once per pipeline with Prepared::new and evaluated per chunk with
Prepared::evaluate or Prepared::evaluate_one, each of which wants the Scratch that
Prepared::scratch hands out.
Implementations§
Source§impl Prepared
impl Prepared
Sourcepub fn new(plan: &Plan, exprs: &[ExprRef], schema: &Schema) -> Result<Self>
pub fn new(plan: &Plan, exprs: &[ExprRef], schema: &Schema) -> Result<Self>
Prepares exprs against schema.
§Errors
If a column reference names a binding the schema does not have, or if an aggregate appears where an ordinary expression was expected. Both are failures of the plan rather than of the data, which is why they are found here, once, rather than on some chunk in the middle of a scan.
Sourcepub fn one(plan: &Plan, expr: ExprRef, schema: &Schema) -> Result<Self>
pub fn one(plan: &Plan, expr: ExprRef, schema: &Schema) -> Result<Self>
Prepares one expression, which is the common case and saves the caller a slice.
§Errors
Whatever Prepared::new reports.
Sourcepub fn evaluate(
&self,
chunk: &Chunk,
scratch: &mut Scratch,
out: &mut Vec<Vector>,
) -> Result<()>
pub fn evaluate( &self, chunk: &Chunk, scratch: &mut Scratch, out: &mut Vec<Vector>, ) -> Result<()>
Evaluates every expression over chunk, appending one vector each to out.
Appends rather than returns a Vec, so a caller in a loop reuses one buffer.
§Errors
Anything a kernel reports, on the first expression that reports it.
Sourcepub fn evaluate_one<'s>(
&'s self,
chunk: &'s Chunk,
scratch: &'s mut Scratch,
) -> Result<&'s Vector>
pub fn evaluate_one<'s>( &'s self, chunk: &'s Chunk, scratch: &'s mut Scratch, ) -> Result<&'s Vector>
Evaluates a single expression over chunk, handing back a reference to the answer.
A reference rather than a vector, because the caller of this is a filter, which reads the
flags to build a selection and then drops them. Nothing about that wants ownership, and a
predicate that is a bare column reference, which WHERE flag is, would otherwise copy the
column to hand it over.
§Errors
Anything a kernel reports, and an internal error if this was not built from exactly one expression.
Sourcepub fn evaluate_filter(
&self,
chunk: &Chunk,
scratch: &mut Scratch,
) -> Result<Selection>
pub fn evaluate_filter( &self, chunk: &Chunk, scratch: &mut Scratch, ) -> Result<Selection>
Evaluates a single expression as a filter, handing back the rows it keeps.
The difference between this and evaluate_one followed by
selection is the whole of what a threaded filter is. An AND evaluated as an expression
runs every conjunct over every row and then combines the flag vectors, so a predicate of four
conjuncts that each pass a fifth of the rows does five times the work of one that stops
looking at a row as soon as a conjunct rejects it. TPC-H Q6 is exactly that predicate.
So the conjuncts of a top level AND are run one at a time, each over the rows the ones
before it left, and the moment nothing is left the rest of the predicate is not run at all.
The order they run in starts as the order the plan gives and then moves, because which
conjunct is worth running first is a question about the data and the scan is the thing
holding the answer. The ordering module has what is measured and how.
A top level OR is threaded the same way against the complement. A row the first branch
accepts is a row the filter keeps whatever the rest of the predicate says about it, so each
branch is run over the rows no branch before it accepted, and the moment every row has been
accepted the rest of the predicate is not run either. That is the mirror of the AND case
and not an approximation of it: the answer is the same set of rows, because OR over three
valued logic is true wherever any branch is true and nothing a later branch says can take a
row back. It is worth less than the AND case in practice, since an OR of selective
branches leaves almost every row in play for the branch after, and it is worth having anyway
because the cost of finding that out is one merge per branch.
What is threaded is the operand’s own comparison rather than the whole of its subtree. A
conjunct of a + b > 5 still adds over the whole chunk, because the scalar kernels take a
vector rather than a selection, and it is the comparison and everything downstream of it that
reads only the rows still in play. An operand that is a bare column or a function produces
flags over the chunk and is narrowed with refine_flags, which is what keeps one awkward
operand from putting the others back on the unthreaded path. An operand that is itself a
connective recurses, so the two conjuncts of each half of (a AND b) OR (c AND d) are
threaded the same way the halves are.
None of this is available to a projection. SELECT a > 5 AND b LIKE 'x%' wants a value per
row and the rows a selection dropped have no value in it, so evaluate and
evaluate_one evaluate the whole tree over the whole chunk and combine
flags. The two are separate entry points picked when the pipeline is built rather than one
path with a flag in it, because conflating them is a wrong answer rather than a slow one.
§Errors
Anything a kernel reports, and an internal error if this was not built from exactly one expression.