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