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