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