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_lowertest::MzReflect;
38use mz_ore::cast::ReinterpretCast;
39use mz_ore::error::ErrorExt;
40use mz_ore::fmt::FormatBuffer;
41use mz_ore::lex::LexBuf;
42use mz_ore::str::StrExt;
43use mz_pgtz::timezone::{Timezone, TimezoneSpec};
44use mz_proto::{ProtoType, RustType, TryFromProtoError};
45use num_traits::Float as NumFloat;
46#[cfg(any(test, feature = "proptest"))]
47use proptest_derive::Arbitrary;
48use regex::bytes::Regex;
49use ryu::Float as RyuFloat;
50use serde::{Deserialize, Serialize};
51use uuid::Uuid;
52
53use crate::adt::array::ArrayDimension;
54use crate::adt::date::Date;
55use crate::adt::datetime::{self, DateTimeField, ParsedDateTime};
56use crate::adt::interval::Interval;
57use crate::adt::jsonb::{Jsonb, JsonbRef};
58use crate::adt::mz_acl_item::{AclItem, MzAclItem};
59use crate::adt::numeric::{self, NUMERIC_DATUM_MAX_PRECISION, Numeric};
60use crate::adt::pg_legacy_name::NAME_MAX_BYTES;
61use crate::adt::range::{Range, RangeBound, RangeInner};
62use crate::adt::timestamp::CheckedTimestamp;
63
64include!(concat!(env!("OUT_DIR"), "/mz_repr.strconv.rs"));
65
66macro_rules! bail {
67 ($($arg:tt)*) => { return Err(format!($($arg)*)) };
68}
69
70#[derive(Debug)]
72pub enum Nestable {
73 Yes,
74 MayNeedEscaping,
75}
76
77pub fn parse_bool(s: &str) -> Result<bool, ParseError> {
83 match s.trim().to_lowercase().as_str() {
84 "t" | "tr" | "tru" | "true" | "y" | "ye" | "yes" | "on" | "1" => Ok(true),
85 "f" | "fa" | "fal" | "fals" | "false" | "n" | "no" | "of" | "off" | "0" => Ok(false),
86 _ => Err(ParseError::invalid_input_syntax("boolean", s)),
87 }
88}
89
90pub fn format_bool_static(b: bool) -> &'static str {
95 match b {
96 true => "t",
97 false => "f",
98 }
99}
100
101pub fn format_bool<F>(buf: &mut F, b: bool) -> Nestable
106where
107 F: FormatBuffer,
108{
109 buf.write_str(format_bool_static(b));
110 Nestable::Yes
111}
112
113pub fn parse_int16(s: &str) -> Result<i16, ParseError> {
118 s.trim()
119 .parse()
120 .map_err(|e| ParseError::invalid_input_syntax("smallint", s).with_details(e))
121}
122
123pub fn format_int16<F>(buf: &mut F, i: i16) -> Nestable
125where
126 F: FormatBuffer,
127{
128 write!(buf, "{}", i);
129 Nestable::Yes
130}
131
132pub fn parse_int32(s: &str) -> Result<i32, ParseError> {
137 s.trim()
138 .parse()
139 .map_err(|e| ParseError::invalid_input_syntax("integer", s).with_details(e))
140}
141
142pub fn format_int32<F>(buf: &mut F, i: i32) -> Nestable
144where
145 F: FormatBuffer,
146{
147 write!(buf, "{}", i);
148 Nestable::Yes
149}
150
151pub fn parse_int64(s: &str) -> Result<i64, ParseError> {
153 s.trim()
154 .parse()
155 .map_err(|e| ParseError::invalid_input_syntax("bigint", s).with_details(e))
156}
157
158pub fn format_int64<F>(buf: &mut F, i: i64) -> Nestable
160where
161 F: FormatBuffer,
162{
163 write!(buf, "{}", i);
164 Nestable::Yes
165}
166
167pub fn parse_uint16(s: &str) -> Result<u16, ParseError> {
172 s.trim()
173 .parse()
174 .map_err(|e| ParseError::invalid_input_syntax("uint2", s).with_details(e))
175}
176
177pub fn format_uint16<F>(buf: &mut F, u: u16) -> Nestable
179where
180 F: FormatBuffer,
181{
182 write!(buf, "{}", u);
183 Nestable::Yes
184}
185
186pub fn parse_uint32(s: &str) -> Result<u32, ParseError> {
191 s.trim()
192 .parse()
193 .map_err(|e| ParseError::invalid_input_syntax("uint4", s).with_details(e))
194}
195
196pub fn format_uint32<F>(buf: &mut F, u: u32) -> Nestable
198where
199 F: FormatBuffer,
200{
201 write!(buf, "{}", u);
202 Nestable::Yes
203}
204
205pub fn parse_uint64(s: &str) -> Result<u64, ParseError> {
207 s.trim()
208 .parse()
209 .map_err(|e| ParseError::invalid_input_syntax("uint8", s).with_details(e))
210}
211
212pub fn format_uint64<F>(buf: &mut F, u: u64) -> Nestable
214where
215 F: FormatBuffer,
216{
217 write!(buf, "{}", u);
218 Nestable::Yes
219}
220
221pub fn parse_mz_timestamp(s: &str) -> Result<crate::Timestamp, ParseError> {
223 s.trim()
224 .parse()
225 .map_err(|e| ParseError::invalid_input_syntax("mz_timestamp", s).with_details(e))
226}
227
228pub fn format_mz_timestamp<F>(buf: &mut F, u: crate::Timestamp) -> Nestable
230where
231 F: FormatBuffer,
232{
233 write!(buf, "{}", u);
234 Nestable::Yes
235}
236
237pub fn parse_oid(s: &str) -> Result<u32, ParseError> {
239 let trimmed = s.trim();
248 if let Ok(oid) = trimmed.parse::<u32>() {
249 return Ok(oid);
250 }
251 let oid: i32 = trimmed
252 .parse()
253 .map_err(|e| ParseError::invalid_input_syntax("oid", s).with_details(e))?;
254 Ok(u32::reinterpret_cast(oid))
255}
256
257pub fn parse_oid_legacy(s: &str) -> Result<u32, ParseError> {
270 let oid: i32 = s
271 .trim()
272 .parse()
273 .map_err(|e| ParseError::invalid_input_syntax("oid", s).with_details(e))?;
274 Ok(u32::reinterpret_cast(oid))
275}
276
277fn parse_float<Fl>(type_name: &'static str, s: &str) -> Result<Fl, ParseError>
278where
279 Fl: NumFloat + FromStr,
280{
281 static ZERO_RE: LazyLock<Regex> =
297 LazyLock::new(|| Regex::new(r#"(?i-u)^[-+]?(0+(\.0*)?|\.0+)(e|$)"#).unwrap());
298 static INF_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new("(?i-u)^[-+]?inf").unwrap());
300
301 let buf = s.trim();
302 let f: Fl = buf
303 .parse()
304 .map_err(|_| ParseError::invalid_input_syntax(type_name, s))?;
305 match f.classify() {
306 FpCategory::Infinite if !INF_RE.is_match(buf.as_bytes()) => {
307 Err(ParseError::out_of_range(type_name, s))
308 }
309 FpCategory::Zero if !ZERO_RE.is_match(buf.as_bytes()) => {
310 Err(ParseError::out_of_range(type_name, s))
311 }
312 _ => Ok(f),
313 }
314}
315
316fn format_float<F, Fl>(buf: &mut F, f: Fl) -> Nestable
317where
318 F: FormatBuffer,
319 Fl: NumFloat + RyuFloat,
320{
321 match f.classify() {
334 FpCategory::Infinite if f.is_sign_negative() => buf.write_str("-Infinity"),
335 FpCategory::Infinite => buf.write_str("Infinity"),
336 FpCategory::Nan => buf.write_str("NaN"),
337 FpCategory::Zero if f.is_sign_negative() => buf.write_str("-0"),
338 _ => {
339 debug_assert!(f.is_finite());
340 let mut ryu_buf = ryu::Buffer::new();
341 let mut s = ryu_buf.format_finite(f);
342 if let Some(trimmed) = s.strip_suffix(".0") {
343 s = trimmed;
344 }
345 let mut chars = s.chars().peekable();
346 while let Some(ch) = chars.next() {
347 buf.write_char(ch);
348 if ch == 'e' && chars.peek() != Some(&'-') {
349 buf.write_char('+');
350 }
351 }
352 }
353 }
354
355 Nestable::Yes
356}
357
358pub fn parse_float32(s: &str) -> Result<f32, ParseError> {
360 parse_float("real", s)
361}
362
363pub fn format_float32<F>(buf: &mut F, f: f32) -> Nestable
365where
366 F: FormatBuffer,
367{
368 format_float(buf, f)
369}
370
371pub fn parse_float64(s: &str) -> Result<f64, ParseError> {
373 parse_float("double precision", s)
374}
375
376pub fn format_float64<F>(buf: &mut F, f: f64) -> Nestable
378where
379 F: FormatBuffer,
380{
381 format_float(buf, f)
382}
383
384fn parse_timestamp_string(s: &str) -> Result<(NaiveDate, NaiveTime, Timezone), String> {
403 if s.is_empty() {
404 return Err("timestamp string is empty".into());
405 }
406
407 if s == "epoch" {
412 return Ok((
413 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
414 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
415 Default::default(),
416 ));
417 }
418
419 let (ts_string, tz_string, era) = datetime::split_timestamp_string(s);
420
421 let pdt = ParsedDateTime::build_parsed_datetime_timestamp(ts_string, era)?;
422 let d: NaiveDate = pdt.compute_date()?;
423 let t: NaiveTime = pdt.compute_time()?;
424
425 let offset = if tz_string.is_empty() {
426 Default::default()
427 } else {
428 Timezone::parse(tz_string, TimezoneSpec::Iso)?
429 };
430
431 Ok((d, t, offset))
432}
433
434pub fn parse_date(s: &str) -> Result<Date, ParseError> {
436 match parse_timestamp_string(s) {
437 Ok((date, _, _)) => Date::try_from(date).map_err(|_| ParseError::out_of_range("date", s)),
438 Err(e) => Err(ParseError::invalid_input_syntax("date", s).with_details(e)),
439 }
440}
441
442pub fn format_date<F>(buf: &mut F, d: Date) -> Nestable
444where
445 F: FormatBuffer,
446{
447 let d: NaiveDate = d.into();
448 let (year_ad, year) = d.year_ce();
449 write!(buf, "{:04}-{}", year, d.format("%m-%d"));
450 if !year_ad {
451 write!(buf, " BC");
452 }
453 Nestable::Yes
454}
455
456pub fn parse_time(s: &str) -> Result<NaiveTime, ParseError> {
464 ParsedDateTime::build_parsed_datetime_time(s)
465 .and_then(|pdt| pdt.compute_time())
466 .map_err(|e| ParseError::invalid_input_syntax("time", s).with_details(e))
467}
468
469pub fn format_time<F>(buf: &mut F, t: NaiveTime) -> Nestable
471where
472 F: FormatBuffer,
473{
474 write!(buf, "{}", t.format("%H:%M:%S"));
475 format_nanos_to_micros(buf, t.nanosecond());
476 Nestable::Yes
477}
478
479pub fn parse_timestamp(s: &str) -> Result<CheckedTimestamp<NaiveDateTime>, ParseError> {
481 match parse_timestamp_string(s) {
482 Ok((date, time, _)) => CheckedTimestamp::from_timestamplike(date.and_time(time))
483 .map_err(|_| ParseError::out_of_range("timestamp", s)),
484 Err(e) => Err(ParseError::invalid_input_syntax("timestamp", s).with_details(e)),
485 }
486}
487
488pub fn format_timestamp<F>(buf: &mut F, ts: &NaiveDateTime) -> Nestable
490where
491 F: FormatBuffer,
492{
493 let (year_ad, year) = ts.year_ce();
494 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
495 format_nanos_to_micros(buf, ts.and_utc().timestamp_subsec_nanos());
496 if !year_ad {
497 write!(buf, " BC");
498 }
499 Nestable::MayNeedEscaping
501}
502
503pub fn parse_timestamptz(s: &str) -> Result<CheckedTimestamp<DateTime<Utc>>, ParseError> {
505 parse_timestamp_string(s)
506 .and_then(|(date, time, timezone)| {
507 use Timezone::*;
508 let mut dt = date.and_time(time);
509 let offset = match timezone {
510 FixedOffset(offset) => offset,
511 Tz(tz) => match tz.offset_from_local_datetime(&dt).latest() {
512 Some(offset) => offset.fix(),
513 None => {
514 dt += Duration::try_hours(1).unwrap();
515 tz.offset_from_local_datetime(&dt)
516 .latest()
517 .ok_or_else(|| "invalid timezone conversion".to_owned())?
518 .fix()
519 }
520 },
521 };
522 Ok(DateTime::from_naive_utc_and_offset(dt - offset, Utc))
523 })
524 .map_err(|e| {
525 ParseError::invalid_input_syntax("timestamp with time zone", s).with_details(e)
526 })
527 .and_then(|ts| {
528 CheckedTimestamp::from_timestamplike(ts)
529 .map_err(|_| ParseError::out_of_range("timestamp with time zone", s))
530 })
531}
532
533pub fn format_timestamptz<F>(buf: &mut F, ts: &DateTime<Utc>) -> Nestable
535where
536 F: FormatBuffer,
537{
538 let (year_ad, year) = ts.year_ce();
539 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
540 format_nanos_to_micros(buf, ts.timestamp_subsec_nanos());
541 write!(buf, "+00");
542 if !year_ad {
543 write!(buf, " BC");
544 }
545 Nestable::MayNeedEscaping
547}
548
549pub fn parse_interval(s: &str) -> Result<Interval, ParseError> {
569 parse_interval_w_disambiguator(s, None, DateTimeField::Second)
570}
571
572pub fn parse_interval_w_disambiguator(
577 s: &str,
578 leading_time_precision: Option<DateTimeField>,
579 d: DateTimeField,
580) -> Result<Interval, ParseError> {
581 ParsedDateTime::build_parsed_datetime_interval(s, leading_time_precision, d)
582 .and_then(|pdt| pdt.compute_interval())
583 .map_err(|e| ParseError::invalid_input_syntax("interval", s).with_details(e))
584}
585
586pub fn format_interval<F>(buf: &mut F, iv: Interval) -> Nestable
587where
588 F: FormatBuffer,
589{
590 write!(buf, "{}", iv);
591 Nestable::MayNeedEscaping
592}
593
594pub fn parse_numeric(s: &str) -> Result<OrderedDecimal<Numeric>, ParseError> {
595 let mut cx = numeric::cx_datum();
596 let mut n = match cx.parse(s.trim()) {
597 Ok(n) => n,
598 Err(..) => {
599 return Err(ParseError::invalid_input_syntax("numeric", s));
600 }
601 };
602
603 let cx_status = cx.status();
604
605 if (n.is_infinite() && !cx_status.overflow())
607 || (n.is_nan() && n.is_negative())
608 || n.is_signaling_nan()
609 {
610 return Err(ParseError::invalid_input_syntax("numeric", s));
611 }
612
613 let out_of_range = numeric::munge_numeric(&mut n).is_err();
615
616 if cx_status.overflow() || cx_status.subnormal() || out_of_range {
617 Err(ParseError::out_of_range("numeric", s).with_details(format!(
618 "exceeds maximum precision {}",
619 NUMERIC_DATUM_MAX_PRECISION
620 )))
621 } else {
622 Ok(OrderedDecimal(n))
623 }
624}
625
626pub fn format_numeric<F>(buf: &mut F, n: &OrderedDecimal<Numeric>) -> Nestable
627where
628 F: FormatBuffer,
629{
630 write!(buf, "{}", n.0.to_standard_notation_string());
631 Nestable::Yes
632}
633
634pub fn format_string<F>(buf: &mut F, s: &str) -> Nestable
635where
636 F: FormatBuffer,
637{
638 buf.write_str(s);
639 Nestable::MayNeedEscaping
640}
641
642pub fn parse_pg_legacy_name(s: &str) -> String {
643 let mut out = String::new();
646 let mut len = 0;
647 for c in s.chars() {
648 len += c.len_utf8();
649 if len > NAME_MAX_BYTES {
650 break;
651 }
652 out.push(c);
653 }
654 out
655}
656
657pub fn parse_bytes(s: &str) -> Result<Vec<u8>, ParseError> {
658 if let Some(remainder) = s.strip_prefix(r"\x") {
664 parse_bytes_hex(remainder).map_err(|e| {
665 ParseError::invalid_input_syntax("bytea", s).with_details(e.to_string_with_causes())
666 })
667 } else {
668 parse_bytes_traditional(s)
669 }
670}
671
672pub fn parse_bytes_hex(s: &str) -> Result<Vec<u8>, ParseHexError> {
673 let decode_nibble = |b| match b {
677 b'a'..=b'f' => Ok(b - b'a' + 10),
678 b'A'..=b'F' => Ok(b - b'A' + 10),
679 b'0'..=b'9' => Ok(b - b'0'),
680 _ => Err(ParseHexError::InvalidHexDigit(char::from(b))),
681 };
682
683 let mut buf = vec![];
684 let mut nibbles = s.as_bytes().iter().copied();
685 while let Some(n) = nibbles.next() {
686 if let b' ' | b'\n' | b'\t' | b'\r' = n {
687 continue;
688 }
689 let n = decode_nibble(n)?;
690 let n2 = match nibbles.next() {
691 None => return Err(ParseHexError::OddLength),
692 Some(n2) => decode_nibble(n2)?,
693 };
694 buf.push((n << 4) | n2);
695 }
696 Ok(buf)
697}
698
699pub fn parse_bytes_traditional(s: &str) -> Result<Vec<u8>, ParseError> {
700 let mut out = Vec::with_capacity(s.len());
704 let mut bytes = s.as_bytes().iter().fuse();
705 while let Some(&b) = bytes.next() {
706 if b != b'\\' {
707 out.push(b);
708 continue;
709 }
710 match bytes.next() {
711 None => {
712 return Err(ParseError::invalid_input_syntax("bytea", s)
713 .with_details("ends with escape character"));
714 }
715 Some(b'\\') => out.push(b'\\'),
716 b => match (b, bytes.next(), bytes.next()) {
717 (Some(d2 @ b'0'..=b'3'), Some(d1 @ b'0'..=b'7'), Some(d0 @ b'0'..=b'7')) => {
718 out.push(((d2 - b'0') << 6) + ((d1 - b'0') << 3) + (d0 - b'0'));
719 }
720 _ => {
721 return Err(ParseError::invalid_input_syntax("bytea", s)
722 .with_details("invalid escape sequence"));
723 }
724 },
725 }
726 }
727 Ok(out)
728}
729
730pub fn format_bytes<F>(buf: &mut F, bytes: &[u8]) -> Nestable
731where
732 F: FormatBuffer,
733{
734 write!(buf, "\\x{}", hex::encode(bytes));
735 Nestable::MayNeedEscaping
736}
737
738pub fn parse_jsonb(s: &str) -> Result<Jsonb, ParseError> {
739 s.trim()
740 .parse()
741 .map_err(|e| ParseError::invalid_input_syntax("jsonb", s).with_details(e))
742}
743
744pub fn format_jsonb<F>(buf: &mut F, jsonb: JsonbRef) -> Nestable
745where
746 F: FormatBuffer,
747{
748 write!(buf, "{}", jsonb);
749 Nestable::MayNeedEscaping
750}
751
752pub fn format_jsonb_pretty<F>(buf: &mut F, jsonb: JsonbRef)
753where
754 F: FormatBuffer,
755{
756 write!(buf, "{:#}", jsonb)
757}
758
759pub fn parse_uuid(s: &str) -> Result<Uuid, ParseError> {
760 s.trim()
761 .parse()
762 .map_err(|e| ParseError::invalid_input_syntax("uuid", s).with_details(e))
763}
764
765pub fn format_uuid<F>(buf: &mut F, uuid: Uuid) -> Nestable
766where
767 F: FormatBuffer,
768{
769 write!(buf, "{}", uuid);
770 Nestable::Yes
771}
772
773fn format_nanos_to_micros<F>(buf: &mut F, nanos: u32)
774where
775 F: FormatBuffer,
776{
777 if nanos >= 500 {
778 let mut micros = nanos / 1000;
779 let rem = nanos % 1000;
780 if rem >= 500 {
781 micros += 1;
782 }
783 let mut width = 6;
785 while micros % 10 == 0 {
786 width -= 1;
787 micros /= 10;
788 }
789 write!(buf, ".{:0width$}", micros, width = width);
790 }
791}
792
793#[derive(Debug, thiserror::Error)]
794enum ArrayParsingError {
795 #[error("Array value must start with \"{{\"")]
796 OpeningBraceMissing,
797 #[error("Specifying array lower bounds is not supported")]
798 DimsUnsupported,
799 #[error("{0}")]
800 Generic(String),
801 #[error("Unexpected \"{0}\" character.")]
802 UnexpectedChar(char),
803 #[error("Multidimensional arrays must have sub-arrays with matching dimensions.")]
804 NonRectilinearDims,
805 #[error("Unexpected array element.")]
806 UnexpectedElement,
807 #[error("Junk after closing right brace.")]
808 Junk,
809 #[error("Unexpected end of input.")]
810 EarlyTerm,
811}
812
813impl From<String> for ArrayParsingError {
814 fn from(value: String) -> Self {
815 ArrayParsingError::Generic(value)
816 }
817}
818
819pub fn parse_array<'a, T, E>(
820 s: &'a str,
821 make_null: impl FnMut() -> T,
822 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
823) -> Result<(Vec<T>, Vec<ArrayDimension>), ParseError>
824where
825 E: ToString,
826{
827 parse_array_inner(s, make_null, gen_elem)
828 .map_err(|details| ParseError::invalid_input_syntax("array", s).with_details(details))
829}
830
831fn parse_array_inner<'a, T, E>(
832 s: &'a str,
833 mut make_null: impl FnMut() -> T,
834 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
835) -> Result<(Vec<T>, Vec<ArrayDimension>), ArrayParsingError>
836where
837 E: ToString,
838{
839 use ArrayParsingError::*;
840
841 #[derive(Clone, Debug, Default)]
842 struct Dimension {
843 length: Option<usize>,
846 staged_element: bool,
850 committed_element_count: usize,
853 }
854
855 #[derive(Clone, Debug, Default)]
856 struct ArrayBuilder<'a> {
857 current_command_char: char,
859 dimensions: Vec<Dimension>,
862 current_dim: usize,
864 sealed: bool,
866 elements: Vec<Option<Cow<'a, str>>>,
870 }
871
872 impl<'a> ArrayBuilder<'a> {
873 fn build(
874 s: &'a str,
875 ) -> Result<(Vec<Option<Cow<'a, str>>>, Vec<ArrayDimension>), ArrayParsingError> {
876 let buf = &mut LexBuf::new(s);
877
878 if buf.consume('[') {
880 Err(DimsUnsupported)?;
881 }
882
883 buf.take_while(|ch| ch.is_ascii_whitespace());
884
885 if !buf.consume('{') {
886 Err(OpeningBraceMissing)?;
887 }
888
889 let mut dimensions = 1;
890
891 loop {
892 buf.take_while(|ch| ch.is_ascii_whitespace());
893 if buf.consume('{') {
894 dimensions += 1;
895 } else {
896 break;
897 }
898 }
899
900 let mut builder = ArrayBuilder {
901 current_command_char: '{',
902 dimensions: vec![Dimension::default(); dimensions],
903 current_dim: dimensions - 1,
906 sealed: false,
907 elements: vec![],
908 };
909
910 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
911 let is_end_of_literal = |c| matches!(c, ',' | '}');
912
913 loop {
914 buf.take_while(|ch| ch.is_ascii_whitespace());
915
916 match buf.next() {
918 None if builder.sealed => {
919 break;
920 }
921 None => Err(EarlyTerm)?,
922 Some(_) if builder.sealed => Err(Junk)?,
923 Some(c) => builder.current_command_char = c,
924 }
925
926 match builder.current_command_char {
928 '{' => builder.enter_dim()?,
929 '}' => builder.exit_dim()?,
930 ',' => builder.commit_element(true)?,
931 c => {
932 buf.prev();
933 let s = match c {
934 '"' => Some(lex_quoted_element(buf)?),
935 _ => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
936 };
937 builder.insert_element(s)?;
938 }
939 }
940 }
941
942 if builder.elements.is_empty() {
943 return Ok((vec![], vec![]));
946 }
947
948 let dims = builder
949 .dimensions
950 .into_iter()
951 .map(|dim| ArrayDimension {
952 length: dim
953 .length
954 .expect("every dimension must have its length discovered"),
955 lower_bound: 1,
956 })
957 .collect();
958
959 Ok((builder.elements, dims))
960 }
961
962 fn enter_dim(&mut self) -> Result<(), ArrayParsingError> {
964 let d = &mut self.dimensions[self.current_dim];
965 if d.staged_element {
967 return Err(UnexpectedChar(self.current_command_char));
968 }
969
970 self.current_dim += 1;
971
972 if self.current_dim >= self.dimensions.len() {
974 return Err(NonRectilinearDims);
975 }
976
977 Ok(())
978 }
979
980 fn insert_element(&mut self, s: Option<Cow<'a, str>>) -> Result<(), ArrayParsingError> {
982 if self.current_dim != self.dimensions.len() - 1 {
985 return Err(UnexpectedElement);
986 }
987
988 self.stage_element()?;
989
990 self.elements.push(s);
991
992 Ok(())
993 }
994
995 fn stage_element(&mut self) -> Result<(), ArrayParsingError> {
999 let d = &mut self.dimensions[self.current_dim];
1000 if d.staged_element {
1003 return Err(UnexpectedElement);
1004 }
1005 d.staged_element = true;
1006 Ok(())
1007 }
1008
1009 fn commit_element(&mut self, require_staged: bool) -> Result<(), ArrayParsingError> {
1013 let d = &mut self.dimensions[self.current_dim];
1014 if !d.staged_element {
1015 return if require_staged || d.committed_element_count > 0 {
1019 Err(UnexpectedChar(self.current_command_char))
1020 } else {
1021 Ok(())
1025 };
1026 }
1027 d.staged_element = false;
1028 d.committed_element_count += 1;
1029
1030 Ok(())
1031 }
1032
1033 fn exit_dim(&mut self) -> Result<(), ArrayParsingError> {
1039 self.commit_element(false)?;
1041
1042 let d = &mut self.dimensions[self.current_dim];
1043
1044 match d.length {
1046 None => d.length = Some(d.committed_element_count),
1047 Some(l) => {
1048 if l != d.committed_element_count {
1049 return Err(NonRectilinearDims);
1050 }
1051 }
1052 }
1053
1054 d.committed_element_count = 0;
1056
1057 if self.current_dim == 0 {
1060 self.sealed = true;
1061 } else {
1062 self.current_dim -= 1;
1063 self.stage_element()?;
1065 }
1066
1067 Ok(())
1068 }
1069 }
1070
1071 let (raw_elems, dims) = ArrayBuilder::build(s)?;
1072
1073 let mut elems = Vec::with_capacity(raw_elems.len());
1074
1075 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1076
1077 for elem in raw_elems.into_iter() {
1078 elems.push(match elem {
1079 Some(elem) => generated(elem)?,
1080 None => make_null(),
1081 });
1082 }
1083
1084 Ok((elems, dims))
1085}
1086
1087pub fn parse_list<'a, T, E>(
1088 s: &'a str,
1089 is_element_type_list: bool,
1090 make_null: impl FnMut() -> T,
1091 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1092) -> Result<Vec<T>, ParseError>
1093where
1094 E: ToString,
1095{
1096 parse_list_inner(s, is_element_type_list, make_null, gen_elem)
1097 .map_err(|details| ParseError::invalid_input_syntax("list", s).with_details(details))
1098}
1099
1100fn parse_list_inner<'a, T, E>(
1103 s: &'a str,
1104 is_element_type_list: bool,
1105 mut make_null: impl FnMut() -> T,
1106 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1107) -> Result<Vec<T>, String>
1108where
1109 E: ToString,
1110{
1111 let mut elems = vec![];
1112 let buf = &mut LexBuf::new(s);
1113
1114 if !buf.consume('{') {
1116 bail!(
1117 "expected '{{', found {}",
1118 match buf.next() {
1119 Some(c) => format!("{}", c),
1120 None => "empty string".to_string(),
1121 }
1122 )
1123 }
1124
1125 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1127 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
1128 let is_end_of_literal = |c| matches!(c, ',' | '}');
1129
1130 loop {
1132 buf.take_while(|ch| ch.is_ascii_whitespace());
1133 match buf.next() {
1135 Some('}') => {
1136 break;
1137 }
1138 _ if elems.len() == 0 => {
1139 buf.prev();
1140 }
1141 Some(',') => {}
1142 Some(c) => bail!("expected ',' or '}}', got '{}'", c),
1143 None => bail!("unexpected end of input"),
1144 }
1145
1146 buf.take_while(|ch| ch.is_ascii_whitespace());
1147 let elem = match buf.peek() {
1149 Some('"') => generated(lex_quoted_element(buf)?)?,
1150 Some('{') => {
1151 if !is_element_type_list {
1152 bail!(
1153 "unescaped '{{' at beginning of element; perhaps you \
1154 want a nested list, e.g. '{{a}}'::text list list"
1155 )
1156 }
1157 generated(lex_embedded_element(buf)?)?
1158 }
1159 Some(_) => match lex_unquoted_element(buf, is_special_char, is_end_of_literal)? {
1160 Some(elem) => generated(elem)?,
1161 None => make_null(),
1162 },
1163 None => bail!("unexpected end of input"),
1164 };
1165 elems.push(elem);
1166 }
1167
1168 buf.take_while(|ch| ch.is_ascii_whitespace());
1169 if let Some(c) = buf.next() {
1170 bail!(
1171 "malformed array literal; contains '{}' after terminal '}}'",
1172 c
1173 )
1174 }
1175
1176 Ok(elems)
1177}
1178
1179pub fn parse_legacy_vector<'a, T, E>(
1180 s: &'a str,
1181 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1182) -> Result<Vec<T>, ParseError>
1183where
1184 E: ToString,
1185{
1186 parse_legacy_vector_inner(s, gen_elem)
1187 .map_err(|details| ParseError::invalid_input_syntax("int2vector", s).with_details(details))
1188}
1189
1190pub fn parse_legacy_vector_inner<'a, T, E>(
1195 s: &'a str,
1196 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1197) -> Result<Vec<T>, String>
1198where
1199 E: ToString,
1200{
1201 let mut elems = vec![];
1202 let buf = &mut LexBuf::new(s);
1203
1204 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1205
1206 loop {
1207 buf.take_while(|ch| ch.is_ascii_whitespace());
1208 match buf.peek() {
1209 Some(_) => {
1210 let elem = buf.take_while(|ch| !ch.is_ascii_whitespace());
1211 elems.push(generated(elem.into())?);
1212 }
1213 None => break,
1214 }
1215 }
1216
1217 Ok(elems)
1218}
1219
1220fn lex_quoted_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1221 assert!(buf.consume('"'));
1222 let s = buf.take_while(|ch| !matches!(ch, '"' | '\\'));
1223
1224 if let Some('"') = buf.peek() {
1226 buf.next();
1227 return Ok(s.into());
1228 }
1229
1230 let mut s = s.to_string();
1231 loop {
1232 match buf.next() {
1233 Some('\\') => match buf.next() {
1234 Some(c) => s.push(c),
1235 None => bail!("unterminated quoted string"),
1236 },
1237 Some('"') => break,
1238 Some(c) => s.push(c),
1239 None => bail!("unterminated quoted string"),
1240 }
1241 }
1242 Ok(s.into())
1243}
1244
1245fn lex_embedded_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1246 let pos = buf.pos();
1247 assert!(matches!(buf.next(), Some('{')));
1248 let mut depth = 1;
1249 let mut in_escape = false;
1250 while depth > 0 {
1251 match buf.next() {
1252 Some('\\') => {
1253 buf.next(); }
1255 Some('"') => in_escape = !in_escape, Some('{') if !in_escape => depth += 1,
1257 Some('}') if !in_escape => depth -= 1,
1258 Some(_) => (),
1259 None => bail!("unterminated embedded element"),
1260 }
1261 }
1262 let s = &buf.inner()[pos..buf.pos()];
1263 Ok(Cow::Borrowed(s))
1264}
1265
1266fn lex_unquoted_element<'a>(
1268 buf: &mut LexBuf<'a>,
1269 is_special_char: impl Fn(char) -> bool,
1270 is_end_of_literal: impl Fn(char) -> bool,
1271) -> Result<Option<Cow<'a, str>>, String> {
1272 assert!(!buf.peek().unwrap().is_ascii_whitespace());
1274
1275 let s = buf.take_while(|ch| !is_special_char(ch) && !ch.is_ascii_whitespace());
1276
1277 match buf.peek() {
1279 Some(',') | Some('}') if !s.is_empty() => {
1280 return Ok(if s.to_uppercase() == "NULL" {
1281 None
1282 } else {
1283 Some(s.into())
1284 });
1285 }
1286 _ => {}
1287 }
1288
1289 let mut escaped_char = false;
1293
1294 let mut s = s.to_string();
1295 let mut trimmed_len = s.len();
1298 loop {
1299 match buf.next() {
1300 Some('\\') => match buf.next() {
1301 Some(c) => {
1302 escaped_char = true;
1303 s.push(c);
1304 trimmed_len = s.len();
1305 }
1306 None => return Err("unterminated element".into()),
1307 },
1308 Some(c) if is_end_of_literal(c) => {
1309 if s.is_empty() {
1312 bail!("malformed literal; missing element")
1313 }
1314 buf.prev();
1315 break;
1316 }
1317 Some(c) if is_special_char(c) => {
1318 bail!("malformed literal; must escape special character '{}'", c)
1319 }
1320 Some(c) => {
1321 s.push(c);
1322 if !c.is_ascii_whitespace() {
1323 trimmed_len = s.len();
1324 }
1325 }
1326 None => bail!("unterminated element"),
1327 }
1328 }
1329 s.truncate(trimmed_len);
1330 Ok(if s.to_uppercase() == "NULL" && !escaped_char {
1331 None
1332 } else {
1333 Some(Cow::Owned(s))
1334 })
1335}
1336
1337pub fn parse_map<'a, V, E>(
1338 s: &'a str,
1339 is_value_type_map: bool,
1340 gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1341) -> Result<BTreeMap<String, V>, ParseError>
1342where
1343 E: ToString,
1344{
1345 parse_map_inner(s, is_value_type_map, gen_elem)
1346 .map_err(|details| ParseError::invalid_input_syntax("map", s).with_details(details))
1347}
1348
1349fn parse_map_inner<'a, V, E>(
1350 s: &'a str,
1351 is_value_type_map: bool,
1352 mut gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1353) -> Result<BTreeMap<String, V>, String>
1354where
1355 E: ToString,
1356{
1357 let mut map = BTreeMap::new();
1358 let buf = &mut LexBuf::new(s);
1359
1360 if !buf.consume('{') {
1362 bail!(
1363 "expected '{{', found {}",
1364 match buf.next() {
1365 Some(c) => format!("{}", c),
1366 None => "empty string".to_string(),
1367 }
1368 )
1369 }
1370
1371 let gen_key = |key: Option<Cow<'a, str>>| -> Result<String, String> {
1373 match key {
1374 Some(Cow::Owned(s)) => Ok(s),
1375 Some(Cow::Borrowed(s)) => Ok(s.to_owned()),
1376 None => Err("expected key".to_owned()),
1377 }
1378 };
1379 let mut gen_value = |elem| gen_elem(elem).map_err(|e| e.to_string());
1380 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '"' | '=' | '>' | '\\');
1381 let is_end_of_literal = |c| matches!(c, ',' | '}' | '=');
1382
1383 loop {
1384 buf.take_while(|ch| ch.is_ascii_whitespace());
1386 match buf.next() {
1387 Some('}') => break,
1388 _ if map.len() == 0 => {
1389 buf.prev();
1390 }
1391 Some(',') => {}
1392 Some(c) => bail!("expected ',' or end of input, got '{}'", c),
1393 None => bail!("unexpected end of input"),
1394 }
1395
1396 buf.take_while(|ch| ch.is_ascii_whitespace());
1398 let key = match buf.peek() {
1399 Some('"') => Some(lex_quoted_element(buf)?),
1400 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1401 None => bail!("unexpected end of input"),
1402 };
1403 let key = gen_key(key)?;
1404
1405 buf.take_while(|ch| ch.is_ascii_whitespace());
1407 if !buf.consume('=') || !buf.consume('>') {
1408 bail!("expected =>")
1409 }
1410
1411 buf.take_while(|ch| ch.is_ascii_whitespace());
1413 let value = match buf.peek() {
1414 Some('"') => Some(lex_quoted_element(buf)?),
1415 Some('{') => {
1416 if !is_value_type_map {
1417 bail!(
1418 "unescaped '{{' at beginning of value; perhaps you \
1419 want a nested map, e.g. '{{a=>{{a=>1}}}}'::map[text=>map[text=>int]]"
1420 )
1421 }
1422 Some(lex_embedded_element(buf)?)
1423 }
1424 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1425 None => bail!("unexpected end of input"),
1426 };
1427 let value = gen_value(value)?;
1428
1429 map.insert(key, value);
1431 }
1432 Ok(map)
1433}
1434
1435pub fn format_map<F, T, E>(
1436 buf: &mut F,
1437 elems: impl IntoIterator<Item = (impl AsRef<str>, T)>,
1438 mut format_elem: impl FnMut(MapValueWriter<F>, T) -> Result<Nestable, E>,
1439) -> Result<Nestable, E>
1440where
1441 F: FormatBuffer,
1442{
1443 buf.write_char('{');
1444 let mut elems = elems.into_iter().peekable();
1445 while let Some((key, value)) = elems.next() {
1446 let key_start = buf.len();
1449 buf.write_str(key.as_ref());
1450 escape_elem::<_, MapElementEscaper>(buf, key_start);
1451
1452 buf.write_str("=>");
1453
1454 let value_start = buf.len();
1455 if let Nestable::MayNeedEscaping = format_elem(MapValueWriter(buf), value)? {
1456 escape_elem::<_, MapElementEscaper>(buf, value_start);
1457 }
1458
1459 if elems.peek().is_some() {
1460 buf.write_char(',');
1461 }
1462 }
1463 buf.write_char('}');
1464 Ok(Nestable::Yes)
1465}
1466
1467pub fn parse_range<'a, V, E>(
1468 s: &'a str,
1469 gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1470) -> Result<Range<V>, ParseError>
1471where
1472 E: ToString,
1473{
1474 Ok(Range {
1475 inner: parse_range_inner(s, gen_elem).map_err(|details| {
1476 ParseError::invalid_input_syntax("range", s).with_details(details)
1477 })?,
1478 })
1479}
1480
1481fn parse_range_inner<'a, V, E>(
1482 s: &'a str,
1483 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1484) -> Result<Option<RangeInner<V>>, String>
1485where
1486 E: ToString,
1487{
1488 let buf = &mut LexBuf::new(s);
1489
1490 buf.take_while(|ch| ch.is_ascii_whitespace());
1491
1492 if buf.consume_str("empty") {
1493 buf.take_while(|ch| ch.is_ascii_whitespace());
1494 if buf.next().is_none() {
1495 return Ok(None);
1496 } else {
1497 bail!("Junk after \"empty\" key word.")
1498 }
1499 }
1500
1501 let lower_inclusive = match buf.next() {
1502 Some('[') => true,
1503 Some('(') => false,
1504 _ => bail!("Missing left parenthesis or bracket."),
1505 };
1506
1507 let lower_bound = match buf.peek() {
1508 Some(',') => None,
1509 Some(_) => {
1510 let v = buf.take_while(|c| !matches!(c, ','));
1511 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1512 Some(v)
1513 }
1514 None => bail!("Unexpected end of input."),
1515 };
1516
1517 buf.take_while(|ch| ch.is_ascii_whitespace());
1518
1519 if buf.next() != Some(',') {
1520 bail!("Missing comma after lower bound.")
1521 }
1522
1523 let upper_bound = match buf.peek() {
1524 Some(']' | ')') => None,
1525 Some(_) => {
1526 let v = buf.take_while(|c| !matches!(c, ')' | ']'));
1527 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1528 Some(v)
1529 }
1530 None => bail!("Unexpected end of input."),
1531 };
1532
1533 let upper_inclusive = match buf.next() {
1534 Some(']') => true,
1535 Some(')') => false,
1536 _ => bail!("Missing left parenthesis or bracket."),
1537 };
1538
1539 buf.take_while(|ch| ch.is_ascii_whitespace());
1540
1541 if buf.next().is_some() {
1542 bail!("Junk after right parenthesis or bracket.")
1543 }
1544
1545 let range = Some(RangeInner {
1546 lower: RangeBound {
1547 inclusive: lower_inclusive,
1548 bound: lower_bound,
1549 },
1550 upper: RangeBound {
1551 inclusive: upper_inclusive,
1552 bound: upper_bound,
1553 },
1554 });
1555
1556 Ok(range)
1557}
1558
1559pub fn format_range<F, V, E>(
1561 buf: &mut F,
1562 r: &Range<V>,
1563 mut format_elem: impl FnMut(RangeElementWriter<F>, Option<&V>) -> Result<Nestable, E>,
1564) -> Result<Nestable, E>
1565where
1566 F: FormatBuffer,
1567{
1568 let range = match &r.inner {
1569 None => {
1570 buf.write_str("empty");
1571 return Ok(Nestable::MayNeedEscaping);
1572 }
1573 Some(i) => i,
1574 };
1575
1576 if range.lower.inclusive {
1577 buf.write_char('[');
1578 } else {
1579 buf.write_char('(');
1580 }
1581
1582 let start = buf.len();
1583 if let Nestable::MayNeedEscaping =
1584 format_elem(RangeElementWriter(buf), range.lower.bound.as_ref())?
1585 {
1586 escape_elem::<_, ListElementEscaper>(buf, start);
1587 }
1588
1589 buf.write_char(',');
1590
1591 let start = buf.len();
1592 if let Nestable::MayNeedEscaping =
1593 format_elem(RangeElementWriter(buf), range.upper.bound.as_ref())?
1594 {
1595 escape_elem::<_, ListElementEscaper>(buf, start);
1596 }
1597
1598 if range.upper.inclusive {
1599 buf.write_char(']');
1600 } else {
1601 buf.write_char(')');
1602 }
1603
1604 Ok(Nestable::MayNeedEscaping)
1605}
1606
1607#[derive(Debug)]
1609pub struct RangeElementWriter<'a, F>(&'a mut F);
1610
1611impl<'a, F> RangeElementWriter<'a, F>
1612where
1613 F: FormatBuffer,
1614{
1615 pub fn write_null(self) -> Nestable {
1617 Nestable::Yes
1620 }
1621
1622 pub fn nonnull_buffer(self) -> &'a mut F {
1625 self.0
1626 }
1627}
1628
1629pub fn format_array<F, T, E>(
1630 buf: &mut F,
1631 dims: &[ArrayDimension],
1632 elems: impl IntoIterator<Item = T>,
1633 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1634) -> Result<Nestable, E>
1635where
1636 F: FormatBuffer,
1637{
1638 if dims.iter().any(|dim| dim.lower_bound != 1) {
1639 for d in dims.iter() {
1640 let (lower, upper) = d.dimension_bounds();
1641 write!(buf, "[{}:{}]", lower, upper);
1642 }
1643 buf.write_char('=');
1644 }
1645
1646 format_array_inner(buf, dims, &mut elems.into_iter(), &mut format_elem)?;
1647 Ok(Nestable::Yes)
1648}
1649
1650pub fn format_array_inner<F, T, E>(
1651 buf: &mut F,
1652 dims: &[ArrayDimension],
1653 elems: &mut impl Iterator<Item = T>,
1654 format_elem: &mut impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1655) -> Result<(), E>
1656where
1657 F: FormatBuffer,
1658{
1659 if dims.is_empty() {
1660 buf.write_str("{}");
1661 return Ok(());
1662 }
1663
1664 buf.write_char('{');
1665 for j in 0..dims[0].length {
1666 if j > 0 {
1667 buf.write_char(',');
1668 }
1669 if dims.len() == 1 {
1670 let start = buf.len();
1671 let elem = elems.next().unwrap();
1672 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1673 escape_elem::<_, ListElementEscaper>(buf, start);
1674 }
1675 } else {
1676 format_array_inner(buf, &dims[1..], elems, format_elem)?;
1677 }
1678 }
1679 buf.write_char('}');
1680
1681 Ok(())
1682}
1683
1684pub fn format_legacy_vector<F, T, E>(
1685 buf: &mut F,
1686 elems: impl IntoIterator<Item = T>,
1687 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1688) -> Result<Nestable, E>
1689where
1690 F: FormatBuffer,
1691{
1692 format_elems(buf, elems, format_elem, ' ')?;
1693 Ok(Nestable::MayNeedEscaping)
1694}
1695
1696pub fn format_list<F, T, E>(
1697 buf: &mut F,
1698 elems: impl IntoIterator<Item = T>,
1699 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1700) -> Result<Nestable, E>
1701where
1702 F: FormatBuffer,
1703{
1704 buf.write_char('{');
1705 format_elems(buf, elems, format_elem, ',')?;
1706 buf.write_char('}');
1707 Ok(Nestable::Yes)
1708}
1709
1710pub fn format_elems<F, T, E>(
1712 buf: &mut F,
1713 elems: impl IntoIterator<Item = T>,
1714 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1715 sep: char,
1716) -> Result<(), E>
1717where
1718 F: FormatBuffer,
1719{
1720 let mut elems = elems.into_iter().peekable();
1721 while let Some(elem) = elems.next() {
1722 let start = buf.len();
1723 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1724 escape_elem::<_, ListElementEscaper>(buf, start);
1725 }
1726 if elems.peek().is_some() {
1727 buf.write_char(sep)
1728 }
1729 }
1730 Ok(())
1731}
1732
1733pub fn format_mz_acl_item<F>(buf: &mut F, mz_acl_item: MzAclItem) -> Nestable
1735where
1736 F: FormatBuffer,
1737{
1738 write!(buf, "{mz_acl_item}");
1739 Nestable::Yes
1740}
1741
1742pub fn parse_mz_acl_item(s: &str) -> Result<MzAclItem, ParseError> {
1744 s.trim()
1745 .parse()
1746 .map_err(|e| ParseError::invalid_input_syntax("mz_aclitem", s).with_details(e))
1747}
1748
1749pub fn format_acl_item<F>(buf: &mut F, acl_item: AclItem) -> Nestable
1751where
1752 F: FormatBuffer,
1753{
1754 write!(buf, "{acl_item}");
1755 Nestable::Yes
1756}
1757
1758pub fn parse_acl_item(s: &str) -> Result<AclItem, ParseError> {
1760 s.trim()
1761 .parse()
1762 .map_err(|e| ParseError::invalid_input_syntax("aclitem", s).with_details(e))
1763}
1764
1765pub trait ElementEscaper {
1766 fn needs_escaping(elem: &[u8]) -> bool;
1767 fn escape_char(c: u8) -> u8;
1768}
1769
1770struct ListElementEscaper;
1771
1772impl ElementEscaper for ListElementEscaper {
1773 fn needs_escaping(elem: &[u8]) -> bool {
1774 elem.is_empty()
1775 || elem == b"NULL"
1776 || elem
1777 .iter()
1778 .any(|c| matches!(c, b'{' | b'}' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1779 }
1780
1781 fn escape_char(_: u8) -> u8 {
1782 b'\\'
1783 }
1784}
1785
1786struct MapElementEscaper;
1787
1788impl ElementEscaper for MapElementEscaper {
1789 fn needs_escaping(elem: &[u8]) -> bool {
1790 elem.is_empty()
1791 || elem == b"NULL"
1792 || elem.iter().any(|c| {
1793 matches!(c, b'{' | b'}' | b',' | b'"' | b'=' | b'>' | b'\\')
1794 || c.is_ascii_whitespace()
1795 })
1796 }
1797
1798 fn escape_char(_: u8) -> u8 {
1799 b'\\'
1800 }
1801}
1802
1803struct RecordElementEscaper;
1804
1805impl ElementEscaper for RecordElementEscaper {
1806 fn needs_escaping(elem: &[u8]) -> bool {
1807 elem.is_empty()
1808 || elem
1809 .iter()
1810 .any(|c| matches!(c, b'(' | b')' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1811 }
1812
1813 fn escape_char(c: u8) -> u8 {
1814 if c == b'"' { b'"' } else { b'\\' }
1815 }
1816}
1817
1818fn escape_elem<F, E>(buf: &mut F, start: usize)
1828where
1829 F: FormatBuffer,
1830 E: ElementEscaper,
1831{
1832 let elem = &buf.as_ref()[start..];
1833 if !E::needs_escaping(elem) {
1834 return;
1835 }
1836
1837 let extras = 2 + elem.iter().filter(|b| matches!(b, b'"' | b'\\')).count();
1840 let orig_end = buf.len();
1841 let new_end = buf.len() + extras;
1842
1843 for _ in 0..extras {
1850 buf.write_char('\0');
1851 }
1852
1853 let elem = unsafe { buf.as_bytes_mut() };
1856
1857 let mut wi = new_end - 1;
1861 elem[wi] = b'"';
1862 wi -= 1;
1863 for ri in (start..orig_end).rev() {
1864 elem[wi] = elem[ri];
1865 wi -= 1;
1866 if let b'\\' | b'"' = elem[ri] {
1867 elem[wi] = E::escape_char(elem[ri]);
1868 wi -= 1;
1869 }
1870 }
1871 elem[wi] = b'"';
1872
1873 assert!(wi == start);
1874}
1875
1876#[derive(Debug)]
1878pub struct ListElementWriter<'a, F>(&'a mut F);
1879
1880impl<'a, F> ListElementWriter<'a, F>
1881where
1882 F: FormatBuffer,
1883{
1884 pub fn write_null(self) -> Nestable {
1886 self.0.write_str("NULL");
1887 Nestable::Yes
1888 }
1889
1890 pub fn nonnull_buffer(self) -> &'a mut F {
1893 self.0
1894 }
1895}
1896
1897#[derive(Debug)]
1899pub struct MapValueWriter<'a, F>(&'a mut F);
1900
1901impl<'a, F> MapValueWriter<'a, F>
1902where
1903 F: FormatBuffer,
1904{
1905 pub fn write_null(self) -> Nestable {
1907 self.0.write_str("NULL");
1908 Nestable::Yes
1909 }
1910
1911 pub fn nonnull_buffer(self) -> &'a mut F {
1914 self.0
1915 }
1916}
1917
1918pub fn format_record<F, T, E>(
1919 buf: &mut F,
1920 elems: impl IntoIterator<Item = T>,
1921 mut format_elem: impl FnMut(RecordElementWriter<F>, T) -> Result<Nestable, E>,
1922) -> Result<Nestable, E>
1923where
1924 F: FormatBuffer,
1925{
1926 buf.write_char('(');
1927 let mut elems = elems.into_iter().peekable();
1928 while let Some(elem) = elems.next() {
1929 let start = buf.len();
1930 if let Nestable::MayNeedEscaping = format_elem(RecordElementWriter(buf), elem)? {
1931 escape_elem::<_, RecordElementEscaper>(buf, start);
1932 }
1933 if elems.peek().is_some() {
1934 buf.write_char(',')
1935 }
1936 }
1937 buf.write_char(')');
1938 Ok(Nestable::MayNeedEscaping)
1939}
1940
1941#[derive(Debug)]
1943pub struct RecordElementWriter<'a, F>(&'a mut F);
1944
1945impl<'a, F> RecordElementWriter<'a, F>
1946where
1947 F: FormatBuffer,
1948{
1949 pub fn write_null(self) -> Nestable {
1951 Nestable::Yes
1952 }
1953
1954 pub fn nonnull_buffer(self) -> &'a mut F {
1957 self.0
1958 }
1959}
1960
1961#[derive(
1963 Ord,
1964 PartialOrd,
1965 Clone,
1966 Debug,
1967 Eq,
1968 PartialEq,
1969 Serialize,
1970 Deserialize,
1971 Hash,
1972 MzReflect
1973)]
1974#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1975pub struct ParseError {
1976 pub kind: ParseErrorKind,
1977 pub type_name: Box<str>,
1978 pub input: Box<str>,
1979 pub details: Option<Box<str>>,
1980}
1981
1982#[derive(
1983 Ord,
1984 PartialOrd,
1985 Clone,
1986 Copy,
1987 Debug,
1988 Eq,
1989 PartialEq,
1990 Serialize,
1991 Deserialize,
1992 Hash,
1993 MzReflect
1994)]
1995#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1996pub enum ParseErrorKind {
1997 OutOfRange,
1998 InvalidInputSyntax,
1999}
2000
2001impl ParseError {
2002 fn new<S>(kind: ParseErrorKind, type_name: &'static str, input: S) -> ParseError
2006 where
2007 S: Into<Box<str>>,
2008 {
2009 ParseError {
2010 kind,
2011 type_name: type_name.into(),
2012 input: input.into(),
2013 details: None,
2014 }
2015 }
2016
2017 fn out_of_range<S>(type_name: &'static str, input: S) -> ParseError
2018 where
2019 S: Into<Box<str>>,
2020 {
2021 ParseError::new(ParseErrorKind::OutOfRange, type_name, input)
2022 }
2023
2024 fn invalid_input_syntax<S>(type_name: &'static str, input: S) -> ParseError
2025 where
2026 S: Into<Box<str>>,
2027 {
2028 ParseError::new(ParseErrorKind::InvalidInputSyntax, type_name, input)
2029 }
2030
2031 fn with_details<D>(mut self, details: D) -> ParseError
2032 where
2033 D: fmt::Display,
2034 {
2035 self.details = Some(details.to_string().into());
2036 self
2037 }
2038}
2039
2040impl fmt::Display for ParseError {
2041 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2042 match self.kind {
2043 ParseErrorKind::OutOfRange => {
2044 write!(
2045 f,
2046 "{} is out of range for type {}",
2047 self.input.quoted(),
2048 self.type_name
2049 )?;
2050 if let Some(details) = &self.details {
2051 write!(f, ": {}", details)?;
2052 }
2053 Ok(())
2054 }
2055 ParseErrorKind::InvalidInputSyntax => {
2056 write!(f, "invalid input syntax for type {}: ", self.type_name)?;
2057 if let Some(details) = &self.details {
2058 write!(f, "{}: ", details)?;
2059 }
2060 write!(f, "{}", self.input.quoted())
2061 }
2062 }
2063 }
2064}
2065
2066impl Error for ParseError {}
2067
2068impl RustType<ProtoParseError> for ParseError {
2069 fn into_proto(&self) -> ProtoParseError {
2070 use Kind::*;
2071 use proto_parse_error::*;
2072 let kind = match self.kind {
2073 ParseErrorKind::OutOfRange => OutOfRange(()),
2074 ParseErrorKind::InvalidInputSyntax => InvalidInputSyntax(()),
2075 };
2076 ProtoParseError {
2077 kind: Some(kind),
2078 type_name: self.type_name.into_proto(),
2079 input: self.input.into_proto(),
2080 details: self.details.into_proto(),
2081 }
2082 }
2083
2084 fn from_proto(proto: ProtoParseError) -> Result<Self, TryFromProtoError> {
2085 use proto_parse_error::Kind::*;
2086
2087 if let Some(kind) = proto.kind {
2088 Ok(ParseError {
2089 kind: match kind {
2090 OutOfRange(()) => ParseErrorKind::OutOfRange,
2091 InvalidInputSyntax(()) => ParseErrorKind::InvalidInputSyntax,
2092 },
2093 type_name: proto.type_name.into(),
2094 input: proto.input.into(),
2095 details: proto.details.into_rust()?,
2096 })
2097 } else {
2098 Err(TryFromProtoError::missing_field("ProtoParseError::kind"))
2099 }
2100 }
2101}
2102
2103#[derive(
2104 Ord,
2105 PartialOrd,
2106 Copy,
2107 Clone,
2108 Debug,
2109 Eq,
2110 PartialEq,
2111 Serialize,
2112 Deserialize,
2113 Hash,
2114 MzReflect
2115)]
2116#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
2117pub enum ParseHexError {
2118 InvalidHexDigit(char),
2119 OddLength,
2120}
2121impl Error for ParseHexError {}
2122
2123impl fmt::Display for ParseHexError {
2124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2125 match self {
2126 ParseHexError::InvalidHexDigit(c) => {
2127 write!(f, "invalid hexadecimal digit: \"{}\"", c.escape_default())
2128 }
2129 ParseHexError::OddLength => {
2130 f.write_str("invalid hexadecimal data: odd number of digits")
2131 }
2132 }
2133 }
2134}
2135
2136impl RustType<ProtoParseHexError> for ParseHexError {
2137 fn into_proto(&self) -> ProtoParseHexError {
2138 use Kind::*;
2139 use proto_parse_hex_error::*;
2140 let kind = match self {
2141 ParseHexError::InvalidHexDigit(v) => InvalidHexDigit(v.into_proto()),
2142 ParseHexError::OddLength => OddLength(()),
2143 };
2144 ProtoParseHexError { kind: Some(kind) }
2145 }
2146
2147 fn from_proto(error: ProtoParseHexError) -> Result<Self, TryFromProtoError> {
2148 use proto_parse_hex_error::Kind::*;
2149 match error.kind {
2150 Some(kind) => match kind {
2151 InvalidHexDigit(v) => Ok(ParseHexError::InvalidHexDigit(char::from_proto(v)?)),
2152 OddLength(()) => Ok(ParseHexError::OddLength),
2153 },
2154 None => Err(TryFromProtoError::missing_field(
2155 "`ProtoParseHexError::kind`",
2156 )),
2157 }
2158 }
2159}
2160
2161#[cfg(test)]
2162mod tests {
2163 use mz_ore::assert_ok;
2164 use mz_proto::protobuf_roundtrip;
2165 use proptest::prelude::*;
2166
2167 use super::*;
2168
2169 proptest! {
2170 #[mz_ore::test]
2171 #[cfg_attr(miri, ignore)] fn parse_error_protobuf_roundtrip(expect in any::<ParseError>()) {
2173 let actual = protobuf_roundtrip::<_, ProtoParseError>(&expect);
2174 assert_ok!(actual);
2175 assert_eq!(actual.unwrap(), expect);
2176 }
2177 }
2178
2179 proptest! {
2180 #[mz_ore::test]
2181 #[cfg_attr(miri, ignore)] fn parse_hex_error_protobuf_roundtrip(expect in any::<ParseHexError>()) {
2183 let actual = protobuf_roundtrip::<_, ProtoParseHexError>(&expect);
2184 assert_ok!(actual);
2185 assert_eq!(actual.unwrap(), expect);
2186 }
2187 }
2188
2189 #[mz_ore::test]
2190 fn test_format_nanos_to_micros() {
2191 let cases: Vec<(u32, &str)> = vec![
2192 (0, ""),
2193 (1, ""),
2194 (499, ""),
2195 (500, ".000001"),
2196 (500_000, ".0005"),
2197 (5_000_000, ".005"),
2198 (1_999_999_999, ".2"),
2201 ];
2202 for (nanos, expect) in cases {
2203 let mut buf = String::new();
2204 format_nanos_to_micros(&mut buf, nanos);
2205 assert_eq!(&buf, expect);
2206 }
2207 }
2208
2209 #[mz_ore::test]
2210 fn test_parse_pg_legacy_name() {
2211 let s = "hello world";
2212 assert_eq!(s, parse_pg_legacy_name(s));
2213
2214 let s = "x".repeat(63);
2215 assert_eq!(s, parse_pg_legacy_name(&s));
2216
2217 let s = "x".repeat(64);
2218 assert_eq!("x".repeat(63), parse_pg_legacy_name(&s));
2219
2220 let s = format!("{}{}", "x".repeat(61), "א");
2222 assert_eq!(s, parse_pg_legacy_name(&s));
2223
2224 let s = format!("{}{}", "x".repeat(62), "א");
2225 assert_eq!("x".repeat(62), parse_pg_legacy_name(&s));
2226 }
2227
2228 #[mz_ore::test]
2229 fn test_parse_oid() {
2230 assert_eq!(parse_oid("0").unwrap(), 0);
2232 assert_eq!(parse_oid("2147483647").unwrap(), 2147483647);
2233 assert_eq!(parse_oid("2147483648").unwrap(), 2147483648);
2234 assert_eq!(parse_oid("4294967295").unwrap(), 4294967295);
2235
2236 assert_eq!(parse_oid("-1").unwrap(), 4294967295);
2238 assert_eq!(parse_oid("-2147483648").unwrap(), 2147483648);
2239
2240 assert_eq!(parse_oid(" 42 ").unwrap(), 42);
2242
2243 assert!(parse_oid("4294967296").is_err());
2245 assert!(parse_oid("-2147483649").is_err());
2246 assert!(parse_oid("nope").is_err());
2247 }
2248
2249 #[mz_ore::test]
2250 fn test_parse_oid_legacy() {
2251 assert_eq!(parse_oid_legacy("0").unwrap(), 0);
2253 assert_eq!(parse_oid_legacy("2147483647").unwrap(), 2147483647);
2254 assert_eq!(parse_oid_legacy("-1").unwrap(), 4294967295);
2255 assert_eq!(parse_oid_legacy("-2147483648").unwrap(), 2147483648);
2256
2257 assert!(parse_oid_legacy("2147483648").is_err());
2260 assert!(parse_oid_legacy("4294967295").is_err());
2261 assert!(parse_oid_legacy("nope").is_err());
2262 }
2263}