Skip to main content

rupg_func/
jsonpath.rs

1//! The executor of `jsonpath` from `jsonpath_exec.c`: `jsonb_path_exists`, `jsonb_path_match`, `jsonb_path_query`, `jsonb_path_query_array`, `jsonb_path_query_first`, their `_tz` forms, and the operators `@?` and `@@`.
2//!
3//! A path runs on the items of a `jsonb` value. An item is a scalar, or an array or an object in a parsed document. In the lax mode, a step unwraps an array and wraps a scalar, and the structural errors are not errors. A call that is not silent gives the error of a step to the caller. In a silent call, a step gives the result "error", and a predicate takes that result as unknown.
4//!
5//! The datetime methods parse a string in the standard mode of `to_timestamp`. The value of a datetime item has its type, and the text of the item is in the XSD style. The `_tz` functions can cast between the types with and without a zone, with the zone of the session. The other functions give an error for these casts.
6//!
7//! `.keyvalue()` gives each pair an `id` from the place of the object in the binary form of its document, as PostgreSQL does. Thus [`Doc::layout`] computes the layout of `convertToJsonb`.
8
9use std::cell::OnceCell;
10use std::cmp::Ordering;
11use std::io::Write;
12use std::rc::Rc;
13
14use rupg_common::{Error, Result, SqlState};
15use rupg_types::{
16    DateFormat, DateOrder, DateStyle, FixedZone, JSONPATH_LAST, JsonItem, JsonNode, JsonPath,
17    JsonTree, Numeric, NumericSign, PathItem, PathOp, UNIX_TO_POSTGRES_USECS, USECS_PER_SEC, Value,
18    adjust_time, adjust_timestamp, bool_in, date_out, float8_in, int4_in, int8_in, json_escape,
19    jsonpath_regex_flags, local_offset, numeric_in, numeric_out, oid, time_out, timestamp_out,
20    timestamptz_out,
21};
22
23use crate::cast::midnight;
24use crate::compare::{compare, datetime_order};
25use crate::formatting::parse_datetime;
26use crate::json::text;
27use crate::{Call, Kernel, bad_value, type_error};
28
29/// The kernel of a `jsonpath` function by its `prosrc`. The `_tz` forms differ only in the casts of the datetime values.
30pub(crate) fn by_src(src: &str) -> Option<Kernel> {
31    Some(match src {
32        "jsonb_path_exists" | "jsonb_path_exists_opr" => |call, args| exists(call, args, false),
33        "jsonb_path_exists_tz" => |call, args| exists(call, args, true),
34        "jsonb_path_match" | "jsonb_path_match_opr" => |call, args| path_match(call, args, false),
35        "jsonb_path_match_tz" => |call, args| path_match(call, args, true),
36        "jsonb_path_query_array" => |call, args| query_array(call, args, false),
37        "jsonb_path_query_array_tz" => |call, args| query_array(call, args, true),
38        "jsonb_path_query_first" => |call, args| query_first(call, args, false),
39        "jsonb_path_query_first_tz" => |call, args| query_first(call, args, true),
40        _ => return None,
41    })
42}
43
44/// The ISO formats that the datetime methods with no template try in order: `date`, `timetz`, `time`, `timestamptz` and `timestamp`, and the timestamps with `T` that `to_json` gives.
45const ISO_FORMATS: [&str; 13] = [
46    "yyyy-mm-dd",
47    "HH24:MI:SS.USTZ",
48    "HH24:MI:SSTZ",
49    "HH24:MI:SS.US",
50    "HH24:MI:SS",
51    "yyyy-mm-dd HH24:MI:SS.USTZ",
52    "yyyy-mm-dd HH24:MI:SSTZ",
53    "yyyy-mm-dd\"T\"HH24:MI:SS.USTZ",
54    "yyyy-mm-dd\"T\"HH24:MI:SSTZ",
55    "yyyy-mm-dd HH24:MI:SS.US",
56    "yyyy-mm-dd HH24:MI:SS",
57    "yyyy-mm-dd\"T\"HH24:MI:SS.US",
58    "yyyy-mm-dd\"T\"HH24:MI:SS",
59];
60
61/// The depth of the steps that a path takes before it stops with the error of `check_stack_depth`.
62const MAX_DEPTH: usize = 2_000;
63
64/// The multiplier of the id of the base object in the `id` of `.keyvalue()`.
65const BASE_ID_FACTOR: i64 = 10_000_000_000;
66
67/// A `jsonb` value that the items of a path refer into.
68struct Doc {
69    text: String,
70    nodes: Vec<JsonNode>,
71    /// The place of each array and object in the binary form, from [`Doc::layout`].
72    offsets: OnceCell<Vec<i64>>,
73}
74
75impl Doc {
76    /// Parses the text of a `jsonb` value.
77    fn parse(text: String) -> Result<Rc<Doc>> {
78        let nodes = JsonTree::parse(&text).map_err(type_error)?.into_nodes();
79        Ok(Rc::new(Doc { text, nodes, offsets: OnceCell::new() }))
80    }
81
82    fn item(&self, at: usize) -> &JsonItem {
83        &self.nodes[at].item
84    }
85
86    /// The text of a node, which is in the form of `jsonb_out`.
87    fn text(&self, at: usize) -> &str {
88        let node = &self.nodes[at];
89        &self.text[node.start..node.end]
90    }
91
92    /// `fillJsonbValue`: the item of a node. A scalar becomes a scalar item.
93    fn get(self: &Rc<Self>, at: usize) -> Result<Item> {
94        Ok(match self.item(at) {
95            JsonItem::Null => Item::Null,
96            JsonItem::Bool(b) => Item::Bool(*b),
97            JsonItem::Number => Item::Numeric(numeric_in(self.text(at), -1).map_err(type_error)?),
98            JsonItem::String(s) => Item::String(s.clone()),
99            JsonItem::Array(_) | JsonItem::Object(_) => Item::Node(Rc::clone(self), at),
100        })
101    }
102
103    /// The node of the value of the key `name`, when the node is an object. The keys of `jsonb` are unique.
104    fn field(&self, at: usize, name: &str) -> Option<usize> {
105        match self.item(at) {
106            JsonItem::Object(fields) => fields.iter().find(|(k, _)| k == name).map(|f| f.1),
107            _ => None,
108        }
109    }
110
111    /// The nodes of the elements of an array or of the values of an object, in the order of the binary form.
112    fn children(&self, at: usize) -> Vec<usize> {
113        match self.item(at) {
114            JsonItem::Array(items) => items.clone(),
115            JsonItem::Object(fields) => fields.iter().map(|f| f.1).collect(),
116            _ => Vec::new(),
117        }
118    }
119
120    /// The place of an array or an object in the binary form, from the start of the root container.
121    fn offset(&self, at: usize) -> i64 {
122        self.offsets.get_or_init(|| self.layout())[at]
123    }
124
125    /// `convertToJsonb`: the places of the arrays and the objects. The binary form starts with a header of 4 bytes. A container and a number start at a multiple of 4. A container has a header of 4 bytes and an entry of 4 bytes for each element, or for each key and each value. Then the data of the elements follows, or the keys and then the values.
126    fn layout(&self) -> Vec<i64> {
127        let mut offsets = vec![0; self.nodes.len()];
128        self.place(0, 4, &mut offsets);
129        offsets
130    }
131
132    /// Puts the node at `pos` and gives the end of its data.
133    fn place(&self, at: usize, pos: usize, offsets: &mut [i64]) -> usize {
134        let mut start = pos.next_multiple_of(4);
135        let (header, children) = match self.item(at) {
136            JsonItem::Null | JsonItem::Bool(_) => return pos,
137            JsonItem::String(s) => return pos + s.len(),
138            JsonItem::Number => {
139                return start + numeric_in(self.text(at), -1).map_or(8, |n| numeric_size(&n));
140            }
141            JsonItem::Array(items) => (4 + 4 * items.len(), items.clone()),
142            JsonItem::Object(fields) => {
143                let keys: usize = fields.iter().map(|f| f.0.len()).sum();
144                (4 + 8 * fields.len() + keys, fields.iter().map(|f| f.1).collect())
145            }
146        };
147        offsets[at] = i64::try_from(start - 4).unwrap_or(i64::MAX);
148        start += header;
149        for child in children {
150            start = self.place(child, start, offsets);
151        }
152        start
153    }
154}
155
156/// `VARSIZE` of a `numeric` that `make_result` makes: the header of the varlena, the short or the long header of the number, and the digits.
157fn numeric_size(n: &Numeric) -> usize {
158    let short = n.dscale() <= 0x3f && (-64..=63).contains(&n.weight());
159    4 + if short { 2 } else { 4 } + 2 * n.digits().len()
160}
161
162/// The text of a number as `numeric_out` gives it.
163fn numeric_text(n: &Numeric) -> String {
164    let mut out = Vec::new();
165    numeric_out(n, &mut out);
166    String::from_utf8(out).unwrap_or_default()
167}
168
169/// The number as an `integer`, rounded as `numeric_int4_safe` rounds it.
170fn int4(n: &Numeric) -> Option<i32> {
171    n.to_integer("integer").ok().and_then(|v| i32::try_from(v).ok())
172}
173
174/// True for `NaN` and the infinities.
175fn is_special(n: &Numeric) -> bool {
176    matches!(n.sign(), NumericSign::NaN | NumericSign::Infinity | NumericSign::NegativeInfinity)
177}
178
179/// An SQL/JSON item: a `JsonbValue` with the scalars extracted.
180#[derive(Clone)]
181enum Item {
182    Null,
183    Bool(bool),
184    Numeric(Numeric),
185    String(String),
186    /// An array or an object in a document.
187    Node(Rc<Doc>, usize),
188    /// A `date`, `time`, `timetz`, `timestamp` or `timestamptz` value, and its text.
189    Datetime(Value, String),
190}
191
192impl Item {
193    /// The elements of the item, when it is an array.
194    fn array(&self) -> Option<(&Rc<Doc>, usize, usize)> {
195        match self {
196            Item::Node(doc, at) => match doc.item(*at) {
197                JsonItem::Array(items) => Some((doc, *at, items.len())),
198                _ => None,
199            },
200            _ => None,
201        }
202    }
203
204    fn is_array(&self) -> bool {
205        self.array().is_some()
206    }
207
208    /// The document and the node of the item, when it is an object.
209    fn object(&self) -> Option<(&Rc<Doc>, usize)> {
210        match self {
211            Item::Node(doc, at) if matches!(doc.item(*at), JsonItem::Object(_)) => Some((doc, *at)),
212            _ => None,
213        }
214    }
215
216    /// `JsonbTypeName`.
217    fn type_name(&self) -> &'static str {
218        match self {
219            Item::Null => "null",
220            Item::Bool(_) => "boolean",
221            Item::Numeric(_) => "number",
222            Item::String(_) => "string",
223            Item::Node(..) if self.is_array() => "array",
224            Item::Node(..) => "object",
225            Item::Datetime(value, _) => match value {
226                Value::Date(_) => "date",
227                Value::Time(_) => "time without time zone",
228                Value::TimeTz(..) => "time with time zone",
229                Value::Timestamp(_) => "timestamp without time zone",
230                _ => "timestamp with time zone",
231            },
232        }
233    }
234
235    /// Adds the text of the item as `jsonb`.
236    fn write(&self, out: &mut String) {
237        match self {
238            Item::Null => out.push_str("null"),
239            Item::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
240            Item::Numeric(n) => out.push_str(&numeric_text(n)),
241            Item::String(s) | Item::Datetime(_, s) => json_escape(s, out),
242            Item::Node(doc, at) => out.push_str(doc.text(*at)),
243        }
244    }
245
246    /// The item as a `jsonb` value.
247    fn to_value(&self) -> Value {
248        let mut out = String::new();
249        self.write(&mut out);
250        Value::Text(out)
251    }
252}
253
254/// `JsonPathExecResult`.
255#[derive(Clone, Copy, Debug, PartialEq, Eq)]
256enum Res {
257    Ok,
258    NotFound,
259    Error,
260}
261
262/// `JsonPathBool`.
263#[derive(Clone, Copy, Debug, PartialEq, Eq)]
264enum Truth {
265    False,
266    True,
267    Unknown,
268}
269
270impl Truth {
271    fn of(b: bool) -> Truth {
272        if b { Truth::True } else { Truth::False }
273    }
274}
275
276/// The list of the items that a step finds, or `None` when the caller only wants to know if there is an item.
277type Found<'f> = Option<&'f mut Vec<Item>>;
278
279/// The test of a predicate on an item of the left operand and an item of the right operand.
280type Test<'t> = &'t mut dyn FnMut(&Item, Option<&Item>) -> Result<Truth>;
281
282/// `JsonBaseObjectInfo`: the container that the ids of `.keyvalue()` count from, and its id.
283#[derive(Clone)]
284struct Base {
285    node: Option<(Rc<Doc>, usize)>,
286    id: i64,
287}
288
289impl Base {
290    /// `setBaseObject`.
291    fn of(item: &Item, id: i64) -> Base {
292        let node = match item {
293            Item::Node(doc, at) => Some((Rc::clone(doc), *at)),
294            _ => None,
295        };
296        Base { node, id }
297    }
298}
299
300/// The arguments of `executeAnyItem` that stay the same at each level.
301struct Walk<'c> {
302    /// The steps to run on each item, or no steps to add the items.
303    chain: &'c [PathItem],
304    first: u32,
305    last: u32,
306    ignore_structural: bool,
307    unwrap: bool,
308}
309
310impl Walk<'_> {
311    /// The walk of one level.
312    fn one(chain: &[PathItem], unwrap: bool) -> Walk<'_> {
313        Walk { chain, first: 1, last: 1, ignore_structural: false, unwrap }
314    }
315}
316
317/// The error of `check_stack_depth`.
318fn too_deep() -> Error {
319    Error::new(SqlState::STATEMENT_TOO_COMPLEX, "stack depth limit exceeded").with_hint("Increase the configuration parameter \"max_stack_depth\" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.")
320}
321
322/// The first item of an operand.
323fn head(chain: &[PathItem]) -> Result<&PathItem> {
324    chain.first().ok_or_else(|| Error::internal("empty jsonpath expression"))
325}
326
327/// The variables of a path.
328enum Vars<'a> {
329    /// An operator, which has no variables.
330    None,
331    /// The object of the argument `vars` of a function.
332    Object(Rc<Doc>),
333    /// The `PASSING` clause of a SQL/JSON query function.
334    Passing(&'a [PathVar]),
335}
336
337/// A value of the `PASSING` clause of a SQL/JSON query function: its name, its type and its value.
338#[derive(Clone, Debug, PartialEq)]
339pub struct PathVar {
340    pub name: String,
341    pub ty: u32,
342    pub value: Value,
343}
344
345/// An item that a SQL/JSON query function finds.
346#[derive(Clone, Debug, PartialEq)]
347pub enum SqlJsonItem {
348    Null,
349    Bool(bool),
350    Numeric(Numeric),
351    String(String),
352    /// A `date`, `time`, `timetz`, `timestamp` or `timestamptz` value, and its text in `jsonb`.
353    Datetime(Value, String),
354    /// An array or an object, as the text of `jsonb`.
355    Container(String),
356}
357
358impl SqlJsonItem {
359    /// The text of the item as `jsonb`.
360    pub fn jsonb(&self) -> String {
361        let mut out = String::new();
362        match self {
363            SqlJsonItem::Null => out.push_str("null"),
364            SqlJsonItem::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
365            SqlJsonItem::Numeric(n) => out.push_str(&numeric_text(n)),
366            SqlJsonItem::String(s) | SqlJsonItem::Datetime(_, s) => json_escape(s, &mut out),
367            SqlJsonItem::Container(text) => out.push_str(text),
368        }
369        out
370    }
371}
372
373/// `JsonItemFromDatum`: the item of a value of `PASSING`.
374fn passing_item(call: &Call<'_>, var: &PathVar) -> Result<Item> {
375    Ok(match (var.ty, &var.value) {
376        (_, Value::Null) => Item::Null,
377        (oid::BOOL, Value::Bool(b)) => Item::Bool(*b),
378        (oid::NUMERIC, Value::Numeric(n)) => Item::Numeric(n.clone()),
379        (oid::INT2 | oid::INT4 | oid::INT8, value) => {
380            Item::Numeric(Numeric::from_integer(value.as_i64().ok_or_else(bad_value)?.into()))
381        }
382        (oid::FLOAT4, value @ Value::Float4(_)) => {
383            match crate::cast::float4_to_numeric(call, std::slice::from_ref(value))? {
384                Value::Numeric(n) => Item::Numeric(n),
385                _ => return Err(bad_value()),
386            }
387        }
388        (oid::FLOAT8, Value::Float8(f)) => Item::Numeric(Numeric::from_f64(*f)),
389        (oid::TEXT | oid::VARCHAR, Value::Text(s)) => Item::String(s.clone()),
390        (oid::DATE | oid::TIME | oid::TIMETZ | oid::TIMESTAMP | oid::TIMESTAMPTZ, value) => {
391            Item::Datetime(value.clone(), datetime_text(value, 0)?)
392        }
393        (oid::JSONB, Value::Text(text)) => Doc::parse(text.clone())?.get(0)?,
394        (oid::JSON, Value::Text(text)) => {
395            let Value::Text(text) = crate::input(oid::JSONB, text, -1, call.session)? else {
396                return Err(bad_value());
397            };
398            Doc::parse(text)?.get(0)?
399        }
400        (ty, _) => {
401            return Err(Error::new(
402                SqlState::INVALID_PARAMETER_VALUE,
403                format!(
404                    "could not convert value of type {} to jsonpath",
405                    crate::type_message_name(ty, call.session)
406                ),
407            ));
408        }
409    })
410}
411
412/// `JsonPathExecContext`.
413struct Exec<'a> {
414    call: &'a Call<'a>,
415    vars: Vars<'a>,
416    lax: bool,
417    ignore_structural: bool,
418    throw: bool,
419    root: Item,
420    current: Item,
421    base: Base,
422    last_id: i64,
423    /// The size of the innermost array of a subscript, for `last`.
424    innermost: Option<usize>,
425    depth: usize,
426    /// True for the `_tz` functions, which can cast a datetime value with the zone of the session.
427    use_tz: bool,
428}
429
430impl Exec<'_> {
431    /// `RETURN_ERROR`: the error when the call is not silent, or the result "error".
432    fn fail(&self, error: Error) -> Result<Res> {
433        if self.throw { Err(error) } else { Ok(Res::Error) }
434    }
435
436    /// [`Exec::fail`] for a step that gives a value: `None` is the result "error".
437    fn fail_value<T>(&self, error: Error) -> Result<Option<T>> {
438        if self.throw { Err(error) } else { Ok(None) }
439    }
440
441    /// The error of a method on an item that it does not take.
442    fn method_fail(&self, state: SqlState, op: PathOp, what: &str) -> Result<Res> {
443        self.fail(Error::new(
444            state,
445            format!("jsonpath item method .{}() can only be applied to {what}", op.name()),
446        ))
447    }
448
449    /// The error of a method for an argument that it cannot cast.
450    fn invalid_argument(&self, text: &str, op: PathOp, sqltype: &str) -> Result<Res> {
451        self.fail(Error::new(
452            SqlState::NON_NUMERIC_SQL_JSON_ITEM,
453            format!(
454                "argument \"{text}\" of jsonpath item method .{}() is invalid for type {sqltype}",
455                op.name()
456            ),
457        ))
458    }
459
460    /// Runs `f` with the errors silent, as the `NoThrow` functions do.
461    fn quiet<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
462        let throw = std::mem::replace(&mut self.throw, false);
463        let out = f(self);
464        self.throw = throw;
465        out
466    }
467
468    /// `executeItem`.
469    fn item(&mut self, chain: &[PathItem], jb: &Item, found: Found<'_>) -> Result<Res> {
470        self.target(chain, jb, found, self.lax)
471    }
472
473    /// `executeNextItem`: runs `rest` on `v`, or adds `v` to `found` when there are no more steps.
474    fn next(&mut self, rest: &[PathItem], v: Item, found: Found<'_>) -> Result<Res> {
475        if !rest.is_empty() {
476            return self.item(rest, &v, found);
477        }
478        if let Some(found) = found {
479            found.push(v);
480        }
481        Ok(Res::Ok)
482    }
483
484    /// `executeItemOptUnwrapTarget`.
485    fn target(
486        &mut self,
487        chain: &[PathItem],
488        jb: &Item,
489        found: Found<'_>,
490        unwrap: bool,
491    ) -> Result<Res> {
492        if self.depth >= MAX_DEPTH {
493            return Err(too_deep());
494        }
495        self.depth += 1;
496        let res = self.step(chain, jb, found, unwrap);
497        self.depth -= 1;
498        res
499    }
500
501    /// `executeItemUnwrapTargetArray`: runs the steps on each element of the array, with no unwrap of the elements.
502    fn unwrap_target(&mut self, chain: &[PathItem], jb: &Item, found: Found<'_>) -> Result<Res> {
503        let Some((doc, at, _)) = jb.array() else { return Err(bad_value()) };
504        self.any(&Walk::one(chain, false), doc, at, found, 1)
505    }
506
507    /// The body of `executeItemOptUnwrapTarget` for the first step of `chain`.
508    fn step(
509        &mut self,
510        chain: &[PathItem],
511        jb: &Item,
512        mut found: Found<'_>,
513        unwrap: bool,
514    ) -> Result<Res> {
515        let (jsp, rest) = (head(chain)?, &chain[1..]);
516        match jsp {
517            PathItem::Null
518            | PathItem::Bool(_)
519            | PathItem::Numeric(_)
520            | PathItem::String(_)
521            | PathItem::Variable(_) => {
522                // Skip the evaluation, but not for a variable, which must give the error when it is missing.
523                if rest.is_empty() && found.is_none() && !matches!(jsp, PathItem::Variable(_)) {
524                    return Ok(Res::Ok);
525                }
526                let base = self.base.clone();
527                let v = self.literal(jsp)?;
528                let res = self.next(rest, v, found);
529                self.base = base;
530                res
531            }
532            PathItem::Binary(
533                op @ (PathOp::Add | PathOp::Sub | PathOp::Mul | PathOp::Div | PathOp::Mod),
534                l,
535                r,
536            ) => self.binary_arith(*op, l, r, rest, jb, found),
537            PathItem::Unary(op @ (PathOp::Plus | PathOp::Minus), arg) => {
538                self.unary_arith(*op, arg, rest, jb, found)
539            }
540            PathItem::Unary(PathOp::Filter, cond) => {
541                if unwrap && jb.is_array() {
542                    return self.unwrap_target(chain, jb, found);
543                }
544                if self.nested_truth(cond, jb)? != Truth::True {
545                    return Ok(Res::NotFound);
546                }
547                self.next(rest, jb.clone(), found)
548            }
549            PathItem::Binary(..) | PathItem::Unary(..) | PathItem::LikeRegex { .. } => {
550                let st = self.truth(jsp, jb)?;
551                self.append_bool(rest, found, st)
552            }
553            PathItem::AnyArray => {
554                if let Some((doc, at, _)) = jb.array() {
555                    return self.any(&Walk::one(rest, self.lax), doc, at, found, 1);
556                }
557                if self.lax {
558                    return self.next(rest, jb.clone(), found);
559                }
560                if !self.ignore_structural {
561                    return self.fail(Error::new(
562                        SqlState::SQL_JSON_ARRAY_NOT_FOUND,
563                        "jsonpath wildcard array accessor can only be applied to an array",
564                    ));
565                }
566                Ok(Res::NotFound)
567            }
568            PathItem::AnyKey => {
569                if let Some((doc, at)) = jb.object() {
570                    return self.any(&Walk::one(rest, self.lax), doc, at, found, 1);
571                }
572                if unwrap && jb.is_array() {
573                    return self.unwrap_target(chain, jb, found);
574                }
575                if !self.ignore_structural {
576                    return self.fail(Error::new(
577                        SqlState::SQL_JSON_OBJECT_NOT_FOUND,
578                        "jsonpath wildcard member accessor can only be applied to an object",
579                    ));
580                }
581                Ok(Res::NotFound)
582            }
583            PathItem::IndexArray(subscripts) => {
584                if !jb.is_array() && !self.lax {
585                    if !self.ignore_structural {
586                        return self.fail(Error::new(
587                            SqlState::SQL_JSON_ARRAY_NOT_FOUND,
588                            "jsonpath array accessor can only be applied to an array",
589                        ));
590                    }
591                    return Ok(Res::NotFound);
592                }
593                let saved = self.innermost;
594                let res = self.subscripts(subscripts, rest, jb, found);
595                self.innermost = saved;
596                res
597            }
598            PathItem::Any { first, last } => {
599                let mut res = Res::NotFound;
600                // First try with no steps between.
601                if *first == 0 {
602                    let saved = std::mem::replace(&mut self.ignore_structural, true);
603                    res = self.next(rest, jb.clone(), found.as_deref_mut())?;
604                    self.ignore_structural = saved;
605                    if res == Res::Ok && found.is_none() {
606                        return Ok(res);
607                    }
608                }
609                if let Item::Node(doc, at) = jb {
610                    let walk = Walk {
611                        chain: rest,
612                        first: *first,
613                        last: *last,
614                        ignore_structural: true,
615                        unwrap: self.lax,
616                    };
617                    res = self.any(&walk, doc, *at, found, 1)?;
618                }
619                Ok(res)
620            }
621            PathItem::Key(name) => {
622                if let Some((doc, at)) = jb.object() {
623                    if let Some(child) = doc.field(at, name) {
624                        return self.next(rest, doc.get(child)?, found);
625                    }
626                    if !self.ignore_structural {
627                        return self.fail(Error::new(
628                            SqlState::SQL_JSON_MEMBER_NOT_FOUND,
629                            format!("JSON object does not contain key \"{name}\""),
630                        ));
631                    }
632                    return Ok(Res::NotFound);
633                }
634                if unwrap && jb.is_array() {
635                    return self.unwrap_target(chain, jb, found);
636                }
637                if !self.ignore_structural {
638                    return self.fail(Error::new(
639                        SqlState::SQL_JSON_MEMBER_NOT_FOUND,
640                        "jsonpath member accessor can only be applied to an object",
641                    ));
642                }
643                Ok(Res::NotFound)
644            }
645            PathItem::Current => {
646                let current = self.current.clone();
647                self.next(rest, current, found)
648            }
649            PathItem::Root => {
650                let root = self.root.clone();
651                let base = std::mem::replace(&mut self.base, Base::of(&root, 0));
652                let res = self.next(rest, root, found);
653                self.base = base;
654                res
655            }
656            PathItem::Last => {
657                let Some(size) = self.innermost else {
658                    return Err(Error::internal(
659                        "evaluating jsonpath LAST outside of array subscript",
660                    ));
661                };
662                if rest.is_empty() && found.is_none() {
663                    return Ok(Res::Ok);
664                }
665                let last = i128::try_from(size).unwrap_or(i128::MAX) - 1;
666                self.next(rest, Item::Numeric(Numeric::from_integer(last)), found)
667            }
668            PathItem::Method(op, args) => self.method(*op, args, chain, jb, found, unwrap),
669        }
670    }
671
672    /// `getJsonPathItem`: the value of a literal or of a variable. A variable makes the object of the variables the base object.
673    fn literal(&mut self, jsp: &PathItem) -> Result<Item> {
674        Ok(match jsp {
675            PathItem::Null => Item::Null,
676            PathItem::Bool(b) => Item::Bool(*b),
677            PathItem::Numeric(n) => Item::Numeric(n.clone()),
678            PathItem::String(s) => Item::String(s.clone()),
679            PathItem::Variable(name) => {
680                let missing = || {
681                    Error::new(
682                        SqlState::UNDEFINED_OBJECT,
683                        format!("could not find jsonpath variable \"{name}\""),
684                    )
685                };
686                match &self.vars {
687                    Vars::None => return Err(missing()),
688                    Vars::Object(vars) => {
689                        let vars = Rc::clone(vars);
690                        let child = vars.field(0, name).ok_or_else(missing)?;
691                        self.base = Base { node: Some((Rc::clone(&vars), 0)), id: 1 };
692                        vars.get(child)?
693                    }
694                    Vars::Passing(vars) => {
695                        let at = vars.iter().position(|v| v.name == *name).ok_or_else(missing)?;
696                        let item = passing_item(self.call, &vars[at])?;
697                        self.base = Base::of(&item, i64::try_from(at + 1).unwrap_or(i64::MAX));
698                        item
699                    }
700                }
701            }
702            _ => return Err(Error::internal("unexpected jsonpath item type")),
703        })
704    }
705
706    /// The subscripts of `jpiIndexArray` on an array, or on a scalar that the lax mode wraps.
707    fn subscripts(
708        &mut self,
709        subscripts: &[(Vec<PathItem>, Option<Vec<PathItem>>)],
710        rest: &[PathItem],
711        jb: &Item,
712        mut found: Found<'_>,
713    ) -> Result<Res> {
714        let array = jb.array();
715        let size = array.map_or(1, |a| a.2);
716        self.innermost = Some(size);
717        let size = i64::try_from(size).unwrap_or(i64::MAX);
718        let mut res = Res::NotFound;
719        for (from, to) in subscripts {
720            let Some(index_from) = self.index(from, jb)? else {
721                res = Res::Error;
722                break;
723            };
724            let index_to = match to {
725                Some(to) => match self.index(to, jb)? {
726                    Some(index) => index,
727                    None => {
728                        res = Res::Error;
729                        break;
730                    }
731                },
732                None => index_from,
733            };
734            let (index_from, index_to) = (i64::from(index_from), i64::from(index_to));
735            if !self.ignore_structural
736                && (index_from < 0 || index_from > index_to || index_to >= size)
737            {
738                return self.fail(Error::new(
739                    SqlState::INVALID_SQL_JSON_SUBSCRIPT,
740                    "jsonpath array subscript is out of bounds",
741                ));
742            }
743            res = Res::NotFound;
744            for index in index_from.max(0)..=index_to.min(size - 1) {
745                let v = match array {
746                    None => jb.clone(),
747                    Some((doc, at, _)) => {
748                        let JsonItem::Array(items) = doc.item(at) else { break };
749                        match usize::try_from(index).ok().and_then(|i| items.get(i)) {
750                            Some(&child) => doc.get(child)?,
751                            None => continue,
752                        }
753                    }
754                };
755                if rest.is_empty() && found.is_none() {
756                    return Ok(Res::Ok);
757                }
758                res = self.next(rest, v, found.as_deref_mut())?;
759                if res == Res::Error || (res == Res::Ok && found.is_none()) {
760                    break;
761                }
762            }
763            if res == Res::Error || (res == Res::Ok && found.is_none()) {
764                break;
765            }
766        }
767        Ok(res)
768    }
769
770    /// `getArrayIndex`: the subscript as an integer, truncated, or `None` for the result "error".
771    fn index(&mut self, chain: &[PathItem], jb: &Item) -> Result<Option<i32>> {
772        let mut found = Vec::new();
773        if self.item(chain, jb, Some(&mut found))? == Res::Error {
774            return Ok(None);
775        }
776        let [Item::Numeric(n)] = found.as_slice() else {
777            return self.fail_value(Error::new(
778                SqlState::INVALID_SQL_JSON_SUBSCRIPT,
779                "jsonpath array subscript is not a single numeric value",
780            ));
781        };
782        match n.trunc(0).ok().as_ref().and_then(int4) {
783            Some(index) => Ok(Some(index)),
784            None => self.fail_value(Error::new(
785                SqlState::INVALID_SQL_JSON_SUBSCRIPT,
786                "jsonpath array subscript is out of integer range",
787            )),
788        }
789    }
790
791    /// `executeAnyItem`: `.**`, `.*` and `[*]` on the container at `at`. `level` is the level of its children.
792    fn any(
793        &mut self,
794        walk: &Walk<'_>,
795        doc: &Rc<Doc>,
796        at: usize,
797        mut found: Found<'_>,
798        level: u32,
799    ) -> Result<Res> {
800        let mut res = Res::NotFound;
801        if level > walk.last {
802            return Ok(res);
803        }
804        if self.depth >= MAX_DEPTH {
805            return Err(too_deep());
806        }
807        self.depth += 1;
808        for child in doc.children(at) {
809            let v = doc.get(child)?;
810            let nested = matches!(v, Item::Node(..));
811            // `.**{last}` takes only the leaves.
812            if level >= walk.first
813                || (walk.first == JSONPATH_LAST && walk.last == JSONPATH_LAST && !nested)
814            {
815                if !walk.chain.is_empty() {
816                    let saved = self.ignore_structural;
817                    if walk.ignore_structural {
818                        self.ignore_structural = true;
819                    }
820                    res = self.target(walk.chain, &v, found.as_deref_mut(), walk.unwrap)?;
821                    self.ignore_structural = saved;
822                    if res == Res::Error || (res == Res::Ok && found.is_none()) {
823                        break;
824                    }
825                } else if let Some(found) = found.as_deref_mut() {
826                    found.push(v);
827                } else {
828                    self.depth -= 1;
829                    return Ok(Res::Ok);
830                }
831            }
832            if level < walk.last && nested {
833                res = self.any(walk, doc, child, found.as_deref_mut(), level + 1)?;
834                if res == Res::Error || (res == Res::Ok && found.is_none()) {
835                    break;
836                }
837            }
838        }
839        self.depth -= 1;
840        Ok(res)
841    }
842
843    /// `executeItemOptUnwrapResult`: the items of the steps, with each array unwrapped in the lax mode when `unwrap` is true.
844    fn sequence(
845        &mut self,
846        chain: &[PathItem],
847        jb: &Item,
848        unwrap: bool,
849        found: &mut Vec<Item>,
850    ) -> Result<Res> {
851        if !(unwrap && self.lax) {
852            return self.item(chain, jb, Some(found));
853        }
854        let mut seq = Vec::new();
855        if self.item(chain, jb, Some(&mut seq))? == Res::Error {
856            return Ok(Res::Error);
857        }
858        for item in seq {
859            match item.array() {
860                Some((doc, at, _)) => {
861                    self.any(&Walk::one(&[], false), doc, at, Some(found), 1)?;
862                }
863                None => found.push(item),
864            }
865        }
866        Ok(Res::Ok)
867    }
868
869    /// `executeBoolItem`.
870    fn truth(&mut self, jsp: &PathItem, jb: &Item) -> Result<Truth> {
871        Ok(match jsp {
872            PathItem::Binary(PathOp::And, l, r) => {
873                let res = self.truth(head(l)?, jb)?;
874                if res == Truth::False {
875                    return Ok(Truth::False);
876                }
877                // SQL/JSON says to check the second operand when the first is unknown.
878                let res2 = self.truth(head(r)?, jb)?;
879                if res2 == Truth::True { res } else { res2 }
880            }
881            PathItem::Binary(PathOp::Or, l, r) => {
882                let res = self.truth(head(l)?, jb)?;
883                if res == Truth::True {
884                    return Ok(Truth::True);
885                }
886                let res2 = self.truth(head(r)?, jb)?;
887                if res2 == Truth::False { res } else { res2 }
888            }
889            PathItem::Unary(PathOp::Not, arg) => match self.truth(head(arg)?, jb)? {
890                Truth::Unknown => Truth::Unknown,
891                Truth::True => Truth::False,
892                Truth::False => Truth::True,
893            },
894            PathItem::Unary(PathOp::IsUnknown, arg) => {
895                Truth::of(self.truth(head(arg)?, jb)? == Truth::Unknown)
896            }
897            PathItem::Binary(
898                op @ (PathOp::Equal
899                | PathOp::NotEqual
900                | PathOp::Less
901                | PathOp::Greater
902                | PathOp::LessOrEqual
903                | PathOp::GreaterOrEqual),
904                l,
905                r,
906            ) => {
907                let (op, call, use_tz) = (*op, self.call, self.use_tz);
908                let mut test = |a: &Item, b: Option<&Item>| match b {
909                    Some(b) => compare_items(call, use_tz, op, a, b),
910                    None => Ok(Truth::Unknown),
911                };
912                self.predicate(l, Some(r), jb, true, &mut test)?
913            }
914            PathItem::Binary(PathOp::StartsWith, l, r) => {
915                let mut test = |whole: &Item, initial: Option<&Item>| {
916                    Ok(match (whole, initial) {
917                        (Item::String(whole), Some(Item::String(initial))) => {
918                            Truth::of(whole.as_bytes().starts_with(initial.as_bytes()))
919                        }
920                        _ => Truth::Unknown,
921                    })
922                };
923                self.predicate(l, Some(r), jb, false, &mut test)?
924            }
925            PathItem::LikeRegex { expr, pattern, flags } => {
926                let cflags = jsonpath_regex_flags(*flags).map_err(type_error)?;
927                let mut regex = None;
928                let mut test = |s: &Item, _: Option<&Item>| {
929                    let Item::String(s) = s else { return Ok(Truth::Unknown) };
930                    if regex.is_none() {
931                        regex = Some(crate::regex::compile(pattern, cflags)?);
932                    }
933                    Ok(Truth::of(regex.as_ref().is_some_and(|r| r.is_match(s))))
934                };
935                self.predicate(expr, None, jb, false, &mut test)?
936            }
937            PathItem::Unary(PathOp::Exists, arg) => {
938                if self.lax {
939                    match self.quiet(|x| x.item(arg, jb, None))? {
940                        Res::Error => Truth::Unknown,
941                        res => Truth::of(res == Res::Ok),
942                    }
943                } else {
944                    // The strict mode needs all the items to check that there is no error.
945                    let mut vals = Vec::new();
946                    match self.quiet(|x| x.item(arg, jb, Some(&mut vals)))? {
947                        Res::Error => Truth::Unknown,
948                        _ => Truth::of(!vals.is_empty()),
949                    }
950                }
951            }
952            _ => return Err(Error::internal("invalid boolean jsonpath item type")),
953        })
954    }
955
956    /// `executeNestedBoolItem`: the condition of a filter, with `@` as the item.
957    fn nested_truth(&mut self, cond: &[PathItem], jb: &Item) -> Result<Truth> {
958        let prev = std::mem::replace(&mut self.current, jb.clone());
959        let res = self.truth(head(cond)?, jb);
960        self.current = prev;
961        res
962    }
963
964    /// `executePredicate`: true when a pair of an item of the left operand and an item of the right operand passes the test. The strict mode checks all the pairs for errors.
965    fn predicate(
966        &mut self,
967        l: &[PathItem],
968        r: Option<&[PathItem]>,
969        jb: &Item,
970        unwrap_right: bool,
971        test: Test<'_>,
972    ) -> Result<Truth> {
973        let mut lseq = Vec::new();
974        if self.quiet(|x| x.sequence(l, jb, true, &mut lseq))? == Res::Error {
975            return Ok(Truth::Unknown);
976        }
977        let mut rseq = Vec::new();
978        if let Some(r) = r
979            && self.quiet(|x| x.sequence(r, jb, unwrap_right, &mut rseq))? == Res::Error
980        {
981            return Ok(Truth::Unknown);
982        }
983        let (mut error, mut found) = (false, false);
984        for lval in &lseq {
985            let mut check = |rval: Option<&Item>| -> Result<bool> {
986                match test(lval, rval)? {
987                    Truth::Unknown => {
988                        error = true;
989                        Ok(!self.lax)
990                    }
991                    Truth::True => {
992                        found = true;
993                        Ok(self.lax)
994                    }
995                    Truth::False => Ok(false),
996                }
997            };
998            let stop = if r.is_some() {
999                let mut stop = false;
1000                for rval in &rseq {
1001                    if check(Some(rval))? {
1002                        stop = true;
1003                        break;
1004                    }
1005                }
1006                stop
1007            } else {
1008                check(None)?
1009            };
1010            if stop {
1011                // An error in the strict mode gives unknown, not success.
1012                if error && !self.lax {
1013                    return Ok(Truth::Unknown);
1014                }
1015                break;
1016            }
1017        }
1018        Ok(if found {
1019            Truth::True
1020        } else if error {
1021            Truth::Unknown
1022        } else {
1023            Truth::False
1024        })
1025    }
1026
1027    /// `appendBoolResult`: the result of a predicate as an item. Unknown is `null`.
1028    fn append_bool(&mut self, rest: &[PathItem], found: Found<'_>, st: Truth) -> Result<Res> {
1029        if rest.is_empty() && found.is_none() {
1030            return Ok(Res::Ok);
1031        }
1032        let v = match st {
1033            Truth::Unknown => Item::Null,
1034            st => Item::Bool(st == Truth::True),
1035        };
1036        self.next(rest, v, found)
1037    }
1038
1039    /// `executeBinaryArithmExpr`: the operands must be single numbers. The lax mode unwraps the arrays.
1040    fn binary_arith(
1041        &mut self,
1042        op: PathOp,
1043        l: &[PathItem],
1044        r: &[PathItem],
1045        rest: &[PathItem],
1046        jb: &Item,
1047        found: Found<'_>,
1048    ) -> Result<Res> {
1049        let (mut lseq, mut rseq) = (Vec::new(), Vec::new());
1050        if self.sequence(l, jb, true, &mut lseq)? == Res::Error
1051            || self.sequence(r, jb, true, &mut rseq)? == Res::Error
1052        {
1053            return Ok(Res::Error);
1054        }
1055        let single = |side: &str| {
1056            Error::new(
1057                SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED,
1058                format!(
1059                    "{side} operand of jsonpath operator {} is not a single numeric value",
1060                    op.name()
1061                ),
1062            )
1063        };
1064        let [Item::Numeric(a)] = lseq.as_slice() else { return self.fail(single("left")) };
1065        let [Item::Numeric(b)] = rseq.as_slice() else { return self.fail(single("right")) };
1066        let v = match op {
1067            PathOp::Add => a.add(b),
1068            PathOp::Sub => a.sub(b),
1069            PathOp::Mul => a.mul(b),
1070            PathOp::Div => a.div(b),
1071            _ => a.modulo(b),
1072        };
1073        let v = match v {
1074            Ok(v) => v,
1075            Err(error) => return self.fail(type_error(error)),
1076        };
1077        if rest.is_empty() && found.is_none() {
1078            return Ok(Res::Ok);
1079        }
1080        self.next(rest, Item::Numeric(v), found)
1081    }
1082
1083    /// `executeUnaryArithmExpr`: the operator on each number of the operand.
1084    fn unary_arith(
1085        &mut self,
1086        op: PathOp,
1087        arg: &[PathItem],
1088        rest: &[PathItem],
1089        jb: &Item,
1090        mut found: Found<'_>,
1091    ) -> Result<Res> {
1092        let mut seq = Vec::new();
1093        if self.sequence(arg, jb, true, &mut seq)? == Res::Error {
1094            return Ok(Res::Error);
1095        }
1096        let mut res = Res::NotFound;
1097        let has_next = !rest.is_empty();
1098        for val in seq {
1099            let Item::Numeric(n) = val else {
1100                if found.is_none() && !has_next {
1101                    continue;
1102                }
1103                return self.fail(Error::new(
1104                    SqlState::SQL_JSON_NUMBER_NOT_FOUND,
1105                    format!(
1106                        "operand of unary jsonpath operator {} is not a numeric value",
1107                        op.name()
1108                    ),
1109                ));
1110            };
1111            if found.is_none() && !has_next {
1112                return Ok(Res::Ok);
1113            }
1114            let n = if op == PathOp::Minus { n.negate() } else { n };
1115            match self.next(rest, Item::Numeric(n), found.as_deref_mut())? {
1116                Res::Error => return Ok(Res::Error),
1117                Res::Ok if found.is_none() => return Ok(Res::Ok),
1118                Res::Ok => res = Res::Ok,
1119                Res::NotFound => {}
1120            }
1121        }
1122        Ok(res)
1123    }
1124
1125    /// The item methods.
1126    fn method(
1127        &mut self,
1128        op: PathOp,
1129        args: &[PathItem],
1130        chain: &[PathItem],
1131        jb: &Item,
1132        found: Found<'_>,
1133        unwrap: bool,
1134    ) -> Result<Res> {
1135        let rest = &chain[1..];
1136        match op {
1137            PathOp::Type => self.next(rest, Item::String(jb.type_name().to_string()), found),
1138            PathOp::Size => {
1139                let size = match jb.array() {
1140                    Some((.., size)) => size,
1141                    None if !self.lax => {
1142                        if !self.ignore_structural {
1143                            return self.method_fail(
1144                                SqlState::SQL_JSON_ARRAY_NOT_FOUND,
1145                                op,
1146                                "an array",
1147                            );
1148                        }
1149                        return Ok(Res::NotFound);
1150                    }
1151                    None => 1,
1152                };
1153                let size = i128::try_from(size).unwrap_or(i128::MAX);
1154                self.next(rest, Item::Numeric(Numeric::from_integer(size)), found)
1155            }
1156            _ if unwrap && jb.is_array() => self.unwrap_target(chain, jb, found),
1157            PathOp::Abs | PathOp::Floor | PathOp::Ceiling => {
1158                let Item::Numeric(n) = jb else {
1159                    return self.method_fail(
1160                        SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1161                        op,
1162                        "a numeric value",
1163                    );
1164                };
1165                let v = match op {
1166                    PathOp::Abs => n.abs(),
1167                    PathOp::Floor => n.whole(false).map_err(type_error)?,
1168                    _ => n.whole(true).map_err(type_error)?,
1169                };
1170                if rest.is_empty() && found.is_none() {
1171                    return Ok(Res::Ok);
1172                }
1173                self.next(rest, Item::Numeric(v), found)
1174            }
1175            PathOp::Double => {
1176                let not_finite = || {
1177                    Error::new(
1178                        SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1179                        format!(
1180                            "NaN or Infinity is not allowed for jsonpath item method .{}()",
1181                            op.name()
1182                        ),
1183                    )
1184                };
1185                let sqltype = "double precision";
1186                let v = match jb {
1187                    Item::Numeric(n) => {
1188                        let text = numeric_text(n);
1189                        match float8_in(&text) {
1190                            Err(_) => return self.invalid_argument(&text, op, sqltype),
1191                            Ok(f) if !f.is_finite() => return self.fail(not_finite()),
1192                            Ok(_) => jb.clone(),
1193                        }
1194                    }
1195                    Item::String(s) => match float8_in(s) {
1196                        Err(_) => return self.invalid_argument(s, op, sqltype),
1197                        Ok(f) if !f.is_finite() => return self.fail(not_finite()),
1198                        Ok(f) => Item::Numeric(Numeric::from_f64(f)),
1199                    },
1200                    _ => {
1201                        return self.method_fail(
1202                            SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1203                            op,
1204                            "a string or numeric value",
1205                        );
1206                    }
1207                };
1208                self.next(rest, v, found)
1209            }
1210            PathOp::Bigint | PathOp::Integer => {
1211                let sqltype = if op == PathOp::Bigint { "bigint" } else { "integer" };
1212                let v = match jb {
1213                    Item::Numeric(n) => {
1214                        let v = n.to_integer(sqltype).ok().filter(|&v| match op {
1215                            PathOp::Bigint => i64::try_from(v).is_ok(),
1216                            _ => i32::try_from(v).is_ok(),
1217                        });
1218                        match v {
1219                            Some(v) => v,
1220                            None => return self.invalid_argument(&numeric_text(n), op, sqltype),
1221                        }
1222                    }
1223                    Item::String(s) => {
1224                        let v = match op {
1225                            PathOp::Bigint => int8_in(s).map(i128::from),
1226                            _ => int4_in(s).map(i128::from),
1227                        };
1228                        match v {
1229                            Ok(v) => v,
1230                            Err(_) => return self.invalid_argument(s, op, sqltype),
1231                        }
1232                    }
1233                    _ => {
1234                        return self.method_fail(
1235                            SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1236                            op,
1237                            "a string or numeric value",
1238                        );
1239                    }
1240                };
1241                self.next(rest, Item::Numeric(Numeric::from_integer(v)), found)
1242            }
1243            PathOp::Boolean => {
1244                let v = match jb {
1245                    Item::Bool(b) => *b,
1246                    Item::Numeric(n) => {
1247                        let text = numeric_text(n);
1248                        match int4_in(&text) {
1249                            Ok(v) => v != 0,
1250                            Err(_) => return self.invalid_argument(&text, op, "boolean"),
1251                        }
1252                    }
1253                    Item::String(s) => match parse_bool(s) {
1254                        Some(b) => b,
1255                        None => return self.invalid_argument(s, op, "boolean"),
1256                    },
1257                    _ => {
1258                        return self.method_fail(
1259                            SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1260                            op,
1261                            "a boolean, string, or numeric value",
1262                        );
1263                    }
1264                };
1265                self.next(rest, Item::Bool(v), found)
1266            }
1267            PathOp::Decimal | PathOp::Number => self.number(op, args, rest, jb, found),
1268            PathOp::StringFunc => {
1269                let v = match jb {
1270                    Item::String(s) => s.clone(),
1271                    Item::Numeric(n) => numeric_text(n),
1272                    Item::Bool(b) => b.to_string(),
1273                    Item::Datetime(_, text) => text.clone(),
1274                    _ => {
1275                        return self.method_fail(
1276                            SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1277                            op,
1278                            "a boolean, string, numeric, or datetime value",
1279                        );
1280                    }
1281                };
1282                self.next(rest, Item::String(v), found)
1283            }
1284            PathOp::Replace
1285            | PathOp::Lower
1286            | PathOp::Upper
1287            | PathOp::Ltrim
1288            | PathOp::Rtrim
1289            | PathOp::Btrim
1290            | PathOp::Initcap
1291            | PathOp::SplitPart => self.string_method(op, args, rest, jb, found),
1292            PathOp::KeyValue => self.keyvalue(rest, jb, found),
1293            PathOp::Datetime
1294            | PathOp::Date
1295            | PathOp::Time
1296            | PathOp::TimeTz
1297            | PathOp::Timestamp
1298            | PathOp::TimestampTz => self.datetime_method(op, args, rest, jb, found),
1299            _ => Err(Error::internal("unrecognized jsonpath item type")),
1300        }
1301    }
1302
1303    /// `.decimal()` and `.number()`. `.decimal()` with a precision and a scale gives the value with that typmod.
1304    fn number(
1305        &mut self,
1306        op: PathOp,
1307        args: &[PathItem],
1308        rest: &[PathItem],
1309        jb: &Item,
1310        found: Found<'_>,
1311    ) -> Result<Res> {
1312        let not_finite = || {
1313            Error::new(
1314                SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1315                format!("NaN or Infinity is not allowed for jsonpath item method .{}()", op.name()),
1316            )
1317        };
1318        let (num, text) = match jb {
1319            Item::Numeric(n) => (n.clone(), None),
1320            Item::String(s) => match numeric_in(s, -1) {
1321                Ok(n) => (n, Some(s.as_str())),
1322                Err(_) => return self.invalid_argument(s, op, "numeric"),
1323            },
1324            _ => {
1325                return self.method_fail(
1326                    SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1327                    op,
1328                    "a string or numeric value",
1329                );
1330            }
1331        };
1332        if is_special(&num) {
1333            return self.fail(not_finite());
1334        }
1335        let num = match (op, args.first()) {
1336            (PathOp::Decimal, Some(precision)) => {
1337                let out_of_range = |what: &str| {
1338                    Error::new(
1339                        SqlState::NON_NUMERIC_SQL_JSON_ITEM,
1340                        format!(
1341                            "{what} of jsonpath item method .{}() is out of range for type integer",
1342                            op.name()
1343                        ),
1344                    )
1345                };
1346                let PathItem::Numeric(precision) = precision else {
1347                    return Err(Error::internal(
1348                        "invalid jsonpath item type for .decimal() precision",
1349                    ));
1350                };
1351                let Some(precision) = int4(precision) else {
1352                    return self.fail(out_of_range("precision"));
1353                };
1354                let scale = match args.get(1) {
1355                    None => 0,
1356                    Some(PathItem::Numeric(scale)) => match int4(scale) {
1357                        Some(scale) => scale,
1358                        None => return self.fail(out_of_range("scale")),
1359                    },
1360                    Some(_) => {
1361                        return Err(Error::internal(
1362                            "invalid jsonpath item type for .decimal() scale",
1363                        ));
1364                    }
1365                };
1366                if !(1..=1000).contains(&precision) {
1367                    return self.fail(Error::new(
1368                        SqlState::INVALID_PARAMETER_VALUE,
1369                        format!("NUMERIC precision {precision} must be between 1 and 1000"),
1370                    ));
1371                }
1372                if !(-1000..=1000).contains(&scale) {
1373                    return self.fail(Error::new(
1374                        SqlState::INVALID_PARAMETER_VALUE,
1375                        format!("NUMERIC scale {scale} must be between -1000 and 1000"),
1376                    ));
1377                }
1378                let typmod = ((precision << 16) | (scale & 0x7ff)) + 4;
1379                let text = text.map_or_else(|| numeric_text(&num), str::to_string);
1380                match numeric_in(&text, typmod) {
1381                    Ok(n) => n,
1382                    Err(_) => return self.invalid_argument(&text, op, "numeric"),
1383                }
1384            }
1385            _ => num,
1386        };
1387        self.next(rest, Item::Numeric(num), found)
1388    }
1389
1390    /// `executeStringInternalMethod`: the string functions of SQL on a string.
1391    fn string_method(
1392        &mut self,
1393        op: PathOp,
1394        args: &[PathItem],
1395        rest: &[PathItem],
1396        jb: &Item,
1397        found: Found<'_>,
1398    ) -> Result<Res> {
1399        let Item::String(s) = jb else {
1400            return self.method_fail(SqlState::INVALID_PARAMETER_VALUE, op, "a string");
1401        };
1402        let string = |at: usize| match args.get(at) {
1403            Some(PathItem::String(s)) => Ok(Value::text(s.as_str())),
1404            _ => Err(Error::internal(format!(
1405                "invalid jsonpath item type for .{}() argument",
1406                op.name()
1407            ))),
1408        };
1409        let mut call_args = vec![Value::text(s.as_str())];
1410        let src = match op {
1411            PathOp::Replace => {
1412                call_args.extend([string(0)?, string(1)?]);
1413                "replace_text"
1414            }
1415            PathOp::Lower => "lower",
1416            PathOp::Upper => "upper",
1417            PathOp::Initcap => "initcap",
1418            PathOp::Ltrim | PathOp::Rtrim | PathOp::Btrim => {
1419                if !args.is_empty() {
1420                    call_args.push(string(0)?);
1421                }
1422                match op {
1423                    PathOp::Ltrim => "ltrim",
1424                    PathOp::Rtrim => "rtrim",
1425                    _ => "btrim",
1426                }
1427            }
1428            _ => {
1429                let position = |what: &str| {
1430                    Error::new(
1431                        SqlState::INVALID_PARAMETER_VALUE,
1432                        format!("field position of jsonpath item method .{}() {what}", op.name()),
1433                    )
1434                };
1435                call_args.push(string(0)?);
1436                let Some(PathItem::Numeric(n)) = args.get(1) else {
1437                    return Err(Error::internal("invalid jsonpath item type for .split_part()"));
1438                };
1439                match int4(n) {
1440                    None => return self.fail(position("is out of range for type integer")),
1441                    Some(0) => return self.fail(position("must not be zero")),
1442                    Some(n) => call_args.push(Value::Int4(n)),
1443                }
1444                "split_part"
1445            }
1446        };
1447        let kernel = crate::text::by_src(src).ok_or_else(bad_value)?;
1448        let v = kernel(self.call, &call_args)?;
1449        let v = v.as_str().ok_or_else(bad_value)?.to_string();
1450        if rest.is_empty() && found.is_none() {
1451            return Ok(Res::Ok);
1452        }
1453        self.next(rest, Item::String(v), found)
1454    }
1455
1456    /// `executeDateTimeMethod`: `.datetime()` and the methods of the datetime types on a string. With no template, the string must have one of the ISO formats. A method of a type casts the value to the type.
1457    #[allow(clippy::too_many_lines)]
1458    fn datetime_method(
1459        &mut self,
1460        op: PathOp,
1461        args: &[PathItem],
1462        rest: &[PathItem],
1463        jb: &Item,
1464        found: Found<'_>,
1465    ) -> Result<Res> {
1466        use Value as V;
1467        let invalid = SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION;
1468        let Item::String(s) = jb else { return self.method_fail(invalid, op, "a string") };
1469        let not_recognized =
1470            |name: &str| Error::new(invalid, format!("{name} format is not recognized: \"{s}\""));
1471        let mut precision = None;
1472        let (mut value, mut tz) = match (op, args.first()) {
1473            (PathOp::Datetime, Some(template)) => {
1474                let PathItem::String(template) = template else {
1475                    return Err(Error::internal(
1476                        "invalid jsonpath item type for .datetime() argument",
1477                    ));
1478                };
1479                match parse_datetime(self.call, s, template)? {
1480                    Ok(v) => v,
1481                    Err(error) => return self.fail(error),
1482                }
1483            }
1484            _ => {
1485                if op != PathOp::Datetime
1486                    && op != PathOp::Date
1487                    && let Some(arg) = args.first()
1488                {
1489                    let PathItem::Numeric(n) = arg else {
1490                        return Err(Error::internal(format!(
1491                            "invalid jsonpath item type for {} argument",
1492                            op.name()
1493                        )));
1494                    };
1495                    let Some(n) = int4(n) else {
1496                        return self.fail(Error::new(
1497                            invalid,
1498                            format!(
1499                                "time precision of jsonpath item method .{}() is out of range for type integer",
1500                                op.name()
1501                            ),
1502                        ));
1503                    };
1504                    precision = Some(n);
1505                }
1506                let iso = ISO_FORMATS.iter().find_map(|format| {
1507                    parse_datetime(self.call, s, format).ok().and_then(Result::ok)
1508                });
1509                match iso {
1510                    Some(v) => v,
1511                    None if op == PathOp::Datetime => {
1512                        return self.fail(not_recognized("datetime").with_hint(
1513                            "Use a datetime template argument to specify the input data format.",
1514                        ));
1515                    }
1516                    None => return self.fail(not_recognized(op.name())),
1517                }
1518            }
1519        };
1520        let call = self.call;
1521        let use_tz = self.use_tz;
1522        value = match (op, &value) {
1523            (PathOp::Datetime, _)
1524            | (PathOp::Date, V::Date(_))
1525            | (PathOp::Time, V::Time(_))
1526            | (PathOp::TimeTz, V::TimeTz(..))
1527            | (PathOp::Timestamp, V::Timestamp(_))
1528            | (PathOp::TimestampTz, V::TimestampTz(_)) => value,
1529            (PathOp::Date, V::Timestamp(_)) => convert(call, "timestamp_date", &value)?,
1530            (PathOp::Date, V::TimestampTz(_)) => {
1531                need_tz(use_tz, "timestamptz", "date")?;
1532                convert(call, "timestamptz_date", &value)?
1533            }
1534            (PathOp::Time, V::TimeTz(..)) => {
1535                need_tz(use_tz, "timetz", "time")?;
1536                convert(call, "timetz_time", &value)?
1537            }
1538            (PathOp::Time, V::Timestamp(_)) => convert(call, "timestamp_time", &value)?,
1539            (PathOp::Time, V::TimestampTz(_)) => {
1540                need_tz(use_tz, "timestamptz", "time")?;
1541                convert(call, "timestamptz_time", &value)?
1542            }
1543            (PathOp::TimeTz, V::Time(_)) => {
1544                need_tz(use_tz, "time", "timetz")?;
1545                convert(call, "time_timetz", &value)?
1546            }
1547            (PathOp::TimeTz, V::TimestampTz(_)) => convert(call, "timestamptz_timetz", &value)?,
1548            (PathOp::Timestamp, V::Date(_)) => convert(call, "date_timestamp", &value)?,
1549            (PathOp::Timestamp, V::TimestampTz(_)) => {
1550                need_tz(use_tz, "timestamptz", "timestamp")?;
1551                convert(call, "timestamptz_timestamp", &value)?
1552            }
1553            (PathOp::TimestampTz, V::Date(date)) => {
1554                need_tz(use_tz, "date", "timestamptz")?;
1555                tz = session_west(call, midnight(*date)?)?;
1556                convert(call, "date_timestamptz", &value)?
1557            }
1558            (PathOp::TimestampTz, V::Timestamp(ts)) => {
1559                need_tz(use_tz, "timestamp", "timestamptz")?;
1560                tz = session_west(call, *ts)?;
1561                convert(call, "timestamp_timestamptz", &value)?
1562            }
1563            _ => return self.fail(not_recognized(op.name())),
1564        };
1565        if let Some(precision) = precision {
1566            let precision = typmod_check(call, op, precision)?;
1567            value = match value {
1568                V::Time(time) => V::Time(adjust_time(time, precision)),
1569                V::TimeTz(time, zone) => V::TimeTz(adjust_time(time, precision), zone),
1570                V::Timestamp(ts) => {
1571                    V::Timestamp(adjust_timestamp(ts, precision).map_err(type_error)?)
1572                }
1573                V::TimestampTz(ts) => {
1574                    V::TimestampTz(adjust_timestamp(ts, precision).map_err(type_error)?)
1575                }
1576                v => v,
1577            };
1578        }
1579        if rest.is_empty() && found.is_none() {
1580            return Ok(Res::Ok);
1581        }
1582        let text = datetime_text(&value, tz)?;
1583        self.next(rest, Item::Datetime(value, text), found)
1584    }
1585
1586    /// `executeKeyValueMethod`: an object `{"id": id, "key": key, "value": value}` for each pair. Each object becomes the base object of the steps after it.
1587    fn keyvalue(&mut self, rest: &[PathItem], jb: &Item, mut found: Found<'_>) -> Result<Res> {
1588        let Some((doc, at)) = jb.object() else {
1589            return self.method_fail(
1590                SqlState::SQL_JSON_OBJECT_NOT_FOUND,
1591                PathOp::KeyValue,
1592                "an object",
1593            );
1594        };
1595        let JsonItem::Object(fields) = doc.item(at) else { return Err(bad_value()) };
1596        let mut offset = doc.offset(at);
1597        if let Some((base, base_at)) = &self.base.node
1598            && Rc::ptr_eq(base, doc)
1599        {
1600            offset -= doc.offset(*base_at);
1601        }
1602        let id = offset + self.base.id * BASE_ID_FACTOR;
1603        let mut res = Res::NotFound;
1604        for (key, value) in fields {
1605            res = Res::Ok;
1606            if rest.is_empty() && found.is_none() {
1607                break;
1608            }
1609            let mut text = format!("{{\"id\": {id}, \"key\": ");
1610            json_escape(key, &mut text);
1611            text.push_str(", \"value\": ");
1612            text.push_str(doc.text(*value));
1613            text.push('}');
1614            let obj = Doc::parse(text)?;
1615            let base = Base { node: Some((Rc::clone(&obj), 0)), id: self.last_id };
1616            self.last_id += 1;
1617            let base = std::mem::replace(&mut self.base, base);
1618            let next = self.next(rest, Item::Node(obj, 0), found.as_deref_mut());
1619            self.base = base;
1620            res = next?;
1621            if res == Res::Error {
1622                return Ok(res);
1623            }
1624            if res == Res::Ok && found.is_none() {
1625                break;
1626            }
1627        }
1628        Ok(res)
1629    }
1630}
1631
1632/// The error of `checkTimezoneIsUsedForCast` for a cast that needs the zone of the session in a function that is not `_tz`.
1633fn need_tz(use_tz: bool, from: &str, to: &str) -> Result<()> {
1634    if use_tz {
1635        return Ok(());
1636    }
1637    Err(Error::new(
1638        SqlState::FEATURE_NOT_SUPPORTED,
1639        format!("cannot convert value from {from} to {to} without time zone usage"),
1640    )
1641    .with_hint("Use *_tz() function for time zone support."))
1642}
1643
1644/// A cast between the datetime types by the `prosrc` of its function.
1645fn convert(call: &Call<'_>, src: &str, value: &Value) -> Result<Value> {
1646    let kernel =
1647        crate::cast::by_src(src).or_else(|| crate::calendar::by_src(src)).ok_or_else(bad_value)?;
1648    kernel(call, std::slice::from_ref(value))
1649}
1650
1651/// `DetermineTimeZoneOffset`: the offset west of UTC of the zone of the session at a local time.
1652fn session_west(call: &Call<'_>, local: i64) -> Result<i32> {
1653    let zone = call.session.zone()?;
1654    let seconds = local.div_euclid(USECS_PER_SEC) - UNIX_TO_POSTGRES_USECS / USECS_PER_SEC;
1655    Ok(local_offset(seconds, zone.as_ref()).0)
1656}
1657
1658/// `anytime_typmod_check` and `anytimestamp_typmod_check`: an error for a precision below zero, and a warning and the largest precision for a precision above it.
1659fn typmod_check(call: &Call<'_>, op: PathOp, precision: i32) -> Result<i32> {
1660    let (kind, zone) = match op {
1661        PathOp::Time => ("TIME", ""),
1662        PathOp::TimeTz => ("TIME", " WITH TIME ZONE"),
1663        PathOp::Timestamp => ("TIMESTAMP", ""),
1664        _ => ("TIMESTAMP", " WITH TIME ZONE"),
1665    };
1666    if precision < 0 {
1667        return Err(Error::new(
1668            SqlState::INVALID_PARAMETER_VALUE,
1669            format!("{kind}({precision}){zone} precision must not be negative"),
1670        ));
1671    }
1672    if precision > 6 {
1673        call.session.warn(Error::new(
1674            SqlState::INVALID_PARAMETER_VALUE,
1675            format!("{kind}({precision}){zone} precision reduced to maximum allowed, 6"),
1676        ));
1677        return Ok(6);
1678    }
1679    Ok(precision)
1680}
1681
1682/// `JsonEncodeDateTime`: the text of a datetime value in the XSD style. A `timestamptz` shows the time at the offset `tz` west of UTC.
1683fn datetime_text(value: &Value, tz: i32) -> Result<String> {
1684    const XSD: DateFormat = DateFormat { style: DateStyle::Xsd, order: DateOrder::Mdy };
1685    let mut out = Vec::new();
1686    match *value {
1687        Value::Date(date) => date_out(date, XSD, &mut out),
1688        Value::Time(time) => time_out(time, &mut out),
1689        Value::TimeTz(time, zone) => {
1690            time_out(time, &mut out);
1691            // `EncodeTimezone` in the XSD style always shows the minutes.
1692            let total = zone.unsigned_abs();
1693            let sign = if zone <= 0 { '+' } else { '-' };
1694            write!(out, "{sign}{:02}:{:02}", total / 3600, total / 60 % 60)
1695                .map_err(|_| bad_value())?;
1696            if total % 60 != 0 {
1697                write!(out, ":{:02}", total % 60).map_err(|_| bad_value())?;
1698            }
1699        }
1700        Value::Timestamp(ts) => timestamp_out(ts, XSD, &mut out).map_err(type_error)?,
1701        Value::TimestampTz(ts) => {
1702            let zone = FixedZone { offset: -tz, abbrev: String::new() };
1703            timestamptz_out(ts, XSD, &zone, &mut out).map_err(type_error)?;
1704        }
1705        _ => return Err(bad_value()),
1706    }
1707    String::from_utf8(out).map_err(|_| bad_value())
1708}
1709
1710/// `compareDatetime`: the order of two datetime values, or `None` when their types do not compare. A cast that needs the zone of the session is an error when `use_tz` is false.
1711fn compare_datetime(
1712    call: &Call<'_>,
1713    use_tz: bool,
1714    a: &Value,
1715    b: &Value,
1716) -> Result<Option<Ordering>> {
1717    use Value as V;
1718    let timetz = |v: &Value| {
1719        need_tz(use_tz, "time", "timetz")?;
1720        convert(call, "time_timetz", v)
1721    };
1722    Ok(Some(match (a, b) {
1723        (V::Time(_), V::TimeTz(..)) => compare(0, &timetz(a)?, 0, b)?,
1724        (V::TimeTz(..), V::Time(_)) => compare(0, a, 0, &timetz(b)?)?,
1725        (V::Time(_), V::Time(_)) | (V::TimeTz(..), V::TimeTz(..)) => compare(0, a, 0, b)?,
1726        (V::Time(_) | V::TimeTz(..), _) | (_, V::Time(_) | V::TimeTz(..)) => return Ok(None),
1727        (V::Date(_), V::TimestampTz(_)) | (V::TimestampTz(_), V::Date(_)) => {
1728            need_tz(use_tz, "date", "timestamptz")?;
1729            datetime_order(call, a, b)?
1730        }
1731        (V::Timestamp(_), V::TimestampTz(_)) | (V::TimestampTz(_), V::Timestamp(_)) => {
1732            need_tz(use_tz, "timestamp", "timestamptz")?;
1733            datetime_order(call, a, b)?
1734        }
1735        _ => datetime_order(call, a, b)?,
1736    }))
1737}
1738
1739/// `parse_bool`: the words of `bool` with no white space around them.
1740fn parse_bool(s: &str) -> Option<bool> {
1741    let space = |c: char| c.is_ascii_whitespace() || c == '\u{b}';
1742    if s.starts_with(space) || s.ends_with(space) {
1743        return None;
1744    }
1745    bool_in(s).ok()
1746}
1747
1748/// `compareItems`: a comparison of two items. A null is equal only to a null, and items of other different types do not compare.
1749fn compare_items(call: &Call<'_>, use_tz: bool, op: PathOp, a: &Item, b: &Item) -> Result<Truth> {
1750    let order = match (a, b) {
1751        (Item::Null, Item::Null) => Ordering::Equal,
1752        (Item::Null, _) | (_, Item::Null) => return Ok(Truth::of(op == PathOp::NotEqual)),
1753        (Item::Bool(x), Item::Bool(y)) => x.cmp(y),
1754        (Item::Numeric(x), Item::Numeric(y)) => x.compare(y),
1755        (Item::String(x), Item::String(y)) => x.as_bytes().cmp(y.as_bytes()),
1756        (Item::Datetime(x, _), Item::Datetime(y, _)) => {
1757            match compare_datetime(call, use_tz, x, y)? {
1758                Some(order) => order,
1759                None => return Ok(Truth::Unknown),
1760            }
1761        }
1762        _ => return Ok(Truth::Unknown),
1763    };
1764    Ok(Truth::of(match op {
1765        PathOp::Equal => order.is_eq(),
1766        PathOp::NotEqual => order.is_ne(),
1767        PathOp::Less => order.is_lt(),
1768        PathOp::Greater => order.is_gt(),
1769        PathOp::LessOrEqual => order.is_le(),
1770        _ => order.is_ge(),
1771    }))
1772}
1773
1774/// `executeJsonPath`: the result and the items of the path on the value. With `want` false, the caller wants only to know if there is an item.
1775fn execute(
1776    call: &Call<'_>,
1777    args: &[Value],
1778    want: bool,
1779    use_tz: bool,
1780) -> Result<(Res, Vec<Item>, bool)> {
1781    let target = Doc::parse(text(args, 0)?.to_string())?;
1782    let Some(Value::JsonPath(path)) = args.get(1) else { return Err(bad_value()) };
1783    let (vars, silent) = match args {
1784        [_, _] => (None, true),
1785        [_, _, vars, Value::Bool(silent)] => {
1786            (Some(Doc::parse(vars.as_str().ok_or_else(bad_value)?.to_string())?), *silent)
1787        }
1788        _ => return Err(bad_value()),
1789    };
1790    if let Some(vars) = &vars
1791        && !matches!(vars.item(0), JsonItem::Object(_))
1792    {
1793        return Err(Error::new(
1794            SqlState::INVALID_PARAMETER_VALUE,
1795            "\"vars\" argument is not an object",
1796        )
1797        .with_detail(
1798            "Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.",
1799        ));
1800    }
1801    let last_id = 1 + i64::from(vars.is_some());
1802    let vars = vars.map_or(Vars::None, Vars::Object);
1803    let (res, items) = run(call, &target, path, vars, last_id, !silent, want, use_tz)?;
1804    Ok((res, items, silent))
1805}
1806
1807/// The run of a path on the root of a document, with the id that `.keyvalue()` gives after the ids of the variables.
1808#[allow(clippy::too_many_arguments)]
1809fn run(
1810    call: &Call<'_>,
1811    target: &Rc<Doc>,
1812    path: &JsonPath,
1813    vars: Vars<'_>,
1814    last_id: i64,
1815    throw: bool,
1816    want: bool,
1817    use_tz: bool,
1818) -> Result<(Res, Vec<Item>)> {
1819    let root = target.get(0)?;
1820    let mut exec = Exec {
1821        call,
1822        last_id,
1823        vars,
1824        lax: path.lax,
1825        ignore_structural: path.lax,
1826        throw,
1827        root: root.clone(),
1828        current: root.clone(),
1829        base: Base { node: None, id: 0 },
1830        innermost: None,
1831        depth: 0,
1832        use_tz,
1833    };
1834    let mut items = Vec::new();
1835    let res = if !want && !path.lax {
1836        // The strict mode needs all the items to check that there is no error.
1837        match exec.item(&path.expr, &root, Some(&mut items))? {
1838            Res::Error => Res::Error,
1839            _ if items.is_empty() => Res::NotFound,
1840            _ => Res::Ok,
1841        }
1842    } else {
1843        exec.item(&path.expr, &root, want.then_some(&mut items))?
1844    };
1845    Ok((res, items))
1846}
1847
1848/// `executeJsonPath` for `JSON_EXISTS`, `JSON_QUERY` and `JSON_VALUE`: whether the path on the `jsonb` value finds an item, and the items when `want` is true. The result is `None` for an error of the path when `throw` is false. The casts of the datetime values can use the zone of the session.
1849///
1850/// # Errors
1851///
1852/// The error of the path when `throw` is true, and the errors that a silent path also gives, such as a variable that `PASSING` does not have.
1853pub fn sql_json_path(
1854    call: &Call<'_>,
1855    target: &Value,
1856    path: &Value,
1857    vars: &[PathVar],
1858    throw: bool,
1859    want: bool,
1860) -> Result<Option<(bool, Vec<SqlJsonItem>)>> {
1861    let Value::Text(target) = target else { return Err(bad_value()) };
1862    let Value::JsonPath(path) = path else { return Err(bad_value()) };
1863    let target = Doc::parse(target.clone())?;
1864    let last_id = 1 + i64::try_from(vars.len()).unwrap_or(i64::MAX);
1865    let (res, items) = run(call, &target, path, Vars::Passing(vars), last_id, throw, want, true)?;
1866    if res == Res::Error {
1867        return Ok(None);
1868    }
1869    let items = items
1870        .into_iter()
1871        .map(|item| match item {
1872            Item::Null => SqlJsonItem::Null,
1873            Item::Bool(b) => SqlJsonItem::Bool(b),
1874            Item::Numeric(n) => SqlJsonItem::Numeric(n),
1875            Item::String(s) => SqlJsonItem::String(s),
1876            Item::Datetime(value, text) => SqlJsonItem::Datetime(value, text),
1877            Item::Node(doc, at) => SqlJsonItem::Container(doc.text(at).to_owned()),
1878        })
1879        .collect();
1880    Ok(Some((res == Res::Ok, items)))
1881}
1882
1883/// `jsonb_path_exists` and `@?`: null for an error in a silent call.
1884fn exists(call: &Call<'_>, args: &[Value], use_tz: bool) -> Result<Value> {
1885    Ok(match execute(call, args, false, use_tz)?.0 {
1886        Res::Error => Value::Null,
1887        res => Value::Bool(res == Res::Ok),
1888    })
1889}
1890
1891/// `jsonb_path_match` and `@@`: the result of a path that gives one boolean.
1892fn path_match(call: &Call<'_>, args: &[Value], use_tz: bool) -> Result<Value> {
1893    let (_, items, silent) = execute(call, args, true, use_tz)?;
1894    match items.as_slice() {
1895        [Item::Bool(b)] => Ok(Value::Bool(*b)),
1896        [Item::Null] => Ok(Value::Null),
1897        _ if !silent => Err(Error::new(
1898            SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED,
1899            "single boolean result is expected",
1900        )),
1901        _ => Ok(Value::Null),
1902    }
1903}
1904
1905/// `jsonb_path_query`: a row for each item.
1906pub(crate) fn jsonb_path_query(call: &Call<'_>, args: &[Value]) -> Result<Vec<Vec<Value>>> {
1907    query(call, args, false)
1908}
1909
1910/// `jsonb_path_query_tz`.
1911pub(crate) fn jsonb_path_query_tz(call: &Call<'_>, args: &[Value]) -> Result<Vec<Vec<Value>>> {
1912    query(call, args, true)
1913}
1914
1915fn query(call: &Call<'_>, args: &[Value], use_tz: bool) -> Result<Vec<Vec<Value>>> {
1916    let (_, items, _) = execute(call, args, true, use_tz)?;
1917    Ok(items.iter().map(|item| vec![item.to_value()]).collect())
1918}
1919
1920/// `jsonb_path_query_array`: the items in an array.
1921fn query_array(call: &Call<'_>, args: &[Value], use_tz: bool) -> Result<Value> {
1922    let (_, items, _) = execute(call, args, true, use_tz)?;
1923    let mut out = String::from("[");
1924    for (i, item) in items.iter().enumerate() {
1925        if i > 0 {
1926            out.push_str(", ");
1927        }
1928        item.write(&mut out);
1929    }
1930    out.push(']');
1931    Ok(Value::Text(out))
1932}
1933
1934/// `jsonb_path_query_first`: the first item, or null.
1935fn query_first(call: &Call<'_>, args: &[Value], use_tz: bool) -> Result<Value> {
1936    let (_, items, _) = execute(call, args, true, use_tz)?;
1937    Ok(items.first().map_or(Value::Null, Item::to_value))
1938}