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