This is an automated email from the ASF dual-hosted git repository.

xudong963 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new 85d53634c feat: support double quoted literal strings for 
dialects(such as mysql,bigquery,spark) (#3056)
85d53634c is described below

commit 85d53634c4d26a3b9e545878e377860c14d01d7d
Author: kamille <[email protected]>
AuthorDate: Mon Aug 8 21:57:49 2022 +0800

    feat: support double quoted literal strings for dialects(such as 
mysql,bigquery,spark) (#3056)
    
    * support double quoted string.
    
    * add test.
    
    * add case sensitie test case.
    
    * fix naming error.
---
 datafusion/core/tests/sql/select.rs | 36 +++++++++++++++++++++++++++++++
 datafusion/sql/src/planner.rs       | 43 ++++++++++++++++++++++++++++++++-----
 2 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/datafusion/core/tests/sql/select.rs 
b/datafusion/core/tests/sql/select.rs
index 5056fa02f..b48f8d7cc 100644
--- a/datafusion/core/tests/sql/select.rs
+++ b/datafusion/core/tests/sql/select.rs
@@ -1210,3 +1210,39 @@ async fn unprojected_filter() {
     ];
     assert_batches_sorted_eq!(expected, &results);
 }
+
+#[tokio::test]
+async fn case_sensitive_in_default_dialect() {
+    let int32_array = Int32Array::from(vec![1, 2, 3, 4, 5]);
+    let schema = Schema::new(vec![Field::new("INT32", DataType::Int32, 
false)]);
+    let batch =
+        RecordBatch::try_new(Arc::new(schema), 
vec![Arc::new(int32_array)]).unwrap();
+
+    let ctx = SessionContext::new();
+    let table = MemTable::try_new(batch.schema(), vec![vec![batch]]).unwrap();
+    ctx.register_table("t", Arc::new(table)).unwrap();
+
+    {
+        let sql = "select \"int32\" from t";
+        let plan = ctx.create_logical_plan(sql);
+        assert!(plan.is_err());
+    }
+
+    {
+        let sql = "select \"INT32\" from t";
+        let actual = execute_to_batches(&ctx, sql).await;
+
+        let expected = vec![
+            "+-------+",
+            "| INT32 |",
+            "+-------+",
+            "| 1     |",
+            "| 2     |",
+            "| 3     |",
+            "| 4     |",
+            "| 5     |",
+            "+-------+",
+        ];
+        assert_batches_eq!(expected, &actual);
+    }
+}
diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs
index 8c615a24a..dc71dc4b2 100644
--- a/datafusion/sql/src/planner.rs
+++ b/datafusion/sql/src/planner.rs
@@ -98,7 +98,9 @@ fn plan_key(key: SQLExpr) -> Result<ScalarValue> {
         SQLExpr::Value(Value::Number(s, _)) => {
             ScalarValue::Int64(Some(s.parse().unwrap()))
         }
-        SQLExpr::Value(Value::SingleQuotedString(s)) => 
ScalarValue::Utf8(Some(s)),
+        SQLExpr::Value(Value::SingleQuotedString(s) | 
Value::DoubleQuotedString(s)) => {
+            ScalarValue::Utf8(Some(s))
+        }
         _ => {
             return Err(DataFusionError::SQL(ParserError(format!(
                 "Unsuported index key expression: {:?}",
@@ -1596,7 +1598,9 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
                 row.into_iter()
                     .map(|v| match v {
                         SQLExpr::Value(Value::Number(n, _)) => 
parse_sql_number(&n),
-                        SQLExpr::Value(Value::SingleQuotedString(s)) => 
Ok(lit(s)),
+                        SQLExpr::Value(
+                            Value::SingleQuotedString(s) | 
Value::DoubleQuotedString(s),
+                        ) => Ok(lit(s)),
                         SQLExpr::Value(Value::Null) => {
                             Ok(Expr::Literal(ScalarValue::Null))
                         }
@@ -1638,7 +1642,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
     ) -> Result<Expr> {
         match sql {
             SQLExpr::Value(Value::Number(n, _)) => parse_sql_number(&n),
-            SQLExpr::Value(Value::SingleQuotedString(ref s)) => 
Ok(lit(s.clone())),
+            SQLExpr::Value(Value::SingleQuotedString(ref s) | 
Value::DoubleQuotedString(ref s)) => Ok(lit(s.clone())),
             SQLExpr::Value(Value::Boolean(n)) => Ok(lit(n)),
             SQLExpr::Value(Value::Null) => 
Ok(Expr::Literal(ScalarValue::Null)),
             SQLExpr::Extract { field, expr } => Ok(Expr::ScalarFunction {
@@ -2219,7 +2223,9 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
 
         // Only handle string exprs for now
         let value = match value {
-            SQLExpr::Value(Value::SingleQuotedString(s)) => s,
+            SQLExpr::Value(
+                Value::SingleQuotedString(s) | Value::DoubleQuotedString(s),
+            ) => s,
             _ => {
                 return Err(DataFusionError::NotImplemented(format!(
                     "Unsupported interval argument. Expected string literal, 
got: {:?}",
@@ -2595,6 +2601,7 @@ fn parse_sql_number(n: &str) -> Result<Expr> {
 mod tests {
     use super::*;
     use crate::assert_contains;
+    use sqlparser::dialect::{Dialect, GenericDialect, MySqlDialect};
     use std::any::Any;
 
     #[test]
@@ -4371,8 +4378,16 @@ mod tests {
     }
 
     fn logical_plan(sql: &str) -> Result<LogicalPlan> {
+        let dialect = &GenericDialect {};
+        logical_plan_with_dialect(sql, dialect)
+    }
+
+    fn logical_plan_with_dialect(
+        sql: &str,
+        dialect: &dyn Dialect,
+    ) -> Result<LogicalPlan> {
         let planner = SqlToRel::new(&MockContextProvider {});
-        let result = DFParser::parse_sql(sql);
+        let result = DFParser::parse_sql_with_dialect(sql, dialect);
         let mut ast = result?;
         planner.statement_to_plan(ast.pop_front().unwrap())
     }
@@ -4840,6 +4855,24 @@ mod tests {
         quick_test(sql, expected);
     }
 
+    #[test]
+    fn test_double_quoted_literal_string() {
+        // Assert double quoted literal string is parsed correctly like single 
quoted one in specific dialect.
+        let dialect = &MySqlDialect {};
+        let single_quoted_res = format!(
+            "{:?}",
+            logical_plan_with_dialect("SELECT '1'", dialect).unwrap()
+        );
+        let double_quoted_res = format!(
+            "{:?}",
+            logical_plan_with_dialect("SELECT \"1\"", dialect).unwrap()
+        );
+        assert_eq!(single_quoted_res, double_quoted_res);
+
+        // It should return error in other dialect.
+        assert!(logical_plan("SELECT \"1\"").is_err());
+    }
+
     fn assert_field_not_found(err: DataFusionError, name: &str) {
         match err {
             DataFusionError::SchemaError { .. } => {

Reply via email to