1use std::borrow::Cow;
27use std::collections::BTreeMap;
28use std::error::Error;
29use std::fmt;
30use std::num::FpCategory;
31use std::str::FromStr;
32use std::sync::LazyLock;
33
34use chrono::offset::{Offset, TimeZone};
35use chrono::{DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
36use dec::OrderedDecimal;
37use mz_ore::cast::ReinterpretCast;
38use mz_ore::error::ErrorExt;
39use mz_ore::fmt::FormatBuffer;
40use mz_ore::lex::LexBuf;
41use mz_ore::str::StrExt;
42use mz_pgtz::timezone::{Timezone, TimezoneSpec};
43use mz_proto::{ProtoType, RustType, TryFromProtoError};
44use num_traits::Float as NumFloat;
45#[cfg(any(test, feature = "proptest"))]
46use proptest_derive::Arbitrary;
47use regex::bytes::Regex;
48use ryu::Float as RyuFloat;
49use serde::{Deserialize, Serialize};
50use uuid::Uuid;
51
52use crate::adt::array::ArrayDimension;
53use crate::adt::date::Date;
54use crate::adt::datetime::{self, DateOrder, DateTimeField, ParsedDateTime};
55use crate::adt::interval::Interval;
56use crate::adt::jsonb::{Jsonb, JsonbRef};
57use crate::adt::mz_acl_item::{AclItem, MzAclItem};
58use crate::adt::numeric::{self, NUMERIC_DATUM_MAX_PRECISION, Numeric};
59use crate::adt::pg_legacy_name::NAME_MAX_BYTES;
60use crate::adt::range::{Range, RangeBound, RangeInner};
61use crate::adt::timestamp::CheckedTimestamp;
62
63include!(concat!(env!("OUT_DIR"), "/mz_repr.strconv.rs"));
64
65macro_rules! bail {
66 ($($arg:tt)*) => { return Err(format!($($arg)*)) };
67}
68
69#[derive(Debug)]
71pub enum Nestable {
72 Yes,
73 MayNeedEscaping,
74}
75
76pub fn parse_bool(s: &str) -> Result<bool, ParseError> {
82 match s.trim().to_lowercase().as_str() {
83 "t" | "tr" | "tru" | "true" | "y" | "ye" | "yes" | "on" | "1" => Ok(true),
84 "f" | "fa" | "fal" | "fals" | "false" | "n" | "no" | "of" | "off" | "0" => Ok(false),
85 _ => Err(ParseError::invalid_input_syntax("boolean", s)),
86 }
87}
88
89pub fn format_bool_static(b: bool) -> &'static str {
94 match b {
95 true => "t",
96 false => "f",
97 }
98}
99
100pub fn format_bool<F>(buf: &mut F, b: bool) -> Nestable
105where
106 F: FormatBuffer,
107{
108 buf.write_str(format_bool_static(b));
109 Nestable::Yes
110}
111
112pub fn parse_int16(s: &str) -> Result<i16, ParseError> {
117 s.trim()
118 .parse()
119 .map_err(|e| ParseError::invalid_input_syntax("smallint", s).with_details(e))
120}
121
122pub fn format_int16<F>(buf: &mut F, i: i16) -> Nestable
124where
125 F: FormatBuffer,
126{
127 write!(buf, "{}", i);
128 Nestable::Yes
129}
130
131pub fn parse_int32(s: &str) -> Result<i32, ParseError> {
136 s.trim()
137 .parse()
138 .map_err(|e| ParseError::invalid_input_syntax("integer", s).with_details(e))
139}
140
141pub fn format_int32<F>(buf: &mut F, i: i32) -> Nestable
143where
144 F: FormatBuffer,
145{
146 write!(buf, "{}", i);
147 Nestable::Yes
148}
149
150pub fn parse_int64(s: &str) -> Result<i64, ParseError> {
152 s.trim()
153 .parse()
154 .map_err(|e| ParseError::invalid_input_syntax("bigint", s).with_details(e))
155}
156
157pub fn format_int64<F>(buf: &mut F, i: i64) -> Nestable
159where
160 F: FormatBuffer,
161{
162 write!(buf, "{}", i);
163 Nestable::Yes
164}
165
166pub fn parse_uint16(s: &str) -> Result<u16, ParseError> {
171 s.trim()
172 .parse()
173 .map_err(|e| ParseError::invalid_input_syntax("uint2", s).with_details(e))
174}
175
176pub fn format_uint16<F>(buf: &mut F, u: u16) -> Nestable
178where
179 F: FormatBuffer,
180{
181 write!(buf, "{}", u);
182 Nestable::Yes
183}
184
185pub fn parse_uint32(s: &str) -> Result<u32, ParseError> {
190 s.trim()
191 .parse()
192 .map_err(|e| ParseError::invalid_input_syntax("uint4", s).with_details(e))
193}
194
195pub fn format_uint32<F>(buf: &mut F, u: u32) -> Nestable
197where
198 F: FormatBuffer,
199{
200 write!(buf, "{}", u);
201 Nestable::Yes
202}
203
204pub fn parse_uint64(s: &str) -> Result<u64, ParseError> {
206 s.trim()
207 .parse()
208 .map_err(|e| ParseError::invalid_input_syntax("uint8", s).with_details(e))
209}
210
211pub fn format_uint64<F>(buf: &mut F, u: u64) -> Nestable
213where
214 F: FormatBuffer,
215{
216 write!(buf, "{}", u);
217 Nestable::Yes
218}
219
220pub fn parse_mz_timestamp(s: &str) -> Result<crate::Timestamp, ParseError> {
222 s.trim()
223 .parse()
224 .map_err(|e| ParseError::invalid_input_syntax("mz_timestamp", s).with_details(e))
225}
226
227pub fn parse_mz_timestamp_legacy(s: &str) -> Result<crate::Timestamp, ParseError> {
235 crate::Timestamp::from_str_legacy(s.trim())
236 .map_err(|e| ParseError::invalid_input_syntax("mz_timestamp", s).with_details(e))
237}
238
239pub fn format_mz_timestamp<F>(buf: &mut F, u: crate::Timestamp) -> Nestable
241where
242 F: FormatBuffer,
243{
244 write!(buf, "{}", u);
245 Nestable::Yes
246}
247
248pub fn parse_oid(s: &str) -> Result<u32, ParseError> {
250 let trimmed = s.trim();
259 if let Ok(oid) = trimmed.parse::<u32>() {
260 return Ok(oid);
261 }
262 let oid: i32 = trimmed
263 .parse()
264 .map_err(|e| ParseError::invalid_input_syntax("oid", s).with_details(e))?;
265 Ok(u32::reinterpret_cast(oid))
266}
267
268pub fn parse_oid_legacy(s: &str) -> Result<u32, ParseError> {
281 let oid: i32 = s
282 .trim()
283 .parse()
284 .map_err(|e| ParseError::invalid_input_syntax("oid", s).with_details(e))?;
285 Ok(u32::reinterpret_cast(oid))
286}
287
288fn parse_float<Fl>(type_name: &'static str, s: &str) -> Result<Fl, ParseError>
289where
290 Fl: NumFloat + FromStr,
291{
292 static ZERO_RE: LazyLock<Regex> =
308 LazyLock::new(|| Regex::new(r#"(?i-u)^[-+]?(0+(\.0*)?|\.0+)(e|$)"#).unwrap());
309 static INF_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new("(?i-u)^[-+]?inf").unwrap());
311
312 let buf = s.trim();
313 let f: Fl = buf
314 .parse()
315 .map_err(|_| ParseError::invalid_input_syntax(type_name, s))?;
316 match f.classify() {
317 FpCategory::Infinite if !INF_RE.is_match(buf.as_bytes()) => {
318 Err(ParseError::out_of_range(type_name, s))
319 }
320 FpCategory::Zero if !ZERO_RE.is_match(buf.as_bytes()) => {
321 Err(ParseError::out_of_range(type_name, s))
322 }
323 _ => Ok(f),
324 }
325}
326
327fn format_float<F, Fl>(buf: &mut F, f: Fl) -> Nestable
328where
329 F: FormatBuffer,
330 Fl: NumFloat + RyuFloat,
331{
332 match f.classify() {
345 FpCategory::Infinite if f.is_sign_negative() => buf.write_str("-Infinity"),
346 FpCategory::Infinite => buf.write_str("Infinity"),
347 FpCategory::Nan => buf.write_str("NaN"),
348 FpCategory::Zero if f.is_sign_negative() => buf.write_str("-0"),
349 _ => {
350 debug_assert!(f.is_finite());
351 let mut ryu_buf = ryu::Buffer::new();
352 let mut s = ryu_buf.format_finite(f);
353 if let Some(trimmed) = s.strip_suffix(".0") {
354 s = trimmed;
355 }
356 let mut chars = s.chars().peekable();
357 while let Some(ch) = chars.next() {
358 buf.write_char(ch);
359 if ch == 'e' && chars.peek() != Some(&'-') {
360 buf.write_char('+');
361 }
362 }
363 }
364 }
365
366 Nestable::Yes
367}
368
369pub fn parse_float32(s: &str) -> Result<f32, ParseError> {
371 parse_float("real", s)
372}
373
374pub fn format_float32<F>(buf: &mut F, f: f32) -> Nestable
376where
377 F: FormatBuffer,
378{
379 format_float(buf, f)
380}
381
382pub fn parse_float64(s: &str) -> Result<f64, ParseError> {
384 parse_float("double precision", s)
385}
386
387pub fn format_float64<F>(buf: &mut F, f: f64) -> Nestable
389where
390 F: FormatBuffer,
391{
392 format_float(buf, f)
393}
394
395fn parse_timestamp_string(
414 s: &str,
415 order: DateOrder,
416) -> Result<(NaiveDate, NaiveTime, Timezone), String> {
417 if s.is_empty() {
418 return Err("timestamp string is empty".into());
419 }
420
421 if s == "epoch" {
426 return Ok((
427 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
428 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
429 Default::default(),
430 ));
431 }
432
433 let (ts_string, tz_string, era) = datetime::split_timestamp_string(s);
434
435 let pdt = ParsedDateTime::build_parsed_datetime_timestamp(ts_string, era, order)?;
436 let d: NaiveDate = pdt.compute_date()?;
437 let t: NaiveTime = pdt.compute_time()?;
438
439 let offset = if tz_string.is_empty() {
440 Default::default()
441 } else {
442 Timezone::parse(tz_string, TimezoneSpec::Iso)?
443 };
444
445 Ok((d, t, offset))
446}
447
448pub fn parse_date(s: &str) -> Result<Date, ParseError> {
450 parse_date_inner(s, DateOrder::Mdy)
451}
452
453pub fn parse_date_legacy(s: &str) -> Result<Date, ParseError> {
460 parse_date_inner(s, DateOrder::LegacyYmd)
461}
462
463fn parse_date_inner(s: &str, order: DateOrder) -> Result<Date, ParseError> {
464 match parse_timestamp_string(s, order) {
465 Ok((date, _, _)) => Date::try_from(date).map_err(|_| ParseError::out_of_range("date", s)),
466 Err(e) => Err(ParseError::invalid_input_syntax("date", s).with_details(e)),
467 }
468}
469
470pub fn format_date<F>(buf: &mut F, d: Date) -> Nestable
472where
473 F: FormatBuffer,
474{
475 let d: NaiveDate = d.into();
476 let (year_ad, year) = d.year_ce();
477 write!(buf, "{:04}-{}", year, d.format("%m-%d"));
478 if !year_ad {
479 write!(buf, " BC");
480 }
481 Nestable::Yes
482}
483
484pub fn parse_time(s: &str) -> Result<NaiveTime, ParseError> {
492 ParsedDateTime::build_parsed_datetime_time(s)
493 .and_then(|pdt| pdt.compute_time())
494 .map_err(|e| ParseError::invalid_input_syntax("time", s).with_details(e))
495}
496
497pub fn format_time<F>(buf: &mut F, t: NaiveTime) -> Nestable
499where
500 F: FormatBuffer,
501{
502 write!(buf, "{}", t.format("%H:%M:%S"));
503 format_nanos_to_micros(buf, t.nanosecond());
504 Nestable::Yes
505}
506
507pub fn parse_timestamp(s: &str) -> Result<CheckedTimestamp<NaiveDateTime>, ParseError> {
509 parse_timestamp_inner(s, DateOrder::Mdy)
510}
511
512pub fn parse_timestamp_legacy(s: &str) -> Result<CheckedTimestamp<NaiveDateTime>, ParseError> {
520 parse_timestamp_inner(s, DateOrder::LegacyYmd)
521}
522
523fn parse_timestamp_inner(
524 s: &str,
525 order: DateOrder,
526) -> Result<CheckedTimestamp<NaiveDateTime>, ParseError> {
527 match parse_timestamp_string(s, order) {
528 Ok((date, time, _)) => CheckedTimestamp::from_timestamplike(date.and_time(time))
529 .map_err(|_| ParseError::out_of_range("timestamp", s)),
530 Err(e) => Err(ParseError::invalid_input_syntax("timestamp", s).with_details(e)),
531 }
532}
533
534pub fn format_timestamp<F>(buf: &mut F, ts: &NaiveDateTime) -> Nestable
536where
537 F: FormatBuffer,
538{
539 let (year_ad, year) = ts.year_ce();
540 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
541 format_nanos_to_micros(buf, ts.and_utc().timestamp_subsec_nanos());
542 if !year_ad {
543 write!(buf, " BC");
544 }
545 Nestable::MayNeedEscaping
547}
548
549pub fn parse_timestamptz(s: &str) -> Result<CheckedTimestamp<DateTime<Utc>>, ParseError> {
551 parse_timestamptz_inner(s, DateOrder::Mdy)
552}
553
554pub fn parse_timestamptz_legacy(s: &str) -> Result<CheckedTimestamp<DateTime<Utc>>, ParseError> {
562 parse_timestamptz_inner(s, DateOrder::LegacyYmd)
563}
564
565fn parse_timestamptz_inner(
566 s: &str,
567 order: DateOrder,
568) -> Result<CheckedTimestamp<DateTime<Utc>>, ParseError> {
569 parse_timestamp_string(s, order)
570 .and_then(|(date, time, timezone)| {
571 use Timezone::*;
572 let mut dt = date.and_time(time);
573 let offset = match timezone {
574 FixedOffset(offset) => offset,
575 Tz(tz) => match tz.offset_from_local_datetime(&dt).latest() {
576 Some(offset) => offset.fix(),
577 None => {
578 dt += Duration::try_hours(1).unwrap();
579 tz.offset_from_local_datetime(&dt)
580 .latest()
581 .ok_or_else(|| "invalid timezone conversion".to_owned())?
582 .fix()
583 }
584 },
585 };
586 Ok(DateTime::from_naive_utc_and_offset(dt - offset, Utc))
587 })
588 .map_err(|e| {
589 ParseError::invalid_input_syntax("timestamp with time zone", s).with_details(e)
590 })
591 .and_then(|ts| {
592 CheckedTimestamp::from_timestamplike(ts)
593 .map_err(|_| ParseError::out_of_range("timestamp with time zone", s))
594 })
595}
596
597pub fn format_timestamptz<F>(buf: &mut F, ts: &DateTime<Utc>) -> Nestable
599where
600 F: FormatBuffer,
601{
602 let (year_ad, year) = ts.year_ce();
603 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
604 format_nanos_to_micros(buf, ts.timestamp_subsec_nanos());
605 write!(buf, "+00");
606 if !year_ad {
607 write!(buf, " BC");
608 }
609 Nestable::MayNeedEscaping
611}
612
613pub fn parse_interval(s: &str) -> Result<Interval, ParseError> {
633 parse_interval_w_disambiguator(s, None, DateTimeField::Second)
634}
635
636pub fn parse_interval_w_disambiguator(
641 s: &str,
642 leading_time_precision: Option<DateTimeField>,
643 d: DateTimeField,
644) -> Result<Interval, ParseError> {
645 ParsedDateTime::build_parsed_datetime_interval(s, leading_time_precision, d)
646 .and_then(|pdt| pdt.compute_interval())
647 .map_err(|e| ParseError::invalid_input_syntax("interval", s).with_details(e))
648}
649
650pub fn format_interval<F>(buf: &mut F, iv: Interval) -> Nestable
651where
652 F: FormatBuffer,
653{
654 write!(buf, "{}", iv);
655 Nestable::MayNeedEscaping
656}
657
658pub fn parse_numeric(s: &str) -> Result<OrderedDecimal<Numeric>, ParseError> {
659 let mut cx = numeric::cx_datum();
660 let mut n = match cx.parse(s.trim()) {
661 Ok(n) => n,
662 Err(..) => {
663 return Err(ParseError::invalid_input_syntax("numeric", s));
664 }
665 };
666
667 let cx_status = cx.status();
668
669 if (n.is_infinite() && !cx_status.overflow())
671 || (n.is_nan() && n.is_negative())
672 || n.is_signaling_nan()
673 {
674 return Err(ParseError::invalid_input_syntax("numeric", s));
675 }
676
677 let out_of_range = numeric::munge_numeric(&mut n).is_err();
679
680 if cx_status.overflow() || cx_status.subnormal() || out_of_range {
681 Err(ParseError::out_of_range("numeric", s).with_details(format!(
682 "exceeds maximum precision {}",
683 NUMERIC_DATUM_MAX_PRECISION
684 )))
685 } else {
686 Ok(OrderedDecimal(n))
687 }
688}
689
690pub fn format_numeric<F>(buf: &mut F, n: &OrderedDecimal<Numeric>) -> Nestable
691where
692 F: FormatBuffer,
693{
694 write!(buf, "{}", n.0.to_standard_notation_string());
695 Nestable::Yes
696}
697
698pub fn format_string<F>(buf: &mut F, s: &str) -> Nestable
699where
700 F: FormatBuffer,
701{
702 buf.write_str(s);
703 Nestable::MayNeedEscaping
704}
705
706pub fn parse_pg_legacy_name(s: &str) -> String {
707 let mut out = String::new();
710 let mut len = 0;
711 for c in s.chars() {
712 len += c.len_utf8();
713 if len > NAME_MAX_BYTES {
714 break;
715 }
716 out.push(c);
717 }
718 out
719}
720
721pub fn parse_bytes(s: &str) -> Result<Vec<u8>, ParseError> {
722 if let Some(remainder) = s.strip_prefix(r"\x") {
728 parse_bytes_hex(remainder).map_err(|e| {
729 ParseError::invalid_input_syntax("bytea", s).with_details(e.to_string_with_causes())
730 })
731 } else {
732 parse_bytes_traditional(s)
733 }
734}
735
736pub fn parse_bytes_hex(s: &str) -> Result<Vec<u8>, ParseHexError> {
737 let decode_nibble = |b| match b {
741 b'a'..=b'f' => Ok(b - b'a' + 10),
742 b'A'..=b'F' => Ok(b - b'A' + 10),
743 b'0'..=b'9' => Ok(b - b'0'),
744 _ => Err(ParseHexError::InvalidHexDigit(char::from(b))),
745 };
746
747 let mut buf = vec![];
748 let mut nibbles = s.as_bytes().iter().copied();
749 while let Some(n) = nibbles.next() {
750 if let b' ' | b'\n' | b'\t' | b'\r' = n {
751 continue;
752 }
753 let n = decode_nibble(n)?;
754 let n2 = match nibbles.next() {
755 None => return Err(ParseHexError::OddLength),
756 Some(n2) => decode_nibble(n2)?,
757 };
758 buf.push((n << 4) | n2);
759 }
760 Ok(buf)
761}
762
763pub fn parse_bytes_traditional(s: &str) -> Result<Vec<u8>, ParseError> {
764 let mut out = Vec::with_capacity(s.len());
768 let mut bytes = s.as_bytes().iter().fuse();
769 while let Some(&b) = bytes.next() {
770 if b != b'\\' {
771 out.push(b);
772 continue;
773 }
774 match bytes.next() {
775 None => {
776 return Err(ParseError::invalid_input_syntax("bytea", s)
777 .with_details("ends with escape character"));
778 }
779 Some(b'\\') => out.push(b'\\'),
780 b => match (b, bytes.next(), bytes.next()) {
781 (Some(d2 @ b'0'..=b'3'), Some(d1 @ b'0'..=b'7'), Some(d0 @ b'0'..=b'7')) => {
782 out.push(((d2 - b'0') << 6) + ((d1 - b'0') << 3) + (d0 - b'0'));
783 }
784 _ => {
785 return Err(ParseError::invalid_input_syntax("bytea", s)
786 .with_details("invalid escape sequence"));
787 }
788 },
789 }
790 }
791 Ok(out)
792}
793
794pub fn format_bytes<F>(buf: &mut F, bytes: &[u8]) -> Nestable
795where
796 F: FormatBuffer,
797{
798 write!(buf, "\\x{}", hex::encode(bytes));
799 Nestable::MayNeedEscaping
800}
801
802pub fn parse_jsonb(s: &str) -> Result<Jsonb, ParseError> {
803 s.trim()
804 .parse()
805 .map_err(|e| ParseError::invalid_input_syntax("jsonb", s).with_details(e))
806}
807
808pub fn format_jsonb<F>(buf: &mut F, jsonb: JsonbRef) -> Nestable
809where
810 F: FormatBuffer,
811{
812 write!(buf, "{}", jsonb);
813 Nestable::MayNeedEscaping
814}
815
816pub fn format_jsonb_pretty<F>(buf: &mut F, jsonb: JsonbRef)
817where
818 F: FormatBuffer,
819{
820 write!(buf, "{:#}", jsonb)
821}
822
823pub fn parse_uuid(s: &str) -> Result<Uuid, ParseError> {
824 s.trim()
825 .parse()
826 .map_err(|e| ParseError::invalid_input_syntax("uuid", s).with_details(e))
827}
828
829pub fn format_uuid<F>(buf: &mut F, uuid: Uuid) -> Nestable
830where
831 F: FormatBuffer,
832{
833 write!(buf, "{}", uuid);
834 Nestable::Yes
835}
836
837fn format_nanos_to_micros<F>(buf: &mut F, nanos: u32)
838where
839 F: FormatBuffer,
840{
841 if nanos >= 500 {
842 let mut micros = nanos / 1000;
843 let rem = nanos % 1000;
844 if rem >= 500 {
845 micros += 1;
846 }
847 let mut width = 6;
849 while micros % 10 == 0 {
850 width -= 1;
851 micros /= 10;
852 }
853 write!(buf, ".{:0width$}", micros, width = width);
854 }
855}
856
857#[derive(Debug, thiserror::Error)]
858enum ArrayParsingError {
859 #[error("Array value must start with \"{{\"")]
860 OpeningBraceMissing,
861 #[error("Specifying array lower bounds is not supported")]
862 DimsUnsupported,
863 #[error("{0}")]
864 Generic(String),
865 #[error("Unexpected \"{0}\" character.")]
866 UnexpectedChar(char),
867 #[error("Multidimensional arrays must have sub-arrays with matching dimensions.")]
868 NonRectilinearDims,
869 #[error("Unexpected array element.")]
870 UnexpectedElement,
871 #[error("Junk after closing right brace.")]
872 Junk,
873 #[error("Unexpected end of input.")]
874 EarlyTerm,
875}
876
877impl From<String> for ArrayParsingError {
878 fn from(value: String) -> Self {
879 ArrayParsingError::Generic(value)
880 }
881}
882
883pub fn parse_array<'a, T, E>(
884 s: &'a str,
885 make_null: impl FnMut() -> T,
886 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
887) -> Result<(Vec<T>, Vec<ArrayDimension>), ParseError>
888where
889 E: ToString,
890{
891 parse_array_inner(s, make_null, gen_elem)
892 .map_err(|details| ParseError::invalid_input_syntax("array", s).with_details(details))
893}
894
895fn parse_array_inner<'a, T, E>(
896 s: &'a str,
897 mut make_null: impl FnMut() -> T,
898 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
899) -> Result<(Vec<T>, Vec<ArrayDimension>), ArrayParsingError>
900where
901 E: ToString,
902{
903 use ArrayParsingError::*;
904
905 #[derive(Clone, Debug, Default)]
906 struct Dimension {
907 length: Option<usize>,
910 staged_element: bool,
914 committed_element_count: usize,
917 }
918
919 #[derive(Clone, Debug, Default)]
920 struct ArrayBuilder<'a> {
921 current_command_char: char,
923 dimensions: Vec<Dimension>,
926 current_dim: usize,
928 sealed: bool,
930 elements: Vec<Option<Cow<'a, str>>>,
934 }
935
936 impl<'a> ArrayBuilder<'a> {
937 fn build(
938 s: &'a str,
939 ) -> Result<(Vec<Option<Cow<'a, str>>>, Vec<ArrayDimension>), ArrayParsingError> {
940 let buf = &mut LexBuf::new(s);
941
942 if buf.consume('[') {
944 Err(DimsUnsupported)?;
945 }
946
947 buf.take_while(|ch| ch.is_ascii_whitespace());
948
949 if !buf.consume('{') {
950 Err(OpeningBraceMissing)?;
951 }
952
953 let mut dimensions = 1;
954
955 loop {
956 buf.take_while(|ch| ch.is_ascii_whitespace());
957 if buf.consume('{') {
958 dimensions += 1;
959 } else {
960 break;
961 }
962 }
963
964 let mut builder = ArrayBuilder {
965 current_command_char: '{',
966 dimensions: vec![Dimension::default(); dimensions],
967 current_dim: dimensions - 1,
970 sealed: false,
971 elements: vec![],
972 };
973
974 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
975 let is_end_of_literal = |c| matches!(c, ',' | '}');
976
977 loop {
978 buf.take_while(|ch| ch.is_ascii_whitespace());
979
980 match buf.next() {
982 None if builder.sealed => {
983 break;
984 }
985 None => Err(EarlyTerm)?,
986 Some(_) if builder.sealed => Err(Junk)?,
987 Some(c) => builder.current_command_char = c,
988 }
989
990 match builder.current_command_char {
992 '{' => builder.enter_dim()?,
993 '}' => builder.exit_dim()?,
994 ',' => builder.commit_element(true)?,
995 c => {
996 buf.prev();
997 let s = match c {
998 '"' => Some(lex_quoted_element(buf)?),
999 _ => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1000 };
1001 builder.insert_element(s)?;
1002 }
1003 }
1004 }
1005
1006 if builder.elements.is_empty() {
1007 return Ok((vec![], vec![]));
1010 }
1011
1012 let dims = builder
1013 .dimensions
1014 .into_iter()
1015 .map(|dim| ArrayDimension {
1016 length: dim
1017 .length
1018 .expect("every dimension must have its length discovered"),
1019 lower_bound: 1,
1020 })
1021 .collect();
1022
1023 Ok((builder.elements, dims))
1024 }
1025
1026 fn enter_dim(&mut self) -> Result<(), ArrayParsingError> {
1028 let d = &mut self.dimensions[self.current_dim];
1029 if d.staged_element {
1031 return Err(UnexpectedChar(self.current_command_char));
1032 }
1033
1034 self.current_dim += 1;
1035
1036 if self.current_dim >= self.dimensions.len() {
1038 return Err(NonRectilinearDims);
1039 }
1040
1041 Ok(())
1042 }
1043
1044 fn insert_element(&mut self, s: Option<Cow<'a, str>>) -> Result<(), ArrayParsingError> {
1046 if self.current_dim != self.dimensions.len() - 1 {
1049 return Err(UnexpectedElement);
1050 }
1051
1052 self.stage_element()?;
1053
1054 self.elements.push(s);
1055
1056 Ok(())
1057 }
1058
1059 fn stage_element(&mut self) -> Result<(), ArrayParsingError> {
1063 let d = &mut self.dimensions[self.current_dim];
1064 if d.staged_element {
1067 return Err(UnexpectedElement);
1068 }
1069 d.staged_element = true;
1070 Ok(())
1071 }
1072
1073 fn commit_element(&mut self, require_staged: bool) -> Result<(), ArrayParsingError> {
1077 let d = &mut self.dimensions[self.current_dim];
1078 if !d.staged_element {
1079 return if require_staged || d.committed_element_count > 0 {
1083 Err(UnexpectedChar(self.current_command_char))
1084 } else {
1085 Ok(())
1089 };
1090 }
1091 d.staged_element = false;
1092 d.committed_element_count += 1;
1093
1094 Ok(())
1095 }
1096
1097 fn exit_dim(&mut self) -> Result<(), ArrayParsingError> {
1103 self.commit_element(false)?;
1105
1106 let ndims = self.dimensions.len();
1107 let d = &mut self.dimensions[self.current_dim];
1108
1109 if d.committed_element_count == 0 && ndims > 1 {
1112 return Err(UnexpectedChar(self.current_command_char));
1113 }
1114
1115 match d.length {
1117 None => d.length = Some(d.committed_element_count),
1118 Some(l) => {
1119 if l != d.committed_element_count {
1120 return Err(NonRectilinearDims);
1121 }
1122 }
1123 }
1124
1125 d.committed_element_count = 0;
1127
1128 if self.current_dim == 0 {
1131 self.sealed = true;
1132 } else {
1133 self.current_dim -= 1;
1134 self.stage_element()?;
1136 }
1137
1138 Ok(())
1139 }
1140 }
1141
1142 let (raw_elems, dims) = ArrayBuilder::build(s)?;
1143
1144 let mut elems = Vec::with_capacity(raw_elems.len());
1145
1146 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1147
1148 for elem in raw_elems.into_iter() {
1149 elems.push(match elem {
1150 Some(elem) => generated(elem)?,
1151 None => make_null(),
1152 });
1153 }
1154
1155 Ok((elems, dims))
1156}
1157
1158pub fn parse_list<'a, T, E>(
1159 s: &'a str,
1160 is_element_type_list: bool,
1161 make_null: impl FnMut() -> T,
1162 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1163) -> Result<Vec<T>, ParseError>
1164where
1165 E: ToString,
1166{
1167 parse_list_inner(s, is_element_type_list, make_null, gen_elem)
1168 .map_err(|details| ParseError::invalid_input_syntax("list", s).with_details(details))
1169}
1170
1171fn parse_list_inner<'a, T, E>(
1174 s: &'a str,
1175 is_element_type_list: bool,
1176 mut make_null: impl FnMut() -> T,
1177 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1178) -> Result<Vec<T>, String>
1179where
1180 E: ToString,
1181{
1182 let mut elems = vec![];
1183 let buf = &mut LexBuf::new(s);
1184
1185 if !buf.consume('{') {
1187 bail!(
1188 "expected '{{', found {}",
1189 match buf.next() {
1190 Some(c) => format!("{}", c),
1191 None => "empty string".to_string(),
1192 }
1193 )
1194 }
1195
1196 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1198 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
1199 let is_end_of_literal = |c| matches!(c, ',' | '}');
1200
1201 loop {
1203 buf.take_while(|ch| ch.is_ascii_whitespace());
1204 match buf.next() {
1206 Some('}') => {
1207 break;
1208 }
1209 _ if elems.len() == 0 => {
1210 buf.prev();
1211 }
1212 Some(',') => {}
1213 Some(c) => bail!("expected ',' or '}}', got '{}'", c),
1214 None => bail!("unexpected end of input"),
1215 }
1216
1217 buf.take_while(|ch| ch.is_ascii_whitespace());
1218 let elem = match buf.peek() {
1220 Some('"') => generated(lex_quoted_element(buf)?)?,
1221 Some('{') => {
1222 if !is_element_type_list {
1223 bail!(
1224 "unescaped '{{' at beginning of element; perhaps you \
1225 want a nested list, e.g. '{{a}}'::text list list"
1226 )
1227 }
1228 generated(lex_embedded_element(buf)?)?
1229 }
1230 Some(_) => match lex_unquoted_element(buf, is_special_char, is_end_of_literal)? {
1231 Some(elem) => generated(elem)?,
1232 None => make_null(),
1233 },
1234 None => bail!("unexpected end of input"),
1235 };
1236 elems.push(elem);
1237 }
1238
1239 buf.take_while(|ch| ch.is_ascii_whitespace());
1240 if let Some(c) = buf.next() {
1241 bail!(
1242 "malformed array literal; contains '{}' after terminal '}}'",
1243 c
1244 )
1245 }
1246
1247 Ok(elems)
1248}
1249
1250pub fn parse_legacy_vector<'a, T, E>(
1251 s: &'a str,
1252 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1253) -> Result<Vec<T>, ParseError>
1254where
1255 E: ToString,
1256{
1257 parse_legacy_vector_inner(s, gen_elem)
1258 .map_err(|details| ParseError::invalid_input_syntax("int2vector", s).with_details(details))
1259}
1260
1261pub fn parse_legacy_vector_inner<'a, T, E>(
1266 s: &'a str,
1267 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1268) -> Result<Vec<T>, String>
1269where
1270 E: ToString,
1271{
1272 let mut elems = vec![];
1273 let buf = &mut LexBuf::new(s);
1274
1275 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1276
1277 loop {
1278 buf.take_while(|ch| ch.is_ascii_whitespace());
1279 match buf.peek() {
1280 Some(_) => {
1281 let elem = buf.take_while(|ch| !ch.is_ascii_whitespace());
1282 elems.push(generated(elem.into())?);
1283 }
1284 None => break,
1285 }
1286 }
1287
1288 Ok(elems)
1289}
1290
1291fn lex_quoted_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1292 assert!(buf.consume('"'));
1293 let s = buf.take_while(|ch| !matches!(ch, '"' | '\\'));
1294
1295 if let Some('"') = buf.peek() {
1297 buf.next();
1298 return Ok(s.into());
1299 }
1300
1301 let mut s = s.to_string();
1302 loop {
1303 match buf.next() {
1304 Some('\\') => match buf.next() {
1305 Some(c) => s.push(c),
1306 None => bail!("unterminated quoted string"),
1307 },
1308 Some('"') => break,
1309 Some(c) => s.push(c),
1310 None => bail!("unterminated quoted string"),
1311 }
1312 }
1313 Ok(s.into())
1314}
1315
1316fn lex_embedded_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1317 let pos = buf.pos();
1318 assert!(matches!(buf.next(), Some('{')));
1319 let mut depth = 1;
1320 let mut in_escape = false;
1321 while depth > 0 {
1322 match buf.next() {
1323 Some('\\') => {
1324 buf.next(); }
1326 Some('"') => in_escape = !in_escape, Some('{') if !in_escape => depth += 1,
1328 Some('}') if !in_escape => depth -= 1,
1329 Some(_) => (),
1330 None => bail!("unterminated embedded element"),
1331 }
1332 }
1333 let s = &buf.inner()[pos..buf.pos()];
1334 Ok(Cow::Borrowed(s))
1335}
1336
1337fn lex_unquoted_element<'a>(
1339 buf: &mut LexBuf<'a>,
1340 is_special_char: impl Fn(char) -> bool,
1341 is_end_of_literal: impl Fn(char) -> bool,
1342) -> Result<Option<Cow<'a, str>>, String> {
1343 assert!(!buf.peek().unwrap().is_ascii_whitespace());
1345
1346 let s = buf.take_while(|ch| !is_special_char(ch) && !ch.is_ascii_whitespace());
1347
1348 match buf.peek() {
1350 Some(',') | Some('}') if !s.is_empty() => {
1351 return Ok(if s.to_uppercase() == "NULL" {
1352 None
1353 } else {
1354 Some(s.into())
1355 });
1356 }
1357 _ => {}
1358 }
1359
1360 let mut escaped_char = false;
1364
1365 let mut s = s.to_string();
1366 let mut trimmed_len = s.len();
1369 loop {
1370 match buf.next() {
1371 Some('\\') => match buf.next() {
1372 Some(c) => {
1373 escaped_char = true;
1374 s.push(c);
1375 trimmed_len = s.len();
1376 }
1377 None => return Err("unterminated element".into()),
1378 },
1379 Some(c) if is_end_of_literal(c) => {
1380 if s.is_empty() {
1383 bail!("malformed literal; missing element")
1384 }
1385 buf.prev();
1386 break;
1387 }
1388 Some(c) if is_special_char(c) => {
1389 bail!("malformed literal; must escape special character '{}'", c)
1390 }
1391 Some(c) => {
1392 s.push(c);
1393 if !c.is_ascii_whitespace() {
1394 trimmed_len = s.len();
1395 }
1396 }
1397 None => bail!("unterminated element"),
1398 }
1399 }
1400 s.truncate(trimmed_len);
1401 Ok(if s.to_uppercase() == "NULL" && !escaped_char {
1402 None
1403 } else {
1404 Some(Cow::Owned(s))
1405 })
1406}
1407
1408pub fn parse_map<'a, V, E>(
1409 s: &'a str,
1410 is_value_type_map: bool,
1411 gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1412) -> Result<BTreeMap<String, V>, ParseError>
1413where
1414 E: ToString,
1415{
1416 parse_map_inner(s, is_value_type_map, gen_elem)
1417 .map_err(|details| ParseError::invalid_input_syntax("map", s).with_details(details))
1418}
1419
1420fn parse_map_inner<'a, V, E>(
1421 s: &'a str,
1422 is_value_type_map: bool,
1423 mut gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1424) -> Result<BTreeMap<String, V>, String>
1425where
1426 E: ToString,
1427{
1428 let mut map = BTreeMap::new();
1429 let buf = &mut LexBuf::new(s);
1430
1431 if !buf.consume('{') {
1433 bail!(
1434 "expected '{{', found {}",
1435 match buf.next() {
1436 Some(c) => format!("{}", c),
1437 None => "empty string".to_string(),
1438 }
1439 )
1440 }
1441
1442 let gen_key = |key: Option<Cow<'a, str>>| -> Result<String, String> {
1444 match key {
1445 Some(Cow::Owned(s)) => Ok(s),
1446 Some(Cow::Borrowed(s)) => Ok(s.to_owned()),
1447 None => Err("expected key".to_owned()),
1448 }
1449 };
1450 let mut gen_value = |elem| gen_elem(elem).map_err(|e| e.to_string());
1451 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '"' | '=' | '>' | '\\');
1452 let is_end_of_literal = |c| matches!(c, ',' | '}' | '=');
1453
1454 loop {
1455 buf.take_while(|ch| ch.is_ascii_whitespace());
1457 match buf.next() {
1458 Some('}') => break,
1459 _ if map.len() == 0 => {
1460 buf.prev();
1461 }
1462 Some(',') => {}
1463 Some(c) => bail!("expected ',' or end of input, got '{}'", c),
1464 None => bail!("unexpected end of input"),
1465 }
1466
1467 buf.take_while(|ch| ch.is_ascii_whitespace());
1469 let key = match buf.peek() {
1470 Some('"') => Some(lex_quoted_element(buf)?),
1471 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1472 None => bail!("unexpected end of input"),
1473 };
1474 let key = gen_key(key)?;
1475
1476 buf.take_while(|ch| ch.is_ascii_whitespace());
1478 if !buf.consume('=') || !buf.consume('>') {
1479 bail!("expected =>")
1480 }
1481
1482 buf.take_while(|ch| ch.is_ascii_whitespace());
1484 let value = match buf.peek() {
1485 Some('"') => Some(lex_quoted_element(buf)?),
1486 Some('{') => {
1487 if !is_value_type_map {
1488 bail!(
1489 "unescaped '{{' at beginning of value; perhaps you \
1490 want a nested map, e.g. '{{a=>{{a=>1}}}}'::map[text=>map[text=>int]]"
1491 )
1492 }
1493 Some(lex_embedded_element(buf)?)
1494 }
1495 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1496 None => bail!("unexpected end of input"),
1497 };
1498 let value = gen_value(value)?;
1499
1500 map.insert(key, value);
1502 }
1503 Ok(map)
1504}
1505
1506pub fn format_map<F, T, E>(
1507 buf: &mut F,
1508 elems: impl IntoIterator<Item = (impl AsRef<str>, T)>,
1509 mut format_elem: impl FnMut(MapValueWriter<F>, T) -> Result<Nestable, E>,
1510) -> Result<Nestable, E>
1511where
1512 F: FormatBuffer,
1513{
1514 buf.write_char('{');
1515 let mut elems = elems.into_iter().peekable();
1516 while let Some((key, value)) = elems.next() {
1517 let key_start = buf.len();
1520 buf.write_str(key.as_ref());
1521 escape_elem::<_, MapElementEscaper>(buf, key_start);
1522
1523 buf.write_str("=>");
1524
1525 let value_start = buf.len();
1526 if let Nestable::MayNeedEscaping = format_elem(MapValueWriter(buf), value)? {
1527 escape_elem::<_, MapElementEscaper>(buf, value_start);
1528 }
1529
1530 if elems.peek().is_some() {
1531 buf.write_char(',');
1532 }
1533 }
1534 buf.write_char('}');
1535 Ok(Nestable::Yes)
1536}
1537
1538pub fn parse_range<'a, V, E>(
1539 s: &'a str,
1540 gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1541) -> Result<Range<V>, ParseError>
1542where
1543 E: ToString,
1544{
1545 Ok(Range {
1546 inner: parse_range_inner(s, gen_elem).map_err(|details| {
1547 ParseError::invalid_input_syntax("range", s).with_details(details)
1548 })?,
1549 })
1550}
1551
1552fn parse_range_inner<'a, V, E>(
1553 s: &'a str,
1554 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1555) -> Result<Option<RangeInner<V>>, String>
1556where
1557 E: ToString,
1558{
1559 let buf = &mut LexBuf::new(s);
1560
1561 buf.take_while(|ch| ch.is_ascii_whitespace());
1562
1563 if buf.consume_str("empty") {
1564 buf.take_while(|ch| ch.is_ascii_whitespace());
1565 if buf.next().is_none() {
1566 return Ok(None);
1567 } else {
1568 bail!("Junk after \"empty\" key word.")
1569 }
1570 }
1571
1572 let lower_inclusive = match buf.next() {
1573 Some('[') => true,
1574 Some('(') => false,
1575 _ => bail!("Missing left parenthesis or bracket."),
1576 };
1577
1578 let lower_bound = match buf.peek() {
1579 Some(',') => None,
1580 Some(_) => {
1581 let v = buf.take_while(|c| !matches!(c, ','));
1582 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1583 Some(v)
1584 }
1585 None => bail!("Unexpected end of input."),
1586 };
1587
1588 buf.take_while(|ch| ch.is_ascii_whitespace());
1589
1590 if buf.next() != Some(',') {
1591 bail!("Missing comma after lower bound.")
1592 }
1593
1594 let upper_bound = match buf.peek() {
1595 Some(']' | ')') => None,
1596 Some(_) => {
1597 let v = buf.take_while(|c| !matches!(c, ')' | ']'));
1598 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1599 Some(v)
1600 }
1601 None => bail!("Unexpected end of input."),
1602 };
1603
1604 let upper_inclusive = match buf.next() {
1605 Some(']') => true,
1606 Some(')') => false,
1607 _ => bail!("Missing left parenthesis or bracket."),
1608 };
1609
1610 buf.take_while(|ch| ch.is_ascii_whitespace());
1611
1612 if buf.next().is_some() {
1613 bail!("Junk after right parenthesis or bracket.")
1614 }
1615
1616 let range = Some(RangeInner {
1617 lower: RangeBound {
1618 inclusive: lower_inclusive,
1619 bound: lower_bound,
1620 },
1621 upper: RangeBound {
1622 inclusive: upper_inclusive,
1623 bound: upper_bound,
1624 },
1625 });
1626
1627 Ok(range)
1628}
1629
1630pub fn format_range<F, V, E>(
1632 buf: &mut F,
1633 r: &Range<V>,
1634 mut format_elem: impl FnMut(RangeElementWriter<F>, Option<&V>) -> Result<Nestable, E>,
1635) -> Result<Nestable, E>
1636where
1637 F: FormatBuffer,
1638{
1639 let range = match &r.inner {
1640 None => {
1641 buf.write_str("empty");
1642 return Ok(Nestable::MayNeedEscaping);
1643 }
1644 Some(i) => i,
1645 };
1646
1647 if range.lower.inclusive {
1648 buf.write_char('[');
1649 } else {
1650 buf.write_char('(');
1651 }
1652
1653 let start = buf.len();
1654 if let Nestable::MayNeedEscaping =
1655 format_elem(RangeElementWriter(buf), range.lower.bound.as_ref())?
1656 {
1657 escape_elem::<_, ListElementEscaper>(buf, start);
1658 }
1659
1660 buf.write_char(',');
1661
1662 let start = buf.len();
1663 if let Nestable::MayNeedEscaping =
1664 format_elem(RangeElementWriter(buf), range.upper.bound.as_ref())?
1665 {
1666 escape_elem::<_, ListElementEscaper>(buf, start);
1667 }
1668
1669 if range.upper.inclusive {
1670 buf.write_char(']');
1671 } else {
1672 buf.write_char(')');
1673 }
1674
1675 Ok(Nestable::MayNeedEscaping)
1676}
1677
1678#[derive(Debug)]
1680pub struct RangeElementWriter<'a, F>(&'a mut F);
1681
1682impl<'a, F> RangeElementWriter<'a, F>
1683where
1684 F: FormatBuffer,
1685{
1686 pub fn write_null(self) -> Nestable {
1688 Nestable::Yes
1691 }
1692
1693 pub fn nonnull_buffer(self) -> &'a mut F {
1696 self.0
1697 }
1698}
1699
1700pub fn format_array<F, T, E>(
1701 buf: &mut F,
1702 dims: &[ArrayDimension],
1703 elems: impl IntoIterator<Item = T>,
1704 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1705) -> Result<Nestable, E>
1706where
1707 F: FormatBuffer,
1708{
1709 if dims.iter().any(|dim| dim.lower_bound != 1) {
1710 for d in dims.iter() {
1711 let (lower, upper) = d.dimension_bounds();
1712 write!(buf, "[{}:{}]", lower, upper);
1713 }
1714 buf.write_char('=');
1715 }
1716
1717 format_array_inner(buf, dims, &mut elems.into_iter(), &mut format_elem)?;
1718 Ok(Nestable::Yes)
1719}
1720
1721pub fn format_array_inner<F, T, E>(
1722 buf: &mut F,
1723 dims: &[ArrayDimension],
1724 elems: &mut impl Iterator<Item = T>,
1725 format_elem: &mut impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1726) -> Result<(), E>
1727where
1728 F: FormatBuffer,
1729{
1730 if dims.is_empty() {
1731 buf.write_str("{}");
1732 return Ok(());
1733 }
1734
1735 buf.write_char('{');
1736 for j in 0..dims[0].length {
1737 if j > 0 {
1738 buf.write_char(',');
1739 }
1740 if dims.len() == 1 {
1741 let start = buf.len();
1742 let elem = elems.next().unwrap();
1743 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1744 escape_elem::<_, ListElementEscaper>(buf, start);
1745 }
1746 } else {
1747 format_array_inner(buf, &dims[1..], elems, format_elem)?;
1748 }
1749 }
1750 buf.write_char('}');
1751
1752 Ok(())
1753}
1754
1755pub fn format_legacy_vector<F, T, E>(
1756 buf: &mut F,
1757 elems: impl IntoIterator<Item = T>,
1758 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1759) -> Result<Nestable, E>
1760where
1761 F: FormatBuffer,
1762{
1763 format_elems(buf, elems, format_elem, ' ')?;
1764 Ok(Nestable::MayNeedEscaping)
1765}
1766
1767pub fn format_list<F, T, E>(
1768 buf: &mut F,
1769 elems: impl IntoIterator<Item = T>,
1770 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1771) -> Result<Nestable, E>
1772where
1773 F: FormatBuffer,
1774{
1775 buf.write_char('{');
1776 format_elems(buf, elems, format_elem, ',')?;
1777 buf.write_char('}');
1778 Ok(Nestable::Yes)
1779}
1780
1781pub fn format_elems<F, T, E>(
1783 buf: &mut F,
1784 elems: impl IntoIterator<Item = T>,
1785 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1786 sep: char,
1787) -> Result<(), E>
1788where
1789 F: FormatBuffer,
1790{
1791 let mut elems = elems.into_iter().peekable();
1792 while let Some(elem) = elems.next() {
1793 let start = buf.len();
1794 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1795 escape_elem::<_, ListElementEscaper>(buf, start);
1796 }
1797 if elems.peek().is_some() {
1798 buf.write_char(sep)
1799 }
1800 }
1801 Ok(())
1802}
1803
1804pub fn format_mz_acl_item<F>(buf: &mut F, mz_acl_item: MzAclItem) -> Nestable
1806where
1807 F: FormatBuffer,
1808{
1809 write!(buf, "{mz_acl_item}");
1810 Nestable::Yes
1811}
1812
1813pub fn parse_mz_acl_item(s: &str) -> Result<MzAclItem, ParseError> {
1815 s.trim()
1816 .parse()
1817 .map_err(|e| ParseError::invalid_input_syntax("mz_aclitem", s).with_details(e))
1818}
1819
1820pub fn format_acl_item<F>(buf: &mut F, acl_item: AclItem) -> Nestable
1822where
1823 F: FormatBuffer,
1824{
1825 write!(buf, "{acl_item}");
1826 Nestable::Yes
1827}
1828
1829pub fn parse_acl_item(s: &str) -> Result<AclItem, ParseError> {
1831 s.trim()
1832 .parse()
1833 .map_err(|e| ParseError::invalid_input_syntax("aclitem", s).with_details(e))
1834}
1835
1836pub trait ElementEscaper {
1837 fn needs_escaping(elem: &[u8]) -> bool;
1838 fn escape_char(c: u8) -> u8;
1839}
1840
1841struct ListElementEscaper;
1842
1843impl ElementEscaper for ListElementEscaper {
1844 fn needs_escaping(elem: &[u8]) -> bool {
1845 elem.is_empty()
1848 || elem.eq_ignore_ascii_case(b"NULL")
1849 || elem
1850 .iter()
1851 .any(|c| matches!(c, b'{' | b'}' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1852 }
1853
1854 fn escape_char(_: u8) -> u8 {
1855 b'\\'
1856 }
1857}
1858
1859struct MapElementEscaper;
1860
1861impl ElementEscaper for MapElementEscaper {
1862 fn needs_escaping(elem: &[u8]) -> bool {
1863 elem.is_empty()
1864 || elem.eq_ignore_ascii_case(b"NULL")
1865 || elem.iter().any(|c| {
1866 matches!(c, b'{' | b'}' | b',' | b'"' | b'=' | b'>' | b'\\')
1867 || c.is_ascii_whitespace()
1868 })
1869 }
1870
1871 fn escape_char(_: u8) -> u8 {
1872 b'\\'
1873 }
1874}
1875
1876struct RecordElementEscaper;
1877
1878impl ElementEscaper for RecordElementEscaper {
1879 fn needs_escaping(elem: &[u8]) -> bool {
1880 elem.is_empty()
1881 || elem
1882 .iter()
1883 .any(|c| matches!(c, b'(' | b')' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1884 }
1885
1886 fn escape_char(c: u8) -> u8 {
1887 if c == b'"' { b'"' } else { b'\\' }
1888 }
1889}
1890
1891fn escape_elem<F, E>(buf: &mut F, start: usize)
1901where
1902 F: FormatBuffer,
1903 E: ElementEscaper,
1904{
1905 let elem = &buf.as_ref()[start..];
1906 if !E::needs_escaping(elem) {
1907 return;
1908 }
1909
1910 let extras = 2 + elem.iter().filter(|b| matches!(b, b'"' | b'\\')).count();
1913 let orig_end = buf.len();
1914 let new_end = buf.len() + extras;
1915
1916 for _ in 0..extras {
1923 buf.write_char('\0');
1924 }
1925
1926 let elem = unsafe { buf.as_bytes_mut() };
1929
1930 let mut wi = new_end - 1;
1934 elem[wi] = b'"';
1935 wi -= 1;
1936 for ri in (start..orig_end).rev() {
1937 elem[wi] = elem[ri];
1938 wi -= 1;
1939 if let b'\\' | b'"' = elem[ri] {
1940 elem[wi] = E::escape_char(elem[ri]);
1941 wi -= 1;
1942 }
1943 }
1944 elem[wi] = b'"';
1945
1946 assert!(wi == start);
1947}
1948
1949#[derive(Debug)]
1951pub struct ListElementWriter<'a, F>(&'a mut F);
1952
1953impl<'a, F> ListElementWriter<'a, F>
1954where
1955 F: FormatBuffer,
1956{
1957 pub fn write_null(self) -> Nestable {
1959 self.0.write_str("NULL");
1960 Nestable::Yes
1961 }
1962
1963 pub fn nonnull_buffer(self) -> &'a mut F {
1966 self.0
1967 }
1968}
1969
1970#[derive(Debug)]
1972pub struct MapValueWriter<'a, F>(&'a mut F);
1973
1974impl<'a, F> MapValueWriter<'a, F>
1975where
1976 F: FormatBuffer,
1977{
1978 pub fn write_null(self) -> Nestable {
1980 self.0.write_str("NULL");
1981 Nestable::Yes
1982 }
1983
1984 pub fn nonnull_buffer(self) -> &'a mut F {
1987 self.0
1988 }
1989}
1990
1991pub fn format_record<F, T, E>(
1992 buf: &mut F,
1993 elems: impl IntoIterator<Item = T>,
1994 mut format_elem: impl FnMut(RecordElementWriter<F>, T) -> Result<Nestable, E>,
1995) -> Result<Nestable, E>
1996where
1997 F: FormatBuffer,
1998{
1999 buf.write_char('(');
2000 let mut elems = elems.into_iter().peekable();
2001 while let Some(elem) = elems.next() {
2002 let start = buf.len();
2003 if let Nestable::MayNeedEscaping = format_elem(RecordElementWriter(buf), elem)? {
2004 escape_elem::<_, RecordElementEscaper>(buf, start);
2005 }
2006 if elems.peek().is_some() {
2007 buf.write_char(',')
2008 }
2009 }
2010 buf.write_char(')');
2011 Ok(Nestable::MayNeedEscaping)
2012}
2013
2014#[derive(Debug)]
2016pub struct RecordElementWriter<'a, F>(&'a mut F);
2017
2018impl<'a, F> RecordElementWriter<'a, F>
2019where
2020 F: FormatBuffer,
2021{
2022 pub fn write_null(self) -> Nestable {
2024 Nestable::Yes
2025 }
2026
2027 pub fn nonnull_buffer(self) -> &'a mut F {
2030 self.0
2031 }
2032}
2033
2034#[derive(
2036 Ord,
2037 PartialOrd,
2038 Clone,
2039 Debug,
2040 Eq,
2041 PartialEq,
2042 Serialize,
2043 Deserialize,
2044 Hash
2045)]
2046#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
2047pub struct ParseError {
2048 pub kind: ParseErrorKind,
2049 pub type_name: Box<str>,
2050 pub input: Box<str>,
2051 pub details: Option<Box<str>>,
2052}
2053
2054#[derive(
2055 Ord,
2056 PartialOrd,
2057 Clone,
2058 Copy,
2059 Debug,
2060 Eq,
2061 PartialEq,
2062 Serialize,
2063 Deserialize,
2064 Hash
2065)]
2066#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
2067pub enum ParseErrorKind {
2068 OutOfRange,
2069 InvalidInputSyntax,
2070}
2071
2072impl ParseError {
2073 fn new<S>(kind: ParseErrorKind, type_name: &'static str, input: S) -> ParseError
2077 where
2078 S: Into<Box<str>>,
2079 {
2080 ParseError {
2081 kind,
2082 type_name: type_name.into(),
2083 input: input.into(),
2084 details: None,
2085 }
2086 }
2087
2088 fn out_of_range<S>(type_name: &'static str, input: S) -> ParseError
2089 where
2090 S: Into<Box<str>>,
2091 {
2092 ParseError::new(ParseErrorKind::OutOfRange, type_name, input)
2093 }
2094
2095 fn invalid_input_syntax<S>(type_name: &'static str, input: S) -> ParseError
2096 where
2097 S: Into<Box<str>>,
2098 {
2099 ParseError::new(ParseErrorKind::InvalidInputSyntax, type_name, input)
2100 }
2101
2102 fn with_details<D>(mut self, details: D) -> ParseError
2103 where
2104 D: fmt::Display,
2105 {
2106 self.details = Some(details.to_string().into());
2107 self
2108 }
2109}
2110
2111impl fmt::Display for ParseError {
2112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2113 match self.kind {
2114 ParseErrorKind::OutOfRange => {
2115 write!(
2116 f,
2117 "{} is out of range for type {}",
2118 self.input.quoted(),
2119 self.type_name
2120 )?;
2121 if let Some(details) = &self.details {
2122 write!(f, ": {}", details)?;
2123 }
2124 Ok(())
2125 }
2126 ParseErrorKind::InvalidInputSyntax => {
2127 write!(f, "invalid input syntax for type {}: ", self.type_name)?;
2128 if let Some(details) = &self.details {
2129 write!(f, "{}: ", details)?;
2130 }
2131 write!(f, "{}", self.input.quoted())
2132 }
2133 }
2134 }
2135}
2136
2137impl Error for ParseError {}
2138
2139impl RustType<ProtoParseError> for ParseError {
2140 fn into_proto(&self) -> ProtoParseError {
2141 use Kind::*;
2142 use proto_parse_error::*;
2143 let kind = match self.kind {
2144 ParseErrorKind::OutOfRange => OutOfRange(()),
2145 ParseErrorKind::InvalidInputSyntax => InvalidInputSyntax(()),
2146 };
2147 ProtoParseError {
2148 kind: Some(kind),
2149 type_name: self.type_name.into_proto(),
2150 input: self.input.into_proto(),
2151 details: self.details.into_proto(),
2152 }
2153 }
2154
2155 fn from_proto(proto: ProtoParseError) -> Result<Self, TryFromProtoError> {
2156 use proto_parse_error::Kind::*;
2157
2158 if let Some(kind) = proto.kind {
2159 Ok(ParseError {
2160 kind: match kind {
2161 OutOfRange(()) => ParseErrorKind::OutOfRange,
2162 InvalidInputSyntax(()) => ParseErrorKind::InvalidInputSyntax,
2163 },
2164 type_name: proto.type_name.into(),
2165 input: proto.input.into(),
2166 details: proto.details.into_rust()?,
2167 })
2168 } else {
2169 Err(TryFromProtoError::missing_field("ProtoParseError::kind"))
2170 }
2171 }
2172}
2173
2174#[derive(
2175 Ord,
2176 PartialOrd,
2177 Copy,
2178 Clone,
2179 Debug,
2180 Eq,
2181 PartialEq,
2182 Serialize,
2183 Deserialize,
2184 Hash
2185)]
2186#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
2187pub enum ParseHexError {
2188 InvalidHexDigit(char),
2189 OddLength,
2190}
2191impl Error for ParseHexError {}
2192
2193impl fmt::Display for ParseHexError {
2194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2195 match self {
2196 ParseHexError::InvalidHexDigit(c) => {
2197 write!(f, "invalid hexadecimal digit: \"{}\"", c.escape_default())
2198 }
2199 ParseHexError::OddLength => {
2200 f.write_str("invalid hexadecimal data: odd number of digits")
2201 }
2202 }
2203 }
2204}
2205
2206impl RustType<ProtoParseHexError> for ParseHexError {
2207 fn into_proto(&self) -> ProtoParseHexError {
2208 use Kind::*;
2209 use proto_parse_hex_error::*;
2210 let kind = match self {
2211 ParseHexError::InvalidHexDigit(v) => InvalidHexDigit(v.into_proto()),
2212 ParseHexError::OddLength => OddLength(()),
2213 };
2214 ProtoParseHexError { kind: Some(kind) }
2215 }
2216
2217 fn from_proto(error: ProtoParseHexError) -> Result<Self, TryFromProtoError> {
2218 use proto_parse_hex_error::Kind::*;
2219 match error.kind {
2220 Some(kind) => match kind {
2221 InvalidHexDigit(v) => Ok(ParseHexError::InvalidHexDigit(char::from_proto(v)?)),
2222 OddLength(()) => Ok(ParseHexError::OddLength),
2223 },
2224 None => Err(TryFromProtoError::missing_field(
2225 "`ProtoParseHexError::kind`",
2226 )),
2227 }
2228 }
2229}
2230
2231#[cfg(test)]
2232mod tests {
2233 use mz_ore::assert_ok;
2234 use mz_proto::protobuf_roundtrip;
2235 use proptest::prelude::*;
2236
2237 use super::*;
2238
2239 proptest! {
2240 #[mz_ore::test]
2241 #[cfg_attr(miri, ignore)] fn parse_error_protobuf_roundtrip(expect in any::<ParseError>()) {
2243 let actual = protobuf_roundtrip::<_, ProtoParseError>(&expect);
2244 assert_ok!(actual);
2245 assert_eq!(actual.unwrap(), expect);
2246 }
2247 }
2248
2249 proptest! {
2250 #[mz_ore::test]
2251 #[cfg_attr(miri, ignore)] fn parse_hex_error_protobuf_roundtrip(expect in any::<ParseHexError>()) {
2253 let actual = protobuf_roundtrip::<_, ProtoParseHexError>(&expect);
2254 assert_ok!(actual);
2255 assert_eq!(actual.unwrap(), expect);
2256 }
2257 }
2258
2259 #[mz_ore::test]
2260 fn test_format_nanos_to_micros() {
2261 let cases: Vec<(u32, &str)> = vec![
2262 (0, ""),
2263 (1, ""),
2264 (499, ""),
2265 (500, ".000001"),
2266 (500_000, ".0005"),
2267 (5_000_000, ".005"),
2268 (1_999_999_999, ".2"),
2271 ];
2272 for (nanos, expect) in cases {
2273 let mut buf = String::new();
2274 format_nanos_to_micros(&mut buf, nanos);
2275 assert_eq!(&buf, expect);
2276 }
2277 }
2278
2279 #[mz_ore::test]
2280 fn test_parse_pg_legacy_name() {
2281 let s = "hello world";
2282 assert_eq!(s, parse_pg_legacy_name(s));
2283
2284 let s = "x".repeat(63);
2285 assert_eq!(s, parse_pg_legacy_name(&s));
2286
2287 let s = "x".repeat(64);
2288 assert_eq!("x".repeat(63), parse_pg_legacy_name(&s));
2289
2290 let s = format!("{}{}", "x".repeat(61), "א");
2292 assert_eq!(s, parse_pg_legacy_name(&s));
2293
2294 let s = format!("{}{}", "x".repeat(62), "א");
2295 assert_eq!("x".repeat(62), parse_pg_legacy_name(&s));
2296 }
2297
2298 #[mz_ore::test]
2299 fn test_parse_oid() {
2300 assert_eq!(parse_oid("0").unwrap(), 0);
2302 assert_eq!(parse_oid("2147483647").unwrap(), 2147483647);
2303 assert_eq!(parse_oid("2147483648").unwrap(), 2147483648);
2304 assert_eq!(parse_oid("4294967295").unwrap(), 4294967295);
2305
2306 assert_eq!(parse_oid("-1").unwrap(), 4294967295);
2308 assert_eq!(parse_oid("-2147483648").unwrap(), 2147483648);
2309
2310 assert_eq!(parse_oid(" 42 ").unwrap(), 42);
2312
2313 assert!(parse_oid("4294967296").is_err());
2315 assert!(parse_oid("-2147483649").is_err());
2316 assert!(parse_oid("nope").is_err());
2317 }
2318
2319 #[mz_ore::test]
2320 fn test_parse_oid_legacy() {
2321 assert_eq!(parse_oid_legacy("0").unwrap(), 0);
2323 assert_eq!(parse_oid_legacy("2147483647").unwrap(), 2147483647);
2324 assert_eq!(parse_oid_legacy("-1").unwrap(), 4294967295);
2325 assert_eq!(parse_oid_legacy("-2147483648").unwrap(), 2147483648);
2326
2327 assert!(parse_oid_legacy("2147483648").is_err());
2330 assert!(parse_oid_legacy("4294967295").is_err());
2331 assert!(parse_oid_legacy("nope").is_err());
2332 }
2333
2334 fn date(y: i32, m: u32, d: u32) -> Date {
2335 Date::try_from(NaiveDate::from_ymd_opt(y, m, d).unwrap()).unwrap()
2336 }
2337
2338 #[mz_ore::test]
2339 fn test_parse_date_mdy() {
2340 assert_eq!(parse_date("01/02/03").unwrap(), date(2003, 1, 2));
2344 assert_eq!(parse_date("1-2-3").unwrap(), date(2003, 1, 2));
2345 assert_eq!(parse_date("01/02/69").unwrap(), date(2069, 1, 2));
2346 assert_eq!(parse_date("01/02/70").unwrap(), date(1970, 1, 2));
2347 assert_eq!(parse_date("01/02/1999").unwrap(), date(1999, 1, 2));
2348 assert_eq!(parse_date("0099-01-08").unwrap(), date(99, 1, 8));
2351 assert_eq!(parse_date("2003-01-02").unwrap(), date(2003, 1, 2));
2352 assert_eq!(parse_date("01/02/03 BC").unwrap(), date(-2, 1, 2));
2354 assert!(parse_date("99-01-08").is_err());
2356 assert!(parse_date("13/01/08").is_err());
2357
2358 assert_eq!(
2359 parse_timestamp("01/02/03 04:05:06").unwrap().to_string(),
2360 "2003-01-02 04:05:06"
2361 );
2362 assert_eq!(
2363 parse_mz_timestamp("01/02/03").unwrap(),
2364 parse_mz_timestamp("2003-01-02").unwrap()
2365 );
2366 }
2367
2368 #[mz_ore::test]
2369 fn test_parse_date_legacy() {
2370 assert_eq!(parse_date_legacy("01/02/03").unwrap(), date(1, 2, 3));
2374 assert_eq!(parse_date_legacy("99-01-08").unwrap(), date(99, 1, 8));
2375 assert!(parse_date_legacy("01/02/1999").is_err());
2376 assert_eq!(
2377 parse_timestamp_legacy("01/02/03 04:05:06")
2378 .unwrap()
2379 .to_string(),
2380 "0001-02-03 04:05:06"
2381 );
2382 assert!(parse_mz_timestamp_legacy("01/02/03").is_err());
2385 assert_eq!(
2386 parse_mz_timestamp_legacy("2003-01-02").unwrap(),
2387 parse_mz_timestamp("2003-01-02").unwrap()
2388 );
2389 }
2390}