Repository: gluesql/gluesql
Pull request #223 (2021-05-13 13:19:33)

New AST for execution layer
GlueSQL was using AST from sqlparser-rs which parses raw sql text to parsed AST.
However, feature requirements for parser and executor are quite different.

To support index, transaction, query planning, etc..., now it is required for us to have own execution layer AST.

New module named `translate` converts `sqlparser::ast` to `gluesql::ast`.



Patch:
diff --git a/examples/api_usage.rs b/examples/api_usage.rs
index de48e4e8..97518e8c 100644
--- a/examples/api_usage.rs
+++ b/examples/api_usage.rs
@@ -1,7 +1,8 @@
 #[cfg(feature = "sled-storage")]
-use futures::executor::block_on;
-#[cfg(feature = "sled-storage")]
-use gluesql::{execute, parse, Glue, SledStorage};
+use {
+    futures::executor::block_on,
+    gluesql::{execute, parse, translate, Glue, SledStorage},
+};
 
 #[cfg(feature = "sled-storage")]
 fn immutable_api() {
@@ -14,11 +15,15 @@ fn immutable_api() {
         DROP TABLE Glue;
     ";
 
-    parse(sqls).unwrap().iter().fold(storage, |storage, query| {
-        let (storage, _) = block_on(execute(storage, query)).unwrap();
+    parse(sqls)
+        .unwrap()
+        .iter()
+        .fold(storage, |storage, parsed| {
+            let statement = translate(&parsed).unwrap();
+            let (storage, _) = block_on(execute(storage, &statement)).unwrap();
 
-        storage
-    });
+            storage
+        });
 }
 
 #[cfg(feature = "sled-storage")]
@@ -33,9 +38,7 @@ fn mutable_api() {
         DROP TABLE Glue;
     ";
 
-    for query in parse(sqls).unwrap() {
-        glue.execute(&query).unwrap();
-    }
+    glue.execute(sqls).unwrap();
 }
 
 fn main() {
diff --git a/examples/hello_world.rs b/examples/hello_world.rs
index 6e1a37df..6fbbbf3d 100644
--- a/examples/hello_world.rs
+++ b/examples/hello_world.rs
@@ -1,6 +1,6 @@
 #[cfg(feature = "sled-storage")]
 mod hello_world {
-    use gluesql::{parse, Glue, Payload, SledStorage, Value};
+    use gluesql::{Glue, Payload, SledStorage, Value};
 
     pub fn run() {
         /*
@@ -25,10 +25,7 @@ mod hello_world {
           INSERT INTO greet VALUES (\"World\");
         ";
 
-        let parsed_queries = parse(queries).expect("Parsing failed");
-        for query in parsed_queries {
-            glue.execute(&query).expect("Execution failed");
-        }
+        glue.execute(queries).expect("Execution failed");
 
         /*
             Select inserted row
@@ -37,9 +34,7 @@ mod hello_world {
           SELECT name FROM greet
         ";
 
-        let parsed_query = &parse(queries).expect("Failed to parse query")[0];
-
-        let result = glue.execute(&parsed_query).expect("Failed to execute");
+        let result = glue.execute(queries).expect("Failed to execute");
 
         /*
             Query results are wrapped into a payload enum, on the basis of the query type
@@ -65,7 +60,10 @@ mod hello_world {
     }
 }
 
+#[cfg(feature = "sled-storage")]
 fn main() {
-    #[cfg(feature = "sled-storage")]
     hello_world::run();
 }
+
+#[cfg(not(feature = "sled-storage"))]
+fn main() {}
diff --git a/examples/sled_multi_threaded.rs b/examples/sled_multi_threaded.rs
index 269aaa74..76c3294c 100644
--- a/examples/sled_multi_threaded.rs
+++ b/examples/sled_multi_threaded.rs
@@ -1,7 +1,7 @@
 #[cfg(feature = "sled-storage")]
 mod sled_multi_threaded {
     use {
-        gluesql::{parse, Glue, Payload, SledStorage, Value},
+        gluesql::{Glue, Payload, SledStorage, Value},
         std::thread,
     };
 
@@ -13,10 +13,8 @@ mod sled_multi_threaded {
           DELETE FROM greet;
         ";
 
-        let parsed_queries = parse(queries).expect("Parsing failed");
-        for query in parsed_queries {
-            glue.execute(&query).expect("Execution failed");
-        }
+        glue.execute(queries).unwrap();
+
         /*
             SledStorage supports cloning, using this we can create copies of the storage for new threads;
               all we need to do is wrap it in glue again.
@@ -24,21 +22,17 @@ mod sled_multi_threaded {
         let foo_storage = storage.clone();
         let foo_thread = thread::spawn(move || {
             let mut glue = Glue::new(foo_storage);
-            let queries = "INSERT INTO greet (name) VALUES (\"Foo\")";
-            let parsed_queries = parse(queries).expect("Parsing failed");
-            for query in parsed_queries {
-                glue.execute(&query).expect("Execution failed");
-            }
+            let query = "INSERT INTO greet (name) VALUES (\"Foo\")";
+
+            glue.execute(query).unwrap();
         });
 
         let world_storage = storage.clone();
         let world_thread = thread::spawn(move || {
             let mut glue = Glue::new(world_storage);
-            let queries = "INSERT INTO greet (name) VALUES (\"World\")";
-            let parsed_queries = parse(queries).expect("Parsing failed");
-            for query in parsed_queries {
-                glue.execute(&query).expect("Execution failed");
-            }
+            let query = "INSERT INTO greet (name) VALUES (\"World\")";
+
+            glue.execute(query).unwrap();
         });
 
         world_thread
@@ -49,13 +43,8 @@ mod sled_multi_threaded {
             .join()
             .expect("Something went wrong in the foo thread");
 
-        let queries = "
-          SELECT name FROM greet
-        ";
-
-        let parsed_query = &parse(queries).expect("Failed to parse query")[0];
-
-        let result = glue.execute(&parsed_query).expect("Failed to execute");
+        let query = "SELECT name FROM greet";
+        let result = glue.execute(query).unwrap();
 
         let rows = match result {
             Payload::Select { labels: _, rows } => rows,
@@ -74,7 +63,10 @@ mod sled_multi_threaded {
     }
 }
 
+#[cfg(feature = "sled-storage")]
 fn main() {
-    #[cfg(feature = "sled-storage")]
     sled_multi_threaded::run();
 }
+
+#[cfg(not(feature = "sled-storage"))]
+fn main() {}
diff --git a/examples/using_config.rs b/examples/using_config.rs
index c9991896..c23549c3 100644
--- a/examples/using_config.rs
+++ b/examples/using_config.rs
@@ -1,8 +1,8 @@
 #[cfg(feature = "sled-storage")]
-use std::convert::TryFrom;
-
-#[cfg(feature = "sled-storage")]
-use gluesql::{parse, sled, Glue, SledStorage};
+use {
+    gluesql::{sled, Glue, SledStorage},
+    std::convert::TryFrom,
+};
 
 #[cfg(feature = "sled-storage")]
 fn main() {
@@ -22,9 +22,7 @@ fn main() {
         DROP TABLE Glue;
     ";
 
-    for query in parse(sqls).unwrap() {
-        glue.execute(&query).unwrap();
-    }
+    glue.execute(sqls).unwrap();
 }
 
 #[cfg(not(feature = "sled-storage"))]
diff --git a/src/ast/ast_literal.rs b/src/ast/ast_literal.rs
new file mode 100644
index 00000000..61e51a9d
--- /dev/null
+++ b/src/ast/ast_literal.rs
@@ -0,0 +1,24 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum AstLiteral {
+    Boolean(bool),
+    Number(String),
+    QuotedString(String),
+    Interval {
+        value: String,
+        leading_field: Option<DateTimeField>,
+        last_field: Option<DateTimeField>,
+    },
+    Null,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum DateTimeField {
+    Year,
+    Month,
+    Day,
+    Hour,
+    Minute,
+    Second,
+}
diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs
new file mode 100644
index 00000000..98bacb92
--- /dev/null
+++ b/src/ast/data_type.rs
@@ -0,0 +1,13 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum DataType {
+    Boolean,
+    Int,
+    Float,
+    Text,
+    Date,
+    Timestamp,
+    Time,
+    Interval,
+}
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
new file mode 100644
index 00000000..e99abb06
--- /dev/null
+++ b/src/ast/ddl.rs
@@ -0,0 +1,47 @@
+use {
+    super::{DataType, Expr, ObjectName},
+    serde::{Deserialize, Serialize},
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum AlterTableOperation {
+    /// `ADD [ COLUMN ] <column_def>`
+    AddColumn { column_def: ColumnDef },
+    /// `DROP [ COLUMN ] [ IF EXISTS ] <column_name> [ CASCADE ]`
+    DropColumn {
+        column_name: String,
+        if_exists: bool,
+    },
+    /// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
+    RenameColumn {
+        old_column_name: String,
+        new_column_name: String,
+    },
+    /// `RENAME TO <table_name>`
+    RenameTable { table_name: ObjectName },
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ColumnDef {
+    pub name: String,
+    pub data_type: DataType,
+    pub options: Vec<ColumnOptionDef>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ColumnOptionDef {
+    pub name: Option<String>,
+    pub option: ColumnOption,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum ColumnOption {
+    /// `NULL`
+    Null,
+    /// `NOT NULL`
+    NotNull,
+    /// `DEFAULT <restricted-expr>`
+    Default(Expr),
+    /// `{ PRIMARY KEY | UNIQUE }`
+    Unique { is_primary: bool },
+}
diff --git a/src/ast/expr.rs b/src/ast/expr.rs
new file mode 100644
index 00000000..be621db4
--- /dev/null
+++ b/src/ast/expr.rs
@@ -0,0 +1,52 @@
+use {
+    super::{AstLiteral, BinaryOperator, DataType, Function, Query, UnaryOperator},
+    serde::{Deserialize, Serialize},
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum Expr {
+    Identifier(String),
+    Wildcard,
+    QualifiedWildcard(Vec<String>),
+    CompoundIdentifier(Vec<String>),
+    IsNull(Box<Expr>),
+    IsNotNull(Box<Expr>),
+    InList {
+        expr: Box<Expr>,
+        list: Vec<Expr>,
+        negated: bool,
+    },
+    InSubquery {
+        expr: Box<Expr>,
+        subquery: Box<Query>,
+        negated: bool,
+    },
+    Between {
+        expr: Box<Expr>,
+        negated: bool,
+        low: Box<Expr>,
+        high: Box<Expr>,
+    },
+    BinaryOp {
+        left: Box<Expr>,
+        op: BinaryOperator,
+        right: Box<Expr>,
+    },
+    UnaryOp {
+        op: UnaryOperator,
+        expr: Box<Expr>,
+    },
+    Cast {
+        expr: Box<Expr>,
+        data_type: DataType,
+    },
+    Nested(Box<Expr>),
+    Literal(AstLiteral),
+    TypedString {
+        data_type: DataType,
+        value: String,
+    },
+    Function(Function),
+    Exists(Box<Query>),
+    Subquery(Box<Query>),
+}
diff --git a/src/ast/function.rs b/src/ast/function.rs
new file mode 100644
index 00000000..8b6cf28f
--- /dev/null
+++ b/src/ast/function.rs
@@ -0,0 +1,16 @@
+use {
+    super::{Expr, ObjectName},
+    serde::{Deserialize, Serialize},
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum FunctionArg {
+    Named { name: String, arg: Expr },
+    Unnamed(Expr),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Function {
+    pub name: ObjectName,
+    pub args: Vec<FunctionArg>,
+}
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
new file mode 100644
index 00000000..296bac8f
--- /dev/null
+++ b/src/ast/mod.rs
@@ -0,0 +1,79 @@
+mod ast_literal;
+mod data_type;
+mod ddl;
+mod expr;
+mod function;
+mod operator;
+mod query;
+
+pub use ast_literal::{AstLiteral, DateTimeField};
+pub use data_type::DataType;
+pub use ddl::*;
+pub use expr::Expr;
+pub use function::{Function, FunctionArg};
+pub use operator::{BinaryOperator, UnaryOperator};
+pub use query::*;
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ObjectName(pub Vec<String>);
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum Statement {
+    /// SELECT
+    Query(Box<Query>),
+    /// INSERT
+    Insert {
+        /// TABLE
+        table_name: ObjectName,
+        /// COLUMNS
+        columns: Vec<String>,
+        /// A SQL query that specifies what to insert
+        source: Box<Query>,
+    },
+    /// UPDATE
+    Update {
+        /// TABLE
+        table_name: ObjectName,
+        /// Column assignments
+        assignments: Vec<Assignment>,
+        /// WHERE
+        selection: Option<Expr>,
+    },
+    /// DELETE
+    Delete {
+        /// FROM
+        table_name: ObjectName,
+        /// WHERE
+        selection: Option<Expr>,
+    },
+    /// CREATE TABLE
+    CreateTable {
+        if_not_exists: bool,
+        /// Table name
+        name: ObjectName,
+        /// Optional schema
+        columns: Vec<ColumnDef>,
+    },
+    /// ALTER TABLE
+    #[cfg(feature = "alter-table")]
+    AlterTable {
+        /// Table name
+        name: ObjectName,
+        operation: AlterTableOperation,
+    },
+    /// DROP
+    DropTable {
+        /// An optional `IF EXISTS` clause. (Non-standard.)
+        if_exists: bool,
+        /// One or more objects to drop. (ANSI SQL requires exactly one.)
+        names: Vec<ObjectName>,
+    },
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Assignment {
+    pub id: String,
+    pub value: Expr,
+}
diff --git a/src/ast/operator.rs b/src/ast/operator.rs
new file mode 100644
index 00000000..852fd0c5
--- /dev/null
+++ b/src/ast/operator.rs
@@ -0,0 +1,25 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum UnaryOperator {
+    Plus,
+    Minus,
+    Not,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum BinaryOperator {
+    Plus,
+    Minus,
+    Multiply,
+    Divide,
+    StringConcat,
+    Gt,
+    Lt,
+    GtEq,
+    LtEq,
+    Eq,
+    NotEq,
+    And,
+    Or,
+}
diff --git a/src/ast/query.rs b/src/ast/query.rs
new file mode 100644
index 00000000..27df510b
--- /dev/null
+++ b/src/ast/query.rs
@@ -0,0 +1,78 @@
+use {
+    super::{Expr, ObjectName},
+    serde::{Deserialize, Serialize},
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Query {
+    pub body: SetExpr,
+    pub limit: Option<Expr>,
+    pub offset: Option<Expr>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum SetExpr {
+    Select(Box<Select>),
+    Values(Values),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Select {
+    pub projection: Vec<SelectItem>,
+    pub from: Vec<TableWithJoins>,
+    /// WHERE
+    pub selection: Option<Expr>,
+    pub group_by: Vec<Expr>,
+    pub having: Option<Expr>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum SelectItem {
+    /// An expression
+    Expr { expr: Expr, label: String },
+    /// `alias.*` or even `schema.table.*`
+    QualifiedWildcard(ObjectName),
+    /// An unqualified `*`
+    Wildcard,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct TableWithJoins {
+    pub relation: TableFactor,
+    pub joins: Vec<Join>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum TableFactor {
+    Table {
+        name: ObjectName,
+        alias: Option<TableAlias>,
+    },
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct TableAlias {
+    pub name: String,
+    pub columns: Vec<String>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Join {
+    pub relation: TableFactor,
+    pub join_operator: JoinOperator,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum JoinOperator {
+    Inner(JoinConstraint),
+    LeftOuter(JoinConstraint),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub enum JoinConstraint {
+    On(Expr),
+    None,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Values(pub Vec<Vec<Expr>>);
diff --git a/src/data/interval/mod.rs b/src/data/interval/mod.rs
index 136dcd93..87f9b944 100644
--- a/src/data/interval/mod.rs
+++ b/src/data/interval/mod.rs
@@ -3,12 +3,11 @@ mod primitive;
 mod string;
 
 use {
-    crate::result::Result,
+    crate::{ast::DateTimeField, result::Result},
     chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike},
     core::str::FromStr,
     rust_decimal::{prelude::ToPrimitive, Decimal},
     serde::{Deserialize, Serialize},
-    sqlparser::ast::DateTimeField,
     std::{cmp::Ordering, fmt::Debug},
 };
 
@@ -281,7 +280,7 @@ impl Interval {
 #[cfg(test)]
 mod tests {
     use super::{Interval, IntervalError};
-    use sqlparser::ast::DateTimeField;
+    use crate::ast::DateTimeField;
 
     #[test]
     fn arithmetic() {
diff --git a/src/data/literal.rs b/src/data/literal.rs
index 91ea1682..84788e57 100644
--- a/src/data/literal.rs
+++ b/src/data/literal.rs
@@ -1,7 +1,9 @@
 use {
-    crate::result::{Error, Result},
+    crate::{
+        ast::{AstLiteral, Expr},
+        result::{Error, Result},
+    },
     serde::Serialize,
-    sqlparser::ast::{Expr, Ident, Value as AstValue},
     std::{borrow::Cow, cmp::Ordering, convert::TryFrom, fmt::Debug},
     thiserror::Error,
     Literal::*,
@@ -9,9 +11,6 @@ use {
 
 #[derive(Error, Serialize, Debug, PartialEq)]
 pub enum LiteralError {
-    #[error("unsupported literal type: {0}")]
-    UnsupportedLiteralType(String),
-
     #[error("unsupported expr: {0}")]
     UnsupportedExpr(String),
 
@@ -37,15 +36,15 @@ pub enum Literal<'a> {
     Null,
 }
 
-impl<'a> TryFrom<&'a AstValue> for Literal<'a> {
+impl<'a> TryFrom<&'a AstLiteral> for Literal<'a> {
     type Error = Error;
 
-    fn try_from(ast_value: &'a AstValue) -> Result<Self> {
-        let literal = match ast_value {
-            AstValue::Boolean(v) => Boolean(*v),
-            AstValue::Number(v, false) => Number(Cow::Borrowed(v)),
-            AstValue::SingleQuotedString(v) => Text(Cow::Borrowed(v)),
-            AstValue::Interval {
+    fn try_from(ast_literal: &'a AstLiteral) -> Result<Self> {
+        let literal = match ast_literal {
+            AstLiteral::Boolean(v) => Boolean(*v),
+            AstLiteral::Number(v) => Number(Cow::Borrowed(v)),
+            AstLiteral::QuotedString(v) => Text(Cow::Borrowed(v)),
+            AstLiteral::Interval {
                 value,
                 leading_field,
                 last_field,
@@ -55,10 +54,7 @@ impl<'a> TryFrom<&'a AstValue> for Literal<'a> {
                 leading_field.as_ref(),
                 last_field.as_ref(),
             )?),
-            AstValue::Null => Null,
-            _ => {
-                return Err(LiteralError::UnsupportedLiteralType(ast_value.to_string()).into());
-            }
+            AstLiteral::Null => Null,
         };
 
         Ok(literal)
@@ -70,10 +66,10 @@ impl<'a> TryFrom<&'a Expr> for Literal<'a> {
 
     fn try_from(expr: &'a Expr) -> Result<Self> {
         match expr {
-            Expr::Value(literal) => Literal::try_from(literal),
+            Expr::Literal(literal) => Literal::try_from(literal),
             // TODO: Expr::TypedString support
-            Expr::Identifier(Ident { value, .. }) => Ok(Literal::Text(Cow::Borrowed(value))),
-            _ => Err(LiteralError::UnsupportedExpr(expr.to_string()).into()),
+            Expr::Identifier(value) => Ok(Literal::Text(Cow::Borrowed(value))),
+            _ => Err(LiteralError::UnsupportedExpr(format!("{:?}", expr)).into()),
         }
     }
 }
diff --git a/src/data/row.rs b/src/data/row.rs
index afc9b9ab..cc536367 100644
--- a/src/data/row.rs
+++ b/src/data/row.rs
@@ -1,11 +1,13 @@
-use serde::{Deserialize, Serialize};
-use std::fmt::Debug;
-use thiserror::Error;
-
-use sqlparser::ast::{ColumnDef, Expr, Ident};
-
-use crate::data::{schema::ColumnDefExt, Value};
-use crate::result::Result;
+use {
+    crate::{
+        ast::{ColumnDef, Expr},
+        data::{schema::ColumnDefExt, Value},
+        result::Result,
+    },
+    serde::{Deserialize, Serialize},
+    std::fmt::Debug,
+    thiserror::Error,
+};
 
 #[derive(Error, Serialize, Debug, PartialEq)]
 pub enum RowError {
@@ -37,7 +39,7 @@ impl Row {
             .ok_or_else(|| RowError::ConflictOnEmptyRow.into())
     }
 
-    pub fn new(column_defs: &[ColumnDef], columns: &[Ident], values: &[Expr]) -> Result<Self> {
+    pub fn new(column_defs: &[ColumnDef], columns: &[String], values: &[Expr]) -> Result<Self> {
         if values.len() > column_defs.len() {
             return Err(RowError::TooManyValues.into());
         }
@@ -53,7 +55,7 @@ impl Row {
 
                 let i = match columns.len() {
                     0 => Some(i),
-                    _ => columns.iter().position(|target| target.value == name),
+                    _ => columns.iter().position(|target| target == &name),
                 };
 
                 let default = column_def.get_default();
diff --git a/src/data/schema.rs b/src/data/schema.rs
index deee494c..9c28b36e 100644
--- a/src/data/schema.rs
+++ b/src/data/schema.rs
@@ -1,6 +1,6 @@
 use {
+    crate::ast::{ColumnDef, ColumnOption, ColumnOptionDef, Expr},
     serde::{Deserialize, Serialize},
-    sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, Expr},
 };
 
 #[derive(Clone, Serialize, Deserialize)]
diff --git a/src/data/table.rs b/src/data/table.rs
index 001894c6..5ce36ef7 100644
--- a/src/data/table.rs
+++ b/src/data/table.rs
@@ -1,18 +1,17 @@
-use serde::Serialize;
-use std::fmt::Debug;
-use thiserror::Error;
-
-use sqlparser::ast::{ObjectName, TableAlias, TableFactor};
-
-use crate::result::Result;
+use {
+    crate::{
+        ast::{ObjectName, TableAlias, TableFactor},
+        result::Result,
+    },
+    serde::Serialize,
+    std::fmt::Debug,
+    thiserror::Error,
+};
 
 #[derive(Error, Serialize, Debug, PartialEq)]
 pub enum TableError {
     #[error("unreachable")]
     Unreachable,
-
-    #[error("TableFactorNotSupported")]
-    TableFactorNotSupported,
 }
 
 pub struct Table<'a> {
@@ -23,13 +22,12 @@ pub struct Table<'a> {
 impl<'a> Table<'a> {
     pub fn new(table_factor: &'a TableFactor) -> Result<Self> {
         match table_factor {
-            TableFactor::Table { name, alias, .. } => {
+            TableFactor::Table { name, alias } => {
                 let name = get_name(name)?;
-                let alias = alias.as_ref().map(|TableAlias { name, .. }| &name.value);
+                let alias = alias.as_ref().map(|TableAlias { name, .. }| name);
 
                 Ok(Self { name, alias })
             }
-            _ => Err(TableError::TableFactorNotSupported.into()),
         }
     }
 
@@ -48,8 +46,5 @@ impl<'a> Table<'a> {
 pub fn get_name(table_name: &ObjectName) -> Result<&String> {
     let ObjectName(idents) = table_name;
 
-    idents
-        .last()
-        .map(|ident| &ident.value)
-        .ok_or_else(|| TableError::Unreachable.into())
+    idents.last().ok_or_else(|| TableError::Unreachable.into())
 }
diff --git a/src/data/value/literal.rs b/src/data/value/literal.rs
index 1c3d1f45..91692bf3 100644
--- a/src/data/value/literal.rs
+++ b/src/data/value/literal.rs
@@ -1,11 +1,11 @@
 use {
     super::{error::ValueError, Value},
     crate::{
+        ast::DataType,
         data::Literal,
         result::{Error, Result},
     },
     chrono::{offset::Utc, DateTime, NaiveDate, NaiveDateTime, NaiveTime},
-    sqlparser::ast::DataType,
     std::{cmp::Ordering, convert::TryFrom},
 };
 
@@ -124,7 +124,7 @@ impl Value {
                 .parse::<i64>()
                 .map(Value::I64)
                 .map_err(|_| ValueError::FailedToParseNumber.into()),
-            (DataType::Float(_), Literal::Number(v)) => v
+            (DataType::Float, Literal::Number(v)) => v
                 .parse::<f64>()
                 .map(Value::F64)
                 .map_err(|_| ValueError::UnreachableNumberParsing.into()),
@@ -142,14 +142,14 @@ impl Value {
             (DataType::Interval, Literal::Interval(v)) => Ok(Value::Interval(*v)),
             (DataType::Boolean, Literal::Null)
             | (DataType::Int, Literal::Null)
-            | (DataType::Float(_), Literal::Null)
+            | (DataType::Float, Literal::Null)
             | (DataType::Text, Literal::Null)
             | (DataType::Date, Literal::Null)
             | (DataType::Timestamp, Literal::Null)
             | (DataType::Time, Literal::Null)
             | (DataType::Interval, Literal::Null) => Ok(Value::Null),
             _ => Err(ValueError::IncompatibleLiteralForDataType {
-                data_type: data_type.to_string(),
+                data_type: format!("{:?}", data_type),
                 literal: format!("{:?}", literal),
             }
             .into()),
@@ -181,11 +181,11 @@ impl Value {
 
                 Ok(Value::I64(v))
             }
-            (DataType::Float(_), Literal::Text(v)) | (DataType::Float(_), Literal::Number(v)) => v
+            (DataType::Float, Literal::Text(v)) | (DataType::Float, Literal::Number(v)) => v
                 .parse::<f64>()
                 .map(Value::F64)
                 .map_err(|_| ValueError::LiteralCastToFloatFailed(v.to_string()).into()),
-            (DataType::Float(_), Literal::Boolean(v)) => {
+            (DataType::Float, Literal::Boolean(v)) => {
                 let v = if *v { 1.0 } else { 0.0 };
 
                 Ok(Value::F64(v))
@@ -200,10 +200,10 @@ impl Value {
             }
             (DataType::Boolean, Literal::Null)
             | (DataType::Int, Literal::Null)
-            | (DataType::Float(_), Literal::Null)
+            | (DataType::Float, Literal::Null)
             | (DataType::Text, Literal::Null) => Ok(Value::Null),
             _ => Err(ValueError::UnimplementedLiteralCast {
-                data_type: data_type.to_string(),
+                data_type: format!("{:?}", data_type),
                 literal: format!("{:?}", literal),
             }
             .into()),
diff --git a/src/data/value/mod.rs b/src/data/value/mod.rs
index 8d11dd24..56c5703a 100644
--- a/src/data/value/mod.rs
+++ b/src/data/value/mod.rs
@@ -1,10 +1,12 @@
 use {
     super::{Interval, Literal},
-    crate::result::Result,
+    crate::{
+        ast::{DataType, Expr},
+        result::Result,
+    },
     chrono::{NaiveDate, NaiveDateTime, NaiveTime},
     core::ops::Sub,
     serde::{Deserialize, Serialize},
-    sqlparser::ast::{DataType, Expr},
     std::{
         cmp::Ordering,
         convert::{TryFrom, TryInto},
@@ -76,7 +78,7 @@ impl PartialOrd<Value> for Value {
 impl Value {
     pub fn from_expr(data_type: &DataType, nullable: bool, expr: &Expr) -> Result<Self> {
         let literal = Literal::try_from(expr)?;
-        let value = Value::try_from_literal(&data_type, &literal)?;
+        let value = Value::try_from_literal(data_type, &literal)?;
 
         value.validate_null(nullable)?;
 
@@ -88,14 +90,14 @@ impl Value {
             (data_type, self),
             (DataType::Boolean, Value::Bool(_))
                 | (DataType::Int, Value::I64(_))
-                | (DataType::Float(_), Value::F64(_))
+                | (DataType::Float, Value::F64(_))
                 | (DataType::Text, Value::Str(_))
                 | (DataType::Date, Value::Date(_))
                 | (DataType::Timestamp, Value::Timestamp(_))
                 | (DataType::Interval, Value::Interval(_))
                 | (DataType::Boolean, Value::Null)
                 | (DataType::Int, Value::Null)
-                | (DataType::Float(_), Value::Null)
+                | (DataType::Float, Value::Null)
                 | (DataType::Text, Value::Null)
                 | (DataType::Date, Value::Null)
                 | (DataType::Timestamp, Value::Null)
@@ -105,7 +107,7 @@ impl Value {
 
         if !valid {
             return Err(ValueError::IncompatibleDataType {
-                data_type: data_type.to_string(),
+                data_type: format!("{:?}", data_type),
                 value: format!("{:?}", self),
             }
             .into());
@@ -126,7 +128,7 @@ impl Value {
         match (data_type, self) {
             (DataType::Boolean, Value::Bool(_))
             | (DataType::Int, Value::I64(_))
-            | (DataType::Float(_), Value::F64(_))
+            | (DataType::Float, Value::F64(_))
             | (DataType::Text, Value::Str(_))
             | (DataType::Date, Value::Date(_))
             | (DataType::Timestamp, Value::Timestamp(_))
@@ -137,7 +139,7 @@ impl Value {
 
             (DataType::Boolean, value) => value.try_into().map(Value::Bool),
             (DataType::Int, value) => value.try_into().map(Value::I64),
-            (DataType::Float(_), value) => value.try_into().map(Value::F64),
+            (DataType::Float, value) => value.try_into().map(Value::F64),
             (DataType::Text, value) => Ok(Value::Str(value.into())),
             (DataType::Date, value) => value.try_into().map(Value::Date),
             (DataType::Timestamp, value) => value.try_into().map(Value::Timestamp),
@@ -535,7 +537,10 @@ mod tests {
 
     #[test]
     fn cast() {
-        use {crate::Value, chrono::NaiveDate, sqlparser::ast::DataType::*};
+        use {
+            crate::{ast::DataType::*, Value},
+            chrono::NaiveDate,
+        };
 
         macro_rules! cast {
             ($input: expr => $data_type: expr, $expected: expr) => {
@@ -554,7 +559,7 @@ mod tests {
         cast!(Bool(true)            => Boolean      , Bool(true));
         cast!(Str("a".to_owned())   => Text         , Str("a".to_owned()));
         cast!(I64(1)                => Int          , I64(1));
-        cast!(F64(1.0)              => Float(None)  , F64(1.0));
+        cast!(F64(1.0)              => Float        , F64(1.0));
 
         // Boolean
         cast!(Str("TRUE".to_owned())    => Boolean, Bool(true));
@@ -573,11 +578,11 @@ mod tests {
         cast!(Null                  => Int, Null);
 
         // Float
-        cast!(Bool(true)            => Float(None), F64(1.0));
-        cast!(Bool(false)           => Float(None), F64(0.0));
-        cast!(I64(1)                => Float(None), F64(1.0));
-        cast!(Str("11".to_owned())  => Float(None), F64(11.0));
-        cast!(Null                  => Float(None), Null);
+        cast!(Bool(true)            => Float, F64(1.0));
+        cast!(Bool(false)           => Float, F64(0.0));
+        cast!(I64(1)                => Float, F64(1.0));
+        cast!(Str("11".to_owned())  => Float, F64(11.0));
+        cast!(Null                  => Float, Null);
 
         // Text
         cast!(Bool(true)    => Text, Str("TRUE".to_owned()));
diff --git a/src/executor/aggregate/mod.rs b/src/executor/aggregate/mod.rs
index 1458c6ea..3032c60d 100644
--- a/src/executor/aggregate/mod.rs
+++ b/src/executor/aggregate/mod.rs
@@ -2,25 +2,25 @@ mod error;
 mod hash;
 mod state;
 
-use boolinator::Boolinator;
-use futures::stream::{self, StreamExt, TryStream, TryStreamExt};
-use std::convert::TryFrom;
-use std::fmt::Debug;
-use std::pin::Pin;
-use std::rc::Rc;
+use {
+    self::state::State,
+    super::{
+        context::{AggregateContext, BlendContext, FilterContext},
+        evaluate::{evaluate, Evaluated},
+        filter::check_expr,
+    },
+    crate::{
+        ast::{Expr, Function, FunctionArg, SelectItem},
+        data::{get_name, Value},
+        result::{Error, Result},
+        store::Store,
+    },
+    boolinator::Boolinator,
+    futures::stream::{self, StreamExt, TryStream, TryStreamExt},
+    std::{convert::TryFrom, fmt::Debug, pin::Pin, rc::Rc},
+};
 
-use sqlparser::ast::{Expr, Function, FunctionArg, SelectItem};
-
-use super::context::{AggregateContext, BlendContext, FilterContext};
-use super::evaluate::{evaluate, Evaluated};
-use super::filter::check_expr;
-use crate::data::{get_name, Value};
-use crate::result::{Error, Result};
-use crate::store::Store;
-
-pub use error::AggregateError;
-pub use hash::GroupKey;
-use state::State;
+pub use {error::AggregateError, hash::GroupKey};
 
 pub struct Aggregate<'a, T: 'static + Debug> {
     storage: &'a dyn Store<T>,
@@ -93,9 +93,7 @@ impl<'a, T: 'static + Debug> Aggregate<'a, T> {
                     .fields
                     .iter()
                     .try_fold(state, |state, field| match field {
-                        SelectItem::UnnamedExpr(expr) | SelectItem::ExprWithAlias { expr, .. } => {
-                            aggregate(state, &blend_context, &expr)
-                        }
+                        SelectItem::Expr { expr, .. } => aggregate(state, &blend_context, &expr),
                         _ => Ok(state),
                     })?;
 
@@ -156,8 +154,7 @@ impl<'a, T: 'static + Debug> Aggregate<'a, T> {
         self.fields
             .iter()
             .map(|field| match field {
-                SelectItem::UnnamedExpr(expr) => check(expr),
-                SelectItem::ExprWithAlias { expr, .. } => check(expr),
+                SelectItem::Expr { expr, .. } => check(expr),
                 _ => Ok(false),
             })
             .collect::<Result<Vec<bool>>>()
@@ -173,17 +170,18 @@ fn aggregate<'a>(
     let aggr = |state, expr| aggregate(state, context, expr);
     let get_value = |expr: &Expr| match expr {
         Expr::Identifier(ident) => context
-            .get_value(&ident.value)
-            .ok_or_else(|| AggregateError::ValueNotFound(ident.value.to_string())),
+            .get_value(&ident)
+            .ok_or_else(|| AggregateError::ValueNotFound(ident.to_string())),
         Expr::CompoundIdentifier(idents) => {
             if idents.len() != 2 {
-                return Err(AggregateError::UnsupportedCompoundIdentifier(
-                    expr.to_string(),
-                ));
+                return Err(AggregateError::UnsupportedCompoundIdentifier(format!(
+                    "{:?}",
+                    expr
+                )));
             }
 
-            let table_alias = &idents[0].value;
-            let column = &idents[1].value;
+            let table_alias = &idents[0];
+            let column = &idents[1];
 
             context
                 .get_alias_value(table_alias, column)
diff --git a/src/executor/aggregate/state.rs b/src/executor/aggregate/state.rs
index c7c69578..8da9ca2c 100644
--- a/src/executor/aggregate/state.rs
+++ b/src/executor/aggregate/state.rs
@@ -1,16 +1,16 @@
-use im_rc::{HashMap, HashSet};
-use itertools::Itertools;
-use std::cmp::Ordering;
-use std::rc::Rc;
-
-use sqlparser::ast::Function;
-
-use crate::utils::{IndexMap, Vector};
-
-use super::hash::GroupKey;
-use crate::data::Value;
-use crate::executor::context::BlendContext;
-use crate::result::Result;
+use {
+    super::hash::GroupKey,
+    crate::{
+        ast::Function,
+        data::Value,
+        executor::context::BlendContext,
+        result::Result,
+        utils::{IndexMap, Vector},
+    },
+    im_rc::{HashMap, HashSet},
+    itertools::Itertools,
+    std::{cmp::Ordering, rc::Rc},
+};
 
 type Group = Rc<Vec<GroupKey>>;
 type ValuesMap<'a> = HashMap<&'a Function, Value>;
diff --git a/src/executor/alter/alter_table.rs b/src/executor/alter/alter_table.rs
index 5c19033e..7d548015 100644
--- a/src/executor/alter/alter_table.rs
+++ b/src/executor/alter/alter_table.rs
@@ -1,11 +1,11 @@
 use {
-    super::{validate, AlterError},
+    super::validate,
     crate::{
+        ast::{AlterTableOperation, ObjectName},
         data::get_name,
         result::MutResult,
         store::{AlterTable, Store, StoreMut},
     },
-    sqlparser::ast::{AlterTableOperation, ObjectName},
     std::fmt::Debug,
 };
 
@@ -40,7 +40,7 @@ pub async fn alter_table<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTa
             new_column_name,
         } => {
             storage
-                .rename_column(table_name, &old_column_name.value, &new_column_name.value)
+                .rename_column(table_name, old_column_name, new_column_name)
                 .await
         }
         AlterTableOperation::AddColumn { column_def } => {
@@ -51,15 +51,10 @@ pub async fn alter_table<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTa
         AlterTableOperation::DropColumn {
             column_name,
             if_exists,
-            ..
         } => {
             storage
-                .drop_column(table_name, &column_name.value, *if_exists)
+                .drop_column(table_name, column_name, *if_exists)
                 .await
         }
-        _ => Err((
-            storage,
-            AlterError::UnsupportedAlterTableOperation(operation.to_string()).into(),
-        )),
     }
 }
diff --git a/src/executor/alter/create_table.rs b/src/executor/alter/create_table.rs
index 7b31673e..6714d156 100644
--- a/src/executor/alter/create_table.rs
+++ b/src/executor/alter/create_table.rs
@@ -1,11 +1,11 @@
 use {
     super::{validate, AlterError},
     crate::{
+        ast::{ColumnDef, ObjectName},
         data::{get_name, Schema},
         result::MutResult,
         store::{AlterTable, Store, StoreMut},
     },
-    sqlparser::ast::{ColumnDef, ObjectName},
     std::fmt::Debug,
 };
 
diff --git a/src/executor/alter/drop.rs b/src/executor/alter/drop.rs
index cfb9f380..eeea16ef 100644
--- a/src/executor/alter/drop.rs
+++ b/src/executor/alter/drop.rs
@@ -1,28 +1,20 @@
 use {
     super::AlterError,
     crate::{
+        ast::ObjectName,
         data::get_name,
         result::MutResult,
         store::{AlterTable, Store, StoreMut},
     },
     futures::stream::{self, TryStreamExt},
-    sqlparser::ast::{ObjectName, ObjectType},
     std::fmt::Debug,
 };
 
 pub async fn drop<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>(
     storage: U,
-    object_type: &ObjectType,
     names: &[ObjectName],
     if_exists: bool,
 ) -> MutResult<U, ()> {
-    if object_type != &ObjectType::Table {
-        return Err((
-            storage,
-            AlterError::DropTypeNotSupported(object_type.to_string()).into(),
-        ));
-    }
-
     stream::iter(names.iter().map(Ok))
         .try_fold((storage, ()), |(storage, _), table_name| async move {
             let schema = (|| async {
diff --git a/src/executor/alter/error.rs b/src/executor/alter/error.rs
index ab039c51..79e186e0 100644
--- a/src/executor/alter/error.rs
+++ b/src/executor/alter/error.rs
@@ -6,25 +6,11 @@ pub enum AlterError {
     #[error("table already exists: {0}")]
     TableAlreadyExists(String),
 
-    // ALTER TABLE
-    #[cfg(feature = "alter-table")]
-    #[error("unsupported alter table operation: {0}")]
-    UnsupportedAlterTableOperation(String),
-
     // DROP
-    #[error("drop type not supported: {0}")]
-    DropTypeNotSupported(String),
-
     #[error("table does not exist: {0}")]
     TableNotFound(String),
 
     // validate column def
-    #[error("unsupported data type: {0}")]
-    UnsupportedDataType(String),
-
-    #[error("unsupported column option: {0}")]
-    UnsupportedColumnOption(String),
-
     #[error("column '{0}' of data type '{1}' is unsupported for unique constraint")]
     UnsupportedDataTypeForUniqueColumn(String, String),
 }
diff --git a/src/executor/alter/validate.rs b/src/executor/alter/validate.rs
index 7cc55c62..f6b15747 100644
--- a/src/executor/alter/validate.rs
+++ b/src/executor/alter/validate.rs
@@ -1,7 +1,9 @@
 use {
     super::AlterError,
-    crate::result::Result,
-    sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, DataType},
+    crate::{
+        ast::{ColumnDef, ColumnOption, ColumnOptionDef, DataType},
+        result::Result,
+    },
 };
 
 pub fn validate(column_def: &ColumnDef) -> Result<()> {
@@ -12,43 +14,15 @@ pub fn validate(column_def: &ColumnDef) -> Result<()> {
         ..
     } = column_def;
 
-    // data type
-    if !matches!(
-        data_type,
-        DataType::Boolean
-            | DataType::Int
-            | DataType::Float(_)
-            | DataType::Text
-            | DataType::Date
-            | DataType::Timestamp
-            | DataType::Time
-            | DataType::Interval
-    ) {
-        return Err(AlterError::UnsupportedDataType(data_type.to_string()).into());
-    }
-
-    // column option
-    if let Some(option) = options.iter().find(|ColumnOptionDef { option, .. }| {
-        !matches!(
-            option,
-            ColumnOption::Null
-                | ColumnOption::NotNull
-                | ColumnOption::Default(_)
-                | ColumnOption::Unique { .. }
-        )
-    }) {
-        return Err(AlterError::UnsupportedColumnOption(option.to_string()).into());
-    }
-
     // unique + data type
-    if matches!(data_type, DataType::Float(_))
+    if matches!(data_type, DataType::Float)
         && options
             .iter()
             .any(|ColumnOptionDef { option, .. }| matches!(option, ColumnOption::Unique { .. }))
     {
         return Err(AlterError::UnsupportedDataTypeForUniqueColumn(
             name.to_string(),
-            data_type.to_string(),
+            format!("{:?}", data_type),
         )
         .into());
     }
diff --git a/src/executor/blend.rs b/src/executor/blend.rs
index 6f2473dd..14e02c58 100644
--- a/src/executor/blend.rs
+++ b/src/executor/blend.rs
@@ -1,18 +1,21 @@
-use futures::stream::{self, StreamExt, TryStreamExt};
-use im_rc::HashMap;
-use serde::Serialize;
-use std::convert::TryInto;
-use std::fmt::Debug;
-use std::rc::Rc;
-use thiserror::Error as ThisError;
-
-use sqlparser::ast::{Function, SelectItem};
-
-use super::context::{AggregateContext, BlendContext, FilterContext};
-use super::evaluate::evaluate;
-use crate::data::{get_name, Row, Value};
-use crate::result::{Error, Result};
-use crate::store::Store;
+use {
+    super::{
+        context::{AggregateContext, BlendContext, FilterContext},
+        evaluate::evaluate,
+    },
+    crate::{
+        ast::{Function, SelectItem},
+        data::{get_name, Row, Value},
+        result::{Error, Result},
+        store::Store,
+    },
+    futures::stream::{self, StreamExt, TryStreamExt},
+    im_rc::HashMap,
+    serde::Serialize,
+    std::convert::TryInto,
+    std::{fmt::Debug, rc::Rc},
+    thiserror::Error as ThisError,
+};
 
 #[derive(ThisError, Serialize, Debug, PartialEq)]
 pub enum BlendError {
@@ -68,7 +71,7 @@ impl<'a, T: 'static + Debug> Blend<'a, T> {
                                 }
                             }
                         }
-                        SelectItem::UnnamedExpr(expr) | SelectItem::ExprWithAlias { expr, .. } => {
+                        SelectItem::Expr { expr, .. } => {
                             evaluate(self.storage, filter_context, aggregated, expr, true)
                                 .await
                                 .map(|evaluated| evaluated.try_into())?
diff --git a/src/executor/context/aggregate_context.rs b/src/executor/context/aggregate_context.rs
index 6e8cc7da..df5b5975 100644
--- a/src/executor/context/aggregate_context.rs
+++ b/src/executor/context/aggregate_context.rs
@@ -1,11 +1,9 @@
-use im_rc::HashMap;
-use std::fmt::Debug;
-use std::rc::Rc;
-
-use sqlparser::ast::Function;
-
-use super::BlendContext;
-use crate::data::Value;
+use {
+    super::BlendContext,
+    crate::{ast::Function, data::Value},
+    im_rc::HashMap,
+    std::{fmt::Debug, rc::Rc},
+};
 
 #[derive(Debug)]
 pub struct AggregateContext<'a> {
diff --git a/src/executor/context/blend_context.rs b/src/executor/context/blend_context.rs
index 77288a5b..2d289b98 100644
--- a/src/executor/context/blend_context.rs
+++ b/src/executor/context/blend_context.rs
@@ -1,14 +1,12 @@
-use std::fmt::Debug;
-use std::rc::Rc;
-
-use sqlparser::ast::Ident;
-
-use crate::data::{Row, Value};
+use {
+    crate::data::{Row, Value},
+    std::{fmt::Debug, rc::Rc},
+};
 
 #[derive(Debug)]
 pub struct BlendContext<'a> {
     table_alias: &'a str,
-    columns: Rc<[Ident]>,
+    columns: Rc<[String]>,
     row: Option<Row>,
     next: Option<Rc<BlendContext<'a>>>,
 }
@@ -16,7 +14,7 @@ pub struct BlendContext<'a> {
 impl<'a> BlendContext<'a> {
     pub fn new(
         table_alias: &'a str,
-        columns: Rc<[Ident]>,
+        columns: Rc<[String]>,
         row: Option<Row>,
         next: Option<Rc<BlendContext<'a>>>,
     ) -> Self {
@@ -32,7 +30,7 @@ impl<'a> BlendContext<'a> {
         let get_value = || {
             self.columns
                 .iter()
-                .position(|column| column.value == target)
+                .position(|column| column == target)
                 .map(|index| self.row.as_ref().and_then(|row| row.get_value(index)))
         };
 
@@ -53,7 +51,7 @@ impl<'a> BlendContext<'a> {
 
             self.columns
                 .iter()
-                .position(|column| column.value == target)
+                .position(|column| column == target)
                 .map(|index| self.row.as_ref().and_then(|row| row.get_value(index)))
         };
 
diff --git a/src/executor/context/filter_context.rs b/src/executor/context/filter_context.rs
index 386bd13c..eda7e783 100644
--- a/src/executor/context/filter_context.rs
+++ b/src/executor/context/filter_context.rs
@@ -1,16 +1,14 @@
-use std::fmt::Debug;
-use std::rc::Rc;
-
-use sqlparser::ast::Ident;
-
-use super::BlendContext;
-use crate::data::{Row, Value};
+use {
+    super::BlendContext,
+    crate::data::{Row, Value},
+    std::{fmt::Debug, rc::Rc},
+};
 
 #[derive(Debug)]
 enum Content<'a> {
     Some {
         table_alias: &'a str,
-        columns: Rc<[Ident]>,
+        columns: Rc<[String]>,
         row: Option<&'a Row>,
     },
     None,
@@ -26,7 +24,7 @@ pub struct FilterContext<'a> {
 impl<'a> FilterContext<'a> {
     pub fn new(
         table_alias: &'a str,
-        columns: Rc<[Ident]>,
+        columns: Rc<[String]>,
         row: Option<&'a Row>,
         next: Option<Rc<FilterContext<'a>>>,
     ) -> Self {
@@ -56,7 +54,7 @@ impl<'a> FilterContext<'a> {
         if let Content::Some { columns, row, .. } = &self.content {
             let value = columns
                 .iter()
-                .position(|column| column.value == target)
+                .position(|column| column == target)
                 .map(|index| row.and_then(|row| row.get_value(index)));
 
             if let Some(value) = value {
@@ -89,7 +87,7 @@ impl<'a> FilterContext<'a> {
 
                 columns
                     .iter()
-                    .position(|column| column.value == target)
+                    .position(|column| column == target)
                     .map(|index| row.and_then(|row| row.get_value(index)))
             };
 
diff --git a/src/executor/evaluate/evaluated.rs b/src/executor/evaluate/evaluated.rs
index 72a1e111..ff345330 100644
--- a/src/executor/evaluate/evaluated.rs
+++ b/src/executor/evaluate/evaluated.rs
@@ -1,10 +1,10 @@
 use {
     super::error::EvaluateError,
     crate::{
+        ast::DataType,
         data::{Literal, Value},
         result::{Error, Result},
     },
-    sqlparser::ast::DataType,
     std::{
         borrow::Cow,
         cmp::Ordering,
diff --git a/src/executor/evaluate/mod.rs b/src/executor/evaluate/mod.rs
index 1da2b656..496bb0a5 100644
--- a/src/executor/evaluate/mod.rs
+++ b/src/executor/evaluate/mod.rs
@@ -4,6 +4,7 @@ mod evaluated;
 use {
     super::{context::FilterContext, select::select},
     crate::{
+        ast::{BinaryOperator, Expr, Function, FunctionArg, UnaryOperator},
         data::{get_name, Literal, Value},
         result::Result,
         store::Store,
@@ -12,7 +13,6 @@ use {
     boolinator::Boolinator,
     futures::stream::{self, StreamExt, TryStreamExt},
     im_rc::HashMap,
-    sqlparser::ast::{BinaryOperator, Expr, Function, FunctionArg, UnaryOperator},
     std::{
         borrow::Cow,
         convert::{TryFrom, TryInto},
@@ -39,35 +39,32 @@ pub async fn evaluate<'a, T: 'static + Debug>(
     };
 
     match expr {
-        Expr::Value(ast_value) => Literal::try_from(ast_value).map(Evaluated::Literal),
+        Expr::Literal(ast_literal) => Literal::try_from(ast_literal).map(Evaluated::Literal),
         Expr::TypedString { data_type, value } => {
             let literal = Literal::Text(Cow::Borrowed(value));
 
             Value::try_from_literal(&data_type, &literal).map(Evaluated::from)
         }
-        Expr::Identifier(ident) => match ident.quote_style {
-            Some(_) => Ok(Literal::Text(Cow::Borrowed(&ident.value))).map(Evaluated::Literal),
-            None => {
-                let context = context.ok_or(EvaluateError::UnreachableEmptyContext)?;
+        Expr::Identifier(ident) => {
+            let context = context.ok_or(EvaluateError::UnreachableEmptyContext)?;
 
-                match (context.get_value(&ident.value), use_empty) {
-                    (Some(value), _) => Ok(value.clone()),
-                    (None, true) => Ok(Value::Null),
-                    (None, false) => {
-                        Err(EvaluateError::ValueNotFound(ident.value.to_string()).into())
-                    }
-                }
-                .map(Evaluated::from)
+            match (context.get_value(&ident), use_empty) {
+                (Some(value), _) => Ok(value.clone()),
+                (None, true) => Ok(Value::Null),
+                (None, false) => Err(EvaluateError::ValueNotFound(ident.to_string()).into()),
             }
-        },
+            .map(Evaluated::from)
+        }
         Expr::Nested(expr) => eval(&expr).await,
         Expr::CompoundIdentifier(idents) => {
             if idents.len() != 2 {
-                return Err(EvaluateError::UnsupportedCompoundIdentifier(expr.to_string()).into());
+                return Err(
+                    EvaluateError::UnsupportedCompoundIdentifier(format!("{:?}", expr)).into(),
+                );
             }
 
-            let table_alias = &idents[0].value;
-            let column = &idents[1].value;
+            let table_alias = &idents[0];
+            let column = &idents[1];
             let context = context.ok_or(EvaluateError::UnreachableEmptyContext)?;
 
             match (context.get_alias_value(table_alias, column), use_empty) {
@@ -120,7 +117,6 @@ pub async fn evaluate<'a, T: 'static + Debug>(
                 BinaryOperator::GtEq => cmp!(l >= r),
                 BinaryOperator::And => cond!(l && r),
                 BinaryOperator::Or => cond!(l || r),
-                _ => Err(EvaluateError::Unimplemented.into()),
             }
         }
         Expr::UnaryOp { op, expr } => {
@@ -130,7 +126,6 @@ pub async fn evaluate<'a, T: 'static + Debug>(
                 UnaryOperator::Plus => v.unary_plus(),
                 UnaryOperator::Minus => v.unary_minus(),
                 UnaryOperator::Not => v.try_into().map(|v: bool| Evaluated::from(Value::Bool(!v))),
-                _ => Err(EvaluateError::Unimplemented.into()),
             }
         }
         Expr::Function(func) => match aggregated.as_ref().map(|aggr| aggr.get(func)).flatten() {
diff --git a/src/executor/execute.rs b/src/executor/execute.rs
index f533cf8e..da65363d 100644
--- a/src/executor/execute.rs
+++ b/src/executor/execute.rs
@@ -1,34 +1,30 @@
-use futures::stream::TryStreamExt;
-use serde::Serialize;
-use std::fmt::Debug;
-use std::rc::Rc;
-use thiserror::Error as ThisError;
-
-use sqlparser::ast::{SetExpr, Statement, Values};
-
-use crate::data::{get_name, Row, Schema};
-use crate::parse_sql::Query;
-use crate::result::{MutResult, Result};
-use crate::store::{AlterTable, Store, StoreMut};
+use {
+    super::{
+        alter::{create_table, drop},
+        fetch::{fetch, fetch_columns},
+        select::{select, select_with_labels},
+        update::Update,
+        validate::{validate_unique, ColumnValidation},
+    },
+    crate::{
+        ast::{Query, SetExpr, Statement, Values},
+        data::{get_name, Row, Schema},
+        result::{MutResult, Result},
+        store::{AlterTable, Store, StoreMut},
+    },
+    futures::stream::TryStreamExt,
+    serde::Serialize,
+    std::{fmt::Debug, rc::Rc},
+    thiserror::Error as ThisError,
+};
 
 #[cfg(feature = "alter-table")]
 use super::alter::alter_table;
-use super::alter::{create_table, drop};
-use super::fetch::{fetch, fetch_columns};
-use super::select::{select, select_with_labels};
-use super::update::Update;
-use super::validate::{validate_unique, ColumnValidation};
 
 #[derive(ThisError, Serialize, Debug, PartialEq)]
 pub enum ExecuteError {
-    #[error("query not supported")]
-    QueryNotSupported,
-
-    #[error("unsupported insert value type: {0}")]
-    UnreachableUnsupportedInsertValueType(String),
-
-    #[error("table does not exist")]
-    TableNotExists,
+    #[error("table not found: {0}")]
+    TableNotFound(String),
 }
 
 #[derive(Serialize, Debug, PartialEq)]
@@ -49,7 +45,7 @@ pub enum Payload {
 
 pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>(
     storage: U,
-    query: &Query,
+    statement: &Statement,
 ) -> MutResult<U, Payload> {
     macro_rules! try_block {
         ($storage: expr, $block: block) => {{
@@ -62,9 +58,7 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
         }};
     }
 
-    let Query(query) = query;
-
-    match query {
+    match statement {
         //- Modification
         //-- Tables
         Statement::CreateTable {
@@ -75,12 +69,9 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
         } => create_table(storage, name, columns, *if_not_exists)
             .await
             .map(|(storage, _)| (storage, Payload::Create)),
-        Statement::Drop {
-            object_type,
-            names,
-            if_exists,
-            ..
-        } => drop(storage, object_type, names, *if_exists)
+        Statement::DropTable {
+            names, if_exists, ..
+        } => drop(storage, names, *if_exists)
             .await
             .map(|(storage, _)| (storage, Payload::DropTable)),
         #[cfg(feature = "alter-table")]
@@ -100,7 +91,7 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
                 let Schema { column_defs, .. } = storage
                     .fetch_schema(table_name)
                     .await?
-                    .ok_or(ExecuteError::TableNotExists)?;
+                    .ok_or_else(|| ExecuteError::TableNotFound(table_name.to_owned()))?;
                 let column_defs = Rc::from(column_defs);
                 let column_validation = ColumnValidation::All(Rc::clone(&column_defs));
 
@@ -110,13 +101,10 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
                         .map(|values| Row::new(&column_defs, columns, values))
                         .collect::<Result<Vec<Row>>>()?,
                     SetExpr::Select(select_query) => {
-                        let query = || sqlparser::ast::Query {
-                            with: None,
+                        let query = || Query {
                             body: SetExpr::Select(select_query.clone()),
-                            order_by: vec![],
                             limit: None,
                             offset: None,
-                            fetch: None,
                         };
 
                         select(&storage, &query(), None)
@@ -133,12 +121,6 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
                             .try_collect::<Vec<_>>()
                             .await?
                     }
-                    set_expr => {
-                        return Err(ExecuteError::UnreachableUnsupportedInsertValueType(
-                            set_expr.to_string(),
-                        )
-                        .into());
-                    }
                 };
 
                 validate_unique(&storage, &table_name, column_validation, rows.iter()).await?;
@@ -163,7 +145,7 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
                 let Schema { column_defs, .. } = storage
                     .fetch_schema(table_name)
                     .await?
-                    .ok_or(ExecuteError::TableNotExists)?;
+                    .ok_or_else(|| ExecuteError::TableNotFound(table_name.to_owned()))?;
                 let update = Update::new(&storage, table_name, assignments, &column_defs)?;
 
                 let all_columns = Rc::from(update.all_columns());
@@ -234,6 +216,5 @@ pub async fn execute<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>
 
             Ok((storage, Payload::Select { labels, rows }))
         }
-        _ => Err((storage, ExecuteError::QueryNotSupported.into())),
     }
 }
diff --git a/src/executor/fetch.rs b/src/executor/fetch.rs
index 70ce8427..85093a08 100644
--- a/src/executor/fetch.rs
+++ b/src/executor/fetch.rs
@@ -1,17 +1,17 @@
-use boolinator::Boolinator;
-use futures::stream::{self, TryStream, TryStreamExt};
-use serde::Serialize;
-use std::fmt::Debug;
-use std::rc::Rc;
-use thiserror::Error as ThisError;
-
-use sqlparser::ast::{ColumnDef, Expr, Ident};
-
-use super::context::FilterContext;
-use super::filter::check_expr;
-use crate::data::Row;
-use crate::result::{Error, Result};
-use crate::store::Store;
+use {
+    super::{context::FilterContext, filter::check_expr},
+    crate::{
+        ast::{ColumnDef, Expr},
+        data::Row,
+        result::{Error, Result},
+        store::Store,
+    },
+    boolinator::Boolinator,
+    futures::stream::{self, TryStream, TryStreamExt},
+    serde::Serialize,
+    std::{fmt::Debug, rc::Rc},
+    thiserror::Error as ThisError,
+};
 
 #[derive(ThisError, Serialize, Debug, PartialEq)]
 pub enum FetchError {
@@ -22,7 +22,7 @@ pub enum FetchError {
 pub async fn fetch_columns<T: 'static + Debug>(
     storage: &dyn Store<T>,
     table_name: &str,
-) -> Result<Vec<Ident>> {
+) -> Result<Vec<String>> {
     Ok(storage
         .fetch_schema(table_name)
         .await?
@@ -30,15 +30,15 @@ pub async fn fetch_columns<T: 'static + Debug>(
         .column_defs
         .into_iter()
         .map(|ColumnDef { name, .. }| name)
-        .collect::<Vec<Ident>>())
+        .collect::<Vec<String>>())
 }
 
 pub async fn fetch<'a, T: 'static + Debug>(
     storage: &'a dyn Store<T>,
     table_name: &'a str,
-    columns: Rc<[Ident]>,
+    columns: Rc<[String]>,
     where_clause: Option<&'a Expr>,
-) -> Result<impl TryStream<Ok = (Rc<[Ident]>, T, Row), Error = Error> + 'a> {
+) -> Result<impl TryStream<Ok = (Rc<[String]>, T, Row), Error = Error> + 'a> {
     let rows = storage
         .scan_data(table_name)
         .await
diff --git a/src/executor/filter.rs b/src/executor/filter.rs
index 80f2ab9a..e2707262 100644
--- a/src/executor/filter.rs
+++ b/src/executor/filter.rs
@@ -3,9 +3,13 @@ use {
         context::{BlendContext, FilterContext},
         evaluate::evaluate,
     },
-    crate::{data::Value, result::Result, store::Store},
+    crate::{
+        ast::{Expr, Function},
+        data::Value,
+        result::Result,
+        store::Store,
+    },
     im_rc::HashMap,
-    sqlparser::ast::{Expr, Function},
     std::{convert::TryInto, fmt::Debug, rc::Rc},
 };
 
diff --git a/src/executor/join.rs b/src/executor/join.rs
index 3b9edb95..e5498acb 100644
--- a/src/executor/join.rs
+++ b/src/executor/join.rs
@@ -1,34 +1,19 @@
-use boolinator::Boolinator;
-use futures::stream::{self, once, StreamExt, TryStream, TryStreamExt};
-use serde::Serialize;
-use std::fmt::Debug;
-use std::pin::Pin;
-use std::rc::Rc;
-use thiserror::Error as ThisError;
-
-use sqlparser::ast::{Ident, Join as AstJoin, JoinConstraint, JoinOperator};
-
-use super::context::{BlendContext, FilterContext};
-use super::filter::Filter;
-use crate::data::Table;
-use crate::result::{Error, Result};
-use crate::store::Store;
-use crate::utils::OrStream;
-
-#[derive(ThisError, Serialize, Debug, PartialEq)]
-pub enum JoinError {
-    #[error("unimplemented! join not supported")]
-    JoinTypeNotSupported,
-
-    #[error("unimplemented! using on join not supported")]
-    UsingOnJoinNotSupported,
-
-    #[error("unimplemented! natural on join not supported")]
-    NaturalOnJoinNotSupported,
-
-    #[error("umimplemented! failed to get table name")]
-    FailedToGetTableName,
-}
+use {
+    super::{
+        context::{BlendContext, FilterContext},
+        filter::Filter,
+    },
+    crate::{
+        ast::{Join as AstJoin, JoinConstraint, JoinOperator},
+        data::Table,
+        result::{Error, Result},
+        store::Store,
+        utils::OrStream,
+    },
+    boolinator::Boolinator,
+    futures::stream::{self, once, StreamExt, TryStream, TryStreamExt},
+    std::{fmt::Debug, pin::Pin, rc::Rc},
+};
 
 pub struct Join<'a, T: 'static + Debug> {
     storage: &'a dyn Store<T>,
@@ -56,7 +41,7 @@ impl<'a, T: 'static + Debug> Join<'a, T> {
     pub async fn apply(
         &self,
         init_context: Result<BlendContext<'a>>,
-        join_columns: Rc<[Rc<[Ident]>]>,
+        join_columns: Rc<[Rc<[String]>]>,
     ) -> Result<Joined<'a>> {
         let init_context = init_context.map(Rc::new);
         let init_rows: Joined<'a> = Box::pin(stream::once(async { init_context }));
@@ -101,7 +86,7 @@ async fn join<'a, T: 'static + Debug>(
     storage: &'a dyn Store<T>,
     filter_context: Option<Rc<FilterContext<'a>>>,
     ast_join: &'a AstJoin,
-    columns: Rc<[Ident]>,
+    columns: Rc<[String]>,
     blend_context: Result<Rc<BlendContext<'a>>>,
 ) -> Result<Joined<'a>> {
     let AstJoin {
@@ -144,7 +129,6 @@ async fn join<'a, T: 'static + Debug>(
 
             rows
         }),
-        _ => Err(JoinError::JoinTypeNotSupported.into()),
     }
 }
 
@@ -152,19 +136,13 @@ async fn fetch_joined<'a, T: 'static + Debug>(
     storage: &'a dyn Store<T>,
     table_name: &'a str,
     table_alias: &'a str,
-    columns: Rc<[Ident]>,
+    columns: Rc<[String]>,
     filter_context: Option<Rc<FilterContext<'a>>>,
     blend_context: Rc<BlendContext<'a>>,
     constraint: &'a JoinConstraint,
 ) -> Result<impl TryStream<Ok = JoinItem<'a>, Error = Error, Item = Result<JoinItem<'a>>> + 'a> {
     let where_clause = match constraint {
         JoinConstraint::On(where_clause) => Some(where_clause),
-        JoinConstraint::Using(_) => {
-            return Err(JoinError::UsingOnJoinNotSupported.into());
-        }
-        JoinConstraint::Natural => {
-            return Err(JoinError::NaturalOnJoinNotSupported.into());
-        }
         JoinConstraint::None => None,
     };
 
diff --git a/src/executor/limit.rs b/src/executor/limit.rs
index 8fe46af3..fc4b4950 100644
--- a/src/executor/limit.rs
+++ b/src/executor/limit.rs
@@ -1,9 +1,11 @@
 use {
     super::context::BlendContext,
-    crate::result::Result,
+    crate::{
+        ast::{AstLiteral, Expr},
+        result::Result,
+    },
     futures::stream::{Stream, StreamExt},
     serde::Serialize,
-    sqlparser::ast::{Expr, Offset, Value as Literal},
     std::{fmt::Debug, pin::Pin, rc::Rc},
     thiserror::Error as ThisError,
 };
@@ -20,20 +22,18 @@ pub struct Limit {
 }
 
 impl Limit {
-    pub fn new(limit: Option<&Expr>, offset: Option<&Offset>) -> Result<Self> {
+    pub fn new(limit: Option<&Expr>, offset: Option<&Expr>) -> Result<Self> {
         let parse = |expr: &Expr| -> Result<usize> {
             match expr {
-                Expr::Value(Literal::Number(v, false)) => {
+                Expr::Literal(AstLiteral::Number(v)) => {
                     v.parse().map_err(|_| LimitError::Unreachable.into())
                 }
                 _ => Err(LimitError::Unreachable.into()),
             }
         };
 
-        let limit = limit.map(|value| parse(value)).transpose()?;
-        let offset = offset
-            .map(|Offset { value, .. }| parse(value))
-            .transpose()?;
+        let limit = limit.map(parse).transpose()?;
+        let offset = offset.map(parse).transpose()?;
 
         Ok(Self { limit, offset })
     }
diff --git a/src/executor/mod.rs b/src/executor/mod.rs
index 3bcb9de1..4e4c1441 100644
--- a/src/executor/mod.rs
+++ b/src/executor/mod.rs
@@ -18,7 +18,6 @@ pub use blend::BlendError;
 pub use evaluate::EvaluateError;
 pub use execute::{execute, ExecuteError, Payload};
 pub use fetch::FetchError;
-pub use join::JoinError;
 pub use limit::LimitError;
 pub use select::SelectError;
 pub use update::UpdateError;
diff --git a/src/executor/select.rs b/src/executor/select.rs
index 7952ac9a..8fb0eb4d 100644
--- a/src/executor/select.rs
+++ b/src/executor/select.rs
@@ -9,6 +9,7 @@ use {
         limit::Limit,
     },
     crate::{
+        ast::{Query, SelectItem, SetExpr, TableWithJoins},
         data::{get_name, Row, Table},
         result::{Error, Result},
         store::Store,
@@ -17,7 +18,6 @@ use {
     futures::stream::{self, Stream, StreamExt, TryStream, TryStreamExt},
     iter_enum::Iterator,
     serde::Serialize,
-    sqlparser::ast::{Expr, Ident, Query, SelectItem, SetExpr, TableWithJoins},
     std::{fmt::Debug, iter::once, rc::Rc},
     thiserror::Error as ThisError,
 };
@@ -37,7 +37,7 @@ pub enum SelectError {
 async fn fetch_blended<'a, T: 'static + Debug>(
     storage: &dyn Store<T>,
     table: Table<'a>,
-    columns: Rc<[Ident]>,
+    columns: Rc<[String]>,
 ) -> Result<impl Stream<Item = Result<BlendContext<'a>>> + 'a> {
     let rows = storage.scan_data(table.get_name()).await?.map(move |data| {
         let (_, row) = data?;
@@ -53,8 +53,8 @@ async fn fetch_blended<'a, T: 'static + Debug>(
 fn get_labels<'a>(
     projection: &[SelectItem],
     table_alias: &str,
-    columns: &'a [Ident],
-    join_columns: &'a [(&String, Vec<Ident>)],
+    columns: &'a [String],
+    join_columns: &'a [(&String, Vec<String>)],
 ) -> Result<Vec<String>> {
     #[derive(Iterator)]
     enum Labeled<I1, I2, I3, I4> {
@@ -77,7 +77,7 @@ fn get_labels<'a>(
         };
     }
 
-    let to_labels = |columns: &'a [Ident]| columns.iter().map(|ident| ident.value.to_string());
+    let to_labels = |columns: &'a [String]| columns.iter().map(|ident| ident.to_owned());
 
     projection
         .iter()
@@ -110,20 +110,7 @@ fn get_labels<'a>(
 
                 Labeled::QualifiedWildcard(labels)
             }
-            SelectItem::UnnamedExpr(expr) => {
-                let label = match expr {
-                    Expr::CompoundIdentifier(idents) => try_into!(idents
-                        .last()
-                        .map(|ident| ident.value.to_string())
-                        .ok_or_else(|| SelectError::Unreachable.into())),
-                    _ => expr.to_string(),
-                };
-
-                Labeled::Once(once(Ok(label)))
-            }
-            SelectItem::ExprWithAlias { alias, .. } => {
-                Labeled::Once(once(Ok(alias.value.to_string())))
-            }
+            SelectItem::Expr { label, .. } => Labeled::Once(once(Ok(label.to_owned()))),
         })
         .collect::<Result<_>>()
 }
diff --git a/src/executor/update.rs b/src/executor/update.rs
index 1d1bc82e..a23e05ca 100644
--- a/src/executor/update.rs
+++ b/src/executor/update.rs
@@ -4,13 +4,13 @@ use {
         evaluate::{evaluate, Evaluated},
     },
     crate::{
+        ast::{Assignment, ColumnDef},
         data::{schema::ColumnDefExt, Row, Value},
         result::Result,
         store::Store,
     },
     futures::stream::{self, TryStreamExt},
     serde::Serialize,
-    sqlparser::ast::{Assignment, ColumnDef, Ident},
     std::{fmt::Debug, rc::Rc},
     thiserror::Error,
 };
@@ -41,11 +41,8 @@ impl<'a, T: 'static + Debug> Update<'a, T> {
         for assignment in fields.iter() {
             let Assignment { id, .. } = assignment;
 
-            if column_defs
-                .iter()
-                .all(|col_def| col_def.name.value != id.value)
-            {
-                return Err(UpdateError::ColumnNotFound(id.value.to_string()).into());
+            if column_defs.iter().all(|col_def| &col_def.name != id) {
+                return Err(UpdateError::ColumnNotFound(id.to_owned()).into());
             }
         }
 
@@ -65,7 +62,7 @@ impl<'a, T: 'static + Debug> Update<'a, T> {
         match self
             .fields
             .iter()
-            .find(|assignment| assignment.id.value == column_def.name.value)
+            .find(|assignment| assignment.id == column_def.name)
         {
             None => Ok(None),
             Some(assignment) => {
@@ -114,17 +111,17 @@ impl<'a, T: 'static + Debug> Update<'a, T> {
             .map(Row)
     }
 
-    pub fn all_columns(&self) -> Vec<Ident> {
+    pub fn all_columns(&self) -> Vec<String> {
         self.column_defs
             .iter()
-            .map(|col_def| col_def.name.clone())
+            .map(|col_def| col_def.name.to_owned())
             .collect()
     }
 
-    pub fn columns_to_update(&self) -> Vec<Ident> {
+    pub fn columns_to_update(&self) -> Vec<String> {
         self.fields
             .iter()
-            .map(|assignment| assignment.id.clone())
+            .map(|assignment| assignment.id.to_owned())
             .collect()
     }
 }
diff --git a/src/executor/validate.rs b/src/executor/validate.rs
index 712b9b56..919a97fc 100644
--- a/src/executor/validate.rs
+++ b/src/executor/validate.rs
@@ -1,5 +1,6 @@
 use {
     crate::{
+        ast::{ColumnDef, ColumnOption},
         data::{Interval, Row, Value},
         result::Result,
         store::Store,
@@ -9,7 +10,6 @@ use {
     chrono::{NaiveDate, NaiveDateTime, NaiveTime},
     im_rc::HashSet,
     serde::Serialize,
-    sqlparser::ast::{ColumnDef, ColumnOption, Ident},
     std::{convert::TryInto, fmt::Debug, rc::Rc},
     thiserror::Error as ThisError,
 };
@@ -25,7 +25,7 @@ pub enum ValidateError {
 
 pub enum ColumnValidation {
     All(Rc<[ColumnDef]>),
-    SpecifiedColumns(Rc<[ColumnDef]>, Vec<Ident>),
+    SpecifiedColumns(Rc<[ColumnDef]>, Vec<String>),
 }
 
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
@@ -156,7 +156,7 @@ fn fetch_all_unique_columns(column_defs: &[ColumnDef]) -> Vec<(usize, String)> {
                 .iter()
                 .any(|opt_def| matches!(opt_def.option, ColumnOption::Unique { .. }))
             {
-                Some((i, table_col.name.value.to_owned()))
+                Some((i, table_col.name.to_owned()))
             } else {
                 None
             }
@@ -166,7 +166,7 @@ fn fetch_all_unique_columns(column_defs: &[ColumnDef]) -> Vec<(usize, String)> {
 
 fn fetch_specified_unique_columns(
     all_column_defs: &[ColumnDef],
-    specified_columns: &[Ident],
+    specified_columns: &[String],
 ) -> Vec<(usize, String)> {
     all_column_defs
         .iter()
@@ -178,11 +178,11 @@ fn fetch_specified_unique_columns(
                 .any(|opt_def| match opt_def.option {
                     ColumnOption::Unique { .. } => specified_columns
                         .iter()
-                        .any(|specified_col| specified_col.value == table_col.name.value),
+                        .any(|specified_col| specified_col == &table_col.name),
                     _ => false,
                 })
             {
-                Some((i, table_col.name.value.to_owned()))
+                Some((i, table_col.name.to_owned()))
             } else {
                 None
             }
diff --git a/src/glue.rs b/src/glue.rs
new file mode 100644
index 00000000..ed51e487
--- /dev/null
+++ b/src/glue.rs
@@ -0,0 +1,83 @@
+#![cfg(feature = "sled-storage")]
+use {
+    crate::{execute, parse, storages::SledStorage, translate, Payload, Result},
+    futures::executor::block_on,
+};
+
+pub struct Glue {
+    storage: Option<SledStorage>,
+}
+
+impl Glue {
+    pub fn new(storage: SledStorage) -> Self {
+        let storage = Some(storage);
+
+        Self { storage }
+    }
+
+    pub fn execute(&mut self, sql: &str) -> Result<Payload> {
+        let parsed = parse(sql)?;
+        let statement = translate(&parsed[0])?;
+
+        let storage = self.storage.take().unwrap();
+
+        match block_on(execute(storage, &statement)) {
+            Ok((storage, payload)) => {
+                self.storage = Some(storage);
+
+                Ok(payload)
+            }
+            Err((storage, error)) => {
+                self.storage = Some(storage);
+
+                Err(error)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use {
+        crate::{Glue, Payload, Row, SledStorage, Value},
+        std::convert::TryFrom,
+    };
+
+    #[test]
+    fn eq() {
+        let config = sled::Config::default()
+            .path("data/using_config")
+            .temporary(true);
+
+        let sled = SledStorage::try_from(config).unwrap();
+        let mut glue = Glue::new(sled);
+
+        assert_eq!(
+            glue.execute("CREATE TABLE api_test (id INTEGER PRIMARY KEY, name TEXT, nullable TEXT NULL, is BOOLEAN)"),
+            Ok(Payload::Create)
+        );
+        assert_eq!(
+            glue.execute("INSERT INTO api_test (id, name, nullable, is) VALUES (1, 'test1', 'not null', TRUE), (2, 'test2', NULL, FALSE)"),
+            Ok(Payload::Insert(2))
+        );
+
+        assert_eq!(
+            glue.execute("SELECT id, name, is FROM api_test"),
+            Ok(Payload::Select {
+                labels: vec![String::from("id"), String::from("name"), String::from("is")],
+                rows: vec![
+                    Row(vec![
+                        Value::I64(1),
+                        Value::Str(String::from("test1")),
+                        Value::Bool(true)
+                    ]),
+                    Row(vec![
+                        Value::I64(2),
+                        Value::Str(String::from("test2")),
+                        Value::Bool(false)
+                    ])
+                ]
+            })
+        );
+    }
+}
diff --git a/src/glue/mod.rs b/src/glue/mod.rs
deleted file mode 100644
index 8eaff8cd..00000000
--- a/src/glue/mod.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-#![cfg(feature = "sled-storage")]
-use {
-    crate::{execute, storages::SledStorage, ExecuteError, Payload, Query, Result},
-    futures::executor::block_on,
-};
-
-mod value;
-
-pub struct Glue {
-    storage: Option<SledStorage>,
-}
-
-impl Glue {
-    pub fn new(storage: SledStorage) -> Self {
-        let storage = Some(storage);
-
-        Self { storage }
-    }
-
-    pub fn execute(&mut self, query: &Query) -> Result<Payload> {
-        let storage = self.storage.take().unwrap();
-
-        match block_on(execute(storage, query)) {
-            Ok((storage, payload)) => {
-                self.storage = Some(storage);
-
-                Ok(payload)
-            }
-            Err((storage, error)) => {
-                self.storage = Some(storage);
-
-                Err(error)
-            }
-        }
-    }
-
-    pub fn select_as_string(&mut self, query: &Query) -> Result<Vec<Vec<String>>> {
-        // TODO: Make this more efficient and not affect database if not select by converting earlier
-        if let Ok(Payload::Select { labels, rows }) = self.execute(query) {
-            Ok(vec![labels] // Gross
-                .into_iter()
-                .chain(
-                    rows.into_iter()
-                        .map(|row| {
-                            row.0
-                                .into_iter()
-                                .map(|value| (&value).into())
-                                .collect::<Vec<String>>()
-                        })
-                        .collect::<Vec<Vec<String>>>(),
-                )
-                .collect())
-        } else {
-            Err(ExecuteError::QueryNotSupported.into())
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        crate::{parse_sql::parse_single, Glue, Payload, Row, SledStorage, Value},
-        std::convert::TryFrom,
-    };
-
-    #[test]
-    fn eq() {
-        let config = sled::Config::default()
-            .path("data/using_config")
-            .temporary(true);
-
-        let sled = SledStorage::try_from(config).unwrap();
-        let mut glue = Glue::new(sled);
-        assert_eq!(
-            glue.execute(
-                &parse_single(
-                    "CREATE TABLE api_test (id INTEGER PRIMARY KEY, name TEXT, nullable TEXT NULL, is BOOLEAN)"
-                )
-                .unwrap(),
-            ),
-            Ok(Payload::Create)
-        );
-        assert_eq!(
-            glue.execute(
-                &parse_single("INSERT INTO api_test (id, name, nullable, is) VALUES (1, 'test1', 'not null', TRUE), (2, 'test2', NULL, FALSE)")
-                    .unwrap()
-            ),
-            Ok(Payload::Insert(2))
-        );
-
-        assert_eq!(
-            glue.execute(&parse_single("SELECT id, name, is FROM api_test").unwrap()), // Not selecting NULL because NULL != NULL. TODO: Expand this test so that NULL == NULL
-            Ok(Payload::Select {
-                labels: vec![String::from("id"), String::from("name"), String::from("is")],
-                rows: vec![
-                    Row(vec![
-                        Value::I64(1),
-                        Value::Str(String::from("test1")),
-                        Value::Bool(true)
-                    ]),
-                    Row(vec![
-                        Value::I64(2),
-                        Value::Str(String::from("test2")),
-                        Value::Bool(false)
-                    ])
-                ]
-            })
-        );
-        assert_eq!(
-            glue.select_as_string(&parse_single("SELECT * FROM api_test").unwrap()),
-            Ok(vec![
-                vec![
-                    String::from("id"),
-                    String::from("name"),
-                    String::from("nullable"),
-                    String::from("is")
-                ],
-                vec![
-                    String::from("1"),
-                    String::from("test1"),
-                    String::from("not null"),
-                    String::from("TRUE")
-                ],
-                vec![
-                    String::from("2"),
-                    String::from("test2"),
-                    String::from("NULL"),
-                    String::from("FALSE")
-                ]
-            ])
-        );
-
-        use std::convert::TryInto;
-
-        let test_value: String = Value::Str(String::from("test")).into();
-        assert_eq!(test_value, String::from("test"));
-        let test_value: String = (&Value::Str(String::from("test"))).into();
-        assert_eq!(test_value, String::from("test"));
-        let test_value: Result<String, _> = Value::I64(1).try_into();
-        assert_eq!(test_value, Ok(String::from("1")));
-        let test_value: Result<String, _> = (&Value::I64(1)).try_into();
-        assert_eq!(test_value, Ok(String::from("1")));
-    }
-}
diff --git a/src/glue/value/mod.rs b/src/glue/value/mod.rs
deleted file mode 100644
index 45c673a0..00000000
--- a/src/glue/value/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use {
-    crate::{
-        result::{Error, Result},
-        Value,
-    },
-    std::convert::TryInto,
-};
-
-impl TryInto<i64> for Value {
-    type Error = Error;
-    fn try_into(self) -> Result<i64> {
-        (&self).try_into()
-    }
-}
-impl TryInto<f64> for Value {
-    type Error = Error;
-    fn try_into(self) -> Result<f64> {
-        (&self).try_into()
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index 04666781..7b340c02 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,6 +20,7 @@
 //!     let mut glue = Glue::new(storage);
 //!
 //!     let sqls = "
+//!         DROP TABLE IF EXISTS Glue;
 //!         CREATE TABLE Glue (id INTEGER);
 //!         INSERT INTO Glue VALUES (100);
 //!         INSERT INTO Glue VALUES (200);
@@ -27,9 +28,7 @@
 //!         DROP TABLE Glue;
 //!     ";
 //!
-//!     for query in parse(sqls).unwrap() {
-//!         glue.execute(&query).unwrap();
-//!     }
+//!     glue.execute(&sqls).unwrap();
 //! }
 //!
 //! #[cfg(not(feature = "sled-storage"))]
@@ -70,16 +69,19 @@ mod parse_sql;
 mod storages;
 mod utils;
 
+pub mod ast;
 pub mod data;
 pub mod result;
 pub mod store;
 pub mod tests;
+pub mod translate;
 
 pub use data::*;
 pub use executor::*;
 pub use parse_sql::*;
 pub use result::*;
 pub use store::*;
+pub use translate::*;
 
 #[cfg(feature = "sled-storage")]
 pub use glue::Glue;
diff --git a/src/parse_sql.rs b/src/parse_sql.rs
index aa8368f0..08945eeb 100644
--- a/src/parse_sql.rs
+++ b/src/parse_sql.rs
@@ -1,19 +1,10 @@
-use sqlparser::ast::Statement;
-use sqlparser::dialect::GenericDialect;
-use sqlparser::parser::Parser;
-pub use sqlparser::parser::ParserError;
+use {
+    crate::result::{Error, Result},
+    sqlparser::{ast::Statement as SqlStatement, dialect::GenericDialect, parser::Parser},
+};
 
-pub struct Query(pub Statement);
-
-pub fn parse(sql: &str) -> Result<Vec<Query>, ParserError> {
+pub fn parse(sql: &str) -> Result<Vec<SqlStatement>> {
     let dialect = GenericDialect {};
 
-    Parser::parse_sql(&dialect, sql).map(|parsed| parsed.into_iter().map(Query).collect())
-}
-
-pub fn parse_single(sql: &str) -> Result<Query, ParserError> {
-    parse(sql)?
-        .into_iter()
-        .next()
-        .ok_or_else(|| ParserError::ParserError(String::from("No Query")))
+    Parser::parse_sql(&dialect, sql).map_err(|e| Error::Parser(format!("{:#?}", e)))
 }
diff --git a/src/result.rs b/src/result.rs
index ba19a005..7938d77a 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -3,8 +3,9 @@ use {
         data::{IntervalError, LiteralError, RowError, TableError, ValueError},
         executor::{
             AggregateError, AlterError, BlendError, EvaluateError, ExecuteError, FetchError,
-            JoinError, LimitError, SelectError, UpdateError, ValidateError,
+            LimitError, SelectError, UpdateError, ValidateError,
         },
+        translate::TranslateError,
     },
     serde::Serialize,
     thiserror::Error as ThisError,
@@ -15,14 +16,20 @@ use crate::store::AlterTableError;
 
 #[derive(ThisError, Serialize, Debug)]
 pub enum Error {
-    #[cfg(feature = "alter-table")]
-    #[error(transparent)]
-    AlterTable(#[from] AlterTableError),
-
     #[error(transparent)]
     #[serde(with = "stringify")]
     Storage(#[from] Box<dyn std::error::Error>),
 
+    #[error("parsing failed: {0}")]
+    Parser(String),
+
+    #[error(transparent)]
+    Translate(#[from] TranslateError),
+
+    #[cfg(feature = "alter-table")]
+    #[error(transparent)]
+    AlterTable(#[from] AlterTableError),
+
     #[error(transparent)]
     Execute(#[from] ExecuteError),
     #[error(transparent)]
@@ -34,8 +41,6 @@ pub enum Error {
     #[error(transparent)]
     Select(#[from] SelectError),
     #[error(transparent)]
-    Join(#[from] JoinError),
-    #[error(transparent)]
     Blend(#[from] BlendError),
     #[error(transparent)]
     Aggregate(#[from] AggregateError),
@@ -65,6 +70,8 @@ impl PartialEq for Error {
         use Error::*;
 
         match (self, other) {
+            (Parser(e), Parser(e2)) => e == e2,
+            (Translate(e), Translate(e2)) => e == e2,
             #[cfg(feature = "alter-table")]
             (AlterTable(e), AlterTable(e2)) => e == e2,
             (Execute(e), Execute(e2)) => e == e2,
@@ -72,7 +79,6 @@ impl PartialEq for Error {
             (Fetch(e), Fetch(e2)) => e == e2,
             (Evaluate(e), Evaluate(e2)) => e == e2,
             (Select(e), Select(e2)) => e == e2,
-            (Join(e), Join(e2)) => e == e2,
             (Blend(e), Blend(e2)) => e == e2,
             (Aggregate(e), Aggregate(e2)) => e == e2,
             (Update(e), Update(e2)) => e == e2,
diff --git a/src/storages/sled_storage/alter_table.rs b/src/storages/sled_storage/alter_table.rs
index 1615be04..a287b6b0 100644
--- a/src/storages/sled_storage/alter_table.rs
+++ b/src/storages/sled_storage/alter_table.rs
@@ -1,15 +1,15 @@
 #![cfg(feature = "alter-table")]
 
-use async_trait::async_trait;
-use boolinator::Boolinator;
-use std::iter::once;
-use std::str;
-
-use sqlparser::ast::{ColumnDef, Ident};
-
-use super::{error::err_into, fetch_schema, SledStorage};
-use crate::utils::Vector;
-use crate::{schema::ColumnDefExt, AlterTable, AlterTableError, MutResult, Row, Schema, Value};
+use {
+    super::{error::err_into, fetch_schema, SledStorage},
+    crate::{
+        ast::ColumnDef, schema::ColumnDefExt, utils::Vector, AlterTable, AlterTableError,
+        MutResult, Row, Schema, Value,
+    },
+    async_trait::async_trait,
+    boolinator::Boolinator,
+    std::{iter::once, str},
+};
 
 macro_rules! try_self {
     ($self: expr, $expr: expr) => {
@@ -87,24 +87,17 @@ impl AlterTable for SledStorage {
 
         let i = column_defs
             .iter()
-            .position(|column_def| column_def.name.value == old_column_name)
+            .position(|column_def| column_def.name == old_column_name)
             .ok_or(AlterTableError::RenamingColumnNotFound);
         let i = try_into!(self, i);
 
         let ColumnDef {
-            name: Ident { quote_style, .. },
-            data_type,
-            collation,
-            options,
+            data_type, options, ..
         } = column_defs[i].clone();
 
         let column_def = ColumnDef {
-            name: Ident {
-                quote_style,
-                value: new_column_name.to_string(),
-            },
+            name: new_column_name.to_owned(),
             data_type,
-            collation,
             options,
         };
         let column_defs = Vector::from(column_defs).update(i, column_def).into();
@@ -130,9 +123,9 @@ impl AlterTable for SledStorage {
 
         if column_defs
             .iter()
-            .any(|ColumnDef { name, .. }| name.value == column_def.name.value)
+            .any(|ColumnDef { name, .. }| name == &column_def.name)
         {
-            let adding_column = column_def.name.value.to_string();
+            let adding_column = column_def.name.to_owned();
 
             return Err((
                 self,
@@ -149,7 +142,7 @@ impl AlterTable for SledStorage {
             (None, false) => {
                 return Err((
                     self,
-                    AlterTableError::DefaultValueRequired(column_def.to_string()).into(),
+                    AlterTableError::DefaultValueRequired(format!("{:?}", column_def)).into(),
                 ));
             }
         };
@@ -198,7 +191,7 @@ impl AlterTable for SledStorage {
 
         let index = column_defs
             .iter()
-            .position(|ColumnDef { name, .. }| name.value == column_name);
+            .position(|ColumnDef { name, .. }| name == column_name);
 
         let index = match (index, if_exists) {
             (Some(index), _) => index,
diff --git a/src/storages/sled_storage/mod.rs b/src/storages/sled_storage/mod.rs
index adbb452d..d7818247 100644
--- a/src/storages/sled_storage/mod.rs
+++ b/src/storages/sled_storage/mod.rs
@@ -5,11 +5,12 @@ mod store_mut;
 #[cfg(not(feature = "alter-table"))]
 impl crate::AlterTable for SledStorage {}
 
-use sled::{self, Config, Db};
-use std::convert::TryFrom;
-
-use crate::{Error, Result, Schema};
-use error::err_into;
+use {
+    crate::{Error, Result, Schema},
+    error::err_into,
+    sled::{self, Config, Db},
+    std::convert::TryFrom,
+};
 
 #[derive(Debug, Clone)]
 pub struct SledStorage {
diff --git a/src/storages/sled_storage/store.rs b/src/storages/sled_storage/store.rs
index f9b7ba41..29ed5708 100644
--- a/src/storages/sled_storage/store.rs
+++ b/src/storages/sled_storage/store.rs
@@ -1,8 +1,9 @@
-use async_trait::async_trait;
-use sled::IVec;
-
-use super::{err_into, fetch_schema, SledStorage};
-use crate::{Result, RowIter, Schema, Store};
+use {
+    super::{err_into, fetch_schema, SledStorage},
+    crate::{Result, RowIter, Schema, Store},
+    async_trait::async_trait,
+    sled::IVec,
+};
 
 #[async_trait(?Send)]
 impl Store<IVec> for SledStorage {
diff --git a/src/storages/sled_storage/store_mut.rs b/src/storages/sled_storage/store_mut.rs
index 79a82cc8..596bb8dc 100644
--- a/src/storages/sled_storage/store_mut.rs
+++ b/src/storages/sled_storage/store_mut.rs
@@ -1,12 +1,13 @@
-use async_trait::async_trait;
-use sled::{
-    transaction::{ConflictableTransactionError, TransactionError},
-    IVec,
+use {
+    super::{err_into, error::StorageError, SledStorage},
+    crate::{MutResult, Row, Schema, StoreMut},
+    async_trait::async_trait,
+    sled::{
+        transaction::{ConflictableTransactionError, TransactionError},
+        IVec,
+    },
 };
 
-use super::{err_into, error::StorageError, SledStorage};
-use crate::{MutResult, Row, Schema, StoreMut};
-
 macro_rules! try_into {
     ($self: expr, $expr: expr) => {
         match $expr.map_err(err_into) {
diff --git a/src/store/alter_table.rs b/src/store/alter_table.rs
index 0b2843e5..99b8c5e4 100644
--- a/src/store/alter_table.rs
+++ b/src/store/alter_table.rs
@@ -1,11 +1,10 @@
-use async_trait::async_trait;
-use serde::Serialize;
-use std::fmt::Debug;
-use thiserror::Error;
-
-use sqlparser::ast::ColumnDef;
-
-use crate::result::MutResult;
+use {
+    crate::{ast::ColumnDef, result::MutResult},
+    async_trait::async_trait,
+    serde::Serialize,
+    std::fmt::Debug,
+    thiserror::Error,
+};
 
 #[derive(Error, Serialize, Debug, PartialEq)]
 pub enum AlterTableError {
diff --git a/src/store/mod.rs b/src/store/mod.rs
index 9a7e5135..2a1e23d3 100644
--- a/src/store/mod.rs
+++ b/src/store/mod.rs
@@ -5,12 +5,14 @@ pub use alter_table::*;
 #[cfg(not(feature = "alter-table"))]
 pub trait AlterTable {}
 
-use async_trait::async_trait;
-use std::fmt::Debug;
-use std::marker::Sized;
-
-use crate::data::{Row, Schema};
-use crate::result::{MutResult, Result};
+use {
+    crate::{
+        data::{Row, Schema},
+        result::{MutResult, Result},
+    },
+    async_trait::async_trait,
+    std::{fmt::Debug, marker::Sized},
+};
 
 pub type RowIter<T> = Box<dyn Iterator<Item = Result<(T, Row)>>>;
 
diff --git a/src/translate/ast_literal.rs b/src/translate/ast_literal.rs
new file mode 100644
index 00000000..356a114b
--- /dev/null
+++ b/src/translate/ast_literal.rs
@@ -0,0 +1,41 @@
+use {
+    super::TranslateError,
+    crate::{
+        ast::{AstLiteral, DateTimeField},
+        result::Result,
+    },
+    sqlparser::ast::{DateTimeField as SqlDateTimeField, Value as SqlValue},
+};
+
+pub fn translate_ast_literal(sql_value: &SqlValue) -> Result<AstLiteral> {
+    Ok(match sql_value {
+        SqlValue::Boolean(v) => AstLiteral::Boolean(*v),
+        SqlValue::Number(v, _) => AstLiteral::Number(v.clone()),
+        SqlValue::SingleQuotedString(v) => AstLiteral::QuotedString(v.clone()),
+        SqlValue::Interval {
+            value,
+            leading_field,
+            last_field,
+            ..
+        } => AstLiteral::Interval {
+            value: value.to_owned(),
+            leading_field: leading_field.as_ref().map(translate_datetime_field),
+            last_field: last_field.as_ref().map(translate_datetime_field),
+        },
+        SqlValue::Null => AstLiteral::Null,
+        _ => {
+            return Err(TranslateError::UnsupportedAstLiteral(sql_value.to_string()).into());
+        }
+    })
+}
+
+fn translate_datetime_field(sql_datetime_field: &SqlDateTimeField) -> DateTimeField {
+    match sql_datetime_field {
+        SqlDateTimeField::Year => DateTimeField::Year,
+        SqlDateTimeField::Month => DateTimeField::Month,
+        SqlDateTimeField::Day => DateTimeField::Day,
+        SqlDateTimeField::Hour => DateTimeField::Hour,
+        SqlDateTimeField::Minute => DateTimeField::Minute,
+        SqlDateTimeField::Second => DateTimeField::Second,
+    }
+}
diff --git a/src/translate/data_type.rs b/src/translate/data_type.rs
new file mode 100644
index 00000000..1b002236
--- /dev/null
+++ b/src/translate/data_type.rs
@@ -0,0 +1,19 @@
+use {
+    super::TranslateError,
+    crate::{ast::DataType, result::Result},
+    sqlparser::ast::DataType as SqlDataType,
+};
+
+pub fn translate_data_type(sql_data_type: &SqlDataType) -> Result<DataType> {
+    match sql_data_type {
+        SqlDataType::Boolean => Ok(DataType::Boolean),
+        SqlDataType::Int => Ok(DataType::Int),
+        SqlDataType::Float(_) => Ok(DataType::Float),
+        SqlDataType::Text => Ok(DataType::Text),
+        SqlDataType::Date => Ok(DataType::Date),
+        SqlDataType::Timestamp => Ok(DataType::Timestamp),
+        SqlDataType::Time => Ok(DataType::Time),
+        SqlDataType::Interval => Ok(DataType::Interval),
+        _ => Err(TranslateError::UnsupportedDataType(sql_data_type.to_string()).into()),
+    }
+}
diff --git a/src/translate/ddl.rs b/src/translate/ddl.rs
new file mode 100644
index 00000000..085b500a
--- /dev/null
+++ b/src/translate/ddl.rs
@@ -0,0 +1,89 @@
+use {
+    super::{data_type::translate_data_type, expr::translate_expr, TranslateError},
+    crate::{
+        ast::{ColumnDef, ColumnOption, ColumnOptionDef},
+        result::Result,
+    },
+    sqlparser::ast::{
+        ColumnDef as SqlColumnDef, ColumnOption as SqlColumnOption,
+        ColumnOptionDef as SqlColumnOptionDef,
+    },
+};
+
+#[cfg(feature = "alter-table")]
+use {
+    super::translate_object_name, crate::ast::AlterTableOperation,
+    sqlparser::ast::AlterTableOperation as SqlAlterTableOperation,
+};
+
+#[cfg(feature = "alter-table")]
+pub fn translate_alter_table_operation(
+    sql_alter_table_operation: &SqlAlterTableOperation,
+) -> Result<AlterTableOperation> {
+    match sql_alter_table_operation {
+        SqlAlterTableOperation::AddColumn { column_def } => Ok(AlterTableOperation::AddColumn {
+            column_def: translate_column_def(column_def)?,
+        }),
+        SqlAlterTableOperation::DropColumn {
+            column_name,
+            if_exists,
+            ..
+        } => Ok(AlterTableOperation::DropColumn {
+            column_name: column_name.value.to_owned(),
+            if_exists: *if_exists,
+        }),
+        SqlAlterTableOperation::RenameColumn {
+            old_column_name,
+            new_column_name,
+        } => Ok(AlterTableOperation::RenameColumn {
+            old_column_name: old_column_name.value.to_owned(),
+            new_column_name: new_column_name.value.to_owned(),
+        }),
+        SqlAlterTableOperation::RenameTable { table_name } => {
+            Ok(AlterTableOperation::RenameTable {
+                table_name: translate_object_name(table_name),
+            })
+        }
+        _ => Err(TranslateError::UnsupportedAlterTableOperation(
+            sql_alter_table_operation.to_string(),
+        )
+        .into()),
+    }
+}
+
+pub fn translate_column_def(sql_column_def: &SqlColumnDef) -> Result<ColumnDef> {
+    let SqlColumnDef {
+        name,
+        data_type,
+        options,
+        ..
+    } = sql_column_def;
+
+    Ok(ColumnDef {
+        name: name.value.to_owned(),
+        data_type: translate_data_type(data_type)?,
+        options: options
+            .iter()
+            .map(translate_column_option_def)
+            .collect::<Result<_>>()?,
+    })
+}
+
+fn translate_column_option_def(
+    sql_column_option_def: &SqlColumnOptionDef,
+) -> Result<ColumnOptionDef> {
+    let SqlColumnOptionDef { name, option } = sql_column_option_def;
+
+    let name = name.as_ref().map(|name| name.value.to_owned());
+    let option = match option {
+        SqlColumnOption::Null => Ok(ColumnOption::Null),
+        SqlColumnOption::NotNull => Ok(ColumnOption::NotNull),
+        SqlColumnOption::Default(expr) => translate_expr(expr).map(ColumnOption::Default),
+        SqlColumnOption::Unique { is_primary } => Ok(ColumnOption::Unique {
+            is_primary: *is_primary,
+        }),
+        _ => Err(TranslateError::UnsupportedColumnOption(option.to_string()).into()),
+    }?;
+
+    Ok(ColumnOptionDef { name, option })
+}
diff --git a/src/translate/error.rs b/src/translate/error.rs
new file mode 100644
index 00000000..52fa937a
--- /dev/null
+++ b/src/translate/error.rs
@@ -0,0 +1,40 @@
+use {serde::Serialize, std::fmt::Debug, thiserror::Error};
+
+#[derive(Error, Serialize, Debug, PartialEq)]
+pub enum TranslateError {
+    #[error("unsupported statement: {0}")]
+    UnsupportedStatement(String),
+
+    #[error("unsupported expr: {0}")]
+    UnsupportedExpr(String),
+
+    #[error("unsupported data type: {0}")]
+    UnsupportedDataType(String),
+
+    #[error("unsupported ast literal: {0}")]
+    UnsupportedAstLiteral(String),
+
+    #[error("unsupported unary operator: {0}")]
+    UnsupportedUnaryOperator(String),
+
+    #[error("unsupported binary operator: {0}")]
+    UnsupportedBinaryOperator(String),
+
+    #[error("unsupported query set expr: {0}")]
+    UnsupportedQuerySetExpr(String),
+
+    #[error("unsupported query table factor: {0}")]
+    UnsupportedQueryTableFactor(String),
+
+    #[error("unsupported join constraint: {0}")]
+    UnsupportedJoinConstraint(String),
+
+    #[error("unsupported join operator: {0}")]
+    UnsupportedJoinOperator(String),
+
+    #[error("unsupported column option: {0}")]
+    UnsupportedColumnOption(String),
+
+    #[error("unsupported alter table operation: {0}")]
+    UnsupportedAlterTableOperation(String),
+}
diff --git a/src/translate/expr.rs b/src/translate/expr.rs
new file mode 100644
index 00000000..9162920f
--- /dev/null
+++ b/src/translate/expr.rs
@@ -0,0 +1,84 @@
+use {
+    super::{
+        ast_literal::translate_ast_literal,
+        data_type::translate_data_type,
+        function::translate_function,
+        operator::{translate_binary_operator, translate_unary_operator},
+        translate_idents, translate_query, TranslateError,
+    },
+    crate::{
+        ast::{AstLiteral, Expr},
+        result::Result,
+    },
+    sqlparser::ast::Expr as SqlExpr,
+};
+
+pub fn translate_expr(sql_expr: &SqlExpr) -> Result<Expr> {
+    match sql_expr {
+        SqlExpr::Identifier(ident) => match ident.quote_style {
+            Some(_) => Ok(Expr::Literal(AstLiteral::QuotedString(
+                ident.value.to_owned(),
+            ))),
+            None => Ok(Expr::Identifier(ident.value.to_owned())),
+        },
+        SqlExpr::Wildcard => Ok(Expr::Wildcard),
+        SqlExpr::QualifiedWildcard(idents) => Ok(Expr::QualifiedWildcard(translate_idents(idents))),
+        SqlExpr::CompoundIdentifier(idents) => {
+            Ok(Expr::CompoundIdentifier(translate_idents(idents)))
+        }
+        SqlExpr::IsNull(expr) => translate_expr(expr).map(Box::new).map(Expr::IsNull),
+        SqlExpr::IsNotNull(expr) => translate_expr(expr).map(Box::new).map(Expr::IsNotNull),
+        SqlExpr::InList {
+            expr,
+            list,
+            negated,
+        } => Ok(Expr::InList {
+            expr: translate_expr(expr).map(Box::new)?,
+            list: list.iter().map(translate_expr).collect::<Result<_>>()?,
+            negated: *negated,
+        }),
+        SqlExpr::InSubquery {
+            expr,
+            subquery,
+            negated,
+        } => Ok(Expr::InSubquery {
+            expr: translate_expr(expr).map(Box::new)?,
+            subquery: translate_query(subquery).map(Box::new)?,
+            negated: *negated,
+        }),
+        SqlExpr::Between {
+            expr,
+            negated,
+            low,
+            high,
+        } => Ok(Expr::Between {
+            expr: translate_expr(expr).map(Box::new)?,
+            negated: *negated,
+            low: translate_expr(low).map(Box::new)?,
+            high: translate_expr(high).map(Box::new)?,
+        }),
+        SqlExpr::BinaryOp { left, op, right } => Ok(Expr::BinaryOp {
+            left: translate_expr(left).map(Box::new)?,
+            op: translate_binary_operator(op)?,
+            right: translate_expr(right).map(Box::new)?,
+        }),
+        SqlExpr::UnaryOp { op, expr } => Ok(Expr::UnaryOp {
+            op: translate_unary_operator(op)?,
+            expr: translate_expr(expr).map(Box::new)?,
+        }),
+        SqlExpr::Cast { expr, data_type } => Ok(Expr::Cast {
+            expr: translate_expr(expr).map(Box::new)?,
+            data_type: translate_data_type(data_type)?,
+        }),
+        SqlExpr::Nested(expr) => translate_expr(expr).map(Box::new).map(Expr::Nested),
+        SqlExpr::Value(value) => translate_ast_literal(value).map(Expr::Literal),
+        SqlExpr::TypedString { data_type, value } => Ok(Expr::TypedString {
+            data_type: translate_data_type(data_type)?,
+            value: value.to_owned(),
+        }),
+        SqlExpr::Function(function) => translate_function(function).map(Expr::Function),
+        SqlExpr::Exists(query) => translate_query(query).map(Box::new).map(Expr::Exists),
+        SqlExpr::Subquery(query) => translate_query(query).map(Box::new).map(Expr::Subquery),
+        _ => Err(TranslateError::UnsupportedExpr(sql_expr.to_string()).into()),
+    }
+}
diff --git a/src/translate/function.rs b/src/translate/function.rs
new file mode 100644
index 00000000..bb58c2b2
--- /dev/null
+++ b/src/translate/function.rs
@@ -0,0 +1,26 @@
+use {
+    super::{expr::translate_expr, translate_object_name},
+    crate::{
+        ast::{Function, FunctionArg},
+        result::Result,
+    },
+    sqlparser::ast::{Function as SqlFunction, FunctionArg as SqlFunctionArg},
+};
+
+pub fn translate_function(sql_function: &SqlFunction) -> Result<Function> {
+    let SqlFunction { name, args, .. } = sql_function;
+
+    let name = translate_object_name(name);
+    let args = args
+        .iter()
+        .map(|arg| match arg {
+            SqlFunctionArg::Named { name, arg } => Ok(FunctionArg::Named {
+                name: name.value.to_owned(),
+                arg: translate_expr(arg)?,
+            }),
+            SqlFunctionArg::Unnamed(expr) => translate_expr(expr).map(FunctionArg::Unnamed),
+        })
+        .collect::<Result<_>>()?;
+
+    Ok(Function { name, args })
+}
diff --git a/src/translate/mod.rs b/src/translate/mod.rs
new file mode 100644
index 00000000..38c90046
--- /dev/null
+++ b/src/translate/mod.rs
@@ -0,0 +1,108 @@
+mod ast_literal;
+mod data_type;
+mod ddl;
+mod error;
+mod expr;
+mod function;
+mod operator;
+mod query;
+
+pub use error::TranslateError;
+
+#[cfg(feature = "alter-table")]
+use ddl::translate_alter_table_operation;
+
+use {
+    self::{ddl::translate_column_def, expr::translate_expr, query::translate_query},
+    crate::{
+        ast::{Assignment, ObjectName, Statement},
+        result::Result,
+    },
+    sqlparser::ast::{
+        Assignment as SqlAssignment, Ident as SqlIdent, ObjectName as SqlObjectName,
+        ObjectType as SqlObjectType, Statement as SqlStatement,
+    },
+};
+
+pub fn translate(sql_statement: &SqlStatement) -> Result<Statement> {
+    match sql_statement {
+        SqlStatement::Query(query) => translate_query(query).map(Box::new).map(Statement::Query),
+        SqlStatement::Insert {
+            table_name,
+            columns,
+            source,
+            ..
+        } => Ok(Statement::Insert {
+            table_name: translate_object_name(table_name),
+            columns: translate_idents(columns),
+            source: translate_query(source).map(Box::new)?,
+        }),
+        SqlStatement::Update {
+            table_name,
+            assignments,
+            selection,
+            ..
+        } => Ok(Statement::Update {
+            table_name: translate_object_name(table_name),
+            assignments: assignments
+                .iter()
+                .map(translate_assignment)
+                .collect::<Result<_>>()?,
+            selection: selection.as_ref().map(translate_expr).transpose()?,
+        }),
+        SqlStatement::Delete {
+            table_name,
+            selection,
+        } => Ok(Statement::Delete {
+            table_name: translate_object_name(table_name),
+            selection: selection.as_ref().map(translate_expr).transpose()?,
+        }),
+        SqlStatement::CreateTable {
+            if_not_exists,
+            name,
+            columns,
+            ..
+        } => Ok(Statement::CreateTable {
+            if_not_exists: *if_not_exists,
+            name: translate_object_name(name),
+            columns: columns
+                .iter()
+                .map(translate_column_def)
+                .collect::<Result<_>>()?,
+        }),
+        #[cfg(feature = "alter-table")]
+        SqlStatement::AlterTable {
+            name, operation, ..
+        } => Ok(Statement::AlterTable {
+            name: translate_object_name(name),
+            operation: translate_alter_table_operation(operation)?,
+        }),
+        SqlStatement::Drop {
+            object_type: SqlObjectType::Table,
+            if_exists,
+            names,
+            ..
+        } => Ok(Statement::DropTable {
+            if_exists: *if_exists,
+            names: names.iter().map(translate_object_name).collect(),
+        }),
+        _ => Err(TranslateError::UnsupportedStatement(sql_statement.to_string()).into()),
+    }
+}
+
+fn translate_assignment(sql_assignment: &SqlAssignment) -> Result<Assignment> {
+    let SqlAssignment { id, value } = sql_assignment;
+
+    Ok(Assignment {
+        id: id.value.to_owned(),
+        value: translate_expr(value)?,
+    })
+}
+
+fn translate_object_name(sql_object_name: &SqlObjectName) -> ObjectName {
+    ObjectName(translate_idents(&sql_object_name.0))
+}
+
+fn translate_idents(idents: &[SqlIdent]) -> Vec<String> {
+    idents.iter().map(|v| v.value.to_owned()).collect()
+}
diff --git a/src/translate/operator.rs b/src/translate/operator.rs
new file mode 100644
index 00000000..5fd95bfd
--- /dev/null
+++ b/src/translate/operator.rs
@@ -0,0 +1,38 @@
+use {
+    super::TranslateError,
+    crate::{
+        ast::{BinaryOperator, UnaryOperator},
+        result::Result,
+    },
+    sqlparser::ast::{BinaryOperator as SqlBinaryOperator, UnaryOperator as SqlUnaryOperator},
+};
+
+pub fn translate_unary_operator(sql_unary_operator: &SqlUnaryOperator) -> Result<UnaryOperator> {
+    match sql_unary_operator {
+        SqlUnaryOperator::Plus => Ok(UnaryOperator::Plus),
+        SqlUnaryOperator::Minus => Ok(UnaryOperator::Minus),
+        SqlUnaryOperator::Not => Ok(UnaryOperator::Not),
+        _ => Err(TranslateError::UnsupportedUnaryOperator(sql_unary_operator.to_string()).into()),
+    }
+}
+
+pub fn translate_binary_operator(
+    sql_binary_operator: &SqlBinaryOperator,
+) -> Result<BinaryOperator> {
+    match sql_binary_operator {
+        SqlBinaryOperator::Plus => Ok(BinaryOperator::Plus),
+        SqlBinaryOperator::Minus => Ok(BinaryOperator::Minus),
+        SqlBinaryOperator::Multiply => Ok(BinaryOperator::Multiply),
+        SqlBinaryOperator::Divide => Ok(BinaryOperator::Divide),
+        SqlBinaryOperator::StringConcat => Ok(BinaryOperator::StringConcat),
+        SqlBinaryOperator::Gt => Ok(BinaryOperator::Gt),
+        SqlBinaryOperator::Lt => Ok(BinaryOperator::Lt),
+        SqlBinaryOperator::GtEq => Ok(BinaryOperator::GtEq),
+        SqlBinaryOperator::LtEq => Ok(BinaryOperator::LtEq),
+        SqlBinaryOperator::Eq => Ok(BinaryOperator::Eq),
+        SqlBinaryOperator::NotEq => Ok(BinaryOperator::NotEq),
+        SqlBinaryOperator::And => Ok(BinaryOperator::And),
+        SqlBinaryOperator::Or => Ok(BinaryOperator::Or),
+        _ => Err(TranslateError::UnsupportedBinaryOperator(sql_binary_operator.to_string()).into()),
+    }
+}
diff --git a/src/translate/query.rs b/src/translate/query.rs
new file mode 100644
index 00000000..bfd141bb
--- /dev/null
+++ b/src/translate/query.rs
@@ -0,0 +1,165 @@
+use {
+    super::{expr::translate_expr, translate_idents, translate_object_name, TranslateError},
+    crate::{
+        ast::{
+            Join, JoinConstraint, JoinOperator, Query, Select, SelectItem, SetExpr, TableAlias,
+            TableFactor, TableWithJoins, Values,
+        },
+        result::Result,
+    },
+    sqlparser::ast::{
+        Expr as SqlExpr, Join as SqlJoin, JoinConstraint as SqlJoinConstraint,
+        JoinOperator as SqlJoinOperator, Query as SqlQuery, Select as SqlSelect,
+        SelectItem as SqlSelectItem, SetExpr as SqlSetExpr, TableAlias as SqlTableAlias,
+        TableFactor as SqlTableFactor, TableWithJoins as SqlTableWithJoins,
+    },
+};
+
+pub fn translate_query(sql_query: &SqlQuery) -> Result<Query> {
+    let SqlQuery {
+        body,
+        limit,
+        offset,
+        ..
+    } = sql_query;
+
+    let body = translate_set_expr(body)?;
+    let limit = limit.as_ref().map(translate_expr).transpose()?;
+    let offset = offset
+        .as_ref()
+        .map(|offset| translate_expr(&offset.value))
+        .transpose()?;
+
+    Ok(Query {
+        body,
+        limit,
+        offset,
+    })
+}
+
+fn translate_set_expr(sql_set_expr: &SqlSetExpr) -> Result<SetExpr> {
+    match sql_set_expr {
+        SqlSetExpr::Select(select) => translate_select(select).map(Box::new).map(SetExpr::Select),
+        SqlSetExpr::Values(values) => values
+            .0
+            .iter()
+            .map(|items| items.iter().map(translate_expr).collect::<Result<_>>())
+            .collect::<Result<_>>()
+            .map(Values)
+            .map(SetExpr::Values),
+        _ => Err(TranslateError::UnsupportedQuerySetExpr(sql_set_expr.to_string()).into()),
+    }
+}
+
+fn translate_select(sql_select: &SqlSelect) -> Result<Select> {
+    let SqlSelect {
+        projection,
+        from,
+        selection,
+        group_by,
+        having,
+        ..
+    } = sql_select;
+
+    Ok(Select {
+        projection: projection
+            .iter()
+            .map(translate_select_item)
+            .collect::<Result<_>>()?,
+        from: from
+            .iter()
+            .map(translate_table_with_joins)
+            .collect::<Result<_>>()?,
+        selection: selection.as_ref().map(translate_expr).transpose()?,
+        group_by: group_by.iter().map(translate_expr).collect::<Result<_>>()?,
+        having: having.as_ref().map(translate_expr).transpose()?,
+    })
+}
+
+fn translate_select_item(sql_select_item: &SqlSelectItem) -> Result<SelectItem> {
+    match sql_select_item {
+        SqlSelectItem::UnnamedExpr(expr) => {
+            let label = match expr {
+                SqlExpr::CompoundIdentifier(idents) => idents
+                    .last()
+                    .map(|ident| ident.value.to_owned())
+                    .unwrap_or_else(|| expr.to_string()),
+                _ => expr.to_string(),
+            };
+
+            Ok(SelectItem::Expr {
+                expr: translate_expr(expr)?,
+                label,
+            })
+        }
+        SqlSelectItem::ExprWithAlias { expr, alias } => {
+            translate_expr(expr).map(|expr| SelectItem::Expr {
+                expr,
+                label: alias.value.to_owned(),
+            })
+        }
+        SqlSelectItem::QualifiedWildcard(object_name) => Ok(SelectItem::QualifiedWildcard(
+            translate_object_name(object_name),
+        )),
+        SqlSelectItem::Wildcard => Ok(SelectItem::Wildcard),
+    }
+}
+
+fn translate_table_with_joins(sql_table_with_joins: &SqlTableWithJoins) -> Result<TableWithJoins> {
+    let SqlTableWithJoins { relation, joins } = sql_table_with_joins;
+
+    Ok(TableWithJoins {
+        relation: translate_table_factor(relation)?,
+        joins: joins.iter().map(translate_join).collect::<Result<_>>()?,
+    })
+}
+
+fn translate_table_factor(sql_table_factor: &SqlTableFactor) -> Result<TableFactor> {
+    match sql_table_factor {
+        SqlTableFactor::Table { name, alias, .. } => Ok(TableFactor::Table {
+            name: translate_object_name(name),
+            alias: alias
+                .as_ref()
+                .map(|SqlTableAlias { name, columns }| TableAlias {
+                    name: name.value.to_owned(),
+                    columns: translate_idents(columns),
+                }),
+        }),
+        _ => Err(TranslateError::UnsupportedQueryTableFactor(sql_table_factor.to_string()).into()),
+    }
+}
+
+fn translate_join(sql_join: &SqlJoin) -> Result<Join> {
+    let SqlJoin {
+        relation,
+        join_operator: sql_join_operator,
+    } = sql_join;
+
+    let translate_constraint = |sql_join_constraint: &SqlJoinConstraint| match sql_join_constraint {
+        SqlJoinConstraint::On(expr) => translate_expr(&expr).map(JoinConstraint::On),
+        SqlJoinConstraint::None => Ok(JoinConstraint::None),
+        SqlJoinConstraint::Using(_) => {
+            Err(TranslateError::UnsupportedJoinConstraint("USING".to_owned()).into())
+        }
+        SqlJoinConstraint::Natural => {
+            Err(TranslateError::UnsupportedJoinConstraint("NATURAL".to_owned()).into())
+        }
+    };
+
+    let join_operator = match sql_join_operator {
+        SqlJoinOperator::Inner(sql_join_constraint) => {
+            translate_constraint(sql_join_constraint).map(JoinOperator::Inner)
+        }
+        SqlJoinOperator::LeftOuter(sql_join_constraint) => {
+            translate_constraint(sql_join_constraint).map(JoinOperator::LeftOuter)
+        }
+        _ => {
+            Err(TranslateError::UnsupportedJoinOperator(format!("{:?}", sql_join_operator)).into())
+        }
+    }?;
+
+    Ok(Join {
+        relation: translate_table_factor(relation)?,
+        join_operator,
+    })
+}


Test patch:
diff --git a/src/tests/aggregate.rs b/src/tests/aggregate.rs
index 74678862..8b98c06f 100644
--- a/src/tests/aggregate.rs
+++ b/src/tests/aggregate.rs
@@ -65,7 +65,15 @@ test_case!(aggregate, async move {
 
     let error_cases = vec![
         (
-            AggregateError::UnsupportedCompoundIdentifier("id.name.ok".to_owned()).into(),
+            AggregateError::UnsupportedCompoundIdentifier(format!(
+                "{:?}",
+                ast::Expr::CompoundIdentifier(vec![
+                    "id".to_owned(),
+                    "name".to_owned(),
+                    "ok".to_owned()
+                ])
+            ))
+            .into(),
             "SELECT SUM(id.name.ok) FROM Item;",
         ),
         (
diff --git a/src/tests/alter_table.rs b/src/tests/alter_table.rs
index f5abc722..85c5d56b 100644
--- a/src/tests/alter_table.rs
+++ b/src/tests/alter_table.rs
@@ -1,6 +1,7 @@
 //! Tests in this file are only executed when feature = "alter-table" is enabled.
 
 use crate::*;
+use ast::*;
 use Value::*;
 
 test_case!(rename, async move {
@@ -40,7 +41,15 @@ test_case!(add_drop, async move {
         ("SELECT * FROM Foo;", Ok(select!(id; I64; 1; 2))),
         (
             "ALTER TABLE Foo ADD COLUMN amount INTEGER",
-            Err(AlterTableError::DefaultValueRequired("amount INT".to_owned()).into()),
+            Err(AlterTableError::DefaultValueRequired(format!(
+                "{:?}",
+                ColumnDef {
+                    name: "amount".to_owned(),
+                    data_type: DataType::Int,
+                    options: vec![]
+                }
+            ))
+            .into()),
         ),
         (
             "ALTER TABLE Foo ADD COLUMN id INTEGER",
@@ -80,21 +89,40 @@ test_case!(add_drop, async move {
         ),
         (
             "ALTER TABLE Foo ADD COLUMN something INTEGER DEFAULT (SELECT id FROM Bar LIMIT 1)",
-            Err(LiteralError::UnsupportedExpr("(SELECT id FROM Bar LIMIT 1)".to_owned()).into()),
+            Err(LiteralError::UnsupportedExpr(format!(
+                "{:?}",
+                Expr::Subquery(Box::new(ast::Query {
+                    body: SetExpr::Select(Box::new(Select {
+                        projection: vec![SelectItem::Expr {
+                            expr: Expr::Identifier("id".to_owned()),
+                            label: "id".to_owned(),
+                        }],
+                        from: vec![TableWithJoins {
+                            relation: TableFactor::Table {
+                                name: ObjectName(vec!["Bar".to_owned()]),
+                                alias: None,
+                            },
+                            joins: vec![],
+                        }],
+                        selection: None,
+                        group_by: vec![],
+                        having: None,
+                    })),
+                    limit: Some(Expr::Literal(AstLiteral::Number("1".to_owned()))),
+                    offset: None,
+                }))
+            ))
+            .into()),
         ),
         (
             "ALTER TABLE Foo ADD COLUMN something SOMEWHAT",
-            Err(AlterError::UnsupportedDataType("SOMEWHAT".to_owned()).into()),
-        ),
-        (
-            "ALTER TABLE Foo ADD COLUMN something INTEGER CHECK (true)",
-            Err(AlterError::UnsupportedColumnOption("CHECK (true)".to_owned()).into()),
+            Err(TranslateError::UnsupportedDataType("SOMEWHAT".to_owned()).into()),
         ),
         (
             "ALTER TABLE Foo ADD COLUMN something FLOAT UNIQUE",
             Err(AlterError::UnsupportedDataTypeForUniqueColumn(
                 "something".to_owned(),
-                "FLOAT".to_owned(),
+                format!("{:?}", DataType::Float),
             )
             .into()),
         ),
diff --git a/src/tests/create_table.rs b/src/tests/create_table.rs
index dfdc6841..26c7da28 100644
--- a/src/tests/create_table.rs
+++ b/src/tests/create_table.rs
@@ -42,11 +42,11 @@ test_case!(create_table, async move {
         ),
         (
             "CREATE TABLE Gluery (id SOMEWHAT);",
-            Err(AlterError::UnsupportedDataType("SOMEWHAT".to_owned()).into()),
+            Err(TranslateError::UnsupportedDataType("SOMEWHAT".to_owned()).into()),
         ),
         (
             "CREATE TABLE Gluery (id INTEGER CHECK (true));",
-            Err(AlterError::UnsupportedColumnOption("CHECK (true)".to_owned()).into()),
+            Err(TranslateError::UnsupportedColumnOption("CHECK (true)".to_owned()).into()),
         ),
         (
             r#"
@@ -56,7 +56,7 @@ test_case!(create_table, async move {
         )"#,
             Err(AlterError::UnsupportedDataTypeForUniqueColumn(
                 "ratio".to_owned(),
-                "FLOAT".to_owned(),
+                format!("{:?}", ast::DataType::Float),
             )
             .into()),
         ),
diff --git a/src/tests/drop_table.rs b/src/tests/drop_table.rs
index 4aae7e3d..cde7b713 100644
--- a/src/tests/drop_table.rs
+++ b/src/tests/drop_table.rs
@@ -54,7 +54,7 @@ CREATE TABLE DropTable (
         ),
         (
             "DROP VIEW DropTable;",
-            Err(AlterError::DropTypeNotSupported("VIEW".to_owned()).into()),
+            Err(TranslateError::UnsupportedStatement("DROP VIEW DropTable".to_owned()).into()),
         ),
     ];
 
diff --git a/src/tests/error.rs b/src/tests/error.rs
index 110ebabd..52a7d31d 100644
--- a/src/tests/error.rs
+++ b/src/tests/error.rs
@@ -5,13 +5,43 @@ test_case!(error, async move {
     run!("INSERT INTO TableA (id) VALUES (1);");
 
     let test_cases = vec![
-        (ExecuteError::QueryNotSupported.into(), "COMMIT;"),
         (
-            ExecuteError::TableNotExists.into(),
+            TranslateError::UnsupportedStatement("COMMIT".to_owned()).into(),
+            "COMMIT;",
+        ),
+        (
+            TranslateError::UnsupportedUnaryOperator("!".to_owned()).into(),
+            "SELECT 2! FROM TableA;",
+        ),
+        (
+            TranslateError::UnsupportedBinaryOperator("^".to_owned()).into(),
+            "SELECT 1 ^ 2 FROM TableA;",
+        ),
+        (
+            TranslateError::UnsupportedQuerySetExpr(
+                "SELECT * FROM TableA UNION SELECT * FROM TableA".to_owned(),
+            )
+            .into(),
+            "SELECT * FROM TableA UNION SELECT * FROM TableA;",
+        ),
+        #[cfg(feature = "alter-table")]
+        (
+            TranslateError::UnsupportedAlterTableOperation(
+                "ADD CONSTRAINT hello UNIQUE (id)".to_owned(),
+            )
+            .into(),
+            "ALTER TABLE TableA ADD CONSTRAINT hello UNIQUE (id)",
+        ),
+        (
+            TranslateError::UnsupportedExpr("1 COLLATE TableA".to_owned()).into(),
+            "SELECT 1 COLLATE TableA FROM TableA;",
+        ),
+        (
+            ExecuteError::TableNotFound("Nothing".to_owned()).into(),
             "INSERT INTO Nothing VALUES (1);",
         ),
         (
-            ExecuteError::TableNotExists.into(),
+            ExecuteError::TableNotFound("Nothing".to_owned()).into(),
             "UPDATE Nothing SET a = 1;",
         ),
         (
@@ -23,15 +53,18 @@ test_case!(error, async move {
             "SELECT * FROM TableA, TableB",
         ),
         (
-            TableError::TableFactorNotSupported.into(),
+            TranslateError::UnsupportedQueryTableFactor(
+                "(SELECT * FROM TableB) AS TableC".to_owned(),
+            )
+            .into(),
             "SELECT * FROM TableA JOIN (SELECT * FROM TableB) as TableC ON 1 = 1",
         ),
         (
-            JoinError::UsingOnJoinNotSupported.into(),
+            TranslateError::UnsupportedJoinConstraint("USING".to_owned()).into(),
             "SELECT * FROM TableA JOIN TableA USING (id);",
         ),
         (
-            JoinError::JoinTypeNotSupported.into(),
+            TranslateError::UnsupportedJoinOperator("CrossJoin".to_owned()).into(),
             "SELECT * FROM TableA CROSS JOIN TableA as A;",
         ),
         (
@@ -55,12 +88,12 @@ test_case!(error, async move {
             "INSERT INTO TableA VALUES (100), (100, 200);",
         ),
         (
-            LiteralError::UnsupportedLiteralType(r#"X'123'"#.to_owned()).into(),
+            TranslateError::UnsupportedAstLiteral(r#"X'123'"#.to_owned()).into(),
             "SELECT * FROM TableA Where id = X'123';",
         ),
         #[cfg(feature = "alter-table")]
         (
-            AlterError::UnsupportedAlterTableOperation(
+            TranslateError::UnsupportedAlterTableOperation(
                 r#"ADD CONSTRAINT "hey" PRIMARY KEY (asdf)"#.to_owned(),
             )
             .into(),
diff --git a/src/tests/function/cast.rs b/src/tests/function/cast.rs
index 6f2343f3..797ac781 100644
--- a/src/tests/function/cast.rs
+++ b/src/tests/function/cast.rs
@@ -83,9 +83,9 @@ test_case!(cast_literal, async move {
             Ok(select_with_null!(cast; Null)),
         ),
         (
-            r#"SELECT CAST(NULL AS NULL) FROM Item"#,
+            r#"SELECT CAST(NULL AS INTERVAL) FROM Item"#,
             Err(ValueError::UnimplementedLiteralCast {
-                data_type: "NULL".to_owned(),
+                data_type: format!("{:?}", ast::DataType::Interval),
                 literal: format!("{:?}", data::Literal::Null),
             }
             .into()),
@@ -138,7 +138,7 @@ test_case!(cast_value, async move {
             Err(ValueError::ImpossibleCast.into()),
         ),
         (
-            r#"SELECT CAST(number AS NULL) FROM Item"#,
+            r#"SELECT CAST(number AS INTERVAL) FROM Item"#,
             Err(ValueError::UnimplementedCast.into()),
         ),
     ];
diff --git a/src/tests/migrate.rs b/src/tests/migrate.rs
index 170a6e0d..c97412b0 100644
--- a/src/tests/migrate.rs
+++ b/src/tests/migrate.rs
@@ -1,4 +1,7 @@
-use crate::*;
+use crate::{
+    ast::{AstLiteral, BinaryOperator, Expr},
+    *,
+};
 
 test_case!(migrate, async move {
     run!(
@@ -21,7 +24,15 @@ test_case!(migrate, async move {
 
     let error_cases = vec![
         (
-            LiteralError::UnsupportedExpr("3 * 2".to_owned()).into(),
+            LiteralError::UnsupportedExpr(format!(
+                "{:?}",
+                Expr::BinaryOp {
+                    left: Box::new(Expr::Literal(AstLiteral::Number("3".to_owned()))),
+                    op: BinaryOperator::Multiply,
+                    right: Box::new(Expr::Literal(AstLiteral::Number("2".to_owned()))),
+                }
+            ))
+            .into(),
             "INSERT INTO Test (id, num) VALUES (3 * 2, 1);",
         ),
         (
@@ -29,15 +40,24 @@ test_case!(migrate, async move {
             r#"INSERT INTO Test (id, num, name) VALUES (1.1, 1, "good");"#,
         ),
         (
-            EvaluateError::UnsupportedCompoundIdentifier("Here.User.id".to_owned()).into(),
+            EvaluateError::UnsupportedCompoundIdentifier(format!(
+                "{:?}",
+                Expr::CompoundIdentifier(vec![
+                    "Here".to_owned(),
+                    "User".to_owned(),
+                    "id".to_owned()
+                ])
+            ))
+            .into(),
             "SELECT * FROM Test WHERE Here.User.id = 1",
         ),
         (
-            JoinError::NaturalOnJoinNotSupported.into(),
+            TranslateError::UnsupportedJoinConstraint("NATURAL".to_owned()).into(),
             "SELECT * FROM Test NATURAL JOIN Test",
         ),
         (
-            TableError::TableFactorNotSupported.into(),
+            TranslateError::UnsupportedQueryTableFactor("(SELECT * FROM Test) AS A".to_owned())
+                .into(),
             "SELECT * FROM (SELECT * FROM Test) as A;",
         ),
     ];
diff --git a/src/tests/tester.rs b/src/tests/tester.rs
index 24e4ff73..aceb0fc3 100644
--- a/src/tests/tester.rs
+++ b/src/tests/tester.rs
@@ -1,39 +1,49 @@
-use async_trait::async_trait;
-use std::cell::RefCell;
-use std::fmt::Debug;
-use std::rc::Rc;
-
-use crate::executor::{execute, Payload};
-use crate::parse_sql::parse;
-use crate::result::Result;
-use crate::store::{AlterTable, Store, StoreMut};
+use {
+    crate::{
+        executor::{execute, Payload},
+        parse_sql::parse,
+        result::Result,
+        store::{AlterTable, Store, StoreMut},
+        translate::translate,
+    },
+    async_trait::async_trait,
+    std::{cell::RefCell, fmt::Debug, rc::Rc},
+};
 
 pub async fn run<T: 'static + Debug, U: Store<T> + StoreMut<T> + AlterTable>(
     cell: Rc<RefCell<Option<U>>>,
     sql: &str,
 ) -> Result<Payload> {
-    println!("[Run] {}", sql);
+    let storage = cell.replace(None).unwrap();
+
+    macro_rules! try_run {
+        ($expr: expr) => {
+            match $expr {
+                Ok(v) => v,
+                Err(e) => {
+                    cell.replace(Some(storage));
 
-    let mut storage = cell.replace(None).unwrap();
+                    return Err(e);
+                }
+            }
+        };
+    }
 
-    let query = &parse(sql).unwrap()[0];
+    let parsed = try_run!(parse(sql));
+    let statement = try_run!(translate(&parsed[0]));
 
-    let result = match execute(storage, query).await {
-        Ok((s, payload)) => {
-            storage = s;
+    match execute(storage, &statement).await {
+        Ok((storage, payload)) => {
+            cell.replace(Some(storage));
 
             Ok(payload)
         }
-        Err((s, error)) => {
-            storage = s;
+        Err((storage, error)) => {
+            cell.replace(Some(storage));
 
             Err(error)
         }
-    };
-
-    cell.replace(Some(storage));
-
-    result
+    }
 }
 
 /// If you want to make your custom storage and want to run integrate tests,
diff --git a/src/tests/validate/types.rs b/src/tests/validate/types.rs
index 7bdee65d..4df4becf 100644
--- a/src/tests/validate/types.rs
+++ b/src/tests/validate/types.rs
@@ -1,4 +1,4 @@
-use {crate::*, sqlparser::ast::DataType, std::borrow::Cow};
+use {crate::ast::DataType, crate::*, std::borrow::Cow};
 
 test_case!(types, async move {
     run!("CREATE TABLE TableB (id BOOLEAN);");
@@ -10,7 +10,7 @@ test_case!(types, async move {
         (
             "INSERT INTO TableB SELECT uid FROM TableC;",
             Err(ValueError::IncompatibleDataType {
-                data_type: DataType::Boolean.to_string(),
+                data_type: format!("{:?}", DataType::Boolean),
                 value: format!("{:?}", Value::I64(1)),
             }
             .into()),
@@ -18,7 +18,7 @@ test_case!(types, async move {
         (
             "INSERT INTO TableC (uid) VALUES (\"A\")",
             Err(ValueError::IncompatibleLiteralForDataType {
-                data_type: DataType::Int.to_string(),
+                data_type: format!("{:?}", DataType::Int),
                 literal: format!("{:?}", data::Literal::Text(Cow::Owned("A".to_owned()))),
             }
             .into()),
@@ -34,7 +34,7 @@ test_case!(types, async move {
         (
             "UPDATE TableC SET uid = TRUE;",
             Err(ValueError::IncompatibleLiteralForDataType {
-                data_type: DataType::Int.to_string(),
+                data_type: format!("{:?}", DataType::Int),
                 literal: format!("{:?}", data::Literal::Boolean(true)),
             }
             .into()),
@@ -42,7 +42,7 @@ test_case!(types, async move {
         (
             "UPDATE TableC SET uid = (SELECT id FROM TableB LIMIT 1) WHERE uid = 1",
             Err(ValueError::IncompatibleDataType {
-                data_type: DataType::Int.to_string(),
+                data_type: format!("{:?}", DataType::Int),
                 value: format!("{:?}", Value::Bool(false)),
             }
             .into()),