Repository: gluesql/gluesql
Pull request #180 (2021-03-15 13:13:57)

Add custom enum Literal, it replaces ast::Value
Now Literal means crate::data::Literal, no more sqlparser::ast::Value.

`sqlparser::ast::Value as Literal` was superset of literals what GlueSQL needs.
By using `enum Literal`, we can define `Literal` more clearly.

resolve https://github.com/gluesql/gluesql/issues/178

@KyGost it was quite a tough work, yeah! 🚀


KyGost: Good work!! Looks good!

Patch:
diff --git a/src/data/literal.rs b/src/data/literal.rs
new file mode 100644
index 00000000..53616c9e
--- /dev/null
+++ b/src/data/literal.rs
@@ -0,0 +1,156 @@
+use {
+    crate::result::{Error, Result},
+    sqlparser::ast::Value as AstValue,
+    std::{borrow::Cow, cmp::Ordering, convert::TryFrom, fmt::Debug},
+    Literal::*,
+};
+
+use {serde::Serialize, thiserror::Error};
+
+#[derive(Error, Serialize, Debug, PartialEq)]
+pub enum LiteralError {
+    #[error("Unsupported literal type: {0}")]
+    UnsupportedLiteralType(String),
+
+    #[error("unsupported literal binary arithmetic between {0} and {1}")]
+    UnsupportedBinaryArithmetic(String, String),
+
+    #[error("literal unary operation on non-numeric")]
+    UnaryOperationOnNonNumeric,
+
+    #[error("unreachable literal binary arithmetic")]
+    UnreachableBinaryArithmetic,
+
+    #[error("unreachable literal unary operation")]
+    UnreachableUnaryOperation,
+}
+
+#[derive(Clone, Debug)]
+pub enum Literal<'a> {
+    Boolean(bool),
+    Number(Cow<'a, String>),
+    Text(Cow<'a, String>),
+    Null,
+}
+
+impl<'a> TryFrom<&'a AstValue> 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::Null => Null,
+            _ => {
+                return Err(LiteralError::UnsupportedLiteralType(ast_value.to_string()).into());
+            }
+        };
+
+        Ok(literal)
+    }
+}
+
+impl PartialEq<Literal<'_>> for Literal<'_> {
+    fn eq(&self, other: &Literal) -> bool {
+        match (self, other) {
+            (Boolean(l), Boolean(r)) => l == r,
+            (Number(l), Number(r)) | (Text(l), Text(r)) => l == r,
+            _ => false,
+        }
+    }
+}
+
+impl PartialOrd<Literal<'_>> for Literal<'_> {
+    fn partial_cmp(&self, other: &Literal) -> Option<Ordering> {
+        match (self, other) {
+            (Boolean(l), Boolean(r)) => Some(l.cmp(r)),
+            (Number(l), Number(r)) => match (l.parse::<i64>(), r.parse::<i64>()) {
+                (Ok(l), Ok(r)) => Some(l.cmp(&r)),
+                (_, Ok(r)) => match l.parse::<f64>() {
+                    Ok(l) => l.partial_cmp(&(r as f64)),
+                    _ => None,
+                },
+                (Ok(l), _) => match r.parse::<f64>() {
+                    Ok(r) => (l as f64).partial_cmp(&r),
+                    _ => None,
+                },
+                _ => match (l.parse::<f64>(), r.parse::<f64>()) {
+                    (Ok(l), Ok(r)) => l.partial_cmp(&r),
+                    _ => None,
+                },
+            },
+            (Text(l), Text(r)) => Some(l.cmp(r)),
+            _ => None,
+        }
+    }
+}
+
+macro_rules! binary_op {
+    ($name:ident, $op:tt) => {
+        pub fn $name<'b>(&self, other: &Literal<'a>) -> Result<Literal<'b>> {
+            match (self, other) {
+                (Number(l), Number(r)) => {
+                    match (l.parse::<i64>(), r.parse::<i64>()) {
+                        (Ok(l), Ok(r)) => Ok((l $op r).to_string()),
+                        (Ok(l), _) => match r.parse::<f64>() {
+                            Ok(r) => Ok(((l as f64) $op r).to_string()),
+                            _ => Err(LiteralError::UnreachableBinaryArithmetic.into()),
+                        },
+                        (_, Ok(r)) => match l.parse::<f64>() {
+                            Ok(l) => Ok((l $op (r as f64)).to_string()),
+                            _ => Err(LiteralError::UnreachableBinaryArithmetic.into()),
+                        },
+                        (_, _) => match (l.parse::<f64>(), r.parse::<f64>()) {
+                            (Ok(l), Ok(r)) => Ok((l $op r).to_string()),
+                            _ => Err(LiteralError::UnreachableBinaryArithmetic.into()),
+                        },
+                    }.map(|v| Number(Cow::Owned(v)))
+                }
+                (Null, Number(_))
+                | (Number(_), Null)
+                | (Null, Null) => {
+                    Ok(Literal::Null)
+                }
+                _ => Err(
+                    LiteralError::UnsupportedBinaryArithmetic(
+                        format!("{:?}", self),
+                        format!("{:?}", other),
+                    ).into()
+                ),
+            }
+        }
+    }
+}
+
+impl<'a> Literal<'a> {
+    pub fn unary_plus(&self) -> Result<Self> {
+        match self {
+            Number(v) => v
+                .parse::<i64>()
+                .map(|_| self.to_owned())
+                .or_else(|_| v.parse::<f64>().map(|_| self.to_owned()))
+                .map_err(|_| LiteralError::UnreachableUnaryOperation.into()),
+            Null => Ok(Null),
+            _ => Err(LiteralError::UnaryOperationOnNonNumeric.into()),
+        }
+    }
+
+    pub fn unary_minus(&self) -> Result<Self> {
+        match self {
+            Number(v) => v
+                .parse::<i64>()
+                .map(|v| (-v).to_string())
+                .or_else(|_| v.parse::<f64>().map(|v| (-v).to_string()))
+                .map(|v| Number(Cow::Owned(v)))
+                .map_err(|_| LiteralError::UnreachableUnaryOperation.into()),
+            Null => Ok(Null),
+            _ => Err(LiteralError::UnaryOperationOnNonNumeric.into()),
+        }
+    }
+
+    binary_op!(add, +);
+    binary_op!(subtract, -);
+    binary_op!(multiply, *);
+    binary_op!(divide, /);
+}
diff --git a/src/data/mod.rs b/src/data/mod.rs
index e29de421..b67cd2c8 100644
--- a/src/data/mod.rs
+++ b/src/data/mod.rs
@@ -1,9 +1,11 @@
+mod literal;
 mod row;
 mod schema;
 mod table;
 pub mod value;
 
 pub use {
+    literal::{Literal, LiteralError},
     row::{Row, RowError},
     schema::Schema,
     table::{get_name, Table, TableError},
diff --git a/src/data/value/literal.rs b/src/data/value/literal.rs
index d91e0cde..fc7aed74 100644
--- a/src/data/value/literal.rs
+++ b/src/data/value/literal.rs
@@ -1,92 +1,111 @@
 use {
     super::{error::ValueError, Value},
-    crate::result::{Error, Result},
-    sqlparser::ast::{DataType, Value as Literal},
+    crate::{
+        data::Literal,
+        result::{Error, Result},
+    },
+    sqlparser::ast::DataType,
     std::{cmp::Ordering, convert::TryFrom},
 };
 
-impl PartialEq<Literal> for Value {
-    fn eq(&self, other: &Literal) -> bool {
+impl PartialEq<Literal<'_>> for Value {
+    fn eq(&self, other: &Literal<'_>) -> bool {
         match (self, other) {
             (Value::Bool(l), Literal::Boolean(r)) => l == r,
-            (Value::I64(l), Literal::Number(r, false)) => match r.parse::<i64>() {
+            (Value::I64(l), Literal::Number(r)) => match r.parse::<i64>() {
                 Ok(r) => l == &r,
                 Err(_) => match r.parse::<f64>() {
                     Ok(r) => (*l as f64) == r,
                     Err(_) => false,
                 },
             },
-            (Value::F64(l), Literal::Number(r, false)) => match r.parse::<f64>() {
+            (Value::F64(l), Literal::Number(r)) => match r.parse::<f64>() {
                 Ok(r) => l == &r,
                 Err(_) => match r.parse::<i64>() {
                     Ok(r) => *l == (r as f64),
                     Err(_) => false,
                 },
             },
-            (Value::Str(l), Literal::SingleQuotedString(r)) => l == r,
+            (Value::Str(l), Literal::Text(r)) => l == r.as_ref(),
             _ => false,
         }
     }
 }
 
-impl PartialOrd<Literal> for Value {
-    fn partial_cmp(&self, other: &Literal) -> Option<Ordering> {
+impl PartialOrd<Literal<'_>> for Value {
+    fn partial_cmp(&self, other: &Literal<'_>) -> Option<Ordering> {
         match (self, other) {
-            (Value::I64(l), Literal::Number(r, false)) => match r.parse::<i64>() {
+            (Value::I64(l), Literal::Number(r)) => match r.parse::<i64>() {
                 Ok(r) => Some(l.cmp(&r)),
                 Err(_) => match r.parse::<f64>() {
                     Ok(r) => (*l as f64).partial_cmp(&r),
                     Err(_) => None,
                 },
             },
-            (Value::F64(l), Literal::Number(r, false)) => match r.parse::<f64>() {
+            (Value::F64(l), Literal::Number(r)) => match r.parse::<f64>() {
                 Ok(r) => l.partial_cmp(&r),
                 Err(_) => match r.parse::<i64>() {
                     Ok(r) => l.partial_cmp(&(r as f64)),
                     Err(_) => None,
                 },
             },
-            (Value::Str(l), Literal::SingleQuotedString(r)) => Some(l.cmp(r)),
+            (Value::Str(l), Literal::Text(r)) => Some(l.cmp(r.as_ref())),
             _ => None,
         }
     }
 }
 
-impl TryFrom<&Literal> for Value {
+impl TryFrom<&Literal<'_>> for Value {
     type Error = Error;
 
-    fn try_from(literal: &Literal) -> Result<Self> {
+    fn try_from(literal: &Literal<'_>) -> Result<Self> {
         match literal {
-            Literal::Number(v, false) => v
+            Literal::Number(v) => v
                 .parse::<i64>()
                 .map_or_else(|_| v.parse::<f64>().map(Value::F64), |v| Ok(Value::I64(v)))
                 .map_err(|_| ValueError::FailedToParseNumber.into()),
             Literal::Boolean(v) => Ok(Value::Bool(*v)),
-            Literal::SingleQuotedString(v) => Ok(Value::Str(v.to_string())),
+            Literal::Text(v) => Ok(Value::Str(v.as_ref().to_owned())),
+            Literal::Null => Ok(Value::Null),
+        }
+    }
+}
+
+impl TryFrom<Literal<'_>> for Value {
+    type Error = Error;
+
+    fn try_from(literal: Literal<'_>) -> Result<Self> {
+        match literal {
+            Literal::Number(v) => v
+                .parse::<i64>()
+                .map_or_else(|_| v.parse::<f64>().map(Value::F64), |v| Ok(Value::I64(v)))
+                .map_err(|_| ValueError::FailedToParseNumber.into()),
+            Literal::Boolean(v) => Ok(Value::Bool(v)),
+            Literal::Text(v) => Ok(Value::Str(v.into_owned())),
             Literal::Null => Ok(Value::Null),
-            _ => Err(ValueError::SqlTypeNotSupported.into()),
         }
     }
 }
 
 pub trait TryFromLiteral {
-    fn try_from_literal(data_type: &DataType, literal: &Literal) -> Result<Value>;
+    fn try_from_literal(data_type: &DataType, literal: &Literal<'_>) -> Result<Value>;
 }
 
 impl TryFromLiteral for Value {
-    fn try_from_literal(data_type: &DataType, literal: &Literal) -> Result<Value> {
+    fn try_from_literal(data_type: &DataType, literal: &Literal<'_>) -> Result<Value> {
         match (data_type, literal) {
-            (DataType::Boolean, Literal::SingleQuotedString(v))
-            | (DataType::Boolean, Literal::Number(v, false)) => match v.to_uppercase().as_str() {
-                "TRUE" | "1" => Ok(Value::Bool(true)),
-                "FALSE" | "0" => Ok(Value::Bool(false)),
-                _ => Err(ValueError::LiteralCastToBooleanFailed(v.to_string()).into()),
-            },
-            (DataType::Int, Literal::SingleQuotedString(v)) => v
+            (DataType::Boolean, Literal::Text(v)) | (DataType::Boolean, Literal::Number(v)) => {
+                match v.to_uppercase().as_str() {
+                    "TRUE" | "1" => Ok(Value::Bool(true)),
+                    "FALSE" | "0" => Ok(Value::Bool(false)),
+                    _ => Err(ValueError::LiteralCastToBooleanFailed(v.to_string()).into()),
+                }
+            }
+            (DataType::Int, Literal::Text(v)) => v
                 .parse::<i64>()
                 .map(Value::I64)
                 .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
-            (DataType::Int, Literal::Number(v, false)) => v
+            (DataType::Int, Literal::Number(v)) => v
                 .parse::<f64>()
                 .map_err(|_| {
                     ValueError::UnreachableLiteralCastFromNumberToInteger(v.to_string()).into()
@@ -97,8 +116,7 @@ impl TryFromLiteral for Value {
 
                 Ok(Value::I64(v))
             }
-            (DataType::Float(_), Literal::SingleQuotedString(v))
-            | (DataType::Float(_), Literal::Number(v, false)) => 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()),
@@ -107,8 +125,9 @@ impl TryFromLiteral for Value {
 
                 Ok(Value::F64(v))
             }
-            (DataType::Text, Literal::Number(v, false))
-            | (DataType::Text, Literal::SingleQuotedString(v)) => Ok(Value::Str(v.to_string())),
+            (DataType::Text, Literal::Number(v)) | (DataType::Text, Literal::Text(v)) => {
+                Ok(Value::Str(v.to_string()))
+            }
             (DataType::Text, Literal::Boolean(v)) => {
                 let v = if *v { "TRUE" } else { "FALSE" };
 
@@ -120,7 +139,7 @@ impl TryFromLiteral for Value {
             | (DataType::Text, Literal::Null) => Ok(Value::Null),
             _ => Err(ValueError::UnimplementedLiteralCast {
                 data_type: data_type.to_string(),
-                literal: literal.to_string(),
+                literal: format!("{:?}", literal),
             }
             .into()),
         }
diff --git a/src/data/value/mod.rs b/src/data/value/mod.rs
index 3e657b3f..59335610 100644
--- a/src/data/value/mod.rs
+++ b/src/data/value/mod.rs
@@ -1,9 +1,10 @@
 use {
+    super::Literal,
     crate::result::Result,
     boolinator::Boolinator,
     serde::{Deserialize, Serialize},
-    sqlparser::ast::{DataType, Expr, Ident, Value as Literal},
-    std::{cmp::Ordering, fmt::Debug},
+    sqlparser::ast::{DataType, Expr, Ident},
+    std::{cmp::Ordering, convert::TryFrom, fmt::Debug},
 };
 
 mod error;
@@ -67,7 +68,9 @@ impl BoolToValue for bool {
 impl Value {
     pub fn from_expr(data_type: &DataType, nullable: bool, expr: &Expr) -> Result<Self> {
         match expr {
-            Expr::Value(literal) => Value::from_data_type(&data_type, nullable, literal),
+            Expr::Value(literal) => {
+                Value::from_data_type(&data_type, nullable, Literal::try_from(literal)?)
+            }
             Expr::Identifier(Ident { value, .. }) => Ok(Value::Str(value.clone())),
             _ => Err(ValueError::ExprNotSupported(expr.to_string()).into()),
         }
@@ -87,18 +90,22 @@ impl Value {
         )
     }
 
-    pub fn from_data_type(data_type: &DataType, nullable: bool, literal: &Literal) -> Result<Self> {
+    pub fn from_data_type(
+        data_type: &DataType,
+        nullable: bool,
+        literal: Literal<'_>,
+    ) -> Result<Self> {
         match (data_type, literal) {
-            (DataType::Int, Literal::Number(v, false)) => v
+            (DataType::Int, Literal::Number(v)) => v
                 .parse()
                 .map(Value::I64)
                 .map_err(|_| ValueError::FailedToParseNumber.into()),
-            (DataType::Float(_), Literal::Number(v, false)) => v
+            (DataType::Float(_), Literal::Number(v)) => v
                 .parse()
                 .map(Value::F64)
                 .map_err(|_| ValueError::FailedToParseNumber.into()),
-            (DataType::Boolean, Literal::Boolean(v)) => Ok(Value::Bool(*v)),
-            (DataType::Text, Literal::SingleQuotedString(v)) => Ok(Value::Str(v.clone())),
+            (DataType::Boolean, Literal::Boolean(v)) => Ok(Value::Bool(v)),
+            (DataType::Text, Literal::Text(v)) => Ok(Value::Str(v.into_owned())),
             (DataType::Int, Literal::Null)
             | (DataType::Float(_), Literal::Null)
             | (DataType::Boolean, Literal::Null)
diff --git a/src/executor/aggregate/hash.rs b/src/executor/aggregate/hash.rs
index b43c0119..cf69cc41 100644
--- a/src/executor/aggregate/hash.rs
+++ b/src/executor/aggregate/hash.rs
@@ -17,7 +17,7 @@ impl TryFrom<&Evaluated<'_>> for GroupKey {
 
     fn try_from(evaluated: &Evaluated<'_>) -> Result<Self> {
         match evaluated {
-            Evaluated::Literal(l) => Value::try_from(l.as_ref())?.try_into(),
+            Evaluated::Literal(l) => Value::try_from(l)?.try_into(),
             Evaluated::Value(v) => v.as_ref().try_into(),
         }
     }
diff --git a/src/executor/evaluate/error.rs b/src/executor/evaluate/error.rs
index b33c66ad..34d2547e 100644
--- a/src/executor/evaluate/error.rs
+++ b/src/executor/evaluate/error.rs
@@ -10,9 +10,6 @@ pub enum EvaluateError {
     #[error("literal add on non-numeric")]
     LiteralAddOnNonNumeric,
 
-    #[error("unary operation on non-numeric")]
-    LiteralUnaryOperationOnNonNumeric,
-
     #[error("function is not supported: {0}")]
     FunctionNotSupported(String),
 
@@ -36,15 +33,9 @@ pub enum EvaluateError {
     #[error("unsupported compound identifier {0}")]
     UnsupportedCompoundIdentifier(String),
 
-    #[error("unsupported literal binary arithmetic between {0} and {1}")]
-    UnsupportedLiteralBinaryArithmetic(String, String),
-
     #[error("unimplemented")]
     Unimplemented,
 
-    #[error("unreachable literal arithmetic")]
-    UnreachableLiteralArithmetic,
-
     #[error("unreachable empty context")]
     UnreachableEmptyContext,
 
diff --git a/src/executor/evaluate/evaluated.rs b/src/executor/evaluate/evaluated.rs
index 61dd92d1..0e1b006e 100644
--- a/src/executor/evaluate/evaluated.rs
+++ b/src/executor/evaluate/evaluated.rs
@@ -1,10 +1,10 @@
 use {
-    super::EvaluateError,
     crate::{
-        data::value::{TryFromLiteral, Value},
+        data::value::TryFromLiteral,
+        data::{Literal, Value},
         result::{Error, Result},
     },
-    sqlparser::ast::{DataType, Value as Literal},
+    sqlparser::ast::DataType,
     std::{
         borrow::Cow,
         cmp::Ordering,
@@ -14,7 +14,7 @@ use {
 
 #[derive(Clone)]
 pub enum Evaluated<'a> {
-    Literal(Cow<'a, Literal>),
+    Literal(Literal<'a>),
     Value(Cow<'a, Value>),
 }
 
@@ -30,24 +30,12 @@ impl<'a> From<&'a Value> for Evaluated<'a> {
     }
 }
 
-impl<'a> From<Literal> for Evaluated<'a> {
-    fn from(literal: Literal) -> Self {
-        Evaluated::Literal(Cow::Owned(literal))
-    }
-}
-
-impl<'a> From<&'a Literal> for Evaluated<'a> {
-    fn from(literal: &'a Literal) -> Self {
-        Evaluated::Literal(Cow::Borrowed(literal))
-    }
-}
-
 impl TryInto<Value> for Evaluated<'_> {
     type Error = Error;
 
     fn try_into(self) -> Result<Value> {
         match self {
-            Evaluated::Literal(v) => Value::try_from(v.as_ref()),
+            Evaluated::Literal(v) => Value::try_from(v),
             Evaluated::Value(v) => Ok(v.into_owned()),
         }
     }
@@ -58,7 +46,7 @@ impl<'a> PartialEq for Evaluated<'a> {
         match (self, other) {
             (Evaluated::Literal(a), Evaluated::Literal(b)) => a == b,
             (Evaluated::Literal(b), Evaluated::Value(a))
-            | (Evaluated::Value(a), Evaluated::Literal(b)) => a == b,
+            | (Evaluated::Value(a), Evaluated::Literal(b)) => a.as_ref() == b,
             (Evaluated::Value(a), Evaluated::Value(b)) => a == b,
         }
     }
@@ -67,96 +55,37 @@ impl<'a> PartialEq for Evaluated<'a> {
 impl<'a> PartialOrd for Evaluated<'a> {
     fn partial_cmp(&self, other: &Evaluated<'a>) -> Option<Ordering> {
         match (self, other) {
-            (Evaluated::Literal(l), Evaluated::Literal(r)) => {
-                literal_partial_cmp(l.as_ref(), r.as_ref())
-            }
+            (Evaluated::Literal(l), Evaluated::Literal(r)) => l.partial_cmp(r),
             (Evaluated::Literal(l), Evaluated::Value(r)) => {
-                r.as_ref().partial_cmp(l.as_ref()).map(|o| o.reverse())
+                r.as_ref().partial_cmp(l).map(|o| o.reverse())
             }
-            (Evaluated::Value(l), Evaluated::Literal(r)) => l.as_ref().partial_cmp(r.as_ref()),
+            (Evaluated::Value(l), Evaluated::Literal(r)) => l.as_ref().partial_cmp(r),
             (Evaluated::Value(l), Evaluated::Value(r)) => l.as_ref().partial_cmp(r.as_ref()),
         }
     }
 }
 
-fn literal_partial_cmp(l: &Literal, r: &Literal) -> Option<Ordering> {
-    match (l, r) {
-        (Literal::Number(l, false), Literal::Number(r, false)) => {
-            match (l.parse::<i64>(), r.parse::<i64>()) {
-                (Ok(l), Ok(r)) => Some(l.cmp(&r)),
-                (_, Ok(r)) => match l.parse::<f64>() {
-                    Ok(l) => l.partial_cmp(&(r as f64)),
-                    _ => None,
-                },
-                (Ok(l), _) => match r.parse::<f64>() {
-                    Ok(r) => (l as f64).partial_cmp(&r),
-                    _ => None,
-                },
-                _ => match (l.parse::<f64>(), r.parse::<f64>()) {
-                    (Ok(l), Ok(r)) => l.partial_cmp(&r),
-                    _ => None,
-                },
-            }
-        }
-        (Literal::SingleQuotedString(l), Literal::SingleQuotedString(r)) => Some(l.cmp(r)),
-        _ => None,
-    }
-}
-
 macro_rules! binary_op {
     ($name:ident, $op:tt) => {
         pub fn $name<'b>(&self, other: &Evaluated<'a>) -> Result<Evaluated<'b>> {
-            let literal_binary_op = |l: &Literal, r: &Literal| match (l, r) {
-                (Literal::Number(l, false), Literal::Number(r, false)) => {
-                    match (l.parse::<i64>(), r.parse::<i64>()) {
-                        (Ok(l), Ok(r)) => Ok(Literal::Number((l $op r).to_string(), false)),
-                        (Ok(l), _) => match r.parse::<f64>() {
-                            Ok(r) => Ok(Literal::Number(((l as f64) $op r).to_string(), false)),
-                            _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-                        },
-                        (_, Ok(r)) => match l.parse::<f64>() {
-                            Ok(l) => Ok(Literal::Number((l $op (r as f64)).to_string(), false)),
-                            _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-                        },
-                        (_, _) => match (l.parse::<f64>(), r.parse::<f64>()) {
-                            (Ok(l), Ok(r)) => Ok(Literal::Number((l $op r).to_string(), false)),
-                            _ => Err(EvaluateError::UnreachableLiteralArithmetic.into()),
-                        },
-                    }.map(Evaluated::from)
-                }
-                (Literal::Null, Literal::Number(_, false))
-                | (Literal::Number(_, false), Literal::Null)
-                | (Literal::Null, Literal::Null) => {
-                    Ok(Evaluated::from(Literal::Null))
-                }
-                _ => Err(
-                    EvaluateError::UnsupportedLiteralBinaryArithmetic(
-                        l.to_string(),
-                        r.to_string()
-                    ).into()
-                ),
-            };
-
-            let value_binary_op = |l: &Value, r: &Value| {
-                l.$name(r).map(Evaluated::from)
-            };
+            let value_binary_op = |l: &Value, r: &Value| l.$name(r).map(Evaluated::from);
 
             match (self, other) {
                 (Evaluated::Literal(l), Evaluated::Literal(r)) => {
-                    literal_binary_op(l.as_ref(), r.as_ref())
+                    l.$name(r).map(Evaluated::Literal)
                 }
                 (Evaluated::Literal(l), Evaluated::Value(r)) => {
-                    value_binary_op(&Value::try_from(l.as_ref())?, r.as_ref())
+                    value_binary_op(&Value::try_from(l)?, r.as_ref())
                 }
                 (Evaluated::Value(l), Evaluated::Literal(r)) => {
-                    value_binary_op(l.as_ref(), &Value::try_from(r.as_ref())?)
+                    value_binary_op(l.as_ref(), &Value::try_from(r)?)
                 }
                 (Evaluated::Value(l), Evaluated::Value(r)) => {
                     value_binary_op(l.as_ref(), r.as_ref())
                 }
             }
         }
-    }
+    };
 }
 
 impl<'a> Evaluated<'a> {
@@ -166,42 +95,15 @@ impl<'a> Evaluated<'a> {
     binary_op!(divide, /);
 
     pub fn unary_plus(&self) -> Result<Evaluated<'a>> {
-        let unary_plus = |v: &Literal| match v {
-            Literal::Number(v, false) => v
-                .parse::<i64>()
-                .map_or_else(
-                    |_| v.parse::<f64>().map(|_| self.to_owned()),
-                    |_| Ok(self.to_owned()),
-                )
-                .map_err(|_| EvaluateError::LiteralUnaryOperationOnNonNumeric.into()),
-            Literal::Null => Ok(Evaluated::from(Literal::Null)),
-            _ => Err(EvaluateError::LiteralUnaryOperationOnNonNumeric.into()),
-        };
-
         match self {
-            Evaluated::Literal(v) => unary_plus(&v),
+            Evaluated::Literal(v) => v.unary_plus().map(Evaluated::Literal),
             Evaluated::Value(v) => v.unary_plus().map(Evaluated::from),
         }
     }
 
     pub fn unary_minus(&self) -> Result<Evaluated<'a>> {
-        let unary_minus = |v: &Literal| match v {
-            Literal::Number(v, false) => v
-                .parse::<i64>()
-                .map_or_else(
-                    |_| {
-                        v.parse::<f64>()
-                            .map(|v| Literal::Number((-v).to_string(), false))
-                    },
-                    |v| Ok(Literal::Number((-v).to_string(), false)),
-                )
-                .map_err(|_| EvaluateError::LiteralUnaryOperationOnNonNumeric.into()),
-            Literal::Null => Ok(Literal::Null),
-            _ => Err(EvaluateError::LiteralUnaryOperationOnNonNumeric.into()),
-        };
-
         match self {
-            Evaluated::Literal(v) => unary_minus(&v).map(Evaluated::from),
+            Evaluated::Literal(v) => v.unary_minus().map(Evaluated::Literal),
             Evaluated::Value(v) => v.unary_minus().map(Evaluated::from),
         }
     }
@@ -220,7 +122,7 @@ impl<'a> Evaluated<'a> {
     pub fn is_some(&self) -> bool {
         match self {
             Evaluated::Value(v) => v.is_some(),
-            Evaluated::Literal(v) => v.as_ref() != &Literal::Null,
+            Evaluated::Literal(v) => !matches!(v, &Literal::Null),
         }
     }
 }
diff --git a/src/executor/evaluate/mod.rs b/src/executor/evaluate/mod.rs
index ea2fa06b..b530b3b1 100644
--- a/src/executor/evaluate/mod.rs
+++ b/src/executor/evaluate/mod.rs
@@ -4,17 +4,16 @@ mod evaluated;
 use {
     super::{context::FilterContext, select::select},
     crate::{
-        data::{get_name, Value},
+        data::{get_name, Literal, Value},
         result::Result,
         store::Store,
     },
     async_recursion::async_recursion,
     futures::stream::{StreamExt, TryStreamExt},
     im_rc::HashMap,
-    sqlparser::ast::{
-        BinaryOperator, Expr, Function, FunctionArg, UnaryOperator, Value as Literal,
-    },
+    sqlparser::ast::{BinaryOperator, Expr, Function, FunctionArg, UnaryOperator},
     std::{
+        borrow::Cow,
         convert::{TryFrom, TryInto},
         fmt::Debug,
         rc::Rc,
@@ -39,17 +38,9 @@ pub async fn evaluate<'a, T: 'static + Debug>(
     };
 
     match expr {
-        Expr::Value(value) => match value {
-            Literal::Number(_, false)
-            | Literal::Boolean(_)
-            | Literal::SingleQuotedString(_)
-            | Literal::Null => Ok(Evaluated::from(value)),
-            _ => Err(EvaluateError::Unimplemented.into()),
-        },
+        Expr::Value(value) => Literal::try_from(value).map(Evaluated::Literal),
         Expr::Identifier(ident) => match ident.quote_style {
-            Some(_) => Ok(Evaluated::from(Literal::SingleQuotedString(
-                ident.value.to_string(),
-            ))),
+            Some(_) => Ok(Literal::Text(Cow::Borrowed(&ident.value))).map(Evaluated::Literal),
             None => {
                 let context = context.ok_or(EvaluateError::UnreachableEmptyContext)?;
 
diff --git a/src/executor/update.rs b/src/executor/update.rs
index 951bb99f..d06bed9c 100644
--- a/src/executor/update.rs
+++ b/src/executor/update.rs
@@ -71,7 +71,7 @@ impl<'a, T: 'static + Debug> Update<'a, T> {
                 let ColumnDef { data_type, .. } = column_def;
 
                 match evaluate(self.storage, context, None, value, false).await? {
-                    Evaluated::Literal(v) => Value::try_from_literal(data_type, v.as_ref()),
+                    Evaluated::Literal(v) => Value::try_from_literal(data_type, &v),
                     Evaluated::Value(v) => Ok(v.into_owned()),
                 }
                 .map(Some)
diff --git a/src/result.rs b/src/result.rs
index 0f416f70..f44a307a 100644
--- a/src/result.rs
+++ b/src/result.rs
@@ -1,6 +1,6 @@
 use {
     crate::{
-        data::{RowError, TableError, ValueError},
+        data::{LiteralError, RowError, TableError, ValueError},
         executor::{
             AggregateError, BlendError, CreateTableError, EvaluateError, ExecuteError, FetchError,
             FilterError, JoinError, LimitError, SelectError, UpdateError, ValidateError,
@@ -52,6 +52,8 @@ pub enum Error {
     #[error(transparent)]
     Value(#[from] ValueError),
     #[error(transparent)]
+    Literal(#[from] LiteralError),
+    #[error(transparent)]
     CreateTable(#[from] CreateTableError),
 }
 
@@ -79,6 +81,7 @@ impl PartialEq for Error {
             (Table(e), Table(e2)) => e == e2,
             (Validate(e), Validate(e2)) => e == e2,
             (Value(e), Value(e2)) => e == e2,
+            (Literal(e), Literal(e2)) => e == e2,
             (CreateTable(e), CreateTable(e2)) => e == e2,
             _ => false,
         }
diff --git a/src/storages/sled_storage/alter_table.rs b/src/storages/sled_storage/alter_table.rs
index 6e31abe3..399b68de 100644
--- a/src/storages/sled_storage/alter_table.rs
+++ b/src/storages/sled_storage/alter_table.rs
@@ -5,7 +5,7 @@ use boolinator::Boolinator;
 use std::iter::once;
 use std::str;
 
-use sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, Ident, Value as Literal};
+use sqlparser::ast::{ColumnDef, ColumnOption, ColumnOptionDef, Ident};
 
 use super::{error::err_into, fetch_schema, SledStorage};
 use crate::utils::Vector;
@@ -158,10 +158,7 @@ impl AlterTable for SledStorage {
 
         let value = match (default, nullable) {
             (Some(value), _) => try_self!(self, value),
-            (None, true) => try_self!(
-                self,
-                Value::from_data_type(&data_type, nullable, &Literal::Null)
-            ),
+            (None, true) => Value::Null,
             (None, false) => {
                 return Err((
                     self,


Test patch:
diff --git a/src/tests/arithmetic.rs b/src/tests/arithmetic.rs
index 46513d73..2ed1f9e6 100644
--- a/src/tests/arithmetic.rs
+++ b/src/tests/arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::*;
+use {crate::*, std::borrow::Cow};
 
 test_case!(arithmetic, async move {
     run!(
@@ -81,8 +81,11 @@ test_case!(arithmetic, async move {
             "UPDATE Arith SET aaa = 1",
         ),
         (
-            EvaluateError::UnsupportedLiteralBinaryArithmetic("true".to_owned(), "1".to_owned())
-                .into(),
+            LiteralError::UnsupportedBinaryArithmetic(
+                format!("{:?}", data::Literal::Boolean(true)),
+                format!("{:?}", data::Literal::Number(Cow::Owned("1".to_owned()))),
+            )
+            .into(),
             "SELECT * FROM Arith WHERE TRUE + 1 = 1",
         ),
     ];
diff --git a/src/tests/error.rs b/src/tests/error.rs
index f8f9b0c6..3bf81971 100644
--- a/src/tests/error.rs
+++ b/src/tests/error.rs
@@ -46,6 +46,10 @@ test_case!(error, async move {
             RowError::TooManyValues.into(),
             "INSERT INTO TableA VALUES (100), (100, 200);",
         ),
+        (
+            LiteralError::UnsupportedLiteralType(r#"X'123'"#.to_owned()).into(),
+            "SELECT * FROM TableA Where id = X'123';",
+        ),
         #[cfg(feature = "alter-table")]
         (
             ExecuteError::UnsupportedAlterTableOperation(
diff --git a/src/tests/filter.rs b/src/tests/filter.rs
index 8e82d3f0..7f1c0cd9 100644
--- a/src/tests/filter.rs
+++ b/src/tests/filter.rs
@@ -95,11 +95,11 @@ test_case!(filter, async move {
 
     let error_sqls = vec![
         (
-            EvaluateError::LiteralUnaryOperationOnNonNumeric.into(),
+            LiteralError::UnaryOperationOnNonNumeric.into(),
             "SELECT id FROM Hunter WHERE +'abcd' > 1.0",
         ),
         (
-            EvaluateError::LiteralUnaryOperationOnNonNumeric.into(),
+            LiteralError::UnaryOperationOnNonNumeric.into(),
             "SELECT id FROM Hunter WHERE -'abcd' < 1.0",
         ),
         (
diff --git a/src/tests/function/cast.rs b/src/tests/function/cast.rs
index 9410f829..6f2343f3 100644
--- a/src/tests/function/cast.rs
+++ b/src/tests/function/cast.rs
@@ -86,7 +86,7 @@ test_case!(cast_literal, async move {
             r#"SELECT CAST(NULL AS NULL) FROM Item"#,
             Err(ValueError::UnimplementedLiteralCast {
                 data_type: "NULL".to_owned(),
-                literal: "NULL".to_owned(),
+                literal: format!("{:?}", data::Literal::Null),
             }
             .into()),
         ),