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