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