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 "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
299struct 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
315fn 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
346fn 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
369fn 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
388fn 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
427fn 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 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
479fn 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
515enum 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
605fn 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
650fn 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
701fn 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 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
851fn 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
882pub(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
923fn 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
947fn 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 text.len()
979}
980
981fn 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
998fn 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
1020struct 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 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 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 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 #[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 #[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 #[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 #[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 #[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}