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