1use std::borrow::Cow;
17use std::cmp;
18use std::fmt;
19
20use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
21use fallible_iterator::FallibleIterator;
22use hmac::{Hmac, Mac};
23use itertools::Itertools;
24use md5::Md5;
25use mz_expr_derive::sqlfunc;
26use mz_lowertest::MzReflect;
27use mz_ore::cast::{CastFrom, ReinterpretCast};
28use mz_pgtz::timezone::TimezoneSpec;
29use mz_repr::ReprColumnType;
30use mz_repr::adt::array::{Array, ArrayDimension, ArrayDimensions, InvalidArrayError};
31use mz_repr::adt::mz_acl_item::{AclItem, AclMode, MzAclItem};
32use mz_repr::adt::range::{InvalidRangeError, Range, RangeBound, parse_range_bound_flags};
33use mz_repr::adt::system::Oid;
34use mz_repr::adt::timestamp::CheckedTimestamp;
35use mz_repr::role_id::RoleId;
36use mz_repr::{
37 ColumnName, Datum, DatumList, FromDatum, InputDatumType, OptionalArg, OutputDatumType, Row,
38 RowArena, SqlColumnType, SqlScalarType, Variadic,
39};
40use serde::{Deserialize, Serialize};
41use sha1::Sha1;
42use sha2::{Sha224, Sha256, Sha384, Sha512};
43
44use crate::func::CaseLiteral;
45use crate::func::{
46 MAX_STRING_FUNC_RESULT_BYTES, array_create_scalar, build_regex, date_bin, parse_timezone,
47 regexp_match_static, regexp_replace_parse_flags, regexp_split_to_array_re, stringify_datum,
48 timezone_time,
49};
50use crate::{EvalError, MirScalarExpr};
51use mz_repr::adt::date::Date;
52use mz_repr::adt::interval::Interval;
53use mz_repr::adt::jsonb::JsonbRef;
54
55#[derive(
56 Ord,
57 PartialOrd,
58 Clone,
59 Debug,
60 Eq,
61 PartialEq,
62 Serialize,
63 Deserialize,
64 Hash,
65 MzReflect
66)]
67pub struct And;
68
69impl fmt::Display for And {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 f.write_str("AND")
72 }
73}
74
75impl LazyVariadicFunc for And {
76 fn eval<'a>(
77 &'a self,
78 datums: &[Datum<'a>],
79 temp_storage: &'a RowArena,
80 exprs: &'a [MirScalarExpr],
81 ) -> Result<Datum<'a>, EvalError> {
82 let mut null = false;
84 let mut err = None;
85 for expr in exprs {
86 match expr.eval(datums, temp_storage) {
87 Ok(Datum::False) => return Ok(Datum::False), Ok(Datum::True) => {}
89 Ok(Datum::Null) => null = true,
91 Err(this_err) => err = std::cmp::max(err.take(), Some(this_err)),
92 _ => unreachable!(),
93 }
94 }
95 match (err, null) {
96 (Some(err), _) => Err(err),
97 (None, true) => Ok(Datum::Null),
98 (None, false) => Ok(Datum::True),
99 }
100 }
101
102 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
103 let in_nullable = input_types.iter().any(|t| t.nullable);
104 SqlScalarType::Bool.nullable(in_nullable)
105 }
106
107 fn propagates_nulls(&self) -> bool {
108 false
109 }
110
111 fn introduces_nulls(&self) -> bool {
112 false
113 }
114
115 fn could_error(&self) -> bool {
116 false
117 }
118
119 fn is_monotone(&self) -> bool {
120 true
121 }
122
123 fn is_associative(&self) -> bool {
124 true
125 }
126
127 fn is_infix_op(&self) -> bool {
128 true
129 }
130}
131
132#[derive(
133 Ord,
134 PartialOrd,
135 Clone,
136 Debug,
137 Eq,
138 PartialEq,
139 Serialize,
140 Deserialize,
141 Hash,
142 MzReflect
143)]
144pub struct ArrayCreate {
145 pub elem_type: SqlScalarType,
146}
147
148#[sqlfunc(
164 ArrayCreate,
165 output_type_expr = "match &self.elem_type { SqlScalarType::Array(_) => self.elem_type.clone().nullable(false), _ => SqlScalarType::Array(Box::new(self.elem_type.clone())).nullable(false) }",
166 introduces_nulls = false
167)]
168fn array_create<'a>(
169 &self,
170 datums: Variadic<Datum<'a>>,
171 temp_storage: &'a RowArena,
172) -> Result<Datum<'a>, EvalError> {
173 match &self.elem_type {
174 SqlScalarType::Array(_) => array_create_multidim(&datums, temp_storage),
175 _ => array_create_scalar(&datums, temp_storage),
176 }
177}
178fn array_create_multidim<'a>(
179 datums: &[Datum<'a>],
180 temp_storage: &'a RowArena,
181) -> Result<Datum<'a>, EvalError> {
182 let mut dim: Option<ArrayDimensions> = None;
183 for datum in datums {
184 let actual_dims = match datum {
185 Datum::Null => ArrayDimensions::default(),
186 Datum::Array(arr) => arr.dims(),
187 d => panic!("unexpected datum {d}"),
188 };
189 if let Some(expected) = &dim {
190 if actual_dims.ndims() != expected.ndims() {
191 let actual = actual_dims.ndims().into();
192 let expected = expected.ndims().into();
193 return Err(InvalidArrayError::WrongCardinality { actual, expected }.into());
195 }
196 if let Some((e, a)) = expected
197 .into_iter()
198 .zip_eq(actual_dims.into_iter())
199 .find(|(e, a)| e != a)
200 {
201 let actual = a.length;
202 let expected = e.length;
203 return Err(InvalidArrayError::WrongCardinality { actual, expected }.into());
205 }
206 }
207 dim = Some(actual_dims);
208 }
209 if dim.as_ref().map_or(true, ArrayDimensions::is_empty) {
211 return Ok(temp_storage.try_make_datum(|packer| packer.try_push_array(&[], &[]))?);
212 }
213
214 let mut dims = vec![ArrayDimension {
215 lower_bound: 1,
216 length: datums.len(),
217 }];
218 if let Some(d) = datums.first() {
219 dims.extend(d.unwrap_array().dims());
220 };
221 let elements = datums
222 .iter()
223 .flat_map(|d| d.unwrap_array().elements().iter());
224 let datum =
225 temp_storage.try_make_datum(move |packer| packer.try_push_array(&dims, elements))?;
226 Ok(datum)
227}
228
229#[derive(
230 Ord,
231 PartialOrd,
232 Clone,
233 Debug,
234 Eq,
235 PartialEq,
236 Serialize,
237 Deserialize,
238 Hash,
239 MzReflect
240)]
241pub struct ArrayFill {
242 pub elem_type: SqlScalarType,
243}
244
245#[sqlfunc(
246 ArrayFill,
247 output_type_expr = "SqlScalarType::Array(Box::new(self.elem_type.clone())).nullable(false)",
248 introduces_nulls = false
249)]
250fn array_fill<'a>(
251 &self,
252 fill: Datum<'a>,
253 dims: Option<Array<'a>>,
254 lower_bounds: OptionalArg<Option<Array<'a>>>,
255 temp_storage: &'a RowArena,
256) -> Result<Datum<'a>, EvalError> {
257 const MAX_SIZE: usize = 1 << 28 - 1;
258 const NULL_ARR_ERR: &str = "dimension array or low bound array";
259 const NULL_ELEM_ERR: &str = "dimension values";
260
261 if matches!(fill, Datum::Array(_)) {
262 return Err(EvalError::Unsupported {
263 feature: "array_fill with arrays".into(),
264 discussion_no: None,
265 });
266 }
267
268 let Some(arr) = dims else {
269 return Err(EvalError::MustNotBeNull(NULL_ARR_ERR.into()));
270 };
271
272 let dimensions = arr
273 .elements()
274 .iter()
275 .map(|d| match d {
276 Datum::Null => Err(EvalError::MustNotBeNull(NULL_ELEM_ERR.into())),
277 d => Ok(usize::cast_from(u32::reinterpret_cast(d.unwrap_int32()))),
278 })
279 .collect::<Result<Vec<_>, _>>()?;
280
281 let lower_bounds = match *lower_bounds {
282 Some(d) => {
283 let Some(arr) = d else {
284 return Err(EvalError::MustNotBeNull(NULL_ARR_ERR.into()));
285 };
286
287 arr.elements()
288 .iter()
289 .map(|l| match l {
290 Datum::Null => Err(EvalError::MustNotBeNull(NULL_ELEM_ERR.into())),
291 l => Ok(isize::cast_from(l.unwrap_int32())),
292 })
293 .collect::<Result<Vec<_>, _>>()?
294 }
295 None => {
296 vec![1isize; dimensions.len()]
297 }
298 };
299
300 if lower_bounds.len() != dimensions.len() {
301 return Err(EvalError::ArrayFillWrongArraySubscripts);
302 }
303
304 let fill_count: usize = dimensions
305 .iter()
306 .cloned()
307 .map(Some)
308 .reduce(|a, b| match (a, b) {
309 (Some(a), Some(b)) => a.checked_mul(b),
310 _ => None,
311 })
312 .flatten()
313 .ok_or(EvalError::MaxArraySizeExceeded(MAX_SIZE))?;
314
315 if matches!(
316 mz_repr::datum_size(&fill).checked_mul(fill_count),
317 None | Some(MAX_SIZE..)
318 ) {
319 return Err(EvalError::MaxArraySizeExceeded(MAX_SIZE));
320 }
321
322 let array_dimensions = if fill_count == 0 {
323 vec![ArrayDimension {
324 lower_bound: 1,
325 length: 0,
326 }]
327 } else {
328 dimensions
329 .into_iter()
330 .zip_eq(lower_bounds)
331 .map(|(length, lower_bound)| ArrayDimension {
332 lower_bound,
333 length,
334 })
335 .collect()
336 };
337
338 Ok(temp_storage.try_make_datum(|packer| {
339 packer.try_push_array(&array_dimensions, vec![fill; fill_count])
340 })?)
341}
342
343#[derive(
344 Ord,
345 PartialOrd,
346 Clone,
347 Debug,
348 Eq,
349 PartialEq,
350 Serialize,
351 Deserialize,
352 Hash,
353 MzReflect
354)]
355pub struct ArrayIndex {
356 pub offset: i64,
357}
358#[sqlfunc(ArrayIndex, sqlname = "array_index", introduces_nulls = true)]
359fn array_index<'a, T: FromDatum<'a>>(
360 &self,
361 array: Array<'a, T>,
362 indices: Variadic<i64>,
363) -> Option<T> {
364 mz_ore::soft_assert_no_log!(
365 self.offset == 0 || self.offset == 1,
366 "offset must be either 0 or 1"
367 );
368
369 let dims = array.dims();
370 if dims.len() != indices.len() {
371 return None;
373 }
374
375 let mut final_idx = 0;
376
377 for (d, idx) in dims.into_iter().zip_eq(indices.iter()) {
378 let idx = isize::cast_from(*idx + self.offset);
380
381 let (lower, upper) = d.dimension_bounds();
382
383 if !(lower..upper + 1).contains(&idx) {
386 return None;
387 }
388
389 final_idx *= d.length;
391
392 final_idx += usize::try_from(idx - d.lower_bound)
396 .expect("previous bounds check ensures physical index is at least 0");
397 }
398
399 array.elements().typed_iter().nth(final_idx)
400}
401
402#[sqlfunc]
403fn array_position<'a>(
404 array: Array<'a>,
405 search: Datum<'a>,
406 initial_pos: OptionalArg<Option<i32>>,
407) -> Result<Option<i32>, EvalError> {
408 if array.dims().len() > 1 {
409 return Err(EvalError::MultiDimensionalArraySearch);
410 }
411
412 if search == Datum::Null {
413 return Ok(None);
414 }
415
416 let skip = match initial_pos.0 {
417 None => 0,
418 Some(None) => return Err(EvalError::MustNotBeNull("initial position".into())),
419 Some(Some(o)) => usize::try_from(o).unwrap_or(0).saturating_sub(1),
420 };
421
422 let Some(r) = array.elements().iter().skip(skip).position(|d| d == search) else {
423 return Ok(None);
424 };
425
426 let p = i32::try_from(r + skip + 1).expect("fewer than i32::MAX elements in array");
428 Ok(Some(p))
429}
430
431#[derive(
432 Ord,
433 PartialOrd,
434 Clone,
435 Debug,
436 Eq,
437 PartialEq,
438 Serialize,
439 Deserialize,
440 Hash,
441 MzReflect
442)]
443pub struct ArrayToString {
444 pub elem_type: SqlScalarType,
445}
446
447#[sqlfunc]
448fn array_to_string<'a>(
449 &self,
450 array: Array<'a>,
451 delimiter: &str,
452 null_str_arg: OptionalArg<Option<&str>>,
453) -> Result<String, EvalError> {
454 let null_str = null_str_arg.flatten();
457 let mut out = String::new();
458 for elem in array.elements().iter() {
459 if elem.is_null() {
460 if let Some(null_str) = null_str {
461 out.push_str(null_str);
462 out.push_str(delimiter);
463 }
464 } else {
465 stringify_datum(&mut out, elem, &self.elem_type)?;
466 out.push_str(delimiter);
467 }
468 }
469 if out.len() > 0 {
470 out.truncate(out.len() - delimiter.len());
472 }
473 Ok(out)
474}
475
476#[derive(
477 Ord,
478 PartialOrd,
479 Clone,
480 Debug,
481 Eq,
482 PartialEq,
483 Serialize,
484 Deserialize,
485 Hash,
486 MzReflect
487)]
488pub struct Coalesce;
489
490impl fmt::Display for Coalesce {
491 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
492 f.write_str("coalesce")
493 }
494}
495
496impl LazyVariadicFunc for Coalesce {
497 fn eval<'a>(
498 &'a self,
499 datums: &[Datum<'a>],
500 temp_storage: &'a RowArena,
501 exprs: &'a [MirScalarExpr],
502 ) -> Result<Datum<'a>, EvalError> {
503 for e in exprs {
504 let d = e.eval(datums, temp_storage)?;
505 if !d.is_null() {
506 return Ok(d);
507 }
508 }
509 Ok(Datum::Null)
510 }
511
512 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
513 let nullable = input_types.iter().all(|typ| typ.nullable);
517 SqlColumnType::union_many(input_types).nullable(nullable)
518 }
519
520 fn propagates_nulls(&self) -> bool {
521 false
522 }
523
524 fn introduces_nulls(&self) -> bool {
525 false
526 }
527
528 fn could_error(&self) -> bool {
529 false
530 }
531
532 fn is_monotone(&self) -> bool {
533 true
534 }
535
536 fn is_associative(&self) -> bool {
537 true
538 }
539}
540
541#[derive(
542 Ord,
543 PartialOrd,
544 Clone,
545 Debug,
546 Eq,
547 PartialEq,
548 Serialize,
549 Deserialize,
550 Hash,
551 MzReflect
552)]
553pub struct RangeCreate {
554 pub elem_type: SqlScalarType,
555}
556
557impl fmt::Display for RangeCreate {
558 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
559 f.write_str(match &self.elem_type {
560 SqlScalarType::Int32 => "int4range",
561 SqlScalarType::Int64 => "int8range",
562 SqlScalarType::Date => "daterange",
563 SqlScalarType::Numeric { .. } => "numrange",
564 SqlScalarType::Timestamp { .. } => "tsrange",
565 SqlScalarType::TimestampTz { .. } => "tstzrange",
566 _ => unreachable!(),
567 })
568 }
569}
570
571impl EagerVariadicFunc for RangeCreate {
572 type Input<'a> = (Datum<'a>, Datum<'a>, Datum<'a>);
573 type Output<'a> = Result<Datum<'a>, EvalError>;
574
575 fn call<'a>(
576 &self,
577 (lower, upper, flags_datum): Self::Input<'a>,
578 temp_storage: &'a RowArena,
579 ) -> Self::Output<'a> {
580 let flags = match flags_datum {
581 Datum::Null => {
582 return Err(EvalError::InvalidRange(
583 InvalidRangeError::NullRangeBoundFlags,
584 ));
585 }
586 o => o.unwrap_str(),
587 };
588
589 let (lower_inclusive, upper_inclusive) = parse_range_bound_flags(flags)?;
590
591 let mut range = Range::new(Some((
592 RangeBound::new(lower, lower_inclusive),
593 RangeBound::new(upper, upper_inclusive),
594 )));
595
596 range.canonicalize()?;
597
598 Ok(temp_storage.make_datum(|row| {
599 row.push_range(range).expect("errors already handled");
600 }))
601 }
602
603 fn output_type(&self, _input_types: &[SqlColumnType]) -> SqlColumnType {
604 SqlScalarType::Range {
605 element_type: Box::new(self.elem_type.clone()),
606 }
607 .nullable(false)
608 }
609
610 fn introduces_nulls(&self) -> bool {
611 false
612 }
613}
614
615#[sqlfunc(sqlname = "datediff")]
616fn date_diff_date(unit_str: &str, a: Date, b: Date) -> Result<i64, EvalError> {
617 let unit = unit_str
618 .parse()
619 .map_err(|_| EvalError::InvalidDatePart(unit_str.into()))?;
620
621 let a_ts = CheckedTimestamp::try_from(NaiveDate::from(a).and_hms_opt(0, 0, 0).unwrap())?;
623 let b_ts = CheckedTimestamp::try_from(NaiveDate::from(b).and_hms_opt(0, 0, 0).unwrap())?;
624 let diff = b_ts.diff_as(&a_ts, unit)?;
625 Ok(diff)
626}
627
628#[sqlfunc(sqlname = "datediff")]
629fn date_diff_time(unit_str: &str, a: NaiveTime, b: NaiveTime) -> Result<i64, EvalError> {
630 let unit = unit_str
631 .parse()
632 .map_err(|_| EvalError::InvalidDatePart(unit_str.into()))?;
633
634 let a_ts =
636 CheckedTimestamp::try_from(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_time(a))?;
637 let b_ts =
638 CheckedTimestamp::try_from(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_time(b))?;
639 let diff = b_ts.diff_as(&a_ts, unit)?;
640 Ok(diff)
641}
642
643#[sqlfunc(sqlname = "datediff")]
644fn date_diff_timestamp(
645 unit: &str,
646 a: CheckedTimestamp<NaiveDateTime>,
647 b: CheckedTimestamp<NaiveDateTime>,
648) -> Result<i64, EvalError> {
649 let unit = unit
650 .parse()
651 .map_err(|_| EvalError::InvalidDatePart(unit.into()))?;
652
653 let diff = b.diff_as(&a, unit)?;
654 Ok(diff)
655}
656
657#[sqlfunc(sqlname = "datediff")]
658fn date_diff_timestamp_tz(
659 unit: &str,
660 a: CheckedTimestamp<DateTime<Utc>>,
661 b: CheckedTimestamp<DateTime<Utc>>,
662) -> Result<i64, EvalError> {
663 let unit = unit
664 .parse()
665 .map_err(|_| EvalError::InvalidDatePart(unit.into()))?;
666
667 let diff = b.diff_as(&a, unit)?;
668 Ok(diff)
669}
670
671#[derive(
672 Ord,
673 PartialOrd,
674 Clone,
675 Debug,
676 Eq,
677 PartialEq,
678 Serialize,
679 Deserialize,
680 Hash,
681 MzReflect
682)]
683pub struct ErrorIfNull;
684
685impl fmt::Display for ErrorIfNull {
686 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
687 f.write_str("error_if_null")
688 }
689}
690
691impl LazyVariadicFunc for ErrorIfNull {
692 fn eval<'a>(
693 &'a self,
694 datums: &[Datum<'a>],
695 temp_storage: &'a RowArena,
696 exprs: &'a [MirScalarExpr],
697 ) -> Result<Datum<'a>, EvalError> {
698 let first = exprs[0].eval(datums, temp_storage)?;
699 match first {
700 Datum::Null => {
701 let err_msg = match exprs[1].eval(datums, temp_storage)? {
702 Datum::Null => {
703 return Err(EvalError::Internal(
704 "unexpected NULL in error side of error_if_null".into(),
705 ));
706 }
707 o => o.unwrap_str(),
708 };
709 Err(EvalError::IfNullError(err_msg.into()))
710 }
711 _ => Ok(first),
712 }
713 }
714
715 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
716 input_types[0].scalar_type.clone().nullable(false)
717 }
718
719 fn propagates_nulls(&self) -> bool {
720 false
721 }
722
723 fn introduces_nulls(&self) -> bool {
724 false
725 }
726}
727
728#[derive(
729 Ord,
730 PartialOrd,
731 Clone,
732 Debug,
733 Eq,
734 PartialEq,
735 Serialize,
736 Deserialize,
737 Hash,
738 MzReflect
739)]
740pub struct Greatest;
741
742impl fmt::Display for Greatest {
743 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744 f.write_str("greatest")
745 }
746}
747
748impl LazyVariadicFunc for Greatest {
749 fn eval<'a>(
750 &'a self,
751 datums: &[Datum<'a>],
752 temp_storage: &'a RowArena,
753 exprs: &'a [MirScalarExpr],
754 ) -> Result<Datum<'a>, EvalError> {
755 let datums = fallible_iterator::convert(exprs.iter().map(|e| e.eval(datums, temp_storage)));
756 Ok(datums
757 .filter(|d| Ok(!d.is_null()))
758 .max()?
759 .unwrap_or(Datum::Null))
760 }
761
762 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
763 SqlColumnType::union_many(input_types)
764 }
765
766 fn propagates_nulls(&self) -> bool {
767 false
768 }
769
770 fn introduces_nulls(&self) -> bool {
771 false
772 }
773
774 fn could_error(&self) -> bool {
775 false
776 }
777
778 fn is_monotone(&self) -> bool {
779 true
780 }
781
782 fn is_associative(&self) -> bool {
783 true
784 }
785}
786
787#[sqlfunc(sqlname = "hmac")]
788fn hmac_string(to_digest: &str, key: &str, typ: &str) -> Result<Vec<u8>, EvalError> {
789 let to_digest = to_digest.as_bytes();
790 let key = key.as_bytes();
791 hmac_inner(to_digest, key, typ)
792}
793
794#[sqlfunc(sqlname = "hmac")]
795fn hmac_bytes(to_digest: &[u8], key: &[u8], typ: &str) -> Result<Vec<u8>, EvalError> {
796 hmac_inner(to_digest, key, typ)
797}
798
799pub fn hmac_inner(to_digest: &[u8], key: &[u8], typ: &str) -> Result<Vec<u8>, EvalError> {
800 match typ {
801 "md5" => {
802 let mut mac = Hmac::<Md5>::new_from_slice(key).expect("HMAC accepts any key size");
803 mac.update(to_digest);
804 Ok(mac.finalize().into_bytes().to_vec())
805 }
806 "sha1" => {
807 let mut mac = Hmac::<Sha1>::new_from_slice(key).expect("HMAC accepts any key size");
808 mac.update(to_digest);
809 Ok(mac.finalize().into_bytes().to_vec())
810 }
811 "sha224" => {
812 let mut mac = Hmac::<Sha224>::new_from_slice(key).expect("HMAC accepts any key size");
813 mac.update(to_digest);
814 Ok(mac.finalize().into_bytes().to_vec())
815 }
816 "sha256" => {
817 let mut mac = Hmac::<Sha256>::new_from_slice(key).expect("HMAC accepts any key size");
818 mac.update(to_digest);
819 Ok(mac.finalize().into_bytes().to_vec())
820 }
821 "sha384" => {
822 let mut mac = Hmac::<Sha384>::new_from_slice(key).expect("HMAC accepts any key size");
823 mac.update(to_digest);
824 Ok(mac.finalize().into_bytes().to_vec())
825 }
826 "sha512" => {
827 let mut mac = Hmac::<Sha512>::new_from_slice(key).expect("HMAC accepts any key size");
828 mac.update(to_digest);
829 Ok(mac.finalize().into_bytes().to_vec())
830 }
831 other => Err(EvalError::InvalidHashAlgorithm(other.into())),
832 }
833}
834
835#[sqlfunc]
836fn jsonb_build_array<'a>(datums: Variadic<Datum<'a>>, temp_storage: &'a RowArena) -> JsonbRef<'a> {
837 let datum = temp_storage.make_datum(|packer| {
838 packer.push_list(datums.into_iter().map(|d| match d {
839 Datum::Null => Datum::JsonNull,
840 d => d,
841 }))
842 });
843 JsonbRef::from_datum(datum)
844}
845
846#[sqlfunc]
847fn jsonb_build_object<'a>(
848 mut kvs: Variadic<(Datum<'a>, Datum<'a>)>,
849 temp_storage: &'a RowArena,
850) -> Result<JsonbRef<'a>, EvalError> {
851 kvs.0.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
852 kvs.0.dedup_by(|kv1, kv2| kv1.0 == kv2.0);
853 let datum = temp_storage.try_make_datum(|packer| {
854 packer.push_dict_with(|packer| {
855 for (k, v) in kvs {
856 if k.is_null() {
857 return Err(EvalError::KeyCannotBeNull);
858 }
859 let v = match v {
860 Datum::Null => Datum::JsonNull,
861 d => d,
862 };
863 packer.push(k);
864 packer.push(v);
865 }
866 Ok(())
867 })
868 })?;
869 Ok(JsonbRef::from_datum(datum))
870}
871
872#[derive(
873 Ord,
874 PartialOrd,
875 Clone,
876 Debug,
877 Eq,
878 PartialEq,
879 Serialize,
880 Deserialize,
881 Hash,
882 MzReflect
883)]
884pub struct Least;
885
886impl fmt::Display for Least {
887 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
888 f.write_str("least")
889 }
890}
891
892impl LazyVariadicFunc for Least {
893 fn eval<'a>(
894 &'a self,
895 datums: &[Datum<'a>],
896 temp_storage: &'a RowArena,
897 exprs: &'a [MirScalarExpr],
898 ) -> Result<Datum<'a>, EvalError> {
899 let datums = fallible_iterator::convert(exprs.iter().map(|e| e.eval(datums, temp_storage)));
900 Ok(datums
901 .filter(|d| Ok(!d.is_null()))
902 .min()?
903 .unwrap_or(Datum::Null))
904 }
905
906 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
907 SqlColumnType::union_many(input_types)
908 }
909
910 fn propagates_nulls(&self) -> bool {
911 false
912 }
913
914 fn introduces_nulls(&self) -> bool {
915 false
916 }
917
918 fn could_error(&self) -> bool {
919 false
920 }
921
922 fn is_monotone(&self) -> bool {
923 true
924 }
925
926 fn is_associative(&self) -> bool {
927 true
928 }
929}
930
931#[derive(
932 Ord,
933 PartialOrd,
934 Clone,
935 Debug,
936 Eq,
937 PartialEq,
938 Serialize,
939 Deserialize,
940 Hash,
941 MzReflect
942)]
943pub struct ListCreate {
944 pub elem_type: SqlScalarType,
945}
946
947#[sqlfunc(
948 output_type_expr = "SqlScalarType::List { element_type: Box::new(self.elem_type.clone()), custom_id: None }.nullable(false)",
949 introduces_nulls = false
950)]
951fn list_create<'a>(&self, datums: Variadic<Datum<'a>>, temp_storage: &'a RowArena) -> Datum<'a> {
952 temp_storage.make_datum(|packer| packer.push_list(datums))
953}
954
955#[derive(
956 Ord,
957 PartialOrd,
958 Clone,
959 Debug,
960 Eq,
961 PartialEq,
962 Serialize,
963 Deserialize,
964 Hash,
965 MzReflect
966)]
967pub struct RecordCreate {
968 pub field_names: Vec<ColumnName>,
969}
970
971#[sqlfunc(
972 output_type_expr = "SqlScalarType::Record { fields: self.field_names.clone().into_iter().zip_eq(input_types.iter().cloned()).collect(), custom_id: None }.nullable(false)",
973 introduces_nulls = false
974)]
975fn record_create<'a>(&self, datums: Variadic<Datum<'a>>, temp_storage: &'a RowArena) -> Datum<'a> {
976 temp_storage.make_datum(|packer| packer.push_list(datums.iter().copied()))
977}
978
979#[sqlfunc(
980 output_type_expr = "input_types[0].scalar_type.unwrap_list_nth_layer_type(input_types.len() - 1).clone().nullable(true)",
981 introduces_nulls = true
982)]
983#[allow(clippy::as_conversions)]
985fn list_index<'a>(buf: DatumList<'a>, indices: Variadic<i64>) -> Datum<'a> {
986 let mut buf = Datum::List(buf);
987 for i in indices {
988 if buf.is_null() {
989 break;
990 }
991 if i < 1 {
992 return Datum::Null;
993 }
994
995 buf = match buf.unwrap_list().iter().nth(i as usize - 1) {
996 Some(datum) => datum,
997 None => return Datum::Null,
998 }
999 }
1000 buf
1001}
1002
1003#[sqlfunc(sqlname = "makeaclitem")]
1004fn make_acl_item(
1005 grantee_oid: u32,
1006 grantor_oid: u32,
1007 privileges: &str,
1008 is_grantable: bool,
1009) -> Result<AclItem, EvalError> {
1010 let grantee = Oid(grantee_oid);
1011 let grantor = Oid(grantor_oid);
1012 let acl_mode = AclMode::parse_multiple_privileges(privileges)
1013 .map_err(|e: anyhow::Error| EvalError::InvalidPrivileges(e.to_string().into()))?;
1014 if is_grantable {
1015 return Err(EvalError::Unsupported {
1016 feature: "GRANT OPTION".into(),
1017 discussion_no: None,
1018 });
1019 }
1020
1021 Ok(AclItem {
1022 grantee,
1023 grantor,
1024 acl_mode,
1025 })
1026}
1027
1028#[sqlfunc(sqlname = "make_mz_aclitem")]
1029fn make_mz_acl_item(
1030 grantee_str: &str,
1031 grantor_str: &str,
1032 privileges: &str,
1033) -> Result<MzAclItem, EvalError> {
1034 let grantee: RoleId = grantee_str
1035 .parse()
1036 .map_err(|e: anyhow::Error| EvalError::InvalidRoleId(e.to_string().into()))?;
1037 let grantor: RoleId = grantor_str
1038 .parse()
1039 .map_err(|e: anyhow::Error| EvalError::InvalidRoleId(e.to_string().into()))?;
1040 if grantor == RoleId::Public {
1041 return Err(EvalError::InvalidRoleId(
1042 "mz_aclitem grantor cannot be PUBLIC role".into(),
1043 ));
1044 }
1045 let acl_mode = AclMode::parse_multiple_privileges(privileges)
1046 .map_err(|e: anyhow::Error| EvalError::InvalidPrivileges(e.to_string().into()))?;
1047
1048 Ok(MzAclItem {
1049 grantee,
1050 grantor,
1051 acl_mode,
1052 })
1053}
1054
1055#[sqlfunc(sqlname = "makets")]
1056#[allow(clippy::as_conversions)]
1058fn make_timestamp(
1059 year: i64,
1060 month: i64,
1061 day: i64,
1062 hour: i64,
1063 minute: i64,
1064 second_float: f64,
1065) -> Result<Option<CheckedTimestamp<NaiveDateTime>>, EvalError> {
1066 let year: i32 = match year.try_into() {
1067 Ok(year) => year,
1068 Err(_) => return Ok(None),
1069 };
1070 let month: u32 = match month.try_into() {
1071 Ok(month) => month,
1072 Err(_) => return Ok(None),
1073 };
1074 let day: u32 = match day.try_into() {
1075 Ok(day) => day,
1076 Err(_) => return Ok(None),
1077 };
1078 let hour: u32 = match hour.try_into() {
1079 Ok(hour) => hour,
1080 Err(_) => return Ok(None),
1081 };
1082 let minute: u32 = match minute.try_into() {
1083 Ok(minute) => minute,
1084 Err(_) => return Ok(None),
1085 };
1086 let second = second_float as u32;
1087 let micros = ((second_float - second as f64) * 1_000_000.0) as u32;
1088 let date = match NaiveDate::from_ymd_opt(year, month, day) {
1089 Some(date) => date,
1090 None => return Ok(None),
1091 };
1092 let timestamp = match date.and_hms_micro_opt(hour, minute, second, micros) {
1093 Some(timestamp) => timestamp,
1094 None => return Ok(None),
1095 };
1096 Ok(Some(timestamp.try_into()?))
1097}
1098
1099#[derive(
1100 Ord,
1101 PartialOrd,
1102 Clone,
1103 Debug,
1104 Eq,
1105 PartialEq,
1106 Serialize,
1107 Deserialize,
1108 Hash,
1109 MzReflect
1110)]
1111pub struct MapBuild {
1112 pub value_type: SqlScalarType,
1113}
1114
1115#[sqlfunc(
1116 output_type_expr = "SqlScalarType::Map { value_type: Box::new(self.value_type.clone()), custom_id: None }.nullable(false)",
1117 introduces_nulls = false
1118)]
1119fn map_build<'a>(
1120 &self,
1121 datums: Variadic<(Option<&str>, Datum<'a>)>,
1122 temp_storage: &'a RowArena,
1123) -> Datum<'a> {
1124 let map: std::collections::BTreeMap<&str, _> = datums
1126 .into_iter()
1127 .filter_map(|(k, v)| k.map(|k| (k, v)))
1128 .collect();
1129
1130 temp_storage.make_datum(|packer| packer.push_dict(map))
1131}
1132
1133#[derive(
1134 Ord,
1135 PartialOrd,
1136 Clone,
1137 Debug,
1138 Eq,
1139 PartialEq,
1140 Serialize,
1141 Deserialize,
1142 Hash,
1143 MzReflect
1144)]
1145pub struct Or;
1146
1147impl fmt::Display for Or {
1148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1149 f.write_str("OR")
1150 }
1151}
1152
1153impl LazyVariadicFunc for Or {
1154 fn eval<'a>(
1155 &'a self,
1156 datums: &[Datum<'a>],
1157 temp_storage: &'a RowArena,
1158 exprs: &'a [MirScalarExpr],
1159 ) -> Result<Datum<'a>, EvalError> {
1160 let mut null = false;
1162 let mut err = None;
1163 for expr in exprs {
1164 match expr.eval(datums, temp_storage) {
1165 Ok(Datum::False) => {}
1166 Ok(Datum::True) => return Ok(Datum::True), Ok(Datum::Null) => null = true,
1169 Err(this_err) => err = std::cmp::max(err.take(), Some(this_err)),
1170 _ => unreachable!(),
1171 }
1172 }
1173 match (err, null) {
1174 (Some(err), _) => Err(err),
1175 (None, true) => Ok(Datum::Null),
1176 (None, false) => Ok(Datum::False),
1177 }
1178 }
1179
1180 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
1181 let in_nullable = input_types.iter().any(|t| t.nullable);
1182 SqlScalarType::Bool.nullable(in_nullable)
1183 }
1184
1185 fn propagates_nulls(&self) -> bool {
1186 false
1187 }
1188
1189 fn introduces_nulls(&self) -> bool {
1190 false
1191 }
1192
1193 fn could_error(&self) -> bool {
1194 false
1195 }
1196
1197 fn is_monotone(&self) -> bool {
1198 true
1199 }
1200
1201 fn is_associative(&self) -> bool {
1202 true
1203 }
1204
1205 fn is_infix_op(&self) -> bool {
1206 true
1207 }
1208}
1209
1210#[sqlfunc(sqlname = "lpad")]
1211fn pad_leading(string: &str, raw_len: i32, pad: OptionalArg<&str>) -> Result<String, EvalError> {
1212 let len = match usize::try_from(raw_len) {
1213 Ok(len) => len,
1214 Err(_) => {
1215 return Err(EvalError::InvalidParameterValue(
1216 "length must be nonnegative".into(),
1217 ));
1218 }
1219 };
1220 if len > MAX_STRING_FUNC_RESULT_BYTES {
1221 return Err(EvalError::LengthTooLarge);
1222 }
1223
1224 let pad_string = pad.unwrap_or(" ");
1225
1226 let (end_char, end_char_byte_offset) = string
1227 .chars()
1228 .take(len)
1229 .fold((0, 0), |acc, char| (acc.0 + 1, acc.1 + char.len_utf8()));
1230
1231 let mut buf = String::with_capacity(len);
1232 if len == end_char {
1233 buf.push_str(&string[0..end_char_byte_offset]);
1234 } else {
1235 buf.extend(pad_string.chars().cycle().take(len - end_char));
1236 buf.push_str(string);
1237 }
1238
1239 Ok(buf)
1240}
1241
1242#[sqlfunc(
1243 output_type_expr = "SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(true)",
1244 introduces_nulls = true
1245)]
1246fn regexp_match<'a>(
1247 haystack: &'a str,
1248 needle: &str,
1249 flags: OptionalArg<&str>,
1250 temp_storage: &'a RowArena,
1251) -> Result<Datum<'a>, EvalError> {
1252 let flags = flags.unwrap_or("");
1253 let needle = build_regex(needle, flags)?;
1254 regexp_match_static(Datum::String(haystack), temp_storage, &needle)
1255}
1256
1257#[sqlfunc(
1258 output_type_expr = "SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false)",
1259 introduces_nulls = false
1260)]
1261fn regexp_split_to_array<'a>(
1262 text: &str,
1263 regexp_str: &str,
1264 flags: OptionalArg<&str>,
1265 temp_storage: &'a RowArena,
1266) -> Result<Datum<'a>, EvalError> {
1267 let flags = flags.unwrap_or("");
1268 let regexp = build_regex(regexp_str, flags)?;
1269 regexp_split_to_array_re(text, ®exp, temp_storage)
1270}
1271
1272#[sqlfunc]
1273fn regexp_replace<'a>(
1274 source: &'a str,
1275 pattern: &str,
1276 replacement: &str,
1277 flags_opt: OptionalArg<&str>,
1278) -> Result<Cow<'a, str>, EvalError> {
1279 let flags = flags_opt.0.unwrap_or("");
1280 let (limit, flags) = regexp_replace_parse_flags(flags);
1281 let regexp = build_regex(pattern, &flags)?;
1282 Ok(regexp.replacen(source, limit, replacement))
1283}
1284
1285#[sqlfunc]
1286fn replace(text: &str, from: &str, to: &str) -> Result<String, EvalError> {
1287 let possible_size = text.len() * to.len();
1294 if possible_size > MAX_STRING_FUNC_RESULT_BYTES {
1295 let replacement_count = text.matches(from).count();
1296 let estimated_size = text.len() + replacement_count * (to.len().saturating_sub(from.len()));
1297 if estimated_size > MAX_STRING_FUNC_RESULT_BYTES {
1298 return Err(EvalError::LengthTooLarge);
1299 }
1300 }
1301
1302 Ok(text.replace(from, to))
1303}
1304
1305#[sqlfunc(
1306 output_type_expr = "SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false)",
1307 introduces_nulls = false,
1308 propagates_nulls = false
1309)]
1310fn string_to_array<'a>(
1311 string: &'a str,
1312 delimiter: Option<&'a str>,
1313 null_string: OptionalArg<Option<&'a str>>,
1314 temp_storage: &'a RowArena,
1315) -> Result<Datum<'a>, EvalError> {
1316 if string.is_empty() {
1317 let mut row = Row::default();
1318 let mut packer = row.packer();
1319 packer.try_push_array(&[], std::iter::empty::<Datum>())?;
1320
1321 return Ok(temp_storage.push_unary_row(row));
1322 }
1323
1324 let Some(delimiter) = delimiter else {
1325 let split_all_chars_delimiter = "";
1326 return string_to_array_impl(
1327 string,
1328 split_all_chars_delimiter,
1329 null_string.flatten(),
1330 temp_storage,
1331 );
1332 };
1333
1334 if delimiter.is_empty() {
1335 let mut row = Row::default();
1336 let mut packer = row.packer();
1337 packer.try_push_array(
1338 &[ArrayDimension {
1339 lower_bound: 1,
1340 length: 1,
1341 }],
1342 vec![string].into_iter().map(Datum::String),
1343 )?;
1344
1345 Ok(temp_storage.push_unary_row(row))
1346 } else {
1347 string_to_array_impl(string, delimiter, null_string.flatten(), temp_storage)
1348 }
1349}
1350
1351fn string_to_array_impl<'a>(
1352 string: &str,
1353 delimiter: &str,
1354 null_string: Option<&'a str>,
1355 temp_storage: &'a RowArena,
1356) -> Result<Datum<'a>, EvalError> {
1357 let mut row = Row::default();
1358 let mut packer = row.packer();
1359
1360 let result = string.split(delimiter);
1361 let found: Vec<&str> = if delimiter.is_empty() {
1362 result.filter(|s| !s.is_empty()).collect()
1363 } else {
1364 result.collect()
1365 };
1366 let array_dimensions = [ArrayDimension {
1367 lower_bound: 1,
1368 length: found.len(),
1369 }];
1370
1371 if let Some(null_string) = null_string {
1372 let found_datums = found.into_iter().map(|chunk| {
1373 if chunk.eq(null_string) {
1374 Datum::Null
1375 } else {
1376 Datum::String(chunk)
1377 }
1378 });
1379
1380 packer.try_push_array(&array_dimensions, found_datums)?;
1381 } else {
1382 packer.try_push_array(&array_dimensions, found.into_iter().map(Datum::String))?;
1383 }
1384
1385 Ok(temp_storage.push_unary_row(row))
1386}
1387
1388#[sqlfunc]
1389fn substr<'a>(s: &'a str, start: i32, length: OptionalArg<i32>) -> Result<&'a str, EvalError> {
1390 let raw_start_idx = i64::from(start) - 1;
1391 let start_idx = match usize::try_from(cmp::max(raw_start_idx, 0)) {
1392 Ok(i) => i,
1393 Err(_) => {
1394 return Err(EvalError::InvalidParameterValue(
1395 format!(
1396 "substring starting index ({}) exceeds min/max position",
1397 raw_start_idx
1398 )
1399 .into(),
1400 ));
1401 }
1402 };
1403
1404 let mut char_indices = s.char_indices();
1405 let get_str_index = |(index, _char)| index;
1406
1407 let str_len = s.len();
1408 let start_char_idx = char_indices.nth(start_idx).map_or(str_len, get_str_index);
1409
1410 if let OptionalArg(Some(len)) = length {
1411 let end_idx = match i64::from(len) {
1412 e if e < 0 => {
1413 return Err(EvalError::InvalidParameterValue(
1414 "negative substring length not allowed".into(),
1415 ));
1416 }
1417 e if e == 0 || e + raw_start_idx < 1 => return Ok(""),
1418 e => {
1419 let e = cmp::min(raw_start_idx + e - 1, e - 1);
1420 match usize::try_from(e) {
1421 Ok(i) => i,
1422 Err(_) => {
1423 return Err(EvalError::InvalidParameterValue(
1424 format!("substring length ({}) exceeds max position", e).into(),
1425 ));
1426 }
1427 }
1428 }
1429 };
1430
1431 let end_char_idx = char_indices.nth(end_idx).map_or(str_len, get_str_index);
1432
1433 Ok(&s[start_char_idx..end_char_idx])
1434 } else {
1435 Ok(&s[start_char_idx..])
1436 }
1437}
1438
1439#[sqlfunc(sqlname = "split_string")]
1440fn split_part<'a>(string: &'a str, delimiter: &str, field: i32) -> Result<&'a str, EvalError> {
1441 let index = match usize::try_from(i64::from(field) - 1) {
1442 Ok(index) => index,
1443 Err(_) => {
1444 return Err(EvalError::InvalidParameterValue(
1445 "field position must be greater than zero".into(),
1446 ));
1447 }
1448 };
1449
1450 if delimiter.is_empty() {
1454 if index == 0 {
1455 return Ok(string);
1456 } else {
1457 return Ok("");
1458 }
1459 }
1460
1461 Ok(string.split(delimiter).nth(index).unwrap_or(""))
1464}
1465
1466#[sqlfunc(is_associative = true)]
1467fn concat(strs: Variadic<Option<&str>>) -> Result<String, EvalError> {
1468 let mut total_size = 0;
1469 for s in &strs {
1470 if let Some(s) = s {
1471 total_size += s.len();
1472 if total_size > MAX_STRING_FUNC_RESULT_BYTES {
1473 return Err(EvalError::LengthTooLarge);
1474 }
1475 }
1476 }
1477 let mut buf = String::with_capacity(total_size);
1478 for s in strs {
1479 if let Some(s) = s {
1480 buf.push_str(s);
1481 }
1482 }
1483 Ok(buf)
1484}
1485
1486#[sqlfunc]
1487fn concat_ws(ws: &str, rest: Variadic<Option<&str>>) -> Result<String, EvalError> {
1488 let mut total_size = 0;
1489 for s in &rest {
1490 if let Some(s) = s {
1491 total_size += s.len();
1492 total_size += ws.len();
1493 if total_size > MAX_STRING_FUNC_RESULT_BYTES {
1494 return Err(EvalError::LengthTooLarge);
1495 }
1496 }
1497 }
1498
1499 let buf = Itertools::join(&mut rest.into_iter().filter_map(|s| s), ws);
1500
1501 Ok(buf)
1502}
1503
1504#[sqlfunc]
1505fn translate(string: &str, from_str: &str, to_str: &str) -> String {
1506 let from = from_str.chars().collect::<Vec<_>>();
1507 let to = to_str.chars().collect::<Vec<_>>();
1508
1509 string
1510 .chars()
1511 .filter_map(|c| match from.iter().position(|f| f == &c) {
1512 Some(idx) => to.get(idx).copied(),
1513 None => Some(c),
1514 })
1515 .collect()
1516}
1517
1518#[sqlfunc(
1519 output_type_expr = "input_types[0].scalar_type.clone().nullable(false)",
1520 introduces_nulls = false
1521)]
1522#[allow(clippy::as_conversions)]
1524fn list_slice_linear<'a>(
1525 list: DatumList<'a>,
1526 first: (i64, i64),
1527 remainder: Variadic<(i64, i64)>,
1528 temp_storage: &'a RowArena,
1529) -> Datum<'a> {
1530 let mut start_idx = 0;
1531 let mut total_length = usize::MAX;
1532
1533 for (start, end) in std::iter::once(first).chain(remainder) {
1534 let start = std::cmp::max(start, 1);
1535
1536 if start > end {
1538 start_idx = 0;
1539 total_length = 0;
1540 break;
1541 }
1542
1543 let start_inner = start as usize - 1;
1544 start_idx += start_inner;
1546
1547 let length_inner = (end - start) as usize + 1;
1549 total_length = std::cmp::min(length_inner, total_length - start_inner);
1550 }
1551
1552 let iter = list.iter().skip(start_idx).take(total_length);
1553
1554 temp_storage.make_datum(|row| {
1555 row.push_list_with(|row| {
1556 for d in iter {
1558 row.push(d);
1559 }
1560 });
1561 })
1562}
1563
1564#[sqlfunc(sqlname = "timestamp_bin")]
1565fn date_bin_timestamp(
1566 stride: Interval,
1567 source: CheckedTimestamp<NaiveDateTime>,
1568 origin: CheckedTimestamp<NaiveDateTime>,
1569) -> Result<CheckedTimestamp<NaiveDateTime>, EvalError> {
1570 date_bin(stride, source, origin)
1571}
1572
1573#[sqlfunc(sqlname = "timestamptz_bin")]
1574fn date_bin_timestamp_tz(
1575 stride: Interval,
1576 source: CheckedTimestamp<DateTime<Utc>>,
1577 origin: CheckedTimestamp<DateTime<Utc>>,
1578) -> Result<CheckedTimestamp<DateTime<Utc>>, EvalError> {
1579 date_bin(stride, source, origin)
1580}
1581
1582#[sqlfunc(sqlname = "timezonet")]
1583fn timezone_time_variadic(
1584 tz_str: &str,
1585 time: NaiveTime,
1586 wall_time: CheckedTimestamp<DateTime<Utc>>,
1587) -> Result<NaiveTime, EvalError> {
1588 parse_timezone(tz_str, TimezoneSpec::Posix)
1589 .map(|tz| timezone_time(tz, time, &wall_time.naive_utc()))
1590}
1591pub(crate) trait LazyVariadicFunc: fmt::Display {
1592 fn eval<'a>(
1593 &'a self,
1594 datums: &[Datum<'a>],
1595 temp_storage: &'a RowArena,
1596 exprs: &'a [MirScalarExpr],
1597 ) -> Result<Datum<'a>, EvalError>;
1598
1599 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType;
1601
1602 fn propagates_nulls(&self) -> bool;
1604
1605 fn introduces_nulls(&self) -> bool;
1607
1608 fn could_error(&self) -> bool {
1610 true
1611 }
1612
1613 fn is_monotone(&self) -> bool {
1615 false
1616 }
1617
1618 fn is_associative(&self) -> bool {
1620 false
1621 }
1622
1623 fn is_infix_op(&self) -> bool {
1625 false
1626 }
1627}
1628
1629pub(crate) trait EagerVariadicFunc: fmt::Display {
1630 type Input<'a>: InputDatumType<'a, EvalError>;
1631 type Output<'a>: OutputDatumType<'a, EvalError>;
1632
1633 fn call<'a>(&self, input: Self::Input<'a>, temp_storage: &'a RowArena) -> Self::Output<'a>;
1634
1635 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType;
1636
1637 fn propagates_nulls(&self) -> bool {
1638 !Self::Input::nullable()
1639 }
1640
1641 fn introduces_nulls(&self) -> bool {
1642 Self::Output::nullable()
1643 }
1644
1645 fn could_error(&self) -> bool {
1646 Self::Output::fallible()
1647 }
1648
1649 fn is_monotone(&self) -> bool {
1650 false
1651 }
1652
1653 fn is_associative(&self) -> bool {
1654 false
1655 }
1656
1657 fn is_infix_op(&self) -> bool {
1658 false
1659 }
1660}
1661
1662impl<T: EagerVariadicFunc> LazyVariadicFunc for T {
1665 fn eval<'a>(
1666 &'a self,
1667 datums: &[Datum<'a>],
1668 temp_storage: &'a RowArena,
1669 exprs: &'a [MirScalarExpr],
1670 ) -> Result<Datum<'a>, EvalError> {
1671 let mut datums = exprs.iter().map(|e| e.eval(datums, temp_storage));
1672 match T::Input::try_from_iter(&mut datums) {
1673 Ok(input) => self.call(input, temp_storage).into_result(temp_storage),
1674 Err(Ok(None)) => Err(EvalError::Internal("missing parameter".into())),
1675 Err(Ok(Some(datum))) if datum.is_null() => Ok(datum),
1676 Err(Ok(Some(_datum))) => {
1677 Err(EvalError::Internal("invalid input type".into()))
1679 }
1680 Err(Err(res)) => Err(res),
1681 }
1682 }
1683
1684 fn output_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
1685 self.output_type(input_types)
1686 }
1687
1688 fn propagates_nulls(&self) -> bool {
1689 self.propagates_nulls()
1690 }
1691
1692 fn introduces_nulls(&self) -> bool {
1693 self.introduces_nulls()
1694 }
1695
1696 fn could_error(&self) -> bool {
1697 self.could_error()
1698 }
1699
1700 fn is_monotone(&self) -> bool {
1701 self.is_monotone()
1702 }
1703
1704 fn is_associative(&self) -> bool {
1705 self.is_associative()
1706 }
1707
1708 fn is_infix_op(&self) -> bool {
1709 self.is_infix_op()
1710 }
1711}
1712
1713derive_variadic! {
1714 Coalesce(Coalesce),
1715 Greatest(Greatest),
1716 Least(Least),
1717 Concat(Concat),
1718 ConcatWs(ConcatWs),
1719 MakeTimestamp(MakeTimestamp),
1720 PadLeading(PadLeading),
1721 Substr(Substr),
1722 Replace(Replace),
1723 JsonbBuildArray(JsonbBuildArray),
1724 JsonbBuildObject(JsonbBuildObject),
1725 MapBuild(MapBuild),
1726 ArrayCreate(ArrayCreate),
1727 ArrayToString(ArrayToString),
1728 ArrayIndex(ArrayIndex),
1729 ListCreate(ListCreate),
1730 RecordCreate(RecordCreate),
1731 ListIndex(ListIndex),
1732 ListSliceLinear(ListSliceLinear),
1733 SplitPart(SplitPart),
1734 RegexpMatch(RegexpMatch),
1735 HmacString(HmacString),
1736 HmacBytes(HmacBytes),
1737 ErrorIfNull(ErrorIfNull),
1738 DateBinTimestamp(DateBinTimestamp),
1739 DateBinTimestampTz(DateBinTimestampTz),
1740 DateDiffTimestamp(DateDiffTimestamp),
1741 DateDiffTimestampTz(DateDiffTimestampTz),
1742 DateDiffDate(DateDiffDate),
1743 DateDiffTime(DateDiffTime),
1744 And(And),
1745 Or(Or),
1746 RangeCreate(RangeCreate),
1747 MakeAclItem(MakeAclItem),
1748 MakeMzAclItem(MakeMzAclItem),
1749 Translate(Translate),
1750 ArrayPosition(ArrayPosition),
1751 ArrayFill(ArrayFill),
1752 StringToArray(StringToArray),
1753 TimezoneTimeVariadic(TimezoneTimeVariadic),
1754 RegexpSplitToArray(RegexpSplitToArray),
1755 RegexpReplace(RegexpReplace),
1756 CaseLiteral(CaseLiteral),
1757}
1758
1759impl VariadicFunc {
1760 pub fn switch_and_or(&self) -> Self {
1761 match self {
1762 VariadicFunc::And(_) => Or.into(),
1763 VariadicFunc::Or(_) => And.into(),
1764 _ => unreachable!(),
1765 }
1766 }
1767
1768 pub fn unit_of_and_or(&self) -> MirScalarExpr {
1771 match self {
1772 VariadicFunc::And(_) => MirScalarExpr::literal_true(),
1773 VariadicFunc::Or(_) => MirScalarExpr::literal_false(),
1774 _ => unreachable!(),
1775 }
1776 }
1777
1778 pub fn zero_of_and_or(&self) -> MirScalarExpr {
1780 match self {
1781 VariadicFunc::And(_) => MirScalarExpr::literal_false(),
1782 VariadicFunc::Or(_) => MirScalarExpr::literal_true(),
1783 _ => unreachable!(),
1784 }
1785 }
1786}