1use std::{cell::Cell, rc::Rc};
4
5use crate::{
6 ast::{BinaryOp, Expr, UnaryOp},
7 error::ParseError,
8 lexer::lex,
9 token::{Keyword, Token},
10};
11
12pub(crate) const MAX_DEPTH: usize = 50;
35
36type QueryTailAndLocking = (
37 Vec<crate::ast::OrderItem>,
38 Option<i64>,
39 Option<i64>,
40 Option<crate::ast::RowLockStrength>,
41);
42
43type SetTail = (Vec<crate::ast::OrderItem>, Option<i64>, Option<i64>);
44
45pub(crate) struct Parser {
46 toks: Vec<(Token, usize)>,
47 source: String,
48 pos: usize,
49 depth: Rc<Cell<usize>>,
57}
58
59#[derive(Debug, Clone, PartialEq)]
60struct ParsedStatement {
61 statement: crate::ast::Statement,
62 command_identity: crate::command::CommandIdentity,
63}
64
65fn emitted(
66 command_identity: crate::command::CommandIdentity,
67 statement: Result<crate::ast::Statement, ParseError>,
68) -> Result<ParsedStatement, ParseError> {
69 statement.map(|statement| ParsedStatement {
70 statement,
71 command_identity,
72 })
73}
74
75struct DepthGuard {
80 depth: Rc<Cell<usize>>,
81}
82
83impl DepthGuard {
84 fn enter(depth: &Rc<Cell<usize>>, position: usize) -> Result<Self, ParseError> {
88 let next = depth.get() + 1;
89 if next > MAX_DEPTH {
90 return Err(ParseError::too_deep(position));
91 }
92 depth.set(next);
93 Ok(Self {
94 depth: Rc::clone(depth),
95 })
96 }
97}
98
99impl Drop for DepthGuard {
100 fn drop(&mut self) {
101 self.depth.set(self.depth.get() - 1);
102 }
103}
104
105impl Parser {
106 pub(crate) fn new(toks: Vec<(Token, usize)>, source: String) -> Self {
107 Self {
108 toks,
109 source,
110 pos: 0,
111 depth: Rc::new(Cell::new(0)),
112 }
113 }
114
115 fn peek(&self) -> &Token {
116 &self.toks[self.pos].0
117 }
118
119 fn peek2(&self) -> &Token {
123 let i = (self.pos + 1).min(self.toks.len() - 1);
124 &self.toks[i].0
125 }
126
127 fn peek_n(&self, n: usize) -> &Token {
129 let i = (self.pos + n).min(self.toks.len() - 1);
130 &self.toks[i].0
131 }
132
133 fn peek3(&self) -> &Token {
138 let i = (self.pos + 2).min(self.toks.len() - 1);
139 &self.toks[i].0
140 }
141
142 fn peek_pos(&self) -> usize {
143 self.toks[self.pos].1
144 }
145
146 fn bump(&mut self) -> Token {
147 let t = self.toks[self.pos].0.clone();
148 if self.pos + 1 < self.toks.len() {
149 self.pos += 1;
150 }
151 t
152 }
153
154 fn eat_keyword(&mut self, kw: Keyword) -> bool {
155 if *self.peek() == Token::Keyword(kw) {
156 self.bump();
157 true
158 } else {
159 false
160 }
161 }
162
163 fn expect(&mut self, want: &Token) -> Result<(), ParseError> {
164 if self.peek() == want {
165 self.bump();
166 Ok(())
167 } else {
168 Err(ParseError::new(
169 format!("expected {want:?}, found {:?}", self.peek()),
170 self.peek_pos(),
171 ))
172 }
173 }
174
175 fn expect_ident(&mut self) -> Result<String, ParseError> {
176 match self.bump() {
177 Token::Ident(s) => Ok(s),
178 other => Err(ParseError::new(
179 format!("expected identifier, found {other:?}"),
180 self.peek_pos(),
181 )),
182 }
183 }
184
185 fn expect_ident_eq(&mut self, want: &str) -> Result<(), ParseError> {
189 let pos = self.peek_pos();
190 match self.bump() {
191 Token::Ident(s) if s.eq_ignore_ascii_case(want) => Ok(()),
192 other => Err(ParseError::new(
193 format!("expected `{want}`, found {other:?}"),
194 pos,
195 )),
196 }
197 }
198
199 fn eat_ident_eq(&mut self, want: &str) -> bool {
200 if matches!(self.peek(), Token::Ident(s) if s.eq_ignore_ascii_case(want)) {
201 self.bump();
202 true
203 } else {
204 false
205 }
206 }
207
208 fn parse_type_name(&mut self) -> Result<crabka_pgtypes::ColumnType, ParseError> {
214 let type_pos = self.peek_pos();
215 let mut type_word = self.expect_ident()?;
216 if type_word.eq_ignore_ascii_case("double")
217 && matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("precision"))
218 {
219 self.bump();
220 type_word = "double precision".to_string();
221 }
222 if type_word.eq_ignore_ascii_case("character")
223 && matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("varying"))
224 {
225 self.bump();
226 type_word = "character varying".to_string();
227 }
228 if (type_word.eq_ignore_ascii_case("timestamp") || type_word.eq_ignore_ascii_case("time"))
234 && (matches!(self.peek(), Token::Keyword(Keyword::With))
235 || matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("without")))
236 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("time"))
237 {
238 let with_zone = matches!(self.bump(), Token::Keyword(Keyword::With));
240 self.expect_ident_eq("time")?;
241 self.expect_ident_eq("zone")?;
242 let qualifier = if with_zone { "with" } else { "without" };
243 type_word = format!("{} {qualifier} time zone", type_word.to_ascii_lowercase());
244 }
245 let ty = crabka_pgtypes::ColumnType::from_sql_name(&type_word)
246 .ok_or_else(|| ParseError::new(format!("unknown type \"{type_word}\""), type_pos))?;
247 if ty.is_numeric() && *self.peek() == Token::LParen {
249 return self.parse_numeric_typmod();
250 }
251 if matches!(
252 ty,
253 crabka_pgtypes::ColumnType::Varchar(_) | crabka_pgtypes::ColumnType::Char(_)
254 ) && *self.peek() == Token::LParen
255 {
256 return self.parse_string_typmod(ty);
257 }
258 Ok(ty)
259 }
260
261 fn parse_string_typmod(
262 &mut self,
263 ty: crabka_pgtypes::ColumnType,
264 ) -> Result<crabka_pgtypes::ColumnType, ParseError> {
265 self.expect(&Token::LParen)?;
266 let limit = self.expect_u16("string length")?;
267 self.expect(&Token::RParen)?;
268 match ty {
269 crabka_pgtypes::ColumnType::Varchar(_) => {
270 Ok(crabka_pgtypes::ColumnType::Varchar(Some(limit)))
271 }
272 crabka_pgtypes::ColumnType::Char(_) => {
273 Ok(crabka_pgtypes::ColumnType::Char(Some(limit)))
274 }
275 _ => unreachable!("parse_string_typmod called for non-string typmod type"),
276 }
277 }
278
279 fn parse_numeric_typmod(&mut self) -> Result<crabka_pgtypes::ColumnType, ParseError> {
282 self.expect(&Token::LParen)?;
283 let precision = self.expect_u16("numeric precision")?;
284 let scale = if self.eat_comma() {
285 self.expect_u16("numeric scale")?
286 } else {
287 0
288 };
289 self.expect(&Token::RParen)?;
290 Ok(crabka_pgtypes::ColumnType::Numeric(Some(
291 crabka_pgtypes::numeric::Typmod { precision, scale },
292 )))
293 }
294
295 fn expect_u16(&mut self, what: &str) -> Result<u16, ParseError> {
297 let pos = self.peek_pos();
298 match self.bump() {
299 Token::IntLit(s) => s
300 .parse::<u16>()
301 .map_err(|_| ParseError::new(format!("invalid {what}"), pos)),
302 other => Err(ParseError::new(
303 format!("expected {what}, found {other:?}"),
304 pos,
305 )),
306 }
307 }
308
309 pub(crate) fn expr(&mut self, min_bp: u8) -> Result<Expr, ParseError> {
311 let _guard = DepthGuard::enter(&self.depth, self.peek_pos())?;
316 let mut lhs = self.prefix()?;
317 let mut iterations: usize = 0;
322 loop {
323 iterations += 1;
324 if iterations > MAX_DEPTH {
325 return Err(ParseError::too_deep(self.peek_pos()));
326 }
327 if *self.peek() == Token::TypeCast {
334 self.bump();
335 let ty = self.parse_type_name()?;
336 lhs = Expr::Cast {
337 expr: Box::new(lhs),
338 ty,
339 };
340 continue;
341 }
342 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("at"))
353 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("time"))
354 && matches!(self.peek3(), Token::Ident(w) if w.eq_ignore_ascii_case("zone"))
355 {
356 self.bump(); self.bump(); self.bump(); let zone = self.expr(11)?;
360 lhs = Expr::Func(crate::ast::FuncCall {
361 name: "timezone".into(),
362 distinct: false,
363 args: crate::ast::FuncArgs::Exprs(vec![zone, lhs]),
364 });
365 continue;
366 }
367 if 5 >= min_bp {
372 match self.peek() {
373 Token::Keyword(Keyword::Is) => {
374 lhs = self.parse_is_null(lhs)?;
375 continue;
376 }
377 Token::Keyword(Keyword::In) => {
378 lhs = self.parse_in(lhs, false)?;
379 continue;
380 }
381 Token::Keyword(Keyword::Between) => {
382 lhs = self.parse_between(lhs, false)?;
383 continue;
384 }
385 Token::Keyword(Keyword::Like) => {
386 lhs = self.parse_like(lhs, false, false)?;
387 continue;
388 }
389 Token::Keyword(Keyword::Ilike) => {
390 lhs = self.parse_like(lhs, false, true)?;
391 continue;
392 }
393 Token::Keyword(Keyword::Not)
397 if matches!(
398 self.peek2(),
399 Token::Keyword(
400 Keyword::In | Keyword::Between | Keyword::Like | Keyword::Ilike
401 )
402 ) =>
403 {
404 self.bump(); lhs = match self.peek() {
406 Token::Keyword(Keyword::In) => self.parse_in(lhs, true)?,
407 Token::Keyword(Keyword::Between) => self.parse_between(lhs, true)?,
408 Token::Keyword(Keyword::Like) => self.parse_like(lhs, true, false)?,
409 Token::Keyword(Keyword::Ilike) => self.parse_like(lhs, true, true)?,
410 _ => unreachable!("lookahead guaranteed a negated predicate"),
411 };
412 continue;
413 }
414 _ => {}
415 }
416 }
417 let (op, l_bp, r_bp) = match self.peek() {
423 Token::Keyword(Keyword::Or) => (BinaryOp::Or, 1, 2),
424 Token::Keyword(Keyword::And) => (BinaryOp::And, 3, 4),
425 Token::Eq => (BinaryOp::Eq, 5, 6),
426 Token::Ne => (BinaryOp::Ne, 5, 6),
427 Token::Lt => (BinaryOp::Lt, 5, 6),
428 Token::Le => (BinaryOp::Le, 5, 6),
429 Token::Gt => (BinaryOp::Gt, 5, 6),
430 Token::Ge => (BinaryOp::Ge, 5, 6),
431 Token::Concat => (BinaryOp::Concat, 7, 8),
432 Token::Plus => (BinaryOp::Add, 9, 10),
433 Token::Minus => (BinaryOp::Sub, 9, 10),
434 Token::Star => (BinaryOp::Mul, 11, 12),
435 Token::Slash => (BinaryOp::Div, 11, 12),
436 _ => break,
437 };
438 if l_bp < min_bp {
439 break;
440 }
441 self.bump();
442 if matches!(
445 op,
446 BinaryOp::Eq
447 | BinaryOp::Ne
448 | BinaryOp::Lt
449 | BinaryOp::Le
450 | BinaryOp::Gt
451 | BinaryOp::Ge
452 ) && matches!(
453 self.peek(),
454 Token::Keyword(Keyword::Any | Keyword::Some | Keyword::All)
455 ) {
456 let all = matches!(self.peek(), Token::Keyword(Keyword::All));
457 self.bump(); self.expect(&Token::LParen)?;
459 let subquery = Box::new(self.query_expr_after_open_paren()?);
460 lhs = Expr::Quantified {
461 expr: Box::new(lhs),
462 op,
463 all,
464 subquery,
465 };
466 continue;
467 }
468 let rhs = self.expr(r_bp)?;
469 lhs = Expr::Binary {
470 op,
471 left: Box::new(lhs),
472 right: Box::new(rhs),
473 };
474 }
475 Ok(lhs)
476 }
477
478 fn prefix(&mut self) -> Result<Expr, ParseError> {
479 match self.peek().clone() {
480 Token::Keyword(Keyword::Not) => {
481 self.bump();
482 Ok(Expr::Unary {
483 op: UnaryOp::Not,
484 expr: Box::new(self.expr(4)?),
485 })
486 }
487 Token::Minus => {
488 self.bump();
489 Ok(Expr::Unary {
492 op: UnaryOp::Neg,
493 expr: Box::new(self.expr(13)?),
494 })
495 }
496 Token::LParen => {
497 if matches!(
500 self.peek2(),
501 Token::Keyword(Keyword::Select | Keyword::Values | Keyword::With)
502 ) {
503 self.bump();
504 let sub = self.query_expr_after_open_paren()?;
505 Ok(Expr::ScalarSubquery(Box::new(sub)))
506 } else {
507 self.bump();
508 let e = self.expr(0)?;
509 self.expect(&Token::RParen)?;
510 Ok(e)
511 }
512 }
513 Token::Keyword(Keyword::Exists) => {
514 self.bump(); self.expect(&Token::LParen)?;
516 let sub = self.query_expr_after_open_paren()?;
517 Ok(Expr::Exists(Box::new(sub)))
518 }
519 Token::IntLit(s) => {
520 self.bump();
521 Ok(Expr::IntLiteral(s))
522 }
523 Token::FloatLit(s) => {
524 self.bump();
525 Ok(Expr::NumericLiteral(s))
526 }
527 Token::StringLit(s) => {
528 self.bump();
529 Ok(Expr::StringLiteral(s))
530 }
531 Token::Keyword(Keyword::True) => {
532 self.bump();
533 Ok(Expr::BoolLiteral(true))
534 }
535 Token::Keyword(Keyword::False) => {
536 self.bump();
537 Ok(Expr::BoolLiteral(false))
538 }
539 Token::Keyword(Keyword::Null) => {
540 self.bump();
541 Ok(Expr::NullLiteral)
542 }
543 Token::Keyword(Keyword::Case) => self.case_expr(),
544 Token::Keyword(Keyword::Cast) => self.cast_expr(),
545 Token::Keyword(Keyword::CurrentUser) => {
546 self.bump();
547 Ok(Expr::Func(crate::ast::FuncCall {
548 name: "current_user".into(),
549 distinct: false,
550 args: crate::ast::FuncArgs::Exprs(vec![]),
551 }))
552 }
553 Token::Keyword(Keyword::Left) => self.keyword_func_call("left"),
557 Token::Keyword(Keyword::Right) => self.keyword_func_call("right"),
558 Token::Param(n) => {
559 self.bump();
560 Ok(Expr::Param(n))
561 }
562 Token::Ident(s) => {
563 let lower = s.to_ascii_lowercase();
572 if matches!(
573 lower.as_str(),
574 "date" | "time" | "timestamp" | "timestamptz" | "interval"
575 ) && matches!(self.peek2(), Token::StringLit(_))
576 {
577 self.bump(); let ty = crabka_pgtypes::ColumnType::from_sql_name(&lower)
579 .expect("single-word datetime type name resolves");
580 let Token::StringLit(string) = self.bump() else {
581 unreachable!("peek2 guaranteed a string literal");
582 };
583 return Ok(Expr::Cast {
584 expr: Box::new(Expr::StringLiteral(string)),
585 ty,
586 });
587 }
588 self.bump();
589 if matches!(
597 lower.as_str(),
598 "current_date"
599 | "current_time"
600 | "session_user"
601 | "localtimestamp"
602 | "localtime"
603 | "current_timestamp"
604 ) && *self.peek() != Token::LParen
605 {
606 return Ok(Expr::Func(crate::ast::FuncCall {
607 name: lower,
608 distinct: false,
609 args: crate::ast::FuncArgs::Exprs(vec![]),
610 }));
611 }
612 if lower == "extract" && *self.peek() == Token::LParen {
617 return self.extract_expr();
618 }
619 if *self.peek() == Token::LParen {
623 self.func_call(s)
624 } else if *self.peek() == Token::Dot {
625 self.bump();
626 let name = self.expect_ident()?;
627 if *self.peek() == Token::LParen {
628 self.func_call(name)
629 } else {
630 Ok(Expr::Column {
631 table: Some(s),
632 name,
633 })
634 }
635 } else {
636 Ok(Expr::Column {
637 table: None,
638 name: s,
639 })
640 }
641 }
642 other => Err(ParseError::new(
643 format!("unexpected token {other:?}"),
644 self.peek_pos(),
645 )),
646 }
647 }
648
649 fn func_call(&mut self, name: String) -> Result<Expr, ParseError> {
653 use crate::ast::{FuncArgs, FuncCall};
654 self.expect(&Token::LParen)?;
655 if *self.peek() == Token::Star {
657 self.bump();
658 self.expect(&Token::RParen)?;
659 return Ok(Expr::Func(FuncCall {
660 name,
661 distinct: false,
662 args: FuncArgs::Star,
663 }));
664 }
665 let distinct = if self.eat_keyword(Keyword::Distinct) {
666 true
667 } else {
668 self.eat_keyword(Keyword::All);
670 false
671 };
672 let mut args = Vec::new();
673 if *self.peek() != Token::RParen {
674 loop {
675 args.push(self.expr(0)?);
676 if self.eat_comma() {
677 continue;
678 }
679 break;
680 }
681 }
682 self.expect(&Token::RParen)?;
683 Ok(Expr::Func(FuncCall {
684 name,
685 distinct,
686 args: FuncArgs::Exprs(args),
687 }))
688 }
689
690 fn keyword_func_call(&mut self, name: &str) -> Result<Expr, ParseError> {
694 self.bump();
695 if *self.peek() == Token::LParen {
696 self.func_call(name.to_string())
697 } else {
698 Err(ParseError::new(
699 format!("`{name}` is reserved here; use it as a function call `{name}(...)`"),
700 self.peek_pos(),
701 ))
702 }
703 }
704
705 fn extract_expr(&mut self) -> Result<Expr, ParseError> {
710 use crate::ast::{FuncArgs, FuncCall};
711 self.expect(&Token::LParen)?;
712 let field = self.expect_ident()?.to_ascii_lowercase();
713 self.expect(&Token::Keyword(Keyword::From))?;
714 let source = self.expr(0)?;
715 self.expect(&Token::RParen)?;
716 Ok(Expr::Func(FuncCall {
717 name: "extract".into(),
718 distinct: false,
719 args: FuncArgs::Exprs(vec![Expr::StringLiteral(field), source]),
720 }))
721 }
722
723 fn parse_is_null(&mut self, lhs: Expr) -> Result<Expr, ParseError> {
726 self.expect(&Token::Keyword(Keyword::Is))?;
727 let negated = self.eat_keyword(Keyword::Not);
728 self.expect(&Token::Keyword(Keyword::Null))?;
729 Ok(Expr::IsNull {
730 expr: Box::new(lhs),
731 negated,
732 })
733 }
734
735 fn parse_in(&mut self, lhs: Expr, negated: bool) -> Result<Expr, ParseError> {
739 self.expect(&Token::Keyword(Keyword::In))?;
740 self.expect(&Token::LParen)?;
741 if matches!(
743 self.peek(),
744 Token::Keyword(Keyword::Select | Keyword::Values | Keyword::With)
745 ) {
746 let subquery = self.query_expr_after_open_paren()?;
747 return Ok(Expr::InSubquery {
748 expr: Box::new(lhs),
749 subquery: Box::new(subquery),
750 negated,
751 });
752 }
753 let mut list = Vec::new();
754 loop {
755 list.push(self.expr(0)?);
756 if self.eat_comma() {
757 continue;
758 }
759 break;
760 }
761 self.expect(&Token::RParen)?;
762 Ok(Expr::InList {
763 expr: Box::new(lhs),
764 list,
765 negated,
766 })
767 }
768
769 fn parse_between(&mut self, lhs: Expr, negated: bool) -> Result<Expr, ParseError> {
773 self.expect(&Token::Keyword(Keyword::Between))?;
774 let low = self.expr(4)?;
775 self.expect(&Token::Keyword(Keyword::And))?;
776 let high = self.expr(4)?;
777 Ok(Expr::Between {
778 expr: Box::new(lhs),
779 low: Box::new(low),
780 high: Box::new(high),
781 negated,
782 })
783 }
784
785 fn parse_like(
790 &mut self,
791 lhs: Expr,
792 negated: bool,
793 case_insensitive: bool,
794 ) -> Result<Expr, ParseError> {
795 self.bump(); let pattern = self.expr(6)?;
797 Ok(Expr::Like {
798 expr: Box::new(lhs),
799 pattern: Box::new(pattern),
800 negated,
801 case_insensitive,
802 })
803 }
804
805 fn case_expr(&mut self) -> Result<Expr, ParseError> {
809 self.expect(&Token::Keyword(Keyword::Case))?;
810 let operand = if *self.peek() == Token::Keyword(Keyword::When) {
811 None
812 } else {
813 Some(Box::new(self.expr(0)?))
814 };
815 let mut whens = Vec::new();
816 while self.eat_keyword(Keyword::When) {
817 let cond = self.expr(0)?;
818 self.expect(&Token::Keyword(Keyword::Then))?;
819 let result = self.expr(0)?;
820 whens.push((cond, result));
821 }
822 if whens.is_empty() {
823 return Err(ParseError::new(
824 "CASE requires at least one WHEN clause",
825 self.peek_pos(),
826 ));
827 }
828 let else_result = if self.eat_keyword(Keyword::Else) {
829 Some(Box::new(self.expr(0)?))
830 } else {
831 None
832 };
833 self.expect(&Token::Keyword(Keyword::End))?;
834 Ok(Expr::Case {
835 operand,
836 whens,
837 else_result,
838 })
839 }
840
841 fn cast_expr(&mut self) -> Result<Expr, ParseError> {
845 self.expect(&Token::Keyword(Keyword::Cast))?;
846 self.expect(&Token::LParen)?;
847 let expr = self.expr(0)?;
848 self.expect(&Token::Keyword(Keyword::As))?;
849 let ty = self.parse_type_name()?;
850 self.expect(&Token::RParen)?;
851 Ok(Expr::Cast {
852 expr: Box::new(expr),
853 ty,
854 })
855 }
856
857 fn program_spanned(
861 &mut self,
862 ) -> Result<Vec<(ParsedStatement, std::ops::Range<usize>)>, ParseError> {
863 let mut stmts = Vec::new();
864 loop {
865 while *self.peek() == Token::Semicolon {
866 self.bump();
867 }
868 if *self.peek() == Token::Eof {
869 break;
870 }
871 let start = self.peek_pos();
872 let s = self.statement()?;
873 let end = self.peek_pos();
874 stmts.push((s, start..end));
875 match self.peek() {
876 Token::Semicolon => {
877 self.bump();
878 }
879 Token::Eof => break,
880 other => {
881 return Err(ParseError::new(
882 format!("expected ; or end of input, found {other:?}"),
883 self.peek_pos(),
884 ));
885 }
886 }
887 }
888 Ok(stmts)
889 }
890
891 fn statement(&mut self) -> Result<ParsedStatement, ParseError> {
892 use crate::command::CommandIdentity as I;
893
894 if self.starts_query_expr() {
895 let identity = self.query_command_identity();
896 return emitted(identity, self.query_statement());
897 }
898 match self.peek() {
899 Token::Keyword(Keyword::Create) => {
900 match self.peek2() {
902 Token::Keyword(
903 Keyword::Index | Keyword::Unique | Keyword::Global | Keyword::Local,
904 ) => emitted(I::CreateIndex, self.create_index()),
905 Token::Keyword(Keyword::View) => emitted(I::CreateView, self.create_view()),
906 Token::Keyword(Keyword::Foreign) => {
907 match self.peek3() {
909 Token::Keyword(Keyword::Table) => {
910 emitted(I::CreateForeignTable, self.create_foreign_table())
911 }
912 Token::Keyword(Keyword::Data) => {
913 emitted(I::CreateForeignDataWrapper, self.create_fdw())
914 }
915 _ => Err(ParseError::new(
916 format!(
917 "unexpected token after CREATE FOREIGN: {:?}",
918 self.peek3()
919 ),
920 self.peek_pos(),
921 )),
922 }
923 }
924 Token::Keyword(Keyword::Server) => {
925 emitted(I::CreateServer, self.create_server())
926 }
927 Token::Keyword(Keyword::User) => {
928 if matches!(self.peek3(), Token::Keyword(Keyword::Mapping)) {
929 emitted(I::CreateUserMapping, self.create_user_mapping())
930 } else {
931 emitted(I::CreateUser, self.create_role(true))
932 }
933 }
934 Token::Ident(s) if s == "role" => {
935 emitted(I::CreateRole, self.create_role(false))
936 }
937 Token::Ident(s) if s == "sequence" => {
938 emitted(I::CreateSequence, self.create_sequence())
939 }
940 Token::Ident(s) if s == "database" => {
941 emitted(I::CreateDatabase, self.create_database_refusal())
942 }
943 _ => emitted(I::CreateTable, self.create_table()),
944 }
945 }
946 Token::Keyword(Keyword::Drop) => {
947 match self.peek2() {
950 Token::Keyword(Keyword::Foreign) => {
951 match self.peek3() {
954 Token::Keyword(Keyword::Table) => {
955 emitted(I::DropForeignTable, self.drop_foreign_table())
956 }
957 Token::Keyword(Keyword::Data) => {
958 emitted(I::DropForeignDataWrapper, self.drop_fdw())
959 }
960 _ => Err(ParseError::new(
961 format!("unexpected token after DROP FOREIGN: {:?}", self.peek3()),
962 self.peek_pos(),
963 )),
964 }
965 }
966 Token::Keyword(Keyword::Server) => emitted(I::DropServer, self.drop_server()),
967 Token::Keyword(Keyword::View) => emitted(I::DropView, self.drop_view()),
968 Token::Keyword(Keyword::Index) => emitted(I::DropIndex, self.drop_index()),
969 Token::Keyword(Keyword::User) => {
970 if matches!(self.peek3(), Token::Keyword(Keyword::Mapping)) {
971 emitted(I::DropUserMapping, self.drop_user_mapping())
972 } else {
973 emitted(I::DropUser, self.drop_role())
974 }
975 }
976 Token::Ident(s) if s == "role" => emitted(I::DropRole, self.drop_role()),
977 Token::Ident(s) if s == "sequence" => {
978 emitted(I::DropSequence, self.drop_sequence())
979 }
980 Token::Ident(s) if s == "database" => {
981 emitted(I::DropDatabase, self.drop_database_refusal())
982 }
983 Token::Ident(s) if s == "extension" => {
984 emitted(I::DropExtension, self.drop_extension_refusal())
985 }
986 _ => emitted(I::DropTable, self.drop_table()),
987 }
988 }
989 Token::Ident(s) if s == "grant" => emitted(I::Grant, self.grant_table_privileges()),
990 Token::Ident(s) if s == "revoke" => emitted(I::Revoke, self.revoke_table_privileges()),
991 Token::Keyword(Keyword::Import) => {
992 emitted(I::ImportForeignSchema, self.import_foreign_schema())
993 }
994 Token::Keyword(Keyword::Insert) => emitted(I::Insert, self.insert()),
995 Token::Keyword(Keyword::Copy) => emitted(I::Copy, self.copy_stmt()),
996 Token::Keyword(Keyword::Begin) => emitted(I::Begin, self.begin()),
998 Token::Keyword(Keyword::Start) => emitted(I::StartTransaction, self.begin()),
999 Token::Keyword(Keyword::Commit) if matches!(self.peek2(), Token::Ident(s) if s == "prepared") => {
1000 emitted(
1001 I::CommitPrepared,
1002 self.prepared_transaction_refusal(crate::ast::RefusalCommand::CommitPrepared),
1003 )
1004 }
1005 Token::Keyword(Keyword::Rollback) if matches!(self.peek2(), Token::Ident(s) if s == "prepared") => {
1006 emitted(
1007 I::RollbackPrepared,
1008 self.prepared_transaction_refusal(crate::ast::RefusalCommand::RollbackPrepared),
1009 )
1010 }
1011 Token::Keyword(keyword @ (Keyword::Commit | Keyword::End)) => {
1012 let identity = if *keyword == Keyword::Commit {
1013 I::Commit
1014 } else {
1015 I::End
1016 };
1017 self.bump();
1018 emitted(identity, Ok(crate::ast::Statement::Commit))
1019 }
1020 Token::Keyword(keyword @ (Keyword::Rollback | Keyword::Abort)) => {
1021 let identity = if *keyword == Keyword::Rollback {
1022 I::Rollback
1023 } else {
1024 I::Abort
1025 };
1026 self.bump();
1027 emitted(identity, Ok(crate::ast::Statement::Rollback))
1028 }
1029 Token::Keyword(Keyword::Update) => emitted(I::Update, self.update()),
1031 Token::Keyword(Keyword::Delete) => emitted(I::Delete, self.delete()),
1032 Token::Keyword(Keyword::Set) => {
1035 if matches!(self.peek2(), Token::Ident(s) if s == "role") {
1036 emitted(I::SetRole, self.set_role_stmt())
1037 } else if matches!(self.peek2(), Token::Keyword(Keyword::Transaction)) {
1038 emitted(I::SetTransaction, self.set_stmt())
1039 } else {
1040 emitted(I::Set, self.set_stmt())
1041 }
1042 }
1043 Token::Ident(s) if s == "show" => emitted(I::Show, self.show_stmt()),
1044 Token::Ident(s) if s == "reset" => emitted(I::Reset, self.reset_stmt()),
1045 Token::Ident(s) if s == "discard" => emitted(I::Discard, self.discard_stmt()),
1046 Token::Ident(s)
1047 if s == "prepare"
1048 && matches!(self.peek2(), Token::Keyword(Keyword::Transaction)) =>
1049 {
1050 emitted(
1051 I::PrepareTransaction,
1052 self.prepared_transaction_refusal(
1053 crate::ast::RefusalCommand::PrepareTransaction,
1054 ),
1055 )
1056 }
1057 Token::Ident(s) if s == "alter" => match self.peek2() {
1059 Token::Keyword(Keyword::Table) => emitted(I::AlterTable, self.alter_table()),
1060 Token::Keyword(Keyword::Server) => emitted(I::AlterServer, self.alter_server()),
1061 Token::Keyword(Keyword::User) => {
1062 emitted(I::AlterUserMapping, self.alter_user_mapping())
1063 }
1064 Token::Ident(s) if s == "database" => {
1065 emitted(I::AlterDatabase, self.alter_database_refusal())
1066 }
1067 Token::Ident(s) if s == "extension" => {
1068 emitted(I::AlterExtension, self.alter_extension_refusal())
1069 }
1070 _ => Err(ParseError::new(
1071 format!("unexpected token after ALTER: {:?}", self.peek2()),
1072 self.peek_pos(),
1073 )),
1074 },
1075 other => Err(ParseError::new(
1076 format!("unexpected statement start {other:?}"),
1077 self.peek_pos(),
1078 )),
1079 }
1080 }
1081
1082 fn query_command_identity(&self) -> crate::command::CommandIdentity {
1083 use crate::command::CommandIdentity;
1084
1085 let mut offset = 0;
1086 while matches!(self.peek_n(offset), Token::LParen) {
1087 offset += 1;
1088 }
1089 if matches!(self.peek_n(offset), Token::Keyword(Keyword::Values)) {
1090 CommandIdentity::Values
1091 } else {
1092 CommandIdentity::Select
1093 }
1094 }
1095
1096 fn create_database_refusal(&mut self) -> Result<crate::ast::Statement, ParseError> {
1097 self.expect(&Token::Keyword(Keyword::Create))?;
1098 self.expect_ident_eq("database")?;
1099 self.expect_ident()?;
1100 Ok(crate::ast::Statement::CompatibilityRefusal(
1101 crate::ast::RefusalCommand::CreateDatabase,
1102 ))
1103 }
1104
1105 fn drop_database_refusal(&mut self) -> Result<crate::ast::Statement, ParseError> {
1106 self.expect(&Token::Keyword(Keyword::Drop))?;
1107 self.expect_ident_eq("database")?;
1108 self.expect_ident()?;
1109 Ok(crate::ast::Statement::CompatibilityRefusal(
1110 crate::ast::RefusalCommand::DropDatabase,
1111 ))
1112 }
1113
1114 fn drop_extension_refusal(&mut self) -> Result<crate::ast::Statement, ParseError> {
1115 self.expect(&Token::Keyword(Keyword::Drop))?;
1116 self.expect_ident_eq("extension")?;
1117 self.expect_ident()?;
1118 Ok(crate::ast::Statement::CompatibilityRefusal(
1119 crate::ast::RefusalCommand::DropExtension,
1120 ))
1121 }
1122
1123 fn alter_database_refusal(&mut self) -> Result<crate::ast::Statement, ParseError> {
1124 self.expect_ident_eq("alter")?;
1125 self.expect_ident_eq("database")?;
1126 self.expect_ident()?;
1127 self.expect_ident_eq("rename")?;
1128 self.expect_keyword_or_ident(Keyword::To, "to")?;
1129 self.expect_ident()?;
1130 Ok(crate::ast::Statement::CompatibilityRefusal(
1131 crate::ast::RefusalCommand::AlterDatabase,
1132 ))
1133 }
1134
1135 fn alter_extension_refusal(&mut self) -> Result<crate::ast::Statement, ParseError> {
1136 self.expect_ident_eq("alter")?;
1137 self.expect_ident_eq("extension")?;
1138 self.expect_ident()?;
1139 self.expect_keyword_or_ident(Keyword::Update, "update")?;
1140 Ok(crate::ast::Statement::CompatibilityRefusal(
1141 crate::ast::RefusalCommand::AlterExtension,
1142 ))
1143 }
1144
1145 fn prepared_transaction_refusal(
1146 &mut self,
1147 command: crate::ast::RefusalCommand,
1148 ) -> Result<crate::ast::Statement, ParseError> {
1149 match command {
1150 crate::ast::RefusalCommand::PrepareTransaction => {
1151 self.expect_ident_eq("prepare")?;
1152 self.expect(&Token::Keyword(Keyword::Transaction))?;
1153 }
1154 crate::ast::RefusalCommand::CommitPrepared => {
1155 self.expect(&Token::Keyword(Keyword::Commit))?;
1156 self.expect_ident_eq("prepared")?;
1157 }
1158 crate::ast::RefusalCommand::RollbackPrepared => {
1159 self.expect(&Token::Keyword(Keyword::Rollback))?;
1160 self.expect_ident_eq("prepared")?;
1161 }
1162 _ => unreachable!("only SQL-level prepared transaction commands use this parser"),
1163 }
1164 match self.bump() {
1165 Token::StringLit(_) => {}
1166 other => {
1167 return Err(ParseError::new(
1168 format!("expected transaction identifier string, found {other:?}"),
1169 self.peek_pos(),
1170 ));
1171 }
1172 }
1173 Ok(crate::ast::Statement::CompatibilityRefusal(command))
1174 }
1175
1176 fn alter_table(&mut self) -> Result<crate::ast::Statement, ParseError> {
1177 use crate::ast::{AlterTableRename, Statement};
1178
1179 self.expect_ident_eq("alter")?;
1180 self.expect(&Token::Keyword(Keyword::Table))?;
1181 let table = self.expect_ident()?;
1182 self.expect_ident_eq("rename")?;
1183 let rename = if self.eat_ident_eq("column") {
1184 let column = self.expect_ident()?;
1185 self.expect_keyword_or_ident(Keyword::To, "to")?;
1186 AlterTableRename::Column {
1187 column,
1188 new_name: self.expect_ident()?,
1189 }
1190 } else if self.eat_keyword(Keyword::To) || self.eat_ident_eq("to") {
1191 AlterTableRename::Table {
1192 new_name: self.expect_ident()?,
1193 }
1194 } else {
1195 let column = self.expect_ident()?;
1196 self.expect_keyword_or_ident(Keyword::To, "to")?;
1197 AlterTableRename::Column {
1198 column,
1199 new_name: self.expect_ident()?,
1200 }
1201 };
1202 Ok(Statement::AlterTableRename { table, rename })
1203 }
1204
1205 fn create_role(&mut self, can_login: bool) -> Result<crate::ast::Statement, ParseError> {
1206 self.expect(&Token::Keyword(Keyword::Create))?;
1207 if can_login {
1208 self.expect(&Token::Keyword(Keyword::User))?;
1209 } else {
1210 self.expect_ident_eq("role")?;
1211 }
1212 Ok(crate::ast::Statement::CreateRole {
1213 name: self.expect_object_name()?,
1214 can_login,
1215 })
1216 }
1217
1218 fn drop_role(&mut self) -> Result<crate::ast::Statement, ParseError> {
1219 self.expect(&Token::Keyword(Keyword::Drop))?;
1220 if self.eat_keyword(Keyword::User) {
1221 } else {
1223 self.expect_ident_eq("role")?;
1224 }
1225 Ok(crate::ast::Statement::DropRole {
1226 name: self.expect_object_name()?,
1227 })
1228 }
1229
1230 fn grant_table_privileges(&mut self) -> Result<crate::ast::Statement, ParseError> {
1231 self.expect_ident_eq("grant")?;
1232 let privileges = self.privilege_list_until_on()?;
1233 self.expect(&Token::Keyword(Keyword::On))?;
1234 self.expect(&Token::Keyword(Keyword::Table))?;
1235 let table = self.expect_object_name()?;
1236 self.expect(&Token::Keyword(Keyword::To))?;
1237 let grantees = self.object_name_list()?;
1238 Ok(crate::ast::Statement::GrantTablePrivileges {
1239 privileges,
1240 table,
1241 grantees,
1242 })
1243 }
1244
1245 fn revoke_table_privileges(&mut self) -> Result<crate::ast::Statement, ParseError> {
1246 self.expect_ident_eq("revoke")?;
1247 let privileges = self.privilege_list_until_on()?;
1248 self.expect(&Token::Keyword(Keyword::On))?;
1249 self.expect(&Token::Keyword(Keyword::Table))?;
1250 let table = self.expect_object_name()?;
1251 self.expect(&Token::Keyword(Keyword::From))?;
1252 let grantees = self.object_name_list()?;
1253 Ok(crate::ast::Statement::RevokeTablePrivileges {
1254 privileges,
1255 table,
1256 grantees,
1257 })
1258 }
1259
1260 fn set_role_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
1261 self.expect(&Token::Keyword(Keyword::Set))?;
1262 self.expect_ident_eq("role")?;
1263 let role = if matches!(self.peek(), Token::Ident(s) if s.eq_ignore_ascii_case("none")) {
1264 self.bump();
1265 None
1266 } else {
1267 Some(self.expect_object_name()?)
1268 };
1269 Ok(crate::ast::Statement::SetRole { role })
1270 }
1271
1272 fn privilege_list_until_on(&mut self) -> Result<Vec<String>, ParseError> {
1273 let mut privileges = Vec::new();
1274 loop {
1275 if matches!(self.peek(), Token::Keyword(Keyword::On)) {
1276 break;
1277 }
1278 privileges.push(self.expect_privilege_name()?);
1279 if !self.eat_comma() {
1280 if matches!(self.peek(), Token::Keyword(Keyword::On)) {
1281 break;
1282 }
1283 return Err(ParseError::new(
1284 "expected `,` or `ON` in privilege list",
1285 self.peek_pos(),
1286 ));
1287 }
1288 }
1289 if privileges.is_empty() {
1290 return Err(ParseError::new(
1291 "expected at least one privilege",
1292 self.peek_pos(),
1293 ));
1294 }
1295 Ok(privileges)
1296 }
1297
1298 fn object_name_list(&mut self) -> Result<Vec<String>, ParseError> {
1299 let mut names = vec![self.expect_object_name()?];
1300 while self.eat_comma() {
1301 names.push(self.expect_object_name()?);
1302 }
1303 Ok(names)
1304 }
1305
1306 fn expect_object_name(&mut self) -> Result<String, ParseError> {
1307 match self.bump() {
1308 Token::Ident(s) => Ok(s),
1309 Token::Keyword(Keyword::Public) => Ok("public".into()),
1310 Token::Keyword(Keyword::CurrentUser) => Ok("current_user".into()),
1311 Token::Keyword(Keyword::User) => Ok("user".into()),
1312 other => Err(ParseError::new(
1313 format!("expected object name, found {other:?}"),
1314 self.peek_pos(),
1315 )),
1316 }
1317 }
1318
1319 fn expect_privilege_name(&mut self) -> Result<String, ParseError> {
1320 match self.bump() {
1321 Token::Ident(s) => Ok(s.to_ascii_uppercase()),
1322 Token::Keyword(Keyword::Select) => Ok("SELECT".into()),
1323 Token::Keyword(Keyword::Insert) => Ok("INSERT".into()),
1324 Token::Keyword(Keyword::Update) => Ok("UPDATE".into()),
1325 Token::Keyword(Keyword::Delete) => Ok("DELETE".into()),
1326 Token::Keyword(Keyword::All) => Ok("ALL".into()),
1327 other => Err(ParseError::new(
1328 format!("expected privilege name, found {other:?}"),
1329 self.peek_pos(),
1330 )),
1331 }
1332 }
1333
1334 fn set_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
1340 use crate::ast::Statement;
1341 self.expect(&Token::Keyword(Keyword::Set))?;
1342 if self.eat_keyword(Keyword::Transaction)
1343 || (matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("session"))
1344 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("characteristics")))
1345 {
1346 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("session")) {
1347 self.bump(); self.bump(); if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("as")) {
1350 self.bump();
1351 }
1352 self.expect(&Token::Keyword(Keyword::Transaction))?;
1353 }
1354 return self.set_transaction_tail();
1355 }
1356 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("session")) {
1358 self.bump();
1359 }
1360 let local = (matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("local"))
1365 || *self.peek() == Token::Keyword(Keyword::Local))
1366 && !matches!(self.peek2(), Token::Eq);
1367 if local {
1368 self.bump(); }
1370 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("time"))
1372 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("zone"))
1373 {
1374 self.bump(); self.bump(); let value = self.set_time_zone_value()?;
1377 return Ok(Statement::Set {
1378 local,
1379 name: "timezone".into(),
1380 value,
1381 });
1382 }
1383 let name = self.expect_ident()?.to_ascii_lowercase();
1385 let sep = *self.peek() == Token::Eq
1387 || *self.peek() == Token::Keyword(Keyword::To)
1388 || matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("to"));
1389 if !sep {
1390 return Err(ParseError::new(
1391 "expected `=` or `TO` in SET",
1392 self.peek_pos(),
1393 ));
1394 }
1395 self.bump(); let value = self.set_value()?;
1397 Ok(Statement::Set { local, name, value })
1398 }
1399
1400 fn set_value(&mut self) -> Result<crate::ast::SetValue, ParseError> {
1403 use crate::ast::SetValue;
1404 let mut rendered = String::new();
1405 let mut separator = "";
1406 loop {
1407 let part = match self.peek().clone() {
1408 Token::Plus | Token::Minus => {
1409 let sign = if self.bump() == Token::Minus {
1410 "-"
1411 } else {
1412 "+"
1413 };
1414 let Token::IntLit(number) = self.bump() else {
1415 return Err(ParseError::new(
1416 "expected a number after SET value sign",
1417 self.peek_pos(),
1418 ));
1419 };
1420 format!("{sign}{number}")
1421 }
1422 Token::StringLit(s) | Token::IntLit(s) | Token::FloatLit(s) => {
1423 self.bump();
1424 s
1425 }
1426 Token::Ident(w) if w.eq_ignore_ascii_case("default") => {
1427 self.bump();
1428 if rendered.is_empty() && *self.peek() != Token::Comma {
1429 return Ok(SetValue::Default);
1430 }
1431 "default".into()
1432 }
1433 Token::Ident(w) => {
1434 self.bump();
1435 w
1436 }
1437 Token::Keyword(Keyword::True | Keyword::On) => {
1438 self.bump();
1439 "on".into()
1440 }
1441 Token::Keyword(Keyword::False) => {
1442 self.bump();
1443 "off".into()
1444 }
1445 Token::Keyword(Keyword::Local) => {
1446 self.bump();
1447 "local".into()
1448 }
1449 Token::Keyword(Keyword::Public) => {
1450 self.bump();
1451 "public".into()
1452 }
1453 other => Err(ParseError::new(
1454 format!("expected a SET value, found {other:?}"),
1455 self.peek_pos(),
1456 ))?,
1457 };
1458 rendered.push_str(separator);
1459 rendered.push_str(&part);
1460 if self.eat_comma() {
1461 separator = ", ";
1462 continue;
1463 }
1464 if matches!(
1465 self.peek(),
1466 Token::Ident(_)
1467 | Token::StringLit(_)
1468 | Token::IntLit(_)
1469 | Token::FloatLit(_)
1470 | Token::Plus
1471 | Token::Minus
1472 | Token::Keyword(
1473 Keyword::True
1474 | Keyword::On
1475 | Keyword::False
1476 | Keyword::Local
1477 | Keyword::Public
1478 )
1479 ) {
1480 separator = " ";
1481 } else {
1482 break;
1483 }
1484 }
1485 Ok(SetValue::Value(rendered))
1486 }
1487
1488 fn set_transaction_tail(&mut self) -> Result<crate::ast::Statement, ParseError> {
1489 use crate::ast::{IsolationLevel, SetValue, Statement};
1490 let isolation = if self.eat_keyword(Keyword::Isolation) {
1491 self.expect(&Token::Keyword(Keyword::Level))?;
1492 if self.eat_keyword(Keyword::Repeatable) {
1493 self.expect(&Token::Keyword(Keyword::Read))?;
1494 Some(IsolationLevel::RepeatableRead)
1495 } else if self.eat_keyword(Keyword::Read) {
1496 self.expect(&Token::Keyword(Keyword::Committed))?;
1497 Some(IsolationLevel::ReadCommitted)
1498 } else {
1499 return Err(ParseError::new(
1500 "expected REPEATABLE READ or READ COMMITTED",
1501 self.peek_pos(),
1502 ));
1503 }
1504 } else {
1505 None
1506 };
1507 let value = match isolation {
1508 Some(IsolationLevel::RepeatableRead) => SetValue::Value("repeatable read".into()),
1509 Some(IsolationLevel::ReadCommitted) => SetValue::Value("read committed".into()),
1510 None => SetValue::Default,
1511 };
1512 Ok(Statement::Set {
1513 local: false,
1514 name: "__set_transaction".into(),
1515 value,
1516 })
1517 }
1518
1519 fn set_time_zone_value(&mut self) -> Result<crate::ast::SetValue, ParseError> {
1522 use crate::ast::SetValue;
1523 match self.peek().clone() {
1524 Token::StringLit(s) => {
1525 self.bump();
1526 Ok(SetValue::Value(s))
1527 }
1528 Token::Ident(w)
1529 if w.eq_ignore_ascii_case("default") || w.eq_ignore_ascii_case("local") =>
1530 {
1531 self.bump();
1532 Ok(SetValue::Default)
1533 }
1534 Token::Keyword(Keyword::Local) => {
1535 self.bump();
1536 Ok(SetValue::Default)
1537 }
1538 Token::Ident(w) => {
1539 self.bump();
1540 Ok(SetValue::Value(w))
1541 }
1542 other => Err(ParseError::new(
1543 format!("expected a TIME ZONE value, found {other:?}"),
1544 self.peek_pos(),
1545 )),
1546 }
1547 }
1548
1549 fn show_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
1551 use crate::ast::Statement;
1552 self.bump(); if self.eat_keyword(Keyword::All) {
1554 return Ok(Statement::Show { name: "all".into() });
1555 }
1556 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("time"))
1558 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("zone"))
1559 {
1560 self.bump(); self.bump(); return Ok(Statement::Show {
1563 name: "timezone".into(),
1564 });
1565 }
1566 let name = self.expect_ident()?.to_ascii_lowercase();
1567 Ok(Statement::Show { name })
1568 }
1569
1570 fn reset_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
1572 use crate::ast::Statement;
1573 self.bump(); if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("role")) {
1575 self.bump();
1576 return Ok(Statement::SetRole { role: None });
1577 }
1578 if self.eat_keyword(Keyword::All) {
1579 return Ok(Statement::Reset {
1580 target: crate::ast::ResetTarget::All,
1581 });
1582 }
1583 if matches!(self.peek(), Token::Ident(w) if w.eq_ignore_ascii_case("time"))
1585 && matches!(self.peek2(), Token::Ident(w) if w.eq_ignore_ascii_case("zone"))
1586 {
1587 self.bump(); self.bump(); return Ok(Statement::Reset {
1590 target: crate::ast::ResetTarget::Name("timezone".into()),
1591 });
1592 }
1593 let name = self.expect_ident()?.to_ascii_lowercase();
1594 Ok(Statement::Reset {
1595 target: crate::ast::ResetTarget::Name(name),
1596 })
1597 }
1598
1599 fn discard_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
1600 self.bump(); self.expect(&Token::Keyword(Keyword::All))?;
1602 Ok(crate::ast::Statement::Set {
1603 local: false,
1604 name: "__discard_all".into(),
1605 value: crate::ast::SetValue::Default,
1606 })
1607 }
1608
1609 fn begin(&mut self) -> Result<crate::ast::Statement, ParseError> {
1610 use crate::ast::{IsolationLevel, Statement};
1611 let leading = self.bump(); if leading == Token::Keyword(Keyword::Start) {
1613 self.expect(&Token::Keyword(Keyword::Transaction))?;
1615 } else {
1616 self.eat_keyword(Keyword::Transaction);
1618 }
1619 let isolation = if self.eat_keyword(Keyword::Isolation) {
1620 self.expect(&Token::Keyword(Keyword::Level))?;
1621 if self.eat_keyword(Keyword::Repeatable) {
1622 self.expect(&Token::Keyword(Keyword::Read))?;
1623 Some(IsolationLevel::RepeatableRead)
1624 } else if self.eat_keyword(Keyword::Read) {
1625 self.expect(&Token::Keyword(Keyword::Committed))?;
1626 Some(IsolationLevel::ReadCommitted)
1627 } else {
1628 return Err(ParseError::new(
1629 "expected REPEATABLE READ or READ COMMITTED",
1630 self.peek_pos(),
1631 ));
1632 }
1633 } else {
1634 None
1635 };
1636 Ok(Statement::Begin { isolation })
1637 }
1638
1639 fn update(&mut self) -> Result<crate::ast::Statement, ParseError> {
1640 use crate::ast::Statement;
1641 self.expect(&Token::Keyword(Keyword::Update))?;
1642 let table = self.expect_ident()?;
1643 self.expect(&Token::Keyword(Keyword::Set))?;
1644 let mut assignments = Vec::new();
1645 loop {
1646 let col = self.expect_ident()?;
1647 self.expect(&Token::Eq)?;
1648 let value = self.expr(0)?;
1649 assignments.push((col, value));
1650 if self.eat_comma() {
1651 continue;
1652 }
1653 break;
1654 }
1655 let filter = if self.eat_keyword(Keyword::Where) {
1656 Some(self.expr(0)?)
1657 } else {
1658 None
1659 };
1660 let returning = self.returning_clause()?;
1661 Ok(Statement::Update {
1662 table,
1663 assignments,
1664 filter,
1665 returning,
1666 })
1667 }
1668
1669 fn delete(&mut self) -> Result<crate::ast::Statement, ParseError> {
1670 use crate::ast::Statement;
1671 self.expect(&Token::Keyword(Keyword::Delete))?;
1672 self.expect(&Token::Keyword(Keyword::From))?;
1673 let table = self.expect_ident()?;
1674 let filter = if self.eat_keyword(Keyword::Where) {
1675 Some(self.expr(0)?)
1676 } else {
1677 None
1678 };
1679 let returning = self.returning_clause()?;
1680 Ok(Statement::Delete {
1681 table,
1682 filter,
1683 returning,
1684 })
1685 }
1686
1687 fn create_table(&mut self) -> Result<crate::ast::Statement, ParseError> {
1688 use crate::ast::{ColumnDef, HashShardingSpec, ShardingSpec, Statement};
1689 self.expect(&Token::Keyword(Keyword::Create))?;
1690 self.expect(&Token::Keyword(Keyword::Table))?;
1691 let name = self.expect_ident()?;
1692 self.expect(&Token::LParen)?;
1693 let mut columns = Vec::new();
1694 let mut constraints = Vec::new();
1695 loop {
1696 if self.eat_ident_eq("primary") {
1697 self.expect_ident_eq("key")?;
1698 constraints.push(crate::ast::TableConstraint::PrimaryKey(
1699 self.parse_ident_list()?,
1700 ));
1701 if self.eat_comma() {
1702 continue;
1703 }
1704 break;
1705 }
1706 if self.eat_keyword(Keyword::Unique) {
1707 constraints.push(crate::ast::TableConstraint::Unique(
1708 self.parse_ident_list()?,
1709 ));
1710 if self.eat_comma() {
1711 continue;
1712 }
1713 break;
1714 }
1715 if self.eat_ident_eq("check") {
1716 self.expect(&Token::LParen)?;
1717 let expr = self.expr(0)?;
1718 self.expect(&Token::RParen)?;
1719 constraints.push(crate::ast::TableConstraint::Check(expr));
1720 if self.eat_comma() {
1721 continue;
1722 }
1723 break;
1724 }
1725 let col_name = self.expect_ident()?;
1726 let (ty, serial) = self.parse_column_type()?;
1727 let constraints = self.column_constraints()?;
1728 columns.push(ColumnDef {
1729 name: col_name,
1730 ty,
1731 serial,
1732 constraints,
1733 });
1734 if self.eat_comma() {
1735 continue;
1736 }
1737 break;
1738 }
1739 self.expect(&Token::RParen)?;
1740 let saw_sharded = self.eat_ident_eq("sharded");
1741 let sharding = if saw_sharded && self.eat_keyword(Keyword::By) {
1742 self.expect_ident_eq("hash")?;
1743 self.expect(&Token::LParen)?;
1744 let hash_columns = vec![self.expect_ident()?];
1745 if self.eat_comma() {
1746 return Err(ParseError::new(
1747 "hash sharding requires exactly one column",
1748 self.peek_pos(),
1749 ));
1750 }
1751 self.expect(&Token::RParen)?;
1752 self.expect_ident_eq("buckets")?;
1753 let buckets = self.expect_hash_bucket_count()?;
1754 let co_location_group = if self.eat_ident_eq("colocated") {
1755 self.expect_keyword_or_ident(Keyword::With, "with")?;
1756 Some(self.expect_ident()?)
1757 } else {
1758 None
1759 };
1760 Some(ShardingSpec::Hash(HashShardingSpec {
1761 columns: hash_columns,
1762 buckets,
1763 co_location_group,
1764 }))
1765 } else {
1766 None
1767 };
1768 let sharded = saw_sharded;
1769 Ok(Statement::CreateTable {
1770 name,
1771 columns,
1772 constraints,
1773 sharded,
1774 sharding,
1775 })
1776 }
1777
1778 fn parse_column_type(
1779 &mut self,
1780 ) -> Result<(crabka_pgtypes::ColumnType, Option<crate::ast::SerialKind>), ParseError> {
1781 let type_pos = self.peek_pos();
1782 let type_name = self.expect_ident()?;
1783 match type_name.as_str() {
1784 "serial" => Ok((
1785 crabka_pgtypes::ColumnType::Int4,
1786 Some(crate::ast::SerialKind::Serial),
1787 )),
1788 "bigserial" => Ok((
1789 crabka_pgtypes::ColumnType::Int8,
1790 Some(crate::ast::SerialKind::BigSerial),
1791 )),
1792 _ => {
1793 self.pos -= 1;
1794 self.parse_type_name()
1795 .map(|ty| (ty, None))
1796 .map_err(|mut err| {
1797 err.position = type_pos;
1798 err
1799 })
1800 }
1801 }
1802 }
1803
1804 fn column_constraints(&mut self) -> Result<Vec<crate::ast::ColumnConstraint>, ParseError> {
1805 use crate::ast::ColumnConstraint;
1806 let mut constraints = Vec::new();
1807 loop {
1808 if self.eat_keyword(Keyword::Not) {
1809 self.expect(&Token::Keyword(Keyword::Null))?;
1810 constraints.push(ColumnConstraint::NotNull);
1811 continue;
1812 }
1813 if self.eat_ident_eq("default") {
1814 constraints.push(ColumnConstraint::Default(self.expr(0)?));
1815 continue;
1816 }
1817 if self.eat_ident_eq("primary") {
1818 self.expect_ident_eq("key")?;
1819 constraints.push(ColumnConstraint::PrimaryKey);
1820 continue;
1821 }
1822 if self.eat_keyword(Keyword::Unique) {
1823 constraints.push(ColumnConstraint::Unique);
1824 continue;
1825 }
1826 if self.eat_ident_eq("check") {
1827 self.expect(&Token::LParen)?;
1828 let expr = self.expr(0)?;
1829 self.expect(&Token::RParen)?;
1830 constraints.push(ColumnConstraint::Check(expr));
1831 continue;
1832 }
1833 break;
1834 }
1835 Ok(constraints)
1836 }
1837
1838 fn create_index(&mut self) -> Result<crate::ast::Statement, ParseError> {
1839 use crate::ast::{IndexPlacement, Statement};
1840
1841 self.expect(&Token::Keyword(Keyword::Create))?;
1842 let mut unique = false;
1843 let mut placement = IndexPlacement::Local;
1844 loop {
1845 if !unique && self.eat_keyword(Keyword::Unique) {
1846 unique = true;
1847 continue;
1848 }
1849 if self.eat_keyword(Keyword::Global) {
1850 placement = IndexPlacement::Global;
1851 continue;
1852 }
1853 if self.eat_keyword(Keyword::Local) {
1854 placement = IndexPlacement::Local;
1855 continue;
1856 }
1857 break;
1858 }
1859 self.expect(&Token::Keyword(Keyword::Index))?;
1860 let name = self.expect_ident()?;
1861 self.expect(&Token::Keyword(Keyword::On))?;
1862 let table = self.expect_ident()?;
1863 let columns = self.parse_ident_list()?;
1864 if columns.is_empty() {
1865 return Err(ParseError::new(
1866 "CREATE INDEX requires at least one column",
1867 self.peek_pos(),
1868 ));
1869 }
1870 Ok(Statement::CreateIndex {
1871 name,
1872 table,
1873 columns,
1874 unique,
1875 placement,
1876 })
1877 }
1878
1879 fn create_view(&mut self) -> Result<crate::ast::Statement, ParseError> {
1880 use crate::ast::Statement;
1881
1882 self.expect(&Token::Keyword(Keyword::Create))?;
1883 self.expect(&Token::Keyword(Keyword::View))?;
1884 let name = self.expect_object_name()?;
1885 self.expect(&Token::Keyword(Keyword::As))?;
1886 let definition_start = self.peek_pos();
1887 let query = self.query_expr()?;
1888 let definition_end = self.peek_pos();
1889 let definition = self.source[definition_start..definition_end]
1890 .trim()
1891 .to_string();
1892 Ok(Statement::CreateView {
1893 name,
1894 definition,
1895 query,
1896 })
1897 }
1898
1899 fn create_sequence(&mut self) -> Result<crate::ast::Statement, ParseError> {
1900 use crate::ast::{SequenceOptions, Statement};
1901 self.expect(&Token::Keyword(Keyword::Create))?;
1902 self.expect_ident_eq("sequence")?;
1903 let name = self.expect_ident()?;
1904 let mut options = SequenceOptions::default();
1905 while !matches!(self.peek(), Token::Semicolon | Token::Eof) {
1906 if self.eat_ident_eq("start") || self.eat_keyword(Keyword::Start) {
1907 self.eat_keyword(Keyword::With);
1908 options.start = Some(self.expect_i64("START value")?);
1909 } else if self.eat_ident_eq("increment") {
1910 self.expect_keyword_or_ident(Keyword::By, "by")?;
1911 options.increment = Some(self.expect_i64("INCREMENT value")?);
1912 } else if self.eat_ident_eq("minvalue") {
1913 options.min = Some(self.expect_i64("MINVALUE")?);
1914 } else if self.eat_ident_eq("maxvalue") {
1915 options.max = Some(self.expect_i64("MAXVALUE")?);
1916 } else if self.eat_ident_eq("no") {
1917 if self.eat_ident_eq("minvalue") {
1918 options.min = None;
1919 } else if self.eat_ident_eq("maxvalue") {
1920 options.max = None;
1921 } else if self.eat_ident_eq("cycle") {
1922 options.cycle = Some(false);
1923 } else {
1924 return Err(ParseError::new(
1925 "expected MINVALUE, MAXVALUE, or CYCLE after NO",
1926 self.peek_pos(),
1927 ));
1928 }
1929 } else if self.eat_ident_eq("cache") {
1930 options.cache = Some(self.expect_i64("CACHE")?);
1931 } else if self.eat_ident_eq("cycle") {
1932 options.cycle = Some(true);
1933 } else {
1934 return Err(ParseError::new(
1935 format!("unexpected CREATE SEQUENCE option {:?}", self.peek()),
1936 self.peek_pos(),
1937 ));
1938 }
1939 }
1940 Ok(Statement::CreateIndex {
1941 name,
1942 table: "__crabka_sequence__".into(),
1943 columns: encode_sequence_options(&options),
1944 unique: false,
1945 placement: crate::ast::IndexPlacement::Local,
1946 })
1947 }
1948
1949 fn drop_sequence(&mut self) -> Result<crate::ast::Statement, ParseError> {
1950 self.expect(&Token::Keyword(Keyword::Drop))?;
1951 self.expect_ident_eq("sequence")?;
1952 self.eat_if_exists()?;
1953 Ok(crate::ast::Statement::DropTable {
1954 name: format!("__crabka_sequence__:{}", self.expect_ident()?),
1955 })
1956 }
1957
1958 fn expect_i64(&mut self, what: &str) -> Result<i64, ParseError> {
1959 let pos = self.peek_pos();
1960 let negative = *self.peek() == Token::Minus;
1961 if negative {
1962 self.bump();
1963 }
1964 let Token::IntLit(raw) = self.bump() else {
1965 return Err(ParseError::new(format!("expected {what}"), pos));
1966 };
1967 let signed = if negative { format!("-{raw}") } else { raw };
1968 signed
1969 .parse::<i64>()
1970 .map_err(|_| ParseError::new(format!("{what} out of range"), pos))
1971 }
1972
1973 fn expect_keyword_or_ident(&mut self, keyword: Keyword, ident: &str) -> Result<(), ParseError> {
1974 if self.eat_keyword(keyword) || self.eat_ident_eq(ident) {
1975 return Ok(());
1976 }
1977
1978 Err(ParseError::new(
1979 format!("expected `{ident}`, found {:?}", self.peek()),
1980 self.peek_pos(),
1981 ))
1982 }
1983
1984 fn expect_hash_bucket_count(&mut self) -> Result<u32, ParseError> {
1985 let pos = self.peek_pos();
1986 let Token::IntLit(raw) = self.bump() else {
1987 return Err(ParseError::new("expected hash bucket count", pos));
1988 };
1989 let buckets = raw
1990 .parse::<u32>()
1991 .map_err(|_| ParseError::new("hash bucket count out of range", pos))?;
1992 if buckets == 0 || !buckets.is_power_of_two() {
1993 return Err(ParseError::new(
1994 "hash bucket count must be a power of two",
1995 pos,
1996 ));
1997 }
1998 Ok(buckets)
1999 }
2000
2001 fn drop_table(&mut self) -> Result<crate::ast::Statement, ParseError> {
2002 use crate::ast::Statement;
2003 self.expect(&Token::Keyword(Keyword::Drop))?;
2004 self.expect(&Token::Keyword(Keyword::Table))?;
2005 self.eat_if_exists()?;
2007 Ok(Statement::DropTable {
2008 name: self.expect_ident()?,
2009 })
2010 }
2011
2012 fn drop_index(&mut self) -> Result<crate::ast::Statement, ParseError> {
2013 use crate::ast::Statement;
2014
2015 self.expect(&Token::Keyword(Keyword::Drop))?;
2016 self.expect(&Token::Keyword(Keyword::Index))?;
2017 let if_exists = self.eat_if_exists()?;
2018 Ok(Statement::DropIndex {
2019 name: self.expect_ident()?,
2020 if_exists,
2021 })
2022 }
2023
2024 fn drop_view(&mut self) -> Result<crate::ast::Statement, ParseError> {
2025 use crate::ast::Statement;
2026
2027 self.expect(&Token::Keyword(Keyword::Drop))?;
2028 self.expect(&Token::Keyword(Keyword::View))?;
2029 let if_exists = self.eat_if_exists()?;
2030 Ok(Statement::DropView {
2031 name: self.expect_object_name()?,
2032 if_exists,
2033 })
2034 }
2035
2036 fn insert(&mut self) -> Result<crate::ast::Statement, ParseError> {
2037 use crate::ast::Statement;
2038 self.expect(&Token::Keyword(Keyword::Insert))?;
2039 self.expect(&Token::Keyword(Keyword::Into))?;
2040 let table = self.expect_ident()?;
2041 let columns = if *self.peek() == Token::LParen {
2042 self.bump();
2043 let mut cols = Vec::new();
2044 loop {
2045 cols.push(self.expect_ident()?);
2046 if self.eat_comma() {
2047 continue;
2048 }
2049 break;
2050 }
2051 self.expect(&Token::RParen)?;
2052 Some(cols)
2053 } else {
2054 None
2055 };
2056 self.expect(&Token::Keyword(Keyword::Values))?;
2057 let mut rows = Vec::new();
2058 loop {
2059 self.expect(&Token::LParen)?;
2060 let mut row = Vec::new();
2061 loop {
2062 row.push(self.insert_value_expr()?);
2063 if self.eat_comma() {
2064 continue;
2065 }
2066 break;
2067 }
2068 self.expect(&Token::RParen)?;
2069 rows.push(row);
2070 if self.eat_comma() {
2071 continue;
2072 }
2073 break;
2074 }
2075 Ok(Statement::Insert {
2076 table,
2077 columns,
2078 rows,
2079 returning: self.returning_clause()?,
2080 })
2081 }
2082
2083 fn returning_clause(&mut self) -> Result<Option<Vec<crate::ast::SelectItem>>, ParseError> {
2084 if !self.eat_keyword(Keyword::Returning) {
2085 return Ok(None);
2086 }
2087
2088 Ok(Some(self.projection_list()?))
2089 }
2090
2091 fn projection_list(&mut self) -> Result<Vec<crate::ast::SelectItem>, ParseError> {
2092 use crate::ast::SelectItem;
2093
2094 let mut projection = Vec::new();
2095 loop {
2096 if *self.peek() == Token::Star {
2097 self.bump();
2098 projection.push(SelectItem::Wildcard);
2099 } else if let Token::Ident(_) = self.peek()
2100 && *self.peek_n(1) == Token::Dot
2101 && *self.peek_n(2) == Token::Star
2102 {
2103 let qualifier = self.expect_ident()?;
2104 self.bump();
2105 self.bump();
2106 projection.push(SelectItem::QualifiedWildcard(qualifier));
2107 } else {
2108 let expr = self.expr(0)?;
2109 let alias = if self.eat_keyword(Keyword::As) {
2110 Some(self.expect_ident()?)
2111 } else if let Token::Ident(_) = self.peek() {
2112 Some(self.expect_ident()?)
2113 } else {
2114 None
2115 };
2116 projection.push(SelectItem::Expr { expr, alias });
2117 }
2118
2119 if self.eat_comma() {
2120 continue;
2121 }
2122 break;
2123 }
2124 Ok(projection)
2125 }
2126
2127 fn insert_value_expr(&mut self) -> Result<crate::ast::Expr, ParseError> {
2128 if self.eat_ident_eq("default") {
2129 return Ok(crate::ast::Expr::Default);
2130 }
2131 self.expr(0)
2132 }
2133
2134 fn copy_stmt(&mut self) -> Result<crate::ast::Statement, ParseError> {
2135 use crate::ast::{CopyFormat, CopyStmt, Statement};
2136
2137 self.expect(&Token::Keyword(Keyword::Copy))?;
2138 let table = self.expect_ident()?;
2139 let columns = if *self.peek() == Token::LParen {
2140 Some(self.parse_parenthesized_ident_list()?)
2141 } else {
2142 None
2143 };
2144
2145 if self.eat_keyword(Keyword::To) {
2146 return Err(ParseError::new_sqlstate(
2147 "0A000",
2148 "COPY TO is not supported",
2149 self.peek_pos(),
2150 ));
2151 }
2152 self.expect(&Token::Keyword(Keyword::From))?;
2153 if !self.eat_ident_eq("stdin") {
2154 return Err(ParseError::new_sqlstate(
2155 "0A000",
2156 "only COPY FROM STDIN is supported",
2157 self.peek_pos(),
2158 ));
2159 }
2160
2161 let mut format = CopyFormat::Text;
2162 if self.eat_keyword(Keyword::With) {
2163 self.expect(&Token::LParen)?;
2164 loop {
2165 let option = self.expect_ident()?.to_ascii_lowercase();
2166 match option.as_str() {
2167 "format" => {
2168 let value = self.expect_ident()?.to_ascii_lowercase();
2169 format = match value.as_str() {
2170 "text" => CopyFormat::Text,
2171 "csv" => CopyFormat::Csv,
2172 "binary" => {
2173 return Err(ParseError::new_sqlstate(
2174 "0A000",
2175 "COPY BINARY is not supported",
2176 self.peek_pos(),
2177 ));
2178 }
2179 _ => {
2180 return Err(ParseError::new(
2181 format!("unsupported COPY format `{value}`"),
2182 self.peek_pos(),
2183 ));
2184 }
2185 };
2186 }
2187 "binary" => {
2188 return Err(ParseError::new_sqlstate(
2189 "0A000",
2190 "COPY BINARY is not supported",
2191 self.peek_pos(),
2192 ));
2193 }
2194 _ => {
2195 return Err(ParseError::new_sqlstate(
2196 "0A000",
2197 format!("COPY option `{option}` is not supported"),
2198 self.peek_pos(),
2199 ));
2200 }
2201 }
2202 if self.eat_comma() {
2203 continue;
2204 }
2205 break;
2206 }
2207 self.expect(&Token::RParen)?;
2208 } else if self.eat_ident_eq("binary") {
2209 return Err(ParseError::new_sqlstate(
2210 "0A000",
2211 "COPY BINARY is not supported",
2212 self.peek_pos(),
2213 ));
2214 }
2215
2216 Ok(Statement::Set {
2217 local: false,
2218 name: crate::ast::COPY_FROM_STDIN_SENTINEL.into(),
2219 value: crate::ast::SetValue::Value(Self::encode_copy_stmt(&CopyStmt {
2220 table,
2221 columns,
2222 format,
2223 })),
2224 })
2225 }
2226
2227 fn parse_parenthesized_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
2228 self.expect(&Token::LParen)?;
2229 let mut cols = Vec::new();
2230 loop {
2231 cols.push(self.expect_ident()?);
2232 if self.eat_comma() {
2233 continue;
2234 }
2235 break;
2236 }
2237 self.expect(&Token::RParen)?;
2238 Ok(cols)
2239 }
2240
2241 fn encode_copy_stmt(copy: &crate::ast::CopyStmt) -> String {
2242 let format = match copy.format {
2243 crate::ast::CopyFormat::Text => "text",
2244 crate::ast::CopyFormat::Csv => "csv",
2245 };
2246 let columns = copy
2247 .columns
2248 .as_ref()
2249 .map(|columns| {
2250 columns
2251 .iter()
2252 .map(|column| Self::encode_copy_part(column))
2253 .collect::<Vec<_>>()
2254 .join(",")
2255 })
2256 .unwrap_or_default();
2257 [format, &Self::encode_copy_part(©.table), &columns].join("\t")
2258 }
2259
2260 fn encode_copy_part(value: &str) -> String {
2261 let mut out = String::with_capacity(value.len());
2262 for ch in value.chars() {
2263 match ch {
2264 '\\' => out.push_str(r"\\"),
2265 '\t' => out.push_str(r"\t"),
2266 ',' => out.push_str(r"\,"),
2267 other => out.push(other),
2268 }
2269 }
2270 out
2271 }
2272
2273 fn select_core(&mut self) -> Result<crate::ast::SelectStmt, ParseError> {
2276 use crate::ast::SelectStmt;
2277 let _guard = DepthGuard::enter(&self.depth, self.peek_pos())?;
2284 self.expect(&Token::Keyword(Keyword::Select))?;
2285 let distinct = self.eat_keyword(Keyword::Distinct);
2287 if !distinct {
2288 self.eat_keyword(Keyword::All);
2289 }
2290 let projection = self.projection_list()?;
2291 let from = if self.eat_keyword(Keyword::From) {
2292 self.parse_from()?
2293 } else {
2294 Vec::new()
2295 };
2296 let filter = if self.eat_keyword(Keyword::Where) {
2297 Some(self.expr(0)?)
2298 } else {
2299 None
2300 };
2301 let mut group_by = Vec::new();
2303 if self.eat_keyword(Keyword::Group) {
2304 self.expect(&Token::Keyword(Keyword::By))?;
2305 loop {
2306 group_by.push(self.expr(0)?);
2307 if self.eat_comma() {
2308 continue;
2309 }
2310 break;
2311 }
2312 }
2313 let having = if self.eat_keyword(Keyword::Having) {
2314 Some(self.expr(0)?)
2315 } else {
2316 None
2317 };
2318 Ok(SelectStmt {
2319 projection,
2320 from,
2321 filter,
2322 distinct,
2323 group_by,
2324 having,
2325 order_by: Vec::new(),
2326 limit: None,
2327 offset: None,
2328 locking: None,
2329 })
2330 }
2331
2332 fn values_stmt(&mut self) -> Result<crate::ast::ValuesStmt, ParseError> {
2333 self.expect(&Token::Keyword(Keyword::Values))?;
2334 let mut rows = Vec::new();
2335 loop {
2336 self.expect(&Token::LParen)?;
2337 if *self.peek() == Token::RParen {
2338 return Err(ParseError::new(
2339 "VALUES row must have at least one expression",
2340 self.peek_pos(),
2341 ));
2342 }
2343 let mut row = vec![self.expr(0)?];
2344 while self.eat_comma() {
2345 row.push(self.expr(0)?);
2346 }
2347 self.expect(&Token::RParen)?;
2348 rows.push(row);
2349 if !self.eat_comma() {
2350 break;
2351 }
2352 }
2353 Ok(crate::ast::ValuesStmt { rows })
2354 }
2355
2356 fn parse_set_tail(&mut self) -> Result<SetTail, ParseError> {
2360 use crate::ast::OrderItem;
2361 let mut order_by = Vec::new();
2362 if self.eat_keyword(Keyword::Order) {
2363 self.expect(&Token::Keyword(Keyword::By))?;
2364 loop {
2365 let expr = self.expr(0)?;
2366 let asc = if self.eat_keyword(Keyword::Desc) {
2367 false
2368 } else {
2369 self.eat_keyword(Keyword::Asc);
2370 true
2371 };
2372 order_by.push(OrderItem { expr, asc });
2373 if self.eat_comma() {
2374 continue;
2375 }
2376 break;
2377 }
2378 }
2379 let mut limit = None;
2381 let mut offset = None;
2382 loop {
2383 if limit.is_none() && self.eat_keyword(Keyword::Limit) {
2384 limit = Some(self.expect_int_count("LIMIT")?);
2385 } else if offset.is_none() && self.eat_keyword(Keyword::Offset) {
2386 offset = Some(self.expect_int_count("OFFSET")?);
2387 } else {
2388 break;
2389 }
2390 }
2391 Ok((order_by, limit, offset))
2392 }
2393
2394 fn parse_locking(&mut self) -> Result<Option<crate::ast::RowLockStrength>, ParseError> {
2396 if self.eat_keyword(Keyword::For) {
2397 if self.eat_keyword(Keyword::Update) {
2398 Ok(Some(crate::ast::RowLockStrength::ForUpdate))
2399 } else if self.eat_keyword(Keyword::Share) {
2400 Ok(Some(crate::ast::RowLockStrength::ForShare))
2401 } else {
2402 Err(ParseError::new(
2403 "expected UPDATE or SHARE after FOR",
2404 self.peek_pos(),
2405 ))
2406 }
2407 } else {
2408 Ok(None)
2409 }
2410 }
2411
2412 fn query_statement(&mut self) -> Result<crate::ast::Statement, ParseError> {
2413 Ok(crate::ast::Statement::Query(self.query_expr()?))
2414 }
2415
2416 fn query_expr(&mut self) -> Result<crate::ast::QueryExpr, ParseError> {
2417 let with = self.parse_with_clause()?;
2418 if *self.peek() == Token::LParen {
2419 let q = self.parenthesized_query_expr()?;
2420 if self.peek_is_set_op() {
2421 let left = self.query_expr_as_set_branch(q)?;
2422 let body = self.set_expr_rest(left, 0)?;
2423 let (order_by, limit, offset, locking) = self.parse_query_tail_and_locking()?;
2424 let mut q = self.finish_query_expr(body, order_by, limit, offset, locking)?;
2425 q.with = with;
2426 return Ok(q);
2427 }
2428 if !self.query_tail_or_locking_starts() {
2429 let mut q = q;
2430 q.with = with;
2431 return Ok(q);
2432 }
2433 let body = Self::query_expr_as_outer_primary(q);
2434 let (order_by, limit, offset, locking) = self.parse_query_tail_and_locking()?;
2435 let mut q = self.finish_query_expr(body, order_by, limit, offset, locking)?;
2436 q.with = with;
2437 return Ok(q);
2438 }
2439 let body = self.set_expr(0)?;
2440 let (order_by, limit, offset, locking) = self.parse_query_tail_and_locking()?;
2441 let mut q = self.finish_query_expr(body, order_by, limit, offset, locking)?;
2442 q.with = with;
2443 Ok(q)
2444 }
2445
2446 fn parse_query_tail_and_locking(&mut self) -> Result<QueryTailAndLocking, ParseError> {
2447 let (order_by, limit, offset) = self.parse_set_tail()?;
2448 let locking = self.parse_locking()?;
2449 Ok((order_by, limit, offset, locking))
2450 }
2451
2452 fn query_expr_as_set_branch(
2453 &mut self,
2454 q: crate::ast::QueryExpr,
2455 ) -> Result<crate::ast::SetExpr, ParseError> {
2456 use crate::ast::{QueryBody, SetExpr};
2457 let has_tail = q.with.is_some()
2458 || !q.order_by.is_empty()
2459 || q.limit.is_some()
2460 || q.offset.is_some()
2461 || q.locking.is_some();
2462 if !has_tail {
2463 return Ok(q.body);
2464 }
2465 if q.locking.is_some() {
2466 return Err(ParseError::new(
2467 "FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT",
2468 self.peek_pos(),
2469 ));
2470 }
2471 match q.body {
2472 SetExpr::Query(QueryBody::Select(mut select)) => {
2473 select.order_by = q.order_by;
2474 select.limit = q.limit;
2475 select.offset = q.offset;
2476 Ok(SetExpr::Query(QueryBody::Select(select)))
2477 }
2478 body => Ok(SetExpr::Query(QueryBody::Nested(Box::new(
2479 crate::ast::QueryExpr {
2480 with: q.with,
2481 body,
2482 order_by: q.order_by,
2483 limit: q.limit,
2484 offset: q.offset,
2485 locking: q.locking,
2486 },
2487 )))),
2488 }
2489 }
2490
2491 fn query_expr_as_outer_primary(q: crate::ast::QueryExpr) -> crate::ast::SetExpr {
2492 use crate::ast::{QueryBody, SetExpr};
2493 let has_tail = q.with.is_some()
2494 || !q.order_by.is_empty()
2495 || q.limit.is_some()
2496 || q.offset.is_some()
2497 || q.locking.is_some();
2498 if has_tail {
2499 SetExpr::Query(QueryBody::Nested(Box::new(q)))
2500 } else {
2501 q.body
2502 }
2503 }
2504
2505 fn finish_query_expr(
2506 &mut self,
2507 body: crate::ast::SetExpr,
2508 order_by: Vec<crate::ast::OrderItem>,
2509 limit: Option<i64>,
2510 offset: Option<i64>,
2511 locking: Option<crate::ast::RowLockStrength>,
2512 ) -> Result<crate::ast::QueryExpr, ParseError> {
2513 use crate::ast::{QueryBody, QueryExpr, SetExpr};
2514 if locking.is_some() {
2515 match &body {
2516 SetExpr::Query(QueryBody::Select(_)) => {}
2517 SetExpr::Query(QueryBody::Values(_)) => {
2518 return Err(ParseError::new(
2519 "FOR UPDATE/SHARE is not allowed with VALUES",
2520 self.peek_pos(),
2521 ));
2522 }
2523 SetExpr::Query(QueryBody::Nested(_)) => {
2524 return Err(ParseError::new(
2525 "FOR UPDATE/SHARE is not allowed with a nested query expression",
2526 self.peek_pos(),
2527 ));
2528 }
2529 SetExpr::SetOp { .. } => {
2530 return Err(ParseError::new(
2531 "FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT",
2532 self.peek_pos(),
2533 ));
2534 }
2535 }
2536 }
2537 Ok(QueryExpr {
2538 with: None,
2539 body,
2540 order_by,
2541 limit,
2542 offset,
2543 locking,
2544 })
2545 }
2546
2547 fn peek_is_set_op(&self) -> bool {
2548 matches!(
2549 self.peek(),
2550 Token::Keyword(Keyword::Union | Keyword::Except | Keyword::Intersect)
2551 )
2552 }
2553
2554 fn query_tail_or_locking_starts(&self) -> bool {
2555 matches!(
2556 self.peek(),
2557 Token::Keyword(Keyword::Order | Keyword::Limit | Keyword::Offset | Keyword::For)
2558 )
2559 }
2560
2561 fn parse_with_clause(&mut self) -> Result<Option<crate::ast::WithClause>, ParseError> {
2562 use crate::ast::{Cte, WithClause};
2563 if !self.eat_keyword(Keyword::With) {
2564 return Ok(None);
2565 }
2566 let recursive = self.eat_keyword(Keyword::Recursive);
2567 let mut ctes = Vec::new();
2568 loop {
2569 let name = self.expect_ident()?;
2570 if ctes.iter().any(|c: &Cte| c.name == name) {
2571 return Err(ParseError::new_sqlstate(
2572 "42712",
2573 format!("table name \"{name}\" specified more than once"),
2574 self.peek_pos(),
2575 ));
2576 }
2577 let columns = if *self.peek() == Token::LParen {
2578 self.bump();
2579 let mut cols = Vec::new();
2580 loop {
2581 cols.push(self.expect_ident()?);
2582 if self.eat_comma() {
2583 continue;
2584 }
2585 break;
2586 }
2587 self.expect(&Token::RParen)?;
2588 Some(cols)
2589 } else {
2590 None
2591 };
2592 self.expect(&Token::Keyword(Keyword::As))?;
2593 self.expect(&Token::LParen)?;
2594 let query = self.query_expr()?;
2595 self.expect(&Token::RParen)?;
2596 ctes.push(Cte {
2597 name,
2598 columns,
2599 query,
2600 });
2601 if !self.eat_comma() {
2602 break;
2603 }
2604 }
2605 Ok(Some(WithClause { recursive, ctes }))
2606 }
2607
2608 fn set_expr(&mut self, min_prec: u8) -> Result<crate::ast::SetExpr, ParseError> {
2611 let _guard = DepthGuard::enter(&self.depth, self.peek_pos())?;
2615 let left = self.set_primary()?;
2616 self.set_expr_rest(left, min_prec)
2617 }
2618
2619 fn set_expr_rest(
2620 &mut self,
2621 mut left: crate::ast::SetExpr,
2622 min_prec: u8,
2623 ) -> Result<crate::ast::SetExpr, ParseError> {
2624 use crate::ast::{SetExpr, SetOp};
2625 let mut iterations: usize = 0;
2630 loop {
2631 let (op, prec) = match self.peek() {
2632 Token::Keyword(Keyword::Union) => (SetOp::Union, 1u8),
2633 Token::Keyword(Keyword::Except) => (SetOp::Except, 1u8),
2634 Token::Keyword(Keyword::Intersect) => (SetOp::Intersect, 2u8),
2635 _ => break,
2636 };
2637 if prec < min_prec {
2638 break;
2639 }
2640 iterations += 1;
2641 if iterations > MAX_DEPTH {
2642 return Err(ParseError::too_deep(self.peek_pos()));
2643 }
2644 self.bump(); let all = self.eat_keyword(Keyword::All);
2646 if !all {
2647 self.eat_keyword(Keyword::Distinct); }
2649 let right = self.set_expr(prec + 1)?;
2650 left = SetExpr::SetOp {
2651 op,
2652 all,
2653 left: Box::new(left),
2654 right: Box::new(right),
2655 };
2656 }
2657 Ok(left)
2658 }
2659
2660 fn parenthesized_query_expr(&mut self) -> Result<crate::ast::QueryExpr, ParseError> {
2664 self.expect(&Token::LParen)?;
2665 self.query_expr_after_open_paren()
2666 }
2667
2668 fn query_expr_after_open_paren(&mut self) -> Result<crate::ast::QueryExpr, ParseError> {
2669 let with = self.parse_with_clause()?;
2670 let body = self.set_expr(0)?;
2671 let (order_by, limit, offset, locking) = self.parse_query_tail_and_locking()?;
2672 self.expect(&Token::RParen)?;
2673 let mut q = self.finish_query_expr(body, order_by, limit, offset, locking)?;
2674 q.with = with;
2675 Ok(q)
2676 }
2677
2678 fn set_primary(&mut self) -> Result<crate::ast::SetExpr, ParseError> {
2679 use crate::ast::{QueryBody, SetExpr};
2680 if *self.peek() == Token::LParen {
2681 self.bump(); if matches!(self.peek(), Token::Keyword(Keyword::With)) {
2683 let query = self.query_expr_after_open_paren()?;
2684 return Ok(Self::query_expr_as_outer_primary(query));
2685 }
2686 let inner = self.set_expr(0)?;
2687 let inner = self.attach_paren_tail(inner)?;
2688 self.expect(&Token::RParen)?;
2689 Ok(inner)
2690 } else if *self.peek() == Token::Keyword(Keyword::Values) {
2691 Ok(SetExpr::Query(QueryBody::Values(self.values_stmt()?)))
2692 } else {
2693 Ok(SetExpr::Query(QueryBody::Select(Box::new(
2694 self.select_core()?,
2695 ))))
2696 }
2697 }
2698
2699 fn attach_paren_tail(
2702 &mut self,
2703 inner: crate::ast::SetExpr,
2704 ) -> Result<crate::ast::SetExpr, ParseError> {
2705 use crate::ast::{QueryBody, QueryExpr, SetExpr};
2706 let has_tail = matches!(
2707 self.peek(),
2708 Token::Keyword(Keyword::Order | Keyword::Limit | Keyword::Offset)
2709 );
2710 if !has_tail {
2711 return Ok(inner);
2712 }
2713 match inner {
2714 SetExpr::Query(QueryBody::Select(mut s)) => {
2715 let (order_by, limit, offset) = self.parse_set_tail()?;
2716 s.order_by = order_by;
2717 s.limit = limit;
2718 s.offset = offset;
2719 Ok(SetExpr::Query(QueryBody::Select(s)))
2720 }
2721 body => {
2722 let (order_by, limit, offset) = self.parse_set_tail()?;
2723 Ok(SetExpr::Query(QueryBody::Nested(Box::new(QueryExpr {
2724 with: None,
2725 body,
2726 order_by,
2727 limit,
2728 offset,
2729 locking: None,
2730 }))))
2731 }
2732 }
2733 }
2734
2735 fn parse_from(&mut self) -> Result<Vec<crate::ast::TableExpr>, ParseError> {
2737 let mut items = vec![self.join_tree()?];
2738 while self.eat_comma() {
2739 items.push(self.join_tree()?);
2740 }
2741 Ok(items)
2742 }
2743
2744 fn join_tree(&mut self) -> Result<crate::ast::TableExpr, ParseError> {
2747 use crate::ast::{JoinConstraint, JoinKind, TableExpr};
2748 let mut left = self.table_factor()?;
2749 loop {
2750 let (kind, natural) = if self.eat_keyword(Keyword::Natural) {
2751 (self.join_kind()?, true)
2752 } else if self.peek_is_join_start() {
2753 (self.join_kind()?, false)
2754 } else {
2755 break;
2756 };
2757 let right = self.table_factor()?;
2758 let constraint = if natural || kind == JoinKind::Cross {
2759 if natural {
2760 JoinConstraint::Natural
2761 } else {
2762 JoinConstraint::None
2763 }
2764 } else if self.eat_keyword(Keyword::On) {
2765 JoinConstraint::On(self.expr(0)?)
2766 } else if self.eat_keyword(Keyword::Using) {
2767 self.expect(&Token::LParen)?;
2768 let mut cols = vec![self.expect_ident()?];
2769 while self.eat_comma() {
2770 cols.push(self.expect_ident()?);
2771 }
2772 self.expect(&Token::RParen)?;
2773 JoinConstraint::Using(cols)
2774 } else {
2775 return Err(ParseError::new(
2776 "expected ON or USING after JOIN",
2777 self.peek_pos(),
2778 ));
2779 };
2780 left = TableExpr::Join {
2781 left: Box::new(left),
2782 right: Box::new(right),
2783 kind,
2784 constraint,
2785 };
2786 }
2787 Ok(left)
2788 }
2789
2790 fn peek_is_join_start(&self) -> bool {
2792 matches!(
2793 self.peek(),
2794 Token::Keyword(
2795 Keyword::Join
2796 | Keyword::Inner
2797 | Keyword::Left
2798 | Keyword::Right
2799 | Keyword::Full
2800 | Keyword::Cross,
2801 )
2802 )
2803 }
2804
2805 fn join_kind(&mut self) -> Result<crate::ast::JoinKind, ParseError> {
2808 use crate::ast::JoinKind;
2809 let kind = if self.eat_keyword(Keyword::Inner) {
2810 JoinKind::Inner
2811 } else if self.eat_keyword(Keyword::Left) {
2812 self.eat_keyword(Keyword::Outer);
2813 JoinKind::Left
2814 } else if self.eat_keyword(Keyword::Right) {
2815 self.eat_keyword(Keyword::Outer);
2816 JoinKind::Right
2817 } else if self.eat_keyword(Keyword::Full) {
2818 self.eat_keyword(Keyword::Outer);
2819 JoinKind::Full
2820 } else if self.eat_keyword(Keyword::Cross) {
2821 JoinKind::Cross
2822 } else {
2823 JoinKind::Inner };
2825 self.expect(&Token::Keyword(Keyword::Join))?;
2826 Ok(kind)
2827 }
2828
2829 fn starts_query_expr(&self) -> bool {
2830 matches!(
2831 self.peek(),
2832 Token::Keyword(Keyword::Select | Keyword::Values | Keyword::With) | Token::LParen
2833 )
2834 }
2835
2836 fn table_factor(&mut self) -> Result<crate::ast::TableExpr, ParseError> {
2839 use crate::ast::TableExpr;
2840 if *self.peek() == Token::LParen {
2841 self.bump();
2842 if matches!(
2843 self.peek(),
2844 Token::Keyword(Keyword::Select | Keyword::Values | Keyword::With)
2845 ) {
2846 let subquery = self.query_expr_after_open_paren()?;
2847 let alias = self.opt_alias()?.ok_or_else(|| {
2848 ParseError::new("subquery in FROM must have an alias", self.peek_pos())
2849 })?;
2850 let columns = self.opt_column_aliases()?;
2851 return Ok(TableExpr::Derived {
2852 subquery,
2853 alias,
2854 columns,
2855 });
2856 }
2857 let inner = self.join_tree()?;
2858 self.expect(&Token::RParen)?;
2859 return Ok(inner);
2860 }
2861 let mut name = self.expect_ident()?;
2862 if *self.peek() == Token::Dot {
2863 self.bump();
2864 let object = self.expect_ident()?;
2865 name = format!("{name}.{object}");
2866 }
2867 let alias = self.opt_alias()?;
2868 Ok(TableExpr::Table { name, alias })
2869 }
2870
2871 fn opt_alias(&mut self) -> Result<Option<String>, ParseError> {
2874 if self.eat_keyword(Keyword::As) {
2875 return Ok(Some(self.expect_ident()?));
2876 }
2877 if let Token::Ident(_) = self.peek() {
2878 return Ok(Some(self.expect_ident()?));
2879 }
2880 Ok(None)
2881 }
2882
2883 fn opt_column_aliases(&mut self) -> Result<Option<Vec<String>>, ParseError> {
2884 if *self.peek() != Token::LParen {
2885 return Ok(None);
2886 }
2887 self.bump();
2888 let mut cols = vec![self.expect_ident()?];
2889 while self.eat_comma() {
2890 cols.push(self.expect_ident()?);
2891 }
2892 self.expect(&Token::RParen)?;
2893 Ok(Some(cols))
2894 }
2895
2896 fn expect_int_count(&mut self, what: &str) -> Result<i64, ParseError> {
2899 let pos = self.peek_pos();
2900 match self.bump() {
2901 Token::IntLit(s) => s
2902 .parse::<i64>()
2903 .map_err(|_| ParseError::new(format!("{what} value out of range"), pos)),
2904 other => Err(ParseError::new(
2905 format!("expected {what} count, found {other:?}"),
2906 pos,
2907 )),
2908 }
2909 }
2910
2911 fn eat_comma(&mut self) -> bool {
2912 if *self.peek() == Token::Comma {
2913 self.bump();
2914 true
2915 } else {
2916 false
2917 }
2918 }
2919
2920 fn expect_string_lit(&mut self) -> Result<String, ParseError> {
2922 match self.bump() {
2923 Token::StringLit(s) => Ok(s),
2924 other => Err(ParseError::new(
2925 format!("expected string literal, found {other:?}"),
2926 self.peek_pos(),
2927 )),
2928 }
2929 }
2930
2931 fn parse_options(&mut self) -> Result<crate::ast::OptionList, ParseError> {
2933 if !self.eat_keyword(Keyword::Options) {
2934 return Ok(vec![]);
2935 }
2936 self.expect(&Token::LParen)?;
2937 let mut opts = Vec::new();
2938 loop {
2939 let k = self.expect_ident()?;
2940 let v = self.expect_string_lit()?;
2941 opts.push((k, v));
2942 if self.eat_comma() {
2943 continue;
2944 }
2945 break;
2946 }
2947 self.expect(&Token::RParen)?;
2948 Ok(opts)
2949 }
2950
2951 fn parse_user_mapping_user(&mut self) -> Result<String, ParseError> {
2955 self.expect(&Token::Keyword(Keyword::For))?;
2956 match self.peek().clone() {
2957 Token::Keyword(Keyword::Public) => {
2958 self.bump();
2959 Ok("public".into())
2960 }
2961 Token::Keyword(Keyword::CurrentUser) => {
2962 self.bump();
2963 Ok("current_user".into())
2964 }
2965 Token::Ident(_) => self.expect_ident(),
2966 other => Err(ParseError::new(
2967 format!("expected user name after FOR, found {other:?}"),
2968 self.peek_pos(),
2969 )),
2970 }
2971 }
2972
2973 fn create_fdw(&mut self) -> Result<crate::ast::Statement, ParseError> {
2977 use crate::ast::Statement;
2978 self.expect(&Token::Keyword(Keyword::Create))?;
2979 self.expect(&Token::Keyword(Keyword::Foreign))?;
2980 self.expect(&Token::Keyword(Keyword::Data))?;
2981 self.expect(&Token::Keyword(Keyword::Wrapper))?;
2982 let name = self.expect_ident()?;
2983 let options = self.parse_options()?;
2984 Ok(Statement::CreateFdw { name, options })
2985 }
2986
2987 fn drop_fdw(&mut self) -> Result<crate::ast::Statement, ParseError> {
2989 use crate::ast::Statement;
2990 self.expect(&Token::Keyword(Keyword::Drop))?;
2991 self.expect(&Token::Keyword(Keyword::Foreign))?;
2992 self.expect(&Token::Keyword(Keyword::Data))?;
2993 self.expect(&Token::Keyword(Keyword::Wrapper))?;
2994 let if_exists = self.eat_if_exists()?;
2995 let name = self.expect_ident()?;
2996 Ok(Statement::DropFdw { name, if_exists })
2997 }
2998
2999 fn create_server(&mut self) -> Result<crate::ast::Statement, ParseError> {
3001 use crate::ast::Statement;
3002 self.expect(&Token::Keyword(Keyword::Create))?;
3003 self.expect(&Token::Keyword(Keyword::Server))?;
3004 let name = self.expect_ident()?;
3005 self.expect(&Token::Keyword(Keyword::Foreign))?;
3006 self.expect(&Token::Keyword(Keyword::Data))?;
3007 self.expect(&Token::Keyword(Keyword::Wrapper))?;
3008 let wrapper = self.expect_ident()?;
3009 let options = self.parse_options()?;
3010 Ok(Statement::CreateServer {
3011 name,
3012 wrapper,
3013 options,
3014 })
3015 }
3016
3017 fn alter_server(&mut self) -> Result<crate::ast::Statement, ParseError> {
3019 use crate::ast::Statement;
3020 self.bump(); self.expect(&Token::Keyword(Keyword::Server))?;
3023 let name = self.expect_ident()?;
3024 let options = self.parse_options()?;
3025 Ok(Statement::AlterServer { name, options })
3026 }
3027
3028 fn drop_server(&mut self) -> Result<crate::ast::Statement, ParseError> {
3030 use crate::ast::Statement;
3031 self.expect(&Token::Keyword(Keyword::Drop))?;
3032 self.expect(&Token::Keyword(Keyword::Server))?;
3033 let if_exists = self.eat_if_exists()?;
3034 let name = self.expect_ident()?;
3035 Ok(Statement::DropServer { name, if_exists })
3036 }
3037
3038 fn create_user_mapping(&mut self) -> Result<crate::ast::Statement, ParseError> {
3040 use crate::ast::Statement;
3041 self.expect(&Token::Keyword(Keyword::Create))?;
3042 self.expect(&Token::Keyword(Keyword::User))?;
3043 self.expect(&Token::Keyword(Keyword::Mapping))?;
3044 let user = self.parse_user_mapping_user()?;
3045 self.expect(&Token::Keyword(Keyword::Server))?;
3046 let server = self.expect_ident()?;
3047 let options = self.parse_options()?;
3048 Ok(Statement::CreateUserMapping {
3049 user,
3050 server,
3051 options,
3052 })
3053 }
3054
3055 fn alter_user_mapping(&mut self) -> Result<crate::ast::Statement, ParseError> {
3057 use crate::ast::Statement;
3058 self.bump(); self.expect(&Token::Keyword(Keyword::User))?;
3061 self.expect(&Token::Keyword(Keyword::Mapping))?;
3062 let user = self.parse_user_mapping_user()?;
3063 self.expect(&Token::Keyword(Keyword::Server))?;
3064 let server = self.expect_ident()?;
3065 let options = self.parse_options()?;
3066 Ok(Statement::AlterUserMapping {
3067 user,
3068 server,
3069 options,
3070 })
3071 }
3072
3073 fn drop_user_mapping(&mut self) -> Result<crate::ast::Statement, ParseError> {
3075 use crate::ast::Statement;
3076 self.expect(&Token::Keyword(Keyword::Drop))?;
3077 self.expect(&Token::Keyword(Keyword::User))?;
3078 self.expect(&Token::Keyword(Keyword::Mapping))?;
3079 let if_exists = self.eat_if_exists()?;
3080 let user = self.parse_user_mapping_user()?;
3081 self.expect(&Token::Keyword(Keyword::Server))?;
3082 let server = self.expect_ident()?;
3083 Ok(Statement::DropUserMapping {
3084 user,
3085 server,
3086 if_exists,
3087 })
3088 }
3089
3090 fn create_foreign_table(&mut self) -> Result<crate::ast::Statement, ParseError> {
3092 use crate::ast::{ColumnDef, Statement};
3093 self.expect(&Token::Keyword(Keyword::Create))?;
3094 self.expect(&Token::Keyword(Keyword::Foreign))?;
3095 self.expect(&Token::Keyword(Keyword::Table))?;
3096 let name = self.expect_ident()?;
3097 self.expect(&Token::LParen)?;
3098 let mut columns = Vec::new();
3099 loop {
3100 let col_name = self.expect_ident()?;
3101 let ty = self.parse_type_name()?;
3102 columns.push(ColumnDef {
3103 name: col_name,
3104 ty,
3105 serial: None,
3106 constraints: Vec::new(),
3107 });
3108 if self.eat_comma() {
3109 continue;
3110 }
3111 break;
3112 }
3113 self.expect(&Token::RParen)?;
3114 self.expect(&Token::Keyword(Keyword::Server))?;
3115 let server = self.expect_ident()?;
3116 let options = self.parse_options()?;
3117 Ok(Statement::CreateForeignTable {
3118 name,
3119 columns,
3120 server,
3121 options,
3122 })
3123 }
3124
3125 fn drop_foreign_table(&mut self) -> Result<crate::ast::Statement, ParseError> {
3127 use crate::ast::Statement;
3128 self.expect(&Token::Keyword(Keyword::Drop))?;
3129 self.expect(&Token::Keyword(Keyword::Foreign))?;
3130 self.expect(&Token::Keyword(Keyword::Table))?;
3131 let if_exists = self.eat_if_exists()?;
3132 let name = self.expect_ident()?;
3133 Ok(Statement::DropForeignTable { name, if_exists })
3134 }
3135
3136 fn import_foreign_schema(&mut self) -> Result<crate::ast::Statement, ParseError> {
3138 use crate::ast::{ImportSelector, Statement};
3139 self.expect(&Token::Keyword(Keyword::Import))?;
3140 self.expect(&Token::Keyword(Keyword::Foreign))?;
3141 self.expect(&Token::Keyword(Keyword::Schema))?;
3142 let remote_schema = self.expect_ident()?;
3143 let selector = if self.eat_keyword(Keyword::Limit) {
3144 self.expect(&Token::Keyword(Keyword::To))?;
3145 ImportSelector::LimitTo(self.parse_ident_list()?)
3146 } else if self.eat_keyword(Keyword::Except) {
3147 ImportSelector::Except(self.parse_ident_list()?)
3148 } else {
3149 ImportSelector::All
3150 };
3151 self.expect(&Token::Keyword(Keyword::From))?;
3152 self.expect(&Token::Keyword(Keyword::Server))?;
3153 let server = self.expect_ident()?;
3154 let into_schema = if self.eat_keyword(Keyword::Into) {
3155 match self.peek().clone() {
3157 Token::Keyword(Keyword::Public) => {
3158 self.bump();
3159 "public".into()
3160 }
3161 Token::Ident(_) => self.expect_ident()?,
3162 other => {
3163 return Err(ParseError::new(
3164 format!("expected schema name after INTO, found {other:?}"),
3165 self.peek_pos(),
3166 ));
3167 }
3168 }
3169 } else {
3170 "public".into()
3171 };
3172 Ok(Statement::ImportForeignSchema {
3173 remote_schema,
3174 selector,
3175 server,
3176 into_schema,
3177 })
3178 }
3179
3180 fn parse_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
3182 self.expect(&Token::LParen)?;
3183 let mut names = vec![self.expect_ident()?];
3184 while self.eat_comma() {
3185 names.push(self.expect_ident()?);
3186 }
3187 self.expect(&Token::RParen)?;
3188 Ok(names)
3189 }
3190
3191 fn eat_if_exists(&mut self) -> Result<bool, ParseError> {
3197 if self.eat_keyword(Keyword::If) {
3198 if *self.peek() == Token::Keyword(Keyword::Exists) {
3200 self.bump();
3201 return Ok(true);
3202 }
3203 return Err(ParseError::new(
3206 format!("expected EXISTS after IF, found {:?}", self.peek()),
3207 self.peek_pos(),
3208 ));
3209 }
3210 Ok(false)
3211 }
3212}
3213
3214#[doc(hidden)]
3221pub fn parse_expr_for_test(sql: &str) -> Result<Expr, ParseError> {
3222 let mut p = Parser::new(lex(sql)?, sql.to_string());
3223 let e = p.expr(0)?;
3224 if *p.peek() != Token::Eof {
3225 return Err(ParseError::new(
3226 "trailing tokens after expression",
3227 p.peek_pos(),
3228 ));
3229 }
3230 Ok(e)
3231}
3232
3233pub fn parse(sql: &str) -> Result<Vec<crate::ast::Statement>, ParseError> {
3239 if let Some((statement, _identity)) = bounded_non_goal_refusal(sql) {
3240 return Ok(vec![statement]);
3241 }
3242 let mut p = Parser::new(lex(sql)?, sql.to_string());
3243 Ok(p.program_spanned()?
3244 .into_iter()
3245 .map(|(parsed, _)| parsed.statement)
3246 .collect())
3247}
3248
3249pub fn parse_with_command_identities(
3257 sql: &str,
3258) -> Result<Vec<(crate::ast::Statement, crate::command::CommandIdentity)>, ParseError> {
3259 if let Some((statement, identity)) = bounded_non_goal_refusal(sql) {
3260 return Ok(vec![(statement, identity)]);
3261 }
3262 let mut parser = Parser::new(lex(sql)?, sql.to_string());
3263 parser
3264 .program_spanned()?
3265 .into_iter()
3266 .map(|(parsed, _range)| Ok((parsed.statement, parsed.command_identity)))
3267 .collect()
3268}
3269
3270pub fn parse_with_source(sql: &str) -> Result<Vec<(crate::ast::Statement, String)>, ParseError> {
3280 if let Some((statement, _identity)) = bounded_non_goal_refusal(sql) {
3281 return Ok(vec![(
3282 statement,
3283 sql.trim().trim_end_matches(';').trim().to_string(),
3284 )]);
3285 }
3286 let mut p = Parser::new(lex(sql)?, sql.to_string());
3287 p.program_spanned()?
3288 .into_iter()
3289 .map(|(parsed, range)| Ok((parsed.statement, sql[range].trim().to_string())))
3290 .collect()
3291}
3292
3293fn bounded_non_goal_refusal(
3294 sql: &str,
3295) -> Option<(crate::ast::Statement, crate::command::CommandIdentity)> {
3296 let trimmed = sql.trim();
3297 let statement = trimmed.strip_suffix(';').unwrap_or(trimmed).trim();
3298 let candidate = lex(statement).ok()?;
3299 crate::ast::NON_GOAL_REFUSALS
3300 .iter()
3301 .find(|spec| refusal_tokens_match(&candidate, spec.representative_sql))
3302 .map(|spec| {
3303 (
3304 crate::ast::Statement::CompatibilityRefusal(spec.command),
3305 spec.identity,
3306 )
3307 })
3308}
3309
3310fn refusal_tokens_match(candidate: &[(Token, usize)], representative: &str) -> bool {
3311 const IDENTIFIER_SLOTS: &[&str] = &[
3312 "conv",
3313 "conv2",
3314 "lang",
3315 "lang2",
3316 "postgres",
3317 "opc",
3318 "opc2",
3319 "opf",
3320 "opf2",
3321 "pub",
3322 "r",
3323 "r2",
3324 "sub",
3325 "ts",
3326 "ts2",
3327 "p",
3328 "p2",
3329 "t",
3330 "t2",
3331 "am",
3332 "handler_fn",
3333 "func",
3334 "int4eq",
3335 "f",
3336 ];
3337 let Ok(pattern) = lex(representative) else {
3338 return false;
3339 };
3340 candidate.len() == pattern.len()
3341 && candidate
3342 .iter()
3343 .zip(pattern)
3344 .all(|((actual, _), (expected, _))| match (&expected, actual) {
3345 (Token::Ident(slot), Token::Ident(_))
3346 if IDENTIFIER_SLOTS.contains(&slot.as_str()) =>
3347 {
3348 true
3349 }
3350 (Token::StringLit(_), Token::StringLit(_))
3351 | (Token::IntLit(_), Token::IntLit(_)) => true,
3352 _ => actual == &expected,
3353 })
3354}
3355
3356fn encode_sequence_options(options: &crate::ast::SequenceOptions) -> Vec<String> {
3357 let mut encoded = Vec::new();
3358 if let Some(value) = options.start {
3359 encoded.push(format!("start={value}"));
3360 }
3361 if let Some(value) = options.increment {
3362 encoded.push(format!("increment={value}"));
3363 }
3364 if let Some(value) = options.min {
3365 encoded.push(format!("min={value}"));
3366 }
3367 if let Some(value) = options.max {
3368 encoded.push(format!("max={value}"));
3369 }
3370 if let Some(value) = options.cache {
3371 encoded.push(format!("cache={value}"));
3372 }
3373 if let Some(value) = options.cycle {
3374 encoded.push(format!("cycle={value}"));
3375 }
3376 encoded
3377}
3378
3379#[cfg(test)]
3380mod tests {
3381 use crabka_pgtypes::ColumnType;
3382
3383 use super::*;
3384 use crate::ast::{
3385 BinaryOp, ColumnConstraint, ColumnDef, Expr, HashShardingSpec, IndexPlacement,
3386 IsolationLevel, SelectItem, ShardingSpec, Statement, TableConstraint, UnaryOp,
3387 };
3388
3389 fn one(sql: &str) -> Statement {
3390 let mut v = parse(sql).expect("parse");
3391 assert_eq!(v.len(), 1);
3392 v.pop().expect("one statement")
3393 }
3394
3395 fn only_query(sql: &str) -> crate::ast::QueryExpr {
3396 let statements = crate::parse(sql).expect("parse ok");
3397 assert_eq!(statements.len(), 1);
3398 match statements.into_iter().next().expect("one statement") {
3399 Statement::Query(q) => q,
3400 other => panic!("expected Statement::Query, got {other:?}"),
3401 }
3402 }
3403
3404 fn only_select(sql: &str) -> crate::ast::SelectStmt {
3405 use crate::ast::{QueryBody, SetExpr};
3406 let q = only_query(sql);
3407 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3408 panic!("expected SELECT query body");
3409 };
3410 let mut select = *select;
3411 select.order_by = q.order_by;
3412 select.limit = q.limit;
3413 select.offset = q.offset;
3414 select.locking = q.locking;
3415 select
3416 }
3417
3418 #[test]
3419 fn row_producing_statements_share_query_expr_shape() {
3420 use crate::ast::{QueryBody, SetExpr};
3421
3422 let q = only_query("SELECT 1 ORDER BY 1 LIMIT 1");
3423 assert_eq!(q.order_by.len(), 1);
3424 assert_eq!(q.limit, Some(1));
3425 assert!(matches!(q.body, SetExpr::Query(QueryBody::Select(_))));
3426
3427 let q = only_query("VALUES (1), (2) ORDER BY 1 OFFSET 1");
3428 assert_eq!(q.order_by.len(), 1);
3429 assert_eq!(q.offset, Some(1));
3430 assert!(matches!(q.body, SetExpr::Query(QueryBody::Values(_))));
3431
3432 let q = only_query("SELECT 1 UNION ALL VALUES (2) ORDER BY 1");
3433 assert_eq!(q.order_by.len(), 1);
3434 assert!(matches!(q.body, SetExpr::SetOp { .. }));
3435 }
3436
3437 #[test]
3438 fn parses_view_ddl_and_retains_definition() {
3439 let Statement::CreateView {
3440 name,
3441 definition,
3442 query,
3443 } = one("CREATE VIEW \"Sales View\" AS SELECT id FROM orders WHERE id > 1")
3444 else {
3445 panic!("expected CREATE VIEW");
3446 };
3447 assert_eq!(name, "Sales View");
3448 assert_eq!(definition, "SELECT id FROM orders WHERE id > 1");
3449 assert!(matches!(
3450 query.body,
3451 crate::ast::SetExpr::Query(crate::ast::QueryBody::Select(_))
3452 ));
3453 assert_eq!(
3454 one("DROP VIEW IF EXISTS \"Sales View\""),
3455 Statement::DropView {
3456 name: "Sales View".into(),
3457 if_exists: true,
3458 }
3459 );
3460 }
3461
3462 #[test]
3463 fn legacy_query_forms_still_parse_after_query_unification() {
3464 for sql in [
3465 "SELECT a, b FROM t WHERE a > 1 ORDER BY b LIMIT 5",
3466 "VALUES (1), (2) ORDER BY 1",
3467 "(SELECT 1 ORDER BY 1 LIMIT 1) UNION SELECT 2 ORDER BY 1",
3468 "SELECT * FROM (SELECT 1 AS x) AS d",
3469 "SELECT * FROM (VALUES (1, 'a')) AS v(id, name)",
3470 ] {
3471 let q = only_query(sql);
3472 assert!(q.locking.is_none());
3473 }
3474 }
3475
3476 #[test]
3477 fn derived_and_expression_subqueries_accept_query_exprs() {
3478 use crate::ast::{Expr, QueryBody, SelectItem, SetExpr, TableExpr};
3479
3480 let outer = only_query("SELECT t.x FROM (SELECT 1 AS x UNION SELECT 2) AS t ORDER BY t.x");
3481 let SetExpr::Query(QueryBody::Select(select)) = outer.body else {
3482 panic!("expected outer SELECT query body");
3483 };
3484 let [
3485 TableExpr::Derived {
3486 subquery, alias, ..
3487 },
3488 ] = select.from.as_slice()
3489 else {
3490 panic!("expected one derived table");
3491 };
3492 assert_eq!(alias, "t");
3493 assert!(matches!(subquery.body, SetExpr::SetOp { .. }));
3494
3495 let scalar = only_query("SELECT (VALUES (1) UNION SELECT 2 ORDER BY 1 LIMIT 1)");
3496 let SetExpr::Query(QueryBody::Select(select)) = scalar.body else {
3497 panic!("expected SELECT");
3498 };
3499 let SelectItem::Expr { expr, .. } = &select.projection[0] else {
3500 panic!("expected expression projection");
3501 };
3502 let Expr::ScalarSubquery(q) = expr else {
3503 panic!("expected scalar query expression");
3504 };
3505 assert!(matches!(q.body, SetExpr::SetOp { .. }));
3506 assert_eq!(q.limit, Some(1));
3507 }
3508
3509 #[test]
3510 fn parenthesized_query_expr_tail_is_preserved_for_values_and_setops() {
3511 use crate::ast::{QueryBody, SetExpr, TableExpr};
3512
3513 let q = only_query("SELECT v.x FROM (VALUES (2), (1) ORDER BY 1 LIMIT 1) AS v(x)");
3514 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3515 panic!("expected SELECT");
3516 };
3517 let [TableExpr::Derived { subquery, .. }] = select.from.as_slice() else {
3518 panic!("expected one derived table");
3519 };
3520 assert!(matches!(
3521 subquery.body,
3522 SetExpr::Query(QueryBody::Values(_))
3523 ));
3524 assert_eq!(subquery.order_by.len(), 1);
3525 assert_eq!(subquery.limit, Some(1));
3526
3527 let q =
3528 only_query("SELECT s.x FROM (SELECT 2 AS x UNION SELECT 1 ORDER BY 1 LIMIT 1) AS s");
3529 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3530 panic!("expected SELECT");
3531 };
3532 let [TableExpr::Derived { subquery, .. }] = select.from.as_slice() else {
3533 panic!("expected one derived table");
3534 };
3535 assert!(matches!(subquery.body, SetExpr::SetOp { .. }));
3536 assert_eq!(subquery.order_by.len(), 1);
3537 assert_eq!(subquery.limit, Some(1));
3538 }
3539
3540 #[test]
3541 fn quantified_query_expr_preserves_tail() {
3542 let Expr::Quantified { subquery, .. } =
3543 expr("1 = ANY (SELECT 1 ORDER BY 1 LIMIT 1 OFFSET 0)")
3544 else {
3545 panic!("expected quantified query expression");
3546 };
3547 assert_eq!(subquery.order_by.len(), 1);
3548 assert_eq!(subquery.limit, Some(1));
3549 assert_eq!(subquery.offset, Some(0));
3550 }
3551
3552 #[test]
3553 fn nested_query_expr_locking_is_preserved_and_validated() {
3554 use crate::ast::{QueryBody, RowLockStrength, SelectItem, SetExpr};
3555
3556 let q = only_query("SELECT (SELECT 1 FOR UPDATE)");
3557 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3558 panic!("expected outer SELECT");
3559 };
3560 let SelectItem::Expr { expr, .. } = &select.projection[0] else {
3561 panic!("expected expression projection");
3562 };
3563 let Expr::ScalarSubquery(subquery) = expr else {
3564 panic!("expected scalar subquery");
3565 };
3566 assert_eq!(subquery.locking, Some(RowLockStrength::ForUpdate));
3567
3568 assert!(crate::parse("SELECT (VALUES (1) FOR UPDATE)").is_err());
3569 assert!(crate::parse("SELECT (SELECT 1 UNION SELECT 2 FOR UPDATE)").is_err());
3570 }
3571
3572 #[test]
3573 fn top_level_parenthesized_query_expr_tail_is_preserved() {
3574 use crate::ast::{QueryBody, SetExpr};
3575
3576 let q = only_query("(VALUES (2), (1) ORDER BY 1 LIMIT 1)");
3577 assert!(matches!(q.body, SetExpr::Query(QueryBody::Values(_))));
3578 assert_eq!(q.order_by.len(), 1);
3579 assert_eq!(q.limit, Some(1));
3580
3581 let q = only_query("(SELECT 2 UNION SELECT 1 ORDER BY 1 LIMIT 1)");
3582 assert!(matches!(q.body, SetExpr::SetOp { .. }));
3583 assert_eq!(q.order_by.len(), 1);
3584 assert_eq!(q.limit, Some(1));
3585 }
3586
3587 #[test]
3588 fn parenthesized_query_expr_outer_tail_preserves_inner_values_and_setop_tails() {
3589 use crate::ast::{QueryBody, SetExpr};
3590
3591 let q = only_query("(VALUES (2), (1) ORDER BY 1) LIMIT 1");
3592 assert_eq!(q.limit, Some(1));
3593 assert!(q.order_by.is_empty());
3594 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3595 panic!("expected nested VALUES query body");
3596 };
3597 assert_eq!(inner.order_by.len(), 1);
3598 assert_eq!(inner.limit, None);
3599 assert!(matches!(inner.body, SetExpr::Query(QueryBody::Values(_))));
3600
3601 let q = only_query("(SELECT 2 UNION SELECT 1 ORDER BY 1) LIMIT 1");
3602 assert_eq!(q.limit, Some(1));
3603 assert!(q.order_by.is_empty());
3604 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3605 panic!("expected nested set-op query body");
3606 };
3607 assert_eq!(inner.order_by.len(), 1);
3608 assert_eq!(inner.limit, None);
3609 assert!(matches!(inner.body, SetExpr::SetOp { .. }));
3610 }
3611
3612 #[test]
3613 fn redundant_parenthesized_query_expr_preserves_inner_values_and_setop_tails() {
3614 use crate::ast::{QueryBody, SetExpr};
3615
3616 let q = only_query("((VALUES (2), (1) ORDER BY 1))");
3617 assert!(q.order_by.is_empty());
3618 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3619 panic!("expected nested VALUES query body");
3620 };
3621 assert_eq!(inner.order_by.len(), 1);
3622 assert_eq!(inner.limit, None);
3623 assert!(matches!(inner.body, SetExpr::Query(QueryBody::Values(_))));
3624
3625 let q = only_query("((VALUES (2), (1) ORDER BY 1) LIMIT 1)");
3626 assert!(q.order_by.is_empty());
3627 assert_eq!(q.limit, Some(1));
3628 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3629 panic!("expected nested VALUES query body");
3630 };
3631 assert_eq!(inner.order_by.len(), 1);
3632 assert_eq!(inner.limit, None);
3633 assert!(matches!(inner.body, SetExpr::Query(QueryBody::Values(_))));
3634
3635 let q = only_query("((SELECT 2 UNION SELECT 1 ORDER BY 1))");
3636 assert!(q.order_by.is_empty());
3637 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3638 panic!("expected nested set-op query body");
3639 };
3640 assert_eq!(inner.order_by.len(), 1);
3641 assert_eq!(inner.limit, None);
3642 assert!(matches!(inner.body, SetExpr::SetOp { .. }));
3643
3644 let q = only_query("((SELECT 2 UNION SELECT 1 ORDER BY 1) LIMIT 1)");
3645 assert!(q.order_by.is_empty());
3646 assert_eq!(q.limit, Some(1));
3647 let SetExpr::Query(QueryBody::Nested(inner)) = q.body else {
3648 panic!("expected nested set-op query body");
3649 };
3650 assert_eq!(inner.order_by.len(), 1);
3651 assert_eq!(inner.limit, None);
3652 assert!(matches!(inner.body, SetExpr::SetOp { .. }));
3653 }
3654
3655 #[test]
3656 fn raw_query_expr_tail_placement_is_visible() {
3657 use crate::ast::{QueryBody, SetExpr};
3658
3659 let q = only_query("SELECT 1 ORDER BY 1 LIMIT 1");
3660 assert_eq!(q.order_by.len(), 1);
3661 assert_eq!(q.limit, Some(1));
3662 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3663 panic!("expected SELECT body");
3664 };
3665 assert!(select.order_by.is_empty());
3666 assert_eq!(select.limit, None);
3667
3668 let q = only_query("((SELECT 1 ORDER BY 1))");
3669 assert!(q.order_by.is_empty());
3670 let SetExpr::Query(QueryBody::Select(select)) = q.body else {
3671 panic!("expected SELECT body");
3672 };
3673 assert_eq!(select.order_by.len(), 1);
3674 }
3675
3676 #[test]
3677 fn left_and_right_keywords_parse_as_functions_in_expression_position() {
3678 use crate::ast::{FuncArgs, FuncCall};
3679 for (sql, name) in [("left('abc', 2)", "left"), ("right('abc', 2)", "right")] {
3682 match parse_expr_for_test(sql).expect("parse fn") {
3683 Expr::Func(FuncCall {
3684 name: n,
3685 args: FuncArgs::Exprs(a),
3686 ..
3687 }) => {
3688 assert_eq!(n, name);
3689 assert_eq!(a.len(), 2);
3690 }
3691 other => panic!("expected a function call, got {other:?}"),
3692 }
3693 }
3694 assert!(parse_expr_for_test("left + 1").is_err());
3696 assert!(parse("SELECT * FROM a LEFT JOIN b ON a.id = b.id").is_ok());
3698 }
3699
3700 #[test]
3701 fn parse_with_source_pairs_each_statement_with_its_exact_text() {
3702 let v =
3703 parse_with_source("INSERT INTO a VALUES (1); INSERT INTO b VALUES (2)").expect("parse");
3704 assert_eq!(v.len(), 2);
3705 assert_eq!(v[0].1, "INSERT INTO a VALUES (1)");
3706 assert_eq!(v[1].1, "INSERT INTO b VALUES (2)");
3707 let solo = parse_with_source(" SELECT 1 ; ").expect("parse one");
3710 assert_eq!(solo.len(), 1);
3711 assert_eq!(solo[0].1, "SELECT 1");
3712 }
3713
3714 #[test]
3715 fn parses_create_table() {
3716 assert_eq!(
3717 one("CREATE TABLE t (id int4, name text)"),
3718 Statement::CreateTable {
3719 name: "t".into(),
3720 sharded: false,
3721 sharding: None,
3722 constraints: Vec::new(),
3723 columns: vec![
3724 ColumnDef {
3725 name: "id".into(),
3726 ty: ColumnType::Int4,
3727 serial: None,
3728 constraints: Vec::new(),
3729 },
3730 ColumnDef {
3731 name: "name".into(),
3732 ty: ColumnType::Text,
3733 serial: None,
3734 constraints: Vec::new(),
3735 },
3736 ],
3737 }
3738 );
3739 }
3740
3741 #[test]
3742 fn parses_column_constraints_and_default_insert_marker() {
3743 let Statement::CreateTable {
3744 columns,
3745 constraints,
3746 ..
3747 } = one(
3748 "CREATE TABLE t (id int4 PRIMARY KEY, name text NOT NULL DEFAULT 'anon', CHECK (id > 0), UNIQUE (name))",
3749 )
3750 else {
3751 panic!("expected create table");
3752 };
3753 assert!(matches!(
3754 columns[0].constraints[0],
3755 ColumnConstraint::PrimaryKey
3756 ));
3757 assert!(matches!(
3758 columns[1].constraints[0],
3759 ColumnConstraint::NotNull
3760 ));
3761 assert!(matches!(
3762 columns[1].constraints[1],
3763 ColumnConstraint::Default(_)
3764 ));
3765 assert!(matches!(constraints[0], TableConstraint::Check(_)));
3766 assert!(matches!(constraints[1], TableConstraint::Unique(_)));
3767
3768 let Statement::Insert { rows, .. } = one("INSERT INTO t (id, name) VALUES (1, DEFAULT)")
3769 else {
3770 panic!("expected insert");
3771 };
3772 assert!(matches!(rows[0][1], Expr::Default));
3773 }
3774
3775 #[test]
3776 fn parses_create_table_sharded_suffix() {
3777 assert_eq!(
3778 one("CREATE TABLE t (id int4) SHARDED"),
3779 Statement::CreateTable {
3780 name: "t".into(),
3781 columns: vec![ColumnDef {
3782 name: "id".into(),
3783 ty: ColumnType::Int4,
3784 serial: None,
3785 constraints: Vec::new(),
3786 }],
3787 constraints: Vec::new(),
3788 sharded: true,
3789 sharding: None,
3790 }
3791 );
3792 }
3793
3794 #[test]
3795 fn parses_create_table_hash_sharded_suffix() {
3796 assert_eq!(
3797 one("CREATE TABLE t (id int4) SHARDED BY HASH (id) BUCKETS 16"),
3798 Statement::CreateTable {
3799 name: "t".into(),
3800 columns: vec![ColumnDef {
3801 name: "id".into(),
3802 ty: ColumnType::Int4,
3803 serial: None,
3804 constraints: Vec::new(),
3805 }],
3806 constraints: Vec::new(),
3807 sharded: true,
3808 sharding: Some(ShardingSpec::Hash(HashShardingSpec {
3809 columns: vec!["id".into()],
3810 buckets: 16,
3811 co_location_group: None,
3812 })),
3813 }
3814 );
3815 }
3816
3817 #[test]
3818 fn parses_create_index_metadata() {
3819 assert_eq!(
3820 one("CREATE UNIQUE GLOBAL INDEX users_email_idx ON users (email, id)"),
3821 Statement::CreateIndex {
3822 name: "users_email_idx".into(),
3823 table: "users".into(),
3824 columns: vec!["email".into(), "id".into()],
3825 unique: true,
3826 placement: IndexPlacement::Global,
3827 }
3828 );
3829 assert_eq!(
3830 one("CREATE INDEX users_id_idx ON users (id)"),
3831 Statement::CreateIndex {
3832 name: "users_id_idx".into(),
3833 table: "users".into(),
3834 columns: vec!["id".into()],
3835 unique: false,
3836 placement: IndexPlacement::Local,
3837 }
3838 );
3839 }
3840
3841 #[test]
3842 fn parses_drop_index_if_exists() {
3843 assert_eq!(
3844 one("DROP INDEX IF EXISTS \"Users Name Idx\""),
3845 Statement::DropIndex {
3846 name: "Users Name Idx".into(),
3847 if_exists: true,
3848 }
3849 );
3850 }
3851
3852 #[test]
3853 fn rejects_non_power_of_two_hash_bucket_count() {
3854 let err = parse("CREATE TABLE t (id int4) SHARDED BY HASH (id) BUCKETS 3")
3855 .expect_err("non-power-of-two buckets");
3856 assert_eq!(err.sqlstate(), "42601");
3857 assert!(err.message.contains("power of two"));
3858 }
3859
3860 #[test]
3861 fn rejects_multiple_hash_sharding_columns() {
3862 let err = parse("CREATE TABLE t (a int4, b int4) SHARDED BY HASH (a, b) BUCKETS 16")
3863 .expect_err("the G9 hash grammar has exactly one column");
3864 assert_eq!(err.sqlstate(), "42601");
3865 assert!(err.message.contains("exactly one column"));
3866 }
3867
3868 #[test]
3869 fn rejects_sharded_in_invalid_create_table_positions() {
3870 let leading = parse("CREATE SHARDED TABLE t (id int4)").expect_err("leading SHARDED");
3871 assert_eq!(leading.sqlstate(), "42601");
3872 assert!(
3873 leading.message.contains("expected Keyword(Table)")
3874 || leading.message.contains("unexpected token")
3875 );
3876
3877 let embedded = parse("CREATE TABLE t SHARDED (id int4)").expect_err("embedded SHARDED");
3878 assert_eq!(embedded.sqlstate(), "42601");
3879 assert!(embedded.message.contains("expected LParen"));
3880 }
3881
3882 #[test]
3883 fn unknown_column_type_is_error() {
3884 let e = parse("CREATE TABLE t (x widget)").expect_err("bad type");
3885 assert_eq!(e.sqlstate(), "42601");
3886 }
3887
3888 #[test]
3889 fn parses_float8_column_types() {
3890 for sql in [
3892 "CREATE TABLE t (x float8)",
3893 "CREATE TABLE t (x float)",
3894 "CREATE TABLE t (x double precision)",
3895 ] {
3896 match one(sql) {
3897 Statement::CreateTable { columns, .. } => {
3898 assert_eq!(columns[0].ty, ColumnType::Float8, "for `{sql}`");
3899 }
3900 other => panic!("expected CreateTable, got {other:?}"),
3901 }
3902 }
3903 assert!(parse("CREATE TABLE t (x double)").is_err());
3905 }
3906
3907 #[test]
3908 fn parses_numeric_column_types_with_optional_typmod() {
3909 use crabka_pgtypes::numeric::Typmod;
3910 let ty = |sql: &str| match one(sql) {
3911 Statement::CreateTable { columns, .. } => columns[0].ty,
3912 other => panic!("expected CreateTable, got {other:?}"),
3913 };
3914 assert_eq!(ty("CREATE TABLE t (x numeric)"), ColumnType::Numeric(None));
3916 assert_eq!(ty("CREATE TABLE t (x decimal)"), ColumnType::Numeric(None));
3917 assert_eq!(
3919 ty("CREATE TABLE t (x numeric(10))"),
3920 ColumnType::Numeric(Some(Typmod {
3921 precision: 10,
3922 scale: 0
3923 }))
3924 );
3925 assert_eq!(
3926 ty("CREATE TABLE t (x numeric(10, 2))"),
3927 ColumnType::Numeric(Some(Typmod {
3928 precision: 10,
3929 scale: 2
3930 }))
3931 );
3932 assert!(matches!(
3934 expr("x::numeric(5,1)"),
3935 Expr::Cast {
3936 ty: ColumnType::Numeric(Some(Typmod {
3937 precision: 5,
3938 scale: 1
3939 })),
3940 ..
3941 }
3942 ));
3943 }
3944
3945 #[test]
3946 fn parses_varchar_and_char_type_modifiers() {
3947 let ty = |sql: &str| match one(sql) {
3948 Statement::CreateTable { columns, .. } => columns[0].ty,
3949 other => panic!("expected CreateTable, got {other:?}"),
3950 };
3951
3952 assert_eq!(ty("CREATE TABLE t (x varchar)"), ColumnType::Varchar(None));
3953 assert_eq!(
3954 ty("CREATE TABLE t (x varchar(12))"),
3955 ColumnType::Varchar(Some(12))
3956 );
3957 assert_eq!(
3958 ty("CREATE TABLE t (x character varying(7))"),
3959 ColumnType::Varchar(Some(7))
3960 );
3961 assert_eq!(ty("CREATE TABLE t (x char)"), ColumnType::Char(Some(1)));
3962 assert_eq!(
3963 ty("CREATE TABLE t (x character(3))"),
3964 ColumnType::Char(Some(3))
3965 );
3966 assert!(matches!(
3967 expr("'abc'::varchar(2)"),
3968 Expr::Cast {
3969 ty: ColumnType::Varchar(Some(2)),
3970 ..
3971 }
3972 ));
3973 }
3974
3975 #[test]
3976 fn parses_niladic_keyword_functions_without_parens() {
3977 use crate::ast::{FuncArgs, FuncCall};
3978 for name in [
3980 "current_date",
3981 "current_time",
3982 "localtimestamp",
3983 "localtime",
3984 "current_timestamp",
3985 ] {
3986 assert_eq!(
3987 expr(name),
3988 Expr::Func(FuncCall {
3989 name: name.into(),
3990 distinct: false,
3991 args: FuncArgs::Exprs(vec![]),
3992 }),
3993 "niladic `{name}`"
3994 );
3995 }
3996 assert_eq!(
3998 expr("now()"),
3999 Expr::Func(FuncCall {
4000 name: "now".into(),
4001 distinct: false,
4002 args: FuncArgs::Exprs(vec![]),
4003 })
4004 );
4005 match expr("current_timestamp(0)") {
4006 Expr::Func(FuncCall { name, args, .. }) => {
4007 assert_eq!(name, "current_timestamp");
4008 assert!(matches!(args, FuncArgs::Exprs(ref v) if v.len() == 1));
4009 }
4010 other => panic!("expected a Func call, got {other:?}"),
4011 }
4012 }
4013
4014 #[test]
4015 fn parses_numeric_literals() {
4016 assert_eq!(expr("1.5"), Expr::NumericLiteral("1.5".into()));
4018 assert_eq!(expr(".25"), Expr::NumericLiteral(".25".into()));
4019 assert_eq!(expr("1e3"), Expr::NumericLiteral("1e3".into()));
4020 assert_eq!(expr("42"), Expr::IntLiteral("42".into()));
4021 match expr("1 + 2.5 * 2") {
4023 Expr::Binary {
4024 op: BinaryOp::Add,
4025 right,
4026 ..
4027 } => assert!(matches!(
4028 *right,
4029 Expr::Binary {
4030 op: BinaryOp::Mul,
4031 ..
4032 }
4033 )),
4034 other => panic!("expected Add(_, Mul), got {other:?}"),
4035 }
4036 }
4037
4038 #[test]
4039 fn parses_drop_table() {
4040 assert_eq!(
4041 one("DROP TABLE t"),
4042 Statement::DropTable { name: "t".into() }
4043 );
4044 }
4045
4046 #[test]
4047 fn parses_multi_row_insert_with_columns() {
4048 match one("INSERT INTO t (a, b) VALUES (1, 'x'), (2, 'y')") {
4049 Statement::Insert {
4050 table,
4051 columns,
4052 rows,
4053 returning,
4054 } => {
4055 assert_eq!(table, "t");
4056 assert_eq!(columns, Some(vec!["a".into(), "b".into()]));
4057 assert_eq!(rows.len(), 2);
4058 assert_eq!(rows[0].len(), 2);
4059 assert_eq!(returning, None);
4060 }
4061 other => panic!("expected Insert, got {other:?}"),
4062 }
4063 }
4064
4065 #[test]
4066 fn parses_select_with_all_clauses() {
4067 let s = only_select("SELECT a, b AS bee FROM t WHERE a > 1 ORDER BY a DESC, b LIMIT 10");
4068 assert_eq!(s.projection.len(), 2);
4069 assert!(
4070 matches!(s.projection[1], SelectItem::Expr { alias: Some(ref n), .. } if n == "bee")
4071 );
4072 assert!(matches!(
4073 s.from.as_slice(),
4074 [crate::ast::TableExpr::Table { name, alias: None }] if name == "t"
4075 ));
4076 assert!(s.filter.is_some());
4077 assert_eq!(s.order_by.len(), 2);
4078 assert!(!s.order_by[0].asc); assert!(s.order_by[1].asc); assert_eq!(s.limit, Some(10));
4081 }
4082
4083 #[test]
4084 fn parses_aggregates_group_by_having() {
4085 use crate::ast::{FuncArgs, FuncCall};
4086 let s = only_select(
4087 "SELECT k, count(*), sum(v) FROM t WHERE v > 0 \
4088 GROUP BY k HAVING count(*) > 1 ORDER BY k LIMIT 5",
4089 );
4090 assert_eq!(s.projection.len(), 3);
4091 assert!(matches!(
4093 s.projection[1],
4094 SelectItem::Expr {
4095 expr: Expr::Func(FuncCall { ref name, distinct: false, args: FuncArgs::Star }),
4096 ..
4097 } if name == "count"
4098 ));
4099 assert_eq!(
4100 s.group_by,
4101 vec![Expr::Column {
4102 table: None,
4103 name: "k".into()
4104 }]
4105 );
4106 assert!(s.having.is_some());
4107 assert_eq!(s.order_by.len(), 1);
4108 assert_eq!(s.limit, Some(5));
4109 }
4110
4111 #[test]
4112 fn parses_count_distinct_and_func_args() {
4113 use crate::ast::{FuncArgs, FuncCall};
4114 let s = only_select("SELECT count(DISTINCT a + 1) FROM t");
4115 match &s.projection[0] {
4116 SelectItem::Expr {
4117 expr:
4118 Expr::Func(FuncCall {
4119 name,
4120 distinct,
4121 args,
4122 }),
4123 ..
4124 } => {
4125 assert_eq!(name, "count");
4126 assert!(*distinct);
4127 match args {
4128 FuncArgs::Exprs(v) => assert_eq!(v.len(), 1),
4129 other @ FuncArgs::Star => panic!("expected Exprs, got {other:?}"),
4130 }
4131 }
4132 other => panic!("expected a Func projection, got {other:?}"),
4133 }
4134 }
4135
4136 #[test]
4137 fn count_distinct_star_is_rejected() {
4138 assert!(parse("SELECT count(DISTINCT *) FROM t").is_err());
4140 }
4141
4142 #[test]
4143 fn parses_multi_key_group_by() {
4144 let s = only_select("SELECT a, b, max(c) FROM t GROUP BY a, b");
4145 assert_eq!(
4146 s.group_by,
4147 vec![
4148 Expr::Column {
4149 table: None,
4150 name: "a".into()
4151 },
4152 Expr::Column {
4153 table: None,
4154 name: "b".into()
4155 }
4156 ]
4157 );
4158 assert!(s.having.is_none());
4159 }
4160
4161 #[test]
4162 fn parses_select_star_no_from() {
4163 let s = only_select("SELECT *");
4164 assert_eq!(s.projection, vec![SelectItem::Wildcard]);
4165 assert!(s.from.is_empty());
4166 }
4167
4168 #[test]
4169 fn parses_multiple_statements() {
4170 let v = parse("SELECT 1; SELECT 2;").expect("parse");
4171 assert_eq!(v.len(), 2);
4172 }
4173
4174 #[test]
4175 fn trailing_garbage_is_error() {
4176 assert!(parse("SELECT 1 foo bar").is_err());
4177 }
4178
4179 #[test]
4180 fn parses_begin_variants() {
4181 assert_eq!(one("BEGIN"), Statement::Begin { isolation: None });
4182 assert_eq!(
4183 one("START TRANSACTION"),
4184 Statement::Begin { isolation: None }
4185 );
4186 assert_eq!(
4187 one("BEGIN ISOLATION LEVEL REPEATABLE READ"),
4188 Statement::Begin {
4189 isolation: Some(IsolationLevel::RepeatableRead)
4190 }
4191 );
4192 assert_eq!(
4193 one("BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED"),
4194 Statement::Begin {
4195 isolation: Some(IsolationLevel::ReadCommitted)
4196 }
4197 );
4198 }
4199
4200 #[test]
4201 fn start_requires_transaction_keyword() {
4202 assert_eq!(
4204 one("START TRANSACTION"),
4205 Statement::Begin { isolation: None }
4206 );
4207 assert!(parse("START").is_err());
4208 }
4209
4210 #[test]
4211 fn parses_commit_rollback_aliases() {
4212 assert_eq!(one("COMMIT"), Statement::Commit);
4213 assert_eq!(one("END"), Statement::Commit);
4214 assert_eq!(one("ROLLBACK"), Statement::Rollback);
4215 assert_eq!(one("ABORT"), Statement::Rollback);
4216 }
4217
4218 #[test]
4219 fn parses_update() {
4220 match one("UPDATE t SET a = 1, b = a + 2 WHERE id = 5") {
4221 Statement::Update {
4222 table,
4223 assignments,
4224 filter,
4225 returning,
4226 } => {
4227 assert_eq!(table, "t");
4228 assert_eq!(assignments.len(), 2);
4229 assert_eq!(assignments[0].0, "a");
4230 assert_eq!(assignments[1].0, "b");
4231 assert!(filter.is_some());
4232 assert_eq!(returning, None);
4233 }
4234 other => panic!("expected Update, got {other:?}"),
4235 }
4236 }
4237
4238 #[test]
4239 fn parses_select_for_update_and_share() {
4240 use crate::ast::RowLockStrength;
4241 assert_eq!(
4242 only_query("SELECT id FROM t FOR UPDATE").locking,
4243 Some(RowLockStrength::ForUpdate)
4244 );
4245 assert_eq!(
4246 only_query("SELECT id FROM t WHERE id > 1 FOR SHARE").locking,
4247 Some(RowLockStrength::ForShare)
4248 );
4249 assert_eq!(only_query("SELECT id FROM t").locking, None);
4250 }
4251
4252 #[test]
4253 fn parses_delete() {
4254 match one("DELETE FROM t WHERE id > 3") {
4255 Statement::Delete {
4256 table,
4257 filter,
4258 returning,
4259 } => {
4260 assert_eq!(table, "t");
4261 assert!(filter.is_some());
4262 assert_eq!(returning, None);
4263 }
4264 other => panic!("expected Delete, got {other:?}"),
4265 }
4266 assert_eq!(
4267 one("DELETE FROM t"),
4268 Statement::Delete {
4269 table: "t".into(),
4270 filter: None,
4271 returning: None,
4272 }
4273 );
4274 }
4275
4276 #[test]
4277 fn parses_dml_returning() {
4278 let Statement::Insert { returning, .. } = one("INSERT INTO t VALUES (1) RETURNING *")
4279 else {
4280 panic!("expected Insert");
4281 };
4282 assert_eq!(returning, Some(vec![SelectItem::Wildcard]));
4283
4284 let Statement::Update { returning, .. } = one("UPDATE t SET a = 1 RETURNING a AS x, a + 1")
4285 else {
4286 panic!("expected Update");
4287 };
4288 assert!(matches!(
4289 returning.as_deref(),
4290 Some([
4291 SelectItem::Expr { alias: Some(alias), .. },
4292 SelectItem::Expr { alias: None, .. }
4293 ]) if alias == "x"
4294 ));
4295
4296 let Statement::Delete { returning, .. } = one("DELETE FROM t RETURNING t.*") else {
4297 panic!("expected Delete");
4298 };
4299 assert_eq!(
4300 returning,
4301 Some(vec![SelectItem::QualifiedWildcard("t".into())])
4302 );
4303 }
4304
4305 fn expr(sql: &str) -> Expr {
4306 parse_expr_for_test(sql).expect("parse expr")
4309 }
4310
4311 #[test]
4312 fn every_binary_operator_parses_to_its_op() {
4313 use crate::ast::BinaryOp::*;
4316 for (src, want) in [
4317 ("a = b", Eq),
4318 ("a <> b", Ne),
4319 ("a < b", Lt),
4320 ("a <= b", Le),
4321 ("a > b", Gt),
4322 ("a >= b", Ge),
4323 ("a + b", Add),
4324 ("a - b", Sub),
4325 ("a * b", Mul),
4326 ("a / b", Div),
4327 ("a || b", Concat),
4328 ] {
4329 match expr(src) {
4330 Expr::Binary { op, .. } => assert_eq!(op, want, "operator in `{src}`"),
4331 other => panic!("`{src}` should parse to a Binary expr, got {other:?}"),
4332 }
4333 }
4334 }
4335
4336 #[test]
4337 fn bump_does_not_advance_past_eof() {
4338 assert!(parse("DROP TABLE").is_err());
4343 assert!(parse("CREATE TABLE").is_err());
4344 }
4345
4346 #[test]
4347 fn precedence_mul_over_add() {
4348 let e = expr("1 + 2 * 3");
4350 assert_eq!(
4351 e,
4352 Expr::Binary {
4353 op: BinaryOp::Add,
4354 left: Box::new(Expr::IntLiteral("1".into())),
4355 right: Box::new(Expr::Binary {
4356 op: BinaryOp::Mul,
4357 left: Box::new(Expr::IntLiteral("2".into())),
4358 right: Box::new(Expr::IntLiteral("3".into())),
4359 }),
4360 }
4361 );
4362 }
4363
4364 #[test]
4365 fn concat_precedence_and_associativity() {
4366 match expr("a || b + c") {
4368 Expr::Binary {
4369 op: BinaryOp::Concat,
4370 right,
4371 ..
4372 } => assert!(matches!(
4373 *right,
4374 Expr::Binary {
4375 op: BinaryOp::Add,
4376 ..
4377 }
4378 )),
4379 other => panic!("expected Concat(.., Add) , got {other:?}"),
4380 }
4381 match expr("a || b = c") {
4383 Expr::Binary {
4384 op: BinaryOp::Eq,
4385 left,
4386 ..
4387 } => assert!(matches!(
4388 *left,
4389 Expr::Binary {
4390 op: BinaryOp::Concat,
4391 ..
4392 }
4393 )),
4394 other => panic!("expected Eq(Concat, ..), got {other:?}"),
4395 }
4396 match expr("a || b || c") {
4398 Expr::Binary {
4399 op: BinaryOp::Concat,
4400 left,
4401 ..
4402 } => assert!(matches!(
4403 *left,
4404 Expr::Binary {
4405 op: BinaryOp::Concat,
4406 ..
4407 }
4408 )),
4409 other => panic!("expected left-nested Concat, got {other:?}"),
4410 }
4411 match expr("a || b LIKE 'p'") {
4413 Expr::Like { expr, .. } => {
4414 assert!(matches!(
4415 *expr,
4416 Expr::Binary {
4417 op: BinaryOp::Concat,
4418 ..
4419 }
4420 ));
4421 }
4422 other => panic!("expected Like over Concat, got {other:?}"),
4423 }
4424 }
4425
4426 #[test]
4427 fn unary_minus_still_binds_tighter_than_star() {
4428 match expr("-a * b") {
4430 Expr::Binary {
4431 op: BinaryOp::Mul,
4432 left,
4433 ..
4434 } => assert!(matches!(
4435 *left,
4436 Expr::Unary {
4437 op: UnaryOp::Neg,
4438 ..
4439 }
4440 )),
4441 other => panic!("expected Mul((-a), b), got {other:?}"),
4442 }
4443 }
4444
4445 #[test]
4446 fn comparison_and_boolean_precedence() {
4447 let e = expr("a = 1 AND b < 2");
4449 assert!(matches!(
4450 e,
4451 Expr::Binary {
4452 op: BinaryOp::And,
4453 ..
4454 }
4455 ));
4456 }
4457
4458 #[test]
4459 fn not_and_or_precedence() {
4460 let e = expr("NOT x OR y");
4462 match e {
4463 Expr::Binary {
4464 op: BinaryOp::Or,
4465 left,
4466 ..
4467 } => {
4468 assert!(matches!(
4469 *left,
4470 Expr::Unary {
4471 op: UnaryOp::Not,
4472 ..
4473 }
4474 ));
4475 }
4476 _ => panic!("expected OR at top, got {e:?}"),
4477 }
4478 }
4479
4480 #[test]
4481 fn unary_minus_and_parens() {
4482 let e = expr("-(1 + 2)");
4483 assert!(matches!(
4484 e,
4485 Expr::Unary {
4486 op: UnaryOp::Neg,
4487 ..
4488 }
4489 ));
4490 }
4491
4492 #[test]
4493 fn literals_columns_params() {
4494 assert_eq!(expr("'hi'"), Expr::StringLiteral("hi".into()));
4495 assert_eq!(expr("true"), Expr::BoolLiteral(true));
4496 assert_eq!(expr("null"), Expr::NullLiteral);
4497 assert_eq!(
4498 expr("col"),
4499 Expr::Column {
4500 table: None,
4501 name: "col".into()
4502 }
4503 );
4504 assert_eq!(expr("$2"), Expr::Param(2));
4505 }
4506
4507 #[test]
4508 fn not_binds_tighter_than_and() {
4509 let e = expr("NOT x AND y");
4511 match e {
4512 Expr::Binary {
4513 op: BinaryOp::And,
4514 left,
4515 ..
4516 } => {
4517 assert!(
4518 matches!(
4519 *left,
4520 Expr::Unary {
4521 op: UnaryOp::Not,
4522 ..
4523 }
4524 ),
4525 "left of AND must be (NOT x), got {left:?}"
4526 );
4527 }
4528 _ => panic!("expected AND at root, got {e:?}"),
4529 }
4530 }
4531
4532 #[test]
4533 fn comparison_binds_tighter_than_not() {
4534 let e = expr("NOT a = 1");
4536 match e {
4537 Expr::Unary {
4538 op: UnaryOp::Not,
4539 expr,
4540 } => {
4541 assert!(
4542 matches!(
4543 *expr,
4544 Expr::Binary {
4545 op: BinaryOp::Eq,
4546 ..
4547 }
4548 ),
4549 "NOT operand must be (a = 1), got {expr:?}"
4550 );
4551 }
4552 _ => panic!("expected NOT at root, got {e:?}"),
4553 }
4554 }
4555
4556 #[test]
4559 fn parses_is_null_and_is_not_null() {
4560 assert!(matches!(
4561 expr("a IS NULL"),
4562 Expr::IsNull { negated: false, .. }
4563 ));
4564 assert!(matches!(
4565 expr("a IS NOT NULL"),
4566 Expr::IsNull { negated: true, .. }
4567 ));
4568 }
4569
4570 #[test]
4571 fn parses_in_and_not_in() {
4572 match expr("a IN (1, 2, 3)") {
4573 Expr::InList { list, negated, .. } => {
4574 assert_eq!(list.len(), 3);
4575 assert!(!negated);
4576 }
4577 other => panic!("expected InList, got {other:?}"),
4578 }
4579 assert!(matches!(
4580 expr("a NOT IN (1, 2)"),
4581 Expr::InList { negated: true, .. }
4582 ));
4583 }
4584
4585 #[test]
4586 fn empty_in_list_is_rejected() {
4587 assert!(parse("SELECT a FROM t WHERE a IN ()").is_err());
4588 }
4589
4590 #[test]
4591 fn not_in_is_infix_but_prefix_not_wraps_in() {
4592 assert!(matches!(
4594 expr("x NOT IN (1)"),
4595 Expr::InList { negated: true, .. }
4596 ));
4597 match expr("NOT x IN (1)") {
4599 Expr::Unary {
4600 op: UnaryOp::Not,
4601 expr,
4602 } => assert!(matches!(*expr, Expr::InList { negated: false, .. })),
4603 other => panic!("expected NOT over InList, got {other:?}"),
4604 }
4605 }
4606
4607 #[test]
4608 fn between_and_does_not_eat_boolean_and() {
4609 match expr("a BETWEEN 1 AND 2 AND b") {
4611 Expr::Binary {
4612 op: BinaryOp::And,
4613 left,
4614 right,
4615 } => {
4616 assert!(matches!(*left, Expr::Between { negated: false, .. }));
4617 assert_eq!(
4618 *right,
4619 Expr::Column {
4620 table: None,
4621 name: "b".into()
4622 }
4623 );
4624 }
4625 other => panic!("expected AND(Between, b), got {other:?}"),
4626 }
4627 assert!(matches!(
4628 expr("a NOT BETWEEN 1 AND 10"),
4629 Expr::Between { negated: true, .. }
4630 ));
4631 }
4632
4633 #[test]
4634 fn parses_like_ilike_all_combinations() {
4635 assert!(matches!(
4636 expr("a LIKE 'x%'"),
4637 Expr::Like {
4638 negated: false,
4639 case_insensitive: false,
4640 ..
4641 }
4642 ));
4643 assert!(matches!(
4644 expr("a NOT LIKE 'x%'"),
4645 Expr::Like {
4646 negated: true,
4647 case_insensitive: false,
4648 ..
4649 }
4650 ));
4651 assert!(matches!(
4652 expr("a ILIKE 'x%'"),
4653 Expr::Like {
4654 negated: false,
4655 case_insensitive: true,
4656 ..
4657 }
4658 ));
4659 assert!(matches!(
4660 expr("a NOT ILIKE 'x%'"),
4661 Expr::Like {
4662 negated: true,
4663 case_insensitive: true,
4664 ..
4665 }
4666 ));
4667 }
4668
4669 #[test]
4670 fn parses_searched_and_simple_case() {
4671 match expr("CASE WHEN a > 0 THEN 'pos' ELSE 'neg' END") {
4672 Expr::Case {
4673 operand,
4674 whens,
4675 else_result,
4676 } => {
4677 assert!(operand.is_none());
4678 assert_eq!(whens.len(), 1);
4679 assert!(else_result.is_some());
4680 }
4681 other => panic!("expected searched CASE, got {other:?}"),
4682 }
4683 match expr("CASE a WHEN 1 THEN 'one' WHEN 2 THEN 'two' END") {
4684 Expr::Case {
4685 operand,
4686 whens,
4687 else_result,
4688 } => {
4689 assert!(operand.is_some());
4690 assert_eq!(whens.len(), 2);
4691 assert!(else_result.is_none());
4692 }
4693 other => panic!("expected simple CASE, got {other:?}"),
4694 }
4695 }
4696
4697 #[test]
4698 fn case_without_when_is_rejected() {
4699 assert!(parse("SELECT CASE END FROM t").is_err());
4700 }
4701
4702 #[test]
4703 fn parses_select_distinct() {
4704 assert!(only_select("SELECT DISTINCT a FROM t").distinct);
4705 assert!(!only_select("SELECT a FROM t").distinct);
4706 }
4707
4708 #[test]
4711 fn parses_cast_both_forms_to_the_same_node() {
4712 use crabka_pgtypes::ColumnType;
4713 let want = Expr::Cast {
4715 expr: Box::new(Expr::IntLiteral("1".into())),
4716 ty: ColumnType::Int8,
4717 };
4718 assert_eq!(expr("1::int8"), want);
4719 assert_eq!(expr("CAST(1 AS int8)"), want);
4720 assert!(matches!(
4722 expr("x::double precision"),
4723 Expr::Cast {
4724 ty: ColumnType::Float8,
4725 ..
4726 }
4727 ));
4728 assert!(matches!(
4729 expr("CAST(x AS integer)"),
4730 Expr::Cast {
4731 ty: ColumnType::Int4,
4732 ..
4733 }
4734 ));
4735 assert!(matches!(
4736 expr("x::text"),
4737 Expr::Cast {
4738 ty: ColumnType::Text,
4739 ..
4740 }
4741 ));
4742 }
4743
4744 #[test]
4745 fn cast_binds_tighter_than_unary_minus_and_arithmetic() {
4746 match expr("-2::int8") {
4748 Expr::Unary {
4749 op: UnaryOp::Neg,
4750 expr,
4751 } => {
4752 assert!(matches!(*expr, Expr::Cast { .. }), "got {expr:?}");
4753 }
4754 other => panic!("expected Neg(Cast), got {other:?}"),
4755 }
4756 match expr("1 + 2::int8") {
4758 Expr::Binary {
4759 op: BinaryOp::Add,
4760 right,
4761 ..
4762 } => {
4763 assert!(matches!(*right, Expr::Cast { .. }), "got {right:?}");
4764 }
4765 other => panic!("expected Add(1, Cast), got {other:?}"),
4766 }
4767 match expr("a::int4 + b") {
4769 Expr::Binary {
4770 op: BinaryOp::Add,
4771 left,
4772 ..
4773 } => {
4774 assert!(matches!(*left, Expr::Cast { .. }), "got {left:?}");
4775 }
4776 other => panic!("expected Add(Cast, b), got {other:?}"),
4777 }
4778 }
4779
4780 #[test]
4781 fn cast_is_left_associative_when_chained() {
4782 match expr("a::int4::text") {
4784 Expr::Cast { expr: inner, ty } => {
4785 assert_eq!(ty, crabka_pgtypes::ColumnType::Text);
4786 assert!(
4787 matches!(
4788 *inner,
4789 Expr::Cast {
4790 ty: crabka_pgtypes::ColumnType::Int4,
4791 ..
4792 }
4793 ),
4794 "got {inner:?}"
4795 );
4796 }
4797 other => panic!("expected outer text Cast over int4 Cast, got {other:?}"),
4798 }
4799 }
4800
4801 #[test]
4802 fn cast_to_unknown_type_is_a_parse_error() {
4803 assert!(parse("SELECT 1::widget").is_err());
4804 assert!(parse("SELECT CAST(1 AS widget)").is_err());
4805 assert!(parse("SELECT CAST(1 int4)").is_err());
4807 }
4808
4809 #[test]
4810 fn parses_uuid_type_in_create_table_and_cast() {
4811 use crate::ast::{Expr, Statement};
4812
4813 let stmts = parse("CREATE TABLE t (id uuid)").expect("parse create");
4814 let Statement::CreateTable { columns, .. } = &stmts[0] else {
4815 panic!("expected create table");
4816 };
4817 assert_eq!(columns[0].ty, crabka_pgtypes::ColumnType::Uuid);
4818 assert!(matches!(
4819 parse_expr_for_test("'550e8400-e29b-41d4-a716-446655440000'::uuid")
4820 .expect("parse cast"),
4821 Expr::Cast {
4822 ty: crabka_pgtypes::ColumnType::Uuid,
4823 ..
4824 }
4825 ));
4826 }
4827
4828 #[test]
4831 fn parses_typed_datetime_literals() {
4832 use crate::ast::Expr;
4833 assert!(matches!(
4834 parse_expr_for_test("DATE '2024-01-01'").expect("d"),
4835 Expr::Cast { .. }
4836 ));
4837 assert!(matches!(
4838 parse_expr_for_test("INTERVAL '1 day'").expect("iv"),
4839 Expr::Cast { .. }
4840 ));
4841 assert!(matches!(
4842 parse_expr_for_test("TIMESTAMP '2024-01-01 00:00:00'").expect("ts"),
4843 Expr::Cast { .. }
4844 ));
4845 assert!(matches!(
4846 parse_expr_for_test("TIMESTAMPTZ '2024-01-01 00:00:00+00'").expect("tstz"),
4847 Expr::Cast { .. }
4848 ));
4849 }
4850
4851 #[test]
4852 fn parses_extract_and_at_time_zone() {
4853 use crate::ast::Expr;
4854 assert!(matches!(
4855 parse_expr_for_test("extract(year from x)").expect("ex"),
4856 Expr::Func(_)
4857 ));
4858 let e = parse_expr_for_test("ts AT TIME ZONE 'UTC' = ts2").expect("attz");
4859 assert!(matches!(
4860 e,
4861 Expr::Binary {
4862 op: crate::ast::BinaryOp::Eq,
4863 ..
4864 }
4865 ));
4866 }
4867
4868 #[test]
4869 fn parses_multiword_type_in_create_and_cast() {
4870 use crate::ast::{Expr, Statement};
4871 let stmts = crate::parser::parse(
4872 "CREATE TABLE t (a timestamp with time zone, b time without time zone)",
4873 )
4874 .expect("ct");
4875 assert!(matches!(&stmts[0], Statement::CreateTable { .. }));
4876 assert!(matches!(
4877 parse_expr_for_test("x::timestamp with time zone").expect("c"),
4878 Expr::Cast {
4879 ty: crabka_pgtypes::ColumnType::Timestamptz,
4880 ..
4881 }
4882 ));
4883 }
4884
4885 #[test]
4888 fn parses_set_timezone_all_spellings() {
4889 use crate::ast::SetValue;
4890 assert_eq!(
4892 one("SET timezone = 'America/New_York'"),
4893 Statement::Set {
4894 local: false,
4895 name: "timezone".into(),
4896 value: SetValue::Value("America/New_York".into()),
4897 }
4898 );
4899 assert_eq!(
4900 one("SET timezone TO 'UTC'"),
4901 Statement::Set {
4902 local: false,
4903 name: "timezone".into(),
4904 value: SetValue::Value("UTC".into()),
4905 }
4906 );
4907 assert_eq!(
4909 one("SET TIME ZONE 'America/New_York'"),
4910 Statement::Set {
4911 local: false,
4912 name: "timezone".into(),
4913 value: SetValue::Value("America/New_York".into()),
4914 }
4915 );
4916 assert_eq!(
4918 one("SET timezone TO utc"),
4919 Statement::Set {
4920 local: false,
4921 name: "timezone".into(),
4922 value: SetValue::Value("utc".into()),
4923 }
4924 );
4925 assert_eq!(
4927 one("SET TimeZone = 'UTC'"),
4928 Statement::Set {
4929 local: false,
4930 name: "timezone".into(),
4931 value: SetValue::Value("UTC".into()),
4932 }
4933 );
4934 }
4935
4936 #[test]
4937 fn parses_set_local_flag_vs_local_value() {
4938 use crate::ast::SetValue;
4939 assert_eq!(
4941 one("SET LOCAL timezone = 'UTC'"),
4942 Statement::Set {
4943 local: true,
4944 name: "timezone".into(),
4945 value: SetValue::Value("UTC".into()),
4946 }
4947 );
4948 assert_eq!(
4949 one("SET LOCAL TIME ZONE 'America/New_York'"),
4950 Statement::Set {
4951 local: true,
4952 name: "timezone".into(),
4953 value: SetValue::Value("America/New_York".into()),
4954 }
4955 );
4956 assert_eq!(
4958 one("SET TIME ZONE LOCAL"),
4959 Statement::Set {
4960 local: false,
4961 name: "timezone".into(),
4962 value: SetValue::Default,
4963 }
4964 );
4965 assert_eq!(
4967 one("SET TIME ZONE DEFAULT"),
4968 Statement::Set {
4969 local: false,
4970 name: "timezone".into(),
4971 value: SetValue::Default,
4972 }
4973 );
4974 assert_eq!(
4976 one("SET timezone = DEFAULT"),
4977 Statement::Set {
4978 local: false,
4979 name: "timezone".into(),
4980 value: SetValue::Default,
4981 }
4982 );
4983 }
4984
4985 #[test]
4986 fn parses_show_and_reset() {
4987 use crate::ast::ResetTarget;
4988 assert_eq!(
4989 one("SHOW timezone"),
4990 Statement::Show {
4991 name: "timezone".into()
4992 }
4993 );
4994 assert_eq!(
4995 one("SHOW TIME ZONE"),
4996 Statement::Show {
4997 name: "timezone".into()
4998 }
4999 );
5000 assert_eq!(
5001 one("SHOW TimeZone"),
5002 Statement::Show {
5003 name: "timezone".into()
5004 }
5005 );
5006 assert_eq!(
5007 one("RESET timezone"),
5008 Statement::Reset {
5009 target: ResetTarget::Name("timezone".into())
5010 }
5011 );
5012 assert_eq!(
5013 one("RESET ALL"),
5014 Statement::Reset {
5015 target: ResetTarget::All
5016 }
5017 );
5018 assert_eq!(
5019 one("DISCARD ALL"),
5020 Statement::Set {
5021 local: false,
5022 name: "__discard_all".into(),
5023 value: crate::ast::SetValue::Default
5024 }
5025 );
5026 assert_eq!(
5027 one("SET TRANSACTION ISOLATION LEVEL READ COMMITTED"),
5028 Statement::Set {
5029 local: false,
5030 name: "__set_transaction".into(),
5031 value: crate::ast::SetValue::Value("read committed".into())
5032 }
5033 );
5034 }
5035
5036 #[test]
5037 fn parses_f1_guc_command_surface() {
5038 use crate::ast::{ResetTarget, SetValue};
5039
5040 for sql in [
5041 "SET SESSION application_name TO 'session-app'",
5042 "SET application_name = 'session-app'",
5043 ] {
5044 assert_eq!(
5045 one(sql),
5046 Statement::Set {
5047 local: false,
5048 name: "application_name".into(),
5049 value: SetValue::Value("session-app".into()),
5050 }
5051 );
5052 }
5053 assert_eq!(
5054 one("SET extra_float_digits = -15"),
5055 Statement::Set {
5056 local: false,
5057 name: "extra_float_digits".into(),
5058 value: SetValue::Value("-15".into()),
5059 }
5060 );
5061 assert_eq!(
5062 one("SET DateStyle TO ISO, MDY"),
5063 Statement::Set {
5064 local: false,
5065 name: "datestyle".into(),
5066 value: SetValue::Value("iso, mdy".into()),
5067 }
5068 );
5069 let statements = crate::parser::parse("SET DateStyle TO SQL DMY; SHOW DateStyle").unwrap();
5070 assert_eq!(
5071 statements[0],
5072 Statement::Set {
5073 local: false,
5074 name: "datestyle".into(),
5075 value: SetValue::Value("sql dmy".into()),
5076 }
5077 );
5078 assert_eq!(
5079 statements[1],
5080 Statement::Show {
5081 name: "datestyle".into(),
5082 }
5083 );
5084 assert_eq!(one("SHOW ALL"), Statement::Show { name: "all".into() });
5085 assert_eq!(
5086 one("RESET ALL"),
5087 Statement::Reset {
5088 target: ResetTarget::All,
5089 }
5090 );
5091 for unsupported in ["DISCARD PLANS", "DISCARD SEQUENCES", "DISCARD TEMP"] {
5092 let error = crate::parser::parse(unsupported).expect_err("unsupported DISCARD");
5093 assert!(error.to_string().contains("All"));
5094 }
5095 }
5096
5097 #[test]
5098 fn set_show_reset_accept_unknown_names_at_parse_time() {
5099 use crate::ast::SetValue;
5101 assert_eq!(
5102 one("SET datestyle = 'ISO, MDY'"),
5103 Statement::Set {
5104 local: false,
5105 name: "datestyle".into(),
5106 value: SetValue::Value("ISO, MDY".into()),
5107 }
5108 );
5109 assert_eq!(
5110 one("SHOW search_path"),
5111 Statement::Show {
5112 name: "search_path".into()
5113 }
5114 );
5115 }
5116
5117 #[test]
5118 fn parses_qualified_column() {
5119 use crate::ast::Expr;
5120 assert_eq!(
5121 expr("a.col"),
5122 Expr::Column {
5123 table: Some("a".into()),
5124 name: "col".into()
5125 }
5126 );
5127 assert_eq!(
5128 expr("col"),
5129 Expr::Column {
5130 table: None,
5131 name: "col".into()
5132 }
5133 );
5134 }
5135
5136 #[test]
5137 fn parses_limit_and_offset_either_order() {
5138 for sql in [
5139 "SELECT a FROM t ORDER BY a LIMIT 5 OFFSET 10",
5140 "SELECT a FROM t ORDER BY a OFFSET 10 LIMIT 5",
5141 ] {
5142 let q = only_query(sql);
5143 assert_eq!(q.limit, Some(5));
5144 assert_eq!(q.offset, Some(10));
5145 }
5146 }
5147
5148 #[test]
5149 fn parses_inner_join_on() {
5150 use crate::ast::{JoinConstraint, JoinKind, TableExpr};
5151 let s = only_select("SELECT a.x FROM a JOIN b ON a.id = b.id");
5152 assert_eq!(s.from.len(), 1);
5153 match &s.from[0] {
5154 TableExpr::Join {
5155 kind, constraint, ..
5156 } => {
5157 assert_eq!(*kind, JoinKind::Inner);
5158 assert!(matches!(constraint, JoinConstraint::On(_)));
5159 }
5160 other => panic!("expected Join, got {other:?}"),
5161 }
5162 }
5163
5164 #[test]
5165 fn parses_left_join_using_and_aliases_and_comma() {
5166 use crate::ast::{JoinConstraint, JoinKind, TableExpr};
5167 let s = only_select("SELECT * FROM a x LEFT OUTER JOIN b AS y USING (id), c");
5168 assert_eq!(s.from.len(), 2); match &s.from[0] {
5170 TableExpr::Join {
5171 kind,
5172 constraint,
5173 left,
5174 right,
5175 } => {
5176 assert_eq!(*kind, JoinKind::Left);
5177 assert_eq!(*constraint, JoinConstraint::Using(vec!["id".into()]));
5178 assert!(
5179 matches!(**left, TableExpr::Table { ref alias, .. } if alias.as_deref() == Some("x"))
5180 );
5181 assert!(
5182 matches!(**right, TableExpr::Table { ref alias, .. } if alias.as_deref() == Some("y"))
5183 );
5184 }
5185 other => panic!("expected Join, got {other:?}"),
5186 }
5187 assert!(matches!(&s.from[1], TableExpr::Table { name, alias: None } if name == "c"));
5188 }
5189
5190 #[test]
5191 fn parses_natural_and_cross_and_derived_and_multiway() {
5192 use crate::ast::TableExpr;
5193 assert!(matches!(
5194 one("SELECT * FROM a NATURAL JOIN b"),
5195 Statement::Query(_)
5196 ));
5197 assert!(matches!(
5198 one("SELECT * FROM a CROSS JOIN b"),
5199 Statement::Query(_)
5200 ));
5201 assert!(matches!(
5202 one("SELECT * FROM a JOIN b ON a.id=b.id JOIN c ON b.id=c.id"),
5203 Statement::Query(_)
5204 ));
5205 let s = only_select("SELECT d.n FROM (SELECT n FROM t) AS d");
5206 assert!(matches!(&s.from[0], TableExpr::Derived { alias, .. } if alias == "d"));
5207 }
5208
5209 #[test]
5210 fn parses_information_schema_qualified_tables() {
5211 let s = only_select(
5212 "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'",
5213 );
5214
5215 assert!(matches!(
5216 &s.from[..],
5217 [crate::ast::TableExpr::Table { name, alias: None }] if name == "information_schema.tables"
5218 ));
5219 }
5220
5221 #[test]
5222 fn parses_qualified_wildcard() {
5223 use crate::ast::SelectItem;
5224 let s = only_select("SELECT a.* FROM a JOIN b ON a.id=b.id");
5225 assert_eq!(s.projection[0], SelectItem::QualifiedWildcard("a".into()));
5226 }
5227
5228 #[test]
5229 fn derived_table_requires_alias() {
5230 assert!(parse("SELECT * FROM (SELECT 1)").is_err());
5231 }
5232
5233 #[test]
5236 fn parses_scalar_subquery_in_expression_position() {
5237 match expr("(SELECT 1)") {
5238 Expr::ScalarSubquery(s) => {
5239 let crate::ast::SetExpr::Query(crate::ast::QueryBody::Select(select)) = &s.body
5240 else {
5241 panic!("expected SELECT scalar subquery");
5242 };
5243 assert_eq!(select.projection.len(), 1);
5244 assert!(select.from.is_empty());
5245 }
5246 other => panic!("expected ScalarSubquery, got {other:?}"),
5247 }
5248 assert!(matches!(
5250 expr("1 + (SELECT a FROM t)"),
5251 Expr::Binary { right, .. } if matches!(*right, Expr::ScalarSubquery(_))
5252 ));
5253 assert!(matches!(expr("(1 + 2) * 3"), Expr::Binary { .. }));
5254 }
5255
5256 #[test]
5257 fn parses_exists_and_not_exists() {
5258 assert!(matches!(expr("EXISTS (SELECT 1 FROM t)"), Expr::Exists(_)));
5259 match expr("NOT EXISTS (SELECT 1 FROM t)") {
5260 Expr::Unary {
5261 op: UnaryOp::Not,
5262 expr,
5263 } => {
5264 assert!(matches!(*expr, Expr::Exists(_)));
5265 }
5266 other => panic!("expected NOT(EXISTS …), got {other:?}"),
5267 }
5268 }
5269
5270 #[test]
5271 fn parses_in_subquery_and_keeps_in_list_working() {
5272 assert!(matches!(expr("a IN (1, 2, 3)"), Expr::InList { .. }));
5273 match expr("a IN (SELECT id FROM t)") {
5274 Expr::InSubquery { negated, .. } => assert!(!negated),
5275 other => panic!("expected InSubquery, got {other:?}"),
5276 }
5277 match expr("a NOT IN (SELECT id FROM t)") {
5278 Expr::InSubquery { negated, .. } => assert!(negated),
5279 other => panic!("expected negated InSubquery, got {other:?}"),
5280 }
5281 }
5282
5283 #[test]
5284 fn parses_quantified_any_all_some() {
5285 match expr("a = ANY (SELECT id FROM t)") {
5286 Expr::Quantified {
5287 op: BinaryOp::Eq,
5288 all,
5289 ..
5290 } => assert!(!all),
5291 other => panic!("expected ANY, got {other:?}"),
5292 }
5293 match expr("a > ALL (SELECT v FROM t)") {
5294 Expr::Quantified {
5295 op: BinaryOp::Gt,
5296 all,
5297 ..
5298 } => assert!(all),
5299 other => panic!("expected ALL, got {other:?}"),
5300 }
5301 match expr("a <> SOME (SELECT v FROM t)") {
5302 Expr::Quantified {
5303 op: BinaryOp::Ne,
5304 all,
5305 ..
5306 } => assert!(!all),
5307 other => panic!("expected SOME(=ANY), got {other:?}"),
5308 }
5309 }
5310
5311 #[test]
5312 fn parses_with_in_nested_select_subquery_positions() {
5313 use crate::ast::{QueryBody, SetExpr, TableExpr};
5314
5315 let sel = only_select("SELECT * FROM (WITH c AS (SELECT 1 AS x) SELECT * FROM c) AS d");
5316 let TableExpr::Derived { subquery, .. } = &sel.from[0] else {
5317 panic!("expected derived table");
5318 };
5319 assert!(subquery.with.is_some());
5320 let SetExpr::Query(QueryBody::Select(_)) = &subquery.body else {
5321 panic!("expected SELECT derived table");
5322 };
5323
5324 match expr("(WITH c AS (SELECT 1 AS x) SELECT x FROM c)") {
5325 Expr::ScalarSubquery(s) => assert!(s.with.is_some()),
5326 other => panic!("expected scalar subquery, got {other:?}"),
5327 }
5328 match expr("EXISTS (WITH c AS (SELECT 1 AS x) SELECT x FROM c)") {
5329 Expr::Exists(s) => assert!(s.with.is_some()),
5330 other => panic!("expected EXISTS, got {other:?}"),
5331 }
5332 match expr("1 IN (WITH c AS (SELECT 1 AS x) SELECT x FROM c)") {
5333 Expr::InSubquery { subquery, .. } => assert!(subquery.with.is_some()),
5334 other => panic!("expected IN subquery, got {other:?}"),
5335 }
5336 match expr("1 = ANY (WITH c AS (SELECT 1 AS x) SELECT x FROM c)") {
5337 Expr::Quantified { subquery, .. } => assert!(subquery.with.is_some()),
5338 other => panic!("expected quantified subquery, got {other:?}"),
5339 }
5340 }
5341
5342 #[test]
5357 fn deeply_nested_parens_return_54001_not_a_crash() {
5358 let n = MAX_DEPTH * 4;
5359 let sql = format!("SELECT {}1{}", "(".repeat(n), ")".repeat(n));
5360 let err = parse(&sql).expect_err("too-deep parens must error, not crash");
5361 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5362 assert_eq!(err.message, "stack depth limit exceeded");
5363 }
5364
5365 #[test]
5367 fn deeply_nested_not_returns_54001() {
5368 let n = MAX_DEPTH * 4;
5369 let sql = format!("SELECT {}true", "NOT ".repeat(n));
5370 let err = parse(&sql).expect_err("too-deep NOT must error");
5371 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5372 }
5373
5374 #[test]
5376 fn deeply_nested_subqueries_return_54001() {
5377 let n = MAX_DEPTH * 2;
5378 let sql = format!("SELECT {}1{}", "(SELECT ".repeat(n), ")".repeat(n));
5379 let err = parse(&sql).expect_err("too-deep subqueries must error");
5380 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5381 }
5382
5383 #[test]
5387 fn long_left_assoc_chain_returns_54001() {
5388 let n = MAX_DEPTH * 4;
5389 let sql = format!("SELECT {}1", "1+".repeat(n));
5390 let err = parse(&sql).expect_err("too-long additive chain must error");
5391 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5392 }
5393
5394 #[test]
5402 fn at_limit_parens_parse_ok() {
5403 let n = MAX_DEPTH - 3;
5404 let sql = format!("SELECT {}1{}", "(".repeat(n), ")".repeat(n));
5405 parse(&sql).expect("a query nested at the limit must parse, not crash");
5406 }
5407
5408 #[test]
5413 fn parens_just_over_limit_returns_54001() {
5414 let n = MAX_DEPTH + 2;
5415 let sql = format!("SELECT {}1{}", "(".repeat(n), ")".repeat(n));
5416 assert_eq!(
5417 parse(&sql)
5418 .expect_err("just over the limit must error")
5419 .sqlstate(),
5420 "54001",
5421 );
5422 }
5423
5424 #[test]
5427 fn modest_nesting_parses_fine() {
5428 let sql = format!("SELECT {}1{}", "(".repeat(20), ")".repeat(20));
5429 parse(&sql).expect("modest nesting must parse");
5430 parse(&format!("SELECT {}1", "1+".repeat(20))).expect("modest chain must parse");
5432 }
5433
5434 #[test]
5439 fn long_union_chain_returns_54001() {
5440 let n = MAX_DEPTH * 4;
5441 let sql = format!("SELECT 1{}", " UNION ALL SELECT 1".repeat(n));
5442 let err = parse(&sql).expect_err("too-long UNION chain must error, not crash");
5443 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5444 }
5445
5446 #[test]
5450 fn deeply_nested_query_parens_return_54001() {
5451 let n = MAX_DEPTH * 4;
5452 let sql = format!("{}SELECT 1{}", "(".repeat(n), ")".repeat(n));
5453 let err = parse(&sql).expect_err("too-deep query parens must error, not crash");
5454 assert_eq!(err.sqlstate(), "54001", "got {err:?}");
5455 }
5456
5457 #[test]
5460 fn modest_union_chain_parses_fine() {
5461 let sql = format!("SELECT 1{}", " UNION ALL SELECT 1".repeat(20));
5462 parse(&sql).expect("modest UNION chain must parse");
5463 }
5464
5465 #[test]
5466 fn parses_standalone_values_query() {
5467 use crate::ast::{Expr, QueryBody, SetExpr};
5468 let q = only_query("VALUES (1, 'a'), (2, 'b') ORDER BY 1 LIMIT 1 OFFSET 1");
5469 let SetExpr::Query(QueryBody::Values(body)) = &q.body else {
5470 panic!("expected VALUES, got {q:?}")
5471 };
5472 assert_eq!(body.rows.len(), 2);
5473 assert_eq!(body.rows[0].len(), 2);
5474 assert!(matches!(body.rows[0][0], Expr::IntLiteral(_)));
5475 assert_eq!(q.order_by.len(), 1);
5476 assert_eq!(q.limit, Some(1));
5477 assert_eq!(q.offset, Some(1));
5478 }
5479
5480 #[test]
5481 fn parses_values_as_set_operation_branch() {
5482 use crate::ast::{QueryBody, SetExpr, SetOp};
5483 let q = only_query("VALUES (1) UNION ALL SELECT 2");
5484 let SetExpr::SetOp {
5485 op,
5486 all,
5487 left,
5488 right,
5489 } = &q.body
5490 else {
5491 panic!("expected set op body")
5492 };
5493 assert_eq!(*op, SetOp::Union);
5494 assert!(*all);
5495 assert!(matches!(
5496 left.as_ref(),
5497 SetExpr::Query(QueryBody::Values(_))
5498 ));
5499 assert!(matches!(
5500 right.as_ref(),
5501 SetExpr::Query(QueryBody::Select(_))
5502 ));
5503 }
5504
5505 #[test]
5506 fn parses_values_derived_table_with_column_aliases() {
5507 use crate::ast::{QueryBody, SetExpr, TableExpr};
5508 let sel = only_select("SELECT id, name FROM (VALUES (1, 'a')) AS v(id, name)");
5509 let TableExpr::Derived {
5510 subquery,
5511 alias,
5512 columns,
5513 } = &sel.from[0]
5514 else {
5515 panic!("expected derived table")
5516 };
5517 assert!(matches!(
5518 subquery.body,
5519 SetExpr::Query(QueryBody::Values(_))
5520 ));
5521 assert_eq!(alias, "v");
5522 assert_eq!(
5523 columns.as_ref().expect("column aliases"),
5524 &vec!["id".to_string(), "name".to_string()]
5525 );
5526 }
5527
5528 #[test]
5529 fn parses_select_derived_table_with_column_aliases() {
5530 use crate::ast::{QueryBody, SetExpr, TableExpr};
5531 let sel = only_select("SELECT n FROM (SELECT a FROM t) AS d(n)");
5532 let TableExpr::Derived {
5533 subquery,
5534 alias,
5535 columns,
5536 } = &sel.from[0]
5537 else {
5538 panic!("expected derived table")
5539 };
5540 assert!(matches!(
5541 subquery.body,
5542 SetExpr::Query(QueryBody::Select(_))
5543 ));
5544 assert_eq!(alias, "d");
5545 assert_eq!(
5546 columns.as_ref().expect("column aliases"),
5547 &vec!["n".to_string()]
5548 );
5549 }
5550
5551 #[test]
5552 fn values_rows_must_have_at_least_one_expr() {
5553 assert!(crate::parse("VALUES ()").is_err());
5554 }
5555
5556 #[test]
5557 fn parses_union_all_and_precedence() {
5558 use crate::ast::{SetExpr, SetOp};
5559 let q = only_query("SELECT 1 UNION SELECT 2 INTERSECT SELECT 3");
5561 let SetExpr::SetOp { op, all, right, .. } = &q.body else {
5562 panic!("expected top SetOp")
5563 };
5564 assert_eq!(*op, SetOp::Union);
5565 assert!(!*all);
5566 assert!(matches!(
5567 right.as_ref(),
5568 SetExpr::SetOp {
5569 op: SetOp::Intersect,
5570 ..
5571 }
5572 ));
5573
5574 let q = only_query("SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3");
5576 let SetExpr::SetOp { all, left, .. } = &q.body else {
5577 panic!()
5578 };
5579 assert!(*all);
5580 assert!(matches!(
5581 left.as_ref(),
5582 SetExpr::SetOp {
5583 op: SetOp::Union,
5584 ..
5585 }
5586 ));
5587 }
5588
5589 #[test]
5590 fn union_order_by_limit_bind_to_whole_query() {
5591 let q = only_query("SELECT 1 UNION SELECT 2 ORDER BY 1 LIMIT 5 OFFSET 1");
5592 assert_eq!(q.order_by.len(), 1);
5593 assert_eq!(q.limit, Some(5));
5594 assert_eq!(q.offset, Some(1));
5595 }
5596
5597 #[test]
5598 fn parenthesized_branch_keeps_its_own_order_limit() {
5599 use crate::ast::{QueryBody, SetExpr};
5600 let q = only_query("(SELECT 1 ORDER BY 1 LIMIT 1) UNION SELECT 2");
5601 let SetExpr::SetOp { left, .. } = &q.body else {
5602 panic!("expected top SetOp")
5603 };
5604 let SetExpr::Query(QueryBody::Select(b)) = left.as_ref() else {
5605 panic!("left branch is a SELECT leaf")
5606 };
5607 assert_eq!(b.limit, Some(1));
5608 assert_eq!(b.order_by.len(), 1);
5609 }
5610
5611 #[test]
5612 fn plain_select_is_unchanged() {
5613 let q = only_query("SELECT a FROM t ORDER BY a LIMIT 3");
5614 assert!(matches!(
5615 q.body,
5616 crate::ast::SetExpr::Query(crate::ast::QueryBody::Select(_))
5617 ));
5618 assert_eq!(q.limit, Some(3));
5619 assert_eq!(q.order_by.len(), 1);
5620 }
5621
5622 #[test]
5623 fn for_update_with_set_op_is_rejected() {
5624 assert!(crate::parse("SELECT 1 UNION SELECT 2 FOR UPDATE").is_err());
5625 }
5626
5627 #[test]
5628 fn parenthesized_tailed_query_exprs_can_be_set_op_branches() {
5629 use crate::ast::{QueryBody, SetExpr};
5630
5631 let q = only_query("(SELECT 1 UNION SELECT 2 ORDER BY 1) UNION SELECT 3");
5632 let SetExpr::SetOp { left, .. } = &q.body else {
5633 panic!("expected top SetOp")
5634 };
5635 let SetExpr::Query(QueryBody::Nested(inner)) = left.as_ref() else {
5636 panic!("left branch preserves the tailed set-op as a nested QueryExpr")
5637 };
5638 assert_eq!(inner.order_by.len(), 1);
5639 assert!(matches!(inner.body, SetExpr::SetOp { .. }));
5640
5641 let q = only_query("(VALUES (2), (1) ORDER BY 1 LIMIT 1) UNION SELECT 3");
5642 let SetExpr::SetOp { left, .. } = &q.body else {
5643 panic!("expected top SetOp")
5644 };
5645 let SetExpr::Query(QueryBody::Nested(inner)) = left.as_ref() else {
5646 panic!("left branch preserves the tailed VALUES as a nested QueryExpr")
5647 };
5648 assert_eq!(inner.order_by.len(), 1);
5649 assert_eq!(inner.limit, Some(1));
5650 assert!(matches!(inner.body, SetExpr::Query(QueryBody::Values(_))));
5651 }
5652
5653 #[test]
5654 fn union_distinct_is_the_default_form() {
5655 use crate::ast::SetExpr;
5656 let q = only_query("SELECT 1 UNION DISTINCT SELECT 2");
5659 let SetExpr::SetOp { all, .. } = &q.body else {
5660 panic!("expected SetOp")
5661 };
5662 assert!(!*all, "UNION DISTINCT is the dedup (all == false) form");
5663 }
5664
5665 #[test]
5666 fn parses_with_select_values_and_setop_bodies() {
5667 use crate::ast::{QueryBody, SetExpr};
5668
5669 let q = only_query("WITH a AS (SELECT 1 AS x), b(y) AS (VALUES (2)) SELECT x FROM a");
5670 let with = q.with.as_ref().expect("with clause");
5671 assert!(!with.recursive);
5672 assert_eq!(with.ctes.len(), 2);
5673 assert_eq!(with.ctes[0].name, "a");
5674 assert!(with.ctes[0].columns.is_none());
5675 assert_eq!(with.ctes[1].name, "b");
5676 assert_eq!(
5677 with.ctes[1].columns.as_deref(),
5678 Some(&["y".to_string()][..])
5679 );
5680 assert!(matches!(
5681 with.ctes[0].query.body,
5682 SetExpr::Query(QueryBody::Select(_))
5683 ));
5684 assert!(matches!(
5685 with.ctes[1].query.body,
5686 SetExpr::Query(QueryBody::Values(_))
5687 ));
5688
5689 let q = only_query("WITH u AS (SELECT 1 UNION SELECT 2) SELECT * FROM u");
5690 assert!(matches!(
5691 q.with.as_ref().expect("with").ctes[0].query.body,
5692 SetExpr::SetOp { .. }
5693 ));
5694 }
5695
5696 #[test]
5697 fn parses_with_recursive_and_rejects_duplicate_cte_names() {
5698 let q = only_query("WITH RECURSIVE r AS (SELECT 1) SELECT * FROM r");
5699 assert!(q.with.as_ref().expect("with").recursive);
5700
5701 let err = parse("WITH a AS (SELECT 1), a AS (SELECT 2) SELECT * FROM a")
5702 .expect_err("duplicate CTE names rejected during parse");
5703 assert_eq!(err.sqlstate(), "42712");
5704 }
5705
5706 #[test]
5707 fn duplicate_cte_names_follow_identifier_normalization() {
5708 let err = parse("WITH a AS (SELECT 1), A AS (SELECT 2) SELECT * FROM a")
5709 .expect_err("unquoted identifiers normalize before duplicate CTE check");
5710 assert_eq!(err.sqlstate(), "42712");
5711
5712 parse("WITH \"A\" AS (SELECT 1), a AS (SELECT 2) SELECT * FROM a")
5713 .expect("quoted case-distinct CTE names are parser-distinct");
5714 }
5715
5716 #[test]
5719 fn parses_create_server() {
5720 assert_eq!(
5721 one(
5722 "CREATE SERVER s FOREIGN DATA WRAPPER kafka_fdw OPTIONS (bootstrap 'h:9092', registry_url 'http://r')"
5723 ),
5724 Statement::CreateServer {
5725 name: "s".into(),
5726 wrapper: "kafka_fdw".into(),
5727 options: vec![
5728 ("bootstrap".into(), "h:9092".into()),
5729 ("registry_url".into(), "http://r".into()),
5730 ],
5731 }
5732 );
5733 }
5734
5735 #[test]
5736 fn parses_create_foreign_table() {
5737 match one(
5738 "CREATE FOREIGN TABLE orders (id int4, total numeric) SERVER s OPTIONS (topic 'orders', value_format 'avro')",
5739 ) {
5740 Statement::CreateForeignTable {
5741 name,
5742 columns,
5743 server,
5744 options,
5745 } => {
5746 assert_eq!(name, "orders");
5747 assert_eq!(server, "s");
5748 assert_eq!(columns.len(), 2);
5749 assert_eq!(options[0], ("topic".into(), "orders".into()));
5750 }
5751 other => panic!("got {other:?}"),
5752 }
5753 }
5754
5755 #[test]
5756 fn parses_import_foreign_schema_limit_to() {
5757 match one(
5758 "IMPORT FOREIGN SCHEMA kafka LIMIT TO (orders, payments) FROM SERVER s INTO public",
5759 ) {
5760 Statement::ImportForeignSchema {
5761 server,
5762 into_schema,
5763 selector,
5764 ..
5765 } => {
5766 assert_eq!(server, "s");
5767 assert_eq!(into_schema, "public");
5768 assert!(
5769 matches!(selector, crate::ast::ImportSelector::LimitTo(ref v) if v == &["orders", "payments"])
5770 );
5771 }
5772 other => panic!("got {other:?}"),
5773 }
5774 }
5775
5776 #[test]
5777 fn create_user_mapping_for_public() {
5778 match one(
5779 "CREATE USER MAPPING FOR PUBLIC SERVER s OPTIONS (sasl_mechanism 'SCRAM-SHA-256', username 'u', password 'p')",
5780 ) {
5781 Statement::CreateUserMapping { user, server, .. } => {
5782 assert_eq!(user, "public");
5783 assert_eq!(server, "s");
5784 }
5785 other => panic!("got {other:?}"),
5786 }
5787 }
5788
5789 #[test]
5790 fn parses_create_fdw() {
5791 assert_eq!(
5792 one("CREATE FOREIGN DATA WRAPPER kafka_fdw OPTIONS (protocol 'kafka')"),
5793 Statement::CreateFdw {
5794 name: "kafka_fdw".into(),
5795 options: vec![("protocol".into(), "kafka".into())],
5796 }
5797 );
5798 }
5799
5800 #[test]
5801 fn parses_drop_fdw() {
5802 assert_eq!(
5803 one("DROP FOREIGN DATA WRAPPER kafka_fdw"),
5804 Statement::DropFdw {
5805 name: "kafka_fdw".into(),
5806 if_exists: false,
5807 }
5808 );
5809 assert_eq!(
5810 one("DROP FOREIGN DATA WRAPPER IF EXISTS kafka_fdw"),
5811 Statement::DropFdw {
5812 name: "kafka_fdw".into(),
5813 if_exists: true,
5814 }
5815 );
5816 }
5817
5818 #[test]
5819 fn parses_drop_server() {
5820 assert_eq!(
5821 one("DROP SERVER s"),
5822 Statement::DropServer {
5823 name: "s".into(),
5824 if_exists: false,
5825 }
5826 );
5827 assert_eq!(
5828 one("DROP SERVER IF EXISTS s"),
5829 Statement::DropServer {
5830 name: "s".into(),
5831 if_exists: true,
5832 }
5833 );
5834 }
5835
5836 #[test]
5837 fn parses_alter_server() {
5838 assert_eq!(
5839 one("ALTER SERVER s OPTIONS (bootstrap 'b:9092')"),
5840 Statement::AlterServer {
5841 name: "s".into(),
5842 options: vec![("bootstrap".into(), "b:9092".into())],
5843 }
5844 );
5845 }
5846
5847 #[test]
5848 fn parses_create_user_mapping_for_current_user() {
5849 match one("CREATE USER MAPPING FOR CURRENT_USER SERVER s OPTIONS (username 'u')") {
5850 Statement::CreateUserMapping {
5851 user,
5852 server,
5853 options,
5854 } => {
5855 assert_eq!(user, "current_user");
5856 assert_eq!(server, "s");
5857 assert_eq!(options[0], ("username".into(), "u".into()));
5858 }
5859 other => panic!("got {other:?}"),
5860 }
5861 }
5862
5863 #[test]
5864 fn parses_alter_user_mapping() {
5865 match one("ALTER USER MAPPING FOR PUBLIC SERVER s OPTIONS (username 'newu')") {
5866 Statement::AlterUserMapping {
5867 user,
5868 server,
5869 options,
5870 } => {
5871 assert_eq!(user, "public");
5872 assert_eq!(server, "s");
5873 assert_eq!(options[0], ("username".into(), "newu".into()));
5874 }
5875 other => panic!("got {other:?}"),
5876 }
5877 }
5878
5879 #[test]
5880 fn parses_drop_user_mapping() {
5881 assert_eq!(
5882 one("DROP USER MAPPING FOR PUBLIC SERVER s"),
5883 Statement::DropUserMapping {
5884 user: "public".into(),
5885 server: "s".into(),
5886 if_exists: false,
5887 }
5888 );
5889 assert_eq!(
5890 one("DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER s"),
5891 Statement::DropUserMapping {
5892 user: "public".into(),
5893 server: "s".into(),
5894 if_exists: true,
5895 }
5896 );
5897 }
5898
5899 #[test]
5900 fn parses_drop_foreign_table() {
5901 assert_eq!(
5902 one("DROP FOREIGN TABLE orders"),
5903 Statement::DropForeignTable {
5904 name: "orders".into(),
5905 if_exists: false,
5906 }
5907 );
5908 assert_eq!(
5909 one("DROP FOREIGN TABLE IF EXISTS orders"),
5910 Statement::DropForeignTable {
5911 name: "orders".into(),
5912 if_exists: true,
5913 }
5914 );
5915 }
5916
5917 #[test]
5918 fn parses_import_foreign_schema_except() {
5919 match one("IMPORT FOREIGN SCHEMA remote EXCEPT (foo, bar) FROM SERVER s INTO myschema") {
5920 Statement::ImportForeignSchema {
5921 remote_schema,
5922 selector,
5923 server,
5924 into_schema,
5925 } => {
5926 assert_eq!(remote_schema, "remote");
5927 assert_eq!(server, "s");
5928 assert_eq!(into_schema, "myschema");
5929 assert!(
5930 matches!(selector, crate::ast::ImportSelector::Except(ref v) if v == &["foo", "bar"])
5931 );
5932 }
5933 other => panic!("got {other:?}"),
5934 }
5935 }
5936
5937 #[test]
5938 fn parses_import_foreign_schema_all() {
5939 match one("IMPORT FOREIGN SCHEMA kafka FROM SERVER s INTO public") {
5940 Statement::ImportForeignSchema {
5941 remote_schema,
5942 selector,
5943 server,
5944 into_schema,
5945 } => {
5946 assert_eq!(remote_schema, "kafka");
5947 assert_eq!(server, "s");
5948 assert_eq!(into_schema, "public");
5949 assert!(matches!(selector, crate::ast::ImportSelector::All));
5950 }
5951 other => panic!("got {other:?}"),
5952 }
5953 }
5954
5955 #[test]
5956 fn parses_create_server_no_options() {
5957 assert_eq!(
5958 one("CREATE SERVER s FOREIGN DATA WRAPPER w"),
5959 Statement::CreateServer {
5960 name: "s".into(),
5961 wrapper: "w".into(),
5962 options: vec![],
5963 }
5964 );
5965 }
5966
5967 #[test]
5968 fn parses_create_foreign_table_no_options() {
5969 match one("CREATE FOREIGN TABLE t (id int4) SERVER s") {
5970 Statement::CreateForeignTable {
5971 name,
5972 columns,
5973 server,
5974 options,
5975 } => {
5976 assert_eq!(name, "t");
5977 assert_eq!(server, "s");
5978 assert_eq!(columns.len(), 1);
5979 assert!(options.is_empty());
5980 }
5981 other => panic!("got {other:?}"),
5982 }
5983 }
5984
5985 #[test]
5988 fn drop_server_with_and_without_if_exists() {
5989 assert_eq!(
5992 one("DROP SERVER myserver"),
5993 Statement::DropServer {
5994 name: "myserver".into(),
5995 if_exists: false,
5996 }
5997 );
5998 assert_eq!(
5999 one("DROP SERVER IF EXISTS myserver"),
6000 Statement::DropServer {
6001 name: "myserver".into(),
6002 if_exists: true,
6003 }
6004 );
6005 }
6006
6007 #[test]
6008 fn drop_user_mapping_routes_correctly() {
6009 assert_eq!(
6011 one("DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER s"),
6012 Statement::DropUserMapping {
6013 user: "public".into(),
6014 server: "s".into(),
6015 if_exists: true,
6016 }
6017 );
6018 }
6019
6020 #[test]
6021 fn drop_foreign_table_routes_to_correct_fn() {
6022 assert_eq!(
6025 one("DROP FOREIGN TABLE IF EXISTS mytable"),
6026 Statement::DropForeignTable {
6027 name: "mytable".into(),
6028 if_exists: true,
6029 }
6030 );
6031 assert_eq!(
6033 one("DROP FOREIGN TABLE mytable"),
6034 Statement::DropForeignTable {
6035 name: "mytable".into(),
6036 if_exists: false,
6037 }
6038 );
6039 }
6040
6041 #[test]
6042 fn drop_fdw_routes_to_correct_fn() {
6043 assert_eq!(
6046 one("DROP FOREIGN DATA WRAPPER IF EXISTS myfdw"),
6047 Statement::DropFdw {
6048 name: "myfdw".into(),
6049 if_exists: true,
6050 }
6051 );
6052 assert_eq!(
6053 one("DROP FOREIGN DATA WRAPPER myfdw"),
6054 Statement::DropFdw {
6055 name: "myfdw".into(),
6056 if_exists: false,
6057 }
6058 );
6059 }
6060
6061 #[test]
6062 fn alter_non_server_is_error() {
6063 assert!(crate::parse("ALTER TABLE t ADD COLUMN x int4").is_err());
6066 }
6067
6068 #[test]
6069 fn alter_ident_guard_is_case_sensitive_to_alter() {
6070 assert!(crate::parse("alters SERVER s OPTIONS (a 'b')").is_err());
6072 }
6073
6074 #[test]
6075 fn eat_if_exists_requires_exists_after_if() {
6076 assert!(crate::parse("DROP SERVER IF notexists myserver").is_err());
6079 }
6080
6081 #[test]
6082 fn drop_if_without_exists_is_error() {
6083 let e = crate::parse("DROP SERVER IF NOTEXIST s")
6087 .expect_err("IF not followed by EXISTS must fail");
6088 assert_eq!(e.sqlstate(), "42601");
6089 }
6090
6091 #[test]
6092 fn drop_foreign_table_if_without_exists_is_error() {
6093 let e = crate::parse("DROP FOREIGN TABLE IF foo t")
6095 .expect_err("IF not followed by EXISTS must fail");
6096 assert_eq!(e.sqlstate(), "42601");
6097 }
6098
6099 #[test]
6101 fn drop_if_exists_valid_forms_still_parse() {
6102 crate::parse("DROP SERVER IF EXISTS s").expect("DROP SERVER IF EXISTS must parse");
6103 crate::parse("DROP SERVER s").expect("DROP SERVER without IF EXISTS must parse");
6104 crate::parse("DROP FOREIGN TABLE IF EXISTS t")
6105 .expect("DROP FOREIGN TABLE IF EXISTS must parse");
6106 crate::parse("DROP FOREIGN TABLE t")
6107 .expect("DROP FOREIGN TABLE without IF EXISTS must parse");
6108 }
6109
6110 #[test]
6111 fn copy_from_stdin_parses_supported_text_subset() {
6112 let stmts = crate::parse("COPY accounts (id, name) FROM STDIN WITH (FORMAT text)")
6113 .expect("COPY FROM STDIN parses");
6114 let [crate::ast::Statement::Set { name, value, .. }] = stmts.as_slice() else {
6115 panic!("expected COPY sentinel statement, got {stmts:?}");
6116 };
6117 assert_eq!(name, crate::ast::COPY_FROM_STDIN_SENTINEL);
6118 assert_eq!(
6119 value,
6120 &crate::ast::SetValue::Value("text\taccounts\tid,name".into())
6121 );
6122 }
6123
6124 #[test]
6125 fn copy_unsupported_paths_are_feature_not_supported() {
6126 for sql in [
6127 "COPY accounts TO STDOUT",
6128 "COPY accounts FROM '/tmp/accounts.tsv'",
6129 "COPY accounts FROM STDIN WITH (FORMAT binary)",
6130 "COPY accounts FROM STDIN WITH (DELIMITER ',')",
6131 ] {
6132 let err = crate::parse(sql).expect_err(sql);
6133 assert_eq!(err.sqlstate(), "0A000", "{sql}");
6134 }
6135 }
6136}
6137#[test]
6138fn explicit_compatibility_refusals_parse_to_typed_statements() {
6139 use crate::ast::{RefusalCommand, Statement};
6140
6141 let cases = [
6142 (
6143 "ALTER DATABASE postgres RENAME TO other",
6144 RefusalCommand::AlterDatabase,
6145 ),
6146 ("CREATE DATABASE other", RefusalCommand::CreateDatabase),
6147 ("DROP DATABASE other", RefusalCommand::DropDatabase),
6148 (
6149 "ALTER EXTENSION plpgsql UPDATE",
6150 RefusalCommand::AlterExtension,
6151 ),
6152 ("DROP EXTENSION plpgsql", RefusalCommand::DropExtension),
6153 (
6154 "PREPARE TRANSACTION 'xid-1'",
6155 RefusalCommand::PrepareTransaction,
6156 ),
6157 ("COMMIT PREPARED 'xid-1'", RefusalCommand::CommitPrepared),
6158 (
6159 "ROLLBACK PREPARED 'xid-1'",
6160 RefusalCommand::RollbackPrepared,
6161 ),
6162 ];
6163
6164 for (sql, command) in cases {
6165 let statements = parse(sql).unwrap_or_else(|error| panic!("{sql}: {error}"));
6166 assert_eq!(statements, vec![Statement::CompatibilityRefusal(command)]);
6167 }
6168}
6169
6170#[test]
6171fn fdw_alter_refusals_share_typed_metadata() {
6172 use crate::ast::RefusalCommand;
6173
6174 for (sql, expected) in [
6175 (
6176 "ALTER SERVER s OPTIONS (host 'localhost')",
6177 RefusalCommand::AlterServer,
6178 ),
6179 (
6180 "ALTER USER MAPPING FOR PUBLIC SERVER s OPTIONS (username 'u')",
6181 RefusalCommand::AlterUserMapping,
6182 ),
6183 ] {
6184 let statement = parse(sql).expect(sql).pop().expect("one statement");
6185 assert_eq!(statement.compatibility_refusal(), Some(expected));
6186 }
6187}
6188
6189#[test]
6190fn dispatch_emits_exact_query_and_table_family_identities() {
6191 use crate::{command::CommandIdentity, parse_with_command_identities};
6192
6193 for (sql, expected) in [
6194 ("SELECT 1", CommandIdentity::Select),
6195 (
6196 "WITH q AS (VALUES (1)) SELECT * FROM q",
6197 CommandIdentity::Select,
6198 ),
6199 ("VALUES (1)", CommandIdentity::Values),
6200 ("(VALUES (1))", CommandIdentity::Values),
6201 ("CREATE TABLE t (id int4)", CommandIdentity::CreateTable),
6202 ("ALTER TABLE t RENAME TO t2", CommandIdentity::AlterTable),
6203 ] {
6204 let parsed = parse_with_command_identities(sql).expect(sql);
6205 assert_eq!(parsed[0].1, expected, "{sql}");
6206 }
6207
6208 for (family, sql) in [
6209 ("CREATE TABLE AS", "CREATE TABLE t AS SELECT 1"),
6210 (
6211 "CREATE TABLE INHERITS",
6212 "CREATE TABLE t (id int4) INHERITS (parent)",
6213 ),
6214 (
6215 "CREATE TABLE PARTITION BY",
6216 "CREATE TABLE t (id int4) PARTITION BY HASH (id)",
6217 ),
6218 (
6219 "CREATE TABLE PARTITION OF",
6220 "CREATE TABLE t PARTITION OF parent DEFAULT",
6221 ),
6222 (
6223 "ALTER TABLE ATTACH PARTITION",
6224 "ALTER TABLE t ATTACH PARTITION p DEFAULT",
6225 ),
6226 (
6227 "ALTER TABLE DETACH PARTITION",
6228 "ALTER TABLE t DETACH PARTITION p",
6229 ),
6230 (
6231 "ALTER TABLE ENABLE ROW LEVEL SECURITY",
6232 "ALTER TABLE t ENABLE ROW LEVEL SECURITY",
6233 ),
6234 ("TABLE", "TABLE t"),
6235 ] {
6236 assert!(
6237 parse_with_command_identities(sql).is_err(),
6238 "unsupported {family} must reject instead of emitting its generic parent identity: {sql}"
6239 );
6240 }
6241}
6242
6243#[test]
6244fn multi_statement_dispatch_preserves_each_emitted_identity() {
6245 use crate::{command::CommandIdentity, parse_with_command_identities};
6246
6247 let parsed = parse_with_command_identities(
6248 "BEGIN; VALUES (1); CREATE USER alice; END; ALTER TABLE t RENAME TO t2",
6249 )
6250 .expect("mixed statements parse");
6251 assert_eq!(
6252 parsed
6253 .into_iter()
6254 .map(|(_, identity)| identity)
6255 .collect::<Vec<_>>(),
6256 vec![
6257 CommandIdentity::Begin,
6258 CommandIdentity::Values,
6259 CommandIdentity::CreateUser,
6260 CommandIdentity::End,
6261 CommandIdentity::AlterTable,
6262 ]
6263 );
6264}
6265
6266#[test]
6267fn shared_ast_fake_dispatch_cannot_exist_without_an_identity_argument() {
6268 use crate::{ast::Statement, command::CommandIdentity};
6269
6270 fn fake_branch(identity: CommandIdentity) -> ParsedStatement {
6271 emitted(identity, Ok(Statement::Commit)).expect("fake branch emits")
6272 }
6273
6274 assert_eq!(
6275 fake_branch(CommandIdentity::Commit).command_identity,
6276 CommandIdentity::Commit
6277 );
6278 assert_eq!(
6279 fake_branch(CommandIdentity::End).command_identity,
6280 CommandIdentity::End
6281 );
6282}
6283
6284#[test]
6285fn explicit_compatibility_refusals_reject_malformed_neighbors() {
6286 for sql in [
6287 "CREATE DATABASE",
6288 "DROP DATABASE db unexpected",
6289 "ALTER DATABASE db",
6290 "ALTER EXTENSION ext UPDATE unexpected",
6291 "DROP EXTENSION",
6292 "PREPARE TRANSACTION xid",
6293 "COMMIT PREPARED xid",
6294 "ROLLBACK PREPARED 'xid' unexpected",
6295 ] {
6296 assert!(parse(sql).is_err(), "malformed refusal form parsed: {sql}");
6297 }
6298}
6299
6300#[test]
6301fn every_non_goal_has_a_bounded_typed_refusal_probe() {
6302 use crate::ast::{NON_GOAL_REFUSALS, Statement};
6303
6304 assert_eq!(NON_GOAL_REFUSALS.len(), 40);
6305 for spec in NON_GOAL_REFUSALS {
6306 assert_eq!(
6307 parse(spec.representative_sql),
6308 Ok(vec![Statement::CompatibilityRefusal(spec.command)]),
6309 "{}",
6310 spec.command.command_name(),
6311 );
6312 assert!(
6313 parse(&format!("{} unexpected", spec.representative_sql)).is_err(),
6314 "{} accepted an arbitrary trailing token",
6315 spec.command.command_name(),
6316 );
6317 let variant = refusal_variant_sql(spec.representative_sql);
6318 assert_ne!(variant, spec.representative_sql);
6319 assert_eq!(
6320 parse(&variant),
6321 Ok(vec![Statement::CompatibilityRefusal(spec.command)]),
6322 "{} variant: {variant}",
6323 spec.command.command_name(),
6324 );
6325 }
6326}
6327
6328#[cfg(test)]
6329fn refusal_variant_sql(sql: &str) -> String {
6330 const PLACEHOLDERS: &[&str] = &[
6331 "conv",
6332 "conv2",
6333 "lang",
6334 "lang2",
6335 "postgres",
6336 "opc",
6337 "opc2",
6338 "opf",
6339 "opf2",
6340 "pub",
6341 "r",
6342 "r2",
6343 "sub",
6344 "ts",
6345 "ts2",
6346 "p",
6347 "p2",
6348 "t",
6349 "t2",
6350 "am",
6351 "handler_fn",
6352 "func",
6353 "int4eq",
6354 "f",
6355 ];
6356 let tokens = lex(sql).expect("representative lexes");
6357 let mut out = String::new();
6358 for (token, _) in tokens {
6359 if token == Token::Eof {
6360 break;
6361 }
6362 if !out.is_empty() {
6363 out.push(' ');
6364 }
6365 match token {
6366 Token::Ident(value) if PLACEHOLDERS.contains(&value.as_str()) => {
6367 out.push_str(&value);
6368 out.push_str("_variant");
6369 }
6370 Token::StringLit(_) => out.push_str("'variant'"),
6371 Token::IntLit(_) => out.push_str("42"),
6372 other => out.push_str(&token_sql(&other)),
6373 }
6374 }
6375 out
6376}
6377
6378#[cfg(test)]
6379fn token_sql(token: &Token) -> String {
6380 match token {
6381 Token::Ident(value) => value.clone(),
6382 Token::Keyword(keyword) => format!("{keyword:?}").to_ascii_lowercase(),
6383 Token::LParen => "(".into(),
6384 Token::RParen => ")".into(),
6385 Token::Comma => ",".into(),
6386 Token::Eq => "=".into(),
6387 Token::Lt => "<".into(),
6388 Token::Plus => "+".into(),
6389 other => panic!("unhandled representative token {other:?}"),
6390 }
6391}