1use rupg_common::SqlState;
6
7use crate::binary::Recv;
8use crate::error::TypeError;
9use crate::jsonb::escape;
10use crate::number::int4_in;
11use crate::numeric::{Numeric, numeric_in, numeric_out};
12use crate::tsquery::too_deep;
13
14pub const JSONPATH_REGEX_ICASE: u8 = 0x01;
16
17pub const JSONPATH_REGEX_DOTALL: u8 = 0x02;
19
20pub const JSONPATH_REGEX_MLINE: u8 = 0x04;
22
23pub const JSONPATH_REGEX_WSPACE: u8 = 0x08;
25
26pub const JSONPATH_REGEX_QUOTE: u8 = 0x10;
28
29const REG_ADVANCED: u32 = 0o3;
31const REG_QUOTE: u32 = 0o4;
32const REG_ICASE: u32 = 0o10;
33const REG_NLSTOP: u32 = 0o100;
34const REG_NLANCH: u32 = 0o200;
35
36const MAX_DEPTH: usize = 1000;
38
39pub const JSONPATH_LAST: u32 = u32::MAX;
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum PathOp {
45 And,
46 Or,
47 Not,
48 IsUnknown,
49 Equal,
50 NotEqual,
51 Less,
52 Greater,
53 LessOrEqual,
54 GreaterOrEqual,
55 Add,
56 Sub,
57 Mul,
58 Div,
59 Mod,
60 Plus,
61 Minus,
62 Filter,
63 Exists,
64 StartsWith,
65 Type,
66 Size,
67 Abs,
68 Floor,
69 Ceiling,
70 Double,
71 Datetime,
72 KeyValue,
73 Bigint,
74 Boolean,
75 Date,
76 Decimal,
77 Integer,
78 Number,
79 StringFunc,
80 Time,
81 TimeTz,
82 Timestamp,
83 TimestampTz,
84 Replace,
85 Lower,
86 Upper,
87 Ltrim,
88 Rtrim,
89 Btrim,
90 Initcap,
91 SplitPart,
92}
93
94impl PathOp {
95 #[must_use]
97 pub fn name(self) -> &'static str {
98 match self {
99 PathOp::And => "&&",
100 PathOp::Or => "||",
101 PathOp::Not => "!",
102 PathOp::IsUnknown => "is unknown",
103 PathOp::Equal => "==",
104 PathOp::NotEqual => "!=",
105 PathOp::Less => "<",
106 PathOp::Greater => ">",
107 PathOp::LessOrEqual => "<=",
108 PathOp::GreaterOrEqual => ">=",
109 PathOp::Add | PathOp::Plus => "+",
110 PathOp::Sub | PathOp::Minus => "-",
111 PathOp::Mul => "*",
112 PathOp::Div => "/",
113 PathOp::Mod => "%",
114 PathOp::Filter => "?",
115 PathOp::Exists => "exists",
116 PathOp::StartsWith => "starts with",
117 PathOp::Type => "type",
118 PathOp::Size => "size",
119 PathOp::Abs => "abs",
120 PathOp::Floor => "floor",
121 PathOp::Ceiling => "ceiling",
122 PathOp::Double => "double",
123 PathOp::Datetime => "datetime",
124 PathOp::KeyValue => "keyvalue",
125 PathOp::Bigint => "bigint",
126 PathOp::Boolean => "boolean",
127 PathOp::Date => "date",
128 PathOp::Decimal => "decimal",
129 PathOp::Integer => "integer",
130 PathOp::Number => "number",
131 PathOp::StringFunc => "string",
132 PathOp::Time => "time",
133 PathOp::TimeTz => "time_tz",
134 PathOp::Timestamp => "timestamp",
135 PathOp::TimestampTz => "timestamp_tz",
136 PathOp::Replace => "replace",
137 PathOp::Lower => "lower",
138 PathOp::Upper => "upper",
139 PathOp::Ltrim => "ltrim",
140 PathOp::Rtrim => "rtrim",
141 PathOp::Btrim => "btrim",
142 PathOp::Initcap => "initcap",
143 PathOp::SplitPart => "split_part",
144 }
145 }
146
147 fn priority(self) -> u8 {
149 match self {
150 PathOp::Or => 0,
151 PathOp::And => 1,
152 PathOp::Equal
153 | PathOp::NotEqual
154 | PathOp::Less
155 | PathOp::Greater
156 | PathOp::LessOrEqual
157 | PathOp::GreaterOrEqual
158 | PathOp::StartsWith => 2,
159 PathOp::Add | PathOp::Sub => 3,
160 PathOp::Mul | PathOp::Div | PathOp::Mod => 4,
161 PathOp::Plus | PathOp::Minus => 5,
162 _ => 6,
163 }
164 }
165}
166
167#[derive(Clone, Debug, PartialEq)]
169pub enum PathItem {
170 Null,
172 String(String),
174 Numeric(Numeric),
176 Bool(bool),
178 Binary(PathOp, Chain, Chain),
180 Unary(PathOp, Chain),
182 LikeRegex { expr: Chain, pattern: String, flags: u8 },
184 AnyArray,
186 AnyKey,
188 IndexArray(Vec<(Chain, Option<Chain>)>),
190 Any { first: u32, last: u32 },
192 Key(String),
194 Current,
196 Root,
198 Variable(String),
200 Last,
202 Method(PathOp, Vec<PathItem>),
204}
205
206impl PathItem {
207 fn priority(&self) -> u8 {
209 match self {
210 PathItem::Binary(op, ..) | PathItem::Unary(op, _) => op.priority(),
211 _ => 6,
212 }
213 }
214}
215
216pub type Chain = Vec<PathItem>;
218
219#[derive(Clone, Debug, PartialEq)]
221pub struct JsonPath {
222 pub lax: bool,
224 pub expr: Chain,
226}
227
228pub fn jsonpath_regex_flags(flags: u8) -> Result<u32, TypeError> {
234 let mut cflags = REG_ADVANCED;
235 if flags & JSONPATH_REGEX_ICASE != 0 {
236 cflags |= REG_ICASE;
237 }
238 if flags & JSONPATH_REGEX_QUOTE != 0 {
239 cflags &= !REG_ADVANCED;
240 cflags |= REG_QUOTE;
241 } else {
242 if flags & JSONPATH_REGEX_DOTALL == 0 {
243 cflags |= REG_NLSTOP;
244 }
245 if flags & JSONPATH_REGEX_MLINE != 0 {
246 cflags |= REG_NLANCH;
247 }
248 if flags & JSONPATH_REGEX_WSPACE != 0 {
249 return Err(TypeError::new(
250 SqlState::FEATURE_NOT_SUPPORTED,
251 "XQuery \"x\" flag (expanded regular expressions) is not implemented".to_string(),
252 ));
253 }
254 }
255 Ok(cflags)
256}
257
258pub type RegexCheck<'a> = &'a dyn Fn(&str, u32) -> Result<(), String>;
260
261fn bad_input(detail: &str) -> TypeError {
263 let mut error = TypeError::new(
264 SqlState::INVALID_TEXT_REPRESENTATION,
265 "invalid input syntax for type jsonpath".to_string(),
266 );
267 error.detail = Some(detail.to_string());
268 error
269}
270
271fn yyerror(message: &str, text: &[u8]) -> TypeError {
273 let message = if text.is_empty() {
274 format!("{message} at end of jsonpath input")
275 } else {
276 format!("{message} at or near \"{}\" of jsonpath input", String::from_utf8_lossy(text))
277 };
278 TypeError::new(SqlState::SYNTAX_ERROR, message)
279}
280
281fn is_special(b: u8) -> bool {
283 b"?%$.[]{}()|&!=<>@#,*:-+/".contains(&b)
284}
285
286fn is_blank(b: u8) -> bool {
288 matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0c)
289}
290
291fn is_other(b: u8) -> bool {
293 !is_special(b) && !is_blank(b) && b != b'\\' && b != b'"'
294}
295
296#[derive(Clone, Copy, Debug, PartialEq, Eq)]
298enum Kw {
299 Is,
300 To,
301 Lax,
302 Flag,
303 Last,
304 Null,
305 True,
306 With,
307 False,
308 Exists,
309 Starts,
310 Strict,
311 Unknown,
312 LikeRegex,
313 Method(PathOp),
315}
316
317const KEYWORDS: [(&str, bool, Kw); 41] = [
319 ("is", false, Kw::Is),
320 ("to", false, Kw::To),
321 ("abs", false, Kw::Method(PathOp::Abs)),
322 ("lax", false, Kw::Lax),
323 ("date", false, Kw::Method(PathOp::Date)),
324 ("flag", false, Kw::Flag),
325 ("last", false, Kw::Last),
326 ("null", true, Kw::Null),
327 ("size", false, Kw::Method(PathOp::Size)),
328 ("time", false, Kw::Method(PathOp::Time)),
329 ("true", true, Kw::True),
330 ("type", false, Kw::Method(PathOp::Type)),
331 ("with", false, Kw::With),
332 ("btrim", false, Kw::Method(PathOp::Btrim)),
333 ("false", true, Kw::False),
334 ("floor", false, Kw::Method(PathOp::Floor)),
335 ("lower", false, Kw::Method(PathOp::Lower)),
336 ("ltrim", false, Kw::Method(PathOp::Ltrim)),
337 ("rtrim", false, Kw::Method(PathOp::Rtrim)),
338 ("upper", false, Kw::Method(PathOp::Upper)),
339 ("bigint", false, Kw::Method(PathOp::Bigint)),
340 ("double", false, Kw::Method(PathOp::Double)),
341 ("exists", false, Kw::Exists),
342 ("number", false, Kw::Method(PathOp::Number)),
343 ("starts", false, Kw::Starts),
344 ("strict", false, Kw::Strict),
345 ("string", false, Kw::Method(PathOp::StringFunc)),
346 ("boolean", false, Kw::Method(PathOp::Boolean)),
347 ("ceiling", false, Kw::Method(PathOp::Ceiling)),
348 ("decimal", false, Kw::Method(PathOp::Decimal)),
349 ("initcap", false, Kw::Method(PathOp::Initcap)),
350 ("integer", false, Kw::Method(PathOp::Integer)),
351 ("replace", false, Kw::Method(PathOp::Replace)),
352 ("time_tz", false, Kw::Method(PathOp::TimeTz)),
353 ("unknown", false, Kw::Unknown),
354 ("datetime", false, Kw::Method(PathOp::Datetime)),
355 ("keyvalue", false, Kw::Method(PathOp::KeyValue)),
356 ("timestamp", false, Kw::Method(PathOp::Timestamp)),
357 ("like_regex", false, Kw::LikeRegex),
358 ("split_part", false, Kw::Method(PathOp::SplitPart)),
359 ("timestamp_tz", false, Kw::Method(PathOp::TimestampTz)),
360];
361
362fn keyword(name: &[u8]) -> Option<Kw> {
364 KEYWORDS.iter().find_map(|&(word, lower, kw)| {
365 let found = if lower {
366 name == word.as_bytes()
367 } else {
368 name.eq_ignore_ascii_case(word.as_bytes())
369 };
370 found.then_some(kw)
371 })
372}
373
374#[derive(Clone, Copy, Debug, PartialEq, Eq)]
376enum Tok {
377 End,
378 And,
379 Or,
380 Not,
381 AnyLevels,
383 Less,
384 LessEqual,
385 Equal,
386 NotEqual,
387 GreaterEqual,
388 Greater,
389 Char(u8),
391 Variable,
392 Str,
393 Numeric,
394 Int,
395 Ident,
396 Kw(Kw),
397}
398
399struct Token {
401 tok: Tok,
402 text: (usize, usize),
403 value: Vec<u8>,
404}
405
406#[derive(Clone, Copy, PartialEq, Eq)]
408enum Rule {
409 Op(Tok, usize),
410 Variable,
411 QuotedVariable,
412 Special,
413 Blank,
414 Comment,
415 Numeric,
416 Int,
417 RealFail,
418 Junk,
419 Quote,
420 Backslash,
421 Name,
422}
423
424#[derive(Clone, Copy, PartialEq, Eq)]
426enum Escape {
427 Char(u8),
428 Unicode,
429 Hex,
430 UnicodeFail,
431 HexFail,
432 UnicodeBackslash,
433 Any,
434 Lone,
435}
436
437struct Lexer<'a> {
439 s: &'a [u8],
440 at: usize,
441 soft: bool,
443}
444
445impl Lexer<'_> {
446 fn byte(&self, i: usize) -> u8 {
447 self.s.get(i).copied().unwrap_or(0)
448 }
449
450 fn has(&self, i: usize, f: fn(u8) -> bool) -> bool {
451 i < self.s.len() && f(self.s[i])
452 }
453
454 fn digits_from(&self, mut q: usize, digit: fn(u8) -> bool, ends: &mut Vec<usize>) {
456 ends.push(q);
457 loop {
458 if self.has(q, digit) {
459 q += 1;
460 } else if self.byte(q) == b'_' && self.has(q + 1, digit) {
461 q += 2;
462 } else {
463 return;
464 }
465 ends.push(q);
466 }
467 }
468
469 fn decinteger(&self, p: usize) -> Vec<usize> {
471 let mut ends = Vec::new();
472 match self.byte(p) {
473 b'0' => ends.push(p + 1),
474 b'1'..=b'9' => self.digits_from(p + 1, |b| b.is_ascii_digit(), &mut ends),
475 _ => {}
476 }
477 ends
478 }
479
480 fn decdigits(&self, p: usize, ends: &mut Vec<usize>) {
482 if self.has(p, |b| b.is_ascii_digit()) {
483 self.digits_from(p + 1, |b| b.is_ascii_digit(), ends);
484 }
485 }
486
487 fn decimal(&self, p: usize) -> Vec<usize> {
489 let mut ends = Vec::new();
490 for end in self.decinteger(p) {
491 if self.byte(end) == b'.' {
492 ends.push(end + 1);
493 self.decdigits(end + 1, &mut ends);
494 }
495 }
496 if self.byte(p) == b'.' {
497 self.decdigits(p + 1, &mut ends);
498 }
499 ends
500 }
501
502 fn real(&self, p: usize) -> (Vec<usize>, Vec<usize>) {
504 let (mut ends, mut fails) = (Vec::new(), Vec::new());
505 let mut bases = self.decinteger(p);
506 bases.extend(self.decimal(p));
507 for base in bases {
508 if matches!(self.byte(base), b'e' | b'E') {
509 self.decdigits(base + 1, &mut ends);
510 if matches!(self.byte(base + 1), b'+' | b'-') {
511 fails.push(base + 2);
512 self.decdigits(base + 2, &mut ends);
513 }
514 }
515 }
516 (ends, fails)
517 }
518
519 fn radix(&self, p: usize, letter: u8, digit: fn(u8) -> bool) -> Option<usize> {
521 if self.byte(p) == b'0'
522 && self.byte(p + 1).to_ascii_lowercase() == letter
523 && self.has(p + 2, digit)
524 {
525 let mut ends = Vec::new();
526 self.digits_from(p + 3, digit, &mut ends);
527 ends.last().copied()
528 } else {
529 None
530 }
531 }
532
533 fn junk(&self, ends: &[usize]) -> Option<usize> {
535 ends.iter().filter(|&&end| self.has(end, is_other)).map(|&end| end + 1).max()
536 }
537
538 fn run(&self, mut p: usize, f: fn(u8) -> bool) -> usize {
540 while self.has(p, f) {
541 p += 1;
542 }
543 p
544 }
545
546 fn longest(&self, p: usize) -> (Rule, usize) {
548 let mut best: Option<(Rule, usize)> = None;
549 let mut offer = |rule: Rule, end: Option<usize>| {
550 if let Some(end) = end
551 && best.is_none_or(|(_, e)| end > e)
552 {
553 best = Some((rule, end));
554 }
555 };
556 let ops: [(&[u8], Tok); 11] = [
557 (b"&&", Tok::And),
558 (b"||", Tok::Or),
559 (b"!", Tok::Not),
560 (b"**", Tok::AnyLevels),
561 (b"<", Tok::Less),
562 (b"<=", Tok::LessEqual),
563 (b"==", Tok::Equal),
564 (b"<>", Tok::NotEqual),
565 (b"!=", Tok::NotEqual),
566 (b">=", Tok::GreaterEqual),
567 (b">", Tok::Greater),
568 ];
569 for (text, tok) in ops {
570 offer(
571 Rule::Op(tok, text.len()),
572 self.s[p..].starts_with(text).then_some(p + text.len()),
573 );
574 }
575 let dollar = self.byte(p) == b'$';
576 offer(
577 Rule::Variable,
578 (dollar && self.has(p + 1, is_other)).then(|| self.run(p + 1, is_other)),
579 );
580 offer(Rule::QuotedVariable, (dollar && self.byte(p + 1) == b'"').then_some(p + 2));
581 offer(Rule::Special, self.has(p, is_special).then_some(p + 1));
582 offer(Rule::Blank, self.has(p, is_blank).then(|| self.run(p, is_blank)));
583 offer(Rule::Comment, self.s[p..].starts_with(b"/*").then_some(p + 2));
584 let (real, realfail) = self.real(p);
585 let decimal = self.decimal(p);
586 let decinteger = self.decinteger(p);
587 offer(Rule::Numeric, real.iter().max().copied());
588 offer(Rule::Numeric, decimal.iter().max().copied());
589 offer(Rule::Int, decinteger.iter().max().copied());
590 offer(Rule::Int, self.radix(p, b'x', |b| b.is_ascii_hexdigit()));
591 offer(Rule::Int, self.radix(p, b'o', |b| matches!(b, b'0'..=b'7')));
592 offer(Rule::Int, self.radix(p, b'b', |b| matches!(b, b'0' | b'1')));
593 offer(Rule::RealFail, realfail.iter().max().copied());
594 offer(Rule::Junk, self.junk(&decinteger));
595 offer(Rule::Junk, self.junk(&decimal));
596 offer(Rule::Junk, self.junk(&real));
597 offer(Rule::Quote, (self.byte(p) == b'"' && p < self.s.len()).then_some(p + 1));
598 offer(Rule::Backslash, (self.byte(p) == b'\\' && p < self.s.len()).then_some(p + 1));
600 offer(Rule::Name, self.has(p, is_other).then(|| self.run(p, is_other)));
601 best.unwrap_or((Rule::Special, p))
602 }
603
604 fn next(&mut self) -> Result<Token, TypeError> {
606 loop {
607 let p = self.at;
608 if p >= self.s.len() {
609 return Ok(Token { tok: Tok::End, text: (p, p), value: Vec::new() });
610 }
611 let (rule, end) = self.longest(p);
612 let token = |tok| Token { tok, text: (p, end), value: self.s[p..end].to_vec() };
613 self.at = end;
614 match rule {
615 Rule::Op(tok, _) => return Ok(token(tok)),
616 Rule::Variable => {
617 return Ok(Token {
618 tok: Tok::Variable,
619 text: (p, end),
620 value: self.s[p + 1..end].to_vec(),
621 });
622 }
623 Rule::QuotedVariable => return self.quoted(Tok::Variable),
624 Rule::Special => return Ok(token(Tok::Char(self.s[p]))),
625 Rule::Blank => {}
626 Rule::Comment => self.comment()?,
627 Rule::Numeric => return Ok(token(Tok::Numeric)),
628 Rule::Int => return Ok(token(Tok::Int)),
629 Rule::RealFail => return Err(yyerror("invalid numeric literal", &self.s[p..end])),
630 Rule::Junk => {
631 return Err(yyerror("trailing junk after numeric literal", &self.s[p..end]));
632 }
633 Rule::Quote => return self.quoted(Tok::Str),
634 Rule::Backslash => {
635 self.at = p;
636 if let Some(token) = self.name(Vec::new())? {
637 return Ok(token);
638 }
639 }
640 Rule::Name => {
641 if let Some(token) = self.name(self.s[p..end].to_vec())? {
642 return Ok(token);
643 }
644 }
645 }
646 }
647 }
648
649 fn comment(&mut self) -> Result<(), TypeError> {
651 match self.s[self.at..].windows(2).position(|w| w == b"*/") {
652 Some(at) => {
653 self.at += at + 2;
654 Ok(())
655 }
656 None => {
657 self.at = self.s.len();
658 Err(yyerror("unexpected end of comment", b""))
659 }
660 }
661 }
662
663 fn name(&mut self, mut value: Vec<u8>) -> Result<Option<Token>, TypeError> {
665 loop {
666 let p = self.at;
667 let end_token = |value: Vec<u8>, text| {
668 let tok = keyword(&value).map_or(Tok::Ident, Tok::Kw);
669 Some(Token { tok, text, value })
670 };
671 if p >= self.s.len() {
672 return Ok(end_token(value, (p, p)));
673 }
674 let b = self.s[p];
675 if is_other(b) {
676 self.at = self.run(p, is_other);
677 value.extend_from_slice(&self.s[p..self.at]);
678 } else if is_blank(b) {
679 self.at = self.run(p, is_blank);
680 return Ok(end_token(value, (p, self.at)));
681 } else if self.s[p..].starts_with(b"/*") {
682 self.at = p + 2;
683 self.comment()?;
684 return Ok(None);
685 } else if b == b'\\' {
686 self.escape(&mut value)?;
687 } else {
688 return Ok(end_token(value, (p, p)));
689 }
690 }
691 }
692
693 fn quoted(&mut self, tok: Tok) -> Result<Token, TypeError> {
695 let mut value = Vec::new();
696 loop {
697 let p = self.at;
698 match self.s.get(p) {
699 None => return Err(yyerror("unterminated quoted string", b"")),
700 Some(b'"') => {
701 self.at = p + 1;
702 return Ok(Token { tok, text: (p, p + 1), value });
703 }
704 Some(b'\\') => self.escape(&mut value)?,
705 Some(_) => {
706 self.at = self.run(p, |b| b != b'\\' && b != b'"');
707 value.extend_from_slice(&self.s[p..self.at]);
708 }
709 }
710 }
711 }
712
713 fn unicode(&self, p: usize) -> Option<usize> {
715 if self.byte(p) != b'\\' || self.byte(p + 1) != b'u' {
716 return None;
717 }
718 if self.byte(p + 2) == b'{' {
719 let end = self.run(p + 3, |b| b.is_ascii_hexdigit()).min(p + 9);
720 (end > p + 3 && self.byte(end) == b'}').then_some(end + 1)
721 } else {
722 (p + 2..p + 6).all(|i| self.has(i, |b| b.is_ascii_hexdigit())).then_some(p + 6)
723 }
724 }
725
726 fn unicode_fail(&self, p: usize) -> Option<usize> {
728 if self.byte(p) != b'\\' || self.byte(p + 1) != b'u' {
729 return None;
730 }
731 Some(if self.byte(p + 2) == b'{' {
732 self.run(p + 3, |b| b.is_ascii_hexdigit()).min(p + 9)
733 } else {
734 self.run(p + 2, |b| b.is_ascii_hexdigit()).min(p + 5)
735 })
736 }
737
738 fn escape(&mut self, value: &mut Vec<u8>) -> Result<(), TypeError> {
740 let p = self.at;
741 let mut bounds = vec![p];
742 while let Some(end) = self.unicode(bounds[bounds.len() - 1]) {
743 bounds.push(end);
744 }
745 let chain = bounds[bounds.len() - 1];
746 let next = self.s.get(p + 1).copied();
747 let mut best: Option<(Escape, usize)> = None;
748 let mut offer = |rule: Escape, end: Option<usize>| {
749 if let Some(end) = end
750 && best.is_none_or(|(_, e)| end > e)
751 {
752 best = Some((rule, end));
753 }
754 };
755 let simple = match next {
756 Some(b'b') => Some(0x08),
757 Some(b'f') => Some(0x0c),
758 Some(b'n') => Some(b'\n'),
759 Some(b'r') => Some(b'\r'),
760 Some(b't') => Some(b'\t'),
761 Some(b'v') => Some(0x0b),
762 _ => None,
763 };
764 if let Some(c) = simple {
765 offer(Escape::Char(c), Some(p + 2));
766 }
767 offer(Escape::Unicode, (chain > p).then_some(chain));
768 let hex = next == Some(b'x');
769 offer(
770 Escape::Hex,
771 (hex && (p + 2..p + 4).all(|i| self.has(i, |b| b.is_ascii_hexdigit())))
772 .then_some(p + 4),
773 );
774 offer(Escape::UnicodeFail, bounds.iter().filter_map(|&at| self.unicode_fail(at)).max());
775 offer(Escape::HexFail, hex.then(|| self.run(p + 2, |b| b.is_ascii_hexdigit()).min(p + 3)));
776 offer(
777 Escape::UnicodeBackslash,
778 (chain > p && self.byte(chain) == b'\\').then_some(chain + 1),
779 );
780 offer(Escape::Any, next.filter(|&b| b != b'\n').map(|_| p + 2));
781 offer(Escape::Lone, Some(p + 1));
782 let (rule, end) = best.unwrap_or((Escape::Lone, p + 1));
783 let text = &self.s[p..end];
784 match rule {
785 Escape::Char(c) => value.push(c),
786 Escape::Unicode | Escape::UnicodeBackslash => {
787 self.unicode_chain(&bounds, value)?;
788 self.at = chain;
789 return Ok(());
790 }
791 Escape::Hex => {
792 let code = u32::from_str_radix(std::str::from_utf8(&text[2..]).unwrap_or("0"), 16)
793 .unwrap_or(0);
794 self.add_char(code, value)?;
795 }
796 Escape::UnicodeFail => return Err(yyerror("invalid Unicode escape sequence", text)),
797 Escape::HexFail => return Err(yyerror("invalid hexadecimal character sequence", text)),
798 Escape::Any => value.push(text[1]),
799 Escape::Lone => return Err(yyerror("unexpected end after backslash", text)),
800 }
801 self.at = end;
802 Ok(())
803 }
804
805 fn unicode_chain(&self, bounds: &[usize], value: &mut Vec<u8>) -> Result<(), TypeError> {
807 let mut high: Option<u32> = None;
808 let low_must_follow = || bad_input("Unicode low surrogate must follow a high surrogate.");
809 for pair in bounds.windows(2) {
810 let digits = &self.s[pair[0] + 2..pair[1]];
811 let digits = digits.strip_prefix(b"{").map_or(digits, |d| &d[..d.len() - 1]);
812 let mut code =
813 u32::from_str_radix(std::str::from_utf8(digits).unwrap_or("0"), 16).unwrap_or(0);
814 if (0xd800..=0xdbff).contains(&code) {
815 if high.is_some() {
816 return Err(bad_input(
817 "Unicode high surrogate must not follow a high surrogate.",
818 ));
819 }
820 high = Some(code);
821 continue;
822 }
823 if (0xdc00..=0xdfff).contains(&code) {
824 let Some(first) = high.take() else { return Err(low_must_follow()) };
825 code = ((first & 0x3ff) << 10) + 0x10000 + (code & 0x3ff);
826 } else if high.is_some() {
827 return Err(low_must_follow());
828 }
829 self.add_char(code, value)?;
830 }
831 if high.is_some() {
832 return Err(low_must_follow());
833 }
834 Ok(())
835 }
836
837 fn add_char(&self, code: u32, value: &mut Vec<u8>) -> Result<(), TypeError> {
839 if code == 0 {
840 let mut error = TypeError::new(
841 SqlState::UNTRANSLATABLE_CHARACTER,
842 "unsupported Unicode escape sequence".to_string(),
843 );
844 error.detail = Some("\\u0000 cannot be converted to text.".to_string());
845 return Err(error);
846 }
847 let Some(c) = char::from_u32(code) else {
848 let message = if self.soft {
849 "could not convert Unicode to server encoding"
850 } else {
851 "invalid Unicode code point"
852 };
853 return Err(TypeError::new(SqlState::SYNTAX_ERROR, message.to_string()));
854 };
855 value.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes());
856 Ok(())
857 }
858}
859
860struct Parser<'a> {
862 lexer: Lexer<'a>,
863 ahead: Option<Token>,
864 depth: usize,
865 regex: RegexCheck<'a>,
866}
867
868fn text_of(value: Vec<u8>) -> String {
870 String::from_utf8(value).unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned())
871}
872
873impl Parser<'_> {
874 fn peek(&mut self) -> Result<Tok, TypeError> {
875 if self.ahead.is_none() {
876 self.ahead = Some(self.lexer.next()?);
877 }
878 Ok(self.ahead.as_ref().map_or(Tok::End, |t| t.tok))
879 }
880
881 fn next(&mut self) -> Result<Token, TypeError> {
882 self.peek()?;
883 Ok(self.ahead.take().unwrap_or(Token { tok: Tok::End, text: (0, 0), value: Vec::new() }))
884 }
885
886 fn error(&mut self) -> TypeError {
888 match &self.ahead {
889 Some(token) => yyerror("syntax error", &self.lexer.s[token.text.0..token.text.1]),
890 None => yyerror("syntax error", b""),
891 }
892 }
893
894 fn expect(&mut self, tok: Tok) -> Result<Token, TypeError> {
895 if self.peek()? == tok { self.next() } else { Err(self.error()) }
896 }
897
898 fn deeper<T>(
900 &mut self,
901 f: impl FnOnce(&mut Self) -> Result<T, TypeError>,
902 ) -> Result<T, TypeError> {
903 if self.depth >= MAX_DEPTH {
904 return Err(too_deep());
905 }
906 self.depth += 1;
907 let result = f(self);
908 self.depth -= 1;
909 result
910 }
911
912 fn or(&mut self, pred: bool) -> Result<(Chain, bool), TypeError> {
914 let (mut left, mut is_pred) = self.and(pred)?;
915 while self.peek()? == Tok::Or {
916 if !is_pred {
917 return Err(self.error());
918 }
919 self.next()?;
920 let right = self.and(true)?.0;
921 left = vec![PathItem::Binary(PathOp::Or, left, right)];
922 is_pred = true;
923 }
924 Ok((left, is_pred))
925 }
926
927 fn and(&mut self, pred: bool) -> Result<(Chain, bool), TypeError> {
928 let (mut left, mut is_pred) = self.not(pred)?;
929 while self.peek()? == Tok::And {
930 if !is_pred {
931 return Err(self.error());
932 }
933 self.next()?;
934 let right = self.not(true)?.0;
935 left = vec![PathItem::Binary(PathOp::And, left, right)];
936 is_pred = true;
937 }
938 Ok((left, is_pred))
939 }
940
941 fn not(&mut self, pred: bool) -> Result<(Chain, bool), TypeError> {
942 if self.peek()? != Tok::Not {
943 return self.comparison(pred);
944 }
945 self.next()?;
946 self.deeper(|p| {
947 let arg = match p.peek()? {
948 Tok::Char(b'(') => {
949 p.next()?;
950 let arg = p.or(true)?.0;
951 p.expect(Tok::Char(b')'))?;
952 arg
953 }
954 Tok::Kw(Kw::Exists) => p.exists()?,
955 _ => return Err(p.error()),
956 };
957 Ok((vec![PathItem::Unary(PathOp::Not, arg)], true))
958 })
959 }
960
961 fn exists(&mut self) -> Result<Chain, TypeError> {
963 self.next()?;
964 self.expect(Tok::Char(b'('))?;
965 let arg = self.expr()?;
966 self.expect(Tok::Char(b')'))?;
967 Ok(vec![PathItem::Unary(PathOp::Exists, arg)])
968 }
969
970 fn expr(&mut self) -> Result<Chain, TypeError> {
972 Ok(self.additive(true)?.0)
973 }
974
975 fn comparison(&mut self, pred: bool) -> Result<(Chain, bool), TypeError> {
976 if self.peek()? == Tok::Kw(Kw::Exists) {
977 return Ok((self.exists()?, true));
978 }
979 let (left, is_pred) = self.additive(false)?;
980 if is_pred {
981 return Ok((left, true));
982 }
983 let op = match self.peek()? {
984 Tok::Equal => PathOp::Equal,
985 Tok::NotEqual => PathOp::NotEqual,
986 Tok::Less => PathOp::Less,
987 Tok::Greater => PathOp::Greater,
988 Tok::LessEqual => PathOp::LessOrEqual,
989 Tok::GreaterEqual => PathOp::GreaterOrEqual,
990 Tok::Kw(Kw::Starts) => {
991 self.next()?;
992 self.expect(Tok::Kw(Kw::With))?;
993 let item = match self.peek()? {
994 Tok::Str => PathItem::String(text_of(self.next()?.value)),
995 Tok::Variable => PathItem::Variable(text_of(self.next()?.value)),
996 _ => return Err(self.error()),
997 };
998 return Ok((vec![PathItem::Binary(PathOp::StartsWith, left, vec![item])], true));
999 }
1000 Tok::Kw(Kw::LikeRegex) => {
1001 self.next()?;
1002 let pattern = text_of(self.expect(Tok::Str)?.value);
1003 let flags = if self.peek()? == Tok::Kw(Kw::Flag) {
1004 self.next()?;
1005 Some(text_of(self.expect(Tok::Str)?.value))
1006 } else {
1007 None
1008 };
1009 return Ok((vec![self.like_regex(left, pattern, flags.as_deref())?], true));
1010 }
1011 _ if pred => return Err(self.error()),
1012 _ => return Ok((left, false)),
1013 };
1014 self.next()?;
1015 let right = self.expr()?;
1016 Ok((vec![PathItem::Binary(op, left, right)], true))
1017 }
1018
1019 fn like_regex(
1021 &self,
1022 expr: Chain,
1023 pattern: String,
1024 flags: Option<&str>,
1025 ) -> Result<PathItem, TypeError> {
1026 let mut bits = 0;
1027 for c in flags.unwrap_or_default().chars() {
1028 bits |= match c {
1029 'i' => JSONPATH_REGEX_ICASE,
1030 's' => JSONPATH_REGEX_DOTALL,
1031 'm' => JSONPATH_REGEX_MLINE,
1032 'x' => JSONPATH_REGEX_WSPACE,
1033 'q' => JSONPATH_REGEX_QUOTE,
1034 c => {
1035 let mut error = bad_input("");
1036 error.sqlstate = SqlState::SYNTAX_ERROR;
1037 error.detail = Some(format!(
1038 "Unrecognized flag character \"{c}\" in LIKE_REGEX predicate."
1039 ));
1040 return Err(error);
1041 }
1042 };
1043 }
1044 let cflags = jsonpath_regex_flags(bits)?;
1045 (self.regex)(&pattern, cflags).map_err(|message| {
1046 TypeError::new(
1047 SqlState::INVALID_REGULAR_EXPRESSION,
1048 format!("invalid regular expression: {message}"),
1049 )
1050 })?;
1051 Ok(PathItem::LikeRegex { expr, pattern, flags: bits })
1052 }
1053
1054 fn additive(&mut self, expr: bool) -> Result<(Chain, bool), TypeError> {
1055 let (mut left, is_pred) = self.multiplicative(expr)?;
1056 if is_pred {
1057 return Ok((left, true));
1058 }
1059 loop {
1060 let op = match self.peek()? {
1061 Tok::Char(b'+') => PathOp::Add,
1062 Tok::Char(b'-') => PathOp::Sub,
1063 _ => return Ok((left, false)),
1064 };
1065 self.next()?;
1066 let right = self.multiplicative(true)?.0;
1067 left = vec![PathItem::Binary(op, left, right)];
1068 }
1069 }
1070
1071 fn multiplicative(&mut self, expr: bool) -> Result<(Chain, bool), TypeError> {
1072 let (mut left, is_pred) = self.unary(expr)?;
1073 if is_pred {
1074 return Ok((left, true));
1075 }
1076 loop {
1077 let op = match self.peek()? {
1078 Tok::Char(b'*') => PathOp::Mul,
1079 Tok::Char(b'/') => PathOp::Div,
1080 Tok::Char(b'%') => PathOp::Mod,
1081 _ => return Ok((left, false)),
1082 };
1083 self.next()?;
1084 let right = self.unary(true)?.0;
1085 left = vec![PathItem::Binary(op, left, right)];
1086 }
1087 }
1088
1089 fn unary(&mut self, expr: bool) -> Result<(Chain, bool), TypeError> {
1091 self.deeper(|p| {
1092 let op = match p.peek()? {
1093 Tok::Char(b'+') => PathOp::Plus,
1094 Tok::Char(b'-') => PathOp::Minus,
1095 _ => return p.accessor_expr(expr),
1096 };
1097 p.next()?;
1098 let arg = p.unary(true)?.0;
1099 Ok((unary(op, arg), false))
1100 })
1101 }
1102
1103 fn accessor_expr(&mut self, expr: bool) -> Result<(Chain, bool), TypeError> {
1105 let item = match self.peek()? {
1106 Tok::Char(b'(') => {
1107 self.next()?;
1108 let (mut inner, is_pred) = self.or(false)?;
1109 self.expect(Tok::Char(b')'))?;
1110 if is_pred && !matches!(self.peek()?, Tok::Char(b'.' | b'[' | b'?')) {
1111 if expr {
1112 return Err(self.error());
1113 }
1114 if self.peek()? == Tok::Kw(Kw::Is) {
1115 self.next()?;
1116 self.expect(Tok::Kw(Kw::Unknown))?;
1117 return Ok((vec![PathItem::Unary(PathOp::IsUnknown, inner)], true));
1118 }
1119 return Ok((inner, true));
1120 }
1121 self.accessors(&mut inner)?;
1122 return Ok((inner, false));
1123 }
1124 Tok::Str => PathItem::String(text_of(self.next()?.value)),
1125 Tok::Kw(Kw::Null) => {
1126 self.next()?;
1127 PathItem::Null
1128 }
1129 Tok::Kw(Kw::True | Kw::False) => PathItem::Bool(self.next()?.tok == Tok::Kw(Kw::True)),
1130 Tok::Numeric | Tok::Int => PathItem::Numeric(number(self.next()?)?),
1131 Tok::Variable => PathItem::Variable(text_of(self.next()?.value)),
1132 Tok::Char(b'$') => {
1133 self.next()?;
1134 PathItem::Root
1135 }
1136 Tok::Char(b'@') => {
1137 self.next()?;
1138 PathItem::Current
1139 }
1140 Tok::Kw(Kw::Last) => {
1141 self.next()?;
1142 PathItem::Last
1143 }
1144 _ => return Err(self.error()),
1145 };
1146 let mut chain = vec![item];
1147 self.accessors(&mut chain)?;
1148 Ok((chain, false))
1149 }
1150
1151 fn accessors(&mut self, chain: &mut Chain) -> Result<(), TypeError> {
1153 loop {
1154 match self.peek()? {
1155 Tok::Char(b'.') => {
1156 self.next()?;
1157 let item = self.after_dot()?;
1158 chain.push(item);
1159 }
1160 Tok::Char(b'[') => {
1161 self.next()?;
1162 if self.peek()? == Tok::Char(b'*') {
1163 self.next()?;
1164 self.expect(Tok::Char(b']'))?;
1165 chain.push(PathItem::AnyArray);
1166 continue;
1167 }
1168 let mut elems = Vec::new();
1169 loop {
1170 let from = self.expr()?;
1171 let to = if self.peek()? == Tok::Kw(Kw::To) {
1172 self.next()?;
1173 Some(self.expr()?)
1174 } else {
1175 None
1176 };
1177 elems.push((from, to));
1178 if self.peek()? != Tok::Char(b',') {
1179 break;
1180 }
1181 self.next()?;
1182 }
1183 self.expect(Tok::Char(b']'))?;
1184 chain.push(PathItem::IndexArray(elems));
1185 }
1186 Tok::Char(b'?') => {
1187 self.next()?;
1188 self.expect(Tok::Char(b'('))?;
1189 let arg = self.deeper(|p| p.or(true))?.0;
1190 self.expect(Tok::Char(b')'))?;
1191 chain.push(PathItem::Unary(PathOp::Filter, arg));
1192 }
1193 _ => return Ok(()),
1194 }
1195 }
1196 }
1197
1198 fn after_dot(&mut self) -> Result<PathItem, TypeError> {
1200 match self.peek()? {
1201 Tok::Char(b'*') => {
1202 self.next()?;
1203 Ok(PathItem::AnyKey)
1204 }
1205 Tok::AnyLevels => {
1206 self.next()?;
1207 if self.peek()? != Tok::Char(b'{') {
1208 return Ok(PathItem::Any { first: 0, last: JSONPATH_LAST });
1209 }
1210 self.next()?;
1211 let first = self.level()?;
1212 let last = if self.peek()? == Tok::Kw(Kw::To) {
1213 self.next()?;
1214 self.level()?
1215 } else {
1216 first
1217 };
1218 self.expect(Tok::Char(b'}'))?;
1219 Ok(PathItem::Any { first, last })
1220 }
1221 Tok::Ident | Tok::Str => Ok(PathItem::Key(text_of(self.next()?.value))),
1222 Tok::Kw(kw) => {
1223 let token = self.next()?;
1224 match kw {
1225 Kw::Method(op) if self.peek()? == Tok::Char(b'(') => {
1226 self.next()?;
1227 self.method(op)
1228 }
1229 _ => Ok(PathItem::Key(text_of(token.value))),
1230 }
1231 }
1232 _ => Err(self.error()),
1233 }
1234 }
1235
1236 fn level(&mut self) -> Result<u32, TypeError> {
1238 match self.peek()? {
1239 Tok::Int => {
1240 let value = text_of(self.next()?.value);
1241 Ok(u32::try_from(int4_in(&value)?).unwrap_or(0))
1242 }
1243 Tok::Kw(Kw::Last) => {
1244 self.next()?;
1245 Ok(JSONPATH_LAST)
1246 }
1247 _ => Err(self.error()),
1248 }
1249 }
1250
1251 fn method(&mut self, op: PathOp) -> Result<PathItem, TypeError> {
1253 let mut args = Vec::new();
1254 match op {
1255 PathOp::Decimal => {
1256 if self.peek()? != Tok::Char(b')') {
1257 args.push(self.int_elem()?);
1258 while self.peek()? == Tok::Char(b',') {
1259 self.next()?;
1260 args.push(self.int_elem()?);
1261 }
1262 }
1263 self.expect(Tok::Char(b')'))?;
1264 if args.len() > 2 {
1265 let mut error =
1266 bad_input(".decimal() can only have an optional precision[,scale].");
1267 error.sqlstate = SqlState::SYNTAX_ERROR;
1268 return Err(error);
1269 }
1270 return Ok(PathItem::Method(op, args));
1271 }
1272 PathOp::Datetime | PathOp::Ltrim | PathOp::Rtrim | PathOp::Btrim => {
1273 if self.peek()? == Tok::Str {
1274 args.push(PathItem::String(text_of(self.next()?.value)));
1275 }
1276 }
1277 PathOp::Time | PathOp::TimeTz | PathOp::Timestamp | PathOp::TimestampTz => {
1278 if self.peek()? == Tok::Int {
1279 args.push(PathItem::Numeric(number(self.next()?)?));
1280 }
1281 }
1282 PathOp::Replace | PathOp::SplitPart => {
1283 args.push(PathItem::String(text_of(self.expect(Tok::Str)?.value)));
1284 self.expect(Tok::Char(b','))?;
1285 args.push(if op == PathOp::Replace {
1286 PathItem::String(text_of(self.expect(Tok::Str)?.value))
1287 } else {
1288 self.int_elem()?
1289 });
1290 }
1291 _ => {}
1292 }
1293 self.expect(Tok::Char(b')'))?;
1294 Ok(PathItem::Method(op, args))
1295 }
1296
1297 fn int_elem(&mut self) -> Result<PathItem, TypeError> {
1299 let negate = match self.peek()? {
1300 Tok::Char(b'+') => false,
1301 Tok::Char(b'-') => true,
1302 Tok::Int => return Ok(PathItem::Numeric(number(self.next()?)?)),
1303 _ => return Err(self.error()),
1304 };
1305 self.next()?;
1306 let value = number(self.expect(Tok::Int)?)?;
1307 Ok(PathItem::Numeric(if negate { value.negate() } else { value }))
1308 }
1309}
1310
1311fn number(token: Token) -> Result<Numeric, TypeError> {
1313 numeric_in(&text_of(token.value), -1)
1314}
1315
1316fn unary(op: PathOp, arg: Chain) -> Chain {
1318 if let [PathItem::Numeric(value)] = arg.as_slice() {
1319 if op == PathOp::Minus {
1320 return vec![PathItem::Numeric(value.negate())];
1321 }
1322 return arg;
1323 }
1324 vec![PathItem::Unary(op, arg)]
1325}
1326
1327fn check(chain: &[PathItem], nesting: u32, subscript: bool) -> Result<(), TypeError> {
1329 for item in chain {
1330 match item {
1331 PathItem::Current if nesting == 0 => {
1332 return Err(TypeError::new(
1333 SqlState::SYNTAX_ERROR,
1334 "@ is not allowed in root expressions".to_string(),
1335 ));
1336 }
1337 PathItem::Last if !subscript => {
1338 return Err(TypeError::new(
1339 SqlState::SYNTAX_ERROR,
1340 "LAST is allowed only in array subscripts".to_string(),
1341 ));
1342 }
1343 PathItem::Binary(_, left, right) => {
1344 check(left, nesting, subscript)?;
1345 check(right, nesting, subscript)?;
1346 }
1347 PathItem::Unary(op, arg) => {
1348 check(arg, nesting + u32::from(*op == PathOp::Filter), subscript)?
1349 }
1350 PathItem::LikeRegex { expr, .. } => check(expr, nesting, subscript)?,
1351 PathItem::IndexArray(elems) => {
1352 for (from, to) in elems {
1353 check(from, nesting, true)?;
1354 if let Some(to) = to {
1355 check(to, nesting, true)?;
1356 }
1357 }
1358 }
1359 _ => {}
1360 }
1361 }
1362 Ok(())
1363}
1364
1365pub fn jsonpath_parse(
1371 text: &str,
1372 soft: bool,
1373 regex: RegexCheck<'_>,
1374) -> Result<JsonPath, TypeError> {
1375 let mut parser =
1376 Parser { lexer: Lexer { s: text.as_bytes(), at: 0, soft }, ahead: None, depth: 0, regex };
1377 let lax = match parser.peek()? {
1378 Tok::End => return Err(TypeError::syntax("jsonpath", text)),
1379 Tok::Kw(Kw::Strict) => {
1380 parser.next()?;
1381 false
1382 }
1383 Tok::Kw(Kw::Lax) => {
1384 parser.next()?;
1385 true
1386 }
1387 _ => true,
1388 };
1389 let expr = parser.or(false)?.0;
1390 if parser.peek()? != Tok::End {
1391 return Err(parser.error());
1392 }
1393 check(&expr, 0, false)?;
1394 Ok(JsonPath { lax, expr })
1395}
1396
1397fn print_chain(chain: &[PathItem], brackets: bool, out: &mut String) {
1399 for (i, item) in chain.iter().enumerate() {
1400 print_item(item, i > 0, i > 0 || brackets, i + 1 < chain.len(), out);
1401 }
1402}
1403
1404fn print_operand(chain: &[PathItem], priority: u8, out: &mut String) {
1406 print_chain(chain, chain[0].priority() <= priority, out);
1407}
1408
1409fn print_item(item: &PathItem, in_key: bool, brackets: bool, has_next: bool, out: &mut String) {
1411 let open = |out: &mut String| {
1412 if brackets {
1413 out.push('(');
1414 }
1415 };
1416 let close = |out: &mut String| {
1417 if brackets {
1418 out.push(')');
1419 }
1420 };
1421 let dot = |out: &mut String| {
1422 if in_key {
1423 out.push('.');
1424 }
1425 };
1426 match item {
1427 PathItem::Null => out.push_str("null"),
1428 PathItem::String(s) => escape(s, out),
1429 PathItem::Numeric(value) => {
1430 let mut bytes = Vec::new();
1431 numeric_out(value, &mut bytes);
1432 let text = String::from_utf8_lossy(&bytes);
1433 if has_next {
1434 out.push('(');
1435 out.push_str(&text);
1436 out.push(')');
1437 } else {
1438 out.push_str(&text);
1439 }
1440 }
1441 PathItem::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
1442 PathItem::Binary(op, left, right) => {
1443 open(out);
1444 print_operand(left, op.priority(), out);
1445 out.push(' ');
1446 out.push_str(op.name());
1447 out.push(' ');
1448 print_operand(right, op.priority(), out);
1449 close(out);
1450 }
1451 PathItem::Unary(op @ (PathOp::Plus | PathOp::Minus), arg) => {
1452 open(out);
1453 out.push_str(op.name());
1454 print_operand(arg, op.priority(), out);
1455 close(out);
1456 }
1457 PathItem::Unary(op, arg) => {
1458 let (before, after) = match op {
1459 PathOp::Not => ("!(", ")"),
1460 PathOp::IsUnknown => ("(", ") is unknown"),
1461 PathOp::Filter => ("?(", ")"),
1462 _ => ("exists (", ")"),
1463 };
1464 out.push_str(before);
1465 print_chain(arg, false, out);
1466 out.push_str(after);
1467 }
1468 PathItem::LikeRegex { expr, pattern, flags } => {
1469 open(out);
1470 print_operand(expr, 6, out);
1471 out.push_str(" like_regex ");
1472 escape(pattern, out);
1473 if *flags != 0 {
1474 out.push_str(" flag \"");
1475 for (bit, c) in [
1476 (JSONPATH_REGEX_ICASE, 'i'),
1477 (JSONPATH_REGEX_DOTALL, 's'),
1478 (JSONPATH_REGEX_MLINE, 'm'),
1479 (JSONPATH_REGEX_WSPACE, 'x'),
1480 (JSONPATH_REGEX_QUOTE, 'q'),
1481 ] {
1482 if flags & bit != 0 {
1483 out.push(c);
1484 }
1485 }
1486 out.push('"');
1487 }
1488 close(out);
1489 }
1490 PathItem::AnyArray => out.push_str("[*]"),
1491 PathItem::AnyKey => {
1492 dot(out);
1493 out.push('*');
1494 }
1495 PathItem::IndexArray(elems) => {
1496 out.push('[');
1497 for (i, (from, to)) in elems.iter().enumerate() {
1498 if i > 0 {
1499 out.push(',');
1500 }
1501 print_chain(from, false, out);
1502 if let Some(to) = to {
1503 out.push_str(" to ");
1504 print_chain(to, false, out);
1505 }
1506 }
1507 out.push(']');
1508 }
1509 PathItem::Any { first, last } => {
1510 dot(out);
1511 let bound =
1512 |n: u32| if n == JSONPATH_LAST { "last".to_string() } else { n.to_string() };
1513 if *first == 0 && *last == JSONPATH_LAST {
1514 out.push_str("**");
1515 } else if first == last {
1516 out.push_str(&format!("**{{{}}}", bound(*first)));
1517 } else {
1518 out.push_str(&format!("**{{{} to {}}}", bound(*first), bound(*last)));
1519 }
1520 }
1521 PathItem::Key(key) => {
1522 dot(out);
1523 escape(key, out);
1524 }
1525 PathItem::Current => out.push('@'),
1526 PathItem::Root => out.push('$'),
1527 PathItem::Variable(name) => {
1528 out.push('$');
1529 escape(name, out);
1530 }
1531 PathItem::Last => out.push_str("last"),
1532 PathItem::Method(op, args) => {
1533 out.push('.');
1534 out.push_str(op.name());
1535 out.push('(');
1536 for (i, arg) in args.iter().enumerate() {
1537 if i > 0 {
1538 out.push(',');
1539 }
1540 print_item(arg, false, false, false, out);
1541 }
1542 out.push(')');
1543 }
1544 }
1545}
1546
1547pub fn jsonpath_deparse(path: &JsonPath, out: &mut Vec<u8>) {
1549 let mut text = String::new();
1550 if !path.lax {
1551 text.push_str("strict ");
1552 }
1553 print_chain(&path.expr, true, &mut text);
1554 out.extend_from_slice(text.as_bytes());
1555}
1556
1557pub fn jsonpath_send(path: &JsonPath, out: &mut Vec<u8>) {
1559 out.push(1);
1560 jsonpath_deparse(path, out);
1561}
1562
1563pub fn jsonpath_recv(recv: &mut Recv<'_>, regex: RegexCheck<'_>) -> Result<JsonPath, TypeError> {
1569 let version = recv.byte()?;
1570 if version != 1 {
1571 return Err(TypeError::new(
1572 SqlState::INTERNAL_ERROR,
1573 format!("unsupported jsonpath version number: {version}"),
1574 ));
1575 }
1576 jsonpath_parse(recv.text()?, false, regex)
1577}
1578
1579#[cfg(test)]
1580mod tests {
1581 use super::*;
1582
1583 fn any_regex(_: &str, _: u32) -> Result<(), String> {
1584 Ok(())
1585 }
1586
1587 fn paren_regex(pattern: &str, _: u32) -> Result<(), String> {
1588 if pattern.contains('(') { Err("parentheses () not balanced".to_string()) } else { Ok(()) }
1589 }
1590
1591 fn out(text: &str) -> String {
1592 let path =
1593 jsonpath_parse(text, false, &any_regex).unwrap_or_else(|e| panic!("{text}: {e}"));
1594 let mut bytes = Vec::new();
1595 jsonpath_deparse(&path, &mut bytes);
1596 String::from_utf8(bytes).expect("utf8")
1597 }
1598
1599 fn err(text: &str) -> String {
1600 match jsonpath_parse(text, false, &paren_regex) {
1601 Ok(_) => panic!("{text} is valid"),
1602 Err(e) => format!("{} {}", e.sqlstate.as_str(), e.message),
1603 }
1604 }
1605
1606 #[test]
1607 fn text_form() {
1608 let cases = [
1609 ("1 + 2", "(1 + 2)"),
1610 ("1 + 2 + 3", "((1 + 2) + 3)"),
1611 ("1 * 2 + 3", "(1 * 2 + 3)"),
1612 ("- -1", "1"),
1613 ("-$.a", "(-$.\"a\")"),
1614 ("-(1).a", "(-(1).\"a\")"),
1615 ("-$.a * 2", "(-$.\"a\" * 2)"),
1616 ("1 / 2 % 3", "((1 / 2) % 3)"),
1617 ("$ ? (@ > 1)", "$?(@ > 1)"),
1618 ("$ ? ((@ > 1) is unknown)", "$?((@ > 1) is unknown)"),
1619 ("$ ? (exists (@.a))", "$?(exists (@.\"a\"))"),
1620 ("$ ? (!exists(@.a))", "$?(!(exists (@.\"a\")))"),
1621 ("$.a[1,2 to 3,last]", "$.\"a\"[1,2 to 3,last]"),
1622 ("$.**{last to 2}", "$.**{last to 2}"),
1623 ("$.**{0 to last}", "$.**"),
1624 ("$.**{last to last}", "$.**{last}"),
1625 ("$.decimal(4,-2)", "$.decimal(4,-2)"),
1626 ("$.Type()", "$.type()"),
1627 ("$.TYPE", "$.\"TYPE\""),
1628 ("STRICT $", "strict $"),
1629 ("lax 1", "1"),
1630 (".5", "0.5"),
1631 ("1e3", "1000"),
1632 ("0x1F", "31"),
1633 ("1_000.5_5", "1000.55"),
1634 ("$var.a", "$\"var\".\"a\""),
1635 ("(1 + $).a", "(1 + $).\"a\""),
1636 ("(($ > 1)).a", "($ > 1).\"a\""),
1637 ("\"\\v\\x41\\u{1F600}\"", "\"\\u000bA\u{1F600}\""),
1638 ("\"\\ud83d\\ude00\"", "\"\u{1F600}\""),
1639 ("$.\\x41", "$.\"A\""),
1640 ("$ /* c */ .a", "$.\"a\""),
1641 ("$ ? (@ like_regex \"a\" flag \"qx\")", "$?(@ like_regex \"a\" flag \"xq\")"),
1642 ("$ ? (-@ like_regex \"a\")", "$?((-@) like_regex \"a\")"),
1643 ("$[last ? (@ > last)]", "$[last?(@ > last)]"),
1644 ("$.split_part(\"\", +1)", "$.split_part(\"\",1)"),
1645 ("$.a.type ( )", "$.\"a\".type()"),
1646 ];
1647 for (text, want) in cases {
1648 assert_eq!(out(text), want, "{text}");
1649 }
1650 }
1651
1652 #[test]
1653 fn errors() {
1654 let cases = [
1655 ("", "22P02 invalid input syntax for type jsonpath: \"\""),
1656 ("/* c */", "22P02 invalid input syntax for type jsonpath: \"/* c */\""),
1657 ("$ abc def", "42601 syntax error at or near \" \" of jsonpath input"),
1658 ("$.a/*c*/", "42601 syntax error at end of jsonpath input"),
1659 ("$.a/*c*/.b", "42601 syntax error at or near \".\" of jsonpath input"),
1660 ("$.1", "42601 syntax error at or near \".1\" of jsonpath input"),
1661 ("1a", "42601 trailing junk after numeric literal at or near \"1a\" of jsonpath input"),
1662 ("00", "42601 trailing junk after numeric literal at or near \"00\" of jsonpath input"),
1663 ("1e5xy", "42601 syntax error at end of jsonpath input"),
1664 (
1665 "1.5e3abc",
1666 "42601 trailing junk after numeric literal at or near \"1.5e3a\" of jsonpath input",
1667 ),
1668 ("1e+", "42601 invalid numeric literal at or near \"1e+\" of jsonpath input"),
1669 ("\"a", "42601 unterminated quoted string at end of jsonpath input"),
1670 ("$ /* a", "42601 unexpected end of comment at end of jsonpath input"),
1671 (
1672 "\"\\u12\"",
1673 "42601 invalid Unicode escape sequence at or near \"\\u12\" of jsonpath input",
1674 ),
1675 (
1676 "\"\\u{1234567}\"",
1677 "42601 invalid Unicode escape sequence at or near \"\\u{123456\" of jsonpath input",
1678 ),
1679 (
1680 "\"\\xZ\"",
1681 "42601 invalid hexadecimal character sequence at or near \"\\x\" of jsonpath input",
1682 ),
1683 ("\"\\u0000\"", "22P05 unsupported Unicode escape sequence"),
1684 ("\"\\ud83d\"", "22P02 invalid input syntax for type jsonpath"),
1685 ("\"\\u{110000}\"", "42601 invalid Unicode code point"),
1686 ("@", "42601 @ is not allowed in root expressions"),
1687 ("$.a[@]", "42601 @ is not allowed in root expressions"),
1688 ("last + @", "42601 LAST is allowed only in array subscripts"),
1689 ("$ > 1 > 2", "42601 syntax error at or near \">\" of jsonpath input"),
1690 ("($ > 1) + 2", "42601 syntax error at or near \"+\" of jsonpath input"),
1691 ("!($.a)", "42601 syntax error at or near \")\" of jsonpath input"),
1692 ("!($ > 1) is unknown", "42601 syntax error at or near \" \" of jsonpath input"),
1693 ("exists($ > 1)", "42601 syntax error at or near \">\" of jsonpath input"),
1694 ("exists(($ > 1))", "42601 syntax error at or near \")\" of jsonpath input"),
1695 ("-($ > 1)", "42601 syntax error at end of jsonpath input"),
1696 ("$ ? (true)", "42601 syntax error at or near \")\" of jsonpath input"),
1697 ("$ ? (@ == TRUE)", "42601 syntax error at end of jsonpath input"),
1698 ("$.time(\"x\")", "42601 syntax error at or near \"\"\" of jsonpath input"),
1699 ("$[1, *]", "42601 syntax error at or near \"*\" of jsonpath input"),
1700 ("$.decimal(1, 2, 3) junk", "42601 invalid input syntax for type jsonpath"),
1701 ("$ like_regex \"(a\" flag \"z\"", "42601 invalid input syntax for type jsonpath"),
1702 (
1703 "$ like_regex \"(a\" junk",
1704 "2201B invalid regular expression: parentheses () not balanced",
1705 ),
1706 (
1707 "$ like_regex \"a\" flag \"x\"",
1708 "0A000 XQuery \"x\" flag (expanded regular expressions) is not implemented",
1709 ),
1710 ("$.**{99999999999}", "22003 value \"99999999999\" is out of range for type integer"),
1711 ("lax strict $", "42601 syntax error at or near \" \" of jsonpath input"),
1712 ("strict", "42601 syntax error at end of jsonpath input"),
1713 ];
1714 for (text, want) in cases {
1715 assert_eq!(err(text), want, "{text}");
1716 }
1717 let soft = jsonpath_parse("\"\\u{110000}\"", true, &any_regex).expect_err("soft");
1718 assert_eq!(soft.message, "could not convert Unicode to server encoding");
1719 }
1720
1721 #[test]
1722 fn binary_form() {
1723 let path = jsonpath_parse("strict $.a ? (@ > 1)", false, &any_regex).expect("path");
1724 let mut bytes = Vec::new();
1725 jsonpath_send(&path, &mut bytes);
1726 assert_eq!(bytes, b"\x01strict $.\"a\"?(@ > 1)");
1727 assert_eq!(jsonpath_recv(&mut Recv::new(&bytes), &any_regex).expect("recv"), path);
1728 let error = jsonpath_recv(&mut Recv::new(b"\x02$"), &any_regex).expect_err("version");
1729 assert_eq!(error.message, "unsupported jsonpath version number: 2");
1730 }
1731}