pub trait ScalarFnVTable:
'static
+ Sized
+ Clone
+ Send
+ Sync {
type Options: 'static + Send + Sync + Clone + Debug + Display + PartialEq + Eq + Hash;
Show 15 methods
// Required methods
fn id(&self) -> ScalarFnId;
fn arity(&self, options: &Self::Options) -> Arity;
fn child_name(&self, options: &Self::Options, child_idx: usize) -> ChildName;
fn return_dtype(
&self,
options: &Self::Options,
args: &[DType],
) -> VortexResult<DType>;
fn execute(
&self,
options: &Self::Options,
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef>;
// Provided methods
fn serialize(
&self,
options: &Self::Options,
) -> VortexResult<Option<Vec<u8>>> { ... }
fn deserialize(
&self,
_metadata: &[u8],
_session: &VortexSession,
) -> VortexResult<Self::Options> { ... }
fn fmt_sql(
&self,
options: &Self::Options,
expr: &dyn ExprDisplay,
f: &mut Formatter<'_>,
) -> Result { ... }
fn coerce_args(
&self,
options: &Self::Options,
args: &[DType],
) -> VortexResult<Vec<DType>> { ... }
fn reduce(
&self,
options: &Self::Options,
node: &dyn ReduceNode,
ctx: &dyn ReduceCtx,
) -> VortexResult<Option<ReduceNodeRef>> { ... }
fn simplify(
&self,
options: &Self::Options,
expr: &Expression,
ctx: &dyn SimplifyCtx,
) -> VortexResult<Option<Expression>> { ... }
fn simplify_untyped(
&self,
options: &Self::Options,
expr: &Expression,
) -> VortexResult<Option<Expression>> { ... }
fn validity(
&self,
options: &Self::Options,
expression: &Expression,
) -> VortexResult<Option<Expression>> { ... }
fn is_strict(&self, options: &Self::Options) -> bool { ... }
fn is_fallible(&self, options: &Self::Options) -> bool { ... }
}Expand description
This trait defines the interface for scalar function vtables, including methods for serialization, deserialization, validation, child naming, return type computation, and evaluation.
This trait is non-object safe and allows the implementer to make use of associated types for improved type safety, while allowing Vortex to enforce runtime checks on the inputs and outputs of each function.
The ScalarFnVTable trait should be implemented for a struct that holds global data across
all instances of the expression. In almost all cases, this struct will be an empty unit
struct, since most expressions do not require any global state.
Required Associated Types§
Required Methods§
Sourcefn id(&self) -> ScalarFnId
fn id(&self) -> ScalarFnId
Returns the ID of the scalar function vtable.
Sourcefn child_name(&self, options: &Self::Options, child_idx: usize) -> ChildName
fn child_name(&self, options: &Self::Options, child_idx: usize) -> ChildName
Returns the name of the nth child of the expr.
Sourcefn return_dtype(
&self,
options: &Self::Options,
args: &[DType],
) -> VortexResult<DType>
fn return_dtype( &self, options: &Self::Options, args: &[DType], ) -> VortexResult<DType>
Compute the return DType of the expression if evaluated over the given input types.
§Preconditions
The length of args must match the Arity of this function. Callers are responsible
for validating this (e.g., Expression::try_new checks arity at construction time).
Implementations may assume correct arity and will panic or return nonsensical results if
violated.
Sourcefn execute(
&self,
options: &Self::Options,
args: &dyn ExecutionArgs,
ctx: &mut ExecutionCtx,
) -> VortexResult<ArrayRef>
fn execute( &self, options: &Self::Options, args: &dyn ExecutionArgs, ctx: &mut ExecutionCtx, ) -> VortexResult<ArrayRef>
Execute the expression over the input arguments.
Implementations are encouraged to check their inputs for constant arrays to perform more optimized execution.
If the input arguments cannot be directly used for execution (for example, an expression
may require canonical input arrays), then the implementation should perform a single
child execution and return a new crate::arrays::ScalarFnArray wrapping up the new child.
This provides maximum opportunities for array-level optimizations using execute_parent kernels.
Provided Methods§
Sourcefn serialize(&self, options: &Self::Options) -> VortexResult<Option<Vec<u8>>>
fn serialize(&self, options: &Self::Options) -> VortexResult<Option<Vec<u8>>>
Serialize the options for this expression.
Should return Ok(None) if the expression is not serializable, and Ok(vec![]) if it is
serializable but has no metadata.
Sourcefn deserialize(
&self,
_metadata: &[u8],
_session: &VortexSession,
) -> VortexResult<Self::Options>
fn deserialize( &self, _metadata: &[u8], _session: &VortexSession, ) -> VortexResult<Self::Options>
Deserialize the options of this expression.
Sourcefn fmt_sql(
&self,
options: &Self::Options,
expr: &dyn ExprDisplay,
f: &mut Formatter<'_>,
) -> Result
fn fmt_sql( &self, options: &Self::Options, expr: &dyn ExprDisplay, f: &mut Formatter<'_>, ) -> Result
Format an expression tree in a human-readable SQL-style format.
The expression may be either an Expression or a
bound expression.
Sourcefn coerce_args(
&self,
options: &Self::Options,
args: &[DType],
) -> VortexResult<Vec<DType>>
fn coerce_args( &self, options: &Self::Options, args: &[DType], ) -> VortexResult<Vec<DType>>
Coerce the arguments of this function.
This is optionally used by Vortex users when performing type coercion over a Vortex expression. Note that direct Vortex query engine integrations (e.g. DuckDB, DataFusion, etc.) do not perform type coercion and rely on the engine’s own logical planner.
Note that the default implementation simply returns the arguments without coercion, and it
is expected that the ScalarFnVTable::return_dtype call may still fail.
Sourcefn reduce(
&self,
options: &Self::Options,
node: &dyn ReduceNode,
ctx: &dyn ReduceCtx,
) -> VortexResult<Option<ReduceNodeRef>>
fn reduce( &self, options: &Self::Options, node: &dyn ReduceNode, ctx: &dyn ReduceCtx, ) -> VortexResult<Option<ReduceNodeRef>>
Implement an abstract reduction rule over a tree of scalar functions.
The ReduceNode can be used to traverse children, inspect their types, and
construct the result expression.
Return Ok(None) if no reduction is possible.
Sourcefn simplify(
&self,
options: &Self::Options,
expr: &Expression,
ctx: &dyn SimplifyCtx,
) -> VortexResult<Option<Expression>>
fn simplify( &self, options: &Self::Options, expr: &Expression, ctx: &dyn SimplifyCtx, ) -> VortexResult<Option<Expression>>
Simplify the expression if possible.
Sourcefn simplify_untyped(
&self,
options: &Self::Options,
expr: &Expression,
) -> VortexResult<Option<Expression>>
fn simplify_untyped( &self, options: &Self::Options, expr: &Expression, ) -> VortexResult<Option<Expression>>
Simplify the expression if possible, without type information.
Sourcefn validity(
&self,
options: &Self::Options,
expression: &Expression,
) -> VortexResult<Option<Expression>>
fn validity( &self, options: &Self::Options, expression: &Expression, ) -> VortexResult<Option<Expression>>
Returns an expression that evaluates to the validity of the result of this expression.
If a validity expression cannot be constructed, returns None and the expression will
be evaluated as normal before extracting the validity mask from the result.
This is essentially a specialized form of a reduce_parent
Sourcefn is_strict(&self, options: &Self::Options) -> bool
fn is_strict(&self, options: &Self::Options) -> bool
Returns whether this scalar function is strict.
A strict function returns null for a row when any argument is null for that row. This
matches PostgreSQL’s STRICT convention
for null propagation.
Return true only when this holds for every argument. add is strict, but Kleene AND
is not because false AND null returns false. is_null is also not strict.
Strictness does not require valid inputs to produce a valid output. For example,
crate::expr::list_sum returns null for a valid empty list. Implement
ScalarFnVTable::validity only when the output validity can be derived without
evaluation.
ScalarFnVTable::return_dtype must return a nullable output dtype when any input dtype is
nullable. A cast that forces a non-nullable output dtype is therefore not strict.
This property applies only to the scalar function, not its child expressions. Nullary
functions are vacuously strict. The default is conservatively false.
Sourcefn is_fallible(&self, options: &Self::Options) -> bool
fn is_fallible(&self, options: &Self::Options) -> bool
Returns whether this scalar function can raise a semantic error.
Return true if a well-typed call can error because of its values. checked_add is
fallible on integer overflow, and integer division is fallible when its divisor is zero.
A null result is not an error: crate::expr::list_sum is infallible for an empty list.
Exclude incidental execution errors, such as canonicalization failures, allocation errors, and encoding mismatches. They are not part of the function’s semantics.
Returning false permits optimizations that evaluate the function over values that no input
row references. Dictionary push-down, for example, evaluates every dictionary value, so a
fallible function could error on a value that row-wise evaluation would never reach.
This applies only to the scalar function, not its child expressions, and only to inputs
accepted by ScalarFnVTable::return_dtype. The default is conservatively true.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".