1use std::error::Error;
6use std::fmt;
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8
9use fsqlite_ast::{
10 AlterTableAction, AlterTableStatement, Assignment, AssignmentTarget, AttachStatement,
11 BeginStatement, ColumnConstraint, ColumnConstraintKind, ColumnDef, CompoundOp, ConflictAction,
12 CreateIndexStatement, CreateTableBody, CreateTableStatement, CreateTriggerStatement,
13 CreateViewStatement, CreateVirtualTableStatement, Cte, CteMaterialized, DefaultValue,
14 Deferrable, DeferrableInitially, DeleteStatement, Distinctness, DropObjectType, DropStatement,
15 Expr, ForeignKeyAction, ForeignKeyActionType, ForeignKeyClause, ForeignKeyTrigger, FrameBound,
16 FrameExclude, FrameSpec, FrameType, FromClause, GeneratedStorage, IndexHint, IndexedColumn,
17 InsertSource, InsertStatement, JoinClause, JoinConstraint, JoinKind, JoinType, LimitClause,
18 Literal, NullsOrder, OrderingTerm, PragmaStatement, PragmaValue, QualifiedName,
19 QualifiedTableRef, ResultColumn, RollbackStatement, SelectBody, SelectCore, SelectStatement,
20 SortDirection, Span, Statement, TableConstraint, TableConstraintKind, TableOrSubquery,
21 TimeTravelClause, TimeTravelTarget, TransactionMode, TriggerEvent, TriggerTiming, TypeName,
22 UpdateStatement, UpsertAction, UpsertClause, UpsertTarget, VacuumStatement, WindowDef,
23 WindowSpec, WithClause,
24};
25
26use crate::lexer::Lexer;
27use crate::token::{Token, TokenKind};
28
29static FSQLITE_PARSE_STATEMENTS_TOTAL: AtomicU64 = AtomicU64::new(0);
35static FSQLITE_PARSE_TOKENS_TOTAL: AtomicU64 = AtomicU64::new(0);
37static FSQLITE_PARSE_ERRORS_TOTAL: AtomicU64 = AtomicU64::new(0);
39static FSQLITE_PARSE_METRICS_ENABLED: AtomicBool = AtomicBool::new(false);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
48pub struct ParseMetricsSnapshot {
49 pub fsqlite_parse_statements_total: u64,
51 pub fsqlite_parse_tokens_total: u64,
53 pub fsqlite_parse_errors_total: u64,
55}
56
57#[must_use]
59pub fn parse_metrics_snapshot() -> ParseMetricsSnapshot {
60 ParseMetricsSnapshot {
61 fsqlite_parse_statements_total: FSQLITE_PARSE_STATEMENTS_TOTAL.load(Ordering::Relaxed),
62 fsqlite_parse_tokens_total: FSQLITE_PARSE_TOKENS_TOTAL.load(Ordering::Relaxed),
63 fsqlite_parse_errors_total: FSQLITE_PARSE_ERRORS_TOTAL.load(Ordering::Relaxed),
64 }
65}
66
67pub fn set_parse_metrics_enabled(enabled: bool) {
69 FSQLITE_PARSE_METRICS_ENABLED.store(enabled, Ordering::Relaxed);
70}
71
72#[must_use]
74pub fn parse_metrics_enabled() -> bool {
75 FSQLITE_PARSE_METRICS_ENABLED.load(Ordering::Relaxed)
76}
77
78pub fn reset_parse_metrics() {
80 FSQLITE_PARSE_STATEMENTS_TOTAL.store(0, Ordering::Relaxed);
81 FSQLITE_PARSE_TOKENS_TOTAL.store(0, Ordering::Relaxed);
82 FSQLITE_PARSE_ERRORS_TOTAL.store(0, Ordering::Relaxed);
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct ParseError {
91 pub message: String,
92 pub span: Span,
93 pub line: u32,
94 pub col: u32,
95}
96
97impl ParseError {
98 #[must_use]
99 pub(crate) fn at(message: impl Into<String>, token: Option<&Token>) -> Self {
100 if let Some(t) = token {
101 Self {
102 message: message.into(),
103 span: t.span,
104 line: t.line,
105 col: t.col,
106 }
107 } else {
108 Self {
109 message: message.into(),
110 span: Span::ZERO,
111 line: 0,
112 col: 0,
113 }
114 }
115 }
116}
117
118impl fmt::Display for ParseError {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 write!(f, "{}:{}: {}", self.line, self.col, self.message)
121 }
122}
123
124impl Error for ParseError {}
125
126#[derive(Debug, Default)]
132pub struct StatementParseScratch {
133 tokens: Vec<Token>,
134 errors: Vec<ParseError>,
135 identifier_interner: crate::lexer::IdentifierInterner,
136}
137
138impl StatementParseScratch {
139 pub fn reset(&mut self) {
141 self.tokens.clear();
142 self.errors.clear();
143 self.identifier_interner.reset();
144 }
145
146 #[must_use]
147 pub fn token_capacity(&self) -> usize {
148 self.tokens.capacity()
149 }
150
151 #[must_use]
152 pub fn error_capacity(&self) -> usize {
153 self.errors.capacity()
154 }
155
156 #[must_use]
157 pub fn retained_bytes(&self) -> usize {
158 self.tokens
159 .capacity()
160 .saturating_mul(std::mem::size_of::<Token>())
161 .saturating_add(
162 self.errors
163 .capacity()
164 .saturating_mul(std::mem::size_of::<ParseError>()),
165 )
166 .saturating_add(self.identifier_interner.retained_bytes())
167 }
168
169 #[cfg(test)]
170 fn identifier_interner_is_empty(&self) -> bool {
171 self.identifier_interner.is_empty()
172 }
173
174 #[cfg(test)]
175 fn identifier_interner_len(&self) -> usize {
176 self.identifier_interner.len()
177 }
178}
179
180pub const MAX_PARSE_DEPTH: u32 = 1000;
190
191pub struct Parser {
192 pub(crate) tokens: Vec<Token>,
193 pub(crate) pos: usize,
194 pub(crate) errors: Vec<ParseError>,
195 pub(crate) depth: u32,
196}
197
198impl Parser {
199 #[must_use]
200 pub fn new(tokens: Vec<Token>) -> Self {
201 Self {
202 tokens,
203 pos: 0,
204 errors: Vec::new(),
205 depth: 0,
206 }
207 }
208
209 pub(crate) fn enter_recursion(&mut self) -> Result<(), ParseError> {
210 if self.depth >= MAX_PARSE_DEPTH {
211 return Err(self.err_msg(format!(
212 "expression tree is too deep (maximum depth {MAX_PARSE_DEPTH})"
213 )));
214 }
215 self.depth += 1;
216 Ok(())
217 }
218
219 pub(crate) fn leave_recursion(&mut self) {
220 self.depth = self.depth.saturating_sub(1);
221 }
222
223 pub(crate) fn with_recursion_guard<T>(
224 &mut self,
225 f: impl FnOnce(&mut Self) -> Result<T, ParseError>,
226 ) -> Result<T, ParseError> {
227 self.enter_recursion()?;
228 let result = f(self);
229 self.leave_recursion();
230 result
231 }
232
233 #[must_use]
234 pub fn from_sql(sql: &str) -> Self {
235 Self::new(Lexer::tokenize(sql))
236 }
237
238 pub fn parse_all(&mut self) -> (Vec<Statement>, Vec<ParseError>) {
239 let parse_debug_enabled = tracing::enabled!(target: "fsqlite.parse", tracing::Level::DEBUG);
240 let collect_parse_metrics = parse_metrics_enabled();
241 if collect_parse_metrics {
242 let token_count = u64::try_from(self.tokens.len()).unwrap_or(u64::MAX);
243 FSQLITE_PARSE_TOKENS_TOTAL.fetch_add(token_count, Ordering::Relaxed);
244 }
245 let span = parse_debug_enabled.then(|| {
246 tracing::debug_span!(
247 target: "fsqlite.parse",
248 "parse",
249 ast_node_count = tracing::field::Empty,
250 parse_errors = tracing::field::Empty,
251 )
252 });
253 let _guard = span.as_ref().map(|span| span.enter());
254
255 let mut stmts = Vec::new();
256 while !self.at_eof() {
257 if self.check(&TokenKind::Semicolon) {
258 self.advance();
259 continue;
260 }
261 match self.parse_statement() {
262 Ok(s) => {
263 if collect_parse_metrics {
264 FSQLITE_PARSE_STATEMENTS_TOTAL.fetch_add(1, Ordering::Relaxed);
265 }
266 stmts.push(s);
267 let _ = self.eat(&TokenKind::Semicolon);
268 }
269 Err(e) => {
270 if collect_parse_metrics {
271 FSQLITE_PARSE_ERRORS_TOTAL.fetch_add(1, Ordering::Relaxed);
272 }
273 tracing::warn!(
274 target: "fsqlite.parse",
275 error = %e,
276 "parse recovery: skipping malformed statement"
277 );
278 self.errors.push(e);
279 self.synchronize();
280 }
281 }
282 }
283
284 let errors = std::mem::take(&mut self.errors);
285 if let Some(span) = span.as_ref() {
286 span.record("ast_node_count", stmts.len() as u64);
287 span.record("parse_errors", errors.len() as u64);
288 }
289
290 (stmts, errors)
291 }
292
293 pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
294 self.parse_statement_inner()
295 }
296
297 #[must_use]
298 pub fn errors(&self) -> &[ParseError] {
299 &self.errors
300 }
301
302 pub(crate) fn peek(&self) -> &TokenKind {
307 self.current().map_or(&TokenKind::Eof, |t| &t.kind)
308 }
309
310 pub(crate) fn current(&self) -> Option<&Token> {
311 self.tokens.get(self.pos)
312 }
313
314 pub(crate) fn peek_nth(&self, n: usize) -> &TokenKind {
315 self.tokens
316 .get(self.pos + n)
317 .map_or(&TokenKind::Eof, |t| &t.kind)
318 }
319
320 pub(crate) fn at_eof(&self) -> bool {
321 matches!(self.peek(), TokenKind::Eof)
322 }
323
324 pub(crate) fn advance(&mut self) -> Option<&Token> {
325 let t = self.tokens.get(self.pos);
326 if self.pos < self.tokens.len().saturating_sub(1) {
327 self.pos += 1;
328 }
329 t
330 }
331
332 pub(crate) fn check(&self, kind: &TokenKind) -> bool {
333 std::mem::discriminant(self.peek()) == std::mem::discriminant(kind)
334 }
335
336 pub(crate) fn check_kw(&self, kw: &TokenKind) -> bool {
337 self.peek() == kw
338 }
339
340 pub(crate) fn eat(&mut self, kind: &TokenKind) -> bool {
341 if self.check(kind) {
342 self.advance();
343 true
344 } else {
345 false
346 }
347 }
348
349 pub(crate) fn eat_kw(&mut self, kw: &TokenKind) -> bool {
350 if self.peek() == kw {
351 self.advance();
352 true
353 } else {
354 false
355 }
356 }
357
358 pub(crate) fn expect_kw(&mut self, kw: &TokenKind) -> Result<Span, ParseError> {
359 if self.peek() == kw {
360 let sp = self.current_span();
361 self.advance();
362 Ok(sp)
363 } else {
364 Err(self.err_expected(&format!("{kw:?}")))
365 }
366 }
367
368 pub(crate) fn expect_token(&mut self, kind: &TokenKind) -> Result<Span, ParseError> {
369 if self.check(kind) {
370 let sp = self.current_span();
371 self.advance();
372 Ok(sp)
373 } else {
374 Err(self.err_expected(&format!("{kind:?}")))
375 }
376 }
377
378 pub(crate) fn current_span(&self) -> Span {
379 self.current().map_or(Span::ZERO, |t| t.span)
380 }
381
382 pub(crate) fn err_expected(&self, what: &str) -> ParseError {
383 ParseError::at(format!("expected {what}"), self.current())
384 }
385
386 pub(crate) fn err_msg(&self, msg: impl Into<String>) -> ParseError {
387 ParseError::at(msg, self.current())
388 }
389
390 fn synchronize(&mut self) {
391 loop {
392 match self.peek() {
393 TokenKind::Eof => return,
394 TokenKind::Semicolon => {
395 self.advance();
396 return;
397 }
398 k if k.is_statement_start() => return,
399 _ => {
400 self.advance();
401 }
402 }
403 }
404 }
405
406 fn recover_trigger_body_after_error(&mut self) {
407 let mut case_depth = 0_usize;
408
409 loop {
410 match self.peek() {
411 TokenKind::Eof => return,
412 TokenKind::KwCase => {
413 case_depth = case_depth.saturating_add(1);
414 self.advance();
415 }
416 TokenKind::KwEnd if case_depth > 0 => {
417 case_depth = case_depth.saturating_sub(1);
418 self.advance();
419 }
420 TokenKind::KwEnd => {
425 self.advance();
426 let _ = self.eat(&TokenKind::Semicolon);
427 return;
428 }
429 _ => {
430 self.advance();
431 }
432 }
433 }
434 }
435
436 pub(crate) fn parse_identifier(&mut self) -> Result<String, ParseError> {
441 match self.peek().clone() {
442 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
443 self.advance();
444 Ok(s.to_string())
445 }
446 TokenKind::String(s) => {
447 self.advance();
448 Ok(s)
449 }
450 ref k if is_nonreserved_kw(k) => {
451 let s = kw_to_str(k);
452 self.advance();
453 Ok(s)
454 }
455 _ => Err(self.err_expected("identifier")),
456 }
457 }
458
459 pub(crate) fn parse_qualified_name(&mut self) -> Result<QualifiedName, ParseError> {
460 let first = self.parse_identifier()?;
461 if self.eat(&TokenKind::Dot) {
462 let second = self.parse_identifier()?;
463 Ok(QualifiedName::qualified(first, second))
464 } else {
465 Ok(QualifiedName::bare(first))
466 }
467 }
468
469 fn parse_qualified_table_ref(&mut self) -> Result<QualifiedTableRef, ParseError> {
470 let name = self.parse_qualified_name()?;
471 let alias = self.try_alias()?;
472 let index_hint = self.parse_index_hint()?;
473 let time_travel = self.parse_time_travel_clause()?;
474 Ok(QualifiedTableRef {
475 name,
476 alias,
477 index_hint,
478 time_travel,
479 })
480 }
481
482 fn try_alias(&mut self) -> Result<Option<String>, ParseError> {
483 if self.eat_kw(&TokenKind::KwAs) {
484 return Ok(Some(self.parse_identifier()?));
485 }
486 match self.peek() {
489 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
490 return Ok(Some(self.parse_identifier()?));
491 }
492 k if is_nonreserved_kw(k) && !is_alias_terminator_kw(k) => {
493 return Ok(Some(self.parse_identifier()?));
494 }
495 _ => {}
496 }
497 Ok(None)
498 }
499
500 fn parse_index_hint(&mut self) -> Result<Option<IndexHint>, ParseError> {
501 if self.eat_kw(&TokenKind::KwIndexed) {
502 self.expect_kw(&TokenKind::KwBy)?;
503 Ok(Some(IndexHint::IndexedBy(self.parse_identifier()?)))
504 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwIndexed {
505 self.advance();
506 self.advance();
507 Ok(Some(IndexHint::NotIndexed))
508 } else {
509 Ok(None)
510 }
511 }
512
513 fn parse_time_travel_clause(&mut self) -> Result<Option<TimeTravelClause>, ParseError> {
521 if !self.check_kw(&TokenKind::KwFor) {
522 return Ok(None);
523 }
524 if !matches!(self.peek_nth(1), TokenKind::Id(s) if s.eq_ignore_ascii_case("SYSTEM_TIME")) {
526 return Ok(None);
527 }
528 self.advance(); self.advance(); self.expect_kw(&TokenKind::KwAs)?;
531 self.expect_kw(&TokenKind::KwOf)?;
532
533 let target = if self.eat_kw(&TokenKind::KwCommitseq) {
534 match self.peek().clone() {
535 TokenKind::Integer(n) if n >= 0 => {
536 self.advance();
537 TimeTravelTarget::CommitSequence(n as u64)
538 }
539 TokenKind::OversizedInt(s) => {
540 if let Ok(n) = s.parse::<u64>() {
541 self.advance();
542 TimeTravelTarget::CommitSequence(n)
543 } else {
544 return Err(self.err_expected("non-negative integer after COMMITSEQ"));
545 }
546 }
547 _ => return Err(self.err_expected("non-negative integer after COMMITSEQ")),
548 }
549 } else {
550 match self.peek().clone() {
551 TokenKind::String(s) => {
552 self.advance();
553 TimeTravelTarget::Timestamp(s)
554 }
555 _ => {
556 return Err(self.err_expected(
557 "COMMITSEQ <n> or '<timestamp>' after FOR SYSTEM_TIME AS OF",
558 ));
559 }
560 }
561 };
562
563 Ok(Some(TimeTravelClause { target }))
564 }
565
566 pub(crate) fn parse_comma_sep<T>(
567 &mut self,
568 f: fn(&mut Self) -> Result<T, ParseError>,
569 ) -> Result<Vec<T>, ParseError> {
570 let mut v = Vec::with_capacity(4);
571 v.push(f(self)?);
572 while self.eat(&TokenKind::Comma) {
573 v.push(f(self)?);
574 }
575 Ok(v)
576 }
577
578 fn parse_statement_inner(&mut self) -> Result<Statement, ParseError> {
583 self.with_recursion_guard(|parser| match parser.peek().clone() {
584 TokenKind::KwSelect | TokenKind::KwValues => {
585 Ok(Statement::Select(parser.parse_select_stmt(None)?))
586 }
587 TokenKind::KwWith => parser.parse_with_leading(),
588 TokenKind::KwInsert | TokenKind::KwReplace => parser.parse_insert_stmt(None),
589 TokenKind::KwUpdate => parser.parse_update_stmt(None),
590 TokenKind::KwDelete => parser.parse_delete_stmt(None),
591 TokenKind::KwCreate => parser.parse_create(),
592 TokenKind::KwDrop => parser.parse_drop(),
593 TokenKind::KwAlter => parser.parse_alter(),
594 TokenKind::KwBegin => parser.parse_begin(),
595 TokenKind::KwCommit | TokenKind::KwEnd => {
596 parser.advance();
597 let _ = parser.eat_kw(&TokenKind::KwTransaction);
598 Ok(Statement::Commit)
599 }
600 TokenKind::KwRollback => parser.parse_rollback(),
601 TokenKind::KwSavepoint => {
602 parser.advance();
603 Ok(Statement::Savepoint(parser.parse_identifier()?))
604 }
605 TokenKind::KwRelease => {
606 parser.advance();
607 let _ = parser.eat_kw(&TokenKind::KwSavepoint);
608 Ok(Statement::Release(parser.parse_identifier()?))
609 }
610 TokenKind::KwAttach => parser.parse_attach(),
611 TokenKind::KwDetach => {
612 parser.advance();
613 let _ = parser.eat_kw(&TokenKind::KwDatabase);
614 Ok(Statement::Detach(parser.parse_identifier()?))
615 }
616 TokenKind::KwPragma => parser.parse_pragma(),
617 TokenKind::KwVacuum => parser.parse_vacuum(),
618 TokenKind::KwReindex => {
619 parser.advance();
620 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
621 Some(parser.parse_qualified_name()?)
622 } else {
623 None
624 };
625 Ok(Statement::Reindex(name))
626 }
627 TokenKind::KwAnalyze => {
628 parser.advance();
629 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
630 Some(parser.parse_qualified_name()?)
631 } else {
632 None
633 };
634 Ok(Statement::Analyze(name))
635 }
636 TokenKind::KwExplain => parser.parse_explain(),
637 _ => Err(parser.err_msg("unexpected token at start of statement")),
638 })
639 }
640
641 fn parse_with_leading(&mut self) -> Result<Statement, ParseError> {
646 let with = self.parse_with_clause()?;
647 match self.peek() {
648 TokenKind::KwSelect | TokenKind::KwValues => {
649 Ok(Statement::Select(self.parse_select_stmt(Some(with))?))
650 }
651 TokenKind::KwInsert | TokenKind::KwReplace => self.parse_insert_stmt(Some(with)),
652 TokenKind::KwUpdate => self.parse_update_stmt(Some(with)),
653 TokenKind::KwDelete => self.parse_delete_stmt(Some(with)),
654 _ => Err(self.err_expected("SELECT, INSERT, UPDATE, or DELETE after WITH")),
655 }
656 }
657
658 pub(crate) fn parse_with_clause(&mut self) -> Result<WithClause, ParseError> {
659 self.expect_kw(&TokenKind::KwWith)?;
660 let recursive = self.eat_kw(&TokenKind::KwRecursive);
661 let ctes = self.parse_comma_sep(Self::parse_cte)?;
662 Ok(WithClause { recursive, ctes })
663 }
664
665 fn parse_cte(&mut self) -> Result<Cte, ParseError> {
666 let name = self.parse_identifier()?;
667 let columns = if self.eat(&TokenKind::LeftParen) {
668 let cols = self.parse_comma_sep(Self::parse_identifier)?;
669 self.expect_token(&TokenKind::RightParen)?;
670 cols
671 } else {
672 vec![]
673 };
674 self.expect_kw(&TokenKind::KwAs)?;
676 let materialized = if self.check_kw(&TokenKind::KwNot) {
677 self.advance();
678 self.expect_kw(&TokenKind::KwMaterialized)?;
679 Some(CteMaterialized::NotMaterialized)
680 } else if self.eat_kw(&TokenKind::KwMaterialized) {
681 Some(CteMaterialized::Materialized)
682 } else {
683 None
684 };
685 self.expect_token(&TokenKind::LeftParen)?;
686 let query = self.parse_select_stmt(None)?;
687 self.expect_token(&TokenKind::RightParen)?;
688 Ok(Cte {
689 name,
690 columns,
691 materialized,
692 query,
693 })
694 }
695
696 pub(crate) fn parse_select_stmt(
701 &mut self,
702 with: Option<WithClause>,
703 ) -> Result<SelectStatement, ParseError> {
704 self.with_recursion_guard(|parser| parser.parse_select_stmt_inner(with))
705 }
706
707 fn parse_select_stmt_inner(
708 &mut self,
709 with: Option<WithClause>,
710 ) -> Result<SelectStatement, ParseError> {
711 let body = self.parse_select_body()?;
712 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
713 self.expect_kw(&TokenKind::KwBy)?;
714 self.parse_comma_sep(Self::parse_ordering_term)?
715 } else {
716 vec![]
717 };
718 let limit = self.parse_limit()?;
719 Ok(SelectStatement {
720 with,
721 body,
722 order_by,
723 limit,
724 })
725 }
726
727 fn parse_select_body(&mut self) -> Result<SelectBody, ParseError> {
728 let select = self.parse_select_core()?;
729 let mut compounds = Vec::new();
730 loop {
731 let op = if self.eat_kw(&TokenKind::KwUnion) {
732 if self.eat_kw(&TokenKind::KwAll) {
733 CompoundOp::UnionAll
734 } else {
735 CompoundOp::Union
736 }
737 } else if self.eat_kw(&TokenKind::KwIntersect) {
738 CompoundOp::Intersect
739 } else if self.eat_kw(&TokenKind::KwExcept) {
740 CompoundOp::Except
741 } else {
742 break;
743 };
744 compounds.push((op, self.parse_select_core()?));
745 }
746 Ok(SelectBody { select, compounds })
747 }
748
749 fn parse_select_core(&mut self) -> Result<SelectCore, ParseError> {
750 if self.eat_kw(&TokenKind::KwValues) {
751 return self.parse_values_core();
752 }
753 self.expect_kw(&TokenKind::KwSelect)?;
754 let distinct = if self.eat_kw(&TokenKind::KwDistinct) {
755 Distinctness::Distinct
756 } else {
757 let _ = self.eat_kw(&TokenKind::KwAll);
758 Distinctness::All
759 };
760 let columns = self.parse_comma_sep(Self::parse_result_column)?;
761 let from = if self.eat_kw(&TokenKind::KwFrom) {
762 Some(self.parse_from_clause()?)
763 } else {
764 None
765 };
766 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
767 Some(Box::new(self.parse_expr()?))
768 } else {
769 None
770 };
771 let group_by = if self.eat_kw(&TokenKind::KwGroup) {
772 self.expect_kw(&TokenKind::KwBy)?;
773 self.parse_comma_sep(Self::parse_expr)?
774 } else {
775 vec![]
776 };
777 let having = if self.eat_kw(&TokenKind::KwHaving) {
778 Some(Box::new(self.parse_expr()?))
779 } else {
780 None
781 };
782 let windows = if self.eat_kw(&TokenKind::KwWindow) {
783 self.parse_comma_sep(Self::parse_window_def)?
784 } else {
785 vec![]
786 };
787 Ok(SelectCore::Select {
788 distinct,
789 columns,
790 from,
791 where_clause,
792 group_by,
793 having,
794 windows,
795 })
796 }
797
798 fn parse_values_core(&mut self) -> Result<SelectCore, ParseError> {
799 let mut rows = Vec::new();
800 loop {
801 self.expect_token(&TokenKind::LeftParen)?;
802 let row = self.parse_comma_sep(Self::parse_expr)?;
803 self.expect_token(&TokenKind::RightParen)?;
804 rows.push(row);
805 if !self.eat(&TokenKind::Comma) {
806 break;
807 }
808 }
809 Ok(SelectCore::Values(rows))
810 }
811
812 fn parse_result_column(&mut self) -> Result<ResultColumn, ParseError> {
813 if self.eat(&TokenKind::Star) {
814 return Ok(ResultColumn::Star);
815 }
816 if matches!(self.peek(), TokenKind::Id(_) | TokenKind::QuotedId(_, _))
817 && self.peek_nth(1) == &TokenKind::Dot
818 {
819 if self.peek_nth(2) == &TokenKind::Star {
820 let table = self.parse_identifier()?;
821 self.expect_token(&TokenKind::Dot)?;
822 self.expect_token(&TokenKind::Star)?;
823 return Ok(ResultColumn::TableStar(QualifiedName::bare(table)));
824 }
825 if matches!(
826 self.peek_nth(2),
827 TokenKind::Id(_) | TokenKind::QuotedId(_, _)
828 ) && self.peek_nth(3) == &TokenKind::Dot
829 && self.peek_nth(4) == &TokenKind::Star
830 {
831 let schema = self.parse_identifier()?;
832 self.expect_token(&TokenKind::Dot)?;
833 let table = self.parse_identifier()?;
834 self.expect_token(&TokenKind::Dot)?;
835 self.expect_token(&TokenKind::Star)?;
836 return Ok(ResultColumn::TableStar(QualifiedName::qualified(
837 schema, table,
838 )));
839 }
840 }
841 let expr = self.parse_expr()?;
842 let alias = self.try_alias()?;
843 Ok(ResultColumn::Expr { expr, alias })
844 }
845
846 fn parse_from_clause(&mut self) -> Result<FromClause, ParseError> {
851 let source = self.parse_table_or_subquery()?;
852 let mut joins = Vec::new();
853 loop {
854 if let Some(jt) = self.try_join_type()? {
855 let table = self.parse_table_or_subquery()?;
856 let constraint = self.parse_join_constraint()?;
857 if jt.natural && constraint.is_some() {
858 return Err(self.err_msg("a NATURAL join may not have an ON or USING clause"));
859 }
860 joins.push(JoinClause {
861 join_type: jt,
862 table,
863 constraint,
864 });
865 } else if self.eat(&TokenKind::Comma) {
866 let table = self.parse_table_or_subquery()?;
867 joins.push(JoinClause {
868 join_type: JoinType {
869 natural: false,
870 kind: JoinKind::Cross,
871 },
872 table,
873 constraint: None,
874 });
875 } else {
876 break;
877 }
878 }
879 Ok(FromClause { source, joins })
880 }
881
882 fn parse_table_or_subquery(&mut self) -> Result<TableOrSubquery, ParseError> {
883 self.with_recursion_guard(|parser| parser.parse_table_or_subquery_inner())
884 }
885
886 fn parse_table_or_subquery_inner(&mut self) -> Result<TableOrSubquery, ParseError> {
887 if self.check(&TokenKind::LeftParen) {
888 self.advance();
889 if matches!(
890 self.peek(),
891 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
892 ) {
893 let with = if self.check_kw(&TokenKind::KwWith) {
894 Some(self.parse_with_clause()?)
895 } else {
896 None
897 };
898 let q = self.parse_select_stmt(with)?;
899 self.expect_token(&TokenKind::RightParen)?;
900 let alias = self.try_alias()?;
901 return Ok(TableOrSubquery::Subquery {
902 query: Box::new(q),
903 alias,
904 });
905 }
906 let fc = self.parse_from_clause()?;
908 self.expect_token(&TokenKind::RightParen)?;
909 return Ok(TableOrSubquery::ParenJoin(Box::new(fc)));
910 }
911
912 let name = self.parse_qualified_name()?;
913
914 if self.check(&TokenKind::LeftParen) && name.schema.is_none() {
916 self.advance();
917 let args = if self.check(&TokenKind::RightParen) {
918 vec![]
919 } else {
920 self.parse_comma_sep(Self::parse_expr)?
921 };
922 self.expect_token(&TokenKind::RightParen)?;
923 let alias = self.try_alias()?;
924 return Ok(TableOrSubquery::TableFunction {
925 name: name.name,
926 args,
927 alias,
928 });
929 }
930
931 let alias = self.try_alias()?;
932 let index_hint = self.parse_index_hint()?;
933 let time_travel = self.parse_time_travel_clause()?;
934 Ok(TableOrSubquery::Table {
935 name,
936 alias,
937 index_hint,
938 time_travel,
939 })
940 }
941
942 fn try_join_type(&mut self) -> Result<Option<JoinType>, ParseError> {
943 let natural = self.eat_kw(&TokenKind::KwNatural);
944 let kind = if self.eat_kw(&TokenKind::KwJoin) {
945 Some(JoinKind::Inner)
946 } else if self.eat_kw(&TokenKind::KwInner) {
947 self.expect_kw(&TokenKind::KwJoin)?;
948 Some(JoinKind::Inner)
949 } else if self.eat_kw(&TokenKind::KwCross) {
950 self.expect_kw(&TokenKind::KwJoin)?;
951 Some(JoinKind::Cross)
952 } else if self.eat_kw(&TokenKind::KwLeft) {
953 let _ = self.eat_kw(&TokenKind::KwOuter);
954 self.expect_kw(&TokenKind::KwJoin)?;
955 Some(JoinKind::Left)
956 } else if self.eat_kw(&TokenKind::KwRight) {
957 let _ = self.eat_kw(&TokenKind::KwOuter);
958 self.expect_kw(&TokenKind::KwJoin)?;
959 Some(JoinKind::Right)
960 } else if self.eat_kw(&TokenKind::KwFull) {
961 let _ = self.eat_kw(&TokenKind::KwOuter);
962 self.expect_kw(&TokenKind::KwJoin)?;
963 Some(JoinKind::Full)
964 } else {
965 None
966 };
967 match kind {
968 Some(k) => Ok(Some(JoinType { natural, kind: k })),
969 None if natural => Err(self.err_expected("JOIN after NATURAL")),
970 None => Ok(None),
971 }
972 }
973
974 fn parse_join_constraint(&mut self) -> Result<Option<JoinConstraint>, ParseError> {
975 if self.eat_kw(&TokenKind::KwOn) {
976 Ok(Some(JoinConstraint::On(self.parse_expr()?)))
977 } else if self.eat_kw(&TokenKind::KwUsing) {
978 self.expect_token(&TokenKind::LeftParen)?;
979 let cols = self.parse_comma_sep(Self::parse_identifier)?;
980 self.expect_token(&TokenKind::RightParen)?;
981 Ok(Some(JoinConstraint::Using(cols)))
982 } else {
983 Ok(None)
984 }
985 }
986
987 pub(crate) fn parse_ordering_term(&mut self) -> Result<OrderingTerm, ParseError> {
992 let expr = self.parse_expr()?;
993 let direction = if self.eat_kw(&TokenKind::KwAsc) {
994 Some(SortDirection::Asc)
995 } else if self.eat_kw(&TokenKind::KwDesc) {
996 Some(SortDirection::Desc)
997 } else {
998 None
999 };
1000 let nulls = if self.eat_kw(&TokenKind::KwNulls) {
1001 if self.eat_kw(&TokenKind::KwFirst) {
1002 Some(NullsOrder::First)
1003 } else {
1004 self.expect_kw(&TokenKind::KwLast)?;
1005 Some(NullsOrder::Last)
1006 }
1007 } else {
1008 None
1009 };
1010 Ok(OrderingTerm {
1011 expr,
1012 direction,
1013 nulls,
1014 })
1015 }
1016
1017 pub(crate) fn parse_limit(&mut self) -> Result<Option<LimitClause>, ParseError> {
1018 if !self.eat_kw(&TokenKind::KwLimit) {
1019 return Ok(None);
1020 }
1021 let first = self.parse_expr()?;
1022 if self.eat_kw(&TokenKind::KwOffset) {
1023 return Ok(Some(LimitClause {
1024 limit: first,
1025 offset: Some(self.parse_expr()?),
1026 }));
1027 }
1028
1029 if self.eat(&TokenKind::Comma) {
1030 let second = self.parse_expr()?;
1032 return Ok(Some(LimitClause {
1033 limit: second,
1034 offset: Some(first),
1035 }));
1036 }
1037
1038 Ok(Some(LimitClause {
1039 limit: first,
1040 offset: None,
1041 }))
1042 }
1043
1044 fn parse_returning(&mut self) -> Result<Vec<ResultColumn>, ParseError> {
1049 if self.eat_kw(&TokenKind::KwReturning) {
1050 self.parse_comma_sep(Self::parse_result_column)
1051 } else {
1052 Ok(vec![])
1053 }
1054 }
1055
1056 fn parse_insert_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
1061 let or_conflict = if self.eat_kw(&TokenKind::KwReplace) {
1062 Some(ConflictAction::Replace)
1063 } else {
1064 self.expect_kw(&TokenKind::KwInsert)?;
1065 if self.eat_kw(&TokenKind::KwOr) {
1066 Some(self.parse_conflict_action()?)
1067 } else {
1068 None
1069 }
1070 };
1071 self.eat_kw(&TokenKind::KwInto);
1072 let table = self.parse_qualified_name()?;
1073 let alias = if self.eat_kw(&TokenKind::KwAs) {
1074 Some(self.parse_identifier()?)
1075 } else {
1076 None
1077 };
1078 let columns = if self.check(&TokenKind::LeftParen)
1079 && !matches!(
1080 self.peek_nth(1),
1081 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
1082 ) {
1083 self.advance();
1084 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1085 self.expect_token(&TokenKind::RightParen)?;
1086 cols
1087 } else {
1088 vec![]
1089 };
1090 let source = if self.eat_kw(&TokenKind::KwDefault) {
1091 self.expect_kw(&TokenKind::KwValues)?;
1092 InsertSource::DefaultValues
1093 } else if self.eat_kw(&TokenKind::KwValues) {
1094 match self.parse_values_core()? {
1095 SelectCore::Values(rows) => InsertSource::Values(rows),
1096 SelectCore::Select { .. } => unreachable!("parse_values_core must return VALUES"),
1097 }
1098 } else {
1099 let inner_with = if self.check_kw(&TokenKind::KwWith) {
1100 Some(self.parse_with_clause()?)
1101 } else {
1102 None
1103 };
1104 InsertSource::Select(Box::new(self.parse_select_stmt(inner_with)?))
1105 };
1106 let upsert = self.parse_upsert_clauses()?;
1107 let returning = self.parse_returning()?;
1108 Ok(Statement::Insert(InsertStatement {
1109 with,
1110 or_conflict,
1111 table,
1112 alias,
1113 columns,
1114 source,
1115 upsert,
1116 returning,
1117 }))
1118 }
1119
1120 fn parse_conflict_action(&mut self) -> Result<ConflictAction, ParseError> {
1121 if self.eat_kw(&TokenKind::KwRollback) {
1122 Ok(ConflictAction::Rollback)
1123 } else if self.eat_kw(&TokenKind::KwAbort) {
1124 Ok(ConflictAction::Abort)
1125 } else if self.eat_kw(&TokenKind::KwFail) {
1126 Ok(ConflictAction::Fail)
1127 } else if self.eat_kw(&TokenKind::KwIgnore) {
1128 Ok(ConflictAction::Ignore)
1129 } else if self.eat_kw(&TokenKind::KwReplace) {
1130 Ok(ConflictAction::Replace)
1131 } else {
1132 Err(self.err_expected("conflict action"))
1133 }
1134 }
1135
1136 fn parse_upsert_clauses(&mut self) -> Result<Vec<UpsertClause>, ParseError> {
1137 let mut clauses = Vec::new();
1138 while self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
1139 self.advance(); self.advance(); let target = if self.check(&TokenKind::LeftParen) {
1142 self.advance();
1143 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1144 self.expect_token(&TokenKind::RightParen)?;
1145 let wh = if self.eat_kw(&TokenKind::KwWhere) {
1146 Some(self.parse_expr()?)
1147 } else {
1148 None
1149 };
1150 Some(UpsertTarget {
1151 columns,
1152 where_clause: wh,
1153 })
1154 } else {
1155 None
1156 };
1157 self.expect_kw(&TokenKind::KwDo)?;
1158 let action = if self.eat_kw(&TokenKind::KwNothing) {
1159 UpsertAction::Nothing
1160 } else {
1161 self.expect_kw(&TokenKind::KwUpdate)?;
1162 self.expect_kw(&TokenKind::KwSet)?;
1163 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
1164 let wh = if self.eat_kw(&TokenKind::KwWhere) {
1165 Some(Box::new(self.parse_expr()?))
1166 } else {
1167 None
1168 };
1169 UpsertAction::Update {
1170 assignments,
1171 where_clause: wh,
1172 }
1173 };
1174 if target.is_none() && matches!(action, UpsertAction::Update { .. }) {
1175 return Err(self.err_msg("ON CONFLICT DO UPDATE requires a conflict target"));
1176 }
1177 clauses.push(UpsertClause { target, action });
1178 }
1179 Ok(clauses)
1180 }
1181
1182 fn parse_update_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
1187 self.expect_kw(&TokenKind::KwUpdate)?;
1188 let or_conflict = if self.eat_kw(&TokenKind::KwOr) {
1189 Some(self.parse_conflict_action()?)
1190 } else {
1191 None
1192 };
1193 let table = self.parse_qualified_table_ref()?;
1194 self.expect_kw(&TokenKind::KwSet)?;
1195 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
1196 let from = if self.eat_kw(&TokenKind::KwFrom) {
1197 Some(self.parse_from_clause()?)
1198 } else {
1199 None
1200 };
1201 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1202 Some(self.parse_expr()?)
1203 } else {
1204 None
1205 };
1206 let returning = self.parse_returning()?;
1207 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1208 self.expect_kw(&TokenKind::KwBy)?;
1209 self.parse_comma_sep(Self::parse_ordering_term)?
1210 } else {
1211 vec![]
1212 };
1213 let limit = self.parse_limit()?;
1214 Ok(Statement::Update(UpdateStatement {
1215 with,
1216 or_conflict,
1217 table,
1218 assignments,
1219 from,
1220 where_clause,
1221 returning,
1222 order_by,
1223 limit,
1224 }))
1225 }
1226
1227 fn parse_assignment(&mut self) -> Result<Assignment, ParseError> {
1228 let target = if self.check(&TokenKind::LeftParen) {
1229 self.advance();
1230 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1231 self.expect_token(&TokenKind::RightParen)?;
1232 AssignmentTarget::ColumnList(cols)
1233 } else {
1234 AssignmentTarget::Column(self.parse_identifier()?)
1235 };
1236 self.expect_token(&TokenKind::Eq)?;
1237 let value = self.parse_expr()?;
1238 Ok(Assignment { target, value })
1239 }
1240
1241 fn parse_delete_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
1246 self.expect_kw(&TokenKind::KwDelete)?;
1247 self.expect_kw(&TokenKind::KwFrom)?;
1248 let table = self.parse_qualified_table_ref()?;
1249 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1250 Some(self.parse_expr()?)
1251 } else {
1252 None
1253 };
1254 let returning = self.parse_returning()?;
1255 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1256 self.expect_kw(&TokenKind::KwBy)?;
1257 self.parse_comma_sep(Self::parse_ordering_term)?
1258 } else {
1259 vec![]
1260 };
1261 let limit = self.parse_limit()?;
1262 Ok(Statement::Delete(DeleteStatement {
1263 with,
1264 table,
1265 where_clause,
1266 returning,
1267 order_by,
1268 limit,
1269 }))
1270 }
1271
1272 fn parse_create(&mut self) -> Result<Statement, ParseError> {
1277 self.expect_kw(&TokenKind::KwCreate)?;
1278 let temporary = self.eat_kw(&TokenKind::KwTemp) || self.eat_kw(&TokenKind::KwTemporary);
1279 let unique = self.eat_kw(&TokenKind::KwUnique);
1280
1281 if self.eat_kw(&TokenKind::KwTable) {
1282 return self.parse_create_table(temporary);
1283 }
1284 if self.eat_kw(&TokenKind::KwIndex) {
1285 return self.parse_create_index(unique);
1286 }
1287 if self.eat_kw(&TokenKind::KwView) {
1288 return self.parse_create_view(temporary);
1289 }
1290 if self.eat_kw(&TokenKind::KwTrigger) {
1291 return self.parse_create_trigger(temporary);
1292 }
1293 if self.eat_kw(&TokenKind::KwVirtual) {
1294 self.expect_kw(&TokenKind::KwTable)?;
1295 return self.parse_create_virtual_table();
1296 }
1297 Err(self.err_expected("TABLE, INDEX, VIEW, TRIGGER, or VIRTUAL"))
1298 }
1299
1300 fn parse_if_not_exists(&mut self) -> bool {
1301 if self.check_kw(&TokenKind::KwIf)
1302 && self.peek_nth(1) == &TokenKind::KwNot
1303 && self.peek_nth(2) == &TokenKind::KwExists
1304 {
1305 self.advance();
1306 self.advance();
1307 self.advance();
1308 true
1309 } else {
1310 false
1311 }
1312 }
1313
1314 fn parse_create_table(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1315 let if_not_exists = self.parse_if_not_exists();
1316 let name = self.parse_qualified_name()?;
1317 let body = if self.eat_kw(&TokenKind::KwAs) {
1318 let with = if self.check_kw(&TokenKind::KwWith) {
1319 Some(self.parse_with_clause()?)
1320 } else {
1321 None
1322 };
1323 CreateTableBody::AsSelect(Box::new(self.parse_select_stmt(with)?))
1324 } else {
1325 self.expect_token(&TokenKind::LeftParen)?;
1326 let mut columns = Vec::new();
1327 let mut constraints = Vec::new();
1328 loop {
1329 if self.is_table_constraint_start() {
1330 constraints.push(self.parse_table_constraint()?);
1331 } else {
1332 columns.push(self.parse_column_def()?);
1333 }
1334 if !self.eat(&TokenKind::Comma) {
1335 break;
1336 }
1337 }
1338 self.expect_token(&TokenKind::RightParen)?;
1339 CreateTableBody::Columns {
1340 columns,
1341 constraints,
1342 }
1343 };
1344 let mut without_rowid = false;
1345 let mut strict = false;
1346 if self.check_kw(&TokenKind::KwWithout) || self.check_kw(&TokenKind::KwStrict) {
1348 loop {
1349 if self.check_kw(&TokenKind::KwWithout) {
1350 self.advance();
1351 let id = self.parse_identifier()?;
1353 if !id.eq_ignore_ascii_case("ROWID") {
1354 return Err(self.err_expected("ROWID after WITHOUT"));
1355 }
1356 without_rowid = true;
1357 } else if self.eat_kw(&TokenKind::KwStrict) {
1358 strict = true;
1359 } else {
1360 return Err(self.err_expected("table option"));
1361 }
1362 if !self.eat(&TokenKind::Comma) {
1363 break;
1364 }
1365 }
1366 }
1367 Ok(Statement::CreateTable(CreateTableStatement {
1368 if_not_exists,
1369 temporary,
1370 name,
1371 body,
1372 without_rowid,
1373 strict,
1374 }))
1375 }
1376
1377 fn is_table_constraint_start(&self) -> bool {
1378 matches!(
1379 self.peek(),
1380 TokenKind::KwPrimary | TokenKind::KwUnique | TokenKind::KwCheck | TokenKind::KwForeign
1381 ) || (self.check_kw(&TokenKind::KwConstraint))
1382 }
1383
1384 fn parse_column_def(&mut self) -> Result<ColumnDef, ParseError> {
1385 let name = self.parse_identifier()?;
1386 let type_name = self.try_type_name()?;
1387 let mut constraints = Vec::new();
1388 while let Some(c) = self.try_column_constraint()? {
1389 constraints.push(c);
1390 }
1391 Ok(ColumnDef {
1392 name,
1393 type_name,
1394 constraints,
1395 })
1396 }
1397
1398 fn try_type_name(&mut self) -> Result<Option<TypeName>, ParseError> {
1399 if self.is_column_constraint_start()
1401 || matches!(
1402 self.peek(),
1403 TokenKind::Comma | TokenKind::RightParen | TokenKind::Eof
1404 )
1405 {
1406 return Ok(None);
1407 }
1408 let mut words = Vec::new();
1410 loop {
1411 match self.peek() {
1412 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
1413 words.push(self.parse_identifier()?);
1414 }
1415 k if is_nonreserved_kw(k) => {
1416 words.push(self.parse_identifier()?);
1417 }
1418 _ => break,
1419 }
1420 if self.is_column_constraint_start()
1421 || matches!(
1422 self.peek(),
1423 TokenKind::Comma | TokenKind::RightParen | TokenKind::LeftParen
1424 )
1425 {
1426 break;
1427 }
1428 }
1429 if words.is_empty() {
1430 return Ok(None);
1431 }
1432 let type_name = words.join(" ");
1433 let (arg1, arg2) = if self.eat(&TokenKind::LeftParen) {
1434 let a1 = self.parse_signed_number_str()?;
1435 let a2 = if self.eat(&TokenKind::Comma) {
1436 Some(self.parse_signed_number_str()?)
1437 } else {
1438 None
1439 };
1440 self.expect_token(&TokenKind::RightParen)?;
1441 (Some(a1), a2)
1442 } else {
1443 (None, None)
1444 };
1445 Ok(Some(TypeName {
1446 name: type_name,
1447 arg1,
1448 arg2,
1449 }))
1450 }
1451
1452 fn parse_signed_number_str(&mut self) -> Result<String, ParseError> {
1453 let neg = self.eat(&TokenKind::Minus);
1454 let plus = if neg {
1455 false
1456 } else {
1457 self.eat(&TokenKind::Plus)
1458 };
1459 let _ = plus; match self.peek().clone() {
1461 TokenKind::Integer(n) => {
1462 self.advance();
1463 Ok(if neg { format!("-{n}") } else { n.to_string() })
1464 }
1465 TokenKind::OversizedInt(s) => {
1466 self.advance();
1467 Ok(if neg { format!("-{s}") } else { s.clone() })
1468 }
1469 TokenKind::Float(f) => {
1470 self.advance();
1471 Ok(if neg { format!("-{f}") } else { f.to_string() })
1472 }
1473 _ => Err(self.err_expected("number")),
1474 }
1475 }
1476
1477 fn is_column_constraint_start(&self) -> bool {
1478 matches!(
1479 self.peek(),
1480 TokenKind::KwPrimary
1481 | TokenKind::KwNot
1482 | TokenKind::KwNull
1483 | TokenKind::KwUnique
1484 | TokenKind::KwCheck
1485 | TokenKind::KwDefault
1486 | TokenKind::KwCollate
1487 | TokenKind::KwReferences
1488 | TokenKind::KwGenerated
1489 | TokenKind::KwConstraint
1490 | TokenKind::KwAs
1491 )
1492 }
1493
1494 fn try_column_constraint(&mut self) -> Result<Option<ColumnConstraint>, ParseError> {
1495 let name = if self.eat_kw(&TokenKind::KwConstraint) {
1496 Some(self.parse_identifier()?)
1497 } else {
1498 None
1499 };
1500 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
1501 self.expect_kw(&TokenKind::KwKey)?;
1502 let direction = if self.eat_kw(&TokenKind::KwAsc) {
1503 Some(SortDirection::Asc)
1504 } else if self.eat_kw(&TokenKind::KwDesc) {
1505 Some(SortDirection::Desc)
1506 } else {
1507 None
1508 };
1509 let conflict = self.parse_on_conflict()?;
1510 let autoincrement = self.eat_kw(&TokenKind::KwAutoincrement);
1511 ColumnConstraintKind::PrimaryKey {
1512 direction,
1513 conflict,
1514 autoincrement,
1515 }
1516 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwNull {
1517 self.advance();
1518 self.advance();
1519 let conflict = self.parse_on_conflict()?;
1520 ColumnConstraintKind::NotNull { conflict }
1521 } else if self.eat_kw(&TokenKind::KwNull) {
1522 ColumnConstraintKind::Null
1523 } else if self.eat_kw(&TokenKind::KwUnique) {
1524 let conflict = self.parse_on_conflict()?;
1525 ColumnConstraintKind::Unique { conflict }
1526 } else if self.eat_kw(&TokenKind::KwCheck) {
1527 self.expect_token(&TokenKind::LeftParen)?;
1528 let expr = self.parse_expr()?;
1529 self.expect_token(&TokenKind::RightParen)?;
1530 ColumnConstraintKind::Check(expr)
1531 } else if self.eat_kw(&TokenKind::KwDefault) {
1532 if self.eat(&TokenKind::LeftParen) {
1533 let expr = self.parse_expr()?;
1534 self.expect_token(&TokenKind::RightParen)?;
1535 ColumnConstraintKind::Default(DefaultValue::ParenExpr(expr))
1536 } else {
1537 let expr = self.parse_expr()?;
1538 ColumnConstraintKind::Default(DefaultValue::Expr(expr))
1539 }
1540 } else if self.eat_kw(&TokenKind::KwCollate) {
1541 ColumnConstraintKind::Collate(self.parse_identifier()?)
1542 } else if self.eat_kw(&TokenKind::KwReferences) {
1543 ColumnConstraintKind::ForeignKey(self.parse_fk_clause()?)
1544 } else if self.eat_kw(&TokenKind::KwGenerated) || self.eat_kw(&TokenKind::KwAs) {
1545 if self.tokens[self.pos.saturating_sub(1)].kind == TokenKind::KwGenerated {
1546 let _ = self.eat_kw(&TokenKind::KwAlways);
1547 let _ = self.eat_kw(&TokenKind::KwAs);
1548 }
1549 self.expect_token(&TokenKind::LeftParen)?;
1550 let expr = self.parse_expr()?;
1551 self.expect_token(&TokenKind::RightParen)?;
1552 let storage = if self.eat_kw(&TokenKind::KwStored) {
1553 Some(GeneratedStorage::Stored)
1554 } else if self.eat_kw(&TokenKind::KwVirtual) {
1555 Some(GeneratedStorage::Virtual)
1556 } else {
1557 None
1558 };
1559 ColumnConstraintKind::Generated { expr, storage }
1560 } else if name.is_some() {
1561 return Err(self.err_expected("constraint kind after CONSTRAINT name"));
1562 } else {
1563 return Ok(None);
1564 };
1565 Ok(Some(ColumnConstraint { name, kind }))
1566 }
1567
1568 fn parse_on_conflict(&mut self) -> Result<Option<ConflictAction>, ParseError> {
1569 if self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
1570 self.advance();
1571 self.advance();
1572 Ok(Some(self.parse_conflict_action()?))
1573 } else {
1574 Ok(None)
1575 }
1576 }
1577
1578 fn parse_fk_clause(&mut self) -> Result<ForeignKeyClause, ParseError> {
1579 let table = self.parse_identifier()?;
1580 let columns = if self.eat(&TokenKind::LeftParen) {
1581 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1582 self.expect_token(&TokenKind::RightParen)?;
1583 cols
1584 } else {
1585 vec![]
1586 };
1587 let mut actions = Vec::new();
1588 let mut deferrable = None;
1589 loop {
1590 if self.check_kw(&TokenKind::KwOn) {
1591 self.advance();
1592 let trigger = if self.eat_kw(&TokenKind::KwDelete) {
1593 ForeignKeyTrigger::OnDelete
1594 } else {
1595 self.expect_kw(&TokenKind::KwUpdate)?;
1596 ForeignKeyTrigger::OnUpdate
1597 };
1598 let action = self.parse_fk_action_type()?;
1599 actions.push(ForeignKeyAction { trigger, action });
1600 } else if self.check_kw(&TokenKind::KwNot) || self.check_kw(&TokenKind::KwDeferrable) {
1601 let not = self.eat_kw(&TokenKind::KwNot);
1602 self.expect_kw(&TokenKind::KwDeferrable)?;
1603 let initially = if self.eat_kw(&TokenKind::KwInitially) {
1604 if self.eat_kw(&TokenKind::KwDeferred) {
1605 Some(DeferrableInitially::Deferred)
1606 } else {
1607 self.expect_kw(&TokenKind::KwImmediate)?;
1608 Some(DeferrableInitially::Immediate)
1609 }
1610 } else {
1611 None
1612 };
1613 deferrable = Some(Deferrable { not, initially });
1614 } else if self.eat_kw(&TokenKind::KwMatch) {
1615 self.parse_identifier()?;
1617 } else {
1618 break;
1619 }
1620 }
1621 Ok(ForeignKeyClause {
1622 table,
1623 columns,
1624 actions,
1625 deferrable,
1626 })
1627 }
1628
1629 fn parse_fk_action_type(&mut self) -> Result<ForeignKeyActionType, ParseError> {
1630 if self.eat_kw(&TokenKind::KwSet) {
1631 if self.eat_kw(&TokenKind::KwNull) {
1632 Ok(ForeignKeyActionType::SetNull)
1633 } else {
1634 self.expect_kw(&TokenKind::KwDefault)?;
1635 Ok(ForeignKeyActionType::SetDefault)
1636 }
1637 } else if self.eat_kw(&TokenKind::KwCascade) {
1638 Ok(ForeignKeyActionType::Cascade)
1639 } else if self.eat_kw(&TokenKind::KwRestrict) {
1640 Ok(ForeignKeyActionType::Restrict)
1641 } else if self.check_kw(&TokenKind::KwNo) {
1642 self.advance();
1643 let id = self.parse_identifier()?;
1644 if !id.eq_ignore_ascii_case("ACTION") {
1645 return Err(self.err_expected("ACTION after NO"));
1646 }
1647 Ok(ForeignKeyActionType::NoAction)
1648 } else {
1649 Err(self.err_expected("foreign key action"))
1650 }
1651 }
1652
1653 fn parse_table_constraint(&mut self) -> Result<TableConstraint, ParseError> {
1654 let name = if self.eat_kw(&TokenKind::KwConstraint) {
1655 Some(self.parse_identifier()?)
1656 } else {
1657 None
1658 };
1659 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
1660 self.expect_kw(&TokenKind::KwKey)?;
1661 self.expect_token(&TokenKind::LeftParen)?;
1662 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1663 self.expect_token(&TokenKind::RightParen)?;
1664 let conflict = self.parse_on_conflict()?;
1665 TableConstraintKind::PrimaryKey { columns, conflict }
1666 } else if self.eat_kw(&TokenKind::KwUnique) {
1667 self.expect_token(&TokenKind::LeftParen)?;
1668 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1669 self.expect_token(&TokenKind::RightParen)?;
1670 let conflict = self.parse_on_conflict()?;
1671 TableConstraintKind::Unique { columns, conflict }
1672 } else if self.eat_kw(&TokenKind::KwCheck) {
1673 self.expect_token(&TokenKind::LeftParen)?;
1674 let expr = self.parse_expr()?;
1675 self.expect_token(&TokenKind::RightParen)?;
1676 TableConstraintKind::Check(expr)
1677 } else if self.eat_kw(&TokenKind::KwForeign) {
1678 self.expect_kw(&TokenKind::KwKey)?;
1679 self.expect_token(&TokenKind::LeftParen)?;
1680 let columns = self.parse_comma_sep(Self::parse_identifier)?;
1681 self.expect_token(&TokenKind::RightParen)?;
1682 self.expect_kw(&TokenKind::KwReferences)?;
1683 let clause = self.parse_fk_clause()?;
1684 TableConstraintKind::ForeignKey { columns, clause }
1685 } else {
1686 return Err(self.err_expected("table constraint"));
1687 };
1688 Ok(TableConstraint { name, kind })
1689 }
1690
1691 fn parse_indexed_column(&mut self) -> Result<IndexedColumn, ParseError> {
1692 let expr = self.parse_expr()?;
1693 let collation = if self.eat_kw(&TokenKind::KwCollate) {
1694 Some(self.parse_identifier()?)
1695 } else {
1696 None
1697 };
1698 let direction = if self.eat_kw(&TokenKind::KwAsc) {
1699 Some(SortDirection::Asc)
1700 } else if self.eat_kw(&TokenKind::KwDesc) {
1701 Some(SortDirection::Desc)
1702 } else {
1703 None
1704 };
1705 Ok(IndexedColumn {
1706 expr,
1707 collation,
1708 direction,
1709 })
1710 }
1711
1712 fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParseError> {
1713 let if_not_exists = self.parse_if_not_exists();
1714 let name = self.parse_qualified_name()?;
1715 self.expect_kw(&TokenKind::KwOn)?;
1716 let table = self.parse_identifier()?;
1717 self.expect_token(&TokenKind::LeftParen)?;
1718 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1719 self.expect_token(&TokenKind::RightParen)?;
1720 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1721 Some(self.parse_expr()?)
1722 } else {
1723 None
1724 };
1725 Ok(Statement::CreateIndex(CreateIndexStatement {
1726 unique,
1727 if_not_exists,
1728 name,
1729 table,
1730 columns,
1731 where_clause,
1732 }))
1733 }
1734
1735 fn parse_create_view(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1736 let if_not_exists = self.parse_if_not_exists();
1737 let name = self.parse_qualified_name()?;
1738 let columns = if self.check(&TokenKind::LeftParen) {
1739 self.advance();
1740 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1741 self.expect_token(&TokenKind::RightParen)?;
1742 cols
1743 } else {
1744 vec![]
1745 };
1746 self.expect_kw(&TokenKind::KwAs)?;
1747 let with = if self.check_kw(&TokenKind::KwWith) {
1748 Some(self.parse_with_clause()?)
1749 } else {
1750 None
1751 };
1752 let query = self.parse_select_stmt(with)?;
1753 Ok(Statement::CreateView(CreateViewStatement {
1754 if_not_exists,
1755 temporary,
1756 name,
1757 columns,
1758 query,
1759 }))
1760 }
1761
1762 fn parse_create_trigger(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1763 let if_not_exists = self.parse_if_not_exists();
1764 let name = self.parse_qualified_name()?;
1765 let timing = if self.eat_kw(&TokenKind::KwBefore) {
1766 TriggerTiming::Before
1767 } else if self.eat_kw(&TokenKind::KwAfter) {
1768 TriggerTiming::After
1769 } else if self.eat_kw(&TokenKind::KwInstead) {
1770 self.expect_kw(&TokenKind::KwOf)?;
1771 TriggerTiming::InsteadOf
1772 } else {
1773 TriggerTiming::Before };
1775 let event = if self.eat_kw(&TokenKind::KwInsert) {
1776 TriggerEvent::Insert
1777 } else if self.eat_kw(&TokenKind::KwDelete) {
1778 TriggerEvent::Delete
1779 } else {
1780 self.expect_kw(&TokenKind::KwUpdate)?;
1781 let cols = if self.eat_kw(&TokenKind::KwOf) {
1782 self.parse_comma_sep(Self::parse_identifier)?
1783 } else {
1784 vec![]
1785 };
1786 TriggerEvent::Update(cols)
1787 };
1788 self.expect_kw(&TokenKind::KwOn)?;
1789 let table = self.parse_identifier()?;
1790 let for_each_row = if self.eat_kw(&TokenKind::KwFor) {
1791 self.expect_kw(&TokenKind::KwEach)?;
1792 self.expect_kw(&TokenKind::KwRow)?;
1793 true
1794 } else {
1795 false
1796 };
1797 let when = if self.eat_kw(&TokenKind::KwWhen) {
1798 Some(self.parse_expr()?)
1799 } else {
1800 None
1801 };
1802 self.expect_kw(&TokenKind::KwBegin)?;
1803 let mut body = Vec::new();
1804 loop {
1805 if self.check_kw(&TokenKind::KwEnd) {
1806 break;
1807 }
1808 let stmt = match self.parse_statement_inner() {
1809 Ok(stmt) => stmt,
1810 Err(err) => {
1811 self.recover_trigger_body_after_error();
1812 return Err(err);
1813 }
1814 };
1815 body.push(stmt);
1816 let _ = self.eat(&TokenKind::Semicolon);
1817 }
1818 self.expect_kw(&TokenKind::KwEnd)?;
1819 Ok(Statement::CreateTrigger(CreateTriggerStatement {
1820 if_not_exists,
1821 temporary,
1822 name,
1823 timing,
1824 event,
1825 table,
1826 for_each_row,
1827 when,
1828 body,
1829 }))
1830 }
1831
1832 fn parse_create_virtual_table(&mut self) -> Result<Statement, ParseError> {
1833 let if_not_exists = self.parse_if_not_exists();
1834 let name = self.parse_qualified_name()?;
1835 self.expect_kw(&TokenKind::KwUsing)?;
1836 let module = self.parse_identifier()?;
1837 let args = if self.eat(&TokenKind::LeftParen) {
1838 if self.check(&TokenKind::RightParen) {
1839 self.advance();
1840 vec![]
1841 } else {
1842 let mut args = Vec::new();
1844 let mut depth = 0i32;
1845 let mut current_arg = String::new();
1846 loop {
1847 match self.peek() {
1848 TokenKind::RightParen if depth == 0 => {
1849 self.advance();
1850 args.push(current_arg.trim().to_owned());
1851 break;
1852 }
1853 TokenKind::LeftParen => {
1854 depth += 1;
1855 current_arg.push('(');
1856 self.advance();
1857 }
1858 TokenKind::RightParen => {
1859 depth -= 1;
1860 current_arg.push(')');
1861 self.advance();
1862 }
1863 TokenKind::Comma if depth == 0 => {
1864 args.push(current_arg.trim().to_owned());
1865 current_arg = String::new();
1866 self.advance();
1867 }
1868 TokenKind::Eof => {
1869 return Err(self.err_expected("closing parenthesis"));
1870 }
1871 _ => {
1872 let t = self
1874 .current()
1875 .ok_or_else(|| self.err_expected("virtual table argument token"))?;
1876 let text = t.kind.to_sql();
1877 if !current_arg.is_empty()
1878 && !current_arg.ends_with(' ')
1879 && !text.is_empty()
1880 {
1881 current_arg.push(' ');
1882 }
1883 current_arg.push_str(&text);
1884 self.advance();
1885 }
1886 }
1887 }
1888 args
1889 }
1890 } else {
1891 vec![]
1892 };
1893 Ok(Statement::CreateVirtualTable(CreateVirtualTableStatement {
1894 if_not_exists,
1895 name,
1896 module,
1897 args,
1898 }))
1899 }
1900
1901 fn parse_drop(&mut self) -> Result<Statement, ParseError> {
1906 self.expect_kw(&TokenKind::KwDrop)?;
1907 let object_type = if self.eat_kw(&TokenKind::KwTable) {
1908 DropObjectType::Table
1909 } else if self.eat_kw(&TokenKind::KwView) {
1910 DropObjectType::View
1911 } else if self.eat_kw(&TokenKind::KwIndex) {
1912 DropObjectType::Index
1913 } else if self.eat_kw(&TokenKind::KwTrigger) {
1914 DropObjectType::Trigger
1915 } else {
1916 return Err(self.err_expected("TABLE, VIEW, INDEX, or TRIGGER"));
1917 };
1918 let if_exists =
1919 if self.check_kw(&TokenKind::KwIf) && self.peek_nth(1) == &TokenKind::KwExists {
1920 self.advance();
1921 self.advance();
1922 true
1923 } else {
1924 false
1925 };
1926 let name = self.parse_qualified_name()?;
1927 Ok(Statement::Drop(DropStatement {
1928 object_type,
1929 if_exists,
1930 name,
1931 }))
1932 }
1933
1934 fn parse_alter(&mut self) -> Result<Statement, ParseError> {
1939 self.expect_kw(&TokenKind::KwAlter)?;
1940 self.expect_kw(&TokenKind::KwTable)?;
1941 let table = self.parse_qualified_name()?;
1942 let action = if self.eat_kw(&TokenKind::KwRename) {
1943 if self.eat_kw(&TokenKind::KwTo) {
1944 AlterTableAction::RenameTo(self.parse_identifier()?)
1945 } else {
1946 let _ = self.eat_kw(&TokenKind::KwColumn);
1947 let old = self.parse_identifier()?;
1948 self.expect_kw(&TokenKind::KwTo)?;
1949 let new = self.parse_identifier()?;
1950 AlterTableAction::RenameColumn { old, new }
1951 }
1952 } else if self.eat_kw(&TokenKind::KwAdd) {
1953 let _ = self.eat_kw(&TokenKind::KwColumn);
1954 AlterTableAction::AddColumn(self.parse_column_def()?)
1955 } else if self.eat_kw(&TokenKind::KwDrop) {
1956 let _ = self.eat_kw(&TokenKind::KwColumn);
1957 AlterTableAction::DropColumn(self.parse_identifier()?)
1958 } else {
1959 return Err(self.err_expected("RENAME, ADD, or DROP"));
1960 };
1961 Ok(Statement::AlterTable(AlterTableStatement { table, action }))
1962 }
1963
1964 fn parse_begin(&mut self) -> Result<Statement, ParseError> {
1969 self.expect_kw(&TokenKind::KwBegin)?;
1970 let mode = if self.eat_kw(&TokenKind::KwDeferred) {
1971 Some(TransactionMode::Deferred)
1972 } else if self.eat_kw(&TokenKind::KwImmediate) {
1973 Some(TransactionMode::Immediate)
1974 } else if self.eat_kw(&TokenKind::KwExclusive) {
1975 Some(TransactionMode::Exclusive)
1976 } else if self.eat_kw(&TokenKind::KwConcurrent) {
1977 Some(TransactionMode::Concurrent)
1978 } else {
1979 None
1980 };
1981 let _ = self.eat_kw(&TokenKind::KwTransaction);
1983 Ok(Statement::Begin(BeginStatement { mode }))
1984 }
1985
1986 fn parse_rollback(&mut self) -> Result<Statement, ParseError> {
1987 self.expect_kw(&TokenKind::KwRollback)?;
1988 let _ = self.eat_kw(&TokenKind::KwTransaction);
1989 let to_savepoint = if self.eat_kw(&TokenKind::KwTo) {
1990 let _ = self.eat_kw(&TokenKind::KwSavepoint);
1991 Some(self.parse_identifier()?)
1992 } else {
1993 None
1994 };
1995 Ok(Statement::Rollback(RollbackStatement { to_savepoint }))
1996 }
1997
1998 fn parse_attach(&mut self) -> Result<Statement, ParseError> {
2003 self.expect_kw(&TokenKind::KwAttach)?;
2004 let _ = self.eat_kw(&TokenKind::KwDatabase);
2005 let expr = self.parse_expr()?;
2006 self.expect_kw(&TokenKind::KwAs)?;
2007 let schema = self.parse_identifier()?;
2008 Ok(Statement::Attach(AttachStatement { expr, schema }))
2009 }
2010
2011 fn parse_pragma_value_expr(&mut self) -> Result<Expr, ParseError> {
2012 if self.check_kw(&TokenKind::KwOn) {
2016 let sp = self.current_span();
2017 self.advance();
2018 return Ok(Expr::Literal(Literal::True, sp));
2019 }
2020 self.parse_expr()
2021 }
2022
2023 fn parse_pragma(&mut self) -> Result<Statement, ParseError> {
2024 self.expect_kw(&TokenKind::KwPragma)?;
2025 let name = self.parse_qualified_name()?;
2026 let value = if self.eat(&TokenKind::Eq) || self.eat(&TokenKind::EqEq) {
2027 Some(PragmaValue::Assign(self.parse_pragma_value_expr()?))
2028 } else if self.eat(&TokenKind::LeftParen) {
2029 let v = self.parse_pragma_value_expr()?;
2030 self.expect_token(&TokenKind::RightParen)?;
2031 Some(PragmaValue::Call(v))
2032 } else {
2033 None
2034 };
2035 Ok(Statement::Pragma(PragmaStatement { name, value }))
2036 }
2037
2038 fn parse_vacuum(&mut self) -> Result<Statement, ParseError> {
2039 self.expect_kw(&TokenKind::KwVacuum)?;
2040 let schema = if !self.at_eof()
2041 && !self.check(&TokenKind::Semicolon)
2042 && !self.check_kw(&TokenKind::KwInto)
2043 {
2044 Some(self.parse_identifier()?)
2045 } else {
2046 None
2047 };
2048 let into = if self.eat_kw(&TokenKind::KwInto) {
2049 Some(self.parse_expr()?)
2050 } else {
2051 None
2052 };
2053 Ok(Statement::Vacuum(VacuumStatement { schema, into }))
2054 }
2055
2056 fn parse_explain(&mut self) -> Result<Statement, ParseError> {
2057 self.expect_kw(&TokenKind::KwExplain)?;
2058 let query_plan = if self.eat_kw(&TokenKind::KwQuery) {
2059 self.expect_kw(&TokenKind::KwPlan)?;
2060 true
2061 } else {
2062 false
2063 };
2064 let stmt = self.parse_statement_inner()?;
2065 Ok(Statement::Explain {
2066 query_plan,
2067 stmt: Box::new(stmt),
2068 })
2069 }
2070
2071 fn parse_window_def(&mut self) -> Result<WindowDef, ParseError> {
2076 let name = self.parse_identifier()?;
2077 self.expect_kw(&TokenKind::KwAs)?;
2078 self.expect_token(&TokenKind::LeftParen)?;
2079 let spec = self.parse_window_spec()?;
2080 self.expect_token(&TokenKind::RightParen)?;
2081 Ok(WindowDef { name, spec })
2082 }
2083
2084 pub(crate) fn parse_window_spec(&mut self) -> Result<WindowSpec, ParseError> {
2085 let has_base_window = match self.peek() {
2087 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => true,
2088 k if is_nonreserved_kw(k) => !matches!(
2089 k,
2090 TokenKind::KwPartition
2091 | TokenKind::KwOrder
2092 | TokenKind::KwRange
2093 | TokenKind::KwRows
2094 | TokenKind::KwGroups
2095 ),
2096 _ => false,
2097 };
2098 let base_window = if has_base_window {
2099 Some(self.parse_identifier()?)
2100 } else {
2101 None
2102 };
2103 let partition_by = if self.eat_kw(&TokenKind::KwPartition) {
2104 self.expect_kw(&TokenKind::KwBy)?;
2105 self.parse_comma_sep(Self::parse_expr)?
2106 } else {
2107 vec![]
2108 };
2109 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
2110 self.expect_kw(&TokenKind::KwBy)?;
2111 self.parse_comma_sep(Self::parse_ordering_term)?
2112 } else {
2113 vec![]
2114 };
2115 let frame = self.try_frame_spec()?;
2116 Ok(WindowSpec {
2117 base_window,
2118 partition_by,
2119 order_by,
2120 frame,
2121 })
2122 }
2123
2124 fn try_frame_spec(&mut self) -> Result<Option<FrameSpec>, ParseError> {
2125 let frame_type = if self.eat_kw(&TokenKind::KwRows) {
2126 FrameType::Rows
2127 } else if self.eat_kw(&TokenKind::KwRange) {
2128 FrameType::Range
2129 } else if self.eat_kw(&TokenKind::KwGroups) {
2130 FrameType::Groups
2131 } else {
2132 return Ok(None);
2133 };
2134 let (start, end) = if self.eat_kw(&TokenKind::KwBetween) {
2135 let s = self.parse_frame_bound()?;
2136 self.expect_kw(&TokenKind::KwAnd)?;
2137 let e = self.parse_frame_bound()?;
2138 (s, Some(e))
2139 } else {
2140 (self.parse_frame_bound()?, None)
2141 };
2142 let exclude = if self.eat_kw(&TokenKind::KwExclude) {
2143 if self.check_kw(&TokenKind::KwNo) {
2144 self.advance();
2145 let id = self.parse_identifier()?;
2147 if !id.eq_ignore_ascii_case("OTHERS") {
2148 return Err(self.err_expected("OTHERS"));
2149 }
2150 Some(FrameExclude::NoOthers)
2151 } else if self.eat_kw(&TokenKind::KwTies) {
2152 Some(FrameExclude::Ties)
2153 } else if self.eat_kw(&TokenKind::KwGroup) {
2154 Some(FrameExclude::Group)
2155 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2156 self.advance();
2157 self.expect_kw(&TokenKind::KwRow)?;
2158 Some(FrameExclude::CurrentRow)
2159 } else {
2160 return Err(
2161 self.err_expected("NO OTHERS, TIES, GROUP, or CURRENT ROW after EXCLUDE")
2162 );
2163 }
2164 } else {
2165 None
2166 };
2167 Ok(Some(FrameSpec {
2168 frame_type,
2169 start,
2170 end,
2171 exclude,
2172 }))
2173 }
2174
2175 fn parse_frame_bound(&mut self) -> Result<FrameBound, ParseError> {
2176 if self.eat_kw(&TokenKind::KwUnbounded) {
2177 if self.eat_kw(&TokenKind::KwPreceding) {
2178 Ok(FrameBound::UnboundedPreceding)
2179 } else {
2180 self.expect_kw(&TokenKind::KwFollowing)?;
2181 Ok(FrameBound::UnboundedFollowing)
2182 }
2183 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2184 self.advance();
2185 self.expect_kw(&TokenKind::KwRow)?;
2186 Ok(FrameBound::CurrentRow)
2187 } else {
2188 let expr = self.parse_expr()?;
2189 if self.eat_kw(&TokenKind::KwPreceding) {
2190 Ok(FrameBound::Preceding(Box::new(expr)))
2191 } else {
2192 self.expect_kw(&TokenKind::KwFollowing)?;
2193 Ok(FrameBound::Following(Box::new(expr)))
2194 }
2195 }
2196 }
2197}
2198
2199fn parse_statements_with_scratch_inner(
2200 sql: &str,
2201 scratch: &mut StatementParseScratch,
2202) -> (Vec<Statement>, Option<ParseError>) {
2203 Lexer::tokenize_into_with_interner(sql, &mut scratch.tokens, &mut scratch.identifier_interner);
2204 let mut parser = Parser {
2205 tokens: std::mem::take(&mut scratch.tokens),
2206 pos: 0,
2207 errors: std::mem::take(&mut scratch.errors),
2208 depth: 0,
2209 };
2210 let (statements, errors) = parser.parse_all();
2211 scratch.tokens = parser.tokens;
2212 scratch.tokens.clear();
2213 scratch.identifier_interner.prepare_for_next_parse();
2214 scratch.errors = errors;
2215 let first_error = scratch.errors.first().cloned();
2216 scratch.errors.clear();
2217 (statements, first_error)
2218}
2219
2220pub fn parse_statements_with_scratch(
2222 sql: &str,
2223 scratch: &mut StatementParseScratch,
2224) -> Result<Vec<Statement>, ParseError> {
2225 let (statements, first_error) = parse_statements_with_scratch_inner(sql, scratch);
2226 if let Some(error) = first_error {
2227 return Err(error);
2228 }
2229 if statements.is_empty() {
2230 return Err(ParseError::at("no SQL statement provided", None));
2231 }
2232 Ok(statements)
2233}
2234
2235pub fn parse_single_statement_with_scratch(
2237 sql: &str,
2238 scratch: &mut StatementParseScratch,
2239) -> Result<Statement, ParseError> {
2240 let statements = parse_statements_with_scratch(sql, scratch)?;
2241 let mut iter = statements.into_iter();
2242 let statement = iter
2243 .next()
2244 .ok_or_else(|| ParseError::at("no SQL statement provided", None))?;
2245 if iter.next().is_some() {
2246 return Err(ParseError::at(
2247 "multiple statements are not supported in this API path",
2248 None,
2249 ));
2250 }
2251 Ok(statement)
2252}
2253
2254pub fn parse_first_statement_with_tail(
2262 sql: &str,
2263) -> Result<Option<(Statement, usize)>, ParseError> {
2264 let mut parser = Parser::from_sql(sql);
2265
2266 while parser.eat(&TokenKind::Semicolon) {}
2267 if parser.at_eof() {
2268 return Ok(None);
2269 }
2270
2271 let statement = parser.parse_statement()?;
2272 let tail_offset = if parser.eat(&TokenKind::Semicolon) {
2273 parser
2274 .tokens
2275 .get(parser.pos.saturating_sub(1))
2276 .map_or(sql.len(), |token| token.span.end as usize)
2277 } else if parser.at_eof() {
2278 sql.len()
2279 } else {
2280 return Err(ParseError::at(
2281 "unexpected token after end of statement; expected ';' separator",
2282 parser.current(),
2283 ));
2284 };
2285
2286 Ok(Some((statement, tail_offset)))
2287}
2288
2289pub(crate) fn is_nonreserved_kw(k: &TokenKind) -> bool {
2294 matches!(
2295 k,
2296 TokenKind::KwAbort
2297 | TokenKind::KwAction
2298 | TokenKind::KwAfter
2299 | TokenKind::KwAlways
2300 | TokenKind::KwAnalyze
2301 | TokenKind::KwAsc
2302 | TokenKind::KwBefore
2303 | TokenKind::KwCascade
2304 | TokenKind::KwColumn
2305 | TokenKind::KwConcurrent
2306 | TokenKind::KwConflict
2307 | TokenKind::KwDatabase
2308 | TokenKind::KwDeferred
2309 | TokenKind::KwDesc
2310 | TokenKind::KwDo
2311 | TokenKind::KwEach
2312 | TokenKind::KwEnd
2313 | TokenKind::KwExclude
2314 | TokenKind::KwExclusive
2315 | TokenKind::KwFail
2316 | TokenKind::KwFilter
2317 | TokenKind::KwFirst
2318 | TokenKind::KwFollowing
2319 | TokenKind::KwFull
2320 | TokenKind::KwGenerated
2321 | TokenKind::KwGroups
2322 | TokenKind::KwIf
2323 | TokenKind::KwIgnore
2324 | TokenKind::KwImmediate
2325 | TokenKind::KwIndex
2326 | TokenKind::KwInitially
2327 | TokenKind::KwInstead
2328 | TokenKind::KwKey
2329 | TokenKind::KwLast
2330 | TokenKind::KwMatch
2331 | TokenKind::KwMaterialized
2332 | TokenKind::KwNo
2333 | TokenKind::KwNothing
2334 | TokenKind::KwNulls
2335 | TokenKind::KwOf
2336 | TokenKind::KwOffset
2337 | TokenKind::KwOthers
2338 | TokenKind::KwOver
2339 | TokenKind::KwPartition
2340 | TokenKind::KwPlan
2341 | TokenKind::KwPragma
2342 | TokenKind::KwPreceding
2343 | TokenKind::KwQuery
2344 | TokenKind::KwRange
2345 | TokenKind::KwRecursive
2346 | TokenKind::KwReindex
2347 | TokenKind::KwRelease
2348 | TokenKind::KwRename
2349 | TokenKind::KwReplace
2350 | TokenKind::KwRestrict
2351 | TokenKind::KwReturning
2352 | TokenKind::KwRow
2353 | TokenKind::KwRows
2354 | TokenKind::KwSavepoint
2355 | TokenKind::KwStored
2356 | TokenKind::KwStrict
2357 | TokenKind::KwTable
2358 | TokenKind::KwTemp
2359 | TokenKind::KwTemporary
2360 | TokenKind::KwTies
2361 | TokenKind::KwTransaction
2362 | TokenKind::KwTrigger
2363 | TokenKind::KwUnbounded
2364 | TokenKind::KwVacuum
2365 | TokenKind::KwView
2366 | TokenKind::KwVirtual
2367 | TokenKind::KwWindow
2368 | TokenKind::KwWithout
2369 )
2370}
2371
2372fn is_alias_terminator_kw(k: &TokenKind) -> bool {
2375 matches!(
2376 k,
2377 TokenKind::KwCross
2378 | TokenKind::KwExcept
2379 | TokenKind::KwFull
2380 | TokenKind::KwGroup
2381 | TokenKind::KwHaving
2382 | TokenKind::KwInner
2383 | TokenKind::KwIntersect
2384 | TokenKind::KwJoin
2385 | TokenKind::KwLeft
2386 | TokenKind::KwLimit
2387 | TokenKind::KwNatural
2388 | TokenKind::KwOffset
2389 | TokenKind::KwOn
2390 | TokenKind::KwOrder
2391 | TokenKind::KwOuter
2392 | TokenKind::KwReturning
2393 | TokenKind::KwRight
2394 | TokenKind::KwUnion
2395 | TokenKind::KwUsing
2396 | TokenKind::KwWhere
2397 | TokenKind::KwWindow
2398 )
2399}
2400
2401pub(crate) fn kw_to_str(k: &TokenKind) -> String {
2402 k.keyword_str()
2403 .map(|s| s.to_ascii_lowercase())
2404 .unwrap_or_else(|| {
2405 let dbg = format!("{k:?}");
2406 dbg.strip_prefix("Kw").unwrap_or(&dbg).to_ascii_lowercase()
2407 })
2408}
2409
2410#[cfg(test)]
2415mod tests {
2416 use super::*;
2417
2418 static PARSE_OBSERVABILITY_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
2419
2420 fn parse_ok(sql: &str) -> Vec<Statement> {
2421 let mut p = Parser::from_sql(sql);
2422 let (stmts, errs) = p.parse_all();
2423 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2424 stmts
2425 }
2426
2427 fn parse_one(sql: &str) -> Statement {
2428 let stmts = parse_ok(sql);
2429 assert_eq!(stmts.len(), 1, "expected 1 statement, got {}", stmts.len());
2430 stmts.into_iter().next().unwrap()
2431 }
2432
2433 #[test]
2434 fn test_parse_metrics_emitted_when_enabled() {
2435 let _guard = PARSE_OBSERVABILITY_LOCK
2436 .lock()
2437 .unwrap_or_else(|poisoned| poisoned.into_inner());
2438 let prev_metrics_enabled = parse_metrics_enabled();
2439 reset_parse_metrics();
2440 set_parse_metrics_enabled(true);
2441
2442 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
2443 let (stmts, errs) = parser.parse_all();
2444 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2445 assert_eq!(stmts.len(), 2);
2446
2447 let snapshot = parse_metrics_snapshot();
2448 assert!(snapshot.fsqlite_parse_statements_total >= 2);
2449
2450 set_parse_metrics_enabled(prev_metrics_enabled);
2451 reset_parse_metrics();
2452 }
2453
2454 #[test]
2455 fn test_parse_metrics_can_be_disabled_off_hot_path() {
2456 let _guard = PARSE_OBSERVABILITY_LOCK
2457 .lock()
2458 .unwrap_or_else(|poisoned| poisoned.into_inner());
2459 let prev_metrics_enabled = parse_metrics_enabled();
2460 reset_parse_metrics();
2461 set_parse_metrics_enabled(false);
2462
2463 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
2464 let (stmts, errs) = parser.parse_all();
2465 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2466 assert_eq!(stmts.len(), 2);
2467
2468 let snapshot = parse_metrics_snapshot();
2469 assert_eq!(snapshot.fsqlite_parse_statements_total, 0);
2470
2471 set_parse_metrics_enabled(prev_metrics_enabled);
2472 reset_parse_metrics();
2473 }
2474
2475 #[test]
2476 fn test_parse_depth_overflow_does_not_poison_following_statement() {
2477 let mut parser = Parser::from_sql("SELECT 1; SELECT 42;");
2478 parser.depth = MAX_PARSE_DEPTH - 1;
2479
2480 let first = parser.parse_statement();
2483 assert!(first.is_err(), "first statement should hit depth guard");
2484 assert_eq!(
2485 parser.depth,
2486 MAX_PARSE_DEPTH - 1,
2487 "depth must not leak upward on recursion-limit error"
2488 );
2489
2490 let _ = parser.eat(&TokenKind::Semicolon);
2494 let second = parser.parse_statement();
2495 assert!(
2496 second.is_err(),
2497 "second statement should still be parseable"
2498 );
2499 assert_eq!(
2500 parser.depth,
2501 MAX_PARSE_DEPTH - 1,
2502 "depth must remain stable across repeated recursion-limit errors"
2503 );
2504 }
2505
2506 #[test]
2507 fn test_parse_first_statement_with_tail_consumes_full_trigger_body() {
2508 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN INSERT INTO audit VALUES('first'); INSERT INTO audit VALUES('second'); END; SELECT 1;";
2509 let Some((statement, tail_offset)) =
2510 parse_first_statement_with_tail(sql).expect("trigger statement should parse")
2511 else {
2512 panic!("expected a trigger statement");
2513 };
2514
2515 assert!(matches!(statement, Statement::CreateTrigger(_)));
2516 assert_eq!(&sql[tail_offset..], " SELECT 1;");
2517 }
2518
2519 #[test]
2520 fn test_parse_first_statement_with_tail_rejects_adjacent_statements_without_separator() {
2521 let error = parse_first_statement_with_tail("SELECT 1 SELECT 2")
2522 .expect_err("adjacent statements without a semicolon must be rejected");
2523
2524 assert!(
2525 error.message.contains("expected ';' separator"),
2526 "unexpected error: {error:?}"
2527 );
2528 }
2529
2530 #[test]
2531 fn test_create_table_without_rowid_and_strict_round_trips_display() {
2532 let sql = "CREATE TABLE s (id INTEGER PRIMARY KEY) WITHOUT ROWID, STRICT";
2533 let Some((statement, _)) =
2534 parse_first_statement_with_tail(sql).expect("statement should parse")
2535 else {
2536 panic!("expected CREATE TABLE statement");
2537 };
2538
2539 assert_eq!(statement.to_string(), sql);
2540 }
2541
2542 #[test]
2543 fn test_error_recovery_does_not_fabricate_top_level_statements_from_trigger_body() {
2544 let mut parser = Parser::from_sql(
2545 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN XYZZY; SELECT 1; END; SELECT 2;",
2546 );
2547 let (stmts, errs) = parser.parse_all();
2548
2549 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
2550 assert_eq!(
2551 stmts.len(),
2552 1,
2553 "only the trailing top-level SELECT should remain"
2554 );
2555 assert!(
2556 matches!(
2557 &stmts[0],
2558 Statement::Select(select)
2559 if matches!(
2560 &select.body.select,
2561 SelectCore::Select { columns, .. }
2562 if matches!(
2563 columns.as_slice(),
2564 [ResultColumn::Expr {
2565 expr: Expr::Literal(Literal::Integer(2), _),
2566 alias: None,
2567 }]
2568 )
2569 )
2570 ),
2571 "parser must skip the malformed trigger instead of reinterpreting body tokens as top-level SQL: {stmts:?}"
2572 );
2573 }
2574
2575 #[test]
2576 fn test_error_recovery_recovers_values_statement_after_garbage() {
2577 let mut parser = Parser::from_sql("XYZZY VALUES (1);");
2578 let (stmts, errs) = parser.parse_all();
2579
2580 assert_eq!(errs.len(), 1, "expected one error for leading garbage");
2581 assert_eq!(stmts.len(), 1, "VALUES statement should still be recovered");
2582 assert!(matches!(stmts[0], Statement::Select(_)));
2583 }
2584
2585 #[test]
2586 fn test_error_recovery_does_not_swallow_top_level_sql_after_unbalanced_trigger_paren() {
2587 let mut parser = Parser::from_sql(
2588 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN SELECT (1; END; SELECT 2;",
2589 );
2590 let (stmts, errs) = parser.parse_all();
2591
2592 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
2593 assert_eq!(
2594 stmts.len(),
2595 1,
2596 "malformed trigger recovery must still preserve the trailing top-level SELECT"
2597 );
2598 assert!(
2599 matches!(
2600 &stmts[0],
2601 Statement::Select(select)
2602 if matches!(
2603 &select.body.select,
2604 SelectCore::Select { columns, .. }
2605 if matches!(
2606 columns.as_slice(),
2607 [ResultColumn::Expr {
2608 expr: Expr::Literal(Literal::Integer(2), _),
2609 alias: None,
2610 }]
2611 )
2612 )
2613 ),
2614 "parser must stop at the trigger END even when parentheses are left unbalanced: {stmts:?}"
2615 );
2616 }
2617
2618 #[test]
2619 fn select_literal() {
2620 let stmt = parse_one("SELECT 1");
2621 assert!(matches!(stmt, Statement::Select(_)));
2622 }
2623
2624 #[test]
2625 fn select_star_from() {
2626 let stmt = parse_one("SELECT * FROM t");
2627 if let Statement::Select(s) = stmt {
2628 if let SelectCore::Select { columns, from, .. } = &s.body.select {
2629 assert!(matches!(columns[0], ResultColumn::Star));
2630 assert!(from.is_some());
2631 } else {
2632 unreachable!("expected Select core");
2633 }
2634 } else {
2635 unreachable!("expected Select");
2636 }
2637 }
2638
2639 #[test]
2640 fn select_where_order_limit() {
2641 let stmt = parse_one("SELECT a FROM t WHERE a > 1 ORDER BY a LIMIT 10 OFFSET 5");
2642 if let Statement::Select(s) = stmt {
2643 assert!(s.limit.is_some());
2644 assert_eq!(s.order_by.len(), 1);
2645 } else {
2646 unreachable!("expected Select");
2647 }
2648 }
2649
2650 #[test]
2651 fn select_limit_comma_syntax_uses_offset_then_count() {
2652 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
2653 if let Statement::Select(s) = stmt {
2654 let limit = s.limit.expect("LIMIT clause");
2655 assert!(matches!(
2656 limit.limit,
2657 Expr::Literal(Literal::Integer(10), _)
2658 ));
2659 assert!(matches!(
2660 limit.offset,
2661 Some(Expr::Literal(Literal::Integer(5), _))
2662 ));
2663 } else {
2664 unreachable!("expected Select");
2665 }
2666 }
2667
2668 #[test]
2669 fn select_order_by_nulls_first_last() {
2670 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST, b DESC NULLS LAST");
2671 if let Statement::Select(s) = stmt {
2672 assert_eq!(s.order_by.len(), 2);
2673 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
2674 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
2675 assert_eq!(s.order_by[1].direction, Some(SortDirection::Desc));
2676 assert_eq!(s.order_by[1].nulls, Some(NullsOrder::Last));
2677 } else {
2678 unreachable!("expected Select");
2679 }
2680 }
2681
2682 #[test]
2683 fn select_from_indexed_by_hint() {
2684 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
2685 if let Statement::Select(s) = stmt {
2686 if let SelectCore::Select { from, .. } = &s.body.select {
2687 let from = from.as_ref().expect("FROM clause");
2688 match &from.source {
2689 TableOrSubquery::Table {
2690 index_hint: Some(IndexHint::IndexedBy(name)),
2691 ..
2692 } => assert_eq!(name, "idx_t"),
2693 other => unreachable!("expected indexed table source, got {other:?}"),
2694 }
2695 } else {
2696 unreachable!("expected Select core");
2697 }
2698 } else {
2699 unreachable!("expected Select");
2700 }
2701 }
2702
2703 #[test]
2704 fn select_from_not_indexed_hint() {
2705 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
2706 if let Statement::Select(s) = stmt {
2707 if let SelectCore::Select { from, .. } = &s.body.select {
2708 let from = from.as_ref().expect("FROM clause");
2709 match &from.source {
2710 TableOrSubquery::Table {
2711 index_hint: Some(IndexHint::NotIndexed),
2712 ..
2713 } => {}
2714 other => unreachable!("expected not-indexed table source, got {other:?}"),
2715 }
2716 } else {
2717 unreachable!("expected Select core");
2718 }
2719 } else {
2720 unreachable!("expected Select");
2721 }
2722 }
2723
2724 #[test]
2725 fn select_from_table_valued_function() {
2726 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
2727 if let Statement::Select(s) = stmt {
2728 if let SelectCore::Select { from, .. } = &s.body.select {
2729 let from = from.as_ref().expect("FROM clause");
2730 match &from.source {
2731 TableOrSubquery::TableFunction { name, args, alias } => {
2732 assert_eq!(name, "generate_series");
2733 assert_eq!(args.len(), 2);
2734 assert_eq!(alias.as_deref(), Some("gs"));
2735 }
2736 other => unreachable!("expected table-valued function source, got {other:?}"),
2737 }
2738 } else {
2739 unreachable!("expected Select core");
2740 }
2741 } else {
2742 unreachable!("expected Select");
2743 }
2744 }
2745
2746 #[test]
2747 fn select_window_function_over_clause() {
2748 let stmt = parse_one(
2749 "SELECT sum(x) OVER (PARTITION BY y ORDER BY z \
2750 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
2751 );
2752 if let Statement::Select(s) = stmt {
2753 if let SelectCore::Select { columns, .. } = &s.body.select {
2754 match &columns[0] {
2755 ResultColumn::Expr {
2756 expr:
2757 Expr::FunctionCall {
2758 over: Some(over), ..
2759 },
2760 ..
2761 } => {
2762 assert_eq!(over.partition_by.len(), 1);
2763 assert_eq!(over.order_by.len(), 1);
2764 assert!(matches!(
2765 over.frame,
2766 Some(FrameSpec {
2767 frame_type: FrameType::Rows,
2768 ..
2769 })
2770 ));
2771 }
2772 other => unreachable!("expected window function result column, got {other:?}"),
2773 }
2774 } else {
2775 unreachable!("expected Select core");
2776 }
2777 } else {
2778 unreachable!("expected Select");
2779 }
2780 }
2781
2782 #[test]
2783 fn select_named_window_definition_and_reference() {
2784 let stmt = parse_one(
2785 "SELECT sum(x) OVER win FROM t \
2786 WINDOW win AS (PARTITION BY y ORDER BY z)",
2787 );
2788 if let Statement::Select(s) = stmt {
2789 if let SelectCore::Select {
2790 columns, windows, ..
2791 } = &s.body.select
2792 {
2793 assert_eq!(windows.len(), 1);
2794 assert_eq!(windows[0].name, "win");
2795 assert_eq!(windows[0].spec.partition_by.len(), 1);
2796 assert_eq!(windows[0].spec.order_by.len(), 1);
2797 match &columns[0] {
2798 ResultColumn::Expr {
2799 expr:
2800 Expr::FunctionCall {
2801 over: Some(over), ..
2802 },
2803 ..
2804 } => assert_eq!(over.base_window.as_deref(), Some("win")),
2805 other => unreachable!("expected named window function, got {other:?}"),
2806 }
2807 } else {
2808 unreachable!("expected Select core");
2809 }
2810 } else {
2811 unreachable!("expected Select");
2812 }
2813 }
2814
2815 #[test]
2816 fn insert_values() {
2817 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2), (3, 4)");
2818 assert!(matches!(stmt, Statement::Insert(_)));
2819 }
2820
2821 #[test]
2822 fn update_set() {
2823 let stmt = parse_one("UPDATE t SET a = 1, b = 2 WHERE id = 3");
2824 assert!(matches!(stmt, Statement::Update(_)));
2825 }
2826
2827 #[test]
2828 fn delete_from() {
2829 let stmt = parse_one("DELETE FROM t WHERE id = 1");
2830 assert!(matches!(stmt, Statement::Delete(_)));
2831 }
2832
2833 #[test]
2834 fn create_table_basic() {
2835 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT NOT NULL)");
2836 if let Statement::CreateTable(ct) = stmt {
2837 assert_eq!(ct.name.name, "t");
2838 if let CreateTableBody::Columns { columns, .. } = ct.body {
2839 assert_eq!(columns.len(), 2);
2840 } else {
2841 unreachable!("expected column defs");
2842 }
2843 } else {
2844 unreachable!("expected CreateTable");
2845 }
2846 }
2847
2848 #[test]
2849 fn create_index() {
2850 let stmt = parse_one("CREATE UNIQUE INDEX idx ON t (a, b DESC)");
2851 if let Statement::CreateIndex(ci) = stmt {
2852 assert!(ci.unique);
2853 assert_eq!(ci.columns.len(), 2);
2854 } else {
2855 unreachable!("expected CreateIndex");
2856 }
2857 }
2858
2859 #[test]
2860 fn drop_table_if_exists() {
2861 let stmt = parse_one("DROP TABLE IF EXISTS t");
2862 if let Statement::Drop(d) = stmt {
2863 assert!(d.if_exists);
2864 assert_eq!(d.object_type, DropObjectType::Table);
2865 } else {
2866 unreachable!("expected Drop");
2867 }
2868 }
2869
2870 #[test]
2871 fn begin_commit() {
2872 let stmts = parse_ok("BEGIN IMMEDIATE; COMMIT");
2873 assert_eq!(stmts.len(), 2);
2874 if let Statement::Begin(b) = &stmts[0] {
2875 assert_eq!(b.mode, Some(TransactionMode::Immediate));
2876 } else {
2877 unreachable!("expected Begin");
2878 }
2879 assert!(matches!(stmts[1], Statement::Commit));
2880 }
2881
2882 #[test]
2883 fn begin_concurrent() {
2884 let stmt = parse_one("BEGIN CONCURRENT");
2885 if let Statement::Begin(b) = stmt {
2886 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
2887 } else {
2888 unreachable!("expected Begin");
2889 }
2890 }
2891
2892 #[test]
2893 fn rollback_to_savepoint() {
2894 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
2895 if let Statement::Rollback(r) = stmt {
2896 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
2897 } else {
2898 unreachable!("expected Rollback");
2899 }
2900 }
2901
2902 #[test]
2903 fn explain_query_plan() {
2904 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT 1");
2905 assert!(matches!(
2906 stmt,
2907 Statement::Explain {
2908 query_plan: true,
2909 ..
2910 }
2911 ));
2912 }
2913
2914 #[test]
2915 fn pragma() {
2916 let stmt = parse_one("PRAGMA journal_mode = WAL");
2917 assert!(matches!(stmt, Statement::Pragma(_)));
2918 }
2919
2920 #[test]
2921 fn pragma_allows_on_value() {
2922 let stmt = parse_one("PRAGMA fsqlite.serializable = ON");
2923 assert!(matches!(stmt, Statement::Pragma(_)));
2924 }
2925
2926 #[test]
2927 fn error_recovery_multiple_statements() {
2928 let mut p = Parser::from_sql("SELECT 1; XYZZY; SELECT 2");
2929 let (stmts, errs) = p.parse_all();
2930 assert_eq!(stmts.len(), 2, "should recover: stmts={stmts:?}");
2931 assert!(!errs.is_empty());
2932 }
2933
2934 #[test]
2935 fn compound_union() {
2936 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
2937 if let Statement::Select(s) = stmt {
2938 assert_eq!(s.body.compounds.len(), 1);
2939 } else {
2940 unreachable!("expected Select");
2941 }
2942 }
2943
2944 #[test]
2945 fn alter_table_rename() {
2946 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
2947 assert!(matches!(
2948 stmt,
2949 Statement::AlterTable(AlterTableStatement {
2950 action: AlterTableAction::RenameTo(_),
2951 ..
2952 })
2953 ));
2954 }
2955
2956 #[test]
2961 fn test_parser_join_inner() {
2962 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
2963 if let Statement::Select(s) = stmt {
2964 if let SelectCore::Select { from, .. } = &s.body.select {
2965 let from = from.as_ref().expect("FROM clause");
2966 assert!(!from.joins.is_empty());
2967 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
2968 } else {
2969 unreachable!("expected Select core");
2970 }
2971 } else {
2972 unreachable!("expected Select");
2973 }
2974 }
2975
2976 #[test]
2977 fn test_parser_join_left() {
2978 let stmt = parse_one("SELECT * FROM a LEFT JOIN b ON a.id = b.a_id");
2979 if let Statement::Select(s) = stmt {
2980 if let SelectCore::Select { from, .. } = &s.body.select {
2981 let from = from.as_ref().expect("FROM clause");
2982 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
2983 } else {
2984 unreachable!("expected Select core");
2985 }
2986 } else {
2987 unreachable!("expected Select");
2988 }
2989 }
2990
2991 #[test]
2992 fn test_parser_join_left_outer() {
2993 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
2994 if let Statement::Select(s) = stmt {
2995 if let SelectCore::Select { from, .. } = &s.body.select {
2996 let from = from.as_ref().expect("FROM clause");
2997 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
2998 } else {
2999 unreachable!("expected Select core");
3000 }
3001 } else {
3002 unreachable!("expected Select");
3003 }
3004 }
3005
3006 #[test]
3007 fn test_parser_join_right() {
3008 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
3009 if let Statement::Select(s) = stmt {
3010 if let SelectCore::Select { from, .. } = &s.body.select {
3011 let from = from.as_ref().expect("FROM clause");
3012 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
3013 } else {
3014 unreachable!("expected Select core");
3015 }
3016 } else {
3017 unreachable!("expected Select");
3018 }
3019 }
3020
3021 #[test]
3022 fn test_parser_join_full() {
3023 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
3024 if let Statement::Select(s) = stmt {
3025 if let SelectCore::Select { from, .. } = &s.body.select {
3026 let from = from.as_ref().expect("FROM clause");
3027 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3028 } else {
3029 unreachable!("expected Select core");
3030 }
3031 } else {
3032 unreachable!("expected Select");
3033 }
3034 }
3035
3036 #[test]
3037 fn test_parser_join_full_outer_with_semicolon() {
3038 let stmt = parse_one("SELECT l.name, r.tag FROM l FULL OUTER JOIN r ON l.id = r.l_id;");
3039 if let Statement::Select(s) = stmt {
3040 if let SelectCore::Select { from, .. } = &s.body.select {
3041 let from = from.as_ref().expect("FROM clause");
3042 assert_eq!(from.joins.len(), 1);
3043 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3044 } else {
3045 unreachable!("expected Select core");
3046 }
3047 } else {
3048 unreachable!("expected Select");
3049 }
3050 }
3051
3052 #[test]
3053 fn test_parser_join_cross() {
3054 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
3055 if let Statement::Select(s) = stmt {
3056 if let SelectCore::Select { from, .. } = &s.body.select {
3057 let from = from.as_ref().expect("FROM clause");
3058 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3059 } else {
3060 unreachable!("expected Select core");
3061 }
3062 } else {
3063 unreachable!("expected Select");
3064 }
3065 }
3066
3067 #[test]
3068 fn test_parser_join_natural() {
3069 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
3070 if let Statement::Select(s) = stmt {
3071 if let SelectCore::Select { from, .. } = &s.body.select {
3072 let from = from.as_ref().expect("FROM clause");
3073 assert!(from.joins[0].join_type.natural);
3074 } else {
3075 unreachable!("expected Select core");
3076 }
3077 } else {
3078 unreachable!("expected Select");
3079 }
3080 }
3081
3082 #[test]
3083 fn test_parser_join_using() {
3084 let stmt = parse_one("SELECT * FROM a JOIN b USING (id)");
3085 if let Statement::Select(s) = stmt {
3086 if let SelectCore::Select { from, .. } = &s.body.select {
3087 let from = from.as_ref().expect("FROM clause");
3088 assert!(matches!(
3089 from.joins[0].constraint,
3090 Some(JoinConstraint::Using(_))
3091 ));
3092 } else {
3093 unreachable!("expected Select core");
3094 }
3095 } else {
3096 unreachable!("expected Select");
3097 }
3098 }
3099
3100 #[test]
3101 fn test_parser_join_comma() {
3102 let stmt = parse_one("SELECT * FROM a, b WHERE a.id = b.a_id");
3104 if let Statement::Select(s) = stmt {
3105 if let SelectCore::Select { from, .. } = &s.body.select {
3106 let from = from.as_ref().expect("FROM clause");
3107 assert!(!from.joins.is_empty());
3108 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3109 } else {
3110 unreachable!("expected Select core");
3111 }
3112 } else {
3113 unreachable!("expected Select");
3114 }
3115 }
3116
3117 #[test]
3122 fn test_parser_cte_basic() {
3123 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
3124 if let Statement::Select(s) = stmt {
3125 let with = s.with.as_ref().expect("WITH clause");
3126 assert!(!with.recursive);
3127 assert_eq!(with.ctes.len(), 1);
3128 assert_eq!(with.ctes[0].name, "cte");
3129 } else {
3130 unreachable!("expected Select");
3131 }
3132 }
3133
3134 #[test]
3135 fn test_parser_cte_multiple() {
3136 let stmt = parse_one("WITH a AS (SELECT 1), b AS (SELECT 2) SELECT * FROM a, b");
3137 if let Statement::Select(s) = stmt {
3138 let with = s.with.as_ref().expect("WITH clause");
3139 assert_eq!(with.ctes.len(), 2);
3140 assert_eq!(with.ctes[0].name, "a");
3141 assert_eq!(with.ctes[1].name, "b");
3142 } else {
3143 unreachable!("expected Select");
3144 }
3145 }
3146
3147 #[test]
3148 fn test_parser_cte_recursive() {
3149 let stmt = parse_one(
3150 "WITH RECURSIVE cnt(x) AS (\
3151 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
3152 ) SELECT x FROM cnt",
3153 );
3154 if let Statement::Select(s) = stmt {
3155 let with = s.with.as_ref().expect("WITH clause");
3156 assert!(with.recursive);
3157 assert_eq!(with.ctes[0].name, "cnt");
3158 assert_eq!(with.ctes[0].columns, vec!["x".to_owned()]);
3159 } else {
3160 unreachable!("expected Select");
3161 }
3162 }
3163
3164 #[test]
3165 fn test_parser_cte_materialized() {
3166 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
3167 if let Statement::Select(s) = stmt {
3168 let with = s.with.as_ref().expect("WITH clause");
3169 assert_eq!(
3170 with.ctes[0].materialized,
3171 Some(CteMaterialized::Materialized)
3172 );
3173 } else {
3174 unreachable!("expected Select");
3175 }
3176 }
3177
3178 #[test]
3183 fn test_select_table_star() {
3184 let stmt = parse_one("SELECT t1.* FROM t1, t2");
3185 if let Statement::Select(s) = stmt {
3186 if let SelectCore::Select { columns, .. } = &s.body.select {
3187 assert!(
3188 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::bare("t1")),
3189 "expected TableStar(t1), got {:?}",
3190 columns[0]
3191 );
3192 } else {
3193 unreachable!("expected Select core");
3194 }
3195 } else {
3196 unreachable!("expected Select");
3197 }
3198 }
3199
3200 #[test]
3201 fn test_select_schema_table_star() {
3202 let stmt = parse_one("SELECT aux.t1.* FROM aux.t1");
3203 if let Statement::Select(s) = stmt {
3204 if let SelectCore::Select { columns, .. } = &s.body.select {
3205 assert!(
3206 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::qualified("aux", "t1")),
3207 "expected TableStar(aux.t1), got {:?}",
3208 columns[0]
3209 );
3210 } else {
3211 unreachable!("expected Select core");
3212 }
3213 } else {
3214 unreachable!("expected Select");
3215 }
3216 }
3217
3218 #[test]
3219 fn test_select_expr_alias() {
3220 let stmt = parse_one("SELECT x + 1 AS result FROM t");
3221 if let Statement::Select(s) = stmt {
3222 if let SelectCore::Select { columns, .. } = &s.body.select {
3223 match &columns[0] {
3224 ResultColumn::Expr {
3225 alias: Some(alias), ..
3226 } => assert_eq!(alias, "result"),
3227 other => unreachable!("expected aliased expr column, got {other:?}"),
3228 }
3229 } else {
3230 unreachable!("expected Select core");
3231 }
3232 } else {
3233 unreachable!("expected Select");
3234 }
3235 }
3236
3237 #[test]
3238 fn test_select_distinct_keyword() {
3239 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
3240 if let Statement::Select(s) = stmt {
3241 if let SelectCore::Select {
3242 distinct, columns, ..
3243 } = &s.body.select
3244 {
3245 assert_eq!(*distinct, Distinctness::Distinct);
3246 assert_eq!(columns.len(), 2);
3247 } else {
3248 unreachable!("expected Select core");
3249 }
3250 } else {
3251 unreachable!("expected Select");
3252 }
3253 }
3254
3255 #[test]
3256 fn test_select_values_clause() {
3257 let stmt = parse_one("VALUES (1, 2), (3, 4)");
3258 if let Statement::Select(s) = stmt {
3259 if let SelectCore::Values(rows) = &s.body.select {
3260 assert_eq!(rows.len(), 2);
3261 assert_eq!(rows[0].len(), 2);
3262 assert_eq!(rows[1].len(), 2);
3263 } else {
3264 unreachable!("expected Values core");
3265 }
3266 } else {
3267 unreachable!("expected Select");
3268 }
3269 }
3270
3271 #[test]
3272 fn test_select_group_by_having() {
3273 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
3274 if let Statement::Select(s) = stmt {
3275 if let SelectCore::Select {
3276 group_by, having, ..
3277 } = &s.body.select
3278 {
3279 assert_eq!(group_by.len(), 1);
3280 assert!(having.is_some(), "HAVING clause must be present");
3281 } else {
3282 unreachable!("expected Select core");
3283 }
3284 } else {
3285 unreachable!("expected Select");
3286 }
3287 }
3288
3289 #[test]
3290 fn test_compound_union() {
3291 let stmt = parse_one("SELECT 1 UNION SELECT 2");
3292 if let Statement::Select(s) = stmt {
3293 assert_eq!(s.body.compounds.len(), 1);
3294 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
3295 } else {
3296 unreachable!("expected Select");
3297 }
3298 }
3299
3300 #[test]
3301 fn test_compound_union_all() {
3302 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
3303 if let Statement::Select(s) = stmt {
3304 assert_eq!(s.body.compounds.len(), 1);
3305 assert_eq!(s.body.compounds[0].0, CompoundOp::UnionAll);
3306 } else {
3307 unreachable!("expected Select");
3308 }
3309 }
3310
3311 #[test]
3312 fn test_compound_intersect() {
3313 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
3314 if let Statement::Select(s) = stmt {
3315 assert_eq!(s.body.compounds.len(), 1);
3316 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
3317 } else {
3318 unreachable!("expected Select");
3319 }
3320 }
3321
3322 #[test]
3323 fn test_compound_except() {
3324 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
3325 if let Statement::Select(s) = stmt {
3326 assert_eq!(s.body.compounds.len(), 1);
3327 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
3328 } else {
3329 unreachable!("expected Select");
3330 }
3331 }
3332
3333 #[test]
3334 fn test_compound_order_applies_to_whole() {
3335 let stmt = parse_one("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
3337 if let Statement::Select(s) = stmt {
3338 assert_eq!(s.body.compounds.len(), 1);
3339 assert_eq!(s.order_by.len(), 1, "ORDER BY must be on compound");
3340 assert!(s.limit.is_some(), "LIMIT must be on compound");
3341 } else {
3342 unreachable!("expected Select");
3343 }
3344 }
3345
3346 #[test]
3347 fn test_compound_three_way() {
3348 let stmt = parse_one("SELECT 1 UNION SELECT 2 INTERSECT SELECT 3");
3349 if let Statement::Select(s) = stmt {
3350 assert_eq!(s.body.compounds.len(), 2);
3351 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
3352 assert_eq!(s.body.compounds[1].0, CompoundOp::Intersect);
3353 } else {
3354 unreachable!("expected Select");
3355 }
3356 }
3357
3358 #[test]
3359 fn test_cte_not_materialized() {
3360 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3361 if let Statement::Select(s) = stmt {
3362 let with = s.with.as_ref().expect("WITH clause");
3363 assert_eq!(
3364 with.ctes[0].materialized,
3365 Some(CteMaterialized::NotMaterialized)
3366 );
3367 } else {
3368 unreachable!("expected Select");
3369 }
3370 }
3371
3372 #[test]
3373 fn test_cte_with_explicit_columns() {
3374 let stmt = parse_one("WITH cte(a, b, c) AS (SELECT 1, 2, 3) SELECT * FROM cte");
3375 if let Statement::Select(s) = stmt {
3376 let with = s.with.as_ref().expect("WITH clause");
3377 assert_eq!(with.ctes[0].columns, vec!["a", "b", "c"]);
3378 } else {
3379 unreachable!("expected Select");
3380 }
3381 }
3382
3383 #[test]
3384 fn test_window_frame_range() {
3385 let stmt = parse_one(
3386 "SELECT sum(x) OVER (ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t",
3387 );
3388 if let Statement::Select(s) = stmt {
3389 if let SelectCore::Select { columns, .. } = &s.body.select {
3390 match &columns[0] {
3391 ResultColumn::Expr {
3392 expr:
3393 Expr::FunctionCall {
3394 over: Some(over), ..
3395 },
3396 ..
3397 } => {
3398 let frame = over.frame.as_ref().expect("frame spec");
3399 assert_eq!(frame.frame_type, FrameType::Range);
3400 assert!(matches!(frame.start, FrameBound::UnboundedPreceding));
3401 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
3402 }
3403 other => unreachable!("expected window function, got {other:?}"),
3404 }
3405 } else {
3406 unreachable!("expected Select core");
3407 }
3408 } else {
3409 unreachable!("expected Select");
3410 }
3411 }
3412
3413 #[test]
3414 fn test_window_frame_groups() {
3415 let stmt = parse_one(
3416 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
3417 );
3418 if let Statement::Select(s) = stmt {
3419 if let SelectCore::Select { columns, .. } = &s.body.select {
3420 match &columns[0] {
3421 ResultColumn::Expr {
3422 expr:
3423 Expr::FunctionCall {
3424 over: Some(over), ..
3425 },
3426 ..
3427 } => {
3428 let frame = over.frame.as_ref().expect("frame spec");
3429 assert_eq!(frame.frame_type, FrameType::Groups);
3430 assert!(matches!(frame.start, FrameBound::Preceding(_)));
3431 assert!(matches!(frame.end, Some(FrameBound::Following(_))));
3432 }
3433 other => unreachable!("expected window function, got {other:?}"),
3434 }
3435 } else {
3436 unreachable!("expected Select core");
3437 }
3438 } else {
3439 unreachable!("expected Select");
3440 }
3441 }
3442
3443 #[test]
3444 fn test_window_frame_exclude_current_row() {
3445 let stmt = parse_one(
3446 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3447 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3448 );
3449 if let Statement::Select(s) = stmt {
3450 if let SelectCore::Select { columns, .. } = &s.body.select {
3451 match &columns[0] {
3452 ResultColumn::Expr {
3453 expr:
3454 Expr::FunctionCall {
3455 over: Some(over), ..
3456 },
3457 ..
3458 } => {
3459 let frame = over.frame.as_ref().expect("frame spec");
3460 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
3461 }
3462 other => unreachable!("expected window function, got {other:?}"),
3463 }
3464 } else {
3465 unreachable!("expected Select core");
3466 }
3467 } else {
3468 unreachable!("expected Select");
3469 }
3470 }
3471
3472 #[test]
3473 fn test_window_frame_exclude_ties() {
3474 let stmt = parse_one(
3475 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3476 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3477 );
3478 if let Statement::Select(s) = stmt {
3479 if let SelectCore::Select { columns, .. } = &s.body.select {
3480 match &columns[0] {
3481 ResultColumn::Expr {
3482 expr:
3483 Expr::FunctionCall {
3484 over: Some(over), ..
3485 },
3486 ..
3487 } => {
3488 let frame = over.frame.as_ref().expect("frame spec");
3489 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
3490 }
3491 other => unreachable!("expected window function, got {other:?}"),
3492 }
3493 } else {
3494 unreachable!("expected Select core");
3495 }
3496 } else {
3497 unreachable!("expected Select");
3498 }
3499 }
3500
3501 #[test]
3502 fn test_window_frame_exclude_group() {
3503 let stmt =
3504 parse_one("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
3505 if let Statement::Select(s) = stmt {
3506 if let SelectCore::Select { columns, .. } = &s.body.select {
3507 match &columns[0] {
3508 ResultColumn::Expr {
3509 expr:
3510 Expr::FunctionCall {
3511 over: Some(over), ..
3512 },
3513 ..
3514 } => {
3515 let frame = over.frame.as_ref().expect("frame spec");
3516 assert_eq!(frame.frame_type, FrameType::Groups);
3517 assert_eq!(frame.exclude, Some(FrameExclude::Group));
3518 }
3519 other => unreachable!("expected window function, got {other:?}"),
3520 }
3521 } else {
3522 unreachable!("expected Select core");
3523 }
3524 } else {
3525 unreachable!("expected Select");
3526 }
3527 }
3528
3529 #[test]
3530 fn test_window_frame_unbounded_following() {
3531 let stmt = parse_one(
3532 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM t",
3533 );
3534 if let Statement::Select(s) = stmt {
3535 if let SelectCore::Select { columns, .. } = &s.body.select {
3536 match &columns[0] {
3537 ResultColumn::Expr {
3538 expr:
3539 Expr::FunctionCall {
3540 over: Some(over), ..
3541 },
3542 ..
3543 } => {
3544 let frame = over.frame.as_ref().expect("frame spec");
3545 assert!(matches!(frame.start, FrameBound::CurrentRow));
3546 assert!(matches!(frame.end, Some(FrameBound::UnboundedFollowing)));
3547 }
3548 other => unreachable!("expected window function, got {other:?}"),
3549 }
3550 } else {
3551 unreachable!("expected Select core");
3552 }
3553 } else {
3554 unreachable!("expected Select");
3555 }
3556 }
3557
3558 #[test]
3559 fn test_filter_clause_aggregate() {
3560 let stmt = parse_one("SELECT count(*) FILTER (WHERE x > 0) FROM t");
3561 if let Statement::Select(s) = stmt {
3562 if let SelectCore::Select { columns, .. } = &s.body.select {
3563 match &columns[0] {
3564 ResultColumn::Expr {
3565 expr: Expr::FunctionCall { filter, .. },
3566 ..
3567 } => {
3568 assert!(
3569 filter.is_some(),
3570 "FILTER clause must be present on aggregate"
3571 );
3572 }
3573 other => unreachable!("expected function call with filter, got {other:?}"),
3574 }
3575 } else {
3576 unreachable!("expected Select core");
3577 }
3578 } else {
3579 unreachable!("expected Select");
3580 }
3581 }
3582
3583 #[test]
3584 fn test_filter_clause_window() {
3585 let stmt = parse_one("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
3586 if let Statement::Select(s) = stmt {
3587 if let SelectCore::Select { columns, .. } = &s.body.select {
3588 match &columns[0] {
3589 ResultColumn::Expr {
3590 expr:
3591 Expr::FunctionCall {
3592 filter,
3593 over: Some(_),
3594 ..
3595 },
3596 ..
3597 } => {
3598 assert!(
3599 filter.is_some(),
3600 "FILTER clause must be present on window function"
3601 );
3602 }
3603 other => unreachable!("expected window function with filter, got {other:?}"),
3604 }
3605 } else {
3606 unreachable!("expected Select core");
3607 }
3608 } else {
3609 unreachable!("expected Select");
3610 }
3611 }
3612
3613 #[test]
3614 fn test_subquery_in_from() {
3615 let stmt = parse_one("SELECT sub.x FROM (SELECT 1 AS x) AS sub");
3616 if let Statement::Select(s) = stmt {
3617 if let SelectCore::Select { from, .. } = &s.body.select {
3618 let from = from.as_ref().expect("FROM clause");
3619 match &from.source {
3620 TableOrSubquery::Subquery { alias, .. } => {
3621 assert_eq!(alias.as_deref(), Some("sub"));
3622 }
3623 other => unreachable!("expected subquery source, got {other:?}"),
3624 }
3625 } else {
3626 unreachable!("expected Select core");
3627 }
3628 } else {
3629 unreachable!("expected Select");
3630 }
3631 }
3632
3633 #[test]
3634 fn test_multiple_joins_chain() {
3635 let stmt = parse_one(
3636 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id \
3637 LEFT JOIN c ON b.id = c.b_id \
3638 CROSS JOIN d",
3639 );
3640 if let Statement::Select(s) = stmt {
3641 if let SelectCore::Select { from, .. } = &s.body.select {
3642 let from = from.as_ref().expect("FROM clause");
3643 assert_eq!(from.joins.len(), 3);
3644 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3645 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
3646 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
3647 } else {
3648 unreachable!("expected Select core");
3649 }
3650 } else {
3651 unreachable!("expected Select");
3652 }
3653 }
3654
3655 #[test]
3656 fn test_natural_left_join() {
3657 let stmt = parse_one("SELECT * FROM a NATURAL LEFT JOIN b");
3658 if let Statement::Select(s) = stmt {
3659 if let SelectCore::Select { from, .. } = &s.body.select {
3660 let from = from.as_ref().expect("FROM clause");
3661 let jt = &from.joins[0].join_type;
3662 assert!(jt.natural, "must be NATURAL");
3663 assert_eq!(jt.kind, JoinKind::Left);
3664 } else {
3665 unreachable!("expected Select core");
3666 }
3667 } else {
3668 unreachable!("expected Select");
3669 }
3670 }
3671
3672 #[test]
3673 fn test_select_nulls_first_default_asc() {
3674 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3676 if let Statement::Select(s) = stmt {
3677 assert_eq!(s.order_by.len(), 1);
3678 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
3679 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
3680 } else {
3681 unreachable!("expected Select");
3682 }
3683 }
3684
3685 #[test]
3686 fn test_select_nulls_last_desc() {
3687 let stmt = parse_one("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3689 if let Statement::Select(s) = stmt {
3690 assert_eq!(s.order_by.len(), 1);
3691 assert_eq!(s.order_by[0].direction, Some(SortDirection::Desc));
3692 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
3693 } else {
3694 unreachable!("expected Select");
3695 }
3696 }
3697
3698 #[test]
3703 fn test_roundtrip_select_filter_clause() {
3704 assert_roundtrip("SELECT count(*) FILTER (WHERE x > 0) FROM t");
3705 }
3706
3707 #[test]
3708 fn test_roundtrip_select_window_frame_groups() {
3709 assert_roundtrip(
3710 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
3711 );
3712 }
3713
3714 #[test]
3715 fn test_roundtrip_select_window_frame_exclude() {
3716 assert_roundtrip(
3717 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3718 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3719 );
3720 assert_roundtrip(
3721 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3722 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3723 );
3724 assert_roundtrip("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
3725 }
3726
3727 #[test]
3728 fn test_roundtrip_select_nulls_order() {
3729 assert_roundtrip("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3730 assert_roundtrip("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3731 }
3732
3733 #[test]
3734 fn test_roundtrip_select_values() {
3735 assert_roundtrip("VALUES (1, 2), (3, 4)");
3736 }
3737
3738 #[test]
3739 fn test_roundtrip_select_compound_order_limit() {
3740 assert_roundtrip("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
3741 }
3742
3743 #[test]
3744 fn test_roundtrip_select_cte_not_materialized() {
3745 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3746 }
3747
3748 #[test]
3749 fn test_roundtrip_select_natural_left_join() {
3750 assert_roundtrip("SELECT * FROM a NATURAL LEFT JOIN b");
3751 }
3752
3753 #[test]
3754 fn test_roundtrip_select_indexed_by() {
3755 assert_roundtrip("SELECT * FROM t INDEXED BY idx_t WHERE x = 1");
3756 }
3757
3758 #[test]
3759 fn test_roundtrip_select_filter_window_combined() {
3760 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
3761 }
3762
3763 #[test]
3764 fn test_roundtrip_select_three_way_compound() {
3765 assert_roundtrip("SELECT 1 UNION SELECT 2 EXCEPT SELECT 3");
3766 }
3767
3768 #[test]
3769 fn test_roundtrip_select_multiple_joins() {
3770 assert_roundtrip(
3771 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id LEFT JOIN c ON b.id = c.b_id",
3772 );
3773 }
3774
3775 #[test]
3780 fn test_select_star() {
3781 let stmt = parse_one("SELECT * FROM t");
3783 if let Statement::Select(s) = stmt {
3784 if let SelectCore::Select { columns, .. } = &s.body.select {
3785 assert!(matches!(columns[0], ResultColumn::Star));
3786 } else {
3787 unreachable!("expected Select core");
3788 }
3789 } else {
3790 unreachable!("expected Select");
3791 }
3792 }
3793
3794 #[test]
3795 fn test_inner_join_on() {
3796 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
3798 if let Statement::Select(s) = stmt {
3799 if let SelectCore::Select { from, .. } = &s.body.select {
3800 let from = from.as_ref().expect("FROM clause");
3801 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3802 assert!(matches!(
3803 from.joins[0].constraint,
3804 Some(JoinConstraint::On(_))
3805 ));
3806 } else {
3807 unreachable!("expected Select core");
3808 }
3809 } else {
3810 unreachable!("expected Select");
3811 }
3812 }
3813
3814 #[test]
3815 fn test_left_outer_join() {
3816 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
3818 if let Statement::Select(s) = stmt {
3819 if let SelectCore::Select { from, .. } = &s.body.select {
3820 let from = from.as_ref().expect("FROM clause");
3821 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
3822 } else {
3823 unreachable!("expected Select core");
3824 }
3825 } else {
3826 unreachable!("expected Select");
3827 }
3828 }
3829
3830 #[test]
3831 fn test_right_outer_join() {
3832 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
3834 if let Statement::Select(s) = stmt {
3835 if let SelectCore::Select { from, .. } = &s.body.select {
3836 let from = from.as_ref().expect("FROM clause");
3837 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
3838 } else {
3839 unreachable!("expected Select core");
3840 }
3841 } else {
3842 unreachable!("expected Select");
3843 }
3844 }
3845
3846 #[test]
3847 fn test_full_outer_join() {
3848 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
3850 if let Statement::Select(s) = stmt {
3851 if let SelectCore::Select { from, .. } = &s.body.select {
3852 let from = from.as_ref().expect("FROM clause");
3853 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3854 } else {
3855 unreachable!("expected Select core");
3856 }
3857 } else {
3858 unreachable!("expected Select");
3859 }
3860 }
3861
3862 #[test]
3863 fn test_cross_join_no_reorder() {
3864 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
3866 if let Statement::Select(s) = stmt {
3867 if let SelectCore::Select { from, .. } = &s.body.select {
3868 let from = from.as_ref().expect("FROM clause");
3869 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3870 assert!(from.joins[0].constraint.is_none());
3872 } else {
3873 unreachable!("expected Select core");
3874 }
3875 } else {
3876 unreachable!("expected Select");
3877 }
3878 }
3879
3880 #[test]
3881 fn test_natural_join() {
3882 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
3884 if let Statement::Select(s) = stmt {
3885 if let SelectCore::Select { from, .. } = &s.body.select {
3886 let from = from.as_ref().expect("FROM clause");
3887 assert!(from.joins[0].join_type.natural);
3888 } else {
3889 unreachable!("expected Select core");
3890 }
3891 } else {
3892 unreachable!("expected Select");
3893 }
3894 }
3895
3896 #[test]
3897 fn test_using_clause() {
3898 let stmt = parse_one("SELECT * FROM a JOIN b USING (id, name)");
3900 if let Statement::Select(s) = stmt {
3901 if let SelectCore::Select { from, .. } = &s.body.select {
3902 let from = from.as_ref().expect("FROM clause");
3903 match &from.joins[0].constraint {
3904 Some(JoinConstraint::Using(cols)) => {
3905 assert_eq!(cols.len(), 2);
3906 assert_eq!(cols[0], "id");
3907 assert_eq!(cols[1], "name");
3908 }
3909 other => unreachable!("expected USING constraint, got {other:?}"),
3910 }
3911 } else {
3912 unreachable!("expected Select core");
3913 }
3914 } else {
3915 unreachable!("expected Select");
3916 }
3917 }
3918
3919 #[test]
3920 fn test_cte_basic() {
3921 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
3923 if let Statement::Select(s) = stmt {
3924 let with = s.with.as_ref().expect("WITH clause");
3925 assert!(!with.recursive);
3926 assert_eq!(with.ctes.len(), 1);
3927 assert_eq!(with.ctes[0].name, "cte");
3928 } else {
3929 unreachable!("expected Select");
3930 }
3931 }
3932
3933 #[test]
3934 fn test_cte_recursive_union_all() {
3935 let stmt = parse_one(
3937 "WITH RECURSIVE cnt(x) AS (\
3938 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
3939 ) SELECT x FROM cnt",
3940 );
3941 if let Statement::Select(s) = stmt {
3942 let with = s.with.as_ref().expect("WITH clause");
3943 assert!(with.recursive);
3944 assert_eq!(with.ctes[0].name, "cnt");
3945 let cte_body = &with.ctes[0].query;
3947 assert_eq!(cte_body.body.compounds.len(), 1);
3948 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::UnionAll);
3949 } else {
3950 unreachable!("expected Select");
3951 }
3952 }
3953
3954 #[test]
3955 fn test_cte_recursive_union_cycle_detection() {
3956 let stmt = parse_one(
3958 "WITH RECURSIVE paths(a, b) AS (\
3959 SELECT src, dst FROM edges \
3960 UNION \
3961 SELECT p.a, e.dst FROM paths p JOIN edges e ON p.b = e.src\
3962 ) SELECT * FROM paths",
3963 );
3964 if let Statement::Select(s) = stmt {
3965 let with = s.with.as_ref().expect("WITH clause");
3966 assert!(with.recursive);
3967 let cte_body = &with.ctes[0].query;
3969 assert_eq!(cte_body.body.compounds.len(), 1);
3970 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::Union);
3971 } else {
3972 unreachable!("expected Select");
3973 }
3974 }
3975
3976 #[test]
3977 fn test_cte_materialized_hint() {
3978 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
3980 if let Statement::Select(s) = stmt {
3981 let with = s.with.as_ref().expect("WITH clause");
3982 assert_eq!(
3983 with.ctes[0].materialized,
3984 Some(CteMaterialized::Materialized)
3985 );
3986 } else {
3987 unreachable!("expected Select");
3988 }
3989 }
3990
3991 #[test]
3992 fn test_cte_not_materialized_hint() {
3993 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3995 if let Statement::Select(s) = stmt {
3996 let with = s.with.as_ref().expect("WITH clause");
3997 assert_eq!(
3998 with.ctes[0].materialized,
3999 Some(CteMaterialized::NotMaterialized)
4000 );
4001 } else {
4002 unreachable!("expected Select");
4003 }
4004 }
4005
4006 #[test]
4007 fn test_window_partition_by() {
4008 let stmt = parse_one("SELECT sum(x) OVER (PARTITION BY dept) FROM emp");
4010 if let Statement::Select(s) = stmt {
4011 if let SelectCore::Select { columns, .. } = &s.body.select {
4012 match &columns[0] {
4013 ResultColumn::Expr {
4014 expr:
4015 Expr::FunctionCall {
4016 over: Some(over), ..
4017 },
4018 ..
4019 } => {
4020 assert_eq!(over.partition_by.len(), 1);
4021 }
4022 other => unreachable!("expected window function, got {other:?}"),
4023 }
4024 } else {
4025 unreachable!("expected Select core");
4026 }
4027 } else {
4028 unreachable!("expected Select");
4029 }
4030 }
4031
4032 #[test]
4033 fn test_window_order_by() {
4034 let stmt = parse_one("SELECT row_number() OVER (ORDER BY salary DESC) FROM emp");
4036 if let Statement::Select(s) = stmt {
4037 if let SelectCore::Select { columns, .. } = &s.body.select {
4038 match &columns[0] {
4039 ResultColumn::Expr {
4040 expr:
4041 Expr::FunctionCall {
4042 over: Some(over), ..
4043 },
4044 ..
4045 } => {
4046 assert_eq!(over.order_by.len(), 1);
4047 assert_eq!(over.order_by[0].direction, Some(SortDirection::Desc));
4048 }
4049 other => unreachable!("expected window function, got {other:?}"),
4050 }
4051 } else {
4052 unreachable!("expected Select core");
4053 }
4054 } else {
4055 unreachable!("expected Select");
4056 }
4057 }
4058
4059 #[test]
4060 fn test_window_frame_rows() {
4061 let stmt = parse_one(
4063 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
4064 );
4065 if let Statement::Select(s) = stmt {
4066 if let SelectCore::Select { columns, .. } = &s.body.select {
4067 match &columns[0] {
4068 ResultColumn::Expr {
4069 expr:
4070 Expr::FunctionCall {
4071 over: Some(over), ..
4072 },
4073 ..
4074 } => {
4075 let frame = over.frame.as_ref().expect("frame spec");
4076 assert_eq!(frame.frame_type, FrameType::Rows);
4077 assert!(matches!(frame.start, FrameBound::Preceding(_)));
4078 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
4079 }
4080 other => unreachable!("expected window function, got {other:?}"),
4081 }
4082 } else {
4083 unreachable!("expected Select core");
4084 }
4085 } else {
4086 unreachable!("expected Select");
4087 }
4088 }
4089
4090 #[test]
4091 fn test_window_exclude_current_row() {
4092 let stmt = parse_one(
4094 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
4095 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
4096 );
4097 if let Statement::Select(s) = stmt {
4098 if let SelectCore::Select { columns, .. } = &s.body.select {
4099 match &columns[0] {
4100 ResultColumn::Expr {
4101 expr:
4102 Expr::FunctionCall {
4103 over: Some(over), ..
4104 },
4105 ..
4106 } => {
4107 let frame = over.frame.as_ref().expect("frame spec");
4108 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
4109 }
4110 other => unreachable!("expected window function, got {other:?}"),
4111 }
4112 } else {
4113 unreachable!("expected Select core");
4114 }
4115 } else {
4116 unreachable!("expected Select");
4117 }
4118 }
4119
4120 #[test]
4121 fn test_window_exclude_ties() {
4122 let stmt = parse_one(
4124 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
4125 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
4126 );
4127 if let Statement::Select(s) = stmt {
4128 if let SelectCore::Select { columns, .. } = &s.body.select {
4129 match &columns[0] {
4130 ResultColumn::Expr {
4131 expr:
4132 Expr::FunctionCall {
4133 over: Some(over), ..
4134 },
4135 ..
4136 } => {
4137 let frame = over.frame.as_ref().expect("frame spec");
4138 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
4139 }
4140 other => unreachable!("expected window function, got {other:?}"),
4141 }
4142 } else {
4143 unreachable!("expected Select core");
4144 }
4145 } else {
4146 unreachable!("expected Select");
4147 }
4148 }
4149
4150 #[test]
4151 fn test_nulls_first_asc() {
4152 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
4154 if let Statement::Select(s) = stmt {
4155 assert_eq!(s.order_by.len(), 1);
4156 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
4157 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
4158 } else {
4159 unreachable!("expected Select");
4160 }
4161 }
4162
4163 #[test]
4164 fn test_nulls_last_asc() {
4165 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS LAST");
4167 if let Statement::Select(s) = stmt {
4168 assert_eq!(s.order_by.len(), 1);
4169 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
4170 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
4171 } else {
4172 unreachable!("expected Select");
4173 }
4174 }
4175
4176 #[test]
4177 fn test_distinct_deduplicates() {
4178 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
4180 if let Statement::Select(s) = stmt {
4181 if let SelectCore::Select { distinct, .. } = &s.body.select {
4182 assert_eq!(*distinct, Distinctness::Distinct);
4183 } else {
4184 unreachable!("expected Select core");
4185 }
4186 } else {
4187 unreachable!("expected Select");
4188 }
4189 }
4190
4191 #[test]
4192 fn test_limit_offset() {
4193 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET 20");
4195 if let Statement::Select(s) = stmt {
4196 let limit = s.limit.expect("LIMIT clause");
4197 assert!(matches!(
4198 limit.limit,
4199 Expr::Literal(Literal::Integer(10), _)
4200 ));
4201 assert!(matches!(
4202 limit.offset,
4203 Some(Expr::Literal(Literal::Integer(20), _))
4204 ));
4205 } else {
4206 unreachable!("expected Select");
4207 }
4208 }
4209
4210 #[test]
4211 fn test_limit_comma_syntax() {
4212 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
4214 if let Statement::Select(s) = stmt {
4215 let limit = s.limit.expect("LIMIT clause");
4216 assert!(matches!(
4218 limit.limit,
4219 Expr::Literal(Literal::Integer(10), _)
4220 ));
4221 assert!(matches!(
4222 limit.offset,
4223 Some(Expr::Literal(Literal::Integer(5), _))
4224 ));
4225 } else {
4226 unreachable!("expected Select");
4227 }
4228 }
4229
4230 #[test]
4231 fn test_negative_limit_unlimited() {
4232 let stmt = parse_one("SELECT a FROM t LIMIT -1");
4234 if let Statement::Select(s) = stmt {
4235 let limit = s.limit.expect("LIMIT clause");
4236 match &limit.limit {
4239 Expr::UnaryOp {
4240 op: fsqlite_ast::UnaryOp::Negate,
4241 ..
4242 } => {}
4243 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
4244 other => unreachable!("expected negative limit expression, got {other:?}"),
4245 }
4246 } else {
4247 unreachable!("expected Select");
4248 }
4249 }
4250
4251 #[test]
4252 fn test_negative_offset_zero() {
4253 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET -5");
4255 if let Statement::Select(s) = stmt {
4256 let limit = s.limit.expect("LIMIT clause");
4257 assert!(limit.offset.is_some());
4258 match limit.offset.as_ref().unwrap() {
4259 Expr::UnaryOp {
4260 op: fsqlite_ast::UnaryOp::Negate,
4261 ..
4262 } => {}
4263 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
4264 other => unreachable!("expected negative offset expression, got {other:?}"),
4265 }
4266 } else {
4267 unreachable!("expected Select");
4268 }
4269 }
4270
4271 #[test]
4272 fn test_current_date_constant() {
4273 let stmt = parse_one("SELECT CURRENT_DATE");
4275 if let Statement::Select(s) = stmt {
4276 if let SelectCore::Select { columns, .. } = &s.body.select {
4277 match &columns[0] {
4278 ResultColumn::Expr {
4279 expr: Expr::Literal(Literal::CurrentDate, _),
4280 ..
4281 } => {}
4282 other => unreachable!("expected CURRENT_DATE literal, got {other:?}"),
4283 }
4284 } else {
4285 unreachable!("expected Select core");
4286 }
4287 } else {
4288 unreachable!("expected Select");
4289 }
4290 }
4291
4292 #[test]
4293 fn test_current_time_constant() {
4294 let stmt = parse_one("SELECT CURRENT_TIME");
4296 if let Statement::Select(s) = stmt {
4297 if let SelectCore::Select { columns, .. } = &s.body.select {
4298 match &columns[0] {
4299 ResultColumn::Expr {
4300 expr: Expr::Literal(Literal::CurrentTime, _),
4301 ..
4302 } => {}
4303 other => unreachable!("expected CURRENT_TIME literal, got {other:?}"),
4304 }
4305 } else {
4306 unreachable!("expected Select core");
4307 }
4308 } else {
4309 unreachable!("expected Select");
4310 }
4311 }
4312
4313 #[test]
4314 fn test_current_timestamp_constant() {
4315 let stmt = parse_one("SELECT CURRENT_TIMESTAMP");
4317 if let Statement::Select(s) = stmt {
4318 if let SelectCore::Select { columns, .. } = &s.body.select {
4319 match &columns[0] {
4320 ResultColumn::Expr {
4321 expr: Expr::Literal(Literal::CurrentTimestamp, _),
4322 ..
4323 } => {}
4324 other => unreachable!("expected CURRENT_TIMESTAMP literal, got {other:?}"),
4325 }
4326 } else {
4327 unreachable!("expected Select core");
4328 }
4329 } else {
4330 unreachable!("expected Select");
4331 }
4332 }
4333
4334 #[test]
4335 fn test_date_constants_evaluated_once_per_statement() {
4336 let stmt = parse_one("SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP FROM t");
4339 if let Statement::Select(s) = stmt {
4340 if let SelectCore::Select { columns, .. } = &s.body.select {
4341 assert_eq!(columns.len(), 3);
4342 assert!(matches!(
4343 &columns[0],
4344 ResultColumn::Expr {
4345 expr: Expr::Literal(Literal::CurrentDate, _),
4346 ..
4347 }
4348 ));
4349 assert!(matches!(
4350 &columns[1],
4351 ResultColumn::Expr {
4352 expr: Expr::Literal(Literal::CurrentTime, _),
4353 ..
4354 }
4355 ));
4356 assert!(matches!(
4357 &columns[2],
4358 ResultColumn::Expr {
4359 expr: Expr::Literal(Literal::CurrentTimestamp, _),
4360 ..
4361 }
4362 ));
4363 } else {
4364 unreachable!("expected Select core");
4365 }
4366 } else {
4367 unreachable!("expected Select");
4368 }
4369 }
4370
4371 #[test]
4372 fn test_indexed_by_hint() {
4373 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
4375 if let Statement::Select(s) = stmt {
4376 if let SelectCore::Select { from, .. } = &s.body.select {
4377 let from = from.as_ref().expect("FROM clause");
4378 match &from.source {
4379 TableOrSubquery::Table {
4380 index_hint: Some(IndexHint::IndexedBy(name)),
4381 ..
4382 } => assert_eq!(name, "idx_t"),
4383 other => unreachable!("expected indexed table source, got {other:?}"),
4384 }
4385 } else {
4386 unreachable!("expected Select core");
4387 }
4388 } else {
4389 unreachable!("expected Select");
4390 }
4391 }
4392
4393 #[test]
4394 fn test_not_indexed_hint() {
4395 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
4397 if let Statement::Select(s) = stmt {
4398 if let SelectCore::Select { from, .. } = &s.body.select {
4399 let from = from.as_ref().expect("FROM clause");
4400 match &from.source {
4401 TableOrSubquery::Table {
4402 index_hint: Some(IndexHint::NotIndexed),
4403 ..
4404 } => {}
4405 other => unreachable!("expected not-indexed table source, got {other:?}"),
4406 }
4407 } else {
4408 unreachable!("expected Select core");
4409 }
4410 } else {
4411 unreachable!("expected Select");
4412 }
4413 }
4414
4415 #[test]
4416 fn test_table_valued_function_in_from() {
4417 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
4419 if let Statement::Select(s) = stmt {
4420 if let SelectCore::Select { from, .. } = &s.body.select {
4421 let from = from.as_ref().expect("FROM clause");
4422 match &from.source {
4423 TableOrSubquery::TableFunction { name, args, alias } => {
4424 assert_eq!(name, "generate_series");
4425 assert_eq!(args.len(), 2);
4426 assert_eq!(alias.as_deref(), Some("gs"));
4427 }
4428 other => unreachable!("expected table-valued function source, got {other:?}"),
4429 }
4430 } else {
4431 unreachable!("expected Select core");
4432 }
4433 } else {
4434 unreachable!("expected Select");
4435 }
4436 }
4437
4438 #[test]
4443 fn test_insert_values_single() {
4444 let stmt = parse_one("INSERT INTO t (a, b, c) VALUES (1, 'hello', 3.14)");
4445 if let Statement::Insert(i) = stmt {
4446 assert_eq!(i.columns, vec!["a", "b", "c"]);
4447 if let InsertSource::Values(rows) = &i.source {
4448 assert_eq!(rows.len(), 1);
4449 assert_eq!(rows[0].len(), 3);
4450 } else {
4451 unreachable!("expected Values source");
4452 }
4453 } else {
4454 unreachable!("expected Insert");
4455 }
4456 }
4457
4458 #[test]
4459 fn test_insert_values_multi() {
4460 let stmt = parse_one("INSERT INTO t (x, y) VALUES (1, 2), (3, 4), (5, 6)");
4461 if let Statement::Insert(i) = stmt {
4462 if let InsertSource::Values(rows) = &i.source {
4463 assert_eq!(rows.len(), 3);
4464 for row in rows {
4465 assert_eq!(row.len(), 2);
4466 }
4467 } else {
4468 unreachable!("expected Values source");
4469 }
4470 } else {
4471 unreachable!("expected Insert");
4472 }
4473 }
4474
4475 #[test]
4476 fn test_insert_from_select() {
4477 let stmt = parse_one("INSERT INTO t2 (a, b) SELECT x, y FROM t1 WHERE x > 0");
4478 if let Statement::Insert(i) = stmt {
4479 assert!(matches!(i.source, InsertSource::Select(_)));
4480 assert_eq!(i.columns, vec!["a", "b"]);
4481 } else {
4482 unreachable!("expected Insert");
4483 }
4484 }
4485
4486 #[test]
4487 fn test_insert_from_select_without_from_clause() {
4488 let stmt = parse_one("INSERT INTO t (a) SELECT 1");
4489 if let Statement::Insert(i) = stmt {
4490 if let InsertSource::Select(select) = &i.source {
4491 if let SelectCore::Select { from, columns, .. } = &select.body.select {
4492 assert!(from.is_none(), "SELECT 1 should parse without FROM");
4493 assert_eq!(columns.len(), 1);
4494 } else {
4495 unreachable!("expected Select core");
4496 }
4497 } else {
4498 unreachable!("expected Select source");
4499 }
4500 } else {
4501 unreachable!("expected Insert");
4502 }
4503 }
4504
4505 #[test]
4506 fn test_insert_from_select_subquery_source() {
4507 let stmt = parse_one("INSERT INTO t (a) SELECT sub.x FROM (SELECT 1 AS x) AS sub");
4508 if let Statement::Insert(i) = stmt {
4509 if let InsertSource::Select(select) = &i.source {
4510 if let SelectCore::Select { from, .. } = &select.body.select {
4511 let from = from.as_ref().expect("FROM clause");
4512 match &from.source {
4513 TableOrSubquery::Subquery { alias, .. } => {
4514 assert_eq!(alias.as_deref(), Some("sub"));
4515 }
4516 other => unreachable!("expected subquery source, got {other:?}"),
4517 }
4518 } else {
4519 unreachable!("expected Select core");
4520 }
4521 } else {
4522 unreachable!("expected Select source");
4523 }
4524 } else {
4525 unreachable!("expected Insert");
4526 }
4527 }
4528
4529 #[test]
4530 fn test_insert_from_select_table_function_source() {
4531 let stmt = parse_one("INSERT INTO t (a) SELECT gs.value FROM generate_series(1, 3) AS gs");
4532 if let Statement::Insert(i) = stmt {
4533 if let InsertSource::Select(select) = &i.source {
4534 if let SelectCore::Select { from, .. } = &select.body.select {
4535 let from = from.as_ref().expect("FROM clause");
4536 match &from.source {
4537 TableOrSubquery::TableFunction { name, args, alias } => {
4538 assert_eq!(name, "generate_series");
4539 assert_eq!(args.len(), 2);
4540 assert_eq!(alias.as_deref(), Some("gs"));
4541 }
4542 other => unreachable!("expected table function source, got {other:?}"),
4543 }
4544 } else {
4545 unreachable!("expected Select core");
4546 }
4547 } else {
4548 unreachable!("expected Select source");
4549 }
4550 } else {
4551 unreachable!("expected Insert");
4552 }
4553 }
4554
4555 #[test]
4556 fn test_insert_default_values() {
4557 let stmt = parse_one("INSERT INTO t DEFAULT VALUES");
4558 if let Statement::Insert(i) = stmt {
4559 assert!(matches!(i.source, InsertSource::DefaultValues));
4560 assert!(i.columns.is_empty());
4561 } else {
4562 unreachable!("expected Insert");
4563 }
4564 }
4565
4566 #[test]
4567 fn test_insert_or_abort() {
4568 let stmt = parse_one("INSERT OR ABORT INTO t (a) VALUES (1)");
4569 if let Statement::Insert(i) = stmt {
4570 assert_eq!(i.or_conflict, Some(ConflictAction::Abort));
4571 } else {
4572 unreachable!("expected Insert");
4573 }
4574 }
4575
4576 #[test]
4577 fn test_insert_or_rollback() {
4578 let stmt = parse_one("INSERT OR ROLLBACK INTO t (a) VALUES (1)");
4579 if let Statement::Insert(i) = stmt {
4580 assert_eq!(i.or_conflict, Some(ConflictAction::Rollback));
4581 } else {
4582 unreachable!("expected Insert");
4583 }
4584 }
4585
4586 #[test]
4587 fn test_insert_or_fail() {
4588 let stmt = parse_one("INSERT OR FAIL INTO t (a) VALUES (1)");
4589 if let Statement::Insert(i) = stmt {
4590 assert_eq!(i.or_conflict, Some(ConflictAction::Fail));
4591 } else {
4592 unreachable!("expected Insert");
4593 }
4594 }
4595
4596 #[test]
4597 fn test_insert_or_ignore() {
4598 let stmt = parse_one("INSERT OR IGNORE INTO t (a) VALUES (1)");
4599 if let Statement::Insert(i) = stmt {
4600 assert_eq!(i.or_conflict, Some(ConflictAction::Ignore));
4601 } else {
4602 unreachable!("expected Insert");
4603 }
4604 }
4605
4606 #[test]
4607 fn test_insert_or_replace() {
4608 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1)");
4610 if let Statement::Insert(i) = stmt {
4611 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4612 } else {
4613 unreachable!("expected Insert");
4614 }
4615 }
4616
4617 #[test]
4618 fn test_upsert_do_update() {
4619 let stmt = parse_one(
4620 "INSERT INTO t (a, b) VALUES (1, 2) ON CONFLICT (a) DO UPDATE SET b = excluded.b",
4621 );
4622 if let Statement::Insert(i) = stmt {
4623 assert_eq!(i.upsert.len(), 1);
4624 assert!(i.upsert[0].target.is_some());
4625 match &i.upsert[0].action {
4626 UpsertAction::Update {
4627 assignments,
4628 where_clause,
4629 } => {
4630 assert_eq!(assignments.len(), 1);
4631 assert!(where_clause.is_none());
4632 }
4633 UpsertAction::Nothing => unreachable!("expected Update action"),
4634 }
4635 } else {
4636 unreachable!("expected Insert");
4637 }
4638 }
4639
4640 #[test]
4641 fn test_upsert_do_nothing() {
4642 let stmt = parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
4643 if let Statement::Insert(i) = stmt {
4644 assert_eq!(i.upsert.len(), 1);
4645 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4646 } else {
4647 unreachable!("expected Insert");
4648 }
4649 }
4650
4651 #[test]
4652 fn test_upsert_excluded_pseudo_table() {
4653 let stmt = parse_one(
4654 "INSERT INTO t (a, b) VALUES (1, 2) \
4655 ON CONFLICT (a) DO UPDATE SET b = excluded.b, a = excluded.a + 1",
4656 );
4657 if let Statement::Insert(i) = stmt {
4658 assert_eq!(i.upsert.len(), 1);
4659 if let UpsertAction::Update { assignments, .. } = &i.upsert[0].action {
4660 assert_eq!(assignments.len(), 2);
4661 match &assignments[0].value {
4663 Expr::Column(col, _) => {
4664 assert_eq!(col.table.as_deref(), Some("excluded"));
4665 assert_eq!(col.column.as_ref(), "b");
4666 }
4667 other => unreachable!("expected Column ref to excluded.b, got {other:?}"),
4668 }
4669 } else {
4670 unreachable!("expected Update action");
4671 }
4672 } else {
4673 unreachable!("expected Insert");
4674 }
4675 }
4676
4677 #[test]
4678 fn test_upsert_multiple_on_conflict() {
4679 let stmt = parse_one(
4680 "INSERT INTO t (a, b) VALUES (1, 2) \
4681 ON CONFLICT (a) DO NOTHING \
4682 ON CONFLICT (b) DO UPDATE SET a = excluded.a",
4683 );
4684 if let Statement::Insert(i) = stmt {
4685 assert_eq!(i.upsert.len(), 2);
4686 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4687 assert!(matches!(i.upsert[1].action, UpsertAction::Update { .. }));
4688 } else {
4689 unreachable!("expected Insert");
4690 }
4691 }
4692
4693 #[test]
4694 fn test_upsert_where_on_conflict_target() {
4695 let stmt = parse_one(
4696 "INSERT INTO t (a, b) VALUES (1, 2) \
4697 ON CONFLICT (a) WHERE a > 0 DO UPDATE SET b = excluded.b WHERE b < 100",
4698 );
4699 if let Statement::Insert(i) = stmt {
4700 assert_eq!(i.upsert.len(), 1);
4701 let target = i.upsert[0].target.as_ref().expect("conflict target");
4702 assert!(target.where_clause.is_some(), "target WHERE missing");
4703 if let UpsertAction::Update { where_clause, .. } = &i.upsert[0].action {
4704 assert!(where_clause.is_some(), "action WHERE missing");
4705 } else {
4706 unreachable!("expected Update action");
4707 }
4708 } else {
4709 unreachable!("expected Insert");
4710 }
4711 }
4712
4713 #[test]
4714 fn test_returning_insert() {
4715 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, rowid");
4716 if let Statement::Insert(i) = stmt {
4717 assert_eq!(i.returning.len(), 3);
4718 } else {
4719 unreachable!("expected Insert");
4720 }
4721 }
4722
4723 #[test]
4724 fn test_returning_insert_select_with_semicolon() {
4725 let stmt = parse_one("INSERT INTO t2 SELECT * FROM t RETURNING *;");
4726 if let Statement::Insert(i) = stmt {
4727 assert!(matches!(i.source, InsertSource::Select(_)));
4728 assert_eq!(i.returning.len(), 1);
4729 assert!(matches!(i.returning[0], ResultColumn::Star));
4730 } else {
4731 unreachable!("expected Insert");
4732 }
4733 }
4734
4735 #[test]
4736 fn test_returning_reflects_before_triggers() {
4737 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING a AS modified_a");
4741 if let Statement::Insert(i) = stmt {
4742 assert_eq!(i.returning.len(), 1);
4743 match &i.returning[0] {
4744 ResultColumn::Expr { alias, .. } => {
4745 assert_eq!(alias.as_deref(), Some("modified_a"));
4746 }
4747 other => unreachable!("expected Expr result column, got {other:?}"),
4748 }
4749 } else {
4750 unreachable!("expected Insert");
4751 }
4752 }
4753
4754 #[test]
4755 fn test_returning_ignores_after_triggers() {
4756 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1) RETURNING *");
4760 if let Statement::Insert(i) = stmt {
4761 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4762 assert_eq!(i.returning.len(), 1);
4763 assert!(matches!(i.returning[0], ResultColumn::Star));
4764 } else {
4765 unreachable!("expected Insert");
4766 }
4767 }
4768
4769 #[test]
4770 fn test_returning_after_before_trigger_modify() {
4771 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, a + b AS total");
4775 if let Statement::Insert(i) = stmt {
4776 assert_eq!(i.returning.len(), 3);
4777 match &i.returning[2] {
4778 ResultColumn::Expr {
4779 alias: Some(alias), ..
4780 } => assert_eq!(alias, "total"),
4781 other => unreachable!("expected aliased expression, got {other:?}"),
4782 }
4783 } else {
4784 unreachable!("expected Insert");
4785 }
4786 }
4787
4788 #[test]
4789 fn test_returning_before_trigger_raise_abort() {
4790 let stmt = parse_one("INSERT INTO t (a) VALUES (1), (2), (3) RETURNING a");
4794 if let Statement::Insert(i) = stmt {
4795 if let InsertSource::Values(rows) = &i.source {
4796 assert_eq!(rows.len(), 3);
4797 } else {
4798 unreachable!("expected Values source");
4799 }
4800 assert_eq!(i.returning.len(), 1);
4801 } else {
4802 unreachable!("expected Insert");
4803 }
4804 }
4805
4806 #[test]
4807 fn test_returning_instead_of_view() {
4808 let stmt = parse_one("INSERT INTO v (a, b) VALUES (1, 2) RETURNING *");
4811 if let Statement::Insert(i) = stmt {
4812 assert_eq!(i.table.name, "v");
4813 assert!(!i.returning.is_empty());
4814 } else {
4815 unreachable!("expected Insert");
4816 }
4817 }
4818
4819 #[test]
4820 fn test_returning_autoincrement_with_trigger() {
4821 let stmt = parse_one("INSERT INTO t (name) VALUES ('test') RETURNING rowid, name");
4824 if let Statement::Insert(i) = stmt {
4825 assert_eq!(i.returning.len(), 2);
4826 } else {
4827 unreachable!("expected Insert");
4828 }
4829 }
4830
4831 #[test]
4832 fn test_update_set_where() {
4833 let stmt = parse_one("UPDATE t SET a = 1, b = 'hello' WHERE id = 42");
4834 if let Statement::Update(u) = stmt {
4835 assert_eq!(u.assignments.len(), 2);
4836 assert!(u.where_clause.is_some());
4837 assert!(u.from.is_none());
4838 } else {
4839 unreachable!("expected Update");
4840 }
4841 }
4842
4843 #[test]
4844 fn test_update_from_join() {
4845 let stmt = parse_one("UPDATE t1 SET a = t2.x FROM t2 WHERE t1.id = t2.id");
4846 if let Statement::Update(u) = stmt {
4847 assert_eq!(u.assignments.len(), 1);
4848 assert!(u.from.is_some());
4849 assert!(u.where_clause.is_some());
4850 } else {
4851 unreachable!("expected Update");
4852 }
4853 }
4854
4855 #[test]
4856 fn test_update_from_multi_match() {
4857 let stmt = parse_one(
4860 "UPDATE t1 SET val = src.val FROM src \
4861 INNER JOIN mapping ON mapping.src_id = src.id \
4862 WHERE t1.id = mapping.dst_id",
4863 );
4864 if let Statement::Update(u) = stmt {
4865 assert!(u.from.is_some());
4866 let from = u.from.as_ref().unwrap();
4867 assert!(!from.joins.is_empty(), "expected JOIN in FROM clause");
4868 } else {
4869 unreachable!("expected Update");
4870 }
4871 }
4872
4873 #[test]
4874 fn test_update_order_by_limit() {
4875 let stmt = parse_one("UPDATE t SET a = a + 1 ORDER BY b DESC LIMIT 10");
4876 if let Statement::Update(u) = stmt {
4877 assert_eq!(u.order_by.len(), 1);
4878 assert_eq!(u.order_by[0].direction, Some(SortDirection::Desc));
4879 assert!(u.limit.is_some());
4880 } else {
4881 unreachable!("expected Update");
4882 }
4883 }
4884
4885 #[test]
4886 fn test_update_returning() {
4887 let stmt = parse_one("UPDATE t SET a = 1 WHERE id = 5 RETURNING id, a AS new_a");
4888 if let Statement::Update(u) = stmt {
4889 assert_eq!(u.returning.len(), 2);
4890 match &u.returning[1] {
4891 ResultColumn::Expr {
4892 alias: Some(alias), ..
4893 } => assert_eq!(alias, "new_a"),
4894 other => unreachable!("expected aliased result column, got {other:?}"),
4895 }
4896 } else {
4897 unreachable!("expected Update");
4898 }
4899 }
4900
4901 #[test]
4902 fn test_update_or_ignore() {
4903 let stmt = parse_one("UPDATE OR IGNORE t SET a = 1 WHERE id = 5");
4904 if let Statement::Update(u) = stmt {
4905 assert_eq!(u.or_conflict, Some(ConflictAction::Ignore));
4906 assert!(u.where_clause.is_some());
4907 } else {
4908 unreachable!("expected Update");
4909 }
4910 }
4911
4912 #[test]
4913 fn test_delete_where() {
4914 let stmt = parse_one("DELETE FROM t WHERE id = 42 AND active = 0");
4915 if let Statement::Delete(d) = stmt {
4916 assert!(d.where_clause.is_some());
4917 assert!(d.returning.is_empty());
4918 } else {
4919 unreachable!("expected Delete");
4920 }
4921 }
4922
4923 #[test]
4924 fn test_delete_order_by_limit() {
4925 let stmt = parse_one("DELETE FROM t ORDER BY created_at ASC LIMIT 100");
4926 if let Statement::Delete(d) = stmt {
4927 assert_eq!(d.order_by.len(), 1);
4928 assert_eq!(d.order_by[0].direction, Some(SortDirection::Asc));
4929 let limit = d.limit.as_ref().expect("LIMIT clause");
4930 assert!(matches!(
4931 limit.limit,
4932 Expr::Literal(Literal::Integer(100), _)
4933 ));
4934 } else {
4935 unreachable!("expected Delete");
4936 }
4937 }
4938
4939 #[test]
4940 fn test_delete_returning() {
4941 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
4942 if let Statement::Delete(d) = stmt {
4943 assert!(d.where_clause.is_some());
4944 assert_eq!(d.returning.len(), 1);
4945 assert!(matches!(d.returning[0], ResultColumn::Star));
4946 } else {
4947 unreachable!("expected Delete");
4948 }
4949 }
4950
4951 #[test]
4952 fn test_delete_bulk_optimization() {
4953 let stmt = parse_one("DELETE FROM t");
4956 if let Statement::Delete(d) = stmt {
4957 assert!(d.where_clause.is_none());
4958 assert!(d.order_by.is_empty());
4959 assert!(d.limit.is_none());
4960 assert!(d.returning.is_empty());
4961 } else {
4962 unreachable!("expected Delete");
4963 }
4964 }
4965
4966 #[test]
4967 fn test_delete_bulk_no_where_fast() {
4968 let stmt = parse_one("DELETE FROM main.t");
4971 if let Statement::Delete(d) = stmt {
4972 assert_eq!(d.table.name.schema.as_deref(), Some("main"));
4973 assert_eq!(d.table.name.name, "t");
4974 assert!(d.where_clause.is_none());
4975 } else {
4976 unreachable!("expected Delete");
4977 }
4978 }
4979
4980 #[test]
4981 fn test_delete_bulk_blocked_by_trigger() {
4982 let stmt = parse_one("DELETE FROM orders");
4985 if let Statement::Delete(d) = stmt {
4986 assert!(d.where_clause.is_none());
4987 assert!(d.returning.is_empty());
4988 } else {
4989 unreachable!("expected Delete");
4990 }
4991 }
4992
4993 #[test]
4994 fn test_delete_bulk_blocked_by_fk() {
4995 let stmt = parse_one("DELETE FROM parent_table");
4998 if let Statement::Delete(d) = stmt {
4999 assert!(d.where_clause.is_none());
5000 } else {
5001 unreachable!("expected Delete");
5002 }
5003 }
5004
5005 #[test]
5006 fn test_delete_bulk_changes_count() {
5007 let stmt = parse_one("DELETE FROM t");
5011 if let Statement::Delete(d) = stmt {
5012 assert!(d.where_clause.is_none());
5013 } else {
5014 unreachable!("expected Delete");
5015 }
5016 }
5017
5018 #[test]
5019 fn test_delete_bulk_autoincrement_preserved() {
5020 let stmt = parse_one("DELETE FROM t");
5024 if let Statement::Delete(d) = stmt {
5025 assert!(d.where_clause.is_none());
5026 assert!(d.limit.is_none());
5027 } else {
5028 unreachable!("expected Delete");
5029 }
5030 }
5031
5032 #[test]
5033 fn test_delete_bulk_where_1_not_optimized() {
5034 let stmt = parse_one("DELETE FROM t WHERE 1");
5037 if let Statement::Delete(d) = stmt {
5038 assert!(
5039 d.where_clause.is_some(),
5040 "WHERE 1 must produce a where_clause"
5041 );
5042 assert!(matches!(
5043 d.where_clause.as_ref().unwrap(),
5044 Expr::Literal(Literal::Integer(1), _)
5045 ));
5046 } else {
5047 unreachable!("expected Delete");
5048 }
5049 }
5050
5051 #[test]
5056 fn test_create_table_basic() {
5057 let stmt = parse_one("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
5058 if let Statement::CreateTable(ct) = stmt {
5059 assert_eq!(ct.name.name, "users");
5060 assert!(!ct.if_not_exists);
5061 assert!(!ct.temporary);
5062 assert!(!ct.without_rowid);
5063 assert!(!ct.strict);
5064 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5065 assert_eq!(columns.len(), 3);
5066 assert_eq!(columns[0].name, "id");
5067 assert_eq!(columns[1].name, "name");
5068 assert_eq!(columns[2].name, "age");
5069 } else {
5070 unreachable!("expected Columns body");
5071 }
5072 } else {
5073 unreachable!("expected CreateTable");
5074 }
5075 }
5076
5077 #[test]
5078 fn test_create_table_if_not_exists() {
5079 let stmt = parse_one("CREATE TABLE IF NOT EXISTS t (id INTEGER)");
5080 if let Statement::CreateTable(ct) = stmt {
5081 assert!(ct.if_not_exists);
5082 } else {
5083 unreachable!("expected CreateTable");
5084 }
5085 }
5086
5087 #[test]
5088 fn test_create_temp_table() {
5089 let stmt = parse_one("CREATE TEMP TABLE session_data (key TEXT, val BLOB)");
5090 if let Statement::CreateTable(ct) = stmt {
5091 assert!(ct.temporary);
5092 } else {
5093 unreachable!("expected CreateTable");
5094 }
5095 }
5096
5097 #[test]
5098 fn test_create_table_as_select() {
5099 let stmt = parse_one("CREATE TABLE t2 AS SELECT id, name FROM t1 WHERE active = 1");
5100 if let Statement::CreateTable(ct) = stmt {
5101 assert!(matches!(ct.body, CreateTableBody::AsSelect(_)));
5102 } else {
5103 unreachable!("expected CreateTable");
5104 }
5105 }
5106
5107 #[test]
5108 fn test_column_primary_key() {
5109 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY ASC)");
5110 if let Statement::CreateTable(ct) = stmt {
5111 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5112 let pk = columns[0]
5113 .constraints
5114 .iter()
5115 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
5116 assert!(pk.is_some(), "PK constraint missing");
5117 if let ColumnConstraintKind::PrimaryKey { direction, .. } = &pk.unwrap().kind {
5118 assert_eq!(*direction, Some(SortDirection::Asc));
5119 }
5120 } else {
5121 unreachable!("expected Columns body");
5122 }
5123 } else {
5124 unreachable!("expected CreateTable");
5125 }
5126 }
5127
5128 #[test]
5129 fn test_column_primary_key_autoincrement() {
5130 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)");
5131 if let Statement::CreateTable(ct) = stmt {
5132 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5133 let pk = columns[0]
5134 .constraints
5135 .iter()
5136 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
5137 if let ColumnConstraintKind::PrimaryKey { autoincrement, .. } = &pk.unwrap().kind {
5138 assert!(autoincrement, "AUTOINCREMENT flag not set");
5139 }
5140 } else {
5141 unreachable!("expected Columns body");
5142 }
5143 } else {
5144 unreachable!("expected CreateTable");
5145 }
5146 }
5147
5148 #[test]
5149 fn test_autoincrement_uses_sqlite_sequence() {
5150 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)");
5153 if let Statement::CreateTable(ct) = stmt {
5154 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5155 assert_eq!(columns.len(), 2);
5156 let pk = columns[0].constraints.iter().find(|c| {
5157 matches!(
5158 c.kind,
5159 ColumnConstraintKind::PrimaryKey {
5160 autoincrement: true,
5161 ..
5162 }
5163 )
5164 });
5165 assert!(pk.is_some(), "AUTOINCREMENT constraint missing");
5166 } else {
5167 unreachable!("expected Columns body");
5168 }
5169 } else {
5170 unreachable!("expected CreateTable");
5171 }
5172 }
5173
5174 #[test]
5175 fn test_column_not_null() {
5176 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL)");
5177 if let Statement::CreateTable(ct) = stmt {
5178 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5179 let nn = columns[0]
5180 .constraints
5181 .iter()
5182 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
5183 assert!(nn.is_some(), "NOT NULL constraint missing");
5184 } else {
5185 unreachable!("expected Columns body");
5186 }
5187 } else {
5188 unreachable!("expected CreateTable");
5189 }
5190 }
5191
5192 #[test]
5193 fn test_column_unique() {
5194 let stmt = parse_one("CREATE TABLE t (email TEXT UNIQUE)");
5195 if let Statement::CreateTable(ct) = stmt {
5196 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5197 let uq = columns[0]
5198 .constraints
5199 .iter()
5200 .find(|c| matches!(c.kind, ColumnConstraintKind::Unique { .. }));
5201 assert!(uq.is_some(), "UNIQUE constraint missing");
5202 } else {
5203 unreachable!("expected Columns body");
5204 }
5205 } else {
5206 unreachable!("expected CreateTable");
5207 }
5208 }
5209
5210 #[test]
5211 fn test_column_check() {
5212 let stmt = parse_one("CREATE TABLE t (age INTEGER CHECK(age >= 0 AND age < 200))");
5213 if let Statement::CreateTable(ct) = stmt {
5214 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5215 let chk = columns[0]
5216 .constraints
5217 .iter()
5218 .find(|c| matches!(c.kind, ColumnConstraintKind::Check(_)));
5219 assert!(chk.is_some(), "CHECK constraint missing");
5220 } else {
5221 unreachable!("expected Columns body");
5222 }
5223 } else {
5224 unreachable!("expected CreateTable");
5225 }
5226 }
5227
5228 #[test]
5229 fn test_column_default_literal() {
5230 let stmt = parse_one("CREATE TABLE t (status TEXT DEFAULT 'active')");
5231 if let Statement::CreateTable(ct) = stmt {
5232 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5233 let def = columns[0]
5234 .constraints
5235 .iter()
5236 .find(|c| matches!(c.kind, ColumnConstraintKind::Default(_)));
5237 assert!(def.is_some(), "DEFAULT constraint missing");
5238 } else {
5239 unreachable!("expected Columns body");
5240 }
5241 } else {
5242 unreachable!("expected CreateTable");
5243 }
5244 }
5245
5246 #[test]
5247 fn test_column_default_expr() {
5248 let stmt = parse_one("CREATE TABLE t (created_at TEXT DEFAULT (datetime('now')))");
5249 if let Statement::CreateTable(ct) = stmt {
5250 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5251 let def = columns[0].constraints.iter().find(|c| {
5252 matches!(
5253 c.kind,
5254 ColumnConstraintKind::Default(DefaultValue::ParenExpr(_))
5255 )
5256 });
5257 assert!(def.is_some(), "DEFAULT (expr) missing");
5258 } else {
5259 unreachable!("expected Columns body");
5260 }
5261 } else {
5262 unreachable!("expected CreateTable");
5263 }
5264 }
5265
5266 #[test]
5267 fn test_column_collate() {
5268 let stmt = parse_one("CREATE TABLE t (name TEXT COLLATE NOCASE)");
5269 if let Statement::CreateTable(ct) = stmt {
5270 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5271 let coll = columns[0]
5272 .constraints
5273 .iter()
5274 .find(|c| matches!(c.kind, ColumnConstraintKind::Collate(_)));
5275 assert!(coll.is_some(), "COLLATE constraint missing");
5276 if let ColumnConstraintKind::Collate(name) = &coll.unwrap().kind {
5277 assert_eq!(name, "NOCASE");
5278 }
5279 } else {
5280 unreachable!("expected Columns body");
5281 }
5282 } else {
5283 unreachable!("expected CreateTable");
5284 }
5285 }
5286
5287 #[test]
5288 fn test_table_constraint_composite_pk() {
5289 let stmt = parse_one("CREATE TABLE t (a INTEGER, b INTEGER, PRIMARY KEY (a, b))");
5290 if let Statement::CreateTable(ct) = stmt {
5291 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5292 let pk = constraints
5293 .iter()
5294 .find(|c| matches!(c.kind, TableConstraintKind::PrimaryKey { .. }));
5295 assert!(pk.is_some(), "composite PK missing");
5296 if let TableConstraintKind::PrimaryKey { columns, .. } = &pk.unwrap().kind {
5297 assert_eq!(columns.len(), 2);
5298 }
5299 } else {
5300 unreachable!("expected Columns body");
5301 }
5302 } else {
5303 unreachable!("expected CreateTable");
5304 }
5305 }
5306
5307 #[test]
5308 fn test_table_constraint_composite_unique() {
5309 let stmt = parse_one("CREATE TABLE t (a TEXT, b TEXT, UNIQUE (a, b))");
5310 if let Statement::CreateTable(ct) = stmt {
5311 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5312 let uq = constraints
5313 .iter()
5314 .find(|c| matches!(c.kind, TableConstraintKind::Unique { .. }));
5315 assert!(uq.is_some(), "composite UNIQUE missing");
5316 if let TableConstraintKind::Unique { columns, .. } = &uq.unwrap().kind {
5317 assert_eq!(columns.len(), 2);
5318 }
5319 } else {
5320 unreachable!("expected Columns body");
5321 }
5322 } else {
5323 unreachable!("expected CreateTable");
5324 }
5325 }
5326
5327 #[test]
5328 fn test_table_constraint_check() {
5329 let stmt = parse_one(
5330 "CREATE TABLE t (start_date TEXT, end_date TEXT, CHECK (start_date < end_date))",
5331 );
5332 if let Statement::CreateTable(ct) = stmt {
5333 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5334 let chk = constraints
5335 .iter()
5336 .find(|c| matches!(c.kind, TableConstraintKind::Check(_)));
5337 assert!(chk.is_some(), "table CHECK constraint missing");
5338 } else {
5339 unreachable!("expected Columns body");
5340 }
5341 } else {
5342 unreachable!("expected CreateTable");
5343 }
5344 }
5345
5346 #[test]
5347 fn test_foreign_key_on_delete_cascade() {
5348 let stmt = parse_one(
5349 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5350 REFERENCES parent(id) ON DELETE CASCADE)",
5351 );
5352 if let Statement::CreateTable(ct) = stmt {
5353 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5354 let fk = columns[1]
5355 .constraints
5356 .iter()
5357 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)));
5358 assert!(fk.is_some(), "FK constraint missing");
5359 if let ColumnConstraintKind::ForeignKey(clause) = &fk.unwrap().kind {
5360 assert_eq!(clause.table, "parent");
5361 let del = clause
5362 .actions
5363 .iter()
5364 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5365 assert!(del.is_some());
5366 assert_eq!(del.unwrap().action, ForeignKeyActionType::Cascade);
5367 }
5368 } else {
5369 unreachable!("expected Columns body");
5370 }
5371 } else {
5372 unreachable!("expected CreateTable");
5373 }
5374 }
5375
5376 #[test]
5377 fn test_foreign_key_on_delete_set_null() {
5378 let stmt = parse_one(
5379 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5380 REFERENCES parent(id) ON DELETE SET NULL)",
5381 );
5382 if let Statement::CreateTable(ct) = stmt {
5383 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5384 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5385 .constraints
5386 .iter()
5387 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5388 .unwrap()
5389 .kind
5390 {
5391 let del = clause
5392 .actions
5393 .iter()
5394 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5395 assert_eq!(del.unwrap().action, ForeignKeyActionType::SetNull);
5396 }
5397 } else {
5398 unreachable!("expected Columns body");
5399 }
5400 } else {
5401 unreachable!("expected CreateTable");
5402 }
5403 }
5404
5405 #[test]
5406 fn test_foreign_key_on_update_cascade() {
5407 let stmt = parse_one(
5408 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5409 REFERENCES parent(id) ON UPDATE CASCADE)",
5410 );
5411 if let Statement::CreateTable(ct) = stmt {
5412 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5413 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5414 .constraints
5415 .iter()
5416 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5417 .unwrap()
5418 .kind
5419 {
5420 let upd = clause
5421 .actions
5422 .iter()
5423 .find(|a| a.trigger == ForeignKeyTrigger::OnUpdate);
5424 assert!(upd.is_some());
5425 assert_eq!(upd.unwrap().action, ForeignKeyActionType::Cascade);
5426 }
5427 } else {
5428 unreachable!("expected Columns body");
5429 }
5430 } else {
5431 unreachable!("expected CreateTable");
5432 }
5433 }
5434
5435 #[test]
5436 fn test_foreign_key_restrict() {
5437 let stmt = parse_one(
5438 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5439 REFERENCES parent(id) ON DELETE RESTRICT)",
5440 );
5441 if let Statement::CreateTable(ct) = stmt {
5442 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5443 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5444 .constraints
5445 .iter()
5446 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5447 .unwrap()
5448 .kind
5449 {
5450 let del = clause
5451 .actions
5452 .iter()
5453 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5454 assert_eq!(del.unwrap().action, ForeignKeyActionType::Restrict);
5455 }
5456 } else {
5457 unreachable!("expected Columns body");
5458 }
5459 } else {
5460 unreachable!("expected CreateTable");
5461 }
5462 }
5463
5464 #[test]
5465 fn test_foreign_key_deferred() {
5466 let stmt = parse_one(
5467 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5468 REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED)",
5469 );
5470 if let Statement::CreateTable(ct) = stmt {
5471 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5472 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5473 .constraints
5474 .iter()
5475 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5476 .unwrap()
5477 .kind
5478 {
5479 let def = clause.deferrable.as_ref().expect("DEFERRABLE missing");
5480 assert!(!def.not, "should be DEFERRABLE, not NOT DEFERRABLE");
5481 assert_eq!(def.initially, Some(DeferrableInitially::Deferred));
5482 }
5483 } else {
5484 unreachable!("expected Columns body");
5485 }
5486 } else {
5487 unreachable!("expected CreateTable");
5488 }
5489 }
5490
5491 #[test]
5492 fn test_foreign_key_pragma_required() {
5493 let stmt = parse_one(
5496 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5497 REFERENCES parent(id) ON DELETE CASCADE ON UPDATE SET NULL)",
5498 );
5499 if let Statement::CreateTable(ct) = stmt {
5500 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5501 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5502 .constraints
5503 .iter()
5504 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5505 .unwrap()
5506 .kind
5507 {
5508 assert_eq!(clause.actions.len(), 2);
5509 }
5510 } else {
5511 unreachable!("expected Columns body");
5512 }
5513 } else {
5514 unreachable!("expected CreateTable");
5515 }
5516 }
5517
5518 #[test]
5519 fn test_conflict_clause_on_not_null() {
5520 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL ON CONFLICT IGNORE)");
5521 if let Statement::CreateTable(ct) = stmt {
5522 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5523 let nn = columns[0]
5524 .constraints
5525 .iter()
5526 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
5527 if let ColumnConstraintKind::NotNull { conflict } = &nn.unwrap().kind {
5528 assert_eq!(*conflict, Some(ConflictAction::Ignore));
5529 }
5530 } else {
5531 unreachable!("expected Columns body");
5532 }
5533 } else {
5534 unreachable!("expected CreateTable");
5535 }
5536 }
5537
5538 #[test]
5539 fn test_without_rowid_table() {
5540 let stmt = parse_one("CREATE TABLE t (k TEXT PRIMARY KEY, v BLOB) WITHOUT ROWID");
5541 if let Statement::CreateTable(ct) = stmt {
5542 assert!(ct.without_rowid);
5543 } else {
5544 unreachable!("expected CreateTable");
5545 }
5546 }
5547
5548 #[test]
5549 fn test_without_rowid_no_autoincrement() {
5550 let stmt = parse_one(
5553 "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT) WITHOUT ROWID",
5554 );
5555 if let Statement::CreateTable(ct) = stmt {
5556 assert!(ct.without_rowid);
5557 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5558 let pk = columns[0].constraints.iter().find(|c| {
5559 matches!(
5560 c.kind,
5561 ColumnConstraintKind::PrimaryKey {
5562 autoincrement: true,
5563 ..
5564 }
5565 )
5566 });
5567 assert!(pk.is_some());
5568 } else {
5569 unreachable!("expected Columns body");
5570 }
5571 } else {
5572 unreachable!("expected CreateTable");
5573 }
5574 }
5575
5576 #[test]
5577 fn test_without_rowid_integer_pk_not_alias() {
5578 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT) WITHOUT ROWID");
5581 if let Statement::CreateTable(ct) = stmt {
5582 assert!(ct.without_rowid);
5583 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5584 assert_eq!(columns[0].name, "id");
5585 assert!(columns[0].type_name.is_some());
5586 } else {
5587 unreachable!("expected Columns body");
5588 }
5589 } else {
5590 unreachable!("expected CreateTable");
5591 }
5592 }
5593
5594 #[test]
5595 fn test_strict_table_type_enforcement() {
5596 let stmt = parse_one("CREATE TABLE t (id INTEGER, name TEXT, score REAL) STRICT");
5599 if let Statement::CreateTable(ct) = stmt {
5600 assert!(ct.strict);
5601 assert!(!ct.without_rowid);
5602 } else {
5603 unreachable!("expected CreateTable");
5604 }
5605 }
5606
5607 #[test]
5608 fn test_strict_table_any_column() {
5609 let stmt = parse_one("CREATE TABLE t (id INTEGER, data ANY) STRICT");
5611 if let Statement::CreateTable(ct) = stmt {
5612 assert!(ct.strict);
5613 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5614 let tn = columns[1].type_name.as_ref().expect("type name");
5615 assert_eq!(tn.name, "ANY");
5616 } else {
5617 unreachable!("expected Columns body");
5618 }
5619 } else {
5620 unreachable!("expected CreateTable");
5621 }
5622 }
5623
5624 #[test]
5625 fn test_strict_allowed_types() {
5626 let stmt =
5628 parse_one("CREATE TABLE t (a INT, b INTEGER, c REAL, d TEXT, e BLOB, f ANY) STRICT");
5629 if let Statement::CreateTable(ct) = stmt {
5630 assert!(ct.strict);
5631 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5632 assert_eq!(columns.len(), 6);
5633 let types: Vec<&str> = columns
5634 .iter()
5635 .map(|c| c.type_name.as_ref().unwrap().name.as_str())
5636 .collect();
5637 assert_eq!(types, vec!["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
5638 } else {
5639 unreachable!("expected Columns body");
5640 }
5641 } else {
5642 unreachable!("expected CreateTable");
5643 }
5644 }
5645
5646 #[test]
5647 fn test_generated_col_virtual() {
5648 let stmt = parse_one(
5649 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a + b) VIRTUAL)",
5650 );
5651 if let Statement::CreateTable(ct) = stmt {
5652 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5653 let generated = columns[2]
5654 .constraints
5655 .iter()
5656 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5657 assert!(generated.is_some(), "Generated constraint missing");
5658 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5659 assert_eq!(*storage, Some(GeneratedStorage::Virtual));
5660 }
5661 } else {
5662 unreachable!("expected Columns body");
5663 }
5664 } else {
5665 unreachable!("expected CreateTable");
5666 }
5667 }
5668
5669 #[test]
5670 fn test_generated_col_stored() {
5671 let stmt = parse_one(
5672 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a * b) STORED)",
5673 );
5674 if let Statement::CreateTable(ct) = stmt {
5675 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5676 let generated = columns[2]
5677 .constraints
5678 .iter()
5679 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5680 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5681 assert_eq!(*storage, Some(GeneratedStorage::Stored));
5682 }
5683 } else {
5684 unreachable!("expected Columns body");
5685 }
5686 } else {
5687 unreachable!("expected CreateTable");
5688 }
5689 }
5690
5691 #[test]
5692 fn test_generated_col_ordering() {
5693 let stmt = parse_one(
5696 "CREATE TABLE t (\
5697 a INTEGER, \
5698 b INTEGER GENERATED ALWAYS AS (a + 1) STORED, \
5699 c INTEGER GENERATED ALWAYS AS (b * 2) VIRTUAL)",
5700 );
5701 if let Statement::CreateTable(ct) = stmt {
5702 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5703 assert_eq!(columns.len(), 3);
5704 let gen_b = columns[1]
5706 .constraints
5707 .iter()
5708 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5709 let gen_c = columns[2]
5710 .constraints
5711 .iter()
5712 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5713 assert!(gen_b, "column b should be generated");
5714 assert!(gen_c, "column c should be generated");
5715 } else {
5716 unreachable!("expected Columns body");
5717 }
5718 } else {
5719 unreachable!("expected CreateTable");
5720 }
5721 }
5722
5723 #[test]
5724 fn test_generated_col_stored_indexable() {
5725 let stmts = parse_ok(
5728 "CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED); \
5729 CREATE INDEX idx_b ON t (b)",
5730 );
5731 assert_eq!(stmts.len(), 2);
5732 assert!(matches!(stmts[0], Statement::CreateTable(_)));
5733 assert!(matches!(stmts[1], Statement::CreateIndex(_)));
5734 }
5735
5736 #[test]
5737 fn test_type_affinity_int() {
5738 let stmt = parse_one("CREATE TABLE t (a INTEGER, b BIGINT, c SMALLINT, d MEDIUMINT)");
5741 if let Statement::CreateTable(ct) = stmt {
5742 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5743 assert_eq!(columns.len(), 4);
5744 for col in columns {
5745 let tn = col.type_name.as_ref().unwrap();
5746 assert!(tn.name.contains("INT"), "{} should contain INT", tn.name);
5747 }
5748 } else {
5749 unreachable!("expected Columns body");
5750 }
5751 } else {
5752 unreachable!("expected CreateTable");
5753 }
5754 }
5755
5756 #[test]
5757 fn test_type_affinity_text() {
5758 let stmt = parse_one("CREATE TABLE t (a TEXT, b VARCHAR, c CLOB, d CHARACTER)");
5759 if let Statement::CreateTable(ct) = stmt {
5760 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5761 assert_eq!(columns.len(), 4);
5762 for col in columns {
5763 assert!(col.type_name.is_some());
5764 }
5765 } else {
5766 unreachable!("expected Columns body");
5767 }
5768 } else {
5769 unreachable!("expected CreateTable");
5770 }
5771 }
5772
5773 #[test]
5774 fn test_type_affinity_blob() {
5775 let stmt = parse_one("CREATE TABLE t (a BLOB, b)");
5776 if let Statement::CreateTable(ct) = stmt {
5777 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5778 assert_eq!(columns.len(), 2);
5779 assert_eq!(columns[0].type_name.as_ref().unwrap().name, "BLOB");
5780 assert!(columns[1].type_name.is_none());
5782 } else {
5783 unreachable!("expected Columns body");
5784 }
5785 } else {
5786 unreachable!("expected CreateTable");
5787 }
5788 }
5789
5790 #[test]
5791 fn test_type_affinity_real() {
5792 let stmt = parse_one("CREATE TABLE t (a REAL, b DOUBLE, c FLOAT)");
5793 if let Statement::CreateTable(ct) = stmt {
5794 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5795 assert_eq!(columns.len(), 3);
5796 for col in columns {
5797 assert!(col.type_name.is_some());
5798 }
5799 } else {
5800 unreachable!("expected Columns body");
5801 }
5802 } else {
5803 unreachable!("expected CreateTable");
5804 }
5805 }
5806
5807 #[test]
5808 fn test_type_affinity_numeric() {
5809 let stmt = parse_one("CREATE TABLE t (a NUMERIC, b DECIMAL, c BOOLEAN)");
5810 if let Statement::CreateTable(ct) = stmt {
5811 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5812 assert_eq!(columns.len(), 3);
5813 for col in columns {
5814 assert!(col.type_name.is_some());
5815 }
5816 } else {
5817 unreachable!("expected Columns body");
5818 }
5819 } else {
5820 unreachable!("expected CreateTable");
5821 }
5822 }
5823
5824 #[test]
5825 fn test_create_unique_index() {
5826 let stmt = parse_one("CREATE UNIQUE INDEX idx_email ON users (email)");
5827 if let Statement::CreateIndex(ci) = stmt {
5828 assert!(ci.unique);
5829 assert_eq!(ci.name.name, "idx_email");
5830 assert_eq!(ci.table, "users");
5831 assert_eq!(ci.columns.len(), 1);
5832 assert!(ci.where_clause.is_none());
5833 } else {
5834 unreachable!("expected CreateIndex");
5835 }
5836 }
5837
5838 #[test]
5839 fn test_partial_index() {
5840 let stmt = parse_one("CREATE INDEX idx_active ON users (name) WHERE active = 1");
5841 if let Statement::CreateIndex(ci) = stmt {
5842 assert!(!ci.unique);
5843 assert_eq!(ci.name.name, "idx_active");
5844 assert!(ci.where_clause.is_some(), "partial index WHERE missing");
5845 } else {
5846 unreachable!("expected CreateIndex");
5847 }
5848 }
5849
5850 #[test]
5851 fn test_partial_index_planner_usage() {
5852 let stmt =
5855 parse_one("CREATE INDEX idx_recent ON orders (created_at) WHERE status != 'archived'");
5856 if let Statement::CreateIndex(ci) = stmt {
5857 assert!(ci.where_clause.is_some());
5858 assert_eq!(ci.columns.len(), 1);
5859 } else {
5860 unreachable!("expected CreateIndex");
5861 }
5862 }
5863
5864 #[test]
5865 fn test_expression_index() {
5866 let stmt = parse_one("CREATE INDEX idx_lower_name ON users (lower(name))");
5867 if let Statement::CreateIndex(ci) = stmt {
5868 assert_eq!(ci.columns.len(), 1);
5869 assert!(
5871 matches!(ci.columns[0].expr, Expr::FunctionCall { .. }),
5872 "expected function call expression in index"
5873 );
5874 } else {
5875 unreachable!("expected CreateIndex");
5876 }
5877 }
5878
5879 #[test]
5880 fn test_expression_index_planner_match() {
5881 let stmt = parse_one("CREATE INDEX idx_calc ON t (a + b * 2)");
5884 if let Statement::CreateIndex(ci) = stmt {
5885 assert_eq!(ci.columns.len(), 1);
5886 assert!(
5887 matches!(ci.columns[0].expr, Expr::BinaryOp { .. }),
5888 "expected binary op in expression index"
5889 );
5890 } else {
5891 unreachable!("expected CreateIndex");
5892 }
5893 }
5894
5895 #[test]
5896 fn test_index_collate_asc_desc() {
5897 let stmt = parse_one("CREATE INDEX idx_multi ON t (a COLLATE NOCASE ASC, b DESC, c)");
5898 if let Statement::CreateIndex(ci) = stmt {
5899 assert_eq!(ci.columns.len(), 3);
5900 assert!(
5902 matches!(
5903 &ci.columns[0].expr,
5904 Expr::Collate { collation, .. } if collation == "NOCASE"
5905 ),
5906 "expected Collate expr with NOCASE"
5907 );
5908 assert_eq!(ci.columns[0].direction, Some(SortDirection::Asc));
5909 assert_eq!(ci.columns[1].direction, Some(SortDirection::Desc));
5910 assert!(ci.columns[2].direction.is_none());
5911 } else {
5912 unreachable!("expected CreateIndex");
5913 }
5914 }
5915
5916 #[test]
5921 fn test_create_view_basic() {
5922 let stmt = parse_one("CREATE VIEW v AS SELECT id, name FROM users");
5923 if let Statement::CreateView(cv) = stmt {
5924 assert_eq!(cv.name.name, "v");
5925 assert!(!cv.if_not_exists);
5926 assert!(!cv.temporary);
5927 assert!(cv.columns.is_empty());
5928 } else {
5929 unreachable!("expected CreateView");
5930 }
5931 }
5932
5933 #[test]
5934 fn test_create_view_column_aliases() {
5935 let stmt = parse_one("CREATE VIEW v (user_id, user_name) AS SELECT id, name FROM users");
5936 if let Statement::CreateView(cv) = stmt {
5937 assert_eq!(cv.columns, vec!["user_id", "user_name"]);
5938 } else {
5939 unreachable!("expected CreateView");
5940 }
5941 }
5942
5943 #[test]
5944 fn test_create_view_if_not_exists() {
5945 let stmt = parse_one("CREATE VIEW IF NOT EXISTS v AS SELECT 1");
5946 if let Statement::CreateView(cv) = stmt {
5947 assert!(cv.if_not_exists);
5948 } else {
5949 unreachable!("expected CreateView");
5950 }
5951 }
5952
5953 #[test]
5954 fn test_create_temp_view() {
5955 let stmt = parse_one("CREATE TEMP VIEW tv AS SELECT 1");
5956 if let Statement::CreateView(cv) = stmt {
5957 assert!(cv.temporary);
5958 } else {
5959 unreachable!("expected CreateView");
5960 }
5961 }
5962
5963 #[test]
5964 fn test_view_inline_expansion() {
5965 let stmt =
5968 parse_one("CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = 1");
5969 if let Statement::CreateView(cv) = stmt {
5970 assert_eq!(cv.name.name, "active_users");
5971 } else {
5972 unreachable!("expected CreateView");
5973 }
5974 }
5975
5976 #[test]
5977 fn test_view_read_only() {
5978 let stmt = parse_one("CREATE VIEW v AS SELECT * FROM t");
5981 assert!(matches!(stmt, Statement::CreateView(_)));
5982 }
5983
5984 #[test]
5985 fn test_view_with_recursive_cte() {
5986 let stmt = parse_one(
5989 "CREATE VIEW tree AS \
5990 SELECT n.id, n.parent FROM nodes n \
5991 WHERE n.parent IS NULL \
5992 UNION ALL \
5993 SELECT c.id, c.parent FROM nodes c JOIN nodes p ON c.parent = p.id",
5994 );
5995 if let Statement::CreateView(cv) = stmt {
5996 assert_eq!(cv.name.name, "tree");
5997 assert!(
5999 !cv.query.body.compounds.is_empty(),
6000 "expected compound SELECT in view"
6001 );
6002 } else {
6003 unreachable!("expected CreateView");
6004 }
6005 }
6006
6007 #[test]
6008 fn test_instead_of_trigger_on_view() {
6009 let stmt = parse_one(
6010 "CREATE TRIGGER tr INSTEAD OF INSERT ON v BEGIN \
6011 INSERT INTO t (a) VALUES (NEW.a); \
6012 END",
6013 );
6014 if let Statement::CreateTrigger(ct) = stmt {
6015 assert_eq!(ct.timing, TriggerTiming::InsteadOf);
6016 assert!(matches!(ct.event, TriggerEvent::Insert));
6017 assert_eq!(ct.table, "v");
6018 assert!(!ct.body.is_empty());
6019 } else {
6020 unreachable!("expected CreateTrigger");
6021 }
6022 }
6023
6024 #[test]
6025 fn test_trigger_before_insert() {
6026 let stmt = parse_one("CREATE TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6027 if let Statement::CreateTrigger(ct) = stmt {
6028 assert_eq!(ct.timing, TriggerTiming::Before);
6029 assert!(matches!(ct.event, TriggerEvent::Insert));
6030 } else {
6031 unreachable!("expected CreateTrigger");
6032 }
6033 }
6034
6035 #[test]
6036 fn test_trigger_after_insert() {
6037 let stmt = parse_one("CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END");
6038 if let Statement::CreateTrigger(ct) = stmt {
6039 assert_eq!(ct.timing, TriggerTiming::After);
6040 assert!(matches!(ct.event, TriggerEvent::Insert));
6041 } else {
6042 unreachable!("expected CreateTrigger");
6043 }
6044 }
6045
6046 #[test]
6047 fn test_trigger_before_update() {
6048 let stmt = parse_one("CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN SELECT OLD.a, NEW.a; END");
6049 if let Statement::CreateTrigger(ct) = stmt {
6050 assert_eq!(ct.timing, TriggerTiming::Before);
6051 assert!(matches!(ct.event, TriggerEvent::Update(_)));
6052 } else {
6053 unreachable!("expected CreateTrigger");
6054 }
6055 }
6056
6057 #[test]
6058 fn test_trigger_after_delete() {
6059 let stmt = parse_one("CREATE TRIGGER tr AFTER DELETE ON t BEGIN SELECT OLD.id; END");
6060 if let Statement::CreateTrigger(ct) = stmt {
6061 assert_eq!(ct.timing, TriggerTiming::After);
6062 assert!(matches!(ct.event, TriggerEvent::Delete));
6063 } else {
6064 unreachable!("expected CreateTrigger");
6065 }
6066 }
6067
6068 #[test]
6069 fn test_trigger_update_of_column() {
6070 let stmt =
6071 parse_one("CREATE TRIGGER tr BEFORE UPDATE OF name, email ON t BEGIN SELECT 1; END");
6072 if let Statement::CreateTrigger(ct) = stmt {
6073 if let TriggerEvent::Update(cols) = &ct.event {
6074 assert_eq!(cols, &["name", "email"]);
6075 } else {
6076 unreachable!("expected Update event with columns");
6077 }
6078 } else {
6079 unreachable!("expected CreateTrigger");
6080 }
6081 }
6082
6083 #[test]
6084 fn test_trigger_when_clause() {
6085 let stmt = parse_one(
6086 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN NEW.active = 1 BEGIN SELECT 1; END",
6087 );
6088 if let Statement::CreateTrigger(ct) = stmt {
6089 assert!(ct.when.is_some(), "WHEN clause missing");
6090 } else {
6091 unreachable!("expected CreateTrigger");
6092 }
6093 }
6094
6095 #[test]
6096 fn test_trigger_old_new_pseudo_tables() {
6097 let stmt = parse_one(
6098 "CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN \
6099 INSERT INTO log (old_val, new_val) VALUES (OLD.a, NEW.a); \
6100 END",
6101 );
6102 if let Statement::CreateTrigger(ct) = stmt {
6103 assert_eq!(ct.body.len(), 1);
6104 assert!(matches!(ct.body[0], Statement::Insert(_)));
6105 } else {
6106 unreachable!("expected CreateTrigger");
6107 }
6108 }
6109
6110 #[test]
6111 fn test_trigger_raise_abort() {
6112 let stmt = parse_one(
6113 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6114 SELECT RAISE(ABORT, 'not allowed'); \
6115 END",
6116 );
6117 if let Statement::CreateTrigger(ct) = stmt {
6118 assert_eq!(ct.body.len(), 1);
6119 } else {
6120 unreachable!("expected CreateTrigger");
6121 }
6122 }
6123
6124 #[test]
6125 fn test_trigger_raise_rollback() {
6126 let stmt = parse_one(
6127 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6128 SELECT RAISE(ROLLBACK, 'invalid'); \
6129 END",
6130 );
6131 if let Statement::CreateTrigger(ct) = stmt {
6132 assert_eq!(ct.body.len(), 1);
6133 } else {
6134 unreachable!("expected CreateTrigger");
6135 }
6136 }
6137
6138 #[test]
6139 fn test_trigger_raise_fail() {
6140 let stmt = parse_one(
6141 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6142 SELECT RAISE(FAIL, 'bad data'); \
6143 END",
6144 );
6145 if let Statement::CreateTrigger(ct) = stmt {
6146 assert_eq!(ct.body.len(), 1);
6147 } else {
6148 unreachable!("expected CreateTrigger");
6149 }
6150 }
6151
6152 #[test]
6153 fn test_trigger_raise_ignore() {
6154 let stmt = parse_one(
6155 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6156 SELECT RAISE(IGNORE); \
6157 END",
6158 );
6159 if let Statement::CreateTrigger(ct) = stmt {
6160 assert_eq!(ct.body.len(), 1);
6161 } else {
6162 unreachable!("expected CreateTrigger");
6163 }
6164 }
6165
6166 #[test]
6167 fn test_trigger_recursive() {
6168 let stmt = parse_one(
6171 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
6172 INSERT INTO t (val) VALUES (NEW.val + 1); \
6173 END",
6174 );
6175 if let Statement::CreateTrigger(ct) = stmt {
6176 assert_eq!(ct.timing, TriggerTiming::After);
6177 assert_eq!(ct.table, "t");
6178 assert_eq!(ct.body.len(), 1);
6179 } else {
6180 unreachable!("expected CreateTrigger");
6181 }
6182 }
6183
6184 #[test]
6185 fn test_trigger_max_recursion_depth() {
6186 let stmt = parse_one(
6189 "CREATE TRIGGER tr AFTER INSERT ON t \
6190 WHEN NEW.depth < 1000 BEGIN \
6191 INSERT INTO t (depth) VALUES (NEW.depth + 1); \
6192 END",
6193 );
6194 if let Statement::CreateTrigger(ct) = stmt {
6195 assert!(ct.when.is_some());
6196 assert_eq!(ct.body.len(), 1);
6197 } else {
6198 unreachable!("expected CreateTrigger");
6199 }
6200 }
6201
6202 #[test]
6203 fn test_trigger_heap_frame_stack() {
6204 let stmt = parse_one(
6207 "CREATE TRIGGER tr AFTER UPDATE ON t BEGIN \
6208 UPDATE t SET counter = counter + 1 WHERE id = NEW.parent_id; \
6209 END",
6210 );
6211 if let Statement::CreateTrigger(ct) = stmt {
6212 assert_eq!(ct.body.len(), 1);
6213 assert!(matches!(ct.body[0], Statement::Update(_)));
6214 } else {
6215 unreachable!("expected CreateTrigger");
6216 }
6217 }
6218
6219 #[test]
6220 fn test_trigger_multiple_dml() {
6221 let stmt = parse_one(
6222 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
6223 INSERT INTO audit (action) VALUES ('insert'); \
6224 UPDATE stats SET count = count + 1; \
6225 END",
6226 );
6227 if let Statement::CreateTrigger(ct) = stmt {
6228 assert_eq!(ct.body.len(), 2);
6229 assert!(matches!(ct.body[0], Statement::Insert(_)));
6230 assert!(matches!(ct.body[1], Statement::Update(_)));
6231 } else {
6232 unreachable!("expected CreateTrigger");
6233 }
6234 }
6235
6236 #[test]
6237 fn test_alter_table_rename() {
6238 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
6239 if let Statement::AlterTable(at) = stmt {
6240 assert_eq!(at.table.name, "t");
6241 assert!(matches!(at.action, AlterTableAction::RenameTo(ref n) if n == "t2"));
6242 } else {
6243 unreachable!("expected AlterTable");
6244 }
6245 }
6246
6247 #[test]
6248 fn test_alter_table_rename_column() {
6249 let stmt = parse_one("ALTER TABLE t RENAME COLUMN old_name TO new_name");
6250 if let Statement::AlterTable(at) = stmt {
6251 if let AlterTableAction::RenameColumn { old, new } = &at.action {
6252 assert_eq!(old, "old_name");
6253 assert_eq!(new, "new_name");
6254 } else {
6255 unreachable!("expected RenameColumn action");
6256 }
6257 } else {
6258 unreachable!("expected AlterTable");
6259 }
6260 }
6261
6262 #[test]
6263 fn test_alter_table_add_column() {
6264 let stmt = parse_one("ALTER TABLE t ADD COLUMN email TEXT NOT NULL DEFAULT ''");
6265 if let Statement::AlterTable(at) = stmt {
6266 if let AlterTableAction::AddColumn(col) = &at.action {
6267 assert_eq!(col.name, "email");
6268 assert!(!col.constraints.is_empty());
6269 } else {
6270 unreachable!("expected AddColumn action");
6271 }
6272 } else {
6273 unreachable!("expected AlterTable");
6274 }
6275 }
6276
6277 #[test]
6278 fn test_alter_table_remove_column() {
6279 let stmt = parse_one("ALTER TABLE t DROP COLUMN old_col");
6280 if let Statement::AlterTable(at) = stmt {
6281 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "old_col"));
6282 } else {
6283 unreachable!("expected AlterTable");
6284 }
6285 }
6286
6287 #[test]
6288 fn test_alter_remove_column_pk_fails() {
6289 let stmt = parse_one("ALTER TABLE t DROP COLUMN id");
6292 if let Statement::AlterTable(at) = stmt {
6293 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "id"));
6294 } else {
6295 unreachable!("expected AlterTable");
6296 }
6297 }
6298
6299 #[test]
6300 fn test_alter_remove_column_unique_fails() {
6301 let stmt = parse_one("ALTER TABLE t DROP COLUMN email");
6303 if let Statement::AlterTable(at) = stmt {
6304 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "email"));
6305 } else {
6306 unreachable!("expected AlterTable");
6307 }
6308 }
6309
6310 #[test]
6311 fn test_alter_remove_column_index_fails() {
6312 let stmt = parse_one("ALTER TABLE t DROP COLUMN indexed_col");
6314 if let Statement::AlterTable(at) = stmt {
6315 assert!(matches!(
6316 at.action,
6317 AlterTableAction::DropColumn(ref c) if c == "indexed_col"
6318 ));
6319 } else {
6320 unreachable!("expected AlterTable");
6321 }
6322 }
6323
6324 #[test]
6325 fn test_alter_remove_column_check_fails() {
6326 let stmt = parse_one("ALTER TABLE t DROP COLUMN checked_col");
6328 if let Statement::AlterTable(at) = stmt {
6329 assert!(matches!(
6330 at.action,
6331 AlterTableAction::DropColumn(ref c) if c == "checked_col"
6332 ));
6333 } else {
6334 unreachable!("expected AlterTable");
6335 }
6336 }
6337
6338 #[test]
6339 fn test_alter_remove_column_fk_fails() {
6340 let stmt = parse_one("ALTER TABLE t DROP COLUMN fk_col");
6342 if let Statement::AlterTable(at) = stmt {
6343 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "fk_col"));
6344 } else {
6345 unreachable!("expected AlterTable");
6346 }
6347 }
6348
6349 #[test]
6350 fn test_alter_remove_only_column_fails() {
6351 let stmt = parse_one("ALTER TABLE t DROP COLUMN only_col");
6353 if let Statement::AlterTable(at) = stmt {
6354 assert!(matches!(
6355 at.action,
6356 AlterTableAction::DropColumn(ref c) if c == "only_col"
6357 ));
6358 } else {
6359 unreachable!("expected AlterTable");
6360 }
6361 }
6362
6363 #[test]
6364 fn test_ddl_remove_table() {
6365 let stmt = parse_one("DROP TABLE t");
6366 if let Statement::Drop(d) = stmt {
6367 assert_eq!(d.object_type, DropObjectType::Table);
6368 assert!(!d.if_exists);
6369 assert_eq!(d.name.name, "t");
6370 } else {
6371 unreachable!("expected Drop");
6372 }
6373 }
6374
6375 #[test]
6376 fn test_ddl_remove_table_if_exists() {
6377 let stmt = parse_one("DROP TABLE IF EXISTS t");
6378 if let Statement::Drop(d) = stmt {
6379 assert_eq!(d.object_type, DropObjectType::Table);
6380 assert!(d.if_exists);
6381 } else {
6382 unreachable!("expected Drop");
6383 }
6384 }
6385
6386 #[test]
6387 fn test_ddl_remove_index() {
6388 let stmt = parse_one("DROP INDEX idx");
6389 if let Statement::Drop(d) = stmt {
6390 assert_eq!(d.object_type, DropObjectType::Index);
6391 assert_eq!(d.name.name, "idx");
6392 } else {
6393 unreachable!("expected Drop");
6394 }
6395 }
6396
6397 #[test]
6398 fn test_ddl_remove_view() {
6399 let stmt = parse_one("DROP VIEW v");
6400 if let Statement::Drop(d) = stmt {
6401 assert_eq!(d.object_type, DropObjectType::View);
6402 assert_eq!(d.name.name, "v");
6403 } else {
6404 unreachable!("expected Drop");
6405 }
6406 }
6407
6408 #[test]
6409 fn test_ddl_remove_trigger() {
6410 let stmt = parse_one("DROP TRIGGER tr");
6411 if let Statement::Drop(d) = stmt {
6412 assert_eq!(d.object_type, DropObjectType::Trigger);
6413 assert_eq!(d.name.name, "tr");
6414 } else {
6415 unreachable!("expected Drop");
6416 }
6417 }
6418
6419 #[test]
6425 fn test_reindex_global() {
6426 let stmt = parse_one("REINDEX");
6427 assert!(matches!(stmt, Statement::Reindex(None)));
6428 }
6429
6430 #[test]
6431 fn test_reindex_table() {
6432 let stmt = parse_one("REINDEX t");
6433 if let Statement::Reindex(Some(name)) = stmt {
6434 assert_eq!(name.name, "t");
6435 assert!(name.schema.is_none());
6436 } else {
6437 unreachable!("expected Reindex(Some), got {stmt:?}");
6438 }
6439 }
6440
6441 #[test]
6442 fn test_reindex_qualified() {
6443 let stmt = parse_one("REINDEX main.idx");
6444 if let Statement::Reindex(Some(name)) = stmt {
6445 assert_eq!(name.schema.as_deref(), Some("main"));
6446 assert_eq!(name.name, "idx");
6447 } else {
6448 unreachable!("expected Reindex(Some), got {stmt:?}");
6449 }
6450 }
6451
6452 #[test]
6453 fn test_analyze_global() {
6454 let stmt = parse_one("ANALYZE");
6455 assert!(matches!(stmt, Statement::Analyze(None)));
6456 }
6457
6458 #[test]
6459 fn test_analyze_table() {
6460 let stmt = parse_one("ANALYZE t");
6461 if let Statement::Analyze(Some(name)) = stmt {
6462 assert_eq!(name.name, "t");
6463 assert!(name.schema.is_none());
6464 } else {
6465 unreachable!("expected Analyze(Some), got {stmt:?}");
6466 }
6467 }
6468
6469 #[test]
6470 fn test_analyze_qualified() {
6471 let stmt = parse_one("ANALYZE main.t");
6472 if let Statement::Analyze(Some(name)) = stmt {
6473 assert_eq!(name.schema.as_deref(), Some("main"));
6474 assert_eq!(name.name, "t");
6475 } else {
6476 unreachable!("expected Analyze(Some), got {stmt:?}");
6477 }
6478 }
6479
6480 #[test]
6481 fn test_drop_view_if_exists() {
6482 let stmt = parse_one("DROP VIEW IF EXISTS v");
6483 if let Statement::Drop(d) = stmt {
6484 assert_eq!(d.object_type, DropObjectType::View);
6485 assert!(d.if_exists);
6486 assert_eq!(d.name.name, "v");
6487 } else {
6488 unreachable!("expected Drop");
6489 }
6490 }
6491
6492 #[test]
6493 fn test_drop_index_if_exists() {
6494 let stmt = parse_one("DROP INDEX IF EXISTS idx");
6495 if let Statement::Drop(d) = stmt {
6496 assert_eq!(d.object_type, DropObjectType::Index);
6497 assert!(d.if_exists);
6498 } else {
6499 unreachable!("expected Drop");
6500 }
6501 }
6502
6503 #[test]
6504 fn test_drop_trigger_if_exists_qualified() {
6505 let stmt = parse_one("DROP TRIGGER IF EXISTS main.tr");
6506 if let Statement::Drop(d) = stmt {
6507 assert_eq!(d.object_type, DropObjectType::Trigger);
6508 assert!(d.if_exists);
6509 assert_eq!(d.name.schema.as_deref(), Some("main"));
6510 assert_eq!(d.name.name, "tr");
6511 } else {
6512 unreachable!("expected Drop");
6513 }
6514 }
6515
6516 #[test]
6517 fn test_drop_table_qualified() {
6518 let stmt = parse_one("DROP TABLE main.t");
6519 if let Statement::Drop(d) = stmt {
6520 assert_eq!(d.name.schema.as_deref(), Some("main"));
6521 assert_eq!(d.name.name, "t");
6522 } else {
6523 unreachable!("expected Drop");
6524 }
6525 }
6526
6527 #[test]
6528 fn test_create_trigger_if_not_exists() {
6529 let stmt =
6530 parse_one("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6531 if let Statement::CreateTrigger(ct) = stmt {
6532 assert!(ct.if_not_exists);
6533 assert_eq!(ct.name.name, "tr");
6534 } else {
6535 unreachable!("expected CreateTrigger");
6536 }
6537 }
6538
6539 #[test]
6540 fn test_create_temp_trigger() {
6541 let stmt = parse_one("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6542 if let Statement::CreateTrigger(ct) = stmt {
6543 assert!(ct.temporary);
6544 assert_eq!(ct.name.name, "tr");
6545 } else {
6546 unreachable!("expected CreateTrigger");
6547 }
6548 }
6549
6550 #[test]
6551 fn test_create_view_qualified_name() {
6552 let stmt = parse_one("CREATE VIEW main.v AS SELECT 1");
6553 if let Statement::CreateView(cv) = stmt {
6554 assert_eq!(cv.name.schema.as_deref(), Some("main"));
6555 assert_eq!(cv.name.name, "v");
6556 } else {
6557 unreachable!("expected CreateView");
6558 }
6559 }
6560
6561 #[test]
6562 fn test_alter_table_qualified() {
6563 let stmt = parse_one("ALTER TABLE main.t RENAME TO u");
6564 if let Statement::AlterTable(at) = stmt {
6565 assert_eq!(at.table.schema.as_deref(), Some("main"));
6566 assert_eq!(at.table.name, "t");
6567 } else {
6568 unreachable!("expected AlterTable");
6569 }
6570 }
6571
6572 #[test]
6573 fn test_roundtrip_reindex_all() {
6574 assert_roundtrip("REINDEX");
6575 assert_roundtrip("REINDEX t");
6576 assert_roundtrip("REINDEX main.idx");
6577 }
6578
6579 #[test]
6580 fn test_roundtrip_analyze_all() {
6581 assert_roundtrip("ANALYZE");
6582 assert_roundtrip("ANALYZE t");
6583 assert_roundtrip("ANALYZE main.t");
6584 }
6585
6586 #[test]
6587 fn test_roundtrip_drop_all_types_extended() {
6588 assert_roundtrip("DROP TABLE IF EXISTS main.t");
6589 assert_roundtrip("DROP VIEW IF EXISTS v");
6590 assert_roundtrip("DROP INDEX IF EXISTS idx");
6591 assert_roundtrip("DROP TRIGGER IF EXISTS main.tr");
6592 }
6593
6594 #[test]
6595 fn test_roundtrip_create_trigger_extended() {
6596 assert_roundtrip("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6597 assert_roundtrip("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6598 assert_roundtrip(
6599 "CREATE TRIGGER tr INSTEAD OF UPDATE ON v BEGIN INSERT INTO log VALUES (1); END",
6600 );
6601 assert_roundtrip("CREATE TRIGGER tr BEFORE UPDATE OF a, b ON t BEGIN SELECT 1; END");
6602 assert_roundtrip(
6603 "CREATE TRIGGER tr AFTER DELETE ON \"order\" BEGIN INSERT INTO log VALUES (OLD.id); END",
6604 );
6605 }
6606
6607 #[test]
6608 fn test_roundtrip_create_view_extended() {
6609 assert_roundtrip("CREATE VIEW main.v AS SELECT 1");
6610 assert_roundtrip("CREATE VIEW v(x, y, z) AS SELECT a, b, c FROM t");
6611 }
6612
6613 #[test]
6614 fn test_roundtrip_alter_table_extended() {
6615 assert_roundtrip("ALTER TABLE t RENAME COLUMN a TO b");
6616 assert_roundtrip("ALTER TABLE main.t RENAME TO u");
6617 assert_roundtrip("ALTER TABLE t ADD COLUMN c INTEGER NOT NULL DEFAULT 0");
6618 }
6619
6620 #[test]
6625 fn test_begin_deferred() {
6626 let stmt = parse_one("BEGIN DEFERRED TRANSACTION");
6627 if let Statement::Begin(b) = stmt {
6628 assert_eq!(b.mode, Some(TransactionMode::Deferred));
6629 } else {
6630 unreachable!("expected Begin");
6631 }
6632 }
6633
6634 #[test]
6635 fn test_begin_immediate() {
6636 let stmt = parse_one("BEGIN IMMEDIATE");
6637 if let Statement::Begin(b) = stmt {
6638 assert_eq!(b.mode, Some(TransactionMode::Immediate));
6639 } else {
6640 unreachable!("expected Begin");
6641 }
6642 }
6643
6644 #[test]
6645 fn test_begin_exclusive() {
6646 let stmt = parse_one("BEGIN EXCLUSIVE TRANSACTION");
6647 if let Statement::Begin(b) = stmt {
6648 assert_eq!(b.mode, Some(TransactionMode::Exclusive));
6649 } else {
6650 unreachable!("expected Begin");
6651 }
6652 }
6653
6654 #[test]
6655 fn test_begin_concurrent() {
6656 let stmt = parse_one("BEGIN CONCURRENT");
6657 if let Statement::Begin(b) = stmt {
6658 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
6659 } else {
6660 unreachable!("expected Begin");
6661 }
6662 }
6663
6664 #[test]
6665 fn test_concurrent_no_conflict() {
6666 let stmt = parse_one("BEGIN");
6669 assert!(matches!(stmt, Statement::Begin(_)));
6670 }
6671
6672 #[test]
6673 fn test_concurrent_page_conflict() {
6674 let stmts = parse_ok("BEGIN; INSERT INTO t (a) VALUES (1)");
6677 assert_eq!(stmts.len(), 2);
6678 assert!(matches!(stmts[0], Statement::Begin(_)));
6679 assert!(matches!(stmts[1], Statement::Insert(_)));
6680 }
6681
6682 #[test]
6683 fn test_commit_end_synonym() {
6684 let stmt1 = parse_one("COMMIT");
6685 assert!(matches!(stmt1, Statement::Commit));
6686 let stmt2 = parse_one("END TRANSACTION");
6687 assert!(matches!(stmt2, Statement::Commit));
6688 let stmt3 = parse_one("COMMIT TRANSACTION");
6689 assert!(matches!(stmt3, Statement::Commit));
6690 }
6691
6692 #[test]
6693 fn test_rollback() {
6694 let stmt = parse_one("ROLLBACK");
6695 if let Statement::Rollback(r) = stmt {
6696 assert!(r.to_savepoint.is_none());
6697 } else {
6698 unreachable!("expected Rollback");
6699 }
6700 }
6701
6702 #[test]
6703 fn test_savepoint_basic() {
6704 let stmt = parse_one("SAVEPOINT sp1");
6705 assert!(matches!(stmt, Statement::Savepoint(ref name) if name == "sp1"));
6706 }
6707
6708 #[test]
6709 fn test_savepoint_release() {
6710 let stmt = parse_one("RELEASE SAVEPOINT sp1");
6711 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp1"));
6712 }
6713
6714 #[test]
6715 fn test_savepoint_release_removes_later() {
6716 let stmt = parse_one("RELEASE sp2");
6719 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp2"));
6720 }
6721
6722 #[test]
6723 fn test_savepoint_rollback_to() {
6724 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
6725 if let Statement::Rollback(r) = stmt {
6726 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
6727 } else {
6728 unreachable!("expected Rollback");
6729 }
6730 }
6731
6732 #[test]
6733 fn test_savepoint_nested() {
6734 let stmts = parse_ok("SAVEPOINT sp1; SAVEPOINT sp2; SAVEPOINT sp3");
6737 assert_eq!(stmts.len(), 3);
6738 assert!(matches!(stmts[0], Statement::Savepoint(ref n) if n == "sp1"));
6739 assert!(matches!(stmts[1], Statement::Savepoint(ref n) if n == "sp2"));
6740 assert!(matches!(stmts[2], Statement::Savepoint(ref n) if n == "sp3"));
6741 }
6742
6743 #[test]
6744 fn test_savepoint_rollback_then_continue() {
6745 let stmts = parse_ok("ROLLBACK TO sp1; INSERT INTO t VALUES (1)");
6747 assert_eq!(stmts.len(), 2);
6748 assert!(matches!(stmts[0], Statement::Rollback(_)));
6749 assert!(matches!(stmts[1], Statement::Insert(_)));
6750 }
6751
6752 #[test]
6753 fn test_attach_database() {
6754 let stmt = parse_one("ATTACH DATABASE 'other.db' AS other");
6755 if let Statement::Attach(a) = stmt {
6756 assert_eq!(a.schema, "other");
6757 } else {
6758 unreachable!("expected Attach");
6759 }
6760 }
6761
6762 #[test]
6763 fn test_attach_schema_qualified_access() {
6764 let stmt = parse_one("SELECT * FROM other.t");
6766 if let Statement::Select(s) = stmt {
6767 if let SelectCore::Select { from, .. } = &s.body.select {
6768 let from = from.as_ref().expect("FROM clause");
6769 match &from.source {
6770 TableOrSubquery::Table { name, .. } => {
6771 assert_eq!(name.schema.as_deref(), Some("other"));
6772 assert_eq!(name.name, "t");
6773 }
6774 other => unreachable!("expected Table source, got {other:?}"),
6775 }
6776 } else {
6777 unreachable!("expected Select core");
6778 }
6779 } else {
6780 unreachable!("expected Select");
6781 }
6782 }
6783
6784 #[test]
6785 fn test_detach_database() {
6786 let stmt = parse_one("DETACH DATABASE other");
6787 assert!(matches!(stmt, Statement::Detach(ref name) if name == "other"));
6788 }
6789
6790 #[test]
6791 fn test_attach_max_limit() {
6792 let stmt = parse_one("ATTACH 'db11.sqlite' AS db11");
6795 if let Statement::Attach(a) = stmt {
6796 assert_eq!(a.schema, "db11");
6797 } else {
6798 unreachable!("expected Attach");
6799 }
6800 }
6801
6802 #[test]
6803 fn test_cross_database_transaction() {
6804 let stmts = parse_ok("BEGIN; INSERT INTO main.t SELECT * FROM other.t; COMMIT");
6807 assert_eq!(stmts.len(), 3);
6808 assert!(matches!(stmts[0], Statement::Begin(_)));
6809 assert!(matches!(stmts[1], Statement::Insert(_)));
6810 assert!(matches!(stmts[2], Statement::Commit));
6811 }
6812
6813 #[test]
6814 fn test_explain_returns_bytecode() {
6815 let stmt = parse_one("EXPLAIN SELECT 1");
6816 if let Statement::Explain { query_plan, stmt } = stmt {
6817 assert!(!query_plan);
6818 assert!(matches!(*stmt, Statement::Select(_)));
6819 } else {
6820 unreachable!("expected Explain");
6821 }
6822 }
6823
6824 #[test]
6825 fn test_explain_query_plan_columns() {
6826 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6827 if let Statement::Explain { query_plan, stmt } = stmt {
6828 assert!(query_plan);
6829 assert!(matches!(*stmt, Statement::Select(_)));
6830 } else {
6831 unreachable!("expected Explain");
6832 }
6833 }
6834
6835 #[test]
6836 fn test_explain_query_plan_shows_index() {
6837 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6840 if let Statement::Explain { query_plan, .. } = stmt {
6841 assert!(query_plan);
6842 } else {
6843 unreachable!("expected Explain");
6844 }
6845 }
6846
6847 #[test]
6848 fn test_explain_query_plan_tree_structure() {
6849 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id");
6852 if let Statement::Explain { query_plan, stmt } = stmt {
6853 assert!(query_plan);
6854 assert!(matches!(*stmt, Statement::Select(_)));
6855 } else {
6856 unreachable!("expected Explain");
6857 }
6858 }
6859
6860 #[test]
6865 fn test_parser_keyword_as_column_name() {
6866 let stmt = parse_one("SELECT \"order\" FROM t");
6868 assert!(matches!(stmt, Statement::Select(_)));
6869 }
6870
6871 #[test]
6872 fn test_parser_keyword_as_alias() {
6873 let stmt = parse_one("SELECT 1 AS \"limit\"");
6874 assert!(matches!(stmt, Statement::Select(_)));
6875 }
6876
6877 #[test]
6878 fn test_parser_keyword_as_table_name() {
6879 let stmt = parse_one("SELECT * FROM \"group\"");
6880 assert!(matches!(stmt, Statement::Select(_)));
6881 }
6882
6883 #[test]
6888 fn test_parser_all_statement_types() {
6889 let statements = [
6891 "SELECT 1",
6893 "INSERT INTO t VALUES (1)",
6894 "INSERT OR REPLACE INTO t VALUES (1)",
6895 "UPDATE t SET a = 1",
6896 "DELETE FROM t WHERE id = 1",
6897 "REPLACE INTO t VALUES (1)",
6898 "CREATE TABLE t (id INTEGER PRIMARY KEY)",
6900 "CREATE TEMPORARY TABLE t (id INTEGER)",
6901 "CREATE TABLE IF NOT EXISTS t (id INTEGER)",
6902 "CREATE INDEX idx ON t (a)",
6903 "CREATE UNIQUE INDEX idx ON t (a)",
6904 "CREATE VIEW v AS SELECT 1",
6905 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END",
6906 "CREATE VIRTUAL TABLE t USING fts5(a, b)",
6907 "ALTER TABLE t RENAME TO t2",
6908 "ALTER TABLE t ADD COLUMN c TEXT",
6909 "ALTER TABLE t DROP COLUMN c",
6910 "ALTER TABLE t RENAME COLUMN a TO b",
6911 "DROP TABLE t",
6912 "DROP TABLE IF EXISTS t",
6913 "DROP INDEX idx",
6914 "DROP VIEW v",
6915 "DROP TRIGGER tr",
6916 "BEGIN",
6918 "BEGIN DEFERRED",
6919 "BEGIN IMMEDIATE",
6920 "BEGIN EXCLUSIVE",
6921 "COMMIT",
6922 "END",
6923 "ROLLBACK",
6924 "SAVEPOINT sp1",
6925 "RELEASE sp1",
6926 "RELEASE SAVEPOINT sp1",
6927 "ROLLBACK TO sp1",
6928 "ROLLBACK TO SAVEPOINT sp1",
6929 "ATTACH DATABASE ':memory:' AS db2",
6931 "DETACH db2",
6932 "ANALYZE",
6933 "ANALYZE t",
6934 "VACUUM",
6935 "VACUUM INTO '/tmp/backup.db'",
6936 "REINDEX",
6937 "REINDEX t",
6938 "EXPLAIN SELECT 1",
6939 "EXPLAIN QUERY PLAN SELECT 1",
6940 "PRAGMA journal_mode",
6942 "PRAGMA journal_mode = WAL",
6943 "PRAGMA table_info(t)",
6944 ];
6945
6946 for sql in &statements {
6947 let mut p = Parser::from_sql(sql);
6948 let (stmts, errs) = p.parse_all();
6949 assert!(errs.is_empty(), "failed to parse '{sql}': {errs:?}");
6950 assert_eq!(
6951 stmts.len(),
6952 1,
6953 "expected 1 statement for '{sql}', got {}",
6954 stmts.len()
6955 );
6956 }
6957 }
6958
6959 #[test]
6964 fn test_parser_expression_precedence_mul_over_add() {
6965 let stmt = parse_one("SELECT 1 + 2 * 3");
6967 if let Statement::Select(s) = stmt {
6968 if let SelectCore::Select { columns, .. } = &s.body.select {
6969 match &columns[0] {
6970 ResultColumn::Expr { expr, .. } => {
6971 assert!(
6973 matches!(expr, Expr::BinaryOp { .. }),
6974 "expected BinaryOp, got {expr:?}"
6975 );
6976 }
6977 other => unreachable!("expected Expr column, got {other:?}"),
6978 }
6979 } else {
6980 unreachable!("expected Select core");
6981 }
6982 } else {
6983 unreachable!("expected Select");
6984 }
6985 }
6986
6987 #[test]
6992 fn test_parser_insert_on_conflict() {
6993 let stmt =
6994 parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a");
6995 if let Statement::Insert(i) = stmt {
6996 assert!(!i.upsert.is_empty());
6997 } else {
6998 unreachable!("expected Insert");
6999 }
7000 }
7001
7002 #[test]
7003 fn test_parser_insert_returning() {
7004 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING *");
7005 if let Statement::Insert(i) = stmt {
7006 assert!(!i.returning.is_empty());
7007 } else {
7008 unreachable!("expected Insert");
7009 }
7010 }
7011
7012 #[test]
7013 fn test_parser_delete_returning() {
7014 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
7015 if let Statement::Delete(d) = stmt {
7016 assert!(!d.returning.is_empty());
7017 } else {
7018 unreachable!("expected Delete");
7019 }
7020 }
7021
7022 #[test]
7023 fn test_parser_update_returning() {
7024 let stmt = parse_one("UPDATE t SET a = 1 RETURNING a, b");
7025 if let Statement::Update(u) = stmt {
7026 assert_eq!(u.returning.len(), 2);
7027 } else {
7028 unreachable!("expected Update");
7029 }
7030 }
7031
7032 #[test]
7037 fn test_parser_union() {
7038 let stmt = parse_one("SELECT 1 UNION SELECT 2");
7039 if let Statement::Select(s) = stmt {
7040 assert_eq!(s.body.compounds.len(), 1);
7041 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
7042 } else {
7043 unreachable!("expected Select");
7044 }
7045 }
7046
7047 #[test]
7048 fn test_parser_intersect() {
7049 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
7050 if let Statement::Select(s) = stmt {
7051 assert_eq!(s.body.compounds.len(), 1);
7052 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
7053 } else {
7054 unreachable!("expected Select");
7055 }
7056 }
7057
7058 #[test]
7059 fn test_parser_except() {
7060 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
7061 if let Statement::Select(s) = stmt {
7062 assert_eq!(s.body.compounds.len(), 1);
7063 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
7064 } else {
7065 unreachable!("expected Select");
7066 }
7067 }
7068
7069 #[test]
7074 fn test_parser_subquery_in_from() {
7075 let stmt = parse_one("SELECT * FROM (SELECT 1 AS x) AS sub");
7076 assert!(matches!(stmt, Statement::Select(_)));
7077 }
7078
7079 #[test]
7084 fn test_parser_create_table_all_constraints() {
7085 let stmt = parse_one(
7086 "CREATE TABLE t (\
7087 id INTEGER PRIMARY KEY AUTOINCREMENT,\
7088 name TEXT NOT NULL DEFAULT '',\
7089 email TEXT UNIQUE,\
7090 age INTEGER CHECK(age >= 0),\
7091 dept_id INTEGER REFERENCES dept(id) ON DELETE CASCADE,\
7092 CONSTRAINT pk PRIMARY KEY (id),\
7093 UNIQUE (email),\
7094 CHECK (age < 200),\
7095 FOREIGN KEY (dept_id) REFERENCES dept(id)\
7096 )",
7097 );
7098 if let Statement::CreateTable(ct) = stmt {
7099 if let CreateTableBody::Columns {
7100 columns,
7101 constraints,
7102 } = ct.body
7103 {
7104 assert_eq!(columns.len(), 5);
7105 assert!(!constraints.is_empty());
7106 } else {
7107 unreachable!("expected column defs");
7108 }
7109 } else {
7110 unreachable!("expected CreateTable");
7111 }
7112 }
7113
7114 #[test]
7119 fn test_parser_create_trigger_before_delete() {
7120 let stmt = parse_one("CREATE TRIGGER tr BEFORE DELETE ON t BEGIN SELECT 1; END");
7121 if let Statement::CreateTrigger(tr) = stmt {
7122 assert_eq!(tr.timing, TriggerTiming::Before);
7123 assert!(matches!(tr.event, TriggerEvent::Delete));
7124 } else {
7125 unreachable!("expected CreateTrigger");
7126 }
7127 }
7128
7129 #[test]
7130 fn test_parser_create_trigger_instead_of_update() {
7131 let stmt =
7132 parse_one("CREATE TRIGGER tr INSTEAD OF UPDATE OF a, b ON v BEGIN SELECT 1; END");
7133 if let Statement::CreateTrigger(tr) = stmt {
7134 assert_eq!(tr.timing, TriggerTiming::InsteadOf);
7135 if let TriggerEvent::Update(cols) = &tr.event {
7136 assert_eq!(cols.len(), 2);
7137 } else {
7138 unreachable!("expected UpdateOf event");
7139 }
7140 } else {
7141 unreachable!("expected CreateTrigger");
7142 }
7143 }
7144
7145 #[test]
7150 fn test_parser_create_view_with_columns() {
7151 let stmt = parse_one("CREATE VIEW v (a, b) AS SELECT 1, 2");
7152 if let Statement::CreateView(cv) = stmt {
7153 assert_eq!(cv.columns, vec!["a".to_owned(), "b".to_owned()]);
7154 } else {
7155 unreachable!("expected CreateView");
7156 }
7157 }
7158
7159 #[test]
7164 fn test_parser_multi_join() {
7165 let stmt = parse_one(
7166 "SELECT a.x, b.y, c.z FROM a \
7167 JOIN b ON a.id = b.a_id \
7168 LEFT JOIN c ON b.id = c.b_id \
7169 CROSS JOIN d",
7170 );
7171 if let Statement::Select(s) = stmt {
7172 if let SelectCore::Select { from, .. } = &s.body.select {
7173 let from = from.as_ref().expect("FROM clause");
7174 assert_eq!(from.joins.len(), 3);
7175 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
7176 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
7177 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
7178 } else {
7179 unreachable!("expected Select core");
7180 }
7181 } else {
7182 unreachable!("expected Select");
7183 }
7184 }
7185
7186 #[test]
7191 fn test_parser_group_by_having() {
7192 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
7193 if let Statement::Select(s) = stmt {
7194 if let SelectCore::Select {
7195 group_by, having, ..
7196 } = &s.body.select
7197 {
7198 assert!(!group_by.is_empty());
7199 assert!(having.is_some());
7200 } else {
7201 unreachable!("expected Select core");
7202 }
7203 } else {
7204 unreachable!("expected Select");
7205 }
7206 }
7207
7208 #[test]
7213 fn test_parser_error_recovery_with_span() {
7214 let sql = "SELECT 1;\nXYZZY 42;\nSELECT 3";
7216 let mut p = Parser::from_sql(sql);
7217 let (stmts, errs) = p.parse_all();
7218 assert_eq!(stmts.len(), 2, "should recover two valid statements");
7219 assert!(!errs.is_empty(), "should report at least one error");
7220
7221 let err = &errs[0];
7222 assert_eq!(err.line, 2, "error should be on line 2");
7224 assert_eq!(err.col, 1, "error should be at column 1");
7225 assert!(
7227 err.span.start < err.span.end,
7228 "error span should be non-empty"
7229 );
7230 let source_len = u32::try_from(sql.len()).unwrap();
7231 assert!(
7232 err.span.end <= source_len,
7233 "error span.end should be within source"
7234 );
7235 }
7236
7237 #[test]
7238 fn test_parser_error_span_mid_line() {
7239 let bad = Parser::from_sql("CREATE").parse_statement();
7241 assert!(bad.is_err());
7242 let err = bad.unwrap_err();
7243 assert_eq!(err.line, 1);
7244 }
7245
7246 #[test]
7251 #[allow(clippy::too_many_lines)]
7252 fn test_parser_keyword_lookup_all_150() {
7253 use crate::token::TokenKind;
7254
7255 let keywords = [
7257 "ABORT",
7258 "ACTION",
7259 "ADD",
7260 "AFTER",
7261 "ALL",
7262 "ALTER",
7263 "ALWAYS",
7264 "ANALYZE",
7265 "AND",
7266 "AS",
7267 "ASC",
7268 "ATTACH",
7269 "AUTOINCREMENT",
7270 "BEFORE",
7271 "BEGIN",
7272 "BETWEEN",
7273 "BY",
7274 "CASCADE",
7275 "CASE",
7276 "CAST",
7277 "CHECK",
7278 "COLLATE",
7279 "COLUMN",
7280 "COMMIT",
7281 "CONCURRENT",
7282 "CONFLICT",
7283 "CONSTRAINT",
7284 "CREATE",
7285 "CROSS",
7286 "CURRENT_DATE",
7287 "CURRENT_TIME",
7288 "CURRENT_TIMESTAMP",
7289 "DATABASE",
7290 "DEFAULT",
7291 "DEFERRABLE",
7292 "DEFERRED",
7293 "DELETE",
7294 "DESC",
7295 "DETACH",
7296 "DISTINCT",
7297 "DO",
7298 "DROP",
7299 "EACH",
7300 "ELSE",
7301 "END",
7302 "ESCAPE",
7303 "EXCEPT",
7304 "EXCLUDE",
7305 "EXCLUSIVE",
7306 "EXISTS",
7307 "EXPLAIN",
7308 "FAIL",
7309 "FILTER",
7310 "FIRST",
7311 "FOLLOWING",
7312 "FOR",
7313 "FOREIGN",
7314 "FROM",
7315 "FULL",
7316 "GENERATED",
7317 "GLOB",
7318 "GROUP",
7319 "GROUPS",
7320 "HAVING",
7321 "IF",
7322 "IGNORE",
7323 "IMMEDIATE",
7324 "IN",
7325 "INDEX",
7326 "INDEXED",
7327 "INITIALLY",
7328 "INNER",
7329 "INSERT",
7330 "INSTEAD",
7331 "INTERSECT",
7332 "INTO",
7333 "IS",
7334 "ISNULL",
7335 "JOIN",
7336 "KEY",
7337 "LAST",
7338 "LEFT",
7339 "LIKE",
7340 "LIMIT",
7341 "MATCH",
7342 "MATERIALIZED",
7343 "NATURAL",
7344 "NO",
7345 "NOT",
7346 "NOTHING",
7347 "NOTNULL",
7348 "NULL",
7349 "NULLS",
7350 "OF",
7351 "OFFSET",
7352 "ON",
7353 "OR",
7354 "ORDER",
7355 "OTHERS",
7356 "OUTER",
7357 "OVER",
7358 "PARTITION",
7359 "PLAN",
7360 "PRAGMA",
7361 "PRECEDING",
7362 "PRIMARY",
7363 "QUERY",
7364 "RAISE",
7365 "RANGE",
7366 "RECURSIVE",
7367 "REFERENCES",
7368 "REGEXP",
7369 "REINDEX",
7370 "RELEASE",
7371 "RENAME",
7372 "REPLACE",
7373 "RESTRICT",
7374 "RETURNING",
7375 "RIGHT",
7376 "ROLLBACK",
7377 "ROW",
7378 "ROWS",
7379 "SAVEPOINT",
7380 "SELECT",
7381 "SET",
7382 "STORED",
7383 "STRICT",
7384 "TABLE",
7385 "TEMP",
7386 "TEMPORARY",
7387 "THEN",
7388 "TIES",
7389 "TO",
7390 "TRANSACTION",
7391 "TRIGGER",
7392 "TRUE",
7393 "FALSE",
7394 "UNBOUNDED",
7395 "UNION",
7396 "UNIQUE",
7397 "UPDATE",
7398 "USING",
7399 "VACUUM",
7400 "VALUES",
7401 "VIEW",
7402 "VIRTUAL",
7403 "WHEN",
7404 "WHERE",
7405 "WINDOW",
7406 "WITH",
7407 "WITHOUT",
7408 ];
7409
7410 assert!(
7411 keywords.len() >= 150,
7412 "expected 150+ keywords, got {}",
7413 keywords.len()
7414 );
7415
7416 for kw in &keywords {
7417 assert!(
7418 TokenKind::lookup_keyword(kw).is_some(),
7419 "keyword {kw} not recognized (uppercase)"
7420 );
7421 let lower = kw.to_ascii_lowercase();
7423 assert!(
7424 TokenKind::lookup_keyword(&lower).is_some(),
7425 "keyword {kw} not recognized (lowercase)"
7426 );
7427 let mixed: String = kw
7429 .chars()
7430 .enumerate()
7431 .map(|(i, c)| {
7432 if i % 2 == 0 {
7433 c.to_ascii_lowercase()
7434 } else {
7435 c.to_ascii_uppercase()
7436 }
7437 })
7438 .collect();
7439 assert!(
7440 TokenKind::lookup_keyword(&mixed).is_some(),
7441 "keyword {kw} not recognized (mixed case: {mixed})"
7442 );
7443 }
7444
7445 assert!(TokenKind::lookup_keyword("FOOBAR").is_none());
7447 assert!(TokenKind::lookup_keyword("").is_none());
7448 }
7449
7450 fn assert_roundtrip(sql: &str) {
7460 let ast1 = parse_one(sql);
7461 let rendered1 = ast1.to_string();
7462 let ast2 = parse_one(&rendered1);
7463 let rendered2 = ast2.to_string();
7464 assert_eq!(
7465 rendered1, rendered2,
7466 "round-trip failed for:\n input: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
7467 );
7468 }
7469
7470 #[test]
7471 fn test_roundtrip_select_simple() {
7472 assert_roundtrip("SELECT 1");
7473 assert_roundtrip("SELECT 1, 2, 3");
7474 assert_roundtrip("SELECT *");
7475 assert_roundtrip("SELECT * FROM t");
7476 assert_roundtrip("SELECT a, b FROM t WHERE a > 10");
7477 assert_roundtrip("SELECT a FROM t ORDER BY a DESC");
7478 assert_roundtrip("SELECT a FROM t LIMIT 10 OFFSET 5");
7479 }
7480
7481 #[test]
7482 fn test_roundtrip_select_distinct() {
7483 assert_roundtrip("SELECT DISTINCT a, b FROM t");
7484 }
7485
7486 #[test]
7487 fn test_roundtrip_select_alias() {
7488 assert_roundtrip("SELECT a AS x, b AS y FROM t AS u");
7489 }
7490
7491 #[test]
7492 fn test_roundtrip_select_join_types() {
7493 assert_roundtrip("SELECT * FROM a INNER JOIN b ON a.id = b.id");
7494 assert_roundtrip("SELECT * FROM a LEFT JOIN b ON a.id = b.id");
7495 assert_roundtrip("SELECT * FROM a RIGHT JOIN b ON a.id = b.id");
7496 assert_roundtrip("SELECT * FROM a FULL JOIN b ON a.id = b.id");
7497 assert_roundtrip("SELECT * FROM a CROSS JOIN b");
7498 assert_roundtrip("SELECT * FROM a NATURAL INNER JOIN b");
7499 assert_roundtrip("SELECT * FROM a LEFT JOIN b USING (id)");
7500 }
7501
7502 #[test]
7503 fn test_roundtrip_select_subquery() {
7504 assert_roundtrip("SELECT * FROM (SELECT 1 AS x) AS sub");
7505 }
7506
7507 #[test]
7508 fn test_roundtrip_select_group_by_having() {
7509 assert_roundtrip("SELECT a, count(*) FROM t GROUP BY a HAVING count(*) > 1");
7510 }
7511
7512 #[test]
7513 fn test_roundtrip_select_window() {
7514 assert_roundtrip("SELECT sum(x) OVER (PARTITION BY g ORDER BY x) FROM t");
7515 }
7516
7517 #[test]
7518 fn test_roundtrip_select_cte() {
7519 assert_roundtrip("WITH cte AS (SELECT 1 AS n) SELECT * FROM cte");
7520 assert_roundtrip(
7521 "WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cnt WHERE x < 10) SELECT * FROM cnt",
7522 );
7523 }
7524
7525 #[test]
7526 fn test_roundtrip_select_compound() {
7527 assert_roundtrip("SELECT 1 UNION SELECT 2");
7528 assert_roundtrip("SELECT 1 UNION ALL SELECT 2");
7529 assert_roundtrip("SELECT 1 INTERSECT SELECT 2");
7530 assert_roundtrip("SELECT 1 EXCEPT SELECT 2");
7531 }
7532
7533 #[test]
7534 fn test_roundtrip_insert() {
7535 assert_roundtrip("INSERT INTO t (a, b) VALUES (1, 2)");
7536 assert_roundtrip("INSERT INTO t DEFAULT VALUES");
7537 assert_roundtrip("INSERT INTO t SELECT * FROM u");
7538 assert_roundtrip("INSERT OR REPLACE INTO t (a) VALUES (1)");
7539 assert_roundtrip("REPLACE INTO t (a) VALUES (1)");
7540 }
7541
7542 #[test]
7543 fn test_roundtrip_insert_returning() {
7544 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING *");
7545 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING a, b");
7546 }
7547
7548 #[test]
7549 fn test_roundtrip_insert_on_conflict() {
7550 assert_roundtrip("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
7551 assert_roundtrip(
7552 "INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a",
7553 );
7554 }
7555
7556 #[test]
7557 fn test_roundtrip_update() {
7558 assert_roundtrip("UPDATE t SET a = 1");
7559 assert_roundtrip("UPDATE t SET a = 1, b = 2 WHERE c > 3");
7560 assert_roundtrip("UPDATE t SET a = 1 RETURNING *");
7561 }
7562
7563 #[test]
7564 fn test_roundtrip_delete() {
7565 assert_roundtrip("DELETE FROM t");
7566 assert_roundtrip("DELETE FROM t WHERE a = 1");
7567 assert_roundtrip("DELETE FROM t RETURNING *");
7568 }
7569
7570 #[test]
7571 fn test_roundtrip_create_table() {
7572 assert_roundtrip("CREATE TABLE t (a INTEGER, b TEXT)");
7573 assert_roundtrip("CREATE TABLE IF NOT EXISTS t (a INTEGER PRIMARY KEY)");
7574 assert_roundtrip("CREATE TEMP TABLE t (a TEXT NOT NULL, b REAL DEFAULT 0.0)");
7575 }
7576
7577 #[test]
7578 fn test_roundtrip_create_index() {
7579 assert_roundtrip("CREATE INDEX idx ON t (a)");
7580 assert_roundtrip("CREATE UNIQUE INDEX IF NOT EXISTS idx ON t (a, b DESC)");
7581 assert_roundtrip("CREATE INDEX idx ON t (a) WHERE a > 0");
7582 }
7583
7584 #[test]
7585 fn test_roundtrip_drop() {
7586 assert_roundtrip("DROP TABLE t");
7587 assert_roundtrip("DROP TABLE IF EXISTS t");
7588 assert_roundtrip("DROP INDEX idx");
7589 assert_roundtrip("DROP VIEW v");
7590 }
7591
7592 #[test]
7593 fn test_roundtrip_alter_table() {
7594 assert_roundtrip("ALTER TABLE t RENAME TO u");
7595 assert_roundtrip("ALTER TABLE t ADD COLUMN c TEXT");
7596 assert_roundtrip("ALTER TABLE t DROP COLUMN c");
7597 }
7598
7599 #[test]
7600 fn test_roundtrip_transaction() {
7601 assert_roundtrip("BEGIN");
7602 assert_roundtrip("BEGIN IMMEDIATE");
7603 assert_roundtrip("BEGIN EXCLUSIVE");
7604 assert_roundtrip("COMMIT");
7605 assert_roundtrip("ROLLBACK");
7606 assert_roundtrip("SAVEPOINT sp1");
7607 assert_roundtrip("RELEASE sp1");
7608 }
7609
7610 #[test]
7611 fn test_roundtrip_pragma() {
7612 assert_roundtrip("PRAGMA journal_mode");
7613 assert_roundtrip("PRAGMA journal_mode = wal");
7614 }
7615
7616 #[test]
7617 fn test_roundtrip_explain() {
7618 assert_roundtrip("EXPLAIN SELECT 1");
7619 assert_roundtrip("EXPLAIN QUERY PLAN SELECT * FROM t");
7620 }
7621
7622 #[test]
7623 fn test_roundtrip_expressions() {
7624 assert_roundtrip("SELECT 1 + 2 * 3");
7625 assert_roundtrip("SELECT NOT a");
7626 assert_roundtrip("SELECT -x");
7627 assert_roundtrip("SELECT ~x");
7628 assert_roundtrip("SELECT a BETWEEN 1 AND 10");
7629 assert_roundtrip("SELECT a NOT BETWEEN 1 AND 10");
7630 assert_roundtrip("SELECT a IN (1, 2, 3)");
7631 assert_roundtrip("SELECT a NOT IN (1, 2, 3)");
7632 assert_roundtrip("SELECT a LIKE '%foo%'");
7633 assert_roundtrip("SELECT a GLOB '*foo*'");
7634 assert_roundtrip("SELECT CASE WHEN a = 1 THEN 'one' ELSE 'other' END");
7635 assert_roundtrip("SELECT CASE x WHEN 1 THEN 'a' WHEN 2 THEN 'b' END");
7636 assert_roundtrip("SELECT CAST(a AS TEXT)");
7637 assert_roundtrip("SELECT EXISTS (SELECT 1)");
7638 assert_roundtrip("SELECT (SELECT 1)");
7639 assert_roundtrip("SELECT a COLLATE NOCASE");
7640 }
7641
7642 #[test]
7643 fn test_roundtrip_literals() {
7644 assert_roundtrip("SELECT NULL");
7645 assert_roundtrip("SELECT TRUE");
7646 assert_roundtrip("SELECT FALSE");
7647 assert_roundtrip("SELECT 42");
7648 assert_roundtrip("SELECT 3.14");
7649 assert_roundtrip("SELECT 'hello'");
7650 assert_roundtrip("SELECT X'DEADBEEF'");
7651 assert_roundtrip("SELECT CURRENT_TIME");
7652 assert_roundtrip("SELECT CURRENT_DATE");
7653 assert_roundtrip("SELECT CURRENT_TIMESTAMP");
7654 }
7655
7656 #[test]
7657 fn test_roundtrip_placeholders() {
7658 assert_roundtrip("SELECT ?");
7659 assert_roundtrip("SELECT ?1");
7660 assert_roundtrip("SELECT :name");
7661 assert_roundtrip("SELECT @name");
7662 assert_roundtrip("SELECT $name");
7663 }
7664
7665 #[test]
7666 fn test_roundtrip_json_arrows() {
7667 assert_roundtrip("SELECT a -> 'key'");
7668 assert_roundtrip("SELECT a ->> 'key'");
7669 }
7670
7671 #[test]
7672 fn test_roundtrip_function_calls() {
7673 assert_roundtrip("SELECT count(*)");
7674 assert_roundtrip("SELECT count(DISTINCT a)");
7675 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0)");
7676 }
7677
7678 #[test]
7679 fn test_roundtrip_isnull_notnull() {
7680 assert_roundtrip("SELECT a ISNULL");
7681 assert_roundtrip("SELECT a IS NOT NULL");
7682 }
7683
7684 #[test]
7685 fn test_roundtrip_create_view() {
7686 assert_roundtrip("CREATE VIEW v AS SELECT * FROM t");
7687 assert_roundtrip("CREATE VIEW IF NOT EXISTS v (a, b) AS SELECT 1, 2");
7688 }
7689
7690 #[test]
7691 fn test_roundtrip_create_trigger() {
7692 assert_roundtrip(
7693 "CREATE TRIGGER tr BEFORE DELETE ON t FOR EACH ROW BEGIN DELETE FROM log WHERE id = OLD.id; END",
7694 );
7695 }
7696
7697 #[test]
7698 fn test_roundtrip_attach_detach() {
7699 assert_roundtrip("ATTACH 'file.db' AS db2");
7700 assert_roundtrip("DETACH db2");
7701 }
7702
7703 #[test]
7704 fn test_roundtrip_vacuum() {
7705 assert_roundtrip("VACUUM");
7706 }
7707
7708 #[test]
7709 fn test_roundtrip_analyze_reindex() {
7710 assert_roundtrip("ANALYZE");
7711 assert_roundtrip("ANALYZE t");
7712 assert_roundtrip("REINDEX");
7713 assert_roundtrip("REINDEX t");
7714 }
7715
7716 #[test]
7717 fn test_roundtrip_cte_materialized() {
7718 assert_roundtrip("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
7719 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
7720 }
7721
7722 mod proptest_roundtrip {
7727 use super::*;
7728 use proptest::prelude::*;
7729
7730 fn is_keyword(s: &str) -> bool {
7732 TokenKind::lookup_keyword(s).is_some()
7733 }
7734
7735 fn arb_ident() -> BoxedStrategy<String> {
7737 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7738 .expect("valid regex")
7739 .prop_filter("must not be keyword", |s| !is_keyword(s))
7740 .boxed()
7741 }
7742
7743 fn arb_literal() -> BoxedStrategy<String> {
7745 prop_oneof![
7746 any::<i32>().prop_map(|n| n.to_string()),
7747 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7748 arb_ident().prop_map(|s| format!("'{s}'")),
7749 Just("NULL".to_string()),
7750 Just("TRUE".to_string()),
7751 Just("FALSE".to_string()),
7752 ]
7753 .boxed()
7754 }
7755
7756 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7758 if depth == 0 {
7759 prop_oneof![
7760 arb_literal(),
7761 arb_ident(),
7762 (arb_ident(), arb_ident()).prop_map(|(t, c)| format!("{t}.{c}")),
7763 ]
7764 .boxed()
7765 } else {
7766 let leaf = arb_expr(0);
7767 prop_oneof![
7768 4 => leaf,
7769 2 => (arb_expr(depth - 1), prop_oneof![
7771 Just("+"), Just("-"), Just("*"), Just("/"),
7772 Just("="), Just("!="), Just("<"), Just("<="),
7773 Just(">"), Just(">="), Just("AND"), Just("OR"),
7774 Just("||"),
7775 ], arb_expr(depth - 1))
7776 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7777 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7779 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7780 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NULL")),
7782 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NOT NULL")),
7783 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7785 .prop_map(|(e, lo, hi)| format!("{e} BETWEEN {lo} AND {hi}")),
7786 1 => (arb_expr(depth - 1), proptest::collection::vec(arb_expr(0), 1..4))
7788 .prop_map(|(e, items)| format!("{e} IN ({})", items.join(", "))),
7789 1 => (arb_expr(depth - 1), arb_ident())
7791 .prop_map(|(e, p)| format!("{e} LIKE '{p}'")),
7792 1 => arb_expr(depth - 1).prop_map(|e| format!("CAST({e} AS TEXT)")),
7794 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7796 .prop_map(|(c, t, el)| format!("CASE WHEN {c} THEN {t} ELSE {el} END")),
7797 1 => (arb_ident(), proptest::collection::vec(arb_expr(0), 0..3))
7799 .prop_map(|(name, args)| format!("{name}({})", args.join(", "))),
7800 1 => arb_expr(0).prop_map(|e| format!("(SELECT {e})")),
7802 ]
7803 .boxed()
7804 }
7805 }
7806
7807 fn arb_select() -> BoxedStrategy<String> {
7809 use std::fmt::Write as _;
7810
7811 let cols =
7812 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
7813 let table = arb_ident();
7814 let where_clause = prop::option::of(arb_expr(1));
7815 let order_by = prop::option::of(arb_ident());
7816 let limit = prop::option::of(1u32..100);
7817
7818 (cols, table, where_clause, order_by, limit)
7819 .prop_map(|(cols, tbl, wh, ord, lim)| {
7820 let mut sql = format!("SELECT {cols} FROM {tbl}");
7821 if let Some(w) = wh {
7822 write!(sql, " WHERE {w}").expect("writing to String should not fail");
7823 }
7824 if let Some(o) = ord {
7825 write!(sql, " ORDER BY {o}").expect("writing to String should not fail");
7826 }
7827 if let Some(l) = lim {
7828 write!(sql, " LIMIT {l}").expect("writing to String should not fail");
7829 }
7830 sql
7831 })
7832 .boxed()
7833 }
7834
7835 fn arb_insert() -> BoxedStrategy<String> {
7837 let ncols = 1usize..4;
7838 ncols
7839 .prop_flat_map(|n| {
7840 let tbl = arb_ident();
7841 let cols = proptest::collection::vec(arb_ident(), n..=n);
7842 let vals = proptest::collection::vec(arb_literal(), n..=n);
7843 (tbl, cols, vals).prop_map(|(t, cs, vs): (String, Vec<String>, Vec<String>)| {
7844 format!(
7845 "INSERT INTO {t} ({}) VALUES ({})",
7846 cs.join(", "),
7847 vs.join(", ")
7848 )
7849 })
7850 })
7851 .boxed()
7852 }
7853
7854 fn arb_statement() -> BoxedStrategy<String> {
7856 prop_oneof![
7857 6 => arb_select(),
7858 3 => arb_insert(),
7859 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
7860 1 => (arb_ident(), arb_expr(1))
7861 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
7862 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
7863 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
7864 ]
7865 .boxed()
7866 }
7867
7868 fn try_parse_one(sql: &str) -> Option<Statement> {
7870 let mut p = Parser::from_sql(sql);
7871 let (stmts, errs) = p.parse_all();
7872 if errs.is_empty() && stmts.len() == 1 {
7873 Some(stmts.into_iter().next().unwrap())
7874 } else {
7875 None
7876 }
7877 }
7878
7879 proptest::proptest! {
7880 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
7881
7882 #[test]
7883 fn test_parser_roundtrip_proptest(sql in arb_statement()) {
7884 let Some(ast1) = try_parse_one(&sql) else {
7886 return Ok(()); };
7888
7889 let rendered1 = ast1.to_string();
7891
7892 let Some(ast2) = try_parse_one(&rendered1) else {
7894 let msg = format!("re-parse failed for rendered SQL: {rendered1:?}");
7895 prop_assert!(false, "{}", msg);
7896 unreachable!()
7897 };
7898
7899 let rendered2 = ast2.to_string();
7901 let msg = format!(
7902 "round-trip not idempotent:\n original: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
7903 );
7904 prop_assert_eq!(rendered1, rendered2, "{}", msg);
7905 }
7906 }
7907 }
7908
7909 mod proptest_properties {
7914 use super::*;
7915 use proptest::prelude::*;
7916
7917 fn arb_ident() -> BoxedStrategy<String> {
7919 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7920 .expect("valid regex")
7921 .prop_filter("must not be keyword", |s| {
7922 TokenKind::lookup_keyword(s).is_none()
7923 })
7924 .boxed()
7925 }
7926
7927 fn arb_literal() -> BoxedStrategy<String> {
7928 prop_oneof![
7929 any::<i32>().prop_map(|n| n.to_string()),
7930 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7931 arb_ident().prop_map(|s| format!("'{s}'")),
7932 Just("NULL".to_string()),
7933 Just("TRUE".to_string()),
7934 Just("FALSE".to_string()),
7935 ]
7936 .boxed()
7937 }
7938
7939 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7940 if depth == 0 {
7941 prop_oneof![arb_literal(), arb_ident(),].boxed()
7942 } else {
7943 let leaf = arb_expr(0);
7944 prop_oneof![
7945 4 => leaf,
7946 2 => (arb_expr(depth - 1), prop_oneof![
7947 Just("+"), Just("-"), Just("*"), Just("/"),
7948 Just("="), Just("!="), Just("<"), Just("<="),
7949 Just(">"), Just(">="), Just("AND"), Just("OR"),
7950 ], arb_expr(depth - 1))
7951 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7952 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7953 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7954 ]
7955 .boxed()
7956 }
7957 }
7958
7959 fn arb_select() -> BoxedStrategy<String> {
7960 use std::fmt::Write as _;
7961 let cols =
7962 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
7963 let table = arb_ident();
7964 let where_clause = prop::option::of(arb_expr(1));
7965 (cols, table, where_clause)
7966 .prop_map(|(cols, tbl, wh)| {
7967 let mut sql = format!("SELECT {cols} FROM {tbl}");
7968 if let Some(w) = wh {
7969 write!(sql, " WHERE {w}").expect("writing to String should not fail");
7970 }
7971 sql
7972 })
7973 .boxed()
7974 }
7975
7976 fn arb_statement() -> BoxedStrategy<String> {
7977 prop_oneof![
7978 6 => arb_select(),
7979 3 => {
7980 let ncols = 1usize..4;
7981 ncols
7982 .prop_flat_map(|n| {
7983 let tbl = arb_ident();
7984 let cols = proptest::collection::vec(arb_ident(), n..=n);
7985 let vals = proptest::collection::vec(arb_literal(), n..=n);
7986 (tbl, cols, vals).prop_map(
7987 |(t, cs, vs): (String, Vec<String>, Vec<String>)| {
7988 format!(
7989 "INSERT INTO {t} ({}) VALUES ({})",
7990 cs.join(", "),
7991 vs.join(", ")
7992 )
7993 },
7994 )
7995 })
7996 .boxed()
7997 },
7998 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
7999 1 => (arb_ident(), arb_expr(1))
8000 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
8001 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
8002 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
8003 ]
8004 .boxed()
8005 }
8006
8007 proptest::proptest! {
8009 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(500))]
8010
8011 #[test]
8012 fn test_parser_determinism(sql in arb_statement()) {
8013 let mut p1 = Parser::from_sql(&sql);
8014 let (stmts1, errs1) = p1.parse_all();
8015
8016 let mut p2 = Parser::from_sql(&sql);
8017 let (stmts2, errs2) = p2.parse_all();
8018
8019 let msg_stmt = format!("different statement counts for: {sql}");
8021 prop_assert_eq!(stmts1.len(), stmts2.len(), "{}", msg_stmt);
8022 let msg_err = format!("different error counts for: {sql}");
8023 prop_assert_eq!(errs1.len(), errs2.len(), "{}", msg_err);
8024
8025 if errs1.is_empty() && !stmts1.is_empty() {
8027 for (s1, s2) in stmts1.iter().zip(stmts2.iter()) {
8028 let r1 = s1.to_string();
8029 let r2 = s2.to_string();
8030 let msg_det = format!("non-deterministic parse output for: {sql}");
8031 prop_assert_eq!(r1, r2, "{}", msg_det);
8032 }
8033 }
8034 }
8035 }
8036
8037 proptest::proptest! {
8039 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(2000))]
8040
8041 #[test]
8042 fn test_parser_fuzz_no_panic(input in prop::collection::vec(any::<u8>(), 0..256)) {
8043 let sql = String::from_utf8_lossy(&input);
8044 let mut p = Parser::from_sql(&sql);
8046 let _ = p.parse_all();
8047 }
8048 }
8049
8050 proptest::proptest! {
8052 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
8053
8054 #[test]
8055 fn test_parser_fuzz_near_valid(
8056 prefix in prop_oneof![
8057 Just("SELECT "),
8058 Just("INSERT INTO "),
8059 Just("DELETE FROM "),
8060 Just("UPDATE "),
8061 Just("CREATE TABLE "),
8062 Just("DROP TABLE "),
8063 Just("BEGIN "),
8064 Just("PRAGMA "),
8065 ],
8066 suffix in prop::string::string_regex("[a-zA-Z0-9_ ,.*=<>!()'\";+\\-/]{0,100}")
8067 .expect("valid regex")
8068 ) {
8069 let sql = format!("{prefix}{suffix}");
8070 let mut p = Parser::from_sql(&sql);
8071 let _ = p.parse_all();
8072 }
8073 }
8074
8075 proptest::proptest! {
8077 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
8078
8079 #[test]
8080 fn test_parser_unicode_identifiers(
8081 name in prop::string::string_regex("[\\p{L}][\\p{L}\\p{N}_]{0,10}")
8082 .expect("valid regex")
8083 .prop_filter("must not be keyword", |s| {
8084 TokenKind::lookup_keyword(s).is_none()
8085 })
8086 ) {
8087 let sql = format!("SELECT \"{name}\" FROM \"{name}\"");
8089 let mut p = Parser::from_sql(&sql);
8090 let (stmts, errs) = p.parse_all();
8091 prop_assert!(
8092 errs.is_empty(),
8093 "Unicode identifier should parse: {sql}, errors: {errs:?}"
8094 );
8095 prop_assert_eq!(stmts.len(), 1);
8096 }
8097 }
8098
8099 proptest::proptest! {
8101 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(300))]
8102
8103 #[test]
8104 fn test_parser_rejects_incomplete_statements(
8105 kind in prop_oneof![
8106 Just("SELECT"),
8107 Just("SELECT FROM"),
8108 Just("INSERT INTO"),
8109 Just("DELETE"),
8110 Just("UPDATE SET"),
8111 Just("CREATE"),
8112 Just("CREATE TABLE"),
8113 Just("DROP"),
8114 ],
8115 trailing in prop::option::of(
8116 prop::string::string_regex("[;, ]{0,3}").expect("valid regex")
8117 )
8118 ) {
8119 let sql = match trailing {
8120 Some(t) => format!("{kind}{t}"),
8121 None => kind.to_string(),
8122 };
8123 let mut p = Parser::from_sql(&sql);
8124 let (stmts, errs) = p.parse_all();
8125 prop_assert!(
8129 !errs.is_empty() || stmts.is_empty(),
8130 "Expected rejection of incomplete SQL: {sql}, got {stmts:?}"
8131 );
8132 }
8133 }
8134
8135 proptest::proptest! {
8138 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
8139
8140 #[test]
8141 fn test_parser_multi_statement_count(
8142 stmts in proptest::collection::vec(arb_statement(), 1..4)
8143 ) {
8144 let sql = stmts.join("; ");
8145 let mut p = Parser::from_sql(&sql);
8146 let (parsed, errors) = p.parse_all();
8147 if errors.is_empty() {
8149 prop_assert!(
8150 parsed.len() >= stmts.len(),
8151 "Expected at least {} statements from: {sql}, got {}",
8152 stmts.len(),
8153 parsed.len()
8154 );
8155 }
8156 }
8157 }
8158 }
8159
8160 #[test]
8161 fn test_parse_statements_with_scratch_reuses_token_and_error_capacity() {
8162 let mut scratch = StatementParseScratch::default();
8163 let err = parse_statements_with_scratch("SELECT FROM", &mut scratch)
8164 .expect_err("malformed SQL should surface a parse error");
8165 assert!(
8166 err.message.contains("expected"),
8167 "malformed parse should preserve its diagnostic detail",
8168 );
8169 let warmed_token_capacity = scratch.token_capacity();
8170 let warmed_error_capacity = scratch.error_capacity();
8171 assert!(
8172 warmed_token_capacity > 0,
8173 "parse scratch should warm token storage"
8174 );
8175 assert!(
8176 warmed_error_capacity > 0,
8177 "parse scratch should warm error storage"
8178 );
8179
8180 let statements = parse_statements_with_scratch("SELECT 1;", &mut scratch)
8181 .expect("follow-up parse should succeed");
8182 assert_eq!(statements.len(), 1);
8183 assert_eq!(
8184 scratch.token_capacity(),
8185 warmed_token_capacity,
8186 "successful parse should reuse token scratch capacity",
8187 );
8188 assert_eq!(
8189 scratch.error_capacity(),
8190 warmed_error_capacity,
8191 "successful parse should preserve error scratch capacity for the next recovery path",
8192 );
8193 }
8194
8195 #[test]
8196 fn test_parse_statements_with_scratch_reuses_identifier_interns_across_parses() {
8197 let mut scratch = StatementParseScratch::default();
8198 let mut sql = String::from("SELECT ");
8199 for i in 0..32 {
8200 if i > 0 {
8201 sql.push_str(", ");
8202 }
8203 sql.push_str(&format!("unique_identifier_{i} AS unique_alias_{i}"));
8204 }
8205 sql.push(';');
8206
8207 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8208 .expect("identifier-heavy statement should parse");
8209 assert_eq!(statements.len(), 1);
8210 let interner_len = scratch.identifier_interner_len();
8211 assert!(
8212 interner_len > 0,
8213 "scratch should retain identifier interns for the next parse",
8214 );
8215
8216 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8217 .expect("repeat parse should also succeed");
8218 assert_eq!(statements.len(), 1);
8219 assert_eq!(
8220 scratch.identifier_interner_len(),
8221 interner_len,
8222 "repeated parse should reuse the retained interner set instead of growing it",
8223 );
8224
8225 scratch.reset();
8226 assert!(
8227 scratch.identifier_interner_is_empty(),
8228 "explicit scratch reset should also keep the interner logically empty",
8229 );
8230 }
8231
8232 #[test]
8233 fn test_parse_statements_with_scratch_drops_oversized_identifier_interner() {
8234 let mut scratch = StatementParseScratch::default();
8235 let mut sql = String::from("SELECT ");
8236 for i in 0..300 {
8237 if i > 0 {
8238 sql.push_str(", ");
8239 }
8240 sql.push_str(&format!(
8241 "very_long_unique_identifier_{i:03} AS alias_{i:03}"
8242 ));
8243 }
8244 sql.push(';');
8245
8246 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8247 .expect("oversized identifier-heavy statement should parse");
8248 assert_eq!(statements.len(), 1);
8249 assert!(
8250 scratch.identifier_interner_is_empty(),
8251 "oversized identifier interners should be dropped instead of retained indefinitely",
8252 );
8253 }
8254
8255 #[test]
8259 fn create_table_quoted_reserved_word_key() {
8260 parse_ok(r#"CREATE TABLE "meta" ("key" TEXT, "val" TEXT);"#);
8262 }
8263
8264 #[test]
8265 fn create_table_unquoted_key_column() {
8266 parse_ok("CREATE TABLE meta (key TEXT, val TEXT);");
8268 }
8269
8270 #[test]
8271 fn create_table_quoted_order_column() {
8272 parse_ok(r#"CREATE TABLE t ("order" INTEGER);"#);
8274 }
8275
8276 #[test]
8277 fn create_table_quoted_select_column() {
8278 parse_ok(r#"CREATE TABLE t ("select" TEXT);"#);
8280 }
8281
8282 #[test]
8283 fn select_with_reserved_word_column_key() {
8284 parse_ok("SELECT key FROM meta;");
8286 }
8287
8288 #[test]
8289 fn select_with_reserved_word_column_value() {
8290 parse_ok("SELECT value FROM meta;");
8292 }
8293
8294 #[test]
8295 fn select_with_reserved_word_column_order() {
8296 parse_ok(r#"SELECT "order" FROM t;"#);
8298 }
8299
8300 #[test]
8301 fn where_clause_with_reserved_word_column() {
8302 parse_ok("UPDATE meta SET val = '2.0' WHERE key = 'version';");
8304 }
8305
8306 #[test]
8307 fn update_set_reserved_word_column() {
8308 parse_ok(r#"UPDATE meta SET "key" = 'newkey' WHERE "key" = 'oldkey';"#);
8310 }
8311
8312 #[test]
8313 fn delete_where_reserved_word_column() {
8314 parse_ok("DELETE FROM meta WHERE key = 'version';");
8315 }
8316
8317 #[test]
8318 fn persistence_dump_with_reserved_word_columns() {
8319 let sql = concat!(
8322 r#"CREATE TABLE "meta" ("key" TEXT, "value" TEXT);"#,
8323 "\n",
8324 r#"INSERT INTO "meta" VALUES ('version', '1.0');"#,
8325 "\n",
8326 r#"INSERT INTO "meta" VALUES ('author', 'test');"#,
8327 );
8328 let mut p = Parser::from_sql(sql);
8329 let (stmts, errs) = p.parse_all();
8330 assert!(
8331 errs.is_empty(),
8332 "persistence dump with reserved-word columns should parse cleanly: {errs:?}"
8333 );
8334 assert_eq!(stmts.len(), 3);
8335 }
8336
8337 #[test]
8338 fn create_table_with_single_quoted_name_parses_cleanly() {
8339 let sql = "CREATE TABLE 'fts_messages_data'(id INTEGER PRIMARY KEY, block BLOB);";
8340 let mut p = Parser::from_sql(sql);
8341 let (stmts, errs) = p.parse_all();
8342 assert!(
8343 errs.is_empty(),
8344 "single-quoted sqlite_master shadow-table SQL should parse cleanly: {errs:?}"
8345 );
8346 assert_eq!(stmts.len(), 1);
8347 match &stmts[0] {
8348 Statement::CreateTable(stmt) => {
8349 assert_eq!(stmt.name.name, "fts_messages_data");
8350 }
8351 other => panic!("expected CreateTable, got {other:?}"),
8352 }
8353 }
8354
8355 #[test]
8356 fn select_qualified_column_with_alias() {
8357 let stmt = parse_one("SELECT a.name AS from_name FROM users a");
8360 if let Statement::Select(s) = stmt {
8361 if let SelectCore::Select { columns, .. } = &s.body.select {
8362 assert_eq!(columns.len(), 1);
8363 match &columns[0] {
8364 ResultColumn::Expr { expr, alias } => {
8365 assert_eq!(
8367 alias.as_deref(),
8368 Some("from_name"),
8369 "alias should be 'from_name', got {alias:?}"
8370 );
8371 if let Expr::Column(col_ref, _) = expr {
8373 assert_eq!(col_ref.table.as_deref(), Some("a"));
8374 assert_eq!(col_ref.column.as_ref(), "name");
8375 } else {
8376 panic!("expected Column expression, got {expr:?}");
8377 }
8378 }
8379 other => panic!("expected Expr variant, got {other:?}"),
8380 }
8381 } else {
8382 panic!("expected Select core");
8383 }
8384 } else {
8385 panic!("expected Select statement");
8386 }
8387 }
8388
8389 #[test]
8390 fn select_qualified_column_with_implicit_alias() {
8391 let stmt = parse_one("SELECT a.name from_name FROM users a");
8393 if let Statement::Select(s) = stmt {
8394 if let SelectCore::Select { columns, .. } = &s.body.select {
8395 assert_eq!(columns.len(), 1);
8396 match &columns[0] {
8397 ResultColumn::Expr { expr, alias } => {
8398 assert_eq!(
8400 alias.as_deref(),
8401 Some("from_name"),
8402 "implicit alias should be 'from_name', got {alias:?}"
8403 );
8404 if let Expr::Column(col_ref, _) = expr {
8406 assert_eq!(col_ref.table.as_deref(), Some("a"));
8407 assert_eq!(col_ref.column.as_ref(), "name");
8408 } else {
8409 panic!("expected Column expression, got {expr:?}");
8410 }
8411 }
8412 other => panic!("expected Expr variant, got {other:?}"),
8413 }
8414 } else {
8415 panic!("expected Select core");
8416 }
8417 } else {
8418 panic!("expected Select statement");
8419 }
8420 }
8421
8422 #[test]
8423 fn select_implicit_alias_non_reserved_keyword() {
8424 let stmt = parse_one("SELECT 1 action");
8427 if let Statement::Select(s) = stmt {
8428 if let SelectCore::Select { columns, .. } = &s.body.select {
8429 if let ResultColumn::Expr { alias, .. } = &columns[0] {
8430 assert_eq!(
8431 alias.as_deref(),
8432 Some("action"),
8433 "implicit alias 'action' (keyword) failed to parse"
8434 );
8435 } else {
8436 unreachable!("expected Expr result column");
8437 }
8438 } else {
8439 unreachable!("expected Select core");
8440 }
8441 } else {
8442 unreachable!("expected Select");
8443 }
8444 }
8445}