1use std::error::Error;
7use std::fmt;
8use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
9
10use fsqlite_ast::{
11 AlterTableAction, AlterTableStatement, Assignment, AssignmentTarget, AttachStatement,
12 BeginStatement, ColumnConstraint, ColumnConstraintKind, ColumnDef, ColumnRef, ConflictAction,
13 CreateIndexStatement, CreateTableBody, CreateTableStatement, CreateTriggerStatement,
14 CreateViewStatement, CreateVirtualTableStatement, DefaultValue, Deferrable,
15 DeferrableInitially, DeleteStatement, DropObjectType, DropStatement, Expr, ForeignKeyAction,
16 ForeignKeyActionType, ForeignKeyClause, ForeignKeyTrigger, GeneratedStorage, IndexHint,
17 IndexedColumn, InsertSource, InsertStatement, JoinKind, JoinType, LimitClause, Literal,
18 NullsOrder, OrderingTerm, PragmaStatement, PragmaValue, QualifiedName, QualifiedTableRef,
19 ResultColumn, RollbackStatement, SelectCore, SelectStatement, SortDirection, Span, Statement,
20 TableConstraint, TableConstraintKind, TimeTravelClause, TimeTravelTarget, TransactionMode,
21 TriggerEvent, TriggerTiming, TypeName, UpdateStatement, UpsertAction, UpsertClause,
22 UpsertTarget, VacuumStatement, ValuesClause, WithClause,
23};
24#[cfg(test)]
25use fsqlite_ast::{
26 CompoundOp, CteMaterialized, Distinctness, FrameBound, FrameExclude, FrameSpec, FrameType,
27 FromClause, JoinClause, JoinConstraint, SelectBody, TableOrSubquery, UnaryOp,
28 ValuesRepresentation, WindowDef, WindowReference, WindowSpec,
29};
30
31#[cfg(test)]
32use crate::expr::{ParsedFrameBound, validate_frame_end, validate_frame_start};
33use crate::lexer::Lexer;
34use crate::token::{Token, TokenKind};
35
36static FSQLITE_PARSE_STATEMENTS_TOTAL: AtomicU64 = AtomicU64::new(0);
42static FSQLITE_PARSE_TOKENS_TOTAL: AtomicU64 = AtomicU64::new(0);
44static FSQLITE_PARSE_ERRORS_TOTAL: AtomicU64 = AtomicU64::new(0);
46static FSQLITE_PARSE_METRICS_ENABLED: AtomicBool = AtomicBool::new(false);
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
55pub struct ParseMetricsSnapshot {
56 pub fsqlite_parse_statements_total: u64,
58 pub fsqlite_parse_tokens_total: u64,
60 pub fsqlite_parse_errors_total: u64,
62}
63
64#[must_use]
66pub fn parse_metrics_snapshot() -> ParseMetricsSnapshot {
67 ParseMetricsSnapshot {
68 fsqlite_parse_statements_total: FSQLITE_PARSE_STATEMENTS_TOTAL.load(Ordering::Relaxed),
69 fsqlite_parse_tokens_total: FSQLITE_PARSE_TOKENS_TOTAL.load(Ordering::Relaxed),
70 fsqlite_parse_errors_total: FSQLITE_PARSE_ERRORS_TOTAL.load(Ordering::Relaxed),
71 }
72}
73
74pub fn set_parse_metrics_enabled(enabled: bool) {
76 FSQLITE_PARSE_METRICS_ENABLED.store(enabled, Ordering::Relaxed);
77}
78
79#[must_use]
81pub fn parse_metrics_enabled() -> bool {
82 FSQLITE_PARSE_METRICS_ENABLED.load(Ordering::Relaxed)
83}
84
85pub fn reset_parse_metrics() {
87 FSQLITE_PARSE_STATEMENTS_TOTAL.store(0, Ordering::Relaxed);
88 FSQLITE_PARSE_TOKENS_TOTAL.store(0, Ordering::Relaxed);
89 FSQLITE_PARSE_ERRORS_TOTAL.store(0, Ordering::Relaxed);
90}
91
92#[derive(Clone, Copy, Debug, Eq, PartialEq)]
93enum DmlParseContext {
94 TopLevel,
95 TriggerBody,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum ParseErrorKind {
104 Syntax,
105 Tokenizer,
110 UnexpectedToken,
115 Semantic,
120 ExpressionTooDeep {
121 max: u32,
122 },
123 RecursionLimit,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct ParseError {
128 pub kind: ParseErrorKind,
129 pub message: String,
130 pub span: Span,
131 pub line: u32,
132 pub col: u32,
133}
134
135impl ParseError {
136 #[must_use]
137 pub(crate) fn at(message: impl Into<String>, token: Option<&Token>) -> Self {
138 if let Some(t) = token {
139 Self {
140 kind: ParseErrorKind::Syntax,
141 message: message.into(),
142 span: t.span,
143 line: t.line,
144 col: t.col,
145 }
146 } else {
147 Self {
148 kind: ParseErrorKind::Syntax,
149 message: message.into(),
150 span: Span::ZERO,
151 line: 0,
152 col: 0,
153 }
154 }
155 }
156
157 #[must_use]
163 pub(crate) fn unexpected_at(message: impl Into<String>, token: Option<&Token>) -> Self {
164 let mut error = Self::at(message, token);
165 error.kind = ParseErrorKind::UnexpectedToken;
166 error
167 }
168
169 #[must_use]
175 pub(crate) fn semantic_at(message: impl Into<String>, token: Option<&Token>) -> Self {
176 let mut error = Self::at(message, token);
177 error.kind = ParseErrorKind::Semantic;
178 error
179 }
180
181 #[must_use]
182 pub(crate) fn expression_too_deep(max: u32, token: Option<&Token>) -> Self {
183 let mut error = Self::at(
184 format!("Expression tree is too large (maximum depth {max})"),
185 token,
186 );
187 error.kind = ParseErrorKind::ExpressionTooDeep { max };
188 error
189 }
190
191 #[must_use]
192 fn recursion_limit(token: Option<&Token>) -> Self {
193 let mut error = Self::at("parser stack overflow", token);
199 error.kind = ParseErrorKind::RecursionLimit;
200 error
201 }
202
203 #[must_use]
204 pub const fn is_expression_too_deep(&self) -> bool {
205 matches!(self.kind, ParseErrorKind::ExpressionTooDeep { .. })
206 }
207}
208
209impl fmt::Display for ParseError {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "{}:{}: {}", self.line, self.col, self.message)
212 }
213}
214
215impl Error for ParseError {}
216
217#[derive(Debug, Default)]
223pub struct StatementParseScratch {
224 tokens: Vec<Token>,
225 errors: Vec<ParseError>,
226 identifier_interner: crate::lexer::IdentifierInterner,
227}
228
229impl StatementParseScratch {
230 pub fn reset(&mut self) {
232 self.tokens.clear();
233 self.errors.clear();
234 self.identifier_interner.reset();
235 }
236
237 #[must_use]
238 pub fn token_capacity(&self) -> usize {
239 self.tokens.capacity()
240 }
241
242 #[must_use]
243 pub fn error_capacity(&self) -> usize {
244 self.errors.capacity()
245 }
246
247 #[must_use]
248 pub fn retained_bytes(&self) -> usize {
249 self.tokens
250 .capacity()
251 .saturating_mul(std::mem::size_of::<Token>())
252 .saturating_add(
253 self.errors
254 .capacity()
255 .saturating_mul(std::mem::size_of::<ParseError>()),
256 )
257 .saturating_add(self.identifier_interner.retained_bytes())
258 }
259
260 #[cfg(test)]
261 fn identifier_interner_is_empty(&self) -> bool {
262 self.identifier_interner.is_empty()
263 }
264
265 #[cfg(test)]
266 fn identifier_interner_len(&self) -> usize {
267 self.identifier_interner.len()
268 }
269}
270
271pub const MAX_PARSE_DEPTH: u32 = 1000;
281
282const MAX_NATIVE_PARSE_DEPTH: u32 = 1000;
288
289pub(crate) struct HeightTracked<T> {
290 pub(crate) value: T,
291 pub(crate) height: u32,
292}
293
294pub struct Parser {
295 pub(crate) tokens: Vec<Token>,
296 pragma_source_sql: Option<String>,
300 pub(crate) pos: usize,
301 pub(crate) errors: Vec<ParseError>,
302 pub(crate) depth: u32,
303 pub(crate) has_with: bool,
304}
305
306impl Parser {
307 #[must_use]
308 pub fn new(mut tokens: Vec<Token>) -> Self {
309 let terminal_eof = tokens
313 .last()
314 .filter(|token| matches!(token.kind, TokenKind::Eof))
315 .cloned();
316 tokens.retain(|token| !matches!(token.kind, TokenKind::Eof));
317 if let Some(eof) = terminal_eof {
318 tokens.push(eof);
319 } else {
320 let (offset, line, col) = tokens.last().map_or((0, 1, 1), |token| {
321 (
322 token.span.end,
323 token.line,
324 token.col.saturating_add(token.span.len()),
325 )
326 });
327 tokens.push(Token {
328 kind: TokenKind::Eof,
329 span: Span::new(offset, offset),
330 line,
331 col,
332 });
333 }
334 Self {
335 tokens,
336 pragma_source_sql: None,
337 pos: 0,
338 errors: Vec::new(),
339 depth: 0,
340 has_with: false,
341 }
342 }
343
344 pub(crate) fn enter_recursion(&mut self) -> Result<(), ParseError> {
345 if self.depth >= MAX_NATIVE_PARSE_DEPTH {
346 return Err(ParseError::recursion_limit(self.current()));
347 }
348 self.depth += 1;
349 Ok(())
350 }
351
352 pub(crate) fn leave_recursion(&mut self) {
353 self.depth = self.depth.saturating_sub(1);
354 }
355
356 pub(crate) fn checked_cached_parent_height(
357 &self,
358 max_child_height: u32,
359 ) -> Result<u32, ParseError> {
360 let height = max_child_height.saturating_add(1);
361 if height > MAX_PARSE_DEPTH {
362 return Err(ParseError::expression_too_deep(
363 MAX_PARSE_DEPTH,
364 self.current(),
365 ));
366 }
367 Ok(height)
368 }
369
370 pub(crate) fn with_recursion_guard<T>(
371 &mut self,
372 f: impl FnOnce(&mut Self) -> Result<T, ParseError>,
373 ) -> Result<T, ParseError> {
374 self.enter_recursion()?;
375 let result = f(self);
376 self.leave_recursion();
377 result
378 }
379
380 #[must_use]
381 pub fn from_sql(sql: &str) -> Self {
382 let mut parser = Self::new(Lexer::tokenize(sql));
383 parser.preserve_pragma_source(sql);
384 parser
385 }
386
387 fn preserve_pragma_source(&mut self, sql: &str) {
388 if self
390 .tokens
391 .iter()
392 .any(|token| token.kind == TokenKind::KwPragma)
393 {
394 self.pragma_source_sql = Some(sql.to_owned());
395 }
396 }
397
398 pub fn parse_all(&mut self) -> (Vec<Statement>, Vec<ParseError>) {
399 let parse_debug_enabled = tracing::enabled!(target: "fsqlite.parse", tracing::Level::DEBUG);
400 let collect_parse_metrics = parse_metrics_enabled();
401 if collect_parse_metrics {
402 let token_count = u64::try_from(self.tokens.len()).unwrap_or(u64::MAX);
403 FSQLITE_PARSE_TOKENS_TOTAL.fetch_add(token_count, Ordering::Relaxed);
404 }
405 let span = parse_debug_enabled.then(|| {
406 tracing::debug_span!(
407 target: "fsqlite.parse",
408 "parse",
409 ast_node_count = tracing::field::Empty,
410 parse_errors = tracing::field::Empty,
411 )
412 });
413 let _guard = span.as_ref().map(|span| span.enter());
414
415 let mut stmts = Vec::new();
416 while !self.at_eof() {
417 if self.check(&TokenKind::Semicolon) {
418 self.advance();
419 continue;
420 }
421 match self.parse_statement() {
422 Ok(s) => {
423 if collect_parse_metrics {
424 FSQLITE_PARSE_STATEMENTS_TOTAL.fetch_add(1, Ordering::Relaxed);
425 }
426 stmts.push(s);
427 if self.at_eof() || self.eat(&TokenKind::Semicolon) {
428 continue;
429 }
430
431 let error = self.err_unexpected(
432 "unexpected token after end of statement; expected ';' separator",
433 );
434 if collect_parse_metrics {
435 FSQLITE_PARSE_ERRORS_TOTAL.fetch_add(1, Ordering::Relaxed);
436 }
437 tracing::warn!(
438 target: "fsqlite.parse",
439 error = %error,
440 "parse recovery: missing statement separator"
441 );
442 self.errors.push(error);
443 self.synchronize();
444 }
445 Err(e) => {
446 if collect_parse_metrics {
447 FSQLITE_PARSE_ERRORS_TOTAL.fetch_add(1, Ordering::Relaxed);
448 }
449 tracing::warn!(
450 target: "fsqlite.parse",
451 error = %e,
452 "parse recovery: skipping malformed statement"
453 );
454 self.errors.push(e);
455 self.synchronize();
456 }
457 }
458 }
459
460 let errors = std::mem::take(&mut self.errors);
461 if let Some(span) = span.as_ref() {
462 span.record("ast_node_count", stmts.len() as u64);
463 span.record("parse_errors", errors.len() as u64);
464 }
465
466 (stmts, errors)
467 }
468
469 pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
470 self.has_with = false;
474 self.parse_statement_inner()
475 }
476
477 #[must_use]
478 pub fn errors(&self) -> &[ParseError] {
479 &self.errors
480 }
481
482 pub(crate) fn peek(&self) -> &TokenKind {
487 self.current().map_or(&TokenKind::Eof, |t| &t.kind)
488 }
489
490 pub(crate) fn current(&self) -> Option<&Token> {
491 self.tokens.get(self.pos)
492 }
493
494 pub(crate) fn peek_nth(&self, n: usize) -> &TokenKind {
495 self.tokens
496 .get(self.pos + n)
497 .map_or(&TokenKind::Eof, |t| &t.kind)
498 }
499
500 pub(crate) fn at_eof(&self) -> bool {
501 matches!(self.peek(), TokenKind::Eof)
502 }
503
504 pub(crate) fn advance(&mut self) -> Option<&Token> {
505 let t = self.tokens.get(self.pos);
506 if self.pos < self.tokens.len().saturating_sub(1) {
507 self.pos += 1;
508 }
509 t
510 }
511
512 pub(crate) fn check(&self, kind: &TokenKind) -> bool {
513 std::mem::discriminant(self.peek()) == std::mem::discriminant(kind)
514 }
515
516 pub(crate) fn check_kw(&self, kw: &TokenKind) -> bool {
517 self.peek() == kw
518 }
519
520 pub(crate) fn eat(&mut self, kind: &TokenKind) -> bool {
521 if self.check(kind) {
522 self.advance();
523 true
524 } else {
525 false
526 }
527 }
528
529 pub(crate) fn eat_kw(&mut self, kw: &TokenKind) -> bool {
530 if self.peek() == kw {
531 self.advance();
532 true
533 } else {
534 false
535 }
536 }
537
538 pub(crate) fn expect_kw(&mut self, kw: &TokenKind) -> Result<Span, ParseError> {
539 if self.peek() == kw {
540 let sp = self.current_span();
541 self.advance();
542 Ok(sp)
543 } else {
544 Err(self.err_expected(&format!("{kw:?}")))
545 }
546 }
547
548 pub(crate) fn expect_token(&mut self, kind: &TokenKind) -> Result<Span, ParseError> {
549 if self.check(kind) {
550 let sp = self.current_span();
551 self.advance();
552 Ok(sp)
553 } else {
554 Err(self.err_expected(&format!("{kind:?}")))
555 }
556 }
557
558 pub(crate) fn current_span(&self) -> Span {
559 self.current().map_or(Span::ZERO, |t| t.span)
560 }
561
562 pub(crate) fn err_expected(&self, what: &str) -> ParseError {
563 let mut error = ParseError::at(format!("expected {what}"), self.current());
568 error.kind = ParseErrorKind::UnexpectedToken;
569 error
570 }
571
572 pub(crate) fn err_msg(&self, msg: impl Into<String>) -> ParseError {
573 ParseError::at(msg, self.current())
574 }
575
576 pub(crate) fn err_unexpected(&self, msg: impl Into<String>) -> ParseError {
581 let mut error = ParseError::at(msg, self.current());
582 error.kind = ParseErrorKind::UnexpectedToken;
583 error
584 }
585
586 pub(crate) fn err_semantic(&self, msg: impl Into<String>) -> ParseError {
590 let mut error = ParseError::at(msg, self.current());
591 error.kind = ParseErrorKind::Semantic;
592 error
593 }
594
595 fn synchronize(&mut self) {
596 loop {
597 match self.peek() {
598 TokenKind::Eof => return,
599 TokenKind::Semicolon => {
600 self.advance();
601 return;
602 }
603 k if k.is_statement_start() => return,
604 _ => {
605 self.advance();
606 }
607 }
608 }
609 }
610
611 fn starts_nested_trigger_definition(&self) -> bool {
612 if !self.check_kw(&TokenKind::KwCreate) {
613 return false;
614 }
615
616 let mut offset = 1_usize;
617 while offset <= 2
618 && matches!(
619 self.peek_nth(offset),
620 TokenKind::KwTemp | TokenKind::KwTemporary | TokenKind::KwUnique
621 )
622 {
623 offset += 1;
624 }
625 self.peek_nth(offset) == &TokenKind::KwTrigger
626 }
627
628 fn recover_trigger_body_after_error(&mut self, statement_start: usize) {
629 self.pos = statement_start.min(self.tokens.len().saturating_sub(1));
633 let mut at_statement_boundary = true;
634 let mut nested_trigger_header = false;
635 let mut nested_trigger_depth = 0_usize;
636
637 loop {
638 match self.peek() {
639 TokenKind::Eof => return,
640 TokenKind::Semicolon => {
641 self.advance();
642 at_statement_boundary = true;
643 nested_trigger_header = false;
644 }
645 TokenKind::KwBegin if nested_trigger_header => {
646 nested_trigger_depth = nested_trigger_depth.saturating_add(1);
647 self.advance();
648 at_statement_boundary = true;
649 nested_trigger_header = false;
650 }
651 TokenKind::KwEnd if at_statement_boundary && nested_trigger_depth > 0 => {
652 nested_trigger_depth -= 1;
653 self.advance();
654 let _ = self.eat(&TokenKind::Semicolon);
655 at_statement_boundary = true;
656 }
657 TokenKind::KwEnd if at_statement_boundary => {
658 self.advance();
659 let _ = self.eat(&TokenKind::Semicolon);
660 return;
661 }
662 _ => {
663 if at_statement_boundary {
664 nested_trigger_header = self.starts_nested_trigger_definition();
665 }
666 self.advance();
667 at_statement_boundary = false;
668 }
669 }
670 }
671 }
672
673 pub(crate) fn parse_identifier(&mut self) -> Result<String, ParseError> {
678 match self.peek().clone() {
679 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
680 self.advance();
681 Ok(s.to_string())
682 }
683 TokenKind::String(s) => {
684 self.advance();
685 Ok(s)
686 }
687 ref k if starts_post_dot_identifier(k) => {
688 let s = kw_to_str(k);
689 self.advance();
690 Ok(s)
691 }
692 _ => Err(self.err_expected("identifier")),
693 }
694 }
695
696 pub(crate) fn parse_table_star_qualifier(&mut self) -> Result<String, ParseError> {
697 match self.peek().clone() {
698 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
699 self.advance();
700 Ok(s.to_string())
701 }
702 TokenKind::String(s) => {
703 self.advance();
704 Ok(s)
705 }
706 ref k if starts_table_star_qualifier(k) => {
707 let s = kw_to_str(k);
708 self.advance();
709 Ok(s)
710 }
711 _ => Err(self.err_expected("table-star qualifier")),
712 }
713 }
714
715 pub(crate) fn parse_window_name(&mut self) -> Result<String, ParseError> {
716 match self.peek().clone() {
717 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
718 self.advance();
719 Ok(s.to_string())
720 }
721 TokenKind::String(s) => {
722 self.advance();
723 Ok(s)
724 }
725 ref k if starts_bare_window_name(k) => {
726 let s = kw_to_str(k);
727 self.advance();
728 Ok(s)
729 }
730 _ => Err(self.err_expected("window name")),
731 }
732 }
733
734 pub(crate) fn parse_qualified_name(&mut self) -> Result<QualifiedName, ParseError> {
735 let first = self.parse_identifier()?;
736 if self.eat(&TokenKind::Dot) {
737 let second = self.parse_identifier()?;
738 Ok(QualifiedName::qualified(first, second))
739 } else {
740 Ok(QualifiedName::bare(first))
741 }
742 }
743
744 fn parse_dml_target_name(
745 &mut self,
746 context: DmlParseContext,
747 ) -> Result<QualifiedName, ParseError> {
748 let first = self.parse_identifier()?;
749 if self.check(&TokenKind::Dot) {
750 if context == DmlParseContext::TriggerBody {
751 return Err(self.err_semantic(
752 "qualified table names are not allowed on INSERT, UPDATE, and DELETE \
753 statements within triggers",
754 ));
755 }
756 self.advance();
757 let second = self.parse_identifier()?;
758 Ok(QualifiedName::qualified(first, second))
759 } else {
760 Ok(QualifiedName::bare(first))
761 }
762 }
763
764 fn parse_qualified_table_ref(
765 &mut self,
766 context: DmlParseContext,
767 ) -> Result<QualifiedTableRef, ParseError> {
768 let name = self.parse_dml_target_name(context)?;
769 let alias = if context == DmlParseContext::TriggerBody {
770 if self.eat_kw(&TokenKind::KwAs) {
771 Some(self.parse_identifier()?)
772 } else {
773 None
774 }
775 } else {
776 self.try_table_alias()?
777 };
778 if context == DmlParseContext::TriggerBody
779 && (self.check_kw(&TokenKind::KwIndexed)
780 || (self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwIndexed))
781 {
782 let clause = if self.check_kw(&TokenKind::KwIndexed) {
785 "INDEXED BY"
786 } else {
787 "NOT INDEXED"
788 };
789 return Err(self.err_semantic(format!(
790 "the {clause} clause is not allowed on UPDATE or DELETE statements within triggers"
791 )));
792 }
793 let index_hint = self.parse_index_hint()?;
794 let time_travel = self.parse_time_travel_clause()?;
795 Ok(QualifiedTableRef {
796 name,
797 alias,
798 index_hint,
799 time_travel,
800 })
801 }
802
803 fn parse_alias_name(&mut self) -> Result<String, ParseError> {
804 match self.peek().clone() {
805 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
806 self.advance();
807 Ok(s.to_string())
808 }
809 TokenKind::String(s) => {
810 self.advance();
811 Ok(s)
812 }
813 ref k if starts_explicit_alias_name(k) => {
814 let s = kw_to_str(k);
815 self.advance();
816 Ok(s)
817 }
818 _ => Err(self.err_expected("alias")),
819 }
820 }
821
822 fn starts_window_clause(&self) -> bool {
823 self.check_kw(&TokenKind::KwWindow)
824 && starts_bare_window_name(self.peek_nth(1))
825 && self.peek_nth(2) == &TokenKind::KwAs
826 }
827
828 fn starts_time_travel_clause(&self) -> bool {
829 self.check_kw(&TokenKind::KwFor)
830 && matches!(
831 self.peek_nth(1),
832 TokenKind::Id(name) if name.eq_ignore_ascii_case("SYSTEM_TIME")
833 )
834 }
835
836 pub(crate) fn try_result_alias(&mut self) -> Result<Option<String>, ParseError> {
837 if self.eat_kw(&TokenKind::KwAs) {
838 return Ok(Some(self.parse_alias_name()?));
839 }
840 if self.starts_window_clause() {
841 return Ok(None);
842 }
843 if starts_result_alias(self.peek()) {
844 return Ok(Some(self.parse_alias_name()?));
845 }
846 Ok(None)
847 }
848
849 pub(crate) fn try_table_alias(&mut self) -> Result<Option<String>, ParseError> {
850 if self.eat_kw(&TokenKind::KwAs) {
851 return Ok(Some(self.parse_alias_name()?));
852 }
853 if self.starts_window_clause() || self.starts_time_travel_clause() {
854 return Ok(None);
855 }
856 if starts_table_alias(self.peek()) {
857 return Ok(Some(self.parse_alias_name()?));
858 }
859 Ok(None)
860 }
861
862 pub(crate) fn parse_index_hint(&mut self) -> Result<Option<IndexHint>, ParseError> {
863 if self.eat_kw(&TokenKind::KwIndexed) {
864 self.expect_kw(&TokenKind::KwBy)?;
865 Ok(Some(IndexHint::IndexedBy(self.parse_identifier()?)))
866 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwIndexed {
867 self.advance();
868 self.advance();
869 Ok(Some(IndexHint::NotIndexed))
870 } else {
871 Ok(None)
872 }
873 }
874
875 pub(crate) fn parse_time_travel_clause(
883 &mut self,
884 ) -> Result<Option<TimeTravelClause>, ParseError> {
885 if !self.check_kw(&TokenKind::KwFor) {
886 return Ok(None);
887 }
888 if !matches!(self.peek_nth(1), TokenKind::Id(s) if s.eq_ignore_ascii_case("SYSTEM_TIME")) {
890 return Ok(None);
891 }
892 self.advance(); self.advance(); self.expect_kw(&TokenKind::KwAs)?;
895 self.expect_kw(&TokenKind::KwOf)?;
896
897 let target = if self.eat_kw(&TokenKind::KwCommitseq) {
898 match self.peek().clone() {
899 TokenKind::Integer(n) if n >= 0 => {
900 self.advance();
901 TimeTravelTarget::CommitSequence(n as u64)
902 }
903 TokenKind::OversizedInt(s) => {
904 if let Ok(n) = s.parse::<u64>() {
905 self.advance();
906 TimeTravelTarget::CommitSequence(n)
907 } else {
908 return Err(self.err_expected("non-negative integer after COMMITSEQ"));
909 }
910 }
911 _ => return Err(self.err_expected("non-negative integer after COMMITSEQ")),
912 }
913 } else {
914 match self.peek().clone() {
915 TokenKind::String(s) => {
916 self.advance();
917 TimeTravelTarget::Timestamp(s)
918 }
919 _ => {
920 return Err(self.err_expected(
921 "COMMITSEQ <n> or '<timestamp>' after FOR SYSTEM_TIME AS OF",
922 ));
923 }
924 }
925 };
926
927 Ok(Some(TimeTravelClause { target }))
928 }
929
930 pub(crate) fn parse_comma_sep<T>(
931 &mut self,
932 f: fn(&mut Self) -> Result<T, ParseError>,
933 ) -> Result<Vec<T>, ParseError> {
934 let mut v = Vec::with_capacity(4);
935 v.push(f(self)?);
936 while self.eat(&TokenKind::Comma) {
937 v.push(f(self)?);
938 }
939 Ok(v)
940 }
941
942 fn parse_statement_inner(&mut self) -> Result<Statement, ParseError> {
947 self.with_recursion_guard(|parser| match parser.peek().clone() {
948 TokenKind::KwSelect | TokenKind::KwValues => {
949 Ok(Statement::Select(parser.parse_select_stmt(None)?))
950 }
951 TokenKind::KwWith => parser.parse_with_leading(),
952 TokenKind::KwInsert | TokenKind::KwReplace => {
953 parser.parse_insert_stmt(None, DmlParseContext::TopLevel)
954 }
955 TokenKind::KwUpdate => parser.parse_update_stmt(None, DmlParseContext::TopLevel),
956 TokenKind::KwDelete => parser.parse_delete_stmt(None, DmlParseContext::TopLevel),
957 TokenKind::KwCreate => parser.parse_create(),
958 TokenKind::KwDrop => parser.parse_drop(),
959 TokenKind::KwAlter => parser.parse_alter(),
960 TokenKind::KwBegin => parser.parse_begin(),
961 TokenKind::KwCommit | TokenKind::KwEnd => {
962 parser.advance();
963 let _ = parser.eat_kw(&TokenKind::KwTransaction);
964 Ok(Statement::Commit)
965 }
966 TokenKind::KwRollback => parser.parse_rollback(),
967 TokenKind::KwSavepoint => {
968 parser.advance();
969 Ok(Statement::Savepoint(parser.parse_identifier()?))
970 }
971 TokenKind::KwRelease => {
972 parser.advance();
973 let _ = parser.eat_kw(&TokenKind::KwSavepoint);
974 Ok(Statement::Release(parser.parse_identifier()?))
975 }
976 TokenKind::KwAttach => parser.parse_attach(),
977 TokenKind::KwDetach => {
978 parser.advance();
979 let _ = parser.eat_kw(&TokenKind::KwDatabase);
980 Ok(Statement::Detach(parser.parse_identifier()?))
981 }
982 TokenKind::KwPragma => parser.parse_pragma(),
983 TokenKind::KwVacuum => parser.parse_vacuum(),
984 TokenKind::KwReindex => {
985 parser.advance();
986 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
987 Some(parser.parse_qualified_name()?)
988 } else {
989 None
990 };
991 Ok(Statement::Reindex(name))
992 }
993 TokenKind::KwAnalyze => {
994 parser.advance();
995 let name = if !parser.at_eof() && !parser.check(&TokenKind::Semicolon) {
996 Some(parser.parse_qualified_name()?)
997 } else {
998 None
999 };
1000 Ok(Statement::Analyze(name))
1001 }
1002 TokenKind::KwExplain => parser.parse_explain(),
1003 _ => Err(parser.err_unexpected("unexpected token at start of statement")),
1004 })
1005 }
1006
1007 fn parse_with_leading(&mut self) -> Result<Statement, ParseError> {
1012 let with = self.parse_with_clause()?;
1013 match self.peek() {
1014 TokenKind::KwSelect | TokenKind::KwValues => {
1015 Ok(Statement::Select(self.parse_select_stmt(Some(with))?))
1016 }
1017 TokenKind::KwInsert | TokenKind::KwReplace => {
1018 self.parse_insert_stmt(Some(with), DmlParseContext::TopLevel)
1019 }
1020 TokenKind::KwUpdate => self.parse_update_stmt(Some(with), DmlParseContext::TopLevel),
1021 TokenKind::KwDelete => self.parse_delete_stmt(Some(with), DmlParseContext::TopLevel),
1022 _ => Err(self.err_expected("SELECT, INSERT, UPDATE, or DELETE after WITH")),
1023 }
1024 }
1025
1026 pub(crate) fn parse_with_clause(&mut self) -> Result<WithClause, ParseError> {
1027 self.parse_with_clause_machine()
1028 }
1029
1030 pub(crate) fn parse_select_stmt(
1035 &mut self,
1036 with: Option<WithClause>,
1037 ) -> Result<SelectStatement, ParseError> {
1038 self.parse_select_stmt_tracked(with)
1039 .map(|tracked| tracked.value)
1040 }
1041
1042 pub(crate) fn parse_select_stmt_tracked(
1043 &mut self,
1044 with: Option<WithClause>,
1045 ) -> Result<HeightTracked<SelectStatement>, ParseError> {
1046 self.parse_select_tracked_machine(with)
1047 }
1048
1049 #[cfg(test)]
1050 pub(crate) fn parse_select_stmt_inner_tracked(
1051 &mut self,
1052 with: Option<WithClause>,
1053 ) -> Result<HeightTracked<SelectStatement>, ParseError> {
1054 let body = self.parse_select_body_tracked()?;
1055 let mut height = body.height;
1056 let final_core = body
1057 .value
1058 .compounds
1059 .last()
1060 .map_or(&body.value.select, |(_, core)| core);
1061 if matches!(final_core, SelectCore::Values(_))
1062 && matches!(self.peek(), TokenKind::KwOrder | TokenKind::KwLimit)
1063 {
1064 return Err(
1065 self.err_unexpected("ORDER BY / LIMIT clause is not allowed after a VALUES term")
1066 );
1067 }
1068 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1069 self.expect_kw(&TokenKind::KwBy)?;
1070 let parsed = self.parse_comma_sep(Self::parse_ordering_term_tracked)?;
1071 let mut terms = Vec::with_capacity(parsed.len());
1072 for tracked in parsed {
1073 height = height.max(tracked.height);
1074 terms.push(tracked.value);
1075 }
1076 terms
1077 } else {
1078 vec![]
1079 };
1080 let limit = self.parse_limit_tracked()?;
1081 height = height.max(limit.height);
1082 if matches!(final_core, SelectCore::Values(_))
1087 && (!order_by.is_empty() || limit.value.is_some())
1088 {
1089 return Err(
1090 self.err_unexpected("ORDER BY / LIMIT clause is not allowed after a VALUES term")
1091 );
1092 }
1093 Ok(HeightTracked {
1094 value: SelectStatement {
1095 with,
1096 body: body.value,
1097 order_by,
1098 limit: limit.value,
1099 },
1100 height,
1101 })
1102 }
1103
1104 #[cfg(test)]
1105 fn parse_select_body_tracked(&mut self) -> Result<HeightTracked<SelectBody>, ParseError> {
1106 let select = self.parse_select_core_tracked()?;
1107 let mut height = select.height;
1108 let mut compounds = Vec::new();
1109 loop {
1110 let op = if self.eat_kw(&TokenKind::KwUnion) {
1111 if self.eat_kw(&TokenKind::KwAll) {
1112 CompoundOp::UnionAll
1113 } else {
1114 CompoundOp::Union
1115 }
1116 } else if self.eat_kw(&TokenKind::KwIntersect) {
1117 CompoundOp::Intersect
1118 } else if self.eat_kw(&TokenKind::KwExcept) {
1119 CompoundOp::Except
1120 } else {
1121 break;
1122 };
1123 let core = self.parse_select_core_tracked()?;
1124 height = height.max(core.height);
1125 compounds.push((op, core.value));
1126 }
1127 Ok(HeightTracked {
1128 value: SelectBody {
1129 select: select.value,
1130 compounds,
1131 },
1132 height,
1133 })
1134 }
1135
1136 #[cfg(test)]
1137 fn parse_select_core_tracked(&mut self) -> Result<HeightTracked<SelectCore>, ParseError> {
1138 if self.eat_kw(&TokenKind::KwValues) {
1139 return self.parse_values_core_tracked();
1140 }
1141 self.expect_kw(&TokenKind::KwSelect)?;
1142 let distinct = if self.eat_kw(&TokenKind::KwDistinct) {
1143 Distinctness::Distinct
1144 } else {
1145 let _ = self.eat_kw(&TokenKind::KwAll);
1146 Distinctness::All
1147 };
1148 let parsed_columns = self.parse_comma_sep(Self::parse_result_column_tracked)?;
1149 let mut height = 0;
1150 let mut columns = Vec::with_capacity(parsed_columns.len());
1151 for tracked in parsed_columns {
1152 height = height.max(tracked.height);
1153 columns.push(tracked.value);
1154 }
1155 let from = if self.eat_kw(&TokenKind::KwFrom) {
1156 Some(self.parse_from_clause()?)
1157 } else {
1158 None
1159 };
1160 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1161 let parsed = self.parse_expr_tracked()?;
1162 height = height.max(parsed.height);
1163 Some(Box::new(parsed.expr))
1164 } else {
1165 None
1166 };
1167 let group_by = if self.eat_kw(&TokenKind::KwGroup) {
1168 self.expect_kw(&TokenKind::KwBy)?;
1169 let parsed = self.parse_comma_sep(Self::parse_expr_tracked)?;
1170 let mut expressions = Vec::with_capacity(parsed.len());
1171 for tracked in parsed {
1172 height = height.max(tracked.height);
1173 expressions.push(tracked.expr);
1174 }
1175 expressions
1176 } else {
1177 vec![]
1178 };
1179 let having = if self.eat_kw(&TokenKind::KwHaving) {
1180 let parsed = self.parse_expr_tracked()?;
1181 height = height.max(parsed.height);
1182 Some(Box::new(parsed.expr))
1183 } else {
1184 None
1185 };
1186 let windows = if self.eat_kw(&TokenKind::KwWindow) {
1187 self.parse_comma_sep(Self::parse_window_def)?
1188 } else {
1189 vec![]
1190 };
1191 Ok(HeightTracked {
1192 value: SelectCore::Select {
1193 distinct,
1194 columns,
1195 from,
1196 where_clause,
1197 group_by,
1198 having,
1199 windows,
1200 },
1201 height,
1202 })
1203 }
1204
1205 fn parse_values_core(&mut self) -> Result<SelectCore, ParseError> {
1206 self.parse_values_core_tracked()
1207 .map(|tracked| tracked.value)
1208 }
1209
1210 fn parse_values_core_tracked(&mut self) -> Result<HeightTracked<SelectCore>, ParseError> {
1211 let mut rows = Vec::new();
1212 let mut height = 0;
1213 let mut force_union_all_from = None;
1214 loop {
1215 self.expect_token(&TokenKind::LeftParen)?;
1216 let parsed = self.parse_comma_sep(Self::parse_expr_tracked)?;
1217 let mut row = Vec::with_capacity(parsed.len());
1218 for tracked in parsed {
1219 height = height.max(tracked.height);
1220 row.push(tracked.expr);
1221 }
1222 self.expect_token(&TokenKind::RightParen)?;
1223 if force_union_all_from.is_none() && self.has_with {
1224 force_union_all_from = Some(rows.len());
1225 }
1226 rows.push(row);
1227 if !self.eat(&TokenKind::Comma) {
1228 break;
1229 }
1230 }
1231 Ok(HeightTracked {
1232 value: SelectCore::Values(ValuesClause::parsed(rows, force_union_all_from)),
1233 height,
1234 })
1235 }
1236
1237 fn parse_result_column_tracked(&mut self) -> Result<HeightTracked<ResultColumn>, ParseError> {
1238 if self.eat(&TokenKind::Star) {
1239 return Ok(HeightTracked {
1240 value: ResultColumn::Star,
1241 height: 0,
1242 });
1243 }
1244 if starts_table_star_qualifier(self.peek()) && self.peek_nth(1) == &TokenKind::Dot {
1245 if self.peek_nth(2) == &TokenKind::Star {
1246 let table = self.parse_table_star_qualifier()?;
1247 self.expect_token(&TokenKind::Dot)?;
1248 self.expect_token(&TokenKind::Star)?;
1249 return Ok(HeightTracked {
1250 value: ResultColumn::TableStar(QualifiedName::bare(table)),
1251 height: 0,
1252 });
1253 }
1254 if starts_table_star_qualifier(self.peek_nth(2))
1255 && self.peek_nth(3) == &TokenKind::Dot
1256 && self.peek_nth(4) == &TokenKind::Star
1257 {
1258 let schema = self.parse_table_star_qualifier()?;
1259 self.expect_token(&TokenKind::Dot)?;
1260 let table = self.parse_table_star_qualifier()?;
1261 self.expect_token(&TokenKind::Dot)?;
1262 self.expect_token(&TokenKind::Star)?;
1263 return Ok(HeightTracked {
1264 value: ResultColumn::TableStar(QualifiedName::qualified(schema, table)),
1265 height: 0,
1266 });
1267 }
1268 }
1269 let parsed = self.parse_expr_tracked()?;
1270 let alias = self.try_result_alias()?;
1271 Ok(HeightTracked {
1272 value: ResultColumn::Expr {
1273 expr: parsed.expr,
1274 alias,
1275 },
1276 height: parsed.height,
1277 })
1278 }
1279
1280 fn parse_result_column(&mut self) -> Result<ResultColumn, ParseError> {
1281 self.parse_result_column_tracked()
1282 .map(|tracked| tracked.value)
1283 }
1284
1285 #[cfg(test)]
1290 fn parse_from_clause(&mut self) -> Result<FromClause, ParseError> {
1291 let source = self.parse_table_or_subquery()?;
1292 let mut joins = Vec::new();
1293 loop {
1294 if let Some(jt) = self.try_join_type()? {
1295 let table = self.parse_table_or_subquery()?;
1296 let constraint = self.parse_join_constraint()?;
1297 if jt.natural && constraint.is_some() {
1298 return Err(self.err_msg("a NATURAL join may not have an ON or USING clause"));
1299 }
1300 joins.push(JoinClause {
1301 join_type: jt,
1302 table,
1303 constraint,
1304 });
1305 } else if self.eat(&TokenKind::Comma) {
1306 let table = self.parse_table_or_subquery()?;
1307 let constraint = self.parse_join_constraint()?;
1308 joins.push(JoinClause {
1309 join_type: JoinType {
1310 natural: false,
1311 kind: JoinKind::Cross,
1312 },
1313 table,
1314 constraint,
1315 });
1316 } else {
1317 break;
1318 }
1319 }
1320 Ok(FromClause { source, joins })
1321 }
1322
1323 #[cfg(test)]
1324 fn parse_table_or_subquery(&mut self) -> Result<TableOrSubquery, ParseError> {
1325 self.with_recursion_guard(|parser| parser.parse_table_or_subquery_inner())
1326 }
1327
1328 #[cfg(test)]
1329 fn parse_table_or_subquery_inner(&mut self) -> Result<TableOrSubquery, ParseError> {
1330 if self.check(&TokenKind::LeftParen) {
1331 self.advance();
1332 if matches!(
1333 self.peek(),
1334 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
1335 ) {
1336 let with = if self.check_kw(&TokenKind::KwWith) {
1337 Some(self.parse_with_clause()?)
1338 } else {
1339 None
1340 };
1341 let q = self.parse_select_stmt(with)?;
1342 self.expect_token(&TokenKind::RightParen)?;
1343 let alias = self.try_table_alias()?;
1344 return Ok(TableOrSubquery::Subquery {
1345 query: Box::new(q),
1346 alias,
1347 });
1348 }
1349 let fc = self.parse_from_clause()?;
1351 self.expect_token(&TokenKind::RightParen)?;
1352 return Ok(TableOrSubquery::ParenJoin(Box::new(fc)));
1353 }
1354
1355 let name = self.parse_qualified_name()?;
1356
1357 if self.check(&TokenKind::LeftParen) && name.schema.is_none() {
1359 self.advance();
1360 let args = if self.check(&TokenKind::RightParen) {
1361 vec![]
1362 } else {
1363 self.parse_comma_sep(Self::parse_expr)?
1364 };
1365 self.expect_token(&TokenKind::RightParen)?;
1366 let alias = self.try_table_alias()?;
1367 return Ok(TableOrSubquery::TableFunction {
1368 name: name.name,
1369 args,
1370 alias,
1371 });
1372 }
1373
1374 let alias = self.try_table_alias()?;
1375 let index_hint = self.parse_index_hint()?;
1376 let time_travel = self.parse_time_travel_clause()?;
1377 Ok(TableOrSubquery::Table {
1378 name,
1379 alias,
1380 index_hint,
1381 time_travel,
1382 })
1383 }
1384
1385 pub(crate) fn try_join_type(&mut self) -> Result<Option<JoinType>, ParseError> {
1386 let natural = self.eat_kw(&TokenKind::KwNatural);
1387 let kind = if self.eat_kw(&TokenKind::KwJoin) {
1388 Some(JoinKind::Inner)
1389 } else if self.eat_kw(&TokenKind::KwInner) {
1390 self.expect_kw(&TokenKind::KwJoin)?;
1391 Some(JoinKind::Inner)
1392 } else if self.eat_kw(&TokenKind::KwCross) {
1393 self.expect_kw(&TokenKind::KwJoin)?;
1394 Some(JoinKind::Cross)
1395 } else if self.eat_kw(&TokenKind::KwLeft) {
1396 let _ = self.eat_kw(&TokenKind::KwOuter);
1397 self.expect_kw(&TokenKind::KwJoin)?;
1398 Some(JoinKind::Left)
1399 } else if self.eat_kw(&TokenKind::KwRight) {
1400 let _ = self.eat_kw(&TokenKind::KwOuter);
1401 self.expect_kw(&TokenKind::KwJoin)?;
1402 Some(JoinKind::Right)
1403 } else if self.eat_kw(&TokenKind::KwFull) {
1404 let _ = self.eat_kw(&TokenKind::KwOuter);
1405 self.expect_kw(&TokenKind::KwJoin)?;
1406 Some(JoinKind::Full)
1407 } else {
1408 None
1409 };
1410 match kind {
1411 Some(k) => Ok(Some(JoinType { natural, kind: k })),
1412 None if natural => Err(self.err_expected("JOIN after NATURAL")),
1413 None => Ok(None),
1414 }
1415 }
1416
1417 #[cfg(test)]
1418 fn parse_join_constraint(&mut self) -> Result<Option<JoinConstraint>, ParseError> {
1419 if self.eat_kw(&TokenKind::KwOn) {
1420 Ok(Some(JoinConstraint::On(self.parse_expr()?)))
1421 } else if self.eat_kw(&TokenKind::KwUsing) {
1422 self.expect_token(&TokenKind::LeftParen)?;
1423 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1424 self.expect_token(&TokenKind::RightParen)?;
1425 Ok(Some(JoinConstraint::Using(cols)))
1426 } else {
1427 Ok(None)
1428 }
1429 }
1430
1431 pub(crate) fn parse_ordering_term(&mut self) -> Result<OrderingTerm, ParseError> {
1436 self.parse_ordering_term_tracked()
1437 .map(|tracked| tracked.value)
1438 }
1439
1440 fn parse_ordering_term_tracked(&mut self) -> Result<HeightTracked<OrderingTerm>, ParseError> {
1441 let parsed = self.parse_expr_tracked()?;
1442 let direction = if self.eat_kw(&TokenKind::KwAsc) {
1443 Some(SortDirection::Asc)
1444 } else if self.eat_kw(&TokenKind::KwDesc) {
1445 Some(SortDirection::Desc)
1446 } else {
1447 None
1448 };
1449 let nulls = if self.eat_kw(&TokenKind::KwNulls) {
1450 if self.eat_kw(&TokenKind::KwFirst) {
1451 Some(NullsOrder::First)
1452 } else {
1453 self.expect_kw(&TokenKind::KwLast)?;
1454 Some(NullsOrder::Last)
1455 }
1456 } else {
1457 None
1458 };
1459 Ok(HeightTracked {
1460 value: OrderingTerm {
1461 expr: parsed.expr,
1462 direction,
1463 nulls,
1464 },
1465 height: parsed.height,
1466 })
1467 }
1468
1469 pub(crate) fn parse_limit(&mut self) -> Result<Option<LimitClause>, ParseError> {
1470 self.parse_limit_tracked().map(|tracked| tracked.value)
1471 }
1472
1473 fn parse_limit_tracked(&mut self) -> Result<HeightTracked<Option<LimitClause>>, ParseError> {
1474 if !self.eat_kw(&TokenKind::KwLimit) {
1475 return Ok(HeightTracked {
1476 value: None,
1477 height: 0,
1478 });
1479 }
1480 let first = self.parse_expr_tracked()?;
1481 if self.eat_kw(&TokenKind::KwOffset) {
1482 let offset = self.parse_expr_tracked()?;
1483 let height = self.checked_cached_parent_height(first.height.max(offset.height))?;
1484 return Ok(HeightTracked {
1485 value: Some(LimitClause {
1486 limit: first.expr,
1487 offset: Some(offset.expr),
1488 }),
1489 height,
1490 });
1491 }
1492
1493 if self.eat(&TokenKind::Comma) {
1494 let second = self.parse_expr_tracked()?;
1496 let height = self.checked_cached_parent_height(first.height.max(second.height))?;
1497 return Ok(HeightTracked {
1498 value: Some(LimitClause {
1499 limit: second.expr,
1500 offset: Some(first.expr),
1501 }),
1502 height,
1503 });
1504 }
1505
1506 let height = self.checked_cached_parent_height(first.height)?;
1507 Ok(HeightTracked {
1508 value: Some(LimitClause {
1509 limit: first.expr,
1510 offset: None,
1511 }),
1512 height,
1513 })
1514 }
1515
1516 fn parse_returning(
1521 &mut self,
1522 context: DmlParseContext,
1523 dml_is_insert: bool,
1524 ) -> Result<Vec<ResultColumn>, ParseError> {
1525 if self.check_kw(&TokenKind::KwReturning) && context == DmlParseContext::TriggerBody {
1526 return Err(if dml_is_insert {
1532 self.err_semantic("cannot use RETURNING in a trigger")
1533 } else {
1534 self.err_unexpected("RETURNING is not allowed in trigger body statements")
1535 });
1536 }
1537 if self.eat_kw(&TokenKind::KwReturning) {
1538 self.parse_comma_sep(Self::parse_result_column)
1539 } else {
1540 Ok(vec![])
1541 }
1542 }
1543
1544 fn parse_insert_stmt(
1549 &mut self,
1550 with: Option<WithClause>,
1551 context: DmlParseContext,
1552 ) -> Result<Statement, ParseError> {
1553 let or_conflict = if self.eat_kw(&TokenKind::KwReplace) {
1554 Some(ConflictAction::Replace)
1555 } else {
1556 self.expect_kw(&TokenKind::KwInsert)?;
1557 if self.eat_kw(&TokenKind::KwOr) {
1558 Some(self.parse_conflict_action()?)
1559 } else {
1560 None
1561 }
1562 };
1563 self.eat_kw(&TokenKind::KwInto);
1564 let table = self.parse_dml_target_name(context)?;
1565 let alias = if self.eat_kw(&TokenKind::KwAs) {
1566 Some(self.parse_identifier()?)
1567 } else {
1568 None
1569 };
1570 let columns = if self.check(&TokenKind::LeftParen)
1571 && !matches!(
1572 self.peek_nth(1),
1573 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
1574 ) {
1575 self.advance();
1576 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1577 self.expect_token(&TokenKind::RightParen)?;
1578 cols
1579 } else {
1580 vec![]
1581 };
1582 let source = if self.check_kw(&TokenKind::KwDefault)
1583 && context == DmlParseContext::TriggerBody
1584 {
1585 return Err(
1586 self.err_unexpected("DEFAULT VALUES is not allowed in trigger body statements")
1587 );
1588 } else if self.eat_kw(&TokenKind::KwDefault) {
1589 self.expect_kw(&TokenKind::KwValues)?;
1590 InsertSource::DefaultValues
1591 } else if self.eat_kw(&TokenKind::KwValues) {
1592 match self.parse_values_core()? {
1593 SelectCore::Values(rows) => InsertSource::Values(rows.into_rows()),
1594 SelectCore::Select { .. } => unreachable!("parse_values_core must return VALUES"),
1595 }
1596 } else {
1597 let inner_with = if self.check_kw(&TokenKind::KwWith) {
1598 Some(self.parse_with_clause()?)
1599 } else {
1600 None
1601 };
1602 InsertSource::Select(Box::new(self.parse_select_stmt(inner_with)?))
1603 };
1604 let upsert = self.parse_upsert_clauses()?;
1605 let returning = self.parse_returning(context, true)?;
1606 Ok(Statement::Insert(InsertStatement {
1607 with,
1608 or_conflict,
1609 table,
1610 alias,
1611 columns,
1612 source,
1613 upsert,
1614 returning,
1615 }))
1616 }
1617
1618 fn parse_conflict_action(&mut self) -> Result<ConflictAction, ParseError> {
1619 if self.eat_kw(&TokenKind::KwRollback) {
1620 Ok(ConflictAction::Rollback)
1621 } else if self.eat_kw(&TokenKind::KwAbort) {
1622 Ok(ConflictAction::Abort)
1623 } else if self.eat_kw(&TokenKind::KwFail) {
1624 Ok(ConflictAction::Fail)
1625 } else if self.eat_kw(&TokenKind::KwIgnore) {
1626 Ok(ConflictAction::Ignore)
1627 } else if self.eat_kw(&TokenKind::KwReplace) {
1628 Ok(ConflictAction::Replace)
1629 } else {
1630 Err(self.err_expected("conflict action"))
1631 }
1632 }
1633
1634 fn parse_upsert_clauses(&mut self) -> Result<Vec<UpsertClause>, ParseError> {
1635 let mut clauses = Vec::new();
1636 while self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
1637 if clauses
1640 .last()
1641 .is_some_and(|clause: &UpsertClause| clause.target.is_none())
1642 {
1643 return Err(self.err_msg(
1644 "ON CONFLICT clause without a conflict target must be the last ON CONFLICT clause",
1645 ));
1646 }
1647 self.advance(); self.advance(); let target = if self.check(&TokenKind::LeftParen) {
1650 self.advance();
1651 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1652 self.expect_token(&TokenKind::RightParen)?;
1653 let wh = if self.eat_kw(&TokenKind::KwWhere) {
1654 Some(self.parse_expr()?)
1655 } else {
1656 None
1657 };
1658 Some(UpsertTarget {
1659 columns,
1660 where_clause: wh,
1661 })
1662 } else {
1663 None
1664 };
1665 self.expect_kw(&TokenKind::KwDo)?;
1666 let action = if self.eat_kw(&TokenKind::KwNothing) {
1667 UpsertAction::Nothing
1668 } else {
1669 self.expect_kw(&TokenKind::KwUpdate)?;
1670 self.expect_kw(&TokenKind::KwSet)?;
1671 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
1672 let wh = if self.eat_kw(&TokenKind::KwWhere) {
1673 Some(Box::new(self.parse_expr()?))
1674 } else {
1675 None
1676 };
1677 UpsertAction::Update {
1678 assignments,
1679 where_clause: wh,
1680 }
1681 };
1682 clauses.push(UpsertClause { target, action });
1683 }
1684 Ok(clauses)
1685 }
1686
1687 fn parse_update_stmt(
1692 &mut self,
1693 with: Option<WithClause>,
1694 context: DmlParseContext,
1695 ) -> Result<Statement, ParseError> {
1696 self.expect_kw(&TokenKind::KwUpdate)?;
1697 let or_conflict = if self.eat_kw(&TokenKind::KwOr) {
1698 Some(self.parse_conflict_action()?)
1699 } else {
1700 None
1701 };
1702 let table = self.parse_qualified_table_ref(context)?;
1703 self.expect_kw(&TokenKind::KwSet)?;
1704 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
1705 let from = if self.eat_kw(&TokenKind::KwFrom) {
1706 Some(self.parse_from_clause_machine()?)
1707 } else {
1708 None
1709 };
1710 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1711 Some(self.parse_expr()?)
1712 } else {
1713 None
1714 };
1715 let returning = self.parse_returning(context, false)?;
1716 if context == DmlParseContext::TriggerBody && self.check_kw(&TokenKind::KwOrder) {
1717 return Err(
1718 self.err_unexpected("ORDER BY is not allowed in trigger body UPDATE statements")
1719 );
1720 }
1721 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1722 self.expect_kw(&TokenKind::KwBy)?;
1723 self.parse_comma_sep(Self::parse_ordering_term)?
1724 } else {
1725 vec![]
1726 };
1727 if context == DmlParseContext::TriggerBody && self.check_kw(&TokenKind::KwLimit) {
1728 return Err(
1729 self.err_unexpected("LIMIT is not allowed in trigger body UPDATE statements")
1730 );
1731 }
1732 let limit = self.parse_limit()?;
1733 Ok(Statement::Update(UpdateStatement {
1734 with,
1735 or_conflict,
1736 table,
1737 assignments,
1738 from,
1739 where_clause,
1740 returning,
1741 order_by,
1742 limit,
1743 }))
1744 }
1745
1746 fn parse_assignment(&mut self) -> Result<Assignment, ParseError> {
1747 let target = if self.check(&TokenKind::LeftParen) {
1748 self.advance();
1749 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1750 self.expect_token(&TokenKind::RightParen)?;
1751 AssignmentTarget::ColumnList(cols)
1752 } else {
1753 AssignmentTarget::Column(self.parse_identifier()?)
1754 };
1755 self.expect_token(&TokenKind::Eq)?;
1756 let value = self.parse_expr()?;
1757 Ok(Assignment { target, value })
1758 }
1759
1760 fn parse_delete_stmt(
1765 &mut self,
1766 with: Option<WithClause>,
1767 context: DmlParseContext,
1768 ) -> Result<Statement, ParseError> {
1769 self.expect_kw(&TokenKind::KwDelete)?;
1770 self.expect_kw(&TokenKind::KwFrom)?;
1771 let table = self.parse_qualified_table_ref(context)?;
1772 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1773 Some(self.parse_expr()?)
1774 } else {
1775 None
1776 };
1777 let returning = self.parse_returning(context, false)?;
1778 if context == DmlParseContext::TriggerBody && self.check_kw(&TokenKind::KwOrder) {
1779 return Err(
1780 self.err_unexpected("ORDER BY is not allowed in trigger body DELETE statements")
1781 );
1782 }
1783 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1784 self.expect_kw(&TokenKind::KwBy)?;
1785 self.parse_comma_sep(Self::parse_ordering_term)?
1786 } else {
1787 vec![]
1788 };
1789 if context == DmlParseContext::TriggerBody && self.check_kw(&TokenKind::KwLimit) {
1790 return Err(
1791 self.err_unexpected("LIMIT is not allowed in trigger body DELETE statements")
1792 );
1793 }
1794 let limit = self.parse_limit()?;
1795 Ok(Statement::Delete(DeleteStatement {
1796 with,
1797 table,
1798 where_clause,
1799 returning,
1800 order_by,
1801 limit,
1802 }))
1803 }
1804
1805 fn parse_create(&mut self) -> Result<Statement, ParseError> {
1810 self.expect_kw(&TokenKind::KwCreate)?;
1811 let temporary = self.eat_kw(&TokenKind::KwTemp) || self.eat_kw(&TokenKind::KwTemporary);
1812 let unique = self.eat_kw(&TokenKind::KwUnique);
1813
1814 if self.eat_kw(&TokenKind::KwTable) {
1815 if unique {
1816 return Err(self.err_expected("INDEX after UNIQUE"));
1817 }
1818 return self.parse_create_table(temporary);
1819 }
1820 if self.eat_kw(&TokenKind::KwIndex) {
1821 if temporary {
1822 return Err(self.err_expected("TABLE, VIEW, or TRIGGER after TEMP"));
1823 }
1824 return self.parse_create_index(unique);
1825 }
1826 if self.eat_kw(&TokenKind::KwView) {
1827 if unique {
1828 return Err(self.err_expected("INDEX after UNIQUE"));
1829 }
1830 return self.parse_create_view(temporary);
1831 }
1832 if self.eat_kw(&TokenKind::KwTrigger) {
1833 if unique {
1834 return Err(self.err_expected("INDEX after UNIQUE"));
1835 }
1836 return self.parse_create_trigger(temporary);
1837 }
1838 if self.eat_kw(&TokenKind::KwVirtual) {
1839 if temporary || unique {
1840 return Err(self.err_expected("TABLE, INDEX, VIEW, or TRIGGER"));
1841 }
1842 self.expect_kw(&TokenKind::KwTable)?;
1843 return self.parse_create_virtual_table();
1844 }
1845 Err(self.err_expected("TABLE, INDEX, VIEW, TRIGGER, or VIRTUAL"))
1846 }
1847
1848 fn parse_if_not_exists(&mut self) -> bool {
1849 if self.check_kw(&TokenKind::KwIf)
1850 && self.peek_nth(1) == &TokenKind::KwNot
1851 && self.peek_nth(2) == &TokenKind::KwExists
1852 {
1853 self.advance();
1854 self.advance();
1855 self.advance();
1856 true
1857 } else {
1858 false
1859 }
1860 }
1861
1862 fn parse_create_table(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1863 let if_not_exists = self.parse_if_not_exists();
1864 let name = self.parse_qualified_name()?;
1865 let body = if self.eat_kw(&TokenKind::KwAs) {
1866 let with = if self.check_kw(&TokenKind::KwWith) {
1867 Some(self.parse_with_clause()?)
1868 } else {
1869 None
1870 };
1871 CreateTableBody::AsSelect(Box::new(self.parse_select_stmt(with)?))
1872 } else {
1873 self.expect_token(&TokenKind::LeftParen)?;
1874 let mut columns = Vec::new();
1875 let mut constraints = Vec::new();
1876 loop {
1877 if self.is_table_constraint_start() {
1878 constraints.push(self.parse_table_constraint()?);
1879 } else {
1880 columns.push(self.parse_column_def()?);
1881 }
1882 if !self.eat(&TokenKind::Comma) {
1883 break;
1884 }
1885 }
1886 self.expect_token(&TokenKind::RightParen)?;
1887 CreateTableBody::Columns {
1888 columns,
1889 constraints,
1890 }
1891 };
1892 let mut without_rowid = false;
1893 let mut strict = false;
1894 if self.check_kw(&TokenKind::KwWithout) || self.check_kw(&TokenKind::KwStrict) {
1896 loop {
1897 if self.check_kw(&TokenKind::KwWithout) {
1898 self.advance();
1899 let id = self.parse_identifier()?;
1901 if !id.eq_ignore_ascii_case("ROWID") {
1902 return Err(self.err_expected("ROWID after WITHOUT"));
1903 }
1904 without_rowid = true;
1905 } else if self.eat_kw(&TokenKind::KwStrict) {
1906 strict = true;
1907 } else {
1908 return Err(self.err_expected("table option"));
1909 }
1910 if !self.eat(&TokenKind::Comma) {
1911 break;
1912 }
1913 }
1914 }
1915 Ok(Statement::CreateTable(CreateTableStatement {
1916 if_not_exists,
1917 temporary,
1918 name,
1919 body,
1920 without_rowid,
1921 strict,
1922 }))
1923 }
1924
1925 fn is_table_constraint_start(&self) -> bool {
1926 matches!(
1927 self.peek(),
1928 TokenKind::KwPrimary | TokenKind::KwUnique | TokenKind::KwCheck | TokenKind::KwForeign
1929 ) || (self.check_kw(&TokenKind::KwConstraint))
1930 }
1931
1932 fn parse_column_def(&mut self) -> Result<ColumnDef, ParseError> {
1933 let name = self.parse_identifier()?;
1934 let type_name = self.try_type_name()?;
1935 let mut constraints = Vec::new();
1936 while let Some(c) = self.try_column_constraint()? {
1937 constraints.push(c);
1938 }
1939 Ok(ColumnDef {
1940 name,
1941 type_name,
1942 constraints,
1943 })
1944 }
1945
1946 fn try_type_name(&mut self) -> Result<Option<TypeName>, ParseError> {
1947 if self.is_column_constraint_start()
1949 || matches!(
1950 self.peek(),
1951 TokenKind::Comma | TokenKind::RightParen | TokenKind::Eof
1952 )
1953 {
1954 return Ok(None);
1955 }
1956 let mut words = Vec::new();
1958 loop {
1959 match self.peek() {
1960 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
1961 words.push(self.parse_identifier()?);
1962 }
1963 k if is_nonreserved_kw(k) => {
1964 words.push(self.parse_identifier()?);
1965 }
1966 _ => break,
1967 }
1968 if self.is_column_constraint_start()
1969 || matches!(
1970 self.peek(),
1971 TokenKind::Comma | TokenKind::RightParen | TokenKind::LeftParen
1972 )
1973 {
1974 break;
1975 }
1976 }
1977 if words.is_empty() {
1978 return Ok(None);
1979 }
1980 let type_name = words.join(" ");
1981 let (arg1, arg2) = if self.eat(&TokenKind::LeftParen) {
1982 let a1 = self.parse_signed_number_str()?;
1983 let a2 = if self.eat(&TokenKind::Comma) {
1984 Some(self.parse_signed_number_str()?)
1985 } else {
1986 None
1987 };
1988 self.expect_token(&TokenKind::RightParen)?;
1989 (Some(a1), a2)
1990 } else {
1991 (None, None)
1992 };
1993 Ok(Some(TypeName {
1994 name: type_name,
1995 arg1,
1996 arg2,
1997 }))
1998 }
1999
2000 fn parse_signed_number_str(&mut self) -> Result<String, ParseError> {
2001 let neg = self.eat(&TokenKind::Minus);
2002 let plus = if neg {
2003 false
2004 } else {
2005 self.eat(&TokenKind::Plus)
2006 };
2007 let _ = plus; match self.peek().clone() {
2009 TokenKind::Integer(n) => {
2010 self.advance();
2011 Ok(if neg { format!("-{n}") } else { n.to_string() })
2012 }
2013 TokenKind::OversizedInt(s) => {
2014 self.advance();
2015 Ok(if neg { format!("-{s}") } else { s.clone() })
2016 }
2017 TokenKind::Float(f) => {
2018 self.advance();
2019 Ok(if neg { format!("-{f}") } else { f.to_string() })
2020 }
2021 _ => Err(self.err_expected("number")),
2022 }
2023 }
2024
2025 fn is_column_constraint_start(&self) -> bool {
2026 matches!(
2027 self.peek(),
2028 TokenKind::KwPrimary
2029 | TokenKind::KwNot
2030 | TokenKind::KwNull
2031 | TokenKind::KwUnique
2032 | TokenKind::KwCheck
2033 | TokenKind::KwDefault
2034 | TokenKind::KwCollate
2035 | TokenKind::KwReferences
2036 | TokenKind::KwGenerated
2037 | TokenKind::KwConstraint
2038 | TokenKind::KwAs
2039 )
2040 }
2041
2042 fn try_column_constraint(&mut self) -> Result<Option<ColumnConstraint>, ParseError> {
2043 let name = if self.eat_kw(&TokenKind::KwConstraint) {
2044 Some(self.parse_identifier()?)
2045 } else {
2046 None
2047 };
2048 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
2049 self.expect_kw(&TokenKind::KwKey)?;
2050 let direction = if self.eat_kw(&TokenKind::KwAsc) {
2051 Some(SortDirection::Asc)
2052 } else if self.eat_kw(&TokenKind::KwDesc) {
2053 Some(SortDirection::Desc)
2054 } else {
2055 None
2056 };
2057 let conflict = self.parse_on_conflict()?;
2058 let autoincrement = self.eat_kw(&TokenKind::KwAutoincrement);
2059 ColumnConstraintKind::PrimaryKey {
2060 direction,
2061 conflict,
2062 autoincrement,
2063 }
2064 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwNull {
2065 self.advance();
2066 self.advance();
2067 let conflict = self.parse_on_conflict()?;
2068 ColumnConstraintKind::NotNull { conflict }
2069 } else if self.eat_kw(&TokenKind::KwNull) {
2070 ColumnConstraintKind::Null
2071 } else if self.eat_kw(&TokenKind::KwUnique) {
2072 let conflict = self.parse_on_conflict()?;
2073 ColumnConstraintKind::Unique { conflict }
2074 } else if self.eat_kw(&TokenKind::KwCheck) {
2075 self.expect_token(&TokenKind::LeftParen)?;
2076 let expr = self.parse_expr()?;
2077 self.expect_token(&TokenKind::RightParen)?;
2078 ColumnConstraintKind::Check(expr)
2079 } else if self.eat_kw(&TokenKind::KwDefault) {
2080 if self.eat(&TokenKind::LeftParen) {
2081 let expr = self.parse_expr()?;
2082 self.expect_token(&TokenKind::RightParen)?;
2083 ColumnConstraintKind::Default(DefaultValue::ParenExpr(expr))
2084 } else if let TokenKind::Id(name) = self.peek().clone() {
2085 let span = self.current_span();
2093 self.advance();
2094 ColumnConstraintKind::Default(DefaultValue::Expr(Expr::Literal(
2095 Literal::String(name.to_string()),
2096 span,
2097 )))
2098 } else {
2099 let expr = self.parse_expr()?;
2100 ColumnConstraintKind::Default(DefaultValue::Expr(expr))
2101 }
2102 } else if self.eat_kw(&TokenKind::KwCollate) {
2103 ColumnConstraintKind::Collate(self.parse_identifier()?)
2104 } else if self.eat_kw(&TokenKind::KwReferences) {
2105 ColumnConstraintKind::ForeignKey(self.parse_fk_clause()?)
2106 } else if self.eat_kw(&TokenKind::KwGenerated) || self.eat_kw(&TokenKind::KwAs) {
2107 if self.tokens[self.pos.saturating_sub(1)].kind == TokenKind::KwGenerated {
2108 let _ = self.eat_kw(&TokenKind::KwAlways);
2109 let _ = self.eat_kw(&TokenKind::KwAs);
2110 }
2111 self.expect_token(&TokenKind::LeftParen)?;
2112 let expr = self.parse_expr()?;
2113 self.expect_token(&TokenKind::RightParen)?;
2114 let storage = if self.eat_kw(&TokenKind::KwStored) {
2115 Some(GeneratedStorage::Stored)
2116 } else if self.eat_kw(&TokenKind::KwVirtual) {
2117 Some(GeneratedStorage::Virtual)
2118 } else {
2119 None
2120 };
2121 ColumnConstraintKind::Generated { expr, storage }
2122 } else if name.is_some() {
2123 return Err(self.err_expected("constraint kind after CONSTRAINT name"));
2124 } else {
2125 return Ok(None);
2126 };
2127 Ok(Some(ColumnConstraint { name, kind }))
2128 }
2129
2130 fn parse_on_conflict(&mut self) -> Result<Option<ConflictAction>, ParseError> {
2131 if self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
2132 self.advance();
2133 self.advance();
2134 Ok(Some(self.parse_conflict_action()?))
2135 } else {
2136 Ok(None)
2137 }
2138 }
2139
2140 fn parse_fk_clause(&mut self) -> Result<ForeignKeyClause, ParseError> {
2141 let table = self.parse_identifier()?;
2142 let columns = if self.eat(&TokenKind::LeftParen) {
2143 let cols = self.parse_comma_sep(Self::parse_identifier)?;
2144 self.expect_token(&TokenKind::RightParen)?;
2145 cols
2146 } else {
2147 vec![]
2148 };
2149 let mut actions = Vec::new();
2150 let mut deferrable = None;
2151 loop {
2152 if self.check_kw(&TokenKind::KwOn) {
2153 self.advance();
2154 let trigger = if self.eat_kw(&TokenKind::KwDelete) {
2155 ForeignKeyTrigger::OnDelete
2156 } else {
2157 self.expect_kw(&TokenKind::KwUpdate)?;
2158 ForeignKeyTrigger::OnUpdate
2159 };
2160 let action = self.parse_fk_action_type()?;
2161 actions.push(ForeignKeyAction { trigger, action });
2162 } else if self.check_kw(&TokenKind::KwNot) || self.check_kw(&TokenKind::KwDeferrable) {
2163 let not = self.eat_kw(&TokenKind::KwNot);
2164 self.expect_kw(&TokenKind::KwDeferrable)?;
2165 let initially = if self.eat_kw(&TokenKind::KwInitially) {
2166 if self.eat_kw(&TokenKind::KwDeferred) {
2167 Some(DeferrableInitially::Deferred)
2168 } else {
2169 self.expect_kw(&TokenKind::KwImmediate)?;
2170 Some(DeferrableInitially::Immediate)
2171 }
2172 } else {
2173 None
2174 };
2175 deferrable = Some(Deferrable { not, initially });
2176 } else if self.eat_kw(&TokenKind::KwMatch) {
2177 self.parse_identifier()?;
2179 } else {
2180 break;
2181 }
2182 }
2183 Ok(ForeignKeyClause {
2184 table,
2185 columns,
2186 actions,
2187 deferrable,
2188 })
2189 }
2190
2191 fn parse_fk_action_type(&mut self) -> Result<ForeignKeyActionType, ParseError> {
2192 if self.eat_kw(&TokenKind::KwSet) {
2193 if self.eat_kw(&TokenKind::KwNull) {
2194 Ok(ForeignKeyActionType::SetNull)
2195 } else {
2196 self.expect_kw(&TokenKind::KwDefault)?;
2197 Ok(ForeignKeyActionType::SetDefault)
2198 }
2199 } else if self.eat_kw(&TokenKind::KwCascade) {
2200 Ok(ForeignKeyActionType::Cascade)
2201 } else if self.eat_kw(&TokenKind::KwRestrict) {
2202 Ok(ForeignKeyActionType::Restrict)
2203 } else if self.check_kw(&TokenKind::KwNo) {
2204 self.advance();
2205 let id = self.parse_identifier()?;
2206 if !id.eq_ignore_ascii_case("ACTION") {
2207 return Err(self.err_expected("ACTION after NO"));
2208 }
2209 Ok(ForeignKeyActionType::NoAction)
2210 } else {
2211 Err(self.err_expected("foreign key action"))
2212 }
2213 }
2214
2215 fn parse_table_constraint(&mut self) -> Result<TableConstraint, ParseError> {
2216 let name = if self.eat_kw(&TokenKind::KwConstraint) {
2217 Some(self.parse_identifier()?)
2218 } else {
2219 None
2220 };
2221 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
2222 self.expect_kw(&TokenKind::KwKey)?;
2223 self.expect_token(&TokenKind::LeftParen)?;
2224 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
2225 self.expect_token(&TokenKind::RightParen)?;
2226 let conflict = self.parse_on_conflict()?;
2227 TableConstraintKind::PrimaryKey { columns, conflict }
2228 } else if self.eat_kw(&TokenKind::KwUnique) {
2229 self.expect_token(&TokenKind::LeftParen)?;
2230 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
2231 self.expect_token(&TokenKind::RightParen)?;
2232 let conflict = self.parse_on_conflict()?;
2233 TableConstraintKind::Unique { columns, conflict }
2234 } else if self.eat_kw(&TokenKind::KwCheck) {
2235 self.expect_token(&TokenKind::LeftParen)?;
2236 let expr = self.parse_expr()?;
2237 self.expect_token(&TokenKind::RightParen)?;
2238 let _conflict = self.parse_on_conflict()?;
2243 TableConstraintKind::Check(expr)
2244 } else if self.eat_kw(&TokenKind::KwForeign) {
2245 self.expect_kw(&TokenKind::KwKey)?;
2246 self.expect_token(&TokenKind::LeftParen)?;
2247 let columns = self.parse_comma_sep(Self::parse_identifier)?;
2248 self.expect_token(&TokenKind::RightParen)?;
2249 self.expect_kw(&TokenKind::KwReferences)?;
2250 let clause = self.parse_fk_clause()?;
2251 TableConstraintKind::ForeignKey { columns, clause }
2252 } else {
2253 return Err(self.err_expected("table constraint"));
2254 };
2255 Ok(TableConstraint { name, kind })
2256 }
2257
2258 fn parse_indexed_column(&mut self) -> Result<IndexedColumn, ParseError> {
2259 let expr = self.parse_expr()?;
2260 let collation = if self.eat_kw(&TokenKind::KwCollate) {
2261 Some(self.parse_identifier()?)
2262 } else {
2263 None
2264 };
2265 let direction = if self.eat_kw(&TokenKind::KwAsc) {
2266 Some(SortDirection::Asc)
2267 } else if self.eat_kw(&TokenKind::KwDesc) {
2268 Some(SortDirection::Desc)
2269 } else {
2270 None
2271 };
2272 Ok(IndexedColumn {
2273 expr,
2274 collation,
2275 direction,
2276 })
2277 }
2278
2279 fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParseError> {
2280 let if_not_exists = self.parse_if_not_exists();
2281 let name = self.parse_qualified_name()?;
2282 self.expect_kw(&TokenKind::KwOn)?;
2283 let table = self.parse_identifier()?;
2284 self.expect_token(&TokenKind::LeftParen)?;
2285 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
2286 self.expect_token(&TokenKind::RightParen)?;
2287 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
2288 Some(self.parse_expr()?)
2289 } else {
2290 None
2291 };
2292 Ok(Statement::CreateIndex(CreateIndexStatement {
2293 unique,
2294 if_not_exists,
2295 name,
2296 table,
2297 columns,
2298 where_clause,
2299 }))
2300 }
2301
2302 fn parse_create_view(&mut self, temporary: bool) -> Result<Statement, ParseError> {
2303 let if_not_exists = self.parse_if_not_exists();
2304 let name = self.parse_qualified_name()?;
2305 let columns = if self.check(&TokenKind::LeftParen) {
2306 self.advance();
2307 let cols = self.parse_comma_sep(Self::parse_identifier)?;
2308 self.expect_token(&TokenKind::RightParen)?;
2309 cols
2310 } else {
2311 vec![]
2312 };
2313 self.expect_kw(&TokenKind::KwAs)?;
2314 let with = if self.check_kw(&TokenKind::KwWith) {
2315 Some(self.parse_with_clause()?)
2316 } else {
2317 None
2318 };
2319 let query = self.parse_select_stmt(with)?;
2320 Ok(Statement::CreateView(CreateViewStatement {
2321 if_not_exists,
2322 temporary,
2323 name,
2324 columns,
2325 query,
2326 }))
2327 }
2328
2329 fn parse_trigger_body_statement_inner(&mut self) -> Result<Statement, ParseError> {
2330 match self.peek().clone() {
2331 TokenKind::KwSelect | TokenKind::KwValues => {
2332 Ok(Statement::Select(self.parse_select_stmt(None)?))
2333 }
2334 TokenKind::KwWith => {
2335 let with = self.parse_with_clause()?;
2339 if matches!(self.peek(), TokenKind::KwSelect | TokenKind::KwValues) {
2340 Ok(Statement::Select(self.parse_select_stmt(Some(with))?))
2341 } else {
2342 Err(self.err_expected("SELECT or VALUES after WITH in a trigger body"))
2343 }
2344 }
2345 TokenKind::KwInsert | TokenKind::KwReplace => {
2346 self.parse_insert_stmt(None, DmlParseContext::TriggerBody)
2347 }
2348 TokenKind::KwUpdate => self.parse_update_stmt(None, DmlParseContext::TriggerBody),
2349 TokenKind::KwDelete => self.parse_delete_stmt(None, DmlParseContext::TriggerBody),
2350 _ => Err(self.err_unexpected(
2351 "trigger body statement must be SELECT, INSERT, UPDATE, or DELETE",
2352 )),
2353 }
2354 }
2355
2356 fn parse_trigger_body_statement(&mut self) -> Result<Statement, ParseError> {
2357 self.parse_trigger_body_statement_inner()
2358 }
2359
2360 fn parse_create_trigger(&mut self, temporary: bool) -> Result<Statement, ParseError> {
2361 let if_not_exists = self.parse_if_not_exists();
2362 let name = self.parse_qualified_name()?;
2363 let timing = if self.eat_kw(&TokenKind::KwBefore) {
2364 TriggerTiming::Before
2365 } else if self.eat_kw(&TokenKind::KwAfter) {
2366 TriggerTiming::After
2367 } else if self.eat_kw(&TokenKind::KwInstead) {
2368 self.expect_kw(&TokenKind::KwOf)?;
2369 TriggerTiming::InsteadOf
2370 } else {
2371 TriggerTiming::Before };
2373 let event = if self.eat_kw(&TokenKind::KwInsert) {
2374 TriggerEvent::Insert
2375 } else if self.eat_kw(&TokenKind::KwDelete) {
2376 TriggerEvent::Delete
2377 } else {
2378 self.expect_kw(&TokenKind::KwUpdate)?;
2379 let cols = if self.eat_kw(&TokenKind::KwOf) {
2380 self.parse_comma_sep(Self::parse_identifier)?
2381 } else {
2382 vec![]
2383 };
2384 TriggerEvent::Update(cols)
2385 };
2386 self.expect_kw(&TokenKind::KwOn)?;
2387 let table = self.parse_identifier()?;
2388 let for_each_row = if self.eat_kw(&TokenKind::KwFor) {
2389 self.expect_kw(&TokenKind::KwEach)?;
2390 self.expect_kw(&TokenKind::KwRow)?;
2391 true
2392 } else {
2393 false
2394 };
2395 let when = if self.eat_kw(&TokenKind::KwWhen) {
2396 Some(self.parse_expr()?)
2397 } else {
2398 None
2399 };
2400 self.expect_kw(&TokenKind::KwBegin)?;
2401 let mut body = Vec::new();
2402 if self.check_kw(&TokenKind::KwEnd) {
2403 let error = self.err_unexpected("trigger body must contain at least one statement");
2404 self.recover_trigger_body_after_error(self.pos);
2405 return Err(error);
2406 }
2407 loop {
2408 if self.check_kw(&TokenKind::KwEnd) {
2409 break;
2410 }
2411 let statement_start = self.pos;
2412 let stmt = match self.parse_trigger_body_statement() {
2413 Ok(stmt) => stmt,
2414 Err(err) => {
2415 self.recover_trigger_body_after_error(statement_start);
2416 return Err(err);
2417 }
2418 };
2419 body.push(stmt);
2420 if !self.eat(&TokenKind::Semicolon) {
2421 let error = self.err_expected("';' after trigger body statement");
2422 self.recover_trigger_body_after_error(self.pos);
2426 return Err(error);
2427 }
2428 }
2429 self.expect_kw(&TokenKind::KwEnd)?;
2430 Ok(Statement::CreateTrigger(CreateTriggerStatement {
2431 if_not_exists,
2432 temporary,
2433 name,
2434 timing,
2435 event,
2436 table,
2437 for_each_row,
2438 when,
2439 body,
2440 }))
2441 }
2442
2443 fn parse_create_virtual_table(&mut self) -> Result<Statement, ParseError> {
2444 let if_not_exists = self.parse_if_not_exists();
2445 let name = self.parse_qualified_name()?;
2446 self.expect_kw(&TokenKind::KwUsing)?;
2447 let module = self.parse_identifier()?;
2448 let args = if self.eat(&TokenKind::LeftParen) {
2449 if self.check(&TokenKind::RightParen) {
2450 self.advance();
2451 vec![]
2452 } else {
2453 let mut args = Vec::new();
2455 let mut depth = 0i32;
2456 let mut current_arg = String::new();
2457 loop {
2458 match self.peek() {
2459 TokenKind::RightParen if depth == 0 => {
2460 self.advance();
2461 args.push(current_arg.trim().to_owned());
2462 break;
2463 }
2464 TokenKind::LeftParen => {
2465 depth += 1;
2466 current_arg.push('(');
2467 self.advance();
2468 }
2469 TokenKind::RightParen => {
2470 depth -= 1;
2471 current_arg.push(')');
2472 self.advance();
2473 }
2474 TokenKind::Comma if depth == 0 => {
2475 args.push(current_arg.trim().to_owned());
2476 current_arg = String::new();
2477 self.advance();
2478 }
2479 TokenKind::Eof => {
2480 return Err(self.err_expected("closing parenthesis"));
2481 }
2482 _ => {
2483 let t = self
2485 .current()
2486 .ok_or_else(|| self.err_expected("virtual table argument token"))?;
2487 let text = t.kind.to_sql();
2488 if !current_arg.is_empty()
2489 && !current_arg.ends_with(' ')
2490 && !text.is_empty()
2491 {
2492 current_arg.push(' ');
2493 }
2494 current_arg.push_str(&text);
2495 self.advance();
2496 }
2497 }
2498 }
2499 args
2500 }
2501 } else {
2502 vec![]
2503 };
2504 Ok(Statement::CreateVirtualTable(CreateVirtualTableStatement {
2505 if_not_exists,
2506 name,
2507 module,
2508 args,
2509 }))
2510 }
2511
2512 fn parse_drop(&mut self) -> Result<Statement, ParseError> {
2517 self.expect_kw(&TokenKind::KwDrop)?;
2518 let object_type = if self.eat_kw(&TokenKind::KwTable) {
2519 DropObjectType::Table
2520 } else if self.eat_kw(&TokenKind::KwView) {
2521 DropObjectType::View
2522 } else if self.eat_kw(&TokenKind::KwIndex) {
2523 DropObjectType::Index
2524 } else if self.eat_kw(&TokenKind::KwTrigger) {
2525 DropObjectType::Trigger
2526 } else {
2527 return Err(self.err_expected("TABLE, VIEW, INDEX, or TRIGGER"));
2528 };
2529 let if_exists =
2530 if self.check_kw(&TokenKind::KwIf) && self.peek_nth(1) == &TokenKind::KwExists {
2531 self.advance();
2532 self.advance();
2533 true
2534 } else {
2535 false
2536 };
2537 let name = self.parse_qualified_name()?;
2538 Ok(Statement::Drop(DropStatement {
2539 object_type,
2540 if_exists,
2541 name,
2542 }))
2543 }
2544
2545 fn parse_alter(&mut self) -> Result<Statement, ParseError> {
2550 self.expect_kw(&TokenKind::KwAlter)?;
2551 self.expect_kw(&TokenKind::KwTable)?;
2552 let table = self.parse_qualified_name()?;
2553 let action = if self.eat_kw(&TokenKind::KwRename) {
2554 if self.eat_kw(&TokenKind::KwTo) {
2555 AlterTableAction::RenameTo(self.parse_identifier()?)
2556 } else {
2557 let _ = self.eat_kw(&TokenKind::KwColumn);
2558 let old = self.parse_identifier()?;
2559 self.expect_kw(&TokenKind::KwTo)?;
2560 let new = self.parse_identifier()?;
2561 AlterTableAction::RenameColumn { old, new }
2562 }
2563 } else if self.eat_kw(&TokenKind::KwAdd) {
2564 let _ = self.eat_kw(&TokenKind::KwColumn);
2565 AlterTableAction::AddColumn(self.parse_column_def()?)
2566 } else if self.eat_kw(&TokenKind::KwDrop) {
2567 let _ = self.eat_kw(&TokenKind::KwColumn);
2568 AlterTableAction::DropColumn(self.parse_identifier()?)
2569 } else {
2570 return Err(self.err_expected("RENAME, ADD, or DROP"));
2571 };
2572 Ok(Statement::AlterTable(AlterTableStatement { table, action }))
2573 }
2574
2575 fn parse_begin(&mut self) -> Result<Statement, ParseError> {
2580 self.expect_kw(&TokenKind::KwBegin)?;
2581 let mode = if self.eat_kw(&TokenKind::KwDeferred) {
2582 Some(TransactionMode::Deferred)
2583 } else if self.eat_kw(&TokenKind::KwImmediate) {
2584 Some(TransactionMode::Immediate)
2585 } else if self.eat_kw(&TokenKind::KwExclusive) {
2586 Some(TransactionMode::Exclusive)
2587 } else if self.eat_kw(&TokenKind::KwConcurrent) {
2588 Some(TransactionMode::Concurrent)
2589 } else {
2590 None
2591 };
2592 let _ = self.eat_kw(&TokenKind::KwTransaction);
2594 Ok(Statement::Begin(BeginStatement { mode }))
2595 }
2596
2597 fn parse_rollback(&mut self) -> Result<Statement, ParseError> {
2598 self.expect_kw(&TokenKind::KwRollback)?;
2599 let _ = self.eat_kw(&TokenKind::KwTransaction);
2600 let to_savepoint = if self.eat_kw(&TokenKind::KwTo) {
2601 let _ = self.eat_kw(&TokenKind::KwSavepoint);
2602 Some(self.parse_identifier()?)
2603 } else {
2604 None
2605 };
2606 Ok(Statement::Rollback(RollbackStatement { to_savepoint }))
2607 }
2608
2609 fn parse_attach(&mut self) -> Result<Statement, ParseError> {
2614 self.expect_kw(&TokenKind::KwAttach)?;
2615 let _ = self.eat_kw(&TokenKind::KwDatabase);
2616 let expr = self.parse_expr()?;
2617 self.expect_kw(&TokenKind::KwAs)?;
2618 let schema = self.parse_identifier()?;
2619 Ok(Statement::Attach(AttachStatement { expr, schema }))
2620 }
2621
2622 fn parse_pragma_value_expr(
2623 &mut self,
2624 preserve_numeric_spelling: bool,
2625 ) -> Result<Expr, ParseError> {
2626 if preserve_numeric_spelling && let Some(sql) = &self.pragma_source_sql {
2627 let signed = matches!(self.peek(), TokenKind::Plus | TokenKind::Minus);
2628 let offset = usize::from(signed);
2629 if matches!(
2630 self.peek_nth(offset),
2631 TokenKind::Integer(_) | TokenKind::OversizedInt(_) | TokenKind::Float(_)
2632 ) {
2633 let token = &self.tokens[self.pos + offset];
2634 let raw = &sql[token.span.start as usize..token.span.end as usize];
2635 if raw.contains('_') {
2636 let mut error = ParseError::at(
2637 "numeric separators are not valid PRAGMA arguments",
2638 Some(token),
2639 );
2640 error.kind = ParseErrorKind::UnexpectedToken;
2641 return Err(error);
2642 }
2643 let value = if matches!(self.peek(), TokenKind::Minus) {
2647 format!("-{raw}")
2648 } else {
2649 raw.to_owned()
2650 };
2651 let span = Span::new(self.current_span().start, token.span.end);
2652 if signed {
2653 self.advance();
2654 }
2655 self.advance();
2656 return Ok(Expr::Literal(Literal::String(value), span));
2657 }
2658 }
2659 if self.check_kw(&TokenKind::KwOn) {
2663 let sp = self.current_span();
2664 self.advance();
2665 return Ok(Expr::Literal(Literal::True, sp));
2666 }
2667 let pragma_value_keyword = match self.peek() {
2675 TokenKind::KwDelete => Some("delete"),
2676 TokenKind::KwDefault => Some("default"),
2677 _ => None,
2678 };
2679 if let Some(name) = pragma_value_keyword {
2680 let sp = self.current_span();
2681 self.advance();
2682 return Ok(Expr::Column(ColumnRef::bare(name), sp));
2683 }
2684 self.parse_expr()
2685 }
2686
2687 fn parse_pragma(&mut self) -> Result<Statement, ParseError> {
2688 self.expect_kw(&TokenKind::KwPragma)?;
2689 let name = self.parse_qualified_name()?;
2690 let preserve_numeric_spelling = name.name.eq_ignore_ascii_case("cache_size")
2691 || name.name.eq_ignore_ascii_case("default_cache_size");
2692 let value = if self.eat(&TokenKind::Eq) || self.eat(&TokenKind::EqEq) {
2693 Some(PragmaValue::Assign(
2694 self.parse_pragma_value_expr(preserve_numeric_spelling)?,
2695 ))
2696 } else if self.eat(&TokenKind::LeftParen) {
2697 let v = self.parse_pragma_value_expr(preserve_numeric_spelling)?;
2698 self.expect_token(&TokenKind::RightParen)?;
2699 Some(PragmaValue::Call(v))
2700 } else {
2701 None
2702 };
2703 Ok(Statement::Pragma(PragmaStatement { name, value }))
2704 }
2705
2706 fn parse_vacuum(&mut self) -> Result<Statement, ParseError> {
2707 self.expect_kw(&TokenKind::KwVacuum)?;
2708 let schema = if !self.at_eof()
2709 && !self.check(&TokenKind::Semicolon)
2710 && !self.check_kw(&TokenKind::KwInto)
2711 {
2712 Some(self.parse_identifier()?)
2713 } else {
2714 None
2715 };
2716 let into = if self.eat_kw(&TokenKind::KwInto) {
2717 Some(self.parse_expr()?)
2718 } else {
2719 None
2720 };
2721 Ok(Statement::Vacuum(VacuumStatement { schema, into }))
2722 }
2723
2724 fn parse_explain(&mut self) -> Result<Statement, ParseError> {
2725 self.expect_kw(&TokenKind::KwExplain)?;
2726 let query_plan = if self.eat_kw(&TokenKind::KwQuery) {
2727 self.expect_kw(&TokenKind::KwPlan)?;
2728 true
2729 } else {
2730 false
2731 };
2732 if self.check_kw(&TokenKind::KwExplain) {
2733 return Err(self.err_unexpected("nested EXPLAIN is not allowed"));
2734 }
2735 let stmt = self.parse_statement_inner()?;
2736 Ok(Statement::Explain {
2737 query_plan,
2738 stmt: Box::new(stmt),
2739 })
2740 }
2741
2742 #[cfg(test)]
2747 fn parse_window_def(&mut self) -> Result<WindowDef, ParseError> {
2748 let name = self.parse_window_name()?;
2749 self.expect_kw(&TokenKind::KwAs)?;
2750 self.expect_token(&TokenKind::LeftParen)?;
2751 let spec = self.parse_window_spec()?;
2752 self.expect_token(&TokenKind::RightParen)?;
2753 Ok(WindowDef { name, spec })
2754 }
2755
2756 #[cfg(test)]
2757 pub(crate) fn parse_window_spec(&mut self) -> Result<WindowSpec, ParseError> {
2758 let has_base_window = starts_window_base_name(self.peek());
2760 let base_window = if has_base_window {
2761 Some(self.parse_window_name()?)
2762 } else {
2763 None
2764 };
2765 let partition_by = if self.eat_kw(&TokenKind::KwPartition) {
2766 self.expect_kw(&TokenKind::KwBy)?;
2767 self.parse_comma_sep(Self::parse_expr)?
2768 } else {
2769 vec![]
2770 };
2771 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
2772 self.expect_kw(&TokenKind::KwBy)?;
2773 self.parse_comma_sep(Self::parse_ordering_term)?
2774 } else {
2775 vec![]
2776 };
2777 let frame = self.try_frame_spec()?;
2778 Ok(WindowSpec {
2779 window_ref: base_window.map(WindowReference::Base),
2780 partition_by,
2781 order_by,
2782 frame,
2783 })
2784 }
2785
2786 #[cfg(test)]
2787 fn try_frame_spec(&mut self) -> Result<Option<FrameSpec>, ParseError> {
2788 let frame_type = if self.eat_kw(&TokenKind::KwRows) {
2789 FrameType::Rows
2790 } else if self.eat_kw(&TokenKind::KwRange) {
2791 FrameType::Range
2792 } else if self.eat_kw(&TokenKind::KwGroups) {
2793 FrameType::Groups
2794 } else {
2795 return Ok(None);
2796 };
2797 let (start, end) = if self.eat_kw(&TokenKind::KwBetween) {
2798 let start = self.parse_frame_bound()?;
2799 validate_frame_start(&start, true)?;
2800 self.expect_kw(&TokenKind::KwAnd)?;
2801 let end = self.parse_frame_bound()?;
2802 validate_frame_end(&start, &end)?;
2803 (start, Some(end))
2804 } else {
2805 let start = self.parse_frame_bound()?;
2806 validate_frame_start(&start, false)?;
2807 (start, None)
2808 };
2809 let exclude = if self.eat_kw(&TokenKind::KwExclude) {
2810 if self.check_kw(&TokenKind::KwNo) {
2811 self.advance();
2812 let id = self.parse_identifier()?;
2814 if !id.eq_ignore_ascii_case("OTHERS") {
2815 return Err(self.err_expected("OTHERS"));
2816 }
2817 Some(FrameExclude::NoOthers)
2818 } else if self.eat_kw(&TokenKind::KwTies) {
2819 Some(FrameExclude::Ties)
2820 } else if self.eat_kw(&TokenKind::KwGroup) {
2821 Some(FrameExclude::Group)
2822 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2823 self.advance();
2824 self.expect_kw(&TokenKind::KwRow)?;
2825 Some(FrameExclude::CurrentRow)
2826 } else {
2827 return Err(
2828 self.err_expected("NO OTHERS, TIES, GROUP, or CURRENT ROW after EXCLUDE")
2829 );
2830 }
2831 } else {
2832 None
2833 };
2834 Ok(Some(FrameSpec {
2835 frame_type,
2836 start: start.value,
2837 end: end.map(|bound| bound.value),
2838 exclude,
2839 }))
2840 }
2841
2842 #[cfg(test)]
2843 fn parse_frame_bound(&mut self) -> Result<ParsedFrameBound, ParseError> {
2844 let origin = self
2845 .current()
2846 .cloned()
2847 .ok_or_else(|| self.err_expected("window frame bound"))?;
2848 let value = if self.eat_kw(&TokenKind::KwUnbounded) {
2849 if self.eat_kw(&TokenKind::KwPreceding) {
2850 FrameBound::UnboundedPreceding
2851 } else {
2852 self.expect_kw(&TokenKind::KwFollowing)?;
2853 FrameBound::UnboundedFollowing
2854 }
2855 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
2856 self.advance();
2857 self.expect_kw(&TokenKind::KwRow)?;
2858 FrameBound::CurrentRow
2859 } else {
2860 let expr = self.parse_expr()?;
2861 if self.eat_kw(&TokenKind::KwPreceding) {
2862 FrameBound::Preceding(Box::new(expr))
2863 } else {
2864 self.expect_kw(&TokenKind::KwFollowing)?;
2865 FrameBound::Following(Box::new(expr))
2866 }
2867 };
2868 Ok(ParsedFrameBound { value, origin })
2869 }
2870}
2871
2872fn parse_statements_with_scratch_inner(
2873 sql: &str,
2874 scratch: &mut StatementParseScratch,
2875) -> (Vec<Statement>, Option<ParseError>) {
2876 Lexer::tokenize_into_with_interner(sql, &mut scratch.tokens, &mut scratch.identifier_interner);
2877 let mut parser = Parser {
2878 tokens: std::mem::take(&mut scratch.tokens),
2879 pragma_source_sql: None,
2880 pos: 0,
2881 errors: std::mem::take(&mut scratch.errors),
2882 depth: 0,
2883 has_with: false,
2884 };
2885 parser.preserve_pragma_source(sql);
2886 let (statements, errors) = parser.parse_all();
2887 scratch.tokens = parser.tokens;
2888 scratch.tokens.clear();
2889 scratch.identifier_interner.prepare_for_next_parse();
2890 scratch.errors = errors;
2891 let first_error = scratch.errors.first().cloned();
2892 scratch.errors.clear();
2893 (statements, first_error)
2894}
2895
2896pub fn parse_statements_with_scratch(
2905 sql: &str,
2906 scratch: &mut StatementParseScratch,
2907) -> Result<Vec<Statement>, ParseError> {
2908 let (statements, first_error) = parse_statements_with_scratch_inner(sql, scratch);
2909 if let Some(error) = first_error {
2910 return Err(error);
2911 }
2912 Ok(statements)
2913}
2914
2915pub fn parse_single_statement_with_scratch(
2917 sql: &str,
2918 scratch: &mut StatementParseScratch,
2919) -> Result<Statement, ParseError> {
2920 let statements = parse_statements_with_scratch(sql, scratch)?;
2921 let mut iter = statements.into_iter();
2922 let statement = iter
2923 .next()
2924 .ok_or_else(|| ParseError::at("no SQL statement provided", None))?;
2925 if iter.next().is_some() {
2926 return Err(ParseError::at(
2927 "multiple statements are not supported in this API path",
2928 None,
2929 ));
2930 }
2931 Ok(statement)
2932}
2933
2934pub fn parse_first_statement_with_tail(
2942 sql: &str,
2943) -> Result<Option<(Statement, usize)>, ParseError> {
2944 let mut parser = Parser::from_sql(sql);
2945
2946 while parser.eat(&TokenKind::Semicolon) {}
2947 if parser.at_eof() {
2948 return Ok(None);
2949 }
2950
2951 let statement = parser.parse_statement()?;
2952 let tail_offset = if parser.eat(&TokenKind::Semicolon) {
2953 parser
2954 .tokens
2955 .get(parser.pos.saturating_sub(1))
2956 .map_or(sql.len(), |token| token.span.end as usize)
2957 } else if parser.at_eof() {
2958 sql.len()
2959 } else {
2960 return Err(parser
2961 .err_unexpected("unexpected token after end of statement; expected ';' separator"));
2962 };
2963
2964 Ok(Some((statement, tail_offset)))
2965}
2966
2967pub(crate) fn starts_bare_window_name(k: &TokenKind) -> bool {
2977 matches!(
2978 k,
2979 TokenKind::Id(_) | TokenKind::QuotedId(_, _) | TokenKind::String(_)
2980 ) || (is_nonreserved_kw(k) && !matches!(k, TokenKind::KwFilter))
2981 || matches!(
2982 k,
2983 TokenKind::KwAttach
2984 | TokenKind::KwBegin
2985 | TokenKind::KwBy
2986 | TokenKind::KwCast
2987 | TokenKind::KwCurrentDate
2988 | TokenKind::KwCurrentTime
2989 | TokenKind::KwCurrentTimestamp
2990 | TokenKind::KwCross
2991 | TokenKind::KwDetach
2992 | TokenKind::KwExplain
2993 | TokenKind::KwFalse
2994 | TokenKind::KwFor
2995 | TokenKind::KwGlob
2996 | TokenKind::KwInner
2997 | TokenKind::KwLeft
2998 | TokenKind::KwLike
2999 | TokenKind::KwNatural
3000 | TokenKind::KwOuter
3001 | TokenKind::KwRaise
3002 | TokenKind::KwRegexp
3003 | TokenKind::KwRight
3004 | TokenKind::KwRollback
3005 | TokenKind::KwTrue
3006 | TokenKind::KwWith
3007 )
3008}
3009
3010pub(crate) fn starts_window_base_name(k: &TokenKind) -> bool {
3015 starts_bare_window_name(k)
3016 && !matches!(
3017 k,
3018 TokenKind::KwPartition
3019 | TokenKind::KwOrder
3020 | TokenKind::KwRange
3021 | TokenKind::KwRows
3022 | TokenKind::KwGroups
3023 )
3024}
3025
3026pub(crate) fn starts_post_dot_identifier(k: &TokenKind) -> bool {
3027 matches!(
3028 k,
3029 TokenKind::Id(_) | TokenKind::QuotedId(_, _) | TokenKind::String(_)
3030 ) || (k.keyword_str().is_some()
3031 && !matches!(
3032 k,
3033 TokenKind::KwAdd
3034 | TokenKind::KwAll
3035 | TokenKind::KwAlter
3036 | TokenKind::KwAnd
3037 | TokenKind::KwAs
3038 | TokenKind::KwAutoincrement
3039 | TokenKind::KwBetween
3040 | TokenKind::KwCase
3041 | TokenKind::KwCheck
3042 | TokenKind::KwCollate
3043 | TokenKind::KwCommit
3044 | TokenKind::KwConstraint
3045 | TokenKind::KwCreate
3046 | TokenKind::KwDefault
3047 | TokenKind::KwDeferrable
3048 | TokenKind::KwDelete
3049 | TokenKind::KwDistinct
3050 | TokenKind::KwDrop
3051 | TokenKind::KwElse
3052 | TokenKind::KwEscape
3053 | TokenKind::KwExcept
3054 | TokenKind::KwExists
3055 | TokenKind::KwForeign
3056 | TokenKind::KwFrom
3057 | TokenKind::KwGroup
3058 | TokenKind::KwHaving
3059 | TokenKind::KwIn
3060 | TokenKind::KwIndex
3061 | TokenKind::KwInsert
3062 | TokenKind::KwIntersect
3063 | TokenKind::KwInto
3064 | TokenKind::KwIs
3065 | TokenKind::KwIsnull
3066 | TokenKind::KwJoin
3067 | TokenKind::KwLimit
3068 | TokenKind::KwNot
3069 | TokenKind::KwNothing
3070 | TokenKind::KwNotnull
3071 | TokenKind::KwNull
3072 | TokenKind::KwOn
3073 | TokenKind::KwOr
3074 | TokenKind::KwOrder
3075 | TokenKind::KwPrimary
3076 | TokenKind::KwReferences
3077 | TokenKind::KwReturning
3078 | TokenKind::KwSelect
3079 | TokenKind::KwSet
3080 | TokenKind::KwTable
3081 | TokenKind::KwThen
3082 | TokenKind::KwTo
3083 | TokenKind::KwTransaction
3084 | TokenKind::KwUnion
3085 | TokenKind::KwUnique
3086 | TokenKind::KwUpdate
3087 | TokenKind::KwUsing
3088 | TokenKind::KwValues
3089 | TokenKind::KwWhen
3090 | TokenKind::KwWhere
3091 ))
3092}
3093
3094pub(crate) fn starts_table_star_qualifier(k: &TokenKind) -> bool {
3095 matches!(
3096 k,
3097 TokenKind::Id(_)
3098 | TokenKind::QuotedId(_, _)
3099 | TokenKind::String(_)
3100 | TokenKind::KwAbort
3101 | TokenKind::KwAction
3102 | TokenKind::KwAfter
3103 | TokenKind::KwAlways
3104 | TokenKind::KwAnalyze
3105 | TokenKind::KwAsc
3106 | TokenKind::KwAttach
3107 | TokenKind::KwBefore
3108 | TokenKind::KwBegin
3109 | TokenKind::KwBy
3110 | TokenKind::KwCascade
3111 | TokenKind::KwColumn
3112 | TokenKind::KwCommitseq
3113 | TokenKind::KwConcurrent
3114 | TokenKind::KwConflict
3115 | TokenKind::KwCross
3116 | TokenKind::KwDatabase
3117 | TokenKind::KwDeferred
3118 | TokenKind::KwDesc
3119 | TokenKind::KwDetach
3120 | TokenKind::KwDo
3121 | TokenKind::KwEach
3122 | TokenKind::KwEnd
3123 | TokenKind::KwExclude
3124 | TokenKind::KwExclusive
3125 | TokenKind::KwExplain
3126 | TokenKind::KwFail
3127 | TokenKind::KwFalse
3128 | TokenKind::KwFilter
3129 | TokenKind::KwFirst
3130 | TokenKind::KwFollowing
3131 | TokenKind::KwFor
3132 | TokenKind::KwFull
3133 | TokenKind::KwGenerated
3134 | TokenKind::KwGlob
3135 | TokenKind::KwGroups
3136 | TokenKind::KwIf
3137 | TokenKind::KwIgnore
3138 | TokenKind::KwImmediate
3139 | TokenKind::KwIndexed
3140 | TokenKind::KwInitially
3141 | TokenKind::KwInner
3142 | TokenKind::KwInstead
3143 | TokenKind::KwKey
3144 | TokenKind::KwLast
3145 | TokenKind::KwLeft
3146 | TokenKind::KwLike
3147 | TokenKind::KwMatch
3148 | TokenKind::KwMaterialized
3149 | TokenKind::KwNatural
3150 | TokenKind::KwNo
3151 | TokenKind::KwNulls
3152 | TokenKind::KwOf
3153 | TokenKind::KwOffset
3154 | TokenKind::KwOthers
3155 | TokenKind::KwOuter
3156 | TokenKind::KwOver
3157 | TokenKind::KwPartition
3158 | TokenKind::KwPlan
3159 | TokenKind::KwPragma
3160 | TokenKind::KwPreceding
3161 | TokenKind::KwQuery
3162 | TokenKind::KwRange
3163 | TokenKind::KwRecursive
3164 | TokenKind::KwRegexp
3165 | TokenKind::KwReindex
3166 | TokenKind::KwRelease
3167 | TokenKind::KwRename
3168 | TokenKind::KwReplace
3169 | TokenKind::KwRestrict
3170 | TokenKind::KwRight
3171 | TokenKind::KwRollback
3172 | TokenKind::KwRow
3173 | TokenKind::KwRows
3174 | TokenKind::KwSavepoint
3175 | TokenKind::KwStored
3176 | TokenKind::KwStrict
3177 | TokenKind::KwTemp
3178 | TokenKind::KwTemporary
3179 | TokenKind::KwTies
3180 | TokenKind::KwTrigger
3181 | TokenKind::KwTrue
3182 | TokenKind::KwUnbounded
3183 | TokenKind::KwVacuum
3184 | TokenKind::KwView
3185 | TokenKind::KwVirtual
3186 | TokenKind::KwWindow
3187 | TokenKind::KwWith
3188 | TokenKind::KwWithout
3189 )
3190}
3191
3192pub(crate) fn is_nonreserved_kw(k: &TokenKind) -> bool {
3193 matches!(
3194 k,
3195 TokenKind::KwAbort
3196 | TokenKind::KwAction
3197 | TokenKind::KwAfter
3198 | TokenKind::KwAlways
3199 | TokenKind::KwAnalyze
3200 | TokenKind::KwAsc
3201 | TokenKind::KwBefore
3202 | TokenKind::KwCascade
3203 | TokenKind::KwColumn
3204 | TokenKind::KwConcurrent
3205 | TokenKind::KwConflict
3206 | TokenKind::KwDatabase
3207 | TokenKind::KwDeferred
3208 | TokenKind::KwDesc
3209 | TokenKind::KwDo
3210 | TokenKind::KwEach
3211 | TokenKind::KwEnd
3212 | TokenKind::KwExclude
3213 | TokenKind::KwExclusive
3214 | TokenKind::KwFail
3215 | TokenKind::KwFilter
3216 | TokenKind::KwFirst
3217 | TokenKind::KwFollowing
3218 | TokenKind::KwFull
3219 | TokenKind::KwGenerated
3220 | TokenKind::KwGroups
3221 | TokenKind::KwIf
3222 | TokenKind::KwIgnore
3223 | TokenKind::KwImmediate
3224 | TokenKind::KwInitially
3225 | TokenKind::KwInstead
3226 | TokenKind::KwKey
3227 | TokenKind::KwLast
3228 | TokenKind::KwMatch
3229 | TokenKind::KwMaterialized
3230 | TokenKind::KwNo
3231 | TokenKind::KwNulls
3232 | TokenKind::KwOf
3233 | TokenKind::KwOffset
3234 | TokenKind::KwOthers
3235 | TokenKind::KwOver
3236 | TokenKind::KwPartition
3237 | TokenKind::KwPlan
3238 | TokenKind::KwPragma
3239 | TokenKind::KwPreceding
3240 | TokenKind::KwQuery
3241 | TokenKind::KwRange
3242 | TokenKind::KwRecursive
3243 | TokenKind::KwReindex
3244 | TokenKind::KwRelease
3245 | TokenKind::KwRename
3246 | TokenKind::KwReplace
3247 | TokenKind::KwRestrict
3248 | TokenKind::KwRow
3249 | TokenKind::KwRows
3250 | TokenKind::KwSavepoint
3251 | TokenKind::KwStored
3252 | TokenKind::KwStrict
3253 | TokenKind::KwTemp
3254 | TokenKind::KwTemporary
3255 | TokenKind::KwTies
3256 | TokenKind::KwTrigger
3257 | TokenKind::KwUnbounded
3258 | TokenKind::KwVacuum
3259 | TokenKind::KwView
3260 | TokenKind::KwVirtual
3261 | TokenKind::KwWindow
3262 | TokenKind::KwWithout
3263 )
3264}
3265
3266fn starts_explicit_alias_name(k: &TokenKind) -> bool {
3272 starts_post_dot_identifier(k)
3273}
3274
3275fn starts_result_alias(k: &TokenKind) -> bool {
3281 starts_explicit_alias_name(k)
3282 && !matches!(
3283 k,
3284 TokenKind::KwCross
3285 | TokenKind::KwFull
3286 | TokenKind::KwGlob
3287 | TokenKind::KwIndexed
3288 | TokenKind::KwInner
3289 | TokenKind::KwLeft
3290 | TokenKind::KwLike
3291 | TokenKind::KwMatch
3292 | TokenKind::KwNatural
3293 | TokenKind::KwOuter
3294 | TokenKind::KwRegexp
3295 | TokenKind::KwRight
3296 )
3297}
3298
3299fn starts_table_alias(k: &TokenKind) -> bool {
3305 starts_explicit_alias_name(k)
3306 && !matches!(
3307 k,
3308 TokenKind::KwCross
3309 | TokenKind::KwFull
3310 | TokenKind::KwIndexed
3311 | TokenKind::KwInner
3312 | TokenKind::KwIsnull
3313 | TokenKind::KwLeft
3314 | TokenKind::KwNatural
3315 | TokenKind::KwNotnull
3316 | TokenKind::KwOuter
3317 | TokenKind::KwRight
3318 )
3319}
3320
3321pub(crate) fn kw_to_str(k: &TokenKind) -> String {
3322 k.keyword_str()
3323 .map(|s| s.to_ascii_lowercase())
3324 .unwrap_or_else(|| {
3325 let dbg = format!("{k:?}");
3326 dbg.strip_prefix("Kw").unwrap_or(&dbg).to_ascii_lowercase()
3327 })
3328}
3329
3330#[cfg(test)]
3335mod tests {
3336 use super::*;
3337
3338 static PARSE_OBSERVABILITY_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
3339
3340 fn parse_ok(sql: &str) -> Vec<Statement> {
3341 let mut p = Parser::from_sql(sql);
3342 let (stmts, errs) = p.parse_all();
3343 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
3344 stmts
3345 }
3346
3347 fn parse_one(sql: &str) -> Statement {
3348 let stmts = parse_ok(sql);
3349 assert_eq!(stmts.len(), 1, "expected 1 statement, got {}", stmts.len());
3350 stmts.into_iter().next().unwrap()
3351 }
3352
3353 fn parse_full_select(sql: &str) -> SelectStatement {
3354 let Some((statement, tail_offset)) =
3355 parse_first_statement_with_tail(sql).expect("full SELECT statement must parse")
3356 else {
3357 panic!("expected one SELECT statement");
3358 };
3359 assert_eq!(
3360 tail_offset,
3361 sql.len(),
3362 "public parser must consume the full statement"
3363 );
3364 let Statement::Select(select) = statement else {
3365 panic!("expected SELECT AST");
3366 };
3367 select
3368 }
3369
3370 fn top_level_values(statement: &Statement) -> &ValuesClause {
3371 let Statement::Select(select) = statement else {
3372 panic!("expected SELECT statement");
3373 };
3374 let SelectCore::Values(values) = &select.body.select else {
3375 panic!("expected top-level VALUES core");
3376 };
3377 values
3378 }
3379
3380 fn scalar_subquery_values(expr: &Expr) -> &ValuesClause {
3381 let Expr::Subquery(select, _) = expr else {
3382 panic!("expected scalar subquery");
3383 };
3384 let SelectCore::Values(values) = &select.body.select else {
3385 panic!("expected VALUES scalar subquery");
3386 };
3387 values
3388 }
3389
3390 fn only_join(select: &SelectStatement) -> &JoinClause {
3391 let SelectCore::Select {
3392 from: Some(from), ..
3393 } = &select.body.select
3394 else {
3395 panic!("expected SELECT with FROM clause");
3396 };
3397 let [join] = from.joins.as_slice() else {
3398 panic!("expected exactly one join");
3399 };
3400 assert_eq!(join.join_type.kind, JoinKind::Cross);
3401 assert!(!join.join_type.natural);
3402 join
3403 }
3404
3405 #[test]
3406 fn test_comma_join_accepts_on_constraint_and_consumes_full_statement() {
3407 let select = parse_full_select("SELECT * FROM a, b ON a.id = b.id");
3408 assert!(matches!(
3409 &only_join(&select).constraint,
3410 Some(JoinConstraint::On(Expr::BinaryOp {
3411 op: fsqlite_ast::BinaryOp::Eq,
3412 ..
3413 }))
3414 ));
3415 }
3416
3417 #[test]
3418 fn test_comma_join_accepts_using_constraint_and_consumes_full_statement() {
3419 let select = parse_full_select("SELECT * FROM a, b USING(id)");
3420 assert!(matches!(
3421 &only_join(&select).constraint,
3422 Some(JoinConstraint::Using(columns))
3423 if columns.len() == 1 && columns[0] == "id"
3424 ));
3425 }
3426
3427 #[test]
3428 fn test_explicit_cross_join_accepts_on_constraint_and_consumes_full_statement() {
3429 let select = parse_full_select("SELECT * FROM a CROSS JOIN b ON a.id = b.id");
3430 assert!(matches!(
3431 &only_join(&select).constraint,
3432 Some(JoinConstraint::On(Expr::BinaryOp {
3433 op: fsqlite_ast::BinaryOp::Eq,
3434 ..
3435 }))
3436 ));
3437 }
3438
3439 #[test]
3440 fn test_nonreserved_keyword_table_star_uses_wildcard_ast() {
3441 let select = parse_full_select("SELECT filter.* FROM t AS filter");
3442 let SelectCore::Select { columns, .. } = &select.body.select else {
3443 panic!("expected SELECT core");
3444 };
3445 assert!(matches!(
3446 columns.as_slice(),
3447 [ResultColumn::TableStar(name)] if name == &QualifiedName::bare("filter")
3448 ));
3449 assert_eq!(
3450 select.to_string(),
3451 "SELECT \"filter\".* FROM t AS \"filter\""
3452 );
3453 }
3454
3455 #[test]
3456 fn test_table_star_qualifier_uses_sqlite_contextual_keyword_matrix() {
3457 for name in [
3458 "abort",
3459 "action",
3460 "after",
3461 "always",
3462 "analyze",
3463 "asc",
3464 "attach",
3465 "before",
3466 "begin",
3467 "by",
3468 "cascade",
3469 "column",
3470 "commitseq",
3471 "concurrent",
3472 "conflict",
3473 "cross",
3474 "database",
3475 "deferred",
3476 "desc",
3477 "detach",
3478 "do",
3479 "each",
3480 "end",
3481 "exclude",
3482 "exclusive",
3483 "explain",
3484 "fail",
3485 "false",
3486 "filter",
3487 "first",
3488 "following",
3489 "for",
3490 "full",
3491 "generated",
3492 "glob",
3493 "groups",
3494 "if",
3495 "ignore",
3496 "immediate",
3497 "indexed",
3498 "initially",
3499 "inner",
3500 "instead",
3501 "key",
3502 "last",
3503 "left",
3504 "like",
3505 "match",
3506 "materialized",
3507 "natural",
3508 "no",
3509 "nulls",
3510 "of",
3511 "offset",
3512 "others",
3513 "outer",
3514 "over",
3515 "partition",
3516 "plan",
3517 "pragma",
3518 "preceding",
3519 "query",
3520 "range",
3521 "recursive",
3522 "regexp",
3523 "reindex",
3524 "release",
3525 "rename",
3526 "replace",
3527 "restrict",
3528 "right",
3529 "rollback",
3530 "row",
3531 "rows",
3532 "savepoint",
3533 "stored",
3534 "strict",
3535 "temp",
3536 "temporary",
3537 "ties",
3538 "trigger",
3539 "true",
3540 "unbounded",
3541 "vacuum",
3542 "view",
3543 "virtual",
3544 "window",
3545 "with",
3546 "without",
3547 ] {
3548 let sql = format!("SELECT {name}.* FROM t AS \"{name}\"");
3549 let select = parse_full_select(&sql);
3550 let SelectCore::Select { columns, .. } = &select.body.select else {
3551 panic!("expected SELECT core for `{sql}`");
3552 };
3553 assert!(matches!(
3554 columns.as_slice(),
3555 [ResultColumn::TableStar(qualifier)] if qualifier == &QualifiedName::bare(name)
3556 ));
3557 }
3558
3559 for name in ["nothing", "transaction", "select", "table"] {
3560 let sql = format!("SELECT {name}.* FROM t AS \"{name}\"");
3561 parse_first_statement_with_tail(&sql)
3562 .expect_err("non-fallback table-star keywords must be rejected");
3563 }
3564 }
3565
3566 #[test]
3567 fn test_qualified_star_is_rejected_outside_result_columns() {
3568 for sql in ["SELECT 1 WHERE t.*", "SELECT abs(t.*) FROM t"] {
3569 let error = parse_first_statement_with_tail(sql)
3570 .expect_err("qualified star must not become an ordinary column expression");
3571 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
3574 assert_eq!(
3575 &sql[error.span.start as usize..error.span.end as usize],
3576 "*",
3577 "the diagnostic for `{sql}` must point at the illegal wildcard"
3578 );
3579 assert!(
3580 error.message.contains("expected column name after '.'"),
3581 "unexpected diagnostic for `{sql}`: {error:?}"
3582 );
3583 }
3584
3585 let valid = parse_full_select("SELECT t.*, filter.* FROM t AS filter");
3586 let SelectCore::Select { columns, .. } = &valid.body.select else {
3587 panic!("expected SELECT core");
3588 };
3589 assert!(matches!(
3590 columns.as_slice(),
3591 [ResultColumn::TableStar(first), ResultColumn::TableStar(second)]
3592 if first == &QualifiedName::bare("t")
3593 && second == &QualifiedName::bare("filter")
3594 ));
3595 }
3596
3597 #[test]
3598 fn test_single_quoted_qualified_identifiers_follow_identifier_context() {
3599 for (sql, expected) in [
3600 ("SELECT 't'.x FROM t", "SELECT t.x FROM t"),
3601 ("SELECT t.'x' FROM t", "SELECT t.x FROM t"),
3602 ("SELECT 't'.'x' FROM t", "SELECT t.x FROM t"),
3603 ("SELECT t.'select' FROM t", "SELECT t.\"select\" FROM t"),
3604 ("SELECT 't'.* FROM t", "SELECT t.* FROM t"),
3605 ] {
3606 let select = parse_full_select(sql);
3607 assert_eq!(
3608 select.to_string(),
3609 expected,
3610 "round-trip mismatch for `{sql}`"
3611 );
3612 }
3613 }
3614
3615 #[test]
3616 fn test_post_dot_identifier_classification_matches_unquoted_names() {
3617 for name in [
3618 "key",
3619 "window",
3620 "filter",
3621 "range",
3622 "rows",
3623 "groups",
3624 "match",
3625 "replace",
3626 "abort",
3627 "column",
3628 "strict",
3629 "true",
3630 "false",
3631 "current_date",
3632 "current_time",
3633 "current_timestamp",
3634 "like",
3635 "glob",
3636 "regexp",
3637 ] {
3638 parse_full_select(&format!("SELECT t.{name} FROM t"));
3639 }
3640
3641 for name in [
3642 "add",
3643 "all",
3644 "alter",
3645 "and",
3646 "as",
3647 "autoincrement",
3648 "between",
3649 "case",
3650 "check",
3651 "collate",
3652 "commit",
3653 "constraint",
3654 "create",
3655 "default",
3656 "deferrable",
3657 "delete",
3658 "distinct",
3659 "drop",
3660 "else",
3661 "escape",
3662 "except",
3663 "exists",
3664 "foreign",
3665 "select",
3666 "from",
3667 "group",
3668 "having",
3669 "in",
3670 "index",
3671 "insert",
3672 "intersect",
3673 "into",
3674 "is",
3675 "isnull",
3676 "join",
3677 "limit",
3678 "not",
3679 "nothing",
3680 "notnull",
3681 "null",
3682 "on",
3683 "or",
3684 "order",
3685 "primary",
3686 "references",
3687 "returning",
3688 "set",
3689 "table",
3690 "then",
3691 "to",
3692 "transaction",
3693 "union",
3694 "unique",
3695 "update",
3696 "using",
3697 "values",
3698 "when",
3699 "where",
3700 ] {
3701 let sql = format!("SELECT t.{name} FROM t");
3702 let error = parse_first_statement_with_tail(&sql)
3703 .expect_err("hard reserved names after a dot must require quoting");
3704 assert_eq!(
3705 &sql[error.span.start as usize..error.span.end as usize],
3706 name,
3707 "the diagnostic for `{sql}` must point at the rejected name"
3708 );
3709 }
3710
3711 for (sql, rejected) in [("SELECT t.1 FROM t", ".1"), ("SELECT t. 1 FROM t", "1")] {
3712 let error = parse_first_statement_with_tail(sql)
3713 .expect_err("numeric tokens after a dot must not become identifiers");
3714 assert_eq!(
3715 &sql[error.span.start as usize..error.span.end as usize],
3716 rejected
3717 );
3718 }
3719 }
3720
3721 #[test]
3722 fn test_leading_qualified_keyword_uses_dot_lookahead_only() {
3723 for name in [
3724 "attach", "begin", "by", "false", "filter", "glob", "inner", "left", "like", "natural",
3725 "outer", "regexp", "right", "rollback", "true", "with",
3726 ] {
3727 let sql = format!("SELECT {name}.x FROM (SELECT 1 AS x) AS \"{name}\"");
3728 let select = parse_full_select(&sql);
3729 let SelectCore::Select { columns, .. } = &select.body.select else {
3730 panic!("expected SELECT core for `{sql}`");
3731 };
3732 assert!(matches!(
3733 columns.as_slice(),
3734 [ResultColumn::Expr {
3735 expr: Expr::Column(column, _),
3736 alias: None,
3737 }] if column.table.as_deref() == Some(name) && column.column.as_ref() == "x"
3738 ));
3739 }
3740
3741 for name in ["cast", "current_date", "nothing", "raise", "transaction"] {
3742 let sql = format!("SELECT {name}.x FROM (SELECT 1 AS x) AS \"{name}\"");
3743 parse_first_statement_with_tail(&sql)
3744 .expect_err("non-fallback leading qualifiers must remain expressions or syntax");
3745 }
3746 }
3747
3748 #[test]
3749 fn test_result_alias_uses_sqlite_contextual_name_policy() {
3750 for (source, expected) in [
3751 ("'single quoted'", "single quoted"),
3752 ("attach", "attach"),
3753 ("cast", "cast"),
3754 ("current_date", "current_date"),
3755 ("false", "false"),
3756 ("raise", "raise"),
3757 ("rollback", "rollback"),
3758 ("true", "true"),
3759 ("with", "with"),
3760 ("window", "window"),
3761 ("offset", "offset"),
3762 ] {
3763 let sql = format!("SELECT 1 {source}");
3764 let select = parse_full_select(&sql);
3765 let SelectCore::Select { columns, .. } = &select.body.select else {
3766 panic!("expected SELECT core for `{sql}`");
3767 };
3768 assert!(matches!(
3769 columns.as_slice(),
3770 [ResultColumn::Expr {
3771 alias: Some(alias),
3772 ..
3773 }] if alias == expected
3774 ));
3775 }
3776
3777 for sql in [
3778 "SELECT 1 indexed",
3779 "SELECT 1 left",
3780 "SELECT 1 match",
3781 "SELECT 1 nothing",
3782 "SELECT 1 transaction",
3783 "SELECT 1 AS isnull",
3784 "SELECT 1 AS notnull",
3785 ] {
3786 parse_first_statement_with_tail(sql)
3787 .expect_err("operators and non-fallback names must not become result aliases");
3788 }
3789 }
3790
3791 #[test]
3792 fn test_table_alias_uses_sqlite_contextual_name_policy() {
3793 for (source, expected) in [
3794 ("'single quoted'", "single quoted"),
3795 ("attach", "attach"),
3796 ("cast", "cast"),
3797 ("current_date", "current_date"),
3798 ("false", "false"),
3799 ("for", "for"),
3800 ("match", "match"),
3801 ("raise", "raise"),
3802 ("rollback", "rollback"),
3803 ("true", "true"),
3804 ("with", "with"),
3805 ("window", "window"),
3806 ("offset", "offset"),
3807 ] {
3808 let sql = format!("SELECT * FROM (SELECT 1) {source}");
3809 let select = parse_full_select(&sql);
3810 let SelectCore::Select {
3811 from:
3812 Some(FromClause {
3813 source: TableOrSubquery::Subquery { alias, .. },
3814 ..
3815 }),
3816 ..
3817 } = &select.body.select
3818 else {
3819 panic!("expected aliased subquery for `{sql}`");
3820 };
3821 assert_eq!(
3822 alias.as_deref(),
3823 Some(expected),
3824 "alias mismatch for `{sql}`"
3825 );
3826 }
3827
3828 for sql in [
3829 "SELECT * FROM (SELECT 1) isnull",
3830 "SELECT * FROM (SELECT 1) notnull",
3831 "SELECT * FROM (SELECT 1) nothing",
3832 "SELECT * FROM (SELECT 1) transaction",
3833 ] {
3834 parse_first_statement_with_tail(sql)
3835 .expect_err("non-table-alias tokens must remain rejected");
3836 }
3837
3838 let select = parse_full_select("SELECT * FROM t WINDOW w AS ()");
3839 let SelectCore::Select { from, windows, .. } = &select.body.select else {
3840 panic!("expected SELECT core");
3841 };
3842 assert!(matches!(
3843 from,
3844 Some(FromClause {
3845 source: TableOrSubquery::Table { alias: None, .. },
3846 ..
3847 })
3848 ));
3849 assert_eq!(windows.len(), 1);
3850 assert_eq!(windows[0].name, "w");
3851
3852 let select = parse_full_select("SELECT * FROM t FOR SYSTEM_TIME AS OF COMMITSEQ 1");
3853 let SelectCore::Select { from, .. } = &select.body.select else {
3854 panic!("expected SELECT core");
3855 };
3856 assert!(matches!(
3857 from,
3858 Some(FromClause {
3859 source: TableOrSubquery::Table {
3860 alias: None,
3861 time_travel: Some(TimeTravelClause {
3862 target: TimeTravelTarget::CommitSequence(1),
3863 }),
3864 ..
3865 },
3866 ..
3867 })
3868 ));
3869 }
3870
3871 #[test]
3872 fn test_indexed_is_explicit_name_but_not_implicit_alias() {
3873 for sql in [
3874 "SELECT 1 AS indexed",
3875 "SELECT * FROM (SELECT 1) AS indexed",
3876 "CREATE TABLE t(indexed); SELECT t.indexed FROM t",
3877 ] {
3878 let mut parser = Parser::from_sql(sql);
3879 let (statements, errors) = parser.parse_all();
3880 assert!(
3881 errors.is_empty(),
3882 "unexpected errors for `{sql}`: {errors:?}"
3883 );
3884 assert!(
3885 !statements.is_empty(),
3886 "explicit INDEXED name context must produce an AST for `{sql}`"
3887 );
3888 }
3889
3890 for sql in ["SELECT 1 indexed", "SELECT * FROM (SELECT 1) indexed"] {
3891 parse_first_statement_with_tail(sql)
3892 .expect_err("INDEXED must remain unavailable as an implicit alias");
3893 }
3894 }
3895
3896 #[test]
3897 fn test_nested_explain_is_rejected_at_the_second_explain() {
3898 for sql in [
3899 "EXPLAIN EXPLAIN SELECT 1",
3900 "EXPLAIN QUERY PLAN EXPLAIN SELECT 1",
3901 ] {
3902 let error = parse_first_statement_with_tail(sql)
3903 .expect_err("SQLite does not permit nested EXPLAIN statements");
3904 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
3906 assert!(
3907 error.message.contains("nested EXPLAIN"),
3908 "unexpected diagnostic for `{sql}`: {error:?}"
3909 );
3910 let second_explain = sql
3911 .match_indices("EXPLAIN")
3912 .nth(1)
3913 .map(|(offset, _)| offset)
3914 .expect("test SQL must contain a second EXPLAIN");
3915 assert_eq!(
3916 &sql[error.span.start as usize..error.span.end as usize],
3917 &sql[second_explain..second_explain + "EXPLAIN".len()],
3918 "the nested-EXPLAIN diagnostic must point at the rejected keyword"
3919 );
3920 }
3921 }
3922
3923 #[test]
3924 fn test_generic_name_slots_use_sqlite_fallback_name_policy() {
3925 for sql in [
3926 "CREATE TABLE begin(x)",
3927 "SELECT * FROM begin",
3928 "DROP TABLE main.begin",
3929 ] {
3930 parse_first_statement_with_tail(sql)
3931 .expect("fallback-name keywords must parse in an established name slot");
3932 }
3933 }
3934
3935 #[test]
3936 fn test_hard_reserved_column_names_require_quoting_in_ddl() {
3937 for name in ["index", "nothing", "returning", "table", "transaction"] {
3938 let sql = format!("CREATE TABLE t({name} INTEGER)");
3939 let error = parse_first_statement_with_tail(&sql)
3940 .expect_err("hard reserved column names must require quoting");
3941 assert_eq!(
3942 &sql[error.span.start as usize..error.span.end as usize],
3943 name
3944 );
3945 }
3946 }
3947
3948 #[test]
3949 fn test_final_values_rejects_order_by_and_limit() {
3950 for (sql, clause) in [
3951 ("VALUES (1) ORDER BY 1", "ORDER"),
3952 ("VALUES (1) LIMIT 1", "LIMIT"),
3953 ("SELECT 1 UNION VALUES (2) ORDER BY 1", "ORDER"),
3954 ("SELECT 1 UNION VALUES (2) LIMIT 1", "LIMIT"),
3955 ] {
3956 let error = parse_first_statement_with_tail(sql)
3957 .expect_err("a trailing clause on a final VALUES term must be rejected");
3958 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
3962 assert!(
3963 error.message.contains("not allowed after a VALUES term"),
3964 "unexpected diagnostic for `{sql}`: {error:?}"
3965 );
3966 assert_eq!(
3967 &sql[error.span.start as usize..error.span.end as usize],
3968 clause,
3969 "the primary error for `{sql}` must point at the forbidden clause"
3970 );
3971 }
3972
3973 let deeply_nested = format!(
3974 "VALUES (1) ORDER BY {}1{}",
3975 "(".repeat(1_200),
3976 ")".repeat(1_200)
3977 );
3978 let error = parse_first_statement_with_tail(&deeply_nested)
3979 .expect_err("the forbidden final-VALUES clause must win over expression depth");
3980 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
3981 assert_eq!(
3982 &deeply_nested[error.span.start as usize..error.span.end as usize],
3983 "ORDER"
3984 );
3985
3986 let final_select = parse_full_select("VALUES (1) UNION SELECT 2 ORDER BY 1 LIMIT 1");
3987 assert_eq!(
3988 final_select.to_string(),
3989 "VALUES (1) UNION SELECT 2 ORDER BY 1 LIMIT 1"
3990 );
3991 let wrapped = parse_full_select("SELECT * FROM (VALUES (1)) ORDER BY 1 LIMIT 1");
3992 assert_eq!(
3993 wrapped.to_string(),
3994 "SELECT * FROM (VALUES (1)) ORDER BY 1 LIMIT 1"
3995 );
3996 }
3997
3998 #[test]
3999 fn test_count_star_rejects_aggregate_order_by() {
4000 let error = parse_first_statement_with_tail("SELECT count(* ORDER BY x) FROM t")
4001 .expect_err("aggregate ORDER BY after count(*) must be rejected");
4002 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
4005 assert!(
4006 error.message.contains("RightParen"),
4007 "unexpected diagnostic: {error:?}"
4008 );
4009
4010 let valid = parse_full_select("SELECT count(*) FILTER (WHERE x > 0) OVER () FROM t");
4011 assert_eq!(
4012 valid.to_string(),
4013 "SELECT count(*) FILTER (WHERE x > 0) OVER () FROM t"
4014 );
4015 }
4016
4017 #[test]
4018 fn test_parse_metrics_emitted_when_enabled() {
4019 let _guard = PARSE_OBSERVABILITY_LOCK
4020 .lock()
4021 .unwrap_or_else(|poisoned| poisoned.into_inner());
4022 let prev_metrics_enabled = parse_metrics_enabled();
4023 reset_parse_metrics();
4024 set_parse_metrics_enabled(true);
4025
4026 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
4027 let (stmts, errs) = parser.parse_all();
4028 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
4029 assert_eq!(stmts.len(), 2);
4030
4031 let snapshot = parse_metrics_snapshot();
4032 assert!(snapshot.fsqlite_parse_statements_total >= 2);
4033
4034 set_parse_metrics_enabled(prev_metrics_enabled);
4035 reset_parse_metrics();
4036 }
4037
4038 #[test]
4039 fn test_public_parser_new_normalizes_empty_and_missing_eof_streams() {
4040 let error = Parser::new(Vec::new())
4041 .parse_expr()
4042 .expect_err("an empty public token stream must return an error, not panic");
4043 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
4044 assert_eq!(error.span, Span::ZERO);
4045
4046 let integer = Token {
4047 kind: TokenKind::Integer(1),
4048 span: Span::new(0, 1),
4049 line: 1,
4050 col: 1,
4051 };
4052 let mut expression_parser = Parser::new(vec![integer]);
4053 assert!(matches!(
4054 expression_parser
4055 .parse_expr()
4056 .expect("a token stream without explicit EOF must be normalized"),
4057 Expr::Literal(Literal::Integer(1), _)
4058 ));
4059 assert!(expression_parser.at_eof());
4060
4061 let mut tokens = Lexer::tokenize("SELECT 1");
4062 assert!(matches!(
4063 tokens.pop(),
4064 Some(Token {
4065 kind: TokenKind::Eof,
4066 ..
4067 })
4068 ));
4069 let (statements, errors) = Parser::new(tokens).parse_all();
4070 assert!(errors.is_empty(), "unexpected errors: {errors:?}");
4071 assert_eq!(statements.len(), 1);
4072 assert_eq!(statements[0].to_string(), "SELECT 1");
4073
4074 let mut tokens = Lexer::tokenize("SELECT 1; SELECT 2");
4075 tokens.insert(
4076 2,
4077 Token {
4078 kind: TokenKind::Eof,
4079 span: Span::new(8, 8),
4080 line: 1,
4081 col: 9,
4082 },
4083 );
4084 let mut parser = Parser::new(tokens);
4085 assert_eq!(
4086 parser
4087 .tokens
4088 .iter()
4089 .filter(|token| token.kind == TokenKind::Eof)
4090 .count(),
4091 1
4092 );
4093 assert!(matches!(
4094 parser.tokens.last(),
4095 Some(Token {
4096 kind: TokenKind::Eof,
4097 ..
4098 })
4099 ));
4100 let (statements, errors) = parser.parse_all();
4101 assert!(
4102 errors.is_empty(),
4103 "embedded EOF normalization must not hide later tokens: {errors:?}"
4104 );
4105 assert_eq!(statements.len(), 2);
4106 assert_eq!(statements[1].to_string(), "SELECT 2");
4107
4108 let tokens = Lexer::tokenize("SELECT CASE WHEN 1 THEN 'a\nb'");
4109 let expected_eof = tokens
4110 .last()
4111 .cloned()
4112 .expect("the lexer must supply a terminal EOF");
4113 let mut parser = Parser::new(tokens);
4114 let normalized_eof = parser
4115 .tokens
4116 .last()
4117 .expect("the normalized stream must retain a terminal EOF");
4118 assert_eq!(normalized_eof, &expected_eof);
4119 assert_eq!(normalized_eof.line, 2);
4120 let (_, errors) = parser.parse_all();
4121 assert!(
4122 errors
4123 .iter()
4124 .any(|error| error.span == expected_eof.span && error.line == expected_eof.line),
4125 "the missing END diagnostic must retain the lexer's multiline EOF coordinates: \
4126 {errors:?}"
4127 );
4128 }
4129
4130 #[test]
4131 fn test_parse_metrics_can_be_disabled_off_hot_path() {
4132 let _guard = PARSE_OBSERVABILITY_LOCK
4133 .lock()
4134 .unwrap_or_else(|poisoned| poisoned.into_inner());
4135 let prev_metrics_enabled = parse_metrics_enabled();
4136 reset_parse_metrics();
4137 set_parse_metrics_enabled(false);
4138
4139 let mut parser = Parser::from_sql("SELECT 1; SELECT 2;");
4140 let (stmts, errs) = parser.parse_all();
4141 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
4142 assert_eq!(stmts.len(), 2);
4143
4144 let snapshot = parse_metrics_snapshot();
4145 assert_eq!(snapshot.fsqlite_parse_statements_total, 0);
4146
4147 set_parse_metrics_enabled(prev_metrics_enabled);
4148 reset_parse_metrics();
4149 }
4150
4151 #[test]
4152 fn test_parse_depth_overflow_does_not_poison_following_statement() {
4153 const OVER_LIMIT: usize = MAX_PARSE_DEPTH as usize + 1;
4154 let expression = std::iter::repeat_n("1", OVER_LIMIT)
4155 .collect::<Vec<_>>()
4156 .join(" + ");
4157 let sql = format!("SELECT {expression}; SELECT 42;");
4158 let mut parser = Parser::from_sql(&sql);
4159 let (statements, errors) = parser.parse_all();
4160
4161 assert_eq!(
4162 errors.len(),
4163 1,
4164 "only the height-1001 statement should be rejected: {errors:?}"
4165 );
4166 assert_eq!(
4167 errors[0].kind,
4168 ParseErrorKind::ExpressionTooDeep {
4169 max: MAX_PARSE_DEPTH
4170 }
4171 );
4172 assert_eq!(statements.len(), 1, "the valid statement must survive");
4173 assert_eq!(statements[0].to_string(), "SELECT 42");
4174 assert_eq!(
4175 parser.depth, 0,
4176 "expression-height recovery must not poison native parser depth"
4177 );
4178 }
4179
4180 #[test]
4181 fn test_parse_first_statement_with_tail_consumes_full_trigger_body() {
4182 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN INSERT INTO audit VALUES('first'); INSERT INTO audit VALUES('second'); END; SELECT 1;";
4183 let Some((statement, tail_offset)) =
4184 parse_first_statement_with_tail(sql).expect("trigger statement should parse")
4185 else {
4186 panic!("expected a trigger statement");
4187 };
4188
4189 assert!(matches!(statement, Statement::CreateTrigger(_)));
4190 assert_eq!(&sql[tail_offset..], " SELECT 1;");
4191 }
4192
4193 #[test]
4194 fn test_trigger_body_accepts_only_sqlite_trigger_commands() {
4195 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4196 SELECT 1; \
4197 VALUES (2); \
4198 INSERT INTO audit VALUES (3); \
4199 REPLACE INTO audit VALUES (4); \
4200 UPDATE audit SET value = 5; \
4201 DELETE FROM audit WHERE value = 6; \
4202 WITH seed(value) AS (VALUES (7)) SELECT value FROM seed; \
4203 SELECT 8 end; \
4204 SELECT * FROM audit end; \
4205 SELECT * FROM (SELECT 9) end; \
4206 UPDATE audit SET value = source.value FROM source \
4207 WHERE audit.id = source.id; \
4208 END";
4209 let Statement::CreateTrigger(trigger) = parse_one(sql) else {
4210 panic!("expected CREATE TRIGGER");
4211 };
4212 assert_eq!(trigger.body.len(), 11);
4213 assert!(matches!(trigger.body[0], Statement::Select(_)));
4214 assert!(matches!(trigger.body[1], Statement::Select(_)));
4215 assert!(matches!(trigger.body[2], Statement::Insert(_)));
4216 assert!(matches!(trigger.body[3], Statement::Insert(_)));
4217 assert!(matches!(trigger.body[4], Statement::Update(_)));
4218 assert!(matches!(trigger.body[5], Statement::Delete(_)));
4219 assert!(matches!(trigger.body[6], Statement::Select(_)));
4220 assert!(matches!(trigger.body[7], Statement::Select(_)));
4221 assert!(matches!(trigger.body[8], Statement::Select(_)));
4222 assert!(matches!(trigger.body[9], Statement::Select(_)));
4223 assert!(matches!(trigger.body[10], Statement::Update(_)));
4224 }
4225
4226 #[test]
4227 fn test_trigger_body_accepts_explicit_table_aliases_only() {
4228 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4229 UPDATE audit AS update_target SET value = 1; \
4230 INSERT INTO audit AS insert_target(value) VALUES (2); \
4231 DELETE FROM audit AS delete_target WHERE delete_target.value = 3; \
4232 END";
4233 let Statement::CreateTrigger(trigger) = parse_one(sql) else {
4234 panic!("expected CREATE TRIGGER");
4235 };
4236
4237 assert!(matches!(
4238 &trigger.body[0],
4239 Statement::Update(UpdateStatement {
4240 table: QualifiedTableRef {
4241 alias: Some(alias),
4242 ..
4243 },
4244 ..
4245 }) if alias == "update_target"
4246 ));
4247 assert!(matches!(
4248 &trigger.body[1],
4249 Statement::Insert(InsertStatement {
4250 alias: Some(alias),
4251 ..
4252 }) if alias == "insert_target"
4253 ));
4254 assert!(matches!(
4255 &trigger.body[2],
4256 Statement::Delete(DeleteStatement {
4257 table: QualifiedTableRef {
4258 alias: Some(alias),
4259 ..
4260 },
4261 ..
4262 }) if alias == "delete_target"
4263 ));
4264
4265 for (body_statement, rejected) in [
4266 ("UPDATE audit target SET value = 1", "target"),
4267 ("INSERT INTO audit target(value) VALUES (1)", "target"),
4268 ("DELETE FROM audit target", "target"),
4269 ] {
4270 let sql = format!("CREATE TRIGGER trg AFTER INSERT ON t BEGIN {body_statement}; END");
4271 let error = parse_first_statement_with_tail(&sql)
4272 .expect_err("trigger-body table aliases without AS must remain rejected");
4273 assert_eq!(
4274 &sql[error.span.start as usize..error.span.end as usize],
4275 rejected,
4276 "the diagnostic for `{sql}` must identify the bare alias"
4277 );
4278 }
4279 }
4280
4281 #[test]
4282 fn test_trigger_body_rejects_empty_missing_semicolon_and_non_dml_commands() {
4283 for (sql, rejected) in [
4284 ("CREATE TRIGGER trg AFTER INSERT ON t BEGIN END", "END"),
4285 (
4286 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN CREATE TABLE bad(x); END",
4287 "CREATE",
4288 ),
4289 (
4290 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN BEGIN; END",
4291 "BEGIN",
4292 ),
4293 (
4294 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN PRAGMA foreign_keys; END",
4295 "PRAGMA",
4296 ),
4297 (
4298 "CREATE TRIGGER outer_trg AFTER INSERT ON t BEGIN \
4299 CREATE TRIGGER inner_trg AFTER INSERT ON t BEGIN SELECT 1; END; END",
4300 "CREATE",
4301 ),
4302 ] {
4303 let error = parse_first_statement_with_tail(sql)
4304 .expect_err("invalid trigger-body grammar must fail closed");
4305 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
4308 assert_eq!(
4309 &sql[error.span.start as usize..error.span.end as usize],
4310 rejected,
4311 "the diagnostic for `{sql}` must identify the rejected token"
4312 );
4313 }
4314
4315 let missing_separator = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN SELECT 1 END";
4316 let error = parse_first_statement_with_tail(missing_separator)
4317 .expect_err("a trigger body statement still requires a semicolon");
4318 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
4322 assert!(
4323 error
4324 .message
4325 .contains("expected ';' after trigger body statement"),
4326 "unexpected missing-separator diagnostic: {error:?}"
4327 );
4328 assert_eq!(
4329 error.span.start, error.span.end,
4330 "like stock SQLite's incomplete-input result, the parser must not reinterpret \
4331 the implicit END alias as the trigger terminator"
4332 );
4333 }
4334
4335 #[test]
4336 fn test_trigger_missing_separator_recovery_preserves_trailing_top_level_sql() {
4337 for body_statement in [
4338 "INSERT INTO audit VALUES (1)",
4339 "UPDATE audit SET value = 1",
4340 "DELETE FROM audit",
4341 ] {
4342 let sql = format!(
4343 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4344 {body_statement} END; SELECT 42;"
4345 );
4346 let (statements, errors) = Parser::from_sql(&sql).parse_all();
4347
4348 assert_eq!(
4349 errors.len(),
4350 1,
4351 "the missing trigger-body separator must be reported: {sql}"
4352 );
4353 assert_eq!(
4354 statements.len(),
4355 1,
4356 "recovery must preserve the trailing top-level statement: {sql}"
4357 );
4358 assert_eq!(statements[0].to_string(), "SELECT 42");
4359 }
4360 }
4361
4362 #[test]
4363 fn test_trigger_body_rejects_stock_forbidden_dml_forms_at_exact_tokens() {
4364 for (sql, rejected) in [
4365 (
4366 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4367 INSERT INTO main.audit VALUES (1); END",
4368 ".",
4369 ),
4370 (
4371 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4372 UPDATE main.audit SET value = 1; END",
4373 ".",
4374 ),
4375 (
4376 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4377 DELETE FROM main.audit; END",
4378 ".",
4379 ),
4380 (
4381 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4382 INSERT INTO audit DEFAULT VALUES; END",
4383 "DEFAULT",
4384 ),
4385 (
4386 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4387 UPDATE audit INDEXED BY audit_idx SET value = 1; END",
4388 "INDEXED",
4389 ),
4390 (
4391 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4392 UPDATE audit NOT INDEXED SET value = 1; END",
4393 "NOT",
4394 ),
4395 (
4396 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4397 DELETE FROM audit INDEXED BY audit_idx; END",
4398 "INDEXED",
4399 ),
4400 (
4401 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4402 DELETE FROM audit NOT INDEXED; END",
4403 "NOT",
4404 ),
4405 (
4406 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4407 UPDATE audit SET value = 1 ORDER BY value; END",
4408 "ORDER",
4409 ),
4410 (
4411 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4412 UPDATE audit SET value = 1 LIMIT 1; END",
4413 "LIMIT",
4414 ),
4415 (
4416 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4417 DELETE FROM audit ORDER BY value; END",
4418 "ORDER",
4419 ),
4420 (
4421 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4422 DELETE FROM audit LIMIT 1; END",
4423 "LIMIT",
4424 ),
4425 (
4426 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4427 INSERT INTO audit VALUES (1) RETURNING value; END",
4428 "RETURNING",
4429 ),
4430 (
4431 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4432 UPDATE audit SET value = 1 RETURNING value; END",
4433 "RETURNING",
4434 ),
4435 (
4436 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4437 DELETE FROM audit RETURNING value; END",
4438 "RETURNING",
4439 ),
4440 (
4441 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4442 WITH seed(value) AS (VALUES (1)) \
4443 INSERT INTO audit SELECT value FROM seed; END",
4444 "INSERT",
4445 ),
4446 ] {
4447 let error = parse_first_statement_with_tail(sql)
4448 .expect_err("stock-forbidden trigger DML must fail closed");
4449 assert!(
4457 matches!(
4458 error.kind,
4459 ParseErrorKind::Syntax
4460 | ParseErrorKind::UnexpectedToken
4461 | ParseErrorKind::Semantic
4462 ),
4463 "unexpected kind for `{sql}`: {error:?}"
4464 );
4465 assert_eq!(
4466 &sql[error.span.start as usize..error.span.end as usize],
4467 rejected,
4468 "the diagnostic for `{sql}` must identify the forbidden token"
4469 );
4470 }
4471 }
4472
4473 #[test]
4474 fn test_trigger_dml_restrictions_do_not_leak_to_top_level_statements() {
4475 for sql in [
4476 "INSERT INTO main.audit DEFAULT VALUES RETURNING rowid",
4477 "UPDATE main.audit INDEXED BY audit_idx SET value = 1 \
4478 RETURNING value ORDER BY value LIMIT 1",
4479 "DELETE FROM main.audit NOT INDEXED RETURNING value ORDER BY value LIMIT 1",
4480 ] {
4481 parse_first_statement_with_tail(sql)
4482 .unwrap_or_else(|error| panic!("top-level DML must remain accepted: {error}"));
4483 }
4484 }
4485
4486 #[test]
4487 fn test_trigger_body_recovery_preserves_following_top_level_statement() {
4488 let sql = "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4489 CREATE TABLE bad(x); END; SELECT 42;";
4490 let (statements, errors) = Parser::from_sql(sql).parse_all();
4491 assert_eq!(errors.len(), 1, "expected one trigger-body grammar error");
4492 assert_eq!(
4493 statements.len(),
4494 1,
4495 "the malformed trigger must be discarded"
4496 );
4497 assert_eq!(statements[0].to_string(), "SELECT 42");
4498 assert_eq!(
4499 &sql[errors[0].span.start as usize..errors[0].span.end as usize],
4500 "CREATE"
4501 );
4502 }
4503
4504 #[test]
4505 fn test_parse_first_statement_with_tail_rejects_adjacent_statements_without_separator() {
4506 let error = parse_first_statement_with_tail("SELECT 1 SELECT 2")
4507 .expect_err("adjacent statements without a semicolon must be rejected");
4508
4509 assert!(
4510 error.message.contains("expected ';' separator"),
4511 "unexpected error: {error:?}"
4512 );
4513 }
4514
4515 #[test]
4516 fn test_parse_all_reports_and_recovers_from_missing_statement_separator() {
4517 let sql = "SELECT 1 SELECT 2";
4518 let mut parser = Parser::from_sql(sql);
4519 let (statements, errors) = parser.parse_all();
4520
4521 assert_eq!(
4522 statements.len(),
4523 2,
4524 "both independently valid statements should remain available for diagnostics"
4525 );
4526 assert_eq!(statements[0].to_string(), "SELECT 1");
4527 assert_eq!(statements[1].to_string(), "SELECT 2");
4528 assert_eq!(errors.len(), 1, "the missing separator must be reported");
4529 assert!(
4530 errors[0].message.contains("expected ';' separator"),
4531 "unexpected diagnostic: {:?}",
4532 errors[0]
4533 );
4534 assert_eq!(
4535 &sql[errors[0].span.start as usize..errors[0].span.end as usize],
4536 "SELECT",
4537 "the separator diagnostic must point at the second statement"
4538 );
4539 }
4540
4541 #[test]
4542 fn test_create_table_without_rowid_and_strict_round_trips_display() {
4543 let sql = "CREATE TABLE s (id INTEGER PRIMARY KEY) WITHOUT ROWID, STRICT";
4544 let Some((statement, _)) =
4545 parse_first_statement_with_tail(sql).expect("statement should parse")
4546 else {
4547 panic!("expected CREATE TABLE statement");
4548 };
4549
4550 assert_eq!(statement.to_string(), sql);
4551 }
4552
4553 #[test]
4554 fn test_error_recovery_does_not_fabricate_top_level_statements_from_trigger_body() {
4555 let mut parser = Parser::from_sql(
4556 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN \
4557 XYZZY; SELECT CASE WHEN 1 THEN 2 END AS end; SELECT 2; END; SELECT 3;",
4558 );
4559 let (stmts, errs) = parser.parse_all();
4560
4561 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
4562 assert_eq!(
4563 stmts.len(),
4564 1,
4565 "only the trailing top-level SELECT should remain"
4566 );
4567 assert!(
4568 matches!(
4569 &stmts[0],
4570 Statement::Select(select)
4571 if matches!(
4572 &select.body.select,
4573 SelectCore::Select { columns, .. }
4574 if matches!(
4575 columns.as_slice(),
4576 [ResultColumn::Expr {
4577 expr: Expr::Literal(Literal::Integer(3), _),
4578 alias: None,
4579 }]
4580 )
4581 )
4582 ),
4583 "parser must skip the malformed trigger instead of reinterpreting body tokens as top-level SQL: {stmts:?}"
4584 );
4585 }
4586
4587 #[test]
4588 fn test_error_recovery_skips_a_rejected_nested_trigger_before_outer_end() {
4589 for nested_prefix in ["CREATE TRIGGER", "CREATE UNIQUE TRIGGER"] {
4590 let sql = format!(
4591 "CREATE TRIGGER outer_trg AFTER INSERT ON t BEGIN \
4592 {nested_prefix} inner_trg AFTER INSERT ON t BEGIN SELECT 1; END; \
4593 END; SELECT 7;"
4594 );
4595 let (stmts, errs) = Parser::from_sql(&sql).parse_all();
4596
4597 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
4598 assert_eq!(
4599 stmts.len(),
4600 1,
4601 "neither nested-trigger tokens nor the outer END may escape as top-level SQL: {sql}"
4602 );
4603 assert_eq!(stmts[0].to_string(), "SELECT 7");
4604 }
4605 }
4606
4607 #[test]
4608 fn test_error_recovery_recovers_values_statement_after_garbage() {
4609 let mut parser = Parser::from_sql("XYZZY VALUES (1);");
4610 let (stmts, errs) = parser.parse_all();
4611
4612 assert_eq!(errs.len(), 1, "expected one error for leading garbage");
4613 assert_eq!(stmts.len(), 1, "VALUES statement should still be recovered");
4614 assert!(matches!(stmts[0], Statement::Select(_)));
4615 }
4616
4617 #[test]
4618 fn test_error_recovery_does_not_swallow_top_level_sql_after_unbalanced_trigger_paren() {
4619 let mut parser = Parser::from_sql(
4620 "CREATE TRIGGER trg AFTER INSERT ON t BEGIN SELECT (1; END; SELECT 2;",
4621 );
4622 let (stmts, errs) = parser.parse_all();
4623
4624 assert_eq!(errs.len(), 1, "expected one trigger-body parse error");
4625 assert_eq!(
4626 stmts.len(),
4627 1,
4628 "malformed trigger recovery must still preserve the trailing top-level SELECT"
4629 );
4630 assert!(
4631 matches!(
4632 &stmts[0],
4633 Statement::Select(select)
4634 if matches!(
4635 &select.body.select,
4636 SelectCore::Select { columns, .. }
4637 if matches!(
4638 columns.as_slice(),
4639 [ResultColumn::Expr {
4640 expr: Expr::Literal(Literal::Integer(2), _),
4641 alias: None,
4642 }]
4643 )
4644 )
4645 ),
4646 "parser must stop at the trigger END even when parentheses are left unbalanced: {stmts:?}"
4647 );
4648 }
4649
4650 #[test]
4651 fn select_literal() {
4652 let stmt = parse_one("SELECT 1");
4653 assert!(matches!(stmt, Statement::Select(_)));
4654 }
4655
4656 #[test]
4657 fn select_star_from() {
4658 let stmt = parse_one("SELECT * FROM t");
4659 if let Statement::Select(s) = stmt {
4660 if let SelectCore::Select { columns, from, .. } = &s.body.select {
4661 assert!(matches!(columns[0], ResultColumn::Star));
4662 assert!(from.is_some());
4663 } else {
4664 unreachable!("expected Select core");
4665 }
4666 } else {
4667 unreachable!("expected Select");
4668 }
4669 }
4670
4671 #[test]
4672 fn select_where_order_limit() {
4673 let stmt = parse_one("SELECT a FROM t WHERE a > 1 ORDER BY a LIMIT 10 OFFSET 5");
4674 if let Statement::Select(s) = stmt {
4675 assert!(s.limit.is_some());
4676 assert_eq!(s.order_by.len(), 1);
4677 } else {
4678 unreachable!("expected Select");
4679 }
4680 }
4681
4682 #[test]
4683 fn select_limit_comma_syntax_uses_offset_then_count() {
4684 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
4685 if let Statement::Select(s) = stmt {
4686 let limit = s.limit.expect("LIMIT clause");
4687 assert!(matches!(
4688 limit.limit,
4689 Expr::Literal(Literal::Integer(10), _)
4690 ));
4691 assert!(matches!(
4692 limit.offset,
4693 Some(Expr::Literal(Literal::Integer(5), _))
4694 ));
4695 } else {
4696 unreachable!("expected Select");
4697 }
4698 }
4699
4700 #[test]
4701 fn select_order_by_nulls_first_last() {
4702 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST, b DESC NULLS LAST");
4703 if let Statement::Select(s) = stmt {
4704 assert_eq!(s.order_by.len(), 2);
4705 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
4706 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
4707 assert_eq!(s.order_by[1].direction, Some(SortDirection::Desc));
4708 assert_eq!(s.order_by[1].nulls, Some(NullsOrder::Last));
4709 } else {
4710 unreachable!("expected Select");
4711 }
4712 }
4713
4714 #[test]
4715 fn select_from_indexed_by_hint() {
4716 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
4717 if let Statement::Select(s) = stmt {
4718 if let SelectCore::Select { from, .. } = &s.body.select {
4719 let from = from.as_ref().expect("FROM clause");
4720 match &from.source {
4721 TableOrSubquery::Table {
4722 index_hint: Some(IndexHint::IndexedBy(name)),
4723 ..
4724 } => assert_eq!(name, "idx_t"),
4725 other => unreachable!("expected indexed table source, got {other:?}"),
4726 }
4727 } else {
4728 unreachable!("expected Select core");
4729 }
4730 } else {
4731 unreachable!("expected Select");
4732 }
4733 }
4734
4735 #[test]
4736 fn select_from_not_indexed_hint() {
4737 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
4738 if let Statement::Select(s) = stmt {
4739 if let SelectCore::Select { from, .. } = &s.body.select {
4740 let from = from.as_ref().expect("FROM clause");
4741 match &from.source {
4742 TableOrSubquery::Table {
4743 index_hint: Some(IndexHint::NotIndexed),
4744 ..
4745 } => {}
4746 other => unreachable!("expected not-indexed table source, got {other:?}"),
4747 }
4748 } else {
4749 unreachable!("expected Select core");
4750 }
4751 } else {
4752 unreachable!("expected Select");
4753 }
4754 }
4755
4756 #[test]
4757 fn select_from_table_valued_function() {
4758 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
4759 if let Statement::Select(s) = stmt {
4760 if let SelectCore::Select { from, .. } = &s.body.select {
4761 let from = from.as_ref().expect("FROM clause");
4762 match &from.source {
4763 TableOrSubquery::TableFunction { name, args, alias } => {
4764 assert_eq!(name, "generate_series");
4765 assert_eq!(args.len(), 2);
4766 assert_eq!(alias.as_deref(), Some("gs"));
4767 }
4768 other => unreachable!("expected table-valued function source, got {other:?}"),
4769 }
4770 } else {
4771 unreachable!("expected Select core");
4772 }
4773 } else {
4774 unreachable!("expected Select");
4775 }
4776 }
4777
4778 #[test]
4779 fn select_window_function_over_clause() {
4780 let stmt = parse_one(
4781 "SELECT sum(x) OVER (PARTITION BY y ORDER BY z \
4782 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
4783 );
4784 if let Statement::Select(s) = stmt {
4785 if let SelectCore::Select { columns, .. } = &s.body.select {
4786 match &columns[0] {
4787 ResultColumn::Expr {
4788 expr:
4789 Expr::FunctionCall {
4790 over: Some(over), ..
4791 },
4792 ..
4793 } => {
4794 assert_eq!(over.partition_by.len(), 1);
4795 assert_eq!(over.order_by.len(), 1);
4796 assert!(matches!(
4797 over.frame,
4798 Some(FrameSpec {
4799 frame_type: FrameType::Rows,
4800 ..
4801 })
4802 ));
4803 }
4804 other => unreachable!("expected window function result column, got {other:?}"),
4805 }
4806 } else {
4807 unreachable!("expected Select core");
4808 }
4809 } else {
4810 unreachable!("expected Select");
4811 }
4812 }
4813
4814 #[test]
4815 fn select_named_window_definition_and_reference() {
4816 let stmt = parse_one(
4817 "SELECT sum(x) OVER win FROM t \
4818 WINDOW win AS (PARTITION BY y ORDER BY z)",
4819 );
4820 if let Statement::Select(s) = stmt {
4821 if let SelectCore::Select {
4822 columns, windows, ..
4823 } = &s.body.select
4824 {
4825 assert_eq!(windows.len(), 1);
4826 assert_eq!(windows[0].name, "win");
4827 assert_eq!(windows[0].spec.partition_by.len(), 1);
4828 assert_eq!(windows[0].spec.order_by.len(), 1);
4829 match &columns[0] {
4830 ResultColumn::Expr {
4831 expr:
4832 Expr::FunctionCall {
4833 over: Some(over), ..
4834 },
4835 ..
4836 } => assert_eq!(
4837 over.window_ref,
4838 Some(WindowReference::Direct("win".to_owned()))
4839 ),
4840 other => unreachable!("expected named window function, got {other:?}"),
4841 }
4842 } else {
4843 unreachable!("expected Select core");
4844 }
4845 } else {
4846 unreachable!("expected Select");
4847 }
4848 }
4849
4850 #[test]
4851 fn select_named_window_reference_uses_sqlite_contextual_keyword_matrix() {
4852 let assert_reference = |reference: &str, name: &str| {
4853 let sql = format!("SELECT sum(1) OVER {reference} WINDOW {name} AS ()");
4854 let select = parse_full_select(&sql);
4855 let SelectCore::Select {
4856 columns, windows, ..
4857 } = &select.body.select
4858 else {
4859 panic!("expected SELECT core for `{sql}`");
4860 };
4861 assert_eq!(windows.len(), 1, "missing WINDOW definition for `{sql}`");
4862 assert_eq!(windows[0].name, name);
4863 let [
4864 ResultColumn::Expr {
4865 expr:
4866 Expr::FunctionCall {
4867 over: Some(window), ..
4868 },
4869 alias: None,
4870 },
4871 ] = columns.as_slice()
4872 else {
4873 panic!("expected one named window call for `{sql}`");
4874 };
4875 let expected = if reference.starts_with('(') {
4876 WindowReference::Base(name.to_owned())
4877 } else {
4878 WindowReference::Direct(name.to_owned())
4879 };
4880 assert_eq!(
4881 window.window_ref,
4882 Some(expected),
4883 "wrong OVER form for `{sql}`"
4884 );
4885 };
4886
4887 for name in [
4888 "attach",
4889 "begin",
4890 "by",
4891 "cast",
4892 "current_date",
4893 "current_time",
4894 "current_timestamp",
4895 "cross",
4896 "detach",
4897 "explain",
4898 "false",
4899 "for",
4900 "glob",
4901 "inner",
4902 "left",
4903 "like",
4904 "natural",
4905 "outer",
4906 "over",
4907 "raise",
4908 "regexp",
4909 "right",
4910 "rollback",
4911 "key",
4912 "true",
4913 "window",
4914 "with",
4915 ] {
4916 assert_reference(name, name);
4917 assert_reference(&format!("({name})"), name);
4918 }
4919
4920 for name in ["partition", "range", "rows", "groups"] {
4921 assert_reference(name, name);
4922 let sql = format!("SELECT sum(1) OVER ({name})");
4923 parse_first_statement_with_tail(&sql)
4924 .expect_err("window-spec delimiters cannot be parenthesized base names");
4925 }
4926 }
4927
4928 #[test]
4929 fn select_named_window_reference_rejects_non_fallback_keywords() {
4930 for name in ["filter", "nothing", "transaction"] {
4931 for reference in [name.to_owned(), format!("({name})")] {
4932 let sql = format!("SELECT sum(1) OVER {reference}");
4933 parse_first_statement_with_tail(&sql)
4934 .expect_err("reserved window-name tokens must not be consumed as names");
4935 }
4936 let sql = format!("SELECT sum(1) WINDOW {name} AS ()");
4937 parse_first_statement_with_tail(&sql)
4938 .expect_err("reserved WINDOW definition names must be rejected");
4939 }
4940 }
4941
4942 #[test]
4943 fn select_named_window_reference_accepts_string_and_parenthesized_names() {
4944 for (sql, expected_name) in [
4945 ("SELECT sum(1) OVER 'w' WINDOW 'w' AS ()", "w"),
4946 ("SELECT sum(1) OVER ('w') WINDOW 'w' AS ()", "w"),
4947 ("SELECT sum(1) OVER (window) WINDOW window AS ()", "window"),
4948 ] {
4949 let select = parse_full_select(sql);
4950 let SelectCore::Select {
4951 columns, windows, ..
4952 } = &select.body.select
4953 else {
4954 panic!("expected SELECT core for `{sql}`");
4955 };
4956 assert_eq!(windows.len(), 1, "missing WINDOW definition for `{sql}`");
4957 assert_eq!(windows[0].name, expected_name);
4958 let [
4959 ResultColumn::Expr {
4960 expr:
4961 Expr::FunctionCall {
4962 over: Some(window), ..
4963 },
4964 alias: None,
4965 },
4966 ] = columns.as_slice()
4967 else {
4968 panic!("expected one named window call for `{sql}`");
4969 };
4970 let expected = if sql.contains("OVER (") {
4971 WindowReference::Base(expected_name.to_owned())
4972 } else {
4973 WindowReference::Direct(expected_name.to_owned())
4974 };
4975 assert_eq!(
4976 window.window_ref,
4977 Some(expected),
4978 "wrong OVER form for `{sql}`"
4979 );
4980 }
4981 }
4982
4983 #[test]
4984 fn over_window_prefers_named_window_reference_over_implicit_alias() {
4985 let sql = "WITH t(x) AS (VALUES (1), (2)) \
4986 SELECT sum(x) OVER window FROM t WINDOW window AS ()";
4987 let select = parse_full_select(sql);
4988 let SelectCore::Select {
4989 columns, windows, ..
4990 } = &select.body.select
4991 else {
4992 panic!("expected SELECT core");
4993 };
4994 assert_eq!(windows.len(), 1);
4995 assert_eq!(windows[0].name, "window");
4996 assert!(matches!(
4997 columns.as_slice(),
4998 [ResultColumn::Expr {
4999 expr: Expr::FunctionCall {
5000 over: Some(WindowSpec {
5001 window_ref: Some(WindowReference::Direct(base_window)),
5002 ..
5003 }),
5004 ..
5005 },
5006 alias: None,
5007 }] if base_window == "window"
5008 ));
5009
5010 let error = parse_first_statement_with_tail("SELECT sum(1) OVER WINDOW w AS ()")
5011 .expect_err("WINDOW after OVER is a window name, not an implicit OVER alias");
5012 assert_eq!(error.kind, ParseErrorKind::UnexpectedToken);
5014 }
5015
5016 #[test]
5017 fn over_implicit_alias_disambiguation_is_preserved_at_real_boundaries() {
5018 for sql in ["SELECT sum(1) OVER, 2", "SELECT sum(1) OVER FROM t"] {
5019 let select = parse_full_select(sql);
5020 let SelectCore::Select { columns, .. } = &select.body.select else {
5021 panic!("expected SELECT core for `{sql}`");
5022 };
5023 assert!(matches!(
5024 columns.first(),
5025 Some(ResultColumn::Expr {
5026 expr: Expr::FunctionCall { over: None, .. },
5027 alias: Some(alias),
5028 }) if alias == "over"
5029 ));
5030 }
5031 }
5032
5033 #[test]
5034 fn overflowing_float_literals_round_trip_as_infinite_numbers() {
5035 fn assert_infinite_columns(select: &SelectStatement) {
5036 let SelectCore::Select { columns, .. } = &select.body.select else {
5037 panic!("expected SELECT core");
5038 };
5039 let [positive, negative] = columns.as_slice() else {
5040 panic!("expected positive and negative infinity columns");
5041 };
5042 assert!(matches!(
5043 positive,
5044 ResultColumn::Expr {
5045 expr: Expr::Literal(Literal::Float(value), _),
5046 ..
5047 } if value.is_infinite() && value.is_sign_positive()
5048 ));
5049 let ResultColumn::Expr {
5050 expr:
5051 Expr::UnaryOp {
5052 op: UnaryOp::Negate,
5053 expr,
5054 ..
5055 },
5056 ..
5057 } = negative
5058 else {
5059 panic!("expected negative infinity to retain unary negation");
5060 };
5061 assert!(matches!(
5062 expr.as_ref(),
5063 Expr::Literal(Literal::Float(value), _)
5064 if value.is_infinite() && value.is_sign_positive()
5065 ));
5066 }
5067
5068 let parsed = parse_full_select("SELECT 9e999, -9e999");
5069 assert_infinite_columns(&parsed);
5070 let rendered = parsed.to_string();
5071 assert_eq!(rendered, "SELECT 9e999, -9e999");
5072 let reparsed = parse_full_select(&rendered);
5073 assert_infinite_columns(&reparsed);
5074 assert_eq!(reparsed.to_string(), rendered);
5075 }
5076
5077 #[test]
5078 fn insert_values() {
5079 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2), (3, 4)");
5080 assert!(matches!(stmt, Statement::Insert(_)));
5081 }
5082
5083 #[test]
5084 fn update_set() {
5085 let stmt = parse_one("UPDATE t SET a = 1, b = 2 WHERE id = 3");
5086 assert!(matches!(stmt, Statement::Update(_)));
5087 }
5088
5089 #[test]
5090 fn delete_from() {
5091 let stmt = parse_one("DELETE FROM t WHERE id = 1");
5092 assert!(matches!(stmt, Statement::Delete(_)));
5093 }
5094
5095 #[test]
5096 fn create_table_basic() {
5097 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT NOT NULL)");
5098 if let Statement::CreateTable(ct) = stmt {
5099 assert_eq!(ct.name.name, "t");
5100 if let CreateTableBody::Columns { columns, .. } = ct.body {
5101 assert_eq!(columns.len(), 2);
5102 } else {
5103 unreachable!("expected column defs");
5104 }
5105 } else {
5106 unreachable!("expected CreateTable");
5107 }
5108 }
5109
5110 #[test]
5111 fn create_index() {
5112 let stmt = parse_one("CREATE UNIQUE INDEX idx ON t (a, b DESC)");
5113 if let Statement::CreateIndex(ci) = stmt {
5114 assert!(ci.unique);
5115 assert_eq!(ci.columns.len(), 2);
5116 } else {
5117 unreachable!("expected CreateIndex");
5118 }
5119 }
5120
5121 #[test]
5122 fn drop_table_if_exists() {
5123 let stmt = parse_one("DROP TABLE IF EXISTS t");
5124 if let Statement::Drop(d) = stmt {
5125 assert!(d.if_exists);
5126 assert_eq!(d.object_type, DropObjectType::Table);
5127 } else {
5128 unreachable!("expected Drop");
5129 }
5130 }
5131
5132 #[test]
5133 fn begin_commit() {
5134 let stmts = parse_ok("BEGIN IMMEDIATE; COMMIT");
5135 assert_eq!(stmts.len(), 2);
5136 if let Statement::Begin(b) = &stmts[0] {
5137 assert_eq!(b.mode, Some(TransactionMode::Immediate));
5138 } else {
5139 unreachable!("expected Begin");
5140 }
5141 assert!(matches!(stmts[1], Statement::Commit));
5142 }
5143
5144 #[test]
5145 fn begin_concurrent() {
5146 let stmt = parse_one("BEGIN CONCURRENT");
5147 if let Statement::Begin(b) = stmt {
5148 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
5149 } else {
5150 unreachable!("expected Begin");
5151 }
5152 }
5153
5154 #[test]
5155 fn rollback_to_savepoint() {
5156 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
5157 if let Statement::Rollback(r) = stmt {
5158 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
5159 } else {
5160 unreachable!("expected Rollback");
5161 }
5162 }
5163
5164 #[test]
5165 fn explain_query_plan() {
5166 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT 1");
5167 assert!(matches!(
5168 stmt,
5169 Statement::Explain {
5170 query_plan: true,
5171 ..
5172 }
5173 ));
5174 }
5175
5176 #[test]
5177 fn pragma() {
5178 let stmt = parse_one("PRAGMA journal_mode = WAL");
5179 assert!(matches!(stmt, Statement::Pragma(_)));
5180 }
5181
5182 #[test]
5183 fn pragma_cache_size_preserves_numeric_spelling_across_sql_entrypoints() {
5184 fn argument(statement: Statement) -> String {
5185 let Statement::Pragma(pragma) = statement else {
5186 panic!("expected PRAGMA");
5187 };
5188 let Some(
5189 PragmaValue::Assign(Expr::Literal(Literal::String(value), _))
5190 | PragmaValue::Call(Expr::Literal(Literal::String(value), _)),
5191 ) = pragma.value
5192 else {
5193 panic!("expected preserved cache argument: {pragma:?}");
5194 };
5195 value
5196 }
5197
5198 let mut scratch = StatementParseScratch::default();
5199 for (sql, expected) in [
5200 ("PRAGMA cache_size=1e3", "1e3"),
5201 ("PRAGMA main.cache_size=-1E-3", "-1E-3"),
5202 ("PRAGMA temp.CACHE_SIZE(+ /* sign */ 0x10)", "0x10"),
5203 ("PRAGMA aux.default_cache_size=- 0x10", "-0x10"),
5204 (
5205 "PRAGMA cache_size=9223372036854775808",
5206 "9223372036854775808",
5207 ),
5208 (
5209 "PRAGMA cache_size=-9223372036854775809",
5210 "-9223372036854775809",
5211 ),
5212 ("PRAGMA cache_size='123abc'", "123abc"),
5213 ] {
5214 assert_eq!(argument(parse_one(sql)), expected, "ordinary: {sql}");
5215 let mut statements = parse_statements_with_scratch(sql, &mut scratch).expect(sql);
5216 assert_eq!(statements.len(), 1, "scratch: {sql}");
5217 assert_eq!(argument(statements.remove(0)), expected, "scratch: {sql}");
5218 let (statement, tail) = parse_first_statement_with_tail(sql).expect(sql).expect(sql);
5219 assert_eq!(tail, sql.len(), "tail: {sql}");
5220 assert_eq!(argument(statement), expected, "tail: {sql}");
5221 }
5222 }
5223
5224 #[test]
5225 fn pragma_cache_size_numeric_spelling_does_not_change_other_parsing() {
5226 let Statement::Pragma(pragma) = parse_one("PRAGMA busy_timeout=1e3") else {
5227 panic!("expected PRAGMA");
5228 };
5229 assert!(matches!(pragma.value,
5230 Some(PragmaValue::Assign(Expr::Literal(Literal::Float(value), _))) if value == 1000.0
5231 ));
5232
5233 let mut parser = Parser::new(Lexer::tokenize("PRAGMA cache_size=1e3"));
5235 let Statement::Pragma(pragma) = parser.parse_statement().expect("token-only parse") else {
5236 panic!("expected PRAGMA");
5237 };
5238 assert!(matches!(pragma.value,
5239 Some(PragmaValue::Assign(Expr::Literal(Literal::Float(value), _))) if value == 1000.0
5240 ));
5241
5242 for sql in ["PRAGMA cache_size=1_0", "PRAGMA default_cache_size=0x1_0"] {
5243 assert!(parse_first_statement_with_tail(sql).is_err(), "{sql}");
5244 }
5245 assert!(Parser::from_sql("SELECT 1e3").pragma_source_sql.is_none());
5246 }
5247
5248 #[test]
5249 fn pragma_allows_on_value() {
5250 let stmt = parse_one("PRAGMA fsqlite.serializable = ON");
5251 assert!(matches!(stmt, Statement::Pragma(_)));
5252 }
5253
5254 #[test]
5255 fn pragma_allows_delete_and_default_keyword_values() {
5256 for (sql, expected) in [
5260 ("PRAGMA journal_mode = DELETE", "delete"),
5261 ("PRAGMA temp_store = DEFAULT", "default"),
5262 ] {
5263 let Statement::Pragma(p) = parse_one(sql) else {
5264 unreachable!("expected Pragma for {sql}");
5265 };
5266 match p.value {
5267 Some(PragmaValue::Assign(Expr::Column(col, _))) => {
5268 assert!(col.table.is_none(), "sql={sql}");
5269 assert_eq!(&*col.column, expected, "sql={sql}");
5270 }
5271 other => unreachable!("expected Assign(Column) for {sql}, got {other:?}"),
5272 }
5273 }
5274 }
5275
5276 #[test]
5277 fn error_recovery_multiple_statements() {
5278 let mut p = Parser::from_sql("SELECT 1; XYZZY; SELECT 2");
5279 let (stmts, errs) = p.parse_all();
5280 assert_eq!(stmts.len(), 2, "should recover: stmts={stmts:?}");
5281 assert!(!errs.is_empty());
5282 }
5283
5284 #[test]
5285 fn compound_union() {
5286 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
5287 if let Statement::Select(s) = stmt {
5288 assert_eq!(s.body.compounds.len(), 1);
5289 } else {
5290 unreachable!("expected Select");
5291 }
5292 }
5293
5294 #[test]
5295 fn alter_table_rename() {
5296 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
5297 assert!(matches!(
5298 stmt,
5299 Statement::AlterTable(AlterTableStatement {
5300 action: AlterTableAction::RenameTo(_),
5301 ..
5302 })
5303 ));
5304 }
5305
5306 #[test]
5311 fn test_parser_join_inner() {
5312 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
5313 if let Statement::Select(s) = stmt {
5314 if let SelectCore::Select { from, .. } = &s.body.select {
5315 let from = from.as_ref().expect("FROM clause");
5316 assert!(!from.joins.is_empty());
5317 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
5318 } else {
5319 unreachable!("expected Select core");
5320 }
5321 } else {
5322 unreachable!("expected Select");
5323 }
5324 }
5325
5326 #[test]
5327 fn test_parser_join_left() {
5328 let stmt = parse_one("SELECT * FROM a LEFT JOIN b ON a.id = b.a_id");
5329 if let Statement::Select(s) = stmt {
5330 if let SelectCore::Select { from, .. } = &s.body.select {
5331 let from = from.as_ref().expect("FROM clause");
5332 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
5333 } else {
5334 unreachable!("expected Select core");
5335 }
5336 } else {
5337 unreachable!("expected Select");
5338 }
5339 }
5340
5341 #[test]
5342 fn test_parser_join_left_outer() {
5343 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
5344 if let Statement::Select(s) = stmt {
5345 if let SelectCore::Select { from, .. } = &s.body.select {
5346 let from = from.as_ref().expect("FROM clause");
5347 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
5348 } else {
5349 unreachable!("expected Select core");
5350 }
5351 } else {
5352 unreachable!("expected Select");
5353 }
5354 }
5355
5356 #[test]
5357 fn test_parser_join_right() {
5358 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
5359 if let Statement::Select(s) = stmt {
5360 if let SelectCore::Select { from, .. } = &s.body.select {
5361 let from = from.as_ref().expect("FROM clause");
5362 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
5363 } else {
5364 unreachable!("expected Select core");
5365 }
5366 } else {
5367 unreachable!("expected Select");
5368 }
5369 }
5370
5371 #[test]
5372 fn test_parser_join_full() {
5373 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
5374 if let Statement::Select(s) = stmt {
5375 if let SelectCore::Select { from, .. } = &s.body.select {
5376 let from = from.as_ref().expect("FROM clause");
5377 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
5378 } else {
5379 unreachable!("expected Select core");
5380 }
5381 } else {
5382 unreachable!("expected Select");
5383 }
5384 }
5385
5386 #[test]
5387 fn test_parser_join_full_outer_with_semicolon() {
5388 let stmt = parse_one("SELECT l.name, r.tag FROM l FULL OUTER JOIN r ON l.id = r.l_id;");
5389 if let Statement::Select(s) = stmt {
5390 if let SelectCore::Select { from, .. } = &s.body.select {
5391 let from = from.as_ref().expect("FROM clause");
5392 assert_eq!(from.joins.len(), 1);
5393 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
5394 } else {
5395 unreachable!("expected Select core");
5396 }
5397 } else {
5398 unreachable!("expected Select");
5399 }
5400 }
5401
5402 #[test]
5403 fn test_parser_join_cross() {
5404 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
5405 if let Statement::Select(s) = stmt {
5406 if let SelectCore::Select { from, .. } = &s.body.select {
5407 let from = from.as_ref().expect("FROM clause");
5408 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
5409 } else {
5410 unreachable!("expected Select core");
5411 }
5412 } else {
5413 unreachable!("expected Select");
5414 }
5415 }
5416
5417 #[test]
5418 fn test_parser_join_natural() {
5419 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
5420 if let Statement::Select(s) = stmt {
5421 if let SelectCore::Select { from, .. } = &s.body.select {
5422 let from = from.as_ref().expect("FROM clause");
5423 assert!(from.joins[0].join_type.natural);
5424 } else {
5425 unreachable!("expected Select core");
5426 }
5427 } else {
5428 unreachable!("expected Select");
5429 }
5430 }
5431
5432 #[test]
5433 fn test_parser_join_using() {
5434 let stmt = parse_one("SELECT * FROM a JOIN b USING (id)");
5435 if let Statement::Select(s) = stmt {
5436 if let SelectCore::Select { from, .. } = &s.body.select {
5437 let from = from.as_ref().expect("FROM clause");
5438 assert!(matches!(
5439 from.joins[0].constraint,
5440 Some(JoinConstraint::Using(_))
5441 ));
5442 } else {
5443 unreachable!("expected Select core");
5444 }
5445 } else {
5446 unreachable!("expected Select");
5447 }
5448 }
5449
5450 #[test]
5451 fn test_parser_join_comma() {
5452 let stmt = parse_one("SELECT * FROM a, b WHERE a.id = b.a_id");
5454 if let Statement::Select(s) = stmt {
5455 if let SelectCore::Select { from, .. } = &s.body.select {
5456 let from = from.as_ref().expect("FROM clause");
5457 assert!(!from.joins.is_empty());
5458 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
5459 } else {
5460 unreachable!("expected Select core");
5461 }
5462 } else {
5463 unreachable!("expected Select");
5464 }
5465 }
5466
5467 #[test]
5472 fn test_parser_cte_basic() {
5473 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
5474 if let Statement::Select(s) = stmt {
5475 let with = s.with.as_ref().expect("WITH clause");
5476 assert!(!with.recursive);
5477 assert_eq!(with.ctes.len(), 1);
5478 assert_eq!(with.ctes[0].name, "cte");
5479 } else {
5480 unreachable!("expected Select");
5481 }
5482 }
5483
5484 #[test]
5485 fn test_parser_cte_multiple() {
5486 let stmt = parse_one("WITH a AS (SELECT 1), b AS (SELECT 2) SELECT * FROM a, b");
5487 if let Statement::Select(s) = stmt {
5488 let with = s.with.as_ref().expect("WITH clause");
5489 assert_eq!(with.ctes.len(), 2);
5490 assert_eq!(with.ctes[0].name, "a");
5491 assert_eq!(with.ctes[1].name, "b");
5492 } else {
5493 unreachable!("expected Select");
5494 }
5495 }
5496
5497 #[test]
5498 fn test_parser_cte_recursive() {
5499 let stmt = parse_one(
5500 "WITH RECURSIVE cnt(x) AS (\
5501 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
5502 ) SELECT x FROM cnt",
5503 );
5504 if let Statement::Select(s) = stmt {
5505 let with = s.with.as_ref().expect("WITH clause");
5506 assert!(with.recursive);
5507 assert_eq!(with.ctes[0].name, "cnt");
5508 assert_eq!(with.ctes[0].columns, vec!["x".to_owned()]);
5509 } else {
5510 unreachable!("expected Select");
5511 }
5512 }
5513
5514 #[test]
5515 fn test_parser_cte_materialized() {
5516 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
5517 if let Statement::Select(s) = stmt {
5518 let with = s.with.as_ref().expect("WITH clause");
5519 assert_eq!(
5520 with.ctes[0].materialized,
5521 Some(CteMaterialized::Materialized)
5522 );
5523 } else {
5524 unreachable!("expected Select");
5525 }
5526 }
5527
5528 #[test]
5533 fn test_select_table_star() {
5534 let stmt = parse_one("SELECT t1.* FROM t1, t2");
5535 if let Statement::Select(s) = stmt {
5536 if let SelectCore::Select { columns, .. } = &s.body.select {
5537 assert!(
5538 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::bare("t1")),
5539 "expected TableStar(t1), got {:?}",
5540 columns[0]
5541 );
5542 } else {
5543 unreachable!("expected Select core");
5544 }
5545 } else {
5546 unreachable!("expected Select");
5547 }
5548 }
5549
5550 #[test]
5551 fn test_select_schema_table_star() {
5552 let stmt = parse_one("SELECT aux.t1.* FROM aux.t1");
5553 if let Statement::Select(s) = stmt {
5554 if let SelectCore::Select { columns, .. } = &s.body.select {
5555 assert!(
5556 matches!(&columns[0], ResultColumn::TableStar(t) if t == &QualifiedName::qualified("aux", "t1")),
5557 "expected TableStar(aux.t1), got {:?}",
5558 columns[0]
5559 );
5560 } else {
5561 unreachable!("expected Select core");
5562 }
5563 } else {
5564 unreachable!("expected Select");
5565 }
5566 }
5567
5568 #[test]
5569 fn test_select_expr_alias() {
5570 let stmt = parse_one("SELECT x + 1 AS result FROM t");
5571 if let Statement::Select(s) = stmt {
5572 if let SelectCore::Select { columns, .. } = &s.body.select {
5573 match &columns[0] {
5574 ResultColumn::Expr {
5575 alias: Some(alias), ..
5576 } => assert_eq!(alias, "result"),
5577 other => unreachable!("expected aliased expr column, got {other:?}"),
5578 }
5579 } else {
5580 unreachable!("expected Select core");
5581 }
5582 } else {
5583 unreachable!("expected Select");
5584 }
5585 }
5586
5587 #[test]
5588 fn test_select_distinct_keyword() {
5589 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
5590 if let Statement::Select(s) = stmt {
5591 if let SelectCore::Select {
5592 distinct, columns, ..
5593 } = &s.body.select
5594 {
5595 assert_eq!(*distinct, Distinctness::Distinct);
5596 assert_eq!(columns.len(), 2);
5597 } else {
5598 unreachable!("expected Select core");
5599 }
5600 } else {
5601 unreachable!("expected Select");
5602 }
5603 }
5604
5605 #[test]
5606 fn test_select_values_clause() {
5607 let stmt = parse_one("VALUES (1, 2), (3, 4)");
5608 if let Statement::Select(s) = stmt {
5609 if let SelectCore::Values(rows) = &s.body.select {
5610 assert_eq!(rows.len(), 2);
5611 assert_eq!(rows[0].len(), 2);
5612 assert_eq!(rows[1].len(), 2);
5613 } else {
5614 unreachable!("expected Values core");
5615 }
5616 } else {
5617 unreachable!("expected Select");
5618 }
5619 }
5620
5621 #[test]
5622 fn test_values_representation_captures_leading_and_nested_with_timing() {
5623 let plain = parse_one("VALUES (1), (2), (3)");
5624 assert_eq!(
5625 top_level_values(&plain).representation(),
5626 ValuesRepresentation::Deferred {
5627 force_union_all_from: None,
5628 }
5629 );
5630
5631 let leading = parse_one("WITH c(x) AS (SELECT 1) VALUES (2), (3)");
5632 assert_eq!(top_level_values(&leading).force_union_all_from(), Some(0));
5633
5634 let nested_first =
5635 parse_one("VALUES ((WITH c(x) AS (SELECT 1) SELECT x FROM c)), (2), (3)");
5636 assert_eq!(
5637 top_level_values(&nested_first).force_union_all_from(),
5638 Some(0)
5639 );
5640
5641 let nested_second =
5642 parse_one("VALUES (1), ((WITH c(x) AS (SELECT 2) SELECT x FROM c)), (3)");
5643 assert_eq!(
5644 top_level_values(&nested_second).force_union_all_from(),
5645 Some(1)
5646 );
5647 }
5648
5649 #[test]
5650 fn test_values_representation_is_sticky_but_not_retroactive_within_a_statement() {
5651 let later_with = parse_full_select(
5652 "SELECT (VALUES (1), (2)), (WITH c(x) AS (SELECT 3) SELECT x FROM c)",
5653 );
5654 let SelectCore::Select { columns, .. } = &later_with.body.select else {
5655 panic!("expected SELECT core");
5656 };
5657 let ResultColumn::Expr { expr, .. } = &columns[0] else {
5658 panic!("expected expression result column");
5659 };
5660 assert_eq!(scalar_subquery_values(expr).force_union_all_from(), None);
5661
5662 let earlier_with = parse_full_select(
5663 "SELECT (WITH c(x) AS (SELECT 3) SELECT x FROM c), (VALUES (1), (2))",
5664 );
5665 let SelectCore::Select { columns, .. } = &earlier_with.body.select else {
5666 panic!("expected SELECT core");
5667 };
5668 let ResultColumn::Expr { expr, .. } = &columns[1] else {
5669 panic!("expected expression result column");
5670 };
5671 assert_eq!(scalar_subquery_values(expr).force_union_all_from(), Some(0));
5672 }
5673
5674 #[test]
5675 fn test_values_with_state_resets_between_parse_all_statements() {
5676 let statements = parse_ok("WITH c(x) AS (SELECT 1) VALUES (2), (3); VALUES (4), (5);");
5677 assert_eq!(statements.len(), 2);
5678 assert_eq!(
5679 top_level_values(&statements[0]).force_union_all_from(),
5680 Some(0)
5681 );
5682 assert_eq!(
5683 top_level_values(&statements[1]).force_union_all_from(),
5684 None
5685 );
5686 }
5687
5688 #[test]
5689 fn test_direct_values_parser_captures_nested_with_row_boundary() {
5690 let mut parser =
5691 Parser::from_sql("VALUES (1), ((WITH c(x) AS (SELECT 2) SELECT x FROM c)), (3)");
5692 let parsed = parser
5693 .parse_select_core_tracked()
5694 .expect("direct VALUES parser must succeed");
5695 let SelectCore::Values(values) = parsed.value else {
5696 panic!("direct parser must return VALUES");
5697 };
5698
5699 assert_eq!(values.force_union_all_from(), Some(1));
5700 assert_eq!(values.len(), 3);
5701 }
5702
5703 #[test]
5704 fn test_insert_values_extraction_retains_nested_values_representation() {
5705 let statement =
5706 parse_one("WITH c(x) AS (SELECT 1) INSERT INTO t VALUES ((VALUES (2), (3)))");
5707 let Statement::Insert(insert) = statement else {
5708 panic!("expected INSERT statement");
5709 };
5710 let InsertSource::Values(rows) = insert.source else {
5711 panic!("expected INSERT VALUES source");
5712 };
5713 let [row] = rows.as_slice() else {
5714 panic!("expected one INSERT row");
5715 };
5716 let [expr] = row.as_slice() else {
5717 panic!("expected one INSERT column");
5718 };
5719
5720 assert_eq!(scalar_subquery_values(expr).force_union_all_from(), Some(0));
5721 }
5722
5723 #[test]
5724 fn test_select_group_by_having() {
5725 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
5726 if let Statement::Select(s) = stmt {
5727 if let SelectCore::Select {
5728 group_by, having, ..
5729 } = &s.body.select
5730 {
5731 assert_eq!(group_by.len(), 1);
5732 assert!(having.is_some(), "HAVING clause must be present");
5733 } else {
5734 unreachable!("expected Select core");
5735 }
5736 } else {
5737 unreachable!("expected Select");
5738 }
5739 }
5740
5741 #[test]
5742 fn test_compound_union() {
5743 let stmt = parse_one("SELECT 1 UNION SELECT 2");
5744 if let Statement::Select(s) = stmt {
5745 assert_eq!(s.body.compounds.len(), 1);
5746 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
5747 } else {
5748 unreachable!("expected Select");
5749 }
5750 }
5751
5752 #[test]
5753 fn test_compound_union_all() {
5754 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
5755 if let Statement::Select(s) = stmt {
5756 assert_eq!(s.body.compounds.len(), 1);
5757 assert_eq!(s.body.compounds[0].0, CompoundOp::UnionAll);
5758 } else {
5759 unreachable!("expected Select");
5760 }
5761 }
5762
5763 #[test]
5764 fn test_compound_intersect() {
5765 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
5766 if let Statement::Select(s) = stmt {
5767 assert_eq!(s.body.compounds.len(), 1);
5768 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
5769 } else {
5770 unreachable!("expected Select");
5771 }
5772 }
5773
5774 #[test]
5775 fn test_compound_except() {
5776 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
5777 if let Statement::Select(s) = stmt {
5778 assert_eq!(s.body.compounds.len(), 1);
5779 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
5780 } else {
5781 unreachable!("expected Select");
5782 }
5783 }
5784
5785 #[test]
5786 fn test_compound_order_applies_to_whole() {
5787 let stmt = parse_one("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
5789 if let Statement::Select(s) = stmt {
5790 assert_eq!(s.body.compounds.len(), 1);
5791 assert_eq!(s.order_by.len(), 1, "ORDER BY must be on compound");
5792 assert!(s.limit.is_some(), "LIMIT must be on compound");
5793 } else {
5794 unreachable!("expected Select");
5795 }
5796 }
5797
5798 #[test]
5799 fn test_compound_three_way() {
5800 let stmt = parse_one("SELECT 1 UNION SELECT 2 INTERSECT SELECT 3");
5801 if let Statement::Select(s) = stmt {
5802 assert_eq!(s.body.compounds.len(), 2);
5803 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
5804 assert_eq!(s.body.compounds[1].0, CompoundOp::Intersect);
5805 } else {
5806 unreachable!("expected Select");
5807 }
5808 }
5809
5810 #[test]
5811 fn test_cte_not_materialized() {
5812 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
5813 if let Statement::Select(s) = stmt {
5814 let with = s.with.as_ref().expect("WITH clause");
5815 assert_eq!(
5816 with.ctes[0].materialized,
5817 Some(CteMaterialized::NotMaterialized)
5818 );
5819 } else {
5820 unreachable!("expected Select");
5821 }
5822 }
5823
5824 #[test]
5825 fn test_cte_with_explicit_columns() {
5826 let stmt = parse_one("WITH cte(a, b, c) AS (SELECT 1, 2, 3) SELECT * FROM cte");
5827 if let Statement::Select(s) = stmt {
5828 let with = s.with.as_ref().expect("WITH clause");
5829 assert_eq!(with.ctes[0].columns, vec!["a", "b", "c"]);
5830 } else {
5831 unreachable!("expected Select");
5832 }
5833 }
5834
5835 #[test]
5836 fn test_window_frame_range() {
5837 let stmt = parse_one(
5838 "SELECT sum(x) OVER (ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t",
5839 );
5840 if let Statement::Select(s) = stmt {
5841 if let SelectCore::Select { columns, .. } = &s.body.select {
5842 match &columns[0] {
5843 ResultColumn::Expr {
5844 expr:
5845 Expr::FunctionCall {
5846 over: Some(over), ..
5847 },
5848 ..
5849 } => {
5850 let frame = over.frame.as_ref().expect("frame spec");
5851 assert_eq!(frame.frame_type, FrameType::Range);
5852 assert!(matches!(frame.start, FrameBound::UnboundedPreceding));
5853 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
5854 }
5855 other => unreachable!("expected window function, got {other:?}"),
5856 }
5857 } else {
5858 unreachable!("expected Select core");
5859 }
5860 } else {
5861 unreachable!("expected Select");
5862 }
5863 }
5864
5865 #[test]
5866 fn test_window_frame_groups() {
5867 let stmt = parse_one(
5868 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
5869 );
5870 if let Statement::Select(s) = stmt {
5871 if let SelectCore::Select { columns, .. } = &s.body.select {
5872 match &columns[0] {
5873 ResultColumn::Expr {
5874 expr:
5875 Expr::FunctionCall {
5876 over: Some(over), ..
5877 },
5878 ..
5879 } => {
5880 let frame = over.frame.as_ref().expect("frame spec");
5881 assert_eq!(frame.frame_type, FrameType::Groups);
5882 assert!(matches!(frame.start, FrameBound::Preceding(_)));
5883 assert!(matches!(frame.end, Some(FrameBound::Following(_))));
5884 }
5885 other => unreachable!("expected window function, got {other:?}"),
5886 }
5887 } else {
5888 unreachable!("expected Select core");
5889 }
5890 } else {
5891 unreachable!("expected Select");
5892 }
5893 }
5894
5895 #[test]
5896 fn test_window_frame_exclude_current_row() {
5897 let stmt = parse_one(
5898 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
5899 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
5900 );
5901 if let Statement::Select(s) = stmt {
5902 if let SelectCore::Select { columns, .. } = &s.body.select {
5903 match &columns[0] {
5904 ResultColumn::Expr {
5905 expr:
5906 Expr::FunctionCall {
5907 over: Some(over), ..
5908 },
5909 ..
5910 } => {
5911 let frame = over.frame.as_ref().expect("frame spec");
5912 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
5913 }
5914 other => unreachable!("expected window function, got {other:?}"),
5915 }
5916 } else {
5917 unreachable!("expected Select core");
5918 }
5919 } else {
5920 unreachable!("expected Select");
5921 }
5922 }
5923
5924 #[test]
5925 fn test_window_frame_exclude_ties() {
5926 let stmt = parse_one(
5927 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
5928 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
5929 );
5930 if let Statement::Select(s) = stmt {
5931 if let SelectCore::Select { columns, .. } = &s.body.select {
5932 match &columns[0] {
5933 ResultColumn::Expr {
5934 expr:
5935 Expr::FunctionCall {
5936 over: Some(over), ..
5937 },
5938 ..
5939 } => {
5940 let frame = over.frame.as_ref().expect("frame spec");
5941 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
5942 }
5943 other => unreachable!("expected window function, got {other:?}"),
5944 }
5945 } else {
5946 unreachable!("expected Select core");
5947 }
5948 } else {
5949 unreachable!("expected Select");
5950 }
5951 }
5952
5953 #[test]
5954 fn test_window_frame_exclude_group() {
5955 let stmt =
5956 parse_one("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
5957 if let Statement::Select(s) = stmt {
5958 if let SelectCore::Select { columns, .. } = &s.body.select {
5959 match &columns[0] {
5960 ResultColumn::Expr {
5961 expr:
5962 Expr::FunctionCall {
5963 over: Some(over), ..
5964 },
5965 ..
5966 } => {
5967 let frame = over.frame.as_ref().expect("frame spec");
5968 assert_eq!(frame.frame_type, FrameType::Groups);
5969 assert_eq!(frame.exclude, Some(FrameExclude::Group));
5970 }
5971 other => unreachable!("expected window function, got {other:?}"),
5972 }
5973 } else {
5974 unreachable!("expected Select core");
5975 }
5976 } else {
5977 unreachable!("expected Select");
5978 }
5979 }
5980
5981 #[test]
5982 fn test_window_frame_unbounded_following() {
5983 let stmt = parse_one(
5984 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM t",
5985 );
5986 if let Statement::Select(s) = stmt {
5987 if let SelectCore::Select { columns, .. } = &s.body.select {
5988 match &columns[0] {
5989 ResultColumn::Expr {
5990 expr:
5991 Expr::FunctionCall {
5992 over: Some(over), ..
5993 },
5994 ..
5995 } => {
5996 let frame = over.frame.as_ref().expect("frame spec");
5997 assert!(matches!(frame.start, FrameBound::CurrentRow));
5998 assert!(matches!(frame.end, Some(FrameBound::UnboundedFollowing)));
5999 }
6000 other => unreachable!("expected window function, got {other:?}"),
6001 }
6002 } else {
6003 unreachable!("expected Select core");
6004 }
6005 } else {
6006 unreachable!("expected Select");
6007 }
6008 }
6009
6010 #[test]
6011 fn test_window_frame_rejects_illegal_bound_order_with_exact_span() {
6012 for (sql, rejected) in [
6013 (
6014 "SELECT sum(x) OVER (ROWS UNBOUNDED FOLLOWING) FROM t",
6015 "UNBOUNDED",
6016 ),
6017 ("SELECT sum(x) OVER (ROWS 1 FOLLOWING) FROM t", "1"),
6018 (
6019 "SELECT sum(x) OVER (ROWS BETWEEN UNBOUNDED FOLLOWING AND UNBOUNDED FOLLOWING) FROM t",
6020 "UNBOUNDED",
6021 ),
6022 (
6023 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED PRECEDING) FROM t",
6024 "UNBOUNDED",
6025 ),
6026 (
6027 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND 1 PRECEDING) FROM t",
6028 "1",
6029 ),
6030 (
6031 "SELECT sum(x) OVER (ROWS BETWEEN 1 FOLLOWING AND CURRENT ROW) FROM t",
6032 "CURRENT",
6033 ),
6034 ] {
6035 let error = parse_first_statement_with_tail(sql)
6036 .expect_err("illegal window-frame boundaries must be rejected");
6037 assert_eq!(error.kind, ParseErrorKind::Syntax);
6038 assert_eq!(
6039 &sql[error.span.start as usize..error.span.end as usize],
6040 rejected,
6041 "the diagnostic for `{sql}` must point at the illegal boundary"
6042 );
6043 }
6044 }
6045
6046 #[test]
6047 fn test_window_frame_accepts_legal_categorical_order_without_offset_comparison() {
6048 for sql in [
6049 "SELECT sum(x) OVER (ROWS 1 PRECEDING) FROM t",
6050 "SELECT sum(x) OVER (ROWS BETWEEN 1 PRECEDING AND 2 PRECEDING) FROM t",
6051 "SELECT sum(x) OVER (ROWS BETWEEN 2 FOLLOWING AND UNBOUNDED FOLLOWING) FROM t",
6052 "SELECT sum(x) OVER (RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING) FROM t",
6053 "SELECT sum(x) OVER (GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM t",
6054 ] {
6055 parse_full_select(sql);
6056 }
6057 }
6058
6059 #[test]
6060 fn test_filter_clause_aggregate() {
6061 let stmt = parse_one("SELECT count(*) FILTER (WHERE x > 0) FROM t");
6062 if let Statement::Select(s) = stmt {
6063 if let SelectCore::Select { columns, .. } = &s.body.select {
6064 match &columns[0] {
6065 ResultColumn::Expr {
6066 expr: Expr::FunctionCall { filter, .. },
6067 ..
6068 } => {
6069 assert!(
6070 filter.is_some(),
6071 "FILTER clause must be present on aggregate"
6072 );
6073 }
6074 other => unreachable!("expected function call with filter, got {other:?}"),
6075 }
6076 } else {
6077 unreachable!("expected Select core");
6078 }
6079 } else {
6080 unreachable!("expected Select");
6081 }
6082 }
6083
6084 #[test]
6085 fn test_filter_clause_window() {
6086 let stmt = parse_one("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
6087 if let Statement::Select(s) = stmt {
6088 if let SelectCore::Select { columns, .. } = &s.body.select {
6089 match &columns[0] {
6090 ResultColumn::Expr {
6091 expr:
6092 Expr::FunctionCall {
6093 filter,
6094 over: Some(_),
6095 ..
6096 },
6097 ..
6098 } => {
6099 assert!(
6100 filter.is_some(),
6101 "FILTER clause must be present on window function"
6102 );
6103 }
6104 other => unreachable!("expected window function with filter, got {other:?}"),
6105 }
6106 } else {
6107 unreachable!("expected Select core");
6108 }
6109 } else {
6110 unreachable!("expected Select");
6111 }
6112 }
6113
6114 #[test]
6115 fn test_subquery_in_from() {
6116 let stmt = parse_one("SELECT sub.x FROM (SELECT 1 AS x) AS sub");
6117 if let Statement::Select(s) = stmt {
6118 if let SelectCore::Select { from, .. } = &s.body.select {
6119 let from = from.as_ref().expect("FROM clause");
6120 match &from.source {
6121 TableOrSubquery::Subquery { alias, .. } => {
6122 assert_eq!(alias.as_deref(), Some("sub"));
6123 }
6124 other => unreachable!("expected subquery source, got {other:?}"),
6125 }
6126 } else {
6127 unreachable!("expected Select core");
6128 }
6129 } else {
6130 unreachable!("expected Select");
6131 }
6132 }
6133
6134 #[test]
6135 fn test_multiple_joins_chain() {
6136 let stmt = parse_one(
6137 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id \
6138 LEFT JOIN c ON b.id = c.b_id \
6139 CROSS JOIN d",
6140 );
6141 if let Statement::Select(s) = stmt {
6142 if let SelectCore::Select { from, .. } = &s.body.select {
6143 let from = from.as_ref().expect("FROM clause");
6144 assert_eq!(from.joins.len(), 3);
6145 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
6146 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
6147 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
6148 } else {
6149 unreachable!("expected Select core");
6150 }
6151 } else {
6152 unreachable!("expected Select");
6153 }
6154 }
6155
6156 #[test]
6157 fn test_natural_left_join() {
6158 let stmt = parse_one("SELECT * FROM a NATURAL LEFT JOIN b");
6159 if let Statement::Select(s) = stmt {
6160 if let SelectCore::Select { from, .. } = &s.body.select {
6161 let from = from.as_ref().expect("FROM clause");
6162 let jt = &from.joins[0].join_type;
6163 assert!(jt.natural, "must be NATURAL");
6164 assert_eq!(jt.kind, JoinKind::Left);
6165 } else {
6166 unreachable!("expected Select core");
6167 }
6168 } else {
6169 unreachable!("expected Select");
6170 }
6171 }
6172
6173 #[test]
6174 fn test_select_nulls_first_default_asc() {
6175 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
6177 if let Statement::Select(s) = stmt {
6178 assert_eq!(s.order_by.len(), 1);
6179 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
6180 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
6181 } else {
6182 unreachable!("expected Select");
6183 }
6184 }
6185
6186 #[test]
6187 fn test_select_nulls_last_desc() {
6188 let stmt = parse_one("SELECT a FROM t ORDER BY a DESC NULLS LAST");
6190 if let Statement::Select(s) = stmt {
6191 assert_eq!(s.order_by.len(), 1);
6192 assert_eq!(s.order_by[0].direction, Some(SortDirection::Desc));
6193 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
6194 } else {
6195 unreachable!("expected Select");
6196 }
6197 }
6198
6199 #[test]
6204 fn test_roundtrip_select_filter_clause() {
6205 assert_roundtrip("SELECT count(*) FILTER (WHERE x > 0) FROM t");
6206 }
6207
6208 #[test]
6209 fn test_roundtrip_select_window_frame_groups() {
6210 assert_roundtrip(
6211 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
6212 );
6213 }
6214
6215 #[test]
6216 fn test_roundtrip_select_window_frame_exclude() {
6217 assert_roundtrip(
6218 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
6219 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
6220 );
6221 assert_roundtrip(
6222 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
6223 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
6224 );
6225 assert_roundtrip("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
6226 }
6227
6228 #[test]
6229 fn test_roundtrip_select_nulls_order() {
6230 assert_roundtrip("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
6231 assert_roundtrip("SELECT a FROM t ORDER BY a DESC NULLS LAST");
6232 }
6233
6234 #[test]
6235 fn test_roundtrip_select_values() {
6236 assert_roundtrip("VALUES (1, 2), (3, 4)");
6237 }
6238
6239 #[test]
6240 fn test_roundtrip_select_compound_order_limit() {
6241 assert_roundtrip("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
6242 }
6243
6244 #[test]
6245 fn test_roundtrip_select_cte_not_materialized() {
6246 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
6247 }
6248
6249 #[test]
6250 fn test_roundtrip_select_natural_left_join() {
6251 assert_roundtrip("SELECT * FROM a NATURAL LEFT JOIN b");
6252 }
6253
6254 #[test]
6255 fn test_roundtrip_select_indexed_by() {
6256 assert_roundtrip("SELECT * FROM t INDEXED BY idx_t WHERE x = 1");
6257 }
6258
6259 #[test]
6260 fn test_roundtrip_select_filter_window_combined() {
6261 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
6262 }
6263
6264 #[test]
6265 fn test_serializer_regression_window_base_name_and_extensions_roundtrip() {
6266 assert_roundtrip("SELECT sum(x) OVER base FROM t");
6267 assert_roundtrip(
6268 "SELECT sum(x) OVER (base PARTITION BY p ORDER BY y \
6269 ROWS BETWEEN z PRECEDING AND CURRENT ROW) FROM t",
6270 );
6271 }
6272
6273 #[test]
6274 fn test_roundtrip_select_three_way_compound() {
6275 assert_roundtrip("SELECT 1 UNION SELECT 2 EXCEPT SELECT 3");
6276 }
6277
6278 #[test]
6279 fn test_roundtrip_select_multiple_joins() {
6280 assert_roundtrip(
6281 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id LEFT JOIN c ON b.id = c.b_id",
6282 );
6283 }
6284
6285 #[test]
6290 fn test_select_star() {
6291 let stmt = parse_one("SELECT * FROM t");
6293 if let Statement::Select(s) = stmt {
6294 if let SelectCore::Select { columns, .. } = &s.body.select {
6295 assert!(matches!(columns[0], ResultColumn::Star));
6296 } else {
6297 unreachable!("expected Select core");
6298 }
6299 } else {
6300 unreachable!("expected Select");
6301 }
6302 }
6303
6304 #[test]
6305 fn test_inner_join_on() {
6306 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
6308 if let Statement::Select(s) = stmt {
6309 if let SelectCore::Select { from, .. } = &s.body.select {
6310 let from = from.as_ref().expect("FROM clause");
6311 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
6312 assert!(matches!(
6313 from.joins[0].constraint,
6314 Some(JoinConstraint::On(_))
6315 ));
6316 } else {
6317 unreachable!("expected Select core");
6318 }
6319 } else {
6320 unreachable!("expected Select");
6321 }
6322 }
6323
6324 #[test]
6325 fn test_left_outer_join() {
6326 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
6328 if let Statement::Select(s) = stmt {
6329 if let SelectCore::Select { from, .. } = &s.body.select {
6330 let from = from.as_ref().expect("FROM clause");
6331 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
6332 } else {
6333 unreachable!("expected Select core");
6334 }
6335 } else {
6336 unreachable!("expected Select");
6337 }
6338 }
6339
6340 #[test]
6341 fn test_right_outer_join() {
6342 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
6344 if let Statement::Select(s) = stmt {
6345 if let SelectCore::Select { from, .. } = &s.body.select {
6346 let from = from.as_ref().expect("FROM clause");
6347 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
6348 } else {
6349 unreachable!("expected Select core");
6350 }
6351 } else {
6352 unreachable!("expected Select");
6353 }
6354 }
6355
6356 #[test]
6357 fn test_full_outer_join() {
6358 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
6360 if let Statement::Select(s) = stmt {
6361 if let SelectCore::Select { from, .. } = &s.body.select {
6362 let from = from.as_ref().expect("FROM clause");
6363 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
6364 } else {
6365 unreachable!("expected Select core");
6366 }
6367 } else {
6368 unreachable!("expected Select");
6369 }
6370 }
6371
6372 #[test]
6373 fn test_cross_join_no_reorder() {
6374 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
6376 if let Statement::Select(s) = stmt {
6377 if let SelectCore::Select { from, .. } = &s.body.select {
6378 let from = from.as_ref().expect("FROM clause");
6379 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
6380 assert!(from.joins[0].constraint.is_none());
6382 } else {
6383 unreachable!("expected Select core");
6384 }
6385 } else {
6386 unreachable!("expected Select");
6387 }
6388 }
6389
6390 #[test]
6391 fn test_natural_join() {
6392 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
6394 if let Statement::Select(s) = stmt {
6395 if let SelectCore::Select { from, .. } = &s.body.select {
6396 let from = from.as_ref().expect("FROM clause");
6397 assert!(from.joins[0].join_type.natural);
6398 } else {
6399 unreachable!("expected Select core");
6400 }
6401 } else {
6402 unreachable!("expected Select");
6403 }
6404 }
6405
6406 #[test]
6407 fn test_using_clause() {
6408 let stmt = parse_one("SELECT * FROM a JOIN b USING (id, name)");
6410 if let Statement::Select(s) = stmt {
6411 if let SelectCore::Select { from, .. } = &s.body.select {
6412 let from = from.as_ref().expect("FROM clause");
6413 match &from.joins[0].constraint {
6414 Some(JoinConstraint::Using(cols)) => {
6415 assert_eq!(cols.len(), 2);
6416 assert_eq!(cols[0], "id");
6417 assert_eq!(cols[1], "name");
6418 }
6419 other => unreachable!("expected USING constraint, got {other:?}"),
6420 }
6421 } else {
6422 unreachable!("expected Select core");
6423 }
6424 } else {
6425 unreachable!("expected Select");
6426 }
6427 }
6428
6429 #[test]
6430 fn test_cte_basic() {
6431 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
6433 if let Statement::Select(s) = stmt {
6434 let with = s.with.as_ref().expect("WITH clause");
6435 assert!(!with.recursive);
6436 assert_eq!(with.ctes.len(), 1);
6437 assert_eq!(with.ctes[0].name, "cte");
6438 } else {
6439 unreachable!("expected Select");
6440 }
6441 }
6442
6443 #[test]
6444 fn test_cte_recursive_union_all() {
6445 let stmt = parse_one(
6447 "WITH RECURSIVE cnt(x) AS (\
6448 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
6449 ) SELECT x FROM cnt",
6450 );
6451 if let Statement::Select(s) = stmt {
6452 let with = s.with.as_ref().expect("WITH clause");
6453 assert!(with.recursive);
6454 assert_eq!(with.ctes[0].name, "cnt");
6455 let cte_body = &with.ctes[0].query;
6457 assert_eq!(cte_body.body.compounds.len(), 1);
6458 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::UnionAll);
6459 } else {
6460 unreachable!("expected Select");
6461 }
6462 }
6463
6464 #[test]
6465 fn test_cte_recursive_union_cycle_detection() {
6466 let stmt = parse_one(
6468 "WITH RECURSIVE paths(a, b) AS (\
6469 SELECT src, dst FROM edges \
6470 UNION \
6471 SELECT p.a, e.dst FROM paths p JOIN edges e ON p.b = e.src\
6472 ) SELECT * FROM paths",
6473 );
6474 if let Statement::Select(s) = stmt {
6475 let with = s.with.as_ref().expect("WITH clause");
6476 assert!(with.recursive);
6477 let cte_body = &with.ctes[0].query;
6479 assert_eq!(cte_body.body.compounds.len(), 1);
6480 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::Union);
6481 } else {
6482 unreachable!("expected Select");
6483 }
6484 }
6485
6486 #[test]
6487 fn test_cte_materialized_hint() {
6488 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
6490 if let Statement::Select(s) = stmt {
6491 let with = s.with.as_ref().expect("WITH clause");
6492 assert_eq!(
6493 with.ctes[0].materialized,
6494 Some(CteMaterialized::Materialized)
6495 );
6496 } else {
6497 unreachable!("expected Select");
6498 }
6499 }
6500
6501 #[test]
6502 fn test_cte_not_materialized_hint() {
6503 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
6505 if let Statement::Select(s) = stmt {
6506 let with = s.with.as_ref().expect("WITH clause");
6507 assert_eq!(
6508 with.ctes[0].materialized,
6509 Some(CteMaterialized::NotMaterialized)
6510 );
6511 } else {
6512 unreachable!("expected Select");
6513 }
6514 }
6515
6516 #[test]
6517 fn test_window_partition_by() {
6518 let stmt = parse_one("SELECT sum(x) OVER (PARTITION BY dept) FROM emp");
6520 if let Statement::Select(s) = stmt {
6521 if let SelectCore::Select { columns, .. } = &s.body.select {
6522 match &columns[0] {
6523 ResultColumn::Expr {
6524 expr:
6525 Expr::FunctionCall {
6526 over: Some(over), ..
6527 },
6528 ..
6529 } => {
6530 assert_eq!(over.partition_by.len(), 1);
6531 }
6532 other => unreachable!("expected window function, got {other:?}"),
6533 }
6534 } else {
6535 unreachable!("expected Select core");
6536 }
6537 } else {
6538 unreachable!("expected Select");
6539 }
6540 }
6541
6542 #[test]
6543 fn test_window_order_by() {
6544 let stmt = parse_one("SELECT row_number() OVER (ORDER BY salary DESC) FROM emp");
6546 if let Statement::Select(s) = stmt {
6547 if let SelectCore::Select { columns, .. } = &s.body.select {
6548 match &columns[0] {
6549 ResultColumn::Expr {
6550 expr:
6551 Expr::FunctionCall {
6552 over: Some(over), ..
6553 },
6554 ..
6555 } => {
6556 assert_eq!(over.order_by.len(), 1);
6557 assert_eq!(over.order_by[0].direction, Some(SortDirection::Desc));
6558 }
6559 other => unreachable!("expected window function, got {other:?}"),
6560 }
6561 } else {
6562 unreachable!("expected Select core");
6563 }
6564 } else {
6565 unreachable!("expected Select");
6566 }
6567 }
6568
6569 #[test]
6570 fn test_window_frame_rows() {
6571 let stmt = parse_one(
6573 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
6574 );
6575 if let Statement::Select(s) = stmt {
6576 if let SelectCore::Select { columns, .. } = &s.body.select {
6577 match &columns[0] {
6578 ResultColumn::Expr {
6579 expr:
6580 Expr::FunctionCall {
6581 over: Some(over), ..
6582 },
6583 ..
6584 } => {
6585 let frame = over.frame.as_ref().expect("frame spec");
6586 assert_eq!(frame.frame_type, FrameType::Rows);
6587 assert!(matches!(frame.start, FrameBound::Preceding(_)));
6588 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
6589 }
6590 other => unreachable!("expected window function, got {other:?}"),
6591 }
6592 } else {
6593 unreachable!("expected Select core");
6594 }
6595 } else {
6596 unreachable!("expected Select");
6597 }
6598 }
6599
6600 #[test]
6601 fn test_window_exclude_current_row() {
6602 let stmt = parse_one(
6604 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
6605 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
6606 );
6607 if let Statement::Select(s) = stmt {
6608 if let SelectCore::Select { columns, .. } = &s.body.select {
6609 match &columns[0] {
6610 ResultColumn::Expr {
6611 expr:
6612 Expr::FunctionCall {
6613 over: Some(over), ..
6614 },
6615 ..
6616 } => {
6617 let frame = over.frame.as_ref().expect("frame spec");
6618 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
6619 }
6620 other => unreachable!("expected window function, got {other:?}"),
6621 }
6622 } else {
6623 unreachable!("expected Select core");
6624 }
6625 } else {
6626 unreachable!("expected Select");
6627 }
6628 }
6629
6630 #[test]
6631 fn test_window_exclude_ties() {
6632 let stmt = parse_one(
6634 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
6635 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
6636 );
6637 if let Statement::Select(s) = stmt {
6638 if let SelectCore::Select { columns, .. } = &s.body.select {
6639 match &columns[0] {
6640 ResultColumn::Expr {
6641 expr:
6642 Expr::FunctionCall {
6643 over: Some(over), ..
6644 },
6645 ..
6646 } => {
6647 let frame = over.frame.as_ref().expect("frame spec");
6648 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
6649 }
6650 other => unreachable!("expected window function, got {other:?}"),
6651 }
6652 } else {
6653 unreachable!("expected Select core");
6654 }
6655 } else {
6656 unreachable!("expected Select");
6657 }
6658 }
6659
6660 #[test]
6661 fn test_nulls_first_asc() {
6662 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
6664 if let Statement::Select(s) = stmt {
6665 assert_eq!(s.order_by.len(), 1);
6666 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
6667 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
6668 } else {
6669 unreachable!("expected Select");
6670 }
6671 }
6672
6673 #[test]
6674 fn test_nulls_last_asc() {
6675 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS LAST");
6677 if let Statement::Select(s) = stmt {
6678 assert_eq!(s.order_by.len(), 1);
6679 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
6680 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
6681 } else {
6682 unreachable!("expected Select");
6683 }
6684 }
6685
6686 #[test]
6687 fn test_distinct_deduplicates() {
6688 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
6690 if let Statement::Select(s) = stmt {
6691 if let SelectCore::Select { distinct, .. } = &s.body.select {
6692 assert_eq!(*distinct, Distinctness::Distinct);
6693 } else {
6694 unreachable!("expected Select core");
6695 }
6696 } else {
6697 unreachable!("expected Select");
6698 }
6699 }
6700
6701 #[test]
6702 fn test_limit_offset() {
6703 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET 20");
6705 if let Statement::Select(s) = stmt {
6706 let limit = s.limit.expect("LIMIT clause");
6707 assert!(matches!(
6708 limit.limit,
6709 Expr::Literal(Literal::Integer(10), _)
6710 ));
6711 assert!(matches!(
6712 limit.offset,
6713 Some(Expr::Literal(Literal::Integer(20), _))
6714 ));
6715 } else {
6716 unreachable!("expected Select");
6717 }
6718 }
6719
6720 #[test]
6721 fn test_limit_comma_syntax() {
6722 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
6724 if let Statement::Select(s) = stmt {
6725 let limit = s.limit.expect("LIMIT clause");
6726 assert!(matches!(
6728 limit.limit,
6729 Expr::Literal(Literal::Integer(10), _)
6730 ));
6731 assert!(matches!(
6732 limit.offset,
6733 Some(Expr::Literal(Literal::Integer(5), _))
6734 ));
6735 } else {
6736 unreachable!("expected Select");
6737 }
6738 }
6739
6740 #[test]
6741 fn test_negative_limit_unlimited() {
6742 let stmt = parse_one("SELECT a FROM t LIMIT -1");
6744 if let Statement::Select(s) = stmt {
6745 let limit = s.limit.expect("LIMIT clause");
6746 match &limit.limit {
6749 Expr::UnaryOp {
6750 op: fsqlite_ast::UnaryOp::Negate,
6751 ..
6752 } => {}
6753 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
6754 other => unreachable!("expected negative limit expression, got {other:?}"),
6755 }
6756 } else {
6757 unreachable!("expected Select");
6758 }
6759 }
6760
6761 #[test]
6762 fn test_negative_offset_zero() {
6763 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET -5");
6765 if let Statement::Select(s) = stmt {
6766 let limit = s.limit.expect("LIMIT clause");
6767 assert!(limit.offset.is_some());
6768 match limit.offset.as_ref().unwrap() {
6769 Expr::UnaryOp {
6770 op: fsqlite_ast::UnaryOp::Negate,
6771 ..
6772 } => {}
6773 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
6774 other => unreachable!("expected negative offset expression, got {other:?}"),
6775 }
6776 } else {
6777 unreachable!("expected Select");
6778 }
6779 }
6780
6781 #[test]
6782 fn test_current_date_constant() {
6783 let stmt = parse_one("SELECT CURRENT_DATE");
6785 if let Statement::Select(s) = stmt {
6786 if let SelectCore::Select { columns, .. } = &s.body.select {
6787 match &columns[0] {
6788 ResultColumn::Expr {
6789 expr: Expr::Literal(Literal::CurrentDate, _),
6790 ..
6791 } => {}
6792 other => unreachable!("expected CURRENT_DATE literal, got {other:?}"),
6793 }
6794 } else {
6795 unreachable!("expected Select core");
6796 }
6797 } else {
6798 unreachable!("expected Select");
6799 }
6800 }
6801
6802 #[test]
6803 fn test_current_time_constant() {
6804 let stmt = parse_one("SELECT CURRENT_TIME");
6806 if let Statement::Select(s) = stmt {
6807 if let SelectCore::Select { columns, .. } = &s.body.select {
6808 match &columns[0] {
6809 ResultColumn::Expr {
6810 expr: Expr::Literal(Literal::CurrentTime, _),
6811 ..
6812 } => {}
6813 other => unreachable!("expected CURRENT_TIME literal, got {other:?}"),
6814 }
6815 } else {
6816 unreachable!("expected Select core");
6817 }
6818 } else {
6819 unreachable!("expected Select");
6820 }
6821 }
6822
6823 #[test]
6824 fn test_current_timestamp_constant() {
6825 let stmt = parse_one("SELECT CURRENT_TIMESTAMP");
6827 if let Statement::Select(s) = stmt {
6828 if let SelectCore::Select { columns, .. } = &s.body.select {
6829 match &columns[0] {
6830 ResultColumn::Expr {
6831 expr: Expr::Literal(Literal::CurrentTimestamp, _),
6832 ..
6833 } => {}
6834 other => unreachable!("expected CURRENT_TIMESTAMP literal, got {other:?}"),
6835 }
6836 } else {
6837 unreachable!("expected Select core");
6838 }
6839 } else {
6840 unreachable!("expected Select");
6841 }
6842 }
6843
6844 #[test]
6845 fn test_date_constants_evaluated_once_per_statement() {
6846 let stmt = parse_one("SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP FROM t");
6849 if let Statement::Select(s) = stmt {
6850 if let SelectCore::Select { columns, .. } = &s.body.select {
6851 assert_eq!(columns.len(), 3);
6852 assert!(matches!(
6853 &columns[0],
6854 ResultColumn::Expr {
6855 expr: Expr::Literal(Literal::CurrentDate, _),
6856 ..
6857 }
6858 ));
6859 assert!(matches!(
6860 &columns[1],
6861 ResultColumn::Expr {
6862 expr: Expr::Literal(Literal::CurrentTime, _),
6863 ..
6864 }
6865 ));
6866 assert!(matches!(
6867 &columns[2],
6868 ResultColumn::Expr {
6869 expr: Expr::Literal(Literal::CurrentTimestamp, _),
6870 ..
6871 }
6872 ));
6873 } else {
6874 unreachable!("expected Select core");
6875 }
6876 } else {
6877 unreachable!("expected Select");
6878 }
6879 }
6880
6881 #[test]
6882 fn test_indexed_by_hint() {
6883 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
6885 if let Statement::Select(s) = stmt {
6886 if let SelectCore::Select { from, .. } = &s.body.select {
6887 let from = from.as_ref().expect("FROM clause");
6888 match &from.source {
6889 TableOrSubquery::Table {
6890 index_hint: Some(IndexHint::IndexedBy(name)),
6891 ..
6892 } => assert_eq!(name, "idx_t"),
6893 other => unreachable!("expected indexed table source, got {other:?}"),
6894 }
6895 } else {
6896 unreachable!("expected Select core");
6897 }
6898 } else {
6899 unreachable!("expected Select");
6900 }
6901 }
6902
6903 #[test]
6904 fn test_not_indexed_hint() {
6905 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
6907 if let Statement::Select(s) = stmt {
6908 if let SelectCore::Select { from, .. } = &s.body.select {
6909 let from = from.as_ref().expect("FROM clause");
6910 match &from.source {
6911 TableOrSubquery::Table {
6912 index_hint: Some(IndexHint::NotIndexed),
6913 ..
6914 } => {}
6915 other => unreachable!("expected not-indexed table source, got {other:?}"),
6916 }
6917 } else {
6918 unreachable!("expected Select core");
6919 }
6920 } else {
6921 unreachable!("expected Select");
6922 }
6923 }
6924
6925 #[test]
6926 fn test_table_valued_function_in_from() {
6927 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
6929 if let Statement::Select(s) = stmt {
6930 if let SelectCore::Select { from, .. } = &s.body.select {
6931 let from = from.as_ref().expect("FROM clause");
6932 match &from.source {
6933 TableOrSubquery::TableFunction { name, args, alias } => {
6934 assert_eq!(name, "generate_series");
6935 assert_eq!(args.len(), 2);
6936 assert_eq!(alias.as_deref(), Some("gs"));
6937 }
6938 other => unreachable!("expected table-valued function source, got {other:?}"),
6939 }
6940 } else {
6941 unreachable!("expected Select core");
6942 }
6943 } else {
6944 unreachable!("expected Select");
6945 }
6946 }
6947
6948 #[test]
6953 fn test_insert_values_single() {
6954 let stmt = parse_one("INSERT INTO t (a, b, c) VALUES (1, 'hello', 3.14)");
6955 if let Statement::Insert(i) = stmt {
6956 assert_eq!(i.columns, vec!["a", "b", "c"]);
6957 if let InsertSource::Values(rows) = &i.source {
6958 assert_eq!(rows.len(), 1);
6959 assert_eq!(rows[0].len(), 3);
6960 } else {
6961 unreachable!("expected Values source");
6962 }
6963 } else {
6964 unreachable!("expected Insert");
6965 }
6966 }
6967
6968 #[test]
6969 fn test_insert_values_multi() {
6970 let stmt = parse_one("INSERT INTO t (x, y) VALUES (1, 2), (3, 4), (5, 6)");
6971 if let Statement::Insert(i) = stmt {
6972 if let InsertSource::Values(rows) = &i.source {
6973 assert_eq!(rows.len(), 3);
6974 for row in rows {
6975 assert_eq!(row.len(), 2);
6976 }
6977 } else {
6978 unreachable!("expected Values source");
6979 }
6980 } else {
6981 unreachable!("expected Insert");
6982 }
6983 }
6984
6985 #[test]
6986 fn test_insert_from_select() {
6987 let stmt = parse_one("INSERT INTO t2 (a, b) SELECT x, y FROM t1 WHERE x > 0");
6988 if let Statement::Insert(i) = stmt {
6989 assert!(matches!(i.source, InsertSource::Select(_)));
6990 assert_eq!(i.columns, vec!["a", "b"]);
6991 } else {
6992 unreachable!("expected Insert");
6993 }
6994 }
6995
6996 #[test]
6997 fn test_insert_from_select_without_from_clause() {
6998 let stmt = parse_one("INSERT INTO t (a) SELECT 1");
6999 if let Statement::Insert(i) = stmt {
7000 if let InsertSource::Select(select) = &i.source {
7001 if let SelectCore::Select { from, columns, .. } = &select.body.select {
7002 assert!(from.is_none(), "SELECT 1 should parse without FROM");
7003 assert_eq!(columns.len(), 1);
7004 } else {
7005 unreachable!("expected Select core");
7006 }
7007 } else {
7008 unreachable!("expected Select source");
7009 }
7010 } else {
7011 unreachable!("expected Insert");
7012 }
7013 }
7014
7015 #[test]
7016 fn test_insert_from_select_subquery_source() {
7017 let stmt = parse_one("INSERT INTO t (a) SELECT sub.x FROM (SELECT 1 AS x) AS sub");
7018 if let Statement::Insert(i) = stmt {
7019 if let InsertSource::Select(select) = &i.source {
7020 if let SelectCore::Select { from, .. } = &select.body.select {
7021 let from = from.as_ref().expect("FROM clause");
7022 match &from.source {
7023 TableOrSubquery::Subquery { alias, .. } => {
7024 assert_eq!(alias.as_deref(), Some("sub"));
7025 }
7026 other => unreachable!("expected subquery source, got {other:?}"),
7027 }
7028 } else {
7029 unreachable!("expected Select core");
7030 }
7031 } else {
7032 unreachable!("expected Select source");
7033 }
7034 } else {
7035 unreachable!("expected Insert");
7036 }
7037 }
7038
7039 #[test]
7040 fn test_insert_from_select_table_function_source() {
7041 let stmt = parse_one("INSERT INTO t (a) SELECT gs.value FROM generate_series(1, 3) AS gs");
7042 if let Statement::Insert(i) = stmt {
7043 if let InsertSource::Select(select) = &i.source {
7044 if let SelectCore::Select { from, .. } = &select.body.select {
7045 let from = from.as_ref().expect("FROM clause");
7046 match &from.source {
7047 TableOrSubquery::TableFunction { name, args, alias } => {
7048 assert_eq!(name, "generate_series");
7049 assert_eq!(args.len(), 2);
7050 assert_eq!(alias.as_deref(), Some("gs"));
7051 }
7052 other => unreachable!("expected table function source, got {other:?}"),
7053 }
7054 } else {
7055 unreachable!("expected Select core");
7056 }
7057 } else {
7058 unreachable!("expected Select source");
7059 }
7060 } else {
7061 unreachable!("expected Insert");
7062 }
7063 }
7064
7065 #[test]
7066 fn test_insert_default_values() {
7067 let stmt = parse_one("INSERT INTO t DEFAULT VALUES");
7068 if let Statement::Insert(i) = stmt {
7069 assert!(matches!(i.source, InsertSource::DefaultValues));
7070 assert!(i.columns.is_empty());
7071 } else {
7072 unreachable!("expected Insert");
7073 }
7074 }
7075
7076 #[test]
7077 fn test_insert_or_abort() {
7078 let stmt = parse_one("INSERT OR ABORT INTO t (a) VALUES (1)");
7079 if let Statement::Insert(i) = stmt {
7080 assert_eq!(i.or_conflict, Some(ConflictAction::Abort));
7081 } else {
7082 unreachable!("expected Insert");
7083 }
7084 }
7085
7086 #[test]
7087 fn test_insert_or_rollback() {
7088 let stmt = parse_one("INSERT OR ROLLBACK INTO t (a) VALUES (1)");
7089 if let Statement::Insert(i) = stmt {
7090 assert_eq!(i.or_conflict, Some(ConflictAction::Rollback));
7091 } else {
7092 unreachable!("expected Insert");
7093 }
7094 }
7095
7096 #[test]
7097 fn test_insert_or_fail() {
7098 let stmt = parse_one("INSERT OR FAIL INTO t (a) VALUES (1)");
7099 if let Statement::Insert(i) = stmt {
7100 assert_eq!(i.or_conflict, Some(ConflictAction::Fail));
7101 } else {
7102 unreachable!("expected Insert");
7103 }
7104 }
7105
7106 #[test]
7107 fn test_insert_or_ignore() {
7108 let stmt = parse_one("INSERT OR IGNORE INTO t (a) VALUES (1)");
7109 if let Statement::Insert(i) = stmt {
7110 assert_eq!(i.or_conflict, Some(ConflictAction::Ignore));
7111 } else {
7112 unreachable!("expected Insert");
7113 }
7114 }
7115
7116 #[test]
7117 fn test_insert_or_replace() {
7118 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1)");
7120 if let Statement::Insert(i) = stmt {
7121 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
7122 } else {
7123 unreachable!("expected Insert");
7124 }
7125 }
7126
7127 #[test]
7128 fn test_upsert_do_update() {
7129 let stmt = parse_one(
7130 "INSERT INTO t (a, b) VALUES (1, 2) ON CONFLICT (a) DO UPDATE SET b = excluded.b",
7131 );
7132 if let Statement::Insert(i) = stmt {
7133 assert_eq!(i.upsert.len(), 1);
7134 assert!(i.upsert[0].target.is_some());
7135 match &i.upsert[0].action {
7136 UpsertAction::Update {
7137 assignments,
7138 where_clause,
7139 } => {
7140 assert_eq!(assignments.len(), 1);
7141 assert!(where_clause.is_none());
7142 }
7143 UpsertAction::Nothing => unreachable!("expected Update action"),
7144 }
7145 } else {
7146 unreachable!("expected Insert");
7147 }
7148 }
7149
7150 #[test]
7151 fn test_upsert_do_nothing() {
7152 let stmt = parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
7153 if let Statement::Insert(i) = stmt {
7154 assert_eq!(i.upsert.len(), 1);
7155 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
7156 } else {
7157 unreachable!("expected Insert");
7158 }
7159 }
7160
7161 #[test]
7162 fn test_upsert_excluded_pseudo_table() {
7163 let stmt = parse_one(
7164 "INSERT INTO t (a, b) VALUES (1, 2) \
7165 ON CONFLICT (a) DO UPDATE SET b = excluded.b, a = excluded.a + 1",
7166 );
7167 if let Statement::Insert(i) = stmt {
7168 assert_eq!(i.upsert.len(), 1);
7169 if let UpsertAction::Update { assignments, .. } = &i.upsert[0].action {
7170 assert_eq!(assignments.len(), 2);
7171 match &assignments[0].value {
7173 Expr::Column(col, _) => {
7174 assert_eq!(col.table.as_deref(), Some("excluded"));
7175 assert_eq!(col.column.as_ref(), "b");
7176 }
7177 other => unreachable!("expected Column ref to excluded.b, got {other:?}"),
7178 }
7179 } else {
7180 unreachable!("expected Update action");
7181 }
7182 } else {
7183 unreachable!("expected Insert");
7184 }
7185 }
7186
7187 #[test]
7188 fn test_upsert_multiple_on_conflict() {
7189 let stmt = parse_one(
7190 "INSERT INTO t (a, b) VALUES (1, 2) \
7191 ON CONFLICT (a) DO NOTHING \
7192 ON CONFLICT (b) DO UPDATE SET a = excluded.a",
7193 );
7194 if let Statement::Insert(i) = stmt {
7195 assert_eq!(i.upsert.len(), 2);
7196 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
7197 assert!(matches!(i.upsert[1].action, UpsertAction::Update { .. }));
7198 } else {
7199 unreachable!("expected Insert");
7200 }
7201 }
7202
7203 #[test]
7204 fn test_upsert_where_on_conflict_target() {
7205 let stmt = parse_one(
7206 "INSERT INTO t (a, b) VALUES (1, 2) \
7207 ON CONFLICT (a) WHERE a > 0 DO UPDATE SET b = excluded.b WHERE b < 100",
7208 );
7209 if let Statement::Insert(i) = stmt {
7210 assert_eq!(i.upsert.len(), 1);
7211 let target = i.upsert[0].target.as_ref().expect("conflict target");
7212 assert!(target.where_clause.is_some(), "target WHERE missing");
7213 if let UpsertAction::Update { where_clause, .. } = &i.upsert[0].action {
7214 assert!(where_clause.is_some(), "action WHERE missing");
7215 } else {
7216 unreachable!("expected Update action");
7217 }
7218 } else {
7219 unreachable!("expected Insert");
7220 }
7221 }
7222
7223 #[test]
7224 fn test_returning_insert() {
7225 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, rowid");
7226 if let Statement::Insert(i) = stmt {
7227 assert_eq!(i.returning.len(), 3);
7228 } else {
7229 unreachable!("expected Insert");
7230 }
7231 }
7232
7233 #[test]
7234 fn test_returning_insert_select_with_semicolon() {
7235 let stmt = parse_one("INSERT INTO t2 SELECT * FROM t RETURNING *;");
7236 if let Statement::Insert(i) = stmt {
7237 assert!(matches!(i.source, InsertSource::Select(_)));
7238 assert_eq!(i.returning.len(), 1);
7239 assert!(matches!(i.returning[0], ResultColumn::Star));
7240 } else {
7241 unreachable!("expected Insert");
7242 }
7243 }
7244
7245 #[test]
7246 fn test_returning_reflects_before_triggers() {
7247 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING a AS modified_a");
7251 if let Statement::Insert(i) = stmt {
7252 assert_eq!(i.returning.len(), 1);
7253 match &i.returning[0] {
7254 ResultColumn::Expr { alias, .. } => {
7255 assert_eq!(alias.as_deref(), Some("modified_a"));
7256 }
7257 other => unreachable!("expected Expr result column, got {other:?}"),
7258 }
7259 } else {
7260 unreachable!("expected Insert");
7261 }
7262 }
7263
7264 #[test]
7265 fn test_returning_ignores_after_triggers() {
7266 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1) RETURNING *");
7270 if let Statement::Insert(i) = stmt {
7271 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
7272 assert_eq!(i.returning.len(), 1);
7273 assert!(matches!(i.returning[0], ResultColumn::Star));
7274 } else {
7275 unreachable!("expected Insert");
7276 }
7277 }
7278
7279 #[test]
7280 fn test_returning_after_before_trigger_modify() {
7281 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, a + b AS total");
7285 if let Statement::Insert(i) = stmt {
7286 assert_eq!(i.returning.len(), 3);
7287 match &i.returning[2] {
7288 ResultColumn::Expr {
7289 alias: Some(alias), ..
7290 } => assert_eq!(alias, "total"),
7291 other => unreachable!("expected aliased expression, got {other:?}"),
7292 }
7293 } else {
7294 unreachable!("expected Insert");
7295 }
7296 }
7297
7298 #[test]
7299 fn test_returning_before_trigger_raise_abort() {
7300 let stmt = parse_one("INSERT INTO t (a) VALUES (1), (2), (3) RETURNING a");
7304 if let Statement::Insert(i) = stmt {
7305 if let InsertSource::Values(rows) = &i.source {
7306 assert_eq!(rows.len(), 3);
7307 } else {
7308 unreachable!("expected Values source");
7309 }
7310 assert_eq!(i.returning.len(), 1);
7311 } else {
7312 unreachable!("expected Insert");
7313 }
7314 }
7315
7316 #[test]
7317 fn test_returning_instead_of_view() {
7318 let stmt = parse_one("INSERT INTO v (a, b) VALUES (1, 2) RETURNING *");
7321 if let Statement::Insert(i) = stmt {
7322 assert_eq!(i.table.name, "v");
7323 assert!(!i.returning.is_empty());
7324 } else {
7325 unreachable!("expected Insert");
7326 }
7327 }
7328
7329 #[test]
7330 fn test_returning_autoincrement_with_trigger() {
7331 let stmt = parse_one("INSERT INTO t (name) VALUES ('test') RETURNING rowid, name");
7334 if let Statement::Insert(i) = stmt {
7335 assert_eq!(i.returning.len(), 2);
7336 } else {
7337 unreachable!("expected Insert");
7338 }
7339 }
7340
7341 #[test]
7342 fn test_update_set_where() {
7343 let stmt = parse_one("UPDATE t SET a = 1, b = 'hello' WHERE id = 42");
7344 if let Statement::Update(u) = stmt {
7345 assert_eq!(u.assignments.len(), 2);
7346 assert!(u.where_clause.is_some());
7347 assert!(u.from.is_none());
7348 } else {
7349 unreachable!("expected Update");
7350 }
7351 }
7352
7353 #[test]
7354 fn test_update_from_join() {
7355 let stmt = parse_one("UPDATE t1 SET a = t2.x FROM t2 WHERE t1.id = t2.id");
7356 if let Statement::Update(u) = stmt {
7357 assert_eq!(u.assignments.len(), 1);
7358 assert!(u.from.is_some());
7359 assert!(u.where_clause.is_some());
7360 } else {
7361 unreachable!("expected Update");
7362 }
7363 }
7364
7365 #[test]
7366 fn test_update_from_multi_match() {
7367 let stmt = parse_one(
7370 "UPDATE t1 SET val = src.val FROM src \
7371 INNER JOIN mapping ON mapping.src_id = src.id \
7372 WHERE t1.id = mapping.dst_id",
7373 );
7374 if let Statement::Update(u) = stmt {
7375 assert!(u.from.is_some());
7376 let from = u.from.as_ref().unwrap();
7377 assert!(!from.joins.is_empty(), "expected JOIN in FROM clause");
7378 } else {
7379 unreachable!("expected Update");
7380 }
7381 }
7382
7383 #[test]
7384 fn test_update_from_parentheses_are_stack_safe_at_1000_and_1001() {
7385 fn drop_update_from_iteratively(statement: Statement) {
7386 let Statement::Update(mut update) = statement else {
7387 panic!("expected UPDATE statement");
7388 };
7389 let Some(mut from) = update.from.take() else {
7390 panic!("expected UPDATE FROM clause");
7391 };
7392 drop(update);
7393 loop {
7394 let FromClause { source, joins } = from;
7395 assert!(joins.is_empty());
7396 match source {
7397 TableOrSubquery::ParenJoin(inner) => from = *inner,
7398 leaf => {
7399 drop(leaf);
7400 break;
7401 }
7402 }
7403 }
7404 }
7405
7406 for height in [1000, 1001] {
7407 let sql = format!(
7408 "UPDATE target SET value = 1 FROM {}source{} WHERE target.id = source.id",
7409 "(".repeat(height),
7410 ")".repeat(height)
7411 );
7412 let (rendered, statement) = std::thread::Builder::new()
7413 .stack_size(1024 * 1024)
7414 .spawn(move || {
7415 let statement = Parser::from_sql(&sql)
7416 .parse_statement()
7417 .expect("deep UPDATE FROM must parse");
7418 let rendered = statement.to_string();
7419 (rendered, statement)
7420 })
7421 .expect("1 MiB parser thread must spawn")
7422 .join()
7423 .expect("deep UPDATE FROM parsing and formatting must not overflow");
7424 assert!(rendered.starts_with("UPDATE target SET value = 1 FROM "));
7425 assert!(rendered.ends_with(" WHERE target.id = source.id"));
7426 assert_eq!(rendered.matches('(').count(), height);
7427 assert_eq!(rendered.matches(')').count(), height);
7428 drop_update_from_iteratively(statement);
7429 }
7430 }
7431
7432 #[test]
7433 fn test_malformed_deep_update_from_recovers_following_statement() {
7434 let sql = format!(
7435 "UPDATE target SET value = 1 FROM {}source{}; SELECT 42;",
7436 "(".repeat(1001),
7437 ")".repeat(1000)
7438 );
7439 let (statements, errors) = std::thread::Builder::new()
7440 .stack_size(1024 * 1024)
7441 .spawn(move || Parser::from_sql(&sql).parse_all())
7442 .expect("1 MiB parser thread must spawn")
7443 .join()
7444 .expect("malformed deep UPDATE FROM recovery must not overflow");
7445
7446 assert_eq!(errors.len(), 1, "expected one unbalanced-FROM error");
7447 assert_eq!(
7448 statements.len(),
7449 1,
7450 "the malformed UPDATE must be discarded"
7451 );
7452 assert_eq!(statements[0].to_string(), "SELECT 42");
7453 }
7454
7455 #[test]
7456 fn recursion_limit_error_uses_stock_parser_stack_overflow_text() {
7457 let mut parser = Parser::from_sql("SELECT 1");
7463 for _ in 0..MAX_NATIVE_PARSE_DEPTH {
7464 parser
7465 .enter_recursion()
7466 .expect("depth below the cap must be accepted");
7467 }
7468 let error = parser
7469 .enter_recursion()
7470 .expect_err("exceeding the native recursion cap must be rejected");
7471 assert_eq!(error.kind, ParseErrorKind::RecursionLimit);
7472 assert_eq!(error.message, "parser stack overflow");
7473 }
7474
7475 #[test]
7476 fn semantically_empty_input_parses_to_no_statements() {
7477 let mut scratch = StatementParseScratch::default();
7482 for sql in [
7483 "",
7484 " ",
7485 "\n\t ",
7486 ";",
7487 " ; ; ",
7488 "-- just a comment",
7489 "/* block */",
7490 ] {
7491 let statements = parse_statements_with_scratch(sql, &mut scratch)
7492 .unwrap_or_else(|error| panic!("empty input {sql:?} must not error: {error}"));
7493 assert!(
7494 statements.is_empty(),
7495 "empty input {sql:?} must parse to zero statements"
7496 );
7497 }
7498 }
7499
7500 #[test]
7501 fn test_update_order_by_limit() {
7502 let stmt = parse_one("UPDATE t SET a = a + 1 ORDER BY b DESC LIMIT 10");
7503 if let Statement::Update(u) = stmt {
7504 assert_eq!(u.order_by.len(), 1);
7505 assert_eq!(u.order_by[0].direction, Some(SortDirection::Desc));
7506 assert!(u.limit.is_some());
7507 } else {
7508 unreachable!("expected Update");
7509 }
7510 }
7511
7512 #[test]
7513 fn test_update_returning() {
7514 let stmt = parse_one("UPDATE t SET a = 1 WHERE id = 5 RETURNING id, a AS new_a");
7515 if let Statement::Update(u) = stmt {
7516 assert_eq!(u.returning.len(), 2);
7517 match &u.returning[1] {
7518 ResultColumn::Expr {
7519 alias: Some(alias), ..
7520 } => assert_eq!(alias, "new_a"),
7521 other => unreachable!("expected aliased result column, got {other:?}"),
7522 }
7523 } else {
7524 unreachable!("expected Update");
7525 }
7526 }
7527
7528 #[test]
7529 fn test_update_or_ignore() {
7530 let stmt = parse_one("UPDATE OR IGNORE t SET a = 1 WHERE id = 5");
7531 if let Statement::Update(u) = stmt {
7532 assert_eq!(u.or_conflict, Some(ConflictAction::Ignore));
7533 assert!(u.where_clause.is_some());
7534 } else {
7535 unreachable!("expected Update");
7536 }
7537 }
7538
7539 #[test]
7540 fn test_delete_where() {
7541 let stmt = parse_one("DELETE FROM t WHERE id = 42 AND active = 0");
7542 if let Statement::Delete(d) = stmt {
7543 assert!(d.where_clause.is_some());
7544 assert!(d.returning.is_empty());
7545 } else {
7546 unreachable!("expected Delete");
7547 }
7548 }
7549
7550 #[test]
7551 fn test_delete_order_by_limit() {
7552 let stmt = parse_one("DELETE FROM t ORDER BY created_at ASC LIMIT 100");
7553 if let Statement::Delete(d) = stmt {
7554 assert_eq!(d.order_by.len(), 1);
7555 assert_eq!(d.order_by[0].direction, Some(SortDirection::Asc));
7556 let limit = d.limit.as_ref().expect("LIMIT clause");
7557 assert!(matches!(
7558 limit.limit,
7559 Expr::Literal(Literal::Integer(100), _)
7560 ));
7561 } else {
7562 unreachable!("expected Delete");
7563 }
7564 }
7565
7566 #[test]
7567 fn test_delete_returning() {
7568 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
7569 if let Statement::Delete(d) = stmt {
7570 assert!(d.where_clause.is_some());
7571 assert_eq!(d.returning.len(), 1);
7572 assert!(matches!(d.returning[0], ResultColumn::Star));
7573 } else {
7574 unreachable!("expected Delete");
7575 }
7576 }
7577
7578 #[test]
7579 fn test_delete_bulk_optimization() {
7580 let stmt = parse_one("DELETE FROM t");
7583 if let Statement::Delete(d) = stmt {
7584 assert!(d.where_clause.is_none());
7585 assert!(d.order_by.is_empty());
7586 assert!(d.limit.is_none());
7587 assert!(d.returning.is_empty());
7588 } else {
7589 unreachable!("expected Delete");
7590 }
7591 }
7592
7593 #[test]
7594 fn test_delete_bulk_no_where_fast() {
7595 let stmt = parse_one("DELETE FROM main.t");
7598 if let Statement::Delete(d) = stmt {
7599 assert_eq!(d.table.name.schema.as_deref(), Some("main"));
7600 assert_eq!(d.table.name.name, "t");
7601 assert!(d.where_clause.is_none());
7602 } else {
7603 unreachable!("expected Delete");
7604 }
7605 }
7606
7607 #[test]
7608 fn test_delete_bulk_blocked_by_trigger() {
7609 let stmt = parse_one("DELETE FROM orders");
7612 if let Statement::Delete(d) = stmt {
7613 assert!(d.where_clause.is_none());
7614 assert!(d.returning.is_empty());
7615 } else {
7616 unreachable!("expected Delete");
7617 }
7618 }
7619
7620 #[test]
7621 fn test_delete_bulk_blocked_by_fk() {
7622 let stmt = parse_one("DELETE FROM parent_table");
7625 if let Statement::Delete(d) = stmt {
7626 assert!(d.where_clause.is_none());
7627 } else {
7628 unreachable!("expected Delete");
7629 }
7630 }
7631
7632 #[test]
7633 fn test_delete_bulk_changes_count() {
7634 let stmt = parse_one("DELETE FROM t");
7638 if let Statement::Delete(d) = stmt {
7639 assert!(d.where_clause.is_none());
7640 } else {
7641 unreachable!("expected Delete");
7642 }
7643 }
7644
7645 #[test]
7646 fn test_delete_bulk_autoincrement_preserved() {
7647 let stmt = parse_one("DELETE FROM t");
7651 if let Statement::Delete(d) = stmt {
7652 assert!(d.where_clause.is_none());
7653 assert!(d.limit.is_none());
7654 } else {
7655 unreachable!("expected Delete");
7656 }
7657 }
7658
7659 #[test]
7660 fn test_delete_bulk_where_1_not_optimized() {
7661 let stmt = parse_one("DELETE FROM t WHERE 1");
7664 if let Statement::Delete(d) = stmt {
7665 assert!(
7666 d.where_clause.is_some(),
7667 "WHERE 1 must produce a where_clause"
7668 );
7669 assert!(matches!(
7670 d.where_clause.as_ref().unwrap(),
7671 Expr::Literal(Literal::Integer(1), _)
7672 ));
7673 } else {
7674 unreachable!("expected Delete");
7675 }
7676 }
7677
7678 #[test]
7683 fn test_create_table_basic() {
7684 let stmt = parse_one("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
7685 if let Statement::CreateTable(ct) = stmt {
7686 assert_eq!(ct.name.name, "users");
7687 assert!(!ct.if_not_exists);
7688 assert!(!ct.temporary);
7689 assert!(!ct.without_rowid);
7690 assert!(!ct.strict);
7691 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7692 assert_eq!(columns.len(), 3);
7693 assert_eq!(columns[0].name, "id");
7694 assert_eq!(columns[1].name, "name");
7695 assert_eq!(columns[2].name, "age");
7696 } else {
7697 unreachable!("expected Columns body");
7698 }
7699 } else {
7700 unreachable!("expected CreateTable");
7701 }
7702 }
7703
7704 #[test]
7705 fn test_create_table_if_not_exists() {
7706 let stmt = parse_one("CREATE TABLE IF NOT EXISTS t (id INTEGER)");
7707 if let Statement::CreateTable(ct) = stmt {
7708 assert!(ct.if_not_exists);
7709 } else {
7710 unreachable!("expected CreateTable");
7711 }
7712 }
7713
7714 #[test]
7715 fn test_create_temp_table() {
7716 let stmt = parse_one("CREATE TEMP TABLE session_data (key TEXT, val BLOB)");
7717 if let Statement::CreateTable(ct) = stmt {
7718 assert!(ct.temporary);
7719 } else {
7720 unreachable!("expected CreateTable");
7721 }
7722 }
7723
7724 #[test]
7725 fn test_create_table_as_select() {
7726 let stmt = parse_one("CREATE TABLE t2 AS SELECT id, name FROM t1 WHERE active = 1");
7727 if let Statement::CreateTable(ct) = stmt {
7728 assert!(matches!(ct.body, CreateTableBody::AsSelect(_)));
7729 } else {
7730 unreachable!("expected CreateTable");
7731 }
7732 }
7733
7734 #[test]
7735 fn test_column_primary_key() {
7736 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY ASC)");
7737 if let Statement::CreateTable(ct) = stmt {
7738 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7739 let pk = columns[0]
7740 .constraints
7741 .iter()
7742 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
7743 assert!(pk.is_some(), "PK constraint missing");
7744 if let ColumnConstraintKind::PrimaryKey { direction, .. } = &pk.unwrap().kind {
7745 assert_eq!(*direction, Some(SortDirection::Asc));
7746 }
7747 } else {
7748 unreachable!("expected Columns body");
7749 }
7750 } else {
7751 unreachable!("expected CreateTable");
7752 }
7753 }
7754
7755 #[test]
7756 fn test_column_primary_key_autoincrement() {
7757 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)");
7758 if let Statement::CreateTable(ct) = stmt {
7759 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7760 let pk = columns[0]
7761 .constraints
7762 .iter()
7763 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
7764 if let ColumnConstraintKind::PrimaryKey { autoincrement, .. } = &pk.unwrap().kind {
7765 assert!(autoincrement, "AUTOINCREMENT flag not set");
7766 }
7767 } else {
7768 unreachable!("expected Columns body");
7769 }
7770 } else {
7771 unreachable!("expected CreateTable");
7772 }
7773 }
7774
7775 #[test]
7776 fn test_autoincrement_uses_sqlite_sequence() {
7777 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)");
7780 if let Statement::CreateTable(ct) = stmt {
7781 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7782 assert_eq!(columns.len(), 2);
7783 let pk = columns[0].constraints.iter().find(|c| {
7784 matches!(
7785 c.kind,
7786 ColumnConstraintKind::PrimaryKey {
7787 autoincrement: true,
7788 ..
7789 }
7790 )
7791 });
7792 assert!(pk.is_some(), "AUTOINCREMENT constraint missing");
7793 } else {
7794 unreachable!("expected Columns body");
7795 }
7796 } else {
7797 unreachable!("expected CreateTable");
7798 }
7799 }
7800
7801 #[test]
7802 fn test_column_not_null() {
7803 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL)");
7804 if let Statement::CreateTable(ct) = stmt {
7805 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7806 let nn = columns[0]
7807 .constraints
7808 .iter()
7809 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
7810 assert!(nn.is_some(), "NOT NULL constraint missing");
7811 } else {
7812 unreachable!("expected Columns body");
7813 }
7814 } else {
7815 unreachable!("expected CreateTable");
7816 }
7817 }
7818
7819 #[test]
7820 fn test_column_unique() {
7821 let stmt = parse_one("CREATE TABLE t (email TEXT UNIQUE)");
7822 if let Statement::CreateTable(ct) = stmt {
7823 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7824 let uq = columns[0]
7825 .constraints
7826 .iter()
7827 .find(|c| matches!(c.kind, ColumnConstraintKind::Unique { .. }));
7828 assert!(uq.is_some(), "UNIQUE constraint missing");
7829 } else {
7830 unreachable!("expected Columns body");
7831 }
7832 } else {
7833 unreachable!("expected CreateTable");
7834 }
7835 }
7836
7837 #[test]
7838 fn test_column_check() {
7839 let stmt = parse_one("CREATE TABLE t (age INTEGER CHECK(age >= 0 AND age < 200))");
7840 if let Statement::CreateTable(ct) = stmt {
7841 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7842 let chk = columns[0]
7843 .constraints
7844 .iter()
7845 .find(|c| matches!(c.kind, ColumnConstraintKind::Check(_)));
7846 assert!(chk.is_some(), "CHECK constraint missing");
7847 } else {
7848 unreachable!("expected Columns body");
7849 }
7850 } else {
7851 unreachable!("expected CreateTable");
7852 }
7853 }
7854
7855 #[test]
7856 fn test_check_constraint_expression_height_fails_closed_at_1001() {
7857 const LIMIT: usize = MAX_PARSE_DEPTH as usize;
7858 let at_limit = std::iter::repeat_n("1", LIMIT)
7859 .collect::<Vec<_>>()
7860 .join(" + ");
7861 let statement = format!("CREATE TABLE t (value INTEGER CHECK({at_limit}))");
7862 assert!(
7863 matches!(parse_one(&statement), Statement::CreateTable(_)),
7864 "height-1000 CHECK must remain attached to its CREATE TABLE"
7865 );
7866
7867 let over_limit = std::iter::repeat_n("1", LIMIT + 1)
7868 .collect::<Vec<_>>()
7869 .join(" + ");
7870 let statement = format!("CREATE TABLE t (value INTEGER CHECK({over_limit}))");
7871 let mut parser = Parser::from_sql(&statement);
7872 let error = parser
7873 .parse_statement()
7874 .expect_err("height-1001 CHECK must reject the entire schema statement");
7875 assert_eq!(
7876 error.kind,
7877 ParseErrorKind::ExpressionTooDeep {
7878 max: MAX_PARSE_DEPTH
7879 }
7880 );
7881 assert_eq!(
7882 parser.depth, 0,
7883 "expression-height rejection must unwind parser recursion state"
7884 );
7885 }
7886
7887 #[test]
7888 fn test_expression_height_boundary_is_context_independent_on_one_mib_stack() {
7889 const LIMIT: usize = MAX_PARSE_DEPTH as usize;
7890 fn right_deep_expression(height: usize) -> String {
7891 format!("{}1{}", "1 + (".repeat(height - 1), ")".repeat(height - 1))
7892 }
7893 fn parse_on_one_mib_stack(sql: String) -> Result<(), ParseError> {
7894 std::thread::Builder::new()
7895 .stack_size(1024 * 1024)
7896 .spawn(move || {
7897 let statement = Parser::from_sql(&sql).parse_statement()?;
7898 drop(statement);
7902 Ok(())
7903 })
7904 .expect("1 MiB parser thread must spawn")
7905 .join()
7906 .expect("schema-context parse must not overflow or panic")
7907 }
7908
7909 let at_limit = right_deep_expression(LIMIT);
7910 let over_limit = right_deep_expression(LIMIT + 1);
7911 let contexts = [
7912 (
7913 "SELECT",
7914 format!("SELECT {at_limit}"),
7915 format!("SELECT {over_limit}"),
7916 ),
7917 (
7918 "column CHECK",
7919 format!("CREATE TABLE t (value INTEGER CHECK({at_limit}))"),
7920 format!("CREATE TABLE t (value INTEGER CHECK({over_limit}))"),
7921 ),
7922 (
7923 "table CHECK",
7924 format!("CREATE TABLE t (value INTEGER, CHECK({at_limit}))"),
7925 format!("CREATE TABLE t (value INTEGER, CHECK({over_limit}))"),
7926 ),
7927 (
7928 "view",
7929 format!("CREATE VIEW v AS SELECT {at_limit}"),
7930 format!("CREATE VIEW v AS SELECT {over_limit}"),
7931 ),
7932 (
7933 "trigger",
7934 format!(
7935 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN {at_limit} \
7936 BEGIN SELECT 1; END"
7937 ),
7938 format!(
7939 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN {over_limit} \
7940 BEGIN SELECT 1; END"
7941 ),
7942 ),
7943 ];
7944
7945 for (context, accepted, rejected) in contexts {
7946 parse_on_one_mib_stack(accepted)
7947 .unwrap_or_else(|error| panic!("{context} height 1000 rejected: {error}"));
7948
7949 let error = parse_on_one_mib_stack(rejected)
7950 .expect_err("height 1001 must reject every expression-bearing context");
7951 assert_eq!(
7952 error.kind,
7953 ParseErrorKind::ExpressionTooDeep {
7954 max: MAX_PARSE_DEPTH
7955 },
7956 "wrong error classification for {context}: {error}"
7957 );
7958 }
7959 }
7960
7961 #[test]
7962 fn test_column_default_literal() {
7963 let stmt = parse_one("CREATE TABLE t (status TEXT DEFAULT 'active')");
7964 if let Statement::CreateTable(ct) = stmt {
7965 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7966 let def = columns[0]
7967 .constraints
7968 .iter()
7969 .find(|c| matches!(c.kind, ColumnConstraintKind::Default(_)));
7970 assert!(def.is_some(), "DEFAULT constraint missing");
7971 } else {
7972 unreachable!("expected Columns body");
7973 }
7974 } else {
7975 unreachable!("expected CreateTable");
7976 }
7977 }
7978
7979 #[test]
7980 fn test_column_default_expr() {
7981 let stmt = parse_one("CREATE TABLE t (created_at TEXT DEFAULT (datetime('now')))");
7982 if let Statement::CreateTable(ct) = stmt {
7983 if let CreateTableBody::Columns { columns, .. } = &ct.body {
7984 let def = columns[0].constraints.iter().find(|c| {
7985 matches!(
7986 c.kind,
7987 ColumnConstraintKind::Default(DefaultValue::ParenExpr(_))
7988 )
7989 });
7990 assert!(def.is_some(), "DEFAULT (expr) missing");
7991 } else {
7992 unreachable!("expected Columns body");
7993 }
7994 } else {
7995 unreachable!("expected CreateTable");
7996 }
7997 }
7998
7999 #[test]
8000 fn test_column_collate() {
8001 let stmt = parse_one("CREATE TABLE t (name TEXT COLLATE NOCASE)");
8002 if let Statement::CreateTable(ct) = stmt {
8003 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8004 let coll = columns[0]
8005 .constraints
8006 .iter()
8007 .find(|c| matches!(c.kind, ColumnConstraintKind::Collate(_)));
8008 assert!(coll.is_some(), "COLLATE constraint missing");
8009 if let ColumnConstraintKind::Collate(name) = &coll.unwrap().kind {
8010 assert_eq!(name, "NOCASE");
8011 }
8012 } else {
8013 unreachable!("expected Columns body");
8014 }
8015 } else {
8016 unreachable!("expected CreateTable");
8017 }
8018 }
8019
8020 #[test]
8021 fn test_table_constraint_composite_pk() {
8022 let stmt = parse_one("CREATE TABLE t (a INTEGER, b INTEGER, PRIMARY KEY (a, b))");
8023 if let Statement::CreateTable(ct) = stmt {
8024 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
8025 let pk = constraints
8026 .iter()
8027 .find(|c| matches!(c.kind, TableConstraintKind::PrimaryKey { .. }));
8028 assert!(pk.is_some(), "composite PK missing");
8029 if let TableConstraintKind::PrimaryKey { columns, .. } = &pk.unwrap().kind {
8030 assert_eq!(columns.len(), 2);
8031 }
8032 } else {
8033 unreachable!("expected Columns body");
8034 }
8035 } else {
8036 unreachable!("expected CreateTable");
8037 }
8038 }
8039
8040 #[test]
8041 fn test_table_constraint_composite_unique() {
8042 let stmt = parse_one("CREATE TABLE t (a TEXT, b TEXT, UNIQUE (a, b))");
8043 if let Statement::CreateTable(ct) = stmt {
8044 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
8045 let uq = constraints
8046 .iter()
8047 .find(|c| matches!(c.kind, TableConstraintKind::Unique { .. }));
8048 assert!(uq.is_some(), "composite UNIQUE missing");
8049 if let TableConstraintKind::Unique { columns, .. } = &uq.unwrap().kind {
8050 assert_eq!(columns.len(), 2);
8051 }
8052 } else {
8053 unreachable!("expected Columns body");
8054 }
8055 } else {
8056 unreachable!("expected CreateTable");
8057 }
8058 }
8059
8060 #[test]
8061 fn test_table_constraint_check() {
8062 let stmt = parse_one(
8063 "CREATE TABLE t (start_date TEXT, end_date TEXT, CHECK (start_date < end_date))",
8064 );
8065 if let Statement::CreateTable(ct) = stmt {
8066 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
8067 let chk = constraints
8068 .iter()
8069 .find(|c| matches!(c.kind, TableConstraintKind::Check(_)));
8070 assert!(chk.is_some(), "table CHECK constraint missing");
8071 } else {
8072 unreachable!("expected Columns body");
8073 }
8074 } else {
8075 unreachable!("expected CreateTable");
8076 }
8077 }
8078
8079 #[test]
8080 fn test_create_rejects_modifiers_for_incompatible_object_kinds() {
8081 for sql in [
8082 "CREATE UNIQUE TABLE t(value INTEGER)",
8083 "CREATE UNIQUE VIEW v AS SELECT 1",
8084 "CREATE UNIQUE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END",
8085 "CREATE UNIQUE VIRTUAL TABLE vt USING fts5(content)",
8086 "CREATE TEMP INDEX i ON t(value)",
8087 "CREATE TEMP VIRTUAL TABLE vt USING fts5(content)",
8088 ] {
8089 Parser::from_sql(sql)
8090 .parse_statement()
8091 .expect_err("CREATE modifiers must not be discarded for incompatible objects");
8092 }
8093 }
8094
8095 #[test]
8096 fn test_invalid_create_modifier_recovers_next_statement() {
8097 let (statements, errors) =
8098 Parser::from_sql("CREATE UNIQUE TABLE t(value INTEGER); SELECT 42;").parse_all();
8099
8100 assert_eq!(errors.len(), 1);
8101 assert_eq!(statements.len(), 1);
8102 assert!(matches!(statements[0], Statement::Select(_)));
8103 }
8104
8105 #[test]
8106 fn test_foreign_key_on_delete_cascade() {
8107 let stmt = parse_one(
8108 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8109 REFERENCES parent(id) ON DELETE CASCADE)",
8110 );
8111 if let Statement::CreateTable(ct) = stmt {
8112 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8113 let fk = columns[1]
8114 .constraints
8115 .iter()
8116 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)));
8117 assert!(fk.is_some(), "FK constraint missing");
8118 if let ColumnConstraintKind::ForeignKey(clause) = &fk.unwrap().kind {
8119 assert_eq!(clause.table, "parent");
8120 let del = clause
8121 .actions
8122 .iter()
8123 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
8124 assert!(del.is_some());
8125 assert_eq!(del.unwrap().action, ForeignKeyActionType::Cascade);
8126 }
8127 } else {
8128 unreachable!("expected Columns body");
8129 }
8130 } else {
8131 unreachable!("expected CreateTable");
8132 }
8133 }
8134
8135 #[test]
8136 fn test_foreign_key_on_delete_set_null() {
8137 let stmt = parse_one(
8138 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8139 REFERENCES parent(id) ON DELETE SET NULL)",
8140 );
8141 if let Statement::CreateTable(ct) = stmt {
8142 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8143 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
8144 .constraints
8145 .iter()
8146 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
8147 .unwrap()
8148 .kind
8149 {
8150 let del = clause
8151 .actions
8152 .iter()
8153 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
8154 assert_eq!(del.unwrap().action, ForeignKeyActionType::SetNull);
8155 }
8156 } else {
8157 unreachable!("expected Columns body");
8158 }
8159 } else {
8160 unreachable!("expected CreateTable");
8161 }
8162 }
8163
8164 #[test]
8165 fn test_foreign_key_on_update_cascade() {
8166 let stmt = parse_one(
8167 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8168 REFERENCES parent(id) ON UPDATE CASCADE)",
8169 );
8170 if let Statement::CreateTable(ct) = stmt {
8171 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8172 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
8173 .constraints
8174 .iter()
8175 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
8176 .unwrap()
8177 .kind
8178 {
8179 let upd = clause
8180 .actions
8181 .iter()
8182 .find(|a| a.trigger == ForeignKeyTrigger::OnUpdate);
8183 assert!(upd.is_some());
8184 assert_eq!(upd.unwrap().action, ForeignKeyActionType::Cascade);
8185 }
8186 } else {
8187 unreachable!("expected Columns body");
8188 }
8189 } else {
8190 unreachable!("expected CreateTable");
8191 }
8192 }
8193
8194 #[test]
8195 fn test_foreign_key_restrict() {
8196 let stmt = parse_one(
8197 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8198 REFERENCES parent(id) ON DELETE RESTRICT)",
8199 );
8200 if let Statement::CreateTable(ct) = stmt {
8201 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8202 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
8203 .constraints
8204 .iter()
8205 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
8206 .unwrap()
8207 .kind
8208 {
8209 let del = clause
8210 .actions
8211 .iter()
8212 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
8213 assert_eq!(del.unwrap().action, ForeignKeyActionType::Restrict);
8214 }
8215 } else {
8216 unreachable!("expected Columns body");
8217 }
8218 } else {
8219 unreachable!("expected CreateTable");
8220 }
8221 }
8222
8223 #[test]
8224 fn test_foreign_key_deferred() {
8225 let stmt = parse_one(
8226 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8227 REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED)",
8228 );
8229 if let Statement::CreateTable(ct) = stmt {
8230 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8231 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
8232 .constraints
8233 .iter()
8234 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
8235 .unwrap()
8236 .kind
8237 {
8238 let def = clause.deferrable.as_ref().expect("DEFERRABLE missing");
8239 assert!(!def.not, "should be DEFERRABLE, not NOT DEFERRABLE");
8240 assert_eq!(def.initially, Some(DeferrableInitially::Deferred));
8241 }
8242 } else {
8243 unreachable!("expected Columns body");
8244 }
8245 } else {
8246 unreachable!("expected CreateTable");
8247 }
8248 }
8249
8250 #[test]
8251 fn test_foreign_key_pragma_required() {
8252 let stmt = parse_one(
8255 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
8256 REFERENCES parent(id) ON DELETE CASCADE ON UPDATE SET NULL)",
8257 );
8258 if let Statement::CreateTable(ct) = stmt {
8259 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8260 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
8261 .constraints
8262 .iter()
8263 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
8264 .unwrap()
8265 .kind
8266 {
8267 assert_eq!(clause.actions.len(), 2);
8268 }
8269 } else {
8270 unreachable!("expected Columns body");
8271 }
8272 } else {
8273 unreachable!("expected CreateTable");
8274 }
8275 }
8276
8277 #[test]
8278 fn test_conflict_clause_on_not_null() {
8279 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL ON CONFLICT IGNORE)");
8280 if let Statement::CreateTable(ct) = stmt {
8281 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8282 let nn = columns[0]
8283 .constraints
8284 .iter()
8285 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
8286 if let ColumnConstraintKind::NotNull { conflict } = &nn.unwrap().kind {
8287 assert_eq!(*conflict, Some(ConflictAction::Ignore));
8288 }
8289 } else {
8290 unreachable!("expected Columns body");
8291 }
8292 } else {
8293 unreachable!("expected CreateTable");
8294 }
8295 }
8296
8297 #[test]
8298 fn test_without_rowid_table() {
8299 let stmt = parse_one("CREATE TABLE t (k TEXT PRIMARY KEY, v BLOB) WITHOUT ROWID");
8300 if let Statement::CreateTable(ct) = stmt {
8301 assert!(ct.without_rowid);
8302 } else {
8303 unreachable!("expected CreateTable");
8304 }
8305 }
8306
8307 #[test]
8308 fn test_without_rowid_no_autoincrement() {
8309 let stmt = parse_one(
8312 "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT) WITHOUT ROWID",
8313 );
8314 if let Statement::CreateTable(ct) = stmt {
8315 assert!(ct.without_rowid);
8316 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8317 let pk = columns[0].constraints.iter().find(|c| {
8318 matches!(
8319 c.kind,
8320 ColumnConstraintKind::PrimaryKey {
8321 autoincrement: true,
8322 ..
8323 }
8324 )
8325 });
8326 assert!(pk.is_some());
8327 } else {
8328 unreachable!("expected Columns body");
8329 }
8330 } else {
8331 unreachable!("expected CreateTable");
8332 }
8333 }
8334
8335 #[test]
8336 fn test_without_rowid_integer_pk_not_alias() {
8337 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT) WITHOUT ROWID");
8340 if let Statement::CreateTable(ct) = stmt {
8341 assert!(ct.without_rowid);
8342 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8343 assert_eq!(columns[0].name, "id");
8344 assert!(columns[0].type_name.is_some());
8345 } else {
8346 unreachable!("expected Columns body");
8347 }
8348 } else {
8349 unreachable!("expected CreateTable");
8350 }
8351 }
8352
8353 #[test]
8354 fn test_strict_table_type_enforcement() {
8355 let stmt = parse_one("CREATE TABLE t (id INTEGER, name TEXT, score REAL) STRICT");
8358 if let Statement::CreateTable(ct) = stmt {
8359 assert!(ct.strict);
8360 assert!(!ct.without_rowid);
8361 } else {
8362 unreachable!("expected CreateTable");
8363 }
8364 }
8365
8366 #[test]
8367 fn test_strict_table_any_column() {
8368 let stmt = parse_one("CREATE TABLE t (id INTEGER, data ANY) STRICT");
8370 if let Statement::CreateTable(ct) = stmt {
8371 assert!(ct.strict);
8372 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8373 let tn = columns[1].type_name.as_ref().expect("type name");
8374 assert_eq!(tn.name, "ANY");
8375 } else {
8376 unreachable!("expected Columns body");
8377 }
8378 } else {
8379 unreachable!("expected CreateTable");
8380 }
8381 }
8382
8383 #[test]
8384 fn test_strict_allowed_types() {
8385 let stmt =
8387 parse_one("CREATE TABLE t (a INT, b INTEGER, c REAL, d TEXT, e BLOB, f ANY) STRICT");
8388 if let Statement::CreateTable(ct) = stmt {
8389 assert!(ct.strict);
8390 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8391 assert_eq!(columns.len(), 6);
8392 let types: Vec<&str> = columns
8393 .iter()
8394 .map(|c| c.type_name.as_ref().unwrap().name.as_str())
8395 .collect();
8396 assert_eq!(types, vec!["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
8397 } else {
8398 unreachable!("expected Columns body");
8399 }
8400 } else {
8401 unreachable!("expected CreateTable");
8402 }
8403 }
8404
8405 #[test]
8406 fn test_generated_col_virtual() {
8407 let stmt = parse_one(
8408 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a + b) VIRTUAL)",
8409 );
8410 if let Statement::CreateTable(ct) = stmt {
8411 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8412 let generated = columns[2]
8413 .constraints
8414 .iter()
8415 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
8416 assert!(generated.is_some(), "Generated constraint missing");
8417 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
8418 assert_eq!(*storage, Some(GeneratedStorage::Virtual));
8419 }
8420 } else {
8421 unreachable!("expected Columns body");
8422 }
8423 } else {
8424 unreachable!("expected CreateTable");
8425 }
8426 }
8427
8428 #[test]
8429 fn test_generated_col_stored() {
8430 let stmt = parse_one(
8431 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a * b) STORED)",
8432 );
8433 if let Statement::CreateTable(ct) = stmt {
8434 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8435 let generated = columns[2]
8436 .constraints
8437 .iter()
8438 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
8439 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
8440 assert_eq!(*storage, Some(GeneratedStorage::Stored));
8441 }
8442 } else {
8443 unreachable!("expected Columns body");
8444 }
8445 } else {
8446 unreachable!("expected CreateTable");
8447 }
8448 }
8449
8450 #[test]
8451 fn test_generated_col_ordering() {
8452 let stmt = parse_one(
8455 "CREATE TABLE t (\
8456 a INTEGER, \
8457 b INTEGER GENERATED ALWAYS AS (a + 1) STORED, \
8458 c INTEGER GENERATED ALWAYS AS (b * 2) VIRTUAL)",
8459 );
8460 if let Statement::CreateTable(ct) = stmt {
8461 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8462 assert_eq!(columns.len(), 3);
8463 let gen_b = columns[1]
8465 .constraints
8466 .iter()
8467 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
8468 let gen_c = columns[2]
8469 .constraints
8470 .iter()
8471 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
8472 assert!(gen_b, "column b should be generated");
8473 assert!(gen_c, "column c should be generated");
8474 } else {
8475 unreachable!("expected Columns body");
8476 }
8477 } else {
8478 unreachable!("expected CreateTable");
8479 }
8480 }
8481
8482 #[test]
8483 fn test_generated_col_stored_indexable() {
8484 let stmts = parse_ok(
8487 "CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED); \
8488 CREATE INDEX idx_b ON t (b)",
8489 );
8490 assert_eq!(stmts.len(), 2);
8491 assert!(matches!(stmts[0], Statement::CreateTable(_)));
8492 assert!(matches!(stmts[1], Statement::CreateIndex(_)));
8493 }
8494
8495 #[test]
8496 fn test_type_affinity_int() {
8497 let stmt = parse_one("CREATE TABLE t (a INTEGER, b BIGINT, c SMALLINT, d MEDIUMINT)");
8500 if let Statement::CreateTable(ct) = stmt {
8501 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8502 assert_eq!(columns.len(), 4);
8503 for col in columns {
8504 let tn = col.type_name.as_ref().unwrap();
8505 assert!(tn.name.contains("INT"), "{} should contain INT", tn.name);
8506 }
8507 } else {
8508 unreachable!("expected Columns body");
8509 }
8510 } else {
8511 unreachable!("expected CreateTable");
8512 }
8513 }
8514
8515 #[test]
8516 fn test_type_affinity_text() {
8517 let stmt = parse_one("CREATE TABLE t (a TEXT, b VARCHAR, c CLOB, d CHARACTER)");
8518 if let Statement::CreateTable(ct) = stmt {
8519 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8520 assert_eq!(columns.len(), 4);
8521 for col in columns {
8522 assert!(col.type_name.is_some());
8523 }
8524 } else {
8525 unreachable!("expected Columns body");
8526 }
8527 } else {
8528 unreachable!("expected CreateTable");
8529 }
8530 }
8531
8532 #[test]
8533 fn test_type_affinity_blob() {
8534 let stmt = parse_one("CREATE TABLE t (a BLOB, b)");
8535 if let Statement::CreateTable(ct) = stmt {
8536 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8537 assert_eq!(columns.len(), 2);
8538 assert_eq!(columns[0].type_name.as_ref().unwrap().name, "BLOB");
8539 assert!(columns[1].type_name.is_none());
8541 } else {
8542 unreachable!("expected Columns body");
8543 }
8544 } else {
8545 unreachable!("expected CreateTable");
8546 }
8547 }
8548
8549 #[test]
8550 fn test_type_affinity_real() {
8551 let stmt = parse_one("CREATE TABLE t (a REAL, b DOUBLE, c FLOAT)");
8552 if let Statement::CreateTable(ct) = stmt {
8553 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8554 assert_eq!(columns.len(), 3);
8555 for col in columns {
8556 assert!(col.type_name.is_some());
8557 }
8558 } else {
8559 unreachable!("expected Columns body");
8560 }
8561 } else {
8562 unreachable!("expected CreateTable");
8563 }
8564 }
8565
8566 #[test]
8567 fn test_type_affinity_numeric() {
8568 let stmt = parse_one("CREATE TABLE t (a NUMERIC, b DECIMAL, c BOOLEAN)");
8569 if let Statement::CreateTable(ct) = stmt {
8570 if let CreateTableBody::Columns { columns, .. } = &ct.body {
8571 assert_eq!(columns.len(), 3);
8572 for col in columns {
8573 assert!(col.type_name.is_some());
8574 }
8575 } else {
8576 unreachable!("expected Columns body");
8577 }
8578 } else {
8579 unreachable!("expected CreateTable");
8580 }
8581 }
8582
8583 #[test]
8584 fn test_create_unique_index() {
8585 let stmt = parse_one("CREATE UNIQUE INDEX idx_email ON users (email)");
8586 if let Statement::CreateIndex(ci) = stmt {
8587 assert!(ci.unique);
8588 assert_eq!(ci.name.name, "idx_email");
8589 assert_eq!(ci.table, "users");
8590 assert_eq!(ci.columns.len(), 1);
8591 assert!(ci.where_clause.is_none());
8592 } else {
8593 unreachable!("expected CreateIndex");
8594 }
8595 }
8596
8597 #[test]
8598 fn test_partial_index() {
8599 let stmt = parse_one("CREATE INDEX idx_active ON users (name) WHERE active = 1");
8600 if let Statement::CreateIndex(ci) = stmt {
8601 assert!(!ci.unique);
8602 assert_eq!(ci.name.name, "idx_active");
8603 assert!(ci.where_clause.is_some(), "partial index WHERE missing");
8604 } else {
8605 unreachable!("expected CreateIndex");
8606 }
8607 }
8608
8609 #[test]
8610 fn test_partial_index_planner_usage() {
8611 let stmt =
8614 parse_one("CREATE INDEX idx_recent ON orders (created_at) WHERE status != 'archived'");
8615 if let Statement::CreateIndex(ci) = stmt {
8616 assert!(ci.where_clause.is_some());
8617 assert_eq!(ci.columns.len(), 1);
8618 } else {
8619 unreachable!("expected CreateIndex");
8620 }
8621 }
8622
8623 #[test]
8624 fn test_expression_index() {
8625 let stmt = parse_one("CREATE INDEX idx_lower_name ON users (lower(name))");
8626 if let Statement::CreateIndex(ci) = stmt {
8627 assert_eq!(ci.columns.len(), 1);
8628 assert!(
8630 matches!(ci.columns[0].expr, Expr::FunctionCall { .. }),
8631 "expected function call expression in index"
8632 );
8633 } else {
8634 unreachable!("expected CreateIndex");
8635 }
8636 }
8637
8638 #[test]
8639 fn test_expression_index_planner_match() {
8640 let stmt = parse_one("CREATE INDEX idx_calc ON t (a + b * 2)");
8643 if let Statement::CreateIndex(ci) = stmt {
8644 assert_eq!(ci.columns.len(), 1);
8645 assert!(
8646 matches!(ci.columns[0].expr, Expr::BinaryOp { .. }),
8647 "expected binary op in expression index"
8648 );
8649 } else {
8650 unreachable!("expected CreateIndex");
8651 }
8652 }
8653
8654 #[test]
8655 fn test_index_collate_asc_desc() {
8656 let stmt = parse_one("CREATE INDEX idx_multi ON t (a COLLATE NOCASE ASC, b DESC, c)");
8657 if let Statement::CreateIndex(ci) = stmt {
8658 assert_eq!(ci.columns.len(), 3);
8659 assert!(
8661 matches!(
8662 &ci.columns[0].expr,
8663 Expr::Collate { collation, .. } if collation == "NOCASE"
8664 ),
8665 "expected Collate expr with NOCASE"
8666 );
8667 assert_eq!(ci.columns[0].direction, Some(SortDirection::Asc));
8668 assert_eq!(ci.columns[1].direction, Some(SortDirection::Desc));
8669 assert!(ci.columns[2].direction.is_none());
8670 } else {
8671 unreachable!("expected CreateIndex");
8672 }
8673 }
8674
8675 #[test]
8680 fn test_create_view_basic() {
8681 let stmt = parse_one("CREATE VIEW v AS SELECT id, name FROM users");
8682 if let Statement::CreateView(cv) = stmt {
8683 assert_eq!(cv.name.name, "v");
8684 assert!(!cv.if_not_exists);
8685 assert!(!cv.temporary);
8686 assert!(cv.columns.is_empty());
8687 } else {
8688 unreachable!("expected CreateView");
8689 }
8690 }
8691
8692 #[test]
8693 fn test_create_view_column_aliases() {
8694 let stmt = parse_one("CREATE VIEW v (user_id, user_name) AS SELECT id, name FROM users");
8695 if let Statement::CreateView(cv) = stmt {
8696 assert_eq!(cv.columns, vec!["user_id", "user_name"]);
8697 } else {
8698 unreachable!("expected CreateView");
8699 }
8700 }
8701
8702 #[test]
8703 fn test_create_view_if_not_exists() {
8704 let stmt = parse_one("CREATE VIEW IF NOT EXISTS v AS SELECT 1");
8705 if let Statement::CreateView(cv) = stmt {
8706 assert!(cv.if_not_exists);
8707 } else {
8708 unreachable!("expected CreateView");
8709 }
8710 }
8711
8712 #[test]
8713 fn test_create_temp_view() {
8714 let stmt = parse_one("CREATE TEMP VIEW tv AS SELECT 1");
8715 if let Statement::CreateView(cv) = stmt {
8716 assert!(cv.temporary);
8717 } else {
8718 unreachable!("expected CreateView");
8719 }
8720 }
8721
8722 #[test]
8723 fn test_view_inline_expansion() {
8724 let stmt =
8727 parse_one("CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = 1");
8728 if let Statement::CreateView(cv) = stmt {
8729 assert_eq!(cv.name.name, "active_users");
8730 } else {
8731 unreachable!("expected CreateView");
8732 }
8733 }
8734
8735 #[test]
8736 fn test_view_read_only() {
8737 let stmt = parse_one("CREATE VIEW v AS SELECT * FROM t");
8740 assert!(matches!(stmt, Statement::CreateView(_)));
8741 }
8742
8743 #[test]
8744 fn test_view_with_recursive_cte() {
8745 let stmt = parse_one(
8748 "CREATE VIEW tree AS \
8749 SELECT n.id, n.parent FROM nodes n \
8750 WHERE n.parent IS NULL \
8751 UNION ALL \
8752 SELECT c.id, c.parent FROM nodes c JOIN nodes p ON c.parent = p.id",
8753 );
8754 if let Statement::CreateView(cv) = stmt {
8755 assert_eq!(cv.name.name, "tree");
8756 assert!(
8758 !cv.query.body.compounds.is_empty(),
8759 "expected compound SELECT in view"
8760 );
8761 } else {
8762 unreachable!("expected CreateView");
8763 }
8764 }
8765
8766 #[test]
8767 fn test_instead_of_trigger_on_view() {
8768 let stmt = parse_one(
8769 "CREATE TRIGGER tr INSTEAD OF INSERT ON v BEGIN \
8770 INSERT INTO t (a) VALUES (NEW.a); \
8771 END",
8772 );
8773 if let Statement::CreateTrigger(ct) = stmt {
8774 assert_eq!(ct.timing, TriggerTiming::InsteadOf);
8775 assert!(matches!(ct.event, TriggerEvent::Insert));
8776 assert_eq!(ct.table, "v");
8777 assert!(!ct.body.is_empty());
8778 } else {
8779 unreachable!("expected CreateTrigger");
8780 }
8781 }
8782
8783 #[test]
8784 fn test_trigger_before_insert() {
8785 let stmt = parse_one("CREATE TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
8786 if let Statement::CreateTrigger(ct) = stmt {
8787 assert_eq!(ct.timing, TriggerTiming::Before);
8788 assert!(matches!(ct.event, TriggerEvent::Insert));
8789 } else {
8790 unreachable!("expected CreateTrigger");
8791 }
8792 }
8793
8794 #[test]
8795 fn test_trigger_after_insert() {
8796 let stmt = parse_one("CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END");
8797 if let Statement::CreateTrigger(ct) = stmt {
8798 assert_eq!(ct.timing, TriggerTiming::After);
8799 assert!(matches!(ct.event, TriggerEvent::Insert));
8800 } else {
8801 unreachable!("expected CreateTrigger");
8802 }
8803 }
8804
8805 #[test]
8806 fn test_trigger_before_update() {
8807 let stmt = parse_one("CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN SELECT OLD.a, NEW.a; END");
8808 if let Statement::CreateTrigger(ct) = stmt {
8809 assert_eq!(ct.timing, TriggerTiming::Before);
8810 assert!(matches!(ct.event, TriggerEvent::Update(_)));
8811 } else {
8812 unreachable!("expected CreateTrigger");
8813 }
8814 }
8815
8816 #[test]
8817 fn test_trigger_after_delete() {
8818 let stmt = parse_one("CREATE TRIGGER tr AFTER DELETE ON t BEGIN SELECT OLD.id; END");
8819 if let Statement::CreateTrigger(ct) = stmt {
8820 assert_eq!(ct.timing, TriggerTiming::After);
8821 assert!(matches!(ct.event, TriggerEvent::Delete));
8822 } else {
8823 unreachable!("expected CreateTrigger");
8824 }
8825 }
8826
8827 #[test]
8828 fn test_trigger_update_of_column() {
8829 let stmt =
8830 parse_one("CREATE TRIGGER tr BEFORE UPDATE OF name, email ON t BEGIN SELECT 1; END");
8831 if let Statement::CreateTrigger(ct) = stmt {
8832 if let TriggerEvent::Update(cols) = &ct.event {
8833 assert_eq!(cols, &["name", "email"]);
8834 } else {
8835 unreachable!("expected Update event with columns");
8836 }
8837 } else {
8838 unreachable!("expected CreateTrigger");
8839 }
8840 }
8841
8842 #[test]
8843 fn test_trigger_when_clause() {
8844 let stmt = parse_one(
8845 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN NEW.active = 1 BEGIN SELECT 1; END",
8846 );
8847 if let Statement::CreateTrigger(ct) = stmt {
8848 assert!(ct.when.is_some(), "WHEN clause missing");
8849 } else {
8850 unreachable!("expected CreateTrigger");
8851 }
8852 }
8853
8854 #[test]
8855 fn test_trigger_old_new_pseudo_tables() {
8856 let stmt = parse_one(
8857 "CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN \
8858 INSERT INTO log (old_val, new_val) VALUES (OLD.a, NEW.a); \
8859 END",
8860 );
8861 if let Statement::CreateTrigger(ct) = stmt {
8862 assert_eq!(ct.body.len(), 1);
8863 assert!(matches!(ct.body[0], Statement::Insert(_)));
8864 } else {
8865 unreachable!("expected CreateTrigger");
8866 }
8867 }
8868
8869 #[test]
8870 fn test_trigger_raise_abort() {
8871 let stmt = parse_one(
8872 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
8873 SELECT RAISE(ABORT, 'not allowed'); \
8874 END",
8875 );
8876 if let Statement::CreateTrigger(ct) = stmt {
8877 assert_eq!(ct.body.len(), 1);
8878 } else {
8879 unreachable!("expected CreateTrigger");
8880 }
8881 }
8882
8883 #[test]
8884 fn test_trigger_raise_rollback() {
8885 let stmt = parse_one(
8886 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
8887 SELECT RAISE(ROLLBACK, 'invalid'); \
8888 END",
8889 );
8890 if let Statement::CreateTrigger(ct) = stmt {
8891 assert_eq!(ct.body.len(), 1);
8892 } else {
8893 unreachable!("expected CreateTrigger");
8894 }
8895 }
8896
8897 #[test]
8898 fn test_trigger_raise_fail() {
8899 let stmt = parse_one(
8900 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
8901 SELECT RAISE(FAIL, 'bad data'); \
8902 END",
8903 );
8904 if let Statement::CreateTrigger(ct) = stmt {
8905 assert_eq!(ct.body.len(), 1);
8906 } else {
8907 unreachable!("expected CreateTrigger");
8908 }
8909 }
8910
8911 #[test]
8912 fn test_trigger_raise_ignore() {
8913 let stmt = parse_one(
8914 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
8915 SELECT RAISE(IGNORE); \
8916 END",
8917 );
8918 if let Statement::CreateTrigger(ct) = stmt {
8919 assert_eq!(ct.body.len(), 1);
8920 } else {
8921 unreachable!("expected CreateTrigger");
8922 }
8923 }
8924
8925 #[test]
8926 fn test_trigger_recursive() {
8927 let stmt = parse_one(
8930 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
8931 INSERT INTO t (val) VALUES (NEW.val + 1); \
8932 END",
8933 );
8934 if let Statement::CreateTrigger(ct) = stmt {
8935 assert_eq!(ct.timing, TriggerTiming::After);
8936 assert_eq!(ct.table, "t");
8937 assert_eq!(ct.body.len(), 1);
8938 } else {
8939 unreachable!("expected CreateTrigger");
8940 }
8941 }
8942
8943 #[test]
8944 fn test_trigger_max_recursion_depth() {
8945 let stmt = parse_one(
8948 "CREATE TRIGGER tr AFTER INSERT ON t \
8949 WHEN NEW.depth < 1000 BEGIN \
8950 INSERT INTO t (depth) VALUES (NEW.depth + 1); \
8951 END",
8952 );
8953 if let Statement::CreateTrigger(ct) = stmt {
8954 assert!(ct.when.is_some());
8955 assert_eq!(ct.body.len(), 1);
8956 } else {
8957 unreachable!("expected CreateTrigger");
8958 }
8959 }
8960
8961 #[test]
8962 fn test_trigger_heap_frame_stack() {
8963 let stmt = parse_one(
8966 "CREATE TRIGGER tr AFTER UPDATE ON t BEGIN \
8967 UPDATE t SET counter = counter + 1 WHERE id = NEW.parent_id; \
8968 END",
8969 );
8970 if let Statement::CreateTrigger(ct) = stmt {
8971 assert_eq!(ct.body.len(), 1);
8972 assert!(matches!(ct.body[0], Statement::Update(_)));
8973 } else {
8974 unreachable!("expected CreateTrigger");
8975 }
8976 }
8977
8978 #[test]
8979 fn test_trigger_multiple_dml() {
8980 let stmt = parse_one(
8981 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
8982 INSERT INTO audit (action) VALUES ('insert'); \
8983 UPDATE stats SET count = count + 1; \
8984 END",
8985 );
8986 if let Statement::CreateTrigger(ct) = stmt {
8987 assert_eq!(ct.body.len(), 2);
8988 assert!(matches!(ct.body[0], Statement::Insert(_)));
8989 assert!(matches!(ct.body[1], Statement::Update(_)));
8990 } else {
8991 unreachable!("expected CreateTrigger");
8992 }
8993 }
8994
8995 #[test]
8996 fn test_alter_table_rename() {
8997 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
8998 if let Statement::AlterTable(at) = stmt {
8999 assert_eq!(at.table.name, "t");
9000 assert!(matches!(at.action, AlterTableAction::RenameTo(ref n) if n == "t2"));
9001 } else {
9002 unreachable!("expected AlterTable");
9003 }
9004 }
9005
9006 #[test]
9007 fn test_alter_table_rename_column() {
9008 let stmt = parse_one("ALTER TABLE t RENAME COLUMN old_name TO new_name");
9009 if let Statement::AlterTable(at) = stmt {
9010 if let AlterTableAction::RenameColumn { old, new } = &at.action {
9011 assert_eq!(old, "old_name");
9012 assert_eq!(new, "new_name");
9013 } else {
9014 unreachable!("expected RenameColumn action");
9015 }
9016 } else {
9017 unreachable!("expected AlterTable");
9018 }
9019 }
9020
9021 #[test]
9022 fn test_alter_table_add_column() {
9023 let stmt = parse_one("ALTER TABLE t ADD COLUMN email TEXT NOT NULL DEFAULT ''");
9024 if let Statement::AlterTable(at) = stmt {
9025 if let AlterTableAction::AddColumn(col) = &at.action {
9026 assert_eq!(col.name, "email");
9027 assert!(!col.constraints.is_empty());
9028 } else {
9029 unreachable!("expected AddColumn action");
9030 }
9031 } else {
9032 unreachable!("expected AlterTable");
9033 }
9034 }
9035
9036 #[test]
9037 fn test_alter_table_remove_column() {
9038 let stmt = parse_one("ALTER TABLE t DROP COLUMN old_col");
9039 if let Statement::AlterTable(at) = stmt {
9040 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "old_col"));
9041 } else {
9042 unreachable!("expected AlterTable");
9043 }
9044 }
9045
9046 #[test]
9047 fn test_alter_remove_column_pk_fails() {
9048 let stmt = parse_one("ALTER TABLE t DROP COLUMN id");
9051 if let Statement::AlterTable(at) = stmt {
9052 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "id"));
9053 } else {
9054 unreachable!("expected AlterTable");
9055 }
9056 }
9057
9058 #[test]
9059 fn test_alter_remove_column_unique_fails() {
9060 let stmt = parse_one("ALTER TABLE t DROP COLUMN email");
9062 if let Statement::AlterTable(at) = stmt {
9063 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "email"));
9064 } else {
9065 unreachable!("expected AlterTable");
9066 }
9067 }
9068
9069 #[test]
9070 fn test_alter_remove_column_index_fails() {
9071 let stmt = parse_one("ALTER TABLE t DROP COLUMN indexed_col");
9073 if let Statement::AlterTable(at) = stmt {
9074 assert!(matches!(
9075 at.action,
9076 AlterTableAction::DropColumn(ref c) if c == "indexed_col"
9077 ));
9078 } else {
9079 unreachable!("expected AlterTable");
9080 }
9081 }
9082
9083 #[test]
9084 fn test_alter_remove_column_check_fails() {
9085 let stmt = parse_one("ALTER TABLE t DROP COLUMN checked_col");
9087 if let Statement::AlterTable(at) = stmt {
9088 assert!(matches!(
9089 at.action,
9090 AlterTableAction::DropColumn(ref c) if c == "checked_col"
9091 ));
9092 } else {
9093 unreachable!("expected AlterTable");
9094 }
9095 }
9096
9097 #[test]
9098 fn test_alter_remove_column_fk_fails() {
9099 let stmt = parse_one("ALTER TABLE t DROP COLUMN fk_col");
9101 if let Statement::AlterTable(at) = stmt {
9102 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "fk_col"));
9103 } else {
9104 unreachable!("expected AlterTable");
9105 }
9106 }
9107
9108 #[test]
9109 fn test_alter_remove_only_column_fails() {
9110 let stmt = parse_one("ALTER TABLE t DROP COLUMN only_col");
9112 if let Statement::AlterTable(at) = stmt {
9113 assert!(matches!(
9114 at.action,
9115 AlterTableAction::DropColumn(ref c) if c == "only_col"
9116 ));
9117 } else {
9118 unreachable!("expected AlterTable");
9119 }
9120 }
9121
9122 #[test]
9123 fn test_ddl_remove_table() {
9124 let stmt = parse_one("DROP TABLE t");
9125 if let Statement::Drop(d) = stmt {
9126 assert_eq!(d.object_type, DropObjectType::Table);
9127 assert!(!d.if_exists);
9128 assert_eq!(d.name.name, "t");
9129 } else {
9130 unreachable!("expected Drop");
9131 }
9132 }
9133
9134 #[test]
9135 fn test_ddl_remove_table_if_exists() {
9136 let stmt = parse_one("DROP TABLE IF EXISTS t");
9137 if let Statement::Drop(d) = stmt {
9138 assert_eq!(d.object_type, DropObjectType::Table);
9139 assert!(d.if_exists);
9140 } else {
9141 unreachable!("expected Drop");
9142 }
9143 }
9144
9145 #[test]
9146 fn test_ddl_remove_index() {
9147 let stmt = parse_one("DROP INDEX idx");
9148 if let Statement::Drop(d) = stmt {
9149 assert_eq!(d.object_type, DropObjectType::Index);
9150 assert_eq!(d.name.name, "idx");
9151 } else {
9152 unreachable!("expected Drop");
9153 }
9154 }
9155
9156 #[test]
9157 fn test_ddl_remove_view() {
9158 let stmt = parse_one("DROP VIEW v");
9159 if let Statement::Drop(d) = stmt {
9160 assert_eq!(d.object_type, DropObjectType::View);
9161 assert_eq!(d.name.name, "v");
9162 } else {
9163 unreachable!("expected Drop");
9164 }
9165 }
9166
9167 #[test]
9168 fn test_ddl_remove_trigger() {
9169 let stmt = parse_one("DROP TRIGGER tr");
9170 if let Statement::Drop(d) = stmt {
9171 assert_eq!(d.object_type, DropObjectType::Trigger);
9172 assert_eq!(d.name.name, "tr");
9173 } else {
9174 unreachable!("expected Drop");
9175 }
9176 }
9177
9178 #[test]
9184 fn test_reindex_global() {
9185 let stmt = parse_one("REINDEX");
9186 assert!(matches!(stmt, Statement::Reindex(None)));
9187 }
9188
9189 #[test]
9190 fn test_reindex_table() {
9191 let stmt = parse_one("REINDEX t");
9192 if let Statement::Reindex(Some(name)) = stmt {
9193 assert_eq!(name.name, "t");
9194 assert!(name.schema.is_none());
9195 } else {
9196 unreachable!("expected Reindex(Some), got {stmt:?}");
9197 }
9198 }
9199
9200 #[test]
9201 fn test_reindex_qualified() {
9202 let stmt = parse_one("REINDEX main.idx");
9203 if let Statement::Reindex(Some(name)) = stmt {
9204 assert_eq!(name.schema.as_deref(), Some("main"));
9205 assert_eq!(name.name, "idx");
9206 } else {
9207 unreachable!("expected Reindex(Some), got {stmt:?}");
9208 }
9209 }
9210
9211 #[test]
9212 fn test_analyze_global() {
9213 let stmt = parse_one("ANALYZE");
9214 assert!(matches!(stmt, Statement::Analyze(None)));
9215 }
9216
9217 #[test]
9218 fn test_analyze_table() {
9219 let stmt = parse_one("ANALYZE t");
9220 if let Statement::Analyze(Some(name)) = stmt {
9221 assert_eq!(name.name, "t");
9222 assert!(name.schema.is_none());
9223 } else {
9224 unreachable!("expected Analyze(Some), got {stmt:?}");
9225 }
9226 }
9227
9228 #[test]
9229 fn test_analyze_qualified() {
9230 let stmt = parse_one("ANALYZE main.t");
9231 if let Statement::Analyze(Some(name)) = stmt {
9232 assert_eq!(name.schema.as_deref(), Some("main"));
9233 assert_eq!(name.name, "t");
9234 } else {
9235 unreachable!("expected Analyze(Some), got {stmt:?}");
9236 }
9237 }
9238
9239 #[test]
9240 fn test_drop_view_if_exists() {
9241 let stmt = parse_one("DROP VIEW IF EXISTS v");
9242 if let Statement::Drop(d) = stmt {
9243 assert_eq!(d.object_type, DropObjectType::View);
9244 assert!(d.if_exists);
9245 assert_eq!(d.name.name, "v");
9246 } else {
9247 unreachable!("expected Drop");
9248 }
9249 }
9250
9251 #[test]
9252 fn test_drop_index_if_exists() {
9253 let stmt = parse_one("DROP INDEX IF EXISTS idx");
9254 if let Statement::Drop(d) = stmt {
9255 assert_eq!(d.object_type, DropObjectType::Index);
9256 assert!(d.if_exists);
9257 } else {
9258 unreachable!("expected Drop");
9259 }
9260 }
9261
9262 #[test]
9263 fn test_drop_trigger_if_exists_qualified() {
9264 let stmt = parse_one("DROP TRIGGER IF EXISTS main.tr");
9265 if let Statement::Drop(d) = stmt {
9266 assert_eq!(d.object_type, DropObjectType::Trigger);
9267 assert!(d.if_exists);
9268 assert_eq!(d.name.schema.as_deref(), Some("main"));
9269 assert_eq!(d.name.name, "tr");
9270 } else {
9271 unreachable!("expected Drop");
9272 }
9273 }
9274
9275 #[test]
9276 fn test_drop_table_qualified() {
9277 let stmt = parse_one("DROP TABLE main.t");
9278 if let Statement::Drop(d) = stmt {
9279 assert_eq!(d.name.schema.as_deref(), Some("main"));
9280 assert_eq!(d.name.name, "t");
9281 } else {
9282 unreachable!("expected Drop");
9283 }
9284 }
9285
9286 #[test]
9287 fn test_create_trigger_if_not_exists() {
9288 let stmt =
9289 parse_one("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
9290 if let Statement::CreateTrigger(ct) = stmt {
9291 assert!(ct.if_not_exists);
9292 assert_eq!(ct.name.name, "tr");
9293 } else {
9294 unreachable!("expected CreateTrigger");
9295 }
9296 }
9297
9298 #[test]
9299 fn test_create_temp_trigger() {
9300 let stmt = parse_one("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
9301 if let Statement::CreateTrigger(ct) = stmt {
9302 assert!(ct.temporary);
9303 assert_eq!(ct.name.name, "tr");
9304 } else {
9305 unreachable!("expected CreateTrigger");
9306 }
9307 }
9308
9309 #[test]
9310 fn test_create_view_qualified_name() {
9311 let stmt = parse_one("CREATE VIEW main.v AS SELECT 1");
9312 if let Statement::CreateView(cv) = stmt {
9313 assert_eq!(cv.name.schema.as_deref(), Some("main"));
9314 assert_eq!(cv.name.name, "v");
9315 } else {
9316 unreachable!("expected CreateView");
9317 }
9318 }
9319
9320 #[test]
9321 fn test_alter_table_qualified() {
9322 let stmt = parse_one("ALTER TABLE main.t RENAME TO u");
9323 if let Statement::AlterTable(at) = stmt {
9324 assert_eq!(at.table.schema.as_deref(), Some("main"));
9325 assert_eq!(at.table.name, "t");
9326 } else {
9327 unreachable!("expected AlterTable");
9328 }
9329 }
9330
9331 #[test]
9332 fn test_roundtrip_reindex_all() {
9333 assert_roundtrip("REINDEX");
9334 assert_roundtrip("REINDEX t");
9335 assert_roundtrip("REINDEX main.idx");
9336 }
9337
9338 #[test]
9339 fn test_roundtrip_analyze_all() {
9340 assert_roundtrip("ANALYZE");
9341 assert_roundtrip("ANALYZE t");
9342 assert_roundtrip("ANALYZE main.t");
9343 }
9344
9345 #[test]
9346 fn test_roundtrip_drop_all_types_extended() {
9347 assert_roundtrip("DROP TABLE IF EXISTS main.t");
9348 assert_roundtrip("DROP VIEW IF EXISTS v");
9349 assert_roundtrip("DROP INDEX IF EXISTS idx");
9350 assert_roundtrip("DROP TRIGGER IF EXISTS main.tr");
9351 }
9352
9353 #[test]
9354 fn test_roundtrip_create_trigger_extended() {
9355 assert_roundtrip("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
9356 assert_roundtrip("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
9357 assert_roundtrip(
9358 "CREATE TRIGGER tr INSTEAD OF UPDATE ON v BEGIN INSERT INTO log VALUES (1); END",
9359 );
9360 assert_roundtrip("CREATE TRIGGER tr BEFORE UPDATE OF a, b ON t BEGIN SELECT 1; END");
9361 assert_roundtrip(
9362 "CREATE TRIGGER tr AFTER DELETE ON \"order\" BEGIN INSERT INTO log VALUES (OLD.id); END",
9363 );
9364 }
9365
9366 #[test]
9367 fn test_roundtrip_create_view_extended() {
9368 assert_roundtrip("CREATE VIEW main.v AS SELECT 1");
9369 assert_roundtrip("CREATE VIEW v(x, y, z) AS SELECT a, b, c FROM t");
9370 }
9371
9372 #[test]
9373 fn test_roundtrip_alter_table_extended() {
9374 assert_roundtrip("ALTER TABLE t RENAME COLUMN a TO b");
9375 assert_roundtrip("ALTER TABLE main.t RENAME TO u");
9376 assert_roundtrip("ALTER TABLE t ADD COLUMN c INTEGER NOT NULL DEFAULT 0");
9377 }
9378
9379 #[test]
9384 fn test_begin_deferred() {
9385 let stmt = parse_one("BEGIN DEFERRED TRANSACTION");
9386 if let Statement::Begin(b) = stmt {
9387 assert_eq!(b.mode, Some(TransactionMode::Deferred));
9388 } else {
9389 unreachable!("expected Begin");
9390 }
9391 }
9392
9393 #[test]
9394 fn test_begin_immediate() {
9395 let stmt = parse_one("BEGIN IMMEDIATE");
9396 if let Statement::Begin(b) = stmt {
9397 assert_eq!(b.mode, Some(TransactionMode::Immediate));
9398 } else {
9399 unreachable!("expected Begin");
9400 }
9401 }
9402
9403 #[test]
9404 fn test_begin_exclusive() {
9405 let stmt = parse_one("BEGIN EXCLUSIVE TRANSACTION");
9406 if let Statement::Begin(b) = stmt {
9407 assert_eq!(b.mode, Some(TransactionMode::Exclusive));
9408 } else {
9409 unreachable!("expected Begin");
9410 }
9411 }
9412
9413 #[test]
9414 fn test_begin_concurrent() {
9415 let stmt = parse_one("BEGIN CONCURRENT");
9416 if let Statement::Begin(b) = stmt {
9417 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
9418 } else {
9419 unreachable!("expected Begin");
9420 }
9421 }
9422
9423 #[test]
9424 fn test_concurrent_no_conflict() {
9425 let stmt = parse_one("BEGIN");
9428 assert!(matches!(stmt, Statement::Begin(_)));
9429 }
9430
9431 #[test]
9432 fn test_concurrent_page_conflict() {
9433 let stmts = parse_ok("BEGIN; INSERT INTO t (a) VALUES (1)");
9436 assert_eq!(stmts.len(), 2);
9437 assert!(matches!(stmts[0], Statement::Begin(_)));
9438 assert!(matches!(stmts[1], Statement::Insert(_)));
9439 }
9440
9441 #[test]
9442 fn test_commit_end_synonym() {
9443 let stmt1 = parse_one("COMMIT");
9444 assert!(matches!(stmt1, Statement::Commit));
9445 let stmt2 = parse_one("END TRANSACTION");
9446 assert!(matches!(stmt2, Statement::Commit));
9447 let stmt3 = parse_one("COMMIT TRANSACTION");
9448 assert!(matches!(stmt3, Statement::Commit));
9449 }
9450
9451 #[test]
9452 fn test_rollback() {
9453 let stmt = parse_one("ROLLBACK");
9454 if let Statement::Rollback(r) = stmt {
9455 assert!(r.to_savepoint.is_none());
9456 } else {
9457 unreachable!("expected Rollback");
9458 }
9459 }
9460
9461 #[test]
9462 fn test_savepoint_basic() {
9463 let stmt = parse_one("SAVEPOINT sp1");
9464 assert!(matches!(stmt, Statement::Savepoint(ref name) if name == "sp1"));
9465 }
9466
9467 #[test]
9468 fn test_savepoint_release() {
9469 let stmt = parse_one("RELEASE SAVEPOINT sp1");
9470 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp1"));
9471 }
9472
9473 #[test]
9474 fn test_savepoint_release_removes_later() {
9475 let stmt = parse_one("RELEASE sp2");
9478 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp2"));
9479 }
9480
9481 #[test]
9482 fn test_savepoint_rollback_to() {
9483 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
9484 if let Statement::Rollback(r) = stmt {
9485 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
9486 } else {
9487 unreachable!("expected Rollback");
9488 }
9489 }
9490
9491 #[test]
9492 fn test_savepoint_nested() {
9493 let stmts = parse_ok("SAVEPOINT sp1; SAVEPOINT sp2; SAVEPOINT sp3");
9496 assert_eq!(stmts.len(), 3);
9497 assert!(matches!(stmts[0], Statement::Savepoint(ref n) if n == "sp1"));
9498 assert!(matches!(stmts[1], Statement::Savepoint(ref n) if n == "sp2"));
9499 assert!(matches!(stmts[2], Statement::Savepoint(ref n) if n == "sp3"));
9500 }
9501
9502 #[test]
9503 fn test_savepoint_rollback_then_continue() {
9504 let stmts = parse_ok("ROLLBACK TO sp1; INSERT INTO t VALUES (1)");
9506 assert_eq!(stmts.len(), 2);
9507 assert!(matches!(stmts[0], Statement::Rollback(_)));
9508 assert!(matches!(stmts[1], Statement::Insert(_)));
9509 }
9510
9511 #[test]
9512 fn test_attach_database() {
9513 let stmt = parse_one("ATTACH DATABASE 'other.db' AS other");
9514 if let Statement::Attach(a) = stmt {
9515 assert_eq!(a.schema, "other");
9516 } else {
9517 unreachable!("expected Attach");
9518 }
9519 }
9520
9521 #[test]
9522 fn test_attach_schema_qualified_access() {
9523 let stmt = parse_one("SELECT * FROM other.t");
9525 if let Statement::Select(s) = stmt {
9526 if let SelectCore::Select { from, .. } = &s.body.select {
9527 let from = from.as_ref().expect("FROM clause");
9528 match &from.source {
9529 TableOrSubquery::Table { name, .. } => {
9530 assert_eq!(name.schema.as_deref(), Some("other"));
9531 assert_eq!(name.name, "t");
9532 }
9533 other => unreachable!("expected Table source, got {other:?}"),
9534 }
9535 } else {
9536 unreachable!("expected Select core");
9537 }
9538 } else {
9539 unreachable!("expected Select");
9540 }
9541 }
9542
9543 #[test]
9544 fn test_detach_database() {
9545 let stmt = parse_one("DETACH DATABASE other");
9546 assert!(matches!(stmt, Statement::Detach(ref name) if name == "other"));
9547 }
9548
9549 #[test]
9550 fn test_attach_max_limit() {
9551 let stmt = parse_one("ATTACH 'db11.sqlite' AS db11");
9554 if let Statement::Attach(a) = stmt {
9555 assert_eq!(a.schema, "db11");
9556 } else {
9557 unreachable!("expected Attach");
9558 }
9559 }
9560
9561 #[test]
9562 fn test_cross_database_transaction() {
9563 let stmts = parse_ok("BEGIN; INSERT INTO main.t SELECT * FROM other.t; COMMIT");
9566 assert_eq!(stmts.len(), 3);
9567 assert!(matches!(stmts[0], Statement::Begin(_)));
9568 assert!(matches!(stmts[1], Statement::Insert(_)));
9569 assert!(matches!(stmts[2], Statement::Commit));
9570 }
9571
9572 #[test]
9573 fn test_explain_returns_bytecode() {
9574 let stmt = parse_one("EXPLAIN SELECT 1");
9575 if let Statement::Explain { query_plan, stmt } = stmt {
9576 assert!(!query_plan);
9577 assert!(matches!(*stmt, Statement::Select(_)));
9578 } else {
9579 unreachable!("expected Explain");
9580 }
9581 }
9582
9583 #[test]
9584 fn test_explain_query_plan_columns() {
9585 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
9586 if let Statement::Explain { query_plan, stmt } = stmt {
9587 assert!(query_plan);
9588 assert!(matches!(*stmt, Statement::Select(_)));
9589 } else {
9590 unreachable!("expected Explain");
9591 }
9592 }
9593
9594 #[test]
9595 fn test_explain_query_plan_shows_index() {
9596 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
9599 if let Statement::Explain { query_plan, .. } = stmt {
9600 assert!(query_plan);
9601 } else {
9602 unreachable!("expected Explain");
9603 }
9604 }
9605
9606 #[test]
9607 fn test_explain_query_plan_tree_structure() {
9608 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id");
9611 if let Statement::Explain { query_plan, stmt } = stmt {
9612 assert!(query_plan);
9613 assert!(matches!(*stmt, Statement::Select(_)));
9614 } else {
9615 unreachable!("expected Explain");
9616 }
9617 }
9618
9619 #[test]
9624 fn test_parser_keyword_as_column_name() {
9625 let stmt = parse_one("SELECT \"order\" FROM t");
9627 assert!(matches!(stmt, Statement::Select(_)));
9628 }
9629
9630 #[test]
9631 fn test_parser_keyword_as_alias() {
9632 let stmt = parse_one("SELECT 1 AS \"limit\"");
9633 assert!(matches!(stmt, Statement::Select(_)));
9634 }
9635
9636 #[test]
9637 fn test_parser_keyword_as_table_name() {
9638 let stmt = parse_one("SELECT * FROM \"group\"");
9639 assert!(matches!(stmt, Statement::Select(_)));
9640 }
9641
9642 #[test]
9647 fn test_parser_all_statement_types() {
9648 let statements = [
9650 "SELECT 1",
9652 "INSERT INTO t VALUES (1)",
9653 "INSERT OR REPLACE INTO t VALUES (1)",
9654 "UPDATE t SET a = 1",
9655 "DELETE FROM t WHERE id = 1",
9656 "REPLACE INTO t VALUES (1)",
9657 "CREATE TABLE t (id INTEGER PRIMARY KEY)",
9659 "CREATE TEMPORARY TABLE t (id INTEGER)",
9660 "CREATE TABLE IF NOT EXISTS t (id INTEGER)",
9661 "CREATE INDEX idx ON t (a)",
9662 "CREATE UNIQUE INDEX idx ON t (a)",
9663 "CREATE VIEW v AS SELECT 1",
9664 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END",
9665 "CREATE VIRTUAL TABLE t USING fts5(a, b)",
9666 "ALTER TABLE t RENAME TO t2",
9667 "ALTER TABLE t ADD COLUMN c TEXT",
9668 "ALTER TABLE t DROP COLUMN c",
9669 "ALTER TABLE t RENAME COLUMN a TO b",
9670 "DROP TABLE t",
9671 "DROP TABLE IF EXISTS t",
9672 "DROP INDEX idx",
9673 "DROP VIEW v",
9674 "DROP TRIGGER tr",
9675 "BEGIN",
9677 "BEGIN DEFERRED",
9678 "BEGIN IMMEDIATE",
9679 "BEGIN EXCLUSIVE",
9680 "COMMIT",
9681 "END",
9682 "ROLLBACK",
9683 "SAVEPOINT sp1",
9684 "RELEASE sp1",
9685 "RELEASE SAVEPOINT sp1",
9686 "ROLLBACK TO sp1",
9687 "ROLLBACK TO SAVEPOINT sp1",
9688 "ATTACH DATABASE ':memory:' AS db2",
9690 "DETACH db2",
9691 "ANALYZE",
9692 "ANALYZE t",
9693 "VACUUM",
9694 "VACUUM INTO '/tmp/backup.db'",
9695 "REINDEX",
9696 "REINDEX t",
9697 "EXPLAIN SELECT 1",
9698 "EXPLAIN QUERY PLAN SELECT 1",
9699 "PRAGMA journal_mode",
9701 "PRAGMA journal_mode = WAL",
9702 "PRAGMA table_info(t)",
9703 ];
9704
9705 for sql in &statements {
9706 let mut p = Parser::from_sql(sql);
9707 let (stmts, errs) = p.parse_all();
9708 assert!(errs.is_empty(), "failed to parse '{sql}': {errs:?}");
9709 assert_eq!(
9710 stmts.len(),
9711 1,
9712 "expected 1 statement for '{sql}', got {}",
9713 stmts.len()
9714 );
9715 }
9716 }
9717
9718 #[test]
9723 fn test_parser_expression_precedence_mul_over_add() {
9724 let stmt = parse_one("SELECT 1 + 2 * 3");
9726 if let Statement::Select(s) = stmt {
9727 if let SelectCore::Select { columns, .. } = &s.body.select {
9728 match &columns[0] {
9729 ResultColumn::Expr { expr, .. } => {
9730 assert!(
9732 matches!(expr, Expr::BinaryOp { .. }),
9733 "expected BinaryOp, got {expr:?}"
9734 );
9735 }
9736 other => unreachable!("expected Expr column, got {other:?}"),
9737 }
9738 } else {
9739 unreachable!("expected Select core");
9740 }
9741 } else {
9742 unreachable!("expected Select");
9743 }
9744 }
9745
9746 #[test]
9751 fn test_parser_insert_on_conflict() {
9752 let stmt =
9753 parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a");
9754 if let Statement::Insert(i) = stmt {
9755 assert!(!i.upsert.is_empty());
9756 } else {
9757 unreachable!("expected Insert");
9758 }
9759 }
9760
9761 #[test]
9762 fn test_parser_insert_returning() {
9763 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING *");
9764 if let Statement::Insert(i) = stmt {
9765 assert!(!i.returning.is_empty());
9766 } else {
9767 unreachable!("expected Insert");
9768 }
9769 }
9770
9771 #[test]
9772 fn test_parser_delete_returning() {
9773 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
9774 if let Statement::Delete(d) = stmt {
9775 assert!(!d.returning.is_empty());
9776 } else {
9777 unreachable!("expected Delete");
9778 }
9779 }
9780
9781 #[test]
9782 fn test_parser_update_returning() {
9783 let stmt = parse_one("UPDATE t SET a = 1 RETURNING a, b");
9784 if let Statement::Update(u) = stmt {
9785 assert_eq!(u.returning.len(), 2);
9786 } else {
9787 unreachable!("expected Update");
9788 }
9789 }
9790
9791 #[test]
9796 fn test_parser_union() {
9797 let stmt = parse_one("SELECT 1 UNION SELECT 2");
9798 if let Statement::Select(s) = stmt {
9799 assert_eq!(s.body.compounds.len(), 1);
9800 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
9801 } else {
9802 unreachable!("expected Select");
9803 }
9804 }
9805
9806 #[test]
9807 fn test_parser_intersect() {
9808 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
9809 if let Statement::Select(s) = stmt {
9810 assert_eq!(s.body.compounds.len(), 1);
9811 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
9812 } else {
9813 unreachable!("expected Select");
9814 }
9815 }
9816
9817 #[test]
9818 fn test_parser_except() {
9819 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
9820 if let Statement::Select(s) = stmt {
9821 assert_eq!(s.body.compounds.len(), 1);
9822 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
9823 } else {
9824 unreachable!("expected Select");
9825 }
9826 }
9827
9828 #[test]
9833 fn test_parser_subquery_in_from() {
9834 let stmt = parse_one("SELECT * FROM (SELECT 1 AS x) AS sub");
9835 assert!(matches!(stmt, Statement::Select(_)));
9836 }
9837
9838 #[test]
9843 fn test_parser_create_table_all_constraints() {
9844 let stmt = parse_one(
9845 "CREATE TABLE t (\
9846 id INTEGER PRIMARY KEY AUTOINCREMENT,\
9847 name TEXT NOT NULL DEFAULT '',\
9848 email TEXT UNIQUE,\
9849 age INTEGER CHECK(age >= 0),\
9850 dept_id INTEGER REFERENCES dept(id) ON DELETE CASCADE,\
9851 CONSTRAINT pk PRIMARY KEY (id),\
9852 UNIQUE (email),\
9853 CHECK (age < 200),\
9854 FOREIGN KEY (dept_id) REFERENCES dept(id)\
9855 )",
9856 );
9857 if let Statement::CreateTable(ct) = stmt {
9858 if let CreateTableBody::Columns {
9859 columns,
9860 constraints,
9861 } = ct.body
9862 {
9863 assert_eq!(columns.len(), 5);
9864 assert!(!constraints.is_empty());
9865 } else {
9866 unreachable!("expected column defs");
9867 }
9868 } else {
9869 unreachable!("expected CreateTable");
9870 }
9871 }
9872
9873 #[test]
9878 fn test_parser_create_trigger_before_delete() {
9879 let stmt = parse_one("CREATE TRIGGER tr BEFORE DELETE ON t BEGIN SELECT 1; END");
9880 if let Statement::CreateTrigger(tr) = stmt {
9881 assert_eq!(tr.timing, TriggerTiming::Before);
9882 assert!(matches!(tr.event, TriggerEvent::Delete));
9883 } else {
9884 unreachable!("expected CreateTrigger");
9885 }
9886 }
9887
9888 #[test]
9889 fn test_parser_create_trigger_instead_of_update() {
9890 let stmt =
9891 parse_one("CREATE TRIGGER tr INSTEAD OF UPDATE OF a, b ON v BEGIN SELECT 1; END");
9892 if let Statement::CreateTrigger(tr) = stmt {
9893 assert_eq!(tr.timing, TriggerTiming::InsteadOf);
9894 if let TriggerEvent::Update(cols) = &tr.event {
9895 assert_eq!(cols.len(), 2);
9896 } else {
9897 unreachable!("expected UpdateOf event");
9898 }
9899 } else {
9900 unreachable!("expected CreateTrigger");
9901 }
9902 }
9903
9904 #[test]
9909 fn test_parser_create_view_with_columns() {
9910 let stmt = parse_one("CREATE VIEW v (a, b) AS SELECT 1, 2");
9911 if let Statement::CreateView(cv) = stmt {
9912 assert_eq!(cv.columns, vec!["a".to_owned(), "b".to_owned()]);
9913 } else {
9914 unreachable!("expected CreateView");
9915 }
9916 }
9917
9918 #[test]
9923 fn test_parser_multi_join() {
9924 let stmt = parse_one(
9925 "SELECT a.x, b.y, c.z FROM a \
9926 JOIN b ON a.id = b.a_id \
9927 LEFT JOIN c ON b.id = c.b_id \
9928 CROSS JOIN d",
9929 );
9930 if let Statement::Select(s) = stmt {
9931 if let SelectCore::Select { from, .. } = &s.body.select {
9932 let from = from.as_ref().expect("FROM clause");
9933 assert_eq!(from.joins.len(), 3);
9934 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
9935 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
9936 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
9937 } else {
9938 unreachable!("expected Select core");
9939 }
9940 } else {
9941 unreachable!("expected Select");
9942 }
9943 }
9944
9945 #[test]
9950 fn test_parser_group_by_having() {
9951 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
9952 if let Statement::Select(s) = stmt {
9953 if let SelectCore::Select {
9954 group_by, having, ..
9955 } = &s.body.select
9956 {
9957 assert!(!group_by.is_empty());
9958 assert!(having.is_some());
9959 } else {
9960 unreachable!("expected Select core");
9961 }
9962 } else {
9963 unreachable!("expected Select");
9964 }
9965 }
9966
9967 #[test]
9972 fn test_parser_error_recovery_with_span() {
9973 let sql = "SELECT 1;\nXYZZY 42;\nSELECT 3";
9975 let mut p = Parser::from_sql(sql);
9976 let (stmts, errs) = p.parse_all();
9977 assert_eq!(stmts.len(), 2, "should recover two valid statements");
9978 assert!(!errs.is_empty(), "should report at least one error");
9979
9980 let err = &errs[0];
9981 assert_eq!(err.line, 2, "error should be on line 2");
9983 assert_eq!(err.col, 1, "error should be at column 1");
9984 assert!(
9986 err.span.start < err.span.end,
9987 "error span should be non-empty"
9988 );
9989 let source_len = u32::try_from(sql.len()).unwrap();
9990 assert!(
9991 err.span.end <= source_len,
9992 "error span.end should be within source"
9993 );
9994 }
9995
9996 #[test]
9997 fn test_parser_error_span_mid_line() {
9998 let bad = Parser::from_sql("CREATE").parse_statement();
10000 assert!(bad.is_err());
10001 let err = bad.unwrap_err();
10002 assert_eq!(err.line, 1);
10003 }
10004
10005 #[test]
10010 #[allow(clippy::too_many_lines)]
10011 fn test_parser_keyword_lookup_all_150() {
10012 use crate::token::TokenKind;
10013
10014 let keywords = [
10016 "ABORT",
10017 "ACTION",
10018 "ADD",
10019 "AFTER",
10020 "ALL",
10021 "ALTER",
10022 "ALWAYS",
10023 "ANALYZE",
10024 "AND",
10025 "AS",
10026 "ASC",
10027 "ATTACH",
10028 "AUTOINCREMENT",
10029 "BEFORE",
10030 "BEGIN",
10031 "BETWEEN",
10032 "BY",
10033 "CASCADE",
10034 "CASE",
10035 "CAST",
10036 "CHECK",
10037 "COLLATE",
10038 "COLUMN",
10039 "COMMIT",
10040 "CONCURRENT",
10041 "CONFLICT",
10042 "CONSTRAINT",
10043 "CREATE",
10044 "CROSS",
10045 "CURRENT_DATE",
10046 "CURRENT_TIME",
10047 "CURRENT_TIMESTAMP",
10048 "DATABASE",
10049 "DEFAULT",
10050 "DEFERRABLE",
10051 "DEFERRED",
10052 "DELETE",
10053 "DESC",
10054 "DETACH",
10055 "DISTINCT",
10056 "DO",
10057 "DROP",
10058 "EACH",
10059 "ELSE",
10060 "END",
10061 "ESCAPE",
10062 "EXCEPT",
10063 "EXCLUDE",
10064 "EXCLUSIVE",
10065 "EXISTS",
10066 "EXPLAIN",
10067 "FAIL",
10068 "FILTER",
10069 "FIRST",
10070 "FOLLOWING",
10071 "FOR",
10072 "FOREIGN",
10073 "FROM",
10074 "FULL",
10075 "GENERATED",
10076 "GLOB",
10077 "GROUP",
10078 "GROUPS",
10079 "HAVING",
10080 "IF",
10081 "IGNORE",
10082 "IMMEDIATE",
10083 "IN",
10084 "INDEX",
10085 "INDEXED",
10086 "INITIALLY",
10087 "INNER",
10088 "INSERT",
10089 "INSTEAD",
10090 "INTERSECT",
10091 "INTO",
10092 "IS",
10093 "ISNULL",
10094 "JOIN",
10095 "KEY",
10096 "LAST",
10097 "LEFT",
10098 "LIKE",
10099 "LIMIT",
10100 "MATCH",
10101 "MATERIALIZED",
10102 "NATURAL",
10103 "NO",
10104 "NOT",
10105 "NOTHING",
10106 "NOTNULL",
10107 "NULL",
10108 "NULLS",
10109 "OF",
10110 "OFFSET",
10111 "ON",
10112 "OR",
10113 "ORDER",
10114 "OTHERS",
10115 "OUTER",
10116 "OVER",
10117 "PARTITION",
10118 "PLAN",
10119 "PRAGMA",
10120 "PRECEDING",
10121 "PRIMARY",
10122 "QUERY",
10123 "RAISE",
10124 "RANGE",
10125 "RECURSIVE",
10126 "REFERENCES",
10127 "REGEXP",
10128 "REINDEX",
10129 "RELEASE",
10130 "RENAME",
10131 "REPLACE",
10132 "RESTRICT",
10133 "RETURNING",
10134 "RIGHT",
10135 "ROLLBACK",
10136 "ROW",
10137 "ROWS",
10138 "SAVEPOINT",
10139 "SELECT",
10140 "SET",
10141 "STORED",
10142 "STRICT",
10143 "TABLE",
10144 "TEMP",
10145 "TEMPORARY",
10146 "THEN",
10147 "TIES",
10148 "TO",
10149 "TRANSACTION",
10150 "TRIGGER",
10151 "TRUE",
10152 "FALSE",
10153 "UNBOUNDED",
10154 "UNION",
10155 "UNIQUE",
10156 "UPDATE",
10157 "USING",
10158 "VACUUM",
10159 "VALUES",
10160 "VIEW",
10161 "VIRTUAL",
10162 "WHEN",
10163 "WHERE",
10164 "WINDOW",
10165 "WITH",
10166 "WITHOUT",
10167 ];
10168
10169 assert!(
10170 keywords.len() >= 150,
10171 "expected 150+ keywords, got {}",
10172 keywords.len()
10173 );
10174
10175 for kw in &keywords {
10176 assert!(
10177 TokenKind::lookup_keyword(kw).is_some(),
10178 "keyword {kw} not recognized (uppercase)"
10179 );
10180 let lower = kw.to_ascii_lowercase();
10182 assert!(
10183 TokenKind::lookup_keyword(&lower).is_some(),
10184 "keyword {kw} not recognized (lowercase)"
10185 );
10186 let mixed: String = kw
10188 .chars()
10189 .enumerate()
10190 .map(|(i, c)| {
10191 if i % 2 == 0 {
10192 c.to_ascii_lowercase()
10193 } else {
10194 c.to_ascii_uppercase()
10195 }
10196 })
10197 .collect();
10198 assert!(
10199 TokenKind::lookup_keyword(&mixed).is_some(),
10200 "keyword {kw} not recognized (mixed case: {mixed})"
10201 );
10202 }
10203
10204 assert!(TokenKind::lookup_keyword("FOOBAR").is_none());
10206 assert!(TokenKind::lookup_keyword("").is_none());
10207 }
10208
10209 fn assert_roundtrip(sql: &str) {
10219 let ast1 = parse_one(sql);
10220 let rendered1 = ast1.to_string();
10221 let ast2 = parse_one(&rendered1);
10222 let rendered2 = ast2.to_string();
10223 assert_eq!(
10224 rendered1, rendered2,
10225 "round-trip failed for:\n input: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
10226 );
10227 }
10228
10229 #[test]
10230 fn test_roundtrip_select_simple() {
10231 assert_roundtrip("SELECT 1");
10232 assert_roundtrip("SELECT 1, 2, 3");
10233 assert_roundtrip("SELECT *");
10234 assert_roundtrip("SELECT * FROM t");
10235 assert_roundtrip("SELECT a, b FROM t WHERE a > 10");
10236 assert_roundtrip("SELECT a FROM t ORDER BY a DESC");
10237 assert_roundtrip("SELECT a FROM t LIMIT 10 OFFSET 5");
10238 }
10239
10240 #[test]
10241 fn test_roundtrip_select_distinct() {
10242 assert_roundtrip("SELECT DISTINCT a, b FROM t");
10243 }
10244
10245 #[test]
10246 fn test_roundtrip_select_alias() {
10247 assert_roundtrip("SELECT a AS x, b AS y FROM t AS u");
10248 }
10249
10250 #[test]
10251 fn test_roundtrip_select_join_types() {
10252 assert_roundtrip("SELECT * FROM a INNER JOIN b ON a.id = b.id");
10253 assert_roundtrip("SELECT * FROM a LEFT JOIN b ON a.id = b.id");
10254 assert_roundtrip("SELECT * FROM a RIGHT JOIN b ON a.id = b.id");
10255 assert_roundtrip("SELECT * FROM a FULL JOIN b ON a.id = b.id");
10256 assert_roundtrip("SELECT * FROM a CROSS JOIN b");
10257 assert_roundtrip("SELECT * FROM a NATURAL INNER JOIN b");
10258 assert_roundtrip("SELECT * FROM a LEFT JOIN b USING (id)");
10259 }
10260
10261 #[test]
10262 fn test_roundtrip_select_subquery() {
10263 assert_roundtrip("SELECT * FROM (SELECT 1 AS x) AS sub");
10264 }
10265
10266 #[test]
10267 fn test_roundtrip_select_group_by_having() {
10268 assert_roundtrip("SELECT a, count(*) FROM t GROUP BY a HAVING count(*) > 1");
10269 }
10270
10271 #[test]
10272 fn test_roundtrip_select_window() {
10273 assert_roundtrip("SELECT sum(x) OVER (PARTITION BY g ORDER BY x) FROM t");
10274 }
10275
10276 #[test]
10277 fn test_roundtrip_select_cte() {
10278 assert_roundtrip("WITH cte AS (SELECT 1 AS n) SELECT * FROM cte");
10279 assert_roundtrip(
10280 "WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cnt WHERE x < 10) SELECT * FROM cnt",
10281 );
10282 }
10283
10284 #[test]
10285 fn test_roundtrip_select_compound() {
10286 assert_roundtrip("SELECT 1 UNION SELECT 2");
10287 assert_roundtrip("SELECT 1 UNION ALL SELECT 2");
10288 assert_roundtrip("SELECT 1 INTERSECT SELECT 2");
10289 assert_roundtrip("SELECT 1 EXCEPT SELECT 2");
10290 }
10291
10292 #[test]
10293 fn test_roundtrip_insert() {
10294 assert_roundtrip("INSERT INTO t (a, b) VALUES (1, 2)");
10295 assert_roundtrip("INSERT INTO t DEFAULT VALUES");
10296 assert_roundtrip("INSERT INTO t SELECT * FROM u");
10297 assert_roundtrip("INSERT OR REPLACE INTO t (a) VALUES (1)");
10298 assert_roundtrip("REPLACE INTO t (a) VALUES (1)");
10299 }
10300
10301 #[test]
10302 fn test_roundtrip_insert_returning() {
10303 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING *");
10304 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING a, b");
10305 }
10306
10307 #[test]
10308 fn test_roundtrip_insert_on_conflict() {
10309 assert_roundtrip("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
10310 assert_roundtrip(
10311 "INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a",
10312 );
10313 }
10314
10315 #[test]
10316 fn test_roundtrip_update() {
10317 assert_roundtrip("UPDATE t SET a = 1");
10318 assert_roundtrip("UPDATE t SET a = 1, b = 2 WHERE c > 3");
10319 assert_roundtrip("UPDATE t SET a = 1 RETURNING *");
10320 }
10321
10322 #[test]
10323 fn test_roundtrip_delete() {
10324 assert_roundtrip("DELETE FROM t");
10325 assert_roundtrip("DELETE FROM t WHERE a = 1");
10326 assert_roundtrip("DELETE FROM t RETURNING *");
10327 }
10328
10329 #[test]
10330 fn test_roundtrip_create_table() {
10331 assert_roundtrip("CREATE TABLE t (a INTEGER, b TEXT)");
10332 assert_roundtrip("CREATE TABLE IF NOT EXISTS t (a INTEGER PRIMARY KEY)");
10333 assert_roundtrip("CREATE TEMP TABLE t (a TEXT NOT NULL, b REAL DEFAULT 0.0)");
10334 }
10335
10336 #[test]
10337 fn test_roundtrip_create_index() {
10338 assert_roundtrip("CREATE INDEX idx ON t (a)");
10339 assert_roundtrip("CREATE UNIQUE INDEX IF NOT EXISTS idx ON t (a, b DESC)");
10340 assert_roundtrip("CREATE INDEX idx ON t (a) WHERE a > 0");
10341 }
10342
10343 #[test]
10344 fn test_roundtrip_drop() {
10345 assert_roundtrip("DROP TABLE t");
10346 assert_roundtrip("DROP TABLE IF EXISTS t");
10347 assert_roundtrip("DROP INDEX idx");
10348 assert_roundtrip("DROP VIEW v");
10349 }
10350
10351 #[test]
10352 fn test_roundtrip_alter_table() {
10353 assert_roundtrip("ALTER TABLE t RENAME TO u");
10354 assert_roundtrip("ALTER TABLE t ADD COLUMN c TEXT");
10355 assert_roundtrip("ALTER TABLE t DROP COLUMN c");
10356 }
10357
10358 #[test]
10359 fn test_roundtrip_transaction() {
10360 assert_roundtrip("BEGIN");
10361 assert_roundtrip("BEGIN IMMEDIATE");
10362 assert_roundtrip("BEGIN EXCLUSIVE");
10363 assert_roundtrip("COMMIT");
10364 assert_roundtrip("ROLLBACK");
10365 assert_roundtrip("SAVEPOINT sp1");
10366 assert_roundtrip("RELEASE sp1");
10367 }
10368
10369 #[test]
10370 fn test_roundtrip_pragma() {
10371 assert_roundtrip("PRAGMA journal_mode");
10372 assert_roundtrip("PRAGMA journal_mode = wal");
10373 }
10374
10375 #[test]
10376 fn test_roundtrip_explain() {
10377 assert_roundtrip("EXPLAIN SELECT 1");
10378 assert_roundtrip("EXPLAIN QUERY PLAN SELECT * FROM t");
10379 }
10380
10381 #[test]
10382 fn test_roundtrip_expressions() {
10383 assert_roundtrip("SELECT 1 + 2 * 3");
10384 assert_roundtrip("SELECT NOT a");
10385 assert_roundtrip("SELECT -x");
10386 assert_roundtrip("SELECT ~x");
10387 assert_roundtrip("SELECT a BETWEEN 1 AND 10");
10388 assert_roundtrip("SELECT a NOT BETWEEN 1 AND 10");
10389 assert_roundtrip("SELECT a IN (1, 2, 3)");
10390 assert_roundtrip("SELECT a NOT IN (1, 2, 3)");
10391 assert_roundtrip("SELECT a LIKE '%foo%'");
10392 assert_roundtrip("SELECT a GLOB '*foo*'");
10393 assert_roundtrip("SELECT CASE WHEN a = 1 THEN 'one' ELSE 'other' END");
10394 assert_roundtrip("SELECT CASE x WHEN 1 THEN 'a' WHEN 2 THEN 'b' END");
10395 assert_roundtrip("SELECT CAST(a AS TEXT)");
10396 assert_roundtrip("SELECT EXISTS (SELECT 1)");
10397 assert_roundtrip("SELECT (SELECT 1)");
10398 assert_roundtrip("SELECT a COLLATE NOCASE");
10399 }
10400
10401 #[test]
10402 fn test_roundtrip_literals() {
10403 assert_roundtrip("SELECT NULL");
10404 assert_roundtrip("SELECT TRUE");
10405 assert_roundtrip("SELECT FALSE");
10406 assert_roundtrip("SELECT 42");
10407 assert_roundtrip("SELECT 3.14");
10408 assert_roundtrip("SELECT 'hello'");
10409 assert_roundtrip("SELECT X'DEADBEEF'");
10410 assert_roundtrip("SELECT CURRENT_TIME");
10411 assert_roundtrip("SELECT CURRENT_DATE");
10412 assert_roundtrip("SELECT CURRENT_TIMESTAMP");
10413 }
10414
10415 #[test]
10416 fn test_roundtrip_placeholders() {
10417 assert_roundtrip("SELECT ?");
10418 assert_roundtrip("SELECT ?1");
10419 assert_roundtrip("SELECT :name");
10420 assert_roundtrip("SELECT @name");
10421 assert_roundtrip("SELECT $name");
10422 }
10423
10424 #[test]
10425 fn test_roundtrip_json_arrows() {
10426 assert_roundtrip("SELECT a -> 'key'");
10427 assert_roundtrip("SELECT a ->> 'key'");
10428 }
10429
10430 #[test]
10431 fn test_roundtrip_function_calls() {
10432 assert_roundtrip("SELECT count(*)");
10433 assert_roundtrip("SELECT count(DISTINCT a)");
10434 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0)");
10435 }
10436
10437 #[test]
10438 fn test_roundtrip_isnull_notnull() {
10439 assert_roundtrip("SELECT a ISNULL");
10440 assert_roundtrip("SELECT a IS NOT NULL");
10441 }
10442
10443 #[test]
10444 fn test_roundtrip_create_view() {
10445 assert_roundtrip("CREATE VIEW v AS SELECT * FROM t");
10446 assert_roundtrip("CREATE VIEW IF NOT EXISTS v (a, b) AS SELECT 1, 2");
10447 }
10448
10449 #[test]
10450 fn test_roundtrip_create_trigger() {
10451 assert_roundtrip(
10452 "CREATE TRIGGER tr BEFORE DELETE ON t FOR EACH ROW BEGIN DELETE FROM log WHERE id = OLD.id; END",
10453 );
10454 }
10455
10456 #[test]
10457 fn test_roundtrip_attach_detach() {
10458 assert_roundtrip("ATTACH 'file.db' AS db2");
10459 assert_roundtrip("DETACH db2");
10460 }
10461
10462 #[test]
10463 fn test_roundtrip_vacuum() {
10464 assert_roundtrip("VACUUM");
10465 }
10466
10467 #[test]
10468 fn test_roundtrip_analyze_reindex() {
10469 assert_roundtrip("ANALYZE");
10470 assert_roundtrip("ANALYZE t");
10471 assert_roundtrip("REINDEX");
10472 assert_roundtrip("REINDEX t");
10473 }
10474
10475 #[test]
10476 fn test_roundtrip_cte_materialized() {
10477 assert_roundtrip("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
10478 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
10479 }
10480
10481 mod proptest_roundtrip {
10486 use super::*;
10487 use proptest::prelude::*;
10488
10489 fn is_keyword(s: &str) -> bool {
10491 TokenKind::lookup_keyword(s).is_some()
10492 }
10493
10494 fn arb_ident() -> BoxedStrategy<String> {
10496 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
10497 .expect("valid regex")
10498 .prop_filter("must not be keyword", |s| !is_keyword(s))
10499 .boxed()
10500 }
10501
10502 fn arb_literal() -> BoxedStrategy<String> {
10504 prop_oneof![
10505 any::<i32>().prop_map(|n| n.to_string()),
10506 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
10507 arb_ident().prop_map(|s| format!("'{s}'")),
10508 Just("NULL".to_string()),
10509 Just("TRUE".to_string()),
10510 Just("FALSE".to_string()),
10511 ]
10512 .boxed()
10513 }
10514
10515 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
10517 if depth == 0 {
10518 prop_oneof![
10519 arb_literal(),
10520 arb_ident(),
10521 (arb_ident(), arb_ident()).prop_map(|(t, c)| format!("{t}.{c}")),
10522 ]
10523 .boxed()
10524 } else {
10525 let leaf = arb_expr(0);
10526 prop_oneof![
10527 4 => leaf,
10528 2 => (arb_expr(depth - 1), prop_oneof![
10530 Just("+"), Just("-"), Just("*"), Just("/"),
10531 Just("="), Just("!="), Just("<"), Just("<="),
10532 Just(">"), Just(">="), Just("AND"), Just("OR"),
10533 Just("||"),
10534 ], arb_expr(depth - 1))
10535 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
10536 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
10538 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
10539 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NULL")),
10541 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NOT NULL")),
10542 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} ISNULL")),
10544 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} NOTNULL")),
10545 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} COLLATE nocase")),
10547 2 => (arb_expr(depth - 1), prop_oneof![
10552 Just("+"), Just("*"), Just("="), Just("<"),
10553 Just("AND"), Just("OR"), Just("||"), Just("IS"),
10554 Just("IS NOT"),
10555 ], arb_expr(depth - 1))
10556 .prop_map(|(l, op, r)| format!("{l} {op} {r}")),
10557 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
10559 .prop_map(|(e, lo, hi)| format!("{e} BETWEEN {lo} AND {hi}")),
10560 1 => (arb_expr(depth - 1), proptest::collection::vec(arb_expr(0), 1..4))
10562 .prop_map(|(e, items)| format!("{e} IN ({})", items.join(", "))),
10563 1 => (arb_expr(depth - 1), arb_ident())
10565 .prop_map(|(e, p)| format!("{e} LIKE '{p}'")),
10566 1 => arb_expr(depth - 1).prop_map(|e| format!("CAST({e} AS TEXT)")),
10568 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
10570 .prop_map(|(c, t, el)| format!("CASE WHEN {c} THEN {t} ELSE {el} END")),
10571 1 => (arb_ident(), proptest::collection::vec(arb_expr(0), 0..3))
10573 .prop_map(|(name, args)| format!("{name}({})", args.join(", "))),
10574 1 => arb_expr(0).prop_map(|e| format!("(SELECT {e})")),
10576 ]
10577 .boxed()
10578 }
10579 }
10580
10581 fn arb_select() -> BoxedStrategy<String> {
10583 use std::fmt::Write as _;
10584
10585 let cols =
10586 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
10587 let table = arb_ident();
10588 let where_clause = prop::option::of(arb_expr(1));
10589 let order_by = prop::option::of(arb_ident());
10590 let limit = prop::option::of(1u32..100);
10591
10592 (cols, table, where_clause, order_by, limit)
10593 .prop_map(|(cols, tbl, wh, ord, lim)| {
10594 let mut sql = format!("SELECT {cols} FROM {tbl}");
10595 if let Some(w) = wh {
10596 write!(sql, " WHERE {w}").expect("writing to String should not fail");
10597 }
10598 if let Some(o) = ord {
10599 write!(sql, " ORDER BY {o}").expect("writing to String should not fail");
10600 }
10601 if let Some(l) = lim {
10602 write!(sql, " LIMIT {l}").expect("writing to String should not fail");
10603 }
10604 sql
10605 })
10606 .boxed()
10607 }
10608
10609 fn arb_insert() -> BoxedStrategy<String> {
10611 let ncols = 1usize..4;
10612 ncols
10613 .prop_flat_map(|n| {
10614 let tbl = arb_ident();
10615 let cols = proptest::collection::vec(arb_ident(), n..=n);
10616 let vals = proptest::collection::vec(arb_literal(), n..=n);
10617 (tbl, cols, vals).prop_map(|(t, cs, vs): (String, Vec<String>, Vec<String>)| {
10618 format!(
10619 "INSERT INTO {t} ({}) VALUES ({})",
10620 cs.join(", "),
10621 vs.join(", ")
10622 )
10623 })
10624 })
10625 .boxed()
10626 }
10627
10628 fn arb_statement() -> BoxedStrategy<String> {
10630 prop_oneof![
10631 6 => arb_select(),
10632 3 => arb_insert(),
10633 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
10634 1 => (arb_ident(), arb_expr(1))
10635 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
10636 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
10637 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
10638 ]
10639 .boxed()
10640 }
10641
10642 fn try_parse_one(sql: &str) -> Option<Statement> {
10644 let mut p = Parser::from_sql(sql);
10645 let (stmts, errs) = p.parse_all();
10646 if errs.is_empty() && stmts.len() == 1 {
10647 Some(stmts.into_iter().next().unwrap())
10648 } else {
10649 None
10650 }
10651 }
10652
10653 proptest::proptest! {
10654 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
10655
10656 #[test]
10657 fn test_parser_roundtrip_proptest(sql in arb_statement()) {
10658 let Some(ast1) = try_parse_one(&sql) else {
10660 return Ok(()); };
10662
10663 let rendered1 = ast1.to_string();
10665
10666 let Some(ast2) = try_parse_one(&rendered1) else {
10668 let msg = format!("re-parse failed for rendered SQL: {rendered1:?}");
10669 prop_assert!(false, "{}", msg);
10670 unreachable!()
10671 };
10672
10673 let rendered2 = ast2.to_string();
10675 let msg = format!(
10676 "round-trip not idempotent:\n original: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
10677 );
10678 prop_assert_eq!(rendered1, rendered2, "{}", msg);
10679 }
10680 }
10681 }
10682
10683 mod proptest_properties {
10688 use super::*;
10689 use proptest::prelude::*;
10690
10691 fn arb_ident() -> BoxedStrategy<String> {
10693 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
10694 .expect("valid regex")
10695 .prop_filter("must not be keyword", |s| {
10696 TokenKind::lookup_keyword(s).is_none()
10697 })
10698 .boxed()
10699 }
10700
10701 fn arb_literal() -> BoxedStrategy<String> {
10702 prop_oneof![
10703 any::<i32>().prop_map(|n| n.to_string()),
10704 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
10705 arb_ident().prop_map(|s| format!("'{s}'")),
10706 Just("NULL".to_string()),
10707 Just("TRUE".to_string()),
10708 Just("FALSE".to_string()),
10709 ]
10710 .boxed()
10711 }
10712
10713 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
10714 if depth == 0 {
10715 prop_oneof![arb_literal(), arb_ident(),].boxed()
10716 } else {
10717 let leaf = arb_expr(0);
10718 prop_oneof![
10719 4 => leaf,
10720 2 => (arb_expr(depth - 1), prop_oneof![
10721 Just("+"), Just("-"), Just("*"), Just("/"),
10722 Just("="), Just("!="), Just("<"), Just("<="),
10723 Just(">"), Just(">="), Just("AND"), Just("OR"),
10724 ], arb_expr(depth - 1))
10725 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
10726 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
10727 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
10728 ]
10729 .boxed()
10730 }
10731 }
10732
10733 fn arb_select() -> BoxedStrategy<String> {
10734 use std::fmt::Write as _;
10735 let cols =
10736 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
10737 let table = arb_ident();
10738 let where_clause = prop::option::of(arb_expr(1));
10739 (cols, table, where_clause)
10740 .prop_map(|(cols, tbl, wh)| {
10741 let mut sql = format!("SELECT {cols} FROM {tbl}");
10742 if let Some(w) = wh {
10743 write!(sql, " WHERE {w}").expect("writing to String should not fail");
10744 }
10745 sql
10746 })
10747 .boxed()
10748 }
10749
10750 fn arb_statement() -> BoxedStrategy<String> {
10751 prop_oneof![
10752 6 => arb_select(),
10753 3 => {
10754 let ncols = 1usize..4;
10755 ncols
10756 .prop_flat_map(|n| {
10757 let tbl = arb_ident();
10758 let cols = proptest::collection::vec(arb_ident(), n..=n);
10759 let vals = proptest::collection::vec(arb_literal(), n..=n);
10760 (tbl, cols, vals).prop_map(
10761 |(t, cs, vs): (String, Vec<String>, Vec<String>)| {
10762 format!(
10763 "INSERT INTO {t} ({}) VALUES ({})",
10764 cs.join(", "),
10765 vs.join(", ")
10766 )
10767 },
10768 )
10769 })
10770 .boxed()
10771 },
10772 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
10773 1 => (arb_ident(), arb_expr(1))
10774 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
10775 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
10776 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
10777 ]
10778 .boxed()
10779 }
10780
10781 proptest::proptest! {
10783 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(500))]
10784
10785 #[test]
10786 fn test_parser_determinism(sql in arb_statement()) {
10787 let mut p1 = Parser::from_sql(&sql);
10788 let (stmts1, errs1) = p1.parse_all();
10789
10790 let mut p2 = Parser::from_sql(&sql);
10791 let (stmts2, errs2) = p2.parse_all();
10792
10793 let msg_stmt = format!("different statement counts for: {sql}");
10795 prop_assert_eq!(stmts1.len(), stmts2.len(), "{}", msg_stmt);
10796 let msg_err = format!("different error counts for: {sql}");
10797 prop_assert_eq!(errs1.len(), errs2.len(), "{}", msg_err);
10798
10799 if errs1.is_empty() && !stmts1.is_empty() {
10801 for (s1, s2) in stmts1.iter().zip(stmts2.iter()) {
10802 let r1 = s1.to_string();
10803 let r2 = s2.to_string();
10804 let msg_det = format!("non-deterministic parse output for: {sql}");
10805 prop_assert_eq!(r1, r2, "{}", msg_det);
10806 }
10807 }
10808 }
10809 }
10810
10811 proptest::proptest! {
10813 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(2000))]
10814
10815 #[test]
10816 fn test_parser_fuzz_no_panic(input in prop::collection::vec(any::<u8>(), 0..256)) {
10817 let sql = String::from_utf8_lossy(&input);
10818 let mut p = Parser::from_sql(&sql);
10820 let _ = p.parse_all();
10821 }
10822 }
10823
10824 proptest::proptest! {
10826 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
10827
10828 #[test]
10829 fn test_parser_fuzz_near_valid(
10830 prefix in prop_oneof![
10831 Just("SELECT "),
10832 Just("INSERT INTO "),
10833 Just("DELETE FROM "),
10834 Just("UPDATE "),
10835 Just("CREATE TABLE "),
10836 Just("DROP TABLE "),
10837 Just("BEGIN "),
10838 Just("PRAGMA "),
10839 ],
10840 suffix in prop::string::string_regex("[a-zA-Z0-9_ ,.*=<>!()'\";+\\-/]{0,100}")
10841 .expect("valid regex")
10842 ) {
10843 let sql = format!("{prefix}{suffix}");
10844 let mut p = Parser::from_sql(&sql);
10845 let _ = p.parse_all();
10846 }
10847 }
10848
10849 proptest::proptest! {
10851 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
10852
10853 #[test]
10854 fn test_parser_unicode_identifiers(
10855 name in prop::string::string_regex("[\\p{L}][\\p{L}\\p{N}_]{0,10}")
10856 .expect("valid regex")
10857 .prop_filter("must not be keyword", |s| {
10858 TokenKind::lookup_keyword(s).is_none()
10859 })
10860 ) {
10861 let sql = format!("SELECT \"{name}\" FROM \"{name}\"");
10863 let mut p = Parser::from_sql(&sql);
10864 let (stmts, errs) = p.parse_all();
10865 prop_assert!(
10866 errs.is_empty(),
10867 "Unicode identifier should parse: {sql}, errors: {errs:?}"
10868 );
10869 prop_assert_eq!(stmts.len(), 1);
10870 }
10871 }
10872
10873 proptest::proptest! {
10875 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(300))]
10876
10877 #[test]
10878 fn test_parser_rejects_incomplete_statements(
10879 kind in prop_oneof![
10880 Just("SELECT"),
10881 Just("SELECT FROM"),
10882 Just("INSERT INTO"),
10883 Just("DELETE"),
10884 Just("UPDATE SET"),
10885 Just("CREATE"),
10886 Just("CREATE TABLE"),
10887 Just("DROP"),
10888 ],
10889 trailing in prop::option::of(
10890 prop::string::string_regex("[;, ]{0,3}").expect("valid regex")
10891 )
10892 ) {
10893 let sql = match trailing {
10894 Some(t) => format!("{kind}{t}"),
10895 None => kind.to_string(),
10896 };
10897 let mut p = Parser::from_sql(&sql);
10898 let (stmts, errs) = p.parse_all();
10899 prop_assert!(
10903 !errs.is_empty() || stmts.is_empty(),
10904 "Expected rejection of incomplete SQL: {sql}, got {stmts:?}"
10905 );
10906 }
10907 }
10908
10909 proptest::proptest! {
10912 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
10913
10914 #[test]
10915 fn test_parser_multi_statement_count(
10916 stmts in proptest::collection::vec(arb_statement(), 1..4)
10917 ) {
10918 let sql = stmts.join("; ");
10919 let mut p = Parser::from_sql(&sql);
10920 let (parsed, errors) = p.parse_all();
10921 if errors.is_empty() {
10923 prop_assert!(
10924 parsed.len() >= stmts.len(),
10925 "Expected at least {} statements from: {sql}, got {}",
10926 stmts.len(),
10927 parsed.len()
10928 );
10929 }
10930 }
10931 }
10932 }
10933
10934 #[test]
10935 fn test_parse_statements_with_scratch_reuses_token_and_error_capacity() {
10936 let mut scratch = StatementParseScratch::default();
10937 let err = parse_statements_with_scratch("SELECT FROM", &mut scratch)
10938 .expect_err("malformed SQL should surface a parse error");
10939 assert!(
10940 err.message.contains("expected"),
10941 "malformed parse should preserve its diagnostic detail",
10942 );
10943 let warmed_token_capacity = scratch.token_capacity();
10944 let warmed_error_capacity = scratch.error_capacity();
10945 assert!(
10946 warmed_token_capacity > 0,
10947 "parse scratch should warm token storage"
10948 );
10949 assert!(
10950 warmed_error_capacity > 0,
10951 "parse scratch should warm error storage"
10952 );
10953
10954 let statements = parse_statements_with_scratch("SELECT 1;", &mut scratch)
10955 .expect("follow-up parse should succeed");
10956 assert_eq!(statements.len(), 1);
10957 assert_eq!(
10958 scratch.token_capacity(),
10959 warmed_token_capacity,
10960 "successful parse should reuse token scratch capacity",
10961 );
10962 assert_eq!(
10963 scratch.error_capacity(),
10964 warmed_error_capacity,
10965 "successful parse should preserve error scratch capacity for the next recovery path",
10966 );
10967 }
10968
10969 #[test]
10970 fn test_parse_statements_with_scratch_enforces_top_level_separators() {
10971 let mut scratch = StatementParseScratch::default();
10972 let sql = "SELECT 1 SELECT 2";
10973 let error = parse_statements_with_scratch(sql, &mut scratch)
10974 .expect_err("scratch parser must reject adjacent statements");
10975 assert!(
10976 error.message.contains("expected ';' separator"),
10977 "unexpected diagnostic: {error:?}"
10978 );
10979 assert_eq!(
10980 &sql[error.span.start as usize..error.span.end as usize],
10981 "SELECT"
10982 );
10983
10984 let statements = parse_statements_with_scratch("SELECT 1; SELECT 2;", &mut scratch)
10985 .expect("semicolon-separated statements must remain valid");
10986 assert_eq!(statements.len(), 2);
10987
10988 let trigger_script = "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
10989 INSERT INTO t VALUES (1); \
10990 INSERT INTO t VALUES (2); \
10991 END; SELECT 3;";
10992 let statements = parse_statements_with_scratch(trigger_script, &mut scratch)
10993 .expect("trigger-body terminators must not become top-level separator errors");
10994 assert_eq!(statements.len(), 2);
10995 assert!(matches!(statements[0], Statement::CreateTrigger(_)));
10996 assert!(matches!(statements[1], Statement::Select(_)));
10997 }
10998
10999 #[test]
11000 fn test_parse_statements_with_scratch_reuses_identifier_interns_across_parses() {
11001 let mut scratch = StatementParseScratch::default();
11002 let mut sql = String::from("SELECT ");
11003 for i in 0..32 {
11004 if i > 0 {
11005 sql.push_str(", ");
11006 }
11007 sql.push_str(&format!("unique_identifier_{i} AS unique_alias_{i}"));
11008 }
11009 sql.push(';');
11010
11011 let statements = parse_statements_with_scratch(&sql, &mut scratch)
11012 .expect("identifier-heavy statement should parse");
11013 assert_eq!(statements.len(), 1);
11014 let interner_len = scratch.identifier_interner_len();
11015 assert!(
11016 interner_len > 0,
11017 "scratch should retain identifier interns for the next parse",
11018 );
11019
11020 let statements = parse_statements_with_scratch(&sql, &mut scratch)
11021 .expect("repeat parse should also succeed");
11022 assert_eq!(statements.len(), 1);
11023 assert_eq!(
11024 scratch.identifier_interner_len(),
11025 interner_len,
11026 "repeated parse should reuse the retained interner set instead of growing it",
11027 );
11028
11029 scratch.reset();
11030 assert!(
11031 scratch.identifier_interner_is_empty(),
11032 "explicit scratch reset should also keep the interner logically empty",
11033 );
11034 }
11035
11036 #[test]
11037 fn test_parse_statements_with_scratch_drops_oversized_identifier_interner() {
11038 let mut scratch = StatementParseScratch::default();
11039 let mut sql = String::from("SELECT ");
11040 for i in 0..300 {
11041 if i > 0 {
11042 sql.push_str(", ");
11043 }
11044 sql.push_str(&format!(
11045 "very_long_unique_identifier_{i:03} AS alias_{i:03}"
11046 ));
11047 }
11048 sql.push(';');
11049
11050 let statements = parse_statements_with_scratch(&sql, &mut scratch)
11051 .expect("oversized identifier-heavy statement should parse");
11052 assert_eq!(statements.len(), 1);
11053 assert!(
11054 scratch.identifier_interner_is_empty(),
11055 "oversized identifier interners should be dropped instead of retained indefinitely",
11056 );
11057 }
11058
11059 #[test]
11063 fn create_table_quoted_reserved_word_key() {
11064 parse_ok(r#"CREATE TABLE "meta" ("key" TEXT, "val" TEXT);"#);
11066 }
11067
11068 #[test]
11069 fn create_table_unquoted_key_column() {
11070 parse_ok("CREATE TABLE meta (key TEXT, val TEXT);");
11072 }
11073
11074 #[test]
11075 fn create_table_quoted_order_column() {
11076 parse_ok(r#"CREATE TABLE t ("order" INTEGER);"#);
11078 }
11079
11080 #[test]
11081 fn create_table_quoted_select_column() {
11082 parse_ok(r#"CREATE TABLE t ("select" TEXT);"#);
11084 }
11085
11086 #[test]
11087 fn select_with_reserved_word_column_key() {
11088 parse_ok("SELECT key FROM meta;");
11090 }
11091
11092 #[test]
11093 fn select_with_reserved_word_column_value() {
11094 parse_ok("SELECT value FROM meta;");
11096 }
11097
11098 #[test]
11099 fn select_with_reserved_word_column_order() {
11100 parse_ok(r#"SELECT "order" FROM t;"#);
11102 }
11103
11104 #[test]
11105 fn where_clause_with_reserved_word_column() {
11106 parse_ok("UPDATE meta SET val = '2.0' WHERE key = 'version';");
11108 }
11109
11110 #[test]
11111 fn update_set_reserved_word_column() {
11112 parse_ok(r#"UPDATE meta SET "key" = 'newkey' WHERE "key" = 'oldkey';"#);
11114 }
11115
11116 #[test]
11117 fn delete_where_reserved_word_column() {
11118 parse_ok("DELETE FROM meta WHERE key = 'version';");
11119 }
11120
11121 #[test]
11122 fn persistence_dump_with_reserved_word_columns() {
11123 let sql = concat!(
11126 r#"CREATE TABLE "meta" ("key" TEXT, "value" TEXT);"#,
11127 "\n",
11128 r#"INSERT INTO "meta" VALUES ('version', '1.0');"#,
11129 "\n",
11130 r#"INSERT INTO "meta" VALUES ('author', 'test');"#,
11131 );
11132 let mut p = Parser::from_sql(sql);
11133 let (stmts, errs) = p.parse_all();
11134 assert!(
11135 errs.is_empty(),
11136 "persistence dump with reserved-word columns should parse cleanly: {errs:?}"
11137 );
11138 assert_eq!(stmts.len(), 3);
11139 }
11140
11141 #[test]
11142 fn create_table_with_single_quoted_name_parses_cleanly() {
11143 let sql = "CREATE TABLE 'fts_messages_data'(id INTEGER PRIMARY KEY, block BLOB);";
11144 let mut p = Parser::from_sql(sql);
11145 let (stmts, errs) = p.parse_all();
11146 assert!(
11147 errs.is_empty(),
11148 "single-quoted sqlite_master shadow-table SQL should parse cleanly: {errs:?}"
11149 );
11150 assert_eq!(stmts.len(), 1);
11151 match &stmts[0] {
11152 Statement::CreateTable(stmt) => {
11153 assert_eq!(stmt.name.name, "fts_messages_data");
11154 }
11155 other => panic!("expected CreateTable, got {other:?}"),
11156 }
11157 }
11158
11159 #[test]
11160 fn select_qualified_column_with_alias() {
11161 let stmt = parse_one("SELECT a.name AS from_name FROM users a");
11164 if let Statement::Select(s) = stmt {
11165 if let SelectCore::Select { columns, .. } = &s.body.select {
11166 assert_eq!(columns.len(), 1);
11167 match &columns[0] {
11168 ResultColumn::Expr { expr, alias } => {
11169 assert_eq!(
11171 alias.as_deref(),
11172 Some("from_name"),
11173 "alias should be 'from_name', got {alias:?}"
11174 );
11175 if let Expr::Column(col_ref, _) = expr {
11177 assert_eq!(col_ref.table.as_deref(), Some("a"));
11178 assert_eq!(col_ref.column.as_ref(), "name");
11179 } else {
11180 panic!("expected Column expression, got {expr:?}");
11181 }
11182 }
11183 other => panic!("expected Expr variant, got {other:?}"),
11184 }
11185 } else {
11186 panic!("expected Select core");
11187 }
11188 } else {
11189 panic!("expected Select statement");
11190 }
11191 }
11192
11193 #[test]
11194 fn select_qualified_column_with_implicit_alias() {
11195 let stmt = parse_one("SELECT a.name from_name FROM users a");
11197 if let Statement::Select(s) = stmt {
11198 if let SelectCore::Select { columns, .. } = &s.body.select {
11199 assert_eq!(columns.len(), 1);
11200 match &columns[0] {
11201 ResultColumn::Expr { expr, alias } => {
11202 assert_eq!(
11204 alias.as_deref(),
11205 Some("from_name"),
11206 "implicit alias should be 'from_name', got {alias:?}"
11207 );
11208 if let Expr::Column(col_ref, _) = expr {
11210 assert_eq!(col_ref.table.as_deref(), Some("a"));
11211 assert_eq!(col_ref.column.as_ref(), "name");
11212 } else {
11213 panic!("expected Column expression, got {expr:?}");
11214 }
11215 }
11216 other => panic!("expected Expr variant, got {other:?}"),
11217 }
11218 } else {
11219 panic!("expected Select core");
11220 }
11221 } else {
11222 panic!("expected Select statement");
11223 }
11224 }
11225
11226 #[test]
11227 fn select_implicit_alias_non_reserved_keyword() {
11228 let stmt = parse_one("SELECT 1 action");
11231 if let Statement::Select(s) = stmt {
11232 if let SelectCore::Select { columns, .. } = &s.body.select {
11233 if let ResultColumn::Expr { alias, .. } = &columns[0] {
11234 assert_eq!(
11235 alias.as_deref(),
11236 Some("action"),
11237 "implicit alias 'action' (keyword) failed to parse"
11238 );
11239 } else {
11240 unreachable!("expected Expr result column");
11241 }
11242 } else {
11243 unreachable!("expected Select core");
11244 }
11245 } else {
11246 unreachable!("expected Select");
11247 }
11248 }
11249}