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