1mod literal_lookup_table;
19
20use super::{Column, Literal};
21use crate::PhysicalExpr;
22use crate::expressions::{
23 CastExpr, LambdaVariable, NegativeExpr, NotExpr, lit, try_cast,
24};
25use arrow::array::*;
26use arrow::compute::kernels::zip::zip;
27use arrow::compute::{
28 FilterBuilder, FilterPredicate, is_not_null, not, nullif, prep_null_mask_filter,
29};
30use arrow::datatypes::{DataType, Schema, UInt32Type, UnionMode};
31use arrow::error::ArrowError;
32use datafusion_common::cast::as_boolean_array;
33use datafusion_common::{
34 DataFusionError, Result, ScalarValue, assert_or_internal_err, exec_err,
35 internal_datafusion_err, internal_err,
36};
37use datafusion_expr::ColumnarValue;
38use indexmap::IndexMap;
39use std::borrow::Cow;
40use std::collections::BTreeSet;
41use std::hash::Hash;
42use std::sync::Arc;
43
44use crate::expressions::case::literal_lookup_table::LiteralLookupTable;
45use arrow::compute::kernels::merge::{MergeIndex, merge, merge_n};
46use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRecursion};
47use datafusion_physical_expr_common::datum::compare_with_eq;
48use datafusion_physical_expr_common::utils::scatter;
49use itertools::Itertools;
50use std::fmt::{Debug, Formatter};
51
52pub(super) type WhenThen = (Arc<dyn PhysicalExpr>, Arc<dyn PhysicalExpr>);
53
54#[derive(Debug, Hash, PartialEq, Eq)]
55enum EvalMethod {
56 NoExpression(ProjectedCaseBody),
61 WithExpression(ProjectedCaseBody),
67 InfallibleExprOrNull,
73 ScalarOrScalar,
78 ExpressionOrExpression(ProjectedCaseBody),
87
88 WithExprScalarLookupTable(LiteralLookupTable),
92}
93
94impl Hash for LiteralLookupTable {
101 fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {}
102}
103
104impl PartialEq for LiteralLookupTable {
111 fn eq(&self, _other: &Self) -> bool {
112 true
113 }
114}
115
116impl Eq for LiteralLookupTable {}
117
118#[derive(Debug, Hash, PartialEq, Eq)]
121struct CaseBody {
122 expr: Option<Arc<dyn PhysicalExpr>>,
124 when_then_expr: Vec<WhenThen>,
126 else_expr: Option<Arc<dyn PhysicalExpr>>,
128}
129
130impl CaseBody {
131 fn project(&self) -> Result<ProjectedCaseBody> {
133 let mut used_column_indices = BTreeSet::<usize>::new();
136 let mut collect_column_indices = |expr: &Arc<dyn PhysicalExpr>| {
137 expr.apply(|expr| {
138 if let Some(column) = expr.downcast_ref::<Column>() {
139 used_column_indices.insert(column.index());
140 } else if let Some(lambda_variable) =
141 expr.downcast_ref::<LambdaVariable>()
142 {
143 used_column_indices.insert(lambda_variable.index());
144 }
145 Ok(TreeNodeRecursion::Continue)
146 })
147 .expect("Closure cannot fail");
148 };
149
150 if let Some(e) = &self.expr {
151 collect_column_indices(e);
152 }
153 self.when_then_expr.iter().for_each(|(w, t)| {
154 collect_column_indices(w);
155 collect_column_indices(t);
156 });
157 if let Some(e) = &self.else_expr {
158 collect_column_indices(e);
159 }
160
161 let column_index_map = used_column_indices
163 .iter()
164 .enumerate()
165 .map(|(projected, original)| (*original, projected))
166 .collect::<IndexMap<usize, usize>>();
167
168 let project = |expr: &Arc<dyn PhysicalExpr>| -> Result<Arc<dyn PhysicalExpr>> {
171 Arc::clone(expr)
172 .transform_down(|e| {
173 if let Some(column) = e.downcast_ref::<Column>() {
174 let original = column.index();
175 let projected = *column_index_map.get(&original).unwrap();
176 if projected != original {
177 return Ok(Transformed::yes(Arc::new(Column::new(
178 column.name(),
179 projected,
180 ))));
181 }
182 } else if let Some(lambda_variable) =
183 e.downcast_ref::<LambdaVariable>()
184 {
185 let original = lambda_variable.index();
186 let projected = *column_index_map.get(&original).unwrap();
187 if projected != original {
188 return Ok(Transformed::yes(Arc::new(LambdaVariable::new(
189 projected,
190 Arc::clone(lambda_variable.field()),
191 ))));
192 }
193 }
194 Ok(Transformed::no(e))
195 })
196 .map(|t| t.data)
197 };
198
199 let projected_body = CaseBody {
200 expr: self.expr.as_ref().map(project).transpose()?,
201 when_then_expr: self
202 .when_then_expr
203 .iter()
204 .map(|(e, t)| Ok((project(e)?, project(t)?)))
205 .collect::<Result<Vec<_>>>()?,
206 else_expr: self.else_expr.as_ref().map(project).transpose()?,
207 };
208
209 let projection = column_index_map
211 .iter()
212 .sorted_by_key(|(_, v)| **v)
213 .map(|(k, _)| *k)
214 .collect::<Vec<_>>();
215
216 Ok(ProjectedCaseBody {
217 projection,
218 body: projected_body,
219 })
220 }
221}
222
223#[derive(Debug, Hash, PartialEq, Eq)]
251struct ProjectedCaseBody {
252 projection: Vec<usize>,
253 body: CaseBody,
254}
255
256#[derive(Debug)]
274pub struct CaseExpr {
275 body: CaseBody,
277 eval_method: EvalMethod,
279}
280
281impl Hash for CaseExpr {
285 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
286 self.body.hash(state);
287 }
288}
289
290impl PartialEq for CaseExpr {
291 fn eq(&self, other: &Self) -> bool {
292 self.body == other.body
293 }
294}
295
296impl Eq for CaseExpr {}
297
298impl std::fmt::Display for CaseExpr {
299 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
300 write!(f, "CASE ")?;
301 if let Some(e) = &self.body.expr {
302 write!(f, "{e} ")?;
303 }
304 for (w, t) in &self.body.when_then_expr {
305 write!(f, "WHEN {w} THEN {t} ")?;
306 }
307 if let Some(e) = &self.body.else_expr {
308 write!(f, "ELSE {e} ")?;
309 }
310 write!(f, "END")
311 }
312}
313
314fn is_cheap_and_infallible(expr: &Arc<dyn PhysicalExpr>) -> bool {
320 expr.is::<Column>()
321}
322
323fn create_filter(predicate: &BooleanArray, optimize: bool) -> FilterPredicate {
325 let mut filter_builder = FilterBuilder::new(predicate);
326 if optimize {
327 filter_builder = filter_builder.optimize();
329 }
330 filter_builder.build()
331}
332
333fn multiple_arrays(data_type: &DataType) -> bool {
334 match data_type {
335 DataType::Struct(fields) => {
336 fields.len() > 1
337 || fields.len() == 1 && multiple_arrays(fields[0].data_type())
338 }
339 DataType::Union(fields, UnionMode::Sparse) => !fields.is_empty(),
340 _ => false,
341 }
342}
343
344fn filter_record_batch(
347 record_batch: &RecordBatch,
348 filter: &FilterPredicate,
349) -> std::result::Result<RecordBatch, ArrowError> {
350 let filtered_columns = record_batch
351 .columns()
352 .iter()
353 .map(|a| filter_array(a, filter))
354 .collect::<std::result::Result<Vec<_>, _>>()?;
355 unsafe {
361 Ok(RecordBatch::new_unchecked(
362 record_batch.schema(),
363 filtered_columns,
364 filter.count(),
365 ))
366 }
367}
368
369#[inline(always)]
374fn filter_array(
375 array: &dyn Array,
376 filter: &FilterPredicate,
377) -> std::result::Result<ArrayRef, ArrowError> {
378 filter.filter(array)
379}
380
381#[derive(Copy, Clone, PartialEq, Eq)]
386struct PartialResultIndex {
387 index: u32,
388}
389
390const NONE_VALUE: u32 = u32::MAX;
391
392impl PartialResultIndex {
393 fn none() -> Self {
395 Self { index: NONE_VALUE }
396 }
397
398 fn zero() -> Self {
399 Self { index: 0 }
400 }
401
402 fn try_new(index: usize) -> Result<Self> {
407 let Ok(index) = u32::try_from(index) else {
408 return internal_err!("Partial result index exceeds limit");
409 };
410
411 assert_or_internal_err!(
412 index != NONE_VALUE,
413 "Partial result index exceeds limit"
414 );
415
416 Ok(Self { index })
417 }
418
419 fn is_none(&self) -> bool {
421 self.index == NONE_VALUE
422 }
423}
424
425impl MergeIndex for PartialResultIndex {
426 fn index(&self) -> Option<usize> {
428 if self.is_none() {
429 None
430 } else {
431 Some(self.index as usize)
432 }
433 }
434}
435
436impl Debug for PartialResultIndex {
437 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
438 if self.is_none() {
439 write!(f, "null")
440 } else {
441 write!(f, "{}", self.index)
442 }
443 }
444}
445
446enum ResultState {
447 Empty,
449 Partial {
451 arrays: Vec<ArrayRef>,
454 indices: Vec<PartialResultIndex>,
456 },
457 Complete(ColumnarValue),
460}
461
462struct ResultBuilder {
472 data_type: DataType,
473 row_count: usize,
475 state: ResultState,
476}
477
478impl ResultBuilder {
479 fn new(data_type: &DataType, row_count: usize) -> Self {
483 Self {
484 data_type: data_type.clone(),
485 row_count,
486 state: ResultState::Empty,
487 }
488 }
489
490 fn add_branch_result(
523 &mut self,
524 row_indices: &ArrayRef,
525 value: ColumnarValue,
526 ) -> Result<()> {
527 match value {
528 ColumnarValue::Array(a) => {
529 if a.len() != row_indices.len() {
530 internal_err!("Array length must match row indices length")
531 } else if row_indices.len() == self.row_count {
532 self.set_complete_result(ColumnarValue::Array(a))
533 } else {
534 self.add_partial_result(row_indices, a)
535 }
536 }
537 ColumnarValue::Scalar(s) => {
538 if row_indices.len() == self.row_count {
539 self.set_complete_result(ColumnarValue::Scalar(s))
540 } else {
541 self.add_partial_result(
542 row_indices,
543 s.to_array_of_size(row_indices.len())?,
544 )
545 }
546 }
547 }
548 }
549
550 fn add_partial_result(
556 &mut self,
557 row_indices: &ArrayRef,
558 row_values: ArrayRef,
559 ) -> Result<()> {
560 assert_or_internal_err!(
561 row_indices.null_count() == 0,
562 "Row indices must not contain nulls"
563 );
564
565 match &mut self.state {
566 ResultState::Empty => {
567 let array_index = PartialResultIndex::zero();
568 let mut indices = vec![PartialResultIndex::none(); self.row_count];
569 for row_ix in row_indices.as_primitive::<UInt32Type>().values().iter() {
570 indices[*row_ix as usize] = array_index;
571 }
572
573 self.state = ResultState::Partial {
574 arrays: vec![row_values],
575 indices,
576 };
577
578 Ok(())
579 }
580 ResultState::Partial { arrays, indices } => {
581 let array_index = PartialResultIndex::try_new(arrays.len())?;
582
583 arrays.push(row_values);
584
585 for row_ix in row_indices.as_primitive::<UInt32Type>().values().iter() {
586 #[cfg(debug_assertions)]
590 assert_or_internal_err!(
591 indices[*row_ix as usize].is_none(),
592 "Duplicate value for row {}",
593 *row_ix
594 );
595
596 indices[*row_ix as usize] = array_index;
597 }
598 Ok(())
599 }
600 ResultState::Complete(_) => internal_err!(
601 "Cannot add a partial result when complete result is already set"
602 ),
603 }
604 }
605
606 fn set_complete_result(&mut self, value: ColumnarValue) -> Result<()> {
612 match &self.state {
613 ResultState::Empty => {
614 self.state = ResultState::Complete(value);
615 Ok(())
616 }
617 ResultState::Partial { .. } => {
618 internal_err!(
619 "Cannot set a complete result when there are already partial results"
620 )
621 }
622 ResultState::Complete(_) => internal_err!("Complete result already set"),
623 }
624 }
625
626 fn finish(self) -> Result<ColumnarValue> {
628 match self.state {
629 ResultState::Empty => {
630 Ok(ColumnarValue::Scalar(ScalarValue::try_new_null(
634 &self.data_type,
635 )?))
636 }
637 ResultState::Partial { arrays, indices } => {
638 let array_refs = arrays.iter().map(|a| a.as_ref()).collect::<Vec<_>>();
640 Ok(ColumnarValue::Array(merge_n(&array_refs, &indices)?))
641 }
642 ResultState::Complete(v) => {
643 Ok(v)
645 }
646 }
647 }
648}
649
650impl CaseExpr {
651 pub fn try_new(
653 expr: Option<Arc<dyn PhysicalExpr>>,
654 when_then_expr: Vec<WhenThen>,
655 else_expr: Option<Arc<dyn PhysicalExpr>>,
656 ) -> Result<Self> {
657 let else_expr = match &else_expr {
660 Some(e) => match e.downcast_ref::<Literal>() {
661 Some(lit) if lit.value().is_null() => None,
662 _ => else_expr,
663 },
664 _ => else_expr,
665 };
666
667 if when_then_expr.is_empty() {
668 return exec_err!("There must be at least one WHEN clause");
669 }
670
671 let body = CaseBody {
672 expr,
673 when_then_expr,
674 else_expr,
675 };
676
677 let eval_method = Self::find_best_eval_method(&body)?;
678
679 Ok(Self { body, eval_method })
680 }
681
682 fn find_best_eval_method(body: &CaseBody) -> Result<EvalMethod> {
683 if body.expr.is_some() {
684 if let Some(mapping) = LiteralLookupTable::maybe_new(body) {
685 return Ok(EvalMethod::WithExprScalarLookupTable(mapping));
686 }
687
688 return Ok(EvalMethod::WithExpression(body.project()?));
689 }
690
691 Ok(
692 if body.when_then_expr.len() == 1
693 && is_cheap_and_infallible(&(body.when_then_expr[0].1))
694 && body.else_expr.is_none()
695 {
696 EvalMethod::InfallibleExprOrNull
697 } else if body.when_then_expr.len() == 1
698 && body.when_then_expr[0].1.is::<Literal>()
699 && body.else_expr.is_some()
700 && body.else_expr.as_ref().unwrap().is::<Literal>()
701 {
702 EvalMethod::ScalarOrScalar
703 } else if body.when_then_expr.len() == 1 {
704 EvalMethod::ExpressionOrExpression(body.project()?)
705 } else {
706 EvalMethod::NoExpression(body.project()?)
707 },
708 )
709 }
710
711 pub fn expr(&self) -> Option<&Arc<dyn PhysicalExpr>> {
713 self.body.expr.as_ref()
714 }
715
716 pub fn when_then_expr(&self) -> &[WhenThen] {
718 &self.body.when_then_expr
719 }
720
721 pub fn else_expr(&self) -> Option<&Arc<dyn PhysicalExpr>> {
723 self.body.else_expr.as_ref()
724 }
725}
726
727impl CaseBody {
728 fn data_type(&self, input_schema: &Schema) -> Result<DataType> {
729 let mut data_type = DataType::Null;
732 for i in 0..self.when_then_expr.len() {
733 data_type = self.when_then_expr[i].1.data_type(input_schema)?;
734 if !data_type.equals_datatype(&DataType::Null) {
735 break;
736 }
737 }
738 if data_type.equals_datatype(&DataType::Null)
740 && let Some(e) = &self.else_expr
741 {
742 data_type = e.data_type(input_schema)?;
743 }
744
745 Ok(data_type)
746 }
747
748 fn case_when_with_expr(
750 &self,
751 batch: &RecordBatch,
752 return_type: &DataType,
753 ) -> Result<ColumnarValue> {
754 let mut result_builder = ResultBuilder::new(return_type, batch.num_rows());
755
756 let mut remainder_rows: ArrayRef =
758 Arc::new(UInt32Array::from_iter_values(0..batch.num_rows() as u32));
759 let mut remainder_batch = Cow::Borrowed(batch);
761
762 let mut base_values = self
764 .expr
765 .as_ref()
766 .unwrap()
767 .evaluate(batch)?
768 .into_array(batch.num_rows())?;
769
770 let base_null_count = base_values.logical_null_count();
775 if base_null_count > 0 {
776 let base_not_nulls = is_not_null(base_values.as_ref())?;
780 let base_all_null = base_null_count == remainder_batch.num_rows();
781
782 if let Some(e) = &self.else_expr {
785 let expr = try_cast(Arc::clone(e), &batch.schema(), return_type.clone())?;
786
787 if base_all_null {
788 let nulls_value = expr.evaluate(&remainder_batch)?;
790 result_builder.add_branch_result(&remainder_rows, nulls_value)?;
791 } else {
792 let nulls_filter = create_filter(¬(&base_not_nulls)?, true);
794 let nulls_batch =
795 filter_record_batch(&remainder_batch, &nulls_filter)?;
796 let nulls_rows = filter_array(&remainder_rows, &nulls_filter)?;
797 let nulls_value = expr.evaluate(&nulls_batch)?;
798 result_builder.add_branch_result(&nulls_rows, nulls_value)?;
799 }
800 }
801
802 if base_all_null {
804 return result_builder.finish();
805 }
806
807 let not_null_filter = create_filter(&base_not_nulls, true);
809 remainder_batch =
810 Cow::Owned(filter_record_batch(&remainder_batch, ¬_null_filter)?);
811 remainder_rows = filter_array(&remainder_rows, ¬_null_filter)?;
812 base_values = filter_array(&base_values, ¬_null_filter)?;
813 }
814
815 let base_value_is_nested = base_values.data_type().is_nested();
818
819 for i in 0..self.when_then_expr.len() {
820 let when_expr = &self.when_then_expr[i].0;
823 let when_value = match when_expr.evaluate(&remainder_batch)? {
824 ColumnarValue::Array(a) => {
825 compare_with_eq(&a, &base_values, base_value_is_nested)
826 }
827 ColumnarValue::Scalar(s) => {
828 compare_with_eq(&s.to_scalar()?, &base_values, base_value_is_nested)
829 }
830 }?;
831
832 if !when_value.has_true() {
836 continue;
837 }
838
839 if when_value.null_count() == 0 && !when_value.has_false() {
841 let then_expression = &self.when_then_expr[i].1;
842 let then_value = then_expression.evaluate(&remainder_batch)?;
843 result_builder.add_branch_result(&remainder_rows, then_value)?;
844 return result_builder.finish();
845 }
846
847 let then_filter = create_filter(&when_value, true);
853 let then_batch = filter_record_batch(&remainder_batch, &then_filter)?;
854 let then_rows = filter_array(&remainder_rows, &then_filter)?;
855
856 let then_expression = &self.when_then_expr[i].1;
857 let then_value = then_expression.evaluate(&then_batch)?;
858 result_builder.add_branch_result(&then_rows, then_value)?;
859
860 if self.else_expr.is_none() && i == self.when_then_expr.len() - 1 {
863 return result_builder.finish();
864 }
865
866 let next_selection = match when_value.null_count() {
868 0 => not(&when_value),
869 _ => {
870 not(&prep_null_mask_filter(&when_value))
873 }
874 }?;
875 let next_filter = create_filter(&next_selection, true);
876 remainder_batch =
877 Cow::Owned(filter_record_batch(&remainder_batch, &next_filter)?);
878 remainder_rows = filter_array(&remainder_rows, &next_filter)?;
879 base_values = filter_array(&base_values, &next_filter)?;
880 }
881
882 if let Some(e) = &self.else_expr {
885 let expr = try_cast(Arc::clone(e), &batch.schema(), return_type.clone())?;
887 let else_value = expr.evaluate(&remainder_batch)?;
888 result_builder.add_branch_result(&remainder_rows, else_value)?;
889 }
890
891 result_builder.finish()
892 }
893
894 fn case_when_no_expr(
896 &self,
897 batch: &RecordBatch,
898 return_type: &DataType,
899 ) -> Result<ColumnarValue> {
900 let mut result_builder = ResultBuilder::new(return_type, batch.num_rows());
901
902 let mut remainder_rows: ArrayRef =
904 Arc::new(UInt32Array::from_iter(0..batch.num_rows() as u32));
905 let mut remainder_batch = Cow::Borrowed(batch);
907
908 for i in 0..self.when_then_expr.len() {
909 let when_predicate = &self.when_then_expr[i].0;
912 let when_value = when_predicate
913 .evaluate(&remainder_batch)?
914 .into_array(remainder_batch.num_rows())?;
915 let when_value = as_boolean_array(&when_value).map_err(|_| {
916 internal_datafusion_err!("WHEN expression did not return a BooleanArray")
917 })?;
918
919 if !when_value.has_true() {
923 continue;
924 }
925
926 if when_value.null_count() == 0 && !when_value.has_false() {
928 let then_expression = &self.when_then_expr[i].1;
929 let then_value = then_expression.evaluate(&remainder_batch)?;
930 result_builder.add_branch_result(&remainder_rows, then_value)?;
931 return result_builder.finish();
932 }
933
934 let then_filter = create_filter(when_value, true);
940 let then_batch = filter_record_batch(&remainder_batch, &then_filter)?;
941 let then_rows = filter_array(&remainder_rows, &then_filter)?;
942
943 let then_expression = &self.when_then_expr[i].1;
944 let then_value = then_expression.evaluate(&then_batch)?;
945 result_builder.add_branch_result(&then_rows, then_value)?;
946
947 if self.else_expr.is_none() && i == self.when_then_expr.len() - 1 {
950 return result_builder.finish();
951 }
952
953 let next_selection = match when_value.null_count() {
955 0 => not(when_value),
956 _ => {
957 not(&prep_null_mask_filter(when_value))
960 }
961 }?;
962 let next_filter = create_filter(&next_selection, true);
963 remainder_batch =
964 Cow::Owned(filter_record_batch(&remainder_batch, &next_filter)?);
965 remainder_rows = filter_array(&remainder_rows, &next_filter)?;
966 }
967
968 if let Some(e) = &self.else_expr {
971 let expr = try_cast(Arc::clone(e), &batch.schema(), return_type.clone())?;
973 let else_value = expr.evaluate(&remainder_batch)?;
974 result_builder.add_branch_result(&remainder_rows, else_value)?;
975 }
976
977 result_builder.finish()
978 }
979
980 fn expr_or_expr(
982 &self,
983 batch: &RecordBatch,
984 when_value: &BooleanArray,
985 ) -> Result<ColumnarValue> {
986 let when_value = match when_value.null_count() {
987 0 => Cow::Borrowed(when_value),
988 _ => {
989 Cow::Owned(prep_null_mask_filter(when_value))
991 }
992 };
993
994 let optimize_filter = batch.num_columns() > 1
995 || (batch.num_columns() == 1 && multiple_arrays(batch.column(0).data_type()));
996
997 let when_filter = create_filter(&when_value, optimize_filter);
998 let then_batch = filter_record_batch(batch, &when_filter)?;
999 let then_value = self.when_then_expr[0].1.evaluate(&then_batch)?;
1000
1001 match &self.else_expr {
1002 None => {
1003 let then_array = then_value.to_array(when_value.true_count())?;
1004 scatter(&when_value, then_array.as_ref()).map(ColumnarValue::Array)
1005 }
1006 Some(else_expr) => {
1007 let else_selection = not(&when_value)?;
1008 let else_filter = create_filter(&else_selection, optimize_filter);
1009 let else_batch = filter_record_batch(batch, &else_filter)?;
1010
1011 let return_type = self.data_type(&batch.schema())?;
1013 let else_expr =
1014 try_cast(Arc::clone(else_expr), &batch.schema(), return_type.clone())
1015 .unwrap_or_else(|_| Arc::clone(else_expr));
1016
1017 let else_value = else_expr.evaluate(&else_batch)?;
1018
1019 Ok(ColumnarValue::Array(match (then_value, else_value) {
1020 (ColumnarValue::Array(t), ColumnarValue::Array(e)) => {
1021 merge(&when_value, &t, &e)
1022 }
1023 (ColumnarValue::Scalar(t), ColumnarValue::Array(e)) => {
1024 merge(&when_value, &t.to_scalar()?, &e)
1025 }
1026 (ColumnarValue::Array(t), ColumnarValue::Scalar(e)) => {
1027 merge(&when_value, &t, &e.to_scalar()?)
1028 }
1029 (ColumnarValue::Scalar(t), ColumnarValue::Scalar(e)) => {
1030 merge(&when_value, &t.to_scalar()?, &e.to_scalar()?)
1031 }
1032 }?))
1033 }
1034 }
1035 }
1036}
1037
1038impl CaseExpr {
1039 fn case_when_with_expr(
1047 &self,
1048 batch: &RecordBatch,
1049 projected: &ProjectedCaseBody,
1050 ) -> Result<ColumnarValue> {
1051 let return_type = self.data_type(&batch.schema())?;
1052 let projection = projected
1054 .projection
1055 .iter()
1056 .copied()
1057 .filter(|index| *index < batch.num_columns())
1058 .collect::<Vec<_>>();
1059 if projection.len() < batch.num_columns() {
1060 let projected_batch = batch.project(&projection)?;
1061 projected
1062 .body
1063 .case_when_with_expr(&projected_batch, &return_type)
1064 } else {
1065 self.body.case_when_with_expr(batch, &return_type)
1066 }
1067 }
1068
1069 fn case_when_no_expr(
1077 &self,
1078 batch: &RecordBatch,
1079 projected: &ProjectedCaseBody,
1080 ) -> Result<ColumnarValue> {
1081 let return_type = self.data_type(&batch.schema())?;
1082 let projection = projected
1084 .projection
1085 .iter()
1086 .copied()
1087 .filter(|index| *index < batch.num_columns())
1088 .collect::<Vec<_>>();
1089 if projection.len() < batch.num_columns() {
1090 let projected_batch = batch.project(&projection)?;
1091 projected
1092 .body
1093 .case_when_no_expr(&projected_batch, &return_type)
1094 } else {
1095 self.body.case_when_no_expr(batch, &return_type)
1096 }
1097 }
1098
1099 fn case_column_or_null(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
1109 let when_expr = &self.body.when_then_expr[0].0;
1110 let then_expr = &self.body.when_then_expr[0].1;
1111
1112 match when_expr.evaluate(batch)? {
1113 ColumnarValue::Scalar(ScalarValue::Boolean(Some(true))) => {
1115 then_expr.evaluate(batch)
1116 }
1117 ColumnarValue::Scalar(_) => {
1119 ScalarValue::try_from(self.data_type(&batch.schema())?)
1121 .map(ColumnarValue::Scalar)
1122 }
1123 ColumnarValue::Array(bit_mask) => {
1125 let bit_mask = bit_mask
1126 .as_any()
1127 .downcast_ref::<BooleanArray>()
1128 .expect("predicate should evaluate to a boolean array");
1129 let bit_mask = match bit_mask.null_count() {
1131 0 => not(bit_mask)?,
1132 _ => not(&prep_null_mask_filter(bit_mask))?,
1133 };
1134 match then_expr.evaluate(batch)? {
1135 ColumnarValue::Array(array) => {
1136 Ok(ColumnarValue::Array(nullif(&array, &bit_mask)?))
1137 }
1138 ColumnarValue::Scalar(_) => {
1139 internal_err!("expression did not evaluate to an array")
1140 }
1141 }
1142 }
1143 }
1144 }
1145
1146 fn scalar_or_scalar(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
1147 let return_type = self.data_type(&batch.schema())?;
1148
1149 let when_value = self.body.when_then_expr[0].0.evaluate(batch)?;
1151 let when_value = when_value.into_array(batch.num_rows())?;
1152 let when_value = as_boolean_array(&when_value).map_err(|_| {
1153 internal_datafusion_err!("WHEN expression did not return a BooleanArray")
1154 })?;
1155
1156 let when_value = match when_value.null_count() {
1158 0 => Cow::Borrowed(when_value),
1159 _ => Cow::Owned(prep_null_mask_filter(when_value)),
1160 };
1161
1162 let then_value = self.body.when_then_expr[0].1.evaluate(batch)?;
1164 let then_value = Scalar::new(then_value.into_array(1)?);
1165
1166 let Some(e) = &self.body.else_expr else {
1167 return internal_err!("expression did not evaluate to an array");
1168 };
1169 let expr = try_cast(Arc::clone(e), &batch.schema(), return_type)?;
1171 let else_ = Scalar::new(expr.evaluate(batch)?.into_array(1)?);
1172 Ok(ColumnarValue::Array(zip(&when_value, &then_value, &else_)?))
1173 }
1174
1175 fn expr_or_expr(
1176 &self,
1177 batch: &RecordBatch,
1178 projected: &ProjectedCaseBody,
1179 ) -> Result<ColumnarValue> {
1180 let when_value = self.body.when_then_expr[0].0.evaluate(batch)?;
1182 let when_value = when_value.into_array(1)?;
1186 let when_value = as_boolean_array(&when_value).map_err(|e| {
1187 DataFusionError::Context(
1188 "WHEN expression did not return a BooleanArray".to_string(),
1189 Box::new(e),
1190 )
1191 })?;
1192
1193 if when_value.null_count() == 0 && !when_value.has_false() {
1194 self.body.when_then_expr[0].1.evaluate(batch)
1196 } else if !when_value.has_true() {
1197 match &self.body.else_expr {
1199 Some(else_expr) => else_expr.evaluate(batch),
1200 None => {
1201 let return_type = self.data_type(&batch.schema())?;
1202 Ok(ColumnarValue::Scalar(ScalarValue::try_new_null(
1203 &return_type,
1204 )?))
1205 }
1206 }
1207 } else {
1208 let projection = projected
1210 .projection
1211 .iter()
1212 .copied()
1213 .filter(|index| *index < batch.num_columns())
1214 .collect::<Vec<_>>();
1215 if projection.len() < batch.num_columns() {
1216 let projected_batch = batch.project(&projection)?;
1219 projected.body.expr_or_expr(&projected_batch, when_value)
1220 } else {
1221 self.body.expr_or_expr(batch, when_value)
1223 }
1224 }
1225 }
1226
1227 fn with_lookup_table(
1228 &self,
1229 batch: &RecordBatch,
1230 lookup_table: &LiteralLookupTable,
1231 ) -> Result<ColumnarValue> {
1232 let expr = self.body.expr.as_ref().unwrap();
1233 let evaluated_expression = expr.evaluate(batch)?;
1234
1235 let is_scalar = matches!(evaluated_expression, ColumnarValue::Scalar(_));
1236 let evaluated_expression = evaluated_expression.to_array(1)?;
1237
1238 let values = lookup_table.map_keys_to_values(&evaluated_expression)?;
1239
1240 let result = if is_scalar {
1241 ColumnarValue::Scalar(ScalarValue::try_from_array(values.as_ref(), 0)?)
1242 } else {
1243 ColumnarValue::Array(values)
1244 };
1245
1246 Ok(result)
1247 }
1248}
1249
1250impl PhysicalExpr for CaseExpr {
1251 fn data_type(&self, input_schema: &Schema) -> Result<DataType> {
1252 self.body.data_type(input_schema)
1253 }
1254
1255 fn nullable(&self, input_schema: &Schema) -> Result<bool> {
1256 let nullable_then = self
1257 .body
1258 .when_then_expr
1259 .iter()
1260 .filter_map(|(w, t)| {
1261 let is_nullable = match t.nullable(input_schema) {
1262 Err(e) => return Some(Err(e)),
1264 Ok(n) => n,
1265 };
1266
1267 if !is_nullable {
1270 return None;
1271 }
1272
1273 if self.body.expr.is_some() {
1275 return Some(Ok(()));
1276 }
1277
1278 let with_null = match replace_with_null(
1284 w,
1285 unwrap_certainly_null_expr(t.as_ref()),
1286 input_schema,
1287 ) {
1288 Err(e) => return Some(Err(e)),
1289 Ok(e) => e,
1290 };
1291
1292 let predicate_result = match evaluate_predicate(&with_null) {
1294 Err(e) => return Some(Err(e)),
1295 Ok(b) => b,
1296 };
1297
1298 match predicate_result {
1299 None | Some(true) => Some(Ok(())),
1301 Some(false) => None,
1304 }
1305 })
1306 .next();
1307
1308 if let Some(nullable_then) = nullable_then {
1309 nullable_then.map(|_| true)
1313 } else if let Some(e) = &self.body.else_expr {
1314 e.nullable(input_schema)
1317 } else {
1318 Ok(true)
1321 }
1322 }
1323
1324 fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
1325 match &self.eval_method {
1326 EvalMethod::WithExpression(p) => {
1327 self.case_when_with_expr(batch, p)
1330 }
1331 EvalMethod::NoExpression(p) => {
1332 self.case_when_no_expr(batch, p)
1335 }
1336 EvalMethod::InfallibleExprOrNull => {
1337 self.case_column_or_null(batch)
1339 }
1340 EvalMethod::ScalarOrScalar => self.scalar_or_scalar(batch),
1341 EvalMethod::ExpressionOrExpression(p) => self.expr_or_expr(batch, p),
1342 EvalMethod::WithExprScalarLookupTable(lookup_table) => {
1343 self.with_lookup_table(batch, lookup_table)
1344 }
1345 }
1346 }
1347
1348 fn children(&self) -> Vec<&Arc<dyn PhysicalExpr>> {
1349 let mut children = vec![];
1350 if let Some(expr) = &self.body.expr {
1351 children.push(expr)
1352 }
1353 self.body.when_then_expr.iter().for_each(|(cond, value)| {
1354 children.push(cond);
1355 children.push(value);
1356 });
1357
1358 if let Some(else_expr) = &self.body.else_expr {
1359 children.push(else_expr)
1360 }
1361 children
1362 }
1363
1364 fn with_new_children(
1366 self: Arc<Self>,
1367 children: Vec<Arc<dyn PhysicalExpr>>,
1368 ) -> Result<Arc<dyn PhysicalExpr>> {
1369 if children.len() != self.children().len() {
1370 internal_err!("CaseExpr: Wrong number of children")
1371 } else {
1372 let (expr, when_then_expr, else_expr) =
1373 match (self.expr().is_some(), self.body.else_expr.is_some()) {
1374 (true, true) => (
1375 Some(&children[0]),
1376 &children[1..children.len() - 1],
1377 Some(&children[children.len() - 1]),
1378 ),
1379 (true, false) => {
1380 (Some(&children[0]), &children[1..children.len()], None)
1381 }
1382 (false, true) => (
1383 None,
1384 &children[0..children.len() - 1],
1385 Some(&children[children.len() - 1]),
1386 ),
1387 (false, false) => (None, &children[0..children.len()], None),
1388 };
1389 Ok(Arc::new(CaseExpr::try_new(
1390 expr.cloned(),
1391 when_then_expr.iter().cloned().tuples().collect(),
1392 else_expr.cloned(),
1393 )?))
1394 }
1395 }
1396
1397 fn fmt_sql(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1398 write!(f, "CASE ")?;
1399 if let Some(e) = &self.body.expr {
1400 e.fmt_sql(f)?;
1401 write!(f, " ")?;
1402 }
1403
1404 for (w, t) in &self.body.when_then_expr {
1405 write!(f, "WHEN ")?;
1406 w.fmt_sql(f)?;
1407 write!(f, " THEN ")?;
1408 t.fmt_sql(f)?;
1409 write!(f, " ")?;
1410 }
1411
1412 if let Some(e) = &self.body.else_expr {
1413 write!(f, "ELSE ")?;
1414 e.fmt_sql(f)?;
1415 write!(f, " ")?;
1416 }
1417 write!(f, "END")
1418 }
1419
1420 #[cfg(feature = "proto")]
1421 fn try_to_proto(
1422 &self,
1423 ctx: &datafusion_physical_expr_common::physical_expr::proto_encode::PhysicalExprEncodeCtx<'_>,
1424 ) -> Result<Option<datafusion_proto_models::protobuf::PhysicalExprNode>> {
1425 use datafusion_proto_models::protobuf;
1426
1427 Ok(Some(protobuf::PhysicalExprNode {
1428 expr_id: None,
1429 expr_type: Some(protobuf::physical_expr_node::ExprType::Case(Box::new(
1430 protobuf::PhysicalCaseNode {
1431 expr: self
1432 .expr()
1433 .map(|expr| ctx.encode_child(expr).map(Box::new))
1434 .transpose()?,
1435 when_then_expr: self
1436 .when_then_expr()
1437 .iter()
1438 .map(|(when_expr, then_expr)| {
1439 Ok(protobuf::PhysicalWhenThen {
1440 when_expr: Some(ctx.encode_child(when_expr)?),
1441 then_expr: Some(ctx.encode_child(then_expr)?),
1442 })
1443 })
1444 .collect::<Result<Vec<_>>>()?,
1445 else_expr: self
1446 .else_expr()
1447 .map(|expr| ctx.encode_child(expr).map(Box::new))
1448 .transpose()?,
1449 },
1450 ))),
1451 }))
1452 }
1453}
1454
1455#[cfg(feature = "proto")]
1456impl CaseExpr {
1457 pub fn try_from_proto(
1459 node: &datafusion_proto_models::protobuf::PhysicalExprNode,
1460 ctx: &datafusion_physical_expr_common::physical_expr::proto_decode::PhysicalExprDecodeCtx<'_>,
1461 ) -> Result<Arc<dyn PhysicalExpr>> {
1462 use datafusion_physical_expr_common::expect_expr_variant;
1463 use datafusion_proto_models::protobuf;
1464
1465 let case = expect_expr_variant!(
1466 node,
1467 protobuf::physical_expr_node::ExprType::Case,
1468 "CaseExpr",
1469 );
1470
1471 Ok(Arc::new(CaseExpr::try_new(
1472 case.expr
1473 .as_deref()
1474 .map(|expr| ctx.decode(expr))
1475 .transpose()?,
1476 case.when_then_expr
1477 .iter()
1478 .map(|when_then| {
1479 Ok((
1480 ctx.decode_required_expression(
1481 when_then.when_expr.as_ref(),
1482 "CaseExpr",
1483 "when_expr",
1484 )?,
1485 ctx.decode_required_expression(
1486 when_then.then_expr.as_ref(),
1487 "CaseExpr",
1488 "then_expr",
1489 )?,
1490 ))
1491 })
1492 .collect::<Result<Vec<_>>>()?,
1493 case.else_expr
1494 .as_deref()
1495 .map(|expr| ctx.decode(expr))
1496 .transpose()?,
1497 )?))
1498 }
1499}
1500
1501fn evaluate_predicate(predicate: &Arc<dyn PhysicalExpr>) -> Result<Option<bool>> {
1507 let batch = RecordBatch::try_new_with_options(
1509 Arc::new(Schema::empty()),
1510 vec![],
1511 &RecordBatchOptions::new().with_row_count(Some(1)),
1512 )?;
1513
1514 let result = match predicate.evaluate(&batch) {
1516 Err(_) => None,
1518 Ok(ColumnarValue::Array(array)) => Some(
1519 ScalarValue::try_from_array(array.as_ref(), 0)?
1520 .cast_to(&DataType::Boolean)?,
1521 ),
1522 Ok(ColumnarValue::Scalar(scalar)) => Some(scalar.cast_to(&DataType::Boolean)?),
1523 };
1524 Ok(result.map(|v| matches!(v, ScalarValue::Boolean(Some(true)))))
1525}
1526
1527fn replace_with_null(
1528 expr: &Arc<dyn PhysicalExpr>,
1529 expr_to_replace: &dyn PhysicalExpr,
1530 input_schema: &Schema,
1531) -> Result<Arc<dyn PhysicalExpr>, DataFusionError> {
1532 let with_null = Arc::clone(expr)
1533 .transform_down(|e| {
1534 if e.as_ref().dyn_eq(expr_to_replace) {
1535 let data_type = e.data_type(input_schema)?;
1536 let null_literal = lit(ScalarValue::try_new_null(&data_type)?);
1537 Ok(Transformed::yes(null_literal))
1538 } else {
1539 Ok(Transformed::no(e))
1540 }
1541 })?
1542 .data;
1543 Ok(with_null)
1544}
1545
1546fn unwrap_certainly_null_expr(expr: &dyn PhysicalExpr) -> &dyn PhysicalExpr {
1554 if let Some(expr) = expr.downcast_ref::<NotExpr>() {
1555 unwrap_certainly_null_expr(expr.arg().as_ref())
1556 } else if let Some(expr) = expr.downcast_ref::<NegativeExpr>() {
1557 unwrap_certainly_null_expr(expr.arg().as_ref())
1558 } else if let Some(expr) = expr.downcast_ref::<CastExpr>() {
1559 unwrap_certainly_null_expr(expr.expr.as_ref())
1560 } else {
1561 expr
1562 }
1563}
1564
1565pub fn case(
1567 expr: Option<Arc<dyn PhysicalExpr>>,
1568 when_thens: Vec<WhenThen>,
1569 else_expr: Option<Arc<dyn PhysicalExpr>>,
1570) -> Result<Arc<dyn PhysicalExpr>> {
1571 Ok(Arc::new(CaseExpr::try_new(expr, when_thens, else_expr)?))
1572}
1573
1574#[cfg(test)]
1575mod tests {
1576 use super::*;
1577
1578 use crate::expressions;
1579 use crate::expressions::{BinaryExpr, binary, cast, col, is_not_null};
1580 use arrow::buffer::Buffer;
1581 use arrow::datatypes::DataType::Float64;
1582 use arrow::datatypes::Field;
1583 use datafusion_common::cast::{as_float64_array, as_int32_array};
1584 use datafusion_common::plan_err;
1585 use datafusion_common::tree_node::{Transformed, TransformedResult, TreeNode};
1586 use datafusion_expr::type_coercion::binary::type_union_coercion;
1587 use datafusion_expr_common::operator::Operator;
1588 use datafusion_physical_expr_common::physical_expr::fmt_sql;
1589 use half::f16;
1590
1591 #[test]
1592 fn case_with_expr() -> Result<()> {
1593 let batch = case_test_batch()?;
1594 let schema = batch.schema();
1595
1596 let when1 = lit("foo");
1598 let then1 = lit(123i32);
1599 let when2 = lit("bar");
1600 let then2 = lit(456i32);
1601
1602 let expr = generate_case_when_with_type_coercion(
1603 Some(col("a", &schema)?),
1604 vec![(when1, then1), (when2, then2)],
1605 None,
1606 schema.as_ref(),
1607 )?;
1608 let result = expr
1609 .evaluate(&batch)?
1610 .into_array(batch.num_rows())
1611 .expect("Failed to convert to array");
1612 let result = as_int32_array(&result)?;
1613
1614 let expected = &Int32Array::from(vec![Some(123), None, None, Some(456)]);
1615
1616 assert_eq!(expected, result);
1617
1618 Ok(())
1619 }
1620
1621 #[test]
1622 fn case_with_expr_dictionary() -> Result<()> {
1623 let schema = Schema::new(vec![Field::new(
1624 "a",
1625 DataType::Dictionary(Box::new(DataType::UInt8), Box::new(DataType::Utf8)),
1626 true,
1627 )]);
1628 let keys = UInt8Array::from(vec![0u8, 1u8, 2u8, 3u8]);
1629 let values = StringArray::from(vec![Some("foo"), Some("baz"), None, Some("bar")]);
1630 let dictionary = DictionaryArray::new(keys, Arc::new(values));
1631 let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(dictionary)])?;
1632
1633 let schema = batch.schema();
1634
1635 let when1 = lit("foo");
1637 let then1 = lit(123i32);
1638 let when2 = lit("bar");
1639 let then2 = lit(456i32);
1640
1641 let expr = generate_case_when_with_type_coercion(
1642 Some(col("a", &schema)?),
1643 vec![(when1, then1), (when2, then2)],
1644 None,
1645 schema.as_ref(),
1646 )?;
1647 let result = expr
1648 .evaluate(&batch)?
1649 .into_array(batch.num_rows())
1650 .expect("Failed to convert to array");
1651 let result = as_int32_array(&result)?;
1652
1653 let expected = &Int32Array::from(vec![Some(123), None, None, Some(456)]);
1654
1655 assert_eq!(expected, result);
1656
1657 Ok(())
1658 }
1659
1660 #[test]
1662 fn case_with_expr_primitive_dictionary() -> Result<()> {
1663 let schema = Schema::new(vec![Field::new(
1664 "a",
1665 DataType::Dictionary(Box::new(DataType::UInt8), Box::new(DataType::UInt64)),
1666 true,
1667 )]);
1668 let keys = UInt8Array::from(vec![0u8, 1u8, 2u8, 3u8]);
1669 let values = UInt64Array::from(vec![Some(10), Some(20), None, Some(30)]);
1670 let dictionary = DictionaryArray::new(keys, Arc::new(values));
1671 let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(dictionary)])?;
1672
1673 let schema = batch.schema();
1674
1675 let when1 = lit(10_u64);
1677 let then1 = lit(123_i32);
1678 let when2 = lit(30_u64);
1679 let then2 = lit(456_i32);
1680
1681 let expr = generate_case_when_with_type_coercion(
1682 Some(col("a", &schema)?),
1683 vec![(when1, then1), (when2, then2)],
1684 None,
1685 schema.as_ref(),
1686 )?;
1687 let result = expr
1688 .evaluate(&batch)?
1689 .into_array(batch.num_rows())
1690 .expect("Failed to convert to array");
1691 let result = as_int32_array(&result)?;
1692
1693 let expected = &Int32Array::from(vec![Some(123), None, None, Some(456)]);
1694
1695 assert_eq!(expected, result);
1696
1697 Ok(())
1698 }
1699
1700 #[test]
1702 fn case_with_expr_boolean_dictionary() -> Result<()> {
1703 let schema = Schema::new(vec![Field::new(
1704 "a",
1705 DataType::Dictionary(Box::new(DataType::UInt8), Box::new(DataType::Boolean)),
1706 true,
1707 )]);
1708 let keys = UInt8Array::from(vec![0u8, 1u8, 2u8, 3u8]);
1709 let values = BooleanArray::from(vec![Some(true), Some(false), None, Some(true)]);
1710 let dictionary = DictionaryArray::new(keys, Arc::new(values));
1711 let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(dictionary)])?;
1712
1713 let schema = batch.schema();
1714
1715 let when1 = lit(true);
1717 let then1 = lit(123i32);
1718 let when2 = lit(false);
1719 let then2 = lit(456i32);
1720
1721 let expr = generate_case_when_with_type_coercion(
1722 Some(col("a", &schema)?),
1723 vec![(when1, then1), (when2, then2)],
1724 None,
1725 schema.as_ref(),
1726 )?;
1727 let result = expr
1728 .evaluate(&batch)?
1729 .into_array(batch.num_rows())
1730 .expect("Failed to convert to array");
1731 let result = as_int32_array(&result)?;
1732
1733 let expected = &Int32Array::from(vec![Some(123), Some(456), None, Some(123)]);
1734
1735 assert_eq!(expected, result);
1736
1737 Ok(())
1738 }
1739
1740 #[test]
1741 fn case_with_expr_all_null_dictionary() -> Result<()> {
1742 let schema = Schema::new(vec![Field::new(
1743 "a",
1744 DataType::Dictionary(Box::new(DataType::UInt8), Box::new(DataType::Utf8)),
1745 true,
1746 )]);
1747 let keys = UInt8Array::from(vec![2u8, 2u8, 2u8, 2u8]);
1748 let values = StringArray::from(vec![Some("foo"), Some("baz"), None, Some("bar")]);
1749 let dictionary = DictionaryArray::new(keys, Arc::new(values));
1750 let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(dictionary)])?;
1751
1752 let schema = batch.schema();
1753
1754 let when1 = lit("foo");
1756 let then1 = lit(123i32);
1757 let when2 = lit("bar");
1758 let then2 = lit(456i32);
1759
1760 let expr = generate_case_when_with_type_coercion(
1761 Some(col("a", &schema)?),
1762 vec![(when1, then1), (when2, then2)],
1763 None,
1764 schema.as_ref(),
1765 )?;
1766 let result = expr
1767 .evaluate(&batch)?
1768 .into_array(batch.num_rows())
1769 .expect("Failed to convert to array");
1770 let result = as_int32_array(&result)?;
1771
1772 let expected = &Int32Array::from(vec![None, None, None, None]);
1773
1774 assert_eq!(expected, result);
1775
1776 Ok(())
1777 }
1778
1779 #[test]
1780 fn case_with_expr_else() -> Result<()> {
1781 let batch = case_test_batch()?;
1782 let schema = batch.schema();
1783
1784 let when1 = lit("foo");
1786 let then1 = lit(123i32);
1787 let when2 = lit("bar");
1788 let then2 = lit(456i32);
1789 let else_value = lit(999i32);
1790
1791 let expr = generate_case_when_with_type_coercion(
1792 Some(col("a", &schema)?),
1793 vec![(when1, then1), (when2, then2)],
1794 Some(else_value),
1795 schema.as_ref(),
1796 )?;
1797 let result = expr
1798 .evaluate(&batch)?
1799 .into_array(batch.num_rows())
1800 .expect("Failed to convert to array");
1801 let result = as_int32_array(&result)?;
1802
1803 let expected =
1804 &Int32Array::from(vec![Some(123), Some(999), Some(999), Some(456)]);
1805
1806 assert_eq!(expected, result);
1807
1808 Ok(())
1809 }
1810
1811 #[test]
1812 fn case_with_expr_divide_by_zero() -> Result<()> {
1813 let batch = case_test_batch1()?;
1814 let schema = batch.schema();
1815
1816 let when1 = lit(0i32);
1818 let then1 = lit(ScalarValue::Float64(None));
1819 let else_value = binary(
1820 lit(25.0f64),
1821 Operator::Divide,
1822 cast(col("a", &schema)?, &batch.schema(), Float64)?,
1823 &batch.schema(),
1824 )?;
1825
1826 let expr = generate_case_when_with_type_coercion(
1827 Some(col("a", &schema)?),
1828 vec![(when1, then1)],
1829 Some(else_value),
1830 schema.as_ref(),
1831 )?;
1832 let result = expr
1833 .evaluate(&batch)?
1834 .into_array(batch.num_rows())
1835 .expect("Failed to convert to array");
1836 let result =
1837 as_float64_array(&result).expect("failed to downcast to Float64Array");
1838
1839 let expected = &Float64Array::from(vec![Some(25.0), None, None, Some(5.0)]);
1840
1841 assert_eq!(expected, result);
1842
1843 Ok(())
1844 }
1845
1846 #[test]
1847 fn case_without_expr() -> Result<()> {
1848 let batch = case_test_batch()?;
1849 let schema = batch.schema();
1850
1851 let when1 = binary(
1853 col("a", &schema)?,
1854 Operator::Eq,
1855 lit("foo"),
1856 &batch.schema(),
1857 )?;
1858 let then1 = lit(123i32);
1859 let when2 = binary(
1860 col("a", &schema)?,
1861 Operator::Eq,
1862 lit("bar"),
1863 &batch.schema(),
1864 )?;
1865 let then2 = lit(456i32);
1866
1867 let expr = generate_case_when_with_type_coercion(
1868 None,
1869 vec![(when1, then1), (when2, then2)],
1870 None,
1871 schema.as_ref(),
1872 )?;
1873 let result = expr
1874 .evaluate(&batch)?
1875 .into_array(batch.num_rows())
1876 .expect("Failed to convert to array");
1877 let result = as_int32_array(&result)?;
1878
1879 let expected = &Int32Array::from(vec![Some(123), None, None, Some(456)]);
1880
1881 assert_eq!(expected, result);
1882
1883 Ok(())
1884 }
1885
1886 #[test]
1887 fn case_with_expr_when_null() -> Result<()> {
1888 let batch = case_test_batch()?;
1889 let schema = batch.schema();
1890
1891 let when1 = lit(ScalarValue::Utf8(None));
1893 let then1 = lit(0i32);
1894 let when2 = col("a", &schema)?;
1895 let then2 = lit(123i32);
1896 let else_value = lit(999i32);
1897
1898 let expr = generate_case_when_with_type_coercion(
1899 Some(col("a", &schema)?),
1900 vec![(when1, then1), (when2, then2)],
1901 Some(else_value),
1902 schema.as_ref(),
1903 )?;
1904 let result = expr
1905 .evaluate(&batch)?
1906 .into_array(batch.num_rows())
1907 .expect("Failed to convert to array");
1908 let result = as_int32_array(&result)?;
1909
1910 let expected =
1911 &Int32Array::from(vec![Some(123), Some(123), Some(999), Some(123)]);
1912
1913 assert_eq!(expected, result);
1914
1915 Ok(())
1916 }
1917
1918 #[test]
1919 fn case_without_expr_divide_by_zero() -> Result<()> {
1920 let batch = case_test_batch1()?;
1921 let schema = batch.schema();
1922
1923 let when1 = binary(col("a", &schema)?, Operator::Gt, lit(0i32), &batch.schema())?;
1925 let then1 = binary(
1926 lit(25.0f64),
1927 Operator::Divide,
1928 cast(col("a", &schema)?, &batch.schema(), Float64)?,
1929 &batch.schema(),
1930 )?;
1931 let x = lit(ScalarValue::Float64(None));
1932
1933 let expr = generate_case_when_with_type_coercion(
1934 None,
1935 vec![(when1, then1)],
1936 Some(x),
1937 schema.as_ref(),
1938 )?;
1939 let result = expr
1940 .evaluate(&batch)?
1941 .into_array(batch.num_rows())
1942 .expect("Failed to convert to array");
1943 let result =
1944 as_float64_array(&result).expect("failed to downcast to Float64Array");
1945
1946 let expected = &Float64Array::from(vec![Some(25.0), None, None, Some(5.0)]);
1947
1948 assert_eq!(expected, result);
1949
1950 Ok(())
1951 }
1952
1953 fn case_test_batch1() -> Result<RecordBatch> {
1954 let schema = Schema::new(vec![
1955 Field::new("a", DataType::Int32, true),
1956 Field::new("b", DataType::Int32, true),
1957 Field::new("c", DataType::Int32, true),
1958 ]);
1959 let a = Int32Array::from(vec![Some(1), Some(0), None, Some(5)]);
1960 let b = Int32Array::from(vec![Some(3), None, Some(14), Some(7)]);
1961 let c = Int32Array::from(vec![Some(0), Some(-3), Some(777), None]);
1962 let batch = RecordBatch::try_new(
1963 Arc::new(schema),
1964 vec![Arc::new(a), Arc::new(b), Arc::new(c)],
1965 )?;
1966 Ok(batch)
1967 }
1968
1969 #[test]
1970 fn case_without_expr_else() -> Result<()> {
1971 let batch = case_test_batch()?;
1972 let schema = batch.schema();
1973
1974 let when1 = binary(
1976 col("a", &schema)?,
1977 Operator::Eq,
1978 lit("foo"),
1979 &batch.schema(),
1980 )?;
1981 let then1 = lit(123i32);
1982 let when2 = binary(
1983 col("a", &schema)?,
1984 Operator::Eq,
1985 lit("bar"),
1986 &batch.schema(),
1987 )?;
1988 let then2 = lit(456i32);
1989 let else_value = lit(999i32);
1990
1991 let expr = generate_case_when_with_type_coercion(
1992 None,
1993 vec![(when1, then1), (when2, then2)],
1994 Some(else_value),
1995 schema.as_ref(),
1996 )?;
1997 let result = expr
1998 .evaluate(&batch)?
1999 .into_array(batch.num_rows())
2000 .expect("Failed to convert to array");
2001 let result = as_int32_array(&result)?;
2002
2003 let expected =
2004 &Int32Array::from(vec![Some(123), Some(999), Some(999), Some(456)]);
2005
2006 assert_eq!(expected, result);
2007
2008 Ok(())
2009 }
2010
2011 #[test]
2012 fn case_with_type_cast() -> Result<()> {
2013 let batch = case_test_batch()?;
2014 let schema = batch.schema();
2015
2016 let when = binary(
2018 col("a", &schema)?,
2019 Operator::Eq,
2020 lit("foo"),
2021 &batch.schema(),
2022 )?;
2023 let then = lit(123.3f64);
2024 let else_value = lit(999i32);
2025
2026 let expr = generate_case_when_with_type_coercion(
2027 None,
2028 vec![(when, then)],
2029 Some(else_value),
2030 schema.as_ref(),
2031 )?;
2032 let result = expr
2033 .evaluate(&batch)?
2034 .into_array(batch.num_rows())
2035 .expect("Failed to convert to array");
2036 let result =
2037 as_float64_array(&result).expect("failed to downcast to Float64Array");
2038
2039 let expected =
2040 &Float64Array::from(vec![Some(123.3), Some(999.0), Some(999.0), Some(999.0)]);
2041
2042 assert_eq!(expected, result);
2043
2044 Ok(())
2045 }
2046
2047 #[test]
2048 fn case_with_matches_and_nulls() -> Result<()> {
2049 let batch = case_test_batch_nulls()?;
2050 let schema = batch.schema();
2051
2052 let when = binary(
2054 col("load4", &schema)?,
2055 Operator::Eq,
2056 lit(1.77f64),
2057 &batch.schema(),
2058 )?;
2059 let then = col("load4", &schema)?;
2060
2061 let expr = generate_case_when_with_type_coercion(
2062 None,
2063 vec![(when, then)],
2064 None,
2065 schema.as_ref(),
2066 )?;
2067 let result = expr
2068 .evaluate(&batch)?
2069 .into_array(batch.num_rows())
2070 .expect("Failed to convert to array");
2071 let result =
2072 as_float64_array(&result).expect("failed to downcast to Float64Array");
2073
2074 let expected =
2075 &Float64Array::from(vec![Some(1.77), None, None, None, None, Some(1.77)]);
2076
2077 assert_eq!(expected, result);
2078
2079 Ok(())
2080 }
2081
2082 #[test]
2083 fn case_with_scalar_predicate() -> Result<()> {
2084 let batch = case_test_batch_nulls()?;
2085 let schema = batch.schema();
2086
2087 let when = lit(true);
2089 let then = col("load4", &schema)?;
2090 let expr = generate_case_when_with_type_coercion(
2091 None,
2092 vec![(when, then)],
2093 None,
2094 schema.as_ref(),
2095 )?;
2096
2097 let result = expr
2099 .evaluate(&batch)?
2100 .into_array(batch.num_rows())
2101 .expect("Failed to convert to array");
2102 let result =
2103 as_float64_array(&result).expect("failed to downcast to Float64Array");
2104 let expected = &Float64Array::from(vec![
2105 Some(1.77),
2106 None,
2107 None,
2108 Some(1.78),
2109 None,
2110 Some(1.77),
2111 ]);
2112 assert_eq!(expected, result);
2113
2114 let expected = Float64Array::from(vec![Some(1.1)]);
2116 let batch =
2117 RecordBatch::try_new(Arc::clone(&schema), vec![Arc::new(expected.clone())])?;
2118 let result = expr
2119 .evaluate(&batch)?
2120 .into_array(batch.num_rows())
2121 .expect("Failed to convert to array");
2122 let result =
2123 as_float64_array(&result).expect("failed to downcast to Float64Array");
2124 assert_eq!(&expected, result);
2125
2126 Ok(())
2127 }
2128
2129 #[test]
2130 fn case_expr_matches_and_nulls() -> Result<()> {
2131 let batch = case_test_batch_nulls()?;
2132 let schema = batch.schema();
2133
2134 let expr = col("load4", &schema)?;
2136 let when = lit(1.77f64);
2137 let then = col("load4", &schema)?;
2138
2139 let expr = generate_case_when_with_type_coercion(
2140 Some(expr),
2141 vec![(when, then)],
2142 None,
2143 schema.as_ref(),
2144 )?;
2145 let result = expr
2146 .evaluate(&batch)?
2147 .into_array(batch.num_rows())
2148 .expect("Failed to convert to array");
2149 let result =
2150 as_float64_array(&result).expect("failed to downcast to Float64Array");
2151
2152 let expected =
2153 &Float64Array::from(vec![Some(1.77), None, None, None, None, Some(1.77)]);
2154
2155 assert_eq!(expected, result);
2156
2157 Ok(())
2158 }
2159
2160 #[test]
2161 fn test_when_null_and_some_cond_else_null() -> Result<()> {
2162 let batch = case_test_batch()?;
2163 let schema = batch.schema();
2164
2165 let when = binary(
2166 Arc::new(Literal::new(ScalarValue::Boolean(None))),
2167 Operator::And,
2168 binary(col("a", &schema)?, Operator::Eq, lit("foo"), &schema)?,
2169 &schema,
2170 )?;
2171 let then = col("a", &schema)?;
2172
2173 let expr = Arc::new(CaseExpr::try_new(None, vec![(when, then)], None)?);
2175 let result = expr
2176 .evaluate(&batch)?
2177 .into_array(batch.num_rows())
2178 .expect("Failed to convert to array");
2179 let result = as_string_array(&result);
2180
2181 assert_eq!(result.logical_null_count(), batch.num_rows());
2183 Ok(())
2184 }
2185
2186 fn case_test_batch() -> Result<RecordBatch> {
2187 let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
2188 let a = StringArray::from(vec![Some("foo"), Some("baz"), None, Some("bar")]);
2189 let batch = RecordBatch::try_new(Arc::new(schema), vec![Arc::new(a)])?;
2190 Ok(batch)
2191 }
2192
2193 fn case_test_batch_nulls() -> Result<RecordBatch> {
2196 let load4: Float64Array = vec![
2197 Some(1.77), Some(1.77), Some(1.77), Some(1.78), None, Some(1.77), ]
2204 .into_iter()
2205 .collect();
2206
2207 let null_buffer = Buffer::from([0b00101001u8]);
2208 let load4 = load4
2209 .into_data()
2210 .into_builder()
2211 .null_bit_buffer(Some(null_buffer))
2212 .build()
2213 .unwrap();
2214 let load4: Float64Array = load4.into();
2215
2216 let batch =
2217 RecordBatch::try_from_iter(vec![("load4", Arc::new(load4) as ArrayRef)])?;
2218 Ok(batch)
2219 }
2220
2221 #[test]
2222 fn case_test_incompatible() -> Result<()> {
2223 let batch = case_test_batch()?;
2226 let schema = batch.schema();
2227
2228 let when1 = binary(
2230 col("a", &schema)?,
2231 Operator::Eq,
2232 lit("foo"),
2233 &batch.schema(),
2234 )?;
2235 let then1 = lit(123i32);
2236 let when2 = binary(
2237 col("a", &schema)?,
2238 Operator::Eq,
2239 lit("bar"),
2240 &batch.schema(),
2241 )?;
2242 let then2 = lit(true);
2243
2244 let expr = generate_case_when_with_type_coercion(
2245 None,
2246 vec![(when1, then1), (when2, then2)],
2247 None,
2248 schema.as_ref(),
2249 );
2250 assert!(expr.is_err());
2251
2252 let when1 = binary(
2257 col("a", &schema)?,
2258 Operator::Eq,
2259 lit("foo"),
2260 &batch.schema(),
2261 )?;
2262 let then1 = lit(123i32);
2263 let when2 = binary(
2264 col("a", &schema)?,
2265 Operator::Eq,
2266 lit("bar"),
2267 &batch.schema(),
2268 )?;
2269 let then2 = lit(456i64);
2270 let else_expr = lit(1.23f64);
2271
2272 let expr = generate_case_when_with_type_coercion(
2273 None,
2274 vec![(when1, then1), (when2, then2)],
2275 Some(else_expr),
2276 schema.as_ref(),
2277 );
2278 assert!(expr.is_ok());
2279 let result_type = expr.unwrap().data_type(schema.as_ref())?;
2280 assert_eq!(Float64, result_type);
2281 Ok(())
2282 }
2283
2284 #[test]
2285 fn case_eq() -> Result<()> {
2286 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
2287
2288 let when1 = lit("foo");
2289 let then1 = lit(123i32);
2290 let when2 = lit("bar");
2291 let then2 = lit(456i32);
2292 let else_value = lit(999i32);
2293
2294 let expr1 = generate_case_when_with_type_coercion(
2295 Some(col("a", &schema)?),
2296 vec![
2297 (Arc::clone(&when1), Arc::clone(&then1)),
2298 (Arc::clone(&when2), Arc::clone(&then2)),
2299 ],
2300 Some(Arc::clone(&else_value)),
2301 &schema,
2302 )?;
2303
2304 let expr2 = generate_case_when_with_type_coercion(
2305 Some(col("a", &schema)?),
2306 vec![
2307 (Arc::clone(&when1), Arc::clone(&then1)),
2308 (Arc::clone(&when2), Arc::clone(&then2)),
2309 ],
2310 Some(Arc::clone(&else_value)),
2311 &schema,
2312 )?;
2313
2314 let expr3 = generate_case_when_with_type_coercion(
2315 Some(col("a", &schema)?),
2316 vec![(Arc::clone(&when1), Arc::clone(&then1)), (when2, then2)],
2317 None,
2318 &schema,
2319 )?;
2320
2321 let expr4 = generate_case_when_with_type_coercion(
2322 Some(col("a", &schema)?),
2323 vec![(when1, then1)],
2324 Some(else_value),
2325 &schema,
2326 )?;
2327
2328 assert!(expr1.eq(&expr2));
2329 assert!(expr2.eq(&expr1));
2330
2331 assert!(expr2.ne(&expr3));
2332 assert!(expr3.ne(&expr2));
2333
2334 assert!(expr1.ne(&expr4));
2335 assert!(expr4.ne(&expr1));
2336
2337 Ok(())
2338 }
2339
2340 #[test]
2341 fn case_transform() -> Result<()> {
2342 let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
2343
2344 let when1 = lit("foo");
2345 let then1 = lit(123i32);
2346 let when2 = lit("bar");
2347 let then2 = lit(456i32);
2348 let else_value = lit(999i32);
2349
2350 let expr = generate_case_when_with_type_coercion(
2351 Some(col("a", &schema)?),
2352 vec![
2353 (Arc::clone(&when1), Arc::clone(&then1)),
2354 (Arc::clone(&when2), Arc::clone(&then2)),
2355 ],
2356 Some(Arc::clone(&else_value)),
2357 &schema,
2358 )?;
2359
2360 let expr2 = Arc::clone(&expr)
2361 .transform(|e| {
2362 let transformed = match e.downcast_ref::<Literal>() {
2363 Some(lit_value) => match lit_value.value() {
2364 ScalarValue::Utf8(Some(str_value)) => {
2365 Some(lit(str_value.to_uppercase()))
2366 }
2367 _ => None,
2368 },
2369 _ => None,
2370 };
2371 Ok(if let Some(transformed) = transformed {
2372 Transformed::yes(transformed)
2373 } else {
2374 Transformed::no(e)
2375 })
2376 })
2377 .data()
2378 .unwrap();
2379
2380 let expr3 = Arc::clone(&expr)
2381 .transform_down(|e| {
2382 let transformed = match e.downcast_ref::<Literal>() {
2383 Some(lit_value) => match lit_value.value() {
2384 ScalarValue::Utf8(Some(str_value)) => {
2385 Some(lit(str_value.to_uppercase()))
2386 }
2387 _ => None,
2388 },
2389 _ => None,
2390 };
2391 Ok(if let Some(transformed) = transformed {
2392 Transformed::yes(transformed)
2393 } else {
2394 Transformed::no(e)
2395 })
2396 })
2397 .data()
2398 .unwrap();
2399
2400 assert!(expr.ne(&expr2));
2401 assert!(expr2.eq(&expr3));
2402
2403 Ok(())
2404 }
2405
2406 #[test]
2407 fn test_column_or_null_specialization() -> Result<()> {
2408 let mut c1 = Int32Builder::new();
2410 let mut c2 = StringBuilder::new();
2411 for i in 0..1000 {
2412 c1.append_value(i);
2413 if i % 7 == 0 {
2414 c2.append_null();
2415 } else {
2416 c2.append_value(format!("string {i}"));
2417 }
2418 }
2419 let c1 = Arc::new(c1.finish());
2420 let c2 = Arc::new(c2.finish());
2421 let schema = Schema::new(vec![
2422 Field::new("c1", DataType::Int32, true),
2423 Field::new("c2", DataType::Utf8, true),
2424 ]);
2425 let batch = RecordBatch::try_new(Arc::new(schema), vec![c1, c2]).unwrap();
2426
2427 let predicate = Arc::new(BinaryExpr::new(
2429 make_col("c1", 0),
2430 Operator::LtEq,
2431 make_lit_i32(250),
2432 ));
2433 let expr = CaseExpr::try_new(None, vec![(predicate, make_col("c2", 1))], None)?;
2434 assert_eq!(expr.eval_method, EvalMethod::InfallibleExprOrNull);
2435 match expr.evaluate(&batch)? {
2436 ColumnarValue::Array(array) => {
2437 assert_eq!(1000, array.len());
2438 assert_eq!(785, array.null_count());
2439 }
2440 _ => unreachable!(),
2441 }
2442 Ok(())
2443 }
2444
2445 #[test]
2446 fn test_expr_or_expr_specialization() -> Result<()> {
2447 let batch = case_test_batch1()?;
2448 let schema = batch.schema();
2449 let when = binary(
2450 col("a", &schema)?,
2451 Operator::LtEq,
2452 lit(2i32),
2453 &batch.schema(),
2454 )?;
2455 let then = col("b", &schema)?;
2456 let else_expr = col("c", &schema)?;
2457 let expr = CaseExpr::try_new(None, vec![(when, then)], Some(else_expr))?;
2458 assert!(matches!(
2459 expr.eval_method,
2460 EvalMethod::ExpressionOrExpression(_)
2461 ));
2462 let result = expr
2463 .evaluate(&batch)?
2464 .into_array(batch.num_rows())
2465 .expect("Failed to convert to array");
2466 let result = as_int32_array(&result).expect("failed to downcast to Int32Array");
2467
2468 let expected = &Int32Array::from(vec![Some(3), None, Some(777), None]);
2469
2470 assert_eq!(expected, result);
2471 Ok(())
2472 }
2473
2474 fn make_col(name: &str, index: usize) -> Arc<dyn PhysicalExpr> {
2475 Arc::new(Column::new(name, index))
2476 }
2477
2478 fn make_lit_i32(n: i32) -> Arc<dyn PhysicalExpr> {
2479 Arc::new(Literal::new(ScalarValue::Int32(Some(n))))
2480 }
2481
2482 fn generate_case_when_with_type_coercion(
2483 expr: Option<Arc<dyn PhysicalExpr>>,
2484 when_thens: Vec<WhenThen>,
2485 else_expr: Option<Arc<dyn PhysicalExpr>>,
2486 input_schema: &Schema,
2487 ) -> Result<Arc<dyn PhysicalExpr>> {
2488 let coerce_type =
2489 get_case_common_type(&when_thens, else_expr.clone(), input_schema);
2490 let (when_thens, else_expr) = match coerce_type {
2491 None => plan_err!(
2492 "Can't get a common type for then {when_thens:?} and else {else_expr:?} expression"
2493 ),
2494 Some(data_type) => {
2495 let left = when_thens
2497 .into_iter()
2498 .map(|(when, then)| {
2499 let then = try_cast(then, input_schema, data_type.clone())?;
2500 Ok((when, then))
2501 })
2502 .collect::<Result<Vec<_>>>()?;
2503 let right = match else_expr {
2504 None => None,
2505 Some(expr) => Some(try_cast(expr, input_schema, data_type.clone())?),
2506 };
2507
2508 Ok((left, right))
2509 }
2510 }?;
2511 case(expr, when_thens, else_expr)
2512 }
2513
2514 fn get_case_common_type(
2515 when_thens: &[WhenThen],
2516 else_expr: Option<Arc<dyn PhysicalExpr>>,
2517 input_schema: &Schema,
2518 ) -> Option<DataType> {
2519 let thens_type = when_thens
2520 .iter()
2521 .map(|when_then| {
2522 let data_type = &when_then.1.data_type(input_schema).unwrap();
2523 data_type.clone()
2524 })
2525 .collect::<Vec<_>>();
2526 let else_type = match else_expr {
2527 None => {
2528 thens_type[0].clone()
2530 }
2531 Some(else_phy_expr) => else_phy_expr.data_type(input_schema).unwrap(),
2532 };
2533 thens_type
2534 .iter()
2535 .try_fold(else_type, |left_type, right_type| {
2536 type_union_coercion(&left_type, right_type)
2537 })
2538 }
2539
2540 #[test]
2541 fn test_fmt_sql() -> Result<()> {
2542 let schema = Schema::new(vec![Field::new("a", DataType::Utf8, true)]);
2543
2544 let when = binary(col("a", &schema)?, Operator::Eq, lit("foo"), &schema)?;
2546 let then = lit(123.3f64);
2547 let else_value = lit(999i32);
2548
2549 let expr = generate_case_when_with_type_coercion(
2550 None,
2551 vec![(when, then)],
2552 Some(else_value),
2553 &schema,
2554 )?;
2555
2556 let display_string = expr.to_string();
2557 assert_eq!(
2558 display_string,
2559 "CASE WHEN a@0 = foo THEN 123.3 ELSE TRY_CAST(999 AS Float64) END"
2560 );
2561
2562 let sql_string = fmt_sql(expr.as_ref()).to_string();
2563 assert_eq!(
2564 sql_string,
2565 "CASE WHEN a = foo THEN 123.3 ELSE TRY_CAST(999 AS Float64) END"
2566 );
2567
2568 Ok(())
2569 }
2570
2571 fn when_then_else(
2572 when: &Arc<dyn PhysicalExpr>,
2573 then: &Arc<dyn PhysicalExpr>,
2574 els: &Arc<dyn PhysicalExpr>,
2575 ) -> Result<Arc<dyn PhysicalExpr>> {
2576 let case = CaseExpr::try_new(
2577 None,
2578 vec![(Arc::clone(when), Arc::clone(then))],
2579 Some(Arc::clone(els)),
2580 )?;
2581 Ok(Arc::new(case))
2582 }
2583
2584 #[test]
2585 fn test_case_expression_nullability_with_nullable_column() -> Result<()> {
2586 case_expression_nullability(true)
2587 }
2588
2589 #[test]
2590 fn test_case_expression_nullability_with_not_nullable_column() -> Result<()> {
2591 case_expression_nullability(false)
2592 }
2593
2594 fn case_expression_nullability(col_is_nullable: bool) -> Result<()> {
2595 let schema =
2596 Schema::new(vec![Field::new("foo", DataType::Int32, col_is_nullable)]);
2597
2598 let foo = col("foo", &schema)?;
2599 let foo_is_not_null = is_not_null(Arc::clone(&foo))?;
2600 let foo_is_null = expressions::is_null(Arc::clone(&foo))?;
2601 let not_foo_is_null = expressions::not(Arc::clone(&foo_is_null))?;
2602 let zero = lit(0);
2603 let foo_eq_zero =
2604 binary(Arc::clone(&foo), Operator::Eq, Arc::clone(&zero), &schema)?;
2605 let cast_foo = cast(Arc::clone(&foo), &schema, DataType::Int64)?;
2606 let negative_foo = expressions::negative(Arc::clone(&foo), &schema)?;
2607
2608 assert_not_nullable(when_then_else(&foo_is_not_null, &foo, &zero)?, &schema);
2609 assert_not_nullable(when_then_else(¬_foo_is_null, &foo, &zero)?, &schema);
2610 assert_not_nullable(when_then_else(&foo_eq_zero, &foo, &zero)?, &schema);
2611 assert_not_nullable(
2612 when_then_else(&foo_is_not_null, &cast_foo, &lit(0i64))?,
2613 &schema,
2614 );
2615 assert_not_nullable(
2616 when_then_else(&foo_is_not_null, &negative_foo, &zero)?,
2617 &schema,
2618 );
2619
2620 let cast_negative_foo = cast(
2624 expressions::negative(Arc::clone(&foo), &schema)?,
2625 &schema,
2626 DataType::Int64,
2627 )?;
2628 assert_not_nullable(
2629 when_then_else(&foo_is_not_null, &cast_negative_foo, &lit(0i64))?,
2630 &schema,
2631 );
2632
2633 let try_cast_foo = try_cast(Arc::clone(&foo), &schema, DataType::Int64)?;
2640 assert_nullable(
2641 when_then_else(&foo_is_not_null, &try_cast_foo, &lit(0i64))?,
2642 &schema,
2643 );
2644
2645 assert_not_nullable(
2646 when_then_else(
2647 &binary(
2648 Arc::clone(&foo_is_not_null),
2649 Operator::And,
2650 Arc::clone(&foo_eq_zero),
2651 &schema,
2652 )?,
2653 &foo,
2654 &zero,
2655 )?,
2656 &schema,
2657 );
2658
2659 assert_not_nullable(
2660 when_then_else(
2661 &binary(
2662 Arc::clone(&foo_eq_zero),
2663 Operator::And,
2664 Arc::clone(&foo_is_not_null),
2665 &schema,
2666 )?,
2667 &foo,
2668 &zero,
2669 )?,
2670 &schema,
2671 );
2672
2673 assert_not_nullable(
2674 when_then_else(
2675 &binary(
2676 Arc::clone(&foo_is_not_null),
2677 Operator::Or,
2678 Arc::clone(&foo_eq_zero),
2679 &schema,
2680 )?,
2681 &foo,
2682 &zero,
2683 )?,
2684 &schema,
2685 );
2686
2687 assert_not_nullable(
2688 when_then_else(
2689 &binary(
2690 Arc::clone(&foo_eq_zero),
2691 Operator::Or,
2692 Arc::clone(&foo_is_not_null),
2693 &schema,
2694 )?,
2695 &foo,
2696 &zero,
2697 )?,
2698 &schema,
2699 );
2700
2701 assert_nullability(
2702 when_then_else(
2703 &binary(
2704 Arc::clone(&foo_is_null),
2705 Operator::Or,
2706 Arc::clone(&foo_eq_zero),
2707 &schema,
2708 )?,
2709 &foo,
2710 &zero,
2711 )?,
2712 &schema,
2713 col_is_nullable,
2714 );
2715
2716 assert_nullability(
2717 when_then_else(
2718 &binary(
2719 binary(Arc::clone(&foo), Operator::Eq, Arc::clone(&zero), &schema)?,
2720 Operator::Or,
2721 Arc::clone(&foo_is_null),
2722 &schema,
2723 )?,
2724 &foo,
2725 &zero,
2726 )?,
2727 &schema,
2728 col_is_nullable,
2729 );
2730
2731 assert_not_nullable(
2732 when_then_else(
2733 &binary(
2734 binary(
2735 binary(
2736 Arc::clone(&foo),
2737 Operator::Eq,
2738 Arc::clone(&zero),
2739 &schema,
2740 )?,
2741 Operator::And,
2742 Arc::clone(&foo_is_not_null),
2743 &schema,
2744 )?,
2745 Operator::Or,
2746 binary(
2747 binary(
2748 Arc::clone(&foo),
2749 Operator::Eq,
2750 Arc::clone(&foo),
2751 &schema,
2752 )?,
2753 Operator::And,
2754 Arc::clone(&foo_is_not_null),
2755 &schema,
2756 )?,
2757 &schema,
2758 )?,
2759 &foo,
2760 &zero,
2761 )?,
2762 &schema,
2763 );
2764
2765 let boolean_schema =
2766 Schema::new(vec![Field::new("predicate", DataType::Boolean, true)]);
2767 let predicate = col("predicate", &boolean_schema)?;
2768 let predicate_is_not_null = is_not_null(Arc::clone(&predicate))?;
2769 let not_predicate = expressions::not(Arc::clone(&predicate))?;
2770 assert_not_nullable(
2771 when_then_else(&predicate_is_not_null, ¬_predicate, &lit(false))?,
2772 &boolean_schema,
2773 );
2774
2775 let not_not_predicate = expressions::not(Arc::clone(¬_predicate))?;
2777 assert_not_nullable(
2778 when_then_else(&predicate_is_not_null, ¬_not_predicate, &lit(false))?,
2779 &boolean_schema,
2780 );
2781
2782 Ok(())
2783 }
2784
2785 fn assert_not_nullable(expr: Arc<dyn PhysicalExpr>, schema: &Schema) {
2786 assert!(!expr.nullable(schema).unwrap());
2787 }
2788
2789 fn assert_nullable(expr: Arc<dyn PhysicalExpr>, schema: &Schema) {
2790 assert!(expr.nullable(schema).unwrap());
2791 }
2792
2793 fn assert_nullability(expr: Arc<dyn PhysicalExpr>, schema: &Schema, nullable: bool) {
2794 if nullable {
2795 assert_nullable(expr, schema);
2796 } else {
2797 assert_not_nullable(expr, schema);
2798 }
2799 }
2800
2801 fn test_case_when_literal_lookup(
2804 values: ArrayRef,
2805 lookup_map: &[(ScalarValue, ScalarValue)],
2806 else_value: Option<ScalarValue>,
2807 expected: ArrayRef,
2808 ) {
2809 let schema = Schema::new(vec![Field::new(
2816 "a",
2817 values.data_type().clone(),
2818 values.is_nullable(),
2819 )]);
2820 let schema = Arc::new(schema);
2821
2822 let batch = RecordBatch::try_new(schema, vec![values])
2823 .expect("failed to create RecordBatch");
2824
2825 let schema = batch.schema_ref();
2826 let case = col("a", schema).expect("failed to create col");
2827
2828 let when_then = lookup_map
2829 .iter()
2830 .map(|(when, then)| {
2831 (
2832 Arc::new(Literal::new(when.clone())) as _,
2833 Arc::new(Literal::new(then.clone())) as _,
2834 )
2835 })
2836 .collect::<Vec<WhenThen>>();
2837
2838 let else_expr = else_value.map(|else_value| {
2839 Arc::new(Literal::new(else_value)) as Arc<dyn PhysicalExpr>
2840 });
2841 let expr = CaseExpr::try_new(Some(case), when_then, else_expr)
2842 .expect("failed to create case");
2843
2844 assert!(
2846 matches!(
2847 expr.eval_method,
2848 EvalMethod::WithExprScalarLookupTable { .. }
2849 ),
2850 "we should use the expected eval method"
2851 );
2852
2853 let actual = expr
2854 .evaluate(&batch)
2855 .expect("failed to evaluate case")
2856 .into_array(batch.num_rows())
2857 .expect("Failed to convert to array");
2858
2859 assert_eq!(
2860 actual.data_type(),
2861 expected.data_type(),
2862 "Data type mismatch"
2863 );
2864
2865 assert_eq!(
2866 actual.as_ref(),
2867 expected.as_ref(),
2868 "actual (left) does not match expected (right)"
2869 );
2870 }
2871
2872 fn create_lookup<When, Then>(
2873 when_then_pairs: impl IntoIterator<Item = (When, Then)>,
2874 ) -> Vec<(ScalarValue, ScalarValue)>
2875 where
2876 ScalarValue: From<When>,
2877 ScalarValue: From<Then>,
2878 {
2879 when_then_pairs
2880 .into_iter()
2881 .map(|(when, then)| (ScalarValue::from(when), ScalarValue::from(then)))
2882 .collect()
2883 }
2884
2885 fn create_input_and_expected<Input, Expected, InputFromItem, ExpectedFromItem>(
2886 input_and_expected_pairs: impl IntoIterator<Item = (InputFromItem, ExpectedFromItem)>,
2887 ) -> (Input, Expected)
2888 where
2889 Input: Array + From<Vec<InputFromItem>>,
2890 Expected: Array + From<Vec<ExpectedFromItem>>,
2891 {
2892 let (input_items, expected_items): (Vec<InputFromItem>, Vec<ExpectedFromItem>) =
2893 input_and_expected_pairs.into_iter().unzip();
2894
2895 (Input::from(input_items), Expected::from(expected_items))
2896 }
2897
2898 fn test_lookup_eval_with_and_without_else(
2899 lookup_map: &[(ScalarValue, ScalarValue)],
2900 input_values: ArrayRef,
2901 expected: StringArray,
2902 ) {
2903 test_case_when_literal_lookup(
2905 Arc::clone(&input_values),
2906 lookup_map,
2907 None,
2908 Arc::new(expected.clone()),
2909 );
2910
2911 let else_value = "___fallback___";
2913
2914 let expected_with_else = expected
2916 .iter()
2917 .map(|item| item.unwrap_or(else_value))
2918 .map(Some)
2919 .collect::<StringArray>();
2920
2921 test_case_when_literal_lookup(
2923 input_values,
2924 lookup_map,
2925 Some(ScalarValue::Utf8(Some(else_value.to_string()))),
2926 Arc::new(expected_with_else),
2927 );
2928 }
2929
2930 #[test]
2931 fn test_case_when_literal_lookup_int32_to_string() {
2932 let lookup_map = create_lookup([
2933 (Some(4), Some("four")),
2934 (Some(2), Some("two")),
2935 (Some(3), Some("three")),
2936 (Some(1), Some("one")),
2937 ]);
2938
2939 let (input_values, expected) =
2940 create_input_and_expected::<Int32Array, StringArray, _, _>([
2941 (1, Some("one")),
2942 (2, Some("two")),
2943 (3, Some("three")),
2944 (3, Some("three")),
2945 (2, Some("two")),
2946 (3, Some("three")),
2947 (5, None), (5, None), (3, Some("three")),
2950 (5, None), ]);
2952
2953 test_lookup_eval_with_and_without_else(
2954 &lookup_map,
2955 Arc::new(input_values),
2956 expected,
2957 );
2958 }
2959
2960 #[test]
2961 fn test_case_when_literal_lookup_none_case_should_never_match() {
2962 let lookup_map = create_lookup([
2963 (Some(4), Some("four")),
2964 (None, Some("none")),
2965 (Some(2), Some("two")),
2966 (Some(1), Some("one")),
2967 ]);
2968
2969 let (input_values, expected) =
2970 create_input_and_expected::<Int32Array, StringArray, _, _>([
2971 (Some(1), Some("one")),
2972 (Some(5), None), (None, None), (Some(2), Some("two")),
2975 (None, None), (None, None), (Some(2), Some("two")),
2978 (Some(5), None), ]);
2980
2981 test_lookup_eval_with_and_without_else(
2982 &lookup_map,
2983 Arc::new(input_values),
2984 expected,
2985 );
2986 }
2987
2988 #[test]
2989 fn test_case_when_literal_lookup_int32_to_string_with_duplicate_cases() {
2990 let lookup_map = create_lookup([
2991 (Some(4), Some("four")),
2992 (Some(4), Some("no 4")),
2993 (Some(2), Some("two")),
2994 (Some(2), Some("no 2")),
2995 (Some(3), Some("three")),
2996 (Some(3), Some("no 3")),
2997 (Some(2), Some("no 2")),
2998 (Some(4), Some("no 4")),
2999 (Some(2), Some("no 2")),
3000 (Some(3), Some("no 3")),
3001 (Some(4), Some("no 4")),
3002 (Some(2), Some("no 2")),
3003 (Some(3), Some("no 3")),
3004 (Some(3), Some("no 3")),
3005 ]);
3006
3007 let (input_values, expected) =
3008 create_input_and_expected::<Int32Array, StringArray, _, _>([
3009 (1, None), (2, Some("two")),
3011 (3, Some("three")),
3012 (3, Some("three")),
3013 (2, Some("two")),
3014 (3, Some("three")),
3015 (5, None), (5, None), (3, Some("three")),
3018 (5, None), ]);
3020
3021 test_lookup_eval_with_and_without_else(
3022 &lookup_map,
3023 Arc::new(input_values),
3024 expected,
3025 );
3026 }
3027
3028 #[test]
3029 fn test_case_when_literal_lookup_f32_to_string_with_special_values_and_duplicate_cases()
3030 {
3031 let lookup_map = create_lookup([
3032 (Some(4.0), Some("four point zero")),
3033 (Some(f32::NAN), Some("NaN")),
3034 (Some(3.2), Some("three point two")),
3035 (Some(f32::NAN), Some("should not use this NaN branch")),
3037 (Some(f32::INFINITY), Some("Infinity")),
3038 (Some(0.0), Some("zero")),
3039 (
3041 Some(f32::INFINITY),
3042 Some("should not use this Infinity branch"),
3043 ),
3044 (Some(1.1), Some("one point one")),
3045 ]);
3046
3047 let (input_values, expected) =
3048 create_input_and_expected::<Float32Array, StringArray, _, _>([
3049 (1.1, Some("one point one")),
3050 (f32::NAN, Some("NaN")),
3051 (3.2, Some("three point two")),
3052 (3.2, Some("three point two")),
3053 (0.0, Some("zero")),
3054 (f32::INFINITY, Some("Infinity")),
3055 (3.2, Some("three point two")),
3056 (f32::NEG_INFINITY, None), (f32::NEG_INFINITY, None), (3.2, Some("three point two")),
3059 (-0.0, None), ]);
3061
3062 test_lookup_eval_with_and_without_else(
3063 &lookup_map,
3064 Arc::new(input_values),
3065 expected,
3066 );
3067 }
3068
3069 #[test]
3070 fn test_case_when_literal_lookup_f16_to_string_with_special_values() {
3071 let lookup_map = create_lookup([
3072 (
3073 ScalarValue::Float16(Some(f16::from_f32(3.2))),
3074 Some("3 dot 2"),
3075 ),
3076 (ScalarValue::Float16(Some(f16::NAN)), Some("NaN")),
3077 (
3078 ScalarValue::Float16(Some(f16::from_f32(17.4))),
3079 Some("17 dot 4"),
3080 ),
3081 (ScalarValue::Float16(Some(f16::INFINITY)), Some("Infinity")),
3082 (ScalarValue::Float16(Some(f16::ZERO)), Some("zero")),
3083 ]);
3084
3085 let (input_values, expected) =
3086 create_input_and_expected::<Float16Array, StringArray, _, _>([
3087 (f16::from_f32(3.2), Some("3 dot 2")),
3088 (f16::NAN, Some("NaN")),
3089 (f16::from_f32(17.4), Some("17 dot 4")),
3090 (f16::from_f32(17.4), Some("17 dot 4")),
3091 (f16::INFINITY, Some("Infinity")),
3092 (f16::from_f32(17.4), Some("17 dot 4")),
3093 (f16::NEG_INFINITY, None), (f16::NEG_INFINITY, None), (f16::from_f32(17.4), Some("17 dot 4")),
3096 (f16::NEG_ZERO, None), ]);
3098
3099 test_lookup_eval_with_and_without_else(
3100 &lookup_map,
3101 Arc::new(input_values),
3102 expected,
3103 );
3104 }
3105
3106 #[test]
3107 fn test_case_when_literal_lookup_f32_to_string_with_special_values() {
3108 let lookup_map = create_lookup([
3109 (3.2, Some("3 dot 2")),
3110 (f32::NAN, Some("NaN")),
3111 (17.4, Some("17 dot 4")),
3112 (f32::INFINITY, Some("Infinity")),
3113 (f32::ZERO, Some("zero")),
3114 ]);
3115
3116 let (input_values, expected) =
3117 create_input_and_expected::<Float32Array, StringArray, _, _>([
3118 (3.2, Some("3 dot 2")),
3119 (f32::NAN, Some("NaN")),
3120 (17.4, Some("17 dot 4")),
3121 (17.4, Some("17 dot 4")),
3122 (f32::INFINITY, Some("Infinity")),
3123 (17.4, Some("17 dot 4")),
3124 (f32::NEG_INFINITY, None), (f32::NEG_INFINITY, None), (17.4, Some("17 dot 4")),
3127 (-0.0, None), ]);
3129
3130 test_lookup_eval_with_and_without_else(
3131 &lookup_map,
3132 Arc::new(input_values),
3133 expected,
3134 );
3135 }
3136
3137 #[test]
3138 fn test_case_when_literal_lookup_f64_to_string_with_special_values() {
3139 let lookup_map = create_lookup([
3140 (3.2, Some("3 dot 2")),
3141 (f64::NAN, Some("NaN")),
3142 (17.4, Some("17 dot 4")),
3143 (f64::INFINITY, Some("Infinity")),
3144 (f64::ZERO, Some("zero")),
3145 ]);
3146
3147 let (input_values, expected) =
3148 create_input_and_expected::<Float64Array, StringArray, _, _>([
3149 (3.2, Some("3 dot 2")),
3150 (f64::NAN, Some("NaN")),
3151 (17.4, Some("17 dot 4")),
3152 (17.4, Some("17 dot 4")),
3153 (f64::INFINITY, Some("Infinity")),
3154 (17.4, Some("17 dot 4")),
3155 (f64::NEG_INFINITY, None), (f64::NEG_INFINITY, None), (17.4, Some("17 dot 4")),
3158 (-0.0, None), ]);
3160
3161 test_lookup_eval_with_and_without_else(
3162 &lookup_map,
3163 Arc::new(input_values),
3164 expected,
3165 );
3166 }
3167
3168 #[test]
3170 fn test_decimal_with_non_default_precision_and_scale() {
3171 let lookup_map = create_lookup([
3172 (ScalarValue::Decimal32(Some(4), 3, 2), Some("four")),
3173 (ScalarValue::Decimal32(Some(2), 3, 2), Some("two")),
3174 (ScalarValue::Decimal32(Some(3), 3, 2), Some("three")),
3175 (ScalarValue::Decimal32(Some(1), 3, 2), Some("one")),
3176 ]);
3177
3178 let (input_values, expected) =
3179 create_input_and_expected::<Decimal32Array, StringArray, _, _>([
3180 (1, Some("one")),
3181 (2, Some("two")),
3182 (3, Some("three")),
3183 (3, Some("three")),
3184 (2, Some("two")),
3185 (3, Some("three")),
3186 (5, None), (5, None), (3, Some("three")),
3189 (5, None), ]);
3191
3192 let input_values = input_values
3193 .with_precision_and_scale(3, 2)
3194 .expect("must be able to set precision and scale");
3195
3196 test_lookup_eval_with_and_without_else(
3197 &lookup_map,
3198 Arc::new(input_values),
3199 expected,
3200 );
3201 }
3202
3203 #[test]
3205 fn test_timestamp_with_non_default_timezone() {
3206 let timezone: Option<Arc<str>> = Some("-10:00".into());
3207 let lookup_map = create_lookup([
3208 (
3209 ScalarValue::TimestampMillisecond(Some(4), timezone.clone()),
3210 Some("four"),
3211 ),
3212 (
3213 ScalarValue::TimestampMillisecond(Some(2), timezone.clone()),
3214 Some("two"),
3215 ),
3216 (
3217 ScalarValue::TimestampMillisecond(Some(3), timezone.clone()),
3218 Some("three"),
3219 ),
3220 (
3221 ScalarValue::TimestampMillisecond(Some(1), timezone.clone()),
3222 Some("one"),
3223 ),
3224 ]);
3225
3226 let (input_values, expected) =
3227 create_input_and_expected::<TimestampMillisecondArray, StringArray, _, _>([
3228 (1, Some("one")),
3229 (2, Some("two")),
3230 (3, Some("three")),
3231 (3, Some("three")),
3232 (2, Some("two")),
3233 (3, Some("three")),
3234 (5, None), (5, None), (3, Some("three")),
3237 (5, None), ]);
3239
3240 let input_values = input_values.with_timezone_opt(timezone);
3241
3242 test_lookup_eval_with_and_without_else(
3243 &lookup_map,
3244 Arc::new(input_values),
3245 expected,
3246 );
3247 }
3248
3249 #[test]
3250 fn test_with_strings_to_int32() {
3251 let lookup_map = create_lookup([
3252 (Some("why"), Some(42)),
3253 (Some("what"), Some(22)),
3254 (Some("when"), Some(17)),
3255 ]);
3256
3257 let (input_values, expected) =
3258 create_input_and_expected::<StringArray, Int32Array, _, _>([
3259 (Some("why"), Some(42)),
3260 (Some("5"), None), (None, None), (Some("what"), Some(22)),
3263 (None, None), (None, None), (Some("what"), Some(22)),
3266 (Some("5"), None), ]);
3268
3269 let input_values = Arc::new(input_values) as ArrayRef;
3270
3271 test_case_when_literal_lookup(
3273 Arc::clone(&input_values),
3274 &lookup_map,
3275 None,
3276 Arc::new(expected.clone()),
3277 );
3278
3279 let else_value = 101;
3281
3282 let expected_with_else = expected
3284 .iter()
3285 .map(|item| item.unwrap_or(else_value))
3286 .map(Some)
3287 .collect::<Int32Array>();
3288
3289 test_case_when_literal_lookup(
3291 input_values,
3292 &lookup_map,
3293 Some(ScalarValue::Int32(Some(else_value))),
3294 Arc::new(expected_with_else),
3295 );
3296 }
3297
3298 #[test]
3303 fn nested_self_referential_case_hash_stays_bounded() -> Result<()> {
3304 use std::hash::Hasher;
3305
3306 #[derive(Default)]
3307 struct CountingHasher {
3308 write_calls: usize,
3309 bytes_written: usize,
3310 }
3311
3312 impl Hasher for CountingHasher {
3313 fn finish(&self) -> u64 {
3314 0
3315 }
3316
3317 fn write(&mut self, bytes: &[u8]) {
3318 self.write_calls += 1;
3319 self.bytes_written += bytes.len();
3320 }
3321 }
3322
3323 let schema =
3324 Arc::new(Schema::new(vec![Field::new("kind", DataType::Utf8, true)]));
3325
3326 let kind = col("kind", &schema)?;
3327 let mut label = Arc::clone(&kind);
3328
3329 let num_levels = 18;
3330 for idx in 0..num_levels {
3331 let predicate = Arc::new(BinaryExpr::new(
3332 Arc::clone(&kind),
3333 Operator::Eq,
3334 lit(idx.to_string()),
3335 )) as Arc<dyn PhysicalExpr>;
3336
3337 label = case(None, vec![(predicate, lit("label"))], Some(label))?;
3338 }
3339
3340 let mut hasher = CountingHasher::default();
3341 label.hash(&mut hasher);
3342
3343 assert!(
3344 hasher.write_calls < 50_000,
3345 "hashing nested CASE expression took {} hasher writes and {} bytes",
3346 hasher.write_calls,
3347 hasher.bytes_written
3348 );
3349
3350 Ok(())
3351 }
3352}
3353
3354#[cfg(all(test, feature = "proto"))]
3355mod proto_tests {
3356 use super::*;
3357 use crate::expressions::col;
3358 use crate::proto_test_util::{
3359 StubDecoder, StubEncoder, UnreachableDecoder, column_node,
3360 };
3361 use arrow::datatypes::Field;
3362 use datafusion_physical_expr_common::physical_expr::proto_decode::PhysicalExprDecodeCtx;
3363 use datafusion_physical_expr_common::physical_expr::proto_encode::PhysicalExprEncodeCtx;
3364 use datafusion_proto_models::protobuf;
3365 use datafusion_proto_models::protobuf::{PhysicalExprNode, PhysicalWhenThen};
3366
3367 fn proto_case_fixture() -> CaseExpr {
3368 let schema = Schema::new(vec![Field::new("a", DataType::Boolean, true)]);
3369 CaseExpr::try_new(
3370 Some(col("a", &schema).unwrap()),
3371 vec![(lit(true), lit(1_i32))],
3372 Some(lit(0_i32)),
3373 )
3374 .unwrap()
3375 }
3376
3377 fn proto_when_then(
3378 when_expr: Option<PhysicalExprNode>,
3379 then_expr: Option<PhysicalExprNode>,
3380 ) -> PhysicalWhenThen {
3381 PhysicalWhenThen {
3382 when_expr,
3383 then_expr,
3384 }
3385 }
3386
3387 fn proto_case_node(
3388 expr: Option<Box<PhysicalExprNode>>,
3389 when_then_expr: Vec<PhysicalWhenThen>,
3390 else_expr: Option<Box<PhysicalExprNode>>,
3391 ) -> PhysicalExprNode {
3392 PhysicalExprNode {
3393 expr_id: None,
3394 expr_type: Some(protobuf::physical_expr_node::ExprType::Case(Box::new(
3395 protobuf::PhysicalCaseNode {
3396 expr,
3397 when_then_expr,
3398 else_expr,
3399 },
3400 ))),
3401 }
3402 }
3403
3404 #[test]
3405 fn try_to_proto_encodes_case_expr() {
3406 let case = proto_case_fixture();
3407 let encoder = StubEncoder::ok();
3408 let ctx = PhysicalExprEncodeCtx::new(&encoder);
3409
3410 let node = case
3411 .try_to_proto(&ctx)
3412 .unwrap()
3413 .expect("CaseExpr should encode to Some(node)");
3414
3415 assert!(node.expr_id.is_none());
3416 let case_node = match node.expr_type {
3417 Some(protobuf::physical_expr_node::ExprType::Case(boxed)) => *boxed,
3418 other => panic!("expected a CaseExpr node, got {other:?}"),
3419 };
3420 assert!(case_node.expr.is_some());
3421 assert_eq!(case_node.when_then_expr.len(), 1);
3422 assert!(case_node.when_then_expr[0].when_expr.is_some());
3423 assert!(case_node.when_then_expr[0].then_expr.is_some());
3424 assert!(case_node.else_expr.is_some());
3425 }
3426
3427 #[test]
3428 fn try_to_proto_propagates_child_encode_error() {
3429 let case = proto_case_fixture();
3430 let encoder = StubEncoder::failing_on(2);
3432 let ctx = PhysicalExprEncodeCtx::new(&encoder);
3433
3434 let err = case.try_to_proto(&ctx).unwrap_err();
3435 assert!(matches!(err, DataFusionError::Internal(msg) if msg.contains("call 2")));
3436 }
3437
3438 #[test]
3439 fn try_from_proto_decodes_case_expr() {
3440 let node = proto_case_node(
3441 Some(Box::new(column_node("case"))),
3442 vec![proto_when_then(
3443 Some(column_node("when")),
3444 Some(column_node("then")),
3445 )],
3446 Some(Box::new(column_node("else"))),
3447 );
3448 let schema = Schema::empty();
3449 let decoder = StubDecoder::ok();
3450 let ctx = PhysicalExprDecodeCtx::new(&schema, &decoder);
3451
3452 let decoded = CaseExpr::try_from_proto(&node, &ctx).unwrap();
3453 let case = decoded
3454 .downcast_ref::<CaseExpr>()
3455 .expect("decoded expr should be a CaseExpr");
3456
3457 assert!(case.expr().is_some());
3458 assert_eq!(case.when_then_expr().len(), 1);
3459 assert!(case.else_expr().is_some());
3460 }
3461
3462 #[test]
3463 fn try_from_proto_rejects_non_case_node() {
3464 let node = column_node("a");
3465 let schema = Schema::empty();
3466 let decoder = UnreachableDecoder;
3467 let ctx = PhysicalExprDecodeCtx::new(&schema, &decoder);
3468
3469 let err = CaseExpr::try_from_proto(&node, &ctx).unwrap_err();
3470 assert!(
3471 matches!(err, DataFusionError::Internal(msg) if msg.contains("PhysicalExprNode is not a CaseExpr"))
3472 );
3473 }
3474
3475 #[test]
3476 fn try_from_proto_rejects_missing_when_expr() {
3477 let node = proto_case_node(
3478 None,
3479 vec![proto_when_then(None, Some(column_node("then")))],
3480 None,
3481 );
3482 let schema = Schema::empty();
3483 let decoder = UnreachableDecoder;
3484 let ctx = PhysicalExprDecodeCtx::new(&schema, &decoder);
3485
3486 let err = CaseExpr::try_from_proto(&node, &ctx).unwrap_err();
3487 assert!(
3488 matches!(err, DataFusionError::Internal(msg) if msg.contains("CaseExpr is missing required field 'when_expr'"))
3489 );
3490 }
3491
3492 #[test]
3493 fn try_from_proto_rejects_missing_then_expr() {
3494 let node = proto_case_node(
3495 None,
3496 vec![proto_when_then(Some(column_node("when")), None)],
3497 None,
3498 );
3499 let schema = Schema::empty();
3500 let decoder = StubDecoder::ok();
3501 let ctx = PhysicalExprDecodeCtx::new(&schema, &decoder);
3502
3503 let err = CaseExpr::try_from_proto(&node, &ctx).unwrap_err();
3504 assert!(
3505 matches!(err, DataFusionError::Internal(msg) if msg.contains("CaseExpr is missing required field 'then_expr'"))
3506 );
3507 }
3508
3509 #[test]
3510 fn try_from_proto_propagates_child_decode_error() {
3511 let node = proto_case_node(
3512 Some(Box::new(column_node("case"))),
3513 vec![proto_when_then(
3514 Some(column_node("when")),
3515 Some(column_node("then")),
3516 )],
3517 Some(Box::new(column_node("else"))),
3518 );
3519 let schema = Schema::empty();
3520 let decoder = StubDecoder::failing_on(2);
3521 let ctx = PhysicalExprDecodeCtx::new(&schema, &decoder);
3522
3523 let err = CaseExpr::try_from_proto(&node, &ctx).unwrap_err();
3524 assert!(matches!(err, DataFusionError::Internal(msg) if msg.contains("call 2")));
3525 }
3526}