1use std::fmt::{self, Display};
16use std::sync::Arc;
17
18use datafusion::arrow::array::{Array, ArrayRef, AsArray, PrimitiveArray};
19use datafusion::arrow::datatypes::DataType as ArrowDataType;
20use datafusion::logical_expr::{ColumnarValue, Volatility};
21use datafusion_common::{DataFusionError, ScalarValue, utils};
22use datafusion_expr::{ScalarFunctionArgs, Signature};
23
24use crate::function::Function;
25use crate::helper::NUMERICS;
26
27#[derive(Clone, Debug)]
28pub struct ClampFunction {
29 signature: Signature,
30}
31
32impl Default for ClampFunction {
33 fn default() -> Self {
34 Self {
35 signature: Signature::uniform(3, NUMERICS.to_vec(), Volatility::Immutable),
37 }
38 }
39}
40
41const CLAMP_NAME: &str = "clamp";
42
43impl Function for ClampFunction {
44 fn name(&self) -> &str {
45 CLAMP_NAME
46 }
47
48 fn return_type(
49 &self,
50 input_types: &[ArrowDataType],
51 ) -> datafusion_common::Result<ArrowDataType> {
52 Ok(input_types[0].clone())
54 }
55
56 fn signature(&self) -> &Signature {
57 &self.signature
58 }
59
60 fn invoke_with_args(
61 &self,
62 args: ScalarFunctionArgs,
63 ) -> datafusion_common::Result<ColumnarValue> {
64 let [col, min, max] = utils::take_function_args(self.name(), args.args)?;
65 clamp_impl(col, min, max)
66 }
67}
68
69impl Display for ClampFunction {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 write!(f, "{}", CLAMP_NAME.to_ascii_uppercase())
72 }
73}
74
75fn clamp_impl(
76 col: ColumnarValue,
77 min: ColumnarValue,
78 max: ColumnarValue,
79) -> datafusion_common::Result<ColumnarValue> {
80 if col.data_type() != min.data_type() || min.data_type() != max.data_type() {
81 return Err(DataFusionError::Execution(format!(
82 "argument data types mismatch: {}, {}, {}",
83 col.data_type(),
84 min.data_type(),
85 max.data_type(),
86 )));
87 }
88
89 macro_rules! with_match_numerics_types {
90 ($data_type:expr, | $_:tt $T:ident | $body:tt) => {{
91 macro_rules! __with_ty__ {
92 ( $_ $T:ident ) => {
93 $body
94 };
95 }
96
97 use datafusion::arrow::datatypes::{
98 Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type,
99 UInt16Type, UInt32Type, UInt64Type,
100 };
101
102 match $data_type {
103 ArrowDataType::Int8 => Ok(__with_ty__! { Int8Type }),
104 ArrowDataType::Int16 => Ok(__with_ty__! { Int16Type }),
105 ArrowDataType::Int32 => Ok(__with_ty__! { Int32Type }),
106 ArrowDataType::Int64 => Ok(__with_ty__! { Int64Type }),
107 ArrowDataType::UInt8 => Ok(__with_ty__! { UInt8Type }),
108 ArrowDataType::UInt16 => Ok(__with_ty__! { UInt16Type }),
109 ArrowDataType::UInt32 => Ok(__with_ty__! { UInt32Type }),
110 ArrowDataType::UInt64 => Ok(__with_ty__! { UInt64Type }),
111 ArrowDataType::Float32 => Ok(__with_ty__! { Float32Type }),
112 ArrowDataType::Float64 => Ok(__with_ty__! { Float64Type }),
113 _ => Err(DataFusionError::Execution(format!(
114 "unsupported numeric data type: '{}'",
115 $data_type
116 ))),
117 }
118 }};
119 }
120
121 macro_rules! clamp {
122 ($v: ident, $min: ident, $max: ident) => {
123 if $v < $min {
124 $min
125 } else if $v > $max {
126 $max
127 } else {
128 $v
129 }
130 };
131 }
132
133 match (col, min, max) {
134 (ColumnarValue::Scalar(col), ColumnarValue::Scalar(min), ColumnarValue::Scalar(max)) => {
135 if min > max {
136 return Err(DataFusionError::Execution(format!(
137 "min '{}' > max '{}'",
138 min, max
139 )));
140 }
141 Ok(ColumnarValue::Scalar(clamp!(col, min, max)))
142 }
143
144 (ColumnarValue::Array(col), ColumnarValue::Array(min), ColumnarValue::Array(max)) => {
145 if col.len() != min.len() || col.len() != max.len() {
146 return Err(DataFusionError::Internal(
147 "arguments not of same length".to_string(),
148 ));
149 }
150 let result = with_match_numerics_types!(
151 col.data_type(),
152 |$S| {
153 let col = col.as_primitive::<$S>();
154 let min = min.as_primitive::<$S>();
155 let max = max.as_primitive::<$S>();
156 Arc::new(PrimitiveArray::<$S>::from(
157 (0..col.len())
158 .map(|i| {
159 let v = col.is_valid(i).then(|| col.value(i));
160 let min = min.is_valid(i).then(|| min.value(i));
162 let max = max.is_valid(i).then(|| max.value(i));
163 Ok(match (v, min, max) {
164 (Some(v), Some(min), Some(max)) => {
165 if min > max {
166 return Err(DataFusionError::Execution(format!(
167 "min '{}' > max '{}'",
168 min, max
169 )));
170 }
171 Some(clamp!(v, min, max))
172 },
173 _ => None,
174 })
175 })
176 .collect::<datafusion_common::Result<Vec<_>>>()?,
177 )
178 ) as ArrayRef
179 }
180 )?;
181 Ok(ColumnarValue::Array(result))
182 }
183
184 (ColumnarValue::Array(col), ColumnarValue::Scalar(min), ColumnarValue::Scalar(max)) => {
185 if min.is_null() || max.is_null() {
186 return Err(DataFusionError::Execution(
187 "argument 'min' or 'max' is null".to_string(),
188 ));
189 }
190 let min = min.to_array()?;
191 let max = max.to_array()?;
192 let result = with_match_numerics_types!(
193 col.data_type(),
194 |$S| {
195 let col = col.as_primitive::<$S>();
196 let min = min.as_primitive::<$S>().value(0);
198 let max = max.as_primitive::<$S>().value(0);
199 if min > max {
200 return Err(DataFusionError::Execution(format!(
201 "min '{}' > max '{}'",
202 min, max
203 )));
204 }
205 Arc::new(PrimitiveArray::<$S>::from(
206 (0..col.len())
207 .map(|x| {
208 col.is_valid(x).then(|| {
209 let v = col.value(x);
210 clamp!(v, min, max)
211 })
212 })
213 .collect::<Vec<_>>(),
214 )
215 ) as ArrayRef
216 }
217 )?;
218 Ok(ColumnarValue::Array(result))
219 }
220 _ => Err(DataFusionError::Internal(
221 "argument column types mismatch".to_string(),
222 )),
223 }
224}
225
226#[derive(Clone, Debug)]
227pub struct ClampMinFunction {
228 signature: Signature,
229}
230
231impl Default for ClampMinFunction {
232 fn default() -> Self {
233 Self {
234 signature: Signature::uniform(2, NUMERICS.to_vec(), Volatility::Immutable),
236 }
237 }
238}
239
240const CLAMP_MIN_NAME: &str = "clamp_min";
241
242impl Function for ClampMinFunction {
243 fn name(&self) -> &str {
244 CLAMP_MIN_NAME
245 }
246
247 fn return_type(
248 &self,
249 input_types: &[ArrowDataType],
250 ) -> datafusion_common::Result<ArrowDataType> {
251 Ok(input_types[0].clone())
252 }
253
254 fn signature(&self) -> &Signature {
255 &self.signature
256 }
257
258 fn invoke_with_args(
259 &self,
260 args: ScalarFunctionArgs,
261 ) -> datafusion_common::Result<ColumnarValue> {
262 let [col, min] = utils::take_function_args(self.name(), args.args)?;
263
264 let Some(max) = ScalarValue::max(&min.data_type()) else {
265 return Err(DataFusionError::Internal(format!(
266 "cannot find a max value for numeric data type {}",
267 min.data_type()
268 )));
269 };
270 clamp_impl(col, min, ColumnarValue::Scalar(max))
271 }
272}
273
274impl Display for ClampMinFunction {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 write!(f, "{}", CLAMP_MIN_NAME.to_ascii_uppercase())
277 }
278}
279
280#[derive(Clone, Debug)]
281pub struct ClampMaxFunction {
282 signature: Signature,
283}
284
285impl Default for ClampMaxFunction {
286 fn default() -> Self {
287 Self {
288 signature: Signature::uniform(2, NUMERICS.to_vec(), Volatility::Immutable),
290 }
291 }
292}
293
294const CLAMP_MAX_NAME: &str = "clamp_max";
295
296impl Function for ClampMaxFunction {
297 fn name(&self) -> &str {
298 CLAMP_MAX_NAME
299 }
300
301 fn return_type(
302 &self,
303 input_types: &[ArrowDataType],
304 ) -> datafusion_common::Result<ArrowDataType> {
305 Ok(input_types[0].clone())
306 }
307
308 fn signature(&self) -> &Signature {
309 &self.signature
310 }
311
312 fn invoke_with_args(
313 &self,
314 args: ScalarFunctionArgs,
315 ) -> datafusion_common::Result<ColumnarValue> {
316 let [col, max] = utils::take_function_args(self.name(), args.args)?;
317
318 let Some(min) = ScalarValue::min(&max.data_type()) else {
319 return Err(DataFusionError::Internal(format!(
320 "cannot find a min value for numeric data type {}",
321 max.data_type()
322 )));
323 };
324 clamp_impl(col, ColumnarValue::Scalar(min), max)
325 }
326}
327
328impl Display for ClampMaxFunction {
329 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330 write!(f, "{}", CLAMP_MAX_NAME.to_ascii_uppercase())
331 }
332}
333
334#[cfg(test)]
335mod test {
336
337 use std::sync::Arc;
338
339 use arrow_schema::Field;
340 use datafusion_common::config::ConfigOptions;
341 use datatypes::arrow::array::{
342 ArrayRef, Decimal128Array, Float64Array, Int64Array, UInt64Array,
343 };
344 use datatypes::arrow_array::StringArray;
345
346 use super::*;
347
348 macro_rules! impl_test_eval {
349 ($func: ty) => {
350 impl $func {
351 fn test_eval(
352 &self,
353 args: Vec<ColumnarValue>,
354 number_rows: usize,
355 ) -> datafusion_common::Result<ArrayRef> {
356 let input_type = args[0].data_type();
357 self.invoke_with_args(ScalarFunctionArgs {
358 args,
359 arg_fields: vec![],
360 number_rows,
361 return_field: Arc::new(Field::new("x", input_type, false)),
362 config_options: Arc::new(ConfigOptions::new()),
363 })
364 .and_then(|v| ColumnarValue::values_to_arrays(&[v]).map_err(Into::into))
365 .map(|mut a| a.remove(0))
366 }
367 }
368 };
369 }
370
371 impl_test_eval!(ClampFunction);
372 impl_test_eval!(ClampMinFunction);
373 impl_test_eval!(ClampMaxFunction);
374
375 fn decimal_array(values: Vec<i128>) -> ColumnarValue {
376 ColumnarValue::Array(Arc::new(
377 Decimal128Array::from(values)
378 .with_precision_and_scale(10, 2)
379 .unwrap(),
380 ))
381 }
382
383 fn decimal_scalar(value: i128) -> ColumnarValue {
384 ColumnarValue::Scalar(ScalarValue::Decimal128(Some(value), 10, 2))
385 }
386
387 #[allow(deprecated)]
388 fn evaluate_decimal(
389 function: &dyn Function,
390 args: Vec<ColumnarValue>,
391 ) -> datafusion_common::Result<ArrayRef> {
392 let input_types = args
393 .iter()
394 .map(ColumnarValue::data_type)
395 .collect::<Vec<_>>();
396 let planned_types = datafusion_expr::type_coercion::functions::data_types(
397 function.name(),
398 &input_types,
399 function.signature(),
400 )?;
401 let args = args
402 .into_iter()
403 .zip(planned_types)
404 .map(|(arg, planned_type)| arg.cast_to(&planned_type, None))
405 .collect::<datafusion_common::Result<Vec<_>>>()?;
406 function
407 .invoke_with_args(ScalarFunctionArgs {
408 args,
409 arg_fields: vec![],
410 number_rows: 3,
411 return_field: Arc::new(Field::new("x", ArrowDataType::Float64, false)),
412 config_options: Arc::new(ConfigOptions::new()),
413 })
414 .and_then(|value| value.to_array(3))
415 }
416
417 #[test]
418 fn clamp_decimal_coercion_executes_as_float64() {
419 let test_cases = [
420 (
421 Box::new(ClampFunction::default()) as Box<dyn Function>,
422 vec![
423 decimal_array(vec![100, 300, 500]),
424 decimal_scalar(200),
425 decimal_scalar(400),
426 ],
427 vec![2.0, 3.0, 4.0],
428 ),
429 (
430 Box::new(ClampMinFunction::default()),
431 vec![decimal_array(vec![100, 300, 500]), decimal_scalar(200)],
432 vec![2.0, 3.0, 5.0],
433 ),
434 (
435 Box::new(ClampMaxFunction::default()),
436 vec![decimal_array(vec![100, 300, 500]), decimal_scalar(200)],
437 vec![1.0, 2.0, 2.0],
438 ),
439 ];
440
441 for (function, args, expected) in test_cases {
442 let result = evaluate_decimal(function.as_ref(), args).unwrap();
443 let expected: ArrayRef = Arc::new(Float64Array::from(expected));
444 assert_eq!(expected.as_ref(), result.as_ref());
445 }
446 }
447
448 #[test]
449 fn clamp_i64() {
450 let inputs = [
451 (
452 vec![Some(-3), Some(-2), Some(-1), Some(0), Some(1), Some(2)],
453 -1i64,
454 10i64,
455 vec![Some(-1), Some(-1), Some(-1), Some(0), Some(1), Some(2)],
456 ),
457 (
458 vec![Some(-3), Some(-2), Some(-1), Some(0), Some(1), Some(2)],
459 0i64,
460 0i64,
461 vec![Some(0), Some(0), Some(0), Some(0), Some(0), Some(0)],
462 ),
463 (
464 vec![Some(-3), None, Some(-1), None, None, Some(2)],
465 -2i64,
466 1i64,
467 vec![Some(-2), None, Some(-1), None, None, Some(1)],
468 ),
469 (
470 vec![None, None, None, None, None],
471 0i64,
472 1i64,
473 vec![None, None, None, None, None],
474 ),
475 ];
476
477 let func = ClampFunction::default();
478 for (in_data, min, max, expected) in inputs {
479 let number_rows = in_data.len();
480 let args = vec![
481 ColumnarValue::Array(Arc::new(Int64Array::from(in_data))),
482 ColumnarValue::Scalar(min.into()),
483 ColumnarValue::Scalar(max.into()),
484 ];
485 let result = func.test_eval(args, number_rows).unwrap();
486 let expected: ArrayRef = Arc::new(Int64Array::from(expected));
487 assert_eq!(expected.as_ref(), result.as_ref());
488 }
489 }
490
491 #[test]
492 fn clamp_u64() {
493 let inputs = [
494 (
495 vec![Some(0), Some(1), Some(2), Some(3), Some(4), Some(5)],
496 1u64,
497 3u64,
498 vec![Some(1), Some(1), Some(2), Some(3), Some(3), Some(3)],
499 ),
500 (
501 vec![Some(0), Some(1), Some(2), Some(3), Some(4), Some(5)],
502 0u64,
503 0u64,
504 vec![Some(0), Some(0), Some(0), Some(0), Some(0), Some(0)],
505 ),
506 (
507 vec![Some(0), None, Some(2), None, None, Some(5)],
508 1u64,
509 3u64,
510 vec![Some(1), None, Some(2), None, None, Some(3)],
511 ),
512 (
513 vec![None, None, None, None, None],
514 0u64,
515 1u64,
516 vec![None, None, None, None, None],
517 ),
518 ];
519
520 let func = ClampFunction::default();
521 for (in_data, min, max, expected) in inputs {
522 let number_rows = in_data.len();
523 let args = vec![
524 ColumnarValue::Array(Arc::new(UInt64Array::from(in_data))),
525 ColumnarValue::Scalar(min.into()),
526 ColumnarValue::Scalar(max.into()),
527 ];
528 let result = func.test_eval(args, number_rows).unwrap();
529 let expected: ArrayRef = Arc::new(UInt64Array::from(expected));
530 assert_eq!(expected.as_ref(), result.as_ref());
531 }
532 }
533
534 #[test]
535 fn clamp_f64() {
536 let inputs = [
537 (
538 vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)],
539 -1.0,
540 10.0,
541 vec![Some(-1.0), Some(-1.0), Some(-1.0), Some(0.0), Some(1.0)],
542 ),
543 (
544 vec![Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)],
545 0.0,
546 0.0,
547 vec![Some(0.0), Some(0.0), Some(0.0), Some(0.0)],
548 ),
549 (
550 vec![Some(-3.0), None, Some(-1.0), None, None, Some(2.0)],
551 -2.0,
552 1.0,
553 vec![Some(-2.0), None, Some(-1.0), None, None, Some(1.0)],
554 ),
555 (
556 vec![None, None, None, None, None],
557 0.0,
558 1.0,
559 vec![None, None, None, None, None],
560 ),
561 ];
562
563 let func = ClampFunction::default();
564 for (in_data, min, max, expected) in inputs {
565 let number_rows = in_data.len();
566 let args = vec![
567 ColumnarValue::Array(Arc::new(Float64Array::from(in_data))),
568 ColumnarValue::Scalar(min.into()),
569 ColumnarValue::Scalar(max.into()),
570 ];
571 let result = func.test_eval(args, number_rows).unwrap();
572 let expected: ArrayRef = Arc::new(Float64Array::from(expected));
573 assert_eq!(expected.as_ref(), result.as_ref());
574 }
575 }
576
577 #[test]
578 fn clamp_invalid_min_max() {
579 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
580 let min = 10.0;
581 let max = -1.0;
582
583 let func = ClampFunction::default();
584 let number_rows = input.len();
585 let args = vec![
586 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
587 ColumnarValue::Scalar(min.into()),
588 ColumnarValue::Scalar(max.into()),
589 ];
590 let result = func.test_eval(args, number_rows);
591 assert!(result.is_err());
592 }
593
594 #[test]
595 fn clamp_type_not_match() {
596 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
597 let min = -1i64;
598 let max = 10u64;
599
600 let func = ClampFunction::default();
601 let number_rows = input.len();
602 let args = vec![
603 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
604 ColumnarValue::Scalar(min.into()),
605 ColumnarValue::Scalar(max.into()),
606 ];
607 let result = func.test_eval(args, number_rows);
608 assert!(result.is_err());
609 }
610
611 #[test]
612 fn clamp_min_is_not_scalar() {
613 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
614 let min = -10.0;
615 let max = 1.0;
616
617 let func = ClampFunction::default();
618 let number_rows = input.len();
619 let args = vec![
620 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
621 ColumnarValue::Array(Arc::new(Float64Array::from(vec![min, max]))),
622 ColumnarValue::Array(Arc::new(Float64Array::from(vec![max, min]))),
623 ];
624 let result = func.test_eval(args, number_rows);
625 assert!(result.is_err());
626 }
627
628 #[test]
629 fn clamp_no_max() {
630 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
631 let min = -10.0;
632
633 let func = ClampFunction::default();
634 let number_rows = input.len();
635 let args = vec![
636 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
637 ColumnarValue::Scalar(min.into()),
638 ];
639 let result = func.test_eval(args, number_rows);
640 assert!(result.is_err());
641 }
642
643 #[test]
644 fn clamp_on_string() {
645 let input = vec![Some("foo"), Some("foo"), Some("foo"), Some("foo")];
646
647 let func = ClampFunction::default();
648 let number_rows = input.len();
649 let args = vec![
650 ColumnarValue::Array(Arc::new(StringArray::from(input))),
651 ColumnarValue::Scalar("bar".into()),
652 ColumnarValue::Scalar("baz".into()),
653 ];
654 let result = func.test_eval(args, number_rows);
655 assert!(result.is_err());
656 }
657
658 #[test]
659 fn clamp_min_i64() {
660 let inputs = [
661 (
662 vec![Some(-3), Some(-2), Some(-1), Some(0), Some(1), Some(2)],
663 -1i64,
664 vec![Some(-1), Some(-1), Some(-1), Some(0), Some(1), Some(2)],
665 ),
666 (
667 vec![Some(-3), None, Some(-1), None, None, Some(2)],
668 -2i64,
669 vec![Some(-2), None, Some(-1), None, None, Some(2)],
670 ),
671 ];
672
673 let func = ClampMinFunction::default();
674 for (in_data, min, expected) in inputs {
675 let number_rows = in_data.len();
676 let args = vec![
677 ColumnarValue::Array(Arc::new(Int64Array::from(in_data))),
678 ColumnarValue::Scalar(min.into()),
679 ];
680 let result = func.test_eval(args, number_rows).unwrap();
681 let expected: ArrayRef = Arc::new(Int64Array::from(expected));
682 assert_eq!(expected.as_ref(), result.as_ref());
683 }
684 }
685
686 #[test]
687 fn clamp_max_i64() {
688 let inputs = [
689 (
690 vec![Some(-3), Some(-2), Some(-1), Some(0), Some(1), Some(2)],
691 1i64,
692 vec![Some(-3), Some(-2), Some(-1), Some(0), Some(1), Some(1)],
693 ),
694 (
695 vec![Some(-3), None, Some(-1), None, None, Some(2)],
696 0i64,
697 vec![Some(-3), None, Some(-1), None, None, Some(0)],
698 ),
699 ];
700
701 let func = ClampMaxFunction::default();
702 for (in_data, max, expected) in inputs {
703 let number_rows = in_data.len();
704 let args = vec![
705 ColumnarValue::Array(Arc::new(Int64Array::from(in_data))),
706 ColumnarValue::Scalar(max.into()),
707 ];
708 let result = func.test_eval(args, number_rows).unwrap();
709 let expected: ArrayRef = Arc::new(Int64Array::from(expected));
710 assert_eq!(expected.as_ref(), result.as_ref());
711 }
712 }
713
714 #[test]
715 fn clamp_min_f64() {
716 let inputs = [(
717 vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)],
718 -1.0,
719 vec![Some(-1.0), Some(-1.0), Some(-1.0), Some(0.0), Some(1.0)],
720 )];
721
722 let func = ClampMinFunction::default();
723 for (in_data, min, expected) in inputs {
724 let number_rows = in_data.len();
725 let args = vec![
726 ColumnarValue::Array(Arc::new(Float64Array::from(in_data))),
727 ColumnarValue::Scalar(min.into()),
728 ];
729 let result = func.test_eval(args, number_rows).unwrap();
730 let expected: ArrayRef = Arc::new(Float64Array::from(expected));
731 assert_eq!(expected.as_ref(), result.as_ref());
732 }
733 }
734
735 #[test]
736 fn clamp_max_f64() {
737 let inputs = [(
738 vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)],
739 0.0,
740 vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(0.0)],
741 )];
742
743 let func = ClampMaxFunction::default();
744 for (in_data, max, expected) in inputs {
745 let number_rows = in_data.len();
746 let args = vec![
747 ColumnarValue::Array(Arc::new(Float64Array::from(in_data))),
748 ColumnarValue::Scalar(max.into()),
749 ];
750 let result = func.test_eval(args, number_rows).unwrap();
751 let expected: ArrayRef = Arc::new(Float64Array::from(expected));
752 assert_eq!(expected.as_ref(), result.as_ref());
753 }
754 }
755
756 #[test]
757 fn clamp_min_type_not_match() {
758 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
759 let min = -1i64;
760
761 let func = ClampMinFunction::default();
762 let number_rows = input.len();
763 let args = vec![
764 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
765 ColumnarValue::Scalar(min.into()),
766 ];
767 let result = func.test_eval(args, number_rows);
768 assert!(result.is_err());
769 }
770
771 #[test]
772 fn clamp_max_type_not_match() {
773 let input = vec![Some(-3.0), Some(-2.0), Some(-1.0), Some(0.0), Some(1.0)];
774 let max = 1i64;
775
776 let func = ClampMaxFunction::default();
777 let number_rows = input.len();
778 let args = vec![
779 ColumnarValue::Array(Arc::new(Float64Array::from(input))),
780 ColumnarValue::Scalar(max.into()),
781 ];
782 let result = func.test_eval(args, number_rows);
783 assert!(result.is_err());
784 }
785}