1use std::error::Error;
6use std::fmt;
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8
9use fsqlite_ast::{
10 AlterTableAction, AlterTableStatement, Assignment, AssignmentTarget, AttachStatement,
11 BeginStatement, ColumnConstraint, ColumnConstraintKind, ColumnDef, CompoundOp, ConflictAction,
12 CreateIndexStatement, CreateTableBody, CreateTableStatement, CreateTriggerStatement,
13 CreateViewStatement, CreateVirtualTableStatement, Cte, CteMaterialized, DefaultValue,
14 Deferrable, DeferrableInitially, DeleteStatement, Distinctness, DropObjectType, DropStatement,
15 Expr, ForeignKeyAction, ForeignKeyActionType, ForeignKeyClause, ForeignKeyTrigger, FrameBound,
16 FrameExclude, FrameSpec, FrameType, FromClause, GeneratedStorage, IndexHint, IndexedColumn,
17 InsertSource, InsertStatement, JoinClause, JoinConstraint, JoinKind, JoinType, LimitClause,
18 Literal, NullsOrder, OrderingTerm, PragmaStatement, PragmaValue, QualifiedName,
19 QualifiedTableRef, ResultColumn, RollbackStatement, SelectBody, SelectCore, SelectStatement,
20 SortDirection, Span, Statement, TableConstraint, TableConstraintKind, TableOrSubquery,
21 TimeTravelClause, TimeTravelTarget, TransactionMode, TriggerEvent, TriggerTiming, TypeName,
22 UpdateStatement, UpsertAction, UpsertClause, UpsertTarget, VacuumStatement, WindowDef,
23 WindowSpec, WithClause,
24};
25
26use crate::lexer::Lexer;
27use crate::token::{Token, TokenKind};
28
29static FSQLITE_PARSE_STATEMENTS_TOTAL: AtomicU64 = AtomicU64::new(0);
35static FSQLITE_PARSE_TOKENS_TOTAL: AtomicU64 = AtomicU64::new(0);
37static FSQLITE_PARSE_ERRORS_TOTAL: AtomicU64 = AtomicU64::new(0);
39static FSQLITE_PARSE_METRICS_ENABLED: AtomicBool = AtomicBool::new(false);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
48pub struct ParseMetricsSnapshot {
49 pub fsqlite_parse_statements_total: u64,
51 pub fsqlite_parse_tokens_total: u64,
53 pub fsqlite_parse_errors_total: u64,
55}
56
57#[must_use]
59pub fn parse_metrics_snapshot() -> ParseMetricsSnapshot {
60 ParseMetricsSnapshot {
61 fsqlite_parse_statements_total: FSQLITE_PARSE_STATEMENTS_TOTAL.load(Ordering::Relaxed),
62 fsqlite_parse_tokens_total: FSQLITE_PARSE_TOKENS_TOTAL.load(Ordering::Relaxed),
63 fsqlite_parse_errors_total: FSQLITE_PARSE_ERRORS_TOTAL.load(Ordering::Relaxed),
64 }
65}
66
67pub fn set_parse_metrics_enabled(enabled: bool) {
69 FSQLITE_PARSE_METRICS_ENABLED.store(enabled, Ordering::Relaxed);
70}
71
72#[must_use]
74pub fn parse_metrics_enabled() -> bool {
75 FSQLITE_PARSE_METRICS_ENABLED.load(Ordering::Relaxed)
76}
77
78pub fn reset_parse_metrics() {
80 FSQLITE_PARSE_STATEMENTS_TOTAL.store(0, Ordering::Relaxed);
81 FSQLITE_PARSE_TOKENS_TOTAL.store(0, Ordering::Relaxed);
82 FSQLITE_PARSE_ERRORS_TOTAL.store(0, Ordering::Relaxed);
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct ParseError {
91 pub message: String,
92 pub span: Span,
93 pub line: u32,
94 pub col: u32,
95}
96
97impl ParseError {
98 #[must_use]
99 pub(crate) fn at(message: impl Into<String>, token: Option<&Token>) -> Self {
100 if let Some(t) = token {
101 Self {
102 message: message.into(),
103 span: t.span,
104 line: t.line,
105 col: t.col,
106 }
107 } else {
108 Self {
109 message: message.into(),
110 span: Span::ZERO,
111 line: 0,
112 col: 0,
113 }
114 }
115 }
116}
117
118impl fmt::Display for ParseError {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 write!(f, "{}:{}: {}", self.line, self.col, self.message)
121 }
122}
123
124impl Error for ParseError {}
125
126#[derive(Debug, Default)]
132pub struct StatementParseScratch {
133 tokens: Vec<Token>,
134 errors: Vec<ParseError>,
135 identifier_interner: crate::lexer::IdentifierInterner,
136}
137
138impl StatementParseScratch {
139 pub fn reset(&mut self) {
141 self.tokens.clear();
142 self.errors.clear();
143 self.identifier_interner.reset();
144 }
145
146 #[must_use]
147 pub fn token_capacity(&self) -> usize {
148 self.tokens.capacity()
149 }
150
151 #[must_use]
152 pub fn error_capacity(&self) -> usize {
153 self.errors.capacity()
154 }
155
156 #[must_use]
157 pub fn retained_bytes(&self) -> usize {
158 self.tokens
159 .capacity()
160 .saturating_mul(std::mem::size_of::<Token>())
161 .saturating_add(
162 self.errors
163 .capacity()
164 .saturating_mul(std::mem::size_of::<ParseError>()),
165 )
166 .saturating_add(self.identifier_interner.retained_bytes())
167 }
168
169 #[cfg(test)]
170 fn identifier_interner_is_empty(&self) -> bool {
171 self.identifier_interner.is_empty()
172 }
173
174 #[cfg(test)]
175 fn identifier_interner_len(&self) -> usize {
176 self.identifier_interner.len()
177 }
178}
179
180pub const MAX_PARSE_DEPTH: u32 = 1000;
190
191pub struct Parser {
192 pub(crate) tokens: Vec<Token>,
193 pub(crate) pos: usize,
194 pub(crate) errors: Vec<ParseError>,
195 pub(crate) depth: u32,
196}
197
198impl Parser {
199 #[must_use]
200 pub fn new(tokens: Vec<Token>) -> Self {
201 Self {
202 tokens,
203 pos: 0,
204 errors: Vec::new(),
205 depth: 0,
206 }
207 }
208
209 pub(crate) fn enter_recursion(&mut self) -> Result<(), ParseError> {
210 if self.depth >= MAX_PARSE_DEPTH {
211 return Err(self.err_msg(format!(
212 "expression tree is too deep (maximum depth {MAX_PARSE_DEPTH})"
213 )));
214 }
215 self.depth += 1;
216 Ok(())
217 }
218
219 pub(crate) fn leave_recursion(&mut self) {
220 self.depth = self.depth.saturating_sub(1);
221 }
222
223 pub(crate) fn with_recursion_guard<T>(
224 &mut self,
225 f: impl FnOnce(&mut Self) -> Result<T, ParseError>,
226 ) -> Result<T, ParseError> {
227 self.enter_recursion()?;
228 let result = f(self);
229 self.leave_recursion();
230 result
231 }
232
233 #[must_use]
234 pub fn from_sql(sql: &str) -> Self {
235 Self::new(Lexer::tokenize(sql))
236 }
237
238 pub fn parse_all(&mut self) -> (Vec<Statement>, Vec<ParseError>) {
239 let parse_debug_enabled = tracing::enabled!(target: "fsqlite.parse", tracing::Level::DEBUG);
240 let collect_parse_metrics = parse_metrics_enabled();
241 if collect_parse_metrics {
242 let token_count = u64::try_from(self.tokens.len()).unwrap_or(u64::MAX);
243 FSQLITE_PARSE_TOKENS_TOTAL.fetch_add(token_count, Ordering::Relaxed);
244 }
245 let span = parse_debug_enabled.then(|| {
246 tracing::debug_span!(
247 target: "fsqlite.parse",
248 "parse",
249 ast_node_count = tracing::field::Empty,
250 parse_errors = tracing::field::Empty,
251 )
252 });
253 let _guard = span.as_ref().map(|span| span.enter());
254
255 let mut stmts = Vec::new();
256 while !self.at_eof() {
257 if self.check(&TokenKind::Semicolon) {
258 self.advance();
259 continue;
260 }
261 match self.parse_statement() {
262 Ok(s) => {
263 if collect_parse_metrics {
264 FSQLITE_PARSE_STATEMENTS_TOTAL.fetch_add(1, Ordering::Relaxed);
265 }
266 stmts.push(s);
267 let _ = self.eat(&TokenKind::Semicolon);
268 }
269 Err(e) => {
270 if collect_parse_metrics {
271 FSQLITE_PARSE_ERRORS_TOTAL.fetch_add(1, Ordering::Relaxed);
272 }
273 tracing::warn!(
274 target: "fsqlite.parse",
275 error = %e,
276 "parse recovery: skipping malformed statement"
277 );
278 self.errors.push(e);
279 self.synchronize();
280 }
281 }
282 }
283
284 let errors = std::mem::take(&mut self.errors);
285 if let Some(span) = span.as_ref() {
286 span.record("ast_node_count", stmts.len() as u64);
287 span.record("parse_errors", errors.len() as u64);
288 }
289
290 (stmts, errors)
291 }
292
293 pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
294 self.parse_statement_inner()
295 }
296
297 #[must_use]
298 pub fn errors(&self) -> &[ParseError] {
299 &self.errors
300 }
301
302 pub(crate) fn peek(&self) -> &TokenKind {
307 self.current().map_or(&TokenKind::Eof, |t| &t.kind)
308 }
309
310 pub(crate) fn current(&self) -> Option<&Token> {
311 self.tokens.get(self.pos)
312 }
313
314 pub(crate) fn peek_nth(&self, n: usize) -> &TokenKind {
315 self.tokens
316 .get(self.pos + n)
317 .map_or(&TokenKind::Eof, |t| &t.kind)
318 }
319
320 pub(crate) fn at_eof(&self) -> bool {
321 matches!(self.peek(), TokenKind::Eof)
322 }
323
324 pub(crate) fn advance(&mut self) -> Option<&Token> {
325 let t = self.tokens.get(self.pos);
326 if self.pos < self.tokens.len().saturating_sub(1) {
327 self.pos += 1;
328 }
329 t
330 }
331
332 pub(crate) fn check(&self, kind: &TokenKind) -> bool {
333 std::mem::discriminant(self.peek()) == std::mem::discriminant(kind)
334 }
335
336 pub(crate) fn check_kw(&self, kw: &TokenKind) -> bool {
337 self.peek() == kw
338 }
339
340 pub(crate) fn eat(&mut self, kind: &TokenKind) -> bool {
341 if self.check(kind) {
342 self.advance();
343 true
344 } else {
345 false
346 }
347 }
348
349 pub(crate) fn eat_kw(&mut self, kw: &TokenKind) -> bool {
350 if self.peek() == kw {
351 self.advance();
352 true
353 } else {
354 false
355 }
356 }
357
358 pub(crate) fn expect_kw(&mut self, kw: &TokenKind) -> Result<Span, ParseError> {
359 if self.peek() == kw {
360 let sp = self.current_span();
361 self.advance();
362 Ok(sp)
363 } else {
364 Err(self.err_expected(&format!("{kw:?}")))
365 }
366 }
367
368 pub(crate) fn expect_token(&mut self, kind: &TokenKind) -> Result<Span, ParseError> {
369 if self.check(kind) {
370 let sp = self.current_span();
371 self.advance();
372 Ok(sp)
373 } else {
374 Err(self.err_expected(&format!("{kind:?}")))
375 }
376 }
377
378 pub(crate) fn current_span(&self) -> Span {
379 self.current().map_or(Span::ZERO, |t| t.span)
380 }
381
382 pub(crate) fn err_expected(&self, what: &str) -> ParseError {
383 ParseError::at(format!("expected {what}"), self.current())
384 }
385
386 pub(crate) fn err_msg(&self, msg: impl Into<String>) -> ParseError {
387 ParseError::at(msg, self.current())
388 }
389
390 fn synchronize(&mut self) {
391 loop {
392 match self.peek() {
393 TokenKind::Eof => return,
394 TokenKind::Semicolon => {
395 self.advance();
396 return;
397 }
398 k if k.is_statement_start() => return,
399 _ => {
400 self.advance();
401 }
402 }
403 }
404 }
405
406 fn recover_trigger_body_after_error(&mut self) {
407 let mut case_depth = 0_usize;
408
409 loop {
410 match self.peek() {
411 TokenKind::Eof => return,
412 TokenKind::KwCase => {
413 case_depth = case_depth.saturating_add(1);
414 self.advance();
415 }
416 TokenKind::KwEnd if case_depth > 0 => {
417 case_depth = case_depth.saturating_sub(1);
418 self.advance();
419 }
420 TokenKind::KwEnd => {
425 self.advance();
426 let _ = self.eat(&TokenKind::Semicolon);
427 return;
428 }
429 _ => {
430 self.advance();
431 }
432 }
433 }
434 }
435
436 pub(crate) fn parse_identifier(&mut self) -> Result<String, ParseError> {
441 match self.peek().clone() {
442 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
443 self.advance();
444 Ok(s.to_string())
445 }
446 TokenKind::String(s) => {
447 self.advance();
448 Ok(s)
449 }
450 ref k if is_nonreserved_kw(k) => {
451 let s = kw_to_str(k);
452 self.advance();
453 Ok(s)
454 }
455 _ => Err(self.err_expected("identifier")),
456 }
457 }
458
459 pub(crate) fn parse_qualified_name(&mut self) -> Result<QualifiedName, ParseError> {
460 let first = self.parse_identifier()?;
461 if self.eat(&TokenKind::Dot) {
462 let second = self.parse_identifier()?;
463 Ok(QualifiedName::qualified(first, second))
464 } else {
465 Ok(QualifiedName::bare(first))
466 }
467 }
468
469 fn parse_qualified_table_ref(&mut self) -> Result<QualifiedTableRef, ParseError> {
470 let name = self.parse_qualified_name()?;
471 let alias = self.try_alias()?;
472 let index_hint = self.parse_index_hint()?;
473 let time_travel = self.parse_time_travel_clause()?;
474 Ok(QualifiedTableRef {
475 name,
476 alias,
477 index_hint,
478 time_travel,
479 })
480 }
481
482 fn try_alias(&mut self) -> Result<Option<String>, ParseError> {
483 if self.eat_kw(&TokenKind::KwAs) {
484 return Ok(Some(self.parse_identifier()?));
485 }
486 match self.peek() {
489 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
490 return Ok(Some(self.parse_identifier()?));
491 }
492 k if is_nonreserved_kw(k) && !is_alias_terminator_kw(k) => {
493 return Ok(Some(self.parse_identifier()?));
494 }
495 _ => {}
496 }
497 Ok(None)
498 }
499
500 fn parse_index_hint(&mut self) -> Result<Option<IndexHint>, ParseError> {
501 if self.eat_kw(&TokenKind::KwIndexed) {
502 self.expect_kw(&TokenKind::KwBy)?;
503 Ok(Some(IndexHint::IndexedBy(self.parse_identifier()?)))
504 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwIndexed {
505 self.advance();
506 self.advance();
507 Ok(Some(IndexHint::NotIndexed))
508 } else {
509 Ok(None)
510 }
511 }
512
513 fn parse_time_travel_clause(&mut self) -> Result<Option<TimeTravelClause>, ParseError> {
521 if !self.check_kw(&TokenKind::KwFor) {
522 return Ok(None);
523 }
524 if !matches!(self.peek_nth(1), TokenKind::Id(s) if s.eq_ignore_ascii_case("SYSTEM_TIME")) {
526 return Ok(None);
527 }
528 self.advance(); self.advance(); self.expect_kw(&TokenKind::KwAs)?;
531 self.expect_kw(&TokenKind::KwOf)?;
532
533 let target = if self.eat_kw(&TokenKind::KwCommitseq) {
534 match self.peek().clone() {
535 TokenKind::Integer(n) if n >= 0 => {
536 self.advance();
537 TimeTravelTarget::CommitSequence(n as u64)
538 }
539 TokenKind::OversizedInt(s) => {
540 if let Ok(n) = s.parse::<u64>() {
541 self.advance();
542 TimeTravelTarget::CommitSequence(n)
543 } else {
544 return Err(self.err_expected("non-negative integer after COMMITSEQ"));
545 }
546 }
547 _ => return Err(self.err_expected("non-negative integer after COMMITSEQ")),
548 }
549 } else {
550 match self.peek().clone() {
551 TokenKind::String(s) => {
552 self.advance();
553 TimeTravelTarget::Timestamp(s)
554 }
555 _ => {
556 return Err(self.err_expected(
557 "COMMITSEQ <n> or '<timestamp>' after FOR SYSTEM_TIME AS OF",
558 ));
559 }
560 }
561 };
562
563 Ok(Some(TimeTravelClause { target }))
564 }
565
566 pub(crate) fn parse_comma_sep<T>(
567 &mut self,
568 f: fn(&mut Self) -> Result<T, ParseError>,
569 ) -> Result<Vec<T>, ParseError> {
570 let mut v = Vec::with_capacity(4);
571 v.push(f(self)?);
572 while self.eat(&TokenKind::Comma) {
573 v.push(f(self)?);
574 }
575 Ok(v)
576 }
577
578 fn parse_statement_inner(&mut self) -> Result<Statement, ParseError> {
583 self.with_recursion_guard(|parser| match parser.peek().clone() {
584 TokenKind::KwSelect | TokenKind::KwValues => {
585 Ok(Statement::Select(parser.parse_select_stmt(None)?))
586 }
587 TokenKind::KwWith => parser.parse_with_leading(),
588 TokenKind::KwInsert | TokenKind::KwReplace => parser.parse_insert_stmt(None),
589 TokenKind::KwUpdate => parser.parse_update_stmt(None),
590 TokenKind::KwDelete => parser.parse_delete_stmt(None),
591 TokenKind::KwCreate => parser.parse_create(),
592 TokenKind::KwDrop => parser.parse_drop(),
593 TokenKind::KwAlter => parser.parse_alter(),
594 TokenKind::KwBegin => parser.parse_begin(),
595 TokenKind::KwCommit | TokenKind::KwEnd => {
596 parser.advance();
597 let _ = parser.eat_kw(&TokenKind::KwTransaction);
598 Ok(Statement::Commit)
599 }
600 TokenKind::KwRollback => parser.parse_rollback(),
601 TokenKind::KwSavepoint => {
602 parser.advance();
603 Ok(Statement::Savepoint(parser.parse_identifier()?))
604 }
605 TokenKind::KwRelease => {
606 parser.advance();
607 let _ = parser.eat_kw(&TokenKind::KwSavepoint);
608 Ok(Statement::Release(parser.parse_identifier()?))
609 }
610 TokenKind::KwAttach => parser.parse_attach(),
611 TokenKind::KwDetach => {
612 parser.advance();
613 let _ = parser.eat_kw(&TokenKind::KwDatabase);
614 Ok(Statement::Detach(parser.parse_identifier()?))
615 }
616 TokenKind::KwPragma => parser.parse_pragma(),
617 TokenKind::KwVacuum => parser.parse_vacuum(),
618 TokenKind::KwReindex => {
619 parser.advance();
620 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
621 Some(parser.parse_qualified_name()?)
622 } else {
623 None
624 };
625 Ok(Statement::Reindex(name))
626 }
627 TokenKind::KwAnalyze => {
628 parser.advance();
629 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
630 Some(parser.parse_qualified_name()?)
631 } else {
632 None
633 };
634 Ok(Statement::Analyze(name))
635 }
636 TokenKind::KwExplain => parser.parse_explain(),
637 _ => Err(parser.err_msg("unexpected token at start of statement")),
638 })
639 }
640
641 fn parse_with_leading(&mut self) -> Result<Statement, ParseError> {
646 let with = self.parse_with_clause()?;
647 match self.peek() {
648 TokenKind::KwSelect | TokenKind::KwValues => {
649 Ok(Statement::Select(self.parse_select_stmt(Some(with))?))
650 }
651 TokenKind::KwInsert | TokenKind::KwReplace => self.parse_insert_stmt(Some(with)),
652 TokenKind::KwUpdate => self.parse_update_stmt(Some(with)),
653 TokenKind::KwDelete => self.parse_delete_stmt(Some(with)),
654 _ => Err(self.err_expected("SELECT, INSERT, UPDATE, or DELETE after WITH")),
655 }
656 }
657
658 pub(crate) fn parse_with_clause(&mut self) -> Result<WithClause, ParseError> {
659 self.expect_kw(&TokenKind::KwWith)?;
660 let recursive = self.eat_kw(&TokenKind::KwRecursive);
661 let ctes = self.parse_comma_sep(Self::parse_cte)?;
662 Ok(WithClause { recursive, ctes })
663 }
664
665 fn parse_cte(&mut self) -> Result<Cte, ParseError> {
666 let name = self.parse_identifier()?;
667 let columns = if self.eat(&TokenKind::LeftParen) {
668 let cols = self.parse_comma_sep(Self::parse_identifier)?;
669 self.expect_token(&TokenKind::RightParen)?;
670 cols
671 } else {
672 vec![]
673 };
674 self.expect_kw(&TokenKind::KwAs)?;
676 let materialized = if self.check_kw(&TokenKind::KwNot) {
677 self.advance();
678 self.expect_kw(&TokenKind::KwMaterialized)?;
679 Some(CteMaterialized::NotMaterialized)
680 } else if self.eat_kw(&TokenKind::KwMaterialized) {
681 Some(CteMaterialized::Materialized)
682 } else {
683 None
684 };
685 self.expect_token(&TokenKind::LeftParen)?;
686 let query = self.parse_select_stmt(None)?;
687 self.expect_token(&TokenKind::RightParen)?;
688 Ok(Cte {
689 name,
690 columns,
691 materialized,
692 query,
693 })
694 }
695
696 pub(crate) fn parse_select_stmt(
701 &mut self,
702 with: Option<WithClause>,
703 ) -> Result<SelectStatement, ParseError> {
704 self.with_recursion_guard(|parser| parser.parse_select_stmt_inner(with))
705 }
706
707 fn parse_select_stmt_inner(
708 &mut self,
709 with: Option<WithClause>,
710 ) -> Result<SelectStatement, ParseError> {
711 let body = self.parse_select_body()?;
712 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
713 self.expect_kw(&TokenKind::KwBy)?;
714 self.parse_comma_sep(Self::parse_ordering_term)?
715 } else {
716 vec![]
717 };
718 let limit = self.parse_limit()?;
719 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 self.parse_expr()
2044 }
2045
2046 fn parse_pragma(&mut self) -> Result<Statement, ParseError> {
2047 self.expect_kw(&TokenKind::KwPragma)?;
2048 let name = self.parse_qualified_name()?;
2049 let value = if self.eat(&TokenKind::Eq) || self.eat(&TokenKind::EqEq) {
2050 Some(PragmaValue::Assign(self.parse_pragma_value_expr()?))
2051 } else if self.eat(&TokenKind::LeftParen) {
2052 let v = self.parse_pragma_value_expr()?;
2053 self.expect_token(&TokenKind::RightParen)?;
2054 Some(PragmaValue::Call(v))
2055 } else {
2056 None
2057 };
2058 Ok(Statement::Pragma(PragmaStatement { name, value }))
2059 }
2060
2061 fn parse_vacuum(&mut self) -> Result<Statement, ParseError> {
2062 self.expect_kw(&TokenKind::KwVacuum)?;
2063 let schema = if !self.at_eof()
2064 && !self.check(&TokenKind::Semicolon)
2065 && !self.check_kw(&TokenKind::KwInto)
2066 {
2067 Some(self.parse_identifier()?)
2068 } else {
2069 None
2070 };
2071 let into = if self.eat_kw(&TokenKind::KwInto) {
2072 Some(self.parse_expr()?)
2073 } else {
2074 None
2075 };
2076 Ok(Statement::Vacuum(VacuumStatement { schema, into }))
2077 }
2078
2079 fn parse_explain(&mut self) -> Result<Statement, ParseError> {
2080 self.expect_kw(&TokenKind::KwExplain)?;
2081 let query_plan = if self.eat_kw(&TokenKind::KwQuery) {
2082 self.expect_kw(&TokenKind::KwPlan)?;
2083 true
2084 } else {
2085 false
2086 };
2087 let stmt = self.parse_statement_inner()?;
2088 Ok(Statement::Explain {
2089 query_plan,
2090 stmt: Box::new(stmt),
2091 })
2092 }
2093
2094 fn parse_window_def(&mut self) -> Result<WindowDef, ParseError> {
2099 let name = self.parse_identifier()?;
2100 self.expect_kw(&TokenKind::KwAs)?;
2101 self.expect_token(&TokenKind::LeftParen)?;
2102 let spec = self.parse_window_spec()?;
2103 self.expect_token(&TokenKind::RightParen)?;
2104 Ok(WindowDef { name, spec })
2105 }
2106
2107 pub(crate) fn parse_window_spec(&mut self) -> Result<WindowSpec, ParseError> {
2108 let has_base_window = match self.peek() {
2110 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => true,
2111 k if is_nonreserved_kw(k) => !matches!(
2112 k,
2113 TokenKind::KwPartition
2114 | TokenKind::KwOrder
2115 | TokenKind::KwRange
2116 | TokenKind::KwRows
2117 | TokenKind::KwGroups
2118 ),
2119 _ => false,
2120 };
2121 let base_window = if has_base_window {
2122 Some(self.parse_identifier()?)
2123 } else {
2124 None
2125 };
2126 let partition_by = if self.eat_kw(&TokenKind::KwPartition) {
2127 self.expect_kw(&TokenKind::KwBy)?;
2128 self.parse_comma_sep(Self::parse_expr)?
2129 } else {
2130 vec![]
2131 };
2132 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
2133 self.expect_kw(&TokenKind::KwBy)?;
2134 self.parse_comma_sep(Self::parse_ordering_term)?
2135 } else {
2136 vec![]
2137 };
2138 let frame = self.try_frame_spec()?;
2139 Ok(WindowSpec {
2140 base_window,
2141 partition_by,
2142 order_by,
2143 frame,
2144 })
2145 }
2146
2147 fn try_frame_spec(&mut self) -> Result<Option<FrameSpec>, ParseError> {
2148 let frame_type = if self.eat_kw(&TokenKind::KwRows) {
2149 FrameType::Rows
2150 } else if self.eat_kw(&TokenKind::KwRange) {
2151 FrameType::Range
2152 } else if self.eat_kw(&TokenKind::KwGroups) {
2153 FrameType::Groups
2154 } else {
2155 return Ok(None);
2156 };
2157 let (start, end) = if self.eat_kw(&TokenKind::KwBetween) {
2158 let s = self.parse_frame_bound()?;
2159 self.expect_kw(&TokenKind::KwAnd)?;
2160 let e = self.parse_frame_bound()?;
2161 (s, Some(e))
2162 } else {
2163 (self.parse_frame_bound()?, None)
2164 };
2165 let exclude = if self.eat_kw(&TokenKind::KwExclude) {
2166 if self.check_kw(&TokenKind::KwNo) {
2167 self.advance();
2168 let id = self.parse_identifier()?;
2170 if !id.eq_ignore_ascii_case("OTHERS") {
2171 return Err(self.err_expected("OTHERS"));
2172 }
2173 Some(FrameExclude::NoOthers)
2174 } else if self.eat_kw(&TokenKind::KwTies) {
2175 Some(FrameExclude::Ties)
2176 } else if self.eat_kw(&TokenKind::KwGroup) {
2177 Some(FrameExclude::Group)
2178 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2179 self.advance();
2180 self.expect_kw(&TokenKind::KwRow)?;
2181 Some(FrameExclude::CurrentRow)
2182 } else {
2183 return Err(
2184 self.err_expected("NO OTHERS, TIES, GROUP, or CURRENT ROW after EXCLUDE")
2185 );
2186 }
2187 } else {
2188 None
2189 };
2190 Ok(Some(FrameSpec {
2191 frame_type,
2192 start,
2193 end,
2194 exclude,
2195 }))
2196 }
2197
2198 fn parse_frame_bound(&mut self) -> Result<FrameBound, ParseError> {
2199 if self.eat_kw(&TokenKind::KwUnbounded) {
2200 if self.eat_kw(&TokenKind::KwPreceding) {
2201 Ok(FrameBound::UnboundedPreceding)
2202 } else {
2203 self.expect_kw(&TokenKind::KwFollowing)?;
2204 Ok(FrameBound::UnboundedFollowing)
2205 }
2206 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2207 self.advance();
2208 self.expect_kw(&TokenKind::KwRow)?;
2209 Ok(FrameBound::CurrentRow)
2210 } else {
2211 let expr = self.parse_expr()?;
2212 if self.eat_kw(&TokenKind::KwPreceding) {
2213 Ok(FrameBound::Preceding(Box::new(expr)))
2214 } else {
2215 self.expect_kw(&TokenKind::KwFollowing)?;
2216 Ok(FrameBound::Following(Box::new(expr)))
2217 }
2218 }
2219 }
2220}
2221
2222fn parse_statements_with_scratch_inner(
2223 sql: &str,
2224 scratch: &mut StatementParseScratch,
2225) -> (Vec<Statement>, Option<ParseError>) {
2226 Lexer::tokenize_into_with_interner(sql, &mut scratch.tokens, &mut scratch.identifier_interner);
2227 let mut parser = Parser {
2228 tokens: std::mem::take(&mut scratch.tokens),
2229 pos: 0,
2230 errors: std::mem::take(&mut scratch.errors),
2231 depth: 0,
2232 };
2233 let (statements, errors) = parser.parse_all();
2234 scratch.tokens = parser.tokens;
2235 scratch.tokens.clear();
2236 scratch.identifier_interner.prepare_for_next_parse();
2237 scratch.errors = errors;
2238 let first_error = scratch.errors.first().cloned();
2239 scratch.errors.clear();
2240 (statements, first_error)
2241}
2242
2243pub fn parse_statements_with_scratch(
2245 sql: &str,
2246 scratch: &mut StatementParseScratch,
2247) -> Result<Vec<Statement>, ParseError> {
2248 let (statements, first_error) = parse_statements_with_scratch_inner(sql, scratch);
2249 if let Some(error) = first_error {
2250 return Err(error);
2251 }
2252 if statements.is_empty() {
2253 return Err(ParseError::at("no SQL statement provided", None));
2254 }
2255 Ok(statements)
2256}
2257
2258pub fn parse_single_statement_with_scratch(
2260 sql: &str,
2261 scratch: &mut StatementParseScratch,
2262) -> Result<Statement, ParseError> {
2263 let statements = parse_statements_with_scratch(sql, scratch)?;
2264 let mut iter = statements.into_iter();
2265 let statement = iter
2266 .next()
2267 .ok_or_else(|| ParseError::at("no SQL statement provided", None))?;
2268 if iter.next().is_some() {
2269 return Err(ParseError::at(
2270 "multiple statements are not supported in this API path",
2271 None,
2272 ));
2273 }
2274 Ok(statement)
2275}
2276
2277pub fn parse_first_statement_with_tail(
2285 sql: &str,
2286) -> Result<Option<(Statement, usize)>, ParseError> {
2287 let mut parser = Parser::from_sql(sql);
2288
2289 while parser.eat(&TokenKind::Semicolon) {}
2290 if parser.at_eof() {
2291 return Ok(None);
2292 }
2293
2294 let statement = parser.parse_statement()?;
2295 let tail_offset = if parser.eat(&TokenKind::Semicolon) {
2296 parser
2297 .tokens
2298 .get(parser.pos.saturating_sub(1))
2299 .map_or(sql.len(), |token| token.span.end as usize)
2300 } else if parser.at_eof() {
2301 sql.len()
2302 } else {
2303 return Err(ParseError::at(
2304 "unexpected token after end of statement; expected ';' separator",
2305 parser.current(),
2306 ));
2307 };
2308
2309 Ok(Some((statement, tail_offset)))
2310}
2311
2312pub(crate) fn is_nonreserved_kw(k: &TokenKind) -> bool {
2317 matches!(
2318 k,
2319 TokenKind::KwAbort
2320 | TokenKind::KwAction
2321 | TokenKind::KwAfter
2322 | TokenKind::KwAlways
2323 | TokenKind::KwAnalyze
2324 | TokenKind::KwAsc
2325 | TokenKind::KwBefore
2326 | TokenKind::KwCascade
2327 | TokenKind::KwColumn
2328 | TokenKind::KwConcurrent
2329 | TokenKind::KwConflict
2330 | TokenKind::KwDatabase
2331 | TokenKind::KwDeferred
2332 | TokenKind::KwDesc
2333 | TokenKind::KwDo
2334 | TokenKind::KwEach
2335 | TokenKind::KwEnd
2336 | TokenKind::KwExclude
2337 | TokenKind::KwExclusive
2338 | TokenKind::KwFail
2339 | TokenKind::KwFilter
2340 | TokenKind::KwFirst
2341 | TokenKind::KwFollowing
2342 | TokenKind::KwFull
2343 | TokenKind::KwGenerated
2344 | TokenKind::KwGroups
2345 | TokenKind::KwIf
2346 | TokenKind::KwIgnore
2347 | TokenKind::KwImmediate
2348 | TokenKind::KwIndex
2349 | TokenKind::KwInitially
2350 | TokenKind::KwInstead
2351 | TokenKind::KwKey
2352 | TokenKind::KwLast
2353 | TokenKind::KwMatch
2354 | TokenKind::KwMaterialized
2355 | TokenKind::KwNo
2356 | TokenKind::KwNothing
2357 | TokenKind::KwNulls
2358 | TokenKind::KwOf
2359 | TokenKind::KwOffset
2360 | TokenKind::KwOthers
2361 | TokenKind::KwOver
2362 | TokenKind::KwPartition
2363 | TokenKind::KwPlan
2364 | TokenKind::KwPragma
2365 | TokenKind::KwPreceding
2366 | TokenKind::KwQuery
2367 | TokenKind::KwRange
2368 | TokenKind::KwRecursive
2369 | TokenKind::KwReindex
2370 | TokenKind::KwRelease
2371 | TokenKind::KwRename
2372 | TokenKind::KwReplace
2373 | TokenKind::KwRestrict
2374 | TokenKind::KwReturning
2375 | TokenKind::KwRow
2376 | TokenKind::KwRows
2377 | TokenKind::KwSavepoint
2378 | TokenKind::KwStored
2379 | TokenKind::KwStrict
2380 | TokenKind::KwTable
2381 | TokenKind::KwTemp
2382 | TokenKind::KwTemporary
2383 | TokenKind::KwTies
2384 | TokenKind::KwTransaction
2385 | TokenKind::KwTrigger
2386 | TokenKind::KwUnbounded
2387 | TokenKind::KwVacuum
2388 | TokenKind::KwView
2389 | TokenKind::KwVirtual
2390 | TokenKind::KwWindow
2391 | TokenKind::KwWithout
2392 )
2393}
2394
2395fn is_alias_terminator_kw(k: &TokenKind) -> bool {
2398 matches!(
2399 k,
2400 TokenKind::KwCross
2401 | TokenKind::KwExcept
2402 | TokenKind::KwFull
2403 | TokenKind::KwGroup
2404 | TokenKind::KwHaving
2405 | TokenKind::KwInner
2406 | TokenKind::KwIntersect
2407 | TokenKind::KwJoin
2408 | TokenKind::KwLeft
2409 | TokenKind::KwLimit
2410 | TokenKind::KwNatural
2411 | TokenKind::KwOffset
2412 | TokenKind::KwOn
2413 | TokenKind::KwOrder
2414 | TokenKind::KwOuter
2415 | TokenKind::KwReturning
2416 | TokenKind::KwRight
2417 | TokenKind::KwUnion
2418 | TokenKind::KwUsing
2419 | TokenKind::KwWhere
2420 | TokenKind::KwWindow
2421 )
2422}
2423
2424pub(crate) fn kw_to_str(k: &TokenKind) -> String {
2425 k.keyword_str()
2426 .map(|s| s.to_ascii_lowercase())
2427 .unwrap_or_else(|| {
2428 let dbg = format!("{k:?}");
2429 dbg.strip_prefix("Kw").unwrap_or(&dbg).to_ascii_lowercase()
2430 })
2431}
2432
2433#[cfg(test)]
2438mod tests {
2439 use super::*;
2440
2441 static PARSE_OBSERVABILITY_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
2442
2443 fn parse_ok(sql: &str) -> Vec<Statement> {
2444 let mut p = Parser::from_sql(sql);
2445 let (stmts, errs) = p.parse_all();
2446 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2447 stmts
2448 }
2449
2450 fn parse_one(sql: &str) -> Statement {
2451 let stmts = parse_ok(sql);
2452 assert_eq!(stmts.len(), 1, "expected 1 statement, got {}", stmts.len());
2453 stmts.into_iter().next().unwrap()
2454 }
2455
2456 #[test]
2457 fn test_parse_metrics_emitted_when_enabled() {
2458 let _guard = PARSE_OBSERVABILITY_LOCK
2459 .lock()
2460 .unwrap_or_else(|poisoned| poisoned.into_inner());
2461 let prev_metrics_enabled = parse_metrics_enabled();
2462 reset_parse_metrics();
2463 set_parse_metrics_enabled(true);
2464
2465 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
2466 let (stmts, errs) = parser.parse_all();
2467 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2468 assert_eq!(stmts.len(), 2);
2469
2470 let snapshot = parse_metrics_snapshot();
2471 assert!(snapshot.fsqlite_parse_statements_total >= 2);
2472
2473 set_parse_metrics_enabled(prev_metrics_enabled);
2474 reset_parse_metrics();
2475 }
2476
2477 #[test]
2478 fn test_parse_metrics_can_be_disabled_off_hot_path() {
2479 let _guard = PARSE_OBSERVABILITY_LOCK
2480 .lock()
2481 .unwrap_or_else(|poisoned| poisoned.into_inner());
2482 let prev_metrics_enabled = parse_metrics_enabled();
2483 reset_parse_metrics();
2484 set_parse_metrics_enabled(false);
2485
2486 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
2487 let (stmts, errs) = parser.parse_all();
2488 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2489 assert_eq!(stmts.len(), 2);
2490
2491 let snapshot = parse_metrics_snapshot();
2492 assert_eq!(snapshot.fsqlite_parse_statements_total, 0);
2493
2494 set_parse_metrics_enabled(prev_metrics_enabled);
2495 reset_parse_metrics();
2496 }
2497
2498 #[test]
2499 fn test_parse_depth_overflow_does_not_poison_following_statement() {
2500 let mut parser = Parser::from_sql("SELECT 1; SELECT 42;");
2501 parser.depth = MAX_PARSE_DEPTH - 1;
2502
2503 let first = parser.parse_statement();
2506 assert!(first.is_err(), "first statement should hit depth guard");
2507 assert_eq!(
2508 parser.depth,
2509 MAX_PARSE_DEPTH - 1,
2510 "depth must not leak upward on recursion-limit error"
2511 );
2512
2513 let _ = parser.eat(&TokenKind::Semicolon);
2517 let second = parser.parse_statement();
2518 assert!(
2519 second.is_err(),
2520 "second statement should still be parseable"
2521 );
2522 assert_eq!(
2523 parser.depth,
2524 MAX_PARSE_DEPTH - 1,
2525 "depth must remain stable across repeated recursion-limit errors"
2526 );
2527 }
2528
2529 #[test]
2530 fn test_parse_first_statement_with_tail_consumes_full_trigger_body() {
2531 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN INSERT INTO audit VALUES('first'); INSERT INTO audit VALUES('second'); END; SELECT 1;";
2532 let Some((statement, tail_offset)) =
2533 parse_first_statement_with_tail(sql).expect("trigger statement should parse")
2534 else {
2535 panic!("expected a trigger statement");
2536 };
2537
2538 assert!(matches!(statement, Statement::CreateTrigger(_)));
2539 assert_eq!(&sql[tail_offset..], " SELECT 1;");
2540 }
2541
2542 #[test]
2543 fn test_parse_first_statement_with_tail_rejects_adjacent_statements_without_separator() {
2544 let error = parse_first_statement_with_tail("SELECT 1 SELECT 2")
2545 .expect_err("adjacent statements without a semicolon must be rejected");
2546
2547 assert!(
2548 error.message.contains("expected ';' separator"),
2549 "unexpected error: {error:?}"
2550 );
2551 }
2552
2553 #[test]
2554 fn test_create_table_without_rowid_and_strict_round_trips_display() {
2555 let sql = "CREATE TABLE s (id INTEGER PRIMARY KEY) WITHOUT ROWID, STRICT";
2556 let Some((statement, _)) =
2557 parse_first_statement_with_tail(sql).expect("statement should parse")
2558 else {
2559 panic!("expected CREATE TABLE statement");
2560 };
2561
2562 assert_eq!(statement.to_string(), sql);
2563 }
2564
2565 #[test]
2566 fn test_error_recovery_does_not_fabricate_top_level_statements_from_trigger_body() {
2567 let mut parser = Parser::from_sql(
2568 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN XYZZY; SELECT 1; END; SELECT 2;",
2569 );
2570 let (stmts, errs) = parser.parse_all();
2571
2572 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
2573 assert_eq!(
2574 stmts.len(),
2575 1,
2576 "only the trailing top-level SELECT should remain"
2577 );
2578 assert!(
2579 matches!(
2580 &stmts[0],
2581 Statement::Select(select)
2582 if matches!(
2583 &select.body.select,
2584 SelectCore::Select { columns, .. }
2585 if matches!(
2586 columns.as_slice(),
2587 [ResultColumn::Expr {
2588 expr: Expr::Literal(Literal::Integer(2), _),
2589 alias: None,
2590 }]
2591 )
2592 )
2593 ),
2594 "parser must skip the malformed trigger instead of reinterpreting body tokens as top-level SQL: {stmts:?}"
2595 );
2596 }
2597
2598 #[test]
2599 fn test_error_recovery_recovers_values_statement_after_garbage() {
2600 let mut parser = Parser::from_sql("XYZZY VALUES (1);");
2601 let (stmts, errs) = parser.parse_all();
2602
2603 assert_eq!(errs.len(), 1, "expected one error for leading garbage");
2604 assert_eq!(stmts.len(), 1, "VALUES statement should still be recovered");
2605 assert!(matches!(stmts[0], Statement::Select(_)));
2606 }
2607
2608 #[test]
2609 fn test_error_recovery_does_not_swallow_top_level_sql_after_unbalanced_trigger_paren() {
2610 let mut parser = Parser::from_sql(
2611 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN SELECT (1; END; SELECT 2;",
2612 );
2613 let (stmts, errs) = parser.parse_all();
2614
2615 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
2616 assert_eq!(
2617 stmts.len(),
2618 1,
2619 "malformed trigger recovery must still preserve the trailing top-level SELECT"
2620 );
2621 assert!(
2622 matches!(
2623 &stmts[0],
2624 Statement::Select(select)
2625 if matches!(
2626 &select.body.select,
2627 SelectCore::Select { columns, .. }
2628 if matches!(
2629 columns.as_slice(),
2630 [ResultColumn::Expr {
2631 expr: Expr::Literal(Literal::Integer(2), _),
2632 alias: None,
2633 }]
2634 )
2635 )
2636 ),
2637 "parser must stop at the trigger END even when parentheses are left unbalanced: {stmts:?}"
2638 );
2639 }
2640
2641 #[test]
2642 fn select_literal() {
2643 let stmt = parse_one("SELECT 1");
2644 assert!(matches!(stmt, Statement::Select(_)));
2645 }
2646
2647 #[test]
2648 fn select_star_from() {
2649 let stmt = parse_one("SELECT * FROM t");
2650 if let Statement::Select(s) = stmt {
2651 if let SelectCore::Select { columns, from, .. } = &s.body.select {
2652 assert!(matches!(columns[0], ResultColumn::Star));
2653 assert!(from.is_some());
2654 } else {
2655 unreachable!("expected Select core");
2656 }
2657 } else {
2658 unreachable!("expected Select");
2659 }
2660 }
2661
2662 #[test]
2663 fn select_where_order_limit() {
2664 let stmt = parse_one("SELECT a FROM t WHERE a > 1 ORDER BY a LIMIT 10 OFFSET 5");
2665 if let Statement::Select(s) = stmt {
2666 assert!(s.limit.is_some());
2667 assert_eq!(s.order_by.len(), 1);
2668 } else {
2669 unreachable!("expected Select");
2670 }
2671 }
2672
2673 #[test]
2674 fn select_limit_comma_syntax_uses_offset_then_count() {
2675 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
2676 if let Statement::Select(s) = stmt {
2677 let limit = s.limit.expect("LIMIT clause");
2678 assert!(matches!(
2679 limit.limit,
2680 Expr::Literal(Literal::Integer(10), _)
2681 ));
2682 assert!(matches!(
2683 limit.offset,
2684 Some(Expr::Literal(Literal::Integer(5), _))
2685 ));
2686 } else {
2687 unreachable!("expected Select");
2688 }
2689 }
2690
2691 #[test]
2692 fn select_order_by_nulls_first_last() {
2693 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST, b DESC NULLS LAST");
2694 if let Statement::Select(s) = stmt {
2695 assert_eq!(s.order_by.len(), 2);
2696 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
2697 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
2698 assert_eq!(s.order_by[1].direction, Some(SortDirection::Desc));
2699 assert_eq!(s.order_by[1].nulls, Some(NullsOrder::Last));
2700 } else {
2701 unreachable!("expected Select");
2702 }
2703 }
2704
2705 #[test]
2706 fn select_from_indexed_by_hint() {
2707 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
2708 if let Statement::Select(s) = stmt {
2709 if let SelectCore::Select { from, .. } = &s.body.select {
2710 let from = from.as_ref().expect("FROM clause");
2711 match &from.source {
2712 TableOrSubquery::Table {
2713 index_hint: Some(IndexHint::IndexedBy(name)),
2714 ..
2715 } => assert_eq!(name, "idx_t"),
2716 other => unreachable!("expected indexed table source, got {other:?}"),
2717 }
2718 } else {
2719 unreachable!("expected Select core");
2720 }
2721 } else {
2722 unreachable!("expected Select");
2723 }
2724 }
2725
2726 #[test]
2727 fn select_from_not_indexed_hint() {
2728 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
2729 if let Statement::Select(s) = stmt {
2730 if let SelectCore::Select { from, .. } = &s.body.select {
2731 let from = from.as_ref().expect("FROM clause");
2732 match &from.source {
2733 TableOrSubquery::Table {
2734 index_hint: Some(IndexHint::NotIndexed),
2735 ..
2736 } => {}
2737 other => unreachable!("expected not-indexed table source, got {other:?}"),
2738 }
2739 } else {
2740 unreachable!("expected Select core");
2741 }
2742 } else {
2743 unreachable!("expected Select");
2744 }
2745 }
2746
2747 #[test]
2748 fn select_from_table_valued_function() {
2749 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
2750 if let Statement::Select(s) = stmt {
2751 if let SelectCore::Select { from, .. } = &s.body.select {
2752 let from = from.as_ref().expect("FROM clause");
2753 match &from.source {
2754 TableOrSubquery::TableFunction { name, args, alias } => {
2755 assert_eq!(name, "generate_series");
2756 assert_eq!(args.len(), 2);
2757 assert_eq!(alias.as_deref(), Some("gs"));
2758 }
2759 other => unreachable!("expected table-valued function source, got {other:?}"),
2760 }
2761 } else {
2762 unreachable!("expected Select core");
2763 }
2764 } else {
2765 unreachable!("expected Select");
2766 }
2767 }
2768
2769 #[test]
2770 fn select_window_function_over_clause() {
2771 let stmt = parse_one(
2772 "SELECT sum(x) OVER (PARTITION BY y ORDER BY z \
2773 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
2774 );
2775 if let Statement::Select(s) = stmt {
2776 if let SelectCore::Select { columns, .. } = &s.body.select {
2777 match &columns[0] {
2778 ResultColumn::Expr {
2779 expr:
2780 Expr::FunctionCall {
2781 over: Some(over), ..
2782 },
2783 ..
2784 } => {
2785 assert_eq!(over.partition_by.len(), 1);
2786 assert_eq!(over.order_by.len(), 1);
2787 assert!(matches!(
2788 over.frame,
2789 Some(FrameSpec {
2790 frame_type: FrameType::Rows,
2791 ..
2792 })
2793 ));
2794 }
2795 other => unreachable!("expected window function result column, got {other:?}"),
2796 }
2797 } else {
2798 unreachable!("expected Select core");
2799 }
2800 } else {
2801 unreachable!("expected Select");
2802 }
2803 }
2804
2805 #[test]
2806 fn select_named_window_definition_and_reference() {
2807 let stmt = parse_one(
2808 "SELECT sum(x) OVER win FROM t \
2809 WINDOW win AS (PARTITION BY y ORDER BY z)",
2810 );
2811 if let Statement::Select(s) = stmt {
2812 if let SelectCore::Select {
2813 columns, windows, ..
2814 } = &s.body.select
2815 {
2816 assert_eq!(windows.len(), 1);
2817 assert_eq!(windows[0].name, "win");
2818 assert_eq!(windows[0].spec.partition_by.len(), 1);
2819 assert_eq!(windows[0].spec.order_by.len(), 1);
2820 match &columns[0] {
2821 ResultColumn::Expr {
2822 expr:
2823 Expr::FunctionCall {
2824 over: Some(over), ..
2825 },
2826 ..
2827 } => assert_eq!(over.base_window.as_deref(), Some("win")),
2828 other => unreachable!("expected named window function, got {other:?}"),
2829 }
2830 } else {
2831 unreachable!("expected Select core");
2832 }
2833 } else {
2834 unreachable!("expected Select");
2835 }
2836 }
2837
2838 #[test]
2839 fn insert_values() {
2840 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2), (3, 4)");
2841 assert!(matches!(stmt, Statement::Insert(_)));
2842 }
2843
2844 #[test]
2845 fn update_set() {
2846 let stmt = parse_one("UPDATE t SET a = 1, b = 2 WHERE id = 3");
2847 assert!(matches!(stmt, Statement::Update(_)));
2848 }
2849
2850 #[test]
2851 fn delete_from() {
2852 let stmt = parse_one("DELETE FROM t WHERE id = 1");
2853 assert!(matches!(stmt, Statement::Delete(_)));
2854 }
2855
2856 #[test]
2857 fn create_table_basic() {
2858 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT NOT NULL)");
2859 if let Statement::CreateTable(ct) = stmt {
2860 assert_eq!(ct.name.name, "t");
2861 if let CreateTableBody::Columns { columns, .. } = ct.body {
2862 assert_eq!(columns.len(), 2);
2863 } else {
2864 unreachable!("expected column defs");
2865 }
2866 } else {
2867 unreachable!("expected CreateTable");
2868 }
2869 }
2870
2871 #[test]
2872 fn create_index() {
2873 let stmt = parse_one("CREATE UNIQUE INDEX idx ON t (a, b DESC)");
2874 if let Statement::CreateIndex(ci) = stmt {
2875 assert!(ci.unique);
2876 assert_eq!(ci.columns.len(), 2);
2877 } else {
2878 unreachable!("expected CreateIndex");
2879 }
2880 }
2881
2882 #[test]
2883 fn drop_table_if_exists() {
2884 let stmt = parse_one("DROP TABLE IF EXISTS t");
2885 if let Statement::Drop(d) = stmt {
2886 assert!(d.if_exists);
2887 assert_eq!(d.object_type, DropObjectType::Table);
2888 } else {
2889 unreachable!("expected Drop");
2890 }
2891 }
2892
2893 #[test]
2894 fn begin_commit() {
2895 let stmts = parse_ok("BEGIN IMMEDIATE; COMMIT");
2896 assert_eq!(stmts.len(), 2);
2897 if let Statement::Begin(b) = &stmts[0] {
2898 assert_eq!(b.mode, Some(TransactionMode::Immediate));
2899 } else {
2900 unreachable!("expected Begin");
2901 }
2902 assert!(matches!(stmts[1], Statement::Commit));
2903 }
2904
2905 #[test]
2906 fn begin_concurrent() {
2907 let stmt = parse_one("BEGIN CONCURRENT");
2908 if let Statement::Begin(b) = stmt {
2909 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
2910 } else {
2911 unreachable!("expected Begin");
2912 }
2913 }
2914
2915 #[test]
2916 fn rollback_to_savepoint() {
2917 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
2918 if let Statement::Rollback(r) = stmt {
2919 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
2920 } else {
2921 unreachable!("expected Rollback");
2922 }
2923 }
2924
2925 #[test]
2926 fn explain_query_plan() {
2927 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT 1");
2928 assert!(matches!(
2929 stmt,
2930 Statement::Explain {
2931 query_plan: true,
2932 ..
2933 }
2934 ));
2935 }
2936
2937 #[test]
2938 fn pragma() {
2939 let stmt = parse_one("PRAGMA journal_mode = WAL");
2940 assert!(matches!(stmt, Statement::Pragma(_)));
2941 }
2942
2943 #[test]
2944 fn pragma_allows_on_value() {
2945 let stmt = parse_one("PRAGMA fsqlite.serializable = ON");
2946 assert!(matches!(stmt, Statement::Pragma(_)));
2947 }
2948
2949 #[test]
2950 fn error_recovery_multiple_statements() {
2951 let mut p = Parser::from_sql("SELECT 1; XYZZY; SELECT 2");
2952 let (stmts, errs) = p.parse_all();
2953 assert_eq!(stmts.len(), 2, "should recover: stmts={stmts:?}");
2954 assert!(!errs.is_empty());
2955 }
2956
2957 #[test]
2958 fn compound_union() {
2959 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
2960 if let Statement::Select(s) = stmt {
2961 assert_eq!(s.body.compounds.len(), 1);
2962 } else {
2963 unreachable!("expected Select");
2964 }
2965 }
2966
2967 #[test]
2968 fn alter_table_rename() {
2969 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
2970 assert!(matches!(
2971 stmt,
2972 Statement::AlterTable(AlterTableStatement {
2973 action: AlterTableAction::RenameTo(_),
2974 ..
2975 })
2976 ));
2977 }
2978
2979 #[test]
2984 fn test_parser_join_inner() {
2985 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
2986 if let Statement::Select(s) = stmt {
2987 if let SelectCore::Select { from, .. } = &s.body.select {
2988 let from = from.as_ref().expect("FROM clause");
2989 assert!(!from.joins.is_empty());
2990 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
2991 } else {
2992 unreachable!("expected Select core");
2993 }
2994 } else {
2995 unreachable!("expected Select");
2996 }
2997 }
2998
2999 #[test]
3000 fn test_parser_join_left() {
3001 let stmt = parse_one("SELECT * FROM a LEFT JOIN b ON a.id = b.a_id");
3002 if let Statement::Select(s) = stmt {
3003 if let SelectCore::Select { from, .. } = &s.body.select {
3004 let from = from.as_ref().expect("FROM clause");
3005 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
3006 } else {
3007 unreachable!("expected Select core");
3008 }
3009 } else {
3010 unreachable!("expected Select");
3011 }
3012 }
3013
3014 #[test]
3015 fn test_parser_join_left_outer() {
3016 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
3017 if let Statement::Select(s) = stmt {
3018 if let SelectCore::Select { from, .. } = &s.body.select {
3019 let from = from.as_ref().expect("FROM clause");
3020 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
3021 } else {
3022 unreachable!("expected Select core");
3023 }
3024 } else {
3025 unreachable!("expected Select");
3026 }
3027 }
3028
3029 #[test]
3030 fn test_parser_join_right() {
3031 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
3032 if let Statement::Select(s) = stmt {
3033 if let SelectCore::Select { from, .. } = &s.body.select {
3034 let from = from.as_ref().expect("FROM clause");
3035 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
3036 } else {
3037 unreachable!("expected Select core");
3038 }
3039 } else {
3040 unreachable!("expected Select");
3041 }
3042 }
3043
3044 #[test]
3045 fn test_parser_join_full() {
3046 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
3047 if let Statement::Select(s) = stmt {
3048 if let SelectCore::Select { from, .. } = &s.body.select {
3049 let from = from.as_ref().expect("FROM clause");
3050 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3051 } else {
3052 unreachable!("expected Select core");
3053 }
3054 } else {
3055 unreachable!("expected Select");
3056 }
3057 }
3058
3059 #[test]
3060 fn test_parser_join_full_outer_with_semicolon() {
3061 let stmt = parse_one("SELECT l.name, r.tag FROM l FULL OUTER JOIN r ON l.id = r.l_id;");
3062 if let Statement::Select(s) = stmt {
3063 if let SelectCore::Select { from, .. } = &s.body.select {
3064 let from = from.as_ref().expect("FROM clause");
3065 assert_eq!(from.joins.len(), 1);
3066 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3067 } else {
3068 unreachable!("expected Select core");
3069 }
3070 } else {
3071 unreachable!("expected Select");
3072 }
3073 }
3074
3075 #[test]
3076 fn test_parser_join_cross() {
3077 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
3078 if let Statement::Select(s) = stmt {
3079 if let SelectCore::Select { from, .. } = &s.body.select {
3080 let from = from.as_ref().expect("FROM clause");
3081 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3082 } else {
3083 unreachable!("expected Select core");
3084 }
3085 } else {
3086 unreachable!("expected Select");
3087 }
3088 }
3089
3090 #[test]
3091 fn test_parser_join_natural() {
3092 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
3093 if let Statement::Select(s) = stmt {
3094 if let SelectCore::Select { from, .. } = &s.body.select {
3095 let from = from.as_ref().expect("FROM clause");
3096 assert!(from.joins[0].join_type.natural);
3097 } else {
3098 unreachable!("expected Select core");
3099 }
3100 } else {
3101 unreachable!("expected Select");
3102 }
3103 }
3104
3105 #[test]
3106 fn test_parser_join_using() {
3107 let stmt = parse_one("SELECT * FROM a JOIN b USING (id)");
3108 if let Statement::Select(s) = stmt {
3109 if let SelectCore::Select { from, .. } = &s.body.select {
3110 let from = from.as_ref().expect("FROM clause");
3111 assert!(matches!(
3112 from.joins[0].constraint,
3113 Some(JoinConstraint::Using(_))
3114 ));
3115 } else {
3116 unreachable!("expected Select core");
3117 }
3118 } else {
3119 unreachable!("expected Select");
3120 }
3121 }
3122
3123 #[test]
3124 fn test_parser_join_comma() {
3125 let stmt = parse_one("SELECT * FROM a, b WHERE a.id = b.a_id");
3127 if let Statement::Select(s) = stmt {
3128 if let SelectCore::Select { from, .. } = &s.body.select {
3129 let from = from.as_ref().expect("FROM clause");
3130 assert!(!from.joins.is_empty());
3131 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3132 } else {
3133 unreachable!("expected Select core");
3134 }
3135 } else {
3136 unreachable!("expected Select");
3137 }
3138 }
3139
3140 #[test]
3145 fn test_parser_cte_basic() {
3146 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
3147 if let Statement::Select(s) = stmt {
3148 let with = s.with.as_ref().expect("WITH clause");
3149 assert!(!with.recursive);
3150 assert_eq!(with.ctes.len(), 1);
3151 assert_eq!(with.ctes[0].name, "cte");
3152 } else {
3153 unreachable!("expected Select");
3154 }
3155 }
3156
3157 #[test]
3158 fn test_parser_cte_multiple() {
3159 let stmt = parse_one("WITH a AS (SELECT 1), b AS (SELECT 2) SELECT * FROM a, b");
3160 if let Statement::Select(s) = stmt {
3161 let with = s.with.as_ref().expect("WITH clause");
3162 assert_eq!(with.ctes.len(), 2);
3163 assert_eq!(with.ctes[0].name, "a");
3164 assert_eq!(with.ctes[1].name, "b");
3165 } else {
3166 unreachable!("expected Select");
3167 }
3168 }
3169
3170 #[test]
3171 fn test_parser_cte_recursive() {
3172 let stmt = parse_one(
3173 "WITH RECURSIVE cnt(x) AS (\
3174 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
3175 ) SELECT x FROM cnt",
3176 );
3177 if let Statement::Select(s) = stmt {
3178 let with = s.with.as_ref().expect("WITH clause");
3179 assert!(with.recursive);
3180 assert_eq!(with.ctes[0].name, "cnt");
3181 assert_eq!(with.ctes[0].columns, vec!["x".to_owned()]);
3182 } else {
3183 unreachable!("expected Select");
3184 }
3185 }
3186
3187 #[test]
3188 fn test_parser_cte_materialized() {
3189 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
3190 if let Statement::Select(s) = stmt {
3191 let with = s.with.as_ref().expect("WITH clause");
3192 assert_eq!(
3193 with.ctes[0].materialized,
3194 Some(CteMaterialized::Materialized)
3195 );
3196 } else {
3197 unreachable!("expected Select");
3198 }
3199 }
3200
3201 #[test]
3206 fn test_select_table_star() {
3207 let stmt = parse_one("SELECT t1.* FROM t1, t2");
3208 if let Statement::Select(s) = stmt {
3209 if let SelectCore::Select { columns, .. } = &s.body.select {
3210 assert!(
3211 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::bare("t1")),
3212 "expected TableStar(t1), got {:?}",
3213 columns[0]
3214 );
3215 } else {
3216 unreachable!("expected Select core");
3217 }
3218 } else {
3219 unreachable!("expected Select");
3220 }
3221 }
3222
3223 #[test]
3224 fn test_select_schema_table_star() {
3225 let stmt = parse_one("SELECT aux.t1.* FROM aux.t1");
3226 if let Statement::Select(s) = stmt {
3227 if let SelectCore::Select { columns, .. } = &s.body.select {
3228 assert!(
3229 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::qualified("aux", "t1")),
3230 "expected TableStar(aux.t1), got {:?}",
3231 columns[0]
3232 );
3233 } else {
3234 unreachable!("expected Select core");
3235 }
3236 } else {
3237 unreachable!("expected Select");
3238 }
3239 }
3240
3241 #[test]
3242 fn test_select_expr_alias() {
3243 let stmt = parse_one("SELECT x + 1 AS result FROM t");
3244 if let Statement::Select(s) = stmt {
3245 if let SelectCore::Select { columns, .. } = &s.body.select {
3246 match &columns[0] {
3247 ResultColumn::Expr {
3248 alias: Some(alias), ..
3249 } => assert_eq!(alias, "result"),
3250 other => unreachable!("expected aliased expr column, got {other:?}"),
3251 }
3252 } else {
3253 unreachable!("expected Select core");
3254 }
3255 } else {
3256 unreachable!("expected Select");
3257 }
3258 }
3259
3260 #[test]
3261 fn test_select_distinct_keyword() {
3262 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
3263 if let Statement::Select(s) = stmt {
3264 if let SelectCore::Select {
3265 distinct, columns, ..
3266 } = &s.body.select
3267 {
3268 assert_eq!(*distinct, Distinctness::Distinct);
3269 assert_eq!(columns.len(), 2);
3270 } else {
3271 unreachable!("expected Select core");
3272 }
3273 } else {
3274 unreachable!("expected Select");
3275 }
3276 }
3277
3278 #[test]
3279 fn test_select_values_clause() {
3280 let stmt = parse_one("VALUES (1, 2), (3, 4)");
3281 if let Statement::Select(s) = stmt {
3282 if let SelectCore::Values(rows) = &s.body.select {
3283 assert_eq!(rows.len(), 2);
3284 assert_eq!(rows[0].len(), 2);
3285 assert_eq!(rows[1].len(), 2);
3286 } else {
3287 unreachable!("expected Values core");
3288 }
3289 } else {
3290 unreachable!("expected Select");
3291 }
3292 }
3293
3294 #[test]
3295 fn test_select_group_by_having() {
3296 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
3297 if let Statement::Select(s) = stmt {
3298 if let SelectCore::Select {
3299 group_by, having, ..
3300 } = &s.body.select
3301 {
3302 assert_eq!(group_by.len(), 1);
3303 assert!(having.is_some(), "HAVING clause must be present");
3304 } else {
3305 unreachable!("expected Select core");
3306 }
3307 } else {
3308 unreachable!("expected Select");
3309 }
3310 }
3311
3312 #[test]
3313 fn test_compound_union() {
3314 let stmt = parse_one("SELECT 1 UNION SELECT 2");
3315 if let Statement::Select(s) = stmt {
3316 assert_eq!(s.body.compounds.len(), 1);
3317 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
3318 } else {
3319 unreachable!("expected Select");
3320 }
3321 }
3322
3323 #[test]
3324 fn test_compound_union_all() {
3325 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
3326 if let Statement::Select(s) = stmt {
3327 assert_eq!(s.body.compounds.len(), 1);
3328 assert_eq!(s.body.compounds[0].0, CompoundOp::UnionAll);
3329 } else {
3330 unreachable!("expected Select");
3331 }
3332 }
3333
3334 #[test]
3335 fn test_compound_intersect() {
3336 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
3337 if let Statement::Select(s) = stmt {
3338 assert_eq!(s.body.compounds.len(), 1);
3339 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
3340 } else {
3341 unreachable!("expected Select");
3342 }
3343 }
3344
3345 #[test]
3346 fn test_compound_except() {
3347 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
3348 if let Statement::Select(s) = stmt {
3349 assert_eq!(s.body.compounds.len(), 1);
3350 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
3351 } else {
3352 unreachable!("expected Select");
3353 }
3354 }
3355
3356 #[test]
3357 fn test_compound_order_applies_to_whole() {
3358 let stmt = parse_one("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
3360 if let Statement::Select(s) = stmt {
3361 assert_eq!(s.body.compounds.len(), 1);
3362 assert_eq!(s.order_by.len(), 1, "ORDER BY must be on compound");
3363 assert!(s.limit.is_some(), "LIMIT must be on compound");
3364 } else {
3365 unreachable!("expected Select");
3366 }
3367 }
3368
3369 #[test]
3370 fn test_compound_three_way() {
3371 let stmt = parse_one("SELECT 1 UNION SELECT 2 INTERSECT SELECT 3");
3372 if let Statement::Select(s) = stmt {
3373 assert_eq!(s.body.compounds.len(), 2);
3374 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
3375 assert_eq!(s.body.compounds[1].0, CompoundOp::Intersect);
3376 } else {
3377 unreachable!("expected Select");
3378 }
3379 }
3380
3381 #[test]
3382 fn test_cte_not_materialized() {
3383 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3384 if let Statement::Select(s) = stmt {
3385 let with = s.with.as_ref().expect("WITH clause");
3386 assert_eq!(
3387 with.ctes[0].materialized,
3388 Some(CteMaterialized::NotMaterialized)
3389 );
3390 } else {
3391 unreachable!("expected Select");
3392 }
3393 }
3394
3395 #[test]
3396 fn test_cte_with_explicit_columns() {
3397 let stmt = parse_one("WITH cte(a, b, c) AS (SELECT 1, 2, 3) SELECT * FROM cte");
3398 if let Statement::Select(s) = stmt {
3399 let with = s.with.as_ref().expect("WITH clause");
3400 assert_eq!(with.ctes[0].columns, vec!["a", "b", "c"]);
3401 } else {
3402 unreachable!("expected Select");
3403 }
3404 }
3405
3406 #[test]
3407 fn test_window_frame_range() {
3408 let stmt = parse_one(
3409 "SELECT sum(x) OVER (ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t",
3410 );
3411 if let Statement::Select(s) = stmt {
3412 if let SelectCore::Select { columns, .. } = &s.body.select {
3413 match &columns[0] {
3414 ResultColumn::Expr {
3415 expr:
3416 Expr::FunctionCall {
3417 over: Some(over), ..
3418 },
3419 ..
3420 } => {
3421 let frame = over.frame.as_ref().expect("frame spec");
3422 assert_eq!(frame.frame_type, FrameType::Range);
3423 assert!(matches!(frame.start, FrameBound::UnboundedPreceding));
3424 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
3425 }
3426 other => unreachable!("expected window function, got {other:?}"),
3427 }
3428 } else {
3429 unreachable!("expected Select core");
3430 }
3431 } else {
3432 unreachable!("expected Select");
3433 }
3434 }
3435
3436 #[test]
3437 fn test_window_frame_groups() {
3438 let stmt = parse_one(
3439 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
3440 );
3441 if let Statement::Select(s) = stmt {
3442 if let SelectCore::Select { columns, .. } = &s.body.select {
3443 match &columns[0] {
3444 ResultColumn::Expr {
3445 expr:
3446 Expr::FunctionCall {
3447 over: Some(over), ..
3448 },
3449 ..
3450 } => {
3451 let frame = over.frame.as_ref().expect("frame spec");
3452 assert_eq!(frame.frame_type, FrameType::Groups);
3453 assert!(matches!(frame.start, FrameBound::Preceding(_)));
3454 assert!(matches!(frame.end, Some(FrameBound::Following(_))));
3455 }
3456 other => unreachable!("expected window function, got {other:?}"),
3457 }
3458 } else {
3459 unreachable!("expected Select core");
3460 }
3461 } else {
3462 unreachable!("expected Select");
3463 }
3464 }
3465
3466 #[test]
3467 fn test_window_frame_exclude_current_row() {
3468 let stmt = parse_one(
3469 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3470 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3471 );
3472 if let Statement::Select(s) = stmt {
3473 if let SelectCore::Select { columns, .. } = &s.body.select {
3474 match &columns[0] {
3475 ResultColumn::Expr {
3476 expr:
3477 Expr::FunctionCall {
3478 over: Some(over), ..
3479 },
3480 ..
3481 } => {
3482 let frame = over.frame.as_ref().expect("frame spec");
3483 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
3484 }
3485 other => unreachable!("expected window function, got {other:?}"),
3486 }
3487 } else {
3488 unreachable!("expected Select core");
3489 }
3490 } else {
3491 unreachable!("expected Select");
3492 }
3493 }
3494
3495 #[test]
3496 fn test_window_frame_exclude_ties() {
3497 let stmt = parse_one(
3498 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3499 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3500 );
3501 if let Statement::Select(s) = stmt {
3502 if let SelectCore::Select { columns, .. } = &s.body.select {
3503 match &columns[0] {
3504 ResultColumn::Expr {
3505 expr:
3506 Expr::FunctionCall {
3507 over: Some(over), ..
3508 },
3509 ..
3510 } => {
3511 let frame = over.frame.as_ref().expect("frame spec");
3512 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
3513 }
3514 other => unreachable!("expected window function, got {other:?}"),
3515 }
3516 } else {
3517 unreachable!("expected Select core");
3518 }
3519 } else {
3520 unreachable!("expected Select");
3521 }
3522 }
3523
3524 #[test]
3525 fn test_window_frame_exclude_group() {
3526 let stmt =
3527 parse_one("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
3528 if let Statement::Select(s) = stmt {
3529 if let SelectCore::Select { columns, .. } = &s.body.select {
3530 match &columns[0] {
3531 ResultColumn::Expr {
3532 expr:
3533 Expr::FunctionCall {
3534 over: Some(over), ..
3535 },
3536 ..
3537 } => {
3538 let frame = over.frame.as_ref().expect("frame spec");
3539 assert_eq!(frame.frame_type, FrameType::Groups);
3540 assert_eq!(frame.exclude, Some(FrameExclude::Group));
3541 }
3542 other => unreachable!("expected window function, got {other:?}"),
3543 }
3544 } else {
3545 unreachable!("expected Select core");
3546 }
3547 } else {
3548 unreachable!("expected Select");
3549 }
3550 }
3551
3552 #[test]
3553 fn test_window_frame_unbounded_following() {
3554 let stmt = parse_one(
3555 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM t",
3556 );
3557 if let Statement::Select(s) = stmt {
3558 if let SelectCore::Select { columns, .. } = &s.body.select {
3559 match &columns[0] {
3560 ResultColumn::Expr {
3561 expr:
3562 Expr::FunctionCall {
3563 over: Some(over), ..
3564 },
3565 ..
3566 } => {
3567 let frame = over.frame.as_ref().expect("frame spec");
3568 assert!(matches!(frame.start, FrameBound::CurrentRow));
3569 assert!(matches!(frame.end, Some(FrameBound::UnboundedFollowing)));
3570 }
3571 other => unreachable!("expected window function, got {other:?}"),
3572 }
3573 } else {
3574 unreachable!("expected Select core");
3575 }
3576 } else {
3577 unreachable!("expected Select");
3578 }
3579 }
3580
3581 #[test]
3582 fn test_filter_clause_aggregate() {
3583 let stmt = parse_one("SELECT count(*) FILTER (WHERE x > 0) FROM t");
3584 if let Statement::Select(s) = stmt {
3585 if let SelectCore::Select { columns, .. } = &s.body.select {
3586 match &columns[0] {
3587 ResultColumn::Expr {
3588 expr: Expr::FunctionCall { filter, .. },
3589 ..
3590 } => {
3591 assert!(
3592 filter.is_some(),
3593 "FILTER clause must be present on aggregate"
3594 );
3595 }
3596 other => unreachable!("expected function call with filter, got {other:?}"),
3597 }
3598 } else {
3599 unreachable!("expected Select core");
3600 }
3601 } else {
3602 unreachable!("expected Select");
3603 }
3604 }
3605
3606 #[test]
3607 fn test_filter_clause_window() {
3608 let stmt = parse_one("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
3609 if let Statement::Select(s) = stmt {
3610 if let SelectCore::Select { columns, .. } = &s.body.select {
3611 match &columns[0] {
3612 ResultColumn::Expr {
3613 expr:
3614 Expr::FunctionCall {
3615 filter,
3616 over: Some(_),
3617 ..
3618 },
3619 ..
3620 } => {
3621 assert!(
3622 filter.is_some(),
3623 "FILTER clause must be present on window function"
3624 );
3625 }
3626 other => unreachable!("expected window function with filter, got {other:?}"),
3627 }
3628 } else {
3629 unreachable!("expected Select core");
3630 }
3631 } else {
3632 unreachable!("expected Select");
3633 }
3634 }
3635
3636 #[test]
3637 fn test_subquery_in_from() {
3638 let stmt = parse_one("SELECT sub.x FROM (SELECT 1 AS x) AS sub");
3639 if let Statement::Select(s) = stmt {
3640 if let SelectCore::Select { from, .. } = &s.body.select {
3641 let from = from.as_ref().expect("FROM clause");
3642 match &from.source {
3643 TableOrSubquery::Subquery { alias, .. } => {
3644 assert_eq!(alias.as_deref(), Some("sub"));
3645 }
3646 other => unreachable!("expected subquery source, got {other:?}"),
3647 }
3648 } else {
3649 unreachable!("expected Select core");
3650 }
3651 } else {
3652 unreachable!("expected Select");
3653 }
3654 }
3655
3656 #[test]
3657 fn test_multiple_joins_chain() {
3658 let stmt = parse_one(
3659 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id \
3660 LEFT JOIN c ON b.id = c.b_id \
3661 CROSS JOIN d",
3662 );
3663 if let Statement::Select(s) = stmt {
3664 if let SelectCore::Select { from, .. } = &s.body.select {
3665 let from = from.as_ref().expect("FROM clause");
3666 assert_eq!(from.joins.len(), 3);
3667 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3668 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
3669 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
3670 } else {
3671 unreachable!("expected Select core");
3672 }
3673 } else {
3674 unreachable!("expected Select");
3675 }
3676 }
3677
3678 #[test]
3679 fn test_natural_left_join() {
3680 let stmt = parse_one("SELECT * FROM a NATURAL LEFT JOIN b");
3681 if let Statement::Select(s) = stmt {
3682 if let SelectCore::Select { from, .. } = &s.body.select {
3683 let from = from.as_ref().expect("FROM clause");
3684 let jt = &from.joins[0].join_type;
3685 assert!(jt.natural, "must be NATURAL");
3686 assert_eq!(jt.kind, JoinKind::Left);
3687 } else {
3688 unreachable!("expected Select core");
3689 }
3690 } else {
3691 unreachable!("expected Select");
3692 }
3693 }
3694
3695 #[test]
3696 fn test_select_nulls_first_default_asc() {
3697 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3699 if let Statement::Select(s) = stmt {
3700 assert_eq!(s.order_by.len(), 1);
3701 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
3702 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
3703 } else {
3704 unreachable!("expected Select");
3705 }
3706 }
3707
3708 #[test]
3709 fn test_select_nulls_last_desc() {
3710 let stmt = parse_one("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3712 if let Statement::Select(s) = stmt {
3713 assert_eq!(s.order_by.len(), 1);
3714 assert_eq!(s.order_by[0].direction, Some(SortDirection::Desc));
3715 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
3716 } else {
3717 unreachable!("expected Select");
3718 }
3719 }
3720
3721 #[test]
3726 fn test_roundtrip_select_filter_clause() {
3727 assert_roundtrip("SELECT count(*) FILTER (WHERE x > 0) FROM t");
3728 }
3729
3730 #[test]
3731 fn test_roundtrip_select_window_frame_groups() {
3732 assert_roundtrip(
3733 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
3734 );
3735 }
3736
3737 #[test]
3738 fn test_roundtrip_select_window_frame_exclude() {
3739 assert_roundtrip(
3740 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3741 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3742 );
3743 assert_roundtrip(
3744 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3745 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3746 );
3747 assert_roundtrip("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
3748 }
3749
3750 #[test]
3751 fn test_roundtrip_select_nulls_order() {
3752 assert_roundtrip("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3753 assert_roundtrip("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3754 }
3755
3756 #[test]
3757 fn test_roundtrip_select_values() {
3758 assert_roundtrip("VALUES (1, 2), (3, 4)");
3759 }
3760
3761 #[test]
3762 fn test_roundtrip_select_compound_order_limit() {
3763 assert_roundtrip("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
3764 }
3765
3766 #[test]
3767 fn test_roundtrip_select_cte_not_materialized() {
3768 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3769 }
3770
3771 #[test]
3772 fn test_roundtrip_select_natural_left_join() {
3773 assert_roundtrip("SELECT * FROM a NATURAL LEFT JOIN b");
3774 }
3775
3776 #[test]
3777 fn test_roundtrip_select_indexed_by() {
3778 assert_roundtrip("SELECT * FROM t INDEXED BY idx_t WHERE x = 1");
3779 }
3780
3781 #[test]
3782 fn test_roundtrip_select_filter_window_combined() {
3783 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
3784 }
3785
3786 #[test]
3787 fn test_roundtrip_select_three_way_compound() {
3788 assert_roundtrip("SELECT 1 UNION SELECT 2 EXCEPT SELECT 3");
3789 }
3790
3791 #[test]
3792 fn test_roundtrip_select_multiple_joins() {
3793 assert_roundtrip(
3794 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id LEFT JOIN c ON b.id = c.b_id",
3795 );
3796 }
3797
3798 #[test]
3803 fn test_select_star() {
3804 let stmt = parse_one("SELECT * FROM t");
3806 if let Statement::Select(s) = stmt {
3807 if let SelectCore::Select { columns, .. } = &s.body.select {
3808 assert!(matches!(columns[0], ResultColumn::Star));
3809 } else {
3810 unreachable!("expected Select core");
3811 }
3812 } else {
3813 unreachable!("expected Select");
3814 }
3815 }
3816
3817 #[test]
3818 fn test_inner_join_on() {
3819 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
3821 if let Statement::Select(s) = stmt {
3822 if let SelectCore::Select { from, .. } = &s.body.select {
3823 let from = from.as_ref().expect("FROM clause");
3824 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3825 assert!(matches!(
3826 from.joins[0].constraint,
3827 Some(JoinConstraint::On(_))
3828 ));
3829 } else {
3830 unreachable!("expected Select core");
3831 }
3832 } else {
3833 unreachable!("expected Select");
3834 }
3835 }
3836
3837 #[test]
3838 fn test_left_outer_join() {
3839 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
3841 if let Statement::Select(s) = stmt {
3842 if let SelectCore::Select { from, .. } = &s.body.select {
3843 let from = from.as_ref().expect("FROM clause");
3844 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
3845 } else {
3846 unreachable!("expected Select core");
3847 }
3848 } else {
3849 unreachable!("expected Select");
3850 }
3851 }
3852
3853 #[test]
3854 fn test_right_outer_join() {
3855 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
3857 if let Statement::Select(s) = stmt {
3858 if let SelectCore::Select { from, .. } = &s.body.select {
3859 let from = from.as_ref().expect("FROM clause");
3860 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
3861 } else {
3862 unreachable!("expected Select core");
3863 }
3864 } else {
3865 unreachable!("expected Select");
3866 }
3867 }
3868
3869 #[test]
3870 fn test_full_outer_join() {
3871 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
3873 if let Statement::Select(s) = stmt {
3874 if let SelectCore::Select { from, .. } = &s.body.select {
3875 let from = from.as_ref().expect("FROM clause");
3876 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3877 } else {
3878 unreachable!("expected Select core");
3879 }
3880 } else {
3881 unreachable!("expected Select");
3882 }
3883 }
3884
3885 #[test]
3886 fn test_cross_join_no_reorder() {
3887 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
3889 if let Statement::Select(s) = stmt {
3890 if let SelectCore::Select { from, .. } = &s.body.select {
3891 let from = from.as_ref().expect("FROM clause");
3892 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3893 assert!(from.joins[0].constraint.is_none());
3895 } else {
3896 unreachable!("expected Select core");
3897 }
3898 } else {
3899 unreachable!("expected Select");
3900 }
3901 }
3902
3903 #[test]
3904 fn test_natural_join() {
3905 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
3907 if let Statement::Select(s) = stmt {
3908 if let SelectCore::Select { from, .. } = &s.body.select {
3909 let from = from.as_ref().expect("FROM clause");
3910 assert!(from.joins[0].join_type.natural);
3911 } else {
3912 unreachable!("expected Select core");
3913 }
3914 } else {
3915 unreachable!("expected Select");
3916 }
3917 }
3918
3919 #[test]
3920 fn test_using_clause() {
3921 let stmt = parse_one("SELECT * FROM a JOIN b USING (id, name)");
3923 if let Statement::Select(s) = stmt {
3924 if let SelectCore::Select { from, .. } = &s.body.select {
3925 let from = from.as_ref().expect("FROM clause");
3926 match &from.joins[0].constraint {
3927 Some(JoinConstraint::Using(cols)) => {
3928 assert_eq!(cols.len(), 2);
3929 assert_eq!(cols[0], "id");
3930 assert_eq!(cols[1], "name");
3931 }
3932 other => unreachable!("expected USING constraint, got {other:?}"),
3933 }
3934 } else {
3935 unreachable!("expected Select core");
3936 }
3937 } else {
3938 unreachable!("expected Select");
3939 }
3940 }
3941
3942 #[test]
3943 fn test_cte_basic() {
3944 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
3946 if let Statement::Select(s) = stmt {
3947 let with = s.with.as_ref().expect("WITH clause");
3948 assert!(!with.recursive);
3949 assert_eq!(with.ctes.len(), 1);
3950 assert_eq!(with.ctes[0].name, "cte");
3951 } else {
3952 unreachable!("expected Select");
3953 }
3954 }
3955
3956 #[test]
3957 fn test_cte_recursive_union_all() {
3958 let stmt = parse_one(
3960 "WITH RECURSIVE cnt(x) AS (\
3961 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
3962 ) SELECT x FROM cnt",
3963 );
3964 if let Statement::Select(s) = stmt {
3965 let with = s.with.as_ref().expect("WITH clause");
3966 assert!(with.recursive);
3967 assert_eq!(with.ctes[0].name, "cnt");
3968 let cte_body = &with.ctes[0].query;
3970 assert_eq!(cte_body.body.compounds.len(), 1);
3971 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::UnionAll);
3972 } else {
3973 unreachable!("expected Select");
3974 }
3975 }
3976
3977 #[test]
3978 fn test_cte_recursive_union_cycle_detection() {
3979 let stmt = parse_one(
3981 "WITH RECURSIVE paths(a, b) AS (\
3982 SELECT src, dst FROM edges \
3983 UNION \
3984 SELECT p.a, e.dst FROM paths p JOIN edges e ON p.b = e.src\
3985 ) SELECT * FROM paths",
3986 );
3987 if let Statement::Select(s) = stmt {
3988 let with = s.with.as_ref().expect("WITH clause");
3989 assert!(with.recursive);
3990 let cte_body = &with.ctes[0].query;
3992 assert_eq!(cte_body.body.compounds.len(), 1);
3993 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::Union);
3994 } else {
3995 unreachable!("expected Select");
3996 }
3997 }
3998
3999 #[test]
4000 fn test_cte_materialized_hint() {
4001 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
4003 if let Statement::Select(s) = stmt {
4004 let with = s.with.as_ref().expect("WITH clause");
4005 assert_eq!(
4006 with.ctes[0].materialized,
4007 Some(CteMaterialized::Materialized)
4008 );
4009 } else {
4010 unreachable!("expected Select");
4011 }
4012 }
4013
4014 #[test]
4015 fn test_cte_not_materialized_hint() {
4016 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
4018 if let Statement::Select(s) = stmt {
4019 let with = s.with.as_ref().expect("WITH clause");
4020 assert_eq!(
4021 with.ctes[0].materialized,
4022 Some(CteMaterialized::NotMaterialized)
4023 );
4024 } else {
4025 unreachable!("expected Select");
4026 }
4027 }
4028
4029 #[test]
4030 fn test_window_partition_by() {
4031 let stmt = parse_one("SELECT sum(x) OVER (PARTITION BY dept) FROM emp");
4033 if let Statement::Select(s) = stmt {
4034 if let SelectCore::Select { columns, .. } = &s.body.select {
4035 match &columns[0] {
4036 ResultColumn::Expr {
4037 expr:
4038 Expr::FunctionCall {
4039 over: Some(over), ..
4040 },
4041 ..
4042 } => {
4043 assert_eq!(over.partition_by.len(), 1);
4044 }
4045 other => unreachable!("expected window function, got {other:?}"),
4046 }
4047 } else {
4048 unreachable!("expected Select core");
4049 }
4050 } else {
4051 unreachable!("expected Select");
4052 }
4053 }
4054
4055 #[test]
4056 fn test_window_order_by() {
4057 let stmt = parse_one("SELECT row_number() OVER (ORDER BY salary DESC) FROM emp");
4059 if let Statement::Select(s) = stmt {
4060 if let SelectCore::Select { columns, .. } = &s.body.select {
4061 match &columns[0] {
4062 ResultColumn::Expr {
4063 expr:
4064 Expr::FunctionCall {
4065 over: Some(over), ..
4066 },
4067 ..
4068 } => {
4069 assert_eq!(over.order_by.len(), 1);
4070 assert_eq!(over.order_by[0].direction, Some(SortDirection::Desc));
4071 }
4072 other => unreachable!("expected window function, got {other:?}"),
4073 }
4074 } else {
4075 unreachable!("expected Select core");
4076 }
4077 } else {
4078 unreachable!("expected Select");
4079 }
4080 }
4081
4082 #[test]
4083 fn test_window_frame_rows() {
4084 let stmt = parse_one(
4086 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
4087 );
4088 if let Statement::Select(s) = stmt {
4089 if let SelectCore::Select { columns, .. } = &s.body.select {
4090 match &columns[0] {
4091 ResultColumn::Expr {
4092 expr:
4093 Expr::FunctionCall {
4094 over: Some(over), ..
4095 },
4096 ..
4097 } => {
4098 let frame = over.frame.as_ref().expect("frame spec");
4099 assert_eq!(frame.frame_type, FrameType::Rows);
4100 assert!(matches!(frame.start, FrameBound::Preceding(_)));
4101 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
4102 }
4103 other => unreachable!("expected window function, got {other:?}"),
4104 }
4105 } else {
4106 unreachable!("expected Select core");
4107 }
4108 } else {
4109 unreachable!("expected Select");
4110 }
4111 }
4112
4113 #[test]
4114 fn test_window_exclude_current_row() {
4115 let stmt = parse_one(
4117 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
4118 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
4119 );
4120 if let Statement::Select(s) = stmt {
4121 if let SelectCore::Select { columns, .. } = &s.body.select {
4122 match &columns[0] {
4123 ResultColumn::Expr {
4124 expr:
4125 Expr::FunctionCall {
4126 over: Some(over), ..
4127 },
4128 ..
4129 } => {
4130 let frame = over.frame.as_ref().expect("frame spec");
4131 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
4132 }
4133 other => unreachable!("expected window function, got {other:?}"),
4134 }
4135 } else {
4136 unreachable!("expected Select core");
4137 }
4138 } else {
4139 unreachable!("expected Select");
4140 }
4141 }
4142
4143 #[test]
4144 fn test_window_exclude_ties() {
4145 let stmt = parse_one(
4147 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
4148 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
4149 );
4150 if let Statement::Select(s) = stmt {
4151 if let SelectCore::Select { columns, .. } = &s.body.select {
4152 match &columns[0] {
4153 ResultColumn::Expr {
4154 expr:
4155 Expr::FunctionCall {
4156 over: Some(over), ..
4157 },
4158 ..
4159 } => {
4160 let frame = over.frame.as_ref().expect("frame spec");
4161 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
4162 }
4163 other => unreachable!("expected window function, got {other:?}"),
4164 }
4165 } else {
4166 unreachable!("expected Select core");
4167 }
4168 } else {
4169 unreachable!("expected Select");
4170 }
4171 }
4172
4173 #[test]
4174 fn test_nulls_first_asc() {
4175 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
4177 if let Statement::Select(s) = stmt {
4178 assert_eq!(s.order_by.len(), 1);
4179 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
4180 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
4181 } else {
4182 unreachable!("expected Select");
4183 }
4184 }
4185
4186 #[test]
4187 fn test_nulls_last_asc() {
4188 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS LAST");
4190 if let Statement::Select(s) = stmt {
4191 assert_eq!(s.order_by.len(), 1);
4192 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
4193 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
4194 } else {
4195 unreachable!("expected Select");
4196 }
4197 }
4198
4199 #[test]
4200 fn test_distinct_deduplicates() {
4201 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
4203 if let Statement::Select(s) = stmt {
4204 if let SelectCore::Select { distinct, .. } = &s.body.select {
4205 assert_eq!(*distinct, Distinctness::Distinct);
4206 } else {
4207 unreachable!("expected Select core");
4208 }
4209 } else {
4210 unreachable!("expected Select");
4211 }
4212 }
4213
4214 #[test]
4215 fn test_limit_offset() {
4216 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET 20");
4218 if let Statement::Select(s) = stmt {
4219 let limit = s.limit.expect("LIMIT clause");
4220 assert!(matches!(
4221 limit.limit,
4222 Expr::Literal(Literal::Integer(10), _)
4223 ));
4224 assert!(matches!(
4225 limit.offset,
4226 Some(Expr::Literal(Literal::Integer(20), _))
4227 ));
4228 } else {
4229 unreachable!("expected Select");
4230 }
4231 }
4232
4233 #[test]
4234 fn test_limit_comma_syntax() {
4235 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
4237 if let Statement::Select(s) = stmt {
4238 let limit = s.limit.expect("LIMIT clause");
4239 assert!(matches!(
4241 limit.limit,
4242 Expr::Literal(Literal::Integer(10), _)
4243 ));
4244 assert!(matches!(
4245 limit.offset,
4246 Some(Expr::Literal(Literal::Integer(5), _))
4247 ));
4248 } else {
4249 unreachable!("expected Select");
4250 }
4251 }
4252
4253 #[test]
4254 fn test_negative_limit_unlimited() {
4255 let stmt = parse_one("SELECT a FROM t LIMIT -1");
4257 if let Statement::Select(s) = stmt {
4258 let limit = s.limit.expect("LIMIT clause");
4259 match &limit.limit {
4262 Expr::UnaryOp {
4263 op: fsqlite_ast::UnaryOp::Negate,
4264 ..
4265 } => {}
4266 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
4267 other => unreachable!("expected negative limit expression, got {other:?}"),
4268 }
4269 } else {
4270 unreachable!("expected Select");
4271 }
4272 }
4273
4274 #[test]
4275 fn test_negative_offset_zero() {
4276 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET -5");
4278 if let Statement::Select(s) = stmt {
4279 let limit = s.limit.expect("LIMIT clause");
4280 assert!(limit.offset.is_some());
4281 match limit.offset.as_ref().unwrap() {
4282 Expr::UnaryOp {
4283 op: fsqlite_ast::UnaryOp::Negate,
4284 ..
4285 } => {}
4286 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
4287 other => unreachable!("expected negative offset expression, got {other:?}"),
4288 }
4289 } else {
4290 unreachable!("expected Select");
4291 }
4292 }
4293
4294 #[test]
4295 fn test_current_date_constant() {
4296 let stmt = parse_one("SELECT CURRENT_DATE");
4298 if let Statement::Select(s) = stmt {
4299 if let SelectCore::Select { columns, .. } = &s.body.select {
4300 match &columns[0] {
4301 ResultColumn::Expr {
4302 expr: Expr::Literal(Literal::CurrentDate, _),
4303 ..
4304 } => {}
4305 other => unreachable!("expected CURRENT_DATE literal, got {other:?}"),
4306 }
4307 } else {
4308 unreachable!("expected Select core");
4309 }
4310 } else {
4311 unreachable!("expected Select");
4312 }
4313 }
4314
4315 #[test]
4316 fn test_current_time_constant() {
4317 let stmt = parse_one("SELECT CURRENT_TIME");
4319 if let Statement::Select(s) = stmt {
4320 if let SelectCore::Select { columns, .. } = &s.body.select {
4321 match &columns[0] {
4322 ResultColumn::Expr {
4323 expr: Expr::Literal(Literal::CurrentTime, _),
4324 ..
4325 } => {}
4326 other => unreachable!("expected CURRENT_TIME literal, got {other:?}"),
4327 }
4328 } else {
4329 unreachable!("expected Select core");
4330 }
4331 } else {
4332 unreachable!("expected Select");
4333 }
4334 }
4335
4336 #[test]
4337 fn test_current_timestamp_constant() {
4338 let stmt = parse_one("SELECT CURRENT_TIMESTAMP");
4340 if let Statement::Select(s) = stmt {
4341 if let SelectCore::Select { columns, .. } = &s.body.select {
4342 match &columns[0] {
4343 ResultColumn::Expr {
4344 expr: Expr::Literal(Literal::CurrentTimestamp, _),
4345 ..
4346 } => {}
4347 other => unreachable!("expected CURRENT_TIMESTAMP literal, got {other:?}"),
4348 }
4349 } else {
4350 unreachable!("expected Select core");
4351 }
4352 } else {
4353 unreachable!("expected Select");
4354 }
4355 }
4356
4357 #[test]
4358 fn test_date_constants_evaluated_once_per_statement() {
4359 let stmt = parse_one("SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP FROM t");
4362 if let Statement::Select(s) = stmt {
4363 if let SelectCore::Select { columns, .. } = &s.body.select {
4364 assert_eq!(columns.len(), 3);
4365 assert!(matches!(
4366 &columns[0],
4367 ResultColumn::Expr {
4368 expr: Expr::Literal(Literal::CurrentDate, _),
4369 ..
4370 }
4371 ));
4372 assert!(matches!(
4373 &columns[1],
4374 ResultColumn::Expr {
4375 expr: Expr::Literal(Literal::CurrentTime, _),
4376 ..
4377 }
4378 ));
4379 assert!(matches!(
4380 &columns[2],
4381 ResultColumn::Expr {
4382 expr: Expr::Literal(Literal::CurrentTimestamp, _),
4383 ..
4384 }
4385 ));
4386 } else {
4387 unreachable!("expected Select core");
4388 }
4389 } else {
4390 unreachable!("expected Select");
4391 }
4392 }
4393
4394 #[test]
4395 fn test_indexed_by_hint() {
4396 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
4398 if let Statement::Select(s) = stmt {
4399 if let SelectCore::Select { from, .. } = &s.body.select {
4400 let from = from.as_ref().expect("FROM clause");
4401 match &from.source {
4402 TableOrSubquery::Table {
4403 index_hint: Some(IndexHint::IndexedBy(name)),
4404 ..
4405 } => assert_eq!(name, "idx_t"),
4406 other => unreachable!("expected indexed table source, got {other:?}"),
4407 }
4408 } else {
4409 unreachable!("expected Select core");
4410 }
4411 } else {
4412 unreachable!("expected Select");
4413 }
4414 }
4415
4416 #[test]
4417 fn test_not_indexed_hint() {
4418 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
4420 if let Statement::Select(s) = stmt {
4421 if let SelectCore::Select { from, .. } = &s.body.select {
4422 let from = from.as_ref().expect("FROM clause");
4423 match &from.source {
4424 TableOrSubquery::Table {
4425 index_hint: Some(IndexHint::NotIndexed),
4426 ..
4427 } => {}
4428 other => unreachable!("expected not-indexed table source, got {other:?}"),
4429 }
4430 } else {
4431 unreachable!("expected Select core");
4432 }
4433 } else {
4434 unreachable!("expected Select");
4435 }
4436 }
4437
4438 #[test]
4439 fn test_table_valued_function_in_from() {
4440 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
4442 if let Statement::Select(s) = stmt {
4443 if let SelectCore::Select { from, .. } = &s.body.select {
4444 let from = from.as_ref().expect("FROM clause");
4445 match &from.source {
4446 TableOrSubquery::TableFunction { name, args, alias } => {
4447 assert_eq!(name, "generate_series");
4448 assert_eq!(args.len(), 2);
4449 assert_eq!(alias.as_deref(), Some("gs"));
4450 }
4451 other => unreachable!("expected table-valued function source, got {other:?}"),
4452 }
4453 } else {
4454 unreachable!("expected Select core");
4455 }
4456 } else {
4457 unreachable!("expected Select");
4458 }
4459 }
4460
4461 #[test]
4466 fn test_insert_values_single() {
4467 let stmt = parse_one("INSERT INTO t (a, b, c) VALUES (1, 'hello', 3.14)");
4468 if let Statement::Insert(i) = stmt {
4469 assert_eq!(i.columns, vec!["a", "b", "c"]);
4470 if let InsertSource::Values(rows) = &i.source {
4471 assert_eq!(rows.len(), 1);
4472 assert_eq!(rows[0].len(), 3);
4473 } else {
4474 unreachable!("expected Values source");
4475 }
4476 } else {
4477 unreachable!("expected Insert");
4478 }
4479 }
4480
4481 #[test]
4482 fn test_insert_values_multi() {
4483 let stmt = parse_one("INSERT INTO t (x, y) VALUES (1, 2), (3, 4), (5, 6)");
4484 if let Statement::Insert(i) = stmt {
4485 if let InsertSource::Values(rows) = &i.source {
4486 assert_eq!(rows.len(), 3);
4487 for row in rows {
4488 assert_eq!(row.len(), 2);
4489 }
4490 } else {
4491 unreachable!("expected Values source");
4492 }
4493 } else {
4494 unreachable!("expected Insert");
4495 }
4496 }
4497
4498 #[test]
4499 fn test_insert_from_select() {
4500 let stmt = parse_one("INSERT INTO t2 (a, b) SELECT x, y FROM t1 WHERE x > 0");
4501 if let Statement::Insert(i) = stmt {
4502 assert!(matches!(i.source, InsertSource::Select(_)));
4503 assert_eq!(i.columns, vec!["a", "b"]);
4504 } else {
4505 unreachable!("expected Insert");
4506 }
4507 }
4508
4509 #[test]
4510 fn test_insert_from_select_without_from_clause() {
4511 let stmt = parse_one("INSERT INTO t (a) SELECT 1");
4512 if let Statement::Insert(i) = stmt {
4513 if let InsertSource::Select(select) = &i.source {
4514 if let SelectCore::Select { from, columns, .. } = &select.body.select {
4515 assert!(from.is_none(), "SELECT 1 should parse without FROM");
4516 assert_eq!(columns.len(), 1);
4517 } else {
4518 unreachable!("expected Select core");
4519 }
4520 } else {
4521 unreachable!("expected Select source");
4522 }
4523 } else {
4524 unreachable!("expected Insert");
4525 }
4526 }
4527
4528 #[test]
4529 fn test_insert_from_select_subquery_source() {
4530 let stmt = parse_one("INSERT INTO t (a) SELECT sub.x FROM (SELECT 1 AS x) AS sub");
4531 if let Statement::Insert(i) = stmt {
4532 if let InsertSource::Select(select) = &i.source {
4533 if let SelectCore::Select { from, .. } = &select.body.select {
4534 let from = from.as_ref().expect("FROM clause");
4535 match &from.source {
4536 TableOrSubquery::Subquery { alias, .. } => {
4537 assert_eq!(alias.as_deref(), Some("sub"));
4538 }
4539 other => unreachable!("expected subquery source, got {other:?}"),
4540 }
4541 } else {
4542 unreachable!("expected Select core");
4543 }
4544 } else {
4545 unreachable!("expected Select source");
4546 }
4547 } else {
4548 unreachable!("expected Insert");
4549 }
4550 }
4551
4552 #[test]
4553 fn test_insert_from_select_table_function_source() {
4554 let stmt = parse_one("INSERT INTO t (a) SELECT gs.value FROM generate_series(1, 3) AS gs");
4555 if let Statement::Insert(i) = stmt {
4556 if let InsertSource::Select(select) = &i.source {
4557 if let SelectCore::Select { from, .. } = &select.body.select {
4558 let from = from.as_ref().expect("FROM clause");
4559 match &from.source {
4560 TableOrSubquery::TableFunction { name, args, alias } => {
4561 assert_eq!(name, "generate_series");
4562 assert_eq!(args.len(), 2);
4563 assert_eq!(alias.as_deref(), Some("gs"));
4564 }
4565 other => unreachable!("expected table function source, got {other:?}"),
4566 }
4567 } else {
4568 unreachable!("expected Select core");
4569 }
4570 } else {
4571 unreachable!("expected Select source");
4572 }
4573 } else {
4574 unreachable!("expected Insert");
4575 }
4576 }
4577
4578 #[test]
4579 fn test_insert_default_values() {
4580 let stmt = parse_one("INSERT INTO t DEFAULT VALUES");
4581 if let Statement::Insert(i) = stmt {
4582 assert!(matches!(i.source, InsertSource::DefaultValues));
4583 assert!(i.columns.is_empty());
4584 } else {
4585 unreachable!("expected Insert");
4586 }
4587 }
4588
4589 #[test]
4590 fn test_insert_or_abort() {
4591 let stmt = parse_one("INSERT OR ABORT INTO t (a) VALUES (1)");
4592 if let Statement::Insert(i) = stmt {
4593 assert_eq!(i.or_conflict, Some(ConflictAction::Abort));
4594 } else {
4595 unreachable!("expected Insert");
4596 }
4597 }
4598
4599 #[test]
4600 fn test_insert_or_rollback() {
4601 let stmt = parse_one("INSERT OR ROLLBACK INTO t (a) VALUES (1)");
4602 if let Statement::Insert(i) = stmt {
4603 assert_eq!(i.or_conflict, Some(ConflictAction::Rollback));
4604 } else {
4605 unreachable!("expected Insert");
4606 }
4607 }
4608
4609 #[test]
4610 fn test_insert_or_fail() {
4611 let stmt = parse_one("INSERT OR FAIL INTO t (a) VALUES (1)");
4612 if let Statement::Insert(i) = stmt {
4613 assert_eq!(i.or_conflict, Some(ConflictAction::Fail));
4614 } else {
4615 unreachable!("expected Insert");
4616 }
4617 }
4618
4619 #[test]
4620 fn test_insert_or_ignore() {
4621 let stmt = parse_one("INSERT OR IGNORE INTO t (a) VALUES (1)");
4622 if let Statement::Insert(i) = stmt {
4623 assert_eq!(i.or_conflict, Some(ConflictAction::Ignore));
4624 } else {
4625 unreachable!("expected Insert");
4626 }
4627 }
4628
4629 #[test]
4630 fn test_insert_or_replace() {
4631 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1)");
4633 if let Statement::Insert(i) = stmt {
4634 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4635 } else {
4636 unreachable!("expected Insert");
4637 }
4638 }
4639
4640 #[test]
4641 fn test_upsert_do_update() {
4642 let stmt = parse_one(
4643 "INSERT INTO t (a, b) VALUES (1, 2) ON CONFLICT (a) DO UPDATE SET b = excluded.b",
4644 );
4645 if let Statement::Insert(i) = stmt {
4646 assert_eq!(i.upsert.len(), 1);
4647 assert!(i.upsert[0].target.is_some());
4648 match &i.upsert[0].action {
4649 UpsertAction::Update {
4650 assignments,
4651 where_clause,
4652 } => {
4653 assert_eq!(assignments.len(), 1);
4654 assert!(where_clause.is_none());
4655 }
4656 UpsertAction::Nothing => unreachable!("expected Update action"),
4657 }
4658 } else {
4659 unreachable!("expected Insert");
4660 }
4661 }
4662
4663 #[test]
4664 fn test_upsert_do_nothing() {
4665 let stmt = parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
4666 if let Statement::Insert(i) = stmt {
4667 assert_eq!(i.upsert.len(), 1);
4668 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4669 } else {
4670 unreachable!("expected Insert");
4671 }
4672 }
4673
4674 #[test]
4675 fn test_upsert_excluded_pseudo_table() {
4676 let stmt = parse_one(
4677 "INSERT INTO t (a, b) VALUES (1, 2) \
4678 ON CONFLICT (a) DO UPDATE SET b = excluded.b, a = excluded.a + 1",
4679 );
4680 if let Statement::Insert(i) = stmt {
4681 assert_eq!(i.upsert.len(), 1);
4682 if let UpsertAction::Update { assignments, .. } = &i.upsert[0].action {
4683 assert_eq!(assignments.len(), 2);
4684 match &assignments[0].value {
4686 Expr::Column(col, _) => {
4687 assert_eq!(col.table.as_deref(), Some("excluded"));
4688 assert_eq!(col.column.as_ref(), "b");
4689 }
4690 other => unreachable!("expected Column ref to excluded.b, got {other:?}"),
4691 }
4692 } else {
4693 unreachable!("expected Update action");
4694 }
4695 } else {
4696 unreachable!("expected Insert");
4697 }
4698 }
4699
4700 #[test]
4701 fn test_upsert_multiple_on_conflict() {
4702 let stmt = parse_one(
4703 "INSERT INTO t (a, b) VALUES (1, 2) \
4704 ON CONFLICT (a) DO NOTHING \
4705 ON CONFLICT (b) DO UPDATE SET a = excluded.a",
4706 );
4707 if let Statement::Insert(i) = stmt {
4708 assert_eq!(i.upsert.len(), 2);
4709 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4710 assert!(matches!(i.upsert[1].action, UpsertAction::Update { .. }));
4711 } else {
4712 unreachable!("expected Insert");
4713 }
4714 }
4715
4716 #[test]
4717 fn test_upsert_where_on_conflict_target() {
4718 let stmt = parse_one(
4719 "INSERT INTO t (a, b) VALUES (1, 2) \
4720 ON CONFLICT (a) WHERE a > 0 DO UPDATE SET b = excluded.b WHERE b < 100",
4721 );
4722 if let Statement::Insert(i) = stmt {
4723 assert_eq!(i.upsert.len(), 1);
4724 let target = i.upsert[0].target.as_ref().expect("conflict target");
4725 assert!(target.where_clause.is_some(), "target WHERE missing");
4726 if let UpsertAction::Update { where_clause, .. } = &i.upsert[0].action {
4727 assert!(where_clause.is_some(), "action WHERE missing");
4728 } else {
4729 unreachable!("expected Update action");
4730 }
4731 } else {
4732 unreachable!("expected Insert");
4733 }
4734 }
4735
4736 #[test]
4737 fn test_returning_insert() {
4738 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, rowid");
4739 if let Statement::Insert(i) = stmt {
4740 assert_eq!(i.returning.len(), 3);
4741 } else {
4742 unreachable!("expected Insert");
4743 }
4744 }
4745
4746 #[test]
4747 fn test_returning_insert_select_with_semicolon() {
4748 let stmt = parse_one("INSERT INTO t2 SELECT * FROM t RETURNING *;");
4749 if let Statement::Insert(i) = stmt {
4750 assert!(matches!(i.source, InsertSource::Select(_)));
4751 assert_eq!(i.returning.len(), 1);
4752 assert!(matches!(i.returning[0], ResultColumn::Star));
4753 } else {
4754 unreachable!("expected Insert");
4755 }
4756 }
4757
4758 #[test]
4759 fn test_returning_reflects_before_triggers() {
4760 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING a AS modified_a");
4764 if let Statement::Insert(i) = stmt {
4765 assert_eq!(i.returning.len(), 1);
4766 match &i.returning[0] {
4767 ResultColumn::Expr { alias, .. } => {
4768 assert_eq!(alias.as_deref(), Some("modified_a"));
4769 }
4770 other => unreachable!("expected Expr result column, got {other:?}"),
4771 }
4772 } else {
4773 unreachable!("expected Insert");
4774 }
4775 }
4776
4777 #[test]
4778 fn test_returning_ignores_after_triggers() {
4779 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1) RETURNING *");
4783 if let Statement::Insert(i) = stmt {
4784 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4785 assert_eq!(i.returning.len(), 1);
4786 assert!(matches!(i.returning[0], ResultColumn::Star));
4787 } else {
4788 unreachable!("expected Insert");
4789 }
4790 }
4791
4792 #[test]
4793 fn test_returning_after_before_trigger_modify() {
4794 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, a + b AS total");
4798 if let Statement::Insert(i) = stmt {
4799 assert_eq!(i.returning.len(), 3);
4800 match &i.returning[2] {
4801 ResultColumn::Expr {
4802 alias: Some(alias), ..
4803 } => assert_eq!(alias, "total"),
4804 other => unreachable!("expected aliased expression, got {other:?}"),
4805 }
4806 } else {
4807 unreachable!("expected Insert");
4808 }
4809 }
4810
4811 #[test]
4812 fn test_returning_before_trigger_raise_abort() {
4813 let stmt = parse_one("INSERT INTO t (a) VALUES (1), (2), (3) RETURNING a");
4817 if let Statement::Insert(i) = stmt {
4818 if let InsertSource::Values(rows) = &i.source {
4819 assert_eq!(rows.len(), 3);
4820 } else {
4821 unreachable!("expected Values source");
4822 }
4823 assert_eq!(i.returning.len(), 1);
4824 } else {
4825 unreachable!("expected Insert");
4826 }
4827 }
4828
4829 #[test]
4830 fn test_returning_instead_of_view() {
4831 let stmt = parse_one("INSERT INTO v (a, b) VALUES (1, 2) RETURNING *");
4834 if let Statement::Insert(i) = stmt {
4835 assert_eq!(i.table.name, "v");
4836 assert!(!i.returning.is_empty());
4837 } else {
4838 unreachable!("expected Insert");
4839 }
4840 }
4841
4842 #[test]
4843 fn test_returning_autoincrement_with_trigger() {
4844 let stmt = parse_one("INSERT INTO t (name) VALUES ('test') RETURNING rowid, name");
4847 if let Statement::Insert(i) = stmt {
4848 assert_eq!(i.returning.len(), 2);
4849 } else {
4850 unreachable!("expected Insert");
4851 }
4852 }
4853
4854 #[test]
4855 fn test_update_set_where() {
4856 let stmt = parse_one("UPDATE t SET a = 1, b = 'hello' WHERE id = 42");
4857 if let Statement::Update(u) = stmt {
4858 assert_eq!(u.assignments.len(), 2);
4859 assert!(u.where_clause.is_some());
4860 assert!(u.from.is_none());
4861 } else {
4862 unreachable!("expected Update");
4863 }
4864 }
4865
4866 #[test]
4867 fn test_update_from_join() {
4868 let stmt = parse_one("UPDATE t1 SET a = t2.x FROM t2 WHERE t1.id = t2.id");
4869 if let Statement::Update(u) = stmt {
4870 assert_eq!(u.assignments.len(), 1);
4871 assert!(u.from.is_some());
4872 assert!(u.where_clause.is_some());
4873 } else {
4874 unreachable!("expected Update");
4875 }
4876 }
4877
4878 #[test]
4879 fn test_update_from_multi_match() {
4880 let stmt = parse_one(
4883 "UPDATE t1 SET val = src.val FROM src \
4884 INNER JOIN mapping ON mapping.src_id = src.id \
4885 WHERE t1.id = mapping.dst_id",
4886 );
4887 if let Statement::Update(u) = stmt {
4888 assert!(u.from.is_some());
4889 let from = u.from.as_ref().unwrap();
4890 assert!(!from.joins.is_empty(), "expected JOIN in FROM clause");
4891 } else {
4892 unreachable!("expected Update");
4893 }
4894 }
4895
4896 #[test]
4897 fn test_update_order_by_limit() {
4898 let stmt = parse_one("UPDATE t SET a = a + 1 ORDER BY b DESC LIMIT 10");
4899 if let Statement::Update(u) = stmt {
4900 assert_eq!(u.order_by.len(), 1);
4901 assert_eq!(u.order_by[0].direction, Some(SortDirection::Desc));
4902 assert!(u.limit.is_some());
4903 } else {
4904 unreachable!("expected Update");
4905 }
4906 }
4907
4908 #[test]
4909 fn test_update_returning() {
4910 let stmt = parse_one("UPDATE t SET a = 1 WHERE id = 5 RETURNING id, a AS new_a");
4911 if let Statement::Update(u) = stmt {
4912 assert_eq!(u.returning.len(), 2);
4913 match &u.returning[1] {
4914 ResultColumn::Expr {
4915 alias: Some(alias), ..
4916 } => assert_eq!(alias, "new_a"),
4917 other => unreachable!("expected aliased result column, got {other:?}"),
4918 }
4919 } else {
4920 unreachable!("expected Update");
4921 }
4922 }
4923
4924 #[test]
4925 fn test_update_or_ignore() {
4926 let stmt = parse_one("UPDATE OR IGNORE t SET a = 1 WHERE id = 5");
4927 if let Statement::Update(u) = stmt {
4928 assert_eq!(u.or_conflict, Some(ConflictAction::Ignore));
4929 assert!(u.where_clause.is_some());
4930 } else {
4931 unreachable!("expected Update");
4932 }
4933 }
4934
4935 #[test]
4936 fn test_delete_where() {
4937 let stmt = parse_one("DELETE FROM t WHERE id = 42 AND active = 0");
4938 if let Statement::Delete(d) = stmt {
4939 assert!(d.where_clause.is_some());
4940 assert!(d.returning.is_empty());
4941 } else {
4942 unreachable!("expected Delete");
4943 }
4944 }
4945
4946 #[test]
4947 fn test_delete_order_by_limit() {
4948 let stmt = parse_one("DELETE FROM t ORDER BY created_at ASC LIMIT 100");
4949 if let Statement::Delete(d) = stmt {
4950 assert_eq!(d.order_by.len(), 1);
4951 assert_eq!(d.order_by[0].direction, Some(SortDirection::Asc));
4952 let limit = d.limit.as_ref().expect("LIMIT clause");
4953 assert!(matches!(
4954 limit.limit,
4955 Expr::Literal(Literal::Integer(100), _)
4956 ));
4957 } else {
4958 unreachable!("expected Delete");
4959 }
4960 }
4961
4962 #[test]
4963 fn test_delete_returning() {
4964 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
4965 if let Statement::Delete(d) = stmt {
4966 assert!(d.where_clause.is_some());
4967 assert_eq!(d.returning.len(), 1);
4968 assert!(matches!(d.returning[0], ResultColumn::Star));
4969 } else {
4970 unreachable!("expected Delete");
4971 }
4972 }
4973
4974 #[test]
4975 fn test_delete_bulk_optimization() {
4976 let stmt = parse_one("DELETE FROM t");
4979 if let Statement::Delete(d) = stmt {
4980 assert!(d.where_clause.is_none());
4981 assert!(d.order_by.is_empty());
4982 assert!(d.limit.is_none());
4983 assert!(d.returning.is_empty());
4984 } else {
4985 unreachable!("expected Delete");
4986 }
4987 }
4988
4989 #[test]
4990 fn test_delete_bulk_no_where_fast() {
4991 let stmt = parse_one("DELETE FROM main.t");
4994 if let Statement::Delete(d) = stmt {
4995 assert_eq!(d.table.name.schema.as_deref(), Some("main"));
4996 assert_eq!(d.table.name.name, "t");
4997 assert!(d.where_clause.is_none());
4998 } else {
4999 unreachable!("expected Delete");
5000 }
5001 }
5002
5003 #[test]
5004 fn test_delete_bulk_blocked_by_trigger() {
5005 let stmt = parse_one("DELETE FROM orders");
5008 if let Statement::Delete(d) = stmt {
5009 assert!(d.where_clause.is_none());
5010 assert!(d.returning.is_empty());
5011 } else {
5012 unreachable!("expected Delete");
5013 }
5014 }
5015
5016 #[test]
5017 fn test_delete_bulk_blocked_by_fk() {
5018 let stmt = parse_one("DELETE FROM parent_table");
5021 if let Statement::Delete(d) = stmt {
5022 assert!(d.where_clause.is_none());
5023 } else {
5024 unreachable!("expected Delete");
5025 }
5026 }
5027
5028 #[test]
5029 fn test_delete_bulk_changes_count() {
5030 let stmt = parse_one("DELETE FROM t");
5034 if let Statement::Delete(d) = stmt {
5035 assert!(d.where_clause.is_none());
5036 } else {
5037 unreachable!("expected Delete");
5038 }
5039 }
5040
5041 #[test]
5042 fn test_delete_bulk_autoincrement_preserved() {
5043 let stmt = parse_one("DELETE FROM t");
5047 if let Statement::Delete(d) = stmt {
5048 assert!(d.where_clause.is_none());
5049 assert!(d.limit.is_none());
5050 } else {
5051 unreachable!("expected Delete");
5052 }
5053 }
5054
5055 #[test]
5056 fn test_delete_bulk_where_1_not_optimized() {
5057 let stmt = parse_one("DELETE FROM t WHERE 1");
5060 if let Statement::Delete(d) = stmt {
5061 assert!(
5062 d.where_clause.is_some(),
5063 "WHERE 1 must produce a where_clause"
5064 );
5065 assert!(matches!(
5066 d.where_clause.as_ref().unwrap(),
5067 Expr::Literal(Literal::Integer(1), _)
5068 ));
5069 } else {
5070 unreachable!("expected Delete");
5071 }
5072 }
5073
5074 #[test]
5079 fn test_create_table_basic() {
5080 let stmt = parse_one("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
5081 if let Statement::CreateTable(ct) = stmt {
5082 assert_eq!(ct.name.name, "users");
5083 assert!(!ct.if_not_exists);
5084 assert!(!ct.temporary);
5085 assert!(!ct.without_rowid);
5086 assert!(!ct.strict);
5087 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5088 assert_eq!(columns.len(), 3);
5089 assert_eq!(columns[0].name, "id");
5090 assert_eq!(columns[1].name, "name");
5091 assert_eq!(columns[2].name, "age");
5092 } else {
5093 unreachable!("expected Columns body");
5094 }
5095 } else {
5096 unreachable!("expected CreateTable");
5097 }
5098 }
5099
5100 #[test]
5101 fn test_create_table_if_not_exists() {
5102 let stmt = parse_one("CREATE TABLE IF NOT EXISTS t (id INTEGER)");
5103 if let Statement::CreateTable(ct) = stmt {
5104 assert!(ct.if_not_exists);
5105 } else {
5106 unreachable!("expected CreateTable");
5107 }
5108 }
5109
5110 #[test]
5111 fn test_create_temp_table() {
5112 let stmt = parse_one("CREATE TEMP TABLE session_data (key TEXT, val BLOB)");
5113 if let Statement::CreateTable(ct) = stmt {
5114 assert!(ct.temporary);
5115 } else {
5116 unreachable!("expected CreateTable");
5117 }
5118 }
5119
5120 #[test]
5121 fn test_create_table_as_select() {
5122 let stmt = parse_one("CREATE TABLE t2 AS SELECT id, name FROM t1 WHERE active = 1");
5123 if let Statement::CreateTable(ct) = stmt {
5124 assert!(matches!(ct.body, CreateTableBody::AsSelect(_)));
5125 } else {
5126 unreachable!("expected CreateTable");
5127 }
5128 }
5129
5130 #[test]
5131 fn test_column_primary_key() {
5132 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY ASC)");
5133 if let Statement::CreateTable(ct) = stmt {
5134 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5135 let pk = columns[0]
5136 .constraints
5137 .iter()
5138 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
5139 assert!(pk.is_some(), "PK constraint missing");
5140 if let ColumnConstraintKind::PrimaryKey { direction, .. } = &pk.unwrap().kind {
5141 assert_eq!(*direction, Some(SortDirection::Asc));
5142 }
5143 } else {
5144 unreachable!("expected Columns body");
5145 }
5146 } else {
5147 unreachable!("expected CreateTable");
5148 }
5149 }
5150
5151 #[test]
5152 fn test_column_primary_key_autoincrement() {
5153 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)");
5154 if let Statement::CreateTable(ct) = stmt {
5155 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5156 let pk = columns[0]
5157 .constraints
5158 .iter()
5159 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
5160 if let ColumnConstraintKind::PrimaryKey { autoincrement, .. } = &pk.unwrap().kind {
5161 assert!(autoincrement, "AUTOINCREMENT flag not set");
5162 }
5163 } else {
5164 unreachable!("expected Columns body");
5165 }
5166 } else {
5167 unreachable!("expected CreateTable");
5168 }
5169 }
5170
5171 #[test]
5172 fn test_autoincrement_uses_sqlite_sequence() {
5173 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)");
5176 if let Statement::CreateTable(ct) = stmt {
5177 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5178 assert_eq!(columns.len(), 2);
5179 let pk = columns[0].constraints.iter().find(|c| {
5180 matches!(
5181 c.kind,
5182 ColumnConstraintKind::PrimaryKey {
5183 autoincrement: true,
5184 ..
5185 }
5186 )
5187 });
5188 assert!(pk.is_some(), "AUTOINCREMENT constraint missing");
5189 } else {
5190 unreachable!("expected Columns body");
5191 }
5192 } else {
5193 unreachable!("expected CreateTable");
5194 }
5195 }
5196
5197 #[test]
5198 fn test_column_not_null() {
5199 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL)");
5200 if let Statement::CreateTable(ct) = stmt {
5201 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5202 let nn = columns[0]
5203 .constraints
5204 .iter()
5205 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
5206 assert!(nn.is_some(), "NOT NULL constraint missing");
5207 } else {
5208 unreachable!("expected Columns body");
5209 }
5210 } else {
5211 unreachable!("expected CreateTable");
5212 }
5213 }
5214
5215 #[test]
5216 fn test_column_unique() {
5217 let stmt = parse_one("CREATE TABLE t (email TEXT UNIQUE)");
5218 if let Statement::CreateTable(ct) = stmt {
5219 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5220 let uq = columns[0]
5221 .constraints
5222 .iter()
5223 .find(|c| matches!(c.kind, ColumnConstraintKind::Unique { .. }));
5224 assert!(uq.is_some(), "UNIQUE constraint missing");
5225 } else {
5226 unreachable!("expected Columns body");
5227 }
5228 } else {
5229 unreachable!("expected CreateTable");
5230 }
5231 }
5232
5233 #[test]
5234 fn test_column_check() {
5235 let stmt = parse_one("CREATE TABLE t (age INTEGER CHECK(age >= 0 AND age < 200))");
5236 if let Statement::CreateTable(ct) = stmt {
5237 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5238 let chk = columns[0]
5239 .constraints
5240 .iter()
5241 .find(|c| matches!(c.kind, ColumnConstraintKind::Check(_)));
5242 assert!(chk.is_some(), "CHECK constraint missing");
5243 } else {
5244 unreachable!("expected Columns body");
5245 }
5246 } else {
5247 unreachable!("expected CreateTable");
5248 }
5249 }
5250
5251 #[test]
5252 fn test_column_default_literal() {
5253 let stmt = parse_one("CREATE TABLE t (status TEXT DEFAULT 'active')");
5254 if let Statement::CreateTable(ct) = stmt {
5255 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5256 let def = columns[0]
5257 .constraints
5258 .iter()
5259 .find(|c| matches!(c.kind, ColumnConstraintKind::Default(_)));
5260 assert!(def.is_some(), "DEFAULT constraint missing");
5261 } else {
5262 unreachable!("expected Columns body");
5263 }
5264 } else {
5265 unreachable!("expected CreateTable");
5266 }
5267 }
5268
5269 #[test]
5270 fn test_column_default_expr() {
5271 let stmt = parse_one("CREATE TABLE t (created_at TEXT DEFAULT (datetime('now')))");
5272 if let Statement::CreateTable(ct) = stmt {
5273 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5274 let def = columns[0].constraints.iter().find(|c| {
5275 matches!(
5276 c.kind,
5277 ColumnConstraintKind::Default(DefaultValue::ParenExpr(_))
5278 )
5279 });
5280 assert!(def.is_some(), "DEFAULT (expr) missing");
5281 } else {
5282 unreachable!("expected Columns body");
5283 }
5284 } else {
5285 unreachable!("expected CreateTable");
5286 }
5287 }
5288
5289 #[test]
5290 fn test_column_collate() {
5291 let stmt = parse_one("CREATE TABLE t (name TEXT COLLATE NOCASE)");
5292 if let Statement::CreateTable(ct) = stmt {
5293 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5294 let coll = columns[0]
5295 .constraints
5296 .iter()
5297 .find(|c| matches!(c.kind, ColumnConstraintKind::Collate(_)));
5298 assert!(coll.is_some(), "COLLATE constraint missing");
5299 if let ColumnConstraintKind::Collate(name) = &coll.unwrap().kind {
5300 assert_eq!(name, "NOCASE");
5301 }
5302 } else {
5303 unreachable!("expected Columns body");
5304 }
5305 } else {
5306 unreachable!("expected CreateTable");
5307 }
5308 }
5309
5310 #[test]
5311 fn test_table_constraint_composite_pk() {
5312 let stmt = parse_one("CREATE TABLE t (a INTEGER, b INTEGER, PRIMARY KEY (a, b))");
5313 if let Statement::CreateTable(ct) = stmt {
5314 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5315 let pk = constraints
5316 .iter()
5317 .find(|c| matches!(c.kind, TableConstraintKind::PrimaryKey { .. }));
5318 assert!(pk.is_some(), "composite PK missing");
5319 if let TableConstraintKind::PrimaryKey { columns, .. } = &pk.unwrap().kind {
5320 assert_eq!(columns.len(), 2);
5321 }
5322 } else {
5323 unreachable!("expected Columns body");
5324 }
5325 } else {
5326 unreachable!("expected CreateTable");
5327 }
5328 }
5329
5330 #[test]
5331 fn test_table_constraint_composite_unique() {
5332 let stmt = parse_one("CREATE TABLE t (a TEXT, b TEXT, UNIQUE (a, b))");
5333 if let Statement::CreateTable(ct) = stmt {
5334 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5335 let uq = constraints
5336 .iter()
5337 .find(|c| matches!(c.kind, TableConstraintKind::Unique { .. }));
5338 assert!(uq.is_some(), "composite UNIQUE missing");
5339 if let TableConstraintKind::Unique { columns, .. } = &uq.unwrap().kind {
5340 assert_eq!(columns.len(), 2);
5341 }
5342 } else {
5343 unreachable!("expected Columns body");
5344 }
5345 } else {
5346 unreachable!("expected CreateTable");
5347 }
5348 }
5349
5350 #[test]
5351 fn test_table_constraint_check() {
5352 let stmt = parse_one(
5353 "CREATE TABLE t (start_date TEXT, end_date TEXT, CHECK (start_date < end_date))",
5354 );
5355 if let Statement::CreateTable(ct) = stmt {
5356 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
5357 let chk = constraints
5358 .iter()
5359 .find(|c| matches!(c.kind, TableConstraintKind::Check(_)));
5360 assert!(chk.is_some(), "table CHECK constraint missing");
5361 } else {
5362 unreachable!("expected Columns body");
5363 }
5364 } else {
5365 unreachable!("expected CreateTable");
5366 }
5367 }
5368
5369 #[test]
5370 fn test_foreign_key_on_delete_cascade() {
5371 let stmt = parse_one(
5372 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5373 REFERENCES parent(id) ON DELETE CASCADE)",
5374 );
5375 if let Statement::CreateTable(ct) = stmt {
5376 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5377 let fk = columns[1]
5378 .constraints
5379 .iter()
5380 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)));
5381 assert!(fk.is_some(), "FK constraint missing");
5382 if let ColumnConstraintKind::ForeignKey(clause) = &fk.unwrap().kind {
5383 assert_eq!(clause.table, "parent");
5384 let del = clause
5385 .actions
5386 .iter()
5387 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5388 assert!(del.is_some());
5389 assert_eq!(del.unwrap().action, ForeignKeyActionType::Cascade);
5390 }
5391 } else {
5392 unreachable!("expected Columns body");
5393 }
5394 } else {
5395 unreachable!("expected CreateTable");
5396 }
5397 }
5398
5399 #[test]
5400 fn test_foreign_key_on_delete_set_null() {
5401 let stmt = parse_one(
5402 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5403 REFERENCES parent(id) ON DELETE SET NULL)",
5404 );
5405 if let Statement::CreateTable(ct) = stmt {
5406 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5407 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5408 .constraints
5409 .iter()
5410 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5411 .unwrap()
5412 .kind
5413 {
5414 let del = clause
5415 .actions
5416 .iter()
5417 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5418 assert_eq!(del.unwrap().action, ForeignKeyActionType::SetNull);
5419 }
5420 } else {
5421 unreachable!("expected Columns body");
5422 }
5423 } else {
5424 unreachable!("expected CreateTable");
5425 }
5426 }
5427
5428 #[test]
5429 fn test_foreign_key_on_update_cascade() {
5430 let stmt = parse_one(
5431 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5432 REFERENCES parent(id) ON UPDATE CASCADE)",
5433 );
5434 if let Statement::CreateTable(ct) = stmt {
5435 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5436 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5437 .constraints
5438 .iter()
5439 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5440 .unwrap()
5441 .kind
5442 {
5443 let upd = clause
5444 .actions
5445 .iter()
5446 .find(|a| a.trigger == ForeignKeyTrigger::OnUpdate);
5447 assert!(upd.is_some());
5448 assert_eq!(upd.unwrap().action, ForeignKeyActionType::Cascade);
5449 }
5450 } else {
5451 unreachable!("expected Columns body");
5452 }
5453 } else {
5454 unreachable!("expected CreateTable");
5455 }
5456 }
5457
5458 #[test]
5459 fn test_foreign_key_restrict() {
5460 let stmt = parse_one(
5461 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5462 REFERENCES parent(id) ON DELETE RESTRICT)",
5463 );
5464 if let Statement::CreateTable(ct) = stmt {
5465 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5466 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5467 .constraints
5468 .iter()
5469 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5470 .unwrap()
5471 .kind
5472 {
5473 let del = clause
5474 .actions
5475 .iter()
5476 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
5477 assert_eq!(del.unwrap().action, ForeignKeyActionType::Restrict);
5478 }
5479 } else {
5480 unreachable!("expected Columns body");
5481 }
5482 } else {
5483 unreachable!("expected CreateTable");
5484 }
5485 }
5486
5487 #[test]
5488 fn test_foreign_key_deferred() {
5489 let stmt = parse_one(
5490 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5491 REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED)",
5492 );
5493 if let Statement::CreateTable(ct) = stmt {
5494 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5495 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5496 .constraints
5497 .iter()
5498 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5499 .unwrap()
5500 .kind
5501 {
5502 let def = clause.deferrable.as_ref().expect("DEFERRABLE missing");
5503 assert!(!def.not, "should be DEFERRABLE, not NOT DEFERRABLE");
5504 assert_eq!(def.initially, Some(DeferrableInitially::Deferred));
5505 }
5506 } else {
5507 unreachable!("expected Columns body");
5508 }
5509 } else {
5510 unreachable!("expected CreateTable");
5511 }
5512 }
5513
5514 #[test]
5515 fn test_foreign_key_pragma_required() {
5516 let stmt = parse_one(
5519 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
5520 REFERENCES parent(id) ON DELETE CASCADE ON UPDATE SET NULL)",
5521 );
5522 if let Statement::CreateTable(ct) = stmt {
5523 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5524 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
5525 .constraints
5526 .iter()
5527 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
5528 .unwrap()
5529 .kind
5530 {
5531 assert_eq!(clause.actions.len(), 2);
5532 }
5533 } else {
5534 unreachable!("expected Columns body");
5535 }
5536 } else {
5537 unreachable!("expected CreateTable");
5538 }
5539 }
5540
5541 #[test]
5542 fn test_conflict_clause_on_not_null() {
5543 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL ON CONFLICT IGNORE)");
5544 if let Statement::CreateTable(ct) = stmt {
5545 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5546 let nn = columns[0]
5547 .constraints
5548 .iter()
5549 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
5550 if let ColumnConstraintKind::NotNull { conflict } = &nn.unwrap().kind {
5551 assert_eq!(*conflict, Some(ConflictAction::Ignore));
5552 }
5553 } else {
5554 unreachable!("expected Columns body");
5555 }
5556 } else {
5557 unreachable!("expected CreateTable");
5558 }
5559 }
5560
5561 #[test]
5562 fn test_without_rowid_table() {
5563 let stmt = parse_one("CREATE TABLE t (k TEXT PRIMARY KEY, v BLOB) WITHOUT ROWID");
5564 if let Statement::CreateTable(ct) = stmt {
5565 assert!(ct.without_rowid);
5566 } else {
5567 unreachable!("expected CreateTable");
5568 }
5569 }
5570
5571 #[test]
5572 fn test_without_rowid_no_autoincrement() {
5573 let stmt = parse_one(
5576 "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT) WITHOUT ROWID",
5577 );
5578 if let Statement::CreateTable(ct) = stmt {
5579 assert!(ct.without_rowid);
5580 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5581 let pk = columns[0].constraints.iter().find(|c| {
5582 matches!(
5583 c.kind,
5584 ColumnConstraintKind::PrimaryKey {
5585 autoincrement: true,
5586 ..
5587 }
5588 )
5589 });
5590 assert!(pk.is_some());
5591 } else {
5592 unreachable!("expected Columns body");
5593 }
5594 } else {
5595 unreachable!("expected CreateTable");
5596 }
5597 }
5598
5599 #[test]
5600 fn test_without_rowid_integer_pk_not_alias() {
5601 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT) WITHOUT ROWID");
5604 if let Statement::CreateTable(ct) = stmt {
5605 assert!(ct.without_rowid);
5606 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5607 assert_eq!(columns[0].name, "id");
5608 assert!(columns[0].type_name.is_some());
5609 } else {
5610 unreachable!("expected Columns body");
5611 }
5612 } else {
5613 unreachable!("expected CreateTable");
5614 }
5615 }
5616
5617 #[test]
5618 fn test_strict_table_type_enforcement() {
5619 let stmt = parse_one("CREATE TABLE t (id INTEGER, name TEXT, score REAL) STRICT");
5622 if let Statement::CreateTable(ct) = stmt {
5623 assert!(ct.strict);
5624 assert!(!ct.without_rowid);
5625 } else {
5626 unreachable!("expected CreateTable");
5627 }
5628 }
5629
5630 #[test]
5631 fn test_strict_table_any_column() {
5632 let stmt = parse_one("CREATE TABLE t (id INTEGER, data ANY) STRICT");
5634 if let Statement::CreateTable(ct) = stmt {
5635 assert!(ct.strict);
5636 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5637 let tn = columns[1].type_name.as_ref().expect("type name");
5638 assert_eq!(tn.name, "ANY");
5639 } else {
5640 unreachable!("expected Columns body");
5641 }
5642 } else {
5643 unreachable!("expected CreateTable");
5644 }
5645 }
5646
5647 #[test]
5648 fn test_strict_allowed_types() {
5649 let stmt =
5651 parse_one("CREATE TABLE t (a INT, b INTEGER, c REAL, d TEXT, e BLOB, f ANY) STRICT");
5652 if let Statement::CreateTable(ct) = stmt {
5653 assert!(ct.strict);
5654 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5655 assert_eq!(columns.len(), 6);
5656 let types: Vec<&str> = columns
5657 .iter()
5658 .map(|c| c.type_name.as_ref().unwrap().name.as_str())
5659 .collect();
5660 assert_eq!(types, vec!["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
5661 } else {
5662 unreachable!("expected Columns body");
5663 }
5664 } else {
5665 unreachable!("expected CreateTable");
5666 }
5667 }
5668
5669 #[test]
5670 fn test_generated_col_virtual() {
5671 let stmt = parse_one(
5672 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a + b) VIRTUAL)",
5673 );
5674 if let Statement::CreateTable(ct) = stmt {
5675 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5676 let generated = columns[2]
5677 .constraints
5678 .iter()
5679 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5680 assert!(generated.is_some(), "Generated constraint missing");
5681 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5682 assert_eq!(*storage, Some(GeneratedStorage::Virtual));
5683 }
5684 } else {
5685 unreachable!("expected Columns body");
5686 }
5687 } else {
5688 unreachable!("expected CreateTable");
5689 }
5690 }
5691
5692 #[test]
5693 fn test_generated_col_stored() {
5694 let stmt = parse_one(
5695 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a * b) STORED)",
5696 );
5697 if let Statement::CreateTable(ct) = stmt {
5698 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5699 let generated = columns[2]
5700 .constraints
5701 .iter()
5702 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5703 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5704 assert_eq!(*storage, Some(GeneratedStorage::Stored));
5705 }
5706 } else {
5707 unreachable!("expected Columns body");
5708 }
5709 } else {
5710 unreachable!("expected CreateTable");
5711 }
5712 }
5713
5714 #[test]
5715 fn test_generated_col_ordering() {
5716 let stmt = parse_one(
5719 "CREATE TABLE t (\
5720 a INTEGER, \
5721 b INTEGER GENERATED ALWAYS AS (a + 1) STORED, \
5722 c INTEGER GENERATED ALWAYS AS (b * 2) VIRTUAL)",
5723 );
5724 if let Statement::CreateTable(ct) = stmt {
5725 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5726 assert_eq!(columns.len(), 3);
5727 let gen_b = columns[1]
5729 .constraints
5730 .iter()
5731 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5732 let gen_c = columns[2]
5733 .constraints
5734 .iter()
5735 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5736 assert!(gen_b, "column b should be generated");
5737 assert!(gen_c, "column c should be generated");
5738 } else {
5739 unreachable!("expected Columns body");
5740 }
5741 } else {
5742 unreachable!("expected CreateTable");
5743 }
5744 }
5745
5746 #[test]
5747 fn test_generated_col_stored_indexable() {
5748 let stmts = parse_ok(
5751 "CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED); \
5752 CREATE INDEX idx_b ON t (b)",
5753 );
5754 assert_eq!(stmts.len(), 2);
5755 assert!(matches!(stmts[0], Statement::CreateTable(_)));
5756 assert!(matches!(stmts[1], Statement::CreateIndex(_)));
5757 }
5758
5759 #[test]
5760 fn test_type_affinity_int() {
5761 let stmt = parse_one("CREATE TABLE t (a INTEGER, b BIGINT, c SMALLINT, d MEDIUMINT)");
5764 if let Statement::CreateTable(ct) = stmt {
5765 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5766 assert_eq!(columns.len(), 4);
5767 for col in columns {
5768 let tn = col.type_name.as_ref().unwrap();
5769 assert!(tn.name.contains("INT"), "{} should contain INT", tn.name);
5770 }
5771 } else {
5772 unreachable!("expected Columns body");
5773 }
5774 } else {
5775 unreachable!("expected CreateTable");
5776 }
5777 }
5778
5779 #[test]
5780 fn test_type_affinity_text() {
5781 let stmt = parse_one("CREATE TABLE t (a TEXT, b VARCHAR, c CLOB, d CHARACTER)");
5782 if let Statement::CreateTable(ct) = stmt {
5783 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5784 assert_eq!(columns.len(), 4);
5785 for col in columns {
5786 assert!(col.type_name.is_some());
5787 }
5788 } else {
5789 unreachable!("expected Columns body");
5790 }
5791 } else {
5792 unreachable!("expected CreateTable");
5793 }
5794 }
5795
5796 #[test]
5797 fn test_type_affinity_blob() {
5798 let stmt = parse_one("CREATE TABLE t (a BLOB, b)");
5799 if let Statement::CreateTable(ct) = stmt {
5800 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5801 assert_eq!(columns.len(), 2);
5802 assert_eq!(columns[0].type_name.as_ref().unwrap().name, "BLOB");
5803 assert!(columns[1].type_name.is_none());
5805 } else {
5806 unreachable!("expected Columns body");
5807 }
5808 } else {
5809 unreachable!("expected CreateTable");
5810 }
5811 }
5812
5813 #[test]
5814 fn test_type_affinity_real() {
5815 let stmt = parse_one("CREATE TABLE t (a REAL, b DOUBLE, c FLOAT)");
5816 if let Statement::CreateTable(ct) = stmt {
5817 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5818 assert_eq!(columns.len(), 3);
5819 for col in columns {
5820 assert!(col.type_name.is_some());
5821 }
5822 } else {
5823 unreachable!("expected Columns body");
5824 }
5825 } else {
5826 unreachable!("expected CreateTable");
5827 }
5828 }
5829
5830 #[test]
5831 fn test_type_affinity_numeric() {
5832 let stmt = parse_one("CREATE TABLE t (a NUMERIC, b DECIMAL, c BOOLEAN)");
5833 if let Statement::CreateTable(ct) = stmt {
5834 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5835 assert_eq!(columns.len(), 3);
5836 for col in columns {
5837 assert!(col.type_name.is_some());
5838 }
5839 } else {
5840 unreachable!("expected Columns body");
5841 }
5842 } else {
5843 unreachable!("expected CreateTable");
5844 }
5845 }
5846
5847 #[test]
5848 fn test_create_unique_index() {
5849 let stmt = parse_one("CREATE UNIQUE INDEX idx_email ON users (email)");
5850 if let Statement::CreateIndex(ci) = stmt {
5851 assert!(ci.unique);
5852 assert_eq!(ci.name.name, "idx_email");
5853 assert_eq!(ci.table, "users");
5854 assert_eq!(ci.columns.len(), 1);
5855 assert!(ci.where_clause.is_none());
5856 } else {
5857 unreachable!("expected CreateIndex");
5858 }
5859 }
5860
5861 #[test]
5862 fn test_partial_index() {
5863 let stmt = parse_one("CREATE INDEX idx_active ON users (name) WHERE active = 1");
5864 if let Statement::CreateIndex(ci) = stmt {
5865 assert!(!ci.unique);
5866 assert_eq!(ci.name.name, "idx_active");
5867 assert!(ci.where_clause.is_some(), "partial index WHERE missing");
5868 } else {
5869 unreachable!("expected CreateIndex");
5870 }
5871 }
5872
5873 #[test]
5874 fn test_partial_index_planner_usage() {
5875 let stmt =
5878 parse_one("CREATE INDEX idx_recent ON orders (created_at) WHERE status != 'archived'");
5879 if let Statement::CreateIndex(ci) = stmt {
5880 assert!(ci.where_clause.is_some());
5881 assert_eq!(ci.columns.len(), 1);
5882 } else {
5883 unreachable!("expected CreateIndex");
5884 }
5885 }
5886
5887 #[test]
5888 fn test_expression_index() {
5889 let stmt = parse_one("CREATE INDEX idx_lower_name ON users (lower(name))");
5890 if let Statement::CreateIndex(ci) = stmt {
5891 assert_eq!(ci.columns.len(), 1);
5892 assert!(
5894 matches!(ci.columns[0].expr, Expr::FunctionCall { .. }),
5895 "expected function call expression in index"
5896 );
5897 } else {
5898 unreachable!("expected CreateIndex");
5899 }
5900 }
5901
5902 #[test]
5903 fn test_expression_index_planner_match() {
5904 let stmt = parse_one("CREATE INDEX idx_calc ON t (a + b * 2)");
5907 if let Statement::CreateIndex(ci) = stmt {
5908 assert_eq!(ci.columns.len(), 1);
5909 assert!(
5910 matches!(ci.columns[0].expr, Expr::BinaryOp { .. }),
5911 "expected binary op in expression index"
5912 );
5913 } else {
5914 unreachable!("expected CreateIndex");
5915 }
5916 }
5917
5918 #[test]
5919 fn test_index_collate_asc_desc() {
5920 let stmt = parse_one("CREATE INDEX idx_multi ON t (a COLLATE NOCASE ASC, b DESC, c)");
5921 if let Statement::CreateIndex(ci) = stmt {
5922 assert_eq!(ci.columns.len(), 3);
5923 assert!(
5925 matches!(
5926 &ci.columns[0].expr,
5927 Expr::Collate { collation, .. } if collation == "NOCASE"
5928 ),
5929 "expected Collate expr with NOCASE"
5930 );
5931 assert_eq!(ci.columns[0].direction, Some(SortDirection::Asc));
5932 assert_eq!(ci.columns[1].direction, Some(SortDirection::Desc));
5933 assert!(ci.columns[2].direction.is_none());
5934 } else {
5935 unreachable!("expected CreateIndex");
5936 }
5937 }
5938
5939 #[test]
5944 fn test_create_view_basic() {
5945 let stmt = parse_one("CREATE VIEW v AS SELECT id, name FROM users");
5946 if let Statement::CreateView(cv) = stmt {
5947 assert_eq!(cv.name.name, "v");
5948 assert!(!cv.if_not_exists);
5949 assert!(!cv.temporary);
5950 assert!(cv.columns.is_empty());
5951 } else {
5952 unreachable!("expected CreateView");
5953 }
5954 }
5955
5956 #[test]
5957 fn test_create_view_column_aliases() {
5958 let stmt = parse_one("CREATE VIEW v (user_id, user_name) AS SELECT id, name FROM users");
5959 if let Statement::CreateView(cv) = stmt {
5960 assert_eq!(cv.columns, vec!["user_id", "user_name"]);
5961 } else {
5962 unreachable!("expected CreateView");
5963 }
5964 }
5965
5966 #[test]
5967 fn test_create_view_if_not_exists() {
5968 let stmt = parse_one("CREATE VIEW IF NOT EXISTS v AS SELECT 1");
5969 if let Statement::CreateView(cv) = stmt {
5970 assert!(cv.if_not_exists);
5971 } else {
5972 unreachable!("expected CreateView");
5973 }
5974 }
5975
5976 #[test]
5977 fn test_create_temp_view() {
5978 let stmt = parse_one("CREATE TEMP VIEW tv AS SELECT 1");
5979 if let Statement::CreateView(cv) = stmt {
5980 assert!(cv.temporary);
5981 } else {
5982 unreachable!("expected CreateView");
5983 }
5984 }
5985
5986 #[test]
5987 fn test_view_inline_expansion() {
5988 let stmt =
5991 parse_one("CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = 1");
5992 if let Statement::CreateView(cv) = stmt {
5993 assert_eq!(cv.name.name, "active_users");
5994 } else {
5995 unreachable!("expected CreateView");
5996 }
5997 }
5998
5999 #[test]
6000 fn test_view_read_only() {
6001 let stmt = parse_one("CREATE VIEW v AS SELECT * FROM t");
6004 assert!(matches!(stmt, Statement::CreateView(_)));
6005 }
6006
6007 #[test]
6008 fn test_view_with_recursive_cte() {
6009 let stmt = parse_one(
6012 "CREATE VIEW tree AS \
6013 SELECT n.id, n.parent FROM nodes n \
6014 WHERE n.parent IS NULL \
6015 UNION ALL \
6016 SELECT c.id, c.parent FROM nodes c JOIN nodes p ON c.parent = p.id",
6017 );
6018 if let Statement::CreateView(cv) = stmt {
6019 assert_eq!(cv.name.name, "tree");
6020 assert!(
6022 !cv.query.body.compounds.is_empty(),
6023 "expected compound SELECT in view"
6024 );
6025 } else {
6026 unreachable!("expected CreateView");
6027 }
6028 }
6029
6030 #[test]
6031 fn test_instead_of_trigger_on_view() {
6032 let stmt = parse_one(
6033 "CREATE TRIGGER tr INSTEAD OF INSERT ON v BEGIN \
6034 INSERT INTO t (a) VALUES (NEW.a); \
6035 END",
6036 );
6037 if let Statement::CreateTrigger(ct) = stmt {
6038 assert_eq!(ct.timing, TriggerTiming::InsteadOf);
6039 assert!(matches!(ct.event, TriggerEvent::Insert));
6040 assert_eq!(ct.table, "v");
6041 assert!(!ct.body.is_empty());
6042 } else {
6043 unreachable!("expected CreateTrigger");
6044 }
6045 }
6046
6047 #[test]
6048 fn test_trigger_before_insert() {
6049 let stmt = parse_one("CREATE TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6050 if let Statement::CreateTrigger(ct) = stmt {
6051 assert_eq!(ct.timing, TriggerTiming::Before);
6052 assert!(matches!(ct.event, TriggerEvent::Insert));
6053 } else {
6054 unreachable!("expected CreateTrigger");
6055 }
6056 }
6057
6058 #[test]
6059 fn test_trigger_after_insert() {
6060 let stmt = parse_one("CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END");
6061 if let Statement::CreateTrigger(ct) = stmt {
6062 assert_eq!(ct.timing, TriggerTiming::After);
6063 assert!(matches!(ct.event, TriggerEvent::Insert));
6064 } else {
6065 unreachable!("expected CreateTrigger");
6066 }
6067 }
6068
6069 #[test]
6070 fn test_trigger_before_update() {
6071 let stmt = parse_one("CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN SELECT OLD.a, NEW.a; END");
6072 if let Statement::CreateTrigger(ct) = stmt {
6073 assert_eq!(ct.timing, TriggerTiming::Before);
6074 assert!(matches!(ct.event, TriggerEvent::Update(_)));
6075 } else {
6076 unreachable!("expected CreateTrigger");
6077 }
6078 }
6079
6080 #[test]
6081 fn test_trigger_after_delete() {
6082 let stmt = parse_one("CREATE TRIGGER tr AFTER DELETE ON t BEGIN SELECT OLD.id; END");
6083 if let Statement::CreateTrigger(ct) = stmt {
6084 assert_eq!(ct.timing, TriggerTiming::After);
6085 assert!(matches!(ct.event, TriggerEvent::Delete));
6086 } else {
6087 unreachable!("expected CreateTrigger");
6088 }
6089 }
6090
6091 #[test]
6092 fn test_trigger_update_of_column() {
6093 let stmt =
6094 parse_one("CREATE TRIGGER tr BEFORE UPDATE OF name, email ON t BEGIN SELECT 1; END");
6095 if let Statement::CreateTrigger(ct) = stmt {
6096 if let TriggerEvent::Update(cols) = &ct.event {
6097 assert_eq!(cols, &["name", "email"]);
6098 } else {
6099 unreachable!("expected Update event with columns");
6100 }
6101 } else {
6102 unreachable!("expected CreateTrigger");
6103 }
6104 }
6105
6106 #[test]
6107 fn test_trigger_when_clause() {
6108 let stmt = parse_one(
6109 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN NEW.active = 1 BEGIN SELECT 1; END",
6110 );
6111 if let Statement::CreateTrigger(ct) = stmt {
6112 assert!(ct.when.is_some(), "WHEN clause missing");
6113 } else {
6114 unreachable!("expected CreateTrigger");
6115 }
6116 }
6117
6118 #[test]
6119 fn test_trigger_old_new_pseudo_tables() {
6120 let stmt = parse_one(
6121 "CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN \
6122 INSERT INTO log (old_val, new_val) VALUES (OLD.a, NEW.a); \
6123 END",
6124 );
6125 if let Statement::CreateTrigger(ct) = stmt {
6126 assert_eq!(ct.body.len(), 1);
6127 assert!(matches!(ct.body[0], Statement::Insert(_)));
6128 } else {
6129 unreachable!("expected CreateTrigger");
6130 }
6131 }
6132
6133 #[test]
6134 fn test_trigger_raise_abort() {
6135 let stmt = parse_one(
6136 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6137 SELECT RAISE(ABORT, 'not allowed'); \
6138 END",
6139 );
6140 if let Statement::CreateTrigger(ct) = stmt {
6141 assert_eq!(ct.body.len(), 1);
6142 } else {
6143 unreachable!("expected CreateTrigger");
6144 }
6145 }
6146
6147 #[test]
6148 fn test_trigger_raise_rollback() {
6149 let stmt = parse_one(
6150 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6151 SELECT RAISE(ROLLBACK, 'invalid'); \
6152 END",
6153 );
6154 if let Statement::CreateTrigger(ct) = stmt {
6155 assert_eq!(ct.body.len(), 1);
6156 } else {
6157 unreachable!("expected CreateTrigger");
6158 }
6159 }
6160
6161 #[test]
6162 fn test_trigger_raise_fail() {
6163 let stmt = parse_one(
6164 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6165 SELECT RAISE(FAIL, 'bad data'); \
6166 END",
6167 );
6168 if let Statement::CreateTrigger(ct) = stmt {
6169 assert_eq!(ct.body.len(), 1);
6170 } else {
6171 unreachable!("expected CreateTrigger");
6172 }
6173 }
6174
6175 #[test]
6176 fn test_trigger_raise_ignore() {
6177 let stmt = parse_one(
6178 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
6179 SELECT RAISE(IGNORE); \
6180 END",
6181 );
6182 if let Statement::CreateTrigger(ct) = stmt {
6183 assert_eq!(ct.body.len(), 1);
6184 } else {
6185 unreachable!("expected CreateTrigger");
6186 }
6187 }
6188
6189 #[test]
6190 fn test_trigger_recursive() {
6191 let stmt = parse_one(
6194 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
6195 INSERT INTO t (val) VALUES (NEW.val + 1); \
6196 END",
6197 );
6198 if let Statement::CreateTrigger(ct) = stmt {
6199 assert_eq!(ct.timing, TriggerTiming::After);
6200 assert_eq!(ct.table, "t");
6201 assert_eq!(ct.body.len(), 1);
6202 } else {
6203 unreachable!("expected CreateTrigger");
6204 }
6205 }
6206
6207 #[test]
6208 fn test_trigger_max_recursion_depth() {
6209 let stmt = parse_one(
6212 "CREATE TRIGGER tr AFTER INSERT ON t \
6213 WHEN NEW.depth < 1000 BEGIN \
6214 INSERT INTO t (depth) VALUES (NEW.depth + 1); \
6215 END",
6216 );
6217 if let Statement::CreateTrigger(ct) = stmt {
6218 assert!(ct.when.is_some());
6219 assert_eq!(ct.body.len(), 1);
6220 } else {
6221 unreachable!("expected CreateTrigger");
6222 }
6223 }
6224
6225 #[test]
6226 fn test_trigger_heap_frame_stack() {
6227 let stmt = parse_one(
6230 "CREATE TRIGGER tr AFTER UPDATE ON t BEGIN \
6231 UPDATE t SET counter = counter + 1 WHERE id = NEW.parent_id; \
6232 END",
6233 );
6234 if let Statement::CreateTrigger(ct) = stmt {
6235 assert_eq!(ct.body.len(), 1);
6236 assert!(matches!(ct.body[0], Statement::Update(_)));
6237 } else {
6238 unreachable!("expected CreateTrigger");
6239 }
6240 }
6241
6242 #[test]
6243 fn test_trigger_multiple_dml() {
6244 let stmt = parse_one(
6245 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
6246 INSERT INTO audit (action) VALUES ('insert'); \
6247 UPDATE stats SET count = count + 1; \
6248 END",
6249 );
6250 if let Statement::CreateTrigger(ct) = stmt {
6251 assert_eq!(ct.body.len(), 2);
6252 assert!(matches!(ct.body[0], Statement::Insert(_)));
6253 assert!(matches!(ct.body[1], Statement::Update(_)));
6254 } else {
6255 unreachable!("expected CreateTrigger");
6256 }
6257 }
6258
6259 #[test]
6260 fn test_alter_table_rename() {
6261 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
6262 if let Statement::AlterTable(at) = stmt {
6263 assert_eq!(at.table.name, "t");
6264 assert!(matches!(at.action, AlterTableAction::RenameTo(ref n) if n == "t2"));
6265 } else {
6266 unreachable!("expected AlterTable");
6267 }
6268 }
6269
6270 #[test]
6271 fn test_alter_table_rename_column() {
6272 let stmt = parse_one("ALTER TABLE t RENAME COLUMN old_name TO new_name");
6273 if let Statement::AlterTable(at) = stmt {
6274 if let AlterTableAction::RenameColumn { old, new } = &at.action {
6275 assert_eq!(old, "old_name");
6276 assert_eq!(new, "new_name");
6277 } else {
6278 unreachable!("expected RenameColumn action");
6279 }
6280 } else {
6281 unreachable!("expected AlterTable");
6282 }
6283 }
6284
6285 #[test]
6286 fn test_alter_table_add_column() {
6287 let stmt = parse_one("ALTER TABLE t ADD COLUMN email TEXT NOT NULL DEFAULT ''");
6288 if let Statement::AlterTable(at) = stmt {
6289 if let AlterTableAction::AddColumn(col) = &at.action {
6290 assert_eq!(col.name, "email");
6291 assert!(!col.constraints.is_empty());
6292 } else {
6293 unreachable!("expected AddColumn action");
6294 }
6295 } else {
6296 unreachable!("expected AlterTable");
6297 }
6298 }
6299
6300 #[test]
6301 fn test_alter_table_remove_column() {
6302 let stmt = parse_one("ALTER TABLE t DROP COLUMN old_col");
6303 if let Statement::AlterTable(at) = stmt {
6304 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "old_col"));
6305 } else {
6306 unreachable!("expected AlterTable");
6307 }
6308 }
6309
6310 #[test]
6311 fn test_alter_remove_column_pk_fails() {
6312 let stmt = parse_one("ALTER TABLE t DROP COLUMN id");
6315 if let Statement::AlterTable(at) = stmt {
6316 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "id"));
6317 } else {
6318 unreachable!("expected AlterTable");
6319 }
6320 }
6321
6322 #[test]
6323 fn test_alter_remove_column_unique_fails() {
6324 let stmt = parse_one("ALTER TABLE t DROP COLUMN email");
6326 if let Statement::AlterTable(at) = stmt {
6327 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "email"));
6328 } else {
6329 unreachable!("expected AlterTable");
6330 }
6331 }
6332
6333 #[test]
6334 fn test_alter_remove_column_index_fails() {
6335 let stmt = parse_one("ALTER TABLE t DROP COLUMN indexed_col");
6337 if let Statement::AlterTable(at) = stmt {
6338 assert!(matches!(
6339 at.action,
6340 AlterTableAction::DropColumn(ref c) if c == "indexed_col"
6341 ));
6342 } else {
6343 unreachable!("expected AlterTable");
6344 }
6345 }
6346
6347 #[test]
6348 fn test_alter_remove_column_check_fails() {
6349 let stmt = parse_one("ALTER TABLE t DROP COLUMN checked_col");
6351 if let Statement::AlterTable(at) = stmt {
6352 assert!(matches!(
6353 at.action,
6354 AlterTableAction::DropColumn(ref c) if c == "checked_col"
6355 ));
6356 } else {
6357 unreachable!("expected AlterTable");
6358 }
6359 }
6360
6361 #[test]
6362 fn test_alter_remove_column_fk_fails() {
6363 let stmt = parse_one("ALTER TABLE t DROP COLUMN fk_col");
6365 if let Statement::AlterTable(at) = stmt {
6366 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "fk_col"));
6367 } else {
6368 unreachable!("expected AlterTable");
6369 }
6370 }
6371
6372 #[test]
6373 fn test_alter_remove_only_column_fails() {
6374 let stmt = parse_one("ALTER TABLE t DROP COLUMN only_col");
6376 if let Statement::AlterTable(at) = stmt {
6377 assert!(matches!(
6378 at.action,
6379 AlterTableAction::DropColumn(ref c) if c == "only_col"
6380 ));
6381 } else {
6382 unreachable!("expected AlterTable");
6383 }
6384 }
6385
6386 #[test]
6387 fn test_ddl_remove_table() {
6388 let stmt = parse_one("DROP TABLE t");
6389 if let Statement::Drop(d) = stmt {
6390 assert_eq!(d.object_type, DropObjectType::Table);
6391 assert!(!d.if_exists);
6392 assert_eq!(d.name.name, "t");
6393 } else {
6394 unreachable!("expected Drop");
6395 }
6396 }
6397
6398 #[test]
6399 fn test_ddl_remove_table_if_exists() {
6400 let stmt = parse_one("DROP TABLE IF EXISTS t");
6401 if let Statement::Drop(d) = stmt {
6402 assert_eq!(d.object_type, DropObjectType::Table);
6403 assert!(d.if_exists);
6404 } else {
6405 unreachable!("expected Drop");
6406 }
6407 }
6408
6409 #[test]
6410 fn test_ddl_remove_index() {
6411 let stmt = parse_one("DROP INDEX idx");
6412 if let Statement::Drop(d) = stmt {
6413 assert_eq!(d.object_type, DropObjectType::Index);
6414 assert_eq!(d.name.name, "idx");
6415 } else {
6416 unreachable!("expected Drop");
6417 }
6418 }
6419
6420 #[test]
6421 fn test_ddl_remove_view() {
6422 let stmt = parse_one("DROP VIEW v");
6423 if let Statement::Drop(d) = stmt {
6424 assert_eq!(d.object_type, DropObjectType::View);
6425 assert_eq!(d.name.name, "v");
6426 } else {
6427 unreachable!("expected Drop");
6428 }
6429 }
6430
6431 #[test]
6432 fn test_ddl_remove_trigger() {
6433 let stmt = parse_one("DROP TRIGGER tr");
6434 if let Statement::Drop(d) = stmt {
6435 assert_eq!(d.object_type, DropObjectType::Trigger);
6436 assert_eq!(d.name.name, "tr");
6437 } else {
6438 unreachable!("expected Drop");
6439 }
6440 }
6441
6442 #[test]
6448 fn test_reindex_global() {
6449 let stmt = parse_one("REINDEX");
6450 assert!(matches!(stmt, Statement::Reindex(None)));
6451 }
6452
6453 #[test]
6454 fn test_reindex_table() {
6455 let stmt = parse_one("REINDEX t");
6456 if let Statement::Reindex(Some(name)) = stmt {
6457 assert_eq!(name.name, "t");
6458 assert!(name.schema.is_none());
6459 } else {
6460 unreachable!("expected Reindex(Some), got {stmt:?}");
6461 }
6462 }
6463
6464 #[test]
6465 fn test_reindex_qualified() {
6466 let stmt = parse_one("REINDEX main.idx");
6467 if let Statement::Reindex(Some(name)) = stmt {
6468 assert_eq!(name.schema.as_deref(), Some("main"));
6469 assert_eq!(name.name, "idx");
6470 } else {
6471 unreachable!("expected Reindex(Some), got {stmt:?}");
6472 }
6473 }
6474
6475 #[test]
6476 fn test_analyze_global() {
6477 let stmt = parse_one("ANALYZE");
6478 assert!(matches!(stmt, Statement::Analyze(None)));
6479 }
6480
6481 #[test]
6482 fn test_analyze_table() {
6483 let stmt = parse_one("ANALYZE t");
6484 if let Statement::Analyze(Some(name)) = stmt {
6485 assert_eq!(name.name, "t");
6486 assert!(name.schema.is_none());
6487 } else {
6488 unreachable!("expected Analyze(Some), got {stmt:?}");
6489 }
6490 }
6491
6492 #[test]
6493 fn test_analyze_qualified() {
6494 let stmt = parse_one("ANALYZE main.t");
6495 if let Statement::Analyze(Some(name)) = stmt {
6496 assert_eq!(name.schema.as_deref(), Some("main"));
6497 assert_eq!(name.name, "t");
6498 } else {
6499 unreachable!("expected Analyze(Some), got {stmt:?}");
6500 }
6501 }
6502
6503 #[test]
6504 fn test_drop_view_if_exists() {
6505 let stmt = parse_one("DROP VIEW IF EXISTS v");
6506 if let Statement::Drop(d) = stmt {
6507 assert_eq!(d.object_type, DropObjectType::View);
6508 assert!(d.if_exists);
6509 assert_eq!(d.name.name, "v");
6510 } else {
6511 unreachable!("expected Drop");
6512 }
6513 }
6514
6515 #[test]
6516 fn test_drop_index_if_exists() {
6517 let stmt = parse_one("DROP INDEX IF EXISTS idx");
6518 if let Statement::Drop(d) = stmt {
6519 assert_eq!(d.object_type, DropObjectType::Index);
6520 assert!(d.if_exists);
6521 } else {
6522 unreachable!("expected Drop");
6523 }
6524 }
6525
6526 #[test]
6527 fn test_drop_trigger_if_exists_qualified() {
6528 let stmt = parse_one("DROP TRIGGER IF EXISTS main.tr");
6529 if let Statement::Drop(d) = stmt {
6530 assert_eq!(d.object_type, DropObjectType::Trigger);
6531 assert!(d.if_exists);
6532 assert_eq!(d.name.schema.as_deref(), Some("main"));
6533 assert_eq!(d.name.name, "tr");
6534 } else {
6535 unreachable!("expected Drop");
6536 }
6537 }
6538
6539 #[test]
6540 fn test_drop_table_qualified() {
6541 let stmt = parse_one("DROP TABLE main.t");
6542 if let Statement::Drop(d) = stmt {
6543 assert_eq!(d.name.schema.as_deref(), Some("main"));
6544 assert_eq!(d.name.name, "t");
6545 } else {
6546 unreachable!("expected Drop");
6547 }
6548 }
6549
6550 #[test]
6551 fn test_create_trigger_if_not_exists() {
6552 let stmt =
6553 parse_one("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6554 if let Statement::CreateTrigger(ct) = stmt {
6555 assert!(ct.if_not_exists);
6556 assert_eq!(ct.name.name, "tr");
6557 } else {
6558 unreachable!("expected CreateTrigger");
6559 }
6560 }
6561
6562 #[test]
6563 fn test_create_temp_trigger() {
6564 let stmt = parse_one("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6565 if let Statement::CreateTrigger(ct) = stmt {
6566 assert!(ct.temporary);
6567 assert_eq!(ct.name.name, "tr");
6568 } else {
6569 unreachable!("expected CreateTrigger");
6570 }
6571 }
6572
6573 #[test]
6574 fn test_create_view_qualified_name() {
6575 let stmt = parse_one("CREATE VIEW main.v AS SELECT 1");
6576 if let Statement::CreateView(cv) = stmt {
6577 assert_eq!(cv.name.schema.as_deref(), Some("main"));
6578 assert_eq!(cv.name.name, "v");
6579 } else {
6580 unreachable!("expected CreateView");
6581 }
6582 }
6583
6584 #[test]
6585 fn test_alter_table_qualified() {
6586 let stmt = parse_one("ALTER TABLE main.t RENAME TO u");
6587 if let Statement::AlterTable(at) = stmt {
6588 assert_eq!(at.table.schema.as_deref(), Some("main"));
6589 assert_eq!(at.table.name, "t");
6590 } else {
6591 unreachable!("expected AlterTable");
6592 }
6593 }
6594
6595 #[test]
6596 fn test_roundtrip_reindex_all() {
6597 assert_roundtrip("REINDEX");
6598 assert_roundtrip("REINDEX t");
6599 assert_roundtrip("REINDEX main.idx");
6600 }
6601
6602 #[test]
6603 fn test_roundtrip_analyze_all() {
6604 assert_roundtrip("ANALYZE");
6605 assert_roundtrip("ANALYZE t");
6606 assert_roundtrip("ANALYZE main.t");
6607 }
6608
6609 #[test]
6610 fn test_roundtrip_drop_all_types_extended() {
6611 assert_roundtrip("DROP TABLE IF EXISTS main.t");
6612 assert_roundtrip("DROP VIEW IF EXISTS v");
6613 assert_roundtrip("DROP INDEX IF EXISTS idx");
6614 assert_roundtrip("DROP TRIGGER IF EXISTS main.tr");
6615 }
6616
6617 #[test]
6618 fn test_roundtrip_create_trigger_extended() {
6619 assert_roundtrip("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6620 assert_roundtrip("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
6621 assert_roundtrip(
6622 "CREATE TRIGGER tr INSTEAD OF UPDATE ON v BEGIN INSERT INTO log VALUES (1); END",
6623 );
6624 assert_roundtrip("CREATE TRIGGER tr BEFORE UPDATE OF a, b ON t BEGIN SELECT 1; END");
6625 assert_roundtrip(
6626 "CREATE TRIGGER tr AFTER DELETE ON \"order\" BEGIN INSERT INTO log VALUES (OLD.id); END",
6627 );
6628 }
6629
6630 #[test]
6631 fn test_roundtrip_create_view_extended() {
6632 assert_roundtrip("CREATE VIEW main.v AS SELECT 1");
6633 assert_roundtrip("CREATE VIEW v(x, y, z) AS SELECT a, b, c FROM t");
6634 }
6635
6636 #[test]
6637 fn test_roundtrip_alter_table_extended() {
6638 assert_roundtrip("ALTER TABLE t RENAME COLUMN a TO b");
6639 assert_roundtrip("ALTER TABLE main.t RENAME TO u");
6640 assert_roundtrip("ALTER TABLE t ADD COLUMN c INTEGER NOT NULL DEFAULT 0");
6641 }
6642
6643 #[test]
6648 fn test_begin_deferred() {
6649 let stmt = parse_one("BEGIN DEFERRED TRANSACTION");
6650 if let Statement::Begin(b) = stmt {
6651 assert_eq!(b.mode, Some(TransactionMode::Deferred));
6652 } else {
6653 unreachable!("expected Begin");
6654 }
6655 }
6656
6657 #[test]
6658 fn test_begin_immediate() {
6659 let stmt = parse_one("BEGIN IMMEDIATE");
6660 if let Statement::Begin(b) = stmt {
6661 assert_eq!(b.mode, Some(TransactionMode::Immediate));
6662 } else {
6663 unreachable!("expected Begin");
6664 }
6665 }
6666
6667 #[test]
6668 fn test_begin_exclusive() {
6669 let stmt = parse_one("BEGIN EXCLUSIVE TRANSACTION");
6670 if let Statement::Begin(b) = stmt {
6671 assert_eq!(b.mode, Some(TransactionMode::Exclusive));
6672 } else {
6673 unreachable!("expected Begin");
6674 }
6675 }
6676
6677 #[test]
6678 fn test_begin_concurrent() {
6679 let stmt = parse_one("BEGIN CONCURRENT");
6680 if let Statement::Begin(b) = stmt {
6681 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
6682 } else {
6683 unreachable!("expected Begin");
6684 }
6685 }
6686
6687 #[test]
6688 fn test_concurrent_no_conflict() {
6689 let stmt = parse_one("BEGIN");
6692 assert!(matches!(stmt, Statement::Begin(_)));
6693 }
6694
6695 #[test]
6696 fn test_concurrent_page_conflict() {
6697 let stmts = parse_ok("BEGIN; INSERT INTO t (a) VALUES (1)");
6700 assert_eq!(stmts.len(), 2);
6701 assert!(matches!(stmts[0], Statement::Begin(_)));
6702 assert!(matches!(stmts[1], Statement::Insert(_)));
6703 }
6704
6705 #[test]
6706 fn test_commit_end_synonym() {
6707 let stmt1 = parse_one("COMMIT");
6708 assert!(matches!(stmt1, Statement::Commit));
6709 let stmt2 = parse_one("END TRANSACTION");
6710 assert!(matches!(stmt2, Statement::Commit));
6711 let stmt3 = parse_one("COMMIT TRANSACTION");
6712 assert!(matches!(stmt3, Statement::Commit));
6713 }
6714
6715 #[test]
6716 fn test_rollback() {
6717 let stmt = parse_one("ROLLBACK");
6718 if let Statement::Rollback(r) = stmt {
6719 assert!(r.to_savepoint.is_none());
6720 } else {
6721 unreachable!("expected Rollback");
6722 }
6723 }
6724
6725 #[test]
6726 fn test_savepoint_basic() {
6727 let stmt = parse_one("SAVEPOINT sp1");
6728 assert!(matches!(stmt, Statement::Savepoint(ref name) if name == "sp1"));
6729 }
6730
6731 #[test]
6732 fn test_savepoint_release() {
6733 let stmt = parse_one("RELEASE SAVEPOINT sp1");
6734 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp1"));
6735 }
6736
6737 #[test]
6738 fn test_savepoint_release_removes_later() {
6739 let stmt = parse_one("RELEASE sp2");
6742 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp2"));
6743 }
6744
6745 #[test]
6746 fn test_savepoint_rollback_to() {
6747 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
6748 if let Statement::Rollback(r) = stmt {
6749 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
6750 } else {
6751 unreachable!("expected Rollback");
6752 }
6753 }
6754
6755 #[test]
6756 fn test_savepoint_nested() {
6757 let stmts = parse_ok("SAVEPOINT sp1; SAVEPOINT sp2; SAVEPOINT sp3");
6760 assert_eq!(stmts.len(), 3);
6761 assert!(matches!(stmts[0], Statement::Savepoint(ref n) if n == "sp1"));
6762 assert!(matches!(stmts[1], Statement::Savepoint(ref n) if n == "sp2"));
6763 assert!(matches!(stmts[2], Statement::Savepoint(ref n) if n == "sp3"));
6764 }
6765
6766 #[test]
6767 fn test_savepoint_rollback_then_continue() {
6768 let stmts = parse_ok("ROLLBACK TO sp1; INSERT INTO t VALUES (1)");
6770 assert_eq!(stmts.len(), 2);
6771 assert!(matches!(stmts[0], Statement::Rollback(_)));
6772 assert!(matches!(stmts[1], Statement::Insert(_)));
6773 }
6774
6775 #[test]
6776 fn test_attach_database() {
6777 let stmt = parse_one("ATTACH DATABASE 'other.db' AS other");
6778 if let Statement::Attach(a) = stmt {
6779 assert_eq!(a.schema, "other");
6780 } else {
6781 unreachable!("expected Attach");
6782 }
6783 }
6784
6785 #[test]
6786 fn test_attach_schema_qualified_access() {
6787 let stmt = parse_one("SELECT * FROM other.t");
6789 if let Statement::Select(s) = stmt {
6790 if let SelectCore::Select { from, .. } = &s.body.select {
6791 let from = from.as_ref().expect("FROM clause");
6792 match &from.source {
6793 TableOrSubquery::Table { name, .. } => {
6794 assert_eq!(name.schema.as_deref(), Some("other"));
6795 assert_eq!(name.name, "t");
6796 }
6797 other => unreachable!("expected Table source, got {other:?}"),
6798 }
6799 } else {
6800 unreachable!("expected Select core");
6801 }
6802 } else {
6803 unreachable!("expected Select");
6804 }
6805 }
6806
6807 #[test]
6808 fn test_detach_database() {
6809 let stmt = parse_one("DETACH DATABASE other");
6810 assert!(matches!(stmt, Statement::Detach(ref name) if name == "other"));
6811 }
6812
6813 #[test]
6814 fn test_attach_max_limit() {
6815 let stmt = parse_one("ATTACH 'db11.sqlite' AS db11");
6818 if let Statement::Attach(a) = stmt {
6819 assert_eq!(a.schema, "db11");
6820 } else {
6821 unreachable!("expected Attach");
6822 }
6823 }
6824
6825 #[test]
6826 fn test_cross_database_transaction() {
6827 let stmts = parse_ok("BEGIN; INSERT INTO main.t SELECT * FROM other.t; COMMIT");
6830 assert_eq!(stmts.len(), 3);
6831 assert!(matches!(stmts[0], Statement::Begin(_)));
6832 assert!(matches!(stmts[1], Statement::Insert(_)));
6833 assert!(matches!(stmts[2], Statement::Commit));
6834 }
6835
6836 #[test]
6837 fn test_explain_returns_bytecode() {
6838 let stmt = parse_one("EXPLAIN SELECT 1");
6839 if let Statement::Explain { query_plan, stmt } = stmt {
6840 assert!(!query_plan);
6841 assert!(matches!(*stmt, Statement::Select(_)));
6842 } else {
6843 unreachable!("expected Explain");
6844 }
6845 }
6846
6847 #[test]
6848 fn test_explain_query_plan_columns() {
6849 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6850 if let Statement::Explain { query_plan, stmt } = stmt {
6851 assert!(query_plan);
6852 assert!(matches!(*stmt, Statement::Select(_)));
6853 } else {
6854 unreachable!("expected Explain");
6855 }
6856 }
6857
6858 #[test]
6859 fn test_explain_query_plan_shows_index() {
6860 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6863 if let Statement::Explain { query_plan, .. } = stmt {
6864 assert!(query_plan);
6865 } else {
6866 unreachable!("expected Explain");
6867 }
6868 }
6869
6870 #[test]
6871 fn test_explain_query_plan_tree_structure() {
6872 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id");
6875 if let Statement::Explain { query_plan, stmt } = stmt {
6876 assert!(query_plan);
6877 assert!(matches!(*stmt, Statement::Select(_)));
6878 } else {
6879 unreachable!("expected Explain");
6880 }
6881 }
6882
6883 #[test]
6888 fn test_parser_keyword_as_column_name() {
6889 let stmt = parse_one("SELECT \"order\" FROM t");
6891 assert!(matches!(stmt, Statement::Select(_)));
6892 }
6893
6894 #[test]
6895 fn test_parser_keyword_as_alias() {
6896 let stmt = parse_one("SELECT 1 AS \"limit\"");
6897 assert!(matches!(stmt, Statement::Select(_)));
6898 }
6899
6900 #[test]
6901 fn test_parser_keyword_as_table_name() {
6902 let stmt = parse_one("SELECT * FROM \"group\"");
6903 assert!(matches!(stmt, Statement::Select(_)));
6904 }
6905
6906 #[test]
6911 fn test_parser_all_statement_types() {
6912 let statements = [
6914 "SELECT 1",
6916 "INSERT INTO t VALUES (1)",
6917 "INSERT OR REPLACE INTO t VALUES (1)",
6918 "UPDATE t SET a = 1",
6919 "DELETE FROM t WHERE id = 1",
6920 "REPLACE INTO t VALUES (1)",
6921 "CREATE TABLE t (id INTEGER PRIMARY KEY)",
6923 "CREATE TEMPORARY TABLE t (id INTEGER)",
6924 "CREATE TABLE IF NOT EXISTS t (id INTEGER)",
6925 "CREATE INDEX idx ON t (a)",
6926 "CREATE UNIQUE INDEX idx ON t (a)",
6927 "CREATE VIEW v AS SELECT 1",
6928 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END",
6929 "CREATE VIRTUAL TABLE t USING fts5(a, b)",
6930 "ALTER TABLE t RENAME TO t2",
6931 "ALTER TABLE t ADD COLUMN c TEXT",
6932 "ALTER TABLE t DROP COLUMN c",
6933 "ALTER TABLE t RENAME COLUMN a TO b",
6934 "DROP TABLE t",
6935 "DROP TABLE IF EXISTS t",
6936 "DROP INDEX idx",
6937 "DROP VIEW v",
6938 "DROP TRIGGER tr",
6939 "BEGIN",
6941 "BEGIN DEFERRED",
6942 "BEGIN IMMEDIATE",
6943 "BEGIN EXCLUSIVE",
6944 "COMMIT",
6945 "END",
6946 "ROLLBACK",
6947 "SAVEPOINT sp1",
6948 "RELEASE sp1",
6949 "RELEASE SAVEPOINT sp1",
6950 "ROLLBACK TO sp1",
6951 "ROLLBACK TO SAVEPOINT sp1",
6952 "ATTACH DATABASE ':memory:' AS db2",
6954 "DETACH db2",
6955 "ANALYZE",
6956 "ANALYZE t",
6957 "VACUUM",
6958 "VACUUM INTO '/tmp/backup.db'",
6959 "REINDEX",
6960 "REINDEX t",
6961 "EXPLAIN SELECT 1",
6962 "EXPLAIN QUERY PLAN SELECT 1",
6963 "PRAGMA journal_mode",
6965 "PRAGMA journal_mode = WAL",
6966 "PRAGMA table_info(t)",
6967 ];
6968
6969 for sql in &statements {
6970 let mut p = Parser::from_sql(sql);
6971 let (stmts, errs) = p.parse_all();
6972 assert!(errs.is_empty(), "failed to parse '{sql}': {errs:?}");
6973 assert_eq!(
6974 stmts.len(),
6975 1,
6976 "expected 1 statement for '{sql}', got {}",
6977 stmts.len()
6978 );
6979 }
6980 }
6981
6982 #[test]
6987 fn test_parser_expression_precedence_mul_over_add() {
6988 let stmt = parse_one("SELECT 1 + 2 * 3");
6990 if let Statement::Select(s) = stmt {
6991 if let SelectCore::Select { columns, .. } = &s.body.select {
6992 match &columns[0] {
6993 ResultColumn::Expr { expr, .. } => {
6994 assert!(
6996 matches!(expr, Expr::BinaryOp { .. }),
6997 "expected BinaryOp, got {expr:?}"
6998 );
6999 }
7000 other => unreachable!("expected Expr column, got {other:?}"),
7001 }
7002 } else {
7003 unreachable!("expected Select core");
7004 }
7005 } else {
7006 unreachable!("expected Select");
7007 }
7008 }
7009
7010 #[test]
7015 fn test_parser_insert_on_conflict() {
7016 let stmt =
7017 parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a");
7018 if let Statement::Insert(i) = stmt {
7019 assert!(!i.upsert.is_empty());
7020 } else {
7021 unreachable!("expected Insert");
7022 }
7023 }
7024
7025 #[test]
7026 fn test_parser_insert_returning() {
7027 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING *");
7028 if let Statement::Insert(i) = stmt {
7029 assert!(!i.returning.is_empty());
7030 } else {
7031 unreachable!("expected Insert");
7032 }
7033 }
7034
7035 #[test]
7036 fn test_parser_delete_returning() {
7037 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
7038 if let Statement::Delete(d) = stmt {
7039 assert!(!d.returning.is_empty());
7040 } else {
7041 unreachable!("expected Delete");
7042 }
7043 }
7044
7045 #[test]
7046 fn test_parser_update_returning() {
7047 let stmt = parse_one("UPDATE t SET a = 1 RETURNING a, b");
7048 if let Statement::Update(u) = stmt {
7049 assert_eq!(u.returning.len(), 2);
7050 } else {
7051 unreachable!("expected Update");
7052 }
7053 }
7054
7055 #[test]
7060 fn test_parser_union() {
7061 let stmt = parse_one("SELECT 1 UNION SELECT 2");
7062 if let Statement::Select(s) = stmt {
7063 assert_eq!(s.body.compounds.len(), 1);
7064 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
7065 } else {
7066 unreachable!("expected Select");
7067 }
7068 }
7069
7070 #[test]
7071 fn test_parser_intersect() {
7072 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
7073 if let Statement::Select(s) = stmt {
7074 assert_eq!(s.body.compounds.len(), 1);
7075 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
7076 } else {
7077 unreachable!("expected Select");
7078 }
7079 }
7080
7081 #[test]
7082 fn test_parser_except() {
7083 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
7084 if let Statement::Select(s) = stmt {
7085 assert_eq!(s.body.compounds.len(), 1);
7086 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
7087 } else {
7088 unreachable!("expected Select");
7089 }
7090 }
7091
7092 #[test]
7097 fn test_parser_subquery_in_from() {
7098 let stmt = parse_one("SELECT * FROM (SELECT 1 AS x) AS sub");
7099 assert!(matches!(stmt, Statement::Select(_)));
7100 }
7101
7102 #[test]
7107 fn test_parser_create_table_all_constraints() {
7108 let stmt = parse_one(
7109 "CREATE TABLE t (\
7110 id INTEGER PRIMARY KEY AUTOINCREMENT,\
7111 name TEXT NOT NULL DEFAULT '',\
7112 email TEXT UNIQUE,\
7113 age INTEGER CHECK(age >= 0),\
7114 dept_id INTEGER REFERENCES dept(id) ON DELETE CASCADE,\
7115 CONSTRAINT pk PRIMARY KEY (id),\
7116 UNIQUE (email),\
7117 CHECK (age < 200),\
7118 FOREIGN KEY (dept_id) REFERENCES dept(id)\
7119 )",
7120 );
7121 if let Statement::CreateTable(ct) = stmt {
7122 if let CreateTableBody::Columns {
7123 columns,
7124 constraints,
7125 } = ct.body
7126 {
7127 assert_eq!(columns.len(), 5);
7128 assert!(!constraints.is_empty());
7129 } else {
7130 unreachable!("expected column defs");
7131 }
7132 } else {
7133 unreachable!("expected CreateTable");
7134 }
7135 }
7136
7137 #[test]
7142 fn test_parser_create_trigger_before_delete() {
7143 let stmt = parse_one("CREATE TRIGGER tr BEFORE DELETE ON t BEGIN SELECT 1; END");
7144 if let Statement::CreateTrigger(tr) = stmt {
7145 assert_eq!(tr.timing, TriggerTiming::Before);
7146 assert!(matches!(tr.event, TriggerEvent::Delete));
7147 } else {
7148 unreachable!("expected CreateTrigger");
7149 }
7150 }
7151
7152 #[test]
7153 fn test_parser_create_trigger_instead_of_update() {
7154 let stmt =
7155 parse_one("CREATE TRIGGER tr INSTEAD OF UPDATE OF a, b ON v BEGIN SELECT 1; END");
7156 if let Statement::CreateTrigger(tr) = stmt {
7157 assert_eq!(tr.timing, TriggerTiming::InsteadOf);
7158 if let TriggerEvent::Update(cols) = &tr.event {
7159 assert_eq!(cols.len(), 2);
7160 } else {
7161 unreachable!("expected UpdateOf event");
7162 }
7163 } else {
7164 unreachable!("expected CreateTrigger");
7165 }
7166 }
7167
7168 #[test]
7173 fn test_parser_create_view_with_columns() {
7174 let stmt = parse_one("CREATE VIEW v (a, b) AS SELECT 1, 2");
7175 if let Statement::CreateView(cv) = stmt {
7176 assert_eq!(cv.columns, vec!["a".to_owned(), "b".to_owned()]);
7177 } else {
7178 unreachable!("expected CreateView");
7179 }
7180 }
7181
7182 #[test]
7187 fn test_parser_multi_join() {
7188 let stmt = parse_one(
7189 "SELECT a.x, b.y, c.z FROM a \
7190 JOIN b ON a.id = b.a_id \
7191 LEFT JOIN c ON b.id = c.b_id \
7192 CROSS JOIN d",
7193 );
7194 if let Statement::Select(s) = stmt {
7195 if let SelectCore::Select { from, .. } = &s.body.select {
7196 let from = from.as_ref().expect("FROM clause");
7197 assert_eq!(from.joins.len(), 3);
7198 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
7199 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
7200 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
7201 } else {
7202 unreachable!("expected Select core");
7203 }
7204 } else {
7205 unreachable!("expected Select");
7206 }
7207 }
7208
7209 #[test]
7214 fn test_parser_group_by_having() {
7215 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
7216 if let Statement::Select(s) = stmt {
7217 if let SelectCore::Select {
7218 group_by, having, ..
7219 } = &s.body.select
7220 {
7221 assert!(!group_by.is_empty());
7222 assert!(having.is_some());
7223 } else {
7224 unreachable!("expected Select core");
7225 }
7226 } else {
7227 unreachable!("expected Select");
7228 }
7229 }
7230
7231 #[test]
7236 fn test_parser_error_recovery_with_span() {
7237 let sql = "SELECT 1;\nXYZZY 42;\nSELECT 3";
7239 let mut p = Parser::from_sql(sql);
7240 let (stmts, errs) = p.parse_all();
7241 assert_eq!(stmts.len(), 2, "should recover two valid statements");
7242 assert!(!errs.is_empty(), "should report at least one error");
7243
7244 let err = &errs[0];
7245 assert_eq!(err.line, 2, "error should be on line 2");
7247 assert_eq!(err.col, 1, "error should be at column 1");
7248 assert!(
7250 err.span.start < err.span.end,
7251 "error span should be non-empty"
7252 );
7253 let source_len = u32::try_from(sql.len()).unwrap();
7254 assert!(
7255 err.span.end <= source_len,
7256 "error span.end should be within source"
7257 );
7258 }
7259
7260 #[test]
7261 fn test_parser_error_span_mid_line() {
7262 let bad = Parser::from_sql("CREATE").parse_statement();
7264 assert!(bad.is_err());
7265 let err = bad.unwrap_err();
7266 assert_eq!(err.line, 1);
7267 }
7268
7269 #[test]
7274 #[allow(clippy::too_many_lines)]
7275 fn test_parser_keyword_lookup_all_150() {
7276 use crate::token::TokenKind;
7277
7278 let keywords = [
7280 "ABORT",
7281 "ACTION",
7282 "ADD",
7283 "AFTER",
7284 "ALL",
7285 "ALTER",
7286 "ALWAYS",
7287 "ANALYZE",
7288 "AND",
7289 "AS",
7290 "ASC",
7291 "ATTACH",
7292 "AUTOINCREMENT",
7293 "BEFORE",
7294 "BEGIN",
7295 "BETWEEN",
7296 "BY",
7297 "CASCADE",
7298 "CASE",
7299 "CAST",
7300 "CHECK",
7301 "COLLATE",
7302 "COLUMN",
7303 "COMMIT",
7304 "CONCURRENT",
7305 "CONFLICT",
7306 "CONSTRAINT",
7307 "CREATE",
7308 "CROSS",
7309 "CURRENT_DATE",
7310 "CURRENT_TIME",
7311 "CURRENT_TIMESTAMP",
7312 "DATABASE",
7313 "DEFAULT",
7314 "DEFERRABLE",
7315 "DEFERRED",
7316 "DELETE",
7317 "DESC",
7318 "DETACH",
7319 "DISTINCT",
7320 "DO",
7321 "DROP",
7322 "EACH",
7323 "ELSE",
7324 "END",
7325 "ESCAPE",
7326 "EXCEPT",
7327 "EXCLUDE",
7328 "EXCLUSIVE",
7329 "EXISTS",
7330 "EXPLAIN",
7331 "FAIL",
7332 "FILTER",
7333 "FIRST",
7334 "FOLLOWING",
7335 "FOR",
7336 "FOREIGN",
7337 "FROM",
7338 "FULL",
7339 "GENERATED",
7340 "GLOB",
7341 "GROUP",
7342 "GROUPS",
7343 "HAVING",
7344 "IF",
7345 "IGNORE",
7346 "IMMEDIATE",
7347 "IN",
7348 "INDEX",
7349 "INDEXED",
7350 "INITIALLY",
7351 "INNER",
7352 "INSERT",
7353 "INSTEAD",
7354 "INTERSECT",
7355 "INTO",
7356 "IS",
7357 "ISNULL",
7358 "JOIN",
7359 "KEY",
7360 "LAST",
7361 "LEFT",
7362 "LIKE",
7363 "LIMIT",
7364 "MATCH",
7365 "MATERIALIZED",
7366 "NATURAL",
7367 "NO",
7368 "NOT",
7369 "NOTHING",
7370 "NOTNULL",
7371 "NULL",
7372 "NULLS",
7373 "OF",
7374 "OFFSET",
7375 "ON",
7376 "OR",
7377 "ORDER",
7378 "OTHERS",
7379 "OUTER",
7380 "OVER",
7381 "PARTITION",
7382 "PLAN",
7383 "PRAGMA",
7384 "PRECEDING",
7385 "PRIMARY",
7386 "QUERY",
7387 "RAISE",
7388 "RANGE",
7389 "RECURSIVE",
7390 "REFERENCES",
7391 "REGEXP",
7392 "REINDEX",
7393 "RELEASE",
7394 "RENAME",
7395 "REPLACE",
7396 "RESTRICT",
7397 "RETURNING",
7398 "RIGHT",
7399 "ROLLBACK",
7400 "ROW",
7401 "ROWS",
7402 "SAVEPOINT",
7403 "SELECT",
7404 "SET",
7405 "STORED",
7406 "STRICT",
7407 "TABLE",
7408 "TEMP",
7409 "TEMPORARY",
7410 "THEN",
7411 "TIES",
7412 "TO",
7413 "TRANSACTION",
7414 "TRIGGER",
7415 "TRUE",
7416 "FALSE",
7417 "UNBOUNDED",
7418 "UNION",
7419 "UNIQUE",
7420 "UPDATE",
7421 "USING",
7422 "VACUUM",
7423 "VALUES",
7424 "VIEW",
7425 "VIRTUAL",
7426 "WHEN",
7427 "WHERE",
7428 "WINDOW",
7429 "WITH",
7430 "WITHOUT",
7431 ];
7432
7433 assert!(
7434 keywords.len() >= 150,
7435 "expected 150+ keywords, got {}",
7436 keywords.len()
7437 );
7438
7439 for kw in &keywords {
7440 assert!(
7441 TokenKind::lookup_keyword(kw).is_some(),
7442 "keyword {kw} not recognized (uppercase)"
7443 );
7444 let lower = kw.to_ascii_lowercase();
7446 assert!(
7447 TokenKind::lookup_keyword(&lower).is_some(),
7448 "keyword {kw} not recognized (lowercase)"
7449 );
7450 let mixed: String = kw
7452 .chars()
7453 .enumerate()
7454 .map(|(i, c)| {
7455 if i % 2 == 0 {
7456 c.to_ascii_lowercase()
7457 } else {
7458 c.to_ascii_uppercase()
7459 }
7460 })
7461 .collect();
7462 assert!(
7463 TokenKind::lookup_keyword(&mixed).is_some(),
7464 "keyword {kw} not recognized (mixed case: {mixed})"
7465 );
7466 }
7467
7468 assert!(TokenKind::lookup_keyword("FOOBAR").is_none());
7470 assert!(TokenKind::lookup_keyword("").is_none());
7471 }
7472
7473 fn assert_roundtrip(sql: &str) {
7483 let ast1 = parse_one(sql);
7484 let rendered1 = ast1.to_string();
7485 let ast2 = parse_one(&rendered1);
7486 let rendered2 = ast2.to_string();
7487 assert_eq!(
7488 rendered1, rendered2,
7489 "round-trip failed for:\n input: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
7490 );
7491 }
7492
7493 #[test]
7494 fn test_roundtrip_select_simple() {
7495 assert_roundtrip("SELECT 1");
7496 assert_roundtrip("SELECT 1, 2, 3");
7497 assert_roundtrip("SELECT *");
7498 assert_roundtrip("SELECT * FROM t");
7499 assert_roundtrip("SELECT a, b FROM t WHERE a > 10");
7500 assert_roundtrip("SELECT a FROM t ORDER BY a DESC");
7501 assert_roundtrip("SELECT a FROM t LIMIT 10 OFFSET 5");
7502 }
7503
7504 #[test]
7505 fn test_roundtrip_select_distinct() {
7506 assert_roundtrip("SELECT DISTINCT a, b FROM t");
7507 }
7508
7509 #[test]
7510 fn test_roundtrip_select_alias() {
7511 assert_roundtrip("SELECT a AS x, b AS y FROM t AS u");
7512 }
7513
7514 #[test]
7515 fn test_roundtrip_select_join_types() {
7516 assert_roundtrip("SELECT * FROM a INNER JOIN b ON a.id = b.id");
7517 assert_roundtrip("SELECT * FROM a LEFT JOIN b ON a.id = b.id");
7518 assert_roundtrip("SELECT * FROM a RIGHT JOIN b ON a.id = b.id");
7519 assert_roundtrip("SELECT * FROM a FULL JOIN b ON a.id = b.id");
7520 assert_roundtrip("SELECT * FROM a CROSS JOIN b");
7521 assert_roundtrip("SELECT * FROM a NATURAL INNER JOIN b");
7522 assert_roundtrip("SELECT * FROM a LEFT JOIN b USING (id)");
7523 }
7524
7525 #[test]
7526 fn test_roundtrip_select_subquery() {
7527 assert_roundtrip("SELECT * FROM (SELECT 1 AS x) AS sub");
7528 }
7529
7530 #[test]
7531 fn test_roundtrip_select_group_by_having() {
7532 assert_roundtrip("SELECT a, count(*) FROM t GROUP BY a HAVING count(*) > 1");
7533 }
7534
7535 #[test]
7536 fn test_roundtrip_select_window() {
7537 assert_roundtrip("SELECT sum(x) OVER (PARTITION BY g ORDER BY x) FROM t");
7538 }
7539
7540 #[test]
7541 fn test_roundtrip_select_cte() {
7542 assert_roundtrip("WITH cte AS (SELECT 1 AS n) SELECT * FROM cte");
7543 assert_roundtrip(
7544 "WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cnt WHERE x < 10) SELECT * FROM cnt",
7545 );
7546 }
7547
7548 #[test]
7549 fn test_roundtrip_select_compound() {
7550 assert_roundtrip("SELECT 1 UNION SELECT 2");
7551 assert_roundtrip("SELECT 1 UNION ALL SELECT 2");
7552 assert_roundtrip("SELECT 1 INTERSECT SELECT 2");
7553 assert_roundtrip("SELECT 1 EXCEPT SELECT 2");
7554 }
7555
7556 #[test]
7557 fn test_roundtrip_insert() {
7558 assert_roundtrip("INSERT INTO t (a, b) VALUES (1, 2)");
7559 assert_roundtrip("INSERT INTO t DEFAULT VALUES");
7560 assert_roundtrip("INSERT INTO t SELECT * FROM u");
7561 assert_roundtrip("INSERT OR REPLACE INTO t (a) VALUES (1)");
7562 assert_roundtrip("REPLACE INTO t (a) VALUES (1)");
7563 }
7564
7565 #[test]
7566 fn test_roundtrip_insert_returning() {
7567 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING *");
7568 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING a, b");
7569 }
7570
7571 #[test]
7572 fn test_roundtrip_insert_on_conflict() {
7573 assert_roundtrip("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
7574 assert_roundtrip(
7575 "INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a",
7576 );
7577 }
7578
7579 #[test]
7580 fn test_roundtrip_update() {
7581 assert_roundtrip("UPDATE t SET a = 1");
7582 assert_roundtrip("UPDATE t SET a = 1, b = 2 WHERE c > 3");
7583 assert_roundtrip("UPDATE t SET a = 1 RETURNING *");
7584 }
7585
7586 #[test]
7587 fn test_roundtrip_delete() {
7588 assert_roundtrip("DELETE FROM t");
7589 assert_roundtrip("DELETE FROM t WHERE a = 1");
7590 assert_roundtrip("DELETE FROM t RETURNING *");
7591 }
7592
7593 #[test]
7594 fn test_roundtrip_create_table() {
7595 assert_roundtrip("CREATE TABLE t (a INTEGER, b TEXT)");
7596 assert_roundtrip("CREATE TABLE IF NOT EXISTS t (a INTEGER PRIMARY KEY)");
7597 assert_roundtrip("CREATE TEMP TABLE t (a TEXT NOT NULL, b REAL DEFAULT 0.0)");
7598 }
7599
7600 #[test]
7601 fn test_roundtrip_create_index() {
7602 assert_roundtrip("CREATE INDEX idx ON t (a)");
7603 assert_roundtrip("CREATE UNIQUE INDEX IF NOT EXISTS idx ON t (a, b DESC)");
7604 assert_roundtrip("CREATE INDEX idx ON t (a) WHERE a > 0");
7605 }
7606
7607 #[test]
7608 fn test_roundtrip_drop() {
7609 assert_roundtrip("DROP TABLE t");
7610 assert_roundtrip("DROP TABLE IF EXISTS t");
7611 assert_roundtrip("DROP INDEX idx");
7612 assert_roundtrip("DROP VIEW v");
7613 }
7614
7615 #[test]
7616 fn test_roundtrip_alter_table() {
7617 assert_roundtrip("ALTER TABLE t RENAME TO u");
7618 assert_roundtrip("ALTER TABLE t ADD COLUMN c TEXT");
7619 assert_roundtrip("ALTER TABLE t DROP COLUMN c");
7620 }
7621
7622 #[test]
7623 fn test_roundtrip_transaction() {
7624 assert_roundtrip("BEGIN");
7625 assert_roundtrip("BEGIN IMMEDIATE");
7626 assert_roundtrip("BEGIN EXCLUSIVE");
7627 assert_roundtrip("COMMIT");
7628 assert_roundtrip("ROLLBACK");
7629 assert_roundtrip("SAVEPOINT sp1");
7630 assert_roundtrip("RELEASE sp1");
7631 }
7632
7633 #[test]
7634 fn test_roundtrip_pragma() {
7635 assert_roundtrip("PRAGMA journal_mode");
7636 assert_roundtrip("PRAGMA journal_mode = wal");
7637 }
7638
7639 #[test]
7640 fn test_roundtrip_explain() {
7641 assert_roundtrip("EXPLAIN SELECT 1");
7642 assert_roundtrip("EXPLAIN QUERY PLAN SELECT * FROM t");
7643 }
7644
7645 #[test]
7646 fn test_roundtrip_expressions() {
7647 assert_roundtrip("SELECT 1 + 2 * 3");
7648 assert_roundtrip("SELECT NOT a");
7649 assert_roundtrip("SELECT -x");
7650 assert_roundtrip("SELECT ~x");
7651 assert_roundtrip("SELECT a BETWEEN 1 AND 10");
7652 assert_roundtrip("SELECT a NOT BETWEEN 1 AND 10");
7653 assert_roundtrip("SELECT a IN (1, 2, 3)");
7654 assert_roundtrip("SELECT a NOT IN (1, 2, 3)");
7655 assert_roundtrip("SELECT a LIKE '%foo%'");
7656 assert_roundtrip("SELECT a GLOB '*foo*'");
7657 assert_roundtrip("SELECT CASE WHEN a = 1 THEN 'one' ELSE 'other' END");
7658 assert_roundtrip("SELECT CASE x WHEN 1 THEN 'a' WHEN 2 THEN 'b' END");
7659 assert_roundtrip("SELECT CAST(a AS TEXT)");
7660 assert_roundtrip("SELECT EXISTS (SELECT 1)");
7661 assert_roundtrip("SELECT (SELECT 1)");
7662 assert_roundtrip("SELECT a COLLATE NOCASE");
7663 }
7664
7665 #[test]
7666 fn test_roundtrip_literals() {
7667 assert_roundtrip("SELECT NULL");
7668 assert_roundtrip("SELECT TRUE");
7669 assert_roundtrip("SELECT FALSE");
7670 assert_roundtrip("SELECT 42");
7671 assert_roundtrip("SELECT 3.14");
7672 assert_roundtrip("SELECT 'hello'");
7673 assert_roundtrip("SELECT X'DEADBEEF'");
7674 assert_roundtrip("SELECT CURRENT_TIME");
7675 assert_roundtrip("SELECT CURRENT_DATE");
7676 assert_roundtrip("SELECT CURRENT_TIMESTAMP");
7677 }
7678
7679 #[test]
7680 fn test_roundtrip_placeholders() {
7681 assert_roundtrip("SELECT ?");
7682 assert_roundtrip("SELECT ?1");
7683 assert_roundtrip("SELECT :name");
7684 assert_roundtrip("SELECT @name");
7685 assert_roundtrip("SELECT $name");
7686 }
7687
7688 #[test]
7689 fn test_roundtrip_json_arrows() {
7690 assert_roundtrip("SELECT a -> 'key'");
7691 assert_roundtrip("SELECT a ->> 'key'");
7692 }
7693
7694 #[test]
7695 fn test_roundtrip_function_calls() {
7696 assert_roundtrip("SELECT count(*)");
7697 assert_roundtrip("SELECT count(DISTINCT a)");
7698 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0)");
7699 }
7700
7701 #[test]
7702 fn test_roundtrip_isnull_notnull() {
7703 assert_roundtrip("SELECT a ISNULL");
7704 assert_roundtrip("SELECT a IS NOT NULL");
7705 }
7706
7707 #[test]
7708 fn test_roundtrip_create_view() {
7709 assert_roundtrip("CREATE VIEW v AS SELECT * FROM t");
7710 assert_roundtrip("CREATE VIEW IF NOT EXISTS v (a, b) AS SELECT 1, 2");
7711 }
7712
7713 #[test]
7714 fn test_roundtrip_create_trigger() {
7715 assert_roundtrip(
7716 "CREATE TRIGGER tr BEFORE DELETE ON t FOR EACH ROW BEGIN DELETE FROM log WHERE id = OLD.id; END",
7717 );
7718 }
7719
7720 #[test]
7721 fn test_roundtrip_attach_detach() {
7722 assert_roundtrip("ATTACH 'file.db' AS db2");
7723 assert_roundtrip("DETACH db2");
7724 }
7725
7726 #[test]
7727 fn test_roundtrip_vacuum() {
7728 assert_roundtrip("VACUUM");
7729 }
7730
7731 #[test]
7732 fn test_roundtrip_analyze_reindex() {
7733 assert_roundtrip("ANALYZE");
7734 assert_roundtrip("ANALYZE t");
7735 assert_roundtrip("REINDEX");
7736 assert_roundtrip("REINDEX t");
7737 }
7738
7739 #[test]
7740 fn test_roundtrip_cte_materialized() {
7741 assert_roundtrip("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
7742 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
7743 }
7744
7745 mod proptest_roundtrip {
7750 use super::*;
7751 use proptest::prelude::*;
7752
7753 fn is_keyword(s: &str) -> bool {
7755 TokenKind::lookup_keyword(s).is_some()
7756 }
7757
7758 fn arb_ident() -> BoxedStrategy<String> {
7760 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7761 .expect("valid regex")
7762 .prop_filter("must not be keyword", |s| !is_keyword(s))
7763 .boxed()
7764 }
7765
7766 fn arb_literal() -> BoxedStrategy<String> {
7768 prop_oneof![
7769 any::<i32>().prop_map(|n| n.to_string()),
7770 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7771 arb_ident().prop_map(|s| format!("'{s}'")),
7772 Just("NULL".to_string()),
7773 Just("TRUE".to_string()),
7774 Just("FALSE".to_string()),
7775 ]
7776 .boxed()
7777 }
7778
7779 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7781 if depth == 0 {
7782 prop_oneof![
7783 arb_literal(),
7784 arb_ident(),
7785 (arb_ident(), arb_ident()).prop_map(|(t, c)| format!("{t}.{c}")),
7786 ]
7787 .boxed()
7788 } else {
7789 let leaf = arb_expr(0);
7790 prop_oneof![
7791 4 => leaf,
7792 2 => (arb_expr(depth - 1), prop_oneof![
7794 Just("+"), Just("-"), Just("*"), Just("/"),
7795 Just("="), Just("!="), Just("<"), Just("<="),
7796 Just(">"), Just(">="), Just("AND"), Just("OR"),
7797 Just("||"),
7798 ], arb_expr(depth - 1))
7799 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7800 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7802 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7803 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NULL")),
7805 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NOT NULL")),
7806 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} ISNULL")),
7808 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} NOTNULL")),
7809 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} COLLATE nocase")),
7811 2 => (arb_expr(depth - 1), prop_oneof![
7816 Just("+"), Just("*"), Just("="), Just("<"),
7817 Just("AND"), Just("OR"), Just("||"), Just("IS"),
7818 Just("IS NOT"),
7819 ], arb_expr(depth - 1))
7820 .prop_map(|(l, op, r)| format!("{l} {op} {r}")),
7821 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7823 .prop_map(|(e, lo, hi)| format!("{e} BETWEEN {lo} AND {hi}")),
7824 1 => (arb_expr(depth - 1), proptest::collection::vec(arb_expr(0), 1..4))
7826 .prop_map(|(e, items)| format!("{e} IN ({})", items.join(", "))),
7827 1 => (arb_expr(depth - 1), arb_ident())
7829 .prop_map(|(e, p)| format!("{e} LIKE '{p}'")),
7830 1 => arb_expr(depth - 1).prop_map(|e| format!("CAST({e} AS TEXT)")),
7832 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7834 .prop_map(|(c, t, el)| format!("CASE WHEN {c} THEN {t} ELSE {el} END")),
7835 1 => (arb_ident(), proptest::collection::vec(arb_expr(0), 0..3))
7837 .prop_map(|(name, args)| format!("{name}({})", args.join(", "))),
7838 1 => arb_expr(0).prop_map(|e| format!("(SELECT {e})")),
7840 ]
7841 .boxed()
7842 }
7843 }
7844
7845 fn arb_select() -> BoxedStrategy<String> {
7847 use std::fmt::Write as _;
7848
7849 let cols =
7850 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
7851 let table = arb_ident();
7852 let where_clause = prop::option::of(arb_expr(1));
7853 let order_by = prop::option::of(arb_ident());
7854 let limit = prop::option::of(1u32..100);
7855
7856 (cols, table, where_clause, order_by, limit)
7857 .prop_map(|(cols, tbl, wh, ord, lim)| {
7858 let mut sql = format!("SELECT {cols} FROM {tbl}");
7859 if let Some(w) = wh {
7860 write!(sql, " WHERE {w}").expect("writing to String should not fail");
7861 }
7862 if let Some(o) = ord {
7863 write!(sql, " ORDER BY {o}").expect("writing to String should not fail");
7864 }
7865 if let Some(l) = lim {
7866 write!(sql, " LIMIT {l}").expect("writing to String should not fail");
7867 }
7868 sql
7869 })
7870 .boxed()
7871 }
7872
7873 fn arb_insert() -> BoxedStrategy<String> {
7875 let ncols = 1usize..4;
7876 ncols
7877 .prop_flat_map(|n| {
7878 let tbl = arb_ident();
7879 let cols = proptest::collection::vec(arb_ident(), n..=n);
7880 let vals = proptest::collection::vec(arb_literal(), n..=n);
7881 (tbl, cols, vals).prop_map(|(t, cs, vs): (String, Vec<String>, Vec<String>)| {
7882 format!(
7883 "INSERT INTO {t} ({}) VALUES ({})",
7884 cs.join(", "),
7885 vs.join(", ")
7886 )
7887 })
7888 })
7889 .boxed()
7890 }
7891
7892 fn arb_statement() -> BoxedStrategy<String> {
7894 prop_oneof![
7895 6 => arb_select(),
7896 3 => arb_insert(),
7897 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
7898 1 => (arb_ident(), arb_expr(1))
7899 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
7900 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
7901 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
7902 ]
7903 .boxed()
7904 }
7905
7906 fn try_parse_one(sql: &str) -> Option<Statement> {
7908 let mut p = Parser::from_sql(sql);
7909 let (stmts, errs) = p.parse_all();
7910 if errs.is_empty() && stmts.len() == 1 {
7911 Some(stmts.into_iter().next().unwrap())
7912 } else {
7913 None
7914 }
7915 }
7916
7917 proptest::proptest! {
7918 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
7919
7920 #[test]
7921 fn test_parser_roundtrip_proptest(sql in arb_statement()) {
7922 let Some(ast1) = try_parse_one(&sql) else {
7924 return Ok(()); };
7926
7927 let rendered1 = ast1.to_string();
7929
7930 let Some(ast2) = try_parse_one(&rendered1) else {
7932 let msg = format!("re-parse failed for rendered SQL: {rendered1:?}");
7933 prop_assert!(false, "{}", msg);
7934 unreachable!()
7935 };
7936
7937 let rendered2 = ast2.to_string();
7939 let msg = format!(
7940 "round-trip not idempotent:\n original: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
7941 );
7942 prop_assert_eq!(rendered1, rendered2, "{}", msg);
7943 }
7944 }
7945 }
7946
7947 mod proptest_properties {
7952 use super::*;
7953 use proptest::prelude::*;
7954
7955 fn arb_ident() -> BoxedStrategy<String> {
7957 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7958 .expect("valid regex")
7959 .prop_filter("must not be keyword", |s| {
7960 TokenKind::lookup_keyword(s).is_none()
7961 })
7962 .boxed()
7963 }
7964
7965 fn arb_literal() -> BoxedStrategy<String> {
7966 prop_oneof![
7967 any::<i32>().prop_map(|n| n.to_string()),
7968 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7969 arb_ident().prop_map(|s| format!("'{s}'")),
7970 Just("NULL".to_string()),
7971 Just("TRUE".to_string()),
7972 Just("FALSE".to_string()),
7973 ]
7974 .boxed()
7975 }
7976
7977 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7978 if depth == 0 {
7979 prop_oneof![arb_literal(), arb_ident(),].boxed()
7980 } else {
7981 let leaf = arb_expr(0);
7982 prop_oneof![
7983 4 => leaf,
7984 2 => (arb_expr(depth - 1), prop_oneof![
7985 Just("+"), Just("-"), Just("*"), Just("/"),
7986 Just("="), Just("!="), Just("<"), Just("<="),
7987 Just(">"), Just(">="), Just("AND"), Just("OR"),
7988 ], arb_expr(depth - 1))
7989 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7990 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7991 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7992 ]
7993 .boxed()
7994 }
7995 }
7996
7997 fn arb_select() -> BoxedStrategy<String> {
7998 use std::fmt::Write as _;
7999 let cols =
8000 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
8001 let table = arb_ident();
8002 let where_clause = prop::option::of(arb_expr(1));
8003 (cols, table, where_clause)
8004 .prop_map(|(cols, tbl, wh)| {
8005 let mut sql = format!("SELECT {cols} FROM {tbl}");
8006 if let Some(w) = wh {
8007 write!(sql, " WHERE {w}").expect("writing to String should not fail");
8008 }
8009 sql
8010 })
8011 .boxed()
8012 }
8013
8014 fn arb_statement() -> BoxedStrategy<String> {
8015 prop_oneof![
8016 6 => arb_select(),
8017 3 => {
8018 let ncols = 1usize..4;
8019 ncols
8020 .prop_flat_map(|n| {
8021 let tbl = arb_ident();
8022 let cols = proptest::collection::vec(arb_ident(), n..=n);
8023 let vals = proptest::collection::vec(arb_literal(), n..=n);
8024 (tbl, cols, vals).prop_map(
8025 |(t, cs, vs): (String, Vec<String>, Vec<String>)| {
8026 format!(
8027 "INSERT INTO {t} ({}) VALUES ({})",
8028 cs.join(", "),
8029 vs.join(", ")
8030 )
8031 },
8032 )
8033 })
8034 .boxed()
8035 },
8036 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
8037 1 => (arb_ident(), arb_expr(1))
8038 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
8039 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
8040 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
8041 ]
8042 .boxed()
8043 }
8044
8045 proptest::proptest! {
8047 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(500))]
8048
8049 #[test]
8050 fn test_parser_determinism(sql in arb_statement()) {
8051 let mut p1 = Parser::from_sql(&sql);
8052 let (stmts1, errs1) = p1.parse_all();
8053
8054 let mut p2 = Parser::from_sql(&sql);
8055 let (stmts2, errs2) = p2.parse_all();
8056
8057 let msg_stmt = format!("different statement counts for: {sql}");
8059 prop_assert_eq!(stmts1.len(), stmts2.len(), "{}", msg_stmt);
8060 let msg_err = format!("different error counts for: {sql}");
8061 prop_assert_eq!(errs1.len(), errs2.len(), "{}", msg_err);
8062
8063 if errs1.is_empty() && !stmts1.is_empty() {
8065 for (s1, s2) in stmts1.iter().zip(stmts2.iter()) {
8066 let r1 = s1.to_string();
8067 let r2 = s2.to_string();
8068 let msg_det = format!("non-deterministic parse output for: {sql}");
8069 prop_assert_eq!(r1, r2, "{}", msg_det);
8070 }
8071 }
8072 }
8073 }
8074
8075 proptest::proptest! {
8077 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(2000))]
8078
8079 #[test]
8080 fn test_parser_fuzz_no_panic(input in prop::collection::vec(any::<u8>(), 0..256)) {
8081 let sql = String::from_utf8_lossy(&input);
8082 let mut p = Parser::from_sql(&sql);
8084 let _ = p.parse_all();
8085 }
8086 }
8087
8088 proptest::proptest! {
8090 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
8091
8092 #[test]
8093 fn test_parser_fuzz_near_valid(
8094 prefix in prop_oneof![
8095 Just("SELECT "),
8096 Just("INSERT INTO "),
8097 Just("DELETE FROM "),
8098 Just("UPDATE "),
8099 Just("CREATE TABLE "),
8100 Just("DROP TABLE "),
8101 Just("BEGIN "),
8102 Just("PRAGMA "),
8103 ],
8104 suffix in prop::string::string_regex("[a-zA-Z0-9_ ,.*=<>!()'\";+\\-/]{0,100}")
8105 .expect("valid regex")
8106 ) {
8107 let sql = format!("{prefix}{suffix}");
8108 let mut p = Parser::from_sql(&sql);
8109 let _ = p.parse_all();
8110 }
8111 }
8112
8113 proptest::proptest! {
8115 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
8116
8117 #[test]
8118 fn test_parser_unicode_identifiers(
8119 name in prop::string::string_regex("[\\p{L}][\\p{L}\\p{N}_]{0,10}")
8120 .expect("valid regex")
8121 .prop_filter("must not be keyword", |s| {
8122 TokenKind::lookup_keyword(s).is_none()
8123 })
8124 ) {
8125 let sql = format!("SELECT \"{name}\" FROM \"{name}\"");
8127 let mut p = Parser::from_sql(&sql);
8128 let (stmts, errs) = p.parse_all();
8129 prop_assert!(
8130 errs.is_empty(),
8131 "Unicode identifier should parse: {sql}, errors: {errs:?}"
8132 );
8133 prop_assert_eq!(stmts.len(), 1);
8134 }
8135 }
8136
8137 proptest::proptest! {
8139 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(300))]
8140
8141 #[test]
8142 fn test_parser_rejects_incomplete_statements(
8143 kind in prop_oneof![
8144 Just("SELECT"),
8145 Just("SELECT FROM"),
8146 Just("INSERT INTO"),
8147 Just("DELETE"),
8148 Just("UPDATE SET"),
8149 Just("CREATE"),
8150 Just("CREATE TABLE"),
8151 Just("DROP"),
8152 ],
8153 trailing in prop::option::of(
8154 prop::string::string_regex("[;, ]{0,3}").expect("valid regex")
8155 )
8156 ) {
8157 let sql = match trailing {
8158 Some(t) => format!("{kind}{t}"),
8159 None => kind.to_string(),
8160 };
8161 let mut p = Parser::from_sql(&sql);
8162 let (stmts, errs) = p.parse_all();
8163 prop_assert!(
8167 !errs.is_empty() || stmts.is_empty(),
8168 "Expected rejection of incomplete SQL: {sql}, got {stmts:?}"
8169 );
8170 }
8171 }
8172
8173 proptest::proptest! {
8176 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
8177
8178 #[test]
8179 fn test_parser_multi_statement_count(
8180 stmts in proptest::collection::vec(arb_statement(), 1..4)
8181 ) {
8182 let sql = stmts.join("; ");
8183 let mut p = Parser::from_sql(&sql);
8184 let (parsed, errors) = p.parse_all();
8185 if errors.is_empty() {
8187 prop_assert!(
8188 parsed.len() >= stmts.len(),
8189 "Expected at least {} statements from: {sql}, got {}",
8190 stmts.len(),
8191 parsed.len()
8192 );
8193 }
8194 }
8195 }
8196 }
8197
8198 #[test]
8199 fn test_parse_statements_with_scratch_reuses_token_and_error_capacity() {
8200 let mut scratch = StatementParseScratch::default();
8201 let err = parse_statements_with_scratch("SELECT FROM", &mut scratch)
8202 .expect_err("malformed SQL should surface a parse error");
8203 assert!(
8204 err.message.contains("expected"),
8205 "malformed parse should preserve its diagnostic detail",
8206 );
8207 let warmed_token_capacity = scratch.token_capacity();
8208 let warmed_error_capacity = scratch.error_capacity();
8209 assert!(
8210 warmed_token_capacity > 0,
8211 "parse scratch should warm token storage"
8212 );
8213 assert!(
8214 warmed_error_capacity > 0,
8215 "parse scratch should warm error storage"
8216 );
8217
8218 let statements = parse_statements_with_scratch("SELECT 1;", &mut scratch)
8219 .expect("follow-up parse should succeed");
8220 assert_eq!(statements.len(), 1);
8221 assert_eq!(
8222 scratch.token_capacity(),
8223 warmed_token_capacity,
8224 "successful parse should reuse token scratch capacity",
8225 );
8226 assert_eq!(
8227 scratch.error_capacity(),
8228 warmed_error_capacity,
8229 "successful parse should preserve error scratch capacity for the next recovery path",
8230 );
8231 }
8232
8233 #[test]
8234 fn test_parse_statements_with_scratch_reuses_identifier_interns_across_parses() {
8235 let mut scratch = StatementParseScratch::default();
8236 let mut sql = String::from("SELECT ");
8237 for i in 0..32 {
8238 if i > 0 {
8239 sql.push_str(", ");
8240 }
8241 sql.push_str(&format!("unique_identifier_{i} AS unique_alias_{i}"));
8242 }
8243 sql.push(';');
8244
8245 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8246 .expect("identifier-heavy statement should parse");
8247 assert_eq!(statements.len(), 1);
8248 let interner_len = scratch.identifier_interner_len();
8249 assert!(
8250 interner_len > 0,
8251 "scratch should retain identifier interns for the next parse",
8252 );
8253
8254 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8255 .expect("repeat parse should also succeed");
8256 assert_eq!(statements.len(), 1);
8257 assert_eq!(
8258 scratch.identifier_interner_len(),
8259 interner_len,
8260 "repeated parse should reuse the retained interner set instead of growing it",
8261 );
8262
8263 scratch.reset();
8264 assert!(
8265 scratch.identifier_interner_is_empty(),
8266 "explicit scratch reset should also keep the interner logically empty",
8267 );
8268 }
8269
8270 #[test]
8271 fn test_parse_statements_with_scratch_drops_oversized_identifier_interner() {
8272 let mut scratch = StatementParseScratch::default();
8273 let mut sql = String::from("SELECT ");
8274 for i in 0..300 {
8275 if i > 0 {
8276 sql.push_str(", ");
8277 }
8278 sql.push_str(&format!(
8279 "very_long_unique_identifier_{i:03} AS alias_{i:03}"
8280 ));
8281 }
8282 sql.push(';');
8283
8284 let statements = parse_statements_with_scratch(&sql, &mut scratch)
8285 .expect("oversized identifier-heavy statement should parse");
8286 assert_eq!(statements.len(), 1);
8287 assert!(
8288 scratch.identifier_interner_is_empty(),
8289 "oversized identifier interners should be dropped instead of retained indefinitely",
8290 );
8291 }
8292
8293 #[test]
8297 fn create_table_quoted_reserved_word_key() {
8298 parse_ok(r#"CREATE TABLE "meta" ("key" TEXT, "val" TEXT);"#);
8300 }
8301
8302 #[test]
8303 fn create_table_unquoted_key_column() {
8304 parse_ok("CREATE TABLE meta (key TEXT, val TEXT);");
8306 }
8307
8308 #[test]
8309 fn create_table_quoted_order_column() {
8310 parse_ok(r#"CREATE TABLE t ("order" INTEGER);"#);
8312 }
8313
8314 #[test]
8315 fn create_table_quoted_select_column() {
8316 parse_ok(r#"CREATE TABLE t ("select" TEXT);"#);
8318 }
8319
8320 #[test]
8321 fn select_with_reserved_word_column_key() {
8322 parse_ok("SELECT key FROM meta;");
8324 }
8325
8326 #[test]
8327 fn select_with_reserved_word_column_value() {
8328 parse_ok("SELECT value FROM meta;");
8330 }
8331
8332 #[test]
8333 fn select_with_reserved_word_column_order() {
8334 parse_ok(r#"SELECT "order" FROM t;"#);
8336 }
8337
8338 #[test]
8339 fn where_clause_with_reserved_word_column() {
8340 parse_ok("UPDATE meta SET val = '2.0' WHERE key = 'version';");
8342 }
8343
8344 #[test]
8345 fn update_set_reserved_word_column() {
8346 parse_ok(r#"UPDATE meta SET "key" = 'newkey' WHERE "key" = 'oldkey';"#);
8348 }
8349
8350 #[test]
8351 fn delete_where_reserved_word_column() {
8352 parse_ok("DELETE FROM meta WHERE key = 'version';");
8353 }
8354
8355 #[test]
8356 fn persistence_dump_with_reserved_word_columns() {
8357 let sql = concat!(
8360 r#"CREATE TABLE "meta" ("key" TEXT, "value" TEXT);"#,
8361 "\n",
8362 r#"INSERT INTO "meta" VALUES ('version', '1.0');"#,
8363 "\n",
8364 r#"INSERT INTO "meta" VALUES ('author', 'test');"#,
8365 );
8366 let mut p = Parser::from_sql(sql);
8367 let (stmts, errs) = p.parse_all();
8368 assert!(
8369 errs.is_empty(),
8370 "persistence dump with reserved-word columns should parse cleanly: {errs:?}"
8371 );
8372 assert_eq!(stmts.len(), 3);
8373 }
8374
8375 #[test]
8376 fn create_table_with_single_quoted_name_parses_cleanly() {
8377 let sql = "CREATE TABLE 'fts_messages_data'(id INTEGER PRIMARY KEY, block BLOB);";
8378 let mut p = Parser::from_sql(sql);
8379 let (stmts, errs) = p.parse_all();
8380 assert!(
8381 errs.is_empty(),
8382 "single-quoted sqlite_master shadow-table SQL should parse cleanly: {errs:?}"
8383 );
8384 assert_eq!(stmts.len(), 1);
8385 match &stmts[0] {
8386 Statement::CreateTable(stmt) => {
8387 assert_eq!(stmt.name.name, "fts_messages_data");
8388 }
8389 other => panic!("expected CreateTable, got {other:?}"),
8390 }
8391 }
8392
8393 #[test]
8394 fn select_qualified_column_with_alias() {
8395 let stmt = parse_one("SELECT a.name AS from_name FROM users a");
8398 if let Statement::Select(s) = stmt {
8399 if let SelectCore::Select { columns, .. } = &s.body.select {
8400 assert_eq!(columns.len(), 1);
8401 match &columns[0] {
8402 ResultColumn::Expr { expr, alias } => {
8403 assert_eq!(
8405 alias.as_deref(),
8406 Some("from_name"),
8407 "alias should be 'from_name', got {alias:?}"
8408 );
8409 if let Expr::Column(col_ref, _) = expr {
8411 assert_eq!(col_ref.table.as_deref(), Some("a"));
8412 assert_eq!(col_ref.column.as_ref(), "name");
8413 } else {
8414 panic!("expected Column expression, got {expr:?}");
8415 }
8416 }
8417 other => panic!("expected Expr variant, got {other:?}"),
8418 }
8419 } else {
8420 panic!("expected Select core");
8421 }
8422 } else {
8423 panic!("expected Select statement");
8424 }
8425 }
8426
8427 #[test]
8428 fn select_qualified_column_with_implicit_alias() {
8429 let stmt = parse_one("SELECT a.name from_name FROM users a");
8431 if let Statement::Select(s) = stmt {
8432 if let SelectCore::Select { columns, .. } = &s.body.select {
8433 assert_eq!(columns.len(), 1);
8434 match &columns[0] {
8435 ResultColumn::Expr { expr, alias } => {
8436 assert_eq!(
8438 alias.as_deref(),
8439 Some("from_name"),
8440 "implicit alias should be 'from_name', got {alias:?}"
8441 );
8442 if let Expr::Column(col_ref, _) = expr {
8444 assert_eq!(col_ref.table.as_deref(), Some("a"));
8445 assert_eq!(col_ref.column.as_ref(), "name");
8446 } else {
8447 panic!("expected Column expression, got {expr:?}");
8448 }
8449 }
8450 other => panic!("expected Expr variant, got {other:?}"),
8451 }
8452 } else {
8453 panic!("expected Select core");
8454 }
8455 } else {
8456 panic!("expected Select statement");
8457 }
8458 }
8459
8460 #[test]
8461 fn select_implicit_alias_non_reserved_keyword() {
8462 let stmt = parse_one("SELECT 1 action");
8465 if let Statement::Select(s) = stmt {
8466 if let SelectCore::Select { columns, .. } = &s.body.select {
8467 if let ResultColumn::Expr { alias, .. } = &columns[0] {
8468 assert_eq!(
8469 alias.as_deref(),
8470 Some("action"),
8471 "implicit alias 'action' (keyword) failed to parse"
8472 );
8473 } else {
8474 unreachable!("expected Expr result column");
8475 }
8476 } else {
8477 unreachable!("expected Select core");
8478 }
8479 } else {
8480 unreachable!("expected Select");
8481 }
8482 }
8483}