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