1use std::borrow::Cow;
5use std::fmt;
6use std::fmt::Debug;
7use std::fmt::Display;
8use std::fmt::Formatter;
9use std::hash::Hash;
10
11use arcref::ArcRef;
12use vortex_error::VortexExpect;
13use vortex_error::VortexResult;
14use vortex_error::vortex_bail;
15use vortex_error::vortex_err;
16use vortex_session::VortexSession;
17use vortex_utils::iter::ReduceBalancedIterExt;
18
19use crate::ArrayRef;
20use crate::ExecutionCtx;
21use crate::IntoArray;
22use crate::arrays::ConstantArray;
23use crate::arrays::ScalarFn;
24use crate::arrays::ScalarFnArray;
25use crate::dtype::DType;
26use crate::expr::BoundExpression;
27use crate::expr::Expression;
28use crate::expr::bound;
29use crate::expr::display::ExprDisplay;
30use crate::scalar::Scalar;
31use crate::scalar_fn::ScalarFnId;
32use crate::scalar_fn::ScalarFnRef;
33use crate::scalar_fn::TypedScalarFnInstance;
34use crate::scalar_fn::fns::binary::Binary;
35use crate::scalar_fn::fns::is_not_null::IsNotNull;
36use crate::scalar_fn::fns::literal::Literal;
37use crate::scalar_fn::fns::operators::Operator;
38use crate::validity::Validity;
39
40#[derive(Clone)]
42pub enum ReduceNodeValidity<T: ReduceNode> {
43 Reduced(T),
49 Irreducible,
57}
58
59pub(crate) fn is_not_null_node<T: ReduceNode>(child: &T) -> VortexResult<T> {
61 child.new_node(IsNotNull.bind(EmptyOptions), std::slice::from_ref(child))
62}
63
64pub fn union_child_validities<T: ReduceNode>(node: &T) -> VortexResult<T> {
66 let mut parts = Vec::with_capacity(node.child_count());
67 for i in 0..node.child_count() {
68 let child = node.child(i);
69 if child.node_dtype()?.is_nullable() {
70 parts.push(is_not_null_node(&child)?);
71 }
72 }
73 let parts = parts
74 .into_iter()
75 .try_reduce_balanced(|lhs, rhs| {
76 lhs.new_node(Binary.bind(Operator::And), &[lhs.clone(), rhs])
77 })?
78 .unwrap_or_else(|| node.new_constant(true.into()));
79 Ok(parts)
80}
81
82pub trait ScalarFnVTable: 'static + Sized + Clone + Send + Sync {
94 type Options: 'static + Send + Sync + Clone + Debug + Display + PartialEq + Eq + Hash;
96
97 fn id(&self) -> ScalarFnId;
99
100 fn serialize(&self, options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
105 _ = options;
106 Ok(None)
107 }
108
109 fn deserialize(
111 &self,
112 _metadata: &[u8],
113 _session: &VortexSession,
114 ) -> VortexResult<Self::Options> {
115 vortex_bail!("Expression {} is not deserializable", self.id());
116 }
117
118 fn arity(&self, options: &Self::Options) -> Arity;
120
121 fn child_name(&self, options: &Self::Options, child_idx: usize) -> ChildName;
123
124 fn fmt_sql(
129 &self,
130 options: &Self::Options,
131 expr: &dyn ExprDisplay,
132 f: &mut Formatter<'_>,
133 ) -> fmt::Result {
134 write!(f, "{}(", self.id())?;
135 let nchildren = expr.display_children_count();
136 for i in 0..nchildren {
137 Display::fmt(expr.display_child(i), f)?;
138 if i + 1 < nchildren {
139 write!(f, ", ")?;
140 }
141 }
142 let opts = format!("{}", options);
143 if !opts.is_empty() {
144 write!(f, ", opts={}", opts)?;
145 }
146 write!(f, ")")
147 }
148
149 fn return_dtype(&self, options: &Self::Options, args: &[DType]) -> VortexResult<DType>;
160
161 fn execute(
173 &self,
174 options: &Self::Options,
175 args: &dyn ExecutionArgs,
176 ctx: &mut ExecutionCtx,
177 ) -> VortexResult<ArrayRef>;
178
179 fn reduce<T: ReduceNode>(&self, options: &Self::Options, node: &T) -> VortexResult<Option<T>> {
187 _ = options;
188 _ = node;
189 Ok(None)
190 }
191
192 fn validity<T: ReduceNode>(
197 &self,
198 options: &Self::Options,
199 node: &T,
200 ) -> VortexResult<ReduceNodeValidity<T>> {
201 if !self.is_strict(options) {
202 return Ok(ReduceNodeValidity::Irreducible);
203 }
204
205 let mut dtypes = Vec::with_capacity(node.child_count());
206 for i in 0..node.child_count() {
207 let dtype = node.child(i).node_dtype()?;
208 if matches!(dtype, DType::Null) {
209 return Ok(ReduceNodeValidity::Irreducible);
210 }
211 dtypes.push(dtype.as_nonnullable());
212 }
213
214 let res = if let Ok(dtype) = self.return_dtype(options, &dtypes)
215 && !dtype.is_nullable()
216 {
217 ReduceNodeValidity::Reduced(union_child_validities(node)?)
218 } else {
219 ReduceNodeValidity::Irreducible
220 };
221 Ok(res)
222 }
223
224 fn simplify(
228 &self,
229 options: &Self::Options,
230 expr: &BoundExpression,
231 ) -> VortexResult<Option<BoundExpression>> {
232 _ = options;
233 _ = expr;
234 Ok(None)
235 }
236
237 fn is_strict(&self, options: &Self::Options) -> bool {
257 _ = options;
258 false
259 }
260
261 fn is_infallible(&self, options: &Self::Options) -> bool {
277 _ = options;
278 false
279 }
280}
281
282pub trait ReduceNode: Clone {
290 fn node_dtype(&self) -> VortexResult<DType>;
292
293 fn scalar_fn(&self) -> Option<&ScalarFnRef>;
295
296 fn child(&self, idx: usize) -> Self;
298
299 fn child_count(&self) -> usize;
301
302 fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self>;
305
306 fn as_constant(&self) -> Option<Scalar> {
308 None
309 }
310
311 fn new_constant(&self, value: Scalar) -> Self;
313
314 fn validity(&self) -> VortexResult<ReduceNodeValidity<Self>>
318 where
319 Self: Sized;
320}
321
322#[derive(Clone)]
324pub struct ExpressionReduceNode<'a> {
325 expression: Cow<'a, BoundExpression>,
326}
327
328impl<'a> ExpressionReduceNode<'a> {
329 pub fn new(expression: &'a BoundExpression) -> Self {
331 Self {
332 expression: Cow::Borrowed(expression),
333 }
334 }
335
336 pub fn expression(&self) -> &BoundExpression {
338 &self.expression
339 }
340
341 pub fn into_expression(self) -> BoundExpression {
343 self.expression.into_owned()
344 }
345}
346
347impl ReduceNode for ExpressionReduceNode<'_> {
348 fn node_dtype(&self) -> VortexResult<DType> {
349 Ok(self.expression.dtype().clone())
350 }
351
352 fn scalar_fn(&self) -> Option<&ScalarFnRef> {
353 self.expression.as_scalar()
354 }
355
356 fn child(&self, idx: usize) -> Self {
357 let expression = match &self.expression {
358 Cow::Borrowed(expression) => Cow::Borrowed(expression.child(idx)),
359 Cow::Owned(expression) => Cow::Owned(expression.child(idx).clone()),
360 };
361 Self { expression }
362 }
363
364 fn child_count(&self) -> usize {
365 self.expression.children().len()
366 }
367
368 fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self> {
369 let expression = BoundExpression::try_new(
370 scalar_fn,
371 children.iter().map(|c| c.expression.as_ref().clone()),
372 )?;
373 Ok(Self {
374 expression: Cow::Owned(expression),
375 })
376 }
377
378 fn as_constant(&self) -> Option<Scalar> {
379 self.expression.as_opt::<Literal>().cloned()
380 }
381
382 fn new_constant(&self, value: Scalar) -> Self {
383 Self {
384 expression: Cow::Owned(bound::lit(value)),
385 }
386 }
387
388 fn validity(&self) -> VortexResult<ReduceNodeValidity<Self>> {
389 match self.expression.as_scalar() {
390 Some(scalar_fn) => scalar_fn.validity_expression(self),
391 None => Ok(ReduceNodeValidity::Irreducible),
392 }
393 }
394}
395
396#[derive(Clone)]
398pub struct ArrayReduceNode<'a> {
399 array: Cow<'a, ArrayRef>,
400}
401
402impl<'a> ArrayReduceNode<'a> {
403 pub fn new(array: &'a ArrayRef) -> Self {
405 Self {
406 array: Cow::Borrowed(array),
407 }
408 }
409
410 pub fn array(&self) -> &ArrayRef {
412 &self.array
413 }
414
415 pub fn into_array(self) -> ArrayRef {
417 self.array.into_owned()
418 }
419}
420
421impl ReduceNode for ArrayReduceNode<'_> {
422 fn node_dtype(&self) -> VortexResult<DType> {
423 Ok(self.array.dtype().clone())
424 }
425
426 fn scalar_fn(&self) -> Option<&ScalarFnRef> {
427 self.array
428 .as_opt::<ScalarFn>()
429 .map(|a| a.data().scalar_fn())
430 }
431
432 fn child(&self, idx: usize) -> Self {
433 let array = match &self.array {
434 Cow::Borrowed(array) => Cow::Borrowed(
435 array
436 .nth_child(idx)
437 .vortex_expect("child idx out of bounds"),
438 ),
439 Cow::Owned(array) => Cow::Owned(
440 array
441 .nth_child(idx)
442 .vortex_expect("child idx out of bounds")
443 .clone(),
444 ),
445 };
446 Self { array }
447 }
448
449 fn child_count(&self) -> usize {
450 self.array.nchildren()
451 }
452
453 fn new_node(&self, scalar_fn: ScalarFnRef, children: &[Self]) -> VortexResult<Self> {
454 let array = ScalarFnArray::try_new_with_len(
455 scalar_fn,
456 children.iter().map(|c| c.array.as_ref().clone()).collect(),
457 self.array.len(),
458 )?;
459 Ok(Self {
460 array: Cow::Owned(array.into_array()),
461 })
462 }
463
464 fn as_constant(&self) -> Option<Scalar> {
465 self.array.as_constant()
466 }
467
468 fn new_constant(&self, value: Scalar) -> Self {
469 let array = ConstantArray::new(value, self.array.len());
470 Self {
471 array: Cow::Owned(array.into_array()),
472 }
473 }
474
475 fn validity(&self) -> VortexResult<ReduceNodeValidity<Self>> {
476 if let Some(scalar_fn) = self.array.as_opt::<ScalarFn>() {
477 return scalar_fn.data().scalar_fn().validity_array(self);
478 }
479 Ok(ReduceNodeValidity::Reduced(
480 match self.array.validity()? {
481 Validity::NonNullable | Validity::AllValid => self.new_constant(true.into()),
482 Validity::AllInvalid => self.new_constant(false.into()),
483 Validity::Array(array) => Self {
484 array: Cow::Owned(array),
485 },
486 },
487 ))
488 }
489}
490
491#[derive(Clone, Copy, Debug, PartialEq, Eq)]
493pub enum Arity {
494 Exact(usize),
495 Variadic { min: usize, max: Option<usize> },
496}
497
498impl Display for Arity {
499 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
500 match self {
501 Arity::Exact(n) => write!(f, "{}", n),
502 Arity::Variadic { min, max } => match max {
503 Some(max) if min == max => write!(f, "{}", min),
504 Some(max) => write!(f, "{}..{}", min, max),
505 None => write!(f, "{}+", min),
506 },
507 }
508 }
509}
510
511impl Arity {
512 pub fn matches(&self, arg_count: usize) -> bool {
514 match self {
515 Arity::Exact(m) => *m == arg_count,
516 Arity::Variadic { min, max } => {
517 if arg_count < *min {
518 return false;
519 }
520 if let Some(max) = max
521 && arg_count > *max
522 {
523 return false;
524 }
525 true
526 }
527 }
528 }
529}
530
531pub trait ExecutionArgs {
533 fn get(&self, index: usize) -> VortexResult<ArrayRef>;
535
536 fn num_inputs(&self) -> usize;
538
539 fn row_count(&self) -> usize;
541}
542
543pub struct VecExecutionArgs {
545 inputs: Vec<ArrayRef>,
546 row_count: usize,
547}
548
549impl VecExecutionArgs {
550 pub fn new(inputs: Vec<ArrayRef>, row_count: usize) -> Self {
552 Self { inputs, row_count }
553 }
554}
555
556impl ExecutionArgs for VecExecutionArgs {
557 fn get(&self, index: usize) -> VortexResult<ArrayRef> {
558 self.inputs.get(index).cloned().ok_or_else(|| {
559 vortex_err!(
560 "Input index {} out of bounds (num_inputs={})",
561 index,
562 self.inputs.len()
563 )
564 })
565 }
566
567 fn num_inputs(&self) -> usize {
568 self.inputs.len()
569 }
570
571 fn row_count(&self) -> usize {
572 self.row_count
573 }
574}
575
576#[derive(Clone, Debug, PartialEq, Eq, Hash)]
577pub struct EmptyOptions;
578impl Display for EmptyOptions {
579 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
580 write!(f, "")
581 }
582}
583
584pub trait ScalarFnVTableExt: ScalarFnVTable {
586 fn bind(&self, options: Self::Options) -> ScalarFnRef {
588 TypedScalarFnInstance::new(self.clone(), options).erased()
589 }
590
591 fn new_expr(
593 &self,
594 options: Self::Options,
595 children: impl IntoIterator<Item = Expression>,
596 ) -> Expression {
597 Self::try_new_expr(self, options, children).vortex_expect("Failed to create expression")
598 }
599
600 fn try_new_expr(
602 &self,
603 options: Self::Options,
604 children: impl IntoIterator<Item = Expression>,
605 ) -> VortexResult<Expression> {
606 Expression::try_new(self.bind(options), children)
607 }
608
609 fn try_new_bound_expr(
611 &self,
612 options: Self::Options,
613 children: impl IntoIterator<Item = BoundExpression>,
614 ) -> VortexResult<BoundExpression> {
615 BoundExpression::try_new(self.bind(options), children)
616 }
617}
618impl<V: ScalarFnVTable> ScalarFnVTableExt for V {}
619
620pub type ChildName = ArcRef<str>;