1use std::error::Error;
6use std::fmt;
7use std::sync::atomic::{AtomicU64, Ordering};
8
9use fsqlite_ast::{
10 AlterTableAction, AlterTableStatement, Assignment, AssignmentTarget, AttachStatement,
11 BeginStatement, ColumnConstraint, ColumnConstraintKind, ColumnDef, CompoundOp, ConflictAction,
12 CreateIndexStatement, CreateTableBody, CreateTableStatement, CreateTriggerStatement,
13 CreateViewStatement, CreateVirtualTableStatement, Cte, CteMaterialized, DefaultValue,
14 Deferrable, DeferrableInitially, DeleteStatement, Distinctness, DropObjectType, DropStatement,
15 Expr, ForeignKeyAction, ForeignKeyActionType, ForeignKeyClause, ForeignKeyTrigger, FrameBound,
16 FrameExclude, FrameSpec, FrameType, FromClause, GeneratedStorage, IndexHint, IndexedColumn,
17 InsertSource, InsertStatement, JoinClause, JoinConstraint, JoinKind, JoinType, LimitClause,
18 Literal, NullsOrder, OrderingTerm, PragmaStatement, PragmaValue, QualifiedName,
19 QualifiedTableRef, ResultColumn, RollbackStatement, SelectBody, SelectCore, SelectStatement,
20 SortDirection, Span, Statement, TableConstraint, TableConstraintKind, TableOrSubquery,
21 TransactionMode, TriggerEvent, TriggerTiming, TypeName, UpdateStatement, UpsertAction,
22 UpsertClause, UpsertTarget, VacuumStatement, WindowDef, WindowSpec, WithClause,
23};
24
25use crate::lexer::Lexer;
26use crate::token::{Token, TokenKind};
27
28static FSQLITE_PARSE_STATEMENTS_TOTAL: AtomicU64 = AtomicU64::new(0);
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
37pub struct ParseMetricsSnapshot {
38 pub fsqlite_parse_statements_total: u64,
40}
41
42#[must_use]
44pub fn parse_metrics_snapshot() -> ParseMetricsSnapshot {
45 ParseMetricsSnapshot {
46 fsqlite_parse_statements_total: FSQLITE_PARSE_STATEMENTS_TOTAL.load(Ordering::Relaxed),
47 }
48}
49
50pub fn reset_parse_metrics() {
52 FSQLITE_PARSE_STATEMENTS_TOTAL.store(0, Ordering::Relaxed);
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct ParseError {
61 pub message: String,
62 pub span: Span,
63 pub line: u32,
64 pub col: u32,
65}
66
67impl ParseError {
68 #[must_use]
69 pub(crate) fn at(message: impl Into<String>, token: Option<&Token>) -> Self {
70 if let Some(t) = token {
71 Self {
72 message: message.into(),
73 span: t.span,
74 line: t.line,
75 col: t.col,
76 }
77 } else {
78 Self {
79 message: message.into(),
80 span: Span::ZERO,
81 line: 0,
82 col: 0,
83 }
84 }
85 }
86}
87
88impl fmt::Display for ParseError {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "{}:{}: {}", self.line, self.col, self.message)
91 }
92}
93
94impl Error for ParseError {}
95
96pub struct Parser {
101 pub(crate) tokens: Vec<Token>,
102 pub(crate) pos: usize,
103 pub(crate) errors: Vec<ParseError>,
104}
105
106impl Parser {
107 #[must_use]
108 pub fn new(tokens: Vec<Token>) -> Self {
109 Self {
110 tokens,
111 pos: 0,
112 errors: Vec::new(),
113 }
114 }
115
116 #[must_use]
117 pub fn from_sql(sql: &str) -> Self {
118 Self::new(Lexer::tokenize(sql))
119 }
120
121 pub fn parse_all(&mut self) -> (Vec<Statement>, Vec<ParseError>) {
122 let span = tracing::debug_span!(
123 target: "fsqlite.parse",
124 "parse",
125 ast_node_count = tracing::field::Empty,
126 parse_errors = tracing::field::Empty,
127 );
128 let _guard = span.enter();
129
130 let mut stmts = Vec::new();
131 while !self.at_eof() {
132 if self.check(&TokenKind::Semicolon) {
133 self.advance();
134 continue;
135 }
136 match self.parse_statement() {
137 Ok(s) => {
138 FSQLITE_PARSE_STATEMENTS_TOTAL.fetch_add(1, Ordering::Relaxed);
139 stmts.push(s);
140 let _ = self.eat(&TokenKind::Semicolon);
141 }
142 Err(e) => {
143 tracing::warn!(
144 target: "fsqlite.parse",
145 error = %e,
146 "parse recovery: skipping malformed statement"
147 );
148 self.errors.push(e);
149 self.synchronize();
150 }
151 }
152 }
153
154 let errors = std::mem::take(&mut self.errors);
155 span.record("ast_node_count", stmts.len() as u64);
156 span.record("parse_errors", errors.len() as u64);
157
158 (stmts, errors)
159 }
160
161 pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
162 self.parse_statement_inner()
163 }
164
165 #[must_use]
166 pub fn errors(&self) -> &[ParseError] {
167 &self.errors
168 }
169
170 pub(crate) fn peek(&self) -> &TokenKind {
175 self.current().map_or(&TokenKind::Eof, |t| &t.kind)
176 }
177
178 pub(crate) fn current(&self) -> Option<&Token> {
179 self.tokens.get(self.pos)
180 }
181
182 pub(crate) fn peek_nth(&self, n: usize) -> &TokenKind {
183 self.tokens
184 .get(self.pos + n)
185 .map_or(&TokenKind::Eof, |t| &t.kind)
186 }
187
188 pub(crate) fn at_eof(&self) -> bool {
189 matches!(self.peek(), TokenKind::Eof)
190 }
191
192 pub(crate) fn advance(&mut self) -> Option<&Token> {
193 let t = self.tokens.get(self.pos);
194 if self.pos < self.tokens.len().saturating_sub(1) {
195 self.pos += 1;
196 }
197 t
198 }
199
200 pub(crate) fn check(&self, kind: &TokenKind) -> bool {
201 std::mem::discriminant(self.peek()) == std::mem::discriminant(kind)
202 }
203
204 pub(crate) fn check_kw(&self, kw: &TokenKind) -> bool {
205 self.peek() == kw
206 }
207
208 pub(crate) fn eat(&mut self, kind: &TokenKind) -> bool {
209 if self.check(kind) {
210 self.advance();
211 true
212 } else {
213 false
214 }
215 }
216
217 pub(crate) fn eat_kw(&mut self, kw: &TokenKind) -> bool {
218 if self.peek() == kw {
219 self.advance();
220 true
221 } else {
222 false
223 }
224 }
225
226 pub(crate) fn expect_kw(&mut self, kw: &TokenKind) -> Result<Span, ParseError> {
227 if self.peek() == kw {
228 let sp = self.current_span();
229 self.advance();
230 Ok(sp)
231 } else {
232 Err(self.err_expected(&format!("{kw:?}")))
233 }
234 }
235
236 pub(crate) fn expect_token(&mut self, kind: &TokenKind) -> Result<Span, ParseError> {
237 if self.check(kind) {
238 let sp = self.current_span();
239 self.advance();
240 Ok(sp)
241 } else {
242 Err(self.err_expected(&format!("{kind:?}")))
243 }
244 }
245
246 pub(crate) fn current_span(&self) -> Span {
247 self.current().map_or(Span::ZERO, |t| t.span)
248 }
249
250 pub(crate) fn err_expected(&self, what: &str) -> ParseError {
251 ParseError::at(format!("expected {what}"), self.current())
252 }
253
254 pub(crate) fn err_msg(&self, msg: impl Into<String>) -> ParseError {
255 ParseError::at(msg, self.current())
256 }
257
258 fn synchronize(&mut self) {
259 loop {
260 match self.peek() {
261 TokenKind::Eof => return,
262 TokenKind::Semicolon => {
263 self.advance();
264 return;
265 }
266 k if k.is_statement_start() => return,
267 _ => {
268 self.advance();
269 }
270 }
271 }
272 }
273
274 pub(crate) fn parse_identifier(&mut self) -> Result<String, ParseError> {
279 match self.peek().clone() {
280 TokenKind::Id(s) | TokenKind::QuotedId(s, _) => {
281 self.advance();
282 Ok(s)
283 }
284 ref k if is_nonreserved_kw(k) => {
285 let s = kw_to_str(k);
286 self.advance();
287 Ok(s)
288 }
289 _ => Err(self.err_expected("identifier")),
290 }
291 }
292
293 pub(crate) fn parse_qualified_name(&mut self) -> Result<QualifiedName, ParseError> {
294 let first = self.parse_identifier()?;
295 if self.eat(&TokenKind::Dot) {
296 let second = self.parse_identifier()?;
297 Ok(QualifiedName::qualified(first, second))
298 } else {
299 Ok(QualifiedName::bare(first))
300 }
301 }
302
303 fn parse_qualified_table_ref(&mut self) -> Result<QualifiedTableRef, ParseError> {
304 let name = self.parse_qualified_name()?;
305 let alias = self.try_alias()?;
306 let index_hint = self.parse_index_hint()?;
307 Ok(QualifiedTableRef {
308 name,
309 alias,
310 index_hint,
311 })
312 }
313
314 fn try_alias(&mut self) -> Result<Option<String>, ParseError> {
315 if self.eat_kw(&TokenKind::KwAs) {
316 return Ok(Some(self.parse_identifier()?));
317 }
318 match self.peek() {
321 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
322 return Ok(Some(self.parse_identifier()?));
323 }
324 k if is_nonreserved_kw(k) && !is_alias_terminator_kw(k) => {
325 return Ok(Some(self.parse_identifier()?));
326 }
327 _ => {}
328 }
329 Ok(None)
330 }
331
332 fn parse_index_hint(&mut self) -> Result<Option<IndexHint>, ParseError> {
333 if self.eat_kw(&TokenKind::KwIndexed) {
334 self.expect_kw(&TokenKind::KwBy)?;
335 Ok(Some(IndexHint::IndexedBy(self.parse_identifier()?)))
336 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwIndexed {
337 self.advance();
338 self.advance();
339 Ok(Some(IndexHint::NotIndexed))
340 } else {
341 Ok(None)
342 }
343 }
344
345 pub(crate) fn parse_comma_sep<T>(
346 &mut self,
347 f: fn(&mut Self) -> Result<T, ParseError>,
348 ) -> Result<Vec<T>, ParseError> {
349 let mut v = vec![f(self)?];
350 while self.eat(&TokenKind::Comma) {
351 v.push(f(self)?);
352 }
353 Ok(v)
354 }
355
356 fn parse_statement_inner(&mut self) -> Result<Statement, ParseError> {
361 match self.peek().clone() {
362 TokenKind::KwSelect | TokenKind::KwValues => {
363 Ok(Statement::Select(self.parse_select_stmt(None)?))
364 }
365 TokenKind::KwWith => self.parse_with_leading(),
366 TokenKind::KwInsert | TokenKind::KwReplace => self.parse_insert_stmt(None),
367 TokenKind::KwUpdate => self.parse_update_stmt(None),
368 TokenKind::KwDelete => self.parse_delete_stmt(None),
369 TokenKind::KwCreate => self.parse_create(),
370 TokenKind::KwDrop => self.parse_drop(),
371 TokenKind::KwAlter => self.parse_alter(),
372 TokenKind::KwBegin => self.parse_begin(),
373 TokenKind::KwCommit | TokenKind::KwEnd => {
374 self.advance();
375 let _ = self.eat_kw(&TokenKind::KwTransaction);
376 Ok(Statement::Commit)
377 }
378 TokenKind::KwRollback => self.parse_rollback(),
379 TokenKind::KwSavepoint => {
380 self.advance();
381 Ok(Statement::Savepoint(self.parse_identifier()?))
382 }
383 TokenKind::KwRelease => {
384 self.advance();
385 let _ = self.eat_kw(&TokenKind::KwSavepoint);
386 Ok(Statement::Release(self.parse_identifier()?))
387 }
388 TokenKind::KwAttach => self.parse_attach(),
389 TokenKind::KwDetach => {
390 self.advance();
391 let _ = self.eat_kw(&TokenKind::KwDatabase);
392 Ok(Statement::Detach(self.parse_identifier()?))
393 }
394 TokenKind::KwPragma => self.parse_pragma(),
395 TokenKind::KwVacuum => self.parse_vacuum(),
396 TokenKind::KwReindex => {
397 self.advance();
398 let name = if !self.at_eof() && !self.check(&TokenKind::Semicolon) {
399 Some(self.parse_qualified_name()?)
400 } else {
401 None
402 };
403 Ok(Statement::Reindex(name))
404 }
405 TokenKind::KwAnalyze => {
406 self.advance();
407 let name = if !self.at_eof() && !self.check(&TokenKind::Semicolon) {
408 Some(self.parse_qualified_name()?)
409 } else {
410 None
411 };
412 Ok(Statement::Analyze(name))
413 }
414 TokenKind::KwExplain => self.parse_explain(),
415 _ => Err(self.err_msg("unexpected token at start of statement")),
416 }
417 }
418
419 fn parse_with_leading(&mut self) -> Result<Statement, ParseError> {
424 let with = self.parse_with_clause()?;
425 match self.peek() {
426 TokenKind::KwSelect | TokenKind::KwValues => {
427 Ok(Statement::Select(self.parse_select_stmt(Some(with))?))
428 }
429 TokenKind::KwInsert | TokenKind::KwReplace => self.parse_insert_stmt(Some(with)),
430 TokenKind::KwUpdate => self.parse_update_stmt(Some(with)),
431 TokenKind::KwDelete => self.parse_delete_stmt(Some(with)),
432 _ => Err(self.err_expected("SELECT, INSERT, UPDATE, or DELETE after WITH")),
433 }
434 }
435
436 fn parse_with_clause(&mut self) -> Result<WithClause, ParseError> {
437 self.expect_kw(&TokenKind::KwWith)?;
438 let recursive = self.eat_kw(&TokenKind::KwRecursive);
439 let ctes = self.parse_comma_sep(Self::parse_cte)?;
440 Ok(WithClause { recursive, ctes })
441 }
442
443 fn parse_cte(&mut self) -> Result<Cte, ParseError> {
444 let name = self.parse_identifier()?;
445 let columns = if self.eat(&TokenKind::LeftParen) {
446 let cols = self.parse_comma_sep(Self::parse_identifier)?;
447 self.expect_token(&TokenKind::RightParen)?;
448 cols
449 } else {
450 vec![]
451 };
452 self.expect_kw(&TokenKind::KwAs)?;
454 let materialized = if self.check_kw(&TokenKind::KwNot) {
455 self.advance();
456 self.expect_kw(&TokenKind::KwMaterialized)?;
457 Some(CteMaterialized::NotMaterialized)
458 } else if self.eat_kw(&TokenKind::KwMaterialized) {
459 Some(CteMaterialized::Materialized)
460 } else {
461 None
462 };
463 self.expect_token(&TokenKind::LeftParen)?;
464 let query = self.parse_select_stmt(None)?;
465 self.expect_token(&TokenKind::RightParen)?;
466 Ok(Cte {
467 name,
468 columns,
469 materialized,
470 query,
471 })
472 }
473
474 pub(crate) fn parse_select_stmt(
479 &mut self,
480 with: Option<WithClause>,
481 ) -> Result<SelectStatement, ParseError> {
482 let body = self.parse_select_body()?;
483 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
484 self.expect_kw(&TokenKind::KwBy)?;
485 self.parse_comma_sep(Self::parse_ordering_term)?
486 } else {
487 vec![]
488 };
489 let limit = self.parse_limit()?;
490 Ok(SelectStatement {
491 with,
492 body,
493 order_by,
494 limit,
495 })
496 }
497
498 fn parse_select_body(&mut self) -> Result<SelectBody, ParseError> {
499 let select = self.parse_select_core()?;
500 let mut compounds = Vec::new();
501 loop {
502 let op = if self.eat_kw(&TokenKind::KwUnion) {
503 if self.eat_kw(&TokenKind::KwAll) {
504 CompoundOp::UnionAll
505 } else {
506 CompoundOp::Union
507 }
508 } else if self.eat_kw(&TokenKind::KwIntersect) {
509 CompoundOp::Intersect
510 } else if self.eat_kw(&TokenKind::KwExcept) {
511 CompoundOp::Except
512 } else {
513 break;
514 };
515 compounds.push((op, self.parse_select_core()?));
516 }
517 Ok(SelectBody { select, compounds })
518 }
519
520 fn parse_select_core(&mut self) -> Result<SelectCore, ParseError> {
521 if self.eat_kw(&TokenKind::KwValues) {
522 return self.parse_values_core();
523 }
524 self.expect_kw(&TokenKind::KwSelect)?;
525 let distinct = if self.eat_kw(&TokenKind::KwDistinct) {
526 Distinctness::Distinct
527 } else {
528 let _ = self.eat_kw(&TokenKind::KwAll);
529 Distinctness::All
530 };
531 let columns = self.parse_comma_sep(Self::parse_result_column)?;
532 let from = if self.eat_kw(&TokenKind::KwFrom) {
533 Some(self.parse_from_clause()?)
534 } else {
535 None
536 };
537 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
538 Some(Box::new(self.parse_expr()?))
539 } else {
540 None
541 };
542 let group_by = if self.eat_kw(&TokenKind::KwGroup) {
543 self.expect_kw(&TokenKind::KwBy)?;
544 self.parse_comma_sep(Self::parse_expr)?
545 } else {
546 vec![]
547 };
548 let having = if self.eat_kw(&TokenKind::KwHaving) {
549 Some(Box::new(self.parse_expr()?))
550 } else {
551 None
552 };
553 let windows = if self.eat_kw(&TokenKind::KwWindow) {
554 self.parse_comma_sep(Self::parse_window_def)?
555 } else {
556 vec![]
557 };
558 Ok(SelectCore::Select {
559 distinct,
560 columns,
561 from,
562 where_clause,
563 group_by,
564 having,
565 windows,
566 })
567 }
568
569 fn parse_values_core(&mut self) -> Result<SelectCore, ParseError> {
570 let mut rows = Vec::new();
571 loop {
572 self.expect_token(&TokenKind::LeftParen)?;
573 let row = self.parse_comma_sep(Self::parse_expr)?;
574 self.expect_token(&TokenKind::RightParen)?;
575 rows.push(row);
576 if !self.eat(&TokenKind::Comma) {
577 break;
578 }
579 }
580 Ok(SelectCore::Values(rows))
581 }
582
583 fn parse_result_column(&mut self) -> Result<ResultColumn, ParseError> {
584 if self.eat(&TokenKind::Star) {
585 return Ok(ResultColumn::Star);
586 }
587 if matches!(self.peek(), TokenKind::Id(_) | TokenKind::QuotedId(_, _))
589 && self.peek_nth(1) == &TokenKind::Dot
590 && self.peek_nth(2) == &TokenKind::Star
591 {
592 let tbl = self.parse_identifier()?;
593 self.advance(); self.advance(); return Ok(ResultColumn::TableStar(tbl));
596 }
597 let expr = self.parse_expr()?;
598 let alias = self.try_alias()?;
599 Ok(ResultColumn::Expr { expr, alias })
600 }
601
602 fn parse_from_clause(&mut self) -> Result<FromClause, ParseError> {
607 let source = self.parse_table_or_subquery()?;
608 let mut joins = Vec::new();
609 loop {
610 if let Some(jt) = self.try_join_type()? {
611 let table = self.parse_table_or_subquery()?;
612 let constraint = self.parse_join_constraint()?;
613 joins.push(JoinClause {
614 join_type: jt,
615 table,
616 constraint,
617 });
618 } else if self.eat(&TokenKind::Comma) {
619 let table = self.parse_table_or_subquery()?;
620 joins.push(JoinClause {
621 join_type: JoinType {
622 natural: false,
623 kind: JoinKind::Cross,
624 },
625 table,
626 constraint: None,
627 });
628 } else {
629 break;
630 }
631 }
632 Ok(FromClause { source, joins })
633 }
634
635 fn parse_table_or_subquery(&mut self) -> Result<TableOrSubquery, ParseError> {
636 if self.check(&TokenKind::LeftParen) {
637 self.advance();
638 if matches!(
639 self.peek(),
640 TokenKind::KwSelect | TokenKind::KwWith | TokenKind::KwValues
641 ) {
642 let q = self.parse_select_stmt(None)?;
643 self.expect_token(&TokenKind::RightParen)?;
644 let alias = self.try_alias()?;
645 return Ok(TableOrSubquery::Subquery {
646 query: Box::new(q),
647 alias,
648 });
649 }
650 let fc = self.parse_from_clause()?;
652 self.expect_token(&TokenKind::RightParen)?;
653 return Ok(TableOrSubquery::ParenJoin(Box::new(fc)));
654 }
655
656 let name = self.parse_qualified_name()?;
657
658 if self.check(&TokenKind::LeftParen) && name.schema.is_none() {
660 self.advance();
661 let args = if self.check(&TokenKind::RightParen) {
662 vec![]
663 } else {
664 self.parse_comma_sep(Self::parse_expr)?
665 };
666 self.expect_token(&TokenKind::RightParen)?;
667 let alias = self.try_alias()?;
668 return Ok(TableOrSubquery::TableFunction {
669 name: name.name,
670 args,
671 alias,
672 });
673 }
674
675 let alias = self.try_alias()?;
676 let index_hint = self.parse_index_hint()?;
677 Ok(TableOrSubquery::Table {
678 name,
679 alias,
680 index_hint,
681 })
682 }
683
684 fn try_join_type(&mut self) -> Result<Option<JoinType>, ParseError> {
685 let natural = self.eat_kw(&TokenKind::KwNatural);
686 let kind = if self.eat_kw(&TokenKind::KwJoin) {
687 Some(JoinKind::Inner)
688 } else if self.eat_kw(&TokenKind::KwInner) {
689 self.expect_kw(&TokenKind::KwJoin)?;
690 Some(JoinKind::Inner)
691 } else if self.eat_kw(&TokenKind::KwCross) {
692 self.expect_kw(&TokenKind::KwJoin)?;
693 Some(JoinKind::Cross)
694 } else if self.eat_kw(&TokenKind::KwLeft) {
695 let _ = self.eat_kw(&TokenKind::KwOuter);
696 self.expect_kw(&TokenKind::KwJoin)?;
697 Some(JoinKind::Left)
698 } else if self.eat_kw(&TokenKind::KwRight) {
699 let _ = self.eat_kw(&TokenKind::KwOuter);
700 self.expect_kw(&TokenKind::KwJoin)?;
701 Some(JoinKind::Right)
702 } else if self.eat_kw(&TokenKind::KwFull) {
703 let _ = self.eat_kw(&TokenKind::KwOuter);
704 self.expect_kw(&TokenKind::KwJoin)?;
705 Some(JoinKind::Full)
706 } else {
707 None
708 };
709 match kind {
710 Some(k) => Ok(Some(JoinType { natural, kind: k })),
711 None if natural => Err(self.err_expected("JOIN after NATURAL")),
712 None => Ok(None),
713 }
714 }
715
716 fn parse_join_constraint(&mut self) -> Result<Option<JoinConstraint>, ParseError> {
717 if self.eat_kw(&TokenKind::KwOn) {
718 Ok(Some(JoinConstraint::On(self.parse_expr()?)))
719 } else if self.eat_kw(&TokenKind::KwUsing) {
720 self.expect_token(&TokenKind::LeftParen)?;
721 let cols = self.parse_comma_sep(Self::parse_identifier)?;
722 self.expect_token(&TokenKind::RightParen)?;
723 Ok(Some(JoinConstraint::Using(cols)))
724 } else {
725 Ok(None)
726 }
727 }
728
729 pub(crate) fn parse_ordering_term(&mut self) -> Result<OrderingTerm, ParseError> {
734 let expr = self.parse_expr()?;
735 let direction = if self.eat_kw(&TokenKind::KwAsc) {
736 Some(SortDirection::Asc)
737 } else if self.eat_kw(&TokenKind::KwDesc) {
738 Some(SortDirection::Desc)
739 } else {
740 None
741 };
742 let nulls = if self.eat_kw(&TokenKind::KwNulls) {
743 if self.eat_kw(&TokenKind::KwFirst) {
744 Some(NullsOrder::First)
745 } else {
746 self.expect_kw(&TokenKind::KwLast)?;
747 Some(NullsOrder::Last)
748 }
749 } else {
750 None
751 };
752 Ok(OrderingTerm {
753 expr,
754 direction,
755 nulls,
756 })
757 }
758
759 pub(crate) fn parse_limit(&mut self) -> Result<Option<LimitClause>, ParseError> {
760 if !self.eat_kw(&TokenKind::KwLimit) {
761 return Ok(None);
762 }
763 let first = self.parse_expr()?;
764 if self.eat_kw(&TokenKind::KwOffset) {
765 return Ok(Some(LimitClause {
766 limit: first,
767 offset: Some(self.parse_expr()?),
768 }));
769 }
770
771 if self.eat(&TokenKind::Comma) {
772 let second = self.parse_expr()?;
774 return Ok(Some(LimitClause {
775 limit: second,
776 offset: Some(first),
777 }));
778 }
779
780 Ok(Some(LimitClause {
781 limit: first,
782 offset: None,
783 }))
784 }
785
786 fn parse_returning(&mut self) -> Result<Vec<ResultColumn>, ParseError> {
791 if self.eat_kw(&TokenKind::KwReturning) {
792 self.parse_comma_sep(Self::parse_result_column)
793 } else {
794 Ok(vec![])
795 }
796 }
797
798 fn parse_insert_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
803 let or_conflict = if self.eat_kw(&TokenKind::KwReplace) {
804 Some(ConflictAction::Replace)
805 } else {
806 self.expect_kw(&TokenKind::KwInsert)?;
807 if self.eat_kw(&TokenKind::KwOr) {
808 Some(self.parse_conflict_action()?)
809 } else {
810 None
811 }
812 };
813 self.expect_kw(&TokenKind::KwInto)?;
814 let table = self.parse_qualified_name()?;
815 let alias = if self.eat_kw(&TokenKind::KwAs) {
816 Some(self.parse_identifier()?)
817 } else {
818 None
819 };
820 let columns = if self.check(&TokenKind::LeftParen)
821 && !matches!(self.peek_nth(1), TokenKind::KwSelect | TokenKind::KwWith)
822 {
823 self.advance();
824 let cols = self.parse_comma_sep(Self::parse_identifier)?;
825 self.expect_token(&TokenKind::RightParen)?;
826 cols
827 } else {
828 vec![]
829 };
830 let source = if self.eat_kw(&TokenKind::KwDefault) {
831 self.expect_kw(&TokenKind::KwValues)?;
832 InsertSource::DefaultValues
833 } else if self.eat_kw(&TokenKind::KwValues) {
834 match self.parse_values_core()? {
835 SelectCore::Values(rows) => InsertSource::Values(rows),
836 SelectCore::Select { .. } => unreachable!("parse_values_core must return VALUES"),
837 }
838 } else {
839 InsertSource::Select(Box::new(self.parse_select_stmt(None)?))
840 };
841 let upsert = self.parse_upsert_clauses()?;
842 let returning = self.parse_returning()?;
843 Ok(Statement::Insert(InsertStatement {
844 with,
845 or_conflict,
846 table,
847 alias,
848 columns,
849 source,
850 upsert,
851 returning,
852 }))
853 }
854
855 fn parse_conflict_action(&mut self) -> Result<ConflictAction, ParseError> {
856 if self.eat_kw(&TokenKind::KwRollback) {
857 Ok(ConflictAction::Rollback)
858 } else if self.eat_kw(&TokenKind::KwAbort) {
859 Ok(ConflictAction::Abort)
860 } else if self.eat_kw(&TokenKind::KwFail) {
861 Ok(ConflictAction::Fail)
862 } else if self.eat_kw(&TokenKind::KwIgnore) {
863 Ok(ConflictAction::Ignore)
864 } else if self.eat_kw(&TokenKind::KwReplace) {
865 Ok(ConflictAction::Replace)
866 } else {
867 Err(self.err_expected("conflict action"))
868 }
869 }
870
871 fn parse_upsert_clauses(&mut self) -> Result<Vec<UpsertClause>, ParseError> {
872 let mut clauses = Vec::new();
873 while self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
874 self.advance(); self.advance(); let target = if self.check(&TokenKind::LeftParen) {
877 self.advance();
878 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
879 self.expect_token(&TokenKind::RightParen)?;
880 let wh = if self.eat_kw(&TokenKind::KwWhere) {
881 Some(self.parse_expr()?)
882 } else {
883 None
884 };
885 Some(UpsertTarget {
886 columns,
887 where_clause: wh,
888 })
889 } else {
890 None
891 };
892 self.expect_kw(&TokenKind::KwDo)?;
893 let action = if self.eat_kw(&TokenKind::KwNothing) {
894 UpsertAction::Nothing
895 } else {
896 self.expect_kw(&TokenKind::KwUpdate)?;
897 self.expect_kw(&TokenKind::KwSet)?;
898 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
899 let wh = if self.eat_kw(&TokenKind::KwWhere) {
900 Some(Box::new(self.parse_expr()?))
901 } else {
902 None
903 };
904 UpsertAction::Update {
905 assignments,
906 where_clause: wh,
907 }
908 };
909 clauses.push(UpsertClause { target, action });
910 }
911 Ok(clauses)
912 }
913
914 fn parse_update_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
919 self.expect_kw(&TokenKind::KwUpdate)?;
920 let or_conflict = if self.eat_kw(&TokenKind::KwOr) {
921 Some(self.parse_conflict_action()?)
922 } else {
923 None
924 };
925 let table = self.parse_qualified_table_ref()?;
926 self.expect_kw(&TokenKind::KwSet)?;
927 let assignments = self.parse_comma_sep(Self::parse_assignment)?;
928 let from = if self.eat_kw(&TokenKind::KwFrom) {
929 Some(self.parse_from_clause()?)
930 } else {
931 None
932 };
933 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
934 Some(self.parse_expr()?)
935 } else {
936 None
937 };
938 let returning = self.parse_returning()?;
939 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
940 self.expect_kw(&TokenKind::KwBy)?;
941 self.parse_comma_sep(Self::parse_ordering_term)?
942 } else {
943 vec![]
944 };
945 let limit = self.parse_limit()?;
946 Ok(Statement::Update(UpdateStatement {
947 with,
948 or_conflict,
949 table,
950 assignments,
951 from,
952 where_clause,
953 returning,
954 order_by,
955 limit,
956 }))
957 }
958
959 fn parse_assignment(&mut self) -> Result<Assignment, ParseError> {
960 let target = if self.check(&TokenKind::LeftParen) {
961 self.advance();
962 let cols = self.parse_comma_sep(Self::parse_identifier)?;
963 self.expect_token(&TokenKind::RightParen)?;
964 AssignmentTarget::ColumnList(cols)
965 } else {
966 AssignmentTarget::Column(self.parse_identifier()?)
967 };
968 self.expect_token(&TokenKind::Eq)?;
969 let value = self.parse_expr()?;
970 Ok(Assignment { target, value })
971 }
972
973 fn parse_delete_stmt(&mut self, with: Option<WithClause>) -> Result<Statement, ParseError> {
978 self.expect_kw(&TokenKind::KwDelete)?;
979 self.expect_kw(&TokenKind::KwFrom)?;
980 let table = self.parse_qualified_table_ref()?;
981 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
982 Some(self.parse_expr()?)
983 } else {
984 None
985 };
986 let returning = self.parse_returning()?;
987 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
988 self.expect_kw(&TokenKind::KwBy)?;
989 self.parse_comma_sep(Self::parse_ordering_term)?
990 } else {
991 vec![]
992 };
993 let limit = self.parse_limit()?;
994 Ok(Statement::Delete(DeleteStatement {
995 with,
996 table,
997 where_clause,
998 returning,
999 order_by,
1000 limit,
1001 }))
1002 }
1003
1004 fn parse_create(&mut self) -> Result<Statement, ParseError> {
1009 self.expect_kw(&TokenKind::KwCreate)?;
1010 let temporary = self.eat_kw(&TokenKind::KwTemp) || self.eat_kw(&TokenKind::KwTemporary);
1011 let unique = self.eat_kw(&TokenKind::KwUnique);
1012
1013 if self.eat_kw(&TokenKind::KwTable) {
1014 return self.parse_create_table(temporary);
1015 }
1016 if self.eat_kw(&TokenKind::KwIndex) {
1017 return self.parse_create_index(unique);
1018 }
1019 if self.eat_kw(&TokenKind::KwView) {
1020 return self.parse_create_view(temporary);
1021 }
1022 if self.eat_kw(&TokenKind::KwTrigger) {
1023 return self.parse_create_trigger(temporary);
1024 }
1025 if self.eat_kw(&TokenKind::KwVirtual) {
1026 self.expect_kw(&TokenKind::KwTable)?;
1027 return self.parse_create_virtual_table();
1028 }
1029 Err(self.err_expected("TABLE, INDEX, VIEW, TRIGGER, or VIRTUAL"))
1030 }
1031
1032 fn parse_if_not_exists(&mut self) -> bool {
1033 if self.check_kw(&TokenKind::KwIf)
1034 && self.peek_nth(1) == &TokenKind::KwNot
1035 && self.peek_nth(2) == &TokenKind::KwExists
1036 {
1037 self.advance();
1038 self.advance();
1039 self.advance();
1040 true
1041 } else {
1042 false
1043 }
1044 }
1045
1046 fn parse_create_table(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1047 let if_not_exists = self.parse_if_not_exists();
1048 let name = self.parse_qualified_name()?;
1049 let body = if self.eat_kw(&TokenKind::KwAs) {
1050 CreateTableBody::AsSelect(Box::new(self.parse_select_stmt(None)?))
1051 } else {
1052 self.expect_token(&TokenKind::LeftParen)?;
1053 let mut columns = Vec::new();
1054 let mut constraints = Vec::new();
1055 loop {
1056 if self.is_table_constraint_start() {
1057 constraints.push(self.parse_table_constraint()?);
1058 } else {
1059 columns.push(self.parse_column_def()?);
1060 }
1061 if !self.eat(&TokenKind::Comma) {
1062 break;
1063 }
1064 }
1065 self.expect_token(&TokenKind::RightParen)?;
1066 CreateTableBody::Columns {
1067 columns,
1068 constraints,
1069 }
1070 };
1071 let mut without_rowid = false;
1072 let mut strict = false;
1073 loop {
1075 if self.check_kw(&TokenKind::KwWithout) {
1076 self.advance();
1077 let id = self.parse_identifier()?;
1079 if !id.eq_ignore_ascii_case("ROWID") {
1080 return Err(self.err_expected("ROWID after WITHOUT"));
1081 }
1082 without_rowid = true;
1083 } else if self.eat_kw(&TokenKind::KwStrict) {
1084 strict = true;
1085 } else {
1086 break;
1087 }
1088 let _ = self.eat(&TokenKind::Comma);
1089 }
1090 Ok(Statement::CreateTable(CreateTableStatement {
1091 if_not_exists,
1092 temporary,
1093 name,
1094 body,
1095 without_rowid,
1096 strict,
1097 }))
1098 }
1099
1100 fn is_table_constraint_start(&self) -> bool {
1101 matches!(
1102 self.peek(),
1103 TokenKind::KwPrimary | TokenKind::KwUnique | TokenKind::KwCheck | TokenKind::KwForeign
1104 ) || (self.check_kw(&TokenKind::KwConstraint))
1105 }
1106
1107 fn parse_column_def(&mut self) -> Result<ColumnDef, ParseError> {
1108 let name = self.parse_identifier()?;
1109 let type_name = self.try_type_name()?;
1110 let mut constraints = Vec::new();
1111 while let Some(c) = self.try_column_constraint()? {
1112 constraints.push(c);
1113 }
1114 Ok(ColumnDef {
1115 name,
1116 type_name,
1117 constraints,
1118 })
1119 }
1120
1121 fn try_type_name(&mut self) -> Result<Option<TypeName>, ParseError> {
1122 if self.is_column_constraint_start()
1124 || matches!(
1125 self.peek(),
1126 TokenKind::Comma | TokenKind::RightParen | TokenKind::Eof
1127 )
1128 {
1129 return Ok(None);
1130 }
1131 let mut words = Vec::new();
1133 loop {
1134 match self.peek() {
1135 TokenKind::Id(_) | TokenKind::QuotedId(_, _) => {
1136 words.push(self.parse_identifier()?);
1137 }
1138 k if is_nonreserved_kw(k) => {
1139 words.push(self.parse_identifier()?);
1140 }
1141 _ => break,
1142 }
1143 if self.is_column_constraint_start()
1144 || matches!(
1145 self.peek(),
1146 TokenKind::Comma | TokenKind::RightParen | TokenKind::LeftParen
1147 )
1148 {
1149 break;
1150 }
1151 }
1152 if words.is_empty() {
1153 return Ok(None);
1154 }
1155 let type_name = words.join(" ");
1156 let (arg1, arg2) = if self.eat(&TokenKind::LeftParen) {
1157 let a1 = self.parse_signed_number_str()?;
1158 let a2 = if self.eat(&TokenKind::Comma) {
1159 Some(self.parse_signed_number_str()?)
1160 } else {
1161 None
1162 };
1163 self.expect_token(&TokenKind::RightParen)?;
1164 (Some(a1), a2)
1165 } else {
1166 (None, None)
1167 };
1168 Ok(Some(TypeName {
1169 name: type_name,
1170 arg1,
1171 arg2,
1172 }))
1173 }
1174
1175 fn parse_signed_number_str(&mut self) -> Result<String, ParseError> {
1176 let neg = self.eat(&TokenKind::Minus);
1177 let plus = if neg {
1178 false
1179 } else {
1180 self.eat(&TokenKind::Plus)
1181 };
1182 let _ = plus; match self.peek().clone() {
1184 TokenKind::Integer(n) => {
1185 self.advance();
1186 Ok(if neg { format!("-{n}") } else { n.to_string() })
1187 }
1188 TokenKind::Float(f) => {
1189 self.advance();
1190 Ok(if neg { format!("-{f}") } else { f.to_string() })
1191 }
1192 _ => Err(self.err_expected("number")),
1193 }
1194 }
1195
1196 fn is_column_constraint_start(&self) -> bool {
1197 matches!(
1198 self.peek(),
1199 TokenKind::KwPrimary
1200 | TokenKind::KwNot
1201 | TokenKind::KwUnique
1202 | TokenKind::KwCheck
1203 | TokenKind::KwDefault
1204 | TokenKind::KwCollate
1205 | TokenKind::KwReferences
1206 | TokenKind::KwGenerated
1207 | TokenKind::KwConstraint
1208 | TokenKind::KwAs
1209 )
1210 }
1211
1212 fn try_column_constraint(&mut self) -> Result<Option<ColumnConstraint>, ParseError> {
1213 let name = if self.eat_kw(&TokenKind::KwConstraint) {
1214 Some(self.parse_identifier()?)
1215 } else {
1216 None
1217 };
1218 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
1219 self.expect_kw(&TokenKind::KwKey)?;
1220 let direction = if self.eat_kw(&TokenKind::KwAsc) {
1221 Some(SortDirection::Asc)
1222 } else if self.eat_kw(&TokenKind::KwDesc) {
1223 Some(SortDirection::Desc)
1224 } else {
1225 None
1226 };
1227 let conflict = self.parse_on_conflict()?;
1228 let autoincrement = self.eat_kw(&TokenKind::KwAutoincrement);
1229 ColumnConstraintKind::PrimaryKey {
1230 direction,
1231 conflict,
1232 autoincrement,
1233 }
1234 } else if self.check_kw(&TokenKind::KwNot) && self.peek_nth(1) == &TokenKind::KwNull {
1235 self.advance();
1236 self.advance();
1237 let conflict = self.parse_on_conflict()?;
1238 ColumnConstraintKind::NotNull { conflict }
1239 } else if self.eat_kw(&TokenKind::KwUnique) {
1240 let conflict = self.parse_on_conflict()?;
1241 ColumnConstraintKind::Unique { conflict }
1242 } else if self.eat_kw(&TokenKind::KwCheck) {
1243 self.expect_token(&TokenKind::LeftParen)?;
1244 let expr = self.parse_expr()?;
1245 self.expect_token(&TokenKind::RightParen)?;
1246 ColumnConstraintKind::Check(expr)
1247 } else if self.eat_kw(&TokenKind::KwDefault) {
1248 if self.eat(&TokenKind::LeftParen) {
1249 let expr = self.parse_expr()?;
1250 self.expect_token(&TokenKind::RightParen)?;
1251 ColumnConstraintKind::Default(DefaultValue::ParenExpr(expr))
1252 } else {
1253 let expr = self.parse_expr()?;
1254 ColumnConstraintKind::Default(DefaultValue::Expr(expr))
1255 }
1256 } else if self.eat_kw(&TokenKind::KwCollate) {
1257 ColumnConstraintKind::Collate(self.parse_identifier()?)
1258 } else if self.eat_kw(&TokenKind::KwReferences) {
1259 ColumnConstraintKind::ForeignKey(self.parse_fk_clause()?)
1260 } else if self.eat_kw(&TokenKind::KwGenerated) || self.eat_kw(&TokenKind::KwAs) {
1261 if self.tokens[self.pos.saturating_sub(1)].kind == TokenKind::KwGenerated {
1262 let _ = self.eat_kw(&TokenKind::KwAlways);
1263 let _ = self.eat_kw(&TokenKind::KwAs);
1264 }
1265 self.expect_token(&TokenKind::LeftParen)?;
1266 let expr = self.parse_expr()?;
1267 self.expect_token(&TokenKind::RightParen)?;
1268 let storage = if self.eat_kw(&TokenKind::KwStored) {
1269 Some(GeneratedStorage::Stored)
1270 } else if self.eat_kw(&TokenKind::KwVirtual) {
1271 Some(GeneratedStorage::Virtual)
1272 } else {
1273 None
1274 };
1275 ColumnConstraintKind::Generated { expr, storage }
1276 } else if name.is_some() {
1277 return Err(self.err_expected("constraint kind after CONSTRAINT name"));
1278 } else {
1279 return Ok(None);
1280 };
1281 Ok(Some(ColumnConstraint { name, kind }))
1282 }
1283
1284 fn parse_on_conflict(&mut self) -> Result<Option<ConflictAction>, ParseError> {
1285 if self.check_kw(&TokenKind::KwOn) && self.peek_nth(1) == &TokenKind::KwConflict {
1286 self.advance();
1287 self.advance();
1288 Ok(Some(self.parse_conflict_action()?))
1289 } else {
1290 Ok(None)
1291 }
1292 }
1293
1294 fn parse_fk_clause(&mut self) -> Result<ForeignKeyClause, ParseError> {
1295 let table = self.parse_identifier()?;
1296 let columns = if self.eat(&TokenKind::LeftParen) {
1297 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1298 self.expect_token(&TokenKind::RightParen)?;
1299 cols
1300 } else {
1301 vec![]
1302 };
1303 let mut actions = Vec::new();
1304 let mut deferrable = None;
1305 loop {
1306 if self.check_kw(&TokenKind::KwOn) {
1307 self.advance();
1308 let trigger = if self.eat_kw(&TokenKind::KwDelete) {
1309 ForeignKeyTrigger::OnDelete
1310 } else {
1311 self.expect_kw(&TokenKind::KwUpdate)?;
1312 ForeignKeyTrigger::OnUpdate
1313 };
1314 let action = self.parse_fk_action_type()?;
1315 actions.push(ForeignKeyAction { trigger, action });
1316 } else if self.check_kw(&TokenKind::KwNot) || self.check_kw(&TokenKind::KwDeferrable) {
1317 let not = self.eat_kw(&TokenKind::KwNot);
1318 self.expect_kw(&TokenKind::KwDeferrable)?;
1319 let initially = if self.eat_kw(&TokenKind::KwInitially) {
1320 if self.eat_kw(&TokenKind::KwDeferred) {
1321 Some(DeferrableInitially::Deferred)
1322 } else {
1323 self.expect_kw(&TokenKind::KwImmediate)?;
1324 Some(DeferrableInitially::Immediate)
1325 }
1326 } else {
1327 None
1328 };
1329 deferrable = Some(Deferrable { not, initially });
1330 } else if self.eat_kw(&TokenKind::KwMatch) {
1331 self.parse_identifier()?;
1333 } else {
1334 break;
1335 }
1336 }
1337 Ok(ForeignKeyClause {
1338 table,
1339 columns,
1340 actions,
1341 deferrable,
1342 })
1343 }
1344
1345 fn parse_fk_action_type(&mut self) -> Result<ForeignKeyActionType, ParseError> {
1346 if self.eat_kw(&TokenKind::KwSet) {
1347 if self.eat_kw(&TokenKind::KwNull) {
1348 Ok(ForeignKeyActionType::SetNull)
1349 } else {
1350 self.expect_kw(&TokenKind::KwDefault)?;
1351 Ok(ForeignKeyActionType::SetDefault)
1352 }
1353 } else if self.eat_kw(&TokenKind::KwCascade) {
1354 Ok(ForeignKeyActionType::Cascade)
1355 } else if self.eat_kw(&TokenKind::KwRestrict) {
1356 Ok(ForeignKeyActionType::Restrict)
1357 } else if self.check_kw(&TokenKind::KwNo) {
1358 self.advance();
1359 let id = self.parse_identifier()?;
1360 if !id.eq_ignore_ascii_case("ACTION") {
1361 return Err(self.err_expected("ACTION after NO"));
1362 }
1363 Ok(ForeignKeyActionType::NoAction)
1364 } else {
1365 Err(self.err_expected("foreign key action"))
1366 }
1367 }
1368
1369 fn parse_table_constraint(&mut self) -> Result<TableConstraint, ParseError> {
1370 let name = if self.eat_kw(&TokenKind::KwConstraint) {
1371 Some(self.parse_identifier()?)
1372 } else {
1373 None
1374 };
1375 let kind = if self.eat_kw(&TokenKind::KwPrimary) {
1376 self.expect_kw(&TokenKind::KwKey)?;
1377 self.expect_token(&TokenKind::LeftParen)?;
1378 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1379 self.expect_token(&TokenKind::RightParen)?;
1380 let conflict = self.parse_on_conflict()?;
1381 TableConstraintKind::PrimaryKey { columns, conflict }
1382 } else if self.eat_kw(&TokenKind::KwUnique) {
1383 self.expect_token(&TokenKind::LeftParen)?;
1384 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1385 self.expect_token(&TokenKind::RightParen)?;
1386 let conflict = self.parse_on_conflict()?;
1387 TableConstraintKind::Unique { columns, conflict }
1388 } else if self.eat_kw(&TokenKind::KwCheck) {
1389 self.expect_token(&TokenKind::LeftParen)?;
1390 let expr = self.parse_expr()?;
1391 self.expect_token(&TokenKind::RightParen)?;
1392 TableConstraintKind::Check(expr)
1393 } else if self.eat_kw(&TokenKind::KwForeign) {
1394 self.expect_kw(&TokenKind::KwKey)?;
1395 self.expect_token(&TokenKind::LeftParen)?;
1396 let columns = self.parse_comma_sep(Self::parse_identifier)?;
1397 self.expect_token(&TokenKind::RightParen)?;
1398 self.expect_kw(&TokenKind::KwReferences)?;
1399 let clause = self.parse_fk_clause()?;
1400 TableConstraintKind::ForeignKey { columns, clause }
1401 } else {
1402 return Err(self.err_expected("table constraint"));
1403 };
1404 Ok(TableConstraint { name, kind })
1405 }
1406
1407 fn parse_indexed_column(&mut self) -> Result<IndexedColumn, ParseError> {
1408 let expr = self.parse_expr()?;
1409 let collation = if self.eat_kw(&TokenKind::KwCollate) {
1410 Some(self.parse_identifier()?)
1411 } else {
1412 None
1413 };
1414 let direction = if self.eat_kw(&TokenKind::KwAsc) {
1415 Some(SortDirection::Asc)
1416 } else if self.eat_kw(&TokenKind::KwDesc) {
1417 Some(SortDirection::Desc)
1418 } else {
1419 None
1420 };
1421 Ok(IndexedColumn {
1422 expr,
1423 collation,
1424 direction,
1425 })
1426 }
1427
1428 fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParseError> {
1429 let if_not_exists = self.parse_if_not_exists();
1430 let name = self.parse_qualified_name()?;
1431 self.expect_kw(&TokenKind::KwOn)?;
1432 let table = self.parse_identifier()?;
1433 self.expect_token(&TokenKind::LeftParen)?;
1434 let columns = self.parse_comma_sep(Self::parse_indexed_column)?;
1435 self.expect_token(&TokenKind::RightParen)?;
1436 let where_clause = if self.eat_kw(&TokenKind::KwWhere) {
1437 Some(self.parse_expr()?)
1438 } else {
1439 None
1440 };
1441 Ok(Statement::CreateIndex(CreateIndexStatement {
1442 unique,
1443 if_not_exists,
1444 name,
1445 table,
1446 columns,
1447 where_clause,
1448 }))
1449 }
1450
1451 fn parse_create_view(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1452 let if_not_exists = self.parse_if_not_exists();
1453 let name = self.parse_qualified_name()?;
1454 let columns = if self.check(&TokenKind::LeftParen) {
1455 self.advance();
1456 let cols = self.parse_comma_sep(Self::parse_identifier)?;
1457 self.expect_token(&TokenKind::RightParen)?;
1458 cols
1459 } else {
1460 vec![]
1461 };
1462 self.expect_kw(&TokenKind::KwAs)?;
1463 let query = self.parse_select_stmt(None)?;
1464 Ok(Statement::CreateView(CreateViewStatement {
1465 if_not_exists,
1466 temporary,
1467 name,
1468 columns,
1469 query,
1470 }))
1471 }
1472
1473 fn parse_create_trigger(&mut self, temporary: bool) -> Result<Statement, ParseError> {
1474 let if_not_exists = self.parse_if_not_exists();
1475 let name = self.parse_qualified_name()?;
1476 let timing = if self.eat_kw(&TokenKind::KwBefore) {
1477 TriggerTiming::Before
1478 } else if self.eat_kw(&TokenKind::KwAfter) {
1479 TriggerTiming::After
1480 } else if self.eat_kw(&TokenKind::KwInstead) {
1481 self.expect_kw(&TokenKind::KwOf)?;
1482 TriggerTiming::InsteadOf
1483 } else {
1484 TriggerTiming::Before };
1486 let event = if self.eat_kw(&TokenKind::KwInsert) {
1487 TriggerEvent::Insert
1488 } else if self.eat_kw(&TokenKind::KwDelete) {
1489 TriggerEvent::Delete
1490 } else {
1491 self.expect_kw(&TokenKind::KwUpdate)?;
1492 let cols = if self.eat_kw(&TokenKind::KwOf) {
1493 self.parse_comma_sep(Self::parse_identifier)?
1494 } else {
1495 vec![]
1496 };
1497 TriggerEvent::Update(cols)
1498 };
1499 self.expect_kw(&TokenKind::KwOn)?;
1500 let table = self.parse_identifier()?;
1501 let for_each_row = if self.eat_kw(&TokenKind::KwFor) {
1502 self.expect_kw(&TokenKind::KwEach)?;
1503 self.expect_kw(&TokenKind::KwRow)?;
1504 true
1505 } else {
1506 false
1507 };
1508 let when = if self.eat_kw(&TokenKind::KwWhen) {
1509 Some(self.parse_expr()?)
1510 } else {
1511 None
1512 };
1513 self.expect_kw(&TokenKind::KwBegin)?;
1514 let mut body = Vec::new();
1515 loop {
1516 if self.check_kw(&TokenKind::KwEnd) {
1517 break;
1518 }
1519 body.push(self.parse_statement_inner()?);
1520 let _ = self.eat(&TokenKind::Semicolon);
1521 }
1522 self.expect_kw(&TokenKind::KwEnd)?;
1523 Ok(Statement::CreateTrigger(CreateTriggerStatement {
1524 if_not_exists,
1525 temporary,
1526 name,
1527 timing,
1528 event,
1529 table,
1530 for_each_row,
1531 when,
1532 body,
1533 }))
1534 }
1535
1536 fn parse_create_virtual_table(&mut self) -> Result<Statement, ParseError> {
1537 let if_not_exists = self.parse_if_not_exists();
1538 let name = self.parse_qualified_name()?;
1539 self.expect_kw(&TokenKind::KwUsing)?;
1540 let module = self.parse_identifier()?;
1541 let args = if self.eat(&TokenKind::LeftParen) {
1542 if self.check(&TokenKind::RightParen) {
1543 self.advance();
1544 vec![]
1545 } else {
1546 let mut args = Vec::new();
1548 let mut depth = 0i32;
1549 let mut current_arg = String::new();
1550 loop {
1551 match self.peek() {
1552 TokenKind::RightParen if depth == 0 => {
1553 self.advance();
1554 args.push(current_arg.trim().to_owned());
1555 break;
1556 }
1557 TokenKind::LeftParen => {
1558 depth += 1;
1559 current_arg.push('(');
1560 self.advance();
1561 }
1562 TokenKind::RightParen => {
1563 depth -= 1;
1564 current_arg.push(')');
1565 self.advance();
1566 }
1567 TokenKind::Comma if depth == 0 => {
1568 args.push(current_arg.trim().to_owned());
1569 current_arg = String::new();
1570 self.advance();
1571 }
1572 TokenKind::Eof => {
1573 return Err(self.err_expected("closing parenthesis"));
1574 }
1575 _ => {
1576 let t = self.current().unwrap();
1578 let text = t.kind.to_sql();
1579 if !current_arg.is_empty()
1580 && !current_arg.ends_with(' ')
1581 && !text.is_empty()
1582 {
1583 current_arg.push(' ');
1584 }
1585 current_arg.push_str(&text);
1586 self.advance();
1587 }
1588 }
1589 }
1590 args
1591 }
1592 } else {
1593 vec![]
1594 };
1595 Ok(Statement::CreateVirtualTable(CreateVirtualTableStatement {
1596 if_not_exists,
1597 name,
1598 module,
1599 args,
1600 }))
1601 }
1602
1603 fn parse_drop(&mut self) -> Result<Statement, ParseError> {
1608 self.expect_kw(&TokenKind::KwDrop)?;
1609 let object_type = if self.eat_kw(&TokenKind::KwTable) {
1610 DropObjectType::Table
1611 } else if self.eat_kw(&TokenKind::KwView) {
1612 DropObjectType::View
1613 } else if self.eat_kw(&TokenKind::KwIndex) {
1614 DropObjectType::Index
1615 } else if self.eat_kw(&TokenKind::KwTrigger) {
1616 DropObjectType::Trigger
1617 } else {
1618 return Err(self.err_expected("TABLE, VIEW, INDEX, or TRIGGER"));
1619 };
1620 let if_exists =
1621 if self.check_kw(&TokenKind::KwIf) && self.peek_nth(1) == &TokenKind::KwExists {
1622 self.advance();
1623 self.advance();
1624 true
1625 } else {
1626 false
1627 };
1628 let name = self.parse_qualified_name()?;
1629 Ok(Statement::Drop(DropStatement {
1630 object_type,
1631 if_exists,
1632 name,
1633 }))
1634 }
1635
1636 fn parse_alter(&mut self) -> Result<Statement, ParseError> {
1641 self.expect_kw(&TokenKind::KwAlter)?;
1642 self.expect_kw(&TokenKind::KwTable)?;
1643 let table = self.parse_qualified_name()?;
1644 let action = if self.eat_kw(&TokenKind::KwRename) {
1645 if self.eat_kw(&TokenKind::KwTo) {
1646 AlterTableAction::RenameTo(self.parse_identifier()?)
1647 } else {
1648 let _ = self.eat_kw(&TokenKind::KwColumn);
1649 let old = self.parse_identifier()?;
1650 self.expect_kw(&TokenKind::KwTo)?;
1651 let new = self.parse_identifier()?;
1652 AlterTableAction::RenameColumn { old, new }
1653 }
1654 } else if self.eat_kw(&TokenKind::KwAdd) {
1655 let _ = self.eat_kw(&TokenKind::KwColumn);
1656 AlterTableAction::AddColumn(self.parse_column_def()?)
1657 } else if self.eat_kw(&TokenKind::KwDrop) {
1658 let _ = self.eat_kw(&TokenKind::KwColumn);
1659 AlterTableAction::DropColumn(self.parse_identifier()?)
1660 } else {
1661 return Err(self.err_expected("RENAME, ADD, or DROP"));
1662 };
1663 Ok(Statement::AlterTable(AlterTableStatement { table, action }))
1664 }
1665
1666 fn parse_begin(&mut self) -> Result<Statement, ParseError> {
1671 self.expect_kw(&TokenKind::KwBegin)?;
1672 let mode = if self.eat_kw(&TokenKind::KwDeferred) {
1673 Some(TransactionMode::Deferred)
1674 } else if self.eat_kw(&TokenKind::KwImmediate) {
1675 Some(TransactionMode::Immediate)
1676 } else if self.eat_kw(&TokenKind::KwExclusive) {
1677 Some(TransactionMode::Exclusive)
1678 } else if self.eat_kw(&TokenKind::KwConcurrent) {
1679 Some(TransactionMode::Concurrent)
1680 } else {
1681 None
1682 };
1683 let _ = self.eat_kw(&TokenKind::KwTransaction);
1685 Ok(Statement::Begin(BeginStatement { mode }))
1686 }
1687
1688 fn parse_rollback(&mut self) -> Result<Statement, ParseError> {
1689 self.expect_kw(&TokenKind::KwRollback)?;
1690 let _ = self.eat_kw(&TokenKind::KwTransaction);
1691 let to_savepoint = if self.eat_kw(&TokenKind::KwTo) {
1692 let _ = self.eat_kw(&TokenKind::KwSavepoint);
1693 Some(self.parse_identifier()?)
1694 } else {
1695 None
1696 };
1697 Ok(Statement::Rollback(RollbackStatement { to_savepoint }))
1698 }
1699
1700 fn parse_attach(&mut self) -> Result<Statement, ParseError> {
1705 self.expect_kw(&TokenKind::KwAttach)?;
1706 let _ = self.eat_kw(&TokenKind::KwDatabase);
1707 let expr = self.parse_expr()?;
1708 self.expect_kw(&TokenKind::KwAs)?;
1709 let schema = self.parse_identifier()?;
1710 Ok(Statement::Attach(AttachStatement { expr, schema }))
1711 }
1712
1713 fn parse_pragma_value_expr(&mut self) -> Result<Expr, ParseError> {
1714 if self.check_kw(&TokenKind::KwOn) {
1718 let sp = self.current_span();
1719 self.advance();
1720 return Ok(Expr::Literal(Literal::True, sp));
1721 }
1722 self.parse_expr()
1723 }
1724
1725 fn parse_pragma(&mut self) -> Result<Statement, ParseError> {
1726 self.expect_kw(&TokenKind::KwPragma)?;
1727 let name = self.parse_qualified_name()?;
1728 let value = if self.eat(&TokenKind::Eq) || self.eat(&TokenKind::EqEq) {
1729 Some(PragmaValue::Assign(self.parse_pragma_value_expr()?))
1730 } else if self.eat(&TokenKind::LeftParen) {
1731 let v = self.parse_pragma_value_expr()?;
1732 self.expect_token(&TokenKind::RightParen)?;
1733 Some(PragmaValue::Call(v))
1734 } else {
1735 None
1736 };
1737 Ok(Statement::Pragma(PragmaStatement { name, value }))
1738 }
1739
1740 fn parse_vacuum(&mut self) -> Result<Statement, ParseError> {
1741 self.expect_kw(&TokenKind::KwVacuum)?;
1742 let schema = if !self.at_eof()
1743 && !self.check(&TokenKind::Semicolon)
1744 && !self.check_kw(&TokenKind::KwInto)
1745 {
1746 Some(self.parse_identifier()?)
1747 } else {
1748 None
1749 };
1750 let into = if self.eat_kw(&TokenKind::KwInto) {
1751 Some(self.parse_expr()?)
1752 } else {
1753 None
1754 };
1755 Ok(Statement::Vacuum(VacuumStatement { schema, into }))
1756 }
1757
1758 fn parse_explain(&mut self) -> Result<Statement, ParseError> {
1759 self.expect_kw(&TokenKind::KwExplain)?;
1760 let query_plan = if self.eat_kw(&TokenKind::KwQuery) {
1761 self.expect_kw(&TokenKind::KwPlan)?;
1762 true
1763 } else {
1764 false
1765 };
1766 let stmt = self.parse_statement_inner()?;
1767 Ok(Statement::Explain {
1768 query_plan,
1769 stmt: Box::new(stmt),
1770 })
1771 }
1772
1773 fn parse_window_def(&mut self) -> Result<WindowDef, ParseError> {
1778 let name = self.parse_identifier()?;
1779 self.expect_kw(&TokenKind::KwAs)?;
1780 self.expect_token(&TokenKind::LeftParen)?;
1781 let spec = self.parse_window_spec()?;
1782 self.expect_token(&TokenKind::RightParen)?;
1783 Ok(WindowDef { name, spec })
1784 }
1785
1786 pub(crate) fn parse_window_spec(&mut self) -> Result<WindowSpec, ParseError> {
1787 let base_window = if matches!(self.peek(), TokenKind::Id(_))
1789 && !self.check_kw(&TokenKind::KwPartition)
1790 && !self.check_kw(&TokenKind::KwOrder)
1791 && !self.check_kw(&TokenKind::KwRange)
1792 && !self.check_kw(&TokenKind::KwRows)
1793 && !self.check_kw(&TokenKind::KwGroups)
1794 {
1795 Some(self.parse_identifier()?)
1796 } else {
1797 None
1798 };
1799 let partition_by = if self.eat_kw(&TokenKind::KwPartition) {
1800 self.expect_kw(&TokenKind::KwBy)?;
1801 self.parse_comma_sep(Self::parse_expr)?
1802 } else {
1803 vec![]
1804 };
1805 let order_by = if self.eat_kw(&TokenKind::KwOrder) {
1806 self.expect_kw(&TokenKind::KwBy)?;
1807 self.parse_comma_sep(Self::parse_ordering_term)?
1808 } else {
1809 vec![]
1810 };
1811 let frame = self.try_frame_spec()?;
1812 Ok(WindowSpec {
1813 base_window,
1814 partition_by,
1815 order_by,
1816 frame,
1817 })
1818 }
1819
1820 fn try_frame_spec(&mut self) -> Result<Option<FrameSpec>, ParseError> {
1821 let frame_type = if self.eat_kw(&TokenKind::KwRows) {
1822 FrameType::Rows
1823 } else if self.eat_kw(&TokenKind::KwRange) {
1824 FrameType::Range
1825 } else if self.eat_kw(&TokenKind::KwGroups) {
1826 FrameType::Groups
1827 } else {
1828 return Ok(None);
1829 };
1830 let (start, end) = if self.eat_kw(&TokenKind::KwBetween) {
1831 let s = self.parse_frame_bound()?;
1832 self.expect_kw(&TokenKind::KwAnd)?;
1833 let e = self.parse_frame_bound()?;
1834 (s, Some(e))
1835 } else {
1836 (self.parse_frame_bound()?, None)
1837 };
1838 let exclude = if self.eat_kw(&TokenKind::KwExclude) {
1839 if self.check_kw(&TokenKind::KwNo) {
1840 self.advance();
1841 let id = self.parse_identifier()?;
1843 if !id.eq_ignore_ascii_case("OTHERS") {
1844 return Err(self.err_expected("OTHERS"));
1845 }
1846 Some(FrameExclude::NoOthers)
1847 } else if self.check_kw(&TokenKind::KwOthers) {
1848 self.advance();
1849 Some(FrameExclude::NoOthers)
1850 } else if self.eat_kw(&TokenKind::KwTies) {
1851 Some(FrameExclude::Ties)
1852 } else if self.eat_kw(&TokenKind::KwGroup) {
1853 Some(FrameExclude::Group)
1854 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
1855 self.advance();
1856 self.expect_kw(&TokenKind::KwRow)?;
1857 Some(FrameExclude::CurrentRow)
1858 } else {
1859 return Err(self.err_expected("GROUP or CURRENT ROW after EXCLUDE"));
1860 }
1861 } else {
1862 None
1863 };
1864 Ok(Some(FrameSpec {
1865 frame_type,
1866 start,
1867 end,
1868 exclude,
1869 }))
1870 }
1871
1872 fn parse_frame_bound(&mut self) -> Result<FrameBound, ParseError> {
1873 if self.eat_kw(&TokenKind::KwUnbounded) {
1874 if self.eat_kw(&TokenKind::KwPreceding) {
1875 Ok(FrameBound::UnboundedPreceding)
1876 } else {
1877 self.expect_kw(&TokenKind::KwFollowing)?;
1878 Ok(FrameBound::UnboundedFollowing)
1879 }
1880 } else if matches!(self.peek(), TokenKind::Id(s) if s.eq_ignore_ascii_case("CURRENT")) {
1881 self.advance();
1882 self.expect_kw(&TokenKind::KwRow)?;
1883 Ok(FrameBound::CurrentRow)
1884 } else {
1885 let expr = self.parse_expr()?;
1886 if self.eat_kw(&TokenKind::KwPreceding) {
1887 Ok(FrameBound::Preceding(Box::new(expr)))
1888 } else {
1889 self.expect_kw(&TokenKind::KwFollowing)?;
1890 Ok(FrameBound::Following(Box::new(expr)))
1891 }
1892 }
1893 }
1894}
1895
1896pub(crate) fn is_nonreserved_kw(k: &TokenKind) -> bool {
1901 matches!(
1902 k,
1903 TokenKind::KwAbort
1904 | TokenKind::KwAction
1905 | TokenKind::KwAfter
1906 | TokenKind::KwAlways
1907 | TokenKind::KwAnalyze
1908 | TokenKind::KwAsc
1909 | TokenKind::KwBefore
1910 | TokenKind::KwCascade
1911 | TokenKind::KwColumn
1912 | TokenKind::KwConcurrent
1913 | TokenKind::KwConflict
1914 | TokenKind::KwDatabase
1915 | TokenKind::KwDeferred
1916 | TokenKind::KwDesc
1917 | TokenKind::KwDo
1918 | TokenKind::KwEach
1919 | TokenKind::KwEnd
1920 | TokenKind::KwExclude
1921 | TokenKind::KwExclusive
1922 | TokenKind::KwFail
1923 | TokenKind::KwFilter
1924 | TokenKind::KwFirst
1925 | TokenKind::KwFollowing
1926 | TokenKind::KwFull
1927 | TokenKind::KwGenerated
1928 | TokenKind::KwGroups
1929 | TokenKind::KwIf
1930 | TokenKind::KwIgnore
1931 | TokenKind::KwImmediate
1932 | TokenKind::KwIndex
1933 | TokenKind::KwInitially
1934 | TokenKind::KwInstead
1935 | TokenKind::KwKey
1936 | TokenKind::KwLast
1937 | TokenKind::KwMatch
1938 | TokenKind::KwMaterialized
1939 | TokenKind::KwNo
1940 | TokenKind::KwNothing
1941 | TokenKind::KwNulls
1942 | TokenKind::KwOf
1943 | TokenKind::KwOffset
1944 | TokenKind::KwOthers
1945 | TokenKind::KwOver
1946 | TokenKind::KwPartition
1947 | TokenKind::KwPlan
1948 | TokenKind::KwPragma
1949 | TokenKind::KwPreceding
1950 | TokenKind::KwQuery
1951 | TokenKind::KwRange
1952 | TokenKind::KwRecursive
1953 | TokenKind::KwReindex
1954 | TokenKind::KwRelease
1955 | TokenKind::KwRename
1956 | TokenKind::KwReplace
1957 | TokenKind::KwRestrict
1958 | TokenKind::KwReturning
1959 | TokenKind::KwRow
1960 | TokenKind::KwRows
1961 | TokenKind::KwSavepoint
1962 | TokenKind::KwStored
1963 | TokenKind::KwStrict
1964 | TokenKind::KwTable
1965 | TokenKind::KwTemp
1966 | TokenKind::KwTemporary
1967 | TokenKind::KwTies
1968 | TokenKind::KwTransaction
1969 | TokenKind::KwTrigger
1970 | TokenKind::KwUnbounded
1971 | TokenKind::KwVacuum
1972 | TokenKind::KwView
1973 | TokenKind::KwVirtual
1974 | TokenKind::KwWindow
1975 | TokenKind::KwWithout
1976 )
1977}
1978
1979fn is_alias_terminator_kw(k: &TokenKind) -> bool {
1982 matches!(
1983 k,
1984 TokenKind::KwCross
1985 | TokenKind::KwExcept
1986 | TokenKind::KwFull
1987 | TokenKind::KwGroup
1988 | TokenKind::KwHaving
1989 | TokenKind::KwInner
1990 | TokenKind::KwIntersect
1991 | TokenKind::KwJoin
1992 | TokenKind::KwLeft
1993 | TokenKind::KwLimit
1994 | TokenKind::KwNatural
1995 | TokenKind::KwOffset
1996 | TokenKind::KwOn
1997 | TokenKind::KwOrder
1998 | TokenKind::KwOuter
1999 | TokenKind::KwReturning
2000 | TokenKind::KwRight
2001 | TokenKind::KwUnion
2002 | TokenKind::KwUsing
2003 | TokenKind::KwWhere
2004 | TokenKind::KwWindow
2005 | TokenKind::KwWindow
2006 )
2007}
2008
2009pub(crate) fn kw_to_str(k: &TokenKind) -> String {
2010 let dbg = format!("{k:?}");
2011 dbg.strip_prefix("Kw").unwrap_or(&dbg).to_ascii_lowercase()
2012}
2013
2014#[cfg(test)]
2019mod tests {
2020 use super::*;
2021
2022 fn parse_ok(sql: &str) -> Vec<Statement> {
2023 let mut p = Parser::from_sql(sql);
2024 let (stmts, errs) = p.parse_all();
2025 assert!(errs.is_empty(), "unexpected errors: {errs:?}");
2026 stmts
2027 }
2028
2029 fn parse_one(sql: &str) -> Statement {
2030 let stmts = parse_ok(sql);
2031 assert_eq!(stmts.len(), 1, "expected 1 statement, got {}", stmts.len());
2032 stmts.into_iter().next().unwrap()
2033 }
2034
2035 #[test]
2036 fn select_literal() {
2037 let stmt = parse_one("SELECT 1");
2038 assert!(matches!(stmt, Statement::Select(_)));
2039 }
2040
2041 #[test]
2042 fn select_star_from() {
2043 let stmt = parse_one("SELECT * FROM t");
2044 if let Statement::Select(s) = stmt {
2045 if let SelectCore::Select { columns, from, .. } = &s.body.select {
2046 assert!(matches!(columns[0], ResultColumn::Star));
2047 assert!(from.is_some());
2048 } else {
2049 unreachable!("expected Select core");
2050 }
2051 } else {
2052 unreachable!("expected Select");
2053 }
2054 }
2055
2056 #[test]
2057 fn select_where_order_limit() {
2058 let stmt = parse_one("SELECT a FROM t WHERE a > 1 ORDER BY a LIMIT 10 OFFSET 5");
2059 if let Statement::Select(s) = stmt {
2060 assert!(s.limit.is_some());
2061 assert_eq!(s.order_by.len(), 1);
2062 } else {
2063 unreachable!("expected Select");
2064 }
2065 }
2066
2067 #[test]
2068 fn select_limit_comma_syntax_uses_offset_then_count() {
2069 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
2070 if let Statement::Select(s) = stmt {
2071 let limit = s.limit.expect("LIMIT clause");
2072 assert!(matches!(
2073 limit.limit,
2074 Expr::Literal(Literal::Integer(10), _)
2075 ));
2076 assert!(matches!(
2077 limit.offset,
2078 Some(Expr::Literal(Literal::Integer(5), _))
2079 ));
2080 } else {
2081 unreachable!("expected Select");
2082 }
2083 }
2084
2085 #[test]
2086 fn select_order_by_nulls_first_last() {
2087 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST, b DESC NULLS LAST");
2088 if let Statement::Select(s) = stmt {
2089 assert_eq!(s.order_by.len(), 2);
2090 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
2091 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
2092 assert_eq!(s.order_by[1].direction, Some(SortDirection::Desc));
2093 assert_eq!(s.order_by[1].nulls, Some(NullsOrder::Last));
2094 } else {
2095 unreachable!("expected Select");
2096 }
2097 }
2098
2099 #[test]
2100 fn select_from_indexed_by_hint() {
2101 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
2102 if let Statement::Select(s) = stmt {
2103 if let SelectCore::Select { from, .. } = &s.body.select {
2104 let from = from.as_ref().expect("FROM clause");
2105 match &from.source {
2106 TableOrSubquery::Table {
2107 index_hint: Some(IndexHint::IndexedBy(name)),
2108 ..
2109 } => assert_eq!(name, "idx_t"),
2110 other => unreachable!("expected indexed table source, got {other:?}"),
2111 }
2112 } else {
2113 unreachable!("expected Select core");
2114 }
2115 } else {
2116 unreachable!("expected Select");
2117 }
2118 }
2119
2120 #[test]
2121 fn select_from_not_indexed_hint() {
2122 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
2123 if let Statement::Select(s) = stmt {
2124 if let SelectCore::Select { from, .. } = &s.body.select {
2125 let from = from.as_ref().expect("FROM clause");
2126 match &from.source {
2127 TableOrSubquery::Table {
2128 index_hint: Some(IndexHint::NotIndexed),
2129 ..
2130 } => {}
2131 other => unreachable!("expected not-indexed table source, got {other:?}"),
2132 }
2133 } else {
2134 unreachable!("expected Select core");
2135 }
2136 } else {
2137 unreachable!("expected Select");
2138 }
2139 }
2140
2141 #[test]
2142 fn select_from_table_valued_function() {
2143 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
2144 if let Statement::Select(s) = stmt {
2145 if let SelectCore::Select { from, .. } = &s.body.select {
2146 let from = from.as_ref().expect("FROM clause");
2147 match &from.source {
2148 TableOrSubquery::TableFunction { name, args, alias } => {
2149 assert_eq!(name, "generate_series");
2150 assert_eq!(args.len(), 2);
2151 assert_eq!(alias.as_deref(), Some("gs"));
2152 }
2153 other => unreachable!("expected table-valued function source, got {other:?}"),
2154 }
2155 } else {
2156 unreachable!("expected Select core");
2157 }
2158 } else {
2159 unreachable!("expected Select");
2160 }
2161 }
2162
2163 #[test]
2164 fn select_window_function_over_clause() {
2165 let stmt = parse_one(
2166 "SELECT sum(x) OVER (PARTITION BY y ORDER BY z \
2167 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
2168 );
2169 if let Statement::Select(s) = stmt {
2170 if let SelectCore::Select { columns, .. } = &s.body.select {
2171 match &columns[0] {
2172 ResultColumn::Expr {
2173 expr:
2174 Expr::FunctionCall {
2175 over: Some(over), ..
2176 },
2177 ..
2178 } => {
2179 assert_eq!(over.partition_by.len(), 1);
2180 assert_eq!(over.order_by.len(), 1);
2181 assert!(matches!(
2182 over.frame,
2183 Some(FrameSpec {
2184 frame_type: FrameType::Rows,
2185 ..
2186 })
2187 ));
2188 }
2189 other => unreachable!("expected window function result column, got {other:?}"),
2190 }
2191 } else {
2192 unreachable!("expected Select core");
2193 }
2194 } else {
2195 unreachable!("expected Select");
2196 }
2197 }
2198
2199 #[test]
2200 fn select_named_window_definition_and_reference() {
2201 let stmt = parse_one(
2202 "SELECT sum(x) OVER win FROM t \
2203 WINDOW win AS (PARTITION BY y ORDER BY z)",
2204 );
2205 if let Statement::Select(s) = stmt {
2206 if let SelectCore::Select {
2207 columns, windows, ..
2208 } = &s.body.select
2209 {
2210 assert_eq!(windows.len(), 1);
2211 assert_eq!(windows[0].name, "win");
2212 assert_eq!(windows[0].spec.partition_by.len(), 1);
2213 assert_eq!(windows[0].spec.order_by.len(), 1);
2214 match &columns[0] {
2215 ResultColumn::Expr {
2216 expr:
2217 Expr::FunctionCall {
2218 over: Some(over), ..
2219 },
2220 ..
2221 } => assert_eq!(over.base_window.as_deref(), Some("win")),
2222 other => unreachable!("expected named window function, got {other:?}"),
2223 }
2224 } else {
2225 unreachable!("expected Select core");
2226 }
2227 } else {
2228 unreachable!("expected Select");
2229 }
2230 }
2231
2232 #[test]
2233 fn insert_values() {
2234 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2), (3, 4)");
2235 assert!(matches!(stmt, Statement::Insert(_)));
2236 }
2237
2238 #[test]
2239 fn update_set() {
2240 let stmt = parse_one("UPDATE t SET a = 1, b = 2 WHERE id = 3");
2241 assert!(matches!(stmt, Statement::Update(_)));
2242 }
2243
2244 #[test]
2245 fn delete_from() {
2246 let stmt = parse_one("DELETE FROM t WHERE id = 1");
2247 assert!(matches!(stmt, Statement::Delete(_)));
2248 }
2249
2250 #[test]
2251 fn create_table_basic() {
2252 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT NOT NULL)");
2253 if let Statement::CreateTable(ct) = stmt {
2254 assert_eq!(ct.name.name, "t");
2255 if let CreateTableBody::Columns { columns, .. } = ct.body {
2256 assert_eq!(columns.len(), 2);
2257 } else {
2258 unreachable!("expected column defs");
2259 }
2260 } else {
2261 unreachable!("expected CreateTable");
2262 }
2263 }
2264
2265 #[test]
2266 fn create_index() {
2267 let stmt = parse_one("CREATE UNIQUE INDEX idx ON t (a, b DESC)");
2268 if let Statement::CreateIndex(ci) = stmt {
2269 assert!(ci.unique);
2270 assert_eq!(ci.columns.len(), 2);
2271 } else {
2272 unreachable!("expected CreateIndex");
2273 }
2274 }
2275
2276 #[test]
2277 fn drop_table_if_exists() {
2278 let stmt = parse_one("DROP TABLE IF EXISTS t");
2279 if let Statement::Drop(d) = stmt {
2280 assert!(d.if_exists);
2281 assert_eq!(d.object_type, DropObjectType::Table);
2282 } else {
2283 unreachable!("expected Drop");
2284 }
2285 }
2286
2287 #[test]
2288 fn begin_commit() {
2289 let stmts = parse_ok("BEGIN IMMEDIATE; COMMIT");
2290 assert_eq!(stmts.len(), 2);
2291 if let Statement::Begin(b) = &stmts[0] {
2292 assert_eq!(b.mode, Some(TransactionMode::Immediate));
2293 } else {
2294 unreachable!("expected Begin");
2295 }
2296 assert!(matches!(stmts[1], Statement::Commit));
2297 }
2298
2299 #[test]
2300 fn begin_concurrent() {
2301 let stmt = parse_one("BEGIN CONCURRENT");
2302 if let Statement::Begin(b) = stmt {
2303 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
2304 } else {
2305 unreachable!("expected Begin");
2306 }
2307 }
2308
2309 #[test]
2310 fn rollback_to_savepoint() {
2311 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
2312 if let Statement::Rollback(r) = stmt {
2313 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
2314 } else {
2315 unreachable!("expected Rollback");
2316 }
2317 }
2318
2319 #[test]
2320 fn explain_query_plan() {
2321 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT 1");
2322 assert!(matches!(
2323 stmt,
2324 Statement::Explain {
2325 query_plan: true,
2326 ..
2327 }
2328 ));
2329 }
2330
2331 #[test]
2332 fn pragma() {
2333 let stmt = parse_one("PRAGMA journal_mode = WAL");
2334 assert!(matches!(stmt, Statement::Pragma(_)));
2335 }
2336
2337 #[test]
2338 fn pragma_allows_on_value() {
2339 let stmt = parse_one("PRAGMA fsqlite.serializable = ON");
2340 assert!(matches!(stmt, Statement::Pragma(_)));
2341 }
2342
2343 #[test]
2344 fn error_recovery_multiple_statements() {
2345 let mut p = Parser::from_sql("SELECT 1; XYZZY; SELECT 2");
2346 let (stmts, errs) = p.parse_all();
2347 assert_eq!(stmts.len(), 2, "should recover: stmts={stmts:?}");
2348 assert!(!errs.is_empty());
2349 }
2350
2351 #[test]
2352 fn compound_union() {
2353 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
2354 if let Statement::Select(s) = stmt {
2355 assert_eq!(s.body.compounds.len(), 1);
2356 } else {
2357 unreachable!("expected Select");
2358 }
2359 }
2360
2361 #[test]
2362 fn alter_table_rename() {
2363 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
2364 assert!(matches!(
2365 stmt,
2366 Statement::AlterTable(AlterTableStatement {
2367 action: AlterTableAction::RenameTo(_),
2368 ..
2369 })
2370 ));
2371 }
2372
2373 #[test]
2378 fn test_parser_join_inner() {
2379 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
2380 if let Statement::Select(s) = stmt {
2381 if let SelectCore::Select { from, .. } = &s.body.select {
2382 let from = from.as_ref().expect("FROM clause");
2383 assert!(!from.joins.is_empty());
2384 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
2385 } else {
2386 unreachable!("expected Select core");
2387 }
2388 } else {
2389 unreachable!("expected Select");
2390 }
2391 }
2392
2393 #[test]
2394 fn test_parser_join_left() {
2395 let stmt = parse_one("SELECT * FROM a LEFT JOIN b ON a.id = b.a_id");
2396 if let Statement::Select(s) = stmt {
2397 if let SelectCore::Select { from, .. } = &s.body.select {
2398 let from = from.as_ref().expect("FROM clause");
2399 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
2400 } else {
2401 unreachable!("expected Select core");
2402 }
2403 } else {
2404 unreachable!("expected Select");
2405 }
2406 }
2407
2408 #[test]
2409 fn test_parser_join_left_outer() {
2410 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
2411 if let Statement::Select(s) = stmt {
2412 if let SelectCore::Select { from, .. } = &s.body.select {
2413 let from = from.as_ref().expect("FROM clause");
2414 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
2415 } else {
2416 unreachable!("expected Select core");
2417 }
2418 } else {
2419 unreachable!("expected Select");
2420 }
2421 }
2422
2423 #[test]
2424 fn test_parser_join_right() {
2425 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
2426 if let Statement::Select(s) = stmt {
2427 if let SelectCore::Select { from, .. } = &s.body.select {
2428 let from = from.as_ref().expect("FROM clause");
2429 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
2430 } else {
2431 unreachable!("expected Select core");
2432 }
2433 } else {
2434 unreachable!("expected Select");
2435 }
2436 }
2437
2438 #[test]
2439 fn test_parser_join_full() {
2440 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
2441 if let Statement::Select(s) = stmt {
2442 if let SelectCore::Select { from, .. } = &s.body.select {
2443 let from = from.as_ref().expect("FROM clause");
2444 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
2445 } else {
2446 unreachable!("expected Select core");
2447 }
2448 } else {
2449 unreachable!("expected Select");
2450 }
2451 }
2452
2453 #[test]
2454 fn test_parser_join_full_outer_with_semicolon() {
2455 let stmt = parse_one("SELECT l.name, r.tag FROM l FULL OUTER JOIN r ON l.id = r.l_id;");
2456 if let Statement::Select(s) = stmt {
2457 if let SelectCore::Select { from, .. } = &s.body.select {
2458 let from = from.as_ref().expect("FROM clause");
2459 assert_eq!(from.joins.len(), 1);
2460 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
2461 } else {
2462 unreachable!("expected Select core");
2463 }
2464 } else {
2465 unreachable!("expected Select");
2466 }
2467 }
2468
2469 #[test]
2470 fn test_parser_join_cross() {
2471 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
2472 if let Statement::Select(s) = stmt {
2473 if let SelectCore::Select { from, .. } = &s.body.select {
2474 let from = from.as_ref().expect("FROM clause");
2475 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
2476 } else {
2477 unreachable!("expected Select core");
2478 }
2479 } else {
2480 unreachable!("expected Select");
2481 }
2482 }
2483
2484 #[test]
2485 fn test_parser_join_natural() {
2486 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
2487 if let Statement::Select(s) = stmt {
2488 if let SelectCore::Select { from, .. } = &s.body.select {
2489 let from = from.as_ref().expect("FROM clause");
2490 assert!(from.joins[0].join_type.natural);
2491 } else {
2492 unreachable!("expected Select core");
2493 }
2494 } else {
2495 unreachable!("expected Select");
2496 }
2497 }
2498
2499 #[test]
2500 fn test_parser_join_using() {
2501 let stmt = parse_one("SELECT * FROM a JOIN b USING (id)");
2502 if let Statement::Select(s) = stmt {
2503 if let SelectCore::Select { from, .. } = &s.body.select {
2504 let from = from.as_ref().expect("FROM clause");
2505 assert!(matches!(
2506 from.joins[0].constraint,
2507 Some(JoinConstraint::Using(_))
2508 ));
2509 } else {
2510 unreachable!("expected Select core");
2511 }
2512 } else {
2513 unreachable!("expected Select");
2514 }
2515 }
2516
2517 #[test]
2518 fn test_parser_join_comma() {
2519 let stmt = parse_one("SELECT * FROM a, b WHERE a.id = b.a_id");
2521 if let Statement::Select(s) = stmt {
2522 if let SelectCore::Select { from, .. } = &s.body.select {
2523 let from = from.as_ref().expect("FROM clause");
2524 assert!(!from.joins.is_empty());
2525 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
2526 } else {
2527 unreachable!("expected Select core");
2528 }
2529 } else {
2530 unreachable!("expected Select");
2531 }
2532 }
2533
2534 #[test]
2539 fn test_parser_cte_basic() {
2540 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
2541 if let Statement::Select(s) = stmt {
2542 let with = s.with.as_ref().expect("WITH clause");
2543 assert!(!with.recursive);
2544 assert_eq!(with.ctes.len(), 1);
2545 assert_eq!(with.ctes[0].name, "cte");
2546 } else {
2547 unreachable!("expected Select");
2548 }
2549 }
2550
2551 #[test]
2552 fn test_parser_cte_multiple() {
2553 let stmt = parse_one("WITH a AS (SELECT 1), b AS (SELECT 2) SELECT * FROM a, b");
2554 if let Statement::Select(s) = stmt {
2555 let with = s.with.as_ref().expect("WITH clause");
2556 assert_eq!(with.ctes.len(), 2);
2557 assert_eq!(with.ctes[0].name, "a");
2558 assert_eq!(with.ctes[1].name, "b");
2559 } else {
2560 unreachable!("expected Select");
2561 }
2562 }
2563
2564 #[test]
2565 fn test_parser_cte_recursive() {
2566 let stmt = parse_one(
2567 "WITH RECURSIVE cnt(x) AS (\
2568 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
2569 ) SELECT x FROM cnt",
2570 );
2571 if let Statement::Select(s) = stmt {
2572 let with = s.with.as_ref().expect("WITH clause");
2573 assert!(with.recursive);
2574 assert_eq!(with.ctes[0].name, "cnt");
2575 assert_eq!(with.ctes[0].columns, vec!["x".to_owned()]);
2576 } else {
2577 unreachable!("expected Select");
2578 }
2579 }
2580
2581 #[test]
2582 fn test_parser_cte_materialized() {
2583 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
2584 if let Statement::Select(s) = stmt {
2585 let with = s.with.as_ref().expect("WITH clause");
2586 assert_eq!(
2587 with.ctes[0].materialized,
2588 Some(CteMaterialized::Materialized)
2589 );
2590 } else {
2591 unreachable!("expected Select");
2592 }
2593 }
2594
2595 #[test]
2600 fn test_select_table_star() {
2601 let stmt = parse_one("SELECT t1.* FROM t1, t2");
2602 if let Statement::Select(s) = stmt {
2603 if let SelectCore::Select { columns, .. } = &s.body.select {
2604 assert!(
2605 matches!(&columns[0], ResultColumn::TableStar(t) if t == "t1"),
2606 "expected TableStar(t1), got {:?}",
2607 columns[0]
2608 );
2609 } else {
2610 unreachable!("expected Select core");
2611 }
2612 } else {
2613 unreachable!("expected Select");
2614 }
2615 }
2616
2617 #[test]
2618 fn test_select_expr_alias() {
2619 let stmt = parse_one("SELECT x + 1 AS result FROM t");
2620 if let Statement::Select(s) = stmt {
2621 if let SelectCore::Select { columns, .. } = &s.body.select {
2622 match &columns[0] {
2623 ResultColumn::Expr {
2624 alias: Some(alias), ..
2625 } => assert_eq!(alias, "result"),
2626 other => unreachable!("expected aliased expr column, got {other:?}"),
2627 }
2628 } else {
2629 unreachable!("expected Select core");
2630 }
2631 } else {
2632 unreachable!("expected Select");
2633 }
2634 }
2635
2636 #[test]
2637 fn test_select_distinct_keyword() {
2638 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
2639 if let Statement::Select(s) = stmt {
2640 if let SelectCore::Select {
2641 distinct, columns, ..
2642 } = &s.body.select
2643 {
2644 assert_eq!(*distinct, Distinctness::Distinct);
2645 assert_eq!(columns.len(), 2);
2646 } else {
2647 unreachable!("expected Select core");
2648 }
2649 } else {
2650 unreachable!("expected Select");
2651 }
2652 }
2653
2654 #[test]
2655 fn test_select_values_clause() {
2656 let stmt = parse_one("VALUES (1, 2), (3, 4)");
2657 if let Statement::Select(s) = stmt {
2658 if let SelectCore::Values(rows) = &s.body.select {
2659 assert_eq!(rows.len(), 2);
2660 assert_eq!(rows[0].len(), 2);
2661 assert_eq!(rows[1].len(), 2);
2662 } else {
2663 unreachable!("expected Values core");
2664 }
2665 } else {
2666 unreachable!("expected Select");
2667 }
2668 }
2669
2670 #[test]
2671 fn test_select_group_by_having() {
2672 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
2673 if let Statement::Select(s) = stmt {
2674 if let SelectCore::Select {
2675 group_by, having, ..
2676 } = &s.body.select
2677 {
2678 assert_eq!(group_by.len(), 1);
2679 assert!(having.is_some(), "HAVING clause must be present");
2680 } else {
2681 unreachable!("expected Select core");
2682 }
2683 } else {
2684 unreachable!("expected Select");
2685 }
2686 }
2687
2688 #[test]
2689 fn test_compound_union() {
2690 let stmt = parse_one("SELECT 1 UNION SELECT 2");
2691 if let Statement::Select(s) = stmt {
2692 assert_eq!(s.body.compounds.len(), 1);
2693 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
2694 } else {
2695 unreachable!("expected Select");
2696 }
2697 }
2698
2699 #[test]
2700 fn test_compound_union_all() {
2701 let stmt = parse_one("SELECT 1 UNION ALL SELECT 2");
2702 if let Statement::Select(s) = stmt {
2703 assert_eq!(s.body.compounds.len(), 1);
2704 assert_eq!(s.body.compounds[0].0, CompoundOp::UnionAll);
2705 } else {
2706 unreachable!("expected Select");
2707 }
2708 }
2709
2710 #[test]
2711 fn test_compound_intersect() {
2712 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
2713 if let Statement::Select(s) = stmt {
2714 assert_eq!(s.body.compounds.len(), 1);
2715 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
2716 } else {
2717 unreachable!("expected Select");
2718 }
2719 }
2720
2721 #[test]
2722 fn test_compound_except() {
2723 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
2724 if let Statement::Select(s) = stmt {
2725 assert_eq!(s.body.compounds.len(), 1);
2726 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
2727 } else {
2728 unreachable!("expected Select");
2729 }
2730 }
2731
2732 #[test]
2733 fn test_compound_order_applies_to_whole() {
2734 let stmt = parse_one("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
2736 if let Statement::Select(s) = stmt {
2737 assert_eq!(s.body.compounds.len(), 1);
2738 assert_eq!(s.order_by.len(), 1, "ORDER BY must be on compound");
2739 assert!(s.limit.is_some(), "LIMIT must be on compound");
2740 } else {
2741 unreachable!("expected Select");
2742 }
2743 }
2744
2745 #[test]
2746 fn test_compound_three_way() {
2747 let stmt = parse_one("SELECT 1 UNION SELECT 2 INTERSECT SELECT 3");
2748 if let Statement::Select(s) = stmt {
2749 assert_eq!(s.body.compounds.len(), 2);
2750 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
2751 assert_eq!(s.body.compounds[1].0, CompoundOp::Intersect);
2752 } else {
2753 unreachable!("expected Select");
2754 }
2755 }
2756
2757 #[test]
2758 fn test_cte_not_materialized() {
2759 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
2760 if let Statement::Select(s) = stmt {
2761 let with = s.with.as_ref().expect("WITH clause");
2762 assert_eq!(
2763 with.ctes[0].materialized,
2764 Some(CteMaterialized::NotMaterialized)
2765 );
2766 } else {
2767 unreachable!("expected Select");
2768 }
2769 }
2770
2771 #[test]
2772 fn test_cte_with_explicit_columns() {
2773 let stmt = parse_one("WITH cte(a, b, c) AS (SELECT 1, 2, 3) SELECT * FROM cte");
2774 if let Statement::Select(s) = stmt {
2775 let with = s.with.as_ref().expect("WITH clause");
2776 assert_eq!(with.ctes[0].columns, vec!["a", "b", "c"]);
2777 } else {
2778 unreachable!("expected Select");
2779 }
2780 }
2781
2782 #[test]
2783 fn test_window_frame_range() {
2784 let stmt = parse_one(
2785 "SELECT sum(x) OVER (ORDER BY y RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t",
2786 );
2787 if let Statement::Select(s) = stmt {
2788 if let SelectCore::Select { columns, .. } = &s.body.select {
2789 match &columns[0] {
2790 ResultColumn::Expr {
2791 expr:
2792 Expr::FunctionCall {
2793 over: Some(over), ..
2794 },
2795 ..
2796 } => {
2797 let frame = over.frame.as_ref().expect("frame spec");
2798 assert_eq!(frame.frame_type, FrameType::Range);
2799 assert!(matches!(frame.start, FrameBound::UnboundedPreceding));
2800 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
2801 }
2802 other => unreachable!("expected window function, got {other:?}"),
2803 }
2804 } else {
2805 unreachable!("expected Select core");
2806 }
2807 } else {
2808 unreachable!("expected Select");
2809 }
2810 }
2811
2812 #[test]
2813 fn test_window_frame_groups() {
2814 let stmt = parse_one(
2815 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
2816 );
2817 if let Statement::Select(s) = stmt {
2818 if let SelectCore::Select { columns, .. } = &s.body.select {
2819 match &columns[0] {
2820 ResultColumn::Expr {
2821 expr:
2822 Expr::FunctionCall {
2823 over: Some(over), ..
2824 },
2825 ..
2826 } => {
2827 let frame = over.frame.as_ref().expect("frame spec");
2828 assert_eq!(frame.frame_type, FrameType::Groups);
2829 assert!(matches!(frame.start, FrameBound::Preceding(_)));
2830 assert!(matches!(frame.end, Some(FrameBound::Following(_))));
2831 }
2832 other => unreachable!("expected window function, got {other:?}"),
2833 }
2834 } else {
2835 unreachable!("expected Select core");
2836 }
2837 } else {
2838 unreachable!("expected Select");
2839 }
2840 }
2841
2842 #[test]
2843 fn test_window_frame_exclude_current_row() {
2844 let stmt = parse_one(
2845 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
2846 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
2847 );
2848 if let Statement::Select(s) = stmt {
2849 if let SelectCore::Select { columns, .. } = &s.body.select {
2850 match &columns[0] {
2851 ResultColumn::Expr {
2852 expr:
2853 Expr::FunctionCall {
2854 over: Some(over), ..
2855 },
2856 ..
2857 } => {
2858 let frame = over.frame.as_ref().expect("frame spec");
2859 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
2860 }
2861 other => unreachable!("expected window function, got {other:?}"),
2862 }
2863 } else {
2864 unreachable!("expected Select core");
2865 }
2866 } else {
2867 unreachable!("expected Select");
2868 }
2869 }
2870
2871 #[test]
2872 fn test_window_frame_exclude_ties() {
2873 let stmt = parse_one(
2874 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
2875 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
2876 );
2877 if let Statement::Select(s) = stmt {
2878 if let SelectCore::Select { columns, .. } = &s.body.select {
2879 match &columns[0] {
2880 ResultColumn::Expr {
2881 expr:
2882 Expr::FunctionCall {
2883 over: Some(over), ..
2884 },
2885 ..
2886 } => {
2887 let frame = over.frame.as_ref().expect("frame spec");
2888 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
2889 }
2890 other => unreachable!("expected window function, got {other:?}"),
2891 }
2892 } else {
2893 unreachable!("expected Select core");
2894 }
2895 } else {
2896 unreachable!("expected Select");
2897 }
2898 }
2899
2900 #[test]
2901 fn test_window_frame_exclude_group() {
2902 let stmt =
2903 parse_one("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
2904 if let Statement::Select(s) = stmt {
2905 if let SelectCore::Select { columns, .. } = &s.body.select {
2906 match &columns[0] {
2907 ResultColumn::Expr {
2908 expr:
2909 Expr::FunctionCall {
2910 over: Some(over), ..
2911 },
2912 ..
2913 } => {
2914 let frame = over.frame.as_ref().expect("frame spec");
2915 assert_eq!(frame.frame_type, FrameType::Groups);
2916 assert_eq!(frame.exclude, Some(FrameExclude::Group));
2917 }
2918 other => unreachable!("expected window function, got {other:?}"),
2919 }
2920 } else {
2921 unreachable!("expected Select core");
2922 }
2923 } else {
2924 unreachable!("expected Select");
2925 }
2926 }
2927
2928 #[test]
2929 fn test_window_frame_unbounded_following() {
2930 let stmt = parse_one(
2931 "SELECT sum(x) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) FROM t",
2932 );
2933 if let Statement::Select(s) = stmt {
2934 if let SelectCore::Select { columns, .. } = &s.body.select {
2935 match &columns[0] {
2936 ResultColumn::Expr {
2937 expr:
2938 Expr::FunctionCall {
2939 over: Some(over), ..
2940 },
2941 ..
2942 } => {
2943 let frame = over.frame.as_ref().expect("frame spec");
2944 assert!(matches!(frame.start, FrameBound::CurrentRow));
2945 assert!(matches!(frame.end, Some(FrameBound::UnboundedFollowing)));
2946 }
2947 other => unreachable!("expected window function, got {other:?}"),
2948 }
2949 } else {
2950 unreachable!("expected Select core");
2951 }
2952 } else {
2953 unreachable!("expected Select");
2954 }
2955 }
2956
2957 #[test]
2958 fn test_filter_clause_aggregate() {
2959 let stmt = parse_one("SELECT count(*) FILTER (WHERE x > 0) FROM t");
2960 if let Statement::Select(s) = stmt {
2961 if let SelectCore::Select { columns, .. } = &s.body.select {
2962 match &columns[0] {
2963 ResultColumn::Expr {
2964 expr: Expr::FunctionCall { filter, .. },
2965 ..
2966 } => {
2967 assert!(
2968 filter.is_some(),
2969 "FILTER clause must be present on aggregate"
2970 );
2971 }
2972 other => unreachable!("expected function call with filter, got {other:?}"),
2973 }
2974 } else {
2975 unreachable!("expected Select core");
2976 }
2977 } else {
2978 unreachable!("expected Select");
2979 }
2980 }
2981
2982 #[test]
2983 fn test_filter_clause_window() {
2984 let stmt = parse_one("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
2985 if let Statement::Select(s) = stmt {
2986 if let SelectCore::Select { columns, .. } = &s.body.select {
2987 match &columns[0] {
2988 ResultColumn::Expr {
2989 expr:
2990 Expr::FunctionCall {
2991 filter,
2992 over: Some(_),
2993 ..
2994 },
2995 ..
2996 } => {
2997 assert!(
2998 filter.is_some(),
2999 "FILTER clause must be present on window function"
3000 );
3001 }
3002 other => unreachable!("expected window function with filter, got {other:?}"),
3003 }
3004 } else {
3005 unreachable!("expected Select core");
3006 }
3007 } else {
3008 unreachable!("expected Select");
3009 }
3010 }
3011
3012 #[test]
3013 fn test_subquery_in_from() {
3014 let stmt = parse_one("SELECT sub.x FROM (SELECT 1 AS x) AS sub");
3015 if let Statement::Select(s) = stmt {
3016 if let SelectCore::Select { from, .. } = &s.body.select {
3017 let from = from.as_ref().expect("FROM clause");
3018 match &from.source {
3019 TableOrSubquery::Subquery { alias, .. } => {
3020 assert_eq!(alias.as_deref(), Some("sub"));
3021 }
3022 other => unreachable!("expected subquery source, got {other:?}"),
3023 }
3024 } else {
3025 unreachable!("expected Select core");
3026 }
3027 } else {
3028 unreachable!("expected Select");
3029 }
3030 }
3031
3032 #[test]
3033 fn test_multiple_joins_chain() {
3034 let stmt = parse_one(
3035 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id \
3036 LEFT JOIN c ON b.id = c.b_id \
3037 CROSS JOIN d",
3038 );
3039 if let Statement::Select(s) = stmt {
3040 if let SelectCore::Select { from, .. } = &s.body.select {
3041 let from = from.as_ref().expect("FROM clause");
3042 assert_eq!(from.joins.len(), 3);
3043 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3044 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
3045 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
3046 } else {
3047 unreachable!("expected Select core");
3048 }
3049 } else {
3050 unreachable!("expected Select");
3051 }
3052 }
3053
3054 #[test]
3055 fn test_natural_left_join() {
3056 let stmt = parse_one("SELECT * FROM a NATURAL LEFT JOIN b");
3057 if let Statement::Select(s) = stmt {
3058 if let SelectCore::Select { from, .. } = &s.body.select {
3059 let from = from.as_ref().expect("FROM clause");
3060 let jt = &from.joins[0].join_type;
3061 assert!(jt.natural, "must be NATURAL");
3062 assert_eq!(jt.kind, JoinKind::Left);
3063 } else {
3064 unreachable!("expected Select core");
3065 }
3066 } else {
3067 unreachable!("expected Select");
3068 }
3069 }
3070
3071 #[test]
3072 fn test_select_nulls_first_default_asc() {
3073 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3075 if let Statement::Select(s) = stmt {
3076 assert_eq!(s.order_by.len(), 1);
3077 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
3078 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
3079 } else {
3080 unreachable!("expected Select");
3081 }
3082 }
3083
3084 #[test]
3085 fn test_select_nulls_last_desc() {
3086 let stmt = parse_one("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3088 if let Statement::Select(s) = stmt {
3089 assert_eq!(s.order_by.len(), 1);
3090 assert_eq!(s.order_by[0].direction, Some(SortDirection::Desc));
3091 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
3092 } else {
3093 unreachable!("expected Select");
3094 }
3095 }
3096
3097 #[test]
3102 fn test_roundtrip_select_filter_clause() {
3103 assert_roundtrip("SELECT count(*) FILTER (WHERE x > 0) FROM t");
3104 }
3105
3106 #[test]
3107 fn test_roundtrip_select_window_frame_groups() {
3108 assert_roundtrip(
3109 "SELECT sum(x) OVER (ORDER BY y GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t",
3110 );
3111 }
3112
3113 #[test]
3114 fn test_roundtrip_select_window_frame_exclude() {
3115 assert_roundtrip(
3116 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3117 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3118 );
3119 assert_roundtrip(
3120 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3121 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3122 );
3123 assert_roundtrip("SELECT sum(x) OVER (ORDER BY y GROUPS CURRENT ROW EXCLUDE GROUP) FROM t");
3124 }
3125
3126 #[test]
3127 fn test_roundtrip_select_nulls_order() {
3128 assert_roundtrip("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3129 assert_roundtrip("SELECT a FROM t ORDER BY a DESC NULLS LAST");
3130 }
3131
3132 #[test]
3133 fn test_roundtrip_select_values() {
3134 assert_roundtrip("VALUES (1, 2), (3, 4)");
3135 }
3136
3137 #[test]
3138 fn test_roundtrip_select_compound_order_limit() {
3139 assert_roundtrip("SELECT a FROM t1 UNION ALL SELECT b FROM t2 ORDER BY 1 LIMIT 10");
3140 }
3141
3142 #[test]
3143 fn test_roundtrip_select_cte_not_materialized() {
3144 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3145 }
3146
3147 #[test]
3148 fn test_roundtrip_select_natural_left_join() {
3149 assert_roundtrip("SELECT * FROM a NATURAL LEFT JOIN b");
3150 }
3151
3152 #[test]
3153 fn test_roundtrip_select_indexed_by() {
3154 assert_roundtrip("SELECT * FROM t INDEXED BY idx_t WHERE x = 1");
3155 }
3156
3157 #[test]
3158 fn test_roundtrip_select_filter_window_combined() {
3159 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0) OVER (ORDER BY y) FROM t");
3160 }
3161
3162 #[test]
3163 fn test_roundtrip_select_three_way_compound() {
3164 assert_roundtrip("SELECT 1 UNION SELECT 2 EXCEPT SELECT 3");
3165 }
3166
3167 #[test]
3168 fn test_roundtrip_select_multiple_joins() {
3169 assert_roundtrip(
3170 "SELECT * FROM a INNER JOIN b ON a.id = b.a_id LEFT JOIN c ON b.id = c.b_id",
3171 );
3172 }
3173
3174 #[test]
3179 fn test_select_star() {
3180 let stmt = parse_one("SELECT * FROM t");
3182 if let Statement::Select(s) = stmt {
3183 if let SelectCore::Select { columns, .. } = &s.body.select {
3184 assert!(matches!(columns[0], ResultColumn::Star));
3185 } else {
3186 unreachable!("expected Select core");
3187 }
3188 } else {
3189 unreachable!("expected Select");
3190 }
3191 }
3192
3193 #[test]
3194 fn test_inner_join_on() {
3195 let stmt = parse_one("SELECT * FROM a INNER JOIN b ON a.id = b.a_id");
3197 if let Statement::Select(s) = stmt {
3198 if let SelectCore::Select { from, .. } = &s.body.select {
3199 let from = from.as_ref().expect("FROM clause");
3200 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
3201 assert!(matches!(
3202 from.joins[0].constraint,
3203 Some(JoinConstraint::On(_))
3204 ));
3205 } else {
3206 unreachable!("expected Select core");
3207 }
3208 } else {
3209 unreachable!("expected Select");
3210 }
3211 }
3212
3213 #[test]
3214 fn test_left_outer_join() {
3215 let stmt = parse_one("SELECT * FROM a LEFT OUTER JOIN b ON a.id = b.a_id");
3217 if let Statement::Select(s) = stmt {
3218 if let SelectCore::Select { from, .. } = &s.body.select {
3219 let from = from.as_ref().expect("FROM clause");
3220 assert_eq!(from.joins[0].join_type.kind, JoinKind::Left);
3221 } else {
3222 unreachable!("expected Select core");
3223 }
3224 } else {
3225 unreachable!("expected Select");
3226 }
3227 }
3228
3229 #[test]
3230 fn test_right_outer_join() {
3231 let stmt = parse_one("SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id");
3233 if let Statement::Select(s) = stmt {
3234 if let SelectCore::Select { from, .. } = &s.body.select {
3235 let from = from.as_ref().expect("FROM clause");
3236 assert_eq!(from.joins[0].join_type.kind, JoinKind::Right);
3237 } else {
3238 unreachable!("expected Select core");
3239 }
3240 } else {
3241 unreachable!("expected Select");
3242 }
3243 }
3244
3245 #[test]
3246 fn test_full_outer_join() {
3247 let stmt = parse_one("SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id");
3249 if let Statement::Select(s) = stmt {
3250 if let SelectCore::Select { from, .. } = &s.body.select {
3251 let from = from.as_ref().expect("FROM clause");
3252 assert_eq!(from.joins[0].join_type.kind, JoinKind::Full);
3253 } else {
3254 unreachable!("expected Select core");
3255 }
3256 } else {
3257 unreachable!("expected Select");
3258 }
3259 }
3260
3261 #[test]
3262 fn test_cross_join_no_reorder() {
3263 let stmt = parse_one("SELECT * FROM a CROSS JOIN b");
3265 if let Statement::Select(s) = stmt {
3266 if let SelectCore::Select { from, .. } = &s.body.select {
3267 let from = from.as_ref().expect("FROM clause");
3268 assert_eq!(from.joins[0].join_type.kind, JoinKind::Cross);
3269 assert!(from.joins[0].constraint.is_none());
3271 } else {
3272 unreachable!("expected Select core");
3273 }
3274 } else {
3275 unreachable!("expected Select");
3276 }
3277 }
3278
3279 #[test]
3280 fn test_natural_join() {
3281 let stmt = parse_one("SELECT * FROM a NATURAL JOIN b");
3283 if let Statement::Select(s) = stmt {
3284 if let SelectCore::Select { from, .. } = &s.body.select {
3285 let from = from.as_ref().expect("FROM clause");
3286 assert!(from.joins[0].join_type.natural);
3287 } else {
3288 unreachable!("expected Select core");
3289 }
3290 } else {
3291 unreachable!("expected Select");
3292 }
3293 }
3294
3295 #[test]
3296 fn test_using_clause() {
3297 let stmt = parse_one("SELECT * FROM a JOIN b USING (id, name)");
3299 if let Statement::Select(s) = stmt {
3300 if let SelectCore::Select { from, .. } = &s.body.select {
3301 let from = from.as_ref().expect("FROM clause");
3302 match &from.joins[0].constraint {
3303 Some(JoinConstraint::Using(cols)) => {
3304 assert_eq!(cols.len(), 2);
3305 assert_eq!(cols[0], "id");
3306 assert_eq!(cols[1], "name");
3307 }
3308 other => unreachable!("expected USING constraint, got {other:?}"),
3309 }
3310 } else {
3311 unreachable!("expected Select core");
3312 }
3313 } else {
3314 unreachable!("expected Select");
3315 }
3316 }
3317
3318 #[test]
3319 fn test_cte_basic() {
3320 let stmt = parse_one("WITH cte AS (SELECT 1 AS x) SELECT * FROM cte");
3322 if let Statement::Select(s) = stmt {
3323 let with = s.with.as_ref().expect("WITH clause");
3324 assert!(!with.recursive);
3325 assert_eq!(with.ctes.len(), 1);
3326 assert_eq!(with.ctes[0].name, "cte");
3327 } else {
3328 unreachable!("expected Select");
3329 }
3330 }
3331
3332 #[test]
3333 fn test_cte_recursive_union_all() {
3334 let stmt = parse_one(
3336 "WITH RECURSIVE cnt(x) AS (\
3337 SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<10\
3338 ) SELECT x FROM cnt",
3339 );
3340 if let Statement::Select(s) = stmt {
3341 let with = s.with.as_ref().expect("WITH clause");
3342 assert!(with.recursive);
3343 assert_eq!(with.ctes[0].name, "cnt");
3344 let cte_body = &with.ctes[0].query;
3346 assert_eq!(cte_body.body.compounds.len(), 1);
3347 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::UnionAll);
3348 } else {
3349 unreachable!("expected Select");
3350 }
3351 }
3352
3353 #[test]
3354 fn test_cte_recursive_union_cycle_detection() {
3355 let stmt = parse_one(
3357 "WITH RECURSIVE paths(a, b) AS (\
3358 SELECT src, dst FROM edges \
3359 UNION \
3360 SELECT p.a, e.dst FROM paths p JOIN edges e ON p.b = e.src\
3361 ) SELECT * FROM paths",
3362 );
3363 if let Statement::Select(s) = stmt {
3364 let with = s.with.as_ref().expect("WITH clause");
3365 assert!(with.recursive);
3366 let cte_body = &with.ctes[0].query;
3368 assert_eq!(cte_body.body.compounds.len(), 1);
3369 assert_eq!(cte_body.body.compounds[0].0, CompoundOp::Union);
3370 } else {
3371 unreachable!("expected Select");
3372 }
3373 }
3374
3375 #[test]
3376 fn test_cte_materialized_hint() {
3377 let stmt = parse_one("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
3379 if let Statement::Select(s) = stmt {
3380 let with = s.with.as_ref().expect("WITH clause");
3381 assert_eq!(
3382 with.ctes[0].materialized,
3383 Some(CteMaterialized::Materialized)
3384 );
3385 } else {
3386 unreachable!("expected Select");
3387 }
3388 }
3389
3390 #[test]
3391 fn test_cte_not_materialized_hint() {
3392 let stmt = parse_one("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
3394 if let Statement::Select(s) = stmt {
3395 let with = s.with.as_ref().expect("WITH clause");
3396 assert_eq!(
3397 with.ctes[0].materialized,
3398 Some(CteMaterialized::NotMaterialized)
3399 );
3400 } else {
3401 unreachable!("expected Select");
3402 }
3403 }
3404
3405 #[test]
3406 fn test_window_partition_by() {
3407 let stmt = parse_one("SELECT sum(x) OVER (PARTITION BY dept) FROM emp");
3409 if let Statement::Select(s) = stmt {
3410 if let SelectCore::Select { columns, .. } = &s.body.select {
3411 match &columns[0] {
3412 ResultColumn::Expr {
3413 expr:
3414 Expr::FunctionCall {
3415 over: Some(over), ..
3416 },
3417 ..
3418 } => {
3419 assert_eq!(over.partition_by.len(), 1);
3420 }
3421 other => unreachable!("expected window function, got {other:?}"),
3422 }
3423 } else {
3424 unreachable!("expected Select core");
3425 }
3426 } else {
3427 unreachable!("expected Select");
3428 }
3429 }
3430
3431 #[test]
3432 fn test_window_order_by() {
3433 let stmt = parse_one("SELECT row_number() OVER (ORDER BY salary DESC) FROM emp");
3435 if let Statement::Select(s) = stmt {
3436 if let SelectCore::Select { columns, .. } = &s.body.select {
3437 match &columns[0] {
3438 ResultColumn::Expr {
3439 expr:
3440 Expr::FunctionCall {
3441 over: Some(over), ..
3442 },
3443 ..
3444 } => {
3445 assert_eq!(over.order_by.len(), 1);
3446 assert_eq!(over.order_by[0].direction, Some(SortDirection::Desc));
3447 }
3448 other => unreachable!("expected window function, got {other:?}"),
3449 }
3450 } else {
3451 unreachable!("expected Select core");
3452 }
3453 } else {
3454 unreachable!("expected Select");
3455 }
3456 }
3457
3458 #[test]
3459 fn test_window_frame_rows() {
3460 let stmt = parse_one(
3462 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t",
3463 );
3464 if let Statement::Select(s) = stmt {
3465 if let SelectCore::Select { columns, .. } = &s.body.select {
3466 match &columns[0] {
3467 ResultColumn::Expr {
3468 expr:
3469 Expr::FunctionCall {
3470 over: Some(over), ..
3471 },
3472 ..
3473 } => {
3474 let frame = over.frame.as_ref().expect("frame spec");
3475 assert_eq!(frame.frame_type, FrameType::Rows);
3476 assert!(matches!(frame.start, FrameBound::Preceding(_)));
3477 assert!(matches!(frame.end, Some(FrameBound::CurrentRow)));
3478 }
3479 other => unreachable!("expected window function, got {other:?}"),
3480 }
3481 } else {
3482 unreachable!("expected Select core");
3483 }
3484 } else {
3485 unreachable!("expected Select");
3486 }
3487 }
3488
3489 #[test]
3490 fn test_window_exclude_current_row() {
3491 let stmt = parse_one(
3493 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3494 UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW) FROM t",
3495 );
3496 if let Statement::Select(s) = stmt {
3497 if let SelectCore::Select { columns, .. } = &s.body.select {
3498 match &columns[0] {
3499 ResultColumn::Expr {
3500 expr:
3501 Expr::FunctionCall {
3502 over: Some(over), ..
3503 },
3504 ..
3505 } => {
3506 let frame = over.frame.as_ref().expect("frame spec");
3507 assert_eq!(frame.exclude, Some(FrameExclude::CurrentRow));
3508 }
3509 other => unreachable!("expected window function, got {other:?}"),
3510 }
3511 } else {
3512 unreachable!("expected Select core");
3513 }
3514 } else {
3515 unreachable!("expected Select");
3516 }
3517 }
3518
3519 #[test]
3520 fn test_window_exclude_ties() {
3521 let stmt = parse_one(
3523 "SELECT sum(x) OVER (ORDER BY y ROWS BETWEEN UNBOUNDED PRECEDING AND \
3524 UNBOUNDED FOLLOWING EXCLUDE TIES) FROM t",
3525 );
3526 if let Statement::Select(s) = stmt {
3527 if let SelectCore::Select { columns, .. } = &s.body.select {
3528 match &columns[0] {
3529 ResultColumn::Expr {
3530 expr:
3531 Expr::FunctionCall {
3532 over: Some(over), ..
3533 },
3534 ..
3535 } => {
3536 let frame = over.frame.as_ref().expect("frame spec");
3537 assert_eq!(frame.exclude, Some(FrameExclude::Ties));
3538 }
3539 other => unreachable!("expected window function, got {other:?}"),
3540 }
3541 } else {
3542 unreachable!("expected Select core");
3543 }
3544 } else {
3545 unreachable!("expected Select");
3546 }
3547 }
3548
3549 #[test]
3550 fn test_nulls_first_asc() {
3551 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS FIRST");
3553 if let Statement::Select(s) = stmt {
3554 assert_eq!(s.order_by.len(), 1);
3555 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
3556 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::First));
3557 } else {
3558 unreachable!("expected Select");
3559 }
3560 }
3561
3562 #[test]
3563 fn test_nulls_last_asc() {
3564 let stmt = parse_one("SELECT a FROM t ORDER BY a ASC NULLS LAST");
3566 if let Statement::Select(s) = stmt {
3567 assert_eq!(s.order_by.len(), 1);
3568 assert_eq!(s.order_by[0].direction, Some(SortDirection::Asc));
3569 assert_eq!(s.order_by[0].nulls, Some(NullsOrder::Last));
3570 } else {
3571 unreachable!("expected Select");
3572 }
3573 }
3574
3575 #[test]
3576 fn test_distinct_deduplicates() {
3577 let stmt = parse_one("SELECT DISTINCT a, b FROM t");
3579 if let Statement::Select(s) = stmt {
3580 if let SelectCore::Select { distinct, .. } = &s.body.select {
3581 assert_eq!(*distinct, Distinctness::Distinct);
3582 } else {
3583 unreachable!("expected Select core");
3584 }
3585 } else {
3586 unreachable!("expected Select");
3587 }
3588 }
3589
3590 #[test]
3591 fn test_limit_offset() {
3592 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET 20");
3594 if let Statement::Select(s) = stmt {
3595 let limit = s.limit.expect("LIMIT clause");
3596 assert!(matches!(
3597 limit.limit,
3598 Expr::Literal(Literal::Integer(10), _)
3599 ));
3600 assert!(matches!(
3601 limit.offset,
3602 Some(Expr::Literal(Literal::Integer(20), _))
3603 ));
3604 } else {
3605 unreachable!("expected Select");
3606 }
3607 }
3608
3609 #[test]
3610 fn test_limit_comma_syntax() {
3611 let stmt = parse_one("SELECT a FROM t LIMIT 5, 10");
3613 if let Statement::Select(s) = stmt {
3614 let limit = s.limit.expect("LIMIT clause");
3615 assert!(matches!(
3617 limit.limit,
3618 Expr::Literal(Literal::Integer(10), _)
3619 ));
3620 assert!(matches!(
3621 limit.offset,
3622 Some(Expr::Literal(Literal::Integer(5), _))
3623 ));
3624 } else {
3625 unreachable!("expected Select");
3626 }
3627 }
3628
3629 #[test]
3630 fn test_negative_limit_unlimited() {
3631 let stmt = parse_one("SELECT a FROM t LIMIT -1");
3633 if let Statement::Select(s) = stmt {
3634 let limit = s.limit.expect("LIMIT clause");
3635 match &limit.limit {
3638 Expr::UnaryOp {
3639 op: fsqlite_ast::UnaryOp::Negate,
3640 ..
3641 } => {}
3642 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
3643 other => unreachable!("expected negative limit expression, got {other:?}"),
3644 }
3645 } else {
3646 unreachable!("expected Select");
3647 }
3648 }
3649
3650 #[test]
3651 fn test_negative_offset_zero() {
3652 let stmt = parse_one("SELECT a FROM t LIMIT 10 OFFSET -5");
3654 if let Statement::Select(s) = stmt {
3655 let limit = s.limit.expect("LIMIT clause");
3656 assert!(limit.offset.is_some());
3657 match limit.offset.as_ref().unwrap() {
3658 Expr::UnaryOp {
3659 op: fsqlite_ast::UnaryOp::Negate,
3660 ..
3661 } => {}
3662 Expr::Literal(Literal::Integer(n), _) if *n < 0 => {}
3663 other => unreachable!("expected negative offset expression, got {other:?}"),
3664 }
3665 } else {
3666 unreachable!("expected Select");
3667 }
3668 }
3669
3670 #[test]
3671 fn test_current_date_constant() {
3672 let stmt = parse_one("SELECT CURRENT_DATE");
3674 if let Statement::Select(s) = stmt {
3675 if let SelectCore::Select { columns, .. } = &s.body.select {
3676 match &columns[0] {
3677 ResultColumn::Expr {
3678 expr: Expr::Literal(Literal::CurrentDate, _),
3679 ..
3680 } => {}
3681 other => unreachable!("expected CURRENT_DATE literal, got {other:?}"),
3682 }
3683 } else {
3684 unreachable!("expected Select core");
3685 }
3686 } else {
3687 unreachable!("expected Select");
3688 }
3689 }
3690
3691 #[test]
3692 fn test_current_time_constant() {
3693 let stmt = parse_one("SELECT CURRENT_TIME");
3695 if let Statement::Select(s) = stmt {
3696 if let SelectCore::Select { columns, .. } = &s.body.select {
3697 match &columns[0] {
3698 ResultColumn::Expr {
3699 expr: Expr::Literal(Literal::CurrentTime, _),
3700 ..
3701 } => {}
3702 other => unreachable!("expected CURRENT_TIME literal, got {other:?}"),
3703 }
3704 } else {
3705 unreachable!("expected Select core");
3706 }
3707 } else {
3708 unreachable!("expected Select");
3709 }
3710 }
3711
3712 #[test]
3713 fn test_current_timestamp_constant() {
3714 let stmt = parse_one("SELECT CURRENT_TIMESTAMP");
3716 if let Statement::Select(s) = stmt {
3717 if let SelectCore::Select { columns, .. } = &s.body.select {
3718 match &columns[0] {
3719 ResultColumn::Expr {
3720 expr: Expr::Literal(Literal::CurrentTimestamp, _),
3721 ..
3722 } => {}
3723 other => unreachable!("expected CURRENT_TIMESTAMP literal, got {other:?}"),
3724 }
3725 } else {
3726 unreachable!("expected Select core");
3727 }
3728 } else {
3729 unreachable!("expected Select");
3730 }
3731 }
3732
3733 #[test]
3734 fn test_date_constants_evaluated_once_per_statement() {
3735 let stmt = parse_one("SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP FROM t");
3738 if let Statement::Select(s) = stmt {
3739 if let SelectCore::Select { columns, .. } = &s.body.select {
3740 assert_eq!(columns.len(), 3);
3741 assert!(matches!(
3742 &columns[0],
3743 ResultColumn::Expr {
3744 expr: Expr::Literal(Literal::CurrentDate, _),
3745 ..
3746 }
3747 ));
3748 assert!(matches!(
3749 &columns[1],
3750 ResultColumn::Expr {
3751 expr: Expr::Literal(Literal::CurrentTime, _),
3752 ..
3753 }
3754 ));
3755 assert!(matches!(
3756 &columns[2],
3757 ResultColumn::Expr {
3758 expr: Expr::Literal(Literal::CurrentTimestamp, _),
3759 ..
3760 }
3761 ));
3762 } else {
3763 unreachable!("expected Select core");
3764 }
3765 } else {
3766 unreachable!("expected Select");
3767 }
3768 }
3769
3770 #[test]
3771 fn test_indexed_by_hint() {
3772 let stmt = parse_one("SELECT * FROM t INDEXED BY idx_t");
3774 if let Statement::Select(s) = stmt {
3775 if let SelectCore::Select { from, .. } = &s.body.select {
3776 let from = from.as_ref().expect("FROM clause");
3777 match &from.source {
3778 TableOrSubquery::Table {
3779 index_hint: Some(IndexHint::IndexedBy(name)),
3780 ..
3781 } => assert_eq!(name, "idx_t"),
3782 other => unreachable!("expected indexed table source, got {other:?}"),
3783 }
3784 } else {
3785 unreachable!("expected Select core");
3786 }
3787 } else {
3788 unreachable!("expected Select");
3789 }
3790 }
3791
3792 #[test]
3793 fn test_not_indexed_hint() {
3794 let stmt = parse_one("SELECT * FROM t NOT INDEXED");
3796 if let Statement::Select(s) = stmt {
3797 if let SelectCore::Select { from, .. } = &s.body.select {
3798 let from = from.as_ref().expect("FROM clause");
3799 match &from.source {
3800 TableOrSubquery::Table {
3801 index_hint: Some(IndexHint::NotIndexed),
3802 ..
3803 } => {}
3804 other => unreachable!("expected not-indexed table source, got {other:?}"),
3805 }
3806 } else {
3807 unreachable!("expected Select core");
3808 }
3809 } else {
3810 unreachable!("expected Select");
3811 }
3812 }
3813
3814 #[test]
3815 fn test_table_valued_function_in_from() {
3816 let stmt = parse_one("SELECT * FROM generate_series(1, 100) AS gs");
3818 if let Statement::Select(s) = stmt {
3819 if let SelectCore::Select { from, .. } = &s.body.select {
3820 let from = from.as_ref().expect("FROM clause");
3821 match &from.source {
3822 TableOrSubquery::TableFunction { name, args, alias } => {
3823 assert_eq!(name, "generate_series");
3824 assert_eq!(args.len(), 2);
3825 assert_eq!(alias.as_deref(), Some("gs"));
3826 }
3827 other => unreachable!("expected table-valued function source, got {other:?}"),
3828 }
3829 } else {
3830 unreachable!("expected Select core");
3831 }
3832 } else {
3833 unreachable!("expected Select");
3834 }
3835 }
3836
3837 #[test]
3842 fn test_insert_values_single() {
3843 let stmt = parse_one("INSERT INTO t (a, b, c) VALUES (1, 'hello', 3.14)");
3844 if let Statement::Insert(i) = stmt {
3845 assert_eq!(i.columns, vec!["a", "b", "c"]);
3846 if let InsertSource::Values(rows) = &i.source {
3847 assert_eq!(rows.len(), 1);
3848 assert_eq!(rows[0].len(), 3);
3849 } else {
3850 unreachable!("expected Values source");
3851 }
3852 } else {
3853 unreachable!("expected Insert");
3854 }
3855 }
3856
3857 #[test]
3858 fn test_insert_values_multi() {
3859 let stmt = parse_one("INSERT INTO t (x, y) VALUES (1, 2), (3, 4), (5, 6)");
3860 if let Statement::Insert(i) = stmt {
3861 if let InsertSource::Values(rows) = &i.source {
3862 assert_eq!(rows.len(), 3);
3863 for row in rows {
3864 assert_eq!(row.len(), 2);
3865 }
3866 } else {
3867 unreachable!("expected Values source");
3868 }
3869 } else {
3870 unreachable!("expected Insert");
3871 }
3872 }
3873
3874 #[test]
3875 fn test_insert_from_select() {
3876 let stmt = parse_one("INSERT INTO t2 (a, b) SELECT x, y FROM t1 WHERE x > 0");
3877 if let Statement::Insert(i) = stmt {
3878 assert!(matches!(i.source, InsertSource::Select(_)));
3879 assert_eq!(i.columns, vec!["a", "b"]);
3880 } else {
3881 unreachable!("expected Insert");
3882 }
3883 }
3884
3885 #[test]
3886 fn test_insert_from_select_without_from_clause() {
3887 let stmt = parse_one("INSERT INTO t (a) SELECT 1");
3888 if let Statement::Insert(i) = stmt {
3889 if let InsertSource::Select(select) = &i.source {
3890 if let SelectCore::Select { from, columns, .. } = &select.body.select {
3891 assert!(from.is_none(), "SELECT 1 should parse without FROM");
3892 assert_eq!(columns.len(), 1);
3893 } else {
3894 unreachable!("expected Select core");
3895 }
3896 } else {
3897 unreachable!("expected Select source");
3898 }
3899 } else {
3900 unreachable!("expected Insert");
3901 }
3902 }
3903
3904 #[test]
3905 fn test_insert_from_select_subquery_source() {
3906 let stmt = parse_one("INSERT INTO t (a) SELECT sub.x FROM (SELECT 1 AS x) AS sub");
3907 if let Statement::Insert(i) = stmt {
3908 if let InsertSource::Select(select) = &i.source {
3909 if let SelectCore::Select { from, .. } = &select.body.select {
3910 let from = from.as_ref().expect("FROM clause");
3911 match &from.source {
3912 TableOrSubquery::Subquery { alias, .. } => {
3913 assert_eq!(alias.as_deref(), Some("sub"));
3914 }
3915 other => unreachable!("expected subquery source, got {other:?}"),
3916 }
3917 } else {
3918 unreachable!("expected Select core");
3919 }
3920 } else {
3921 unreachable!("expected Select source");
3922 }
3923 } else {
3924 unreachable!("expected Insert");
3925 }
3926 }
3927
3928 #[test]
3929 fn test_insert_from_select_table_function_source() {
3930 let stmt = parse_one("INSERT INTO t (a) SELECT gs.value FROM generate_series(1, 3) AS gs");
3931 if let Statement::Insert(i) = stmt {
3932 if let InsertSource::Select(select) = &i.source {
3933 if let SelectCore::Select { from, .. } = &select.body.select {
3934 let from = from.as_ref().expect("FROM clause");
3935 match &from.source {
3936 TableOrSubquery::TableFunction { name, args, alias } => {
3937 assert_eq!(name, "generate_series");
3938 assert_eq!(args.len(), 2);
3939 assert_eq!(alias.as_deref(), Some("gs"));
3940 }
3941 other => unreachable!("expected table function source, got {other:?}"),
3942 }
3943 } else {
3944 unreachable!("expected Select core");
3945 }
3946 } else {
3947 unreachable!("expected Select source");
3948 }
3949 } else {
3950 unreachable!("expected Insert");
3951 }
3952 }
3953
3954 #[test]
3955 fn test_insert_default_values() {
3956 let stmt = parse_one("INSERT INTO t DEFAULT VALUES");
3957 if let Statement::Insert(i) = stmt {
3958 assert!(matches!(i.source, InsertSource::DefaultValues));
3959 assert!(i.columns.is_empty());
3960 } else {
3961 unreachable!("expected Insert");
3962 }
3963 }
3964
3965 #[test]
3966 fn test_insert_or_abort() {
3967 let stmt = parse_one("INSERT OR ABORT INTO t (a) VALUES (1)");
3968 if let Statement::Insert(i) = stmt {
3969 assert_eq!(i.or_conflict, Some(ConflictAction::Abort));
3970 } else {
3971 unreachable!("expected Insert");
3972 }
3973 }
3974
3975 #[test]
3976 fn test_insert_or_rollback() {
3977 let stmt = parse_one("INSERT OR ROLLBACK INTO t (a) VALUES (1)");
3978 if let Statement::Insert(i) = stmt {
3979 assert_eq!(i.or_conflict, Some(ConflictAction::Rollback));
3980 } else {
3981 unreachable!("expected Insert");
3982 }
3983 }
3984
3985 #[test]
3986 fn test_insert_or_fail() {
3987 let stmt = parse_one("INSERT OR FAIL INTO t (a) VALUES (1)");
3988 if let Statement::Insert(i) = stmt {
3989 assert_eq!(i.or_conflict, Some(ConflictAction::Fail));
3990 } else {
3991 unreachable!("expected Insert");
3992 }
3993 }
3994
3995 #[test]
3996 fn test_insert_or_ignore() {
3997 let stmt = parse_one("INSERT OR IGNORE INTO t (a) VALUES (1)");
3998 if let Statement::Insert(i) = stmt {
3999 assert_eq!(i.or_conflict, Some(ConflictAction::Ignore));
4000 } else {
4001 unreachable!("expected Insert");
4002 }
4003 }
4004
4005 #[test]
4006 fn test_insert_or_replace() {
4007 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1)");
4009 if let Statement::Insert(i) = stmt {
4010 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4011 } else {
4012 unreachable!("expected Insert");
4013 }
4014 }
4015
4016 #[test]
4017 fn test_upsert_do_update() {
4018 let stmt = parse_one(
4019 "INSERT INTO t (a, b) VALUES (1, 2) ON CONFLICT (a) DO UPDATE SET b = excluded.b",
4020 );
4021 if let Statement::Insert(i) = stmt {
4022 assert_eq!(i.upsert.len(), 1);
4023 assert!(i.upsert[0].target.is_some());
4024 match &i.upsert[0].action {
4025 UpsertAction::Update {
4026 assignments,
4027 where_clause,
4028 } => {
4029 assert_eq!(assignments.len(), 1);
4030 assert!(where_clause.is_none());
4031 }
4032 UpsertAction::Nothing => unreachable!("expected Update action"),
4033 }
4034 } else {
4035 unreachable!("expected Insert");
4036 }
4037 }
4038
4039 #[test]
4040 fn test_upsert_do_nothing() {
4041 let stmt = parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
4042 if let Statement::Insert(i) = stmt {
4043 assert_eq!(i.upsert.len(), 1);
4044 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4045 } else {
4046 unreachable!("expected Insert");
4047 }
4048 }
4049
4050 #[test]
4051 fn test_upsert_excluded_pseudo_table() {
4052 let stmt = parse_one(
4053 "INSERT INTO t (a, b) VALUES (1, 2) \
4054 ON CONFLICT (a) DO UPDATE SET b = excluded.b, a = excluded.a + 1",
4055 );
4056 if let Statement::Insert(i) = stmt {
4057 assert_eq!(i.upsert.len(), 1);
4058 if let UpsertAction::Update { assignments, .. } = &i.upsert[0].action {
4059 assert_eq!(assignments.len(), 2);
4060 match &assignments[0].value {
4062 Expr::Column(col, _) => {
4063 assert_eq!(col.table.as_deref(), Some("excluded"));
4064 assert_eq!(col.column, "b");
4065 }
4066 other => unreachable!("expected Column ref to excluded.b, got {other:?}"),
4067 }
4068 } else {
4069 unreachable!("expected Update action");
4070 }
4071 } else {
4072 unreachable!("expected Insert");
4073 }
4074 }
4075
4076 #[test]
4077 fn test_upsert_multiple_on_conflict() {
4078 let stmt = parse_one(
4079 "INSERT INTO t (a, b) VALUES (1, 2) \
4080 ON CONFLICT (a) DO NOTHING \
4081 ON CONFLICT (b) DO UPDATE SET a = excluded.a",
4082 );
4083 if let Statement::Insert(i) = stmt {
4084 assert_eq!(i.upsert.len(), 2);
4085 assert!(matches!(i.upsert[0].action, UpsertAction::Nothing));
4086 assert!(matches!(i.upsert[1].action, UpsertAction::Update { .. }));
4087 } else {
4088 unreachable!("expected Insert");
4089 }
4090 }
4091
4092 #[test]
4093 fn test_upsert_where_on_conflict_target() {
4094 let stmt = parse_one(
4095 "INSERT INTO t (a, b) VALUES (1, 2) \
4096 ON CONFLICT (a) WHERE a > 0 DO UPDATE SET b = excluded.b WHERE b < 100",
4097 );
4098 if let Statement::Insert(i) = stmt {
4099 assert_eq!(i.upsert.len(), 1);
4100 let target = i.upsert[0].target.as_ref().expect("conflict target");
4101 assert!(target.where_clause.is_some(), "target WHERE missing");
4102 if let UpsertAction::Update { where_clause, .. } = &i.upsert[0].action {
4103 assert!(where_clause.is_some(), "action WHERE missing");
4104 } else {
4105 unreachable!("expected Update action");
4106 }
4107 } else {
4108 unreachable!("expected Insert");
4109 }
4110 }
4111
4112 #[test]
4113 fn test_returning_insert() {
4114 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, rowid");
4115 if let Statement::Insert(i) = stmt {
4116 assert_eq!(i.returning.len(), 3);
4117 } else {
4118 unreachable!("expected Insert");
4119 }
4120 }
4121
4122 #[test]
4123 fn test_returning_insert_select_with_semicolon() {
4124 let stmt = parse_one("INSERT INTO t2 SELECT * FROM t RETURNING *;");
4125 if let Statement::Insert(i) = stmt {
4126 assert!(matches!(i.source, InsertSource::Select(_)));
4127 assert_eq!(i.returning.len(), 1);
4128 assert!(matches!(i.returning[0], ResultColumn::Star));
4129 } else {
4130 unreachable!("expected Insert");
4131 }
4132 }
4133
4134 #[test]
4135 fn test_returning_reflects_before_triggers() {
4136 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING a AS modified_a");
4140 if let Statement::Insert(i) = stmt {
4141 assert_eq!(i.returning.len(), 1);
4142 match &i.returning[0] {
4143 ResultColumn::Expr { alias, .. } => {
4144 assert_eq!(alias.as_deref(), Some("modified_a"));
4145 }
4146 other => unreachable!("expected Expr result column, got {other:?}"),
4147 }
4148 } else {
4149 unreachable!("expected Insert");
4150 }
4151 }
4152
4153 #[test]
4154 fn test_returning_ignores_after_triggers() {
4155 let stmt = parse_one("INSERT OR REPLACE INTO t (a) VALUES (1) RETURNING *");
4159 if let Statement::Insert(i) = stmt {
4160 assert_eq!(i.or_conflict, Some(ConflictAction::Replace));
4161 assert_eq!(i.returning.len(), 1);
4162 assert!(matches!(i.returning[0], ResultColumn::Star));
4163 } else {
4164 unreachable!("expected Insert");
4165 }
4166 }
4167
4168 #[test]
4169 fn test_returning_after_before_trigger_modify() {
4170 let stmt = parse_one("INSERT INTO t (a, b) VALUES (1, 2) RETURNING a, b, a + b AS total");
4174 if let Statement::Insert(i) = stmt {
4175 assert_eq!(i.returning.len(), 3);
4176 match &i.returning[2] {
4177 ResultColumn::Expr {
4178 alias: Some(alias), ..
4179 } => assert_eq!(alias, "total"),
4180 other => unreachable!("expected aliased expression, got {other:?}"),
4181 }
4182 } else {
4183 unreachable!("expected Insert");
4184 }
4185 }
4186
4187 #[test]
4188 fn test_returning_before_trigger_raise_abort() {
4189 let stmt = parse_one("INSERT INTO t (a) VALUES (1), (2), (3) RETURNING a");
4193 if let Statement::Insert(i) = stmt {
4194 if let InsertSource::Values(rows) = &i.source {
4195 assert_eq!(rows.len(), 3);
4196 } else {
4197 unreachable!("expected Values source");
4198 }
4199 assert_eq!(i.returning.len(), 1);
4200 } else {
4201 unreachable!("expected Insert");
4202 }
4203 }
4204
4205 #[test]
4206 fn test_returning_instead_of_view() {
4207 let stmt = parse_one("INSERT INTO v (a, b) VALUES (1, 2) RETURNING *");
4210 if let Statement::Insert(i) = stmt {
4211 assert_eq!(i.table.name, "v");
4212 assert!(!i.returning.is_empty());
4213 } else {
4214 unreachable!("expected Insert");
4215 }
4216 }
4217
4218 #[test]
4219 fn test_returning_autoincrement_with_trigger() {
4220 let stmt = parse_one("INSERT INTO t (name) VALUES ('test') RETURNING rowid, name");
4223 if let Statement::Insert(i) = stmt {
4224 assert_eq!(i.returning.len(), 2);
4225 } else {
4226 unreachable!("expected Insert");
4227 }
4228 }
4229
4230 #[test]
4231 fn test_update_set_where() {
4232 let stmt = parse_one("UPDATE t SET a = 1, b = 'hello' WHERE id = 42");
4233 if let Statement::Update(u) = stmt {
4234 assert_eq!(u.assignments.len(), 2);
4235 assert!(u.where_clause.is_some());
4236 assert!(u.from.is_none());
4237 } else {
4238 unreachable!("expected Update");
4239 }
4240 }
4241
4242 #[test]
4243 fn test_update_from_join() {
4244 let stmt = parse_one("UPDATE t1 SET a = t2.x FROM t2 WHERE t1.id = t2.id");
4245 if let Statement::Update(u) = stmt {
4246 assert_eq!(u.assignments.len(), 1);
4247 assert!(u.from.is_some());
4248 assert!(u.where_clause.is_some());
4249 } else {
4250 unreachable!("expected Update");
4251 }
4252 }
4253
4254 #[test]
4255 fn test_update_from_multi_match() {
4256 let stmt = parse_one(
4259 "UPDATE t1 SET val = src.val FROM src \
4260 INNER JOIN mapping ON mapping.src_id = src.id \
4261 WHERE t1.id = mapping.dst_id",
4262 );
4263 if let Statement::Update(u) = stmt {
4264 assert!(u.from.is_some());
4265 let from = u.from.as_ref().unwrap();
4266 assert!(!from.joins.is_empty(), "expected JOIN in FROM clause");
4267 } else {
4268 unreachable!("expected Update");
4269 }
4270 }
4271
4272 #[test]
4273 fn test_update_order_by_limit() {
4274 let stmt = parse_one("UPDATE t SET a = a + 1 ORDER BY b DESC LIMIT 10");
4275 if let Statement::Update(u) = stmt {
4276 assert_eq!(u.order_by.len(), 1);
4277 assert_eq!(u.order_by[0].direction, Some(SortDirection::Desc));
4278 assert!(u.limit.is_some());
4279 } else {
4280 unreachable!("expected Update");
4281 }
4282 }
4283
4284 #[test]
4285 fn test_update_returning() {
4286 let stmt = parse_one("UPDATE t SET a = 1 WHERE id = 5 RETURNING id, a AS new_a");
4287 if let Statement::Update(u) = stmt {
4288 assert_eq!(u.returning.len(), 2);
4289 match &u.returning[1] {
4290 ResultColumn::Expr {
4291 alias: Some(alias), ..
4292 } => assert_eq!(alias, "new_a"),
4293 other => unreachable!("expected aliased result column, got {other:?}"),
4294 }
4295 } else {
4296 unreachable!("expected Update");
4297 }
4298 }
4299
4300 #[test]
4301 fn test_update_or_ignore() {
4302 let stmt = parse_one("UPDATE OR IGNORE t SET a = 1 WHERE id = 5");
4303 if let Statement::Update(u) = stmt {
4304 assert_eq!(u.or_conflict, Some(ConflictAction::Ignore));
4305 assert!(u.where_clause.is_some());
4306 } else {
4307 unreachable!("expected Update");
4308 }
4309 }
4310
4311 #[test]
4312 fn test_delete_where() {
4313 let stmt = parse_one("DELETE FROM t WHERE id = 42 AND active = 0");
4314 if let Statement::Delete(d) = stmt {
4315 assert!(d.where_clause.is_some());
4316 assert!(d.returning.is_empty());
4317 } else {
4318 unreachable!("expected Delete");
4319 }
4320 }
4321
4322 #[test]
4323 fn test_delete_order_by_limit() {
4324 let stmt = parse_one("DELETE FROM t ORDER BY created_at ASC LIMIT 100");
4325 if let Statement::Delete(d) = stmt {
4326 assert_eq!(d.order_by.len(), 1);
4327 assert_eq!(d.order_by[0].direction, Some(SortDirection::Asc));
4328 let limit = d.limit.as_ref().expect("LIMIT clause");
4329 assert!(matches!(
4330 limit.limit,
4331 Expr::Literal(Literal::Integer(100), _)
4332 ));
4333 } else {
4334 unreachable!("expected Delete");
4335 }
4336 }
4337
4338 #[test]
4339 fn test_delete_returning() {
4340 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
4341 if let Statement::Delete(d) = stmt {
4342 assert!(d.where_clause.is_some());
4343 assert_eq!(d.returning.len(), 1);
4344 assert!(matches!(d.returning[0], ResultColumn::Star));
4345 } else {
4346 unreachable!("expected Delete");
4347 }
4348 }
4349
4350 #[test]
4351 fn test_delete_bulk_optimization() {
4352 let stmt = parse_one("DELETE FROM t");
4355 if let Statement::Delete(d) = stmt {
4356 assert!(d.where_clause.is_none());
4357 assert!(d.order_by.is_empty());
4358 assert!(d.limit.is_none());
4359 assert!(d.returning.is_empty());
4360 } else {
4361 unreachable!("expected Delete");
4362 }
4363 }
4364
4365 #[test]
4366 fn test_delete_bulk_no_where_fast() {
4367 let stmt = parse_one("DELETE FROM main.t");
4370 if let Statement::Delete(d) = stmt {
4371 assert_eq!(d.table.name.schema.as_deref(), Some("main"));
4372 assert_eq!(d.table.name.name, "t");
4373 assert!(d.where_clause.is_none());
4374 } else {
4375 unreachable!("expected Delete");
4376 }
4377 }
4378
4379 #[test]
4380 fn test_delete_bulk_blocked_by_trigger() {
4381 let stmt = parse_one("DELETE FROM orders");
4384 if let Statement::Delete(d) = stmt {
4385 assert!(d.where_clause.is_none());
4386 assert!(d.returning.is_empty());
4387 } else {
4388 unreachable!("expected Delete");
4389 }
4390 }
4391
4392 #[test]
4393 fn test_delete_bulk_blocked_by_fk() {
4394 let stmt = parse_one("DELETE FROM parent_table");
4397 if let Statement::Delete(d) = stmt {
4398 assert!(d.where_clause.is_none());
4399 } else {
4400 unreachable!("expected Delete");
4401 }
4402 }
4403
4404 #[test]
4405 fn test_delete_bulk_changes_count() {
4406 let stmt = parse_one("DELETE FROM t");
4410 if let Statement::Delete(d) = stmt {
4411 assert!(d.where_clause.is_none());
4412 } else {
4413 unreachable!("expected Delete");
4414 }
4415 }
4416
4417 #[test]
4418 fn test_delete_bulk_autoincrement_preserved() {
4419 let stmt = parse_one("DELETE FROM t");
4423 if let Statement::Delete(d) = stmt {
4424 assert!(d.where_clause.is_none());
4425 assert!(d.limit.is_none());
4426 } else {
4427 unreachable!("expected Delete");
4428 }
4429 }
4430
4431 #[test]
4432 fn test_delete_bulk_where_1_not_optimized() {
4433 let stmt = parse_one("DELETE FROM t WHERE 1");
4436 if let Statement::Delete(d) = stmt {
4437 assert!(
4438 d.where_clause.is_some(),
4439 "WHERE 1 must produce a where_clause"
4440 );
4441 assert!(matches!(
4442 d.where_clause.as_ref().unwrap(),
4443 Expr::Literal(Literal::Integer(1), _)
4444 ));
4445 } else {
4446 unreachable!("expected Delete");
4447 }
4448 }
4449
4450 #[test]
4455 fn test_create_table_basic() {
4456 let stmt = parse_one("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
4457 if let Statement::CreateTable(ct) = stmt {
4458 assert_eq!(ct.name.name, "users");
4459 assert!(!ct.if_not_exists);
4460 assert!(!ct.temporary);
4461 assert!(!ct.without_rowid);
4462 assert!(!ct.strict);
4463 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4464 assert_eq!(columns.len(), 3);
4465 assert_eq!(columns[0].name, "id");
4466 assert_eq!(columns[1].name, "name");
4467 assert_eq!(columns[2].name, "age");
4468 } else {
4469 unreachable!("expected Columns body");
4470 }
4471 } else {
4472 unreachable!("expected CreateTable");
4473 }
4474 }
4475
4476 #[test]
4477 fn test_create_table_if_not_exists() {
4478 let stmt = parse_one("CREATE TABLE IF NOT EXISTS t (id INTEGER)");
4479 if let Statement::CreateTable(ct) = stmt {
4480 assert!(ct.if_not_exists);
4481 } else {
4482 unreachable!("expected CreateTable");
4483 }
4484 }
4485
4486 #[test]
4487 fn test_create_temp_table() {
4488 let stmt = parse_one("CREATE TEMP TABLE session_data (key TEXT, val BLOB)");
4489 if let Statement::CreateTable(ct) = stmt {
4490 assert!(ct.temporary);
4491 } else {
4492 unreachable!("expected CreateTable");
4493 }
4494 }
4495
4496 #[test]
4497 fn test_create_table_as_select() {
4498 let stmt = parse_one("CREATE TABLE t2 AS SELECT id, name FROM t1 WHERE active = 1");
4499 if let Statement::CreateTable(ct) = stmt {
4500 assert!(matches!(ct.body, CreateTableBody::AsSelect(_)));
4501 } else {
4502 unreachable!("expected CreateTable");
4503 }
4504 }
4505
4506 #[test]
4507 fn test_column_primary_key() {
4508 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY ASC)");
4509 if let Statement::CreateTable(ct) = stmt {
4510 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4511 let pk = columns[0]
4512 .constraints
4513 .iter()
4514 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
4515 assert!(pk.is_some(), "PK constraint missing");
4516 if let ColumnConstraintKind::PrimaryKey { direction, .. } = &pk.unwrap().kind {
4517 assert_eq!(*direction, Some(SortDirection::Asc));
4518 }
4519 } else {
4520 unreachable!("expected Columns body");
4521 }
4522 } else {
4523 unreachable!("expected CreateTable");
4524 }
4525 }
4526
4527 #[test]
4528 fn test_column_primary_key_autoincrement() {
4529 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT)");
4530 if let Statement::CreateTable(ct) = stmt {
4531 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4532 let pk = columns[0]
4533 .constraints
4534 .iter()
4535 .find(|c| matches!(c.kind, ColumnConstraintKind::PrimaryKey { .. }));
4536 if let ColumnConstraintKind::PrimaryKey { autoincrement, .. } = &pk.unwrap().kind {
4537 assert!(autoincrement, "AUTOINCREMENT flag not set");
4538 }
4539 } else {
4540 unreachable!("expected Columns body");
4541 }
4542 } else {
4543 unreachable!("expected CreateTable");
4544 }
4545 }
4546
4547 #[test]
4548 fn test_autoincrement_uses_sqlite_sequence() {
4549 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)");
4552 if let Statement::CreateTable(ct) = stmt {
4553 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4554 assert_eq!(columns.len(), 2);
4555 let pk = columns[0].constraints.iter().find(|c| {
4556 matches!(
4557 c.kind,
4558 ColumnConstraintKind::PrimaryKey {
4559 autoincrement: true,
4560 ..
4561 }
4562 )
4563 });
4564 assert!(pk.is_some(), "AUTOINCREMENT constraint missing");
4565 } else {
4566 unreachable!("expected Columns body");
4567 }
4568 } else {
4569 unreachable!("expected CreateTable");
4570 }
4571 }
4572
4573 #[test]
4574 fn test_column_not_null() {
4575 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL)");
4576 if let Statement::CreateTable(ct) = stmt {
4577 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4578 let nn = columns[0]
4579 .constraints
4580 .iter()
4581 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
4582 assert!(nn.is_some(), "NOT NULL constraint missing");
4583 } else {
4584 unreachable!("expected Columns body");
4585 }
4586 } else {
4587 unreachable!("expected CreateTable");
4588 }
4589 }
4590
4591 #[test]
4592 fn test_column_unique() {
4593 let stmt = parse_one("CREATE TABLE t (email TEXT UNIQUE)");
4594 if let Statement::CreateTable(ct) = stmt {
4595 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4596 let uq = columns[0]
4597 .constraints
4598 .iter()
4599 .find(|c| matches!(c.kind, ColumnConstraintKind::Unique { .. }));
4600 assert!(uq.is_some(), "UNIQUE constraint missing");
4601 } else {
4602 unreachable!("expected Columns body");
4603 }
4604 } else {
4605 unreachable!("expected CreateTable");
4606 }
4607 }
4608
4609 #[test]
4610 fn test_column_check() {
4611 let stmt = parse_one("CREATE TABLE t (age INTEGER CHECK(age >= 0 AND age < 200))");
4612 if let Statement::CreateTable(ct) = stmt {
4613 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4614 let chk = columns[0]
4615 .constraints
4616 .iter()
4617 .find(|c| matches!(c.kind, ColumnConstraintKind::Check(_)));
4618 assert!(chk.is_some(), "CHECK constraint missing");
4619 } else {
4620 unreachable!("expected Columns body");
4621 }
4622 } else {
4623 unreachable!("expected CreateTable");
4624 }
4625 }
4626
4627 #[test]
4628 fn test_column_default_literal() {
4629 let stmt = parse_one("CREATE TABLE t (status TEXT DEFAULT 'active')");
4630 if let Statement::CreateTable(ct) = stmt {
4631 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4632 let def = columns[0]
4633 .constraints
4634 .iter()
4635 .find(|c| matches!(c.kind, ColumnConstraintKind::Default(_)));
4636 assert!(def.is_some(), "DEFAULT constraint missing");
4637 } else {
4638 unreachable!("expected Columns body");
4639 }
4640 } else {
4641 unreachable!("expected CreateTable");
4642 }
4643 }
4644
4645 #[test]
4646 fn test_column_default_expr() {
4647 let stmt = parse_one("CREATE TABLE t (created_at TEXT DEFAULT (datetime('now')))");
4648 if let Statement::CreateTable(ct) = stmt {
4649 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4650 let def = columns[0].constraints.iter().find(|c| {
4651 matches!(
4652 c.kind,
4653 ColumnConstraintKind::Default(DefaultValue::ParenExpr(_))
4654 )
4655 });
4656 assert!(def.is_some(), "DEFAULT (expr) missing");
4657 } else {
4658 unreachable!("expected Columns body");
4659 }
4660 } else {
4661 unreachable!("expected CreateTable");
4662 }
4663 }
4664
4665 #[test]
4666 fn test_column_collate() {
4667 let stmt = parse_one("CREATE TABLE t (name TEXT COLLATE NOCASE)");
4668 if let Statement::CreateTable(ct) = stmt {
4669 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4670 let coll = columns[0]
4671 .constraints
4672 .iter()
4673 .find(|c| matches!(c.kind, ColumnConstraintKind::Collate(_)));
4674 assert!(coll.is_some(), "COLLATE constraint missing");
4675 if let ColumnConstraintKind::Collate(name) = &coll.unwrap().kind {
4676 assert_eq!(name, "NOCASE");
4677 }
4678 } else {
4679 unreachable!("expected Columns body");
4680 }
4681 } else {
4682 unreachable!("expected CreateTable");
4683 }
4684 }
4685
4686 #[test]
4687 fn test_table_constraint_composite_pk() {
4688 let stmt = parse_one("CREATE TABLE t (a INTEGER, b INTEGER, PRIMARY KEY (a, b))");
4689 if let Statement::CreateTable(ct) = stmt {
4690 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
4691 let pk = constraints
4692 .iter()
4693 .find(|c| matches!(c.kind, TableConstraintKind::PrimaryKey { .. }));
4694 assert!(pk.is_some(), "composite PK missing");
4695 if let TableConstraintKind::PrimaryKey { columns, .. } = &pk.unwrap().kind {
4696 assert_eq!(columns.len(), 2);
4697 }
4698 } else {
4699 unreachable!("expected Columns body");
4700 }
4701 } else {
4702 unreachable!("expected CreateTable");
4703 }
4704 }
4705
4706 #[test]
4707 fn test_table_constraint_composite_unique() {
4708 let stmt = parse_one("CREATE TABLE t (a TEXT, b TEXT, UNIQUE (a, b))");
4709 if let Statement::CreateTable(ct) = stmt {
4710 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
4711 let uq = constraints
4712 .iter()
4713 .find(|c| matches!(c.kind, TableConstraintKind::Unique { .. }));
4714 assert!(uq.is_some(), "composite UNIQUE missing");
4715 if let TableConstraintKind::Unique { columns, .. } = &uq.unwrap().kind {
4716 assert_eq!(columns.len(), 2);
4717 }
4718 } else {
4719 unreachable!("expected Columns body");
4720 }
4721 } else {
4722 unreachable!("expected CreateTable");
4723 }
4724 }
4725
4726 #[test]
4727 fn test_table_constraint_check() {
4728 let stmt = parse_one(
4729 "CREATE TABLE t (start_date TEXT, end_date TEXT, CHECK (start_date < end_date))",
4730 );
4731 if let Statement::CreateTable(ct) = stmt {
4732 if let CreateTableBody::Columns { constraints, .. } = &ct.body {
4733 let chk = constraints
4734 .iter()
4735 .find(|c| matches!(c.kind, TableConstraintKind::Check(_)));
4736 assert!(chk.is_some(), "table CHECK constraint missing");
4737 } else {
4738 unreachable!("expected Columns body");
4739 }
4740 } else {
4741 unreachable!("expected CreateTable");
4742 }
4743 }
4744
4745 #[test]
4746 fn test_foreign_key_on_delete_cascade() {
4747 let stmt = parse_one(
4748 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4749 REFERENCES parent(id) ON DELETE CASCADE)",
4750 );
4751 if let Statement::CreateTable(ct) = stmt {
4752 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4753 let fk = columns[1]
4754 .constraints
4755 .iter()
4756 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)));
4757 assert!(fk.is_some(), "FK constraint missing");
4758 if let ColumnConstraintKind::ForeignKey(clause) = &fk.unwrap().kind {
4759 assert_eq!(clause.table, "parent");
4760 let del = clause
4761 .actions
4762 .iter()
4763 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
4764 assert!(del.is_some());
4765 assert_eq!(del.unwrap().action, ForeignKeyActionType::Cascade);
4766 }
4767 } else {
4768 unreachable!("expected Columns body");
4769 }
4770 } else {
4771 unreachable!("expected CreateTable");
4772 }
4773 }
4774
4775 #[test]
4776 fn test_foreign_key_on_delete_set_null() {
4777 let stmt = parse_one(
4778 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4779 REFERENCES parent(id) ON DELETE SET NULL)",
4780 );
4781 if let Statement::CreateTable(ct) = stmt {
4782 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4783 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
4784 .constraints
4785 .iter()
4786 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
4787 .unwrap()
4788 .kind
4789 {
4790 let del = clause
4791 .actions
4792 .iter()
4793 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
4794 assert_eq!(del.unwrap().action, ForeignKeyActionType::SetNull);
4795 }
4796 } else {
4797 unreachable!("expected Columns body");
4798 }
4799 } else {
4800 unreachable!("expected CreateTable");
4801 }
4802 }
4803
4804 #[test]
4805 fn test_foreign_key_on_update_cascade() {
4806 let stmt = parse_one(
4807 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4808 REFERENCES parent(id) ON UPDATE CASCADE)",
4809 );
4810 if let Statement::CreateTable(ct) = stmt {
4811 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4812 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
4813 .constraints
4814 .iter()
4815 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
4816 .unwrap()
4817 .kind
4818 {
4819 let upd = clause
4820 .actions
4821 .iter()
4822 .find(|a| a.trigger == ForeignKeyTrigger::OnUpdate);
4823 assert!(upd.is_some());
4824 assert_eq!(upd.unwrap().action, ForeignKeyActionType::Cascade);
4825 }
4826 } else {
4827 unreachable!("expected Columns body");
4828 }
4829 } else {
4830 unreachable!("expected CreateTable");
4831 }
4832 }
4833
4834 #[test]
4835 fn test_foreign_key_restrict() {
4836 let stmt = parse_one(
4837 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4838 REFERENCES parent(id) ON DELETE RESTRICT)",
4839 );
4840 if let Statement::CreateTable(ct) = stmt {
4841 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4842 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
4843 .constraints
4844 .iter()
4845 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
4846 .unwrap()
4847 .kind
4848 {
4849 let del = clause
4850 .actions
4851 .iter()
4852 .find(|a| a.trigger == ForeignKeyTrigger::OnDelete);
4853 assert_eq!(del.unwrap().action, ForeignKeyActionType::Restrict);
4854 }
4855 } else {
4856 unreachable!("expected Columns body");
4857 }
4858 } else {
4859 unreachable!("expected CreateTable");
4860 }
4861 }
4862
4863 #[test]
4864 fn test_foreign_key_deferred() {
4865 let stmt = parse_one(
4866 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4867 REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED)",
4868 );
4869 if let Statement::CreateTable(ct) = stmt {
4870 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4871 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
4872 .constraints
4873 .iter()
4874 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
4875 .unwrap()
4876 .kind
4877 {
4878 let def = clause.deferrable.as_ref().expect("DEFERRABLE missing");
4879 assert!(!def.not, "should be DEFERRABLE, not NOT DEFERRABLE");
4880 assert_eq!(def.initially, Some(DeferrableInitially::Deferred));
4881 }
4882 } else {
4883 unreachable!("expected Columns body");
4884 }
4885 } else {
4886 unreachable!("expected CreateTable");
4887 }
4888 }
4889
4890 #[test]
4891 fn test_foreign_key_pragma_required() {
4892 let stmt = parse_one(
4895 "CREATE TABLE child (id INTEGER, parent_id INTEGER \
4896 REFERENCES parent(id) ON DELETE CASCADE ON UPDATE SET NULL)",
4897 );
4898 if let Statement::CreateTable(ct) = stmt {
4899 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4900 if let ColumnConstraintKind::ForeignKey(clause) = &columns[1]
4901 .constraints
4902 .iter()
4903 .find(|c| matches!(c.kind, ColumnConstraintKind::ForeignKey(_)))
4904 .unwrap()
4905 .kind
4906 {
4907 assert_eq!(clause.actions.len(), 2);
4908 }
4909 } else {
4910 unreachable!("expected Columns body");
4911 }
4912 } else {
4913 unreachable!("expected CreateTable");
4914 }
4915 }
4916
4917 #[test]
4918 fn test_conflict_clause_on_not_null() {
4919 let stmt = parse_one("CREATE TABLE t (name TEXT NOT NULL ON CONFLICT IGNORE)");
4920 if let Statement::CreateTable(ct) = stmt {
4921 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4922 let nn = columns[0]
4923 .constraints
4924 .iter()
4925 .find(|c| matches!(c.kind, ColumnConstraintKind::NotNull { .. }));
4926 if let ColumnConstraintKind::NotNull { conflict } = &nn.unwrap().kind {
4927 assert_eq!(*conflict, Some(ConflictAction::Ignore));
4928 }
4929 } else {
4930 unreachable!("expected Columns body");
4931 }
4932 } else {
4933 unreachable!("expected CreateTable");
4934 }
4935 }
4936
4937 #[test]
4938 fn test_without_rowid_table() {
4939 let stmt = parse_one("CREATE TABLE t (k TEXT PRIMARY KEY, v BLOB) WITHOUT ROWID");
4940 if let Statement::CreateTable(ct) = stmt {
4941 assert!(ct.without_rowid);
4942 } else {
4943 unreachable!("expected CreateTable");
4944 }
4945 }
4946
4947 #[test]
4948 fn test_without_rowid_no_autoincrement() {
4949 let stmt = parse_one(
4952 "CREATE TABLE t (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT) WITHOUT ROWID",
4953 );
4954 if let Statement::CreateTable(ct) = stmt {
4955 assert!(ct.without_rowid);
4956 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4957 let pk = columns[0].constraints.iter().find(|c| {
4958 matches!(
4959 c.kind,
4960 ColumnConstraintKind::PrimaryKey {
4961 autoincrement: true,
4962 ..
4963 }
4964 )
4965 });
4966 assert!(pk.is_some());
4967 } else {
4968 unreachable!("expected Columns body");
4969 }
4970 } else {
4971 unreachable!("expected CreateTable");
4972 }
4973 }
4974
4975 #[test]
4976 fn test_without_rowid_integer_pk_not_alias() {
4977 let stmt = parse_one("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT) WITHOUT ROWID");
4980 if let Statement::CreateTable(ct) = stmt {
4981 assert!(ct.without_rowid);
4982 if let CreateTableBody::Columns { columns, .. } = &ct.body {
4983 assert_eq!(columns[0].name, "id");
4984 assert!(columns[0].type_name.is_some());
4985 } else {
4986 unreachable!("expected Columns body");
4987 }
4988 } else {
4989 unreachable!("expected CreateTable");
4990 }
4991 }
4992
4993 #[test]
4994 fn test_strict_table_type_enforcement() {
4995 let stmt = parse_one("CREATE TABLE t (id INTEGER, name TEXT, score REAL) STRICT");
4998 if let Statement::CreateTable(ct) = stmt {
4999 assert!(ct.strict);
5000 assert!(!ct.without_rowid);
5001 } else {
5002 unreachable!("expected CreateTable");
5003 }
5004 }
5005
5006 #[test]
5007 fn test_strict_table_any_column() {
5008 let stmt = parse_one("CREATE TABLE t (id INTEGER, data ANY) STRICT");
5010 if let Statement::CreateTable(ct) = stmt {
5011 assert!(ct.strict);
5012 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5013 let tn = columns[1].type_name.as_ref().expect("type name");
5014 assert_eq!(tn.name, "ANY");
5015 } else {
5016 unreachable!("expected Columns body");
5017 }
5018 } else {
5019 unreachable!("expected CreateTable");
5020 }
5021 }
5022
5023 #[test]
5024 fn test_strict_allowed_types() {
5025 let stmt =
5027 parse_one("CREATE TABLE t (a INT, b INTEGER, c REAL, d TEXT, e BLOB, f ANY) STRICT");
5028 if let Statement::CreateTable(ct) = stmt {
5029 assert!(ct.strict);
5030 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5031 assert_eq!(columns.len(), 6);
5032 let types: Vec<&str> = columns
5033 .iter()
5034 .map(|c| c.type_name.as_ref().unwrap().name.as_str())
5035 .collect();
5036 assert_eq!(types, vec!["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"]);
5037 } else {
5038 unreachable!("expected Columns body");
5039 }
5040 } else {
5041 unreachable!("expected CreateTable");
5042 }
5043 }
5044
5045 #[test]
5046 fn test_generated_col_virtual() {
5047 let stmt = parse_one(
5048 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a + b) VIRTUAL)",
5049 );
5050 if let Statement::CreateTable(ct) = stmt {
5051 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5052 let generated = columns[2]
5053 .constraints
5054 .iter()
5055 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5056 assert!(generated.is_some(), "Generated constraint missing");
5057 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5058 assert_eq!(*storage, Some(GeneratedStorage::Virtual));
5059 }
5060 } else {
5061 unreachable!("expected Columns body");
5062 }
5063 } else {
5064 unreachable!("expected CreateTable");
5065 }
5066 }
5067
5068 #[test]
5069 fn test_generated_col_stored() {
5070 let stmt = parse_one(
5071 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER GENERATED ALWAYS AS (a * b) STORED)",
5072 );
5073 if let Statement::CreateTable(ct) = stmt {
5074 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5075 let generated = columns[2]
5076 .constraints
5077 .iter()
5078 .find(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5079 if let ColumnConstraintKind::Generated { storage, .. } = &generated.unwrap().kind {
5080 assert_eq!(*storage, Some(GeneratedStorage::Stored));
5081 }
5082 } else {
5083 unreachable!("expected Columns body");
5084 }
5085 } else {
5086 unreachable!("expected CreateTable");
5087 }
5088 }
5089
5090 #[test]
5091 fn test_generated_col_ordering() {
5092 let stmt = parse_one(
5095 "CREATE TABLE t (\
5096 a INTEGER, \
5097 b INTEGER GENERATED ALWAYS AS (a + 1) STORED, \
5098 c INTEGER GENERATED ALWAYS AS (b * 2) VIRTUAL)",
5099 );
5100 if let Statement::CreateTable(ct) = stmt {
5101 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5102 assert_eq!(columns.len(), 3);
5103 let gen_b = columns[1]
5105 .constraints
5106 .iter()
5107 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5108 let gen_c = columns[2]
5109 .constraints
5110 .iter()
5111 .any(|c| matches!(c.kind, ColumnConstraintKind::Generated { .. }));
5112 assert!(gen_b, "column b should be generated");
5113 assert!(gen_c, "column c should be generated");
5114 } else {
5115 unreachable!("expected Columns body");
5116 }
5117 } else {
5118 unreachable!("expected CreateTable");
5119 }
5120 }
5121
5122 #[test]
5123 fn test_generated_col_stored_indexable() {
5124 let stmts = parse_ok(
5127 "CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED); \
5128 CREATE INDEX idx_b ON t (b)",
5129 );
5130 assert_eq!(stmts.len(), 2);
5131 assert!(matches!(stmts[0], Statement::CreateTable(_)));
5132 assert!(matches!(stmts[1], Statement::CreateIndex(_)));
5133 }
5134
5135 #[test]
5136 fn test_type_affinity_int() {
5137 let stmt = parse_one("CREATE TABLE t (a INTEGER, b BIGINT, c SMALLINT, d MEDIUMINT)");
5140 if let Statement::CreateTable(ct) = stmt {
5141 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5142 assert_eq!(columns.len(), 4);
5143 for col in columns {
5144 let tn = col.type_name.as_ref().unwrap();
5145 assert!(tn.name.contains("INT"), "{} should contain INT", tn.name);
5146 }
5147 } else {
5148 unreachable!("expected Columns body");
5149 }
5150 } else {
5151 unreachable!("expected CreateTable");
5152 }
5153 }
5154
5155 #[test]
5156 fn test_type_affinity_text() {
5157 let stmt = parse_one("CREATE TABLE t (a TEXT, b VARCHAR, c CLOB, d CHARACTER)");
5158 if let Statement::CreateTable(ct) = stmt {
5159 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5160 assert_eq!(columns.len(), 4);
5161 for col in columns {
5162 assert!(col.type_name.is_some());
5163 }
5164 } else {
5165 unreachable!("expected Columns body");
5166 }
5167 } else {
5168 unreachable!("expected CreateTable");
5169 }
5170 }
5171
5172 #[test]
5173 fn test_type_affinity_blob() {
5174 let stmt = parse_one("CREATE TABLE t (a BLOB, b)");
5175 if let Statement::CreateTable(ct) = stmt {
5176 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5177 assert_eq!(columns.len(), 2);
5178 assert_eq!(columns[0].type_name.as_ref().unwrap().name, "BLOB");
5179 assert!(columns[1].type_name.is_none());
5181 } else {
5182 unreachable!("expected Columns body");
5183 }
5184 } else {
5185 unreachable!("expected CreateTable");
5186 }
5187 }
5188
5189 #[test]
5190 fn test_type_affinity_real() {
5191 let stmt = parse_one("CREATE TABLE t (a REAL, b DOUBLE, c FLOAT)");
5192 if let Statement::CreateTable(ct) = stmt {
5193 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5194 assert_eq!(columns.len(), 3);
5195 for col in columns {
5196 assert!(col.type_name.is_some());
5197 }
5198 } else {
5199 unreachable!("expected Columns body");
5200 }
5201 } else {
5202 unreachable!("expected CreateTable");
5203 }
5204 }
5205
5206 #[test]
5207 fn test_type_affinity_numeric() {
5208 let stmt = parse_one("CREATE TABLE t (a NUMERIC, b DECIMAL, c BOOLEAN)");
5209 if let Statement::CreateTable(ct) = stmt {
5210 if let CreateTableBody::Columns { columns, .. } = &ct.body {
5211 assert_eq!(columns.len(), 3);
5212 for col in columns {
5213 assert!(col.type_name.is_some());
5214 }
5215 } else {
5216 unreachable!("expected Columns body");
5217 }
5218 } else {
5219 unreachable!("expected CreateTable");
5220 }
5221 }
5222
5223 #[test]
5224 fn test_create_unique_index() {
5225 let stmt = parse_one("CREATE UNIQUE INDEX idx_email ON users (email)");
5226 if let Statement::CreateIndex(ci) = stmt {
5227 assert!(ci.unique);
5228 assert_eq!(ci.name.name, "idx_email");
5229 assert_eq!(ci.table, "users");
5230 assert_eq!(ci.columns.len(), 1);
5231 assert!(ci.where_clause.is_none());
5232 } else {
5233 unreachable!("expected CreateIndex");
5234 }
5235 }
5236
5237 #[test]
5238 fn test_partial_index() {
5239 let stmt = parse_one("CREATE INDEX idx_active ON users (name) WHERE active = 1");
5240 if let Statement::CreateIndex(ci) = stmt {
5241 assert!(!ci.unique);
5242 assert_eq!(ci.name.name, "idx_active");
5243 assert!(ci.where_clause.is_some(), "partial index WHERE missing");
5244 } else {
5245 unreachable!("expected CreateIndex");
5246 }
5247 }
5248
5249 #[test]
5250 fn test_partial_index_planner_usage() {
5251 let stmt =
5254 parse_one("CREATE INDEX idx_recent ON orders (created_at) WHERE status != 'archived'");
5255 if let Statement::CreateIndex(ci) = stmt {
5256 assert!(ci.where_clause.is_some());
5257 assert_eq!(ci.columns.len(), 1);
5258 } else {
5259 unreachable!("expected CreateIndex");
5260 }
5261 }
5262
5263 #[test]
5264 fn test_expression_index() {
5265 let stmt = parse_one("CREATE INDEX idx_lower_name ON users (lower(name))");
5266 if let Statement::CreateIndex(ci) = stmt {
5267 assert_eq!(ci.columns.len(), 1);
5268 assert!(
5270 matches!(ci.columns[0].expr, Expr::FunctionCall { .. }),
5271 "expected function call expression in index"
5272 );
5273 } else {
5274 unreachable!("expected CreateIndex");
5275 }
5276 }
5277
5278 #[test]
5279 fn test_expression_index_planner_match() {
5280 let stmt = parse_one("CREATE INDEX idx_calc ON t (a + b * 2)");
5283 if let Statement::CreateIndex(ci) = stmt {
5284 assert_eq!(ci.columns.len(), 1);
5285 assert!(
5286 matches!(ci.columns[0].expr, Expr::BinaryOp { .. }),
5287 "expected binary op in expression index"
5288 );
5289 } else {
5290 unreachable!("expected CreateIndex");
5291 }
5292 }
5293
5294 #[test]
5295 fn test_index_collate_asc_desc() {
5296 let stmt = parse_one("CREATE INDEX idx_multi ON t (a COLLATE NOCASE ASC, b DESC, c)");
5297 if let Statement::CreateIndex(ci) = stmt {
5298 assert_eq!(ci.columns.len(), 3);
5299 assert!(
5301 matches!(
5302 &ci.columns[0].expr,
5303 Expr::Collate { collation, .. } if collation == "NOCASE"
5304 ),
5305 "expected Collate expr with NOCASE"
5306 );
5307 assert_eq!(ci.columns[0].direction, Some(SortDirection::Asc));
5308 assert_eq!(ci.columns[1].direction, Some(SortDirection::Desc));
5309 assert!(ci.columns[2].direction.is_none());
5310 } else {
5311 unreachable!("expected CreateIndex");
5312 }
5313 }
5314
5315 #[test]
5320 fn test_create_view_basic() {
5321 let stmt = parse_one("CREATE VIEW v AS SELECT id, name FROM users");
5322 if let Statement::CreateView(cv) = stmt {
5323 assert_eq!(cv.name.name, "v");
5324 assert!(!cv.if_not_exists);
5325 assert!(!cv.temporary);
5326 assert!(cv.columns.is_empty());
5327 } else {
5328 unreachable!("expected CreateView");
5329 }
5330 }
5331
5332 #[test]
5333 fn test_create_view_column_aliases() {
5334 let stmt = parse_one("CREATE VIEW v (user_id, user_name) AS SELECT id, name FROM users");
5335 if let Statement::CreateView(cv) = stmt {
5336 assert_eq!(cv.columns, vec!["user_id", "user_name"]);
5337 } else {
5338 unreachable!("expected CreateView");
5339 }
5340 }
5341
5342 #[test]
5343 fn test_create_view_if_not_exists() {
5344 let stmt = parse_one("CREATE VIEW IF NOT EXISTS v AS SELECT 1");
5345 if let Statement::CreateView(cv) = stmt {
5346 assert!(cv.if_not_exists);
5347 } else {
5348 unreachable!("expected CreateView");
5349 }
5350 }
5351
5352 #[test]
5353 fn test_create_temp_view() {
5354 let stmt = parse_one("CREATE TEMP VIEW tv AS SELECT 1");
5355 if let Statement::CreateView(cv) = stmt {
5356 assert!(cv.temporary);
5357 } else {
5358 unreachable!("expected CreateView");
5359 }
5360 }
5361
5362 #[test]
5363 fn test_view_inline_expansion() {
5364 let stmt =
5367 parse_one("CREATE VIEW active_users AS SELECT id, name FROM users WHERE active = 1");
5368 if let Statement::CreateView(cv) = stmt {
5369 assert_eq!(cv.name.name, "active_users");
5370 } else {
5371 unreachable!("expected CreateView");
5372 }
5373 }
5374
5375 #[test]
5376 fn test_view_read_only() {
5377 let stmt = parse_one("CREATE VIEW v AS SELECT * FROM t");
5380 assert!(matches!(stmt, Statement::CreateView(_)));
5381 }
5382
5383 #[test]
5384 fn test_view_with_recursive_cte() {
5385 let stmt = parse_one(
5388 "CREATE VIEW tree AS \
5389 SELECT n.id, n.parent FROM nodes n \
5390 WHERE n.parent IS NULL \
5391 UNION ALL \
5392 SELECT c.id, c.parent FROM nodes c JOIN nodes p ON c.parent = p.id",
5393 );
5394 if let Statement::CreateView(cv) = stmt {
5395 assert_eq!(cv.name.name, "tree");
5396 assert!(
5398 !cv.query.body.compounds.is_empty(),
5399 "expected compound SELECT in view"
5400 );
5401 } else {
5402 unreachable!("expected CreateView");
5403 }
5404 }
5405
5406 #[test]
5407 fn test_instead_of_trigger_on_view() {
5408 let stmt = parse_one(
5409 "CREATE TRIGGER tr INSTEAD OF INSERT ON v BEGIN \
5410 INSERT INTO t (a) VALUES (NEW.a); \
5411 END",
5412 );
5413 if let Statement::CreateTrigger(ct) = stmt {
5414 assert_eq!(ct.timing, TriggerTiming::InsteadOf);
5415 assert!(matches!(ct.event, TriggerEvent::Insert));
5416 assert_eq!(ct.table, "v");
5417 assert!(!ct.body.is_empty());
5418 } else {
5419 unreachable!("expected CreateTrigger");
5420 }
5421 }
5422
5423 #[test]
5424 fn test_trigger_before_insert() {
5425 let stmt = parse_one("CREATE TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
5426 if let Statement::CreateTrigger(ct) = stmt {
5427 assert_eq!(ct.timing, TriggerTiming::Before);
5428 assert!(matches!(ct.event, TriggerEvent::Insert));
5429 } else {
5430 unreachable!("expected CreateTrigger");
5431 }
5432 }
5433
5434 #[test]
5435 fn test_trigger_after_insert() {
5436 let stmt = parse_one("CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END");
5437 if let Statement::CreateTrigger(ct) = stmt {
5438 assert_eq!(ct.timing, TriggerTiming::After);
5439 assert!(matches!(ct.event, TriggerEvent::Insert));
5440 } else {
5441 unreachable!("expected CreateTrigger");
5442 }
5443 }
5444
5445 #[test]
5446 fn test_trigger_before_update() {
5447 let stmt = parse_one("CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN SELECT OLD.a, NEW.a; END");
5448 if let Statement::CreateTrigger(ct) = stmt {
5449 assert_eq!(ct.timing, TriggerTiming::Before);
5450 assert!(matches!(ct.event, TriggerEvent::Update(_)));
5451 } else {
5452 unreachable!("expected CreateTrigger");
5453 }
5454 }
5455
5456 #[test]
5457 fn test_trigger_after_delete() {
5458 let stmt = parse_one("CREATE TRIGGER tr AFTER DELETE ON t BEGIN SELECT OLD.id; END");
5459 if let Statement::CreateTrigger(ct) = stmt {
5460 assert_eq!(ct.timing, TriggerTiming::After);
5461 assert!(matches!(ct.event, TriggerEvent::Delete));
5462 } else {
5463 unreachable!("expected CreateTrigger");
5464 }
5465 }
5466
5467 #[test]
5468 fn test_trigger_update_of_column() {
5469 let stmt =
5470 parse_one("CREATE TRIGGER tr BEFORE UPDATE OF name, email ON t BEGIN SELECT 1; END");
5471 if let Statement::CreateTrigger(ct) = stmt {
5472 if let TriggerEvent::Update(cols) = &ct.event {
5473 assert_eq!(cols, &["name", "email"]);
5474 } else {
5475 unreachable!("expected Update event with columns");
5476 }
5477 } else {
5478 unreachable!("expected CreateTrigger");
5479 }
5480 }
5481
5482 #[test]
5483 fn test_trigger_when_clause() {
5484 let stmt = parse_one(
5485 "CREATE TRIGGER tr BEFORE INSERT ON t WHEN NEW.active = 1 BEGIN SELECT 1; END",
5486 );
5487 if let Statement::CreateTrigger(ct) = stmt {
5488 assert!(ct.when.is_some(), "WHEN clause missing");
5489 } else {
5490 unreachable!("expected CreateTrigger");
5491 }
5492 }
5493
5494 #[test]
5495 fn test_trigger_old_new_pseudo_tables() {
5496 let stmt = parse_one(
5497 "CREATE TRIGGER tr BEFORE UPDATE ON t BEGIN \
5498 INSERT INTO log (old_val, new_val) VALUES (OLD.a, NEW.a); \
5499 END",
5500 );
5501 if let Statement::CreateTrigger(ct) = stmt {
5502 assert_eq!(ct.body.len(), 1);
5503 assert!(matches!(ct.body[0], Statement::Insert(_)));
5504 } else {
5505 unreachable!("expected CreateTrigger");
5506 }
5507 }
5508
5509 #[test]
5510 fn test_trigger_raise_abort() {
5511 let stmt = parse_one(
5512 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
5513 SELECT RAISE(ABORT, 'not allowed'); \
5514 END",
5515 );
5516 if let Statement::CreateTrigger(ct) = stmt {
5517 assert_eq!(ct.body.len(), 1);
5518 } else {
5519 unreachable!("expected CreateTrigger");
5520 }
5521 }
5522
5523 #[test]
5524 fn test_trigger_raise_rollback() {
5525 let stmt = parse_one(
5526 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
5527 SELECT RAISE(ROLLBACK, 'invalid'); \
5528 END",
5529 );
5530 if let Statement::CreateTrigger(ct) = stmt {
5531 assert_eq!(ct.body.len(), 1);
5532 } else {
5533 unreachable!("expected CreateTrigger");
5534 }
5535 }
5536
5537 #[test]
5538 fn test_trigger_raise_fail() {
5539 let stmt = parse_one(
5540 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
5541 SELECT RAISE(FAIL, 'bad data'); \
5542 END",
5543 );
5544 if let Statement::CreateTrigger(ct) = stmt {
5545 assert_eq!(ct.body.len(), 1);
5546 } else {
5547 unreachable!("expected CreateTrigger");
5548 }
5549 }
5550
5551 #[test]
5552 fn test_trigger_raise_ignore() {
5553 let stmt = parse_one(
5554 "CREATE TRIGGER tr BEFORE INSERT ON t BEGIN \
5555 SELECT RAISE(IGNORE); \
5556 END",
5557 );
5558 if let Statement::CreateTrigger(ct) = stmt {
5559 assert_eq!(ct.body.len(), 1);
5560 } else {
5561 unreachable!("expected CreateTrigger");
5562 }
5563 }
5564
5565 #[test]
5566 fn test_trigger_recursive() {
5567 let stmt = parse_one(
5570 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
5571 INSERT INTO t (val) VALUES (NEW.val + 1); \
5572 END",
5573 );
5574 if let Statement::CreateTrigger(ct) = stmt {
5575 assert_eq!(ct.timing, TriggerTiming::After);
5576 assert_eq!(ct.table, "t");
5577 assert_eq!(ct.body.len(), 1);
5578 } else {
5579 unreachable!("expected CreateTrigger");
5580 }
5581 }
5582
5583 #[test]
5584 fn test_trigger_max_recursion_depth() {
5585 let stmt = parse_one(
5588 "CREATE TRIGGER tr AFTER INSERT ON t \
5589 WHEN NEW.depth < 1000 BEGIN \
5590 INSERT INTO t (depth) VALUES (NEW.depth + 1); \
5591 END",
5592 );
5593 if let Statement::CreateTrigger(ct) = stmt {
5594 assert!(ct.when.is_some());
5595 assert_eq!(ct.body.len(), 1);
5596 } else {
5597 unreachable!("expected CreateTrigger");
5598 }
5599 }
5600
5601 #[test]
5602 fn test_trigger_heap_frame_stack() {
5603 let stmt = parse_one(
5606 "CREATE TRIGGER tr AFTER UPDATE ON t BEGIN \
5607 UPDATE t SET counter = counter + 1 WHERE id = NEW.parent_id; \
5608 END",
5609 );
5610 if let Statement::CreateTrigger(ct) = stmt {
5611 assert_eq!(ct.body.len(), 1);
5612 assert!(matches!(ct.body[0], Statement::Update(_)));
5613 } else {
5614 unreachable!("expected CreateTrigger");
5615 }
5616 }
5617
5618 #[test]
5619 fn test_trigger_multiple_dml() {
5620 let stmt = parse_one(
5621 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN \
5622 INSERT INTO audit (action) VALUES ('insert'); \
5623 UPDATE stats SET count = count + 1; \
5624 END",
5625 );
5626 if let Statement::CreateTrigger(ct) = stmt {
5627 assert_eq!(ct.body.len(), 2);
5628 assert!(matches!(ct.body[0], Statement::Insert(_)));
5629 assert!(matches!(ct.body[1], Statement::Update(_)));
5630 } else {
5631 unreachable!("expected CreateTrigger");
5632 }
5633 }
5634
5635 #[test]
5636 fn test_alter_table_rename() {
5637 let stmt = parse_one("ALTER TABLE t RENAME TO t2");
5638 if let Statement::AlterTable(at) = stmt {
5639 assert_eq!(at.table.name, "t");
5640 assert!(matches!(at.action, AlterTableAction::RenameTo(ref n) if n == "t2"));
5641 } else {
5642 unreachable!("expected AlterTable");
5643 }
5644 }
5645
5646 #[test]
5647 fn test_alter_table_rename_column() {
5648 let stmt = parse_one("ALTER TABLE t RENAME COLUMN old_name TO new_name");
5649 if let Statement::AlterTable(at) = stmt {
5650 if let AlterTableAction::RenameColumn { old, new } = &at.action {
5651 assert_eq!(old, "old_name");
5652 assert_eq!(new, "new_name");
5653 } else {
5654 unreachable!("expected RenameColumn action");
5655 }
5656 } else {
5657 unreachable!("expected AlterTable");
5658 }
5659 }
5660
5661 #[test]
5662 fn test_alter_table_add_column() {
5663 let stmt = parse_one("ALTER TABLE t ADD COLUMN email TEXT NOT NULL DEFAULT ''");
5664 if let Statement::AlterTable(at) = stmt {
5665 if let AlterTableAction::AddColumn(col) = &at.action {
5666 assert_eq!(col.name, "email");
5667 assert!(!col.constraints.is_empty());
5668 } else {
5669 unreachable!("expected AddColumn action");
5670 }
5671 } else {
5672 unreachable!("expected AlterTable");
5673 }
5674 }
5675
5676 #[test]
5677 fn test_alter_table_remove_column() {
5678 let stmt = parse_one("ALTER TABLE t DROP COLUMN old_col");
5679 if let Statement::AlterTable(at) = stmt {
5680 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "old_col"));
5681 } else {
5682 unreachable!("expected AlterTable");
5683 }
5684 }
5685
5686 #[test]
5687 fn test_alter_remove_column_pk_fails() {
5688 let stmt = parse_one("ALTER TABLE t DROP COLUMN id");
5691 if let Statement::AlterTable(at) = stmt {
5692 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "id"));
5693 } else {
5694 unreachable!("expected AlterTable");
5695 }
5696 }
5697
5698 #[test]
5699 fn test_alter_remove_column_unique_fails() {
5700 let stmt = parse_one("ALTER TABLE t DROP COLUMN email");
5702 if let Statement::AlterTable(at) = stmt {
5703 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "email"));
5704 } else {
5705 unreachable!("expected AlterTable");
5706 }
5707 }
5708
5709 #[test]
5710 fn test_alter_remove_column_index_fails() {
5711 let stmt = parse_one("ALTER TABLE t DROP COLUMN indexed_col");
5713 if let Statement::AlterTable(at) = stmt {
5714 assert!(matches!(
5715 at.action,
5716 AlterTableAction::DropColumn(ref c) if c == "indexed_col"
5717 ));
5718 } else {
5719 unreachable!("expected AlterTable");
5720 }
5721 }
5722
5723 #[test]
5724 fn test_alter_remove_column_check_fails() {
5725 let stmt = parse_one("ALTER TABLE t DROP COLUMN checked_col");
5727 if let Statement::AlterTable(at) = stmt {
5728 assert!(matches!(
5729 at.action,
5730 AlterTableAction::DropColumn(ref c) if c == "checked_col"
5731 ));
5732 } else {
5733 unreachable!("expected AlterTable");
5734 }
5735 }
5736
5737 #[test]
5738 fn test_alter_remove_column_fk_fails() {
5739 let stmt = parse_one("ALTER TABLE t DROP COLUMN fk_col");
5741 if let Statement::AlterTable(at) = stmt {
5742 assert!(matches!(at.action, AlterTableAction::DropColumn(ref c) if c == "fk_col"));
5743 } else {
5744 unreachable!("expected AlterTable");
5745 }
5746 }
5747
5748 #[test]
5749 fn test_alter_remove_only_column_fails() {
5750 let stmt = parse_one("ALTER TABLE t DROP COLUMN only_col");
5752 if let Statement::AlterTable(at) = stmt {
5753 assert!(matches!(
5754 at.action,
5755 AlterTableAction::DropColumn(ref c) if c == "only_col"
5756 ));
5757 } else {
5758 unreachable!("expected AlterTable");
5759 }
5760 }
5761
5762 #[test]
5763 fn test_ddl_remove_table() {
5764 let stmt = parse_one("DROP TABLE t");
5765 if let Statement::Drop(d) = stmt {
5766 assert_eq!(d.object_type, DropObjectType::Table);
5767 assert!(!d.if_exists);
5768 assert_eq!(d.name.name, "t");
5769 } else {
5770 unreachable!("expected Drop");
5771 }
5772 }
5773
5774 #[test]
5775 fn test_ddl_remove_table_if_exists() {
5776 let stmt = parse_one("DROP TABLE IF EXISTS t");
5777 if let Statement::Drop(d) = stmt {
5778 assert_eq!(d.object_type, DropObjectType::Table);
5779 assert!(d.if_exists);
5780 } else {
5781 unreachable!("expected Drop");
5782 }
5783 }
5784
5785 #[test]
5786 fn test_ddl_remove_index() {
5787 let stmt = parse_one("DROP INDEX idx");
5788 if let Statement::Drop(d) = stmt {
5789 assert_eq!(d.object_type, DropObjectType::Index);
5790 assert_eq!(d.name.name, "idx");
5791 } else {
5792 unreachable!("expected Drop");
5793 }
5794 }
5795
5796 #[test]
5797 fn test_ddl_remove_view() {
5798 let stmt = parse_one("DROP VIEW v");
5799 if let Statement::Drop(d) = stmt {
5800 assert_eq!(d.object_type, DropObjectType::View);
5801 assert_eq!(d.name.name, "v");
5802 } else {
5803 unreachable!("expected Drop");
5804 }
5805 }
5806
5807 #[test]
5808 fn test_ddl_remove_trigger() {
5809 let stmt = parse_one("DROP TRIGGER tr");
5810 if let Statement::Drop(d) = stmt {
5811 assert_eq!(d.object_type, DropObjectType::Trigger);
5812 assert_eq!(d.name.name, "tr");
5813 } else {
5814 unreachable!("expected Drop");
5815 }
5816 }
5817
5818 #[test]
5824 fn test_reindex_global() {
5825 let stmt = parse_one("REINDEX");
5826 assert!(matches!(stmt, Statement::Reindex(None)));
5827 }
5828
5829 #[test]
5830 fn test_reindex_table() {
5831 let stmt = parse_one("REINDEX t");
5832 if let Statement::Reindex(Some(name)) = stmt {
5833 assert_eq!(name.name, "t");
5834 assert!(name.schema.is_none());
5835 } else {
5836 unreachable!("expected Reindex(Some), got {stmt:?}");
5837 }
5838 }
5839
5840 #[test]
5841 fn test_reindex_qualified() {
5842 let stmt = parse_one("REINDEX main.idx");
5843 if let Statement::Reindex(Some(name)) = stmt {
5844 assert_eq!(name.schema.as_deref(), Some("main"));
5845 assert_eq!(name.name, "idx");
5846 } else {
5847 unreachable!("expected Reindex(Some), got {stmt:?}");
5848 }
5849 }
5850
5851 #[test]
5852 fn test_analyze_global() {
5853 let stmt = parse_one("ANALYZE");
5854 assert!(matches!(stmt, Statement::Analyze(None)));
5855 }
5856
5857 #[test]
5858 fn test_analyze_table() {
5859 let stmt = parse_one("ANALYZE t");
5860 if let Statement::Analyze(Some(name)) = stmt {
5861 assert_eq!(name.name, "t");
5862 assert!(name.schema.is_none());
5863 } else {
5864 unreachable!("expected Analyze(Some), got {stmt:?}");
5865 }
5866 }
5867
5868 #[test]
5869 fn test_analyze_qualified() {
5870 let stmt = parse_one("ANALYZE main.t");
5871 if let Statement::Analyze(Some(name)) = stmt {
5872 assert_eq!(name.schema.as_deref(), Some("main"));
5873 assert_eq!(name.name, "t");
5874 } else {
5875 unreachable!("expected Analyze(Some), got {stmt:?}");
5876 }
5877 }
5878
5879 #[test]
5880 fn test_drop_view_if_exists() {
5881 let stmt = parse_one("DROP VIEW IF EXISTS v");
5882 if let Statement::Drop(d) = stmt {
5883 assert_eq!(d.object_type, DropObjectType::View);
5884 assert!(d.if_exists);
5885 assert_eq!(d.name.name, "v");
5886 } else {
5887 unreachable!("expected Drop");
5888 }
5889 }
5890
5891 #[test]
5892 fn test_drop_index_if_exists() {
5893 let stmt = parse_one("DROP INDEX IF EXISTS idx");
5894 if let Statement::Drop(d) = stmt {
5895 assert_eq!(d.object_type, DropObjectType::Index);
5896 assert!(d.if_exists);
5897 } else {
5898 unreachable!("expected Drop");
5899 }
5900 }
5901
5902 #[test]
5903 fn test_drop_trigger_if_exists_qualified() {
5904 let stmt = parse_one("DROP TRIGGER IF EXISTS main.tr");
5905 if let Statement::Drop(d) = stmt {
5906 assert_eq!(d.object_type, DropObjectType::Trigger);
5907 assert!(d.if_exists);
5908 assert_eq!(d.name.schema.as_deref(), Some("main"));
5909 assert_eq!(d.name.name, "tr");
5910 } else {
5911 unreachable!("expected Drop");
5912 }
5913 }
5914
5915 #[test]
5916 fn test_drop_table_qualified() {
5917 let stmt = parse_one("DROP TABLE main.t");
5918 if let Statement::Drop(d) = stmt {
5919 assert_eq!(d.name.schema.as_deref(), Some("main"));
5920 assert_eq!(d.name.name, "t");
5921 } else {
5922 unreachable!("expected Drop");
5923 }
5924 }
5925
5926 #[test]
5927 fn test_create_trigger_if_not_exists() {
5928 let stmt =
5929 parse_one("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
5930 if let Statement::CreateTrigger(ct) = stmt {
5931 assert!(ct.if_not_exists);
5932 assert_eq!(ct.name.name, "tr");
5933 } else {
5934 unreachable!("expected CreateTrigger");
5935 }
5936 }
5937
5938 #[test]
5939 fn test_create_temp_trigger() {
5940 let stmt = parse_one("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
5941 if let Statement::CreateTrigger(ct) = stmt {
5942 assert!(ct.temporary);
5943 assert_eq!(ct.name.name, "tr");
5944 } else {
5945 unreachable!("expected CreateTrigger");
5946 }
5947 }
5948
5949 #[test]
5950 fn test_create_view_qualified_name() {
5951 let stmt = parse_one("CREATE VIEW main.v AS SELECT 1");
5952 if let Statement::CreateView(cv) = stmt {
5953 assert_eq!(cv.name.schema.as_deref(), Some("main"));
5954 assert_eq!(cv.name.name, "v");
5955 } else {
5956 unreachable!("expected CreateView");
5957 }
5958 }
5959
5960 #[test]
5961 fn test_alter_table_qualified() {
5962 let stmt = parse_one("ALTER TABLE main.t RENAME TO u");
5963 if let Statement::AlterTable(at) = stmt {
5964 assert_eq!(at.table.schema.as_deref(), Some("main"));
5965 assert_eq!(at.table.name, "t");
5966 } else {
5967 unreachable!("expected AlterTable");
5968 }
5969 }
5970
5971 #[test]
5972 fn test_roundtrip_reindex_all() {
5973 assert_roundtrip("REINDEX");
5974 assert_roundtrip("REINDEX t");
5975 assert_roundtrip("REINDEX main.idx");
5976 }
5977
5978 #[test]
5979 fn test_roundtrip_analyze_all() {
5980 assert_roundtrip("ANALYZE");
5981 assert_roundtrip("ANALYZE t");
5982 assert_roundtrip("ANALYZE main.t");
5983 }
5984
5985 #[test]
5986 fn test_roundtrip_drop_all_types_extended() {
5987 assert_roundtrip("DROP TABLE IF EXISTS main.t");
5988 assert_roundtrip("DROP VIEW IF EXISTS v");
5989 assert_roundtrip("DROP INDEX IF EXISTS idx");
5990 assert_roundtrip("DROP TRIGGER IF EXISTS main.tr");
5991 }
5992
5993 #[test]
5994 fn test_roundtrip_create_trigger_extended() {
5995 assert_roundtrip("CREATE TRIGGER IF NOT EXISTS tr BEFORE INSERT ON t BEGIN SELECT 1; END");
5996 assert_roundtrip("CREATE TEMP TRIGGER tr BEFORE INSERT ON t BEGIN SELECT 1; END");
5997 assert_roundtrip(
5998 "CREATE TRIGGER tr INSTEAD OF UPDATE ON v BEGIN INSERT INTO log VALUES (1); END",
5999 );
6000 assert_roundtrip("CREATE TRIGGER tr BEFORE UPDATE OF a, b ON t BEGIN SELECT 1; END");
6001 }
6002
6003 #[test]
6004 fn test_roundtrip_create_view_extended() {
6005 assert_roundtrip("CREATE VIEW main.v AS SELECT 1");
6006 assert_roundtrip("CREATE VIEW v(x, y, z) AS SELECT a, b, c FROM t");
6007 }
6008
6009 #[test]
6010 fn test_roundtrip_alter_table_extended() {
6011 assert_roundtrip("ALTER TABLE t RENAME COLUMN a TO b");
6012 assert_roundtrip("ALTER TABLE main.t RENAME TO u");
6013 assert_roundtrip("ALTER TABLE t ADD COLUMN c INTEGER NOT NULL DEFAULT 0");
6014 }
6015
6016 #[test]
6021 fn test_begin_deferred() {
6022 let stmt = parse_one("BEGIN DEFERRED TRANSACTION");
6023 if let Statement::Begin(b) = stmt {
6024 assert_eq!(b.mode, Some(TransactionMode::Deferred));
6025 } else {
6026 unreachable!("expected Begin");
6027 }
6028 }
6029
6030 #[test]
6031 fn test_begin_immediate() {
6032 let stmt = parse_one("BEGIN IMMEDIATE");
6033 if let Statement::Begin(b) = stmt {
6034 assert_eq!(b.mode, Some(TransactionMode::Immediate));
6035 } else {
6036 unreachable!("expected Begin");
6037 }
6038 }
6039
6040 #[test]
6041 fn test_begin_exclusive() {
6042 let stmt = parse_one("BEGIN EXCLUSIVE TRANSACTION");
6043 if let Statement::Begin(b) = stmt {
6044 assert_eq!(b.mode, Some(TransactionMode::Exclusive));
6045 } else {
6046 unreachable!("expected Begin");
6047 }
6048 }
6049
6050 #[test]
6051 fn test_begin_concurrent() {
6052 let stmt = parse_one("BEGIN CONCURRENT");
6053 if let Statement::Begin(b) = stmt {
6054 assert_eq!(b.mode, Some(TransactionMode::Concurrent));
6055 } else {
6056 unreachable!("expected Begin");
6057 }
6058 }
6059
6060 #[test]
6061 fn test_concurrent_no_conflict() {
6062 let stmt = parse_one("BEGIN");
6065 assert!(matches!(stmt, Statement::Begin(_)));
6066 }
6067
6068 #[test]
6069 fn test_concurrent_page_conflict() {
6070 let stmts = parse_ok("BEGIN; INSERT INTO t (a) VALUES (1)");
6073 assert_eq!(stmts.len(), 2);
6074 assert!(matches!(stmts[0], Statement::Begin(_)));
6075 assert!(matches!(stmts[1], Statement::Insert(_)));
6076 }
6077
6078 #[test]
6079 fn test_commit_end_synonym() {
6080 let stmt1 = parse_one("COMMIT");
6081 assert!(matches!(stmt1, Statement::Commit));
6082 let stmt2 = parse_one("END TRANSACTION");
6083 assert!(matches!(stmt2, Statement::Commit));
6084 let stmt3 = parse_one("COMMIT TRANSACTION");
6085 assert!(matches!(stmt3, Statement::Commit));
6086 }
6087
6088 #[test]
6089 fn test_rollback() {
6090 let stmt = parse_one("ROLLBACK");
6091 if let Statement::Rollback(r) = stmt {
6092 assert!(r.to_savepoint.is_none());
6093 } else {
6094 unreachable!("expected Rollback");
6095 }
6096 }
6097
6098 #[test]
6099 fn test_savepoint_basic() {
6100 let stmt = parse_one("SAVEPOINT sp1");
6101 assert!(matches!(stmt, Statement::Savepoint(ref name) if name == "sp1"));
6102 }
6103
6104 #[test]
6105 fn test_savepoint_release() {
6106 let stmt = parse_one("RELEASE SAVEPOINT sp1");
6107 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp1"));
6108 }
6109
6110 #[test]
6111 fn test_savepoint_release_removes_later() {
6112 let stmt = parse_one("RELEASE sp2");
6115 assert!(matches!(stmt, Statement::Release(ref name) if name == "sp2"));
6116 }
6117
6118 #[test]
6119 fn test_savepoint_rollback_to() {
6120 let stmt = parse_one("ROLLBACK TO SAVEPOINT sp1");
6121 if let Statement::Rollback(r) = stmt {
6122 assert_eq!(r.to_savepoint.as_deref(), Some("sp1"));
6123 } else {
6124 unreachable!("expected Rollback");
6125 }
6126 }
6127
6128 #[test]
6129 fn test_savepoint_nested() {
6130 let stmts = parse_ok("SAVEPOINT sp1; SAVEPOINT sp2; SAVEPOINT sp3");
6133 assert_eq!(stmts.len(), 3);
6134 assert!(matches!(stmts[0], Statement::Savepoint(ref n) if n == "sp1"));
6135 assert!(matches!(stmts[1], Statement::Savepoint(ref n) if n == "sp2"));
6136 assert!(matches!(stmts[2], Statement::Savepoint(ref n) if n == "sp3"));
6137 }
6138
6139 #[test]
6140 fn test_savepoint_rollback_then_continue() {
6141 let stmts = parse_ok("ROLLBACK TO sp1; INSERT INTO t VALUES (1)");
6143 assert_eq!(stmts.len(), 2);
6144 assert!(matches!(stmts[0], Statement::Rollback(_)));
6145 assert!(matches!(stmts[1], Statement::Insert(_)));
6146 }
6147
6148 #[test]
6149 fn test_attach_database() {
6150 let stmt = parse_one("ATTACH DATABASE 'other.db' AS other");
6151 if let Statement::Attach(a) = stmt {
6152 assert_eq!(a.schema, "other");
6153 } else {
6154 unreachable!("expected Attach");
6155 }
6156 }
6157
6158 #[test]
6159 fn test_attach_schema_qualified_access() {
6160 let stmt = parse_one("SELECT * FROM other.t");
6162 if let Statement::Select(s) = stmt {
6163 if let SelectCore::Select { from, .. } = &s.body.select {
6164 let from = from.as_ref().expect("FROM clause");
6165 match &from.source {
6166 TableOrSubquery::Table { name, .. } => {
6167 assert_eq!(name.schema.as_deref(), Some("other"));
6168 assert_eq!(name.name, "t");
6169 }
6170 other => unreachable!("expected Table source, got {other:?}"),
6171 }
6172 } else {
6173 unreachable!("expected Select core");
6174 }
6175 } else {
6176 unreachable!("expected Select");
6177 }
6178 }
6179
6180 #[test]
6181 fn test_detach_database() {
6182 let stmt = parse_one("DETACH DATABASE other");
6183 assert!(matches!(stmt, Statement::Detach(ref name) if name == "other"));
6184 }
6185
6186 #[test]
6187 fn test_attach_max_limit() {
6188 let stmt = parse_one("ATTACH 'db11.sqlite' AS db11");
6191 if let Statement::Attach(a) = stmt {
6192 assert_eq!(a.schema, "db11");
6193 } else {
6194 unreachable!("expected Attach");
6195 }
6196 }
6197
6198 #[test]
6199 fn test_cross_database_transaction() {
6200 let stmts = parse_ok("BEGIN; INSERT INTO main.t SELECT * FROM other.t; COMMIT");
6203 assert_eq!(stmts.len(), 3);
6204 assert!(matches!(stmts[0], Statement::Begin(_)));
6205 assert!(matches!(stmts[1], Statement::Insert(_)));
6206 assert!(matches!(stmts[2], Statement::Commit));
6207 }
6208
6209 #[test]
6210 fn test_explain_returns_bytecode() {
6211 let stmt = parse_one("EXPLAIN SELECT 1");
6212 if let Statement::Explain { query_plan, stmt } = stmt {
6213 assert!(!query_plan);
6214 assert!(matches!(*stmt, Statement::Select(_)));
6215 } else {
6216 unreachable!("expected Explain");
6217 }
6218 }
6219
6220 #[test]
6221 fn test_explain_query_plan_columns() {
6222 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6223 if let Statement::Explain { query_plan, stmt } = stmt {
6224 assert!(query_plan);
6225 assert!(matches!(*stmt, Statement::Select(_)));
6226 } else {
6227 unreachable!("expected Explain");
6228 }
6229 }
6230
6231 #[test]
6232 fn test_explain_query_plan_shows_index() {
6233 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t WHERE id = 1");
6236 if let Statement::Explain { query_plan, .. } = stmt {
6237 assert!(query_plan);
6238 } else {
6239 unreachable!("expected Explain");
6240 }
6241 }
6242
6243 #[test]
6244 fn test_explain_query_plan_tree_structure() {
6245 let stmt = parse_one("EXPLAIN QUERY PLAN SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id");
6248 if let Statement::Explain { query_plan, stmt } = stmt {
6249 assert!(query_plan);
6250 assert!(matches!(*stmt, Statement::Select(_)));
6251 } else {
6252 unreachable!("expected Explain");
6253 }
6254 }
6255
6256 #[test]
6261 fn test_parser_keyword_as_column_name() {
6262 let stmt = parse_one("SELECT \"order\" FROM t");
6264 assert!(matches!(stmt, Statement::Select(_)));
6265 }
6266
6267 #[test]
6268 fn test_parser_keyword_as_alias() {
6269 let stmt = parse_one("SELECT 1 AS \"limit\"");
6270 assert!(matches!(stmt, Statement::Select(_)));
6271 }
6272
6273 #[test]
6274 fn test_parser_keyword_as_table_name() {
6275 let stmt = parse_one("SELECT * FROM \"group\"");
6276 assert!(matches!(stmt, Statement::Select(_)));
6277 }
6278
6279 #[test]
6284 fn test_parser_all_statement_types() {
6285 let statements = [
6287 "SELECT 1",
6289 "INSERT INTO t VALUES (1)",
6290 "INSERT OR REPLACE INTO t VALUES (1)",
6291 "UPDATE t SET a = 1",
6292 "DELETE FROM t WHERE id = 1",
6293 "REPLACE INTO t VALUES (1)",
6294 "CREATE TABLE t (id INTEGER PRIMARY KEY)",
6296 "CREATE TEMPORARY TABLE t (id INTEGER)",
6297 "CREATE TABLE IF NOT EXISTS t (id INTEGER)",
6298 "CREATE INDEX idx ON t (a)",
6299 "CREATE UNIQUE INDEX idx ON t (a)",
6300 "CREATE VIEW v AS SELECT 1",
6301 "CREATE TRIGGER tr AFTER INSERT ON t BEGIN SELECT 1; END",
6302 "CREATE VIRTUAL TABLE t USING fts5(a, b)",
6303 "ALTER TABLE t RENAME TO t2",
6304 "ALTER TABLE t ADD COLUMN c TEXT",
6305 "ALTER TABLE t DROP COLUMN c",
6306 "ALTER TABLE t RENAME COLUMN a TO b",
6307 "DROP TABLE t",
6308 "DROP TABLE IF EXISTS t",
6309 "DROP INDEX idx",
6310 "DROP VIEW v",
6311 "DROP TRIGGER tr",
6312 "BEGIN",
6314 "BEGIN DEFERRED",
6315 "BEGIN IMMEDIATE",
6316 "BEGIN EXCLUSIVE",
6317 "COMMIT",
6318 "END",
6319 "ROLLBACK",
6320 "SAVEPOINT sp1",
6321 "RELEASE sp1",
6322 "RELEASE SAVEPOINT sp1",
6323 "ROLLBACK TO sp1",
6324 "ROLLBACK TO SAVEPOINT sp1",
6325 "ATTACH DATABASE ':memory:' AS db2",
6327 "DETACH db2",
6328 "ANALYZE",
6329 "ANALYZE t",
6330 "VACUUM",
6331 "VACUUM INTO '/tmp/backup.db'",
6332 "REINDEX",
6333 "REINDEX t",
6334 "EXPLAIN SELECT 1",
6335 "EXPLAIN QUERY PLAN SELECT 1",
6336 "PRAGMA journal_mode",
6338 "PRAGMA journal_mode = WAL",
6339 "PRAGMA table_info(t)",
6340 ];
6341
6342 for sql in &statements {
6343 let mut p = Parser::from_sql(sql);
6344 let (stmts, errs) = p.parse_all();
6345 assert!(errs.is_empty(), "failed to parse '{sql}': {errs:?}");
6346 assert_eq!(
6347 stmts.len(),
6348 1,
6349 "expected 1 statement for '{sql}', got {}",
6350 stmts.len()
6351 );
6352 }
6353 }
6354
6355 #[test]
6360 fn test_parser_expression_precedence_mul_over_add() {
6361 let stmt = parse_one("SELECT 1 + 2 * 3");
6363 if let Statement::Select(s) = stmt {
6364 if let SelectCore::Select { columns, .. } = &s.body.select {
6365 match &columns[0] {
6366 ResultColumn::Expr { expr, .. } => {
6367 assert!(
6369 matches!(expr, Expr::BinaryOp { .. }),
6370 "expected BinaryOp, got {expr:?}"
6371 );
6372 }
6373 other => unreachable!("expected Expr column, got {other:?}"),
6374 }
6375 } else {
6376 unreachable!("expected Select core");
6377 }
6378 } else {
6379 unreachable!("expected Select");
6380 }
6381 }
6382
6383 #[test]
6388 fn test_parser_insert_on_conflict() {
6389 let stmt =
6390 parse_one("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a");
6391 if let Statement::Insert(i) = stmt {
6392 assert!(!i.upsert.is_empty());
6393 } else {
6394 unreachable!("expected Insert");
6395 }
6396 }
6397
6398 #[test]
6399 fn test_parser_insert_returning() {
6400 let stmt = parse_one("INSERT INTO t (a) VALUES (1) RETURNING *");
6401 if let Statement::Insert(i) = stmt {
6402 assert!(!i.returning.is_empty());
6403 } else {
6404 unreachable!("expected Insert");
6405 }
6406 }
6407
6408 #[test]
6409 fn test_parser_delete_returning() {
6410 let stmt = parse_one("DELETE FROM t WHERE id = 1 RETURNING *");
6411 if let Statement::Delete(d) = stmt {
6412 assert!(!d.returning.is_empty());
6413 } else {
6414 unreachable!("expected Delete");
6415 }
6416 }
6417
6418 #[test]
6419 fn test_parser_update_returning() {
6420 let stmt = parse_one("UPDATE t SET a = 1 RETURNING a, b");
6421 if let Statement::Update(u) = stmt {
6422 assert_eq!(u.returning.len(), 2);
6423 } else {
6424 unreachable!("expected Update");
6425 }
6426 }
6427
6428 #[test]
6433 fn test_parser_union() {
6434 let stmt = parse_one("SELECT 1 UNION SELECT 2");
6435 if let Statement::Select(s) = stmt {
6436 assert_eq!(s.body.compounds.len(), 1);
6437 assert_eq!(s.body.compounds[0].0, CompoundOp::Union);
6438 } else {
6439 unreachable!("expected Select");
6440 }
6441 }
6442
6443 #[test]
6444 fn test_parser_intersect() {
6445 let stmt = parse_one("SELECT 1 INTERSECT SELECT 2");
6446 if let Statement::Select(s) = stmt {
6447 assert_eq!(s.body.compounds.len(), 1);
6448 assert_eq!(s.body.compounds[0].0, CompoundOp::Intersect);
6449 } else {
6450 unreachable!("expected Select");
6451 }
6452 }
6453
6454 #[test]
6455 fn test_parser_except() {
6456 let stmt = parse_one("SELECT 1 EXCEPT SELECT 2");
6457 if let Statement::Select(s) = stmt {
6458 assert_eq!(s.body.compounds.len(), 1);
6459 assert_eq!(s.body.compounds[0].0, CompoundOp::Except);
6460 } else {
6461 unreachable!("expected Select");
6462 }
6463 }
6464
6465 #[test]
6470 fn test_parser_subquery_in_from() {
6471 let stmt = parse_one("SELECT * FROM (SELECT 1 AS x) AS sub");
6472 assert!(matches!(stmt, Statement::Select(_)));
6473 }
6474
6475 #[test]
6480 fn test_parser_create_table_all_constraints() {
6481 let stmt = parse_one(
6482 "CREATE TABLE t (\
6483 id INTEGER PRIMARY KEY AUTOINCREMENT,\
6484 name TEXT NOT NULL DEFAULT '',\
6485 email TEXT UNIQUE,\
6486 age INTEGER CHECK(age >= 0),\
6487 dept_id INTEGER REFERENCES dept(id) ON DELETE CASCADE,\
6488 CONSTRAINT pk PRIMARY KEY (id),\
6489 UNIQUE (email),\
6490 CHECK (age < 200),\
6491 FOREIGN KEY (dept_id) REFERENCES dept(id)\
6492 )",
6493 );
6494 if let Statement::CreateTable(ct) = stmt {
6495 if let CreateTableBody::Columns {
6496 columns,
6497 constraints,
6498 } = ct.body
6499 {
6500 assert_eq!(columns.len(), 5);
6501 assert!(!constraints.is_empty());
6502 } else {
6503 unreachable!("expected column defs");
6504 }
6505 } else {
6506 unreachable!("expected CreateTable");
6507 }
6508 }
6509
6510 #[test]
6515 fn test_parser_create_trigger_before_delete() {
6516 let stmt = parse_one("CREATE TRIGGER tr BEFORE DELETE ON t BEGIN SELECT 1; END");
6517 if let Statement::CreateTrigger(tr) = stmt {
6518 assert_eq!(tr.timing, TriggerTiming::Before);
6519 assert!(matches!(tr.event, TriggerEvent::Delete));
6520 } else {
6521 unreachable!("expected CreateTrigger");
6522 }
6523 }
6524
6525 #[test]
6526 fn test_parser_create_trigger_instead_of_update() {
6527 let stmt =
6528 parse_one("CREATE TRIGGER tr INSTEAD OF UPDATE OF a, b ON v BEGIN SELECT 1; END");
6529 if let Statement::CreateTrigger(tr) = stmt {
6530 assert_eq!(tr.timing, TriggerTiming::InsteadOf);
6531 if let TriggerEvent::Update(cols) = &tr.event {
6532 assert_eq!(cols.len(), 2);
6533 } else {
6534 unreachable!("expected UpdateOf event");
6535 }
6536 } else {
6537 unreachable!("expected CreateTrigger");
6538 }
6539 }
6540
6541 #[test]
6546 fn test_parser_create_view_with_columns() {
6547 let stmt = parse_one("CREATE VIEW v (a, b) AS SELECT 1, 2");
6548 if let Statement::CreateView(cv) = stmt {
6549 assert_eq!(cv.columns, vec!["a".to_owned(), "b".to_owned()]);
6550 } else {
6551 unreachable!("expected CreateView");
6552 }
6553 }
6554
6555 #[test]
6560 fn test_parser_multi_join() {
6561 let stmt = parse_one(
6562 "SELECT a.x, b.y, c.z FROM a \
6563 JOIN b ON a.id = b.a_id \
6564 LEFT JOIN c ON b.id = c.b_id \
6565 CROSS JOIN d",
6566 );
6567 if let Statement::Select(s) = stmt {
6568 if let SelectCore::Select { from, .. } = &s.body.select {
6569 let from = from.as_ref().expect("FROM clause");
6570 assert_eq!(from.joins.len(), 3);
6571 assert_eq!(from.joins[0].join_type.kind, JoinKind::Inner);
6572 assert_eq!(from.joins[1].join_type.kind, JoinKind::Left);
6573 assert_eq!(from.joins[2].join_type.kind, JoinKind::Cross);
6574 } else {
6575 unreachable!("expected Select core");
6576 }
6577 } else {
6578 unreachable!("expected Select");
6579 }
6580 }
6581
6582 #[test]
6587 fn test_parser_group_by_having() {
6588 let stmt = parse_one("SELECT dept, count(*) FROM emp GROUP BY dept HAVING count(*) > 5");
6589 if let Statement::Select(s) = stmt {
6590 if let SelectCore::Select {
6591 group_by, having, ..
6592 } = &s.body.select
6593 {
6594 assert!(!group_by.is_empty());
6595 assert!(having.is_some());
6596 } else {
6597 unreachable!("expected Select core");
6598 }
6599 } else {
6600 unreachable!("expected Select");
6601 }
6602 }
6603
6604 #[test]
6609 fn test_parser_error_recovery_with_span() {
6610 let sql = "SELECT 1;\nXYZZY 42;\nSELECT 3";
6612 let mut p = Parser::from_sql(sql);
6613 let (stmts, errs) = p.parse_all();
6614 assert_eq!(stmts.len(), 2, "should recover two valid statements");
6615 assert!(!errs.is_empty(), "should report at least one error");
6616
6617 let err = &errs[0];
6618 assert_eq!(err.line, 2, "error should be on line 2");
6620 assert_eq!(err.col, 1, "error should be at column 1");
6621 assert!(
6623 err.span.start < err.span.end,
6624 "error span should be non-empty"
6625 );
6626 let source_len = u32::try_from(sql.len()).unwrap();
6627 assert!(
6628 err.span.end <= source_len,
6629 "error span.end should be within source"
6630 );
6631 }
6632
6633 #[test]
6634 fn test_parser_error_span_mid_line() {
6635 let bad = Parser::from_sql("CREATE").parse_statement();
6637 assert!(bad.is_err());
6638 let err = bad.unwrap_err();
6639 assert_eq!(err.line, 1);
6640 }
6641
6642 #[test]
6647 #[allow(clippy::too_many_lines)]
6648 fn test_parser_keyword_lookup_all_150() {
6649 use crate::token::TokenKind;
6650
6651 let keywords = [
6653 "ABORT",
6654 "ACTION",
6655 "ADD",
6656 "AFTER",
6657 "ALL",
6658 "ALTER",
6659 "ALWAYS",
6660 "ANALYZE",
6661 "AND",
6662 "AS",
6663 "ASC",
6664 "ATTACH",
6665 "AUTOINCREMENT",
6666 "BEFORE",
6667 "BEGIN",
6668 "BETWEEN",
6669 "BY",
6670 "CASCADE",
6671 "CASE",
6672 "CAST",
6673 "CHECK",
6674 "COLLATE",
6675 "COLUMN",
6676 "COMMIT",
6677 "CONCURRENT",
6678 "CONFLICT",
6679 "CONSTRAINT",
6680 "CREATE",
6681 "CROSS",
6682 "CURRENT_DATE",
6683 "CURRENT_TIME",
6684 "CURRENT_TIMESTAMP",
6685 "DATABASE",
6686 "DEFAULT",
6687 "DEFERRABLE",
6688 "DEFERRED",
6689 "DELETE",
6690 "DESC",
6691 "DETACH",
6692 "DISTINCT",
6693 "DO",
6694 "DROP",
6695 "EACH",
6696 "ELSE",
6697 "END",
6698 "ESCAPE",
6699 "EXCEPT",
6700 "EXCLUDE",
6701 "EXCLUSIVE",
6702 "EXISTS",
6703 "EXPLAIN",
6704 "FAIL",
6705 "FILTER",
6706 "FIRST",
6707 "FOLLOWING",
6708 "FOR",
6709 "FOREIGN",
6710 "FROM",
6711 "FULL",
6712 "GENERATED",
6713 "GLOB",
6714 "GROUP",
6715 "GROUPS",
6716 "HAVING",
6717 "IF",
6718 "IGNORE",
6719 "IMMEDIATE",
6720 "IN",
6721 "INDEX",
6722 "INDEXED",
6723 "INITIALLY",
6724 "INNER",
6725 "INSERT",
6726 "INSTEAD",
6727 "INTERSECT",
6728 "INTO",
6729 "IS",
6730 "ISNULL",
6731 "JOIN",
6732 "KEY",
6733 "LAST",
6734 "LEFT",
6735 "LIKE",
6736 "LIMIT",
6737 "MATCH",
6738 "MATERIALIZED",
6739 "NATURAL",
6740 "NO",
6741 "NOT",
6742 "NOTHING",
6743 "NOTNULL",
6744 "NULL",
6745 "NULLS",
6746 "OF",
6747 "OFFSET",
6748 "ON",
6749 "OR",
6750 "ORDER",
6751 "OTHERS",
6752 "OUTER",
6753 "OVER",
6754 "PARTITION",
6755 "PLAN",
6756 "PRAGMA",
6757 "PRECEDING",
6758 "PRIMARY",
6759 "QUERY",
6760 "RAISE",
6761 "RANGE",
6762 "RECURSIVE",
6763 "REFERENCES",
6764 "REGEXP",
6765 "REINDEX",
6766 "RELEASE",
6767 "RENAME",
6768 "REPLACE",
6769 "RESTRICT",
6770 "RETURNING",
6771 "RIGHT",
6772 "ROLLBACK",
6773 "ROW",
6774 "ROWS",
6775 "SAVEPOINT",
6776 "SELECT",
6777 "SET",
6778 "STORED",
6779 "STRICT",
6780 "TABLE",
6781 "TEMP",
6782 "TEMPORARY",
6783 "THEN",
6784 "TIES",
6785 "TO",
6786 "TRANSACTION",
6787 "TRIGGER",
6788 "TRUE",
6789 "FALSE",
6790 "UNBOUNDED",
6791 "UNION",
6792 "UNIQUE",
6793 "UPDATE",
6794 "USING",
6795 "VACUUM",
6796 "VALUES",
6797 "VIEW",
6798 "VIRTUAL",
6799 "WHEN",
6800 "WHERE",
6801 "WINDOW",
6802 "WITH",
6803 "WITHOUT",
6804 ];
6805
6806 assert!(
6807 keywords.len() >= 150,
6808 "expected 150+ keywords, got {}",
6809 keywords.len()
6810 );
6811
6812 for kw in &keywords {
6813 assert!(
6814 TokenKind::lookup_keyword(kw).is_some(),
6815 "keyword {kw} not recognized (uppercase)"
6816 );
6817 let lower = kw.to_ascii_lowercase();
6819 assert!(
6820 TokenKind::lookup_keyword(&lower).is_some(),
6821 "keyword {kw} not recognized (lowercase)"
6822 );
6823 let mixed: String = kw
6825 .chars()
6826 .enumerate()
6827 .map(|(i, c)| {
6828 if i % 2 == 0 {
6829 c.to_ascii_lowercase()
6830 } else {
6831 c.to_ascii_uppercase()
6832 }
6833 })
6834 .collect();
6835 assert!(
6836 TokenKind::lookup_keyword(&mixed).is_some(),
6837 "keyword {kw} not recognized (mixed case: {mixed})"
6838 );
6839 }
6840
6841 assert!(TokenKind::lookup_keyword("FOOBAR").is_none());
6843 assert!(TokenKind::lookup_keyword("").is_none());
6844 }
6845
6846 fn assert_roundtrip(sql: &str) {
6856 let ast1 = parse_one(sql);
6857 let rendered1 = ast1.to_string();
6858 let ast2 = parse_one(&rendered1);
6859 let rendered2 = ast2.to_string();
6860 assert_eq!(
6861 rendered1, rendered2,
6862 "round-trip failed for:\n input: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
6863 );
6864 }
6865
6866 #[test]
6867 fn test_roundtrip_select_simple() {
6868 assert_roundtrip("SELECT 1");
6869 assert_roundtrip("SELECT 1, 2, 3");
6870 assert_roundtrip("SELECT *");
6871 assert_roundtrip("SELECT * FROM t");
6872 assert_roundtrip("SELECT a, b FROM t WHERE a > 10");
6873 assert_roundtrip("SELECT a FROM t ORDER BY a DESC");
6874 assert_roundtrip("SELECT a FROM t LIMIT 10 OFFSET 5");
6875 }
6876
6877 #[test]
6878 fn test_roundtrip_select_distinct() {
6879 assert_roundtrip("SELECT DISTINCT a, b FROM t");
6880 }
6881
6882 #[test]
6883 fn test_roundtrip_select_alias() {
6884 assert_roundtrip("SELECT a AS x, b AS y FROM t AS u");
6885 }
6886
6887 #[test]
6888 fn test_roundtrip_select_join_types() {
6889 assert_roundtrip("SELECT * FROM a INNER JOIN b ON a.id = b.id");
6890 assert_roundtrip("SELECT * FROM a LEFT JOIN b ON a.id = b.id");
6891 assert_roundtrip("SELECT * FROM a RIGHT JOIN b ON a.id = b.id");
6892 assert_roundtrip("SELECT * FROM a FULL JOIN b ON a.id = b.id");
6893 assert_roundtrip("SELECT * FROM a CROSS JOIN b");
6894 assert_roundtrip("SELECT * FROM a NATURAL INNER JOIN b");
6895 assert_roundtrip("SELECT * FROM a LEFT JOIN b USING (id)");
6896 }
6897
6898 #[test]
6899 fn test_roundtrip_select_subquery() {
6900 assert_roundtrip("SELECT * FROM (SELECT 1 AS x) AS sub");
6901 }
6902
6903 #[test]
6904 fn test_roundtrip_select_group_by_having() {
6905 assert_roundtrip("SELECT a, count(*) FROM t GROUP BY a HAVING count(*) > 1");
6906 }
6907
6908 #[test]
6909 fn test_roundtrip_select_window() {
6910 assert_roundtrip("SELECT sum(x) OVER (PARTITION BY g ORDER BY x) FROM t");
6911 }
6912
6913 #[test]
6914 fn test_roundtrip_select_cte() {
6915 assert_roundtrip("WITH cte AS (SELECT 1 AS n) SELECT * FROM cte");
6916 assert_roundtrip(
6917 "WITH RECURSIVE cnt(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM cnt WHERE x < 10) SELECT * FROM cnt",
6918 );
6919 }
6920
6921 #[test]
6922 fn test_roundtrip_select_compound() {
6923 assert_roundtrip("SELECT 1 UNION SELECT 2");
6924 assert_roundtrip("SELECT 1 UNION ALL SELECT 2");
6925 assert_roundtrip("SELECT 1 INTERSECT SELECT 2");
6926 assert_roundtrip("SELECT 1 EXCEPT SELECT 2");
6927 }
6928
6929 #[test]
6930 fn test_roundtrip_insert() {
6931 assert_roundtrip("INSERT INTO t (a, b) VALUES (1, 2)");
6932 assert_roundtrip("INSERT INTO t DEFAULT VALUES");
6933 assert_roundtrip("INSERT INTO t SELECT * FROM u");
6934 assert_roundtrip("INSERT OR REPLACE INTO t (a) VALUES (1)");
6935 assert_roundtrip("REPLACE INTO t (a) VALUES (1)");
6936 }
6937
6938 #[test]
6939 fn test_roundtrip_insert_returning() {
6940 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING *");
6941 assert_roundtrip("INSERT INTO t (a) VALUES (1) RETURNING a, b");
6942 }
6943
6944 #[test]
6945 fn test_roundtrip_insert_on_conflict() {
6946 assert_roundtrip("INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO NOTHING");
6947 assert_roundtrip(
6948 "INSERT INTO t (a) VALUES (1) ON CONFLICT (a) DO UPDATE SET a = excluded.a",
6949 );
6950 }
6951
6952 #[test]
6953 fn test_roundtrip_update() {
6954 assert_roundtrip("UPDATE t SET a = 1");
6955 assert_roundtrip("UPDATE t SET a = 1, b = 2 WHERE c > 3");
6956 assert_roundtrip("UPDATE t SET a = 1 RETURNING *");
6957 }
6958
6959 #[test]
6960 fn test_roundtrip_delete() {
6961 assert_roundtrip("DELETE FROM t");
6962 assert_roundtrip("DELETE FROM t WHERE a = 1");
6963 assert_roundtrip("DELETE FROM t RETURNING *");
6964 }
6965
6966 #[test]
6967 fn test_roundtrip_create_table() {
6968 assert_roundtrip("CREATE TABLE t (a INTEGER, b TEXT)");
6969 assert_roundtrip("CREATE TABLE IF NOT EXISTS t (a INTEGER PRIMARY KEY)");
6970 assert_roundtrip("CREATE TEMP TABLE t (a TEXT NOT NULL, b REAL DEFAULT 0.0)");
6971 }
6972
6973 #[test]
6974 fn test_roundtrip_create_index() {
6975 assert_roundtrip("CREATE INDEX idx ON t (a)");
6976 assert_roundtrip("CREATE UNIQUE INDEX IF NOT EXISTS idx ON t (a, b DESC)");
6977 assert_roundtrip("CREATE INDEX idx ON t (a) WHERE a > 0");
6978 }
6979
6980 #[test]
6981 fn test_roundtrip_drop() {
6982 assert_roundtrip("DROP TABLE t");
6983 assert_roundtrip("DROP TABLE IF EXISTS t");
6984 assert_roundtrip("DROP INDEX idx");
6985 assert_roundtrip("DROP VIEW v");
6986 }
6987
6988 #[test]
6989 fn test_roundtrip_alter_table() {
6990 assert_roundtrip("ALTER TABLE t RENAME TO u");
6991 assert_roundtrip("ALTER TABLE t ADD COLUMN c TEXT");
6992 assert_roundtrip("ALTER TABLE t DROP COLUMN c");
6993 }
6994
6995 #[test]
6996 fn test_roundtrip_transaction() {
6997 assert_roundtrip("BEGIN");
6998 assert_roundtrip("BEGIN IMMEDIATE");
6999 assert_roundtrip("BEGIN EXCLUSIVE");
7000 assert_roundtrip("COMMIT");
7001 assert_roundtrip("ROLLBACK");
7002 assert_roundtrip("SAVEPOINT sp1");
7003 assert_roundtrip("RELEASE sp1");
7004 }
7005
7006 #[test]
7007 fn test_roundtrip_pragma() {
7008 assert_roundtrip("PRAGMA journal_mode");
7009 assert_roundtrip("PRAGMA journal_mode = wal");
7010 }
7011
7012 #[test]
7013 fn test_roundtrip_explain() {
7014 assert_roundtrip("EXPLAIN SELECT 1");
7015 assert_roundtrip("EXPLAIN QUERY PLAN SELECT * FROM t");
7016 }
7017
7018 #[test]
7019 fn test_roundtrip_expressions() {
7020 assert_roundtrip("SELECT 1 + 2 * 3");
7021 assert_roundtrip("SELECT NOT a");
7022 assert_roundtrip("SELECT -x");
7023 assert_roundtrip("SELECT ~x");
7024 assert_roundtrip("SELECT a BETWEEN 1 AND 10");
7025 assert_roundtrip("SELECT a NOT BETWEEN 1 AND 10");
7026 assert_roundtrip("SELECT a IN (1, 2, 3)");
7027 assert_roundtrip("SELECT a NOT IN (1, 2, 3)");
7028 assert_roundtrip("SELECT a LIKE '%foo%'");
7029 assert_roundtrip("SELECT a GLOB '*foo*'");
7030 assert_roundtrip("SELECT CASE WHEN a = 1 THEN 'one' ELSE 'other' END");
7031 assert_roundtrip("SELECT CASE x WHEN 1 THEN 'a' WHEN 2 THEN 'b' END");
7032 assert_roundtrip("SELECT CAST(a AS TEXT)");
7033 assert_roundtrip("SELECT EXISTS (SELECT 1)");
7034 assert_roundtrip("SELECT (SELECT 1)");
7035 assert_roundtrip("SELECT a COLLATE NOCASE");
7036 }
7037
7038 #[test]
7039 fn test_roundtrip_literals() {
7040 assert_roundtrip("SELECT NULL");
7041 assert_roundtrip("SELECT TRUE");
7042 assert_roundtrip("SELECT FALSE");
7043 assert_roundtrip("SELECT 42");
7044 assert_roundtrip("SELECT 3.14");
7045 assert_roundtrip("SELECT 'hello'");
7046 assert_roundtrip("SELECT X'DEADBEEF'");
7047 assert_roundtrip("SELECT CURRENT_TIME");
7048 assert_roundtrip("SELECT CURRENT_DATE");
7049 assert_roundtrip("SELECT CURRENT_TIMESTAMP");
7050 }
7051
7052 #[test]
7053 fn test_roundtrip_placeholders() {
7054 assert_roundtrip("SELECT ?");
7055 assert_roundtrip("SELECT ?1");
7056 assert_roundtrip("SELECT :name");
7057 assert_roundtrip("SELECT @name");
7058 assert_roundtrip("SELECT $name");
7059 }
7060
7061 #[test]
7062 fn test_roundtrip_json_arrows() {
7063 assert_roundtrip("SELECT a -> 'key'");
7064 assert_roundtrip("SELECT a ->> 'key'");
7065 }
7066
7067 #[test]
7068 fn test_roundtrip_function_calls() {
7069 assert_roundtrip("SELECT count(*)");
7070 assert_roundtrip("SELECT count(DISTINCT a)");
7071 assert_roundtrip("SELECT sum(x) FILTER (WHERE x > 0)");
7072 }
7073
7074 #[test]
7075 fn test_roundtrip_isnull_notnull() {
7076 assert_roundtrip("SELECT a ISNULL");
7077 assert_roundtrip("SELECT a IS NOT NULL");
7078 }
7079
7080 #[test]
7081 fn test_roundtrip_create_view() {
7082 assert_roundtrip("CREATE VIEW v AS SELECT * FROM t");
7083 assert_roundtrip("CREATE VIEW IF NOT EXISTS v (a, b) AS SELECT 1, 2");
7084 }
7085
7086 #[test]
7087 fn test_roundtrip_create_trigger() {
7088 assert_roundtrip(
7089 "CREATE TRIGGER tr BEFORE DELETE ON t FOR EACH ROW BEGIN DELETE FROM log WHERE id = OLD.id; END",
7090 );
7091 }
7092
7093 #[test]
7094 fn test_roundtrip_attach_detach() {
7095 assert_roundtrip("ATTACH 'file.db' AS db2");
7096 assert_roundtrip("DETACH db2");
7097 }
7098
7099 #[test]
7100 fn test_roundtrip_vacuum() {
7101 assert_roundtrip("VACUUM");
7102 }
7103
7104 #[test]
7105 fn test_roundtrip_analyze_reindex() {
7106 assert_roundtrip("ANALYZE");
7107 assert_roundtrip("ANALYZE t");
7108 assert_roundtrip("REINDEX");
7109 assert_roundtrip("REINDEX t");
7110 }
7111
7112 #[test]
7113 fn test_roundtrip_cte_materialized() {
7114 assert_roundtrip("WITH cte AS MATERIALIZED (SELECT 1) SELECT * FROM cte");
7115 assert_roundtrip("WITH cte AS NOT MATERIALIZED (SELECT 1) SELECT * FROM cte");
7116 }
7117
7118 mod proptest_roundtrip {
7123 use super::*;
7124 use proptest::prelude::*;
7125
7126 fn is_keyword(s: &str) -> bool {
7128 TokenKind::lookup_keyword(s).is_some()
7129 }
7130
7131 fn arb_ident() -> BoxedStrategy<String> {
7133 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7134 .expect("valid regex")
7135 .prop_filter("must not be keyword", |s| !is_keyword(s))
7136 .boxed()
7137 }
7138
7139 fn arb_literal() -> BoxedStrategy<String> {
7141 prop_oneof![
7142 any::<i32>().prop_map(|n| n.to_string()),
7143 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7144 arb_ident().prop_map(|s| format!("'{s}'")),
7145 Just("NULL".to_string()),
7146 Just("TRUE".to_string()),
7147 Just("FALSE".to_string()),
7148 ]
7149 .boxed()
7150 }
7151
7152 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7154 if depth == 0 {
7155 prop_oneof![
7156 arb_literal(),
7157 arb_ident(),
7158 (arb_ident(), arb_ident()).prop_map(|(t, c)| format!("{t}.{c}")),
7159 ]
7160 .boxed()
7161 } else {
7162 let leaf = arb_expr(0);
7163 prop_oneof![
7164 4 => leaf,
7165 2 => (arb_expr(depth - 1), prop_oneof![
7167 Just("+"), Just("-"), Just("*"), Just("/"),
7168 Just("="), Just("!="), Just("<"), Just("<="),
7169 Just(">"), Just(">="), Just("AND"), Just("OR"),
7170 Just("||"),
7171 ], arb_expr(depth - 1))
7172 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7173 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7175 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7176 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NULL")),
7178 1 => arb_expr(depth - 1).prop_map(|e| format!("{e} IS NOT NULL")),
7179 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7181 .prop_map(|(e, lo, hi)| format!("{e} BETWEEN {lo} AND {hi}")),
7182 1 => (arb_expr(depth - 1), proptest::collection::vec(arb_expr(0), 1..4))
7184 .prop_map(|(e, items)| format!("{e} IN ({})", items.join(", "))),
7185 1 => (arb_expr(depth - 1), arb_ident())
7187 .prop_map(|(e, p)| format!("{e} LIKE '{p}'")),
7188 1 => arb_expr(depth - 1).prop_map(|e| format!("CAST({e} AS TEXT)")),
7190 1 => (arb_expr(depth - 1), arb_expr(0), arb_expr(0))
7192 .prop_map(|(c, t, el)| format!("CASE WHEN {c} THEN {t} ELSE {el} END")),
7193 1 => (arb_ident(), proptest::collection::vec(arb_expr(0), 0..3))
7195 .prop_map(|(name, args)| format!("{name}({})", args.join(", "))),
7196 1 => arb_expr(0).prop_map(|e| format!("(SELECT {e})")),
7198 ]
7199 .boxed()
7200 }
7201 }
7202
7203 fn arb_select() -> BoxedStrategy<String> {
7205 use std::fmt::Write as _;
7206
7207 let cols =
7208 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
7209 let table = arb_ident();
7210 let where_clause = prop::option::of(arb_expr(1));
7211 let order_by = prop::option::of(arb_ident());
7212 let limit = prop::option::of(1u32..100);
7213
7214 (cols, table, where_clause, order_by, limit)
7215 .prop_map(|(cols, tbl, wh, ord, lim)| {
7216 let mut sql = format!("SELECT {cols} FROM {tbl}");
7217 if let Some(w) = wh {
7218 write!(sql, " WHERE {w}").expect("writing to String should not fail");
7219 }
7220 if let Some(o) = ord {
7221 write!(sql, " ORDER BY {o}").expect("writing to String should not fail");
7222 }
7223 if let Some(l) = lim {
7224 write!(sql, " LIMIT {l}").expect("writing to String should not fail");
7225 }
7226 sql
7227 })
7228 .boxed()
7229 }
7230
7231 fn arb_insert() -> BoxedStrategy<String> {
7233 let ncols = 1usize..4;
7234 ncols
7235 .prop_flat_map(|n| {
7236 let tbl = arb_ident();
7237 let cols = proptest::collection::vec(arb_ident(), n..=n);
7238 let vals = proptest::collection::vec(arb_literal(), n..=n);
7239 (tbl, cols, vals).prop_map(|(t, cs, vs): (String, Vec<String>, Vec<String>)| {
7240 format!(
7241 "INSERT INTO {t} ({}) VALUES ({})",
7242 cs.join(", "),
7243 vs.join(", ")
7244 )
7245 })
7246 })
7247 .boxed()
7248 }
7249
7250 fn arb_statement() -> BoxedStrategy<String> {
7252 prop_oneof![
7253 6 => arb_select(),
7254 3 => arb_insert(),
7255 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
7256 1 => (arb_ident(), arb_expr(1))
7257 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
7258 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
7259 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
7260 ]
7261 .boxed()
7262 }
7263
7264 fn try_parse_one(sql: &str) -> Option<Statement> {
7266 let mut p = Parser::from_sql(sql);
7267 let (stmts, errs) = p.parse_all();
7268 if errs.is_empty() && stmts.len() == 1 {
7269 Some(stmts.into_iter().next().unwrap())
7270 } else {
7271 None
7272 }
7273 }
7274
7275 proptest::proptest! {
7276 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
7277
7278 #[test]
7279 fn test_parser_roundtrip_proptest(sql in arb_statement()) {
7280 let Some(ast1) = try_parse_one(&sql) else {
7282 return Ok(()); };
7284
7285 let rendered1 = ast1.to_string();
7287
7288 let Some(ast2) = try_parse_one(&rendered1) else {
7290 let msg = format!("re-parse failed for rendered SQL: {rendered1:?}");
7291 prop_assert!(false, "{}", msg);
7292 unreachable!()
7293 };
7294
7295 let rendered2 = ast2.to_string();
7297 let msg = format!(
7298 "round-trip not idempotent:\n original: {sql}\n rendered1: {rendered1}\n rendered2: {rendered2}"
7299 );
7300 prop_assert_eq!(rendered1, rendered2, "{}", msg);
7301 }
7302 }
7303 }
7304
7305 mod proptest_properties {
7310 use super::*;
7311 use proptest::prelude::*;
7312
7313 fn arb_ident() -> BoxedStrategy<String> {
7315 prop::string::string_regex("[a-z][a-z0-9]{0,5}")
7316 .expect("valid regex")
7317 .prop_filter("must not be keyword", |s| {
7318 TokenKind::lookup_keyword(s).is_none()
7319 })
7320 .boxed()
7321 }
7322
7323 fn arb_literal() -> BoxedStrategy<String> {
7324 prop_oneof![
7325 any::<i32>().prop_map(|n| n.to_string()),
7326 (1i32..1000).prop_map(|n| format!("{n}.{}", n % 100)),
7327 arb_ident().prop_map(|s| format!("'{s}'")),
7328 Just("NULL".to_string()),
7329 Just("TRUE".to_string()),
7330 Just("FALSE".to_string()),
7331 ]
7332 .boxed()
7333 }
7334
7335 fn arb_expr(depth: u32) -> BoxedStrategy<String> {
7336 if depth == 0 {
7337 prop_oneof![arb_literal(), arb_ident(),].boxed()
7338 } else {
7339 let leaf = arb_expr(0);
7340 prop_oneof![
7341 4 => leaf,
7342 2 => (arb_expr(depth - 1), prop_oneof![
7343 Just("+"), Just("-"), Just("*"), Just("/"),
7344 Just("="), Just("!="), Just("<"), Just("<="),
7345 Just(">"), Just(">="), Just("AND"), Just("OR"),
7346 ], arb_expr(depth - 1))
7347 .prop_map(|(l, op, r)| format!("({l} {op} {r})")),
7348 1 => arb_expr(depth - 1).prop_map(|e| format!("(-{e})")),
7349 1 => arb_expr(depth - 1).prop_map(|e| format!("(NOT {e})")),
7350 ]
7351 .boxed()
7352 }
7353 }
7354
7355 fn arb_select() -> BoxedStrategy<String> {
7356 use std::fmt::Write as _;
7357 let cols =
7358 proptest::collection::vec(arb_expr(1), 1..4).prop_map(|cols| cols.join(", "));
7359 let table = arb_ident();
7360 let where_clause = prop::option::of(arb_expr(1));
7361 (cols, table, where_clause)
7362 .prop_map(|(cols, tbl, wh)| {
7363 let mut sql = format!("SELECT {cols} FROM {tbl}");
7364 if let Some(w) = wh {
7365 write!(sql, " WHERE {w}").expect("writing to String should not fail");
7366 }
7367 sql
7368 })
7369 .boxed()
7370 }
7371
7372 fn arb_statement() -> BoxedStrategy<String> {
7373 prop_oneof![
7374 6 => arb_select(),
7375 3 => {
7376 let ncols = 1usize..4;
7377 ncols
7378 .prop_flat_map(|n| {
7379 let tbl = arb_ident();
7380 let cols = proptest::collection::vec(arb_ident(), n..=n);
7381 let vals = proptest::collection::vec(arb_literal(), n..=n);
7382 (tbl, cols, vals).prop_map(
7383 |(t, cs, vs): (String, Vec<String>, Vec<String>)| {
7384 format!(
7385 "INSERT INTO {t} ({}) VALUES ({})",
7386 cs.join(", "),
7387 vs.join(", ")
7388 )
7389 },
7390 )
7391 })
7392 .boxed()
7393 },
7394 1 => arb_expr(2).prop_map(|e| format!("SELECT {e}")),
7395 1 => (arb_ident(), arb_expr(1))
7396 .prop_map(|(t, w)| format!("DELETE FROM {t} WHERE {w}")),
7397 1 => (arb_ident(), arb_ident(), arb_literal(), arb_expr(1))
7398 .prop_map(|(t, c, v, w)| format!("UPDATE {t} SET {c} = {v} WHERE {w}")),
7399 ]
7400 .boxed()
7401 }
7402
7403 proptest::proptest! {
7405 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(500))]
7406
7407 #[test]
7408 fn test_parser_determinism(sql in arb_statement()) {
7409 let mut p1 = Parser::from_sql(&sql);
7410 let (stmts1, errs1) = p1.parse_all();
7411
7412 let mut p2 = Parser::from_sql(&sql);
7413 let (stmts2, errs2) = p2.parse_all();
7414
7415 let msg_stmt = format!("different statement counts for: {sql}");
7417 prop_assert_eq!(stmts1.len(), stmts2.len(), "{}", msg_stmt);
7418 let msg_err = format!("different error counts for: {sql}");
7419 prop_assert_eq!(errs1.len(), errs2.len(), "{}", msg_err);
7420
7421 if errs1.is_empty() && !stmts1.is_empty() {
7423 for (s1, s2) in stmts1.iter().zip(stmts2.iter()) {
7424 let r1 = s1.to_string();
7425 let r2 = s2.to_string();
7426 let msg_det = format!("non-deterministic parse output for: {sql}");
7427 prop_assert_eq!(r1, r2, "{}", msg_det);
7428 }
7429 }
7430 }
7431 }
7432
7433 proptest::proptest! {
7435 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(2000))]
7436
7437 #[test]
7438 fn test_parser_fuzz_no_panic(input in prop::collection::vec(any::<u8>(), 0..256)) {
7439 let sql = String::from_utf8_lossy(&input);
7440 let mut p = Parser::from_sql(&sql);
7442 let _ = p.parse_all();
7443 }
7444 }
7445
7446 proptest::proptest! {
7448 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1000))]
7449
7450 #[test]
7451 fn test_parser_fuzz_near_valid(
7452 prefix in prop_oneof![
7453 Just("SELECT "),
7454 Just("INSERT INTO "),
7455 Just("DELETE FROM "),
7456 Just("UPDATE "),
7457 Just("CREATE TABLE "),
7458 Just("DROP TABLE "),
7459 Just("BEGIN "),
7460 Just("PRAGMA "),
7461 ],
7462 suffix in prop::string::string_regex("[a-zA-Z0-9_ ,.*=<>!()'\";+\\-/]{0,100}")
7463 .expect("valid regex")
7464 ) {
7465 let sql = format!("{prefix}{suffix}");
7466 let mut p = Parser::from_sql(&sql);
7467 let _ = p.parse_all();
7468 }
7469 }
7470
7471 proptest::proptest! {
7473 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
7474
7475 #[test]
7476 fn test_parser_unicode_identifiers(
7477 name in prop::string::string_regex("[\\p{L}][\\p{L}\\p{N}_]{0,10}")
7478 .expect("valid regex")
7479 .prop_filter("must not be keyword", |s| {
7480 TokenKind::lookup_keyword(s).is_none()
7481 })
7482 ) {
7483 let sql = format!("SELECT \"{name}\" FROM \"{name}\"");
7485 let mut p = Parser::from_sql(&sql);
7486 let (stmts, errs) = p.parse_all();
7487 prop_assert!(
7488 errs.is_empty(),
7489 "Unicode identifier should parse: {sql}, errors: {errs:?}"
7490 );
7491 prop_assert_eq!(stmts.len(), 1);
7492 }
7493 }
7494
7495 proptest::proptest! {
7497 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(300))]
7498
7499 #[test]
7500 fn test_parser_rejects_incomplete_statements(
7501 kind in prop_oneof![
7502 Just("SELECT"),
7503 Just("SELECT FROM"),
7504 Just("INSERT INTO"),
7505 Just("DELETE"),
7506 Just("UPDATE SET"),
7507 Just("CREATE"),
7508 Just("CREATE TABLE"),
7509 Just("DROP"),
7510 ],
7511 trailing in prop::option::of(
7512 prop::string::string_regex("[;, ]{0,3}").expect("valid regex")
7513 )
7514 ) {
7515 let sql = match trailing {
7516 Some(t) => format!("{kind}{t}"),
7517 None => kind.to_string(),
7518 };
7519 let mut p = Parser::from_sql(&sql);
7520 let (stmts, errs) = p.parse_all();
7521 prop_assert!(
7525 !errs.is_empty() || stmts.is_empty(),
7526 "Expected rejection of incomplete SQL: {sql}, got {stmts:?}"
7527 );
7528 }
7529 }
7530
7531 proptest::proptest! {
7534 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(200))]
7535
7536 #[test]
7537 fn test_parser_multi_statement_count(
7538 stmts in proptest::collection::vec(arb_statement(), 1..4)
7539 ) {
7540 let sql = stmts.join("; ");
7541 let mut p = Parser::from_sql(&sql);
7542 let (parsed, errors) = p.parse_all();
7543 if errors.is_empty() {
7545 prop_assert!(
7546 parsed.len() >= stmts.len(),
7547 "Expected at least {} statements from: {sql}, got {}",
7548 stmts.len(),
7549 parsed.len()
7550 );
7551 }
7552 }
7553 }
7554 }
7555
7556 #[test]
7560 fn create_table_quoted_reserved_word_key() {
7561 parse_ok(r#"CREATE TABLE "meta" ("key" TEXT, "val" TEXT);"#);
7563 }
7564
7565 #[test]
7566 fn create_table_unquoted_key_column() {
7567 parse_ok("CREATE TABLE meta (key TEXT, val TEXT);");
7569 }
7570
7571 #[test]
7572 fn create_table_quoted_order_column() {
7573 parse_ok(r#"CREATE TABLE t ("order" INTEGER);"#);
7575 }
7576
7577 #[test]
7578 fn create_table_quoted_select_column() {
7579 parse_ok(r#"CREATE TABLE t ("select" TEXT);"#);
7581 }
7582
7583 #[test]
7584 fn select_with_reserved_word_column_key() {
7585 parse_ok("SELECT key FROM meta;");
7587 }
7588
7589 #[test]
7590 fn select_with_reserved_word_column_value() {
7591 parse_ok("SELECT value FROM meta;");
7593 }
7594
7595 #[test]
7596 fn select_with_reserved_word_column_order() {
7597 parse_ok(r#"SELECT "order" FROM t;"#);
7599 }
7600
7601 #[test]
7602 fn where_clause_with_reserved_word_column() {
7603 parse_ok("UPDATE meta SET val = '2.0' WHERE key = 'version';");
7605 }
7606
7607 #[test]
7608 fn update_set_reserved_word_column() {
7609 parse_ok(r#"UPDATE meta SET "key" = 'newkey' WHERE "key" = 'oldkey';"#);
7611 }
7612
7613 #[test]
7614 fn delete_where_reserved_word_column() {
7615 parse_ok("DELETE FROM meta WHERE key = 'version';");
7616 }
7617
7618 #[test]
7619 fn persistence_dump_with_reserved_word_columns() {
7620 let sql = concat!(
7623 r#"CREATE TABLE "meta" ("key" TEXT, "value" TEXT);"#,
7624 "\n",
7625 r#"INSERT INTO "meta" VALUES ('version', '1.0');"#,
7626 "\n",
7627 r#"INSERT INTO "meta" VALUES ('author', 'test');"#,
7628 );
7629 let mut p = Parser::from_sql(sql);
7630 let (stmts, errs) = p.parse_all();
7631 assert!(
7632 errs.is_empty(),
7633 "persistence dump with reserved-word columns should parse cleanly: {errs:?}"
7634 );
7635 assert_eq!(stmts.len(), 3);
7636 }
7637
7638 #[test]
7639 fn select_qualified_column_with_alias() {
7640 let stmt = parse_one("SELECT a.name AS from_name FROM users a");
7643 if let Statement::Select(s) = stmt {
7644 if let SelectCore::Select { columns, .. } = &s.body.select {
7645 assert_eq!(columns.len(), 1);
7646 match &columns[0] {
7647 ResultColumn::Expr { expr, alias } => {
7648 assert_eq!(
7650 alias.as_deref(),
7651 Some("from_name"),
7652 "alias should be 'from_name', got {alias:?}"
7653 );
7654 if let Expr::Column(col_ref, _) = expr {
7656 assert_eq!(col_ref.table.as_deref(), Some("a"));
7657 assert_eq!(col_ref.column, "name");
7658 } else {
7659 panic!("expected Column expression, got {expr:?}");
7660 }
7661 }
7662 other => panic!("expected Expr variant, got {other:?}"),
7663 }
7664 } else {
7665 panic!("expected Select core");
7666 }
7667 } else {
7668 panic!("expected Select statement");
7669 }
7670 }
7671
7672 #[test]
7673 fn select_qualified_column_with_implicit_alias() {
7674 let stmt = parse_one("SELECT a.name from_name FROM users a");
7676 if let Statement::Select(s) = stmt {
7677 if let SelectCore::Select { columns, .. } = &s.body.select {
7678 assert_eq!(columns.len(), 1);
7679 match &columns[0] {
7680 ResultColumn::Expr { expr, alias } => {
7681 assert_eq!(
7683 alias.as_deref(),
7684 Some("from_name"),
7685 "implicit alias should be 'from_name', got {alias:?}"
7686 );
7687 if let Expr::Column(col_ref, _) = expr {
7689 assert_eq!(col_ref.table.as_deref(), Some("a"));
7690 assert_eq!(col_ref.column, "name");
7691 } else {
7692 panic!("expected Column expression, got {expr:?}");
7693 }
7694 }
7695 other => panic!("expected Expr variant, got {other:?}"),
7696 }
7697 } else {
7698 panic!("expected Select core");
7699 }
7700 } else {
7701 panic!("expected Select statement");
7702 }
7703 }
7704
7705 #[test]
7706 fn select_implicit_alias_non_reserved_keyword() {
7707 let stmt = parse_one("SELECT 1 action");
7710 if let Statement::Select(s) = stmt {
7711 if let SelectCore::Select { columns, .. } = &s.body.select {
7712 if let ResultColumn::Expr { alias, .. } = &columns[0] {
7713 assert_eq!(
7714 alias.as_deref(),
7715 Some("action"),
7716 "implicit alias 'action' (keyword) failed to parse"
7717 );
7718 } else {
7719 unreachable!("expected Expr result column");
7720 }
7721 } else {
7722 unreachable!("expected Select core");
7723 }
7724 } else {
7725 unreachable!("expected Select");
7726 }
7727 }
7728}