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 oid: i32 = s
245 .trim()
246 .parse()
247 .map_err(|e| ParseError::invalid_input_syntax("oid", s).with_details(e))?;
248 Ok(u32::reinterpret_cast(oid))
249}
250
251fn parse_float<Fl>(type_name: &'static str, s: &str) -> Result<Fl, ParseError>
252where
253 Fl: NumFloat + FromStr,
254{
255 static ZERO_RE: LazyLock<Regex> =
271 LazyLock::new(|| Regex::new(r#"(?i-u)^[-+]?(0+(\.0*)?|\.0+)(e|$)"#).unwrap());
272 static INF_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new("(?i-u)^[-+]?inf").unwrap());
274
275 let buf = s.trim();
276 let f: Fl = buf
277 .parse()
278 .map_err(|_| ParseError::invalid_input_syntax(type_name, s))?;
279 match f.classify() {
280 FpCategory::Infinite if !INF_RE.is_match(buf.as_bytes()) => {
281 Err(ParseError::out_of_range(type_name, s))
282 }
283 FpCategory::Zero if !ZERO_RE.is_match(buf.as_bytes()) => {
284 Err(ParseError::out_of_range(type_name, s))
285 }
286 _ => Ok(f),
287 }
288}
289
290fn format_float<F, Fl>(buf: &mut F, f: Fl) -> Nestable
291where
292 F: FormatBuffer,
293 Fl: NumFloat + RyuFloat,
294{
295 match f.classify() {
308 FpCategory::Infinite if f.is_sign_negative() => buf.write_str("-Infinity"),
309 FpCategory::Infinite => buf.write_str("Infinity"),
310 FpCategory::Nan => buf.write_str("NaN"),
311 FpCategory::Zero if f.is_sign_negative() => buf.write_str("-0"),
312 _ => {
313 debug_assert!(f.is_finite());
314 let mut ryu_buf = ryu::Buffer::new();
315 let mut s = ryu_buf.format_finite(f);
316 if let Some(trimmed) = s.strip_suffix(".0") {
317 s = trimmed;
318 }
319 let mut chars = s.chars().peekable();
320 while let Some(ch) = chars.next() {
321 buf.write_char(ch);
322 if ch == 'e' && chars.peek() != Some(&'-') {
323 buf.write_char('+');
324 }
325 }
326 }
327 }
328
329 Nestable::Yes
330}
331
332pub fn parse_float32(s: &str) -> Result<f32, ParseError> {
334 parse_float("real", s)
335}
336
337pub fn format_float32<F>(buf: &mut F, f: f32) -> Nestable
339where
340 F: FormatBuffer,
341{
342 format_float(buf, f)
343}
344
345pub fn parse_float64(s: &str) -> Result<f64, ParseError> {
347 parse_float("double precision", s)
348}
349
350pub fn format_float64<F>(buf: &mut F, f: f64) -> Nestable
352where
353 F: FormatBuffer,
354{
355 format_float(buf, f)
356}
357
358fn parse_timestamp_string(s: &str) -> Result<(NaiveDate, NaiveTime, Timezone), String> {
377 if s.is_empty() {
378 return Err("timestamp string is empty".into());
379 }
380
381 if s == "epoch" {
386 return Ok((
387 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
388 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
389 Default::default(),
390 ));
391 }
392
393 let (ts_string, tz_string, era) = datetime::split_timestamp_string(s);
394
395 let pdt = ParsedDateTime::build_parsed_datetime_timestamp(ts_string, era)?;
396 let d: NaiveDate = pdt.compute_date()?;
397 let t: NaiveTime = pdt.compute_time()?;
398
399 let offset = if tz_string.is_empty() {
400 Default::default()
401 } else {
402 Timezone::parse(tz_string, TimezoneSpec::Iso)?
403 };
404
405 Ok((d, t, offset))
406}
407
408pub fn parse_date(s: &str) -> Result<Date, ParseError> {
410 match parse_timestamp_string(s) {
411 Ok((date, _, _)) => Date::try_from(date).map_err(|_| ParseError::out_of_range("date", s)),
412 Err(e) => Err(ParseError::invalid_input_syntax("date", s).with_details(e)),
413 }
414}
415
416pub fn format_date<F>(buf: &mut F, d: Date) -> Nestable
418where
419 F: FormatBuffer,
420{
421 let d: NaiveDate = d.into();
422 let (year_ad, year) = d.year_ce();
423 write!(buf, "{:04}-{}", year, d.format("%m-%d"));
424 if !year_ad {
425 write!(buf, " BC");
426 }
427 Nestable::Yes
428}
429
430pub fn parse_time(s: &str) -> Result<NaiveTime, ParseError> {
438 ParsedDateTime::build_parsed_datetime_time(s)
439 .and_then(|pdt| pdt.compute_time())
440 .map_err(|e| ParseError::invalid_input_syntax("time", s).with_details(e))
441}
442
443pub fn format_time<F>(buf: &mut F, t: NaiveTime) -> Nestable
445where
446 F: FormatBuffer,
447{
448 write!(buf, "{}", t.format("%H:%M:%S"));
449 format_nanos_to_micros(buf, t.nanosecond());
450 Nestable::Yes
451}
452
453pub fn parse_timestamp(s: &str) -> Result<CheckedTimestamp<NaiveDateTime>, ParseError> {
455 match parse_timestamp_string(s) {
456 Ok((date, time, _)) => CheckedTimestamp::from_timestamplike(date.and_time(time))
457 .map_err(|_| ParseError::out_of_range("timestamp", s)),
458 Err(e) => Err(ParseError::invalid_input_syntax("timestamp", s).with_details(e)),
459 }
460}
461
462pub fn format_timestamp<F>(buf: &mut F, ts: &NaiveDateTime) -> Nestable
464where
465 F: FormatBuffer,
466{
467 let (year_ad, year) = ts.year_ce();
468 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
469 format_nanos_to_micros(buf, ts.and_utc().timestamp_subsec_nanos());
470 if !year_ad {
471 write!(buf, " BC");
472 }
473 Nestable::MayNeedEscaping
475}
476
477pub fn parse_timestamptz(s: &str) -> Result<CheckedTimestamp<DateTime<Utc>>, ParseError> {
479 parse_timestamp_string(s)
480 .and_then(|(date, time, timezone)| {
481 use Timezone::*;
482 let mut dt = date.and_time(time);
483 let offset = match timezone {
484 FixedOffset(offset) => offset,
485 Tz(tz) => match tz.offset_from_local_datetime(&dt).latest() {
486 Some(offset) => offset.fix(),
487 None => {
488 dt += Duration::try_hours(1).unwrap();
489 tz.offset_from_local_datetime(&dt)
490 .latest()
491 .ok_or_else(|| "invalid timezone conversion".to_owned())?
492 .fix()
493 }
494 },
495 };
496 Ok(DateTime::from_naive_utc_and_offset(dt - offset, Utc))
497 })
498 .map_err(|e| {
499 ParseError::invalid_input_syntax("timestamp with time zone", s).with_details(e)
500 })
501 .and_then(|ts| {
502 CheckedTimestamp::from_timestamplike(ts)
503 .map_err(|_| ParseError::out_of_range("timestamp with time zone", s))
504 })
505}
506
507pub fn format_timestamptz<F>(buf: &mut F, ts: &DateTime<Utc>) -> Nestable
509where
510 F: FormatBuffer,
511{
512 let (year_ad, year) = ts.year_ce();
513 write!(buf, "{:04}-{}", year, ts.format("%m-%d %H:%M:%S"));
514 format_nanos_to_micros(buf, ts.timestamp_subsec_nanos());
515 write!(buf, "+00");
516 if !year_ad {
517 write!(buf, " BC");
518 }
519 Nestable::MayNeedEscaping
521}
522
523pub fn parse_interval(s: &str) -> Result<Interval, ParseError> {
543 parse_interval_w_disambiguator(s, None, DateTimeField::Second)
544}
545
546pub fn parse_interval_w_disambiguator(
551 s: &str,
552 leading_time_precision: Option<DateTimeField>,
553 d: DateTimeField,
554) -> Result<Interval, ParseError> {
555 ParsedDateTime::build_parsed_datetime_interval(s, leading_time_precision, d)
556 .and_then(|pdt| pdt.compute_interval())
557 .map_err(|e| ParseError::invalid_input_syntax("interval", s).with_details(e))
558}
559
560pub fn format_interval<F>(buf: &mut F, iv: Interval) -> Nestable
561where
562 F: FormatBuffer,
563{
564 write!(buf, "{}", iv);
565 Nestable::MayNeedEscaping
566}
567
568pub fn parse_numeric(s: &str) -> Result<OrderedDecimal<Numeric>, ParseError> {
569 let mut cx = numeric::cx_datum();
570 let mut n = match cx.parse(s.trim()) {
571 Ok(n) => n,
572 Err(..) => {
573 return Err(ParseError::invalid_input_syntax("numeric", s));
574 }
575 };
576
577 let cx_status = cx.status();
578
579 if (n.is_infinite() && !cx_status.overflow())
581 || (n.is_nan() && n.is_negative())
582 || n.is_signaling_nan()
583 {
584 return Err(ParseError::invalid_input_syntax("numeric", s));
585 }
586
587 let out_of_range = numeric::munge_numeric(&mut n).is_err();
589
590 if cx_status.overflow() || cx_status.subnormal() || out_of_range {
591 Err(ParseError::out_of_range("numeric", s).with_details(format!(
592 "exceeds maximum precision {}",
593 NUMERIC_DATUM_MAX_PRECISION
594 )))
595 } else {
596 Ok(OrderedDecimal(n))
597 }
598}
599
600pub fn format_numeric<F>(buf: &mut F, n: &OrderedDecimal<Numeric>) -> Nestable
601where
602 F: FormatBuffer,
603{
604 write!(buf, "{}", n.0.to_standard_notation_string());
605 Nestable::Yes
606}
607
608pub fn format_string<F>(buf: &mut F, s: &str) -> Nestable
609where
610 F: FormatBuffer,
611{
612 buf.write_str(s);
613 Nestable::MayNeedEscaping
614}
615
616pub fn parse_pg_legacy_name(s: &str) -> String {
617 let mut out = String::new();
620 let mut len = 0;
621 for c in s.chars() {
622 len += c.len_utf8();
623 if len > NAME_MAX_BYTES {
624 break;
625 }
626 out.push(c);
627 }
628 out
629}
630
631pub fn parse_bytes(s: &str) -> Result<Vec<u8>, ParseError> {
632 if let Some(remainder) = s.strip_prefix(r"\x") {
638 parse_bytes_hex(remainder).map_err(|e| {
639 ParseError::invalid_input_syntax("bytea", s).with_details(e.to_string_with_causes())
640 })
641 } else {
642 parse_bytes_traditional(s)
643 }
644}
645
646pub fn parse_bytes_hex(s: &str) -> Result<Vec<u8>, ParseHexError> {
647 let decode_nibble = |b| match b {
651 b'a'..=b'f' => Ok(b - b'a' + 10),
652 b'A'..=b'F' => Ok(b - b'A' + 10),
653 b'0'..=b'9' => Ok(b - b'0'),
654 _ => Err(ParseHexError::InvalidHexDigit(char::from(b))),
655 };
656
657 let mut buf = vec![];
658 let mut nibbles = s.as_bytes().iter().copied();
659 while let Some(n) = nibbles.next() {
660 if let b' ' | b'\n' | b'\t' | b'\r' = n {
661 continue;
662 }
663 let n = decode_nibble(n)?;
664 let n2 = match nibbles.next() {
665 None => return Err(ParseHexError::OddLength),
666 Some(n2) => decode_nibble(n2)?,
667 };
668 buf.push((n << 4) | n2);
669 }
670 Ok(buf)
671}
672
673pub fn parse_bytes_traditional(s: &str) -> Result<Vec<u8>, ParseError> {
674 let mut out = Vec::with_capacity(s.len());
678 let mut bytes = s.as_bytes().iter().fuse();
679 while let Some(&b) = bytes.next() {
680 if b != b'\\' {
681 out.push(b);
682 continue;
683 }
684 match bytes.next() {
685 None => {
686 return Err(ParseError::invalid_input_syntax("bytea", s)
687 .with_details("ends with escape character"));
688 }
689 Some(b'\\') => out.push(b'\\'),
690 b => match (b, bytes.next(), bytes.next()) {
691 (Some(d2 @ b'0'..=b'3'), Some(d1 @ b'0'..=b'7'), Some(d0 @ b'0'..=b'7')) => {
692 out.push(((d2 - b'0') << 6) + ((d1 - b'0') << 3) + (d0 - b'0'));
693 }
694 _ => {
695 return Err(ParseError::invalid_input_syntax("bytea", s)
696 .with_details("invalid escape sequence"));
697 }
698 },
699 }
700 }
701 Ok(out)
702}
703
704pub fn format_bytes<F>(buf: &mut F, bytes: &[u8]) -> Nestable
705where
706 F: FormatBuffer,
707{
708 write!(buf, "\\x{}", hex::encode(bytes));
709 Nestable::MayNeedEscaping
710}
711
712pub fn parse_jsonb(s: &str) -> Result<Jsonb, ParseError> {
713 s.trim()
714 .parse()
715 .map_err(|e| ParseError::invalid_input_syntax("jsonb", s).with_details(e))
716}
717
718pub fn format_jsonb<F>(buf: &mut F, jsonb: JsonbRef) -> Nestable
719where
720 F: FormatBuffer,
721{
722 write!(buf, "{}", jsonb);
723 Nestable::MayNeedEscaping
724}
725
726pub fn format_jsonb_pretty<F>(buf: &mut F, jsonb: JsonbRef)
727where
728 F: FormatBuffer,
729{
730 write!(buf, "{:#}", jsonb)
731}
732
733pub fn parse_uuid(s: &str) -> Result<Uuid, ParseError> {
734 let trimmed = s.trim();
735 if trimmed.len() < 32 || !trimmed.is_ascii() {
740 return Err(ParseError::invalid_input_syntax("uuid", s));
741 }
742 trimmed
743 .parse()
744 .map_err(|e| ParseError::invalid_input_syntax("uuid", s).with_details(e))
745}
746
747pub fn format_uuid<F>(buf: &mut F, uuid: Uuid) -> Nestable
748where
749 F: FormatBuffer,
750{
751 write!(buf, "{}", uuid);
752 Nestable::Yes
753}
754
755fn format_nanos_to_micros<F>(buf: &mut F, nanos: u32)
756where
757 F: FormatBuffer,
758{
759 if nanos >= 500 {
760 let mut micros = nanos / 1000;
761 let rem = nanos % 1000;
762 if rem >= 500 {
763 micros += 1;
764 }
765 let mut width = 6;
767 while micros % 10 == 0 {
768 width -= 1;
769 micros /= 10;
770 }
771 write!(buf, ".{:0width$}", micros, width = width);
772 }
773}
774
775#[derive(Debug, thiserror::Error)]
776enum ArrayParsingError {
777 #[error("Array value must start with \"{{\"")]
778 OpeningBraceMissing,
779 #[error("Specifying array lower bounds is not supported")]
780 DimsUnsupported,
781 #[error("{0}")]
782 Generic(String),
783 #[error("Unexpected \"{0}\" character.")]
784 UnexpectedChar(char),
785 #[error("Multidimensional arrays must have sub-arrays with matching dimensions.")]
786 NonRectilinearDims,
787 #[error("Unexpected array element.")]
788 UnexpectedElement,
789 #[error("Junk after closing right brace.")]
790 Junk,
791 #[error("Unexpected end of input.")]
792 EarlyTerm,
793}
794
795impl From<String> for ArrayParsingError {
796 fn from(value: String) -> Self {
797 ArrayParsingError::Generic(value)
798 }
799}
800
801pub fn parse_array<'a, T, E>(
802 s: &'a str,
803 make_null: impl FnMut() -> T,
804 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
805) -> Result<(Vec<T>, Vec<ArrayDimension>), ParseError>
806where
807 E: ToString,
808{
809 parse_array_inner(s, make_null, gen_elem)
810 .map_err(|details| ParseError::invalid_input_syntax("array", s).with_details(details))
811}
812
813fn parse_array_inner<'a, T, E>(
814 s: &'a str,
815 mut make_null: impl FnMut() -> T,
816 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
817) -> Result<(Vec<T>, Vec<ArrayDimension>), ArrayParsingError>
818where
819 E: ToString,
820{
821 use ArrayParsingError::*;
822
823 #[derive(Clone, Debug, Default)]
824 struct Dimension {
825 length: Option<usize>,
828 staged_element: bool,
832 committed_element_count: usize,
835 }
836
837 #[derive(Clone, Debug, Default)]
838 struct ArrayBuilder<'a> {
839 current_command_char: char,
841 dimensions: Vec<Dimension>,
844 current_dim: usize,
846 sealed: bool,
848 elements: Vec<Option<Cow<'a, str>>>,
852 }
853
854 impl<'a> ArrayBuilder<'a> {
855 fn build(
856 s: &'a str,
857 ) -> Result<(Vec<Option<Cow<'a, str>>>, Vec<ArrayDimension>), ArrayParsingError> {
858 let buf = &mut LexBuf::new(s);
859
860 if buf.consume('[') {
862 Err(DimsUnsupported)?;
863 }
864
865 buf.take_while(|ch| ch.is_ascii_whitespace());
866
867 if !buf.consume('{') {
868 Err(OpeningBraceMissing)?;
869 }
870
871 let mut dimensions = 1;
872
873 loop {
874 buf.take_while(|ch| ch.is_ascii_whitespace());
875 if buf.consume('{') {
876 dimensions += 1;
877 } else {
878 break;
879 }
880 }
881
882 let mut builder = ArrayBuilder {
883 current_command_char: '{',
884 dimensions: vec![Dimension::default(); dimensions],
885 current_dim: dimensions - 1,
888 sealed: false,
889 elements: vec![],
890 };
891
892 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
893 let is_end_of_literal = |c| matches!(c, ',' | '}');
894
895 loop {
896 buf.take_while(|ch| ch.is_ascii_whitespace());
897
898 match buf.next() {
900 None if builder.sealed => {
901 break;
902 }
903 None => Err(EarlyTerm)?,
904 Some(_) if builder.sealed => Err(Junk)?,
905 Some(c) => builder.current_command_char = c,
906 }
907
908 match builder.current_command_char {
910 '{' => builder.enter_dim()?,
911 '}' => builder.exit_dim()?,
912 ',' => builder.commit_element(true)?,
913 c => {
914 buf.prev();
915 let s = match c {
916 '"' => Some(lex_quoted_element(buf)?),
917 _ => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
918 };
919 builder.insert_element(s)?;
920 }
921 }
922 }
923
924 if builder.elements.is_empty() {
925 return Ok((vec![], vec![]));
928 }
929
930 let dims = builder
931 .dimensions
932 .into_iter()
933 .map(|dim| ArrayDimension {
934 length: dim
935 .length
936 .expect("every dimension must have its length discovered"),
937 lower_bound: 1,
938 })
939 .collect();
940
941 Ok((builder.elements, dims))
942 }
943
944 fn enter_dim(&mut self) -> Result<(), ArrayParsingError> {
946 let d = &mut self.dimensions[self.current_dim];
947 if d.staged_element {
949 return Err(UnexpectedChar(self.current_command_char));
950 }
951
952 self.current_dim += 1;
953
954 if self.current_dim >= self.dimensions.len() {
956 return Err(NonRectilinearDims);
957 }
958
959 Ok(())
960 }
961
962 fn insert_element(&mut self, s: Option<Cow<'a, str>>) -> Result<(), ArrayParsingError> {
964 if self.current_dim != self.dimensions.len() - 1 {
967 return Err(UnexpectedElement);
968 }
969
970 self.stage_element()?;
971
972 self.elements.push(s);
973
974 Ok(())
975 }
976
977 fn stage_element(&mut self) -> Result<(), ArrayParsingError> {
981 let d = &mut self.dimensions[self.current_dim];
982 if d.staged_element {
985 return Err(UnexpectedElement);
986 }
987 d.staged_element = true;
988 Ok(())
989 }
990
991 fn commit_element(&mut self, require_staged: bool) -> Result<(), ArrayParsingError> {
995 let d = &mut self.dimensions[self.current_dim];
996 if !d.staged_element {
997 return if require_staged || d.committed_element_count > 0 {
1001 Err(UnexpectedChar(self.current_command_char))
1002 } else {
1003 Ok(())
1007 };
1008 }
1009 d.staged_element = false;
1010 d.committed_element_count += 1;
1011
1012 Ok(())
1013 }
1014
1015 fn exit_dim(&mut self) -> Result<(), ArrayParsingError> {
1021 self.commit_element(false)?;
1023
1024 let d = &mut self.dimensions[self.current_dim];
1025
1026 match d.length {
1028 None => d.length = Some(d.committed_element_count),
1029 Some(l) => {
1030 if l != d.committed_element_count {
1031 return Err(NonRectilinearDims);
1032 }
1033 }
1034 }
1035
1036 d.committed_element_count = 0;
1038
1039 if self.current_dim == 0 {
1042 self.sealed = true;
1043 } else {
1044 self.current_dim -= 1;
1045 self.stage_element()?;
1047 }
1048
1049 Ok(())
1050 }
1051 }
1052
1053 let (raw_elems, dims) = ArrayBuilder::build(s)?;
1054
1055 let mut elems = Vec::with_capacity(raw_elems.len());
1056
1057 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1058
1059 for elem in raw_elems.into_iter() {
1060 elems.push(match elem {
1061 Some(elem) => generated(elem)?,
1062 None => make_null(),
1063 });
1064 }
1065
1066 Ok((elems, dims))
1067}
1068
1069pub fn parse_list<'a, T, E>(
1070 s: &'a str,
1071 is_element_type_list: bool,
1072 make_null: impl FnMut() -> T,
1073 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1074) -> Result<Vec<T>, ParseError>
1075where
1076 E: ToString,
1077{
1078 parse_list_inner(s, is_element_type_list, make_null, gen_elem)
1079 .map_err(|details| ParseError::invalid_input_syntax("list", s).with_details(details))
1080}
1081
1082fn parse_list_inner<'a, T, E>(
1085 s: &'a str,
1086 is_element_type_list: bool,
1087 mut make_null: impl FnMut() -> T,
1088 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1089) -> Result<Vec<T>, String>
1090where
1091 E: ToString,
1092{
1093 let mut elems = vec![];
1094 let buf = &mut LexBuf::new(s);
1095
1096 if !buf.consume('{') {
1098 bail!(
1099 "expected '{{', found {}",
1100 match buf.next() {
1101 Some(c) => format!("{}", c),
1102 None => "empty string".to_string(),
1103 }
1104 )
1105 }
1106
1107 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1109 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '\\' | '"');
1110 let is_end_of_literal = |c| matches!(c, ',' | '}');
1111
1112 loop {
1114 buf.take_while(|ch| ch.is_ascii_whitespace());
1115 match buf.next() {
1117 Some('}') => {
1118 break;
1119 }
1120 _ if elems.len() == 0 => {
1121 buf.prev();
1122 }
1123 Some(',') => {}
1124 Some(c) => bail!("expected ',' or '}}', got '{}'", c),
1125 None => bail!("unexpected end of input"),
1126 }
1127
1128 buf.take_while(|ch| ch.is_ascii_whitespace());
1129 let elem = match buf.peek() {
1131 Some('"') => generated(lex_quoted_element(buf)?)?,
1132 Some('{') => {
1133 if !is_element_type_list {
1134 bail!(
1135 "unescaped '{{' at beginning of element; perhaps you \
1136 want a nested list, e.g. '{{a}}'::text list list"
1137 )
1138 }
1139 generated(lex_embedded_element(buf)?)?
1140 }
1141 Some(_) => match lex_unquoted_element(buf, is_special_char, is_end_of_literal)? {
1142 Some(elem) => generated(elem)?,
1143 None => make_null(),
1144 },
1145 None => bail!("unexpected end of input"),
1146 };
1147 elems.push(elem);
1148 }
1149
1150 buf.take_while(|ch| ch.is_ascii_whitespace());
1151 if let Some(c) = buf.next() {
1152 bail!(
1153 "malformed array literal; contains '{}' after terminal '}}'",
1154 c
1155 )
1156 }
1157
1158 Ok(elems)
1159}
1160
1161pub fn parse_legacy_vector<'a, T, E>(
1162 s: &'a str,
1163 gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1164) -> Result<Vec<T>, ParseError>
1165where
1166 E: ToString,
1167{
1168 parse_legacy_vector_inner(s, gen_elem)
1169 .map_err(|details| ParseError::invalid_input_syntax("int2vector", s).with_details(details))
1170}
1171
1172pub fn parse_legacy_vector_inner<'a, T, E>(
1177 s: &'a str,
1178 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<T, E>,
1179) -> Result<Vec<T>, String>
1180where
1181 E: ToString,
1182{
1183 let mut elems = vec![];
1184 let buf = &mut LexBuf::new(s);
1185
1186 let mut generated = |elem| gen_elem(elem).map_err(|e| e.to_string());
1187
1188 loop {
1189 buf.take_while(|ch| ch.is_ascii_whitespace());
1190 match buf.peek() {
1191 Some(_) => {
1192 let elem = buf.take_while(|ch| !ch.is_ascii_whitespace());
1193 elems.push(generated(elem.into())?);
1194 }
1195 None => break,
1196 }
1197 }
1198
1199 Ok(elems)
1200}
1201
1202fn lex_quoted_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1203 assert!(buf.consume('"'));
1204 let s = buf.take_while(|ch| !matches!(ch, '"' | '\\'));
1205
1206 if let Some('"') = buf.peek() {
1208 buf.next();
1209 return Ok(s.into());
1210 }
1211
1212 let mut s = s.to_string();
1213 loop {
1214 match buf.next() {
1215 Some('\\') => match buf.next() {
1216 Some(c) => s.push(c),
1217 None => bail!("unterminated quoted string"),
1218 },
1219 Some('"') => break,
1220 Some(c) => s.push(c),
1221 None => bail!("unterminated quoted string"),
1222 }
1223 }
1224 Ok(s.into())
1225}
1226
1227fn lex_embedded_element<'a>(buf: &mut LexBuf<'a>) -> Result<Cow<'a, str>, String> {
1228 let pos = buf.pos();
1229 assert!(matches!(buf.next(), Some('{')));
1230 let mut depth = 1;
1231 let mut in_escape = false;
1232 while depth > 0 {
1233 match buf.next() {
1234 Some('\\') => {
1235 buf.next(); }
1237 Some('"') => in_escape = !in_escape, Some('{') if !in_escape => depth += 1,
1239 Some('}') if !in_escape => depth -= 1,
1240 Some(_) => (),
1241 None => bail!("unterminated embedded element"),
1242 }
1243 }
1244 let s = &buf.inner()[pos..buf.pos()];
1245 Ok(Cow::Borrowed(s))
1246}
1247
1248fn lex_unquoted_element<'a>(
1250 buf: &mut LexBuf<'a>,
1251 is_special_char: impl Fn(char) -> bool,
1252 is_end_of_literal: impl Fn(char) -> bool,
1253) -> Result<Option<Cow<'a, str>>, String> {
1254 assert!(!buf.peek().unwrap().is_ascii_whitespace());
1256
1257 let s = buf.take_while(|ch| !is_special_char(ch) && !ch.is_ascii_whitespace());
1258
1259 match buf.peek() {
1261 Some(',') | Some('}') if !s.is_empty() => {
1262 return Ok(if s.to_uppercase() == "NULL" {
1263 None
1264 } else {
1265 Some(s.into())
1266 });
1267 }
1268 _ => {}
1269 }
1270
1271 let mut escaped_char = false;
1275
1276 let mut s = s.to_string();
1277 let mut trimmed_len = s.len();
1280 loop {
1281 match buf.next() {
1282 Some('\\') => match buf.next() {
1283 Some(c) => {
1284 escaped_char = true;
1285 s.push(c);
1286 trimmed_len = s.len();
1287 }
1288 None => return Err("unterminated element".into()),
1289 },
1290 Some(c) if is_end_of_literal(c) => {
1291 if s.is_empty() {
1294 bail!("malformed literal; missing element")
1295 }
1296 buf.prev();
1297 break;
1298 }
1299 Some(c) if is_special_char(c) => {
1300 bail!("malformed literal; must escape special character '{}'", c)
1301 }
1302 Some(c) => {
1303 s.push(c);
1304 if !c.is_ascii_whitespace() {
1305 trimmed_len = s.len();
1306 }
1307 }
1308 None => bail!("unterminated element"),
1309 }
1310 }
1311 s.truncate(trimmed_len);
1312 Ok(if s.to_uppercase() == "NULL" && !escaped_char {
1313 None
1314 } else {
1315 Some(Cow::Owned(s))
1316 })
1317}
1318
1319pub fn parse_map<'a, V, E>(
1320 s: &'a str,
1321 is_value_type_map: bool,
1322 gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1323) -> Result<BTreeMap<String, V>, ParseError>
1324where
1325 E: ToString,
1326{
1327 parse_map_inner(s, is_value_type_map, gen_elem)
1328 .map_err(|details| ParseError::invalid_input_syntax("map", s).with_details(details))
1329}
1330
1331fn parse_map_inner<'a, V, E>(
1332 s: &'a str,
1333 is_value_type_map: bool,
1334 mut gen_elem: impl FnMut(Option<Cow<'a, str>>) -> Result<V, E>,
1335) -> Result<BTreeMap<String, V>, String>
1336where
1337 E: ToString,
1338{
1339 let mut map = BTreeMap::new();
1340 let buf = &mut LexBuf::new(s);
1341
1342 if !buf.consume('{') {
1344 bail!(
1345 "expected '{{', found {}",
1346 match buf.next() {
1347 Some(c) => format!("{}", c),
1348 None => "empty string".to_string(),
1349 }
1350 )
1351 }
1352
1353 let gen_key = |key: Option<Cow<'a, str>>| -> Result<String, String> {
1355 match key {
1356 Some(Cow::Owned(s)) => Ok(s),
1357 Some(Cow::Borrowed(s)) => Ok(s.to_owned()),
1358 None => Err("expected key".to_owned()),
1359 }
1360 };
1361 let mut gen_value = |elem| gen_elem(elem).map_err(|e| e.to_string());
1362 let is_special_char = |c| matches!(c, '{' | '}' | ',' | '"' | '=' | '>' | '\\');
1363 let is_end_of_literal = |c| matches!(c, ',' | '}' | '=');
1364
1365 loop {
1366 buf.take_while(|ch| ch.is_ascii_whitespace());
1368 match buf.next() {
1369 Some('}') => break,
1370 _ if map.len() == 0 => {
1371 buf.prev();
1372 }
1373 Some(',') => {}
1374 Some(c) => bail!("expected ',' or end of input, got '{}'", c),
1375 None => bail!("unexpected end of input"),
1376 }
1377
1378 buf.take_while(|ch| ch.is_ascii_whitespace());
1380 let key = match buf.peek() {
1381 Some('"') => Some(lex_quoted_element(buf)?),
1382 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1383 None => bail!("unexpected end of input"),
1384 };
1385 let key = gen_key(key)?;
1386
1387 buf.take_while(|ch| ch.is_ascii_whitespace());
1389 if !buf.consume('=') || !buf.consume('>') {
1390 bail!("expected =>")
1391 }
1392
1393 buf.take_while(|ch| ch.is_ascii_whitespace());
1395 let value = match buf.peek() {
1396 Some('"') => Some(lex_quoted_element(buf)?),
1397 Some('{') => {
1398 if !is_value_type_map {
1399 bail!(
1400 "unescaped '{{' at beginning of value; perhaps you \
1401 want a nested map, e.g. '{{a=>{{a=>1}}}}'::map[text=>map[text=>int]]"
1402 )
1403 }
1404 Some(lex_embedded_element(buf)?)
1405 }
1406 Some(_) => lex_unquoted_element(buf, is_special_char, is_end_of_literal)?,
1407 None => bail!("unexpected end of input"),
1408 };
1409 let value = gen_value(value)?;
1410
1411 map.insert(key, value);
1413 }
1414 Ok(map)
1415}
1416
1417pub fn format_map<F, T, E>(
1418 buf: &mut F,
1419 elems: impl IntoIterator<Item = (impl AsRef<str>, T)>,
1420 mut format_elem: impl FnMut(MapValueWriter<F>, T) -> Result<Nestable, E>,
1421) -> Result<Nestable, E>
1422where
1423 F: FormatBuffer,
1424{
1425 buf.write_char('{');
1426 let mut elems = elems.into_iter().peekable();
1427 while let Some((key, value)) = elems.next() {
1428 let key_start = buf.len();
1431 buf.write_str(key.as_ref());
1432 escape_elem::<_, MapElementEscaper>(buf, key_start);
1433
1434 buf.write_str("=>");
1435
1436 let value_start = buf.len();
1437 if let Nestable::MayNeedEscaping = format_elem(MapValueWriter(buf), value)? {
1438 escape_elem::<_, MapElementEscaper>(buf, value_start);
1439 }
1440
1441 if elems.peek().is_some() {
1442 buf.write_char(',');
1443 }
1444 }
1445 buf.write_char('}');
1446 Ok(Nestable::Yes)
1447}
1448
1449pub fn parse_range<'a, V, E>(
1450 s: &'a str,
1451 gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1452) -> Result<Range<V>, ParseError>
1453where
1454 E: ToString,
1455{
1456 Ok(Range {
1457 inner: parse_range_inner(s, gen_elem).map_err(|details| {
1458 ParseError::invalid_input_syntax("range", s).with_details(details)
1459 })?,
1460 })
1461}
1462
1463fn parse_range_inner<'a, V, E>(
1464 s: &'a str,
1465 mut gen_elem: impl FnMut(Cow<'a, str>) -> Result<V, E>,
1466) -> Result<Option<RangeInner<V>>, String>
1467where
1468 E: ToString,
1469{
1470 let buf = &mut LexBuf::new(s);
1471
1472 buf.take_while(|ch| ch.is_ascii_whitespace());
1473
1474 if buf.consume_str("empty") {
1475 buf.take_while(|ch| ch.is_ascii_whitespace());
1476 if buf.next().is_none() {
1477 return Ok(None);
1478 } else {
1479 bail!("Junk after \"empty\" key word.")
1480 }
1481 }
1482
1483 let lower_inclusive = match buf.next() {
1484 Some('[') => true,
1485 Some('(') => false,
1486 _ => bail!("Missing left parenthesis or bracket."),
1487 };
1488
1489 let lower_bound = match buf.peek() {
1490 Some(',') => None,
1491 Some(_) => {
1492 let v = buf.take_while(|c| !matches!(c, ','));
1493 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1494 Some(v)
1495 }
1496 None => bail!("Unexpected end of input."),
1497 };
1498
1499 buf.take_while(|ch| ch.is_ascii_whitespace());
1500
1501 if buf.next() != Some(',') {
1502 bail!("Missing comma after lower bound.")
1503 }
1504
1505 let upper_bound = match buf.peek() {
1506 Some(']' | ')') => None,
1507 Some(_) => {
1508 let v = buf.take_while(|c| !matches!(c, ')' | ']'));
1509 let v = gen_elem(Cow::from(v)).map_err(|e| e.to_string())?;
1510 Some(v)
1511 }
1512 None => bail!("Unexpected end of input."),
1513 };
1514
1515 let upper_inclusive = match buf.next() {
1516 Some(']') => true,
1517 Some(')') => false,
1518 _ => bail!("Missing left parenthesis or bracket."),
1519 };
1520
1521 buf.take_while(|ch| ch.is_ascii_whitespace());
1522
1523 if buf.next().is_some() {
1524 bail!("Junk after right parenthesis or bracket.")
1525 }
1526
1527 let range = Some(RangeInner {
1528 lower: RangeBound {
1529 inclusive: lower_inclusive,
1530 bound: lower_bound,
1531 },
1532 upper: RangeBound {
1533 inclusive: upper_inclusive,
1534 bound: upper_bound,
1535 },
1536 });
1537
1538 Ok(range)
1539}
1540
1541pub fn format_range<F, V, E>(
1543 buf: &mut F,
1544 r: &Range<V>,
1545 mut format_elem: impl FnMut(RangeElementWriter<F>, Option<&V>) -> Result<Nestable, E>,
1546) -> Result<Nestable, E>
1547where
1548 F: FormatBuffer,
1549{
1550 let range = match &r.inner {
1551 None => {
1552 buf.write_str("empty");
1553 return Ok(Nestable::MayNeedEscaping);
1554 }
1555 Some(i) => i,
1556 };
1557
1558 if range.lower.inclusive {
1559 buf.write_char('[');
1560 } else {
1561 buf.write_char('(');
1562 }
1563
1564 let start = buf.len();
1565 if let Nestable::MayNeedEscaping =
1566 format_elem(RangeElementWriter(buf), range.lower.bound.as_ref())?
1567 {
1568 escape_elem::<_, ListElementEscaper>(buf, start);
1569 }
1570
1571 buf.write_char(',');
1572
1573 let start = buf.len();
1574 if let Nestable::MayNeedEscaping =
1575 format_elem(RangeElementWriter(buf), range.upper.bound.as_ref())?
1576 {
1577 escape_elem::<_, ListElementEscaper>(buf, start);
1578 }
1579
1580 if range.upper.inclusive {
1581 buf.write_char(']');
1582 } else {
1583 buf.write_char(')');
1584 }
1585
1586 Ok(Nestable::MayNeedEscaping)
1587}
1588
1589#[derive(Debug)]
1591pub struct RangeElementWriter<'a, F>(&'a mut F);
1592
1593impl<'a, F> RangeElementWriter<'a, F>
1594where
1595 F: FormatBuffer,
1596{
1597 pub fn write_null(self) -> Nestable {
1599 Nestable::Yes
1602 }
1603
1604 pub fn nonnull_buffer(self) -> &'a mut F {
1607 self.0
1608 }
1609}
1610
1611pub fn format_array<F, T, E>(
1612 buf: &mut F,
1613 dims: &[ArrayDimension],
1614 elems: impl IntoIterator<Item = T>,
1615 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1616) -> Result<Nestable, E>
1617where
1618 F: FormatBuffer,
1619{
1620 if dims.iter().any(|dim| dim.lower_bound != 1) {
1621 for d in dims.iter() {
1622 let (lower, upper) = d.dimension_bounds();
1623 write!(buf, "[{}:{}]", lower, upper);
1624 }
1625 buf.write_char('=');
1626 }
1627
1628 format_array_inner(buf, dims, &mut elems.into_iter(), &mut format_elem)?;
1629 Ok(Nestable::Yes)
1630}
1631
1632pub fn format_array_inner<F, T, E>(
1633 buf: &mut F,
1634 dims: &[ArrayDimension],
1635 elems: &mut impl Iterator<Item = T>,
1636 format_elem: &mut impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1637) -> Result<(), E>
1638where
1639 F: FormatBuffer,
1640{
1641 if dims.is_empty() {
1642 buf.write_str("{}");
1643 return Ok(());
1644 }
1645
1646 buf.write_char('{');
1647 for j in 0..dims[0].length {
1648 if j > 0 {
1649 buf.write_char(',');
1650 }
1651 if dims.len() == 1 {
1652 let start = buf.len();
1653 let elem = elems.next().unwrap();
1654 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1655 escape_elem::<_, ListElementEscaper>(buf, start);
1656 }
1657 } else {
1658 format_array_inner(buf, &dims[1..], elems, format_elem)?;
1659 }
1660 }
1661 buf.write_char('}');
1662
1663 Ok(())
1664}
1665
1666pub fn format_legacy_vector<F, T, E>(
1667 buf: &mut F,
1668 elems: impl IntoIterator<Item = T>,
1669 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1670) -> Result<Nestable, E>
1671where
1672 F: FormatBuffer,
1673{
1674 format_elems(buf, elems, format_elem, ' ')?;
1675 Ok(Nestable::MayNeedEscaping)
1676}
1677
1678pub fn format_list<F, T, E>(
1679 buf: &mut F,
1680 elems: impl IntoIterator<Item = T>,
1681 format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1682) -> Result<Nestable, E>
1683where
1684 F: FormatBuffer,
1685{
1686 buf.write_char('{');
1687 format_elems(buf, elems, format_elem, ',')?;
1688 buf.write_char('}');
1689 Ok(Nestable::Yes)
1690}
1691
1692pub fn format_elems<F, T, E>(
1694 buf: &mut F,
1695 elems: impl IntoIterator<Item = T>,
1696 mut format_elem: impl FnMut(ListElementWriter<F>, T) -> Result<Nestable, E>,
1697 sep: char,
1698) -> Result<(), E>
1699where
1700 F: FormatBuffer,
1701{
1702 let mut elems = elems.into_iter().peekable();
1703 while let Some(elem) = elems.next() {
1704 let start = buf.len();
1705 if let Nestable::MayNeedEscaping = format_elem(ListElementWriter(buf), elem)? {
1706 escape_elem::<_, ListElementEscaper>(buf, start);
1707 }
1708 if elems.peek().is_some() {
1709 buf.write_char(sep)
1710 }
1711 }
1712 Ok(())
1713}
1714
1715pub fn format_mz_acl_item<F>(buf: &mut F, mz_acl_item: MzAclItem) -> Nestable
1717where
1718 F: FormatBuffer,
1719{
1720 write!(buf, "{mz_acl_item}");
1721 Nestable::Yes
1722}
1723
1724pub fn parse_mz_acl_item(s: &str) -> Result<MzAclItem, ParseError> {
1726 s.trim()
1727 .parse()
1728 .map_err(|e| ParseError::invalid_input_syntax("mz_aclitem", s).with_details(e))
1729}
1730
1731pub fn format_acl_item<F>(buf: &mut F, acl_item: AclItem) -> Nestable
1733where
1734 F: FormatBuffer,
1735{
1736 write!(buf, "{acl_item}");
1737 Nestable::Yes
1738}
1739
1740pub fn parse_acl_item(s: &str) -> Result<AclItem, ParseError> {
1742 s.trim()
1743 .parse()
1744 .map_err(|e| ParseError::invalid_input_syntax("aclitem", s).with_details(e))
1745}
1746
1747pub trait ElementEscaper {
1748 fn needs_escaping(elem: &[u8]) -> bool;
1749 fn escape_char(c: u8) -> u8;
1750}
1751
1752struct ListElementEscaper;
1753
1754impl ElementEscaper for ListElementEscaper {
1755 fn needs_escaping(elem: &[u8]) -> bool {
1756 elem.is_empty()
1757 || elem == b"NULL"
1758 || elem
1759 .iter()
1760 .any(|c| matches!(c, b'{' | b'}' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1761 }
1762
1763 fn escape_char(_: u8) -> u8 {
1764 b'\\'
1765 }
1766}
1767
1768struct MapElementEscaper;
1769
1770impl ElementEscaper for MapElementEscaper {
1771 fn needs_escaping(elem: &[u8]) -> bool {
1772 elem.is_empty()
1773 || elem == b"NULL"
1774 || elem.iter().any(|c| {
1775 matches!(c, b'{' | b'}' | b',' | b'"' | b'=' | b'>' | b'\\')
1776 || c.is_ascii_whitespace()
1777 })
1778 }
1779
1780 fn escape_char(_: u8) -> u8 {
1781 b'\\'
1782 }
1783}
1784
1785struct RecordElementEscaper;
1786
1787impl ElementEscaper for RecordElementEscaper {
1788 fn needs_escaping(elem: &[u8]) -> bool {
1789 elem.is_empty()
1790 || elem
1791 .iter()
1792 .any(|c| matches!(c, b'(' | b')' | b',' | b'"' | b'\\') || c.is_ascii_whitespace())
1793 }
1794
1795 fn escape_char(c: u8) -> u8 {
1796 if c == b'"' { b'"' } else { b'\\' }
1797 }
1798}
1799
1800fn escape_elem<F, E>(buf: &mut F, start: usize)
1810where
1811 F: FormatBuffer,
1812 E: ElementEscaper,
1813{
1814 let elem = &buf.as_ref()[start..];
1815 if !E::needs_escaping(elem) {
1816 return;
1817 }
1818
1819 let extras = 2 + elem.iter().filter(|b| matches!(b, b'"' | b'\\')).count();
1822 let orig_end = buf.len();
1823 let new_end = buf.len() + extras;
1824
1825 for _ in 0..extras {
1832 buf.write_char('\0');
1833 }
1834
1835 let elem = unsafe { buf.as_bytes_mut() };
1838
1839 let mut wi = new_end - 1;
1843 elem[wi] = b'"';
1844 wi -= 1;
1845 for ri in (start..orig_end).rev() {
1846 elem[wi] = elem[ri];
1847 wi -= 1;
1848 if let b'\\' | b'"' = elem[ri] {
1849 elem[wi] = E::escape_char(elem[ri]);
1850 wi -= 1;
1851 }
1852 }
1853 elem[wi] = b'"';
1854
1855 assert!(wi == start);
1856}
1857
1858#[derive(Debug)]
1860pub struct ListElementWriter<'a, F>(&'a mut F);
1861
1862impl<'a, F> ListElementWriter<'a, F>
1863where
1864 F: FormatBuffer,
1865{
1866 pub fn write_null(self) -> Nestable {
1868 self.0.write_str("NULL");
1869 Nestable::Yes
1870 }
1871
1872 pub fn nonnull_buffer(self) -> &'a mut F {
1875 self.0
1876 }
1877}
1878
1879#[derive(Debug)]
1881pub struct MapValueWriter<'a, F>(&'a mut F);
1882
1883impl<'a, F> MapValueWriter<'a, F>
1884where
1885 F: FormatBuffer,
1886{
1887 pub fn write_null(self) -> Nestable {
1889 self.0.write_str("NULL");
1890 Nestable::Yes
1891 }
1892
1893 pub fn nonnull_buffer(self) -> &'a mut F {
1896 self.0
1897 }
1898}
1899
1900pub fn format_record<F, T, E>(
1901 buf: &mut F,
1902 elems: impl IntoIterator<Item = T>,
1903 mut format_elem: impl FnMut(RecordElementWriter<F>, T) -> Result<Nestable, E>,
1904) -> Result<Nestable, E>
1905where
1906 F: FormatBuffer,
1907{
1908 buf.write_char('(');
1909 let mut elems = elems.into_iter().peekable();
1910 while let Some(elem) = elems.next() {
1911 let start = buf.len();
1912 if let Nestable::MayNeedEscaping = format_elem(RecordElementWriter(buf), elem)? {
1913 escape_elem::<_, RecordElementEscaper>(buf, start);
1914 }
1915 if elems.peek().is_some() {
1916 buf.write_char(',')
1917 }
1918 }
1919 buf.write_char(')');
1920 Ok(Nestable::MayNeedEscaping)
1921}
1922
1923#[derive(Debug)]
1925pub struct RecordElementWriter<'a, F>(&'a mut F);
1926
1927impl<'a, F> RecordElementWriter<'a, F>
1928where
1929 F: FormatBuffer,
1930{
1931 pub fn write_null(self) -> Nestable {
1933 Nestable::Yes
1934 }
1935
1936 pub fn nonnull_buffer(self) -> &'a mut F {
1939 self.0
1940 }
1941}
1942
1943#[derive(
1945 Ord,
1946 PartialOrd,
1947 Clone,
1948 Debug,
1949 Eq,
1950 PartialEq,
1951 Serialize,
1952 Deserialize,
1953 Hash,
1954 MzReflect
1955)]
1956#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1957pub struct ParseError {
1958 pub kind: ParseErrorKind,
1959 pub type_name: Box<str>,
1960 pub input: Box<str>,
1961 pub details: Option<Box<str>>,
1962}
1963
1964#[derive(
1965 Ord,
1966 PartialOrd,
1967 Clone,
1968 Copy,
1969 Debug,
1970 Eq,
1971 PartialEq,
1972 Serialize,
1973 Deserialize,
1974 Hash,
1975 MzReflect
1976)]
1977#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
1978pub enum ParseErrorKind {
1979 OutOfRange,
1980 InvalidInputSyntax,
1981}
1982
1983impl ParseError {
1984 fn new<S>(kind: ParseErrorKind, type_name: &'static str, input: S) -> ParseError
1988 where
1989 S: Into<Box<str>>,
1990 {
1991 ParseError {
1992 kind,
1993 type_name: type_name.into(),
1994 input: input.into(),
1995 details: None,
1996 }
1997 }
1998
1999 fn out_of_range<S>(type_name: &'static str, input: S) -> ParseError
2000 where
2001 S: Into<Box<str>>,
2002 {
2003 ParseError::new(ParseErrorKind::OutOfRange, type_name, input)
2004 }
2005
2006 fn invalid_input_syntax<S>(type_name: &'static str, input: S) -> ParseError
2007 where
2008 S: Into<Box<str>>,
2009 {
2010 ParseError::new(ParseErrorKind::InvalidInputSyntax, type_name, input)
2011 }
2012
2013 fn with_details<D>(mut self, details: D) -> ParseError
2014 where
2015 D: fmt::Display,
2016 {
2017 self.details = Some(details.to_string().into());
2018 self
2019 }
2020}
2021
2022impl fmt::Display for ParseError {
2023 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2024 match self.kind {
2025 ParseErrorKind::OutOfRange => {
2026 write!(
2027 f,
2028 "{} is out of range for type {}",
2029 self.input.quoted(),
2030 self.type_name
2031 )?;
2032 if let Some(details) = &self.details {
2033 write!(f, ": {}", details)?;
2034 }
2035 Ok(())
2036 }
2037 ParseErrorKind::InvalidInputSyntax => {
2038 write!(f, "invalid input syntax for type {}: ", self.type_name)?;
2039 if let Some(details) = &self.details {
2040 write!(f, "{}: ", details)?;
2041 }
2042 write!(f, "{}", self.input.quoted())
2043 }
2044 }
2045 }
2046}
2047
2048impl Error for ParseError {}
2049
2050impl RustType<ProtoParseError> for ParseError {
2051 fn into_proto(&self) -> ProtoParseError {
2052 use Kind::*;
2053 use proto_parse_error::*;
2054 let kind = match self.kind {
2055 ParseErrorKind::OutOfRange => OutOfRange(()),
2056 ParseErrorKind::InvalidInputSyntax => InvalidInputSyntax(()),
2057 };
2058 ProtoParseError {
2059 kind: Some(kind),
2060 type_name: self.type_name.into_proto(),
2061 input: self.input.into_proto(),
2062 details: self.details.into_proto(),
2063 }
2064 }
2065
2066 fn from_proto(proto: ProtoParseError) -> Result<Self, TryFromProtoError> {
2067 use proto_parse_error::Kind::*;
2068
2069 if let Some(kind) = proto.kind {
2070 Ok(ParseError {
2071 kind: match kind {
2072 OutOfRange(()) => ParseErrorKind::OutOfRange,
2073 InvalidInputSyntax(()) => ParseErrorKind::InvalidInputSyntax,
2074 },
2075 type_name: proto.type_name.into(),
2076 input: proto.input.into(),
2077 details: proto.details.into_rust()?,
2078 })
2079 } else {
2080 Err(TryFromProtoError::missing_field("ProtoParseError::kind"))
2081 }
2082 }
2083}
2084
2085#[derive(
2086 Ord,
2087 PartialOrd,
2088 Copy,
2089 Clone,
2090 Debug,
2091 Eq,
2092 PartialEq,
2093 Serialize,
2094 Deserialize,
2095 Hash,
2096 MzReflect
2097)]
2098#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
2099pub enum ParseHexError {
2100 InvalidHexDigit(char),
2101 OddLength,
2102}
2103impl Error for ParseHexError {}
2104
2105impl fmt::Display for ParseHexError {
2106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2107 match self {
2108 ParseHexError::InvalidHexDigit(c) => {
2109 write!(f, "invalid hexadecimal digit: \"{}\"", c.escape_default())
2110 }
2111 ParseHexError::OddLength => {
2112 f.write_str("invalid hexadecimal data: odd number of digits")
2113 }
2114 }
2115 }
2116}
2117
2118impl RustType<ProtoParseHexError> for ParseHexError {
2119 fn into_proto(&self) -> ProtoParseHexError {
2120 use Kind::*;
2121 use proto_parse_hex_error::*;
2122 let kind = match self {
2123 ParseHexError::InvalidHexDigit(v) => InvalidHexDigit(v.into_proto()),
2124 ParseHexError::OddLength => OddLength(()),
2125 };
2126 ProtoParseHexError { kind: Some(kind) }
2127 }
2128
2129 fn from_proto(error: ProtoParseHexError) -> Result<Self, TryFromProtoError> {
2130 use proto_parse_hex_error::Kind::*;
2131 match error.kind {
2132 Some(kind) => match kind {
2133 InvalidHexDigit(v) => Ok(ParseHexError::InvalidHexDigit(char::from_proto(v)?)),
2134 OddLength(()) => Ok(ParseHexError::OddLength),
2135 },
2136 None => Err(TryFromProtoError::missing_field(
2137 "`ProtoParseHexError::kind`",
2138 )),
2139 }
2140 }
2141}
2142
2143#[cfg(test)]
2144mod tests {
2145 use mz_ore::assert_ok;
2146 use mz_proto::protobuf_roundtrip;
2147 use proptest::prelude::*;
2148
2149 use super::*;
2150
2151 proptest! {
2152 #[mz_ore::test]
2153 #[cfg_attr(miri, ignore)] fn parse_error_protobuf_roundtrip(expect in any::<ParseError>()) {
2155 let actual = protobuf_roundtrip::<_, ProtoParseError>(&expect);
2156 assert_ok!(actual);
2157 assert_eq!(actual.unwrap(), expect);
2158 }
2159 }
2160
2161 proptest! {
2162 #[mz_ore::test]
2163 #[cfg_attr(miri, ignore)] fn parse_hex_error_protobuf_roundtrip(expect in any::<ParseHexError>()) {
2165 let actual = protobuf_roundtrip::<_, ProtoParseHexError>(&expect);
2166 assert_ok!(actual);
2167 assert_eq!(actual.unwrap(), expect);
2168 }
2169 }
2170
2171 #[mz_ore::test]
2172 fn test_format_nanos_to_micros() {
2173 let cases: Vec<(u32, &str)> = vec![
2174 (0, ""),
2175 (1, ""),
2176 (499, ""),
2177 (500, ".000001"),
2178 (500_000, ".0005"),
2179 (5_000_000, ".005"),
2180 (1_999_999_999, ".2"),
2183 ];
2184 for (nanos, expect) in cases {
2185 let mut buf = String::new();
2186 format_nanos_to_micros(&mut buf, nanos);
2187 assert_eq!(&buf, expect);
2188 }
2189 }
2190
2191 #[mz_ore::test]
2192 fn test_parse_pg_legacy_name() {
2193 let s = "hello world";
2194 assert_eq!(s, parse_pg_legacy_name(s));
2195
2196 let s = "x".repeat(63);
2197 assert_eq!(s, parse_pg_legacy_name(&s));
2198
2199 let s = "x".repeat(64);
2200 assert_eq!("x".repeat(63), parse_pg_legacy_name(&s));
2201
2202 let s = format!("{}{}", "x".repeat(61), "א");
2204 assert_eq!(s, parse_pg_legacy_name(&s));
2205
2206 let s = format!("{}{}", "x".repeat(62), "א");
2207 assert_eq!("x".repeat(62), parse_pg_legacy_name(&s));
2208 }
2209
2210 #[mz_ore::test]
2211 fn test_parse_uuid_rejects_non_uuid_input() {
2212 for s in ["", "{}", "{\0}", "{", "}", "xyz", "{ }", "\u{0}\u{0}\u{0}"] {
2217 assert!(parse_uuid(s).is_err(), "parse_uuid({s:?}) should be Err");
2218 }
2219 assert!(parse_uuid("00000000-0000-0000-0000-000000000000").is_ok());
2221 assert!(parse_uuid("{00000000-0000-0000-0000-000000000000}").is_ok());
2222 assert!(parse_uuid("00000000000000000000000000000000").is_ok());
2223 }
2224}