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

dheres 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 231027274 feat: Support simple Arrays with Literals (#2194)
231027274 is described below

commit 231027274b13e92fbbfb6011f149fec414d55ab8
Author: Dmitry Patsura <[email protected]>
AuthorDate: Wed Apr 13 13:17:36 2022 +0300

    feat: Support simple Arrays with Literals (#2194)
    
    * feat: Support simple Arrays (literals only)
    
    * Update datafusion/core/src/sql/planner.rs
    
    Co-authored-by: Andrew Lamb <[email protected]>
    
    Co-authored-by: Andrew Lamb <[email protected]>
---
 datafusion/core/src/sql/planner.rs | 72 +++++++++++++++++++++++++++++++++++++-
 datafusion/core/tests/sql/expr.rs  | 19 ++++++++++
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/datafusion/core/src/sql/planner.rs 
b/datafusion/core/src/sql/planner.rs
index 84ddace9a..12bae6ba0 100644
--- a/datafusion/core/src/sql/planner.rs
+++ b/datafusion/core/src/sql/planner.rs
@@ -49,6 +49,7 @@ use crate::{
 };
 use arrow::datatypes::*;
 use hashbrown::HashMap;
+
 use sqlparser::ast::{
     BinaryOperator, DataType as SQLDataType, DateTimeField, Expr as SQLExpr, 
FunctionArg,
     FunctionArgExpr, Ident, Join, JoinConstraint, JoinOperator, ObjectName, 
Query,
@@ -1437,6 +1438,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
                 fractional_seconds_precision,
             ),
 
+            SQLExpr::Array(arr) => self.sql_array_literal(arr.elem, schema),
+
             SQLExpr::Identifier(id) => {
                 if id.value.starts_with('@') {
                     // TODO: figure out if ScalarVariables should be 
insensitive.
@@ -2117,6 +2120,51 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
             .get_table_provider(tables_reference)
             .is_some()
     }
+
+    fn sql_array_literal(
+        &self,
+        elements: Vec<SQLExpr>,
+        schema: &DFSchema,
+    ) -> Result<Expr> {
+        let mut values = Vec::with_capacity(elements.len());
+
+        for element in elements {
+            let value = self.sql_expr_to_logical_expr(element, schema)?;
+            match value {
+                Expr::Literal(scalar) => {
+                    values.push(scalar);
+                }
+                _ => {
+                    return Err(DataFusionError::NotImplemented(format!(
+                        "Arrays with elements other than literal are not 
supported: {}",
+                        value
+                    )));
+                }
+            }
+        }
+
+        let data_types: HashSet<DataType> =
+            values.iter().map(|e| e.get_datatype()).collect();
+
+        if data_types.is_empty() {
+            Ok(Expr::Literal(ScalarValue::List(
+                None,
+                Box::new(DataType::Utf8),
+            )))
+        } else if data_types.len() > 1 {
+            Err(DataFusionError::NotImplemented(format!(
+                "Arrays with different types are not supported: {:?}",
+                data_types,
+            )))
+        } else {
+            let data_type = values[0].get_datatype();
+
+            Ok(Expr::Literal(ScalarValue::List(
+                Some(Box::new(values)),
+                Box::new(data_type),
+            )))
+        }
+    }
 }
 
 /// Remove join expressions from a filter expression
@@ -2260,7 +2308,7 @@ fn parse_sql_number(n: &str) -> Result<Expr> {
 mod tests {
     use crate::datasource::empty::EmptyTable;
     use crate::physical_plan::functions::Volatility;
-    use crate::{logical_plan::create_udf, sql::parser::DFParser};
+    use crate::{assert_contains, logical_plan::create_udf, 
sql::parser::DFParser};
     use datafusion_expr::ScalarFunctionImplementation;
 
     use super::*;
@@ -2968,6 +3016,28 @@ mod tests {
         );
     }
 
+    #[test]
+    fn select_array_no_common_type() {
+        let sql = "SELECT [1, true, null]";
+        let err = logical_plan(sql).expect_err("query should have failed");
+
+        // HashSet doesn't guarantee order
+        assert_contains!(
+            err.to_string(),
+            r#"Arrays with different types are not supported: "#
+        );
+    }
+
+    #[test]
+    fn select_array_non_literal_type() {
+        let sql = "SELECT [now()]";
+        let err = logical_plan(sql).expect_err("query should have failed");
+        assert_eq!(
+            r#"NotImplemented("Arrays with elements other than literal are not 
supported: now()")"#,
+            format!("{:?}", err)
+        );
+    }
+
     #[test]
     fn 
select_simple_aggregate_with_groupby_and_column_is_in_aggregate_and_groupby() {
         quick_test(
diff --git a/datafusion/core/tests/sql/expr.rs 
b/datafusion/core/tests/sql/expr.rs
index 565af3203..de71764ba 100644
--- a/datafusion/core/tests/sql/expr.rs
+++ b/datafusion/core/tests/sql/expr.rs
@@ -457,6 +457,25 @@ async fn test_crypto_expressions() -> Result<()> {
     Ok(())
 }
 
+#[tokio::test]
+async fn test_array_literals() -> Result<()> {
+    // Named, just another syntax
+    test_expression!("ARRAY[1,2,3,4,5]", "[1, 2, 3, 4, 5]");
+    // Unnamed variant
+    test_expression!("[1,2,3,4,5]", "[1, 2, 3, 4, 5]");
+    test_expression!("[true, false]", "[true, false]");
+    test_expression!("['str1', 'str2']", "[str1, str2]");
+    test_expression!("[[1,2], [3,4]]", "[[1, 2], [3, 4]]");
+
+    // TODO: Not supported in parser, uncomment when it will be available
+    // test_expression!(
+    //     "[]",
+    //     "[]"
+    // );
+
+    Ok(())
+}
+
 #[tokio::test]
 async fn test_interval_expressions() -> Result<()> {
     // day nano intervals

Reply via email to