feat: make blob(binary) type working (#1818)

* feat: test blob type

* feat: make blob type working

* chore: comment

* Update src/sql/src/statements/insert.rs

Co-authored-by: Lei, HUANG <6406592+v0y4g3r@users.noreply.github.com>

* chore: by CR comments

* fix: comment

* Update src/sql/src/statements/insert.rs

Co-authored-by: Ruihang Xia <waynestxia@gmail.com>

* Update src/sql/src/statements/insert.rs

Co-authored-by: Ruihang Xia <waynestxia@gmail.com>

* fix: test

---------

Co-authored-by: Lei, HUANG <6406592+v0y4g3r@users.noreply.github.com>
Co-authored-by: Ruihang Xia <waynestxia@gmail.com>
This commit is contained in:
dennis zhuang
2023-06-26 16:49:04 +08:00
committed by GitHub
parent a95f8767a8
commit 034564fd27
11 changed files with 335 additions and 71 deletions

View File

@@ -352,7 +352,9 @@ pub fn sql_data_type_to_concrete_data_type(data_type: &SqlDataType) -> Result<Co
SqlDataType::Double => Ok(ConcreteDataType::float64_datatype()),
SqlDataType::Boolean => Ok(ConcreteDataType::boolean_datatype()),
SqlDataType::Date => Ok(ConcreteDataType::date_datatype()),
SqlDataType::Varbinary(_) => Ok(ConcreteDataType::binary_datatype()),
SqlDataType::Blob(_) | SqlDataType::Bytea | SqlDataType::Varbinary(_) => {
Ok(ConcreteDataType::binary_datatype())
}
SqlDataType::Datetime(_) => Ok(ConcreteDataType::datetime_datatype()),
SqlDataType::Timestamp(precision, _) => Ok(precision
.as_ref()

View File

@@ -15,7 +15,7 @@ use sqlparser::ast::{ObjectName, Query, SetExpr, Statement, UnaryOperator, Value
use sqlparser::parser::ParserError;
use crate::ast::{Expr, Value};
use crate::error::{self, Result};
use crate::error::Result;
use crate::statements::query::Query as GtQuery;
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -24,6 +24,15 @@ pub struct Insert {
pub inner: Statement,
}
macro_rules! parse_fail {
($expr: expr) => {
return crate::error::ParseSqlValueSnafu {
msg: format!("{:?}", $expr),
}
.fail();
};
}
impl Insert {
pub fn table_name(&self) -> &ObjectName {
match &self.inner {
@@ -39,8 +48,9 @@ impl Insert {
}
}
pub fn values_body(&self) -> Result<Option<Vec<Vec<Value>>>> {
let values = match &self.inner {
/// Extracts the literal insert statement body if possible
pub fn values_body(&self) -> Result<Vec<Vec<Value>>> {
match &self.inner {
Statement::Insert {
source:
box Query {
@@ -48,11 +58,41 @@ impl Insert {
..
},
..
} => Some(sql_exprs_to_values(rows)?),
_ => None,
};
} => sql_exprs_to_values(rows),
_ => unreachable!(),
}
}
Ok(values)
/// Returns true when the insert statement can extract literal values.
/// The rules is the same as function `values_body()`.
pub fn can_extract_values(&self) -> bool {
match &self.inner {
Statement::Insert {
source:
box Query {
body: box SetExpr::Values(Values { rows, .. }),
..
},
..
} => rows.iter().all(|es| {
es.iter().all(|expr| match expr {
Expr::Value(_) => true,
Expr::Identifier(ident) => {
if ident.quote_style.is_none() {
ident.value.to_lowercase() == "default"
} else {
ident.quote_style == Some('"')
}
}
Expr::UnaryOp { op, expr } => {
matches!(op, UnaryOperator::Minus | UnaryOperator::Plus)
&& matches!(&**expr, Expr::Value(Value::Number(_, _)))
}
_ => false,
})
}),
_ => false,
}
}
pub fn query_body(&self) -> Result<Option<GtQuery>> {
@@ -63,19 +103,6 @@ impl Insert {
_ => None,
})
}
pub fn is_insert_select(&self) -> bool {
matches!(
self.inner,
Statement::Insert {
source: box Query {
body: box SetExpr::Select { .. },
..
},
..
}
)
}
}
fn sql_exprs_to_values(exprs: &Vec<Vec<Expr>>) -> Result<Vec<Vec<Value>>> {
@@ -87,9 +114,19 @@ fn sql_exprs_to_values(exprs: &Vec<Vec<Expr>>) -> Result<Vec<Vec<Value>>> {
Expr::Value(v) => v.clone(),
Expr::Identifier(ident) => {
if ident.quote_style.is_none() {
Value::Placeholder(ident.value.clone())
// Special processing for `default` value
if ident.value.to_lowercase() == "default" {
Value::Placeholder(ident.value.clone())
} else {
parse_fail!(expr);
}
} else {
Value::SingleQuotedString(ident.value.clone())
// Identifiers with double quotes, we treat them as strings.
if ident.quote_style == Some('"') {
Value::SingleQuotedString(ident.value.clone())
} else {
parse_fail!(expr);
}
}
}
Expr::UnaryOp { op, expr }
@@ -102,17 +139,11 @@ fn sql_exprs_to_values(exprs: &Vec<Vec<Expr>>) -> Result<Vec<Vec<Value>>> {
_ => unreachable!(),
}
} else {
return error::ParseSqlValueSnafu {
msg: format!("{expr:?}"),
}
.fail();
parse_fail!(expr);
}
}
_ => {
return error::ParseSqlValueSnafu {
msg: format!("{expr:?}"),
}
.fail()
parse_fail!(expr);
}
});
}
@@ -150,7 +181,7 @@ mod tests {
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap().unwrap();
let values = insert.values_body().unwrap();
assert_eq!(values, vec![vec![Value::Number("-1".to_string(), false)]]);
}
_ => unreachable!(),
@@ -163,7 +194,7 @@ mod tests {
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap().unwrap();
let values = insert.values_body().unwrap();
assert_eq!(values, vec![vec![Value::Number("1".to_string(), false)]]);
}
_ => unreachable!(),
@@ -179,7 +210,7 @@ mod tests {
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap().unwrap();
let values = insert.values_body().unwrap();
assert_eq!(values, vec![vec![Value::Placeholder("default".to_owned())]]);
}
_ => unreachable!(),
@@ -195,7 +226,7 @@ mod tests {
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap().unwrap();
let values = insert.values_body().unwrap();
assert_eq!(values, vec![vec![Value::Placeholder("DEFAULT".to_owned())]]);
}
_ => unreachable!(),
@@ -204,14 +235,14 @@ mod tests {
#[test]
fn test_insert_value_with_quoted_string() {
// insert "'default'"
// insert 'default'
let sql = "INSERT INTO my_table VALUES('default')";
let stmt = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {})
.unwrap()
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap().unwrap();
let values = insert.values_body().unwrap();
assert_eq!(
values,
vec![vec![Value::SingleQuotedString("default".to_owned())]]
@@ -219,6 +250,33 @@ mod tests {
}
_ => unreachable!(),
}
// insert "default". Treating double-quoted identifiers as strings.
let sql = "INSERT INTO my_table VALUES(\"default\")";
let stmt = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {})
.unwrap()
.remove(0);
match stmt {
Statement::Insert(insert) => {
let values = insert.values_body().unwrap();
assert_eq!(
values,
vec![vec![Value::SingleQuotedString("default".to_owned())]]
);
}
_ => unreachable!(),
}
let sql = "INSERT INTO my_table VALUES(`default`)";
let stmt = ParserContext::create_with_dialect(sql, &GreptimeDbDialect {})
.unwrap()
.remove(0);
match stmt {
Statement::Insert(insert) => {
assert!(insert.values_body().is_err());
}
_ => unreachable!(),
}
}
#[test]
@@ -229,7 +287,6 @@ mod tests {
.remove(0);
match stmt {
Statement::Insert(insert) => {
assert!(insert.is_insert_select());
let q = insert.query_body().unwrap().unwrap();
assert!(matches!(
q.inner,