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