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