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