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

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 2af3d3a55b Implement user defined planner for position (#11243)
2af3d3a55b is described below

commit 2af3d3a55ba67726ff915743680380fb02a3e2c2
Author: Xin Li <[email protected]>
AuthorDate: Sat Jul 6 04:55:55 2024 -0700

    Implement user defined planner for position (#11243)
    
    * Implement user defined planner for position
    
    * Fix format
    
    * Move planner to session_state
    
    * Extract function
---
 datafusion/core/src/execution/session_state.rs |  2 ++
 datafusion/expr/src/planner.rs                 |  6 ++++
 datafusion/functions/src/unicode/mod.rs        |  1 +
 datafusion/functions/src/unicode/planner.rs    | 36 +++++++++++++++++++++
 datafusion/sql/src/expr/mod.rs                 | 44 +++++++++++++++-----------
 5 files changed, 70 insertions(+), 19 deletions(-)

diff --git a/datafusion/core/src/execution/session_state.rs 
b/datafusion/core/src/execution/session_state.rs
index a831f92def..ffaaa2df5e 100644
--- a/datafusion/core/src/execution/session_state.rs
+++ b/datafusion/core/src/execution/session_state.rs
@@ -240,6 +240,8 @@ impl SessionState {
             Arc::new(functions_array::planner::FieldAccessPlanner),
             #[cfg(feature = "datetime_expressions")]
             Arc::new(functions::datetime::planner::ExtractPlanner),
+            #[cfg(feature = "unicode_expressions")]
+            Arc::new(functions::unicode::planner::PositionPlanner),
         ];
 
         let mut new_self = SessionState {
diff --git a/datafusion/expr/src/planner.rs b/datafusion/expr/src/planner.rs
index bba0228ae0..bcbf5eb203 100644
--- a/datafusion/expr/src/planner.rs
+++ b/datafusion/expr/src/planner.rs
@@ -116,6 +116,12 @@ pub trait UserDefinedSQLPlanner: Send + Sync {
         Ok(PlannerResult::Original(exprs))
     }
 
+    // Plan the POSITION expression, e.g., POSITION(<expr> in <expr>)
+    // returns origin expression arguments if not possible
+    fn plan_position(&self, args: Vec<Expr>) -> 
Result<PlannerResult<Vec<Expr>>> {
+        Ok(PlannerResult::Original(args))
+    }
+
     /// Plan the dictionary literal `{ key: value, ...}`
     ///
     /// Returns origin expression arguments if not possible
diff --git a/datafusion/functions/src/unicode/mod.rs 
b/datafusion/functions/src/unicode/mod.rs
index 9e8c07cd36..a391b8ba11 100644
--- a/datafusion/functions/src/unicode/mod.rs
+++ b/datafusion/functions/src/unicode/mod.rs
@@ -25,6 +25,7 @@ pub mod character_length;
 pub mod find_in_set;
 pub mod left;
 pub mod lpad;
+pub mod planner;
 pub mod reverse;
 pub mod right;
 pub mod rpad;
diff --git a/datafusion/functions/src/unicode/planner.rs 
b/datafusion/functions/src/unicode/planner.rs
new file mode 100644
index 0000000000..4d6f73321b
--- /dev/null
+++ b/datafusion/functions/src/unicode/planner.rs
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! SQL planning extensions like [`PositionPlanner`]
+
+use datafusion_common::Result;
+use datafusion_expr::{
+    expr::ScalarFunction,
+    planner::{PlannerResult, UserDefinedSQLPlanner},
+    Expr,
+};
+
+#[derive(Default)]
+pub struct PositionPlanner;
+
+impl UserDefinedSQLPlanner for PositionPlanner {
+    fn plan_position(&self, args: Vec<Expr>) -> 
Result<PlannerResult<Vec<Expr>>> {
+        Ok(PlannerResult::Planned(Expr::ScalarFunction(
+            ScalarFunction::new_udf(crate::unicode::strpos(), args),
+        )))
+    }
+}
diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs
index 2ddd2d22c0..6295821fa9 100644
--- a/datafusion/sql/src/expr/mod.rs
+++ b/datafusion/sql/src/expr/mod.rs
@@ -629,6 +629,31 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
         }
     }
 
+    fn sql_position_to_expr(
+        &self,
+        substr_expr: SQLExpr,
+        str_expr: SQLExpr,
+        schema: &DFSchema,
+        planner_context: &mut PlannerContext,
+    ) -> Result<Expr> {
+        let substr =
+            self.sql_expr_to_logical_expr(substr_expr, schema, 
planner_context)?;
+        let fullstr = self.sql_expr_to_logical_expr(str_expr, schema, 
planner_context)?;
+        let mut extract_args = vec![fullstr, substr];
+        for planner in self.planners.iter() {
+            match planner.plan_position(extract_args)? {
+                PlannerResult::Planned(expr) => return Ok(expr),
+                PlannerResult::Original(args) => {
+                    extract_args = args;
+                }
+            }
+        }
+
+        not_impl_err!(
+            "Position not supported by UserDefinedExtensionPlanners: 
{extract_args:?}"
+        )
+    }
+
     fn try_plan_dictionary_literal(
         &self,
         fields: Vec<DictionaryField>,
@@ -924,25 +949,6 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
         };
         Ok(Expr::ScalarFunction(ScalarFunction::new_udf(fun, args)))
     }
-    fn sql_position_to_expr(
-        &self,
-        substr_expr: SQLExpr,
-        str_expr: SQLExpr,
-        schema: &DFSchema,
-        planner_context: &mut PlannerContext,
-    ) -> Result<Expr> {
-        let fun = self
-            .context_provider
-            .get_function_meta("strpos")
-            .ok_or_else(|| {
-                internal_datafusion_err!("Unable to find expected 'strpos' 
function")
-            })?;
-        let substr =
-            self.sql_expr_to_logical_expr(substr_expr, schema, 
planner_context)?;
-        let fullstr = self.sql_expr_to_logical_expr(str_expr, schema, 
planner_context)?;
-        let args = vec![fullstr, substr];
-        Ok(Expr::ScalarFunction(ScalarFunction::new_udf(fun, args)))
-    }
 }
 
 #[cfg(test)]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to