1#![allow(unused)]
2
3use std::{
4 any::Any,
5 borrow::Cow,
6 io::{Cursor, Write},
7 ops::Deref,
8 path::Display,
9 slice,
10};
11
12use sqlparser::{
13 ast::{
14 Assignment, AssignmentTarget, BinaryOperator, CastKind, CharacterLength, ColumnDef,
15 ColumnOptionDef, CreateIndex, CreateTable as SqlParserCreateTable, CreateTableOptions,
16 Delete, ExactNumberInfo, Expr, FromTable, FunctionArguments, HiveDistributionStyle,
17 HiveFormat, Ident, IndexColumn, JoinConstraint, ObjectName, ObjectNamePart, ObjectType,
18 OrderByExpr, Query, ReferentialAction, SelectItem, SetExpr, SqliteOnConflict, Statement,
19 Table, TableConstraint, TableFactor, TableWithJoins, UpdateTableFromKind, Value,
20 ValueWithSpan,
21 },
22 dialect::{self, Dialect, MySqlDialect, PostgreSqlDialect, SQLiteDialect},
23 keywords::Keyword,
24 parser::Parser,
25 tokenizer::{Token, Word},
26};
27
28use crate::{Error, Result};
29
30#[derive(Debug, Clone, Copy, PartialEq)]
32pub enum DataType {
33 SmallSerial,
34 Serial,
35 BigSerial,
36 I16,
37 I32,
38 I64,
39 F32,
40 F64,
41 Bool,
42 String,
43 Char(u64),
44 VarChar(u64),
45 Bytes,
46 Json,
47 Uuid,
48 Decimal { precision: u64, scale: i64 },
49 Date,
50 Time,
51 Timestamp,
52}
53
54impl TryFrom<&sqlparser::ast::DataType> for DataType {
55 type Error = Error;
56
57 fn try_from(value: &sqlparser::ast::DataType) -> Result<Self, Self::Error> {
58 let dt = match value {
59 sqlparser::ast::DataType::SmallInt(_) => DataType::I16,
60 sqlparser::ast::DataType::Int(_) => DataType::I32,
61 sqlparser::ast::DataType::Integer(_) => DataType::I32,
62 sqlparser::ast::DataType::BigInt(_) => DataType::I64,
63 sqlparser::ast::DataType::Real => DataType::F32,
64 sqlparser::ast::DataType::Double(_) => DataType::F64,
65 sqlparser::ast::DataType::DoublePrecision => DataType::F64,
66 sqlparser::ast::DataType::Bool => DataType::Bool,
67 sqlparser::ast::DataType::Boolean => DataType::Bool,
68 sqlparser::ast::DataType::Text => DataType::String,
69 sqlparser::ast::DataType::Char(Some(CharacterLength::IntegerLength {
70 length, ..
71 })) => DataType::Char(*length),
72 sqlparser::ast::DataType::Varchar(Some(CharacterLength::IntegerLength {
73 length,
74 ..
75 })) => DataType::VarChar(*length),
76 sqlparser::ast::DataType::Bytea => DataType::Bytes,
77 sqlparser::ast::DataType::JSON => DataType::Json,
78 sqlparser::ast::DataType::Uuid => DataType::Uuid,
79 sqlparser::ast::DataType::Decimal(ExactNumberInfo::PrecisionAndScale(
80 precision,
81 scale,
82 )) => DataType::Decimal {
83 precision: *precision,
84 scale: *scale,
85 },
86 sqlparser::ast::DataType::Numeric(ExactNumberInfo::PrecisionAndScale(
87 precision,
88 scale,
89 )) => DataType::Decimal {
90 precision: *precision,
91 scale: *scale,
92 },
93 sqlparser::ast::DataType::Custom(ObjectName(name_parts), _) => {
94 match extract_serial(name_parts) {
95 Some(dt) => dt,
96 None => Err(format!("unsupported data type: {value:?}"))?,
97 }
98 }
99 sqlparser::ast::DataType::Date => DataType::Date,
100 sqlparser::ast::DataType::Time(_, _) => DataType::Time,
101 sqlparser::ast::DataType::Timestamp(_, _) => DataType::Timestamp,
102 sqlparser::ast::DataType::Datetime(_) => DataType::Timestamp,
103 _ => Err(format!("unsupported data type: {value:?}"))?,
104 };
105 Ok(dt)
106 }
107}
108
109fn extract_serial(name_parts: &[ObjectNamePart]) -> Option<DataType> {
110 let name = match name_parts.first() {
111 None => return None,
112 Some(ObjectNamePart::Function(_)) => return None,
113 Some(ObjectNamePart::Identifier(name)) => name,
114 };
115 let name = name.value.to_ascii_lowercase();
116 match name.as_str() {
117 "bigserial" => Some(DataType::BigSerial),
118 "serial" => Some(DataType::Serial),
119 "smallserial" => Some(DataType::SmallSerial),
120 _ => None,
121 }
122}
123
124#[derive(Debug, Clone, PartialEq)]
125pub struct Column {
126 pub name: String,
127 pub data_type: DataType,
128 pub options: ColumnOptions,
129}
130
131impl TryFrom<&ColumnDef> for Column {
132 type Error = Error;
133
134 fn try_from(value: &ColumnDef) -> std::result::Result<Self, Self::Error> {
135 let ColumnDef {
136 name,
137 data_type,
138 options,
139 } = value;
140 Ok(Self {
141 name: name.value.clone(),
142 data_type: data_type.try_into()?,
143 options: ColumnOptions::try_from(options.as_slice())?,
144 })
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq)]
149pub struct ColumnOptions(u32);
150
151#[derive(Debug, Clone, Copy, PartialEq)]
152#[repr(u32)]
153pub enum ColumnOption {
154 PrimaryKey = 1,
155 AutoInrement = 1 << 1,
156 Nullable = 1 << 2,
157 NotNull = 1 << 3,
158 Unique = 1 << 4,
159}
160
161impl ColumnOptions {
162 fn new() -> Self {
163 Self(0)
164 }
165
166 fn set_primary_key(mut self) -> Self {
167 self.0 |= ColumnOption::PrimaryKey as u32;
168 self
169 }
170
171 fn is_primary_key(self) -> bool {
172 self.0 & ColumnOption::PrimaryKey as u32 != 0
173 }
174
175 fn set_auto_increment(mut self) -> Self {
176 self.0 |= ColumnOption::AutoInrement as u32;
177 self
178 }
179
180 fn unset_auto_increment(mut self) -> Self {
181 self.0 &= !(ColumnOption::AutoInrement as u32);
182 self
183 }
184
185 fn is_auto_increment(self) -> bool {
186 self.0 & ColumnOption::AutoInrement as u32 != 0
187 }
188
189 fn set_nullable(mut self) -> Self {
190 self.0 |= ColumnOption::Nullable as u32;
191 self
192 }
193
194 fn is_nullable(self) -> bool {
195 self.0 & ColumnOption::Nullable as u32 != 0
196 }
197
198 fn set_not_null(mut self) -> Self {
199 self.0 |= ColumnOption::NotNull as u32;
200 self
201 }
202
203 fn is_not_null(self) -> bool {
204 self.0 & ColumnOption::NotNull as u32 != 0
205 }
206
207 fn set_unique(mut self) -> Self {
208 self.0 |= ColumnOption::Unique as u32;
209 self
210 }
211
212 fn is_unique(self) -> bool {
213 self.0 & ColumnOption::Unique as u32 != 0
214 }
215
216 #[allow(clippy::type_complexity)]
217 fn mapping() -> &'static [(ColumnOption, fn(Self) -> bool)] {
218 &[
219 (ColumnOption::PrimaryKey, ColumnOptions::is_primary_key),
220 (ColumnOption::AutoInrement, ColumnOptions::is_auto_increment),
221 (ColumnOption::Nullable, ColumnOptions::is_nullable),
222 (ColumnOption::NotNull, ColumnOptions::is_not_null),
223 (ColumnOption::Unique, ColumnOptions::is_unique),
224 ]
225 }
226}
227
228pub struct ColumnIterator {
229 column_options: ColumnOptions,
230 pos: usize,
231}
232
233impl Iterator for ColumnIterator {
234 type Item = ColumnOption;
235
236 fn next(&mut self) -> Option<Self::Item> {
237 let mapping = ColumnOptions::mapping();
238 loop {
239 if self.pos >= mapping.len() {
240 return None;
241 }
242 let (option, check) = mapping[self.pos];
243 self.pos += 1;
244 if check(self.column_options) {
245 return Some(option);
246 }
247 }
248 }
249}
250
251impl IntoIterator for ColumnOptions {
252 type Item = ColumnOption;
253 type IntoIter = ColumnIterator;
254
255 fn into_iter(self) -> Self::IntoIter {
256 ColumnIterator {
257 column_options: self,
258 pos: 0,
259 }
260 }
261}
262
263impl std::fmt::Display for ColumnOptions {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 for option in self.into_iter() {
266 write!(f, "{option:?} ")?;
267 }
268 Ok(())
269 }
270}
271
272impl TryFrom<&[ColumnOptionDef]> for ColumnOptions {
273 type Error = Error;
274
275 fn try_from(values: &[ColumnOptionDef]) -> Result<Self, Self::Error> {
276 values.iter().try_fold(
277 ColumnOptions::new(),
278 |mut options, value| -> Result<_, Error> {
279 let options = match &value.option {
280 sqlparser::ast::ColumnOption::Unique { is_primary, .. } if *is_primary => {
281 options.set_primary_key()
282 }
283 sqlparser::ast::ColumnOption::NotNull => options.set_not_null(),
284 sqlparser::ast::ColumnOption::Null => options.set_nullable(),
285 option if is_auto_increment_option(option) => options.set_auto_increment(),
286 option => Err(format!("unsupported column option: {option:?}"))?,
287 };
288 Ok(options)
289 },
290 )
291 }
292}
293
294fn is_auto_increment_option(option: &sqlparser::ast::ColumnOption) -> bool {
295 match option {
296 sqlparser::ast::ColumnOption::DialectSpecific(tokens) if tokens.len() == 1 => tokens
297 .first()
298 .map(|token| match token {
299 Token::Word(Word { keyword, .. }) => {
300 *keyword == Keyword::AUTOINCREMENT || *keyword == Keyword::AUTO_INCREMENT
301 }
302 _ => false,
303 })
304 .unwrap(),
305 _ => false,
306 }
307}
308
309#[derive(Debug, Clone, PartialEq)]
310pub enum Constraint {
311 PrimaryKey(Vec<String>),
312 ForeignKey {
313 columns: Vec<String>,
314 referred_columns: Vec<String>,
315 foreign_table: String,
316 on_delete: Option<OnDeleteAction>,
317 },
318}
319
320#[derive(Debug, Clone, PartialEq)]
321pub enum OnDeleteAction {
322 Cascade,
323 SetNull,
324 Restrict,
325}
326
327impl TryFrom<&ReferentialAction> for OnDeleteAction {
328 type Error = Error;
329
330 fn try_from(value: &ReferentialAction) -> Result<Self, Self::Error> {
331 match value {
332 ReferentialAction::Cascade => Ok(OnDeleteAction::Cascade),
333 ReferentialAction::Restrict => Ok(OnDeleteAction::Restrict),
334 ReferentialAction::SetNull => Ok(OnDeleteAction::SetNull),
335 other => Err(format!(
336 "on delete {other} in foreign key constraint is not supported"
337 ))?,
338 }
339 }
340}
341
342#[derive(Debug, Clone, PartialEq)]
343pub struct Constraints(Vec<Constraint>);
344
345impl Constraints {
346 fn len(&self) -> usize {
347 self.0.len()
348 }
349}
350
351#[derive(Debug)]
352pub struct ConstraintsIter<'a> {
353 constraints: &'a Constraints,
354 pos: usize,
355}
356
357impl<'a> Iterator for ConstraintsIter<'a> {
358 type Item = &'a Constraint;
359
360 fn next(&mut self) -> Option<Self::Item> {
361 if self.constraints.0.len() > self.pos {
362 let item = &self.constraints.0[self.pos];
363 self.pos += 1;
364 return Some(item);
365 }
366 None
367 }
368}
369
370impl<'a> IntoIterator for &'a Constraints {
371 type IntoIter = ConstraintsIter<'a>;
372 type Item = &'a Constraint;
373
374 fn into_iter(self) -> Self::IntoIter {
375 ConstraintsIter {
376 pos: 0,
377 constraints: self,
378 }
379 }
380}
381
382impl TryFrom<&[TableConstraint]> for Constraints {
383 type Error = Error;
384
385 fn try_from(value: &[TableConstraint]) -> Result<Self, Self::Error> {
386 let constraints = value
387 .iter()
388 .map(|constraint| -> Result<_> {
389 let res = match constraint {
390 TableConstraint::PrimaryKey {
391 columns,
392 name,
393 index_name,
394 index_type,
395 index_options,
396 characteristics,
397 } => {
398 if name.is_some() {
399 Err("PRIMARY KEY with name is not supported")?
400 }
401 if index_name.is_some() {
402 Err("PRIMARY KEY with index name is not supported")?
403 }
404 if index_type.is_some() {
405 Err("PRIMARY KEY with index type is not supported")?
406 }
407 if !index_options.is_empty() {
408 Err("PRIMARY KEY with index options is not supported")?
409 }
410 if characteristics.is_some() {
411 Err("PRIMARY KEY with characteristics is not supported")?
412 }
413 let columns = columns
414 .iter()
415 .map(
416 |IndexColumn {
417 column,
418 operator_class,
419 }| {
420 if operator_class.is_some() {
421 Err("PRIMARY KEY with operator class is not supported")?;
422 };
423 let OrderByExpr {
424 expr,
425 options,
426 with_fill,
427 } = column;
428 if with_fill.is_some() {
429 Err("PRIMARY KEY with `WITH FILL` is not supported")?;
430 }
431 if options.nulls_first.is_some() || options.asc.is_some() {
432 Err("PRIMARY KEY with options is not supported")?;
433 }
434 match expr {
435 Expr::Identifier(ident) => Ok(ident.value.clone()),
436 _ => Err(format!(
437 "Unsupported expression {expr:?} in PRIMARY KEY"
438 ))?,
439 }
440 },
441 )
442 .collect::<Result<Vec<_>>>()?;
443 Constraint::PrimaryKey(columns)
444 }
445 TableConstraint::ForeignKey {
446 name,
447 columns,
448 foreign_table,
449 referred_columns,
450 on_delete,
451 on_update,
452 characteristics,
453 index_name,
454 } => {
455 if name.is_some() {
456 Err("named foreign key constraint is not supported")?
457 }
458 if on_update.is_some() {
459 Err("on update in foreign key constraint is not supported")?
460 }
461 if characteristics.is_some() {
462 Err("characteristics in foreign key constraint is not supported")?
463 }
464 let on_delete = match on_delete {
465 None => None,
466 Some(action) => Some(action.try_into()?),
467 };
468 let columns = columns
469 .iter()
470 .map(|Ident { value, .. }| value.clone())
471 .collect();
472 let referred_columns = referred_columns
473 .iter()
474 .map(|Ident { value, .. }| value.clone())
475 .collect();
476 let foreign_table = Ast::parse_object_name(foreign_table)?;
477 Constraint::ForeignKey {
478 columns,
479 referred_columns,
480 foreign_table,
481 on_delete,
482 }
483 }
484 _ => Err(format!("unsupported constraint: {constraint:?}"))?,
485 };
486 Ok(res)
487 })
488 .collect::<Result<Vec<Constraint>, _>>()?;
489 Ok(Constraints(constraints))
490 }
491}
492
493#[derive(Debug, Clone, PartialEq)]
494pub enum Ast {
495 CreateTable {
496 if_not_exists: bool,
497 name: String,
498 columns: Vec<Column>,
499 constraints: Constraints,
500 },
501 AlterTable {
502 name: String,
503 operation: AlterTableOperation,
504 },
505 CreateIndex {
506 unique: bool,
507 name: String,
508 table: String,
509 columns: Vec<String>,
510 },
511 Select {
512 distinct: bool,
513 projections: Vec<Projection>,
514 from_clause: FromClause,
515 selection: Option<Selection>,
516 group_by: Vec<GroupByParameter>,
517 order_by: Vec<OrderByParameter>,
518 },
519 Insert {
520 table: String,
521 columns: Vec<String>,
522 source: Vec<Vec<InsertSource>>,
523 },
524 Update {
525 table: String,
526 assignments: Vec<UpdateAssignment>,
527 selection: Option<Selection>,
528 },
529 Delete {
530 from_clause: FromClause,
531 selection: Option<Selection>,
532 },
533 Drop {
534 object_type: DropObjectType,
535 if_exists: bool,
536 name: String,
537 table: Option<String>,
538 },
539}
540
541#[derive(Debug, Clone, PartialEq)]
542pub enum Projection {
543 WildCard,
544 Identifier(String),
545 CompoundIdentifier(CompoundIdentifier),
546 Function(Function),
547 NumericLiteral(String),
548 String(String),
549}
550
551#[derive(Debug, Clone, PartialEq)]
552pub struct CompoundIdentifier {
553 table: String,
554 column: String,
555}
556
557#[derive(Debug, Clone, PartialEq)]
558pub enum Function {
559 Count(FunctionArg),
560}
561
562#[derive(Debug, Clone, PartialEq)]
563pub enum FunctionArg {
564 Wildcard,
565 Ident(String),
566}
567
568#[derive(Debug, Clone, PartialEq)]
569pub enum Selection {
570 BinaryOp {
571 op: Op,
572 left: Box<Selection>,
573 right: Box<Selection>,
574 },
575 Ident(String),
576 CompoundIdentifier(CompoundIdentifier),
577 Number(String),
578 String(String),
579 Placeholder,
580 InList {
581 negated: bool,
582 ident: String,
583 list: Vec<Selection>,
584 },
585}
586
587impl TryFrom<&Expr> for Selection {
588 type Error = Error;
589
590 fn try_from(expr: &Expr) -> std::result::Result<Self, Self::Error> {
591 let selection = match expr {
592 Expr::BinaryOp { left, op, right } => Selection::BinaryOp {
593 op: op.try_into()?,
594 left: {
595 let left: Selection = left.as_ref().try_into()?;
596 Box::new(left)
597 },
598 right: {
599 let right: Selection = right.as_ref().try_into()?;
600 Box::new(right)
601 },
602 },
603 Expr::Identifier(id) => Selection::Ident(id.value.clone()),
604 Expr::CompoundIdentifier(ids) => {
605 if ids.len() != 2 {
607 Err(format!(
608 "only two-parts compound identifiers are supported, not {}",
609 ids.len()
610 ))?
611 }
612 Selection::CompoundIdentifier(CompoundIdentifier {
613 table: ids[0].value.clone(),
614 column: ids[1].value.clone(),
615 })
616 }
617 Expr::Value(value) => match &value.value {
618 Value::Number(number, _) => Selection::Number(number.clone()),
619 Value::SingleQuotedString(string) => Selection::String(string.clone()),
620 Value::Placeholder(_) => Selection::Placeholder,
621 _ => Err(format!(
622 "unsupported conversion to Selection from value: {:#?}",
623 value.value
624 ))?,
625 },
626 Expr::InList {
627 expr,
628 list,
629 negated,
630 } => {
631 let ident = match expr.as_ref().try_into()? {
632 Selection::Ident(ident) => ident,
633 _ => Err("unsupported conversion to Selection, InList currently supports only Identifiers".to_string())?,
634 };
635 let list = list
636 .iter()
637 .map(|expr| {
638 let ok = match expr.try_into()? {
639 ok@Selection::String(_) => ok,
640 ok@Selection::Number(_) => ok,
641 ok@Selection::Placeholder => ok,
642 _ => Err(format!(
643 "unsupported conversion in Selection, unsupported expression in list of InList: {expr:?}"
644 ))?
645 };
646 Ok(ok)
647 })
648 .collect::<Result<Vec<Selection>>>()?;
649 Selection::InList {
650 negated: *negated,
651 ident,
652 list,
653 }
654 }
655 expr => Err(format!(
656 "unsupported conversion to Selection from expr: {expr:?}"
657 ))?,
658 };
659 Ok(selection)
660 }
661}
662
663#[derive(Debug, Clone, PartialEq)]
664pub enum GroupByParameter {
665 Ident(String),
666}
667
668#[derive(Debug, Clone, PartialEq)]
669pub struct OrderByParameter {
670 ident: String,
671 option: OrderOption,
672}
673
674#[derive(Debug, Clone, PartialEq)]
675pub enum OrderOption {
676 Asc,
677 Desc,
678 None,
679}
680
681#[derive(Debug, Clone, PartialEq)]
682pub enum InsertSource {
683 String(String),
684 Number(String),
685 Null,
686 Placeholder,
687 Cast {
688 cast: String,
689 source: Box<InsertSource>,
690 },
691}
692
693impl TryFrom<&Expr> for InsertSource {
694 type Error = Error;
695
696 fn try_from(value: &Expr) -> Result<Self, Self::Error> {
697 let value = match value {
698 Expr::Value(value) => &value.value,
699 Expr::Cast {
700 kind,
701 expr,
702 data_type,
703 format,
704 } if *kind == CastKind::DoubleColon && format.is_none() => match expr.as_ref() {
705 Expr::Value(_) => {
706 return Ok(InsertSource::Cast {
707 cast: data_type.to_string(),
708 source: Box::new(expr.as_ref().try_into()?),
709 });
710 }
711 _ => Err(format!(
712 "unsupported conversion to insert source cast from expr: {expr:#?}"
713 ))?,
714 },
715 value => Err(format!(
716 "unsupported conversion to insert source from value: {value:#?}"
717 ))?,
718 };
719 let insert_source = match value {
720 Value::Null => InsertSource::Null,
721 Value::Number(number, _) => InsertSource::Number(number.clone()),
722 Value::SingleQuotedString(string) => InsertSource::String(string.clone()),
723 Value::Placeholder(_) => InsertSource::Placeholder,
724 value => Err(format!(
725 "unsupported conversion to insert source from value: {value:#?}"
726 ))?,
727 };
728 Ok(insert_source)
729 }
730}
731
732#[derive(Debug, Clone, PartialEq)]
733pub struct UpdateAssignment {
734 target: String,
735 value: UpdateValue,
736}
737
738#[derive(Debug, Clone, PartialEq)]
739pub enum UpdateValue {
740 String(String),
741 Number(String),
742 Null,
743 Placeholder,
744}
745
746impl TryFrom<&Expr> for UpdateValue {
747 type Error = Error;
748
749 fn try_from(expr: &Expr) -> Result<Self, Self::Error> {
750 let value = match expr {
751 Expr::Value(value) => &value.value,
752 expr => Err(format!(
753 "unsupported conversion to UpdateValue from expr: {expr:?}"
754 ))?,
755 };
756 let update_value = match value {
757 Value::Null => UpdateValue::Null,
758 Value::Number(number, _) => UpdateValue::Number(number.clone()),
759 Value::SingleQuotedString(string) => UpdateValue::String(string.clone()),
760 Value::Placeholder(_) => UpdateValue::Placeholder,
761 value => Err(format!(
762 "unsupported conversion into UpdateValue from value: {value:#?}"
763 ))?,
764 };
765 Ok(update_value)
766 }
767}
768
769#[derive(Debug, Clone, Copy, PartialEq)]
770pub enum Op {
771 Eq,
772 And,
773 Or,
774}
775
776#[derive(Debug, Clone, Copy, PartialEq)]
777pub enum DropObjectType {
778 Table,
779 Index,
780}
781
782impl TryFrom<&BinaryOperator> for Op {
783 type Error = Error;
784 fn try_from(op: &BinaryOperator) -> std::result::Result<Self, Self::Error> {
785 let op = match op {
786 BinaryOperator::And => Op::And,
787 BinaryOperator::Eq => Op::Eq,
788 BinaryOperator::Or => Op::Or,
789 _ => Err(format!("binary operator not supported {op:?}"))?,
790 };
791 Ok(op)
792 }
793}
794
795#[derive(Debug, Clone, PartialEq)]
796pub enum FromClause {
797 Table(String),
798 TableWithJoin(TableJoin),
799 None,
800}
801
802#[derive(Debug, Clone, PartialEq)]
803pub struct TableJoin {
804 name: String,
805 join: Vec<Join>,
806}
807
808#[derive(Debug, Clone, PartialEq)]
809pub struct Join {
810 name: String,
811 operator: JoinOperator,
812}
813
814#[derive(Debug, Clone, PartialEq)]
815pub enum JoinOperator {
816 Join(Selection),
817 Inner(Selection),
818}
819
820impl TryFrom<&sqlparser::ast::Join> for Join {
821 type Error = Error;
822
823 fn try_from(table: &sqlparser::ast::Join) -> Result<Self, Self::Error> {
824 if table.global {
827 Err("global keyword before the join operator isn't supported")?
828 };
829
830 let name = table_relation_to_object_name(&table.relation)?;
831 let operator = match &table.join_operator {
832 sqlparser::ast::JoinOperator::Join(constraint) => match constraint {
833 JoinConstraint::On(expr) => JoinOperator::Join(expr.try_into()?),
834 other => Err(format!("join constraint '{other:?}' is not supported"))?,
835 },
836 sqlparser::ast::JoinOperator::Inner(constraint) => match constraint {
837 JoinConstraint::On(expr) => JoinOperator::Inner(expr.try_into()?),
838 other => Err(format!("join constraint '{other:?}' is not supported"))?,
839 },
840 other => Err(format!("join operator '{other:?}' is not supported"))?,
841 };
842
843 Ok(Self { name, operator })
844 }
845}
846
847fn table_relation_to_object_name(relation: &TableFactor) -> Result<String> {
848 match relation {
849 TableFactor::Table {
850 name,
851 alias,
852 args,
853 with_hints,
854 version,
855 with_ordinality,
856 partitions,
857 json_path,
858 sample,
859 index_hints,
860 } => {
861 if alias.is_some() {
862 Err("alias is not supported in table factor 'table'")?
863 }
864 if args.is_some() {
866 Err(
867 "arguments of a table-valued function are not supported in table factor 'table'",
868 )?
869 }
870 if !with_hints.is_empty() {
872 Err("with hints are not supported in table factor 'table'")?
873 }
874 if version.is_some() {
876 Err("version is not supported in table factor 'table'")?
877 }
878 if *with_ordinality {
880 Err("with ordinality is not supported in table factor 'table'")?
881 }
882 if !partitions.is_empty() {
884 Err("partitions are not supported in table factor 'table'")?
885 }
886 if json_path.is_some() {
888 Err("json path is not supported in table factor 'table'")?
889 }
890 if sample.is_some() {
892 Err("sample is not supported in table factor 'table'")?
893 }
894 if !index_hints.is_empty() {
896 Err("index hints are not supported in table factor 'table'")?
897 }
898 Ok(Ast::parse_object_name(name)?)
899 }
900 other => Err(format!("unsupported table factor: {other:?}"))?,
901 }
902}
903
904impl TryFrom<&[TableWithJoins]> for FromClause {
905 type Error = Error;
906
907 fn try_from(tables: &[TableWithJoins]) -> Result<Self, Self::Error> {
908 let from = match tables {
909 &[
910 TableWithJoins {
911 ref relation,
912 ref joins,
913 },
914 ] => {
915 let name = table_relation_to_object_name(relation)?;
916 if joins.is_empty() {
917 Self::Table(name)
918 } else {
919 Self::TableWithJoin(TableJoin {
920 name,
921 join: joins.iter().map(|t| t.try_into()).collect::<Result<_>>()?,
922 })
923 }
924 }
925 &[] => Self::None,
926 other => Err(format!(
927 "select with multiple tables is not supported yet: {other:?}"
928 ))?,
929 };
930 Ok(from)
931 }
932}
933
934#[derive(Debug, Clone, PartialEq)]
935pub enum AlterTableOperation {
936 AddColumn { column: Column },
937 RenameColumn { from: String, to: String },
938 DropColumn { name: String },
939 RenameTable { to: String },
940}
941
942impl TryFrom<&sqlparser::ast::AlterTableOperation> for AlterTableOperation {
943 type Error = Error;
944
945 fn try_from(
946 op: &sqlparser::ast::AlterTableOperation,
947 ) -> std::result::Result<Self, Self::Error> {
948 let op = match op {
949 sqlparser::ast::AlterTableOperation::AddColumn {
950 column_keyword,
951 if_not_exists,
952 column_def,
953 column_position,
954 } => {
955 let _ = column_keyword;
956 if *if_not_exists {
957 Err("`IF NOT EXISTS` is not supported in `ALTER TABLE ADD COLUMN`")?
958 }
959 if column_position.is_some() {
960 Err("column position is not supported in `ALTER TABLE ADD COLUMN")?
961 }
962 let column = column_def.try_into()?;
963 AlterTableOperation::AddColumn { column }
964 }
965 sqlparser::ast::AlterTableOperation::RenameTable { table_name } => {
966 let table_name = match table_name {
967 sqlparser::ast::RenameTableNameKind::As(_) => {
969 Err("ALTER TABLE with AS keyword is not supported")?
970 }
971 sqlparser::ast::RenameTableNameKind::To(table_name) => table_name,
972 };
973 AlterTableOperation::RenameTable {
974 to: Ast::parse_object_name(table_name)?,
975 }
976 }
977 sqlparser::ast::AlterTableOperation::RenameColumn {
978 old_column_name,
979 new_column_name,
980 } => AlterTableOperation::RenameColumn {
981 from: old_column_name.value.clone(),
982 to: new_column_name.value.clone(),
983 },
984 sqlparser::ast::AlterTableOperation::DropColumn {
985 if_exists,
986 drop_behavior,
987 has_column_keyword,
988 column_names,
989 } => {
990 if *if_exists {
991 Err("`IF EXISTS` is not supported in `ALTER TABLE DROP COLUMN`")?
992 }
993 if drop_behavior.is_some() {
994 Err("drop behaviour is not supported in `ALTER TABLE DROP COLUMN`")?;
995 }
996 if column_names.len() > 1 {
997 Err("multiple columns names is not supported in `ALTER TABLE DROP COLUMN`")?
998 }
999 AlterTableOperation::DropColumn {
1000 name: column_names.first().unwrap().value.clone(),
1001 }
1002 }
1003 _ => Err(format!("unsupported operation: {op:?}"))?,
1004 };
1005 Ok(op)
1006 }
1007}
1008
1009impl Ast {
1010 fn parse_object_name(name: &ObjectName) -> Result<String> {
1011 let name_parts = &name.0;
1012 if name_parts.len() > 1 {
1013 Err("schema-qualified names are not supported")?
1014 }
1015 match name_parts.first() {
1016 None => Err("failed to parse object name, name parts are empty")?,
1017 Some(ObjectNamePart::Identifier(ident)) => Ok(ident.value.clone()),
1018 Some(ObjectNamePart::Function(_)) => {
1019 Err("failed to parse object name, function names are not supported")?
1020 }
1021 }
1022 }
1023
1024 fn parse_create_table(
1025 SqlParserCreateTable {
1026 or_replace,
1027 temporary,
1028 external,
1029 global,
1030 if_not_exists,
1031 transient,
1032 volatile,
1033 iceberg,
1034 name,
1035 columns,
1036 constraints,
1037 hive_distribution,
1038 hive_formats,
1039 file_format,
1040 location,
1041 query,
1042 without_rowid,
1043 like,
1044 clone,
1045 comment,
1046 on_commit,
1047 on_cluster,
1048 primary_key,
1049 order_by,
1050 partition_by,
1051 cluster_by,
1052 clustered_by,
1053 inherits,
1054 strict,
1055 copy_grants,
1056 enable_schema_evolution,
1057 change_tracking,
1058 data_retention_time_in_days,
1059 max_data_extension_time_in_days,
1060 default_ddl_collation,
1061 with_aggregation_policy,
1062 with_row_access_policy,
1063 with_tags,
1064 external_volume,
1065 base_location,
1066 catalog,
1067 catalog_sync,
1068 storage_serialization_policy,
1069 dynamic,
1070 table_options,
1071 version,
1072 target_lag,
1073 warehouse,
1074 refresh_mode,
1075 initialize,
1076 require_user,
1077 }: &SqlParserCreateTable,
1078 ) -> Result<Ast> {
1079 if *or_replace {
1080 Err("'or replace' is not supported in create table")?
1081 }
1082 if *temporary {
1083 Err("temporary is not supported in create table")?
1084 }
1085 if *external {
1086 Err("external is not supported in create table")?
1087 }
1088 if global.is_some() {
1089 Err("global is not supported in create table")?
1090 }
1091 if *transient {
1092 Err("transient is not supported in create table")?
1093 }
1094 if *volatile {
1095 Err("volatile is not supported in create table")?
1096 }
1097 if *iceberg {
1098 Err("iceberg is not supported in create table")?
1099 }
1100 match hive_distribution {
1101 HiveDistributionStyle::NONE => {}
1102 _ => Err("hive distribution style is not supported in create_table")?,
1103 }
1104
1105 if let Some(HiveFormat {
1107 row_format,
1108 serde_properties,
1109 storage,
1110 location,
1111 }) = hive_formats
1112 && (row_format.is_some()
1113 || serde_properties.is_some()
1114 || storage.is_some()
1115 || location.is_some())
1116 {
1117 Err("hive formats are not supported in create table")?
1118 }
1119
1120 if file_format.is_some() {
1121 Err("file format is not supported in create table")?
1122 }
1123 if location.is_some() {
1124 Err("location is not supported in create table")?
1125 }
1126 if query.is_some() {
1127 Err("query is not supported in create table")?
1128 }
1129 if *without_rowid {
1130 Err("'without rowid' is not supported in create table")?
1131 }
1132 if like.is_some() {
1133 Err("'like' is not supported in create table")?
1134 }
1135 if clone.is_some() {
1136 Err("clone is not supported in create table")?
1137 }
1138 if comment.is_some() {
1139 Err("comment is not supported in create table")?
1140 }
1141 if on_commit.is_some() {
1142 Err("'on commit' is not supported in create table")?
1143 }
1144 if on_cluster.is_some() {
1146 Err("'on cluster' is not supported in create table")?
1147 }
1148 if primary_key.is_some() {
1150 Err("primary key is not supported in create table")?
1151 }
1152 if order_by.is_some() {
1154 Err("'order by' is not supported in create table")?
1155 }
1156 if partition_by.is_some() {
1158 Err("'partition by' is not supported in create table")?
1159 }
1160 if cluster_by.is_some() {
1162 Err("'cluster_by' is not supported in create table")?
1163 }
1164 if clustered_by.is_some() {
1166 Err("'clustered_by' is not supported in create table")?
1167 }
1168 if inherits.is_some() {
1170 Err("inherits are not supported in create table")?
1171 }
1172 if *strict {
1174 Err("strict is not supported in create table")?
1175 }
1176 if *copy_grants {
1178 Err("copy grant is not supported in create table")?
1179 }
1180 if enable_schema_evolution.is_some() {
1182 Err("'enable schema evolution' is not supported in create table")?
1183 }
1184 if change_tracking.is_some() {
1186 Err("'change tracking' is not supported in create table")?
1187 }
1188 if data_retention_time_in_days.is_some() {
1190 Err("'data retention time in days' is not supported in create table")?
1191 }
1192 if max_data_extension_time_in_days.is_some() {
1194 Err("'max data extension time in days' is not supported in create table")?
1195 }
1196 if default_ddl_collation.is_some() {
1198 Err("'default ddl collation' is not supported in create table")?
1199 }
1200 if with_aggregation_policy.is_some() {
1202 Err("'with aggregation policy' is not supported in create table")?
1203 }
1204 if with_row_access_policy.is_some() {
1206 Err("'with row access policy' is not supported in create table")?
1207 }
1208 if with_tags.is_some() {
1210 Err("'with tags' is not supported in create table")?
1211 }
1212 if external_volume.is_some() {
1214 Err("'external volume' is not supported in create table")?
1215 }
1216 if base_location.is_some() {
1218 Err("'base location' is not supported in create table")?
1219 }
1220 if catalog.is_some() {
1222 Err("catalog is not supported in create table")?
1223 }
1224 if catalog_sync.is_some() {
1226 Err("'catalog sync' is not supported in create table")?
1227 }
1228 if storage_serialization_policy.is_some() {
1230 Err("'storage serialization policy' is not supported in create table")?
1231 }
1232 if *dynamic {
1233 Err("'dynamic' is not supported in create table")?
1234 }
1235 match table_options {
1236 CreateTableOptions::None => (),
1237 _ => Err("table options are not supported in create table")?,
1238 };
1239
1240 if version.is_some() {
1241 Err("versions are not supported in create table")?
1242 }
1243
1244 if target_lag.is_some() {
1246 Err("target lag is not supportec in create table")?
1247 }
1248 if warehouse.is_some() {
1250 Err("warehouse is not supported in create table")?
1251 }
1252 if refresh_mode.is_some() {
1254 Err("refresh mode is not supported in create table")?
1255 }
1256 if initialize.is_some() {
1258 Err("initialize is not supported in create table")?
1259 }
1260 if *require_user {
1262 Err("require user is not supported in create table")?
1263 }
1264
1265 let name = Self::parse_object_name(name)?;
1266 let columns = {
1267 columns
1268 .iter()
1269 .map(TryFrom::try_from)
1270 .collect::<Result<Vec<_>>>()?
1271 };
1272 Ok(Ast::CreateTable {
1273 if_not_exists: *if_not_exists,
1274 name,
1275 columns,
1276 constraints: Constraints::try_from(constraints.as_slice())?,
1277 })
1278 }
1279
1280 #[allow(clippy::too_many_arguments)]
1281 fn parse_alter_table(
1282 name: &ObjectName,
1283 if_exists: bool,
1284 only: bool,
1285 operations: &[sqlparser::ast::AlterTableOperation],
1286 location: Option<&sqlparser::ast::HiveSetLocation>,
1287 on_cluster: Option<&Ident>,
1288 iceberg: bool,
1289 _end_token: &sqlparser::ast::helpers::attached_token::AttachedToken,
1290 ) -> Result<Ast> {
1291 if if_exists {
1293 Err("if exists is not supported in ALTER TABLE")?
1294 }
1295 if only {
1297 Err("`ON` keyword is not supported in ALTER TABLE")?
1298 }
1299 if on_cluster.is_some() {
1301 Err("ON CLUSTER syntax is not supported")?
1302 }
1303 if location.is_some() {
1305 Err("LOCATION syntax is not supported")?
1306 }
1307 if iceberg {
1309 Err("ICEBERG syntax is not supported")?
1310 }
1311 let name = Self::parse_object_name(name)?;
1312 if operations.len() != 1 {
1313 Err("ALTER TABLE only supports single operation")?
1314 }
1315 let operation = operations.first().unwrap().try_into()?;
1316 Ok(Ast::AlterTable { name, operation })
1317 }
1318
1319 fn parse_function_args(args: &FunctionArguments) -> Result<Vec<FunctionArg>> {
1320 let args = match args {
1321 FunctionArguments::None => vec![],
1322 FunctionArguments::List(list) => {
1323 if !list.clauses.is_empty() {
1324 Err(format!("function clauses are not yet supported: {list:?}"))?
1325 };
1326 if list.duplicate_treatment.is_some() {
1327 Err(format!(
1328 "function duplicate treatment not supported: {list:?}"
1329 ))?
1330 }
1331 list.args
1332 .iter()
1333 .map(|arg| -> Result<_> {
1334 let arg = match arg {
1336 sqlparser::ast::FunctionArg::ExprNamed { .. } => {
1337 Err("named expressions are not supported in function arguments")?
1338 }
1339 sqlparser::ast::FunctionArg::Named { .. } => {
1340 Err("named columns are not supported in function arguments(yet)")?
1341 }
1342 sqlparser::ast::FunctionArg::Unnamed(expr) => match expr {
1343 sqlparser::ast::FunctionArgExpr::Wildcard => FunctionArg::Wildcard,
1344 sqlparser::ast::FunctionArgExpr::Expr(Expr::Identifier(ident)) => {
1345 FunctionArg::Ident(ident.value.clone())
1346 }
1347 _ => Err(format!("unsupported function argument: {expr:?}"))?,
1348 },
1349 };
1350 Ok(arg)
1351 })
1352 .collect::<Result<_>>()?
1353 }
1354 FunctionArguments::Subquery(query) => Err(format!(
1355 "function arguments are not yet supported: {query:?}"
1356 ))?,
1357 };
1358 Ok(args)
1359 }
1360
1361 fn parse_create_index(
1362 CreateIndex {
1363 name,
1364 table_name,
1365 columns,
1366 if_not_exists,
1367 unique,
1368 concurrently,
1369 using,
1370 include,
1371 nulls_distinct,
1372 with,
1373 predicate,
1374 index_options,
1375 alter_options,
1376 }: &CreateIndex,
1377 ) -> Result<Self> {
1378 if *if_not_exists {
1379 Err("`CREATE INDEX` with existance check is not supported")?
1380 };
1381 if name.is_none() {
1382 Err("`CREATE INDEX` without name is not supported")?
1383 }
1384 if *concurrently {
1385 Err("concurrent `CREATE INDEX` is not supported")?
1386 }
1387 if using.is_some() {
1388 Err("`CREATE INDEX` with `USING` keyword is not supported")?
1389 }
1390 if !include.is_empty() {
1391 Err("`CREATE INDEX` with `INCLUDE` is not supported")?
1392 }
1393 if nulls_distinct.is_some() {
1394 Err("`CREATE INDEX` with `DISTINCT NULLS` is not supported")?
1395 }
1396 if !with.is_empty() {
1397 Err("`CREATE INDEX` with `WITH` keyword is not supported")?
1398 }
1399 if predicate.is_some() {
1400 Err("`CREATE INDEX` with predicates is not supported")?
1401 }
1402 if !index_options.is_empty() {
1404 Err("`CREATE INDEX` with index options is not supported")?
1405 }
1406 if !alter_options.is_empty() {
1408 Err("`CREATE INDEX` with alter options is not supported")?
1409 }
1410 let columns = columns
1411 .iter()
1412 .map(|IndexColumn { column, .. }| -> Result<String> {
1413 match &column.expr {
1414 Expr::Identifier(Ident { value, .. }) => Ok(value.clone()),
1415 expr => Err(format!("unsupported index column: {expr:?}"))?,
1416 }
1417 })
1418 .collect::<Result<Vec<String>>>()?;
1419 Ok(Ast::CreateIndex {
1420 unique: *unique,
1421 name: Self::parse_object_name(name.as_ref().unwrap())?,
1422 table: Self::parse_object_name(table_name)?,
1423 columns,
1424 })
1425 }
1426
1427 fn parse_query(query: &Query) -> Result<Ast> {
1428 if query.with.is_some() {
1430 Err("CTE is not yet supported")?
1431 }
1432 if query.fetch.is_some() {
1433 Err("FETCH is not supported")?;
1434 }
1435 if query.limit_clause.is_some() {
1437 Err("LIMIT is not yet supported")?
1438 }
1439 if !query.locks.is_empty() {
1440 Err("LOCKS are not supported")?
1441 }
1442 if query.for_clause.is_some() {
1443 Err("FOR clause is not yet supported")?
1444 }
1445 let select = match &*query.body {
1446 SetExpr::Select(select) => &**select,
1447 other => Err(format!("only SELECT supported, got:\n{other:#?}"))?,
1448 };
1449 if select.top.is_some() || select.top_before_distinct {
1450 return Err("TOP statement is not supported")?;
1451 }
1452 let projections = select
1453 .projection
1454 .iter()
1455 .map(|projection| -> Result<_> {
1456 match projection {
1457 SelectItem::Wildcard(_) => Ok(Projection::WildCard),
1458 SelectItem::UnnamedExpr(Expr::Identifier(ident)) => {
1459 Ok(Projection::Identifier(ident.value.clone()))
1460 }
1461 SelectItem::UnnamedExpr(Expr::Function(function)) => {
1462 let function_name = Self::parse_object_name(&function.name)?.to_lowercase();
1463 match function_name.as_str() {
1464 "count" => {
1465 let mut args = Self::parse_function_args(&function.args)?;
1466 if args.len() != 1 {
1467 Err("COUNT function can only have single argument: {args:?}")?
1468 }
1469 let arg = args.pop().unwrap();
1470 Ok(Projection::Function(Function::Count(arg)))
1471 }
1472 name => Err(format!("unsupported function '{name}'"))?,
1473 }
1474 }
1475 SelectItem::UnnamedExpr(Expr::Value(value)) => match &value.value {
1476 Value::Number(value, _) => Ok(Projection::NumericLiteral(value.clone())),
1477 Value::SingleQuotedString(value) => Ok(Projection::String(value.clone())),
1478 value => Err("unsupported value type in projection: {value:?}")?,
1479 },
1480 SelectItem::UnnamedExpr(Expr::CompoundIdentifier(values)) => {
1481 if values.len() != 2 {
1483 Err(format!(
1484 "only two-parts compound identifiers are supported, not {}",
1485 values.len()
1486 ))?
1487 }
1488 Ok(Projection::CompoundIdentifier(CompoundIdentifier {
1489 table: values[0].value.clone(),
1490 column: values[1].value.clone(),
1491 }))
1492 }
1493 _ => Err(format!("unsupported projection: {projection:?}"))?,
1494 }
1495 })
1496 .collect::<Result<Vec<Projection>>>()?;
1497
1498 let from_clause = select.from.as_slice().try_into()?;
1499
1500 let selection = select
1501 .selection
1502 .as_ref()
1503 .map(|selection| selection.try_into())
1504 .transpose()?;
1505 let group_by = match &select.group_by {
1506 sqlparser::ast::GroupByExpr::Expressions(expr, modifier) if modifier.is_empty() => expr
1507 .iter()
1508 .map(|expr| match expr {
1509 Expr::Identifier(ident) => Ok(GroupByParameter::Ident(ident.value.clone())),
1510 _ => Err(format!("unsupported expression in group by: {expr:?}"))?,
1511 })
1512 .collect::<Result<Vec<GroupByParameter>>>()?,
1513 expr => Err(format!("unsupported group by expression: {expr:?}"))?,
1514 };
1515 let order_by = match query.order_by.as_ref() {
1516 Some(order_by) => {
1517 if order_by.interpolate.is_some() {
1518 Err("order by interpolate is not supported")?;
1519 };
1520 match &order_by.kind {
1521 sqlparser::ast::OrderByKind::All(_) => Err("order by all is not supported")?,
1522 sqlparser::ast::OrderByKind::Expressions(expressions) => expressions
1523 .iter()
1524 .map(|expression| {
1525 if expression.with_fill.is_some() {
1526 Err("with fill is not supported")?
1527 }
1528 let ident = match &expression.expr {
1529 Expr::Identifier(ident) => ident.value.clone(),
1530 expr => Err(format!("unsupported order by expression: {expr:?}"))?,
1531 };
1532 let option = match &expression.options {
1533 sqlparser::ast::OrderByOptions { nulls_first, .. }
1534 if nulls_first.is_some() =>
1535 {
1536 Err("order by with nulls first not supported")?
1537 }
1538 sqlparser::ast::OrderByOptions { asc, .. } => match asc {
1539 None => OrderOption::None,
1540 Some(true) => OrderOption::Asc,
1541 Some(false) => OrderOption::Desc,
1542 },
1543 };
1544 Ok(OrderByParameter { ident, option })
1545 })
1546 .collect::<Result<Vec<_>>>()?,
1547 }
1548 }
1549 None => vec![],
1550 };
1551 let ast = Ast::Select {
1552 distinct: select.distinct.is_some(),
1553 projections,
1554 from_clause,
1555 selection,
1556 group_by,
1557 order_by,
1558 };
1559 Ok(ast)
1560 }
1561
1562 fn parse_insert(insert: &sqlparser::ast::Insert) -> Result<Ast> {
1563 let sqlparser::ast::Insert {
1564 or,
1565 ignore,
1566 into,
1567 table,
1568 table_alias,
1569 columns,
1570 overwrite,
1571 source,
1572 assignments,
1573 partitioned,
1574 after_columns,
1575 has_table_keyword,
1576 on,
1577 returning,
1578 replace_into,
1579 priority,
1580 insert_alias,
1581 settings,
1582 format_clause,
1583 } = insert;
1584 if or.is_some() {
1586 Err("insert or not yet supported")?
1587 };
1588 if *ignore {
1590 Err("insert ignore is not yet supported")?
1591 }
1592 if !*into {
1593 Err("insert without into is not supported")?
1594 }
1595 if table_alias.is_some() {
1596 Err("table alias in insert it not supported")?
1597 }
1598 if *overwrite {
1599 Err("overwrite in insert it not supported")?
1600 }
1601 if !assignments.is_empty() {
1602 Err("insert assignments are not supported")?
1603 }
1604 if partitioned.is_some() || !after_columns.is_empty() {
1605 Err("partitioned inserts are not supported")?
1606 }
1607 if *has_table_keyword {
1608 Err("insert doesn't support TABLE keyword")?
1609 }
1610 if on.is_some() {
1612 Err("insert with ON is not supported")?
1613 }
1614 if returning.is_some() {
1615 Err("insert RETURNING is not supported")?
1616 }
1617 if *replace_into {
1618 Err("insert with replace into is not supported")?
1619 }
1620 if priority.is_some() {
1621 Err("insert with priority is not supported")?
1622 }
1623 if insert_alias.is_some() {
1624 Err("insert with insert alias is not supported")?
1625 }
1626 if settings.is_some() {
1627 Err("insert with settings is not supported")?
1628 }
1629 if format_clause.is_some() {
1630 Err("insert with format clause is not supported")?
1631 }
1632 let name = match &table {
1633 sqlparser::ast::TableObject::TableName(name) => Self::parse_object_name(name)?,
1634 _ => Err("unsupported table name type: {table:?}")?,
1635 };
1636 let source = match source {
1637 Some(source) => source,
1638 None => Err("insert source is empty")?,
1639 };
1640 Ok(Ast::Insert {
1641 table: name,
1642 columns: columns.iter().map(|ident| ident.value.clone()).collect(),
1643 source: Self::parse_insert_source(source)?,
1644 })
1645 }
1646
1647 fn parse_insert_source(values: &Query) -> Result<Vec<Vec<InsertSource>>> {
1648 let values = match values.body.as_ref() {
1649 SetExpr::Values(values) if !values.explicit_row => values
1650 .rows
1651 .iter()
1652 .map(|row| -> Result<Vec<InsertSource>> {
1653 row.iter()
1654 .map(|value| value.try_into())
1655 .collect::<Result<_>>()
1656 })
1657 .collect::<Result<_>>()?,
1658 _ => Err(format!("unsupported insert source values: {values:#?}"))?,
1659 };
1660 Ok(values)
1661 }
1662
1663 fn parse_update(
1664 table: &TableWithJoins,
1665 assignments: &[Assignment],
1666 from: Option<&UpdateTableFromKind>,
1667 selection: Option<&Expr>,
1668 returning: Option<&[SelectItem]>,
1669 or: Option<&SqliteOnConflict>,
1670 limit: Option<&Expr>,
1671 ) -> Result<Ast> {
1672 if from.is_some() {
1673 Err("update from table from kind is not supported")?
1674 }
1675 if returning.is_some() {
1676 Err("update with returning is not supported")?
1677 }
1678 if or.is_some() {
1679 Err("update with OR is not supported")?
1680 }
1681 if limit.is_some() {
1682 Err("update with LIMIT is not supported")?
1683 }
1684 let table = match &table.relation {
1685 TableFactor::Table { name, .. } => Self::parse_object_name(name)?,
1686 _ => Err(format!("unsupported table type: {table:#?}"))?,
1687 };
1688 let assignments = assignments
1689 .iter()
1690 .map(|assigment| {
1691 let target = match &assigment.target {
1692 AssignmentTarget::ColumnName(name) => Self::parse_object_name(name)?,
1693 target => Err(format!("unsupported assignment target: {target:?}"))?,
1694 };
1695 let value = (&assigment.value).try_into()?;
1696 Ok(UpdateAssignment { target, value })
1697 })
1698 .collect::<Result<Vec<UpdateAssignment>>>()?;
1699 let selection: Option<Selection> = selection
1700 .map(|selection| selection.try_into())
1701 .transpose()?;
1702 Ok(Ast::Update {
1703 table,
1704 assignments,
1705 selection,
1706 })
1707 }
1708
1709 fn parse_delete(delete: &Delete) -> Result<Ast> {
1710 if !delete.tables.is_empty() {
1711 Err("multi tables delete is not supported")?
1712 }
1713 if delete.using.is_some() {
1714 Err("delete with using is not supported")?
1715 }
1716 if delete.returning.is_some() {
1717 Err("delete with returning is not supported")?
1718 }
1719 if !delete.order_by.is_empty() {
1720 Err("delete with order by is not supported")?
1721 }
1722 if delete.limit.is_some() {
1723 Err("delete with limit is not supported")?
1724 }
1725
1726 let tables = match &delete.from {
1727 FromTable::WithFromKeyword(tables) => tables,
1728 FromTable::WithoutKeyword(_) => Err("delete without from keyword is not supported")?,
1729 };
1730 let from_clause = tables.as_slice().try_into()?;
1731
1732 let selection = delete
1733 .selection
1734 .as_ref()
1735 .map(|selection| selection.try_into())
1736 .transpose()?;
1737 Ok(Ast::Delete {
1738 from_clause,
1739 selection,
1740 })
1741 }
1742
1743 fn parse_drop(
1744 object_type: &ObjectType,
1745 if_exists: bool,
1746 names: &[ObjectName],
1747 table: Option<&ObjectName>,
1748 ) -> Result<Self> {
1749 let (object_type, table) = match object_type {
1750 ObjectType::Table => (DropObjectType::Table, None),
1751 ObjectType::Index => (
1752 DropObjectType::Index,
1753 table.map(Self::parse_object_name).transpose()?,
1754 ),
1755 _ => Err(format!("drop of {object_type:?} is not supported"))?,
1756 };
1757 if names.len() > 1 {
1758 Err("multiple names are not supported")?
1759 }
1760 let name = Self::parse_object_name(names.first().ok_or("no drop names found")?)?;
1761 Ok(Ast::Drop {
1762 object_type,
1763 if_exists,
1764 name,
1765 table,
1766 })
1767 }
1768
1769 pub fn parse(query: &str) -> Result<Vec<Ast>> {
1770 Parser::parse_sql(&dialect::GenericDialect {}, query)?
1771 .iter()
1772 .map(|statement| {
1773 let result = match statement {
1774 Statement::CreateTable(create_table) => Self::parse_create_table(create_table)?,
1775 Statement::AlterTable {
1776 name,
1777 if_exists,
1778 only,
1779 operations,
1780 location,
1781 on_cluster,
1782 iceberg,
1783 end_token,
1784 } => Self::parse_alter_table(
1785 name,
1786 *if_exists,
1787 *only,
1788 operations.as_slice(),
1789 location.as_ref(),
1790 on_cluster.as_ref(),
1791 *iceberg,
1792 end_token,
1793 )?,
1794 Statement::CreateIndex(index) => Self::parse_create_index(index)?,
1795 Statement::Query(query) => Self::parse_query(query)?,
1796 Statement::Drop {
1797 object_type,
1798 if_exists,
1799 names,
1800 cascade,
1801 restrict,
1802 purge,
1803 temporary,
1804 table,
1805 } => Self::parse_drop(object_type, *if_exists, names, table.as_ref())?,
1806 Statement::Insert(insert) => Self::parse_insert(insert)?,
1807 Statement::Update {
1808 table,
1809 assignments,
1810 from,
1811 selection,
1812 returning,
1813 or,
1814 limit,
1815 } => Self::parse_update(
1816 table,
1817 assignments.as_slice(),
1818 from.as_ref(),
1819 selection.as_ref(),
1820 returning.as_deref(),
1821 or.as_ref(),
1822 limit.as_ref(),
1823 )?,
1824 Statement::Delete(delete) => Self::parse_delete(delete)?,
1825 _ => Err(format!("unsupported statement: {statement:?}"))?,
1826 };
1827 Ok(result)
1828 })
1829 .collect::<Result<Vec<_>>>()
1830 }
1831
1832 fn create_table_to_sql(
1833 dialect: &dyn ToQuery,
1834 buf: &mut dyn Write,
1835 if_not_exists: bool,
1836 name: &str,
1837 columns: &[Column],
1838 constraints: &Constraints,
1839 ) -> Result<()> {
1840 buf.write_all(b"CREATE TABLE ")?;
1841 if if_not_exists {
1842 buf.write_all(b"IF NOT EXISTS ")?;
1843 }
1844 Self::write_quoted(dialect, buf, name)?;
1845 buf.write_all(b" (\n")?;
1846 Self::table_columns_to_sql(dialect, buf, columns, "\n")?;
1847 if constraints.len() > 0 {
1848 buf.write_all(b",\n")?;
1849 }
1850 for (pos, constraint) in constraints.into_iter().enumerate() {
1851 match constraint {
1852 Constraint::PrimaryKey(fields) => {
1853 buf.write_all(b"PRIMARY KEY (")?;
1854 for (pos, field) in fields.iter().enumerate() {
1855 Self::write_quoted(dialect, buf, field)?;
1856 if pos != fields.len() - 1 {
1857 buf.write_all(b", ")?;
1858 }
1859 }
1860 buf.write_all(b")")?;
1861 }
1862 Constraint::ForeignKey {
1863 columns,
1864 referred_columns,
1865 foreign_table,
1866 on_delete,
1867 } => {
1868 buf.write_all(b"FOREIGN KEY (")?;
1869 for (pos, column) in columns.iter().enumerate() {
1870 Self::write_quoted(dialect, buf, column)?;
1871 if pos != columns.len() - 1 {
1872 buf.write_all(b", ")?;
1873 }
1874 }
1875 buf.write_all(b") REFERENCES ")?;
1876 buf.write_all(foreign_table.as_bytes());
1877 buf.write_all(b"(")?;
1878 for (pos, column) in referred_columns.iter().enumerate() {
1879 Self::write_quoted(dialect, buf, column)?;
1880 if pos != columns.len() - 1 {
1881 buf.write_all(b", ")?;
1882 }
1883 }
1884 buf.write_all(b")")?;
1885
1886 if let Some(delete_action) = on_delete {
1887 buf.write_all(b" ON DELETE ")?;
1888 match delete_action {
1889 OnDeleteAction::Cascade => buf.write_all(b"CASCADE")?,
1890 OnDeleteAction::SetNull => buf.write_all(b"SET NULL")?,
1891 OnDeleteAction::Restrict => buf.write_all(b"RESTRICT")?,
1892 }
1893 }
1894 }
1895 }
1896 if pos != constraints.len() - 1 {
1897 buf.write_all(b",\n")?;
1898 }
1899 }
1900 buf.write_all(b"\n)")?;
1901 Ok(())
1902 }
1903
1904 fn table_columns_to_sql(
1905 dialect: &dyn ToQuery,
1906 buf: &mut dyn Write,
1907 columns: &[Column],
1908 separator: &str,
1909 ) -> Result<()> {
1910 for (pos, column) in columns.iter().enumerate() {
1911 Self::write_quoted(dialect, buf, &column.name)?;
1912 buf.write_all(b" ")?;
1913
1914 dialect.emit_column_spec(column, buf)?;
1915 if pos != columns.len() - 1 {
1916 buf.write_all(b",")?;
1917 buf.write_all(separator.as_bytes())?;
1918 }
1919 }
1920 Ok(())
1921 }
1922
1923 fn create_index_to_sql(
1924 dialect: &dyn ToQuery,
1925 buf: &mut dyn Write,
1926 unique: bool,
1927 name: &str,
1928 table: &str,
1929 columns: &[String],
1930 ) -> Result<()> {
1931 if unique {
1932 buf.write_all(b"CREATE UNIQUE INDEX ")?;
1933 } else {
1934 buf.write_all(b"CREATE INDEX ")?;
1935 }
1936 Self::write_quoted(dialect, buf, name)?;
1937 buf.write_all(b" ON ")?;
1938 Self::write_quoted(dialect, buf, table)?;
1939 buf.write_all(b" (")?;
1940 for (pos, column) in columns.iter().enumerate() {
1941 Self::write_quoted(dialect, buf, column)?;
1942 if pos != columns.len() - 1 {
1943 buf.write_all(b", ")?;
1944 }
1945 }
1946 buf.write_all(b")")?;
1947 Ok(())
1948 }
1949
1950 #[allow(clippy::too_many_arguments)]
1951 fn select_to_sql(
1952 dialect: &dyn ToQuery,
1953 buf: &mut dyn Write,
1954 distinct: bool,
1955 projections: &[Projection],
1956 from_clause: &FromClause,
1957 selection: Option<&Selection>,
1958 group_by: &[GroupByParameter],
1959 order_by: &[OrderByParameter],
1960 ) -> Result<()> {
1961 buf.write_all(b"SELECT ")?;
1962 if distinct {
1963 buf.write_all(b"DISTINCT ")?;
1964 }
1965 for (pos, projection) in projections.iter().enumerate() {
1966 match projection {
1967 Projection::WildCard => buf.write_all(b"*")?,
1968 Projection::Identifier(ident) => {
1969 Self::write_quoted(dialect, buf, ident)?;
1970 }
1971 Projection::CompoundIdentifier(compound) => {
1972 Self::write_quoted(dialect, buf, &compound.table)?;
1973 buf.write_all(b".");
1974 Self::write_quoted(dialect, buf, &compound.column)?;
1975 }
1976 Projection::Function(function) => match function {
1977 Function::Count(FunctionArg::Wildcard) => buf.write_all(b"COUNT(*)")?,
1978 Function::Count(FunctionArg::Ident(ident)) => {
1979 buf.write_all(b"COUNT(")?;
1980 Self::write_quoted(dialect, buf, ident)?;
1981 buf.write_all(b")")?
1982 }
1983 },
1984 Projection::NumericLiteral(value) => buf.write_all(value.as_bytes())?,
1985 Projection::String(value) => Self::write_single_quoted(dialect, buf, value)?,
1986 };
1987 if pos != projections.len() - 1 {
1988 buf.write_all(b", ")?;
1989 }
1990 }
1991
1992 match from_clause {
1993 FromClause::Table(name) => {
1994 buf.write_all(b" FROM ")?;
1995 Self::write_quoted(dialect, buf, name)?
1996 }
1997 FromClause::None => (),
1998 FromClause::TableWithJoin(table) => {
1999 buf.write_all(b" FROM ")?;
2000 Self::write_quoted(dialect, buf, &table.name)?;
2001 for table in table.join.iter() {
2002 match &table.operator {
2003 JoinOperator::Join(selection) => {
2004 buf.write_all(b" JOIN ")?;
2005 Self::write_quoted(dialect, buf, &table.name);
2006 buf.write_all(b" ON ")?;
2007 Self::selection_to_sql(dialect, buf, selection)?;
2008 }
2009 JoinOperator::Inner(selection) => {
2010 buf.write_all(b" INNER JOIN ")?;
2011 Self::write_quoted(dialect, buf, &table.name);
2012 buf.write_all(b" ON ")?;
2013 Self::selection_to_sql(dialect, buf, selection)?;
2014 }
2015 }
2016 }
2017 }
2018 }
2019 if let Some(selection) = selection.as_ref() {
2020 buf.write_all(b" WHERE ")?;
2021 Self::selection_to_sql(dialect, buf, selection)?;
2022 };
2023
2024 if !group_by.is_empty() {
2025 buf.write_all(b" GROUP BY (")?;
2026 for (pos, parameter) in group_by.iter().enumerate() {
2027 match parameter {
2028 GroupByParameter::Ident(ident) => Self::write_quoted(dialect, buf, ident)?,
2029 }
2030 if pos != group_by.len() - 1 {
2031 buf.write_all(b", ")?;
2032 }
2033 }
2034 buf.write_all(b")")?;
2035 }
2036 if !order_by.is_empty() {
2037 buf.write_all(b" ORDER BY ")?;
2038 for (pos, order_option) in order_by.iter().enumerate() {
2039 Self::write_quoted(dialect, buf, order_option.ident.as_str())?;
2040 match &order_option.option {
2041 OrderOption::Asc => buf.write_all(b" ASC")?,
2042 OrderOption::Desc => buf.write_all(b" DESC")?,
2043 OrderOption::None => (),
2044 };
2045 if pos != order_by.len() - 1 {
2046 buf.write_all(b", ")?;
2047 }
2048 }
2049 }
2050 Ok(())
2051 }
2052
2053 fn insert_source_to_sql(
2054 dialect: &dyn ToQuery,
2055 buf: &mut dyn Write,
2056 insert_source: &InsertSource,
2057 place_holder_num: usize,
2058 ) -> Result<()> {
2059 match insert_source {
2060 InsertSource::Null => buf.write_all(b"NULL")?,
2061 InsertSource::Number(num) => buf.write_all(num.as_bytes())?,
2062 InsertSource::String(string) => Self::write_single_quoted(dialect, buf, string)?,
2063 InsertSource::Placeholder => {
2064 buf.write_all(dialect.placeholder(place_holder_num).as_bytes())?;
2065 }
2066 InsertSource::Cast { cast, source } => {
2067 Self::insert_source_to_sql(dialect, buf, source, place_holder_num)?;
2068 if dialect.placeholder_supports_cast() {
2069 buf.write_all(b"::")?;
2070 buf.write_all(cast.as_bytes())?;
2071 }
2072 }
2073 };
2074 Ok(())
2075 }
2076
2077 fn insert_to_sql(
2078 dialect: &dyn ToQuery,
2079 buf: &mut dyn Write,
2080 table: &str,
2081 columns: &[String],
2082 values: &[Vec<InsertSource>],
2083 ) -> Result<()> {
2084 buf.write_all(b"INSERT INTO ")?;
2085 Self::write_quoted(dialect, buf, table)?;
2086 if !columns.is_empty() {
2087 buf.write_all(b"(")?;
2088 for (pos, column) in columns.iter().enumerate() {
2089 if pos != 0 {
2090 buf.write_all(b", ")?;
2091 }
2092 Self::write_quoted(dialect, buf, column)?;
2093 }
2094 buf.write_all(b")")?;
2095 }
2096 buf.write_all(b" VALUES ")?;
2097 for (row_pos, row) in values.iter().enumerate() {
2098 if row_pos != 0 {
2099 buf.write_all(b", ")?;
2100 }
2101 buf.write_all(b"(")?;
2102 for (col_pos, insert_source) in row.iter().enumerate() {
2103 if col_pos != 0 {
2104 buf.write_all(b", ")?;
2105 }
2106 Self::insert_source_to_sql(
2107 dialect,
2108 buf,
2109 insert_source,
2110 row_pos * row.len() + col_pos + 1,
2111 )?;
2112 }
2113 buf.write_all(b")")?;
2114 }
2115 Ok(())
2116 }
2117
2118 fn selection_to_sql(
2119 dialect: &dyn ToQuery,
2120 buf: &mut dyn Write,
2121 selection: &Selection,
2122 ) -> Result<()> {
2123 let mut placeholder_count = 0;
2124 Self::selection_to_sql_with_placeholder_count(
2125 dialect,
2126 buf,
2127 selection,
2128 &mut placeholder_count,
2129 )
2130 }
2131
2132 fn selection_to_sql_with_placeholder_count(
2133 dialect: &dyn ToQuery,
2134 buf: &mut dyn Write,
2135 selection: &Selection,
2136 placeholder_count: &mut usize,
2137 ) -> Result<()> {
2138 match selection {
2139 Selection::BinaryOp { op, left, right } => {
2140 Self::selection_to_sql_with_placeholder_count(
2141 dialect,
2142 buf,
2143 left,
2144 placeholder_count,
2145 )?;
2146 match op {
2147 Op::And => buf.write_all(b" AND ")?,
2148 Op::Eq => buf.write_all(b" = ")?,
2149 Op::Or => buf.write_all(b" OR ")?,
2150 }
2151 Self::selection_to_sql_with_placeholder_count(
2152 dialect,
2153 buf,
2154 right,
2155 placeholder_count,
2156 )?;
2157 }
2158 Selection::Ident(ident) => Self::write_quoted(dialect, buf, ident)?,
2159 Selection::CompoundIdentifier(compound) => {
2160 Self::write_quoted(dialect, buf, &compound.table)?;
2161 buf.write_all(b".");
2162 Self::write_quoted(dialect, buf, &compound.column)?;
2163 }
2164 Selection::Number(number) => buf.write_all(number.as_bytes())?,
2165 Selection::String(string) => {
2166 for chunk in [b"'", string.as_bytes(), b"'"] {
2167 buf.write_all(chunk)?;
2168 }
2169 }
2170 Selection::Placeholder => {
2171 *placeholder_count += 1;
2172 buf.write_all(dialect.placeholder(*placeholder_count).as_bytes())?;
2173 }
2174 Selection::InList {
2175 negated,
2176 ident,
2177 list,
2178 } => {
2179 Self::write_quoted(dialect, buf, ident)?;
2180 if *negated {
2181 buf.write_all(b" NOT")?;
2182 }
2183 buf.write_all(b" IN ")?;
2184 buf.write_all(b"(")?;
2185 for (pos, selection) in list.iter().enumerate() {
2186 if pos != 0 {
2187 buf.write_all(b", ")?;
2188 }
2189 Self::selection_to_sql_with_placeholder_count(
2190 dialect,
2191 buf,
2192 selection,
2193 placeholder_count,
2194 )?;
2195 }
2196 buf.write_all(b")")?;
2197 }
2198 };
2199 Ok(())
2200 }
2201
2202 fn update_to_sql(
2203 dialect: &dyn ToQuery,
2204 buf: &mut dyn Write,
2205 table: &str,
2206 assignments: &[UpdateAssignment],
2207 selection: Option<&Selection>,
2208 ) -> Result<()> {
2209 buf.write_all(b"UPDATE ")?;
2210 Self::write_quoted(dialect, buf, table)?;
2211 buf.write_all(b" SET ")?;
2212 for (pos, assignment) in assignments.iter().enumerate() {
2213 if pos != 0 {
2214 buf.write_all(b", ")?;
2215 }
2216 Self::write_quoted(dialect, buf, assignment.target.as_bytes())?;
2217 buf.write_all(b"=")?;
2218 match &assignment.value {
2219 UpdateValue::Null => buf.write_all(b"NULL")?,
2220 UpdateValue::String(string) => Self::write_single_quoted(dialect, buf, string)?,
2221 UpdateValue::Number(number) => buf.write_all(number.as_bytes())?,
2222 UpdateValue::Placeholder => {
2223 buf.write_all(dialect.placeholder(pos + 1).as_bytes())?
2224 }
2225 }
2226 }
2227 if let Some(selection) = selection.as_ref() {
2228 buf.write_all(b" WHERE ")?;
2229 Self::selection_to_sql(dialect, buf, selection)?;
2230 };
2231 Ok(())
2232 }
2233
2234 fn delete_to_sql(
2235 dialect: &dyn ToQuery,
2236 buf: &mut dyn Write,
2237 from_clause: &FromClause,
2238 selection: Option<&Selection>,
2239 ) -> Result<()> {
2240 buf.write_all(b"DELETE FROM ")?;
2241 match from_clause {
2242 FromClause::Table(name) => Self::write_quoted(dialect, buf, name)?,
2243 FromClause::None => Err("DELETE without FROM is not supported")?,
2244 FromClause::TableWithJoin(_) => Err("DELETE with joins is not supported")?,
2245 }
2246 if let Some(selection) = selection.as_ref() {
2247 buf.write_all(b" WHERE ")?;
2248 Self::selection_to_sql(dialect, buf, selection)?;
2249 };
2250 Ok(())
2251 }
2252
2253 fn drop_to_sql(
2254 dialect: &dyn ToQuery,
2255 buf: &mut dyn Write,
2256 object_type: DropObjectType,
2257 if_exists: bool,
2258 name: &str,
2259 table: Option<&str>,
2260 ) -> Result<()> {
2261 match object_type {
2262 DropObjectType::Table => buf.write_all(b"DROP TABLE ")?,
2263 DropObjectType::Index => buf.write_all(b"DROP INDEX ")?,
2264 };
2265 if if_exists {
2266 buf.write_all(b"IF EXISTS ")?;
2267 }
2268 Self::write_quoted(dialect, buf, name);
2269 match (
2270 object_type == DropObjectType::Index,
2271 dialect.drop_index_requires_table(),
2272 table,
2273 ) {
2274 (true, true, Some(table)) => {
2275 buf.write_all(b" ON ")?;
2276 Self::write_quoted(dialect, buf, table)?;
2277 }
2278 (true, _, None) => Err("`DROP INDEX` requires table name")?,
2279 _ => (),
2280 };
2281 Ok(())
2282 }
2283
2284 fn write_quoted(
2285 dialect: &dyn ToQuery,
2286 buf: &mut dyn Write,
2287 input: impl AsRef<[u8]>,
2288 ) -> Result<()> {
2289 buf.write_all(dialect.quote())?;
2290 buf.write_all(input.as_ref())?;
2291 buf.write_all(dialect.quote())?;
2292 Ok(())
2293 }
2294
2295 fn write_single_quoted(
2296 dialect: &dyn ToQuery,
2297 buf: &mut dyn Write,
2298 input: impl AsRef<[u8]>,
2299 ) -> Result<()> {
2300 buf.write_all(b"'")?;
2301 buf.write_all(input.as_ref())?;
2302 buf.write_all(b"'")?;
2303 Ok(())
2304 }
2305
2306 fn alter_table_to_sql(
2307 dialect: &dyn ToQuery,
2308 buf: &mut dyn Write,
2309 table_name: &str,
2310 operation: &AlterTableOperation,
2311 ) -> Result<()> {
2312 buf.write_all(b"ALTER TABLE ")?;
2313 Self::write_quoted(dialect, buf, table_name)?;
2314 match operation {
2315 AlterTableOperation::AddColumn { column } => {
2316 buf.write_all(b" ADD COLUMN ")?;
2317 let columns: &[Column] = slice::from_ref(column);
2318 Self::table_columns_to_sql(dialect, buf, columns, "")?;
2319 }
2320 AlterTableOperation::RenameColumn { from, to } => {
2321 buf.write_all(b" RENAME COLUMN ")?;
2322 Self::write_quoted(dialect, buf, from)?;
2323 buf.write_all(b" TO ")?;
2324 Self::write_quoted(dialect, buf, to)?;
2325 }
2326 AlterTableOperation::DropColumn { name } => {
2327 buf.write_all(b" DROP COLUMN ")?;
2328 Self::write_quoted(dialect, buf, name)?;
2329 }
2330 AlterTableOperation::RenameTable { to } => {
2331 buf.write_all(b" RENAME TO ")?;
2332 Self::write_quoted(dialect, buf, to)?;
2333 }
2334 }
2335 Ok(())
2336 }
2337
2338 pub fn to_sql(&self, dialect: &dyn ToQuery) -> Result<String> {
2339 let buf = &mut Cursor::new(Vec::with_capacity(1024));
2340 match self {
2341 Ast::CreateTable {
2342 if_not_exists,
2343 name,
2344 columns,
2345 constraints,
2346 } => {
2347 Self::create_table_to_sql(dialect, buf, *if_not_exists, name, columns, constraints)?
2348 }
2349 Ast::AlterTable { name, operation } => {
2350 Self::alter_table_to_sql(dialect, buf, name.as_str(), operation)?
2351 }
2352 Ast::CreateIndex {
2353 unique,
2354 name,
2355 table,
2356 columns,
2357 } => Self::create_index_to_sql(dialect, buf, *unique, name, table, columns)?,
2358 Ast::Select {
2359 distinct,
2360 projections,
2361 from_clause,
2362 selection,
2363 group_by,
2364 order_by,
2365 } => Self::select_to_sql(
2366 dialect,
2367 buf,
2368 *distinct,
2369 projections,
2370 from_clause,
2371 selection.as_ref(),
2372 group_by,
2373 order_by,
2374 )?,
2375 Ast::Insert {
2376 table,
2377 columns,
2378 source,
2379 } => Self::insert_to_sql(
2380 dialect,
2381 buf,
2382 table.as_str(),
2383 columns.as_slice(),
2384 source.as_slice(),
2385 )?,
2386 Ast::Update {
2387 table,
2388 assignments,
2389 selection,
2390 } => Self::update_to_sql(
2391 dialect,
2392 buf,
2393 table.as_str(),
2394 assignments.as_slice(),
2395 selection.as_ref(),
2396 )?,
2397 Ast::Delete {
2398 from_clause,
2399 selection,
2400 } => Self::delete_to_sql(dialect, buf, from_clause, selection.as_ref())?,
2401 Ast::Drop {
2402 object_type,
2403 if_exists,
2404 name,
2405 table,
2406 } => Self::drop_to_sql(
2407 dialect,
2408 buf,
2409 *object_type,
2410 *if_exists,
2411 name,
2412 table.as_ref().map(AsRef::as_ref),
2413 )?,
2414 };
2415 let buf = std::mem::replace(buf, Cursor::new(Vec::new()));
2416 Ok(String::from_utf8(buf.into_inner())?)
2417 }
2418}
2419
2420pub trait ToQuery {
2421 fn quote(&self) -> &'static [u8];
2422
2423 fn placeholder(&self, pos: usize) -> Cow<'static, str>;
2424
2425 fn placeholder_supports_cast(&self) -> bool {
2426 false
2427 }
2428
2429 fn emit_column_spec(&self, column: &Column, buf: &mut dyn Write) -> Result<()>;
2430
2431 fn drop_index_requires_table(&self) -> bool {
2432 false
2433 }
2434}
2435
2436impl ToQuery for MySqlDialect {
2437 fn quote(&self) -> &'static [u8] {
2438 b"`"
2439 }
2440
2441 fn placeholder(&self, _: usize) -> Cow<'static, str> {
2442 Cow::Borrowed("?")
2443 }
2444
2445 fn emit_column_spec(
2446 &self,
2447 Column {
2448 name,
2449 data_type,
2450 options,
2451 }: &Column,
2452 buf: &mut dyn Write,
2453 ) -> Result<()> {
2454 let mut options = *options;
2455 let spec = match data_type {
2456 DataType::SmallSerial if options.is_primary_key() => {
2457 options = options.set_auto_increment();
2458 Cow::Borrowed("SMALLINT")
2459 }
2460 DataType::Serial if options.is_primary_key() => {
2461 options = options.set_auto_increment();
2462 Cow::Borrowed("INT")
2463 }
2464 DataType::BigSerial if options.is_primary_key() => {
2465 options = options.set_auto_increment();
2466 Cow::Borrowed("BIGINT")
2467 }
2468 DataType::SmallSerial | DataType::Serial | DataType::BigSerial => {
2469 Err("expected smallserial/serial/bigserial with `PRIMARY KEY` constraint")?
2470 }
2471 DataType::I16 => Cow::Borrowed("SMALLLINT"),
2472 DataType::I32 => Cow::Borrowed("INT"),
2473 DataType::I64 => Cow::Borrowed("BIGINT"),
2474 DataType::F32 => Cow::Borrowed("REAL"),
2475 DataType::F64 => Cow::Borrowed("DOUBLE"),
2476 DataType::Bool => Cow::Borrowed("BOOLEAN"),
2477 DataType::String => Cow::Borrowed("TEXT"),
2478 DataType::Char(len) => Cow::Owned(format!("CHAR({len})")),
2479 DataType::VarChar(len) => Cow::Owned(format!("VARCHAR({len})")),
2480 DataType::Bytes => Cow::Borrowed("BLOB"),
2481 DataType::Json => Cow::Borrowed("JSON"),
2482 DataType::Uuid => Cow::Borrowed("CHAR(36)"),
2483 DataType::Decimal { precision, scale } => {
2484 Cow::Owned(format!("DECIMAL({precision}, {scale})"))
2485 }
2486 DataType::Date => Cow::Borrowed("DATE"),
2487 DataType::Time => Cow::Borrowed("TIME"),
2488 DataType::Timestamp => Cow::Borrowed("DATETIME"),
2489 };
2490
2491 buf.write_all(spec.as_bytes())?;
2492 let options = options
2493 .into_iter()
2494 .map(|option| match option {
2495 ColumnOption::PrimaryKey => "PRIMARY KEY",
2496 ColumnOption::AutoInrement => "AUTO_INCREMENT",
2497 ColumnOption::NotNull => "NOT NULL",
2498 ColumnOption::Nullable => "NULL",
2499 ColumnOption::Unique => "UNIQUE",
2500 })
2501 .collect::<Vec<_>>()
2502 .join(" ");
2503 if !options.is_empty() {
2504 buf.write_all(b" ")?;
2505 buf.write_all(options.as_bytes())?;
2506 }
2507 Ok(())
2508 }
2509
2510 fn drop_index_requires_table(&self) -> bool {
2511 true
2512 }
2513}
2514
2515impl ToQuery for PostgreSqlDialect {
2516 fn quote(&self) -> &'static [u8] {
2517 b"\""
2518 }
2519
2520 fn placeholder(&self, pos: usize) -> Cow<'static, str> {
2521 Cow::Owned(format!("${pos}"))
2522 }
2523
2524 fn placeholder_supports_cast(&self) -> bool {
2525 true
2526 }
2527
2528 fn emit_column_spec(
2529 &self,
2530 Column {
2531 name,
2532 data_type,
2533 options,
2534 }: &Column,
2535 buf: &mut dyn Write,
2536 ) -> Result<()> {
2537 let mut options = *options;
2538 let spec = match data_type {
2539 DataType::SmallSerial if options.is_primary_key() => Cow::Borrowed("SMALLSERIAL"),
2540 DataType::Serial if options.is_primary_key() => Cow::Borrowed("SERIAL"),
2541 DataType::BigSerial if options.is_primary_key() => Cow::Borrowed("BIGSERIAL"),
2542 DataType::SmallSerial | DataType::Serial | DataType::BigSerial => {
2543 Err("expected smallserial/serial/bigserial with `PRIMARY KEY` constraint")?
2544 }
2545 DataType::I16 if options.is_primary_key() && options.is_auto_increment() => {
2546 Cow::Borrowed("SMALLSERIAL")
2547 }
2548 DataType::I32 if options.is_primary_key() && options.is_auto_increment() => {
2549 Cow::Borrowed("SERIAL")
2550 }
2551 DataType::I64 if options.is_primary_key() && options.is_auto_increment() => {
2552 Cow::Borrowed("BIGSERIAL")
2553 }
2554 DataType::I16 => Cow::Borrowed("SMALLLINT"),
2555 DataType::I32 => Cow::Borrowed("INT"),
2556 DataType::I64 => Cow::Borrowed("BIGINT"),
2557 DataType::F32 => Cow::Borrowed("REAL"),
2558 DataType::F64 => Cow::Borrowed("DOUBLE"),
2559 DataType::Bool => Cow::Borrowed("BOOLEAN"),
2560 DataType::String => Cow::Borrowed("TEXT"),
2561 DataType::Char(len) => Cow::Owned(format!("CHAR({len})")),
2562 DataType::VarChar(len) => Cow::Owned(format!("VARCHAR({len})")),
2563 DataType::Bytes => Cow::Borrowed("BYTEA"),
2564 DataType::Json => Cow::Borrowed("JSON"),
2565 DataType::Uuid => Cow::Borrowed("UUID"),
2566 DataType::Decimal { precision, scale } => {
2567 Cow::Owned(format!("DECIMAL({precision}, {scale})"))
2568 }
2569 DataType::Date => Cow::Borrowed("DATE"),
2570 DataType::Time => Cow::Borrowed("TIME"),
2571 DataType::Timestamp => Cow::Borrowed("TIMESTAMP"),
2572 };
2573 buf.write_all(spec.as_bytes())?;
2574 let options = options
2575 .into_iter()
2576 .filter_map(|option| match option {
2577 ColumnOption::PrimaryKey => Some("PRIMARY KEY"),
2578 ColumnOption::AutoInrement => None,
2579 ColumnOption::NotNull => Some("NOT NULL"),
2580 ColumnOption::Nullable => Some("NULL"),
2581 ColumnOption::Unique => Some("UNIQUE"),
2582 })
2583 .collect::<Vec<_>>()
2584 .join(" ");
2585 if !options.is_empty() {
2586 buf.write_all(b" ")?;
2587 buf.write_all(options.as_bytes())?;
2588 }
2589 Ok(())
2590 }
2591}
2592
2593impl ToQuery for SQLiteDialect {
2594 fn quote(&self) -> &'static [u8] {
2595 b"`"
2596 }
2597
2598 fn placeholder(&self, _: usize) -> Cow<'static, str> {
2599 Cow::Borrowed("?")
2600 }
2601
2602 fn emit_column_spec(
2603 &self,
2604 Column {
2605 name,
2606 data_type,
2607 options,
2608 }: &Column,
2609 buf: &mut dyn Write,
2610 ) -> Result<()> {
2611 let mut options = *options;
2612 let spec = match data_type {
2613 DataType::SmallSerial | DataType::Serial | DataType::BigSerial
2614 if options.is_primary_key() =>
2615 {
2616 Cow::Borrowed("INTEGER")
2617 }
2618 DataType::SmallSerial | DataType::Serial | DataType::BigSerial => {
2619 Err("expected smallserial/serial/bigserial with `PRIMARY KEY` constraint")?
2620 }
2621 DataType::I16 | DataType::I32 | DataType::I64 if options.is_primary_key() => {
2622 options = options.unset_auto_increment();
2625 Cow::Borrowed("INTEGER")
2626 }
2627 DataType::I32 => Cow::Borrowed("INTEGER"),
2628 DataType::I64 => Cow::Borrowed("INTEGER"),
2629 DataType::I16 => Cow::Borrowed("INTEGER"),
2630 DataType::I32 => Cow::Borrowed("INTEGER"),
2631 DataType::I64 => Cow::Borrowed("INTEGER"),
2632 DataType::F32 => Cow::Borrowed("FLOAT"),
2633 DataType::F64 => Cow::Borrowed("DOUBLE"),
2634 DataType::Bool => Cow::Borrowed("BOOLEAN"),
2635 DataType::String => Cow::Borrowed("TEXT"),
2636 DataType::Char(len) => Cow::Owned(format!("CHAR({len})")),
2637 DataType::VarChar(len) => Cow::Owned(format!("VARCHAR({len})")),
2638 DataType::Bytes => Cow::Borrowed("BLOB"),
2639 DataType::Json => Cow::Borrowed("JSON"),
2640 DataType::Uuid => Cow::Borrowed("UUID"),
2641 DataType::Decimal { precision, scale } => {
2642 Cow::Owned(format!("DECIMAL({precision}, {scale})"))
2643 }
2644 DataType::Date => Cow::Borrowed("TEXT"),
2645 DataType::Time => Cow::Borrowed("TEXT"),
2646 DataType::Timestamp => Cow::Borrowed("TEXT"),
2647 };
2648 buf.write_all(spec.as_bytes())?;
2649 let options = options
2650 .into_iter()
2651 .map(|option| match option {
2652 ColumnOption::PrimaryKey => "PRIMARY KEY",
2653 ColumnOption::AutoInrement => "AUTOINCREMENT",
2654 ColumnOption::NotNull => "NOT NULL",
2655 ColumnOption::Nullable => "NULL",
2656 ColumnOption::Unique => "UNIQUE",
2657 })
2658 .collect::<Vec<_>>()
2659 .join(" ");
2660 if !options.is_empty() {
2661 buf.write_all(b" ")?;
2662 buf.write_all(options.as_bytes())?;
2663 }
2664 Ok(())
2665 }
2666}