Skip to main content

rupg_types/
jsonpath.rs

1//! The `jsonpath` type, from `jsonpath_scan.l`, `jsonpath_gram.y` and `jsonpath.c`. A value is the tree of the path, as `flattenJsonPathParseItem` writes it. The text form is the text of `printJsonPathItem`, and the binary form is the version byte 1 and the text form.
2//!
3//! The scanner gives the tokens that the scanner of flex gives: the longest match wins, and the first rule wins a tie. The text of a token is the text that flex has in `yytext`, so a syntax error names the same text as PostgreSQL. The parser follows the grammar, and it stops at the first token that the grammar cannot take, as bison does.
4
5use 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
14/// `JSP_REGEX_ICASE`: the flag `i` of `like_regex`.
15pub const JSONPATH_REGEX_ICASE: u8 = 0x01;
16
17/// `JSP_REGEX_DOTALL`: the flag `s` of `like_regex`.
18pub const JSONPATH_REGEX_DOTALL: u8 = 0x02;
19
20/// `JSP_REGEX_MLINE`: the flag `m` of `like_regex`.
21pub const JSONPATH_REGEX_MLINE: u8 = 0x04;
22
23/// `JSP_REGEX_WSPACE`: the flag `x` of `like_regex`.
24pub const JSONPATH_REGEX_WSPACE: u8 = 0x08;
25
26/// `JSP_REGEX_QUOTE`: the flag `q` of `like_regex`.
27pub const JSONPATH_REGEX_QUOTE: u8 = 0x10;
28
29/// The bits of `cflags` in `regex.h` that [`jsonpath_regex_flags`] gives.
30const 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
36/// The deepest nesting of parentheses, operators and filters. PostgreSQL stops a deep path when it reaches `max_stack_depth`. The parser here works by recursion, and this limit keeps it on the stack. It is the limit of the analyzer.
37const MAX_DEPTH: usize = 1000;
38
39/// The `last` bound of `.**{}`, as `PG_UINT32_MAX`.
40pub const JSONPATH_LAST: u32 = u32::MAX;
41
42/// An operator or a method of a path, as `JsonPathItemType` has it.
43#[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    /// `jspOperationName`: the name of the operator or the method in the text form and in the errors of the executor. The operators `!`, `is unknown`, `?` and `exists` have no name there, and the name here is their text.
96    #[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    /// `operationPriority`: an operand with a priority that is not higher than the priority of its operator is in parentheses in the text form.
148    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/// One item of a path. The items that follow an item, its `next` items in PostgreSQL, are the items after it in its [`Chain`].
168#[derive(Clone, Debug, PartialEq)]
169pub enum PathItem {
170    /// `null`.
171    Null,
172    /// A string literal.
173    String(String),
174    /// A number literal.
175    Numeric(Numeric),
176    /// `true` or `false`.
177    Bool(bool),
178    /// `&&`, `||`, a comparison, an arithmetic operator or `starts with`, with the left and the right operand.
179    Binary(PathOp, Chain, Chain),
180    /// `!`, `is unknown`, unary `+` and `-`, the filter `?()` and `exists`, with the operand.
181    Unary(PathOp, Chain),
182    /// `like_regex`: the operand, the pattern and the bits of the flags.
183    LikeRegex { expr: Chain, pattern: String, flags: u8 },
184    /// `[*]`.
185    AnyArray,
186    /// `.*`.
187    AnyKey,
188    /// `[...]`: each subscript, with the end of a range `to`.
189    IndexArray(Vec<(Chain, Option<Chain>)>),
190    /// `.**`, with the first and the last level. [`JSONPATH_LAST`] is `last`.
191    Any { first: u32, last: u32 },
192    /// `.key`.
193    Key(String),
194    /// `@`.
195    Current,
196    /// `$`.
197    Root,
198    /// `$name`.
199    Variable(String),
200    /// `last`.
201    Last,
202    /// A method such as `.type()`, with its arguments. An argument is a string or a number.
203    Method(PathOp, Vec<PathItem>),
204}
205
206impl PathItem {
207    /// The priority of the item as an operand.
208    fn priority(&self) -> u8 {
209        match self {
210            PathItem::Binary(op, ..) | PathItem::Unary(op, _) => op.priority(),
211            _ => 6,
212        }
213    }
214}
215
216/// An item and the items that follow it. A chain is never empty.
217pub type Chain = Vec<PathItem>;
218
219/// A value of `jsonpath`.
220#[derive(Clone, Debug, PartialEq)]
221pub struct JsonPath {
222    /// False for `strict`.
223    pub lax: bool,
224    /// The path.
225    pub expr: Chain,
226}
227
228/// `jspConvertRegexFlags`: the `cflags` of the regular expression of `like_regex` with the flags `flags`.
229///
230/// # Errors
231///
232/// `0A000` for the flag `x` with no flag `q`.
233pub 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
258/// The check of a regular expression: the pattern and the `cflags`, and the message of `pg_regerror` for a pattern that is not valid.
259pub type RegexCheck<'a> = &'a dyn Fn(&str, u32) -> Result<(), String>;
260
261/// The error `22P02` of the type with a detail.
262fn 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
271/// `jsonpath_yyerror`: the message and the text of the token, or the end of the input when the text is empty.
272fn 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
281/// `special`: a character that is a token by itself.
282fn is_special(b: u8) -> bool {
283    b"?%$.[]{}()|&!=<>@#,*:-+/".contains(&b)
284}
285
286/// `blank`.
287fn is_blank(b: u8) -> bool {
288    matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0c)
289}
290
291/// `other`: a byte that is not special, not blank and not `\` or `"`.
292fn is_other(b: u8) -> bool {
293    !is_special(b) && !is_blank(b) && b != b'\\' && b != b'"'
294}
295
296/// A key word of the scanner.
297#[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    /// A key word that names a method.
314    Method(PathOp),
315}
316
317/// `keywords`: the key words, and true for a key word that matches only in lower case.
318const 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
362/// `checkKeyword`: the key word that a name is, if any.
363fn 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/// The kind of a token.
375#[derive(Clone, Copy, Debug, PartialEq, Eq)]
376enum Tok {
377    End,
378    And,
379    Or,
380    Not,
381    /// `**`.
382    AnyLevels,
383    Less,
384    LessEqual,
385    Equal,
386    NotEqual,
387    GreaterEqual,
388    Greater,
389    /// A special character.
390    Char(u8),
391    Variable,
392    Str,
393    Numeric,
394    Int,
395    Ident,
396    Kw(Kw),
397}
398
399/// A token: the kind, the bounds of the text of flex in the input, and the string of a name, a string, a variable or a number.
400struct Token {
401    tok: Tok,
402    text: (usize, usize),
403    value: Vec<u8>,
404}
405
406/// The rules of the start state of the scanner that can match at a position, in the order of `jsonpath_scan.l`.
407#[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/// The rules of an escape in a name or a string, in the order of `jsonpath_scan.l`.
425#[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
437/// The scanner, at a position of the input.
438struct Lexer<'a> {
439    s: &'a [u8],
440    at: usize,
441    /// True for the soft input of `pg_input_is_valid`, which changes the error for a code point that is too large.
442    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    /// The ends of the matches of `(_?{digit})*` after a digit that ends at `q`.
455    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    /// The ends of the matches of `decinteger` at `p`.
470    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    /// The ends of the matches of `decdigits` at `p`.
481    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    /// The ends of the matches of `decimal` at `p`.
488    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    /// The ends of the matches of `real` at `p`, and of `realfail`.
503    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    /// The end of the match of `0x`, `0o` or `0b` and its digits at `p`.
520    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    /// The end of a match of a rule `{x}_junk`: the longest match of `x` that one `other` byte follows.
534    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    /// The end of a run of bytes from `p` that `f` takes.
539    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    /// The longest rule of the start state at `p`, and the end of its match. The first rule wins a tie.
547    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        // The rule `\\` gives back its match, so it ties with nothing.
599        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    /// The next token. A name that a comment follows gives no token, as in PostgreSQL.
605    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    /// The state `xc`: the rest of a comment.
650    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    /// The state `xnq`: the rest of a name. The result is `None` when a comment follows the name, as the scanner of PostgreSQL then drops the name.
664    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    /// The states `xq` and `xvq`: the rest of a quoted string or variable.
694    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    /// The end of a match of `unicode` at `p`.
714    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    /// The end of the longest match of `unicodefail` at `p`.
727    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    /// An escape at the backslash at `self.at`, with the rules of `jsonpath_scan.l`.
739    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    /// `parseUnicode`: the escapes `\u` between the bounds, with the pairs of surrogates.
806    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    /// `addUnicodeChar`: one code point in UTF-8.
838    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
860/// The parser, with the token that it reads ahead.
861struct Parser<'a> {
862    lexer: Lexer<'a>,
863    ahead: Option<Token>,
864    depth: usize,
865    regex: RegexCheck<'a>,
866}
867
868/// The text of a token as a string.
869fn 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    /// The syntax error at the token that the parser reads ahead.
887    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    /// The guard of the depth of the recursion.
899    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    /// `expr_or_predicate`, or `predicate` when `pred` is true. The flag of the result is true for a predicate.
913    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    /// `EXISTS '(' expr ')'`.
962    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    /// An `expr`, where a predicate cannot be.
971    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    /// `makeItemLikeRegex`: the flags and the check of the pattern.
1020    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    /// Unary `+` and `-`, which `makeItemUnary` folds into a number.
1090    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    /// `accessor_expr`, or a predicate in parentheses with no accessor. When `expr` is true, a predicate in parentheses must have an accessor.
1104    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    /// The `accessor_op` items after an item.
1152    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    /// The accessor after `.`: a key, `*`, `**` or a method.
1199    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    /// `any_level`: a number or `last`. The number is an `int4`.
1237    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    /// The arguments of a method after `(`, and the `)`.
1252    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    /// `int_elem`: an integer with an optional sign.
1298    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
1311/// `makeItemNumeric`: the number of a token. An error of `numeric_in` is a hard error.
1312fn number(token: Token) -> Result<Numeric, TypeError> {
1313    numeric_in(&text_of(token.value), -1)
1314}
1315
1316/// `makeItemUnary` for `+` and `-`: a number with no accessor takes the sign.
1317fn 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
1327/// The checks of `flattenJsonPathParseItem`: `@` must be in a filter and `last` must be in a subscript. The order of the checks is the order of PostgreSQL: an item, then its operands, then the next item.
1328fn 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
1365/// `jsonpath_in`: a path from its text. `soft` is true for the soft input of `pg_input_is_valid`, and `regex` checks the pattern of `like_regex`.
1366///
1367/// # Errors
1368///
1369/// `42601` and `22P02` for text that is not a path, `22P05` for `\u0000`, `0A000` for the flag `x`, `2201B` for a pattern that is not valid, `22003` for a number that is too large and `54001` for a path that is too deep. The last two are hard errors in PostgreSQL.
1370pub 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
1397/// `printJsonPathItem` for a chain: the first item, then the items that follow it.
1398fn 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
1404/// An operand, in parentheses when its priority is not higher than `priority`.
1405fn print_operand(chain: &[PathItem], priority: u8, out: &mut String) {
1406    print_chain(chain, chain[0].priority() <= priority, out);
1407}
1408
1409/// `printJsonPathItem` for one item.
1410fn 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
1547/// `jsonpath_out`: the text form of a path.
1548pub 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
1557/// `jsonpath_send`: the version 1 and the text form.
1558pub fn jsonpath_send(path: &JsonPath, out: &mut Vec<u8>) {
1559    out.push(1);
1560    jsonpath_deparse(path, out);
1561}
1562
1563/// `jsonpath_recv`: a path from the version 1 and the text form. Each error is a hard error.
1564///
1565/// # Errors
1566///
1567/// `XX000` for another version, and the errors of [`jsonpath_parse`].
1568pub 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}