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