1use sqlparser::ast as sp;
4use sqlparser::dialect::GenericDialect;
5use sqlparser::parser::Parser;
6
7use crate::error::{Result, SqlError};
8use crate::types::{DataType, Value};
9
10#[derive(Debug, Clone)]
13pub enum Statement {
14 CreateTable(CreateTableStmt),
15 DropTable(DropTableStmt),
16 CreateIndex(CreateIndexStmt),
17 DropIndex(DropIndexStmt),
18 CreateView(CreateViewStmt),
19 DropView(DropViewStmt),
20 AlterTable(Box<AlterTableStmt>),
21 Insert(InsertStmt),
22 Select(Box<SelectQuery>),
23 Update(UpdateStmt),
24 Delete(DeleteStmt),
25 Begin,
26 Commit,
27 Rollback,
28 Savepoint(String),
29 ReleaseSavepoint(String),
30 RollbackTo(String),
31 Explain(Box<Statement>),
32}
33
34#[derive(Debug, Clone)]
35pub struct AlterTableStmt {
36 pub table: String,
37 pub op: AlterTableOp,
38}
39
40#[derive(Debug, Clone)]
41pub enum AlterTableOp {
42 AddColumn {
43 column: Box<ColumnSpec>,
44 foreign_key: Option<ForeignKeyDef>,
45 if_not_exists: bool,
46 },
47 DropColumn {
48 name: String,
49 if_exists: bool,
50 },
51 RenameColumn {
52 old_name: String,
53 new_name: String,
54 },
55 RenameTable {
56 new_name: String,
57 },
58}
59
60#[derive(Debug, Clone)]
61pub struct CreateTableStmt {
62 pub name: String,
63 pub columns: Vec<ColumnSpec>,
64 pub primary_key: Vec<String>,
65 pub if_not_exists: bool,
66 pub check_constraints: Vec<TableCheckConstraint>,
67 pub foreign_keys: Vec<ForeignKeyDef>,
68}
69
70#[derive(Debug, Clone)]
71pub struct TableCheckConstraint {
72 pub name: Option<String>,
73 pub expr: Expr,
74 pub sql: String,
75}
76
77#[derive(Debug, Clone)]
78pub struct ForeignKeyDef {
79 pub name: Option<String>,
80 pub columns: Vec<String>,
81 pub foreign_table: String,
82 pub referred_columns: Vec<String>,
83}
84
85#[derive(Debug, Clone)]
86pub struct ColumnSpec {
87 pub name: String,
88 pub data_type: DataType,
89 pub nullable: bool,
90 pub is_primary_key: bool,
91 pub default_expr: Option<Expr>,
92 pub default_sql: Option<String>,
93 pub check_expr: Option<Expr>,
94 pub check_sql: Option<String>,
95 pub check_name: Option<String>,
96}
97
98#[derive(Debug, Clone)]
99pub struct DropTableStmt {
100 pub name: String,
101 pub if_exists: bool,
102}
103
104#[derive(Debug, Clone)]
105pub struct CreateIndexStmt {
106 pub index_name: String,
107 pub table_name: String,
108 pub columns: Vec<String>,
109 pub unique: bool,
110 pub if_not_exists: bool,
111}
112
113#[derive(Debug, Clone)]
114pub struct DropIndexStmt {
115 pub index_name: String,
116 pub if_exists: bool,
117}
118
119#[derive(Debug, Clone)]
120pub struct CreateViewStmt {
121 pub name: String,
122 pub sql: String,
123 pub column_aliases: Vec<String>,
124 pub or_replace: bool,
125 pub if_not_exists: bool,
126}
127
128#[derive(Debug, Clone)]
129pub struct DropViewStmt {
130 pub name: String,
131 pub if_exists: bool,
132}
133
134#[derive(Debug, Clone)]
135pub enum InsertSource {
136 Values(Vec<Vec<Expr>>),
137 Select(Box<SelectQuery>),
138}
139
140#[derive(Debug, Clone)]
141pub struct InsertStmt {
142 pub table: String,
143 pub columns: Vec<String>,
144 pub source: InsertSource,
145}
146
147#[derive(Debug, Clone)]
148pub struct TableRef {
149 pub name: String,
150 pub alias: Option<String>,
151}
152
153#[derive(Debug, Clone, Copy, PartialEq)]
154pub enum JoinType {
155 Inner,
156 Cross,
157 Left,
158 Right,
159}
160
161#[derive(Debug, Clone)]
162pub struct JoinClause {
163 pub join_type: JoinType,
164 pub table: TableRef,
165 pub on_clause: Option<Expr>,
166}
167
168#[derive(Debug, Clone)]
169pub struct SelectStmt {
170 pub columns: Vec<SelectColumn>,
171 pub from: String,
172 pub from_alias: Option<String>,
173 pub joins: Vec<JoinClause>,
174 pub distinct: bool,
175 pub where_clause: Option<Expr>,
176 pub order_by: Vec<OrderByItem>,
177 pub limit: Option<Expr>,
178 pub offset: Option<Expr>,
179 pub group_by: Vec<Expr>,
180 pub having: Option<Expr>,
181}
182
183#[derive(Debug, Clone)]
184pub enum SetOp {
185 Union,
186 Intersect,
187 Except,
188}
189
190#[derive(Debug, Clone)]
191pub struct CompoundSelect {
192 pub op: SetOp,
193 pub all: bool,
194 pub left: Box<QueryBody>,
195 pub right: Box<QueryBody>,
196 pub order_by: Vec<OrderByItem>,
197 pub limit: Option<Expr>,
198 pub offset: Option<Expr>,
199}
200
201#[derive(Debug, Clone)]
202pub enum QueryBody {
203 Select(Box<SelectStmt>),
204 Compound(Box<CompoundSelect>),
205}
206
207#[derive(Debug, Clone)]
208pub struct CteDefinition {
209 pub name: String,
210 pub column_aliases: Vec<String>,
211 pub body: QueryBody,
212}
213
214#[derive(Debug, Clone)]
215pub struct SelectQuery {
216 pub ctes: Vec<CteDefinition>,
217 pub recursive: bool,
218 pub body: QueryBody,
219}
220
221#[derive(Debug, Clone)]
222pub struct UpdateStmt {
223 pub table: String,
224 pub assignments: Vec<(String, Expr)>,
225 pub where_clause: Option<Expr>,
226}
227
228#[derive(Debug, Clone)]
229pub struct DeleteStmt {
230 pub table: String,
231 pub where_clause: Option<Expr>,
232}
233
234#[derive(Debug, Clone)]
235pub enum SelectColumn {
236 AllColumns,
237 Expr { expr: Expr, alias: Option<String> },
238}
239
240#[derive(Debug, Clone)]
241pub struct OrderByItem {
242 pub expr: Expr,
243 pub descending: bool,
244 pub nulls_first: Option<bool>,
245}
246
247#[derive(Debug, Clone)]
248pub enum Expr {
249 Literal(Value),
250 Column(String),
251 QualifiedColumn {
252 table: String,
253 column: String,
254 },
255 BinaryOp {
256 left: Box<Expr>,
257 op: BinOp,
258 right: Box<Expr>,
259 },
260 UnaryOp {
261 op: UnaryOp,
262 expr: Box<Expr>,
263 },
264 IsNull(Box<Expr>),
265 IsNotNull(Box<Expr>),
266 Function {
267 name: String,
268 args: Vec<Expr>,
269 },
270 CountStar,
271 InSubquery {
272 expr: Box<Expr>,
273 subquery: Box<SelectStmt>,
274 negated: bool,
275 },
276 InList {
277 expr: Box<Expr>,
278 list: Vec<Expr>,
279 negated: bool,
280 },
281 Exists {
282 subquery: Box<SelectStmt>,
283 negated: bool,
284 },
285 ScalarSubquery(Box<SelectStmt>),
286 InSet {
287 expr: Box<Expr>,
288 values: std::collections::HashSet<Value>,
289 has_null: bool,
290 negated: bool,
291 },
292 Between {
293 expr: Box<Expr>,
294 low: Box<Expr>,
295 high: Box<Expr>,
296 negated: bool,
297 },
298 Like {
299 expr: Box<Expr>,
300 pattern: Box<Expr>,
301 escape: Option<Box<Expr>>,
302 negated: bool,
303 },
304 Case {
305 operand: Option<Box<Expr>>,
306 conditions: Vec<(Expr, Expr)>,
307 else_result: Option<Box<Expr>>,
308 },
309 Coalesce(Vec<Expr>),
310 Cast {
311 expr: Box<Expr>,
312 data_type: DataType,
313 },
314 Parameter(usize),
315 WindowFunction {
316 name: String,
317 args: Vec<Expr>,
318 spec: WindowSpec,
319 },
320}
321
322#[derive(Debug, Clone)]
323pub struct WindowSpec {
324 pub partition_by: Vec<Expr>,
325 pub order_by: Vec<OrderByItem>,
326 pub frame: Option<WindowFrame>,
327}
328
329#[derive(Debug, Clone)]
330pub struct WindowFrame {
331 pub units: WindowFrameUnits,
332 pub start: WindowFrameBound,
333 pub end: WindowFrameBound,
334}
335
336#[derive(Debug, Clone, Copy)]
337pub enum WindowFrameUnits {
338 Rows,
339 Range,
340 Groups,
341}
342
343#[derive(Debug, Clone)]
344pub enum WindowFrameBound {
345 UnboundedPreceding,
346 Preceding(Box<Expr>),
347 CurrentRow,
348 Following(Box<Expr>),
349 UnboundedFollowing,
350}
351
352#[derive(Debug, Clone, Copy, PartialEq, Eq)]
353pub enum BinOp {
354 Add,
355 Sub,
356 Mul,
357 Div,
358 Mod,
359 Eq,
360 NotEq,
361 Lt,
362 Gt,
363 LtEq,
364 GtEq,
365 And,
366 Or,
367 Concat,
368}
369
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum UnaryOp {
372 Neg,
373 Not,
374}
375
376pub fn has_subquery(expr: &Expr) -> bool {
379 match expr {
380 Expr::InSubquery { .. } | Expr::Exists { .. } | Expr::ScalarSubquery(_) => true,
381 Expr::BinaryOp { left, right, .. } => has_subquery(left) || has_subquery(right),
382 Expr::UnaryOp { expr, .. } => has_subquery(expr),
383 Expr::IsNull(e) | Expr::IsNotNull(e) => has_subquery(e),
384 Expr::InList { expr, list, .. } => has_subquery(expr) || list.iter().any(has_subquery),
385 Expr::InSet { expr, .. } => has_subquery(expr),
386 Expr::Between {
387 expr, low, high, ..
388 } => has_subquery(expr) || has_subquery(low) || has_subquery(high),
389 Expr::Like {
390 expr,
391 pattern,
392 escape,
393 ..
394 } => {
395 has_subquery(expr)
396 || has_subquery(pattern)
397 || escape.as_ref().is_some_and(|e| has_subquery(e))
398 }
399 Expr::Case {
400 operand,
401 conditions,
402 else_result,
403 } => {
404 operand.as_ref().is_some_and(|e| has_subquery(e))
405 || conditions
406 .iter()
407 .any(|(c, r)| has_subquery(c) || has_subquery(r))
408 || else_result.as_ref().is_some_and(|e| has_subquery(e))
409 }
410 Expr::Coalesce(args) | Expr::Function { args, .. } => args.iter().any(has_subquery),
411 Expr::Cast { expr, .. } => has_subquery(expr),
412 _ => false,
413 }
414}
415
416pub fn parse_sql_expr(sql: &str) -> Result<Expr> {
419 let dialect = GenericDialect {};
420 let mut parser = Parser::new(&dialect)
421 .try_with_sql(sql)
422 .map_err(|e| SqlError::Parse(e.to_string()))?;
423 let sp_expr = parser
424 .parse_expr()
425 .map_err(|e| SqlError::Parse(e.to_string()))?;
426 convert_expr(&sp_expr)
427}
428
429pub fn parse_sql(sql: &str) -> Result<Statement> {
432 let dialect = GenericDialect {};
433 let stmts = Parser::parse_sql(&dialect, sql).map_err(|e| SqlError::Parse(e.to_string()))?;
434
435 if stmts.is_empty() {
436 return Err(SqlError::Parse("empty SQL".into()));
437 }
438 if stmts.len() > 1 {
439 return Err(SqlError::Unsupported("multiple statements".into()));
440 }
441
442 convert_statement(stmts.into_iter().next().unwrap())
443}
444
445pub fn count_params(stmt: &Statement) -> usize {
449 let mut max_idx = 0usize;
450 visit_exprs_stmt(stmt, &mut |e| {
451 if let Expr::Parameter(n) = e {
452 max_idx = max_idx.max(*n);
453 }
454 });
455 max_idx
456}
457
458pub fn bind_params(
460 stmt: &Statement,
461 params: &[crate::types::Value],
462) -> crate::error::Result<Statement> {
463 bind_stmt(stmt, params)
464}
465
466fn bind_stmt(stmt: &Statement, params: &[crate::types::Value]) -> crate::error::Result<Statement> {
467 match stmt {
468 Statement::Select(sq) => Ok(Statement::Select(Box::new(bind_select_query(sq, params)?))),
469 Statement::Insert(ins) => {
470 let source = match &ins.source {
471 InsertSource::Values(rows) => {
472 let bound = rows
473 .iter()
474 .map(|row| {
475 row.iter()
476 .map(|e| bind_expr(e, params))
477 .collect::<crate::error::Result<Vec<_>>>()
478 })
479 .collect::<crate::error::Result<Vec<_>>>()?;
480 InsertSource::Values(bound)
481 }
482 InsertSource::Select(sq) => {
483 InsertSource::Select(Box::new(bind_select_query(sq, params)?))
484 }
485 };
486 Ok(Statement::Insert(InsertStmt {
487 table: ins.table.clone(),
488 columns: ins.columns.clone(),
489 source,
490 }))
491 }
492 Statement::Update(upd) => {
493 let assignments = upd
494 .assignments
495 .iter()
496 .map(|(col, e)| Ok((col.clone(), bind_expr(e, params)?)))
497 .collect::<crate::error::Result<Vec<_>>>()?;
498 let where_clause = upd
499 .where_clause
500 .as_ref()
501 .map(|e| bind_expr(e, params))
502 .transpose()?;
503 Ok(Statement::Update(UpdateStmt {
504 table: upd.table.clone(),
505 assignments,
506 where_clause,
507 }))
508 }
509 Statement::Delete(del) => {
510 let where_clause = del
511 .where_clause
512 .as_ref()
513 .map(|e| bind_expr(e, params))
514 .transpose()?;
515 Ok(Statement::Delete(DeleteStmt {
516 table: del.table.clone(),
517 where_clause,
518 }))
519 }
520 Statement::Explain(inner) => Ok(Statement::Explain(Box::new(bind_stmt(inner, params)?))),
521 other => Ok(other.clone()),
522 }
523}
524
525fn bind_select(
526 sel: &SelectStmt,
527 params: &[crate::types::Value],
528) -> crate::error::Result<SelectStmt> {
529 let columns = sel
530 .columns
531 .iter()
532 .map(|c| match c {
533 SelectColumn::AllColumns => Ok(SelectColumn::AllColumns),
534 SelectColumn::Expr { expr, alias } => Ok(SelectColumn::Expr {
535 expr: bind_expr(expr, params)?,
536 alias: alias.clone(),
537 }),
538 })
539 .collect::<crate::error::Result<Vec<_>>>()?;
540 let joins = sel
541 .joins
542 .iter()
543 .map(|j| {
544 let on_clause = j
545 .on_clause
546 .as_ref()
547 .map(|e| bind_expr(e, params))
548 .transpose()?;
549 Ok(JoinClause {
550 join_type: j.join_type,
551 table: j.table.clone(),
552 on_clause,
553 })
554 })
555 .collect::<crate::error::Result<Vec<_>>>()?;
556 let where_clause = sel
557 .where_clause
558 .as_ref()
559 .map(|e| bind_expr(e, params))
560 .transpose()?;
561 let order_by = sel
562 .order_by
563 .iter()
564 .map(|o| {
565 Ok(OrderByItem {
566 expr: bind_expr(&o.expr, params)?,
567 descending: o.descending,
568 nulls_first: o.nulls_first,
569 })
570 })
571 .collect::<crate::error::Result<Vec<_>>>()?;
572 let limit = sel
573 .limit
574 .as_ref()
575 .map(|e| bind_expr(e, params))
576 .transpose()?;
577 let offset = sel
578 .offset
579 .as_ref()
580 .map(|e| bind_expr(e, params))
581 .transpose()?;
582 let group_by = sel
583 .group_by
584 .iter()
585 .map(|e| bind_expr(e, params))
586 .collect::<crate::error::Result<Vec<_>>>()?;
587 let having = sel
588 .having
589 .as_ref()
590 .map(|e| bind_expr(e, params))
591 .transpose()?;
592
593 Ok(SelectStmt {
594 columns,
595 from: sel.from.clone(),
596 from_alias: sel.from_alias.clone(),
597 joins,
598 distinct: sel.distinct,
599 where_clause,
600 order_by,
601 limit,
602 offset,
603 group_by,
604 having,
605 })
606}
607
608fn bind_query_body(
609 body: &QueryBody,
610 params: &[crate::types::Value],
611) -> crate::error::Result<QueryBody> {
612 match body {
613 QueryBody::Select(sel) => Ok(QueryBody::Select(Box::new(bind_select(sel, params)?))),
614 QueryBody::Compound(comp) => {
615 let order_by = comp
616 .order_by
617 .iter()
618 .map(|o| {
619 Ok(OrderByItem {
620 expr: bind_expr(&o.expr, params)?,
621 descending: o.descending,
622 nulls_first: o.nulls_first,
623 })
624 })
625 .collect::<crate::error::Result<Vec<_>>>()?;
626 let limit = comp
627 .limit
628 .as_ref()
629 .map(|e| bind_expr(e, params))
630 .transpose()?;
631 let offset = comp
632 .offset
633 .as_ref()
634 .map(|e| bind_expr(e, params))
635 .transpose()?;
636 Ok(QueryBody::Compound(Box::new(CompoundSelect {
637 op: comp.op.clone(),
638 all: comp.all,
639 left: Box::new(bind_query_body(&comp.left, params)?),
640 right: Box::new(bind_query_body(&comp.right, params)?),
641 order_by,
642 limit,
643 offset,
644 })))
645 }
646 }
647}
648
649fn bind_select_query(
650 sq: &SelectQuery,
651 params: &[crate::types::Value],
652) -> crate::error::Result<SelectQuery> {
653 let ctes = sq
654 .ctes
655 .iter()
656 .map(|cte| {
657 Ok(CteDefinition {
658 name: cte.name.clone(),
659 column_aliases: cte.column_aliases.clone(),
660 body: bind_query_body(&cte.body, params)?,
661 })
662 })
663 .collect::<crate::error::Result<Vec<_>>>()?;
664 let body = bind_query_body(&sq.body, params)?;
665 Ok(SelectQuery {
666 ctes,
667 recursive: sq.recursive,
668 body,
669 })
670}
671
672fn bind_expr(expr: &Expr, params: &[crate::types::Value]) -> crate::error::Result<Expr> {
673 match expr {
674 Expr::Parameter(n) => {
675 if *n == 0 || *n > params.len() {
676 return Err(SqlError::ParameterCountMismatch {
677 expected: *n,
678 got: params.len(),
679 });
680 }
681 Ok(Expr::Literal(params[*n - 1].clone()))
682 }
683 Expr::Literal(_) | Expr::Column(_) | Expr::QualifiedColumn { .. } | Expr::CountStar => {
684 Ok(expr.clone())
685 }
686 Expr::BinaryOp { left, op, right } => Ok(Expr::BinaryOp {
687 left: Box::new(bind_expr(left, params)?),
688 op: *op,
689 right: Box::new(bind_expr(right, params)?),
690 }),
691 Expr::UnaryOp { op, expr: e } => Ok(Expr::UnaryOp {
692 op: *op,
693 expr: Box::new(bind_expr(e, params)?),
694 }),
695 Expr::IsNull(e) => Ok(Expr::IsNull(Box::new(bind_expr(e, params)?))),
696 Expr::IsNotNull(e) => Ok(Expr::IsNotNull(Box::new(bind_expr(e, params)?))),
697 Expr::Function { name, args } => {
698 let args = args
699 .iter()
700 .map(|a| bind_expr(a, params))
701 .collect::<crate::error::Result<Vec<_>>>()?;
702 Ok(Expr::Function {
703 name: name.clone(),
704 args,
705 })
706 }
707 Expr::InSubquery {
708 expr: e,
709 subquery,
710 negated,
711 } => Ok(Expr::InSubquery {
712 expr: Box::new(bind_expr(e, params)?),
713 subquery: Box::new(bind_select(subquery, params)?),
714 negated: *negated,
715 }),
716 Expr::InList {
717 expr: e,
718 list,
719 negated,
720 } => {
721 let list = list
722 .iter()
723 .map(|l| bind_expr(l, params))
724 .collect::<crate::error::Result<Vec<_>>>()?;
725 Ok(Expr::InList {
726 expr: Box::new(bind_expr(e, params)?),
727 list,
728 negated: *negated,
729 })
730 }
731 Expr::Exists { subquery, negated } => Ok(Expr::Exists {
732 subquery: Box::new(bind_select(subquery, params)?),
733 negated: *negated,
734 }),
735 Expr::ScalarSubquery(sq) => Ok(Expr::ScalarSubquery(Box::new(bind_select(sq, params)?))),
736 Expr::InSet {
737 expr: e,
738 values,
739 has_null,
740 negated,
741 } => Ok(Expr::InSet {
742 expr: Box::new(bind_expr(e, params)?),
743 values: values.clone(),
744 has_null: *has_null,
745 negated: *negated,
746 }),
747 Expr::Between {
748 expr: e,
749 low,
750 high,
751 negated,
752 } => Ok(Expr::Between {
753 expr: Box::new(bind_expr(e, params)?),
754 low: Box::new(bind_expr(low, params)?),
755 high: Box::new(bind_expr(high, params)?),
756 negated: *negated,
757 }),
758 Expr::Like {
759 expr: e,
760 pattern,
761 escape,
762 negated,
763 } => Ok(Expr::Like {
764 expr: Box::new(bind_expr(e, params)?),
765 pattern: Box::new(bind_expr(pattern, params)?),
766 escape: escape
767 .as_ref()
768 .map(|esc| bind_expr(esc, params).map(Box::new))
769 .transpose()?,
770 negated: *negated,
771 }),
772 Expr::Case {
773 operand,
774 conditions,
775 else_result,
776 } => {
777 let operand = operand
778 .as_ref()
779 .map(|e| bind_expr(e, params).map(Box::new))
780 .transpose()?;
781 let conditions = conditions
782 .iter()
783 .map(|(cond, then)| Ok((bind_expr(cond, params)?, bind_expr(then, params)?)))
784 .collect::<crate::error::Result<Vec<_>>>()?;
785 let else_result = else_result
786 .as_ref()
787 .map(|e| bind_expr(e, params).map(Box::new))
788 .transpose()?;
789 Ok(Expr::Case {
790 operand,
791 conditions,
792 else_result,
793 })
794 }
795 Expr::Coalesce(args) => {
796 let args = args
797 .iter()
798 .map(|a| bind_expr(a, params))
799 .collect::<crate::error::Result<Vec<_>>>()?;
800 Ok(Expr::Coalesce(args))
801 }
802 Expr::Cast { expr: e, data_type } => Ok(Expr::Cast {
803 expr: Box::new(bind_expr(e, params)?),
804 data_type: *data_type,
805 }),
806 Expr::WindowFunction { name, args, spec } => {
807 let args = args
808 .iter()
809 .map(|a| bind_expr(a, params))
810 .collect::<crate::error::Result<Vec<_>>>()?;
811 let partition_by = spec
812 .partition_by
813 .iter()
814 .map(|e| bind_expr(e, params))
815 .collect::<crate::error::Result<Vec<_>>>()?;
816 let order_by = spec
817 .order_by
818 .iter()
819 .map(|o| {
820 Ok(OrderByItem {
821 expr: bind_expr(&o.expr, params)?,
822 descending: o.descending,
823 nulls_first: o.nulls_first,
824 })
825 })
826 .collect::<crate::error::Result<Vec<_>>>()?;
827 let frame = match &spec.frame {
828 Some(f) => Some(WindowFrame {
829 units: f.units,
830 start: bind_frame_bound(&f.start, params)?,
831 end: bind_frame_bound(&f.end, params)?,
832 }),
833 None => None,
834 };
835 Ok(Expr::WindowFunction {
836 name: name.clone(),
837 args,
838 spec: WindowSpec {
839 partition_by,
840 order_by,
841 frame,
842 },
843 })
844 }
845 }
846}
847
848fn bind_frame_bound(
849 bound: &WindowFrameBound,
850 params: &[crate::types::Value],
851) -> crate::error::Result<WindowFrameBound> {
852 match bound {
853 WindowFrameBound::Preceding(e) => {
854 Ok(WindowFrameBound::Preceding(Box::new(bind_expr(e, params)?)))
855 }
856 WindowFrameBound::Following(e) => {
857 Ok(WindowFrameBound::Following(Box::new(bind_expr(e, params)?)))
858 }
859 other => Ok(other.clone()),
860 }
861}
862
863fn visit_exprs_stmt(stmt: &Statement, visitor: &mut impl FnMut(&Expr)) {
864 match stmt {
865 Statement::Select(sq) => {
866 for cte in &sq.ctes {
867 visit_exprs_query_body(&cte.body, visitor);
868 }
869 visit_exprs_query_body(&sq.body, visitor);
870 }
871 Statement::Insert(ins) => match &ins.source {
872 InsertSource::Values(rows) => {
873 for row in rows {
874 for e in row {
875 visit_expr(e, visitor);
876 }
877 }
878 }
879 InsertSource::Select(sq) => {
880 for cte in &sq.ctes {
881 visit_exprs_query_body(&cte.body, visitor);
882 }
883 visit_exprs_query_body(&sq.body, visitor);
884 }
885 },
886 Statement::Update(upd) => {
887 for (_, e) in &upd.assignments {
888 visit_expr(e, visitor);
889 }
890 if let Some(w) = &upd.where_clause {
891 visit_expr(w, visitor);
892 }
893 }
894 Statement::Delete(del) => {
895 if let Some(w) = &del.where_clause {
896 visit_expr(w, visitor);
897 }
898 }
899 Statement::Explain(inner) => visit_exprs_stmt(inner, visitor),
900 _ => {}
901 }
902}
903
904fn visit_exprs_query_body(body: &QueryBody, visitor: &mut impl FnMut(&Expr)) {
905 match body {
906 QueryBody::Select(sel) => visit_exprs_select(sel, visitor),
907 QueryBody::Compound(comp) => {
908 visit_exprs_query_body(&comp.left, visitor);
909 visit_exprs_query_body(&comp.right, visitor);
910 for o in &comp.order_by {
911 visit_expr(&o.expr, visitor);
912 }
913 if let Some(l) = &comp.limit {
914 visit_expr(l, visitor);
915 }
916 if let Some(o) = &comp.offset {
917 visit_expr(o, visitor);
918 }
919 }
920 }
921}
922
923fn visit_exprs_select(sel: &SelectStmt, visitor: &mut impl FnMut(&Expr)) {
924 for col in &sel.columns {
925 if let SelectColumn::Expr { expr, .. } = col {
926 visit_expr(expr, visitor);
927 }
928 }
929 for j in &sel.joins {
930 if let Some(on) = &j.on_clause {
931 visit_expr(on, visitor);
932 }
933 }
934 if let Some(w) = &sel.where_clause {
935 visit_expr(w, visitor);
936 }
937 for o in &sel.order_by {
938 visit_expr(&o.expr, visitor);
939 }
940 if let Some(l) = &sel.limit {
941 visit_expr(l, visitor);
942 }
943 if let Some(o) = &sel.offset {
944 visit_expr(o, visitor);
945 }
946 for g in &sel.group_by {
947 visit_expr(g, visitor);
948 }
949 if let Some(h) = &sel.having {
950 visit_expr(h, visitor);
951 }
952}
953
954fn visit_expr(expr: &Expr, visitor: &mut impl FnMut(&Expr)) {
955 visitor(expr);
956 match expr {
957 Expr::BinaryOp { left, right, .. } => {
958 visit_expr(left, visitor);
959 visit_expr(right, visitor);
960 }
961 Expr::UnaryOp { expr: e, .. } | Expr::IsNull(e) | Expr::IsNotNull(e) => {
962 visit_expr(e, visitor);
963 }
964 Expr::Function { args, .. } | Expr::Coalesce(args) => {
965 for a in args {
966 visit_expr(a, visitor);
967 }
968 }
969 Expr::InSubquery {
970 expr: e, subquery, ..
971 } => {
972 visit_expr(e, visitor);
973 visit_exprs_select(subquery, visitor);
974 }
975 Expr::InList { expr: e, list, .. } => {
976 visit_expr(e, visitor);
977 for l in list {
978 visit_expr(l, visitor);
979 }
980 }
981 Expr::Exists { subquery, .. } => visit_exprs_select(subquery, visitor),
982 Expr::ScalarSubquery(sq) => visit_exprs_select(sq, visitor),
983 Expr::InSet { expr: e, .. } => visit_expr(e, visitor),
984 Expr::Between {
985 expr: e, low, high, ..
986 } => {
987 visit_expr(e, visitor);
988 visit_expr(low, visitor);
989 visit_expr(high, visitor);
990 }
991 Expr::Like {
992 expr: e,
993 pattern,
994 escape,
995 ..
996 } => {
997 visit_expr(e, visitor);
998 visit_expr(pattern, visitor);
999 if let Some(esc) = escape {
1000 visit_expr(esc, visitor);
1001 }
1002 }
1003 Expr::Case {
1004 operand,
1005 conditions,
1006 else_result,
1007 } => {
1008 if let Some(op) = operand {
1009 visit_expr(op, visitor);
1010 }
1011 for (cond, then) in conditions {
1012 visit_expr(cond, visitor);
1013 visit_expr(then, visitor);
1014 }
1015 if let Some(el) = else_result {
1016 visit_expr(el, visitor);
1017 }
1018 }
1019 Expr::Cast { expr: e, .. } => visit_expr(e, visitor),
1020 Expr::WindowFunction { args, spec, .. } => {
1021 for a in args {
1022 visit_expr(a, visitor);
1023 }
1024 for p in &spec.partition_by {
1025 visit_expr(p, visitor);
1026 }
1027 for o in &spec.order_by {
1028 visit_expr(&o.expr, visitor);
1029 }
1030 if let Some(ref frame) = spec.frame {
1031 if let WindowFrameBound::Preceding(e) | WindowFrameBound::Following(e) =
1032 &frame.start
1033 {
1034 visit_expr(e, visitor);
1035 }
1036 if let WindowFrameBound::Preceding(e) | WindowFrameBound::Following(e) = &frame.end
1037 {
1038 visit_expr(e, visitor);
1039 }
1040 }
1041 }
1042 Expr::Literal(_)
1043 | Expr::Column(_)
1044 | Expr::QualifiedColumn { .. }
1045 | Expr::CountStar
1046 | Expr::Parameter(_) => {}
1047 }
1048}
1049
1050fn convert_statement(stmt: sp::Statement) -> Result<Statement> {
1053 match stmt {
1054 sp::Statement::CreateTable(ct) => convert_create_table(ct),
1055 sp::Statement::CreateIndex(ci) => convert_create_index(ci),
1056 sp::Statement::Drop {
1057 object_type: sp::ObjectType::Table,
1058 if_exists,
1059 names,
1060 ..
1061 } => {
1062 if names.len() != 1 {
1063 return Err(SqlError::Unsupported("multi-table DROP".into()));
1064 }
1065 Ok(Statement::DropTable(DropTableStmt {
1066 name: object_name_to_string(&names[0]),
1067 if_exists,
1068 }))
1069 }
1070 sp::Statement::Drop {
1071 object_type: sp::ObjectType::Index,
1072 if_exists,
1073 names,
1074 ..
1075 } => {
1076 if names.len() != 1 {
1077 return Err(SqlError::Unsupported("multi-index DROP".into()));
1078 }
1079 Ok(Statement::DropIndex(DropIndexStmt {
1080 index_name: object_name_to_string(&names[0]),
1081 if_exists,
1082 }))
1083 }
1084 sp::Statement::CreateView(cv) => convert_create_view(cv),
1085 sp::Statement::Drop {
1086 object_type: sp::ObjectType::View,
1087 if_exists,
1088 names,
1089 ..
1090 } => {
1091 if names.len() != 1 {
1092 return Err(SqlError::Unsupported("multi-view DROP".into()));
1093 }
1094 Ok(Statement::DropView(DropViewStmt {
1095 name: object_name_to_string(&names[0]),
1096 if_exists,
1097 }))
1098 }
1099 sp::Statement::AlterTable(at) => convert_alter_table(at),
1100 sp::Statement::Insert(insert) => convert_insert(insert),
1101 sp::Statement::Query(query) => convert_query(*query),
1102 sp::Statement::Update(update) => convert_update(update),
1103 sp::Statement::Delete(delete) => convert_delete(delete),
1104 sp::Statement::StartTransaction { .. } => Ok(Statement::Begin),
1105 sp::Statement::Commit { chain: true, .. } => {
1106 Err(SqlError::Unsupported("COMMIT AND CHAIN".into()))
1107 }
1108 sp::Statement::Commit { .. } => Ok(Statement::Commit),
1109 sp::Statement::Rollback { chain: true, .. } => {
1110 Err(SqlError::Unsupported("ROLLBACK AND CHAIN".into()))
1111 }
1112 sp::Statement::Rollback {
1113 savepoint: Some(name),
1114 ..
1115 } => Ok(Statement::RollbackTo(name.value.to_ascii_lowercase())),
1116 sp::Statement::Rollback { .. } => Ok(Statement::Rollback),
1117 sp::Statement::Savepoint { name } => {
1118 Ok(Statement::Savepoint(name.value.to_ascii_lowercase()))
1119 }
1120 sp::Statement::ReleaseSavepoint { name } => {
1121 Ok(Statement::ReleaseSavepoint(name.value.to_ascii_lowercase()))
1122 }
1123 sp::Statement::Explain {
1124 statement, analyze, ..
1125 } => {
1126 if analyze {
1127 return Err(SqlError::Unsupported("EXPLAIN ANALYZE".into()));
1128 }
1129 let inner = convert_statement(*statement)?;
1130 Ok(Statement::Explain(Box::new(inner)))
1131 }
1132 _ => Err(SqlError::Unsupported(format!("statement type: {}", stmt))),
1133 }
1134}
1135
1136fn convert_column_def(
1139 col_def: &sp::ColumnDef,
1140) -> Result<(ColumnSpec, Option<ForeignKeyDef>, bool)> {
1141 let col_name = col_def.name.value.clone();
1142 let data_type = convert_data_type(&col_def.data_type)?;
1143 let mut nullable = true;
1144 let mut is_primary_key = false;
1145 let mut default_expr = None;
1146 let mut default_sql = None;
1147 let mut check_expr = None;
1148 let mut check_sql = None;
1149 let mut check_name = None;
1150 let mut fk_def = None;
1151
1152 for opt in &col_def.options {
1153 match &opt.option {
1154 sp::ColumnOption::NotNull => nullable = false,
1155 sp::ColumnOption::Null => nullable = true,
1156 sp::ColumnOption::PrimaryKey(_) => {
1157 is_primary_key = true;
1158 nullable = false;
1159 }
1160 sp::ColumnOption::Default(expr) => {
1161 default_sql = Some(expr.to_string());
1162 default_expr = Some(convert_expr(expr)?);
1163 }
1164 sp::ColumnOption::Check(check) => {
1165 check_sql = Some(check.expr.to_string());
1166 let converted = convert_expr(&check.expr)?;
1167 if has_subquery(&converted) {
1168 return Err(SqlError::Unsupported("subquery in CHECK constraint".into()));
1169 }
1170 check_expr = Some(converted);
1171 check_name = check.name.as_ref().map(|n| n.value.clone());
1172 }
1173 sp::ColumnOption::ForeignKey(fk) => {
1174 convert_fk_actions(&fk.on_delete, &fk.on_update)?;
1175 let ftable = object_name_to_string(&fk.foreign_table).to_ascii_lowercase();
1176 let referred: Vec<String> = fk
1177 .referred_columns
1178 .iter()
1179 .map(|i| i.value.to_ascii_lowercase())
1180 .collect();
1181 fk_def = Some(ForeignKeyDef {
1182 name: fk.name.as_ref().map(|n| n.value.clone()),
1183 columns: vec![col_name.to_ascii_lowercase()],
1184 foreign_table: ftable,
1185 referred_columns: referred,
1186 });
1187 }
1188 _ => {}
1189 }
1190 }
1191
1192 let spec = ColumnSpec {
1193 name: col_name,
1194 data_type,
1195 nullable,
1196 is_primary_key,
1197 default_expr,
1198 default_sql,
1199 check_expr,
1200 check_sql,
1201 check_name,
1202 };
1203 Ok((spec, fk_def, is_primary_key))
1204}
1205
1206fn convert_create_table(ct: sp::CreateTable) -> Result<Statement> {
1207 let name = object_name_to_string(&ct.name);
1208 let if_not_exists = ct.if_not_exists;
1209
1210 let mut columns = Vec::new();
1211 let mut inline_pk: Vec<String> = Vec::new();
1212 let mut foreign_keys: Vec<ForeignKeyDef> = Vec::new();
1213
1214 for col_def in &ct.columns {
1215 let (spec, fk_def, was_pk) = convert_column_def(col_def)?;
1216 if was_pk {
1217 inline_pk.push(spec.name.clone());
1218 }
1219 if let Some(fk) = fk_def {
1220 foreign_keys.push(fk);
1221 }
1222 columns.push(spec);
1223 }
1224
1225 let mut check_constraints: Vec<TableCheckConstraint> = Vec::new();
1227
1228 for constraint in &ct.constraints {
1229 match constraint {
1230 sp::TableConstraint::PrimaryKey(pk_constraint) => {
1231 for idx_col in &pk_constraint.columns {
1232 let col_name = match &idx_col.column.expr {
1233 sp::Expr::Identifier(ident) => ident.value.clone(),
1234 _ => continue,
1235 };
1236 if !inline_pk.contains(&col_name) {
1237 inline_pk.push(col_name.clone());
1238 }
1239 if let Some(col) = columns.iter_mut().find(|c| c.name == col_name) {
1240 col.nullable = false;
1241 col.is_primary_key = true;
1242 }
1243 }
1244 }
1245 sp::TableConstraint::Check(check) => {
1246 let sql = check.expr.to_string();
1247 let converted = convert_expr(&check.expr)?;
1248 if has_subquery(&converted) {
1249 return Err(SqlError::Unsupported("subquery in CHECK constraint".into()));
1250 }
1251 check_constraints.push(TableCheckConstraint {
1252 name: check.name.as_ref().map(|n| n.value.clone()),
1253 expr: converted,
1254 sql,
1255 });
1256 }
1257 sp::TableConstraint::ForeignKey(fk) => {
1258 convert_fk_actions(&fk.on_delete, &fk.on_update)?;
1259 let cols: Vec<String> = fk
1260 .columns
1261 .iter()
1262 .map(|i| i.value.to_ascii_lowercase())
1263 .collect();
1264 let ftable = object_name_to_string(&fk.foreign_table).to_ascii_lowercase();
1265 let referred: Vec<String> = fk
1266 .referred_columns
1267 .iter()
1268 .map(|i| i.value.to_ascii_lowercase())
1269 .collect();
1270 foreign_keys.push(ForeignKeyDef {
1271 name: fk.name.as_ref().map(|n| n.value.clone()),
1272 columns: cols,
1273 foreign_table: ftable,
1274 referred_columns: referred,
1275 });
1276 }
1277 _ => {}
1278 }
1279 }
1280
1281 Ok(Statement::CreateTable(CreateTableStmt {
1282 name,
1283 columns,
1284 primary_key: inline_pk,
1285 if_not_exists,
1286 check_constraints,
1287 foreign_keys,
1288 }))
1289}
1290
1291fn convert_alter_table(at: sp::AlterTable) -> Result<Statement> {
1292 let table = object_name_to_string(&at.name);
1293 if at.operations.len() != 1 {
1294 return Err(SqlError::Unsupported(
1295 "ALTER TABLE with multiple operations".into(),
1296 ));
1297 }
1298 let op = match at.operations.into_iter().next().unwrap() {
1299 sp::AlterTableOperation::AddColumn {
1300 column_def,
1301 if_not_exists,
1302 ..
1303 } => {
1304 let (spec, fk, _was_pk) = convert_column_def(&column_def)?;
1305 AlterTableOp::AddColumn {
1306 column: Box::new(spec),
1307 foreign_key: fk,
1308 if_not_exists,
1309 }
1310 }
1311 sp::AlterTableOperation::DropColumn {
1312 column_names,
1313 if_exists,
1314 ..
1315 } => {
1316 if column_names.len() != 1 {
1317 return Err(SqlError::Unsupported(
1318 "DROP COLUMN with multiple columns".into(),
1319 ));
1320 }
1321 AlterTableOp::DropColumn {
1322 name: column_names.into_iter().next().unwrap().value,
1323 if_exists,
1324 }
1325 }
1326 sp::AlterTableOperation::RenameColumn {
1327 old_column_name,
1328 new_column_name,
1329 } => AlterTableOp::RenameColumn {
1330 old_name: old_column_name.value,
1331 new_name: new_column_name.value,
1332 },
1333 sp::AlterTableOperation::RenameTable { table_name } => {
1334 let new_name = match table_name {
1335 sp::RenameTableNameKind::To(name) | sp::RenameTableNameKind::As(name) => {
1336 object_name_to_string(&name)
1337 }
1338 };
1339 AlterTableOp::RenameTable { new_name }
1340 }
1341 other => {
1342 return Err(SqlError::Unsupported(format!(
1343 "ALTER TABLE operation: {other}"
1344 )));
1345 }
1346 };
1347 Ok(Statement::AlterTable(Box::new(AlterTableStmt {
1348 table,
1349 op,
1350 })))
1351}
1352
1353fn convert_fk_actions(
1354 on_delete: &Option<sp::ReferentialAction>,
1355 on_update: &Option<sp::ReferentialAction>,
1356) -> Result<()> {
1357 for action in [on_delete, on_update] {
1358 match action {
1359 None
1360 | Some(sp::ReferentialAction::Restrict)
1361 | Some(sp::ReferentialAction::NoAction) => {}
1362 Some(other) => {
1363 return Err(SqlError::Unsupported(format!(
1364 "FOREIGN KEY action: {other}"
1365 )));
1366 }
1367 }
1368 }
1369 Ok(())
1370}
1371
1372fn convert_create_index(ci: sp::CreateIndex) -> Result<Statement> {
1373 let index_name = ci
1374 .name
1375 .as_ref()
1376 .map(object_name_to_string)
1377 .ok_or_else(|| SqlError::Parse("index name required".into()))?;
1378
1379 let table_name = object_name_to_string(&ci.table_name);
1380
1381 let columns: Vec<String> = ci
1382 .columns
1383 .iter()
1384 .map(|idx_col| match &idx_col.column.expr {
1385 sp::Expr::Identifier(ident) => Ok(ident.value.clone()),
1386 other => Err(SqlError::Unsupported(format!("expression index: {other}"))),
1387 })
1388 .collect::<Result<_>>()?;
1389
1390 if columns.is_empty() {
1391 return Err(SqlError::Parse(
1392 "index must have at least one column".into(),
1393 ));
1394 }
1395
1396 Ok(Statement::CreateIndex(CreateIndexStmt {
1397 index_name,
1398 table_name,
1399 columns,
1400 unique: ci.unique,
1401 if_not_exists: ci.if_not_exists,
1402 }))
1403}
1404
1405fn convert_create_view(cv: sp::CreateView) -> Result<Statement> {
1406 let name = object_name_to_string(&cv.name);
1407
1408 if cv.materialized {
1409 return Err(SqlError::Unsupported("MATERIALIZED VIEW".into()));
1410 }
1411
1412 let sql = cv.query.to_string();
1413
1414 let dialect = GenericDialect {};
1416 let test = Parser::parse_sql(&dialect, &sql).map_err(|e| SqlError::Parse(e.to_string()))?;
1417 if test.is_empty() {
1418 return Err(SqlError::Parse("empty view definition".into()));
1419 }
1420 match &test[0] {
1421 sp::Statement::Query(_) => {}
1422 _ => {
1423 return Err(SqlError::Parse(
1424 "view body must be a SELECT statement".into(),
1425 ))
1426 }
1427 }
1428
1429 let column_aliases: Vec<String> = cv
1430 .columns
1431 .iter()
1432 .map(|c| c.name.value.to_ascii_lowercase())
1433 .collect();
1434
1435 Ok(Statement::CreateView(CreateViewStmt {
1436 name,
1437 sql,
1438 column_aliases,
1439 or_replace: cv.or_replace,
1440 if_not_exists: cv.if_not_exists,
1441 }))
1442}
1443
1444fn convert_insert(insert: sp::Insert) -> Result<Statement> {
1445 let table = match &insert.table {
1446 sp::TableObject::TableName(name) => object_name_to_string(name).to_ascii_lowercase(),
1447 _ => return Err(SqlError::Unsupported("INSERT into non-table object".into())),
1448 };
1449
1450 let columns: Vec<String> = insert
1451 .columns
1452 .iter()
1453 .map(|c| c.value.to_ascii_lowercase())
1454 .collect();
1455
1456 let query = insert
1457 .source
1458 .ok_or_else(|| SqlError::Parse("INSERT requires VALUES or SELECT".into()))?;
1459
1460 let source = match *query.body {
1461 sp::SetExpr::Values(sp::Values { rows, .. }) => {
1462 let mut result = Vec::new();
1463 for row in rows {
1464 let mut exprs = Vec::new();
1465 for expr in row {
1466 exprs.push(convert_expr(&expr)?);
1467 }
1468 result.push(exprs);
1469 }
1470 InsertSource::Values(result)
1471 }
1472 _ => {
1473 let (ctes, recursive) = if let Some(ref with) = query.with {
1474 convert_with(with)?
1475 } else {
1476 (vec![], false)
1477 };
1478 let body = convert_query_body(&query)?;
1479 InsertSource::Select(Box::new(SelectQuery {
1480 ctes,
1481 recursive,
1482 body,
1483 }))
1484 }
1485 };
1486
1487 Ok(Statement::Insert(InsertStmt {
1488 table,
1489 columns,
1490 source,
1491 }))
1492}
1493
1494fn convert_select_body(select: &sp::Select) -> Result<SelectStmt> {
1495 let distinct = match &select.distinct {
1496 Some(sp::Distinct::Distinct) => true,
1497 Some(sp::Distinct::On(_)) => {
1498 return Err(SqlError::Unsupported("DISTINCT ON".into()));
1499 }
1500 _ => false,
1501 };
1502
1503 let (from, from_alias, joins) = if select.from.is_empty() {
1505 (String::new(), None, vec![])
1506 } else if select.from.len() == 1 {
1507 let table_with_joins = &select.from[0];
1508 let (name, alias) = match &table_with_joins.relation {
1509 sp::TableFactor::Table { name, alias, .. } => {
1510 let table_name = object_name_to_string(name);
1511 let alias_str = alias.as_ref().map(|a| a.name.value.clone());
1512 (table_name, alias_str)
1513 }
1514 _ => return Err(SqlError::Unsupported("non-table FROM source".into())),
1515 };
1516 let j = table_with_joins
1517 .joins
1518 .iter()
1519 .map(convert_join)
1520 .collect::<Result<Vec<_>>>()?;
1521 (name, alias, j)
1522 } else {
1523 return Err(SqlError::Unsupported("comma-separated FROM tables".into()));
1524 };
1525
1526 let columns: Vec<SelectColumn> = select
1528 .projection
1529 .iter()
1530 .map(convert_select_item)
1531 .collect::<Result<_>>()?;
1532
1533 let where_clause = select.selection.as_ref().map(convert_expr).transpose()?;
1535
1536 let group_by = match &select.group_by {
1538 sp::GroupByExpr::Expressions(exprs, _) => {
1539 exprs.iter().map(convert_expr).collect::<Result<_>>()?
1540 }
1541 sp::GroupByExpr::All(_) => {
1542 return Err(SqlError::Unsupported("GROUP BY ALL".into()));
1543 }
1544 };
1545
1546 let having = select.having.as_ref().map(convert_expr).transpose()?;
1548
1549 Ok(SelectStmt {
1550 columns,
1551 from,
1552 from_alias,
1553 joins,
1554 distinct,
1555 where_clause,
1556 order_by: vec![],
1557 limit: None,
1558 offset: None,
1559 group_by,
1560 having,
1561 })
1562}
1563
1564fn convert_set_expr(set_expr: &sp::SetExpr) -> Result<QueryBody> {
1565 match set_expr {
1566 sp::SetExpr::Select(sel) => Ok(QueryBody::Select(Box::new(convert_select_body(sel)?))),
1567 sp::SetExpr::SetOperation {
1568 op,
1569 set_quantifier,
1570 left,
1571 right,
1572 } => {
1573 let set_op = match op {
1574 sp::SetOperator::Union => SetOp::Union,
1575 sp::SetOperator::Intersect => SetOp::Intersect,
1576 sp::SetOperator::Except | sp::SetOperator::Minus => SetOp::Except,
1577 };
1578 let all = match set_quantifier {
1579 sp::SetQuantifier::All => true,
1580 sp::SetQuantifier::None | sp::SetQuantifier::Distinct => false,
1581 _ => {
1582 return Err(SqlError::Unsupported("BY NAME set operations".into()));
1583 }
1584 };
1585 Ok(QueryBody::Compound(Box::new(CompoundSelect {
1586 op: set_op,
1587 all,
1588 left: Box::new(convert_set_expr(left)?),
1589 right: Box::new(convert_set_expr(right)?),
1590 order_by: vec![],
1591 limit: None,
1592 offset: None,
1593 })))
1594 }
1595 _ => Err(SqlError::Unsupported("unsupported set expression".into())),
1596 }
1597}
1598
1599fn convert_query_body(query: &sp::Query) -> Result<QueryBody> {
1600 let mut body = convert_set_expr(&query.body)?;
1601
1602 let order_by = if let Some(ref ob) = query.order_by {
1604 match &ob.kind {
1605 sp::OrderByKind::Expressions(exprs) => exprs
1606 .iter()
1607 .map(convert_order_by_expr)
1608 .collect::<Result<_>>()?,
1609 sp::OrderByKind::All { .. } => {
1610 return Err(SqlError::Unsupported("ORDER BY ALL".into()));
1611 }
1612 }
1613 } else {
1614 vec![]
1615 };
1616
1617 let (limit, offset) = match &query.limit_clause {
1619 Some(sp::LimitClause::LimitOffset { limit, offset, .. }) => {
1620 let l = limit.as_ref().map(convert_expr).transpose()?;
1621 let o = offset
1622 .as_ref()
1623 .map(|o| convert_expr(&o.value))
1624 .transpose()?;
1625 (l, o)
1626 }
1627 Some(sp::LimitClause::OffsetCommaLimit { limit, offset }) => {
1628 let l = Some(convert_expr(limit)?);
1629 let o = Some(convert_expr(offset)?);
1630 (l, o)
1631 }
1632 None => (None, None),
1633 };
1634
1635 match &mut body {
1636 QueryBody::Select(sel) => {
1637 sel.order_by = order_by;
1638 sel.limit = limit;
1639 sel.offset = offset;
1640 }
1641 QueryBody::Compound(comp) => {
1642 comp.order_by = order_by;
1643 comp.limit = limit;
1644 comp.offset = offset;
1645 }
1646 }
1647
1648 Ok(body)
1649}
1650
1651fn convert_subquery(query: &sp::Query) -> Result<SelectStmt> {
1652 if query.with.is_some() {
1653 return Err(SqlError::Unsupported("CTEs in subqueries".into()));
1654 }
1655 match convert_query_body(query)? {
1656 QueryBody::Select(s) => Ok(*s),
1657 QueryBody::Compound(_) => Err(SqlError::Unsupported(
1658 "UNION/INTERSECT/EXCEPT in subqueries".into(),
1659 )),
1660 }
1661}
1662
1663fn convert_with(with: &sp::With) -> Result<(Vec<CteDefinition>, bool)> {
1664 let mut names = std::collections::HashSet::new();
1665 let mut ctes = Vec::new();
1666 for cte in &with.cte_tables {
1667 let name = cte.alias.name.value.to_ascii_lowercase();
1668 if !names.insert(name.clone()) {
1669 return Err(SqlError::DuplicateCteName(name));
1670 }
1671 let column_aliases: Vec<String> = cte
1672 .alias
1673 .columns
1674 .iter()
1675 .map(|c| c.name.value.to_ascii_lowercase())
1676 .collect();
1677 let body = convert_query_body(&cte.query)?;
1678 ctes.push(CteDefinition {
1679 name,
1680 column_aliases,
1681 body,
1682 });
1683 }
1684 Ok((ctes, with.recursive))
1685}
1686
1687fn convert_query(query: sp::Query) -> Result<Statement> {
1688 let (ctes, recursive) = if let Some(ref with) = query.with {
1689 convert_with(with)?
1690 } else {
1691 (vec![], false)
1692 };
1693 let body = convert_query_body(&query)?;
1694 Ok(Statement::Select(Box::new(SelectQuery {
1695 ctes,
1696 recursive,
1697 body,
1698 })))
1699}
1700
1701fn convert_join(join: &sp::Join) -> Result<JoinClause> {
1702 let (join_type, constraint) = match &join.join_operator {
1703 sp::JoinOperator::Inner(c) => (JoinType::Inner, Some(c)),
1704 sp::JoinOperator::Join(c) => (JoinType::Inner, Some(c)),
1705 sp::JoinOperator::CrossJoin(c) => (JoinType::Cross, Some(c)),
1706 sp::JoinOperator::Left(c) => (JoinType::Left, Some(c)),
1707 sp::JoinOperator::LeftSemi(c) => (JoinType::Left, Some(c)),
1708 sp::JoinOperator::LeftAnti(c) => (JoinType::Left, Some(c)),
1709 sp::JoinOperator::Right(c) => (JoinType::Right, Some(c)),
1710 sp::JoinOperator::RightSemi(c) => (JoinType::Right, Some(c)),
1711 sp::JoinOperator::RightAnti(c) => (JoinType::Right, Some(c)),
1712 other => return Err(SqlError::Unsupported(format!("join type: {other:?}"))),
1713 };
1714
1715 let (name, alias) = match &join.relation {
1716 sp::TableFactor::Table { name, alias, .. } => {
1717 let table_name = object_name_to_string(name);
1718 let alias_str = alias.as_ref().map(|a| a.name.value.clone());
1719 (table_name, alias_str)
1720 }
1721 _ => return Err(SqlError::Unsupported("non-table JOIN source".into())),
1722 };
1723
1724 let on_clause = match constraint {
1725 Some(sp::JoinConstraint::On(expr)) => Some(convert_expr(expr)?),
1726 Some(sp::JoinConstraint::None) | None => None,
1727 Some(other) => return Err(SqlError::Unsupported(format!("join constraint: {other:?}"))),
1728 };
1729
1730 Ok(JoinClause {
1731 join_type,
1732 table: TableRef { name, alias },
1733 on_clause,
1734 })
1735}
1736
1737fn convert_update(update: sp::Update) -> Result<Statement> {
1738 let table = match &update.table.relation {
1739 sp::TableFactor::Table { name, .. } => object_name_to_string(name),
1740 _ => return Err(SqlError::Unsupported("non-table UPDATE target".into())),
1741 };
1742
1743 let assignments = update
1744 .assignments
1745 .iter()
1746 .map(|a| {
1747 let col = match &a.target {
1748 sp::AssignmentTarget::ColumnName(name) => object_name_to_string(name),
1749 _ => return Err(SqlError::Unsupported("tuple assignment".into())),
1750 };
1751 let expr = convert_expr(&a.value)?;
1752 Ok((col, expr))
1753 })
1754 .collect::<Result<_>>()?;
1755
1756 let where_clause = update.selection.as_ref().map(convert_expr).transpose()?;
1757
1758 Ok(Statement::Update(UpdateStmt {
1759 table,
1760 assignments,
1761 where_clause,
1762 }))
1763}
1764
1765fn convert_delete(delete: sp::Delete) -> Result<Statement> {
1766 let table_name = match &delete.from {
1767 sp::FromTable::WithFromKeyword(tables) => {
1768 if tables.len() != 1 {
1769 return Err(SqlError::Unsupported("multi-table DELETE".into()));
1770 }
1771 match &tables[0].relation {
1772 sp::TableFactor::Table { name, .. } => object_name_to_string(name),
1773 _ => return Err(SqlError::Unsupported("non-table DELETE target".into())),
1774 }
1775 }
1776 sp::FromTable::WithoutKeyword(tables) => {
1777 if tables.len() != 1 {
1778 return Err(SqlError::Unsupported("multi-table DELETE".into()));
1779 }
1780 match &tables[0].relation {
1781 sp::TableFactor::Table { name, .. } => object_name_to_string(name),
1782 _ => return Err(SqlError::Unsupported("non-table DELETE target".into())),
1783 }
1784 }
1785 };
1786
1787 let where_clause = delete.selection.as_ref().map(convert_expr).transpose()?;
1788
1789 Ok(Statement::Delete(DeleteStmt {
1790 table: table_name,
1791 where_clause,
1792 }))
1793}
1794
1795fn convert_expr(expr: &sp::Expr) -> Result<Expr> {
1798 match expr {
1799 sp::Expr::Value(v) => convert_value(&v.value),
1800 sp::Expr::Identifier(ident) => Ok(Expr::Column(ident.value.to_ascii_lowercase())),
1801 sp::Expr::CompoundIdentifier(parts) => {
1802 if parts.len() == 2 {
1803 Ok(Expr::QualifiedColumn {
1804 table: parts[0].value.to_ascii_lowercase(),
1805 column: parts[1].value.to_ascii_lowercase(),
1806 })
1807 } else {
1808 Ok(Expr::Column(
1809 parts.last().unwrap().value.to_ascii_lowercase(),
1810 ))
1811 }
1812 }
1813 sp::Expr::BinaryOp { left, op, right } => {
1814 let bin_op = convert_bin_op(op)?;
1815 Ok(Expr::BinaryOp {
1816 left: Box::new(convert_expr(left)?),
1817 op: bin_op,
1818 right: Box::new(convert_expr(right)?),
1819 })
1820 }
1821 sp::Expr::UnaryOp { op, expr } => {
1822 let unary_op = match op {
1823 sp::UnaryOperator::Minus => UnaryOp::Neg,
1824 sp::UnaryOperator::Not => UnaryOp::Not,
1825 _ => return Err(SqlError::Unsupported(format!("unary op: {op}"))),
1826 };
1827 Ok(Expr::UnaryOp {
1828 op: unary_op,
1829 expr: Box::new(convert_expr(expr)?),
1830 })
1831 }
1832 sp::Expr::IsNull(e) => Ok(Expr::IsNull(Box::new(convert_expr(e)?))),
1833 sp::Expr::IsNotNull(e) => Ok(Expr::IsNotNull(Box::new(convert_expr(e)?))),
1834 sp::Expr::Nested(e) => convert_expr(e),
1835 sp::Expr::Function(func) => convert_function(func),
1836 sp::Expr::InSubquery {
1837 expr: e,
1838 subquery,
1839 negated,
1840 } => {
1841 let inner_expr = convert_expr(e)?;
1842 let stmt = convert_subquery(subquery)?;
1843 Ok(Expr::InSubquery {
1844 expr: Box::new(inner_expr),
1845 subquery: Box::new(stmt),
1846 negated: *negated,
1847 })
1848 }
1849 sp::Expr::InList {
1850 expr: e,
1851 list,
1852 negated,
1853 } => {
1854 let inner_expr = convert_expr(e)?;
1855 let items = list.iter().map(convert_expr).collect::<Result<Vec<_>>>()?;
1856 Ok(Expr::InList {
1857 expr: Box::new(inner_expr),
1858 list: items,
1859 negated: *negated,
1860 })
1861 }
1862 sp::Expr::Exists { subquery, negated } => {
1863 let stmt = convert_subquery(subquery)?;
1864 Ok(Expr::Exists {
1865 subquery: Box::new(stmt),
1866 negated: *negated,
1867 })
1868 }
1869 sp::Expr::Subquery(query) => {
1870 let stmt = convert_subquery(query)?;
1871 Ok(Expr::ScalarSubquery(Box::new(stmt)))
1872 }
1873 sp::Expr::Between {
1874 expr: e,
1875 negated,
1876 low,
1877 high,
1878 } => Ok(Expr::Between {
1879 expr: Box::new(convert_expr(e)?),
1880 low: Box::new(convert_expr(low)?),
1881 high: Box::new(convert_expr(high)?),
1882 negated: *negated,
1883 }),
1884 sp::Expr::Like {
1885 expr: e,
1886 negated,
1887 pattern,
1888 escape_char,
1889 ..
1890 } => {
1891 let esc = escape_char
1892 .as_ref()
1893 .map(convert_escape_value)
1894 .transpose()?
1895 .map(Box::new);
1896 Ok(Expr::Like {
1897 expr: Box::new(convert_expr(e)?),
1898 pattern: Box::new(convert_expr(pattern)?),
1899 escape: esc,
1900 negated: *negated,
1901 })
1902 }
1903 sp::Expr::ILike {
1904 expr: e,
1905 negated,
1906 pattern,
1907 escape_char,
1908 ..
1909 } => {
1910 let esc = escape_char
1911 .as_ref()
1912 .map(convert_escape_value)
1913 .transpose()?
1914 .map(Box::new);
1915 Ok(Expr::Like {
1916 expr: Box::new(convert_expr(e)?),
1917 pattern: Box::new(convert_expr(pattern)?),
1918 escape: esc,
1919 negated: *negated,
1920 })
1921 }
1922 sp::Expr::Case {
1923 operand,
1924 conditions,
1925 else_result,
1926 ..
1927 } => {
1928 let op = operand
1929 .as_ref()
1930 .map(|e| convert_expr(e))
1931 .transpose()?
1932 .map(Box::new);
1933 let conds: Vec<(Expr, Expr)> = conditions
1934 .iter()
1935 .map(|cw| Ok((convert_expr(&cw.condition)?, convert_expr(&cw.result)?)))
1936 .collect::<Result<_>>()?;
1937 let else_r = else_result
1938 .as_ref()
1939 .map(|e| convert_expr(e))
1940 .transpose()?
1941 .map(Box::new);
1942 Ok(Expr::Case {
1943 operand: op,
1944 conditions: conds,
1945 else_result: else_r,
1946 })
1947 }
1948 sp::Expr::Cast {
1949 expr: e,
1950 data_type: dt,
1951 ..
1952 } => {
1953 let target = convert_data_type(dt)?;
1954 Ok(Expr::Cast {
1955 expr: Box::new(convert_expr(e)?),
1956 data_type: target,
1957 })
1958 }
1959 sp::Expr::Substring {
1960 expr: e,
1961 substring_from,
1962 substring_for,
1963 ..
1964 } => {
1965 let mut args = vec![convert_expr(e)?];
1966 if let Some(from) = substring_from {
1967 args.push(convert_expr(from)?);
1968 }
1969 if let Some(f) = substring_for {
1970 args.push(convert_expr(f)?);
1971 }
1972 Ok(Expr::Function {
1973 name: "SUBSTR".into(),
1974 args,
1975 })
1976 }
1977 sp::Expr::Trim {
1978 expr: e,
1979 trim_where,
1980 trim_what,
1981 trim_characters,
1982 } => {
1983 let fn_name = match trim_where {
1984 Some(sp::TrimWhereField::Leading) => "LTRIM",
1985 Some(sp::TrimWhereField::Trailing) => "RTRIM",
1986 _ => "TRIM",
1987 };
1988 let mut args = vec![convert_expr(e)?];
1989 if let Some(what) = trim_what {
1990 args.push(convert_expr(what)?);
1991 } else if let Some(chars) = trim_characters {
1992 if let Some(first) = chars.first() {
1993 args.push(convert_expr(first)?);
1994 }
1995 }
1996 Ok(Expr::Function {
1997 name: fn_name.into(),
1998 args,
1999 })
2000 }
2001 sp::Expr::Ceil { expr: e, .. } => Ok(Expr::Function {
2002 name: "CEIL".into(),
2003 args: vec![convert_expr(e)?],
2004 }),
2005 sp::Expr::Floor { expr: e, .. } => Ok(Expr::Function {
2006 name: "FLOOR".into(),
2007 args: vec![convert_expr(e)?],
2008 }),
2009 sp::Expr::Position { expr: e, r#in } => Ok(Expr::Function {
2010 name: "INSTR".into(),
2011 args: vec![convert_expr(r#in)?, convert_expr(e)?],
2012 }),
2013 _ => Err(SqlError::Unsupported(format!("expression: {expr}"))),
2014 }
2015}
2016
2017fn convert_value(val: &sp::Value) -> Result<Expr> {
2018 match val {
2019 sp::Value::Number(n, _) => {
2020 if let Ok(i) = n.parse::<i64>() {
2021 Ok(Expr::Literal(Value::Integer(i)))
2022 } else if let Ok(f) = n.parse::<f64>() {
2023 Ok(Expr::Literal(Value::Real(f)))
2024 } else {
2025 Err(SqlError::InvalidValue(format!("cannot parse number: {n}")))
2026 }
2027 }
2028 sp::Value::SingleQuotedString(s) => Ok(Expr::Literal(Value::Text(s.as_str().into()))),
2029 sp::Value::Boolean(b) => Ok(Expr::Literal(Value::Boolean(*b))),
2030 sp::Value::Null => Ok(Expr::Literal(Value::Null)),
2031 sp::Value::Placeholder(s) => {
2032 let idx_str = s
2033 .strip_prefix('$')
2034 .ok_or_else(|| SqlError::Parse(format!("invalid placeholder: {s}")))?;
2035 let idx: usize = idx_str
2036 .parse()
2037 .map_err(|_| SqlError::Parse(format!("invalid placeholder index: {s}")))?;
2038 if idx == 0 {
2039 return Err(SqlError::Parse("placeholder index must be >= 1".into()));
2040 }
2041 Ok(Expr::Parameter(idx))
2042 }
2043 _ => Err(SqlError::Unsupported(format!("value type: {val}"))),
2044 }
2045}
2046
2047fn convert_escape_value(val: &sp::Value) -> Result<Expr> {
2048 match val {
2049 sp::Value::SingleQuotedString(s) => Ok(Expr::Literal(Value::Text(s.as_str().into()))),
2050 _ => Err(SqlError::Unsupported(format!("ESCAPE value: {val}"))),
2051 }
2052}
2053
2054fn convert_bin_op(op: &sp::BinaryOperator) -> Result<BinOp> {
2055 match op {
2056 sp::BinaryOperator::Plus => Ok(BinOp::Add),
2057 sp::BinaryOperator::Minus => Ok(BinOp::Sub),
2058 sp::BinaryOperator::Multiply => Ok(BinOp::Mul),
2059 sp::BinaryOperator::Divide => Ok(BinOp::Div),
2060 sp::BinaryOperator::Modulo => Ok(BinOp::Mod),
2061 sp::BinaryOperator::Eq => Ok(BinOp::Eq),
2062 sp::BinaryOperator::NotEq => Ok(BinOp::NotEq),
2063 sp::BinaryOperator::Lt => Ok(BinOp::Lt),
2064 sp::BinaryOperator::Gt => Ok(BinOp::Gt),
2065 sp::BinaryOperator::LtEq => Ok(BinOp::LtEq),
2066 sp::BinaryOperator::GtEq => Ok(BinOp::GtEq),
2067 sp::BinaryOperator::And => Ok(BinOp::And),
2068 sp::BinaryOperator::Or => Ok(BinOp::Or),
2069 sp::BinaryOperator::StringConcat => Ok(BinOp::Concat),
2070 _ => Err(SqlError::Unsupported(format!("binary op: {op}"))),
2071 }
2072}
2073
2074fn convert_function(func: &sp::Function) -> Result<Expr> {
2075 let name = object_name_to_string(&func.name).to_ascii_uppercase();
2076
2077 let (args, is_count_star) = match &func.args {
2078 sp::FunctionArguments::List(list) => {
2079 if list.args.is_empty() && name == "COUNT" {
2080 (vec![], true)
2081 } else {
2082 let mut count_star = false;
2083 let args = list
2084 .args
2085 .iter()
2086 .map(|arg| match arg {
2087 sp::FunctionArg::Unnamed(sp::FunctionArgExpr::Expr(e)) => convert_expr(e),
2088 sp::FunctionArg::Unnamed(sp::FunctionArgExpr::Wildcard) => {
2089 if name == "COUNT" {
2090 count_star = true;
2091 Ok(Expr::CountStar)
2092 } else {
2093 Err(SqlError::Unsupported(format!("{name}(*)")))
2094 }
2095 }
2096 _ => Err(SqlError::Unsupported(format!(
2097 "function arg type in {name}"
2098 ))),
2099 })
2100 .collect::<Result<Vec<_>>>()?;
2101 if name == "COUNT" && args.len() == 1 && count_star {
2102 (vec![], true)
2103 } else {
2104 (args, false)
2105 }
2106 }
2107 }
2108 sp::FunctionArguments::None => {
2109 if name == "COUNT" {
2110 (vec![], true)
2111 } else {
2112 (vec![], false)
2113 }
2114 }
2115 sp::FunctionArguments::Subquery(_) => {
2116 return Err(SqlError::Unsupported("subquery in function".into()));
2117 }
2118 };
2119
2120 if let Some(over) = &func.over {
2122 let spec = match over {
2123 sp::WindowType::WindowSpec(ws) => convert_window_spec(ws)?,
2124 sp::WindowType::NamedWindow(_) => {
2125 return Err(SqlError::Unsupported("named windows".into()));
2126 }
2127 };
2128 return Ok(Expr::WindowFunction { name, args, spec });
2129 }
2130
2131 if is_count_star {
2133 return Ok(Expr::CountStar);
2134 }
2135
2136 if name == "COALESCE" {
2137 if args.is_empty() {
2138 return Err(SqlError::Parse(
2139 "COALESCE requires at least one argument".into(),
2140 ));
2141 }
2142 return Ok(Expr::Coalesce(args));
2143 }
2144
2145 if name == "NULLIF" {
2146 if args.len() != 2 {
2147 return Err(SqlError::Parse(
2148 "NULLIF requires exactly two arguments".into(),
2149 ));
2150 }
2151 return Ok(Expr::Case {
2152 operand: None,
2153 conditions: vec![(
2154 Expr::BinaryOp {
2155 left: Box::new(args[0].clone()),
2156 op: BinOp::Eq,
2157 right: Box::new(args[1].clone()),
2158 },
2159 Expr::Literal(Value::Null),
2160 )],
2161 else_result: Some(Box::new(args[0].clone())),
2162 });
2163 }
2164
2165 if name == "IIF" {
2166 if args.len() != 3 {
2167 return Err(SqlError::Parse(
2168 "IIF requires exactly three arguments".into(),
2169 ));
2170 }
2171 return Ok(Expr::Case {
2172 operand: None,
2173 conditions: vec![(args[0].clone(), args[1].clone())],
2174 else_result: Some(Box::new(args[2].clone())),
2175 });
2176 }
2177
2178 Ok(Expr::Function { name, args })
2179}
2180
2181fn convert_window_spec(ws: &sp::WindowSpec) -> Result<WindowSpec> {
2182 let partition_by = ws
2183 .partition_by
2184 .iter()
2185 .map(convert_expr)
2186 .collect::<Result<Vec<_>>>()?;
2187 let order_by = ws
2188 .order_by
2189 .iter()
2190 .map(convert_order_by_expr)
2191 .collect::<Result<Vec<_>>>()?;
2192 let frame = ws
2193 .window_frame
2194 .as_ref()
2195 .map(convert_window_frame)
2196 .transpose()?;
2197 Ok(WindowSpec {
2198 partition_by,
2199 order_by,
2200 frame,
2201 })
2202}
2203
2204fn convert_window_frame(wf: &sp::WindowFrame) -> Result<WindowFrame> {
2205 let units = match wf.units {
2206 sp::WindowFrameUnits::Rows => WindowFrameUnits::Rows,
2207 sp::WindowFrameUnits::Range => WindowFrameUnits::Range,
2208 sp::WindowFrameUnits::Groups => {
2209 return Err(SqlError::Unsupported("GROUPS window frame".into()));
2210 }
2211 };
2212 let start = convert_window_frame_bound(&wf.start_bound)?;
2213 let end = match &wf.end_bound {
2214 Some(b) => convert_window_frame_bound(b)?,
2215 None => WindowFrameBound::CurrentRow,
2216 };
2217 Ok(WindowFrame { units, start, end })
2218}
2219
2220fn convert_window_frame_bound(b: &sp::WindowFrameBound) -> Result<WindowFrameBound> {
2221 match b {
2222 sp::WindowFrameBound::CurrentRow => Ok(WindowFrameBound::CurrentRow),
2223 sp::WindowFrameBound::Preceding(None) => Ok(WindowFrameBound::UnboundedPreceding),
2224 sp::WindowFrameBound::Preceding(Some(e)) => {
2225 Ok(WindowFrameBound::Preceding(Box::new(convert_expr(e)?)))
2226 }
2227 sp::WindowFrameBound::Following(None) => Ok(WindowFrameBound::UnboundedFollowing),
2228 sp::WindowFrameBound::Following(Some(e)) => {
2229 Ok(WindowFrameBound::Following(Box::new(convert_expr(e)?)))
2230 }
2231 }
2232}
2233
2234fn convert_select_item(item: &sp::SelectItem) -> Result<SelectColumn> {
2235 match item {
2236 sp::SelectItem::Wildcard(_) => Ok(SelectColumn::AllColumns),
2237 sp::SelectItem::UnnamedExpr(e) => {
2238 let expr = convert_expr(e)?;
2239 Ok(SelectColumn::Expr { expr, alias: None })
2240 }
2241 sp::SelectItem::ExprWithAlias { expr, alias } => {
2242 let expr = convert_expr(expr)?;
2243 Ok(SelectColumn::Expr {
2244 expr,
2245 alias: Some(alias.value.clone()),
2246 })
2247 }
2248 sp::SelectItem::QualifiedWildcard(_, _) => {
2249 Err(SqlError::Unsupported("qualified wildcard (table.*)".into()))
2250 }
2251 }
2252}
2253
2254fn convert_order_by_expr(expr: &sp::OrderByExpr) -> Result<OrderByItem> {
2255 let e = convert_expr(&expr.expr)?;
2256 let descending = expr.options.asc.map(|asc| !asc).unwrap_or(false);
2257 let nulls_first = expr.options.nulls_first;
2258
2259 Ok(OrderByItem {
2260 expr: e,
2261 descending,
2262 nulls_first,
2263 })
2264}
2265
2266fn convert_data_type(dt: &sp::DataType) -> Result<DataType> {
2269 match dt {
2270 sp::DataType::Int(_)
2271 | sp::DataType::Integer(_)
2272 | sp::DataType::BigInt(_)
2273 | sp::DataType::SmallInt(_)
2274 | sp::DataType::TinyInt(_)
2275 | sp::DataType::Int2(_)
2276 | sp::DataType::Int4(_)
2277 | sp::DataType::Int8(_) => Ok(DataType::Integer),
2278
2279 sp::DataType::Real
2280 | sp::DataType::Double(..)
2281 | sp::DataType::DoublePrecision
2282 | sp::DataType::Float(_)
2283 | sp::DataType::Float4
2284 | sp::DataType::Float64 => Ok(DataType::Real),
2285
2286 sp::DataType::Varchar(_)
2287 | sp::DataType::Text
2288 | sp::DataType::Char(_)
2289 | sp::DataType::Character(_)
2290 | sp::DataType::String(_) => Ok(DataType::Text),
2291
2292 sp::DataType::Blob(_) | sp::DataType::Bytea => Ok(DataType::Blob),
2293
2294 sp::DataType::Boolean | sp::DataType::Bool => Ok(DataType::Boolean),
2295
2296 _ => Err(SqlError::Unsupported(format!("data type: {dt}"))),
2297 }
2298}
2299
2300fn object_name_to_string(name: &sp::ObjectName) -> String {
2303 name.0
2304 .iter()
2305 .filter_map(|p| match p {
2306 sp::ObjectNamePart::Identifier(ident) => Some(ident.value.clone()),
2307 _ => None,
2308 })
2309 .collect::<Vec<_>>()
2310 .join(".")
2311}
2312
2313#[cfg(test)]
2314mod tests {
2315 use super::*;
2316
2317 #[test]
2318 fn parse_create_table() {
2319 let stmt = parse_sql(
2320 "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER)",
2321 )
2322 .unwrap();
2323
2324 match stmt {
2325 Statement::CreateTable(ct) => {
2326 assert_eq!(ct.name, "users");
2327 assert_eq!(ct.columns.len(), 3);
2328 assert_eq!(ct.columns[0].name, "id");
2329 assert_eq!(ct.columns[0].data_type, DataType::Integer);
2330 assert!(ct.columns[0].is_primary_key);
2331 assert!(!ct.columns[0].nullable);
2332 assert_eq!(ct.columns[1].name, "name");
2333 assert_eq!(ct.columns[1].data_type, DataType::Text);
2334 assert!(!ct.columns[1].nullable);
2335 assert_eq!(ct.columns[2].name, "age");
2336 assert!(ct.columns[2].nullable);
2337 assert_eq!(ct.primary_key, vec!["id"]);
2338 }
2339 _ => panic!("expected CreateTable"),
2340 }
2341 }
2342
2343 #[test]
2344 fn parse_create_table_if_not_exists() {
2345 let stmt = parse_sql("CREATE TABLE IF NOT EXISTS t (id INT PRIMARY KEY)").unwrap();
2346 match stmt {
2347 Statement::CreateTable(ct) => assert!(ct.if_not_exists),
2348 _ => panic!("expected CreateTable"),
2349 }
2350 }
2351
2352 #[test]
2353 fn parse_drop_table() {
2354 let stmt = parse_sql("DROP TABLE users").unwrap();
2355 match stmt {
2356 Statement::DropTable(dt) => {
2357 assert_eq!(dt.name, "users");
2358 assert!(!dt.if_exists);
2359 }
2360 _ => panic!("expected DropTable"),
2361 }
2362 }
2363
2364 #[test]
2365 fn parse_drop_table_if_exists() {
2366 let stmt = parse_sql("DROP TABLE IF EXISTS users").unwrap();
2367 match stmt {
2368 Statement::DropTable(dt) => assert!(dt.if_exists),
2369 _ => panic!("expected DropTable"),
2370 }
2371 }
2372
2373 #[test]
2374 fn parse_insert() {
2375 let stmt =
2376 parse_sql("INSERT INTO users (id, name) VALUES (1, 'Alice'), (2, 'Bob')").unwrap();
2377
2378 match stmt {
2379 Statement::Insert(ins) => {
2380 assert_eq!(ins.table, "users");
2381 assert_eq!(ins.columns, vec!["id", "name"]);
2382 let values = match &ins.source {
2383 InsertSource::Values(v) => v,
2384 _ => panic!("expected Values"),
2385 };
2386 assert_eq!(values.len(), 2);
2387 assert!(matches!(values[0][0], Expr::Literal(Value::Integer(1))));
2388 assert!(matches!(&values[0][1], Expr::Literal(Value::Text(s)) if s == "Alice"));
2389 }
2390 _ => panic!("expected Insert"),
2391 }
2392 }
2393
2394 #[test]
2395 fn parse_select_all() {
2396 let stmt = parse_sql("SELECT * FROM users").unwrap();
2397 match stmt {
2398 Statement::Select(sq) => match sq.body {
2399 QueryBody::Select(sel) => {
2400 assert_eq!(sel.from, "users");
2401 assert!(matches!(sel.columns[0], SelectColumn::AllColumns));
2402 assert!(sel.where_clause.is_none());
2403 }
2404 _ => panic!("expected QueryBody::Select"),
2405 },
2406 _ => panic!("expected Select"),
2407 }
2408 }
2409
2410 #[test]
2411 fn parse_select_where() {
2412 let stmt = parse_sql("SELECT id, name FROM users WHERE age > 18").unwrap();
2413 match stmt {
2414 Statement::Select(sq) => match sq.body {
2415 QueryBody::Select(sel) => {
2416 assert_eq!(sel.columns.len(), 2);
2417 assert!(sel.where_clause.is_some());
2418 }
2419 _ => panic!("expected QueryBody::Select"),
2420 },
2421 _ => panic!("expected Select"),
2422 }
2423 }
2424
2425 #[test]
2426 fn parse_select_order_limit() {
2427 let stmt = parse_sql("SELECT * FROM users ORDER BY name ASC LIMIT 10 OFFSET 5").unwrap();
2428 match stmt {
2429 Statement::Select(sq) => match sq.body {
2430 QueryBody::Select(sel) => {
2431 assert_eq!(sel.order_by.len(), 1);
2432 assert!(!sel.order_by[0].descending);
2433 assert!(sel.limit.is_some());
2434 assert!(sel.offset.is_some());
2435 }
2436 _ => panic!("expected QueryBody::Select"),
2437 },
2438 _ => panic!("expected Select"),
2439 }
2440 }
2441
2442 #[test]
2443 fn parse_update() {
2444 let stmt = parse_sql("UPDATE users SET name = 'Bob' WHERE id = 1").unwrap();
2445 match stmt {
2446 Statement::Update(upd) => {
2447 assert_eq!(upd.table, "users");
2448 assert_eq!(upd.assignments.len(), 1);
2449 assert_eq!(upd.assignments[0].0, "name");
2450 assert!(upd.where_clause.is_some());
2451 }
2452 _ => panic!("expected Update"),
2453 }
2454 }
2455
2456 #[test]
2457 fn parse_delete() {
2458 let stmt = parse_sql("DELETE FROM users WHERE id = 1").unwrap();
2459 match stmt {
2460 Statement::Delete(del) => {
2461 assert_eq!(del.table, "users");
2462 assert!(del.where_clause.is_some());
2463 }
2464 _ => panic!("expected Delete"),
2465 }
2466 }
2467
2468 #[test]
2469 fn parse_aggregate() {
2470 let stmt = parse_sql("SELECT COUNT(*), SUM(age) FROM users").unwrap();
2471 match stmt {
2472 Statement::Select(sq) => match sq.body {
2473 QueryBody::Select(sel) => {
2474 assert_eq!(sel.columns.len(), 2);
2475 match &sel.columns[0] {
2476 SelectColumn::Expr {
2477 expr: Expr::CountStar,
2478 ..
2479 } => {}
2480 other => panic!("expected CountStar, got {other:?}"),
2481 }
2482 }
2483 _ => panic!("expected QueryBody::Select"),
2484 },
2485 _ => panic!("expected Select"),
2486 }
2487 }
2488
2489 #[test]
2490 fn parse_group_by_having() {
2491 let stmt = parse_sql(
2492 "SELECT department, COUNT(*) FROM employees GROUP BY department HAVING COUNT(*) > 5",
2493 )
2494 .unwrap();
2495 match stmt {
2496 Statement::Select(sq) => match sq.body {
2497 QueryBody::Select(sel) => {
2498 assert_eq!(sel.group_by.len(), 1);
2499 assert!(sel.having.is_some());
2500 }
2501 _ => panic!("expected QueryBody::Select"),
2502 },
2503 _ => panic!("expected Select"),
2504 }
2505 }
2506
2507 #[test]
2508 fn parse_expressions() {
2509 let stmt = parse_sql("SELECT id + 1, -price, NOT active FROM items").unwrap();
2510 match stmt {
2511 Statement::Select(sq) => match sq.body {
2512 QueryBody::Select(sel) => {
2513 assert_eq!(sel.columns.len(), 3);
2514 match &sel.columns[0] {
2516 SelectColumn::Expr {
2517 expr: Expr::BinaryOp { op: BinOp::Add, .. },
2518 ..
2519 } => {}
2520 other => panic!("expected BinaryOp Add, got {other:?}"),
2521 }
2522 match &sel.columns[1] {
2524 SelectColumn::Expr {
2525 expr:
2526 Expr::UnaryOp {
2527 op: UnaryOp::Neg, ..
2528 },
2529 ..
2530 } => {}
2531 other => panic!("expected UnaryOp Neg, got {other:?}"),
2532 }
2533 match &sel.columns[2] {
2535 SelectColumn::Expr {
2536 expr:
2537 Expr::UnaryOp {
2538 op: UnaryOp::Not, ..
2539 },
2540 ..
2541 } => {}
2542 other => panic!("expected UnaryOp Not, got {other:?}"),
2543 }
2544 }
2545 _ => panic!("expected QueryBody::Select"),
2546 },
2547 _ => panic!("expected Select"),
2548 }
2549 }
2550
2551 #[test]
2552 fn parse_is_null() {
2553 let stmt = parse_sql("SELECT * FROM t WHERE x IS NULL").unwrap();
2554 match stmt {
2555 Statement::Select(sq) => match sq.body {
2556 QueryBody::Select(sel) => {
2557 assert!(matches!(sel.where_clause, Some(Expr::IsNull(_))));
2558 }
2559 _ => panic!("expected QueryBody::Select"),
2560 },
2561 _ => panic!("expected Select"),
2562 }
2563 }
2564
2565 #[test]
2566 fn parse_inner_join() {
2567 let stmt = parse_sql("SELECT * FROM a JOIN b ON a.id = b.id").unwrap();
2568 match stmt {
2569 Statement::Select(sq) => match sq.body {
2570 QueryBody::Select(sel) => {
2571 assert_eq!(sel.from, "a");
2572 assert_eq!(sel.joins.len(), 1);
2573 assert_eq!(sel.joins[0].join_type, JoinType::Inner);
2574 assert_eq!(sel.joins[0].table.name, "b");
2575 assert!(sel.joins[0].on_clause.is_some());
2576 }
2577 _ => panic!("expected QueryBody::Select"),
2578 },
2579 _ => panic!("expected Select"),
2580 }
2581 }
2582
2583 #[test]
2584 fn parse_inner_join_explicit() {
2585 let stmt = parse_sql("SELECT * FROM a INNER JOIN b ON a.id = b.a_id").unwrap();
2586 match stmt {
2587 Statement::Select(sq) => match sq.body {
2588 QueryBody::Select(sel) => {
2589 assert_eq!(sel.joins.len(), 1);
2590 assert_eq!(sel.joins[0].join_type, JoinType::Inner);
2591 }
2592 _ => panic!("expected QueryBody::Select"),
2593 },
2594 _ => panic!("expected Select"),
2595 }
2596 }
2597
2598 #[test]
2599 fn parse_cross_join() {
2600 let stmt = parse_sql("SELECT * FROM a CROSS JOIN b").unwrap();
2601 match stmt {
2602 Statement::Select(sq) => match sq.body {
2603 QueryBody::Select(sel) => {
2604 assert_eq!(sel.joins.len(), 1);
2605 assert_eq!(sel.joins[0].join_type, JoinType::Cross);
2606 assert!(sel.joins[0].on_clause.is_none());
2607 }
2608 _ => panic!("expected QueryBody::Select"),
2609 },
2610 _ => panic!("expected Select"),
2611 }
2612 }
2613
2614 #[test]
2615 fn parse_left_join() {
2616 let stmt = parse_sql("SELECT * FROM a LEFT JOIN b ON a.id = b.a_id").unwrap();
2617 match stmt {
2618 Statement::Select(sq) => match sq.body {
2619 QueryBody::Select(sel) => {
2620 assert_eq!(sel.joins.len(), 1);
2621 assert_eq!(sel.joins[0].join_type, JoinType::Left);
2622 }
2623 _ => panic!("expected QueryBody::Select"),
2624 },
2625 _ => panic!("expected Select"),
2626 }
2627 }
2628
2629 #[test]
2630 fn parse_table_alias() {
2631 let stmt = parse_sql("SELECT u.id FROM users u JOIN orders o ON u.id = o.user_id").unwrap();
2632 match stmt {
2633 Statement::Select(sq) => match sq.body {
2634 QueryBody::Select(sel) => {
2635 assert_eq!(sel.from, "users");
2636 assert_eq!(sel.from_alias.as_deref(), Some("u"));
2637 assert_eq!(sel.joins[0].table.name, "orders");
2638 assert_eq!(sel.joins[0].table.alias.as_deref(), Some("o"));
2639 }
2640 _ => panic!("expected QueryBody::Select"),
2641 },
2642 _ => panic!("expected Select"),
2643 }
2644 }
2645
2646 #[test]
2647 fn parse_multi_join() {
2648 let stmt =
2649 parse_sql("SELECT * FROM a JOIN b ON a.id = b.a_id JOIN c ON b.id = c.b_id").unwrap();
2650 match stmt {
2651 Statement::Select(sq) => match sq.body {
2652 QueryBody::Select(sel) => {
2653 assert_eq!(sel.joins.len(), 2);
2654 }
2655 _ => panic!("expected QueryBody::Select"),
2656 },
2657 _ => panic!("expected Select"),
2658 }
2659 }
2660
2661 #[test]
2662 fn parse_qualified_column() {
2663 let stmt = parse_sql("SELECT u.id, u.name FROM users u").unwrap();
2664 match stmt {
2665 Statement::Select(sq) => match sq.body {
2666 QueryBody::Select(sel) => match &sel.columns[0] {
2667 SelectColumn::Expr {
2668 expr: Expr::QualifiedColumn { table, column },
2669 ..
2670 } => {
2671 assert_eq!(table, "u");
2672 assert_eq!(column, "id");
2673 }
2674 other => panic!("expected QualifiedColumn, got {other:?}"),
2675 },
2676 _ => panic!("expected QueryBody::Select"),
2677 },
2678 _ => panic!("expected Select"),
2679 }
2680 }
2681
2682 #[test]
2683 fn reject_subquery() {
2684 assert!(parse_sql("SELECT * FROM (SELECT 1)").is_err());
2685 }
2686
2687 #[test]
2688 fn parse_type_mapping() {
2689 let stmt = parse_sql(
2690 "CREATE TABLE t (a INT PRIMARY KEY, b BIGINT, c SMALLINT, d REAL, e DOUBLE PRECISION, f VARCHAR(255), g BOOLEAN, h BLOB, i BYTEA)"
2691 ).unwrap();
2692 match stmt {
2693 Statement::CreateTable(ct) => {
2694 assert_eq!(ct.columns[0].data_type, DataType::Integer); assert_eq!(ct.columns[1].data_type, DataType::Integer); assert_eq!(ct.columns[2].data_type, DataType::Integer); assert_eq!(ct.columns[3].data_type, DataType::Real); assert_eq!(ct.columns[4].data_type, DataType::Real); assert_eq!(ct.columns[5].data_type, DataType::Text); assert_eq!(ct.columns[6].data_type, DataType::Boolean); assert_eq!(ct.columns[7].data_type, DataType::Blob); assert_eq!(ct.columns[8].data_type, DataType::Blob); }
2704 _ => panic!("expected CreateTable"),
2705 }
2706 }
2707
2708 #[test]
2709 fn parse_boolean_literals() {
2710 let stmt = parse_sql("INSERT INTO t (a, b) VALUES (true, false)").unwrap();
2711 match stmt {
2712 Statement::Insert(ins) => {
2713 let values = match &ins.source {
2714 InsertSource::Values(v) => v,
2715 _ => panic!("expected Values"),
2716 };
2717 assert!(matches!(values[0][0], Expr::Literal(Value::Boolean(true))));
2718 assert!(matches!(values[0][1], Expr::Literal(Value::Boolean(false))));
2719 }
2720 _ => panic!("expected Insert"),
2721 }
2722 }
2723
2724 #[test]
2725 fn parse_null_literal() {
2726 let stmt = parse_sql("INSERT INTO t (a) VALUES (NULL)").unwrap();
2727 match stmt {
2728 Statement::Insert(ins) => {
2729 let values = match &ins.source {
2730 InsertSource::Values(v) => v,
2731 _ => panic!("expected Values"),
2732 };
2733 assert!(matches!(values[0][0], Expr::Literal(Value::Null)));
2734 }
2735 _ => panic!("expected Insert"),
2736 }
2737 }
2738
2739 #[test]
2740 fn parse_alias() {
2741 let stmt = parse_sql("SELECT id AS user_id FROM users").unwrap();
2742 match stmt {
2743 Statement::Select(sq) => match sq.body {
2744 QueryBody::Select(sel) => match &sel.columns[0] {
2745 SelectColumn::Expr { alias: Some(a), .. } => assert_eq!(a, "user_id"),
2746 other => panic!("expected alias, got {other:?}"),
2747 },
2748 _ => panic!("expected QueryBody::Select"),
2749 },
2750 _ => panic!("expected Select"),
2751 }
2752 }
2753
2754 #[test]
2755 fn parse_begin() {
2756 let stmt = parse_sql("BEGIN").unwrap();
2757 assert!(matches!(stmt, Statement::Begin));
2758 }
2759
2760 #[test]
2761 fn parse_begin_transaction() {
2762 let stmt = parse_sql("BEGIN TRANSACTION").unwrap();
2763 assert!(matches!(stmt, Statement::Begin));
2764 }
2765
2766 #[test]
2767 fn parse_commit() {
2768 let stmt = parse_sql("COMMIT").unwrap();
2769 assert!(matches!(stmt, Statement::Commit));
2770 }
2771
2772 #[test]
2773 fn parse_rollback() {
2774 let stmt = parse_sql("ROLLBACK").unwrap();
2775 assert!(matches!(stmt, Statement::Rollback));
2776 }
2777
2778 #[test]
2779 fn parse_savepoint() {
2780 let stmt = parse_sql("SAVEPOINT sp1").unwrap();
2781 match stmt {
2782 Statement::Savepoint(name) => assert_eq!(name, "sp1"),
2783 other => panic!("expected Savepoint, got {other:?}"),
2784 }
2785 }
2786
2787 #[test]
2788 fn parse_savepoint_case_insensitive() {
2789 let stmt = parse_sql("SAVEPOINT My_SP").unwrap();
2790 match stmt {
2791 Statement::Savepoint(name) => assert_eq!(name, "my_sp"),
2792 other => panic!("expected Savepoint, got {other:?}"),
2793 }
2794 }
2795
2796 #[test]
2797 fn parse_release_savepoint() {
2798 let stmt = parse_sql("RELEASE SAVEPOINT sp1").unwrap();
2799 match stmt {
2800 Statement::ReleaseSavepoint(name) => assert_eq!(name, "sp1"),
2801 other => panic!("expected ReleaseSavepoint, got {other:?}"),
2802 }
2803 }
2804
2805 #[test]
2806 fn parse_release_without_savepoint_keyword() {
2807 let stmt = parse_sql("RELEASE sp1").unwrap();
2808 match stmt {
2809 Statement::ReleaseSavepoint(name) => assert_eq!(name, "sp1"),
2810 other => panic!("expected ReleaseSavepoint, got {other:?}"),
2811 }
2812 }
2813
2814 #[test]
2815 fn parse_rollback_to_savepoint() {
2816 let stmt = parse_sql("ROLLBACK TO SAVEPOINT sp1").unwrap();
2817 match stmt {
2818 Statement::RollbackTo(name) => assert_eq!(name, "sp1"),
2819 other => panic!("expected RollbackTo, got {other:?}"),
2820 }
2821 }
2822
2823 #[test]
2824 fn parse_rollback_to_without_savepoint_keyword() {
2825 let stmt = parse_sql("ROLLBACK TO sp1").unwrap();
2826 match stmt {
2827 Statement::RollbackTo(name) => assert_eq!(name, "sp1"),
2828 other => panic!("expected RollbackTo, got {other:?}"),
2829 }
2830 }
2831
2832 #[test]
2833 fn parse_rollback_to_case_insensitive() {
2834 let stmt = parse_sql("ROLLBACK TO My_SP").unwrap();
2835 match stmt {
2836 Statement::RollbackTo(name) => assert_eq!(name, "my_sp"),
2837 other => panic!("expected RollbackTo, got {other:?}"),
2838 }
2839 }
2840
2841 #[test]
2842 fn parse_commit_and_chain_rejected() {
2843 let err = parse_sql("COMMIT AND CHAIN").unwrap_err();
2844 assert!(matches!(err, SqlError::Unsupported(_)));
2845 }
2846
2847 #[test]
2848 fn parse_rollback_and_chain_rejected() {
2849 let err = parse_sql("ROLLBACK AND CHAIN").unwrap_err();
2850 assert!(matches!(err, SqlError::Unsupported(_)));
2851 }
2852
2853 #[test]
2854 fn parse_select_distinct() {
2855 let stmt = parse_sql("SELECT DISTINCT name FROM users").unwrap();
2856 match stmt {
2857 Statement::Select(sq) => match sq.body {
2858 QueryBody::Select(sel) => {
2859 assert!(sel.distinct);
2860 assert_eq!(sel.columns.len(), 1);
2861 }
2862 _ => panic!("expected QueryBody::Select"),
2863 },
2864 _ => panic!("expected Select"),
2865 }
2866 }
2867
2868 #[test]
2869 fn parse_select_without_distinct() {
2870 let stmt = parse_sql("SELECT name FROM users").unwrap();
2871 match stmt {
2872 Statement::Select(sq) => match sq.body {
2873 QueryBody::Select(sel) => {
2874 assert!(!sel.distinct);
2875 }
2876 _ => panic!("expected QueryBody::Select"),
2877 },
2878 _ => panic!("expected Select"),
2879 }
2880 }
2881
2882 #[test]
2883 fn parse_select_distinct_all_columns() {
2884 let stmt = parse_sql("SELECT DISTINCT * FROM users").unwrap();
2885 match stmt {
2886 Statement::Select(sq) => match sq.body {
2887 QueryBody::Select(sel) => {
2888 assert!(sel.distinct);
2889 assert!(matches!(sel.columns[0], SelectColumn::AllColumns));
2890 }
2891 _ => panic!("expected QueryBody::Select"),
2892 },
2893 _ => panic!("expected Select"),
2894 }
2895 }
2896
2897 #[test]
2898 fn reject_distinct_on() {
2899 assert!(parse_sql("SELECT DISTINCT ON (id) * FROM users").is_err());
2900 }
2901
2902 #[test]
2903 fn parse_create_index() {
2904 let stmt = parse_sql("CREATE INDEX idx_name ON users (name)").unwrap();
2905 match stmt {
2906 Statement::CreateIndex(ci) => {
2907 assert_eq!(ci.index_name, "idx_name");
2908 assert_eq!(ci.table_name, "users");
2909 assert_eq!(ci.columns, vec!["name"]);
2910 assert!(!ci.unique);
2911 assert!(!ci.if_not_exists);
2912 }
2913 _ => panic!("expected CreateIndex"),
2914 }
2915 }
2916
2917 #[test]
2918 fn parse_create_unique_index() {
2919 let stmt = parse_sql("CREATE UNIQUE INDEX idx_email ON users (email)").unwrap();
2920 match stmt {
2921 Statement::CreateIndex(ci) => {
2922 assert!(ci.unique);
2923 assert_eq!(ci.columns, vec!["email"]);
2924 }
2925 _ => panic!("expected CreateIndex"),
2926 }
2927 }
2928
2929 #[test]
2930 fn parse_create_index_if_not_exists() {
2931 let stmt = parse_sql("CREATE INDEX IF NOT EXISTS idx_x ON t (a)").unwrap();
2932 match stmt {
2933 Statement::CreateIndex(ci) => assert!(ci.if_not_exists),
2934 _ => panic!("expected CreateIndex"),
2935 }
2936 }
2937
2938 #[test]
2939 fn parse_create_index_multi_column() {
2940 let stmt = parse_sql("CREATE INDEX idx_multi ON t (a, b, c)").unwrap();
2941 match stmt {
2942 Statement::CreateIndex(ci) => {
2943 assert_eq!(ci.columns, vec!["a", "b", "c"]);
2944 }
2945 _ => panic!("expected CreateIndex"),
2946 }
2947 }
2948
2949 #[test]
2950 fn parse_drop_index() {
2951 let stmt = parse_sql("DROP INDEX idx_name").unwrap();
2952 match stmt {
2953 Statement::DropIndex(di) => {
2954 assert_eq!(di.index_name, "idx_name");
2955 assert!(!di.if_exists);
2956 }
2957 _ => panic!("expected DropIndex"),
2958 }
2959 }
2960
2961 #[test]
2962 fn parse_drop_index_if_exists() {
2963 let stmt = parse_sql("DROP INDEX IF EXISTS idx_name").unwrap();
2964 match stmt {
2965 Statement::DropIndex(di) => {
2966 assert!(di.if_exists);
2967 }
2968 _ => panic!("expected DropIndex"),
2969 }
2970 }
2971
2972 #[test]
2973 fn parse_explain_select() {
2974 let stmt = parse_sql("EXPLAIN SELECT * FROM users WHERE id = 1").unwrap();
2975 match stmt {
2976 Statement::Explain(inner) => {
2977 assert!(matches!(*inner, Statement::Select(_)));
2978 }
2979 _ => panic!("expected Explain"),
2980 }
2981 }
2982
2983 #[test]
2984 fn parse_explain_insert() {
2985 let stmt = parse_sql("EXPLAIN INSERT INTO t (a) VALUES (1)").unwrap();
2986 assert!(matches!(stmt, Statement::Explain(_)));
2987 }
2988
2989 #[test]
2990 fn reject_explain_analyze() {
2991 assert!(parse_sql("EXPLAIN ANALYZE SELECT * FROM t").is_err());
2992 }
2993
2994 #[test]
2995 fn parse_parameter_placeholder() {
2996 let stmt = parse_sql("SELECT * FROM t WHERE id = $1").unwrap();
2997 match stmt {
2998 Statement::Select(sq) => match sq.body {
2999 QueryBody::Select(sel) => match &sel.where_clause {
3000 Some(Expr::BinaryOp { right, .. }) => {
3001 assert!(matches!(right.as_ref(), Expr::Parameter(1)));
3002 }
3003 other => panic!("expected BinaryOp with Parameter, got {other:?}"),
3004 },
3005 _ => panic!("expected QueryBody::Select"),
3006 },
3007 _ => panic!("expected Select"),
3008 }
3009 }
3010
3011 #[test]
3012 fn parse_multiple_parameters() {
3013 let stmt = parse_sql("INSERT INTO t (a, b) VALUES ($1, $2)").unwrap();
3014 match stmt {
3015 Statement::Insert(ins) => {
3016 let values = match &ins.source {
3017 InsertSource::Values(v) => v,
3018 _ => panic!("expected Values"),
3019 };
3020 assert!(matches!(values[0][0], Expr::Parameter(1)));
3021 assert!(matches!(values[0][1], Expr::Parameter(2)));
3022 }
3023 _ => panic!("expected Insert"),
3024 }
3025 }
3026
3027 #[test]
3028 fn parse_insert_select() {
3029 let stmt =
3030 parse_sql("INSERT INTO t2 (id, name) SELECT id, name FROM t1 WHERE id > 5").unwrap();
3031 match stmt {
3032 Statement::Insert(ins) => {
3033 assert_eq!(ins.table, "t2");
3034 assert_eq!(ins.columns, vec!["id", "name"]);
3035 match &ins.source {
3036 InsertSource::Select(sq) => match &sq.body {
3037 QueryBody::Select(sel) => {
3038 assert_eq!(sel.from, "t1");
3039 assert_eq!(sel.columns.len(), 2);
3040 assert!(sel.where_clause.is_some());
3041 }
3042 _ => panic!("expected QueryBody::Select"),
3043 },
3044 _ => panic!("expected InsertSource::Select"),
3045 }
3046 }
3047 _ => panic!("expected Insert"),
3048 }
3049 }
3050
3051 #[test]
3052 fn parse_insert_select_no_columns() {
3053 let stmt = parse_sql("INSERT INTO t2 SELECT * FROM t1").unwrap();
3054 match stmt {
3055 Statement::Insert(ins) => {
3056 assert_eq!(ins.table, "t2");
3057 assert!(ins.columns.is_empty());
3058 assert!(matches!(&ins.source, InsertSource::Select(_)));
3059 }
3060 _ => panic!("expected Insert"),
3061 }
3062 }
3063
3064 #[test]
3065 fn reject_zero_parameter() {
3066 assert!(parse_sql("SELECT $0 FROM t").is_err());
3067 }
3068
3069 #[test]
3070 fn count_params_basic() {
3071 let stmt = parse_sql("SELECT * FROM t WHERE a = $1 AND b = $3").unwrap();
3072 assert_eq!(count_params(&stmt), 3);
3073 }
3074
3075 #[test]
3076 fn count_params_none() {
3077 let stmt = parse_sql("SELECT * FROM t WHERE a = 1").unwrap();
3078 assert_eq!(count_params(&stmt), 0);
3079 }
3080
3081 #[test]
3082 fn bind_params_basic() {
3083 let stmt = parse_sql("SELECT * FROM t WHERE id = $1").unwrap();
3084 let bound = bind_params(&stmt, &[Value::Integer(42)]).unwrap();
3085 match bound {
3086 Statement::Select(sq) => match sq.body {
3087 QueryBody::Select(sel) => match &sel.where_clause {
3088 Some(Expr::BinaryOp { right, .. }) => {
3089 assert!(matches!(right.as_ref(), Expr::Literal(Value::Integer(42))));
3090 }
3091 other => panic!("expected BinaryOp with Literal, got {other:?}"),
3092 },
3093 _ => panic!("expected QueryBody::Select"),
3094 },
3095 _ => panic!("expected Select"),
3096 }
3097 }
3098
3099 #[test]
3100 fn bind_params_out_of_range() {
3101 let stmt = parse_sql("SELECT * FROM t WHERE id = $2").unwrap();
3102 let result = bind_params(&stmt, &[Value::Integer(1)]);
3103 assert!(result.is_err());
3104 }
3105
3106 #[test]
3107 fn parse_table_constraint_pk() {
3108 let stmt = parse_sql("CREATE TABLE t (a INTEGER, b TEXT, PRIMARY KEY (a))").unwrap();
3109 match stmt {
3110 Statement::CreateTable(ct) => {
3111 assert_eq!(ct.primary_key, vec!["a"]);
3112 assert!(ct.columns[0].is_primary_key);
3113 assert!(!ct.columns[0].nullable);
3114 }
3115 _ => panic!("expected CreateTable"),
3116 }
3117 }
3118}