datafusion_sql/expr/
substring.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::planner::{ContextProvider, PlannerContext, SqlToRel};
19use datafusion_common::{not_impl_err, plan_err};
20use datafusion_common::{DFSchema, Result, ScalarValue};
21use datafusion_expr::{planner::PlannerResult, Expr};
22
23use sqlparser::ast::Expr as SQLExpr;
24
25impl<S: ContextProvider> SqlToRel<'_, S> {
26    pub(super) fn sql_substring_to_expr(
27        &self,
28        expr: Box<SQLExpr>,
29        substring_from: Option<Box<SQLExpr>>,
30        substring_for: Option<Box<SQLExpr>>,
31        schema: &DFSchema,
32        planner_context: &mut PlannerContext,
33    ) -> Result<Expr> {
34        let mut substring_args = match (substring_from, substring_for) {
35            (Some(from_expr), Some(for_expr)) => {
36                let arg =
37                    self.sql_expr_to_logical_expr(*expr, schema, planner_context)?;
38                let from_logic =
39                    self.sql_expr_to_logical_expr(*from_expr, schema, planner_context)?;
40                let for_logic =
41                    self.sql_expr_to_logical_expr(*for_expr, schema, planner_context)?;
42                vec![arg, from_logic, for_logic]
43            }
44            (Some(from_expr), None) => {
45                let arg =
46                    self.sql_expr_to_logical_expr(*expr, schema, planner_context)?;
47                let from_logic =
48                    self.sql_expr_to_logical_expr(*from_expr, schema, planner_context)?;
49                vec![arg, from_logic]
50            }
51            (None, Some(for_expr)) => {
52                let arg =
53                    self.sql_expr_to_logical_expr(*expr, schema, planner_context)?;
54                let from_logic = Expr::Literal(ScalarValue::Int64(Some(1)), None);
55                let for_logic =
56                    self.sql_expr_to_logical_expr(*for_expr, schema, planner_context)?;
57                vec![arg, from_logic, for_logic]
58            }
59            (None, None) => {
60                let orig_sql = SQLExpr::Substring {
61                    expr,
62                    substring_from: None,
63                    substring_for: None,
64                    special: false,
65                    shorthand: false,
66                };
67
68                return plan_err!("Substring without for/from is not valid {orig_sql:?}");
69            }
70        };
71
72        // Try to plan the substring expression using one of the registered planners
73        for planner in self.context_provider.get_expr_planners() {
74            match planner.plan_substring(substring_args)? {
75                PlannerResult::Planned(expr) => return Ok(expr),
76                PlannerResult::Original(args) => {
77                    substring_args = args;
78                }
79            }
80        }
81
82        not_impl_err!("Substring could not be planned by registered expr planner. \
83                        Hint: Please try with `unicode_expressions` DataFusion feature enabled")
84    }
85}