1use 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 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#[derive(Debug)]
56struct Line<'a> {
57 depth: usize,
59 text: &'a str,
61 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 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 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 "TableFetch" => {
202 let catalog = read_name(plan, c)?;
203 c.expect(".")?;
204 let schema = read_name(plan, c)?;
205 c.expect(".")?;
206 let table = read_name(plan, c)?;
207 c.expect_word("row")?;
208 c.expect("=")?;
209 let row = read_expr(plan, c)?;
210 let index = read_table_index(c)?;
211 let columns = read_schema(plan, c)?;
212 Ok(Built::unary(move |input| Node::TableFetch {
213 input,
214 index,
215 catalog,
216 schema,
217 table,
218 columns,
219 row,
220 }))
221 }
222 "Filter" => {
223 let predicate = read_expr(plan, c)?;
224 Ok(Built::unary(move |input| Node::Filter { input, predicate }))
225 }
226 "Project" => {
227 let index = read_table_index(c)?;
228 let mut exprs = Vec::new();
229 let mut names = Vec::new();
230 c.expect("[")?;
231 if !c.eat_space_then("]") {
232 loop {
233 exprs.push(read_expr(plan, c)?);
234 c.expect_word("AS")?;
235 names.push(read_name(plan, c)?);
236 if !c.eat_space_then(",") {
237 break;
238 }
239 }
240 c.expect("]")?;
241 }
242 let exprs = plan.add_expr_list(&exprs);
243 let names = plan.add_name_list(&names);
244 Ok(Built::unary(move |input| Node::Project { input, index, exprs, names }))
245 }
246 "Aggregate" => {
247 let index = read_table_index(c)?;
248 c.expect_word("groups")?;
249 c.expect("=")?;
250 let groups = read_expr_list(plan, c)?;
251 c.expect_word("aggregates")?;
252 c.expect("=")?;
253 let aggregates = read_aggregate_list(plan, c)?;
254 Ok(Built::unary(move |input| Node::Aggregate { input, index, groups, aggregates }))
255 }
256 "Sort" => {
257 let keys = read_sort_keys(plan, c)?;
258 Ok(Built::unary(move |input| Node::Sort { input, keys }))
259 }
260 "Limit" => {
261 let count = if c.eat_word("ALL") { None } else { Some(read_count(c)?) };
262 c.expect_word("offset")?;
263 let offset = read_count(c)?;
264 Ok(Built::unary(move |input| Node::Limit { input, count, offset }))
265 }
266 "TopN" => {
267 let count = read_count(c)?;
268 c.expect_word("offset")?;
269 let offset = read_count(c)?;
270 let keys = read_sort_keys(plan, c)?;
271 Ok(Built::unary(move |input| Node::TopN { input, keys, count, offset }))
272 }
273 "Distinct" => {
274 c.expect_word("on")?;
275 c.expect("=")?;
276 let on = read_expr_list(plan, c)?;
277 Ok(Built::unary(move |input| Node::Distinct { input, on }))
278 }
279 "Join" => {
280 let kind = read_keyword(c, &JoinKind::ALL, JoinKind::keyword, "a join kind")?;
281 c.expect_word("on")?;
282 c.expect("=")?;
283 let conditions = read_expr_list(plan, c)?;
284 Ok(Built {
285 arity: 2,
286 assemble: Box::new(move |left, right| Node::Join {
287 left,
288 right,
289 kind,
290 conditions,
291 }),
292 })
293 }
294 "SetOp" => {
295 let kind = read_keyword(c, &SetOpKind::ALL, SetOpKind::keyword, "a set operation")?;
296 let all = if c.eat_word("ALL") {
297 true
298 } else if c.eat_word("DISTINCT") {
299 false
300 } else {
301 return Err(c.error("expected ALL or DISTINCT"));
302 };
303 let index = read_table_index(c)?;
304 Ok(Built {
305 arity: 2,
306 assemble: Box::new(move |left, right| Node::SetOp {
307 left,
308 right,
309 kind,
310 all,
311 index,
312 }),
313 })
314 }
315 other => Err(Error::parser(format!("\"{other}\" is not an operator"))),
316 }
317 }
318}
319
320struct Built {
322 arity: usize,
323 assemble: Box<dyn FnOnce(NodeRef, NodeRef) -> Node>,
324}
325
326impl Built {
327 fn leaf(node: Node) -> Self {
328 Self { arity: 0, assemble: Box::new(move |_, _| node) }
329 }
330
331 fn unary(make: impl FnOnce(NodeRef) -> Node + 'static) -> Self {
332 Self { arity: 1, assemble: Box::new(move |input, _| make(input)) }
333 }
334}
335
336fn read_table_index(c: &mut Cursor<'_>) -> Result<u32> {
339 c.expect("#")?;
340 read_number(c)
341}
342
343fn read_count(c: &mut Cursor<'_>) -> Result<u64> {
344 c.skip_space();
345 let start = c.at;
346 while c.peek().is_some_and(|ch| ch.is_ascii_digit()) {
347 c.at += 1;
348 }
349 if c.at == start {
350 return Err(c.error("expected a row count"));
351 }
352 c.text[start..c.at].parse().map_err(|_| c.error("that row count does not fit in 64 bits"))
353}
354
355fn read_number(c: &mut Cursor<'_>) -> Result<u32> {
356 c.skip_space();
357 let start = c.at;
358 while c.peek().is_some_and(|ch| ch.is_ascii_digit()) {
359 c.at += 1;
360 }
361 if c.at == start {
362 return Err(c.error("expected a number"));
363 }
364 c.text[start..c.at].parse().map_err(|_| c.error("that number does not fit in 32 bits"))
365}
366
367fn read_keyword<T: Copy>(
370 c: &mut Cursor<'_>,
371 all: &[T],
372 spell: impl Fn(T) -> &'static str,
373 what: &str,
374) -> Result<T> {
375 let mut candidates: Vec<T> = all.to_vec();
376 candidates.sort_by_key(|&kind| std::cmp::Reverse(spell(kind).len()));
377 for candidate in candidates {
378 if c.eat_word(spell(candidate)) {
379 return Ok(candidate);
380 }
381 }
382 Err(c.error(&format!("expected {what}")))
383}
384
385fn read_name(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<u32> {
386 let name = read_identifier(c)?;
387 Ok(plan.intern(&name))
388}
389
390fn read_schema(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
392 let mut fields = Vec::new();
393 c.expect("[")?;
394 if !c.eat_space_then("]") {
395 loop {
396 let name = read_identifier(c)?;
397 c.expect("::")?;
398 let ty = read_type(c)?;
399 fields.push(Field::new(name, ty));
400 if !c.eat_space_then(",") {
401 break;
402 }
403 }
404 c.expect("]")?;
405 }
406 Ok(plan.add_fields(&fields))
407}
408
409fn read_options(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<(Slice, Slice)> {
414 if !c.eat_space_then("options=[") {
415 return Ok((Slice::EMPTY, Slice::EMPTY));
416 }
417 let mut names = Vec::new();
418 let mut settings = Vec::new();
419 if !c.eat_space_then("]") {
420 loop {
421 names.push(read_name(plan, c)?);
422 c.expect("=")?;
423 settings.push(read_expr(plan, c)?);
424 if !c.eat_space_then(",") {
425 break;
426 }
427 }
428 c.expect("]")?;
429 }
430 Ok((plan.add_name_list(&names), plan.add_expr_list(&settings)))
431}
432
433fn read_expr_list(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
434 let mut exprs = Vec::new();
435 c.expect("[")?;
436 if !c.eat_space_then("]") {
437 loop {
438 exprs.push(read_expr(plan, c)?);
439 if !c.eat_space_then(",") {
440 break;
441 }
442 }
443 c.expect("]")?;
444 }
445 Ok(plan.add_expr_list(&exprs))
446}
447
448fn read_aggregate_list(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
454 let mut exprs = Vec::new();
455 c.expect("[")?;
456 if !c.eat_space_then("]") {
457 loop {
458 exprs.push(read_aggregate(plan, c)?);
459 if !c.eat_space_then(",") {
460 break;
461 }
462 }
463 c.expect("]")?;
464 }
465 Ok(plan.add_expr_list(&exprs))
466}
467
468fn read_aggregate(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<ExprRef> {
469 c.skip_space();
470 let Some(name) = try_call_name(c) else {
471 return Err(c.error("expected an aggregate call"));
472 };
473 let name = plan.intern(&name);
474 let distinct = c.eat_keyword_before_argument("DISTINCT");
475 let mut args = Vec::new();
476 let mut filter = None;
477 if !c.eat_space_then(")") {
478 let mut filtered = c.eat_keyword_before_argument("FILTER");
481 if !filtered {
482 loop {
483 args.push(read_expr(plan, c)?);
484 if !c.eat_space_then(",") {
485 break;
486 }
487 }
488 filtered = c.eat_keyword_before_argument("FILTER");
489 }
490 if filtered {
491 filter = Some(read_expr(plan, c)?);
492 }
493 c.expect(")")?;
494 }
495 let args = plan.add_expr_list(&args);
496 let ty = read_annotation(c)?;
497 Ok(plan.add_expr(Expr::Aggregate { name, args, distinct, filter }, ty))
498}
499
500fn read_sort_keys(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Slice> {
502 let mut keys = Vec::new();
503 c.expect("[")?;
504 if !c.eat_space_then("]") {
505 loop {
506 keys.push(read_sort_key(plan, c)?);
507 if !c.eat_space_then(",") {
508 break;
509 }
510 }
511 c.expect("]")?;
512 }
513 Ok(plan.add_sort_keys(&keys))
514}
515
516fn read_sort_key(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<SortKey> {
517 let expr = read_expr(plan, c)?;
518 let descending = if c.eat_word("DESC") {
519 true
520 } else if c.eat_word("ASC") {
521 false
522 } else {
523 return Err(c.error("expected ASC or DESC"));
524 };
525 c.expect_word("NULLS")?;
526 let nulls_first = if c.eat_word("FIRST") {
527 true
528 } else if c.eat_word("LAST") {
529 false
530 } else {
531 return Err(c.error("expected FIRST or LAST"));
532 };
533 Ok(SortKey { expr, descending, nulls_first })
534}
535
536enum Form {
544 Done(Expr),
545 Constant(Range<usize>),
546}
547
548fn read_expr(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<ExprRef> {
549 let form = read_form(plan, c)?;
550 let ty = read_annotation(c)?;
551 let expr = match form {
552 Form::Done(expr) => expr,
553 Form::Constant(span) => {
554 let text = &c.text[span];
555 let value = read_value(text, &ty)
556 .map_err(|error| c.error(&format!("{text} is not a {ty}: {}", error.message())))?;
557 Expr::Constant(plan.add_value(value))
558 }
559 };
560 Ok(plan.add_expr(expr, ty))
561}
562
563fn read_annotation(c: &mut Cursor<'_>) -> Result<LogicalType> {
564 c.expect("::")?;
565 read_type(c)
566}
567
568fn read_type(c: &mut Cursor<'_>) -> Result<LogicalType> {
569 c.skip_space();
570 let end = type_extent(c.text, c.at);
571 if end == c.at {
572 return Err(c.error("expected a type"));
573 }
574 let text = &c.text[c.at..end];
575 c.at = end;
576 LogicalType::parse(text)
577}
578
579fn read_form(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Form> {
580 c.skip_space();
581 if c.eat("#") {
582 let table = read_number(c)?;
583 c.expect(".")?;
584 let column = read_number(c)?;
585 return Ok(Form::Done(Expr::Column(ColumnBinding::new(table, column))));
586 }
587 if c.eat("(") {
588 return read_bracketed(plan, c).map(Form::Done);
589 }
590 if c.eat_word("CASE") {
591 return read_case(plan, c).map(Form::Done);
592 }
593 for (word, try_cast) in [("TRY_CAST", true), ("CAST", false)] {
594 if c.eat_word(word) {
595 c.expect("(")?;
596 let input = read_expr(plan, c)?;
597 c.expect(")")?;
598 return Ok(Form::Done(Expr::Cast { input, try_cast }));
599 }
600 }
601 if let Some(name) = try_call_name(c) {
602 let name = plan.intern(&name);
603 let mut args = Vec::new();
604 if !c.eat_space_then(")") {
605 loop {
606 args.push(read_expr(plan, c)?);
607 if !c.eat_space_then(",") {
608 break;
609 }
610 }
611 c.expect(")")?;
612 }
613 let args = plan.add_expr_list(&args);
614 return Ok(Form::Done(Expr::Function { name, args }));
615 }
616
617 let end = literal_extent(c.text, c.at);
618 if end == c.at {
619 return Err(c.error("expected an expression"));
620 }
621 let span = c.at..end;
622 c.at = end;
623 Ok(Form::Constant(span))
624}
625
626fn read_bracketed(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Expr> {
632 let left = read_expr(plan, c)?;
633 for op in [ConjunctionOp::And, ConjunctionOp::Or] {
634 if c.eat_word(op.keyword()) {
635 let mut children = vec![left];
636 loop {
637 children.push(read_expr(plan, c)?);
638 if !c.eat_word(op.keyword()) {
639 break;
640 }
641 }
642 c.expect(")")?;
643 let children = plan.add_expr_list(&children);
644 return Ok(Expr::Conjunction { op, children });
645 }
646 }
647 c.skip_space();
648 let found = CompareOp::SPELLINGS.into_iter().find(|op| c.eat(op.symbol()));
649 let Some(op) = found else {
650 return Err(c.error("expected a comparison, AND or OR"));
651 };
652 let right = read_expr(plan, c)?;
653 c.expect(")")?;
654 Ok(Expr::Compare { op, left, right })
655}
656
657fn read_case(plan: &mut Plan, c: &mut Cursor<'_>) -> Result<Expr> {
658 let mut arms = Vec::new();
659 while c.eat_word("WHEN") {
660 let when = read_expr(plan, c)?;
661 c.expect_word("THEN")?;
662 let then = read_expr(plan, c)?;
663 arms.push(Arm { when, then });
664 }
665 let otherwise = if c.eat_word("ELSE") { Some(read_expr(plan, c)?) } else { None };
666 c.expect_word("END")?;
667 let arms = plan.add_arms(&arms);
668 Ok(Expr::Case { arms, otherwise })
669}
670
671fn try_call_name(c: &mut Cursor<'_>) -> Option<String> {
677 let start = c.at;
678 let Ok(name) = read_identifier(c) else {
679 c.at = start;
680 return None;
681 };
682 if c.peek() == Some('(') {
683 c.at += 1;
684 Some(name)
685 } else {
686 c.at = start;
687 None
688 }
689}
690
691fn read_identifier(c: &mut Cursor<'_>) -> Result<String> {
692 c.skip_space();
693 if c.eat("\"") {
694 let mut name = String::new();
695 loop {
696 let Some(character) = c.peek() else {
697 return Err(c.error("a quoted name is not closed"));
698 };
699 c.at += character.len_utf8();
700 if character == '"' {
701 if c.peek() == Some('"') {
702 name.push('"');
703 c.at += 1;
704 continue;
705 }
706 break;
707 }
708 name.push(character);
709 }
710 return Ok(name);
711 }
712 let start = c.at;
713 while c.peek().is_some_and(|ch| ch.is_ascii_alphanumeric() || ch == '_') {
714 c.at += 1;
715 }
716 if c.at == start {
717 return Err(c.error("expected a name"));
718 }
719 Ok(c.text[start..c.at].to_string())
720}
721
722fn read_value(text: &str, ty: &LogicalType) -> Result<Value> {
725 let text = text.trim();
726 if text.eq_ignore_ascii_case("NULL") {
727 return Ok(Value::Null);
728 }
729 let whole = |what: &str| Error::parser(format!("{text} is not {what}"));
730 match ty {
731 LogicalType::Boolean => match text {
732 "TRUE" => Ok(Value::Boolean(true)),
733 "FALSE" => Ok(Value::Boolean(false)),
734 _ => Err(whole("TRUE or FALSE")),
735 },
736 LogicalType::TinyInt => text.parse().map(Value::TinyInt).map_err(|_| whole("a TINYINT")),
737 LogicalType::SmallInt => text.parse().map(Value::SmallInt).map_err(|_| whole("a SMALLINT")),
738 LogicalType::Integer => text.parse().map(Value::Integer).map_err(|_| whole("an INTEGER")),
739 LogicalType::BigInt => text.parse().map(Value::BigInt).map_err(|_| whole("a BIGINT")),
740 LogicalType::HugeInt => text.parse().map(Value::HugeInt).map_err(|_| whole("a HUGEINT")),
741 LogicalType::UTinyInt => text.parse().map(Value::UTinyInt).map_err(|_| whole("a UTINYINT")),
742 LogicalType::USmallInt => {
743 text.parse().map(Value::USmallInt).map_err(|_| whole("a USMALLINT"))
744 }
745 LogicalType::UInteger => text.parse().map(Value::UInteger).map_err(|_| whole("a UINTEGER")),
746 LogicalType::UBigInt => text.parse().map(Value::UBigInt).map_err(|_| whole("a UBIGINT")),
747 LogicalType::UHugeInt => text.parse().map(Value::UHugeInt).map_err(|_| whole("a UHUGEINT")),
748 LogicalType::Float => text.parse().map(Value::Float).map_err(|_| whole("a FLOAT")),
749 LogicalType::Double => text.parse().map(Value::Double).map_err(|_| whole("a DOUBLE")),
750 LogicalType::Decimal { width, scale } => read_decimal(text, *width, *scale),
751 LogicalType::Varchar => read_string(text).map(Value::Varchar),
752 LogicalType::Blob => read_blob(text).map(Value::Blob),
753 LogicalType::Date => text.parse().map(Value::Date).map_err(|_| whole("a day number")),
754 LogicalType::Time => {
755 text.parse().map(Value::Time).map_err(|_| whole("a microsecond count"))
756 }
757 LogicalType::TimeTz => {
758 text.parse().map(Value::TimeTz).map_err(|_| whole("a microsecond count"))
759 }
760 LogicalType::Timestamp => {
761 text.parse().map(Value::Timestamp).map_err(|_| whole("a microsecond count"))
762 }
763 LogicalType::TimestampTz => {
764 text.parse().map(Value::TimestampTz).map_err(|_| whole("a microsecond count"))
765 }
766 LogicalType::Interval => {
767 let parts = read_braced(text)?;
768 let [months, days, micros] = parts.as_slice() else {
769 return Err(whole("an interval, which is three numbers in braces"));
770 };
771 Ok(Value::Interval {
772 months: months.trim().parse().map_err(|_| whole("an interval"))?,
773 days: days.trim().parse().map_err(|_| whole("an interval"))?,
774 micros: micros.trim().parse().map_err(|_| whole("an interval"))?,
775 })
776 }
777 LogicalType::List(element) => {
778 let values = read_braced(text)?
779 .into_iter()
780 .map(|part| read_value(part, element))
781 .collect::<Result<Vec<_>>>()?;
782 Ok(Value::List { element: element.as_ref().clone(), values })
783 }
784 LogicalType::Struct(fields) => {
785 let parts = read_braced(text)?;
786 if parts.len() != fields.len() {
787 return Err(whole(&format!("a struct of {} fields", fields.len())));
788 }
789 let mut held = Vec::with_capacity(parts.len());
790 for (part, field) in parts.into_iter().zip(fields) {
791 held.push((field.name.clone(), read_value(part, &field.ty)?));
792 }
793 Ok(Value::Struct(held))
794 }
795 other => Err(Error::not_implemented(format!(
799 "a constant of type {other} has no value representation yet"
800 ))),
801 }
802}
803
804fn read_decimal(text: &str, width: u8, scale: u8) -> Result<Value> {
805 let bad = || Error::parser(format!("{text} is not a DECIMAL({width},{scale})"));
806 let negative = text.starts_with('-');
807 let body = text.strip_prefix(['-', '+']).unwrap_or(text);
808 let digits = if scale == 0 {
809 if body.contains('.') {
810 return Err(bad());
811 }
812 body.to_string()
813 } else {
814 let (whole, fraction) = body.split_once('.').ok_or_else(bad)?;
815 if fraction.len() != usize::from(scale) {
816 return Err(bad());
817 }
818 format!("{whole}{fraction}")
819 };
820 if digits.is_empty() || !digits.bytes().all(|byte| byte.is_ascii_digit()) {
821 return Err(bad());
822 }
823 let signed = if negative { format!("-{digits}") } else { digits };
824 let unscaled: i128 = signed.parse().map_err(|_| bad())?;
825 Ok(Value::Decimal { unscaled, width, scale })
826}
827
828fn read_string(text: &str) -> Result<String> {
829 let inner = text
830 .strip_prefix('\'')
831 .and_then(|rest| rest.strip_suffix('\''))
832 .ok_or_else(|| Error::parser(format!("{text} is not a quoted string")))?;
833 let mut out = String::new();
834 let mut characters = inner.chars();
835 while let Some(character) = characters.next() {
836 match character {
837 '\'' => {
838 if characters.next() != Some('\'') {
839 return Err(Error::parser(format!("{text} has a quote that is not doubled")));
840 }
841 out.push('\'');
842 }
843 '\\' => match characters.next() {
844 Some('\\') => out.push('\\'),
845 Some('x') => {
846 let high = characters.next().unwrap_or(' ');
847 let low = characters.next().unwrap_or(' ');
848 let code = u8::from_str_radix(&format!("{high}{low}"), 16)
849 .map_err(|_| Error::parser(format!("{text} has a bad escape")))?;
850 out.push(char::from(code));
851 }
852 _ => return Err(Error::parser(format!("{text} has a bad escape"))),
853 },
854 other => out.push(other),
855 }
856 }
857 Ok(out)
858}
859
860fn read_blob(text: &str) -> Result<Vec<u8>> {
861 let bad = || Error::parser(format!("{text} is not a hex blob"));
862 let inner = text
863 .strip_prefix(['X', 'x'])
864 .and_then(|rest| rest.strip_prefix('\''))
865 .and_then(|rest| rest.strip_suffix('\''))
866 .ok_or_else(bad)?;
867 if inner.len() % 2 != 0 {
868 return Err(bad());
869 }
870 let mut bytes = Vec::with_capacity(inner.len() / 2);
871 for pair in inner.as_bytes().chunks(2) {
872 let pair = std::str::from_utf8(pair).map_err(|_| bad())?;
873 bytes.push(u8::from_str_radix(pair, 16).map_err(|_| bad())?);
874 }
875 Ok(bytes)
876}
877
878fn read_braced(text: &str) -> Result<Vec<&str>> {
880 let inner = text
881 .strip_prefix('{')
882 .and_then(|rest| rest.strip_suffix('}'))
883 .ok_or_else(|| Error::parser(format!("{text} is not a braced list")))?;
884 if inner.trim().is_empty() {
885 return Ok(Vec::new());
886 }
887 let mut parts = Vec::new();
888 let mut depth = 0usize;
889 let mut start = 0usize;
890 let bytes = inner.as_bytes();
891 let mut at = 0usize;
892 while at < bytes.len() {
893 match bytes[at] {
894 b'\'' => at = skip_string(inner, at) - 1,
895 b'{' => depth += 1,
896 b'}' => depth = depth.saturating_sub(1),
897 b',' if depth == 0 => {
898 parts.push(inner[start..at].trim());
899 start = at + 1;
900 }
901 _ => {}
902 }
903 at += 1;
904 }
905 parts.push(inner[start..].trim());
906 Ok(parts)
907}
908
909pub(crate) fn type_extent(text: &str, from: usize) -> usize {
923 let bytes = text.as_bytes();
924 let mut at = if bytes.get(from) == Some(&b'"') {
925 skip_quoted_name(text, from)
926 } else {
927 let mut at = from;
928 while at < bytes.len() && (bytes[at].is_ascii_alphanumeric() || bytes[at] == b'_') {
929 at += 1;
930 }
931 at
932 };
933 at = balanced(text, at, b'(', b')');
934 for suffix in [" WITH TIME ZONE", " WITHOUT TIME ZONE"] {
935 if starts_with_ignoring_case(&text[at..], suffix) {
936 at += suffix.len();
937 break;
938 }
939 }
940 loop {
941 let next = balanced(text, at, b'[', b']');
942 if next == at {
943 break;
944 }
945 at = next;
946 }
947 at
948}
949
950fn literal_extent(text: &str, from: usize) -> usize {
955 let bytes = text.as_bytes();
956 let mut at = from;
957 let mut depth = 0usize;
958 while at < bytes.len() {
959 match bytes[at] {
960 b'\'' => {
961 at = skip_string(text, at);
962 continue;
963 }
964 b'{' => depth += 1,
965 b'}' => depth = depth.saturating_sub(1),
966 b':' if depth == 0 && bytes.get(at + 1) == Some(&b':') => return at,
967 _ => {}
968 }
969 at += 1;
970 }
971 at
972}
973
974fn balanced(text: &str, at: usize, open: u8, close: u8) -> usize {
976 let bytes = text.as_bytes();
977 if bytes.get(at) != Some(&open) {
978 return at;
979 }
980 let mut depth = 0usize;
981 let mut here = at;
982 while here < bytes.len() {
983 match bytes[here] {
984 b'"' => {
985 here = skip_quoted_name(text, here);
986 continue;
987 }
988 b'\'' => {
989 here = skip_string(text, here);
990 continue;
991 }
992 byte if byte == open => depth += 1,
993 byte if byte == close => {
994 depth -= 1;
995 if depth == 0 {
996 return here + 1;
997 }
998 }
999 _ => {}
1000 }
1001 here += 1;
1002 }
1003 text.len()
1006}
1007
1008fn skip_string(text: &str, at: usize) -> usize {
1010 let bytes = text.as_bytes();
1011 let mut here = at + 1;
1012 while here < bytes.len() {
1013 if bytes[here] == b'\'' {
1014 if bytes.get(here + 1) == Some(&b'\'') {
1015 here += 2;
1016 continue;
1017 }
1018 return here + 1;
1019 }
1020 here += 1;
1021 }
1022 text.len()
1023}
1024
1025fn skip_quoted_name(text: &str, at: usize) -> usize {
1027 let bytes = text.as_bytes();
1028 let mut here = at + 1;
1029 while here < bytes.len() {
1030 if bytes[here] == b'"' {
1031 if bytes.get(here + 1) == Some(&b'"') {
1032 here += 2;
1033 continue;
1034 }
1035 return here + 1;
1036 }
1037 here += 1;
1038 }
1039 text.len()
1040}
1041
1042fn starts_with_ignoring_case(text: &str, prefix: &str) -> bool {
1043 text.len() >= prefix.len()
1044 && text.as_bytes()[..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
1045}
1046
1047struct Cursor<'a> {
1049 text: &'a str,
1050 at: usize,
1051}
1052
1053impl<'a> Cursor<'a> {
1054 fn new(text: &'a str) -> Self {
1055 Self { text, at: 0 }
1056 }
1057
1058 fn rest(&self) -> &'a str {
1059 &self.text[self.at..]
1060 }
1061
1062 fn peek(&self) -> Option<char> {
1063 self.rest().chars().next()
1064 }
1065
1066 fn skip_space(&mut self) {
1067 while self.rest().starts_with(' ') {
1068 self.at += 1;
1069 }
1070 }
1071
1072 fn eat(&mut self, token: &str) -> bool {
1073 if self.rest().starts_with(token) {
1074 self.at += token.len();
1075 true
1076 } else {
1077 false
1078 }
1079 }
1080
1081 fn eat_word(&mut self, word: &str) -> bool {
1086 let start = self.at;
1087 self.skip_space();
1088 if !starts_with_ignoring_case(self.rest(), word) {
1089 self.at = start;
1090 return false;
1091 }
1092 let after = self.text[self.at + word.len()..].chars().next();
1093 if after.is_some_and(|ch| ch.is_ascii_alphanumeric() || ch == '_') {
1094 self.at = start;
1095 return false;
1096 }
1097 self.at += word.len();
1098 true
1099 }
1100
1101 fn eat_keyword_before_argument(&mut self, word: &str) -> bool {
1109 let start = self.at;
1110 self.skip_space();
1111 if starts_with_ignoring_case(self.rest(), word)
1112 && self.text[self.at + word.len()..].starts_with(' ')
1113 {
1114 self.at += word.len();
1115 return true;
1116 }
1117 self.at = start;
1118 false
1119 }
1120
1121 fn eat_space_then(&mut self, token: &str) -> bool {
1123 let start = self.at;
1124 self.skip_space();
1125 if self.eat(token) {
1126 true
1127 } else {
1128 self.at = start;
1129 false
1130 }
1131 }
1132
1133 fn expect(&mut self, token: &str) -> Result<()> {
1134 if self.eat_space_then(token) {
1135 Ok(())
1136 } else {
1137 Err(self.error(&format!("expected \"{token}\"")))
1138 }
1139 }
1140
1141 fn expect_word(&mut self, word: &str) -> Result<()> {
1142 if self.eat_word(word) { Ok(()) } else { Err(self.error(&format!("expected \"{word}\""))) }
1143 }
1144
1145 fn done(&mut self) -> bool {
1146 self.skip_space();
1147 self.at >= self.text.len()
1148 }
1149
1150 fn error(&self, what: &str) -> Error {
1151 Error::parser(format!("{what} at column {}, reading \"{}\"", self.at + 1, self.text.trim()))
1152 }
1153}
1154
1155#[cfg(test)]
1156mod tests {
1157 use super::*;
1158 use crate::print::{RESERVED, is_plain_identifier};
1159
1160 #[test]
1161 fn a_type_annotation_ends_where_the_type_does() {
1162 for (text, expected) in [
1163 ("INTEGER DESC", "INTEGER"),
1164 ("INTEGER, x", "INTEGER"),
1165 ("INTEGER)", "INTEGER"),
1166 ("DECIMAL(18,3) AS a", "DECIMAL(18,3)"),
1167 ("INTEGER[] AS a", "INTEGER[]"),
1168 ("INTEGER[3][] ", "INTEGER[3][]"),
1169 ("MAP(VARCHAR, INTEGER)[]", "MAP(VARCHAR, INTEGER)[]"),
1170 ("STRUCT(a INTEGER, b VARCHAR) AS s", "STRUCT(a INTEGER, b VARCHAR)"),
1171 ("TIMESTAMP WITH TIME ZONE, x", "TIMESTAMP WITH TIME ZONE"),
1172 ("TIME WITH TIME ZONE]", "TIME WITH TIME ZONE"),
1173 ("TIME WITH TIME ZONE[], x", "TIME WITH TIME ZONE[]"),
1174 ("TIMESTAMP WITH TIME ZONE[4] AS t", "TIMESTAMP WITH TIME ZONE[4]"),
1175 ("TIMESTAMP DESC", "TIMESTAMP"),
1176 ("\"NULL\" AS n", "\"NULL\""),
1177 ] {
1178 let end = type_extent(text, 0);
1179 assert_eq!(&text[..end], expected, "wrong extent in {text}");
1180 LogicalType::parse(expected)
1181 .unwrap_or_else(|e| panic!("{expected} does not parse: {e}"));
1182 }
1183 }
1184
1185 #[test]
1188 fn a_quoted_field_name_does_not_end_the_type_early() {
1189 let text = "STRUCT(\"a)b\" INTEGER) AS s";
1190 let end = type_extent(text, 0);
1191 assert_eq!(&text[..end], "STRUCT(\"a)b\" INTEGER)");
1192 }
1193
1194 #[test]
1195 fn a_constant_ends_at_the_colon_pair_that_types_it() {
1196 for (text, expected) in [
1197 ("5::INTEGER", "5"),
1198 ("-5::INTEGER", "-5"),
1199 ("''::VARCHAR", "''"),
1200 ("'a::b'::VARCHAR", "'a::b'"),
1201 ("'it''s'::VARCHAR", "'it''s'"),
1202 ("{1, 2}::INTEGER[]", "{1, 2}"),
1203 ("{{1}, {2}}::INTEGER[][]", "{{1}, {2}}"),
1204 ("X'00ff'::BLOB", "X'00ff'"),
1205 ("NULL::VARCHAR", "NULL"),
1206 ] {
1207 let end = literal_extent(text, 0);
1208 assert_eq!(&text[..end], expected, "wrong extent in {text}");
1209 }
1210 }
1211
1212 #[test]
1213 fn a_decimal_reads_back_at_its_own_scale() {
1214 assert_eq!(
1215 read_decimal("12.34", 6, 2).unwrap(),
1216 Value::Decimal { unscaled: 1234, width: 6, scale: 2 }
1217 );
1218 assert_eq!(
1219 read_decimal("-0.005", 6, 3).unwrap(),
1220 Value::Decimal { unscaled: -5, width: 6, scale: 3 }
1221 );
1222 assert_eq!(
1223 read_decimal("1234", 6, 0).unwrap(),
1224 Value::Decimal { unscaled: 1234, width: 6, scale: 0 }
1225 );
1226 }
1227
1228 #[test]
1232 fn a_decimal_with_the_wrong_number_of_digits_is_rejected() {
1233 assert!(read_decimal("1.5", 6, 2).is_err());
1234 assert!(read_decimal("1.500", 6, 2).is_err());
1235 assert!(read_decimal("15", 6, 2).is_err());
1236 assert!(read_decimal("1.5", 6, 0).is_err());
1237 }
1238
1239 #[test]
1240 fn a_string_gives_its_quotes_and_escapes_back() {
1241 assert_eq!(read_string("''").unwrap(), "");
1242 assert_eq!(read_string("'it''s'").unwrap(), "it's");
1243 assert_eq!(read_string("'a\\\\b'").unwrap(), "a\\b");
1244 assert_eq!(read_string("'one\\x0atwo'").unwrap(), "one\ntwo");
1245 assert!(read_string("'").is_err());
1246 assert!(read_string("no quotes").is_err());
1247 }
1248
1249 #[test]
1250 fn a_blob_is_pairs_of_hex_digits() {
1251 assert_eq!(read_blob("X''").unwrap(), Vec::<u8>::new());
1252 assert_eq!(read_blob("X'00ff10'").unwrap(), vec![0x00, 0xff, 0x10]);
1253 assert!(read_blob("X'0'").is_err(), "an odd number of digits is not a byte string");
1254 assert!(read_blob("X'zz'").is_err());
1255 }
1256
1257 #[test]
1258 fn a_braced_list_splits_at_the_top_level_only() {
1259 assert_eq!(read_braced("{}").unwrap(), Vec::<&str>::new());
1260 assert_eq!(read_braced("{1}").unwrap(), vec!["1"]);
1261 assert_eq!(read_braced("{1, 2}").unwrap(), vec!["1", "2"]);
1262 assert_eq!(read_braced("{{1, 2}, {3}}").unwrap(), vec!["{1, 2}", "{3}"]);
1263 assert_eq!(read_braced("{'a,b', 'c'}").unwrap(), vec!["'a,b'", "'c'"]);
1264 assert!(read_braced("1, 2").is_err());
1265 }
1266
1267 #[test]
1268 fn a_keyword_needs_a_word_boundary() {
1269 let mut c = Cursor::new(" ALLOWED");
1270 assert!(!c.eat_word("ALL"), "ALL should not match the front of ALLOWED");
1271 assert!(c.eat_word("ALLOWED"));
1272 let mut c = Cursor::new(" all ");
1273 assert!(c.eat_word("ALL"), "keywords are case insensitive");
1274 }
1275
1276 #[test]
1277 fn an_odd_indent_is_an_error_and_says_so() {
1278 let message = Plan::parse("Filter x\n Dummy\n").unwrap_err().to_string();
1279 assert!(message.contains("whole number of levels"), "unhelpful message: {message}");
1280 }
1281
1282 #[test]
1283 fn a_tab_is_an_error_rather_than_a_guess() {
1284 let message = Plan::parse("Filter x\n\tDummy\n").unwrap_err().to_string();
1285 assert!(message.contains("tab"), "unhelpful message: {message}");
1286 }
1287
1288 #[test]
1289 fn an_unknown_operator_names_itself() {
1290 let message = Plan::parse("Frobnicate\n").unwrap_err().to_string();
1291 assert!(message.contains("Frobnicate"), "unhelpful message: {message}");
1292 }
1293
1294 #[test]
1295 fn a_missing_child_is_an_error_rather_than_a_plan_with_a_hole() {
1296 let message = Plan::parse("Filter TRUE::BOOLEAN\n").unwrap_err().to_string();
1297 assert!(message.contains("expected an operator"), "unhelpful message: {message}");
1298 }
1299
1300 #[test]
1301 fn a_second_root_is_an_error() {
1302 let message = Plan::parse("Dummy\nDummy\n").unwrap_err().to_string();
1303 assert!(message.contains("past the end"), "unhelpful message: {message}");
1304 }
1305
1306 #[test]
1307 fn text_left_over_on_a_line_is_an_error() {
1308 let message = Plan::parse("Dummy nonsense\n").unwrap_err().to_string();
1309 assert!(message.contains("left over"), "unhelpful message: {message}");
1310 }
1311
1312 #[test]
1313 fn an_empty_plan_is_not_a_plan() {
1314 assert!(Plan::parse("").is_err());
1315 assert!(Plan::parse("\n\n \n").is_err());
1316 }
1317
1318 #[test]
1321 fn the_reader_runs_the_plan_invariant() {
1322 let message = Plan::parse("Filter 1::INTEGER\n Dummy\n").unwrap_err().to_string();
1323 assert!(message.contains("BOOLEAN"), "unhelpful message: {message}");
1324 }
1325
1326 #[test]
1330 fn a_quoted_reserved_word_is_a_function_and_not_syntax() {
1331 for reserved in RESERVED {
1332 let text = format!("Project #1 [\"{reserved}\"(1::INTEGER)::INTEGER AS a]\n Dummy\n");
1333 let plan = Plan::parse(&text).unwrap_or_else(|e| panic!("{text} does not read: {e}"));
1334 assert!(matches!(plan.expr(0), Expr::Constant(_)));
1335 assert!(matches!(plan.expr(1), Expr::Function { .. }), "{reserved} became syntax");
1336 assert_eq!(plan.to_string(), text);
1337 }
1338 }
1339
1340 #[test]
1341 fn an_unquoted_cast_is_syntax_and_not_a_function() {
1342 let text = "Project #1 [CAST(1::INTEGER)::BIGINT AS a]\n Dummy\n";
1343 let plan = Plan::parse(text).expect("a cast reads back");
1344 assert!(matches!(plan.expr(1), Expr::Cast { try_cast: false, .. }));
1345 assert_eq!(plan.to_string(), text);
1346 }
1347
1348 #[test]
1351 fn a_function_called_filter_in_argument_position_is_a_call() {
1352 let text = "Aggregate #1 groups=[] aggregates=[sum(filter(1::INTEGER)::INTEGER)::HUGEINT]\n Dummy\n";
1353 let plan = Plan::parse(text).expect("an argument called filter reads back");
1354 assert_eq!(plan.to_string(), text);
1355 }
1356
1357 #[test]
1358 fn an_aggregate_with_no_arguments_can_still_have_a_filter() {
1359 let text = "Aggregate #1 groups=[] aggregates=[count_star(FILTER TRUE::BOOLEAN)::BIGINT]\n Dummy\n";
1360 let plan = Plan::parse(text).expect("count(*) FILTER (WHERE p) is a real query");
1361 assert_eq!(plan.to_string(), text);
1362 }
1363
1364 #[test]
1365 fn a_name_that_is_not_a_plain_identifier_is_quoted_by_the_printer_and_read_here() {
1366 let mut c = Cursor::new("\"say \"\"hi\"\"\" rest");
1367 assert_eq!(read_identifier(&mut c).unwrap(), "say \"hi\"");
1368 assert_eq!(c.rest(), " rest");
1369 assert!(!is_plain_identifier("say \"hi\""));
1370 }
1371}