1use arrow::{
21 array::{
22 Array, ArrayRef, Date32Array, Date64Array, NullArray, TimestampMicrosecondArray,
23 TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray,
24 },
25 compute::{CastOptions, kernels, max, min},
26 datatypes::{DataType, TimeUnit},
27 util::pretty::pretty_format_columns,
28};
29use datafusion_common::internal_datafusion_err;
30use datafusion_common::{
31 Result, ScalarValue,
32 format::DEFAULT_CAST_OPTIONS,
33 internal_err,
34 scalar::{
35 date_to_timestamp_multiplier, ensure_timestamp_in_bounds,
36 timestamp_to_timestamp_multiplier,
37 },
38};
39use std::fmt;
40use std::sync::Arc;
41
42#[derive(Clone, Debug)]
102pub enum ColumnarValue {
103 Array(ArrayRef),
105 Scalar(ScalarValue),
107}
108
109impl From<ArrayRef> for ColumnarValue {
110 fn from(value: ArrayRef) -> Self {
111 ColumnarValue::Array(value)
112 }
113}
114
115impl From<ScalarValue> for ColumnarValue {
116 fn from(value: ScalarValue) -> Self {
117 ColumnarValue::Scalar(value)
118 }
119}
120
121impl ColumnarValue {
122 pub fn data_type(&self) -> DataType {
123 match self {
124 ColumnarValue::Array(array_value) => array_value.data_type().clone(),
125 ColumnarValue::Scalar(scalar_value) => scalar_value.data_type(),
126 }
127 }
128
129 pub fn into_array(self, num_rows: usize) -> Result<ArrayRef> {
143 Ok(match self {
144 ColumnarValue::Array(array) => array,
145 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(num_rows)?,
146 })
147 }
148
149 pub fn into_array_of_size(self, num_rows: usize) -> Result<ArrayRef> {
163 match self {
164 ColumnarValue::Array(array) => {
165 if array.len() == num_rows {
166 Ok(array)
167 } else {
168 internal_err!(
169 "Array length {} does not match expected length {}",
170 array.len(),
171 num_rows
172 )
173 }
174 }
175 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(num_rows),
176 }
177 }
178
179 pub fn to_array(&self, num_rows: usize) -> Result<ArrayRef> {
193 Ok(match self {
194 ColumnarValue::Array(array) => Arc::clone(array),
195 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(num_rows)?,
196 })
197 }
198
199 pub fn to_array_of_size(&self, num_rows: usize) -> Result<ArrayRef> {
213 match self {
214 ColumnarValue::Array(array) => {
215 if array.len() == num_rows {
216 Ok(Arc::clone(array))
217 } else {
218 internal_err!(
219 "Array length {} does not match expected length {}",
220 array.len(),
221 num_rows
222 )
223 }
224 }
225 ColumnarValue::Scalar(scalar) => scalar.to_array_of_size(num_rows),
226 }
227 }
228
229 pub fn create_null_array(num_rows: usize) -> Self {
232 ColumnarValue::Array(Arc::new(NullArray::new(num_rows)))
233 }
234
235 pub fn values_to_arrays(args: &[ColumnarValue]) -> Result<Vec<ArrayRef>> {
250 if args.is_empty() {
251 return Ok(vec![]);
252 }
253
254 let mut array_len = None;
255 for arg in args {
256 array_len = match (arg, array_len) {
257 (ColumnarValue::Array(a), None) => Some(a.len()),
258 (ColumnarValue::Array(a), Some(array_len)) => {
259 if array_len == a.len() {
260 Some(array_len)
261 } else {
262 return internal_err!(
263 "Arguments has mixed length. Expected length: {array_len}, found length: {}",
264 a.len()
265 );
266 }
267 }
268 (ColumnarValue::Scalar(_), array_len) => array_len,
269 }
270 }
271
272 let inferred_length = array_len.unwrap_or(1);
274
275 let args = args
276 .iter()
277 .map(|arg| arg.to_array(inferred_length))
278 .collect::<Result<Vec<_>>>()?;
279
280 Ok(args)
281 }
282
283 pub fn cast_to(
295 &self,
296 cast_type: &DataType,
297 cast_options: Option<&CastOptions<'static>>,
298 ) -> Result<ColumnarValue> {
299 let cast_options = cast_options.cloned().unwrap_or(DEFAULT_CAST_OPTIONS);
300 match self {
301 ColumnarValue::Array(array) => {
302 let casted = cast_array_by_name(array, cast_type, &cast_options)?;
303 Ok(ColumnarValue::Array(casted))
304 }
305 ColumnarValue::Scalar(scalar) => Ok(ColumnarValue::Scalar(
306 scalar.cast_to_with_options(cast_type, &cast_options)?,
307 )),
308 }
309 }
310}
311
312fn cast_array_by_name(
313 array: &ArrayRef,
314 cast_type: &DataType,
315 cast_options: &CastOptions<'static>,
316) -> Result<ArrayRef> {
317 if array.data_type() == cast_type {
319 return Ok(Arc::clone(array));
320 }
321
322 if datafusion_common::nested_struct::requires_nested_struct_cast(
323 array.data_type(),
324 cast_type,
325 ) {
326 datafusion_common::nested_struct::cast_column(array, cast_type, cast_options)
327 } else {
328 if !cast_options.safe {
329 ensure_temporal_array_timestamp_bounds(array, cast_type)?;
330 }
331 Ok(kernels::cast::cast_with_options(
332 array,
333 cast_type,
334 cast_options,
335 )?)
336 }
337}
338
339fn ensure_temporal_array_timestamp_bounds(
340 array: &ArrayRef,
341 cast_type: &DataType,
342) -> Result<()> {
343 let source_type = array.data_type().clone();
344 let Some(multiplier) = date_to_timestamp_multiplier(&source_type, cast_type)
345 .or_else(|| timestamp_to_timestamp_multiplier(&source_type, cast_type))
346 else {
347 return Ok(());
348 };
349
350 if multiplier <= 1 {
351 return Ok(());
352 }
353
354 let (min_val, max_val): (Option<i64>, Option<i64>) = match &source_type {
356 DataType::Date32 => {
357 let arr = array
358 .as_any()
359 .downcast_ref::<Date32Array>()
360 .ok_or_else(|| {
361 internal_datafusion_err!(
362 "Expected Date32Array but found {}",
363 array.data_type()
364 )
365 })?;
366 (min(arr).map(|v| v as i64), max(arr).map(|v| v as i64))
367 }
368 DataType::Date64 => {
369 let arr = array
370 .as_any()
371 .downcast_ref::<Date64Array>()
372 .ok_or_else(|| {
373 internal_datafusion_err!(
374 "Expected Date64Array but found {}",
375 array.data_type()
376 )
377 })?;
378 (min(arr), max(arr))
379 }
380 DataType::Timestamp(TimeUnit::Second, _) => {
381 let arr = array
382 .as_any()
383 .downcast_ref::<TimestampSecondArray>()
384 .ok_or_else(|| {
385 internal_datafusion_err!(
386 "Expected TimestampSecondArray but found {}",
387 array.data_type()
388 )
389 })?;
390 (min(arr), max(arr))
391 }
392 DataType::Timestamp(TimeUnit::Millisecond, _) => {
393 let arr = array
394 .as_any()
395 .downcast_ref::<TimestampMillisecondArray>()
396 .ok_or_else(|| {
397 internal_datafusion_err!(
398 "Expected TimestampMillisecondArray but found {}",
399 array.data_type()
400 )
401 })?;
402 (min(arr), max(arr))
403 }
404 DataType::Timestamp(TimeUnit::Microsecond, _) => {
405 let arr = array
406 .as_any()
407 .downcast_ref::<TimestampMicrosecondArray>()
408 .ok_or_else(|| {
409 internal_datafusion_err!(
410 "Expected TimestampMicrosecondArray but found {}",
411 array.data_type()
412 )
413 })?;
414 (min(arr), max(arr))
415 }
416 DataType::Timestamp(TimeUnit::Nanosecond, _) => {
417 let arr = array
418 .as_any()
419 .downcast_ref::<TimestampNanosecondArray>()
420 .ok_or_else(|| {
421 internal_datafusion_err!(
422 "Expected TimestampNanosecondArray but found {}",
423 array.data_type()
424 )
425 })?;
426 (min(arr), max(arr))
427 }
428 _ => return Ok(()), };
430
431 if let Some(min) = min_val {
433 ensure_timestamp_in_bounds(min, multiplier, &source_type, cast_type)?;
434 }
435 if let Some(max) = max_val {
436 ensure_timestamp_in_bounds(max, multiplier, &source_type, cast_type)?;
437 }
438
439 Ok(())
440}
441
442impl fmt::Display for ColumnarValue {
444 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
445 let formatted = match self {
446 ColumnarValue::Array(array) => {
447 pretty_format_columns("ColumnarValue(ArrayRef)", &[Arc::clone(array)])
448 }
449 ColumnarValue::Scalar(_) => {
450 if let Ok(array) = self.to_array(1) {
451 pretty_format_columns("ColumnarValue(ScalarValue)", &[array])
452 } else {
453 return write!(f, "Error formatting columnar value");
454 }
455 }
456 };
457
458 if let Ok(formatted) = formatted {
459 write!(f, "{formatted}")
460 } else {
461 write!(f, "Error formatting columnar value")
462 }
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469 use arrow::{
470 array::{Date64Array, Int32Array, StructArray},
471 datatypes::{Field, Fields, TimeUnit},
472 };
473
474 #[test]
475 fn into_array_of_size() {
476 let arr = make_array(1, 3);
478 let arr_columnar_value = ColumnarValue::Array(Arc::clone(&arr));
479 assert_eq!(&arr_columnar_value.into_array_of_size(3).unwrap(), &arr);
480
481 let scalar_columnar_value = ColumnarValue::Scalar(ScalarValue::Int32(Some(42)));
483 let expected_array = make_array(42, 100);
484 assert_eq!(
485 &scalar_columnar_value.into_array_of_size(100).unwrap(),
486 &expected_array
487 );
488
489 let arr = make_array(1, 3);
491 let arr_columnar_value = ColumnarValue::Array(Arc::clone(&arr));
492 let result = arr_columnar_value.into_array_of_size(5);
493 let err = result.unwrap_err();
494 assert!(
495 err.to_string().starts_with(
496 "Internal error: Array length 3 does not match expected length 5"
497 ),
498 "Found: {err}"
499 );
500 }
501
502 #[test]
503 fn values_to_arrays() {
504 let cases = vec![
506 TestCase {
508 input: vec![],
509 expected: vec![],
510 },
511 TestCase {
513 input: vec![ColumnarValue::Array(make_array(1, 3))],
514 expected: vec![make_array(1, 3)],
515 },
516 TestCase {
518 input: vec![
519 ColumnarValue::Array(make_array(1, 3)),
520 ColumnarValue::Array(make_array(2, 3)),
521 ],
522 expected: vec![make_array(1, 3), make_array(2, 3)],
523 },
524 TestCase {
526 input: vec![
527 ColumnarValue::Array(make_array(1, 3)),
528 ColumnarValue::Scalar(ScalarValue::Int32(Some(100))),
529 ],
530 expected: vec![
531 make_array(1, 3),
532 make_array(100, 3), ],
534 },
535 TestCase {
537 input: vec![
538 ColumnarValue::Scalar(ScalarValue::Int32(Some(100))),
539 ColumnarValue::Array(make_array(1, 3)),
540 ],
541 expected: vec![
542 make_array(100, 3), make_array(1, 3),
544 ],
545 },
546 TestCase {
548 input: vec![
549 ColumnarValue::Scalar(ScalarValue::Int32(Some(100))),
550 ColumnarValue::Array(make_array(1, 3)),
551 ColumnarValue::Scalar(ScalarValue::Int32(Some(200))),
552 ],
553 expected: vec![
554 make_array(100, 3), make_array(1, 3),
556 make_array(200, 3), ],
558 },
559 ];
560 for case in cases {
561 case.run();
562 }
563 }
564
565 #[test]
566 #[should_panic(
567 expected = "Arguments has mixed length. Expected length: 3, found length: 4"
568 )]
569 fn values_to_arrays_mixed_length() {
570 ColumnarValue::values_to_arrays(&[
571 ColumnarValue::Array(make_array(1, 3)),
572 ColumnarValue::Array(make_array(2, 4)),
573 ])
574 .unwrap();
575 }
576
577 #[test]
578 #[should_panic(
579 expected = "Arguments has mixed length. Expected length: 3, found length: 7"
580 )]
581 fn values_to_arrays_mixed_length_and_scalar() {
582 ColumnarValue::values_to_arrays(&[
583 ColumnarValue::Array(make_array(1, 3)),
584 ColumnarValue::Scalar(ScalarValue::Int32(Some(100))),
585 ColumnarValue::Array(make_array(2, 7)),
586 ])
587 .unwrap();
588 }
589
590 struct TestCase {
591 input: Vec<ColumnarValue>,
592 expected: Vec<ArrayRef>,
593 }
594
595 impl TestCase {
596 fn run(self) {
597 let Self { input, expected } = self;
598
599 assert_eq!(
600 ColumnarValue::values_to_arrays(&input).unwrap(),
601 expected,
602 "\ninput: {input:?}\nexpected: {expected:?}"
603 );
604 }
605 }
606
607 fn make_array(val: i32, len: usize) -> ArrayRef {
609 Arc::new(Int32Array::from(vec![val; len]))
610 }
611
612 #[test]
613 fn test_display_scalar() {
614 let column = ColumnarValue::from(ScalarValue::from("foo"));
615 assert_eq!(
616 column.to_string(),
617 concat!(
618 "+----------------------------+\n",
619 "| ColumnarValue(ScalarValue) |\n",
620 "+----------------------------+\n",
621 "| foo |\n",
622 "+----------------------------+"
623 )
624 );
625 }
626
627 #[test]
628 fn test_display_array() {
629 let array: ArrayRef = Arc::new(Int32Array::from_iter_values(vec![1, 2, 3]));
630 let column = ColumnarValue::from(array);
631 assert_eq!(
632 column.to_string(),
633 concat!(
634 "+-------------------------+\n",
635 "| ColumnarValue(ArrayRef) |\n",
636 "+-------------------------+\n",
637 "| 1 |\n",
638 "| 2 |\n",
639 "| 3 |\n",
640 "+-------------------------+"
641 )
642 );
643 }
644
645 #[test]
646 fn cast_struct_by_field_name() {
647 let source_fields = Fields::from(vec![
648 Field::new("b", DataType::Int32, true),
649 Field::new("a", DataType::Int32, true),
650 ]);
651
652 let target_fields = Fields::from(vec![
653 Field::new("a", DataType::Int32, true),
654 Field::new("b", DataType::Int32, true),
655 ]);
656
657 let struct_array = StructArray::new(
658 source_fields,
659 vec![
660 Arc::new(Int32Array::from(vec![Some(3)])),
661 Arc::new(Int32Array::from(vec![Some(4)])),
662 ],
663 None,
664 );
665
666 let value = ColumnarValue::Array(Arc::new(struct_array));
667 let casted = value
668 .cast_to(&DataType::Struct(target_fields.clone()), None)
669 .expect("struct cast should succeed");
670
671 let ColumnarValue::Array(arr) = casted else {
672 panic!("expected array after cast");
673 };
674
675 let struct_array = arr
676 .as_any()
677 .downcast_ref::<StructArray>()
678 .expect("expected StructArray");
679
680 let field_a = struct_array
681 .column_by_name("a")
682 .expect("expected field a in cast result");
683 let field_b = struct_array
684 .column_by_name("b")
685 .expect("expected field b in cast result");
686
687 assert_eq!(
688 field_a
689 .as_any()
690 .downcast_ref::<Int32Array>()
691 .expect("expected Int32 array")
692 .value(0),
693 4
694 );
695 assert_eq!(
696 field_b
697 .as_any()
698 .downcast_ref::<Int32Array>()
699 .expect("expected Int32 array")
700 .value(0),
701 3
702 );
703 }
704
705 #[test]
706 fn cast_struct_missing_field_inserts_nulls() {
707 let source_fields = Fields::from(vec![Field::new("a", DataType::Int32, true)]);
708
709 let target_fields = Fields::from(vec![
710 Field::new("a", DataType::Int32, true),
711 Field::new("b", DataType::Int32, true),
712 ]);
713
714 let struct_array = StructArray::new(
715 source_fields,
716 vec![Arc::new(Int32Array::from(vec![Some(5)]))],
717 None,
718 );
719
720 let value = ColumnarValue::Array(Arc::new(struct_array));
721 let casted = value
722 .cast_to(&DataType::Struct(target_fields.clone()), None)
723 .expect("struct cast should succeed");
724
725 let ColumnarValue::Array(arr) = casted else {
726 panic!("expected array after cast");
727 };
728
729 let struct_array = arr
730 .as_any()
731 .downcast_ref::<StructArray>()
732 .expect("expected StructArray");
733
734 let field_b = struct_array
735 .column_by_name("b")
736 .expect("expected missing field to be added");
737
738 assert!(field_b.is_null(0));
739 }
740
741 #[test]
742 fn cast_date64_array_to_timestamp_overflow() {
743 let overflow_value = i64::MAX / 1_000_000 + 1;
744 let array: ArrayRef = Arc::new(Date64Array::from(vec![Some(overflow_value)]));
745 let value = ColumnarValue::Array(array);
746 let result =
747 value.cast_to(&DataType::Timestamp(TimeUnit::Nanosecond, None), None);
748 let err = result.expect_err("expected overflow to be detected");
749 assert!(
750 err.to_string()
751 .contains("converted value exceeds the representable i64 range"),
752 "unexpected error: {err}"
753 );
754 }
755
756 #[test]
757 fn cast_timestamp_array_to_timestamp_overflow() {
758 let overflow_value = i64::MAX / 1_000_000_000 + 1;
759 let array: ArrayRef =
760 Arc::new(TimestampSecondArray::from(vec![Some(overflow_value)]));
761 let value = ColumnarValue::Array(array);
762 let result =
763 value.cast_to(&DataType::Timestamp(TimeUnit::Nanosecond, None), None);
764 let err = result.expect_err("expected overflow to be detected");
765 assert!(
766 err.to_string()
767 .contains("converted value exceeds the representable i64 range"),
768 "unexpected error: {err}"
769 );
770 }
771
772 #[test]
773 fn safe_cast_timestamp_array_to_timestamp_overflow_returns_null() {
774 let overflow_value = i64::MAX / 1_000_000_000 + 1;
775 let array: ArrayRef =
776 Arc::new(TimestampSecondArray::from(vec![Some(overflow_value)]));
777 let value = ColumnarValue::Array(array);
778 let safe_options = CastOptions {
779 safe: true,
780 ..DEFAULT_CAST_OPTIONS
781 };
782
783 let casted = value
784 .cast_to(
785 &DataType::Timestamp(TimeUnit::Nanosecond, None),
786 Some(&safe_options),
787 )
788 .expect("expected safe cast to return null");
789
790 let ColumnarValue::Array(array) = casted else {
791 panic!("expected array after cast");
792 };
793 let array = array
794 .as_any()
795 .downcast_ref::<TimestampNanosecondArray>()
796 .expect("expected TimestampNanosecondArray");
797 assert!(array.is_null(0));
798 }
799}