Skip to main content

rudb_plan/
parse.rs

1//! The reader for the textual form.
2//!
3//! Recursive descent over lines for the tree and over characters for the expressions. It is a
4//! hand-written parser rather than a generated one because the grammar is fixed by the printer in
5//! `print.rs`, the two are edited together, and the useful property is that every construct the
6//! printer emits has exactly one place here that reads it back.
7//!
8//! Two things make this a small parser rather than a large one. Expressions are fully bracketed,
9//! so there is no precedence and no lookahead beyond one token. And every expression is followed
10//! by its type, so a constant is read with its type already in hand: `5` is an `INTEGER` or a
11//! `DATE` or the unscaled part of a `DECIMAL(6,2)` depending on what comes after it, and none of
12//! that has to be guessed from the digits.
13
14use std::ops::Range;
15
16use rudb_common::{Error, Field, LogicalType, Result, Value};
17
18use crate::expr::{Arm, ColumnBinding, CompareOp, ConjunctionOp, Expr, SortKey};
19use crate::node::{JoinKind, Node, SetOpKind};
20use crate::plan::Plan;
21use crate::{ExprRef, NodeRef, Slice};
22
23impl Plan {
24    /// Reads a plan back from its textual form.
25    ///
26    /// Printing the result produces the text that was read, which is a test in
27    /// `tests/roundtrip.rs` rather than a claim here. The plan is validated before it is returned,
28    /// so a text that parses is a text that names a plan somebody could have built.
29    ///
30    /// # Errors
31    ///
32    /// With the line number and the column, because the thing a person wants from a dump that will
33    /// not read back is which character of which operator.
34    pub fn parse(text: &str) -> Result<Self> {
35        let lines = split_lines(text)?;
36        if lines.is_empty() {
37            return Err(Error::parser("a plan has at least one operator".to_string()));
38        }
39        let mut reader = Reader { lines, at: 0, plan: Self::without_nodes() };
40        let root = reader.node(0)?;
41        if let Some(line) = reader.lines.get(reader.at) {
42            return Err(Error::parser(format!(
43                "line {}: \"{}\" is past the end of the plan",
44                line.number, line.text
45            )));
46        }
47        let mut plan = reader.plan;
48        plan.set_root(root);
49        plan.validate()?;
50        Ok(plan)
51    }
52}
53
54/// One operator line, with its blank lines and its indentation already dealt with.
55#[derive(Debug)]
56struct Line<'a> {
57    /// How many levels in, which is half the leading spaces.
58    depth: usize,
59    /// The line with the indentation removed.
60    text: &'a str,
61    /// The line number in the original text, one based, for error messages.
62    number: usize,
63}
64
65fn split_lines(text: &str) -> Result<Vec<Line<'_>>> {
66    let mut lines = Vec::new();
67    for (index, raw) in text.lines().enumerate() {
68        let number = index + 1;
69        if raw.trim().is_empty() {
70            continue;
71        }
72        if raw.contains('\t') {
73            return Err(Error::parser(format!("line {number}: indented with a tab")));
74        }
75        let spaces = raw.len() - raw.trim_start_matches(' ').len();
76        if spaces % 2 != 0 {
77            return Err(Error::parser(format!(
78                "line {number}: indented {spaces} spaces, which is not a whole number of levels"
79            )));
80        }
81        lines.push(Line { depth: spaces / 2, text: raw[spaces..].trim_end(), number });
82    }
83    Ok(lines)
84}
85
86struct Reader<'a> {
87    lines: Vec<Line<'a>>,
88    at: usize,
89    plan: Plan,
90}
91
92impl Reader<'_> {
93    /// Reads the operator at `depth` and everything under it.
94    ///
95    /// Children are read before the node is built, which is not a stylistic choice: the arena's
96    /// backwards-reference rule says a child index is smaller than its parent's, and building the
97    /// parent first would break it on every plan with more than one operator.
98    fn node(&mut self, depth: usize) -> Result<NodeRef> {
99        let Some(line) = self.lines.get(self.at) else {
100            return Err(Error::parser(format!("expected an operator {depth} levels in")));
101        };
102        if line.depth != depth {
103            return Err(Error::parser(format!(
104                "line {}: \"{}\" is {} levels in and {depth} was expected",
105                line.number, line.text, line.depth
106            )));
107        }
108        let number = line.number;
109        let text = line.text;
110        self.at += 1;
111
112        let (keyword, arguments) = match text.find(' ') {
113            Some(space) => (&text[..space], &text[space..]),
114            None => (text, ""),
115        };
116        let mut cursor = Cursor::new(arguments);
117        let built = self
118            .arguments(keyword, &mut cursor)
119            .map_err(|error| Error::parser(format!("line {number}: {}", error.message())))?;
120        if !cursor.done() {
121            return Err(Error::parser(format!(
122                "line {number}: \"{}\" is left over after the {keyword}",
123                cursor.rest()
124            )));
125        }
126
127        let left = if built.arity > 0 { Some(self.node(depth + 1)?) } else { None };
128        let right = if built.arity > 1 { Some(self.node(depth + 1)?) } else { None };
129        Ok(self.plan.add_node((built.assemble)(left.unwrap_or(0), right.unwrap_or(0))))
130    }
131
132    /// Reads one operator's arguments, returning how many inputs it takes and how to build it once
133    /// they have been read.
134    fn arguments(&mut self, keyword: &str, c: &mut Cursor<'_>) -> Result<Built> {
135        let plan = &mut self.plan;
136        match keyword {
137            "Dummy" => Ok(Built::leaf(Node::Dummy)),
138            "CrossProduct" => Ok(Built {
139                arity: 2,
140                assemble: Box::new(|left, right| Node::CrossProduct { left, right }),
141            }),
142            "Get" => {
143                let catalog = read_name(plan, c)?;
144                c.expect(".")?;
145                let schema = read_name(plan, c)?;
146                c.expect(".")?;
147                let table = read_name(plan, c)?;
148                c.expect_word("AS")?;
149                let alias = read_name(plan, c)?;
150                let index = read_table_index(c)?;
151                let columns = read_schema(plan, c)?;
152                Ok(Built::leaf(Node::Get { catalog, schema, table, alias, index, columns }))
153            }
154            "Values" => {
155                let index = read_table_index(c)?;
156                let columns = read_schema(plan, c)?;
157                c.expect_word("rows")?;
158                c.expect("=")?;
159                c.expect("[")?;
160                let mut rows = Vec::new();
161                if !c.eat_space_then("]") {
162                    loop {
163                        rows.push(read_expr_list(plan, c)?);
164                        if !c.eat_space_then(",") {
165                            break;
166                        }
167                    }
168                    c.expect("]")?;
169                }
170                let rows = plan.add_rows(&rows);
171                Ok(Built::leaf(Node::Values { index, columns, rows }))
172            }
173            "TableFunction" => {
174                let function = read_name(plan, c)?;
175                c.expect_word("args")?;
176                c.expect("=")?;
177                let args = read_expr_list(plan, c)?;
178                let (options, settings) = read_options(plan, c)?;
179                let index = read_table_index(c)?;
180                let columns = read_schema(plan, c)?;
181                Ok(Built::leaf(Node::TableFunction {
182                    index,
183                    function,
184                    args,
185                    options,
186                    settings,
187                    columns,
188                }))
189            }
190            "Fetch" => {
191                c.expect_word("args")?;
192                c.expect("=")?;
193                let args = read_expr_list(plan, c)?;
194                c.expect_word("row")?;
195                c.expect("=")?;
196                let row = read_expr(plan, c)?;
197                let index = read_table_index(c)?;
198                let columns = read_schema(plan, c)?;
199                Ok(Built::unary(move |input| Node::Fetch { input, index, args, columns, row }))
200            }
201            "Filter" => {
202                let predicate = read_expr(plan, c)?;
203                Ok(Built::unary(move |input| Node::Filter { input, predicate }))
204            }
205            "Project" => {
206                let index = read_table_index(c)?;
207                let mut exprs = Vec::new();
208                let mut names = Vec::new();
209                c.expect("[")?;
210                if !c.eat_space_then("]") {
211                    loop {
212                        exprs.push(read_expr(plan, c)?);
213                        c.expect_word("AS")?;
214                        names.push(read_name(plan, c)?);
215                        if !c.eat_space_then(",") {
216                            break;
217                        }
218                    }
219                    c.expect("]")?;
220                }
221                let exprs = plan.add_expr_list(&exprs);
222                let names = plan.add_name_list(&names);
223                Ok(Built::unary(move |input| Node::Project { input, index, exprs, names }))
224            }
225            "Aggregate" => {
226                let index = read_table_index(c)?;
227                c.expect_word("groups")?;
228                c.expect("=")?;
229                let groups = read_expr_list(plan, c)?;
230                c.expect_word("aggregates")?;
231                c.expect("=")?;
232                let aggregates = read_aggregate_list(plan, c)?;
233                Ok(Built::unary(move |input| Node::Aggregate { input, index, groups, aggregates }))
234            }
235            "Sort" => {
236                let keys = read_sort_keys(plan, c)?;
237                Ok(Built::unary(move |input| Node::Sort { input, keys }))
238            }
239            "Limit" => {
240                let count = if c.eat_word("ALL") { None } else { Some(read_count(c)?) };
241                c.expect_word("offset")?;
242                let offset = read_count(c)?;
243                Ok(Built::unary(move |input| Node::Limit { input, count, offset }))
244            }
245            "TopN" => {
246                let count = read_count(c)?;
247                c.expect_word("offset")?;
248                let offset = read_count(c)?;
249                let keys = read_sort_keys(plan, c)?;
250                Ok(Built::unary(move |input| Node::TopN { input, keys, count, offset }))
251            }
252            "Distinct" => {
253                c.expect_word("on")?;
254                c.expect("=")?;
255                let on = read_expr_list(plan, c)?;
256                Ok(Built::unary(move |input| Node::Distinct { input, on }))
257            }
258            "Join" => {
259                let kind = read_keyword(c, &JoinKind::ALL, JoinKind::keyword, "a join kind")?;
260                c.expect_word("on")?;
261                c.expect("=")?;
262                let conditions = read_expr_list(plan, c)?;
263                Ok(Built {
264                    arity: 2,
265                    assemble: Box::new(move |left, right| Node::Join {
266                        left,
267                        right,
268                        kind,
269                        conditions,
270                    }),
271                })
272            }
273            "SetOp" => {
274                let kind = read_keyword(c, &SetOpKind::ALL, SetOpKind::keyword, "a set operation")?;
275                let all = if c.eat_word("ALL") {
276                    true
277                } else if c.eat_word("DISTINCT") {
278                    false
279                } else {
280                    return Err(c.error("expected ALL or DISTINCT"));
281                };
282                let index = read_table_index(c)?;
283                Ok(Built {
284                    arity: 2,
285                    assemble: Box::new(move |left, right| Node::SetOp {
286                        left,
287                        right,
288                        kind,
289                        all,
290                        index,
291                    }),
292                })
293            }
294            other => Err(Error::parser(format!("\"{other}\" is not an operator"))),
295        }
296    }
297}
298
299/// An operator whose arguments have been read and whose inputs have not.
300struct Built {
301    arity: usize,
302    assemble: Box<dyn FnOnce(NodeRef, NodeRef) -> Node>,
303}
304
305impl Built {
306    fn leaf(node: Node) -> Self {
307        Self { arity: 0, assemble: Box::new(move |_, _| node) }
308    }
309
310    fn unary(make: impl FnOnce(NodeRef) -> Node + 'static) -> Self {
311        Self { arity: 1, assemble: Box::new(move |input, _| make(input)) }
312    }
313}
314
315// Node arguments.
316
317fn read_table_index(c: &mut Cursor<'_>) -> Result<u32> {
318    c.expect("#")?;
319    read_number(c)
320}
321
322fn read_count(c: &mut Cursor<'_>) -> Result<u64> {
323    c.skip_space();
324    let start = c.at;
325    while c.peek().is_some_and(|ch| ch.is_ascii_digit()) {
326        c.at += 1;
327    }
328    if c.at == start {
329        return Err(c.error("expected a row count"));
330    }
331    c.text[start..c.at].parse().map_err(|_| c.error("that row count does not fit in 64 bits"))
332}
333
334fn read_number(c: &mut Cursor<'_>) -> Result<u32> {
335    c.skip_space();
336    let start = c.at;
337    while c.peek().is_some_and(|ch| ch.is_ascii_digit()) {
338        c.at += 1;
339    }
340    if c.at == start {
341        return Err(c.error("expected a number"));
342    }
343    c.text[start..c.at].parse().map_err(|_| c.error("that number does not fit in 32 bits"))
344}
345
346/// One of a fixed set of keywords, matched longest first so that a keyword which is a prefix of
347/// another cannot shadow it.
348fn read_keyword<T: Copy>(
349    c: &mut Cursor<'_>,
350    all: &[T],
351    spell: impl Fn(T) -> &'static str,
352    what: &str,
353) -> Result<T> {
354    let mut candidates: Vec<T> = all.to_vec();
355    candidates.sort_by_key(|&kind| std::cmp::Reverse(spell(kind).len()));
356    for candidate in candidates {
357        if c.eat_word(spell(candidate)) {
358            return Ok(candidate);
359        }
360    }
361    Err(c.error(&format!("expected {what}")))
362}
363
364fn read_name(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<u32> {
365    let name = read_identifier(c)?;
366    Ok(plan.intern(&name))
367}
368
369/// A named and typed column list, which is what a scan and a `VALUES` produce.
370fn read_schema(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
371    let mut fields = Vec::new();
372    c.expect("[")?;
373    if !c.eat_space_then("]") {
374        loop {
375            let name = read_identifier(c)?;
376            c.expect("::")?;
377            let ty = read_type(c)?;
378            fields.push(Field::new(name, ty));
379            if !c.eat_space_then(",") {
380                break;
381            }
382        }
383        c.expect("]")?;
384    }
385    Ok(plan.add_fields(&fields))
386}
387
388/// The named parameters a table function call was written with, which most calls have none of.
389///
390/// Nothing is written when there are none, so the whole segment is optional and its absence is two
391/// empty slices rather than an error.
392fn read_options(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<(Slice, Slice)> {
393    if !c.eat_space_then("options=[") {
394        return Ok((Slice::EMPTY, Slice::EMPTY));
395    }
396    let mut names = Vec::new();
397    let mut settings = Vec::new();
398    if !c.eat_space_then("]") {
399        loop {
400            names.push(read_name(plan, c)?);
401            c.expect("=")?;
402            settings.push(read_expr(plan, c)?);
403            if !c.eat_space_then(",") {
404                break;
405            }
406        }
407        c.expect("]")?;
408    }
409    Ok((plan.add_name_list(&names), plan.add_expr_list(&settings)))
410}
411
412fn read_expr_list(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
413    let mut exprs = Vec::new();
414    c.expect("[")?;
415    if !c.eat_space_then("]") {
416        loop {
417            exprs.push(read_expr(plan, c)?);
418            if !c.eat_space_then(",") {
419                break;
420            }
421        }
422        c.expect("]")?;
423    }
424    Ok(plan.add_expr_list(&exprs))
425}
426
427/// The aggregate list of an `Aggregate`, which is the only place an aggregate can appear.
428///
429/// An aggregate and a scalar function print identically, so this is not a different syntax, it is
430/// the same syntax read in the one slot where it means something else. Reading it anywhere else
431/// would produce a plan `Plan::validate` rejects, which is the check that keeps the two in step.
432fn read_aggregate_list(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
433    let mut exprs = Vec::new();
434    c.expect("[")?;
435    if !c.eat_space_then("]") {
436        loop {
437            exprs.push(read_aggregate(plan, c)?);
438            if !c.eat_space_then(",") {
439                break;
440            }
441        }
442        c.expect("]")?;
443    }
444    Ok(plan.add_expr_list(&exprs))
445}
446
447fn read_aggregate(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<ExprRef> {
448    c.skip_space();
449    let Some(name) = try_call_name(c) else {
450        return Err(c.error("expected an aggregate call"));
451    };
452    let name = plan.intern(&name);
453    let distinct = c.eat_keyword_before_argument("DISTINCT");
454    let mut args = Vec::new();
455    let mut filter = None;
456    if !c.eat_space_then(")") {
457        // `count(*) FILTER (WHERE p)` binds to a zero argument aggregate with a filter, so the
458        // filter has to be reachable without going through the argument loop first.
459        let mut filtered = c.eat_keyword_before_argument("FILTER");
460        if !filtered {
461            loop {
462                args.push(read_expr(plan, c)?);
463                if !c.eat_space_then(",") {
464                    break;
465                }
466            }
467            filtered = c.eat_keyword_before_argument("FILTER");
468        }
469        if filtered {
470            filter = Some(read_expr(plan, c)?);
471        }
472        c.expect(")")?;
473    }
474    let args = plan.add_expr_list(&args);
475    let ty = read_annotation(c)?;
476    Ok(plan.add_expr(Expr::Aggregate { name, args, distinct, filter }, ty))
477}
478
479/// A bracketed list of sort keys, which is what a sort and a top N both carry.
480fn read_sort_keys(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
481    let mut keys = Vec::new();
482    c.expect("[")?;
483    if !c.eat_space_then("]") {
484        loop {
485            keys.push(read_sort_key(plan, c)?);
486            if !c.eat_space_then(",") {
487                break;
488            }
489        }
490        c.expect("]")?;
491    }
492    Ok(plan.add_sort_keys(&keys))
493}
494
495fn read_sort_key(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<SortKey> {
496    let expr = read_expr(plan, c)?;
497    let descending = if c.eat_word("DESC") {
498        true
499    } else if c.eat_word("ASC") {
500        false
501    } else {
502        return Err(c.error("expected ASC or DESC"));
503    };
504    c.expect_word("NULLS")?;
505    let nulls_first = if c.eat_word("FIRST") {
506        true
507    } else if c.eat_word("LAST") {
508        false
509    } else {
510        return Err(c.error("expected FIRST or LAST"));
511    };
512    Ok(SortKey { expr, descending, nulls_first })
513}
514
515// Expressions.
516
517/// What an expression's form turned out to be.
518///
519/// A constant cannot be finished until its type has been read, because the type is what says
520/// whether `5` is an integer, a day number or the unscaled part of a decimal. Everything else is
521/// finished by the time the type arrives.
522enum Form {
523    Done(Expr),
524    Constant(Range<usize>),
525}
526
527fn read_expr(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<ExprRef> {
528    let form = read_form(plan, c)?;
529    let ty = read_annotation(c)?;
530    let expr = match form {
531        Form::Done(expr) => expr,
532        Form::Constant(span) => {
533            let text = &c.text[span];
534            let value = read_value(text, &ty)
535                .map_err(|error| c.error(&format!("{text} is not a {ty}: {}", error.message())))?;
536            Expr::Constant(plan.add_value(value))
537        }
538    };
539    Ok(plan.add_expr(expr, ty))
540}
541
542fn read_annotation(c: &mut Cursor<'_>) -> Result<LogicalType> {
543    c.expect("::")?;
544    read_type(c)
545}
546
547fn read_type(c: &mut Cursor<'_>) -> Result<LogicalType> {
548    c.skip_space();
549    let end = type_extent(c.text, c.at);
550    if end == c.at {
551        return Err(c.error("expected a type"));
552    }
553    let text = &c.text[c.at..end];
554    c.at = end;
555    LogicalType::parse(text)
556}
557
558fn read_form(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Form> {
559    c.skip_space();
560    if c.eat("#") {
561        let table = read_number(c)?;
562        c.expect(".")?;
563        let column = read_number(c)?;
564        return Ok(Form::Done(Expr::Column(ColumnBinding::new(table, column))));
565    }
566    if c.eat("(") {
567        return read_bracketed(plan, c).map(Form::Done);
568    }
569    if c.eat_word("CASE") {
570        return read_case(plan, c).map(Form::Done);
571    }
572    for (word, try_cast) in [("TRY_CAST", true), ("CAST", false)] {
573        if c.eat_word(word) {
574            c.expect("(")?;
575            let input = read_expr(plan, c)?;
576            c.expect(")")?;
577            return Ok(Form::Done(Expr::Cast { input, try_cast }));
578        }
579    }
580    if let Some(name) = try_call_name(c) {
581        let name = plan.intern(&name);
582        let mut args = Vec::new();
583        if !c.eat_space_then(")") {
584            loop {
585                args.push(read_expr(plan, c)?);
586                if !c.eat_space_then(",") {
587                    break;
588                }
589            }
590            c.expect(")")?;
591        }
592        let args = plan.add_expr_list(&args);
593        return Ok(Form::Done(Expr::Function { name, args }));
594    }
595
596    let end = literal_extent(c.text, c.at);
597    if end == c.at {
598        return Err(c.error("expected an expression"));
599    }
600    let span = c.at..end;
601    c.at = end;
602    Ok(Form::Constant(span))
603}
604
605/// A comparison or a conjunction, with the opening parenthesis already eaten.
606///
607/// Which of the two it is only becomes clear after the first operand, since both start the same
608/// way. That is one token of lookahead over an operand that has already been parsed, which is why
609/// there is no backtracking here.
610fn read_bracketed(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Expr> {
611    let left = read_expr(plan, c)?;
612    for op in [ConjunctionOp::And, ConjunctionOp::Or] {
613        if c.eat_word(op.keyword()) {
614            let mut children = vec![left];
615            loop {
616                children.push(read_expr(plan, c)?);
617                if !c.eat_word(op.keyword()) {
618                    break;
619                }
620            }
621            c.expect(")")?;
622            let children = plan.add_expr_list(&children);
623            return Ok(Expr::Conjunction { op, children });
624        }
625    }
626    c.skip_space();
627    let found = CompareOp::SPELLINGS.into_iter().find(|op| c.eat(op.symbol()));
628    let Some(op) = found else {
629        return Err(c.error("expected a comparison, AND or OR"));
630    };
631    let right = read_expr(plan, c)?;
632    c.expect(")")?;
633    Ok(Expr::Compare { op, left, right })
634}
635
636fn read_case(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Expr> {
637    let mut arms = Vec::new();
638    while c.eat_word("WHEN") {
639        let when = read_expr(plan, c)?;
640        c.expect_word("THEN")?;
641        let then = read_expr(plan, c)?;
642        arms.push(Arm { when, then });
643    }
644    let otherwise = if c.eat_word("ELSE") { Some(read_expr(plan, c)?) } else { None };
645    c.expect_word("END")?;
646    let arms = plan.add_arms(&arms);
647    Ok(Expr::Case { arms, otherwise })
648}
649
650/// A function name followed immediately by its opening parenthesis, or nothing consumed.
651///
652/// The parenthesis has to be adjacent, which is what separates a call from the bare words `NULL`,
653/// `TRUE` and `FALSE`. It is also why a function called `cast` is printed quoted: an unquoted
654/// `CAST(` is syntax and is checked before this runs, and `"cast"(` reaches here.
655fn try_call_name(c: &mut Cursor<'_>) -> Option<String> {
656    let start = c.at;
657    let Ok(name) = read_identifier(c) else {
658        c.at = start;
659        return None;
660    };
661    if c.peek() == Some('(') {
662        c.at += 1;
663        Some(name)
664    } else {
665        c.at = start;
666        None
667    }
668}
669
670fn read_identifier(c: &mut Cursor<'_>) -> Result<String> {
671    c.skip_space();
672    if c.eat("\"") {
673        let mut name = String::new();
674        loop {
675            let Some(character) = c.peek() else {
676                return Err(c.error("a quoted name is not closed"));
677            };
678            c.at += character.len_utf8();
679            if character == '"' {
680                if c.peek() == Some('"') {
681                    name.push('"');
682                    c.at += 1;
683                    continue;
684                }
685                break;
686            }
687            name.push(character);
688        }
689        return Ok(name);
690    }
691    let start = c.at;
692    while c.peek().is_some_and(|ch| ch.is_ascii_alphanumeric() || ch == '_') {
693        c.at += 1;
694    }
695    if c.at == start {
696        return Err(c.error("expected a name"));
697    }
698    Ok(c.text[start..c.at].to_string())
699}
700
701// Constants, read with their type already known.
702
703fn read_value(text: &str, ty: &LogicalType) -> Result<Value> {
704    let text = text.trim();
705    if text.eq_ignore_ascii_case("NULL") {
706        return Ok(Value::Null);
707    }
708    let whole = |what: &str| Error::parser(format!("{text} is not {what}"));
709    match ty {
710        LogicalType::Boolean => match text {
711            "TRUE" => Ok(Value::Boolean(true)),
712            "FALSE" => Ok(Value::Boolean(false)),
713            _ => Err(whole("TRUE or FALSE")),
714        },
715        LogicalType::TinyInt => text.parse().map(Value::TinyInt).map_err(|_| whole("a TINYINT")),
716        LogicalType::SmallInt => text.parse().map(Value::SmallInt).map_err(|_| whole("a SMALLINT")),
717        LogicalType::Integer => text.parse().map(Value::Integer).map_err(|_| whole("an INTEGER")),
718        LogicalType::BigInt => text.parse().map(Value::BigInt).map_err(|_| whole("a BIGINT")),
719        LogicalType::HugeInt => text.parse().map(Value::HugeInt).map_err(|_| whole("a HUGEINT")),
720        LogicalType::UTinyInt => text.parse().map(Value::UTinyInt).map_err(|_| whole("a UTINYINT")),
721        LogicalType::USmallInt => {
722            text.parse().map(Value::USmallInt).map_err(|_| whole("a USMALLINT"))
723        }
724        LogicalType::UInteger => text.parse().map(Value::UInteger).map_err(|_| whole("a UINTEGER")),
725        LogicalType::UBigInt => text.parse().map(Value::UBigInt).map_err(|_| whole("a UBIGINT")),
726        LogicalType::UHugeInt => text.parse().map(Value::UHugeInt).map_err(|_| whole("a UHUGEINT")),
727        LogicalType::Float => text.parse().map(Value::Float).map_err(|_| whole("a FLOAT")),
728        LogicalType::Double => text.parse().map(Value::Double).map_err(|_| whole("a DOUBLE")),
729        LogicalType::Decimal { width, scale } => read_decimal(text, *width, *scale),
730        LogicalType::Varchar => read_string(text).map(Value::Varchar),
731        LogicalType::Blob => read_blob(text).map(Value::Blob),
732        LogicalType::Date => text.parse().map(Value::Date).map_err(|_| whole("a day number")),
733        LogicalType::Time => {
734            text.parse().map(Value::Time).map_err(|_| whole("a microsecond count"))
735        }
736        LogicalType::Timestamp => {
737            text.parse().map(Value::Timestamp).map_err(|_| whole("a microsecond count"))
738        }
739        LogicalType::Interval => {
740            let parts = read_braced(text)?;
741            let [months, days, micros] = parts.as_slice() else {
742                return Err(whole("an interval, which is three numbers in braces"));
743            };
744            Ok(Value::Interval {
745                months: months.trim().parse().map_err(|_| whole("an interval"))?,
746                days: days.trim().parse().map_err(|_| whole("an interval"))?,
747                micros: micros.trim().parse().map_err(|_| whole("an interval"))?,
748            })
749        }
750        LogicalType::List(element) => {
751            let values = read_braced(text)?
752                .into_iter()
753                .map(|part| read_value(part, element))
754                .collect::<Result<Vec<_>>>()?;
755            Ok(Value::List { element: element.as_ref().clone(), values })
756        }
757        LogicalType::Struct(fields) => {
758            let parts = read_braced(text)?;
759            if parts.len() != fields.len() {
760                return Err(whole(&format!("a struct of {} fields", fields.len())));
761            }
762            let mut held = Vec::with_capacity(parts.len());
763            for (part, field) in parts.into_iter().zip(fields) {
764                held.push((field.name.clone(), read_value(part, &field.ty)?));
765            }
766            Ok(Value::Struct(held))
767        }
768        // Everything left is a type rudb_common::Value cannot hold, so a constant of that type
769        // cannot have been printed and cannot be built here either. A typed null of one of them is
770        // fine and was handled above.
771        other => Err(Error::not_implemented(format!(
772            "a constant of type {other} has no value representation yet"
773        ))),
774    }
775}
776
777fn read_decimal(text: &str, width: u8, scale: u8) -> Result<Value> {
778    let bad = || Error::parser(format!("{text} is not a DECIMAL({width},{scale})"));
779    let negative = text.starts_with('-');
780    let body = text.strip_prefix(['-', '+']).unwrap_or(text);
781    let digits = if scale == 0 {
782        if body.contains('.') {
783            return Err(bad());
784        }
785        body.to_string()
786    } else {
787        let (whole, fraction) = body.split_once('.').ok_or_else(bad)?;
788        if fraction.len() != usize::from(scale) {
789            return Err(bad());
790        }
791        format!("{whole}{fraction}")
792    };
793    if digits.is_empty() || !digits.bytes().all(|byte| byte.is_ascii_digit()) {
794        return Err(bad());
795    }
796    let signed = if negative { format!("-{digits}") } else { digits };
797    let unscaled: i128 = signed.parse().map_err(|_| bad())?;
798    Ok(Value::Decimal { unscaled, width, scale })
799}
800
801fn read_string(text: &str) -> Result<String> {
802    let inner = text
803        .strip_prefix('\'')
804        .and_then(|rest| rest.strip_suffix('\''))
805        .ok_or_else(|| Error::parser(format!("{text} is not a quoted string")))?;
806    let mut out = String::new();
807    let mut characters = inner.chars();
808    while let Some(character) = characters.next() {
809        match character {
810            '\'' => {
811                if characters.next() != Some('\'') {
812                    return Err(Error::parser(format!("{text} has a quote that is not doubled")));
813                }
814                out.push('\'');
815            }
816            '\\' => match characters.next() {
817                Some('\\') => out.push('\\'),
818                Some('x') => {
819                    let high = characters.next().unwrap_or(' ');
820                    let low = characters.next().unwrap_or(' ');
821                    let code = u8::from_str_radix(&format!("{high}{low}"), 16)
822                        .map_err(|_| Error::parser(format!("{text} has a bad escape")))?;
823                    out.push(char::from(code));
824                }
825                _ => return Err(Error::parser(format!("{text} has a bad escape"))),
826            },
827            other => out.push(other),
828        }
829    }
830    Ok(out)
831}
832
833fn read_blob(text: &str) -> Result<Vec<u8>> {
834    let bad = || Error::parser(format!("{text} is not a hex blob"));
835    let inner = text
836        .strip_prefix(['X', 'x'])
837        .and_then(|rest| rest.strip_prefix('\''))
838        .and_then(|rest| rest.strip_suffix('\''))
839        .ok_or_else(bad)?;
840    if inner.len() % 2 != 0 {
841        return Err(bad());
842    }
843    let mut bytes = Vec::with_capacity(inner.len() / 2);
844    for pair in inner.as_bytes().chunks(2) {
845        let pair = std::str::from_utf8(pair).map_err(|_| bad())?;
846        bytes.push(u8::from_str_radix(pair, 16).map_err(|_| bad())?);
847    }
848    Ok(bytes)
849}
850
851/// The comma separated parts of a braced list, at brace depth one.
852fn read_braced(text: &str) -> Result<Vec<&str>> {
853    let inner = text
854        .strip_prefix('{')
855        .and_then(|rest| rest.strip_suffix('}'))
856        .ok_or_else(|| Error::parser(format!("{text} is not a braced list")))?;
857    if inner.trim().is_empty() {
858        return Ok(Vec::new());
859    }
860    let mut parts = Vec::new();
861    let mut depth = 0usize;
862    let mut start = 0usize;
863    let bytes = inner.as_bytes();
864    let mut at = 0usize;
865    while at < bytes.len() {
866        match bytes[at] {
867            b'\'' => at = skip_string(inner, at) - 1,
868            b'{' => depth += 1,
869            b'}' => depth = depth.saturating_sub(1),
870            b',' if depth == 0 => {
871                parts.push(inner[start..at].trim());
872                start = at + 1;
873            }
874            _ => {}
875        }
876        at += 1;
877    }
878    parts.push(inner[start..].trim());
879    Ok(parts)
880}
881
882// Extents. Both of these answer the same question from two directions: how much of this text
883// belongs to the thing that starts here. They are byte scans rather than parses because the answer
884// is handed to a real parser afterwards, and a second grammar that has to agree with the first is
885// a second grammar that will not.
886
887/// How far a type annotation starting at `from` runs.
888///
889/// A type is a name, then an optional balanced parenthesis group, then optionally `WITH TIME ZONE`,
890/// then any number of balanced bracket groups. The time zone suffix comes before the brackets and
891/// not after, because a list of them prints as `TIME WITH TIME ZONE[]`: the suffix belongs to the
892/// element type and the brackets are the list wrapped around it. Every type
893/// [`LogicalType`](rudb_common::LogicalType) prints fits that, which `print::prints_readably`
894/// asserts over the whole type set.
895pub(crate) fn type_extent(text: &str, from: usize) -> usize {
896    let bytes = text.as_bytes();
897    let mut at = if bytes.get(from) == Some(&b'"') {
898        skip_quoted_name(text, from)
899    } else {
900        let mut at = from;
901        while at < bytes.len() && (bytes[at].is_ascii_alphanumeric() || bytes[at] == b'_') {
902            at += 1;
903        }
904        at
905    };
906    at = balanced(text, at, b'(', b')');
907    for suffix in [" WITH TIME ZONE", " WITHOUT TIME ZONE"] {
908        if starts_with_ignoring_case(&text[at..], suffix) {
909            at += suffix.len();
910            break;
911        }
912    }
913    loop {
914        let next = balanced(text, at, b'[', b']');
915        if next == at {
916            break;
917        }
918        at = next;
919    }
920    at
921}
922
923/// How far a constant starting at `from` runs, which is up to the `::` that types it.
924///
925/// Braces nest and single quotes hide everything inside them, so a string holding a colon pair and
926/// a list of structs both come out in one piece.
927fn literal_extent(text: &str, from: usize) -> usize {
928    let bytes = text.as_bytes();
929    let mut at = from;
930    let mut depth = 0usize;
931    while at < bytes.len() {
932        match bytes[at] {
933            b'\'' => {
934                at = skip_string(text, at);
935                continue;
936            }
937            b'{' => depth += 1,
938            b'}' => depth = depth.saturating_sub(1),
939            b':' if depth == 0 && bytes.get(at + 1) == Some(&b':') => return at,
940            _ => {}
941        }
942        at += 1;
943    }
944    at
945}
946
947/// Past a balanced group starting at `at`, or `at` unchanged if no group starts there.
948fn balanced(text: &str, at: usize, open: u8, close: u8) -> usize {
949    let bytes = text.as_bytes();
950    if bytes.get(at) != Some(&open) {
951        return at;
952    }
953    let mut depth = 0usize;
954    let mut here = at;
955    while here < bytes.len() {
956        match bytes[here] {
957            b'"' => {
958                here = skip_quoted_name(text, here);
959                continue;
960            }
961            b'\'' => {
962                here = skip_string(text, here);
963                continue;
964            }
965            byte if byte == open => depth += 1,
966            byte if byte == close => {
967                depth -= 1;
968                if depth == 0 {
969                    return here + 1;
970                }
971            }
972            _ => {}
973        }
974        here += 1;
975    }
976    // Unbalanced. Handing the rest of the line to the type parser gets a message naming the text
977    // that is wrong, which is more useful than one naming the character where counting stopped.
978    text.len()
979}
980
981/// Past a single quoted string starting at `at`, doubled quotes included.
982fn skip_string(text: &str, at: usize) -> usize {
983    let bytes = text.as_bytes();
984    let mut here = at + 1;
985    while here < bytes.len() {
986        if bytes[here] == b'\'' {
987            if bytes.get(here + 1) == Some(&b'\'') {
988                here += 2;
989                continue;
990            }
991            return here + 1;
992        }
993        here += 1;
994    }
995    text.len()
996}
997
998/// Past a double quoted name starting at `at`, doubled quotes included.
999fn skip_quoted_name(text: &str, at: usize) -> usize {
1000    let bytes = text.as_bytes();
1001    let mut here = at + 1;
1002    while here < bytes.len() {
1003        if bytes[here] == b'"' {
1004            if bytes.get(here + 1) == Some(&b'"') {
1005                here += 2;
1006                continue;
1007            }
1008            return here + 1;
1009        }
1010        here += 1;
1011    }
1012    text.len()
1013}
1014
1015fn starts_with_ignoring_case(text: &str, prefix: &str) -> bool {
1016    text.len() >= prefix.len()
1017        && text.as_bytes()[..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
1018}
1019
1020/// A position in one operator's argument text.
1021struct Cursor<'a> {
1022    text: &'a str,
1023    at: usize,
1024}
1025
1026impl<'a> Cursor<'a> {
1027    fn new(text: &'a str) -> Self {
1028        Self { text, at: 0 }
1029    }
1030
1031    fn rest(&self) -> &'a str {
1032        &self.text[self.at..]
1033    }
1034
1035    fn peek(&self) -> Option<char> {
1036        self.rest().chars().next()
1037    }
1038
1039    fn skip_space(&mut self) {
1040        while self.rest().starts_with(' ') {
1041            self.at += 1;
1042        }
1043    }
1044
1045    fn eat(&mut self, token: &str) -> bool {
1046        if self.rest().starts_with(token) {
1047            self.at += token.len();
1048            true
1049        } else {
1050            false
1051        }
1052    }
1053
1054    /// Eats a keyword, case insensitively, only if a whole word is there.
1055    ///
1056    /// Without the boundary check `ALL` would match the front of a column called `ALLOWED` and the
1057    /// error would land on whatever came after it.
1058    fn eat_word(&mut self, word: &str) -> bool {
1059        let start = self.at;
1060        self.skip_space();
1061        if !starts_with_ignoring_case(self.rest(), word) {
1062            self.at = start;
1063            return false;
1064        }
1065        let after = self.text[self.at + word.len()..].chars().next();
1066        if after.is_some_and(|ch| ch.is_ascii_alphanumeric() || ch == '_') {
1067            self.at = start;
1068            return false;
1069        }
1070        self.at += word.len();
1071        true
1072    }
1073
1074    /// Eats a keyword that stands where an argument could stand.
1075    ///
1076    /// `DISTINCT` and `FILTER` sit just inside an aggregate's parentheses, which is exactly where a
1077    /// call to a function of the same name could be, and [`Cursor::eat_word`] would take
1078    /// `filter(x)` for the keyword followed by a parenthesised expression. The printed form always
1079    /// puts a space after these two and a call always has its parenthesis hard against the name,
1080    /// so requiring the space is what tells them apart.
1081    fn eat_keyword_before_argument(&mut self, word: &str) -> bool {
1082        let start = self.at;
1083        self.skip_space();
1084        if starts_with_ignoring_case(self.rest(), word)
1085            && self.text[self.at + word.len()..].starts_with(' ')
1086        {
1087            self.at += word.len();
1088            return true;
1089        }
1090        self.at = start;
1091        false
1092    }
1093
1094    /// Eats a token after any spaces, leaving the cursor alone if the token is not there.
1095    fn eat_space_then(&mut self, token: &str) -> bool {
1096        let start = self.at;
1097        self.skip_space();
1098        if self.eat(token) {
1099            true
1100        } else {
1101            self.at = start;
1102            false
1103        }
1104    }
1105
1106    fn expect(&mut self, token: &str) -> Result<()> {
1107        if self.eat_space_then(token) {
1108            Ok(())
1109        } else {
1110            Err(self.error(&format!("expected \"{token}\"")))
1111        }
1112    }
1113
1114    fn expect_word(&mut self, word: &str) -> Result<()> {
1115        if self.eat_word(word) { Ok(()) } else { Err(self.error(&format!("expected \"{word}\""))) }
1116    }
1117
1118    fn done(&mut self) -> bool {
1119        self.skip_space();
1120        self.at >= self.text.len()
1121    }
1122
1123    fn error(&self, what: &str) -> Error {
1124        Error::parser(format!("{what} at column {}, reading \"{}\"", self.at + 1, self.text.trim()))
1125    }
1126}
1127
1128#[cfg(test)]
1129mod tests {
1130    use super::*;
1131    use crate::print::{RESERVED, is_plain_identifier};
1132
1133    #[test]
1134    fn a_type_annotation_ends_where_the_type_does() {
1135        for (text, expected) in [
1136            ("INTEGER DESC", "INTEGER"),
1137            ("INTEGER, x", "INTEGER"),
1138            ("INTEGER)", "INTEGER"),
1139            ("DECIMAL(18,3) AS a", "DECIMAL(18,3)"),
1140            ("INTEGER[] AS a", "INTEGER[]"),
1141            ("INTEGER[3][] ", "INTEGER[3][]"),
1142            ("MAP(VARCHAR, INTEGER)[]", "MAP(VARCHAR, INTEGER)[]"),
1143            ("STRUCT(a INTEGER, b VARCHAR) AS s", "STRUCT(a INTEGER, b VARCHAR)"),
1144            ("TIMESTAMP WITH TIME ZONE, x", "TIMESTAMP WITH TIME ZONE"),
1145            ("TIME WITH TIME ZONE]", "TIME WITH TIME ZONE"),
1146            ("TIME WITH TIME ZONE[], x", "TIME WITH TIME ZONE[]"),
1147            ("TIMESTAMP WITH TIME ZONE[4] AS t", "TIMESTAMP WITH TIME ZONE[4]"),
1148            ("TIMESTAMP DESC", "TIMESTAMP"),
1149            ("\"NULL\" AS n", "\"NULL\""),
1150        ] {
1151            let end = type_extent(text, 0);
1152            assert_eq!(&text[..end], expected, "wrong extent in {text}");
1153            LogicalType::parse(expected)
1154                .unwrap_or_else(|e| panic!("{expected} does not parse: {e}"));
1155        }
1156    }
1157
1158    /// A field name inside a struct that needs quoting can hold a bracket, and the extent scanner
1159    /// counting it would end the type in the middle of itself.
1160    #[test]
1161    fn a_quoted_field_name_does_not_end_the_type_early() {
1162        let text = "STRUCT(\"a)b\" INTEGER) AS s";
1163        let end = type_extent(text, 0);
1164        assert_eq!(&text[..end], "STRUCT(\"a)b\" INTEGER)");
1165    }
1166
1167    #[test]
1168    fn a_constant_ends_at_the_colon_pair_that_types_it() {
1169        for (text, expected) in [
1170            ("5::INTEGER", "5"),
1171            ("-5::INTEGER", "-5"),
1172            ("''::VARCHAR", "''"),
1173            ("'a::b'::VARCHAR", "'a::b'"),
1174            ("'it''s'::VARCHAR", "'it''s'"),
1175            ("{1, 2}::INTEGER[]", "{1, 2}"),
1176            ("{{1}, {2}}::INTEGER[][]", "{{1}, {2}}"),
1177            ("X'00ff'::BLOB", "X'00ff'"),
1178            ("NULL::VARCHAR", "NULL"),
1179        ] {
1180            let end = literal_extent(text, 0);
1181            assert_eq!(&text[..end], expected, "wrong extent in {text}");
1182        }
1183    }
1184
1185    #[test]
1186    fn a_decimal_reads_back_at_its_own_scale() {
1187        assert_eq!(
1188            read_decimal("12.34", 6, 2).unwrap(),
1189            Value::Decimal { unscaled: 1234, width: 6, scale: 2 }
1190        );
1191        assert_eq!(
1192            read_decimal("-0.005", 6, 3).unwrap(),
1193            Value::Decimal { unscaled: -5, width: 6, scale: 3 }
1194        );
1195        assert_eq!(
1196            read_decimal("1234", 6, 0).unwrap(),
1197            Value::Decimal { unscaled: 1234, width: 6, scale: 0 }
1198        );
1199    }
1200
1201    /// The digits after the point have to be exactly the scale. `1.5::DECIMAL(6,2)` is a hundred
1202    /// times off from `1.50::DECIMAL(6,2)` and there is no reading of it that is obviously right,
1203    /// so it is rejected rather than guessed at.
1204    #[test]
1205    fn a_decimal_with_the_wrong_number_of_digits_is_rejected() {
1206        assert!(read_decimal("1.5", 6, 2).is_err());
1207        assert!(read_decimal("1.500", 6, 2).is_err());
1208        assert!(read_decimal("15", 6, 2).is_err());
1209        assert!(read_decimal("1.5", 6, 0).is_err());
1210    }
1211
1212    #[test]
1213    fn a_string_gives_its_quotes_and_escapes_back() {
1214        assert_eq!(read_string("''").unwrap(), "");
1215        assert_eq!(read_string("'it''s'").unwrap(), "it's");
1216        assert_eq!(read_string("'a\\\\b'").unwrap(), "a\\b");
1217        assert_eq!(read_string("'one\\x0atwo'").unwrap(), "one\ntwo");
1218        assert!(read_string("'").is_err());
1219        assert!(read_string("no quotes").is_err());
1220    }
1221
1222    #[test]
1223    fn a_blob_is_pairs_of_hex_digits() {
1224        assert_eq!(read_blob("X''").unwrap(), Vec::<u8>::new());
1225        assert_eq!(read_blob("X'00ff10'").unwrap(), vec![0x00, 0xff, 0x10]);
1226        assert!(read_blob("X'0'").is_err(), "an odd number of digits is not a byte string");
1227        assert!(read_blob("X'zz'").is_err());
1228    }
1229
1230    #[test]
1231    fn a_braced_list_splits_at_the_top_level_only() {
1232        assert_eq!(read_braced("{}").unwrap(), Vec::<&str>::new());
1233        assert_eq!(read_braced("{1}").unwrap(), vec!["1"]);
1234        assert_eq!(read_braced("{1, 2}").unwrap(), vec!["1", "2"]);
1235        assert_eq!(read_braced("{{1, 2}, {3}}").unwrap(), vec!["{1, 2}", "{3}"]);
1236        assert_eq!(read_braced("{'a,b', 'c'}").unwrap(), vec!["'a,b'", "'c'"]);
1237        assert!(read_braced("1, 2").is_err());
1238    }
1239
1240    #[test]
1241    fn a_keyword_needs_a_word_boundary() {
1242        let mut c = Cursor::new(" ALLOWED");
1243        assert!(!c.eat_word("ALL"), "ALL should not match the front of ALLOWED");
1244        assert!(c.eat_word("ALLOWED"));
1245        let mut c = Cursor::new(" all ");
1246        assert!(c.eat_word("ALL"), "keywords are case insensitive");
1247    }
1248
1249    #[test]
1250    fn an_odd_indent_is_an_error_and_says_so() {
1251        let message = Plan::parse("Filter x\n   Dummy\n").unwrap_err().to_string();
1252        assert!(message.contains("whole number of levels"), "unhelpful message: {message}");
1253    }
1254
1255    #[test]
1256    fn a_tab_is_an_error_rather_than_a_guess() {
1257        let message = Plan::parse("Filter x\n\tDummy\n").unwrap_err().to_string();
1258        assert!(message.contains("tab"), "unhelpful message: {message}");
1259    }
1260
1261    #[test]
1262    fn an_unknown_operator_names_itself() {
1263        let message = Plan::parse("Frobnicate\n").unwrap_err().to_string();
1264        assert!(message.contains("Frobnicate"), "unhelpful message: {message}");
1265    }
1266
1267    #[test]
1268    fn a_missing_child_is_an_error_rather_than_a_plan_with_a_hole() {
1269        let message = Plan::parse("Filter TRUE::BOOLEAN\n").unwrap_err().to_string();
1270        assert!(message.contains("expected an operator"), "unhelpful message: {message}");
1271    }
1272
1273    #[test]
1274    fn a_second_root_is_an_error() {
1275        let message = Plan::parse("Dummy\nDummy\n").unwrap_err().to_string();
1276        assert!(message.contains("past the end"), "unhelpful message: {message}");
1277    }
1278
1279    #[test]
1280    fn text_left_over_on_a_line_is_an_error() {
1281        let message = Plan::parse("Dummy nonsense\n").unwrap_err().to_string();
1282        assert!(message.contains("left over"), "unhelpful message: {message}");
1283    }
1284
1285    #[test]
1286    fn an_empty_plan_is_not_a_plan() {
1287        assert!(Plan::parse("").is_err());
1288        assert!(Plan::parse("\n\n  \n").is_err());
1289    }
1290
1291    /// The reader has to reject what the validator rejects, or a hand-written dump becomes a way
1292    /// to build a plan nobody could build through the arena.
1293    #[test]
1294    fn the_reader_runs_the_plan_invariant() {
1295        let message = Plan::parse("Filter 1::INTEGER\n  Dummy\n").unwrap_err().to_string();
1296        assert!(message.contains("BOOLEAN"), "unhelpful message: {message}");
1297    }
1298
1299    /// The printer quotes a function whose name is a reserved word. If that quoting did not buy a
1300    /// different reading here it would be quoting for nothing, and a function called `cast` would
1301    /// come back as a cast with the wrong number of operands.
1302    #[test]
1303    fn a_quoted_reserved_word_is_a_function_and_not_syntax() {
1304        for reserved in RESERVED {
1305            let text = format!("Project #1 [\"{reserved}\"(1::INTEGER)::INTEGER AS a]\n  Dummy\n");
1306            let plan = Plan::parse(&text).unwrap_or_else(|e| panic!("{text} does not read: {e}"));
1307            assert!(matches!(plan.expr(0), Expr::Constant(_)));
1308            assert!(matches!(plan.expr(1), Expr::Function { .. }), "{reserved} became syntax");
1309            assert_eq!(plan.to_string(), text);
1310        }
1311    }
1312
1313    #[test]
1314    fn an_unquoted_cast_is_syntax_and_not_a_function() {
1315        let text = "Project #1 [CAST(1::INTEGER)::BIGINT AS a]\n  Dummy\n";
1316        let plan = Plan::parse(text).expect("a cast reads back");
1317        assert!(matches!(plan.expr(1), Expr::Cast { try_cast: false, .. }));
1318        assert_eq!(plan.to_string(), text);
1319    }
1320
1321    /// `FILTER` and `DISTINCT` stand where an argument could stand, so a function of the same name
1322    /// in argument position is the case that tells whether the keyword check is precise enough.
1323    #[test]
1324    fn a_function_called_filter_in_argument_position_is_a_call() {
1325        let text = "Aggregate #1 groups=[] aggregates=[sum(filter(1::INTEGER)::INTEGER)::HUGEINT]\n  Dummy\n";
1326        let plan = Plan::parse(text).expect("an argument called filter reads back");
1327        assert_eq!(plan.to_string(), text);
1328    }
1329
1330    #[test]
1331    fn an_aggregate_with_no_arguments_can_still_have_a_filter() {
1332        let text = "Aggregate #1 groups=[] aggregates=[count_star(FILTER TRUE::BOOLEAN)::BIGINT]\n  Dummy\n";
1333        let plan = Plan::parse(text).expect("count(*) FILTER (WHERE p) is a real query");
1334        assert_eq!(plan.to_string(), text);
1335    }
1336
1337    #[test]
1338    fn a_name_that_is_not_a_plain_identifier_is_quoted_by_the_printer_and_read_here() {
1339        let mut c = Cursor::new("\"say \"\"hi\"\"\" rest");
1340        assert_eq!(read_identifier(&mut c).unwrap(), "say \"hi\"");
1341        assert_eq!(c.rest(), " rest");
1342        assert!(!is_plain_identifier("say \"hi\""));
1343    }
1344}