sql_bridge/
ast.rs

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/// Common datatypes which are supported across all databases
31#[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                // SQLite only supports table.column, not schema.table.column or database.table.column
606                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        /// ClickHouse supports the optional `GLOBAL` keyword before the join operator.
825        /// See [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join)
826        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            // Postgre + MSSQL
865            if args.is_some() {
866                Err(
867                    "arguments of a table-valued function are not supported in table factor 'table'",
868                )?
869            }
870            //  MSSQL-specific `WITH (...)` hints such as NOLOCK.
871            if !with_hints.is_empty() {
872                Err("with hints are not supported in table factor 'table'")?
873            }
874            // Table time-travel, as supported by BigQuery and MSSQL.
875            if version.is_some() {
876                Err("version is not supported in table factor 'table'")?
877            }
878            // Postgres.
879            if *with_ordinality {
880                Err("with ordinality is not supported in table factor 'table'")?
881            }
882            // Mysql
883            if !partitions.is_empty() {
884                Err("partitions are not supported in table factor 'table'")?
885            }
886            // Optional PartiQL JsonPath
887            if json_path.is_some() {
888                Err("json path is not supported in table factor 'table'")?
889            }
890            // Optional table sample modifier
891            if sample.is_some() {
892                Err("sample is not supported in table factor 'table'")?
893            }
894            // Optional index hints (mysql)
895            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                    // only mysql
968                    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        // Hive formats for some reason are always Some()
1106        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        // ClickHouse "ON CLUSTER" clause:
1145        if on_cluster.is_some() {
1146            Err("'on cluster' is not supported in create table")?
1147        }
1148        // ClickHouse "PRIMARY KEY " clause.
1149        if primary_key.is_some() {
1150            Err("primary key is not supported in create table")?
1151        }
1152        // ClickHouse "ORDER BY " clause.
1153        if order_by.is_some() {
1154            Err("'order by' is not supported in create table")?
1155        }
1156        // BigQuery: A partition expression for the table.
1157        if partition_by.is_some() {
1158            Err("'partition by' is not supported in create table")?
1159        }
1160        // BigQuery: Table clustering column list.
1161        if cluster_by.is_some() {
1162            Err("'cluster_by' is not supported in create table")?
1163        }
1164        // Hive: Table clustering column list.
1165        if clustered_by.is_some() {
1166            Err("'clustered_by' is not supported in create table")?
1167        }
1168        // Postgres `INHERITs` clause, which contains the list of tables from which the new table inherits.
1169        if inherits.is_some() {
1170            Err("inherits are not supported in create table")?
1171        }
1172        // SQLite "STRICT" clause.
1173        if *strict {
1174            Err("strict is not supported in create table")?
1175        }
1176        // Snowflake "COPY GRANTS" clause.
1177        if *copy_grants {
1178            Err("copy grant is not supported in create table")?
1179        }
1180        // Snowflake "ENABLE_SCHEMA_EVOLUTION" clause.
1181        if enable_schema_evolution.is_some() {
1182            Err("'enable schema evolution' is not supported in create table")?
1183        }
1184        // Snowflake "CHANGE_TRACKING" clause.
1185        if change_tracking.is_some() {
1186            Err("'change tracking' is not supported in create table")?
1187        }
1188        // Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause.
1189        if data_retention_time_in_days.is_some() {
1190            Err("'data retention time in days' is not supported in create table")?
1191        }
1192        // Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause.
1193        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        // Snowflake "DEFAULT_DDL_COLLATION" clause.
1197        if default_ddl_collation.is_some() {
1198            Err("'default ddl collation' is not supported in create table")?
1199        }
1200        // Snowflake "WITH AGGREGATION POLICY" clause.
1201        if with_aggregation_policy.is_some() {
1202            Err("'with aggregation policy' is not supported in create table")?
1203        }
1204        // Snowflake "WITH ROW ACCESS POLICY" clause.
1205        if with_row_access_policy.is_some() {
1206            Err("'with row access policy' is not supported in create table")?
1207        }
1208        // Snowflake "WITH TAG" clause.
1209        if with_tags.is_some() {
1210            Err("'with tags' is not supported in create table")?
1211        }
1212        // Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
1213        if external_volume.is_some() {
1214            Err("'external volume' is not supported in create table")?
1215        }
1216        // Snowflake "BASE_LOCATION" clause for Iceberg tables
1217        if base_location.is_some() {
1218            Err("'base location' is not supported in create table")?
1219        }
1220        // Snowflake "CATALOG" clause for Iceberg tables
1221        if catalog.is_some() {
1222            Err("catalog is not supported in create table")?
1223        }
1224        // Snowflake "CATALOG_SYNC" clause for Iceberg tables
1225        if catalog_sync.is_some() {
1226            Err("'catalog sync' is not supported in create table")?
1227        }
1228        // Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
1229        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        // Snowflake "TARGET_LAG" clause for dybamic tables
1245        if target_lag.is_some() {
1246            Err("target lag is not supportec in create table")?
1247        }
1248        // Snowflake "WAREHOUSE" clause for dybamic tables
1249        if warehouse.is_some() {
1250            Err("warehouse is not supported in create table")?
1251        }
1252        // Snowflake "REFRESH_MODE" clause for dybamic tables
1253        if refresh_mode.is_some() {
1254            Err("refresh mode is not supported in create table")?
1255        }
1256        // Snowflake "INITIALIZE" clause for dybamic tables
1257        if initialize.is_some() {
1258            Err("initialize is not supported in create table")?
1259        }
1260        // Snowflake "REQUIRE USER" clause for dybamic tables
1261        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        // sqlite doesn't support if exists in alter
1292        if if_exists {
1293            Err("if exists is not supported in ALTER TABLE")?
1294        }
1295        // sqlite doesn't support `ON` clause in alter table
1296        if only {
1297            Err("`ON` keyword is not supported in ALTER TABLE")?
1298        }
1299        // clickhouse syntax
1300        if on_cluster.is_some() {
1301            Err("ON CLUSTER syntax is not supported")?
1302        }
1303        // hive syntax
1304        if location.is_some() {
1305            Err("LOCATION syntax is not supported")?
1306        }
1307        // iceberg syntax
1308        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                        // FIXME: move to TryFrom
1335                        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        // PG only
1403        if !index_options.is_empty() {
1404            Err("`CREATE INDEX` with index options is not supported")?
1405        }
1406        // Mysql only
1407        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        // FIXME:
1429        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        // FIXME:
1436        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                        // SQLite only supports table.column, not schema.table.column or database.table.column
1482                        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        // FIXME:
1585        if or.is_some() {
1586            Err("insert or not yet supported")?
1587        };
1588        // FIXME:
1589        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        // FIXME:
1611        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                // Sqlite doesn't need auto increment for integer primary key, since it's already auto incremented
2623                // in nature
2624                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}