datafusion_sql/unparser/
expr.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 datafusion_expr::expr::{AggregateFunctionParams, Unnest, WindowFunctionParams};
19use sqlparser::ast::Value::SingleQuotedString;
20use sqlparser::ast::{
21    self, Array, BinaryOperator, CaseWhen, Expr as AstExpr, Function, Ident, Interval,
22    ObjectName, OrderByOptions, Subscript, TimezoneInfo, UnaryOperator, ValueWithSpan,
23};
24use std::sync::Arc;
25use std::vec;
26
27use super::dialect::IntervalStyle;
28use super::Unparser;
29use arrow::array::{
30    types::{
31        ArrowTemporalType, Time32MillisecondType, Time32SecondType,
32        Time64MicrosecondType, Time64NanosecondType, TimestampMicrosecondType,
33        TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType,
34    },
35    ArrayRef, Date32Array, Date64Array, PrimitiveArray,
36};
37use arrow::datatypes::{DataType, Decimal128Type, Decimal256Type, DecimalType};
38use arrow::util::display::array_value_to_string;
39use datafusion_common::{
40    internal_datafusion_err, internal_err, not_impl_err, plan_err, Column, Result,
41    ScalarValue,
42};
43use datafusion_expr::{
44    expr::{Alias, Exists, InList, ScalarFunction, Sort, WindowFunction},
45    Between, BinaryExpr, Case, Cast, Expr, GroupingSet, Like, Operator, TryCast,
46};
47use sqlparser::ast::helpers::attached_token::AttachedToken;
48use sqlparser::tokenizer::Span;
49
50/// Convert a DataFusion [`Expr`] to [`ast::Expr`]
51///
52/// This function is the opposite of [`SqlToRel::sql_to_expr`] and can be used
53/// to, among other things, convert [`Expr`]s to SQL strings. Such strings could
54/// be used to pass filters or other expressions to another SQL engine.
55///
56/// # Errors
57///
58/// Throws an error if [`Expr`] can not be represented by an [`ast::Expr`]
59///
60/// # See Also
61///
62/// * [`Unparser`] for more control over the conversion to SQL
63/// * [`plan_to_sql`] for converting a [`LogicalPlan`] to SQL
64///
65/// # Example
66/// ```
67/// use datafusion_expr::{col, lit};
68/// use datafusion_sql::unparser::expr_to_sql;
69/// let expr = col("a").gt(lit(4)); // form an expression `a > 4`
70/// let sql = expr_to_sql(&expr).unwrap(); // convert to ast::Expr
71/// // use the Display impl to convert to SQL text
72/// assert_eq!(sql.to_string(), "(a > 4)")
73/// ```
74///
75/// [`SqlToRel::sql_to_expr`]: crate::planner::SqlToRel::sql_to_expr
76/// [`plan_to_sql`]: crate::unparser::plan_to_sql
77/// [`LogicalPlan`]: datafusion_expr::logical_plan::LogicalPlan
78pub fn expr_to_sql(expr: &Expr) -> Result<ast::Expr> {
79    let unparser = Unparser::default();
80    unparser.expr_to_sql(expr)
81}
82
83const LOWEST: &BinaryOperator = &BinaryOperator::Or;
84// Closest precedence we have to IS operator is BitwiseAnd (any other) in PG docs
85// (https://www.postgresql.org/docs/7.2/sql-precedence.html)
86const IS: &BinaryOperator = &BinaryOperator::BitwiseAnd;
87
88impl Unparser<'_> {
89    pub fn expr_to_sql(&self, expr: &Expr) -> Result<ast::Expr> {
90        let mut root_expr = self.expr_to_sql_inner(expr)?;
91        if self.pretty {
92            root_expr = self.remove_unnecessary_nesting(root_expr, LOWEST, LOWEST);
93        }
94        Ok(root_expr)
95    }
96
97    #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
98    fn expr_to_sql_inner(&self, expr: &Expr) -> Result<ast::Expr> {
99        match expr {
100            Expr::InList(InList {
101                expr,
102                list,
103                negated,
104            }) => {
105                let list_expr = list
106                    .iter()
107                    .map(|e| self.expr_to_sql_inner(e))
108                    .collect::<Result<Vec<_>>>()?;
109                Ok(ast::Expr::InList {
110                    expr: Box::new(self.expr_to_sql_inner(expr)?),
111                    list: list_expr,
112                    negated: *negated,
113                })
114            }
115            Expr::ScalarFunction(ScalarFunction { func, args }) => {
116                let func_name = func.name();
117
118                if let Some(expr) = self
119                    .dialect
120                    .scalar_function_to_sql_overrides(self, func_name, args)?
121                {
122                    return Ok(expr);
123                }
124
125                self.scalar_function_to_sql(func_name, args)
126            }
127            Expr::Between(Between {
128                expr,
129                negated,
130                low,
131                high,
132            }) => {
133                let sql_parser_expr = self.expr_to_sql_inner(expr)?;
134                let sql_low = self.expr_to_sql_inner(low)?;
135                let sql_high = self.expr_to_sql_inner(high)?;
136                Ok(ast::Expr::Nested(Box::new(self.between_op_to_sql(
137                    sql_parser_expr,
138                    *negated,
139                    sql_low,
140                    sql_high,
141                ))))
142            }
143            Expr::Column(col) => self.col_to_sql(col),
144            Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
145                let l = self.expr_to_sql_inner(left.as_ref())?;
146                let r = self.expr_to_sql_inner(right.as_ref())?;
147                let op = self.op_to_sql(op)?;
148
149                Ok(ast::Expr::Nested(Box::new(self.binary_op_to_sql(l, r, op))))
150            }
151            Expr::Case(Case {
152                expr,
153                when_then_expr,
154                else_expr,
155            }) => {
156                let conditions = when_then_expr
157                    .iter()
158                    .map(|(cond, result)| {
159                        Ok(CaseWhen {
160                            condition: self.expr_to_sql_inner(cond)?,
161                            result: self.expr_to_sql_inner(result)?,
162                        })
163                    })
164                    .collect::<Result<Vec<CaseWhen>>>()?;
165
166                let operand = match expr.as_ref() {
167                    Some(e) => match self.expr_to_sql_inner(e) {
168                        Ok(sql_expr) => Some(Box::new(sql_expr)),
169                        Err(_) => None,
170                    },
171                    None => None,
172                };
173                let else_result = match else_expr.as_ref() {
174                    Some(e) => match self.expr_to_sql_inner(e) {
175                        Ok(sql_expr) => Some(Box::new(sql_expr)),
176                        Err(_) => None,
177                    },
178                    None => None,
179                };
180
181                Ok(ast::Expr::Case {
182                    operand,
183                    conditions,
184                    else_result,
185                })
186            }
187            Expr::Cast(Cast { expr, data_type }) => {
188                Ok(self.cast_to_sql(expr, data_type)?)
189            }
190            Expr::Literal(value, _) => Ok(self.scalar_to_sql(value)?),
191            Expr::Alias(Alias { expr, name: _, .. }) => self.expr_to_sql_inner(expr),
192            Expr::WindowFunction(window_fun) => {
193                let WindowFunction {
194                    fun,
195                    params:
196                        WindowFunctionParams {
197                            args,
198                            partition_by,
199                            order_by,
200                            window_frame,
201                            ..
202                        },
203                } = window_fun.as_ref();
204                let func_name = fun.name();
205
206                let args = self.function_args_to_sql(args)?;
207
208                let units = match window_frame.units {
209                    datafusion_expr::window_frame::WindowFrameUnits::Rows => {
210                        ast::WindowFrameUnits::Rows
211                    }
212                    datafusion_expr::window_frame::WindowFrameUnits::Range => {
213                        ast::WindowFrameUnits::Range
214                    }
215                    datafusion_expr::window_frame::WindowFrameUnits::Groups => {
216                        ast::WindowFrameUnits::Groups
217                    }
218                };
219
220                let order_by = order_by
221                    .iter()
222                    .map(|sort_expr| self.sort_to_sql(sort_expr))
223                    .collect::<Result<Vec<_>>>()?;
224
225                let start_bound = self.convert_bound(&window_frame.start_bound)?;
226                let end_bound = self.convert_bound(&window_frame.end_bound)?;
227
228                let window_frame = if self.dialect.window_func_support_window_frame(
229                    func_name,
230                    &start_bound,
231                    &end_bound,
232                ) {
233                    Some(ast::WindowFrame {
234                        units,
235                        start_bound,
236                        end_bound: Some(end_bound),
237                    })
238                } else {
239                    None
240                };
241
242                let over = Some(ast::WindowType::WindowSpec(ast::WindowSpec {
243                    window_name: None,
244                    partition_by: partition_by
245                        .iter()
246                        .map(|e| self.expr_to_sql_inner(e))
247                        .collect::<Result<Vec<_>>>()?,
248                    order_by,
249                    window_frame,
250                }));
251
252                Ok(ast::Expr::Function(Function {
253                    name: ObjectName::from(vec![Ident {
254                        value: func_name.to_string(),
255                        quote_style: None,
256                        span: Span::empty(),
257                    }]),
258                    args: ast::FunctionArguments::List(ast::FunctionArgumentList {
259                        duplicate_treatment: None,
260                        args,
261                        clauses: vec![],
262                    }),
263                    filter: None,
264                    null_treatment: None,
265                    over,
266                    within_group: vec![],
267                    parameters: ast::FunctionArguments::None,
268                    uses_odbc_syntax: false,
269                }))
270            }
271            Expr::SimilarTo(Like {
272                negated,
273                expr,
274                pattern,
275                escape_char,
276                case_insensitive: _,
277            }) => Ok(ast::Expr::Like {
278                negated: *negated,
279                expr: Box::new(self.expr_to_sql_inner(expr)?),
280                pattern: Box::new(self.expr_to_sql_inner(pattern)?),
281                escape_char: escape_char.map(|c| c.to_string()),
282                any: false,
283            }),
284            Expr::Like(Like {
285                negated,
286                expr,
287                pattern,
288                escape_char,
289                case_insensitive,
290            }) => {
291                if *case_insensitive {
292                    Ok(ast::Expr::ILike {
293                        negated: *negated,
294                        expr: Box::new(self.expr_to_sql_inner(expr)?),
295                        pattern: Box::new(self.expr_to_sql_inner(pattern)?),
296                        escape_char: escape_char.map(|c| c.to_string()),
297                        any: false,
298                    })
299                } else {
300                    Ok(ast::Expr::Like {
301                        negated: *negated,
302                        expr: Box::new(self.expr_to_sql_inner(expr)?),
303                        pattern: Box::new(self.expr_to_sql_inner(pattern)?),
304                        escape_char: escape_char.map(|c| c.to_string()),
305                        any: false,
306                    })
307                }
308            }
309
310            Expr::AggregateFunction(agg) => {
311                let func_name = agg.func.name();
312                let AggregateFunctionParams {
313                    distinct,
314                    args,
315                    filter,
316                    order_by,
317                    ..
318                } = &agg.params;
319
320                let args = self.function_args_to_sql(args)?;
321                let filter = match filter {
322                    Some(filter) => Some(Box::new(self.expr_to_sql_inner(filter)?)),
323                    None => None,
324                };
325                let within_group = if agg.func.is_ordered_set_aggregate() {
326                    order_by
327                        .as_ref()
328                        .unwrap_or(&Vec::new())
329                        .iter()
330                        .map(|sort_expr| self.sort_to_sql(sort_expr))
331                        .collect::<Result<Vec<_>>>()?
332                } else {
333                    Vec::new()
334                };
335                Ok(ast::Expr::Function(Function {
336                    name: ObjectName::from(vec![Ident {
337                        value: func_name.to_string(),
338                        quote_style: None,
339                        span: Span::empty(),
340                    }]),
341                    args: ast::FunctionArguments::List(ast::FunctionArgumentList {
342                        duplicate_treatment: distinct
343                            .then_some(ast::DuplicateTreatment::Distinct),
344                        args,
345                        clauses: vec![],
346                    }),
347                    filter,
348                    null_treatment: None,
349                    over: None,
350                    within_group,
351                    parameters: ast::FunctionArguments::None,
352                    uses_odbc_syntax: false,
353                }))
354            }
355            Expr::ScalarSubquery(subq) => {
356                let sub_statement = self.plan_to_sql(subq.subquery.as_ref())?;
357                let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
358                {
359                    inner_query
360                } else {
361                    return plan_err!(
362                        "Subquery must be a Query, but found {sub_statement:?}"
363                    );
364                };
365                Ok(ast::Expr::Subquery(sub_query))
366            }
367            Expr::InSubquery(insubq) => {
368                let inexpr = Box::new(self.expr_to_sql_inner(insubq.expr.as_ref())?);
369                let sub_statement =
370                    self.plan_to_sql(insubq.subquery.subquery.as_ref())?;
371                let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
372                {
373                    inner_query
374                } else {
375                    return plan_err!(
376                        "Subquery must be a Query, but found {sub_statement:?}"
377                    );
378                };
379                Ok(ast::Expr::InSubquery {
380                    expr: inexpr,
381                    subquery: sub_query,
382                    negated: insubq.negated,
383                })
384            }
385            Expr::Exists(Exists { subquery, negated }) => {
386                let sub_statement = self.plan_to_sql(subquery.subquery.as_ref())?;
387                let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
388                {
389                    inner_query
390                } else {
391                    return plan_err!(
392                        "Subquery must be a Query, but found {sub_statement:?}"
393                    );
394                };
395                Ok(ast::Expr::Exists {
396                    subquery: sub_query,
397                    negated: *negated,
398                })
399            }
400            Expr::IsNull(expr) => {
401                Ok(ast::Expr::IsNull(Box::new(self.expr_to_sql_inner(expr)?)))
402            }
403            Expr::IsNotNull(expr) => Ok(ast::Expr::IsNotNull(Box::new(
404                self.expr_to_sql_inner(expr)?,
405            ))),
406            Expr::IsTrue(expr) => {
407                Ok(ast::Expr::IsTrue(Box::new(self.expr_to_sql_inner(expr)?)))
408            }
409            Expr::IsNotTrue(expr) => Ok(ast::Expr::IsNotTrue(Box::new(
410                self.expr_to_sql_inner(expr)?,
411            ))),
412            Expr::IsFalse(expr) => {
413                Ok(ast::Expr::IsFalse(Box::new(self.expr_to_sql_inner(expr)?)))
414            }
415            Expr::IsNotFalse(expr) => Ok(ast::Expr::IsNotFalse(Box::new(
416                self.expr_to_sql_inner(expr)?,
417            ))),
418            Expr::IsUnknown(expr) => Ok(ast::Expr::IsUnknown(Box::new(
419                self.expr_to_sql_inner(expr)?,
420            ))),
421            Expr::IsNotUnknown(expr) => Ok(ast::Expr::IsNotUnknown(Box::new(
422                self.expr_to_sql_inner(expr)?,
423            ))),
424            Expr::Not(expr) => {
425                let sql_parser_expr = self.expr_to_sql_inner(expr)?;
426                Ok(AstExpr::UnaryOp {
427                    op: UnaryOperator::Not,
428                    expr: Box::new(sql_parser_expr),
429                })
430            }
431            Expr::Negative(expr) => {
432                let sql_parser_expr = self.expr_to_sql_inner(expr)?;
433                Ok(AstExpr::UnaryOp {
434                    op: UnaryOperator::Minus,
435                    expr: Box::new(sql_parser_expr),
436                })
437            }
438            Expr::ScalarVariable(_, ids) => {
439                if ids.is_empty() {
440                    return internal_err!("Not a valid ScalarVariable");
441                }
442
443                Ok(if ids.len() == 1 {
444                    ast::Expr::Identifier(
445                        self.new_ident_without_quote_style(ids[0].to_string()),
446                    )
447                } else {
448                    ast::Expr::CompoundIdentifier(
449                        ids.iter()
450                            .map(|i| self.new_ident_without_quote_style(i.to_string()))
451                            .collect(),
452                    )
453                })
454            }
455            Expr::TryCast(TryCast { expr, data_type }) => {
456                let inner_expr = self.expr_to_sql_inner(expr)?;
457                Ok(ast::Expr::Cast {
458                    kind: ast::CastKind::TryCast,
459                    expr: Box::new(inner_expr),
460                    data_type: self.arrow_dtype_to_ast_dtype(data_type)?,
461                    format: None,
462                })
463            }
464            // TODO: unparsing wildcard addition options
465            #[expect(deprecated)]
466            Expr::Wildcard { qualifier, .. } => {
467                let attached_token = AttachedToken::empty();
468                if let Some(qualifier) = qualifier {
469                    let idents: Vec<Ident> =
470                        qualifier.to_vec().into_iter().map(Ident::new).collect();
471                    Ok(ast::Expr::QualifiedWildcard(
472                        ObjectName::from(idents),
473                        attached_token,
474                    ))
475                } else {
476                    Ok(ast::Expr::Wildcard(attached_token))
477                }
478            }
479            Expr::GroupingSet(grouping_set) => match grouping_set {
480                GroupingSet::GroupingSets(grouping_sets) => {
481                    let expr_ast_sets = grouping_sets
482                        .iter()
483                        .map(|set| {
484                            set.iter()
485                                .map(|e| self.expr_to_sql_inner(e))
486                                .collect::<Result<Vec<_>>>()
487                        })
488                        .collect::<Result<Vec<_>>>()?;
489
490                    Ok(ast::Expr::GroupingSets(expr_ast_sets))
491                }
492                GroupingSet::Cube(cube) => {
493                    let expr_ast_sets = cube
494                        .iter()
495                        .map(|e| {
496                            let sql = self.expr_to_sql_inner(e)?;
497                            Ok(vec![sql])
498                        })
499                        .collect::<Result<Vec<_>>>()?;
500                    Ok(ast::Expr::Cube(expr_ast_sets))
501                }
502                GroupingSet::Rollup(rollup) => {
503                    let expr_ast_sets: Vec<Vec<AstExpr>> = rollup
504                        .iter()
505                        .map(|e| {
506                            let sql = self.expr_to_sql_inner(e)?;
507                            Ok(vec![sql])
508                        })
509                        .collect::<Result<Vec<_>>>()?;
510                    Ok(ast::Expr::Rollup(expr_ast_sets))
511                }
512            },
513            Expr::Placeholder(p) => {
514                Ok(ast::Expr::value(ast::Value::Placeholder(p.id.to_string())))
515            }
516            Expr::OuterReferenceColumn(_, col) => self.col_to_sql(col),
517            Expr::Unnest(unnest) => self.unnest_to_sql(unnest),
518        }
519    }
520
521    pub fn scalar_function_to_sql(
522        &self,
523        func_name: &str,
524        args: &[Expr],
525    ) -> Result<ast::Expr> {
526        match func_name {
527            "make_array" => self.make_array_to_sql(args),
528            "array_element" => self.array_element_to_sql(args),
529            "named_struct" => self.named_struct_to_sql(args),
530            "get_field" => self.get_field_to_sql(args),
531            "map" => self.map_to_sql(args),
532            // TODO: support for the construct and access functions of the `map` type
533            _ => self.scalar_function_to_sql_internal(func_name, args),
534        }
535    }
536
537    fn scalar_function_to_sql_internal(
538        &self,
539        func_name: &str,
540        args: &[Expr],
541    ) -> Result<ast::Expr> {
542        let args = self.function_args_to_sql(args)?;
543        Ok(ast::Expr::Function(Function {
544            name: ObjectName::from(vec![Ident {
545                value: func_name.to_string(),
546                quote_style: None,
547                span: Span::empty(),
548            }]),
549            args: ast::FunctionArguments::List(ast::FunctionArgumentList {
550                duplicate_treatment: None,
551                args,
552                clauses: vec![],
553            }),
554            filter: None,
555            null_treatment: None,
556            over: None,
557            within_group: vec![],
558            parameters: ast::FunctionArguments::None,
559            uses_odbc_syntax: false,
560        }))
561    }
562
563    fn make_array_to_sql(&self, args: &[Expr]) -> Result<ast::Expr> {
564        let args = args
565            .iter()
566            .map(|e| self.expr_to_sql(e))
567            .collect::<Result<Vec<_>>>()?;
568        Ok(ast::Expr::Array(Array {
569            elem: args,
570            named: false,
571        }))
572    }
573
574    fn scalar_value_list_to_sql(&self, array: &ArrayRef) -> Result<ast::Expr> {
575        let mut elem = Vec::new();
576        for i in 0..array.len() {
577            let value = ScalarValue::try_from_array(&array, i)?;
578            elem.push(self.scalar_to_sql(&value)?);
579        }
580
581        Ok(ast::Expr::Array(Array { elem, named: false }))
582    }
583
584    fn array_element_to_sql(&self, args: &[Expr]) -> Result<ast::Expr> {
585        if args.len() != 2 {
586            return internal_err!("array_element must have exactly 2 arguments");
587        }
588        let array = self.expr_to_sql(&args[0])?;
589        let index = self.expr_to_sql(&args[1])?;
590        Ok(ast::Expr::CompoundFieldAccess {
591            root: Box::new(array),
592            access_chain: vec![ast::AccessExpr::Subscript(Subscript::Index { index })],
593        })
594    }
595
596    fn named_struct_to_sql(&self, args: &[Expr]) -> Result<ast::Expr> {
597        if args.len() % 2 != 0 {
598            return internal_err!("named_struct must have an even number of arguments");
599        }
600
601        let args = args
602            .chunks_exact(2)
603            .map(|chunk| {
604                let key = match &chunk[0] {
605                    Expr::Literal(ScalarValue::Utf8(Some(s)), _) => self.new_ident_quoted_if_needs(s.to_string()),
606                    _ => return internal_err!("named_struct expects even arguments to be strings, but received: {:?}", &chunk[0])
607                };
608
609                Ok(ast::DictionaryField {
610                    key,
611                    value: Box::new(self.expr_to_sql(&chunk[1])?),
612                })
613            })
614            .collect::<Result<Vec<_>>>()?;
615
616        Ok(ast::Expr::Dictionary(args))
617    }
618
619    fn get_field_to_sql(&self, args: &[Expr]) -> Result<ast::Expr> {
620        if args.len() != 2 {
621            return internal_err!("get_field must have exactly 2 arguments");
622        }
623
624        let mut id = match &args[0] {
625            Expr::Column(col) => match self.col_to_sql(col)? {
626                ast::Expr::Identifier(ident) => vec![ident],
627                ast::Expr::CompoundIdentifier(idents) => idents,
628                other => return internal_err!("expected col_to_sql to return an Identifier or CompoundIdentifier, but received: {:?}", other),
629            },
630            _ => return internal_err!("get_field expects first argument to be column, but received: {:?}", &args[0]),
631        };
632
633        let field = match &args[1] {
634            Expr::Literal(lit, _) => self.new_ident_quoted_if_needs(lit.to_string()),
635            _ => {
636                return internal_err!(
637                "get_field expects second argument to be a string, but received: {:?}",
638                &args[0]
639            )
640            }
641        };
642        id.push(field);
643
644        Ok(ast::Expr::CompoundIdentifier(id))
645    }
646
647    fn map_to_sql(&self, args: &[Expr]) -> Result<ast::Expr> {
648        if args.len() != 2 {
649            return internal_err!("map must have exactly 2 arguments");
650        }
651
652        let ast::Expr::Array(Array { elem: keys, .. }) = self.expr_to_sql(&args[0])?
653        else {
654            return internal_err!(
655                "map expects first argument to be an array, but received: {:?}",
656                &args[0]
657            );
658        };
659
660        let ast::Expr::Array(Array { elem: values, .. }) = self.expr_to_sql(&args[1])?
661        else {
662            return internal_err!(
663                "map expects second argument to be an array, but received: {:?}",
664                &args[1]
665            );
666        };
667
668        let entries = keys
669            .into_iter()
670            .zip(values)
671            .map(|(key, value)| ast::MapEntry {
672                key: Box::new(key),
673                value: Box::new(value),
674            })
675            .collect();
676
677        Ok(ast::Expr::Map(ast::Map { entries }))
678    }
679
680    pub fn sort_to_sql(&self, sort: &Sort) -> Result<ast::OrderByExpr> {
681        let Sort {
682            expr,
683            asc,
684            nulls_first,
685        } = sort;
686        let sql_parser_expr = self.expr_to_sql(expr)?;
687
688        let nulls_first = if self.dialect.supports_nulls_first_in_sort() {
689            Some(*nulls_first)
690        } else {
691            None
692        };
693
694        Ok(ast::OrderByExpr {
695            expr: sql_parser_expr,
696            options: OrderByOptions {
697                asc: Some(*asc),
698                nulls_first,
699            },
700            with_fill: None,
701        })
702    }
703
704    fn ast_type_for_date64_in_cast(&self) -> ast::DataType {
705        if self.dialect.use_timestamp_for_date64() {
706            ast::DataType::Timestamp(None, TimezoneInfo::None)
707        } else {
708            ast::DataType::Datetime(None)
709        }
710    }
711
712    pub fn col_to_sql(&self, col: &Column) -> Result<ast::Expr> {
713        if let Some(table_ref) = &col.relation {
714            let mut id = if self.dialect.full_qualified_col() {
715                table_ref.to_vec()
716            } else {
717                vec![table_ref.table().to_string()]
718            };
719            id.push(col.name.to_string());
720            return Ok(ast::Expr::CompoundIdentifier(
721                id.iter()
722                    .map(|i| self.new_ident_quoted_if_needs(i.to_string()))
723                    .collect(),
724            ));
725        }
726        Ok(ast::Expr::Identifier(
727            self.new_ident_quoted_if_needs(col.name.to_string()),
728        ))
729    }
730
731    fn convert_bound(
732        &self,
733        bound: &datafusion_expr::window_frame::WindowFrameBound,
734    ) -> Result<ast::WindowFrameBound> {
735        match bound {
736            datafusion_expr::window_frame::WindowFrameBound::Preceding(val) => {
737                Ok(ast::WindowFrameBound::Preceding({
738                    let val = self.scalar_to_sql(val)?;
739                    if let ast::Expr::Value(ValueWithSpan {
740                        value: ast::Value::Null,
741                        span: _,
742                    }) = &val
743                    {
744                        None
745                    } else {
746                        Some(Box::new(val))
747                    }
748                }))
749            }
750            datafusion_expr::window_frame::WindowFrameBound::Following(val) => {
751                Ok(ast::WindowFrameBound::Following({
752                    let val = self.scalar_to_sql(val)?;
753                    if let ast::Expr::Value(ValueWithSpan {
754                        value: ast::Value::Null,
755                        span: _,
756                    }) = &val
757                    {
758                        None
759                    } else {
760                        Some(Box::new(val))
761                    }
762                }))
763            }
764            datafusion_expr::window_frame::WindowFrameBound::CurrentRow => {
765                Ok(ast::WindowFrameBound::CurrentRow)
766            }
767        }
768    }
769
770    pub(crate) fn function_args_to_sql(
771        &self,
772        args: &[Expr],
773    ) -> Result<Vec<ast::FunctionArg>> {
774        args.iter()
775            .map(|e| {
776                #[expect(deprecated)]
777                if matches!(
778                    e,
779                    Expr::Wildcard {
780                        qualifier: None,
781                        ..
782                    }
783                ) {
784                    Ok(ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Wildcard))
785                } else {
786                    self.expr_to_sql(e)
787                        .map(|e| ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e)))
788                }
789            })
790            .collect::<Result<Vec<_>>>()
791    }
792
793    /// This function can create an identifier with or without quotes based on the dialect rules
794    pub(super) fn new_ident_quoted_if_needs(&self, ident: String) -> Ident {
795        let quote_style = self.dialect.identifier_quote_style(&ident);
796        Ident {
797            value: ident,
798            quote_style,
799            span: Span::empty(),
800        }
801    }
802
803    pub(super) fn new_ident_without_quote_style(&self, str: String) -> Ident {
804        Ident {
805            value: str,
806            quote_style: None,
807            span: Span::empty(),
808        }
809    }
810
811    pub(super) fn binary_op_to_sql(
812        &self,
813        lhs: ast::Expr,
814        rhs: ast::Expr,
815        op: BinaryOperator,
816    ) -> ast::Expr {
817        ast::Expr::BinaryOp {
818            left: Box::new(lhs),
819            op,
820            right: Box::new(rhs),
821        }
822    }
823
824    /// Given an expression of the form `((a + b) * (c * d))`,
825    /// the parenthesis is redundant if the precedence of the nested expression is already higher
826    /// than the surrounding operators' precedence. The above expression would become
827    /// `(a + b) * c * d`.
828    ///
829    /// Also note that when fetching the precedence of a nested expression, we ignore other nested
830    /// expressions, so precedence of expr `(a * (b + c))` equals `*` and not `+`.
831    fn remove_unnecessary_nesting(
832        &self,
833        expr: ast::Expr,
834        left_op: &BinaryOperator,
835        right_op: &BinaryOperator,
836    ) -> ast::Expr {
837        match expr {
838            ast::Expr::Nested(nested) => {
839                let surrounding_precedence = self
840                    .sql_op_precedence(left_op)
841                    .max(self.sql_op_precedence(right_op));
842
843                let inner_precedence = self.inner_precedence(&nested);
844
845                let not_associative =
846                    matches!(left_op, BinaryOperator::Minus | BinaryOperator::Divide);
847
848                if inner_precedence == surrounding_precedence && not_associative {
849                    ast::Expr::Nested(Box::new(
850                        self.remove_unnecessary_nesting(*nested, LOWEST, LOWEST),
851                    ))
852                } else if inner_precedence >= surrounding_precedence {
853                    self.remove_unnecessary_nesting(*nested, left_op, right_op)
854                } else {
855                    ast::Expr::Nested(Box::new(
856                        self.remove_unnecessary_nesting(*nested, LOWEST, LOWEST),
857                    ))
858                }
859            }
860            ast::Expr::BinaryOp { left, op, right } => ast::Expr::BinaryOp {
861                left: Box::new(self.remove_unnecessary_nesting(*left, left_op, &op)),
862                right: Box::new(self.remove_unnecessary_nesting(*right, &op, right_op)),
863                op,
864            },
865            ast::Expr::IsTrue(expr) => ast::Expr::IsTrue(Box::new(
866                self.remove_unnecessary_nesting(*expr, left_op, IS),
867            )),
868            ast::Expr::IsNotTrue(expr) => ast::Expr::IsNotTrue(Box::new(
869                self.remove_unnecessary_nesting(*expr, left_op, IS),
870            )),
871            ast::Expr::IsFalse(expr) => ast::Expr::IsFalse(Box::new(
872                self.remove_unnecessary_nesting(*expr, left_op, IS),
873            )),
874            ast::Expr::IsNotFalse(expr) => ast::Expr::IsNotFalse(Box::new(
875                self.remove_unnecessary_nesting(*expr, left_op, IS),
876            )),
877            ast::Expr::IsNull(expr) => ast::Expr::IsNull(Box::new(
878                self.remove_unnecessary_nesting(*expr, left_op, IS),
879            )),
880            ast::Expr::IsNotNull(expr) => ast::Expr::IsNotNull(Box::new(
881                self.remove_unnecessary_nesting(*expr, left_op, IS),
882            )),
883            ast::Expr::IsUnknown(expr) => ast::Expr::IsUnknown(Box::new(
884                self.remove_unnecessary_nesting(*expr, left_op, IS),
885            )),
886            ast::Expr::IsNotUnknown(expr) => ast::Expr::IsNotUnknown(Box::new(
887                self.remove_unnecessary_nesting(*expr, left_op, IS),
888            )),
889            _ => expr,
890        }
891    }
892
893    fn inner_precedence(&self, expr: &ast::Expr) -> u8 {
894        match expr {
895            ast::Expr::Nested(_) | ast::Expr::Identifier(_) | ast::Expr::Value(_) => 100,
896            ast::Expr::BinaryOp { op, .. } => self.sql_op_precedence(op),
897            // Closest precedence we currently have to Between is PGLikeMatch
898            // (https://www.postgresql.org/docs/7.2/sql-precedence.html)
899            ast::Expr::Between { .. } => {
900                self.sql_op_precedence(&BinaryOperator::PGLikeMatch)
901            }
902            _ => 0,
903        }
904    }
905
906    pub(super) fn between_op_to_sql(
907        &self,
908        expr: ast::Expr,
909        negated: bool,
910        low: ast::Expr,
911        high: ast::Expr,
912    ) -> ast::Expr {
913        ast::Expr::Between {
914            expr: Box::new(expr),
915            negated,
916            low: Box::new(low),
917            high: Box::new(high),
918        }
919    }
920
921    fn sql_op_precedence(&self, op: &BinaryOperator) -> u8 {
922        match self.sql_to_op(op) {
923            Ok(op) => op.precedence(),
924            Err(_) => 0,
925        }
926    }
927
928    fn sql_to_op(&self, op: &BinaryOperator) -> Result<Operator> {
929        match op {
930            BinaryOperator::Eq => Ok(Operator::Eq),
931            BinaryOperator::NotEq => Ok(Operator::NotEq),
932            BinaryOperator::Lt => Ok(Operator::Lt),
933            BinaryOperator::LtEq => Ok(Operator::LtEq),
934            BinaryOperator::Gt => Ok(Operator::Gt),
935            BinaryOperator::GtEq => Ok(Operator::GtEq),
936            BinaryOperator::Plus => Ok(Operator::Plus),
937            BinaryOperator::Minus => Ok(Operator::Minus),
938            BinaryOperator::Multiply => Ok(Operator::Multiply),
939            BinaryOperator::Divide => Ok(Operator::Divide),
940            BinaryOperator::Modulo => Ok(Operator::Modulo),
941            BinaryOperator::And => Ok(Operator::And),
942            BinaryOperator::Or => Ok(Operator::Or),
943            BinaryOperator::PGRegexMatch => Ok(Operator::RegexMatch),
944            BinaryOperator::PGRegexIMatch => Ok(Operator::RegexIMatch),
945            BinaryOperator::PGRegexNotMatch => Ok(Operator::RegexNotMatch),
946            BinaryOperator::PGRegexNotIMatch => Ok(Operator::RegexNotIMatch),
947            BinaryOperator::PGILikeMatch => Ok(Operator::ILikeMatch),
948            BinaryOperator::PGNotLikeMatch => Ok(Operator::NotLikeMatch),
949            BinaryOperator::PGLikeMatch => Ok(Operator::LikeMatch),
950            BinaryOperator::PGNotILikeMatch => Ok(Operator::NotILikeMatch),
951            BinaryOperator::BitwiseAnd => Ok(Operator::BitwiseAnd),
952            BinaryOperator::BitwiseOr => Ok(Operator::BitwiseOr),
953            BinaryOperator::BitwiseXor => Ok(Operator::BitwiseXor),
954            BinaryOperator::PGBitwiseShiftRight => Ok(Operator::BitwiseShiftRight),
955            BinaryOperator::PGBitwiseShiftLeft => Ok(Operator::BitwiseShiftLeft),
956            BinaryOperator::StringConcat => Ok(Operator::StringConcat),
957            BinaryOperator::AtArrow => Ok(Operator::AtArrow),
958            BinaryOperator::ArrowAt => Ok(Operator::ArrowAt),
959            BinaryOperator::Arrow => Ok(Operator::Arrow),
960            BinaryOperator::LongArrow => Ok(Operator::LongArrow),
961            BinaryOperator::HashArrow => Ok(Operator::HashArrow),
962            BinaryOperator::HashLongArrow => Ok(Operator::HashLongArrow),
963            BinaryOperator::AtAt => Ok(Operator::AtAt),
964            BinaryOperator::DuckIntegerDivide | BinaryOperator::MyIntegerDivide => {
965                Ok(Operator::IntegerDivide)
966            }
967            BinaryOperator::HashMinus => Ok(Operator::HashMinus),
968            BinaryOperator::AtQuestion => Ok(Operator::AtQuestion),
969            BinaryOperator::Question => Ok(Operator::Question),
970            BinaryOperator::QuestionAnd => Ok(Operator::QuestionAnd),
971            BinaryOperator::QuestionPipe => Ok(Operator::QuestionPipe),
972            _ => not_impl_err!("unsupported operation: {op:?}"),
973        }
974    }
975
976    fn op_to_sql(&self, op: &Operator) -> Result<BinaryOperator> {
977        match op {
978            Operator::Eq => Ok(BinaryOperator::Eq),
979            Operator::NotEq => Ok(BinaryOperator::NotEq),
980            Operator::Lt => Ok(BinaryOperator::Lt),
981            Operator::LtEq => Ok(BinaryOperator::LtEq),
982            Operator::Gt => Ok(BinaryOperator::Gt),
983            Operator::GtEq => Ok(BinaryOperator::GtEq),
984            Operator::Plus => Ok(BinaryOperator::Plus),
985            Operator::Minus => Ok(BinaryOperator::Minus),
986            Operator::Multiply => Ok(BinaryOperator::Multiply),
987            Operator::Divide => Ok(self.dialect.division_operator()),
988            Operator::Modulo => Ok(BinaryOperator::Modulo),
989            Operator::And => Ok(BinaryOperator::And),
990            Operator::Or => Ok(BinaryOperator::Or),
991            Operator::IsDistinctFrom => not_impl_err!("unsupported operation: {op:?}"),
992            Operator::IsNotDistinctFrom => not_impl_err!("unsupported operation: {op:?}"),
993            Operator::RegexMatch => Ok(BinaryOperator::PGRegexMatch),
994            Operator::RegexIMatch => Ok(BinaryOperator::PGRegexIMatch),
995            Operator::RegexNotMatch => Ok(BinaryOperator::PGRegexNotMatch),
996            Operator::RegexNotIMatch => Ok(BinaryOperator::PGRegexNotIMatch),
997            Operator::ILikeMatch => Ok(BinaryOperator::PGILikeMatch),
998            Operator::NotLikeMatch => Ok(BinaryOperator::PGNotLikeMatch),
999            Operator::LikeMatch => Ok(BinaryOperator::PGLikeMatch),
1000            Operator::NotILikeMatch => Ok(BinaryOperator::PGNotILikeMatch),
1001            Operator::BitwiseAnd => Ok(BinaryOperator::BitwiseAnd),
1002            Operator::BitwiseOr => Ok(BinaryOperator::BitwiseOr),
1003            Operator::BitwiseXor => Ok(BinaryOperator::BitwiseXor),
1004            Operator::BitwiseShiftRight => Ok(BinaryOperator::PGBitwiseShiftRight),
1005            Operator::BitwiseShiftLeft => Ok(BinaryOperator::PGBitwiseShiftLeft),
1006            Operator::StringConcat => Ok(BinaryOperator::StringConcat),
1007            Operator::AtArrow => Ok(BinaryOperator::AtArrow),
1008            Operator::ArrowAt => Ok(BinaryOperator::ArrowAt),
1009            Operator::Arrow => Ok(BinaryOperator::Arrow),
1010            Operator::LongArrow => Ok(BinaryOperator::LongArrow),
1011            Operator::HashArrow => Ok(BinaryOperator::HashArrow),
1012            Operator::HashLongArrow => Ok(BinaryOperator::HashLongArrow),
1013            Operator::AtAt => Ok(BinaryOperator::AtAt),
1014            Operator::IntegerDivide => Ok(BinaryOperator::DuckIntegerDivide),
1015            Operator::HashMinus => Ok(BinaryOperator::HashMinus),
1016            Operator::AtQuestion => Ok(BinaryOperator::AtQuestion),
1017            Operator::Question => Ok(BinaryOperator::Question),
1018            Operator::QuestionAnd => Ok(BinaryOperator::QuestionAnd),
1019            Operator::QuestionPipe => Ok(BinaryOperator::QuestionPipe),
1020        }
1021    }
1022
1023    fn handle_timestamp<T: ArrowTemporalType>(
1024        &self,
1025        v: &ScalarValue,
1026        tz: &Option<Arc<str>>,
1027    ) -> Result<ast::Expr>
1028    where
1029        i64: From<T::Native>,
1030    {
1031        let ts = if let Some(tz) = tz {
1032            v.to_array()?
1033                .as_any()
1034                .downcast_ref::<PrimitiveArray<T>>()
1035                .ok_or(internal_datafusion_err!(
1036                    "Failed to downcast type {v:?} to arrow array"
1037                ))?
1038                .value_as_datetime_with_tz(0, tz.parse()?)
1039                .ok_or(internal_datafusion_err!(
1040                    "Unable to convert {v:?} to DateTime"
1041                ))?
1042                .to_string()
1043        } else {
1044            v.to_array()?
1045                .as_any()
1046                .downcast_ref::<PrimitiveArray<T>>()
1047                .ok_or(internal_datafusion_err!(
1048                    "Failed to downcast type {v:?} to arrow array"
1049                ))?
1050                .value_as_datetime(0)
1051                .ok_or(internal_datafusion_err!(
1052                    "Unable to convert {v:?} to DateTime"
1053                ))?
1054                .to_string()
1055        };
1056
1057        let time_unit = match T::DATA_TYPE {
1058            DataType::Timestamp(unit, _) => unit,
1059            _ => {
1060                return Err(internal_datafusion_err!(
1061                    "Expected Timestamp, got {:?}",
1062                    T::DATA_TYPE
1063                ))
1064            }
1065        };
1066
1067        Ok(ast::Expr::Cast {
1068            kind: ast::CastKind::Cast,
1069            expr: Box::new(ast::Expr::value(SingleQuotedString(ts))),
1070            data_type: self.dialect.timestamp_cast_dtype(&time_unit, &None),
1071            format: None,
1072        })
1073    }
1074
1075    fn handle_time<T: ArrowTemporalType>(&self, v: &ScalarValue) -> Result<ast::Expr>
1076    where
1077        i64: From<T::Native>,
1078    {
1079        let time = v
1080            .to_array()?
1081            .as_any()
1082            .downcast_ref::<PrimitiveArray<T>>()
1083            .ok_or(internal_datafusion_err!(
1084                "Failed to downcast type {v:?} to arrow array"
1085            ))?
1086            .value_as_time(0)
1087            .ok_or(internal_datafusion_err!("Unable to convert {v:?} to Time"))?
1088            .to_string();
1089        Ok(ast::Expr::Cast {
1090            kind: ast::CastKind::Cast,
1091            expr: Box::new(ast::Expr::value(SingleQuotedString(time))),
1092            data_type: ast::DataType::Time(None, TimezoneInfo::None),
1093            format: None,
1094        })
1095    }
1096
1097    // Explicit type cast on ast::Expr::Value is not needed by underlying engine for certain types
1098    // For example: CAST(Utf8("binary_value") AS Binary) and  CAST(Utf8("dictionary_value") AS Dictionary)
1099    fn cast_to_sql(&self, expr: &Expr, data_type: &DataType) -> Result<ast::Expr> {
1100        let inner_expr = self.expr_to_sql_inner(expr)?;
1101        match inner_expr {
1102            ast::Expr::Value(_) => match data_type {
1103                DataType::Dictionary(_, _) | DataType::Binary | DataType::BinaryView => {
1104                    Ok(inner_expr)
1105                }
1106                _ => Ok(ast::Expr::Cast {
1107                    kind: ast::CastKind::Cast,
1108                    expr: Box::new(inner_expr),
1109                    data_type: self.arrow_dtype_to_ast_dtype(data_type)?,
1110                    format: None,
1111                }),
1112            },
1113            _ => Ok(ast::Expr::Cast {
1114                kind: ast::CastKind::Cast,
1115                expr: Box::new(inner_expr),
1116                data_type: self.arrow_dtype_to_ast_dtype(data_type)?,
1117                format: None,
1118            }),
1119        }
1120    }
1121
1122    /// DataFusion ScalarValues sometimes require a ast::Expr to construct.
1123    /// For example ScalarValue::Date32(d) corresponds to the ast::Expr CAST('datestr' as DATE)
1124    fn scalar_to_sql(&self, v: &ScalarValue) -> Result<ast::Expr> {
1125        match v {
1126            ScalarValue::Null => Ok(ast::Expr::value(ast::Value::Null)),
1127            ScalarValue::Boolean(Some(b)) => {
1128                Ok(ast::Expr::value(ast::Value::Boolean(b.to_owned())))
1129            }
1130            ScalarValue::Boolean(None) => Ok(ast::Expr::value(ast::Value::Null)),
1131            ScalarValue::Float16(Some(f)) => {
1132                Ok(ast::Expr::value(ast::Value::Number(f.to_string(), false)))
1133            }
1134            ScalarValue::Float16(None) => Ok(ast::Expr::value(ast::Value::Null)),
1135            ScalarValue::Float32(Some(f)) => {
1136                let f_val = match f.fract() {
1137                    0.0 => format!("{f:.1}"),
1138                    _ => format!("{f}"),
1139                };
1140                Ok(ast::Expr::value(ast::Value::Number(f_val, false)))
1141            }
1142            ScalarValue::Float32(None) => Ok(ast::Expr::value(ast::Value::Null)),
1143            ScalarValue::Float64(Some(f)) => {
1144                let f_val = match f.fract() {
1145                    0.0 => format!("{f:.1}"),
1146                    _ => format!("{f}"),
1147                };
1148                Ok(ast::Expr::value(ast::Value::Number(f_val, false)))
1149            }
1150            ScalarValue::Float64(None) => Ok(ast::Expr::value(ast::Value::Null)),
1151            ScalarValue::Decimal128(Some(value), precision, scale) => {
1152                Ok(ast::Expr::value(ast::Value::Number(
1153                    Decimal128Type::format_decimal(*value, *precision, *scale),
1154                    false,
1155                )))
1156            }
1157            ScalarValue::Decimal128(None, ..) => Ok(ast::Expr::value(ast::Value::Null)),
1158            ScalarValue::Decimal256(Some(value), precision, scale) => {
1159                Ok(ast::Expr::value(ast::Value::Number(
1160                    Decimal256Type::format_decimal(*value, *precision, *scale),
1161                    false,
1162                )))
1163            }
1164            ScalarValue::Decimal256(None, ..) => Ok(ast::Expr::value(ast::Value::Null)),
1165            ScalarValue::Int8(Some(i)) => {
1166                Ok(ast::Expr::value(ast::Value::Number(i.to_string(), false)))
1167            }
1168            ScalarValue::Int8(None) => Ok(ast::Expr::value(ast::Value::Null)),
1169            ScalarValue::Int16(Some(i)) => {
1170                Ok(ast::Expr::value(ast::Value::Number(i.to_string(), false)))
1171            }
1172            ScalarValue::Int16(None) => Ok(ast::Expr::value(ast::Value::Null)),
1173            ScalarValue::Int32(Some(i)) => {
1174                Ok(ast::Expr::value(ast::Value::Number(i.to_string(), false)))
1175            }
1176            ScalarValue::Int32(None) => Ok(ast::Expr::value(ast::Value::Null)),
1177            ScalarValue::Int64(Some(i)) => {
1178                Ok(ast::Expr::value(ast::Value::Number(i.to_string(), false)))
1179            }
1180            ScalarValue::Int64(None) => Ok(ast::Expr::value(ast::Value::Null)),
1181            ScalarValue::UInt8(Some(ui)) => {
1182                Ok(ast::Expr::value(ast::Value::Number(ui.to_string(), false)))
1183            }
1184            ScalarValue::UInt8(None) => Ok(ast::Expr::value(ast::Value::Null)),
1185            ScalarValue::UInt16(Some(ui)) => {
1186                Ok(ast::Expr::value(ast::Value::Number(ui.to_string(), false)))
1187            }
1188            ScalarValue::UInt16(None) => Ok(ast::Expr::value(ast::Value::Null)),
1189            ScalarValue::UInt32(Some(ui)) => {
1190                Ok(ast::Expr::value(ast::Value::Number(ui.to_string(), false)))
1191            }
1192            ScalarValue::UInt32(None) => Ok(ast::Expr::value(ast::Value::Null)),
1193            ScalarValue::UInt64(Some(ui)) => {
1194                Ok(ast::Expr::value(ast::Value::Number(ui.to_string(), false)))
1195            }
1196            ScalarValue::UInt64(None) => Ok(ast::Expr::value(ast::Value::Null)),
1197            ScalarValue::Utf8(Some(str)) => {
1198                Ok(ast::Expr::value(SingleQuotedString(str.to_string())))
1199            }
1200            ScalarValue::Utf8(None) => Ok(ast::Expr::value(ast::Value::Null)),
1201            ScalarValue::Utf8View(Some(str)) => {
1202                Ok(ast::Expr::value(SingleQuotedString(str.to_string())))
1203            }
1204            ScalarValue::Utf8View(None) => Ok(ast::Expr::value(ast::Value::Null)),
1205            ScalarValue::LargeUtf8(Some(str)) => {
1206                Ok(ast::Expr::value(SingleQuotedString(str.to_string())))
1207            }
1208            ScalarValue::LargeUtf8(None) => Ok(ast::Expr::value(ast::Value::Null)),
1209            ScalarValue::Binary(Some(_)) => not_impl_err!("Unsupported scalar: {v:?}"),
1210            ScalarValue::Binary(None) => Ok(ast::Expr::value(ast::Value::Null)),
1211            ScalarValue::BinaryView(Some(_)) => {
1212                not_impl_err!("Unsupported scalar: {v:?}")
1213            }
1214            ScalarValue::BinaryView(None) => Ok(ast::Expr::value(ast::Value::Null)),
1215            ScalarValue::FixedSizeBinary(..) => {
1216                not_impl_err!("Unsupported scalar: {v:?}")
1217            }
1218            ScalarValue::LargeBinary(Some(_)) => {
1219                not_impl_err!("Unsupported scalar: {v:?}")
1220            }
1221            ScalarValue::LargeBinary(None) => Ok(ast::Expr::value(ast::Value::Null)),
1222            ScalarValue::FixedSizeList(a) => self.scalar_value_list_to_sql(a.values()),
1223            ScalarValue::List(a) => self.scalar_value_list_to_sql(a.values()),
1224            ScalarValue::LargeList(a) => self.scalar_value_list_to_sql(a.values()),
1225            ScalarValue::Date32(Some(_)) => {
1226                let date = v
1227                    .to_array()?
1228                    .as_any()
1229                    .downcast_ref::<Date32Array>()
1230                    .ok_or(internal_datafusion_err!(
1231                        "Unable to downcast to Date32 from Date32 scalar"
1232                    ))?
1233                    .value_as_date(0)
1234                    .ok_or(internal_datafusion_err!(
1235                        "Unable to convert Date32 to NaiveDate"
1236                    ))?;
1237
1238                Ok(ast::Expr::Cast {
1239                    kind: ast::CastKind::Cast,
1240                    expr: Box::new(ast::Expr::value(SingleQuotedString(
1241                        date.to_string(),
1242                    ))),
1243                    data_type: ast::DataType::Date,
1244                    format: None,
1245                })
1246            }
1247            ScalarValue::Date32(None) => Ok(ast::Expr::value(ast::Value::Null)),
1248            ScalarValue::Date64(Some(_)) => {
1249                let datetime = v
1250                    .to_array()?
1251                    .as_any()
1252                    .downcast_ref::<Date64Array>()
1253                    .ok_or(internal_datafusion_err!(
1254                        "Unable to downcast to Date64 from Date64 scalar"
1255                    ))?
1256                    .value_as_datetime(0)
1257                    .ok_or(internal_datafusion_err!(
1258                        "Unable to convert Date64 to NaiveDateTime"
1259                    ))?;
1260
1261                Ok(ast::Expr::Cast {
1262                    kind: ast::CastKind::Cast,
1263                    expr: Box::new(ast::Expr::value(SingleQuotedString(
1264                        datetime.to_string(),
1265                    ))),
1266                    data_type: self.ast_type_for_date64_in_cast(),
1267                    format: None,
1268                })
1269            }
1270            ScalarValue::Date64(None) => Ok(ast::Expr::value(ast::Value::Null)),
1271            ScalarValue::Time32Second(Some(_t)) => {
1272                self.handle_time::<Time32SecondType>(v)
1273            }
1274            ScalarValue::Time32Second(None) => Ok(ast::Expr::value(ast::Value::Null)),
1275            ScalarValue::Time32Millisecond(Some(_t)) => {
1276                self.handle_time::<Time32MillisecondType>(v)
1277            }
1278            ScalarValue::Time32Millisecond(None) => {
1279                Ok(ast::Expr::value(ast::Value::Null))
1280            }
1281            ScalarValue::Time64Microsecond(Some(_t)) => {
1282                self.handle_time::<Time64MicrosecondType>(v)
1283            }
1284            ScalarValue::Time64Microsecond(None) => {
1285                Ok(ast::Expr::value(ast::Value::Null))
1286            }
1287            ScalarValue::Time64Nanosecond(Some(_t)) => {
1288                self.handle_time::<Time64NanosecondType>(v)
1289            }
1290            ScalarValue::Time64Nanosecond(None) => Ok(ast::Expr::value(ast::Value::Null)),
1291            ScalarValue::TimestampSecond(Some(_ts), tz) => {
1292                self.handle_timestamp::<TimestampSecondType>(v, tz)
1293            }
1294            ScalarValue::TimestampSecond(None, _) => {
1295                Ok(ast::Expr::value(ast::Value::Null))
1296            }
1297            ScalarValue::TimestampMillisecond(Some(_ts), tz) => {
1298                self.handle_timestamp::<TimestampMillisecondType>(v, tz)
1299            }
1300            ScalarValue::TimestampMillisecond(None, _) => {
1301                Ok(ast::Expr::value(ast::Value::Null))
1302            }
1303            ScalarValue::TimestampMicrosecond(Some(_ts), tz) => {
1304                self.handle_timestamp::<TimestampMicrosecondType>(v, tz)
1305            }
1306            ScalarValue::TimestampMicrosecond(None, _) => {
1307                Ok(ast::Expr::value(ast::Value::Null))
1308            }
1309            ScalarValue::TimestampNanosecond(Some(_ts), tz) => {
1310                self.handle_timestamp::<TimestampNanosecondType>(v, tz)
1311            }
1312            ScalarValue::TimestampNanosecond(None, _) => {
1313                Ok(ast::Expr::value(ast::Value::Null))
1314            }
1315            ScalarValue::IntervalYearMonth(Some(_))
1316            | ScalarValue::IntervalDayTime(Some(_))
1317            | ScalarValue::IntervalMonthDayNano(Some(_)) => {
1318                self.interval_scalar_to_sql(v)
1319            }
1320            ScalarValue::IntervalYearMonth(None) => {
1321                Ok(ast::Expr::value(ast::Value::Null))
1322            }
1323            ScalarValue::IntervalDayTime(None) => Ok(ast::Expr::value(ast::Value::Null)),
1324            ScalarValue::IntervalMonthDayNano(None) => {
1325                Ok(ast::Expr::value(ast::Value::Null))
1326            }
1327            ScalarValue::DurationSecond(Some(_d)) => {
1328                not_impl_err!("Unsupported scalar: {v:?}")
1329            }
1330            ScalarValue::DurationSecond(None) => Ok(ast::Expr::value(ast::Value::Null)),
1331            ScalarValue::DurationMillisecond(Some(_d)) => {
1332                not_impl_err!("Unsupported scalar: {v:?}")
1333            }
1334            ScalarValue::DurationMillisecond(None) => {
1335                Ok(ast::Expr::value(ast::Value::Null))
1336            }
1337            ScalarValue::DurationMicrosecond(Some(_d)) => {
1338                not_impl_err!("Unsupported scalar: {v:?}")
1339            }
1340            ScalarValue::DurationMicrosecond(None) => {
1341                Ok(ast::Expr::value(ast::Value::Null))
1342            }
1343            ScalarValue::DurationNanosecond(Some(_d)) => {
1344                not_impl_err!("Unsupported scalar: {v:?}")
1345            }
1346            ScalarValue::DurationNanosecond(None) => {
1347                Ok(ast::Expr::value(ast::Value::Null))
1348            }
1349            ScalarValue::Struct(_) => not_impl_err!("Unsupported scalar: {v:?}"),
1350            ScalarValue::Map(_) => not_impl_err!("Unsupported scalar: {v:?}"),
1351            ScalarValue::Union(..) => not_impl_err!("Unsupported scalar: {v:?}"),
1352            ScalarValue::Dictionary(_k, v) => self.scalar_to_sql(v),
1353        }
1354    }
1355
1356    /// MySQL requires INTERVAL sql to be in the format: INTERVAL 1 YEAR + INTERVAL 1 MONTH + INTERVAL 1 DAY etc
1357    /// `<https://dev.mysql.com/doc/refman/8.4/en/expressions.html#temporal-intervals>`
1358    /// Interval sequence can't be wrapped in brackets - (INTERVAL 1 YEAR + INTERVAL 1 MONTH ...) so we need to generate
1359    /// a single INTERVAL expression so it works correct for interval subtraction cases
1360    /// MySQL supports the DAY_MICROSECOND unit type (format is DAYS HOURS:MINUTES:SECONDS.MICROSECONDS), but it is not supported by sqlparser
1361    /// so we calculate the best single interval to represent the provided duration
1362    fn interval_to_mysql_expr(
1363        &self,
1364        months: i32,
1365        days: i32,
1366        microseconds: i64,
1367    ) -> Result<ast::Expr> {
1368        // MONTH only
1369        if months != 0 && days == 0 && microseconds == 0 {
1370            let interval = Interval {
1371                value: Box::new(ast::Expr::value(ast::Value::Number(
1372                    months.to_string(),
1373                    false,
1374                ))),
1375                leading_field: Some(ast::DateTimeField::Month),
1376                leading_precision: None,
1377                last_field: None,
1378                fractional_seconds_precision: None,
1379            };
1380            return Ok(ast::Expr::Interval(interval));
1381        } else if months != 0 {
1382            return not_impl_err!("Unsupported Interval scalar with both Month and DayTime for IntervalStyle::MySQL");
1383        }
1384
1385        // DAY only
1386        if microseconds == 0 {
1387            let interval = Interval {
1388                value: Box::new(ast::Expr::value(ast::Value::Number(
1389                    days.to_string(),
1390                    false,
1391                ))),
1392                leading_field: Some(ast::DateTimeField::Day),
1393                leading_precision: None,
1394                last_field: None,
1395                fractional_seconds_precision: None,
1396            };
1397            return Ok(ast::Expr::Interval(interval));
1398        }
1399
1400        // Calculate the best single interval to represent the provided days and microseconds
1401
1402        let microseconds = microseconds + (days as i64 * 24 * 60 * 60 * 1_000_000);
1403
1404        if microseconds % 1_000_000 != 0 {
1405            let interval = Interval {
1406                value: Box::new(ast::Expr::value(ast::Value::Number(
1407                    microseconds.to_string(),
1408                    false,
1409                ))),
1410                leading_field: Some(ast::DateTimeField::Microsecond),
1411                leading_precision: None,
1412                last_field: None,
1413                fractional_seconds_precision: None,
1414            };
1415            return Ok(ast::Expr::Interval(interval));
1416        }
1417
1418        let secs = microseconds / 1_000_000;
1419
1420        if secs % 60 != 0 {
1421            let interval = Interval {
1422                value: Box::new(ast::Expr::value(ast::Value::Number(
1423                    secs.to_string(),
1424                    false,
1425                ))),
1426                leading_field: Some(ast::DateTimeField::Second),
1427                leading_precision: None,
1428                last_field: None,
1429                fractional_seconds_precision: None,
1430            };
1431            return Ok(ast::Expr::Interval(interval));
1432        }
1433
1434        let mins = secs / 60;
1435
1436        if mins % 60 != 0 {
1437            let interval = Interval {
1438                value: Box::new(ast::Expr::value(ast::Value::Number(
1439                    mins.to_string(),
1440                    false,
1441                ))),
1442                leading_field: Some(ast::DateTimeField::Minute),
1443                leading_precision: None,
1444                last_field: None,
1445                fractional_seconds_precision: None,
1446            };
1447            return Ok(ast::Expr::Interval(interval));
1448        }
1449
1450        let hours = mins / 60;
1451
1452        if hours % 24 != 0 {
1453            let interval = Interval {
1454                value: Box::new(ast::Expr::value(ast::Value::Number(
1455                    hours.to_string(),
1456                    false,
1457                ))),
1458                leading_field: Some(ast::DateTimeField::Hour),
1459                leading_precision: None,
1460                last_field: None,
1461                fractional_seconds_precision: None,
1462            };
1463            return Ok(ast::Expr::Interval(interval));
1464        }
1465
1466        let days = hours / 24;
1467
1468        let interval = Interval {
1469            value: Box::new(ast::Expr::value(ast::Value::Number(
1470                days.to_string(),
1471                false,
1472            ))),
1473            leading_field: Some(ast::DateTimeField::Day),
1474            leading_precision: None,
1475            last_field: None,
1476            fractional_seconds_precision: None,
1477        };
1478        Ok(ast::Expr::Interval(interval))
1479    }
1480
1481    fn interval_scalar_to_sql(&self, v: &ScalarValue) -> Result<ast::Expr> {
1482        match self.dialect.interval_style() {
1483            IntervalStyle::PostgresVerbose => {
1484                let wrap_array = v.to_array()?;
1485                let Some(result) = array_value_to_string(&wrap_array, 0).ok() else {
1486                    return internal_err!(
1487                        "Unable to convert interval scalar value to string"
1488                    );
1489                };
1490                let interval = Interval {
1491                    value: Box::new(ast::Expr::value(SingleQuotedString(
1492                        result.to_uppercase(),
1493                    ))),
1494                    leading_field: None,
1495                    leading_precision: None,
1496                    last_field: None,
1497                    fractional_seconds_precision: None,
1498                };
1499                Ok(ast::Expr::Interval(interval))
1500            }
1501            // If the interval standard is SQLStandard, implement a simple unparse logic
1502            IntervalStyle::SQLStandard => match v {
1503                ScalarValue::IntervalYearMonth(Some(v)) => {
1504                    let interval = Interval {
1505                        value: Box::new(ast::Expr::value(SingleQuotedString(
1506                            v.to_string(),
1507                        ))),
1508                        leading_field: Some(ast::DateTimeField::Month),
1509                        leading_precision: None,
1510                        last_field: None,
1511                        fractional_seconds_precision: None,
1512                    };
1513                    Ok(ast::Expr::Interval(interval))
1514                }
1515                ScalarValue::IntervalDayTime(Some(v)) => {
1516                    let days = v.days;
1517                    let secs = v.milliseconds / 1_000;
1518                    let mins = secs / 60;
1519                    let hours = mins / 60;
1520
1521                    let secs = secs - (mins * 60);
1522                    let mins = mins - (hours * 60);
1523
1524                    let millis = v.milliseconds % 1_000;
1525                    let interval = Interval {
1526                        value: Box::new(ast::Expr::value(SingleQuotedString(format!(
1527                            "{days} {hours}:{mins}:{secs}.{millis:3}"
1528                        )))),
1529                        leading_field: Some(ast::DateTimeField::Day),
1530                        leading_precision: None,
1531                        last_field: Some(ast::DateTimeField::Second),
1532                        fractional_seconds_precision: None,
1533                    };
1534                    Ok(ast::Expr::Interval(interval))
1535                }
1536                ScalarValue::IntervalMonthDayNano(Some(v)) => {
1537                    if v.months >= 0 && v.days == 0 && v.nanoseconds == 0 {
1538                        let interval = Interval {
1539                            value: Box::new(ast::Expr::value(SingleQuotedString(
1540                                v.months.to_string(),
1541                            ))),
1542                            leading_field: Some(ast::DateTimeField::Month),
1543                            leading_precision: None,
1544                            last_field: None,
1545                            fractional_seconds_precision: None,
1546                        };
1547                        Ok(ast::Expr::Interval(interval))
1548                    } else if v.months == 0 && v.nanoseconds % 1_000_000 == 0 {
1549                        let days = v.days;
1550                        let secs = v.nanoseconds / 1_000_000_000;
1551                        let mins = secs / 60;
1552                        let hours = mins / 60;
1553
1554                        let secs = secs - (mins * 60);
1555                        let mins = mins - (hours * 60);
1556
1557                        let millis = (v.nanoseconds % 1_000_000_000) / 1_000_000;
1558
1559                        let interval = Interval {
1560                            value: Box::new(ast::Expr::value(SingleQuotedString(
1561                                format!("{days} {hours}:{mins}:{secs}.{millis:03}"),
1562                            ))),
1563                            leading_field: Some(ast::DateTimeField::Day),
1564                            leading_precision: None,
1565                            last_field: Some(ast::DateTimeField::Second),
1566                            fractional_seconds_precision: None,
1567                        };
1568                        Ok(ast::Expr::Interval(interval))
1569                    } else {
1570                        not_impl_err!("Unsupported IntervalMonthDayNano scalar with both Month and DayTime for IntervalStyle::SQLStandard")
1571                    }
1572                }
1573                _ => not_impl_err!(
1574                    "Unsupported ScalarValue for Interval conversion: {v:?}"
1575                ),
1576            },
1577            IntervalStyle::MySQL => match v {
1578                ScalarValue::IntervalYearMonth(Some(v)) => {
1579                    self.interval_to_mysql_expr(*v, 0, 0)
1580                }
1581                ScalarValue::IntervalDayTime(Some(v)) => {
1582                    self.interval_to_mysql_expr(0, v.days, v.milliseconds as i64 * 1_000)
1583                }
1584                ScalarValue::IntervalMonthDayNano(Some(v)) => {
1585                    if v.nanoseconds % 1_000 != 0 {
1586                        return not_impl_err!(
1587                            "Unsupported IntervalMonthDayNano scalar with nanoseconds precision for IntervalStyle::MySQL"
1588                        );
1589                    }
1590                    self.interval_to_mysql_expr(v.months, v.days, v.nanoseconds / 1_000)
1591                }
1592                _ => not_impl_err!(
1593                    "Unsupported ScalarValue for Interval conversion: {v:?}"
1594                ),
1595            },
1596        }
1597    }
1598
1599    /// Converts an UNNEST operation to an AST expression by wrapping it as a function call,
1600    /// since there is no direct representation for UNNEST in the AST.
1601    fn unnest_to_sql(&self, unnest: &Unnest) -> Result<ast::Expr> {
1602        let args = self.function_args_to_sql(std::slice::from_ref(&unnest.expr))?;
1603
1604        Ok(ast::Expr::Function(Function {
1605            name: ObjectName::from(vec![Ident {
1606                value: "UNNEST".to_string(),
1607                quote_style: None,
1608                span: Span::empty(),
1609            }]),
1610            args: ast::FunctionArguments::List(ast::FunctionArgumentList {
1611                duplicate_treatment: None,
1612                args,
1613                clauses: vec![],
1614            }),
1615            filter: None,
1616            null_treatment: None,
1617            over: None,
1618            within_group: vec![],
1619            parameters: ast::FunctionArguments::None,
1620            uses_odbc_syntax: false,
1621        }))
1622    }
1623
1624    fn arrow_dtype_to_ast_dtype(&self, data_type: &DataType) -> Result<ast::DataType> {
1625        match data_type {
1626            DataType::Null => {
1627                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1628            }
1629            DataType::Boolean => Ok(ast::DataType::Bool),
1630            DataType::Int8 => Ok(ast::DataType::TinyInt(None)),
1631            DataType::Int16 => Ok(ast::DataType::SmallInt(None)),
1632            DataType::Int32 => Ok(self.dialect.int32_cast_dtype()),
1633            DataType::Int64 => Ok(self.dialect.int64_cast_dtype()),
1634            DataType::UInt8 => Ok(ast::DataType::TinyIntUnsigned(None)),
1635            DataType::UInt16 => Ok(ast::DataType::SmallIntUnsigned(None)),
1636            DataType::UInt32 => Ok(ast::DataType::IntegerUnsigned(None)),
1637            DataType::UInt64 => Ok(ast::DataType::BigIntUnsigned(None)),
1638            DataType::Float16 => {
1639                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1640            }
1641            DataType::Float32 => Ok(ast::DataType::Float(None)),
1642            DataType::Float64 => Ok(self.dialect.float64_ast_dtype()),
1643            DataType::Timestamp(time_unit, tz) => {
1644                Ok(self.dialect.timestamp_cast_dtype(time_unit, tz))
1645            }
1646            DataType::Date32 => Ok(self.dialect.date32_cast_dtype()),
1647            DataType::Date64 => Ok(self.ast_type_for_date64_in_cast()),
1648            DataType::Time32(_) => {
1649                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1650            }
1651            DataType::Time64(_) => {
1652                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1653            }
1654            DataType::Duration(_) => {
1655                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1656            }
1657            DataType::Interval(_) => Ok(ast::DataType::Interval),
1658            DataType::Binary => {
1659                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1660            }
1661            DataType::FixedSizeBinary(_) => {
1662                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1663            }
1664            DataType::LargeBinary => {
1665                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1666            }
1667            DataType::BinaryView => {
1668                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1669            }
1670            DataType::Utf8 => Ok(self.dialect.utf8_cast_dtype()),
1671            DataType::LargeUtf8 => Ok(self.dialect.large_utf8_cast_dtype()),
1672            DataType::Utf8View => Ok(self.dialect.utf8_cast_dtype()),
1673            DataType::List(_) => {
1674                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1675            }
1676            DataType::FixedSizeList(_, _) => {
1677                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1678            }
1679            DataType::LargeList(_) => {
1680                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1681            }
1682            DataType::ListView(_) => {
1683                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1684            }
1685            DataType::LargeListView(_) => {
1686                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1687            }
1688            DataType::Struct(_) => {
1689                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1690            }
1691            DataType::Union(_, _) => {
1692                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1693            }
1694            DataType::Dictionary(_, val) => self.arrow_dtype_to_ast_dtype(val),
1695            DataType::Decimal128(precision, scale)
1696            | DataType::Decimal256(precision, scale) => {
1697                let mut new_precision = *precision as u64;
1698                let mut new_scale = *scale as u64;
1699                if *scale < 0 {
1700                    new_precision = (*precision as i16 - *scale as i16) as u64;
1701                    new_scale = 0
1702                }
1703
1704                Ok(ast::DataType::Decimal(
1705                    ast::ExactNumberInfo::PrecisionAndScale(new_precision, new_scale),
1706                ))
1707            }
1708            DataType::Map(_, _) => {
1709                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1710            }
1711            DataType::RunEndEncoded(_, _) => {
1712                not_impl_err!("Unsupported DataType: conversion: {data_type:?}")
1713            }
1714        }
1715    }
1716}
1717
1718#[cfg(test)]
1719mod tests {
1720    use std::ops::{Add, Sub};
1721    use std::{any::Any, sync::Arc, vec};
1722
1723    use crate::unparser::dialect::SqliteDialect;
1724    use arrow::array::{LargeListArray, ListArray};
1725    use arrow::datatypes::{DataType::Int8, Field, Int32Type, Schema, TimeUnit};
1726    use ast::ObjectName;
1727    use datafusion_common::{Spans, TableReference};
1728    use datafusion_expr::expr::WildcardOptions;
1729    use datafusion_expr::{
1730        case, cast, col, cube, exists, grouping_set, interval_datetime_lit,
1731        interval_year_month_lit, lit, not, not_exists, out_ref_col, placeholder, rollup,
1732        table_scan, try_cast, when, ColumnarValue, ScalarFunctionArgs, ScalarUDF,
1733        ScalarUDFImpl, Signature, Volatility, WindowFrame, WindowFunctionDefinition,
1734    };
1735    use datafusion_expr::{interval_month_day_nano_lit, ExprFunctionExt};
1736    use datafusion_functions::datetime::from_unixtime::FromUnixtimeFunc;
1737    use datafusion_functions::expr_fn::{get_field, named_struct};
1738    use datafusion_functions_aggregate::count::count_udaf;
1739    use datafusion_functions_aggregate::expr_fn::sum;
1740    use datafusion_functions_nested::expr_fn::{array_element, make_array};
1741    use datafusion_functions_nested::map::map;
1742    use datafusion_functions_window::rank::rank_udwf;
1743    use datafusion_functions_window::row_number::row_number_udwf;
1744    use sqlparser::ast::ExactNumberInfo;
1745
1746    use crate::unparser::dialect::{
1747        CharacterLengthStyle, CustomDialect, CustomDialectBuilder, DateFieldExtractStyle,
1748        DefaultDialect, Dialect, DuckDBDialect, PostgreSqlDialect, ScalarFnToSqlHandler,
1749    };
1750
1751    use super::*;
1752
1753    /// Mocked UDF
1754    #[derive(Debug)]
1755    struct DummyUDF {
1756        signature: Signature,
1757    }
1758
1759    impl DummyUDF {
1760        fn new() -> Self {
1761            Self {
1762                signature: Signature::variadic_any(Volatility::Immutable),
1763            }
1764        }
1765    }
1766
1767    impl ScalarUDFImpl for DummyUDF {
1768        fn as_any(&self) -> &dyn Any {
1769            self
1770        }
1771
1772        fn name(&self) -> &str {
1773            "dummy_udf"
1774        }
1775
1776        fn signature(&self) -> &Signature {
1777            &self.signature
1778        }
1779
1780        fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
1781            Ok(DataType::Int32)
1782        }
1783
1784        fn invoke_with_args(&self, _args: ScalarFunctionArgs) -> Result<ColumnarValue> {
1785            panic!("dummy - not implemented")
1786        }
1787    }
1788    // See sql::tests for E2E tests.
1789
1790    #[test]
1791    fn expr_to_sql_ok() -> Result<()> {
1792        let dummy_schema = Schema::new(vec![Field::new("a", DataType::Int32, false)]);
1793        #[expect(deprecated)]
1794        let dummy_logical_plan = table_scan(Some("t"), &dummy_schema, None)?
1795            .project(vec![Expr::Wildcard {
1796                qualifier: None,
1797                options: Box::new(WildcardOptions::default()),
1798            }])?
1799            .filter(col("a").eq(lit(1)))?
1800            .build()?;
1801
1802        let tests: Vec<(Expr, &str)> = vec![
1803            ((col("a") + col("b")).gt(lit(4)), r#"((a + b) > 4)"#),
1804            (
1805                Expr::Column(Column {
1806                    relation: Some(TableReference::partial("a", "b")),
1807                    name: "c".to_string(),
1808                    spans: Spans::new(),
1809                })
1810                .gt(lit(4)),
1811                r#"(b.c > 4)"#,
1812            ),
1813            (
1814                case(col("a"))
1815                    .when(lit(1), lit(true))
1816                    .when(lit(0), lit(false))
1817                    .otherwise(lit(ScalarValue::Null))?,
1818                r#"CASE a WHEN 1 THEN true WHEN 0 THEN false ELSE NULL END"#,
1819            ),
1820            (
1821                when(col("a").is_null(), lit(true)).otherwise(lit(false))?,
1822                r#"CASE WHEN a IS NULL THEN true ELSE false END"#,
1823            ),
1824            (
1825                when(col("a").is_not_null(), lit(true)).otherwise(lit(false))?,
1826                r#"CASE WHEN a IS NOT NULL THEN true ELSE false END"#,
1827            ),
1828            (
1829                Expr::Cast(Cast {
1830                    expr: Box::new(col("a")),
1831                    data_type: DataType::Date64,
1832                }),
1833                r#"CAST(a AS DATETIME)"#,
1834            ),
1835            (
1836                Expr::Cast(Cast {
1837                    expr: Box::new(col("a")),
1838                    data_type: DataType::Timestamp(
1839                        TimeUnit::Nanosecond,
1840                        Some("+08:00".into()),
1841                    ),
1842                }),
1843                r#"CAST(a AS TIMESTAMP WITH TIME ZONE)"#,
1844            ),
1845            (
1846                Expr::Cast(Cast {
1847                    expr: Box::new(col("a")),
1848                    data_type: DataType::Timestamp(TimeUnit::Millisecond, None),
1849                }),
1850                r#"CAST(a AS TIMESTAMP)"#,
1851            ),
1852            (
1853                Expr::Cast(Cast {
1854                    expr: Box::new(col("a")),
1855                    data_type: DataType::UInt32,
1856                }),
1857                r#"CAST(a AS INTEGER UNSIGNED)"#,
1858            ),
1859            (
1860                col("a").in_list(vec![lit(1), lit(2), lit(3)], false),
1861                r#"a IN (1, 2, 3)"#,
1862            ),
1863            (
1864                col("a").in_list(vec![lit(1), lit(2), lit(3)], true),
1865                r#"a NOT IN (1, 2, 3)"#,
1866            ),
1867            (
1868                ScalarUDF::new_from_impl(DummyUDF::new()).call(vec![col("a"), col("b")]),
1869                r#"dummy_udf(a, b)"#,
1870            ),
1871            (
1872                ScalarUDF::new_from_impl(DummyUDF::new())
1873                    .call(vec![col("a"), col("b")])
1874                    .is_null(),
1875                r#"dummy_udf(a, b) IS NULL"#,
1876            ),
1877            (
1878                ScalarUDF::new_from_impl(DummyUDF::new())
1879                    .call(vec![col("a"), col("b")])
1880                    .is_not_null(),
1881                r#"dummy_udf(a, b) IS NOT NULL"#,
1882            ),
1883            (
1884                Expr::Like(Like {
1885                    negated: true,
1886                    expr: Box::new(col("a")),
1887                    pattern: Box::new(lit("foo")),
1888                    escape_char: Some('o'),
1889                    case_insensitive: false,
1890                }),
1891                r#"a NOT LIKE 'foo' ESCAPE 'o'"#,
1892            ),
1893            (
1894                Expr::Like(Like {
1895                    negated: true,
1896                    expr: Box::new(col("a")),
1897                    pattern: Box::new(lit("foo")),
1898                    escape_char: Some('o'),
1899                    case_insensitive: true,
1900                }),
1901                r#"a NOT ILIKE 'foo' ESCAPE 'o'"#,
1902            ),
1903            (
1904                Expr::SimilarTo(Like {
1905                    negated: false,
1906                    expr: Box::new(col("a")),
1907                    pattern: Box::new(lit("foo")),
1908                    escape_char: Some('o'),
1909                    case_insensitive: true,
1910                }),
1911                r#"a LIKE 'foo' ESCAPE 'o'"#,
1912            ),
1913            (
1914                Expr::Literal(ScalarValue::Date64(Some(0)), None),
1915                r#"CAST('1970-01-01 00:00:00' AS DATETIME)"#,
1916            ),
1917            (
1918                Expr::Literal(ScalarValue::Date64(Some(10000)), None),
1919                r#"CAST('1970-01-01 00:00:10' AS DATETIME)"#,
1920            ),
1921            (
1922                Expr::Literal(ScalarValue::Date64(Some(-10000)), None),
1923                r#"CAST('1969-12-31 23:59:50' AS DATETIME)"#,
1924            ),
1925            (
1926                Expr::Literal(ScalarValue::Date32(Some(0)), None),
1927                r#"CAST('1970-01-01' AS DATE)"#,
1928            ),
1929            (
1930                Expr::Literal(ScalarValue::Date32(Some(10)), None),
1931                r#"CAST('1970-01-11' AS DATE)"#,
1932            ),
1933            (
1934                Expr::Literal(ScalarValue::Date32(Some(-1)), None),
1935                r#"CAST('1969-12-31' AS DATE)"#,
1936            ),
1937            (
1938                Expr::Literal(ScalarValue::TimestampSecond(Some(10001), None), None),
1939                r#"CAST('1970-01-01 02:46:41' AS TIMESTAMP)"#,
1940            ),
1941            (
1942                Expr::Literal(
1943                    ScalarValue::TimestampSecond(Some(10001), Some("+08:00".into())),
1944                    None,
1945                ),
1946                r#"CAST('1970-01-01 10:46:41 +08:00' AS TIMESTAMP)"#,
1947            ),
1948            (
1949                Expr::Literal(ScalarValue::TimestampMillisecond(Some(10001), None), None),
1950                r#"CAST('1970-01-01 00:00:10.001' AS TIMESTAMP)"#,
1951            ),
1952            (
1953                Expr::Literal(
1954                    ScalarValue::TimestampMillisecond(Some(10001), Some("+08:00".into())),
1955                    None,
1956                ),
1957                r#"CAST('1970-01-01 08:00:10.001 +08:00' AS TIMESTAMP)"#,
1958            ),
1959            (
1960                Expr::Literal(ScalarValue::TimestampMicrosecond(Some(10001), None), None),
1961                r#"CAST('1970-01-01 00:00:00.010001' AS TIMESTAMP)"#,
1962            ),
1963            (
1964                Expr::Literal(
1965                    ScalarValue::TimestampMicrosecond(Some(10001), Some("+08:00".into())),
1966                    None,
1967                ),
1968                r#"CAST('1970-01-01 08:00:00.010001 +08:00' AS TIMESTAMP)"#,
1969            ),
1970            (
1971                Expr::Literal(ScalarValue::TimestampNanosecond(Some(10001), None), None),
1972                r#"CAST('1970-01-01 00:00:00.000010001' AS TIMESTAMP)"#,
1973            ),
1974            (
1975                Expr::Literal(
1976                    ScalarValue::TimestampNanosecond(Some(10001), Some("+08:00".into())),
1977                    None,
1978                ),
1979                r#"CAST('1970-01-01 08:00:00.000010001 +08:00' AS TIMESTAMP)"#,
1980            ),
1981            (
1982                Expr::Literal(ScalarValue::Time32Second(Some(10001)), None),
1983                r#"CAST('02:46:41' AS TIME)"#,
1984            ),
1985            (
1986                Expr::Literal(ScalarValue::Time32Millisecond(Some(10001)), None),
1987                r#"CAST('00:00:10.001' AS TIME)"#,
1988            ),
1989            (
1990                Expr::Literal(ScalarValue::Time64Microsecond(Some(10001)), None),
1991                r#"CAST('00:00:00.010001' AS TIME)"#,
1992            ),
1993            (
1994                Expr::Literal(ScalarValue::Time64Nanosecond(Some(10001)), None),
1995                r#"CAST('00:00:00.000010001' AS TIME)"#,
1996            ),
1997            (sum(col("a")), r#"sum(a)"#),
1998            (
1999                #[expect(deprecated)]
2000                count_udaf()
2001                    .call(vec![Expr::Wildcard {
2002                        qualifier: None,
2003                        options: Box::new(WildcardOptions::default()),
2004                    }])
2005                    .distinct()
2006                    .build()
2007                    .unwrap(),
2008                "count(DISTINCT *)",
2009            ),
2010            (
2011                #[expect(deprecated)]
2012                count_udaf()
2013                    .call(vec![Expr::Wildcard {
2014                        qualifier: None,
2015                        options: Box::new(WildcardOptions::default()),
2016                    }])
2017                    .filter(lit(true))
2018                    .build()
2019                    .unwrap(),
2020                "count(*) FILTER (WHERE true)",
2021            ),
2022            (
2023                Expr::from(WindowFunction {
2024                    fun: WindowFunctionDefinition::WindowUDF(row_number_udwf()),
2025                    params: WindowFunctionParams {
2026                        args: vec![col("col")],
2027                        partition_by: vec![],
2028                        order_by: vec![],
2029                        window_frame: WindowFrame::new(None),
2030                        null_treatment: None,
2031                    },
2032                }),
2033                r#"row_number(col) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)"#,
2034            ),
2035            (
2036                #[expect(deprecated)]
2037                Expr::from(WindowFunction {
2038                    fun: WindowFunctionDefinition::AggregateUDF(count_udaf()),
2039                    params: WindowFunctionParams {
2040                        args: vec![Expr::Wildcard {
2041                            qualifier: None,
2042                            options: Box::new(WildcardOptions::default()),
2043                        }],
2044                        partition_by: vec![],
2045                        order_by: vec![Sort::new(col("a"), false, true)],
2046                        window_frame: WindowFrame::new_bounds(
2047                            datafusion_expr::WindowFrameUnits::Range,
2048                            datafusion_expr::WindowFrameBound::Preceding(
2049                                ScalarValue::UInt32(Some(6)),
2050                            ),
2051                            datafusion_expr::WindowFrameBound::Following(
2052                                ScalarValue::UInt32(Some(2)),
2053                            ),
2054                        ),
2055                        null_treatment: None,
2056                    },
2057                }),
2058                r#"count(*) OVER (ORDER BY a DESC NULLS FIRST RANGE BETWEEN 6 PRECEDING AND 2 FOLLOWING)"#,
2059            ),
2060            (col("a").is_not_null(), r#"a IS NOT NULL"#),
2061            (col("a").is_null(), r#"a IS NULL"#),
2062            (
2063                (col("a") + col("b")).gt(lit(4)).is_true(),
2064                r#"((a + b) > 4) IS TRUE"#,
2065            ),
2066            (
2067                (col("a") + col("b")).gt(lit(4)).is_not_true(),
2068                r#"((a + b) > 4) IS NOT TRUE"#,
2069            ),
2070            (
2071                (col("a") + col("b")).gt(lit(4)).is_false(),
2072                r#"((a + b) > 4) IS FALSE"#,
2073            ),
2074            (
2075                (col("a") + col("b")).gt(lit(4)).is_not_false(),
2076                r#"((a + b) > 4) IS NOT FALSE"#,
2077            ),
2078            (
2079                (col("a") + col("b")).gt(lit(4)).is_unknown(),
2080                r#"((a + b) > 4) IS UNKNOWN"#,
2081            ),
2082            (
2083                (col("a") + col("b")).gt(lit(4)).is_not_unknown(),
2084                r#"((a + b) > 4) IS NOT UNKNOWN"#,
2085            ),
2086            (not(col("a")), r#"NOT a"#),
2087            (
2088                Expr::between(col("a"), lit(1), lit(7)),
2089                r#"(a BETWEEN 1 AND 7)"#,
2090            ),
2091            (Expr::Negative(Box::new(col("a"))), r#"-a"#),
2092            (
2093                exists(Arc::new(dummy_logical_plan.clone())),
2094                r#"EXISTS (SELECT * FROM t WHERE (t.a = 1))"#,
2095            ),
2096            (
2097                not_exists(Arc::new(dummy_logical_plan)),
2098                r#"NOT EXISTS (SELECT * FROM t WHERE (t.a = 1))"#,
2099            ),
2100            (
2101                try_cast(col("a"), DataType::Date64),
2102                r#"TRY_CAST(a AS DATETIME)"#,
2103            ),
2104            (
2105                try_cast(col("a"), DataType::UInt32),
2106                r#"TRY_CAST(a AS INTEGER UNSIGNED)"#,
2107            ),
2108            (
2109                Expr::ScalarVariable(Int8, vec![String::from("@a")]),
2110                r#"@a"#,
2111            ),
2112            (
2113                Expr::ScalarVariable(
2114                    Int8,
2115                    vec![String::from("@root"), String::from("foo")],
2116                ),
2117                r#"@root.foo"#,
2118            ),
2119            (col("x").eq(placeholder("$1")), r#"(x = $1)"#),
2120            (
2121                out_ref_col(DataType::Int32, "t.a").gt(lit(1)),
2122                r#"(t.a > 1)"#,
2123            ),
2124            (
2125                grouping_set(vec![vec![col("a"), col("b")], vec![col("a")]]),
2126                r#"GROUPING SETS ((a, b), (a))"#,
2127            ),
2128            (cube(vec![col("a"), col("b")]), r#"CUBE (a, b)"#),
2129            (rollup(vec![col("a"), col("b")]), r#"ROLLUP (a, b)"#),
2130            (col("table").eq(lit(1)), r#"("table" = 1)"#),
2131            (
2132                col("123_need_quoted").eq(lit(1)),
2133                r#"("123_need_quoted" = 1)"#,
2134            ),
2135            (col("need-quoted").eq(lit(1)), r#"("need-quoted" = 1)"#),
2136            (col("need quoted").eq(lit(1)), r#"("need quoted" = 1)"#),
2137            // See test_interval_scalar_to_expr for interval literals
2138            (
2139                (col("a") + col("b")).gt(Expr::Literal(
2140                    ScalarValue::Decimal128(Some(100123), 28, 3),
2141                    None,
2142                )),
2143                r#"((a + b) > 100.123)"#,
2144            ),
2145            (
2146                (col("a") + col("b")).gt(Expr::Literal(
2147                    ScalarValue::Decimal256(Some(100123.into()), 28, 3),
2148                    None,
2149                )),
2150                r#"((a + b) > 100.123)"#,
2151            ),
2152            (
2153                Expr::Cast(Cast {
2154                    expr: Box::new(col("a")),
2155                    data_type: DataType::Decimal128(10, -2),
2156                }),
2157                r#"CAST(a AS DECIMAL(12,0))"#,
2158            ),
2159            (
2160                Expr::Unnest(Unnest {
2161                    expr: Box::new(Expr::Column(Column {
2162                        relation: Some(TableReference::partial("schema", "table")),
2163                        name: "array_col".to_string(),
2164                        spans: Spans::new(),
2165                    })),
2166                }),
2167                r#"UNNEST("table".array_col)"#,
2168            ),
2169            (make_array(vec![lit(1), lit(2), lit(3)]), "[1, 2, 3]"),
2170            (array_element(col("array_col"), lit(1)), "array_col[1]"),
2171            (
2172                array_element(make_array(vec![lit(1), lit(2), lit(3)]), lit(1)),
2173                "[1, 2, 3][1]",
2174            ),
2175            (
2176                named_struct(vec![lit("a"), lit("1"), lit("b"), lit(2)]),
2177                "{a: '1', b: 2}",
2178            ),
2179            (get_field(col("a.b"), "c"), "a.b.c"),
2180            (
2181                map(vec![lit("a"), lit("b")], vec![lit(1), lit(2)]),
2182                "MAP {'a': 1, 'b': 2}",
2183            ),
2184            (
2185                Expr::Literal(
2186                    ScalarValue::Dictionary(
2187                        Box::new(DataType::Int32),
2188                        Box::new(ScalarValue::Utf8(Some("foo".into()))),
2189                    ),
2190                    None,
2191                ),
2192                "'foo'",
2193            ),
2194            (
2195                Expr::Literal(
2196                    ScalarValue::List(Arc::new(ListArray::from_iter_primitive::<
2197                        Int32Type,
2198                        _,
2199                        _,
2200                    >(vec![Some(vec![
2201                        Some(1),
2202                        Some(2),
2203                        Some(3),
2204                    ])]))),
2205                    None,
2206                ),
2207                "[1, 2, 3]",
2208            ),
2209            (
2210                Expr::Literal(
2211                    ScalarValue::LargeList(Arc::new(
2212                        LargeListArray::from_iter_primitive::<Int32Type, _, _>(vec![
2213                            Some(vec![Some(1), Some(2), Some(3)]),
2214                        ]),
2215                    )),
2216                    None,
2217                ),
2218                "[1, 2, 3]",
2219            ),
2220            (
2221                Expr::BinaryExpr(BinaryExpr {
2222                    left: Box::new(col("a")),
2223                    op: Operator::ArrowAt,
2224                    right: Box::new(col("b")),
2225                }),
2226                "(a <@ b)",
2227            ),
2228            (
2229                Expr::BinaryExpr(BinaryExpr {
2230                    left: Box::new(col("a")),
2231                    op: Operator::AtArrow,
2232                    right: Box::new(col("b")),
2233                }),
2234                "(a @> b)",
2235            ),
2236        ];
2237
2238        for (expr, expected) in tests {
2239            let ast = expr_to_sql(&expr)?;
2240
2241            let actual = format!("{ast}");
2242
2243            assert_eq!(actual, expected);
2244        }
2245
2246        Ok(())
2247    }
2248
2249    #[test]
2250    fn custom_dialect_with_identifier_quote_style() -> Result<()> {
2251        let dialect = CustomDialectBuilder::new()
2252            .with_identifier_quote_style('\'')
2253            .build();
2254        let unparser = Unparser::new(&dialect);
2255
2256        let expr = col("a").gt(lit(4));
2257        let ast = unparser.expr_to_sql(&expr)?;
2258
2259        let actual = format!("{ast}");
2260
2261        let expected = r#"('a' > 4)"#;
2262        assert_eq!(actual, expected);
2263
2264        Ok(())
2265    }
2266
2267    #[test]
2268    fn custom_dialect_without_identifier_quote_style() -> Result<()> {
2269        let dialect = CustomDialect::default();
2270        let unparser = Unparser::new(&dialect);
2271
2272        let expr = col("a").gt(lit(4));
2273        let ast = unparser.expr_to_sql(&expr)?;
2274
2275        let actual = format!("{ast}");
2276
2277        let expected = r#"(a > 4)"#;
2278        assert_eq!(actual, expected);
2279
2280        Ok(())
2281    }
2282
2283    #[test]
2284    fn custom_dialect_use_timestamp_for_date64() -> Result<()> {
2285        for (use_timestamp_for_date64, identifier) in
2286            [(false, "DATETIME"), (true, "TIMESTAMP")]
2287        {
2288            let dialect = CustomDialectBuilder::new()
2289                .with_use_timestamp_for_date64(use_timestamp_for_date64)
2290                .build();
2291            let unparser = Unparser::new(&dialect);
2292
2293            let expr = Expr::Cast(Cast {
2294                expr: Box::new(col("a")),
2295                data_type: DataType::Date64,
2296            });
2297            let ast = unparser.expr_to_sql(&expr)?;
2298
2299            let actual = format!("{ast}");
2300
2301            let expected = format!(r#"CAST(a AS {identifier})"#);
2302            assert_eq!(actual, expected);
2303        }
2304        Ok(())
2305    }
2306
2307    #[test]
2308    fn custom_dialect_float64_ast_dtype() -> Result<()> {
2309        for (float64_ast_dtype, identifier) in [
2310            (ast::DataType::Double(ExactNumberInfo::None), "DOUBLE"),
2311            (ast::DataType::DoublePrecision, "DOUBLE PRECISION"),
2312        ] {
2313            let dialect = CustomDialectBuilder::new()
2314                .with_float64_ast_dtype(float64_ast_dtype)
2315                .build();
2316            let unparser = Unparser::new(&dialect);
2317
2318            let expr = Expr::Cast(Cast {
2319                expr: Box::new(col("a")),
2320                data_type: DataType::Float64,
2321            });
2322            let ast = unparser.expr_to_sql(&expr)?;
2323
2324            let actual = format!("{ast}");
2325
2326            let expected = format!(r#"CAST(a AS {identifier})"#);
2327            assert_eq!(actual, expected);
2328        }
2329        Ok(())
2330    }
2331
2332    #[test]
2333    fn customer_dialect_support_nulls_first_in_ort() -> Result<()> {
2334        let tests: Vec<(Sort, &str, bool)> = vec![
2335            (col("a").sort(true, true), r#"a ASC NULLS FIRST"#, true),
2336            (col("a").sort(true, true), r#"a ASC"#, false),
2337        ];
2338
2339        for (expr, expected, supports_nulls_first_in_sort) in tests {
2340            let dialect = CustomDialectBuilder::new()
2341                .with_supports_nulls_first_in_sort(supports_nulls_first_in_sort)
2342                .build();
2343            let unparser = Unparser::new(&dialect);
2344            let ast = unparser.sort_to_sql(&expr)?;
2345
2346            let actual = format!("{ast}");
2347
2348            assert_eq!(actual, expected);
2349        }
2350
2351        Ok(())
2352    }
2353
2354    #[test]
2355    fn test_character_length_scalar_to_expr() {
2356        let tests = [
2357            (CharacterLengthStyle::Length, "length(x)"),
2358            (CharacterLengthStyle::CharacterLength, "character_length(x)"),
2359        ];
2360
2361        for (style, expected) in tests {
2362            let dialect = CustomDialectBuilder::new()
2363                .with_character_length_style(style)
2364                .build();
2365            let unparser = Unparser::new(&dialect);
2366
2367            let expr = ScalarUDF::new_from_impl(
2368                datafusion_functions::unicode::character_length::CharacterLengthFunc::new(
2369                ),
2370            )
2371            .call(vec![col("x")]);
2372
2373            let ast = unparser.expr_to_sql(&expr).expect("to be unparsed");
2374
2375            let actual = format!("{ast}");
2376
2377            assert_eq!(actual, expected);
2378        }
2379    }
2380
2381    #[test]
2382    fn test_interval_scalar_to_expr() {
2383        let tests = [
2384            (
2385                interval_month_day_nano_lit("1 MONTH"),
2386                IntervalStyle::SQLStandard,
2387                "INTERVAL '1' MONTH",
2388            ),
2389            (
2390                interval_month_day_nano_lit("1.5 DAY"),
2391                IntervalStyle::SQLStandard,
2392                "INTERVAL '1 12:0:0.000' DAY TO SECOND",
2393            ),
2394            (
2395                interval_month_day_nano_lit("-1.5 DAY"),
2396                IntervalStyle::SQLStandard,
2397                "INTERVAL '-1 -12:0:0.000' DAY TO SECOND",
2398            ),
2399            (
2400                interval_month_day_nano_lit("1.51234 DAY"),
2401                IntervalStyle::SQLStandard,
2402                "INTERVAL '1 12:17:46.176' DAY TO SECOND",
2403            ),
2404            (
2405                interval_datetime_lit("1.51234 DAY"),
2406                IntervalStyle::SQLStandard,
2407                "INTERVAL '1 12:17:46.176' DAY TO SECOND",
2408            ),
2409            (
2410                interval_year_month_lit("1 YEAR"),
2411                IntervalStyle::SQLStandard,
2412                "INTERVAL '12' MONTH",
2413            ),
2414            (
2415                interval_month_day_nano_lit(
2416                    "1 YEAR 1 MONTH 1 DAY 3 HOUR 10 MINUTE 20 SECOND",
2417                ),
2418                IntervalStyle::PostgresVerbose,
2419                r#"INTERVAL '13 MONS 1 DAYS 3 HOURS 10 MINS 20.000000000 SECS'"#,
2420            ),
2421            (
2422                interval_month_day_nano_lit("1.5 MONTH"),
2423                IntervalStyle::PostgresVerbose,
2424                r#"INTERVAL '1 MONS 15 DAYS'"#,
2425            ),
2426            (
2427                interval_month_day_nano_lit("-3 MONTH"),
2428                IntervalStyle::PostgresVerbose,
2429                r#"INTERVAL '-3 MONS'"#,
2430            ),
2431            (
2432                interval_month_day_nano_lit("1 MONTH")
2433                    .add(interval_month_day_nano_lit("1 DAY")),
2434                IntervalStyle::PostgresVerbose,
2435                r#"(INTERVAL '1 MONS' + INTERVAL '1 DAYS')"#,
2436            ),
2437            (
2438                interval_month_day_nano_lit("1 MONTH")
2439                    .sub(interval_month_day_nano_lit("1 DAY")),
2440                IntervalStyle::PostgresVerbose,
2441                r#"(INTERVAL '1 MONS' - INTERVAL '1 DAYS')"#,
2442            ),
2443            (
2444                interval_datetime_lit("10 DAY 1 HOUR 10 MINUTE 20 SECOND"),
2445                IntervalStyle::PostgresVerbose,
2446                r#"INTERVAL '10 DAYS 1 HOURS 10 MINS 20.000 SECS'"#,
2447            ),
2448            (
2449                interval_datetime_lit("10 DAY 1.5 HOUR 10 MINUTE 20 SECOND"),
2450                IntervalStyle::PostgresVerbose,
2451                r#"INTERVAL '10 DAYS 1 HOURS 40 MINS 20.000 SECS'"#,
2452            ),
2453            (
2454                interval_year_month_lit("1 YEAR 1 MONTH"),
2455                IntervalStyle::PostgresVerbose,
2456                r#"INTERVAL '1 YEARS 1 MONS'"#,
2457            ),
2458            (
2459                interval_year_month_lit("1.5 YEAR 1 MONTH"),
2460                IntervalStyle::PostgresVerbose,
2461                r#"INTERVAL '1 YEARS 7 MONS'"#,
2462            ),
2463            (
2464                interval_year_month_lit("1 YEAR 1 MONTH"),
2465                IntervalStyle::MySQL,
2466                r#"INTERVAL 13 MONTH"#,
2467            ),
2468            (
2469                interval_month_day_nano_lit("1 YEAR -1 MONTH"),
2470                IntervalStyle::MySQL,
2471                r#"INTERVAL 11 MONTH"#,
2472            ),
2473            (
2474                interval_month_day_nano_lit("15 DAY"),
2475                IntervalStyle::MySQL,
2476                r#"INTERVAL 15 DAY"#,
2477            ),
2478            (
2479                interval_month_day_nano_lit("-40 HOURS"),
2480                IntervalStyle::MySQL,
2481                r#"INTERVAL -40 HOUR"#,
2482            ),
2483            (
2484                interval_datetime_lit("-1.5 DAY 1 HOUR"),
2485                IntervalStyle::MySQL,
2486                "INTERVAL -35 HOUR",
2487            ),
2488            (
2489                interval_datetime_lit("1000000 DAY 1.5 HOUR 10 MINUTE 20 SECOND"),
2490                IntervalStyle::MySQL,
2491                r#"INTERVAL 86400006020 SECOND"#,
2492            ),
2493            (
2494                interval_year_month_lit("0 DAY 0 HOUR"),
2495                IntervalStyle::MySQL,
2496                r#"INTERVAL 0 DAY"#,
2497            ),
2498            (
2499                interval_month_day_nano_lit("-1296000000 SECOND"),
2500                IntervalStyle::MySQL,
2501                r#"INTERVAL -15000 DAY"#,
2502            ),
2503        ];
2504
2505        for (value, style, expected) in tests {
2506            let dialect = CustomDialectBuilder::new()
2507                .with_interval_style(style)
2508                .build();
2509            let unparser = Unparser::new(&dialect);
2510
2511            let ast = unparser.expr_to_sql(&value).expect("to be unparsed");
2512
2513            let actual = format!("{ast}");
2514
2515            assert_eq!(actual, expected);
2516        }
2517    }
2518
2519    #[test]
2520    fn test_float_scalar_to_expr() {
2521        let tests = [
2522            (Expr::Literal(ScalarValue::Float64(Some(3f64)), None), "3.0"),
2523            (
2524                Expr::Literal(ScalarValue::Float64(Some(3.1f64)), None),
2525                "3.1",
2526            ),
2527            (
2528                Expr::Literal(ScalarValue::Float32(Some(-2f32)), None),
2529                "-2.0",
2530            ),
2531            (
2532                Expr::Literal(ScalarValue::Float32(Some(-2.989f32)), None),
2533                "-2.989",
2534            ),
2535        ];
2536        for (value, expected) in tests {
2537            let dialect = CustomDialectBuilder::new().build();
2538            let unparser = Unparser::new(&dialect);
2539
2540            let ast = unparser.expr_to_sql(&value).expect("to be unparsed");
2541            let actual = format!("{ast}");
2542
2543            assert_eq!(actual, expected);
2544        }
2545    }
2546
2547    #[test]
2548    fn test_cast_value_to_binary_expr() {
2549        let tests = [
2550            (
2551                Expr::Cast(Cast {
2552                    expr: Box::new(Expr::Literal(
2553                        ScalarValue::Utf8(Some("blah".to_string())),
2554                        None,
2555                    )),
2556                    data_type: DataType::Binary,
2557                }),
2558                "'blah'",
2559            ),
2560            (
2561                Expr::Cast(Cast {
2562                    expr: Box::new(Expr::Literal(
2563                        ScalarValue::Utf8(Some("blah".to_string())),
2564                        None,
2565                    )),
2566                    data_type: DataType::BinaryView,
2567                }),
2568                "'blah'",
2569            ),
2570        ];
2571        for (value, expected) in tests {
2572            let dialect = CustomDialectBuilder::new().build();
2573            let unparser = Unparser::new(&dialect);
2574
2575            let ast = unparser.expr_to_sql(&value).expect("to be unparsed");
2576            let actual = format!("{ast}");
2577
2578            assert_eq!(actual, expected);
2579        }
2580    }
2581
2582    #[test]
2583    fn custom_dialect_use_char_for_utf8_cast() -> Result<()> {
2584        let default_dialect = CustomDialectBuilder::default().build();
2585        let mysql_custom_dialect = CustomDialectBuilder::new()
2586            .with_utf8_cast_dtype(ast::DataType::Char(None))
2587            .with_large_utf8_cast_dtype(ast::DataType::Char(None))
2588            .build();
2589
2590        for (dialect, data_type, identifier) in [
2591            (&default_dialect, DataType::Utf8, "VARCHAR"),
2592            (&default_dialect, DataType::LargeUtf8, "TEXT"),
2593            (&mysql_custom_dialect, DataType::Utf8, "CHAR"),
2594            (&mysql_custom_dialect, DataType::LargeUtf8, "CHAR"),
2595        ] {
2596            let unparser = Unparser::new(dialect);
2597
2598            let expr = Expr::Cast(Cast {
2599                expr: Box::new(col("a")),
2600                data_type,
2601            });
2602            let ast = unparser.expr_to_sql(&expr)?;
2603
2604            let actual = format!("{ast}");
2605            let expected = format!(r#"CAST(a AS {identifier})"#);
2606
2607            assert_eq!(actual, expected);
2608        }
2609        Ok(())
2610    }
2611
2612    #[test]
2613    fn custom_dialect_with_date_field_extract_style() -> Result<()> {
2614        for (extract_style, unit, expected) in [
2615            (
2616                DateFieldExtractStyle::DatePart,
2617                "YEAR",
2618                "date_part('YEAR', x)",
2619            ),
2620            (
2621                DateFieldExtractStyle::Extract,
2622                "YEAR",
2623                "EXTRACT(YEAR FROM x)",
2624            ),
2625            (DateFieldExtractStyle::Strftime, "YEAR", "strftime('%Y', x)"),
2626            (
2627                DateFieldExtractStyle::DatePart,
2628                "MONTH",
2629                "date_part('MONTH', x)",
2630            ),
2631            (
2632                DateFieldExtractStyle::Extract,
2633                "MONTH",
2634                "EXTRACT(MONTH FROM x)",
2635            ),
2636            (
2637                DateFieldExtractStyle::Strftime,
2638                "MONTH",
2639                "strftime('%m', x)",
2640            ),
2641            (
2642                DateFieldExtractStyle::DatePart,
2643                "DAY",
2644                "date_part('DAY', x)",
2645            ),
2646            (DateFieldExtractStyle::Strftime, "DAY", "strftime('%d', x)"),
2647            (DateFieldExtractStyle::Extract, "DAY", "EXTRACT(DAY FROM x)"),
2648        ] {
2649            let dialect = CustomDialectBuilder::new()
2650                .with_date_field_extract_style(extract_style)
2651                .build();
2652
2653            let unparser = Unparser::new(&dialect);
2654            let expr = ScalarUDF::new_from_impl(
2655                datafusion_functions::datetime::date_part::DatePartFunc::new(),
2656            )
2657            .call(vec![
2658                Expr::Literal(ScalarValue::new_utf8(unit), None),
2659                col("x"),
2660            ]);
2661
2662            let ast = unparser.expr_to_sql(&expr)?;
2663            let actual = format!("{ast}");
2664
2665            assert_eq!(actual, expected);
2666        }
2667        Ok(())
2668    }
2669
2670    #[test]
2671    fn custom_dialect_with_int64_cast_dtype() -> Result<()> {
2672        let default_dialect = CustomDialectBuilder::new().build();
2673        let mysql_dialect = CustomDialectBuilder::new()
2674            .with_int64_cast_dtype(ast::DataType::Custom(
2675                ObjectName::from(vec![Ident::new("SIGNED")]),
2676                vec![],
2677            ))
2678            .build();
2679
2680        for (dialect, identifier) in
2681            [(default_dialect, "BIGINT"), (mysql_dialect, "SIGNED")]
2682        {
2683            let unparser = Unparser::new(&dialect);
2684            let expr = Expr::Cast(Cast {
2685                expr: Box::new(col("a")),
2686                data_type: DataType::Int64,
2687            });
2688            let ast = unparser.expr_to_sql(&expr)?;
2689
2690            let actual = format!("{ast}");
2691            let expected = format!(r#"CAST(a AS {identifier})"#);
2692
2693            assert_eq!(actual, expected);
2694        }
2695        Ok(())
2696    }
2697
2698    #[test]
2699    fn custom_dialect_with_int32_cast_dtype() -> Result<()> {
2700        let default_dialect = CustomDialectBuilder::new().build();
2701        let mysql_dialect = CustomDialectBuilder::new()
2702            .with_int32_cast_dtype(ast::DataType::Custom(
2703                ObjectName::from(vec![Ident::new("SIGNED")]),
2704                vec![],
2705            ))
2706            .build();
2707
2708        for (dialect, identifier) in
2709            [(default_dialect, "INTEGER"), (mysql_dialect, "SIGNED")]
2710        {
2711            let unparser = Unparser::new(&dialect);
2712            let expr = Expr::Cast(Cast {
2713                expr: Box::new(col("a")),
2714                data_type: DataType::Int32,
2715            });
2716            let ast = unparser.expr_to_sql(&expr)?;
2717
2718            let actual = format!("{ast}");
2719            let expected = format!(r#"CAST(a AS {identifier})"#);
2720
2721            assert_eq!(actual, expected);
2722        }
2723        Ok(())
2724    }
2725
2726    #[test]
2727    fn custom_dialect_with_timestamp_cast_dtype() -> Result<()> {
2728        let default_dialect = CustomDialectBuilder::new().build();
2729        let mysql_dialect = CustomDialectBuilder::new()
2730            .with_timestamp_cast_dtype(
2731                ast::DataType::Datetime(None),
2732                ast::DataType::Datetime(None),
2733            )
2734            .build();
2735
2736        let timestamp = DataType::Timestamp(TimeUnit::Nanosecond, None);
2737        let timestamp_with_tz =
2738            DataType::Timestamp(TimeUnit::Nanosecond, Some("+08:00".into()));
2739
2740        for (dialect, data_type, identifier) in [
2741            (&default_dialect, &timestamp, "TIMESTAMP"),
2742            (
2743                &default_dialect,
2744                &timestamp_with_tz,
2745                "TIMESTAMP WITH TIME ZONE",
2746            ),
2747            (&mysql_dialect, &timestamp, "DATETIME"),
2748            (&mysql_dialect, &timestamp_with_tz, "DATETIME"),
2749        ] {
2750            let unparser = Unparser::new(dialect);
2751            let expr = Expr::Cast(Cast {
2752                expr: Box::new(col("a")),
2753                data_type: data_type.clone(),
2754            });
2755            let ast = unparser.expr_to_sql(&expr)?;
2756
2757            let actual = format!("{ast}");
2758            let expected = format!(r#"CAST(a AS {identifier})"#);
2759
2760            assert_eq!(actual, expected);
2761        }
2762        Ok(())
2763    }
2764
2765    #[test]
2766    fn custom_dialect_with_timestamp_cast_dtype_scalar_expr() -> Result<()> {
2767        let default_dialect = CustomDialectBuilder::new().build();
2768        let mysql_dialect = CustomDialectBuilder::new()
2769            .with_timestamp_cast_dtype(
2770                ast::DataType::Datetime(None),
2771                ast::DataType::Datetime(None),
2772            )
2773            .build();
2774
2775        for (dialect, identifier) in [
2776            (&default_dialect, "TIMESTAMP"),
2777            (&mysql_dialect, "DATETIME"),
2778        ] {
2779            let unparser = Unparser::new(dialect);
2780            let expr = Expr::Literal(
2781                ScalarValue::TimestampMillisecond(Some(1738285549123), None),
2782                None,
2783            );
2784            let ast = unparser.expr_to_sql(&expr)?;
2785
2786            let actual = format!("{ast}");
2787            let expected = format!(r#"CAST('2025-01-31 01:05:49.123' AS {identifier})"#);
2788
2789            assert_eq!(actual, expected);
2790        }
2791        Ok(())
2792    }
2793
2794    #[test]
2795    fn custom_dialect_date32_ast_dtype() -> Result<()> {
2796        let default_dialect = CustomDialectBuilder::default().build();
2797        let sqlite_custom_dialect = CustomDialectBuilder::new()
2798            .with_date32_cast_dtype(ast::DataType::Text)
2799            .build();
2800
2801        for (dialect, data_type, identifier) in [
2802            (&default_dialect, DataType::Date32, "DATE"),
2803            (&sqlite_custom_dialect, DataType::Date32, "TEXT"),
2804        ] {
2805            let unparser = Unparser::new(dialect);
2806
2807            let expr = Expr::Cast(Cast {
2808                expr: Box::new(col("a")),
2809                data_type,
2810            });
2811            let ast = unparser.expr_to_sql(&expr)?;
2812
2813            let actual = format!("{ast}");
2814            let expected = format!(r#"CAST(a AS {identifier})"#);
2815
2816            assert_eq!(actual, expected);
2817        }
2818        Ok(())
2819    }
2820
2821    #[test]
2822    fn custom_dialect_division_operator() -> Result<()> {
2823        let default_dialect = CustomDialectBuilder::new().build();
2824        let duckdb_dialect = CustomDialectBuilder::new()
2825            .with_division_operator(BinaryOperator::DuckIntegerDivide)
2826            .build();
2827
2828        for (dialect, expected) in
2829            [(default_dialect, "(a / b)"), (duckdb_dialect, "(a // b)")]
2830        {
2831            let unparser = Unparser::new(&dialect);
2832            let expr = Expr::BinaryExpr(BinaryExpr {
2833                left: Box::new(col("a")),
2834                op: Operator::Divide,
2835                right: Box::new(col("b")),
2836            });
2837            let ast = unparser.expr_to_sql(&expr)?;
2838
2839            let actual = format!("{ast}");
2840            let expected = expected.to_string();
2841
2842            assert_eq!(actual, expected);
2843        }
2844        Ok(())
2845    }
2846
2847    #[test]
2848    fn test_cast_value_to_dict_expr() {
2849        let tests = [(
2850            Expr::Cast(Cast {
2851                expr: Box::new(Expr::Literal(
2852                    ScalarValue::Utf8(Some("variation".to_string())),
2853                    None,
2854                )),
2855                data_type: DataType::Dictionary(Box::new(Int8), Box::new(DataType::Utf8)),
2856            }),
2857            "'variation'",
2858        )];
2859        for (value, expected) in tests {
2860            let dialect = CustomDialectBuilder::new().build();
2861            let unparser = Unparser::new(&dialect);
2862
2863            let ast = unparser.expr_to_sql(&value).expect("to be unparsed");
2864            let actual = format!("{ast}");
2865
2866            assert_eq!(actual, expected);
2867        }
2868    }
2869
2870    #[test]
2871    fn test_round_scalar_fn_to_expr() -> Result<()> {
2872        let default_dialect: Arc<dyn Dialect> = Arc::new(
2873            CustomDialectBuilder::new()
2874                .with_identifier_quote_style('"')
2875                .build(),
2876        );
2877        let postgres_dialect: Arc<dyn Dialect> = Arc::new(PostgreSqlDialect {});
2878
2879        for (dialect, identifier) in
2880            [(default_dialect, "DOUBLE"), (postgres_dialect, "NUMERIC")]
2881        {
2882            let unparser = Unparser::new(dialect.as_ref());
2883            let expr = Expr::ScalarFunction(ScalarFunction {
2884                func: Arc::new(ScalarUDF::from(
2885                    datafusion_functions::math::round::RoundFunc::new(),
2886                )),
2887                args: vec![
2888                    Expr::Cast(Cast {
2889                        expr: Box::new(col("a")),
2890                        data_type: DataType::Float64,
2891                    }),
2892                    Expr::Literal(ScalarValue::Int64(Some(2)), None),
2893                ],
2894            });
2895            let ast = unparser.expr_to_sql(&expr)?;
2896
2897            let actual = format!("{ast}");
2898            let expected = format!(r#"round(CAST("a" AS {identifier}), 2)"#);
2899
2900            assert_eq!(actual, expected);
2901        }
2902        Ok(())
2903    }
2904
2905    #[test]
2906    fn test_window_func_support_window_frame() -> Result<()> {
2907        let default_dialect: Arc<dyn Dialect> =
2908            Arc::new(CustomDialectBuilder::new().build());
2909
2910        let test_dialect: Arc<dyn Dialect> = Arc::new(
2911            CustomDialectBuilder::new()
2912                .with_window_func_support_window_frame(false)
2913                .build(),
2914        );
2915
2916        for (dialect, expected) in [
2917            (
2918                default_dialect,
2919                "rank() OVER (ORDER BY a ASC NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)",
2920            ),
2921            (test_dialect, "rank() OVER (ORDER BY a ASC NULLS FIRST)"),
2922        ] {
2923            let unparser = Unparser::new(dialect.as_ref());
2924            let func = WindowFunctionDefinition::WindowUDF(rank_udwf());
2925            let mut window_func = WindowFunction::new(func, vec![]);
2926            window_func.params.order_by = vec![Sort::new(col("a"), true, true)];
2927            let expr = Expr::from(window_func);
2928            let ast = unparser.expr_to_sql(&expr)?;
2929
2930            let actual = ast.to_string();
2931            let expected = expected.to_string();
2932
2933            assert_eq!(actual, expected);
2934        }
2935        Ok(())
2936    }
2937
2938    #[test]
2939    fn test_from_unixtime() -> Result<()> {
2940        let default_dialect: Arc<dyn Dialect> = Arc::new(DefaultDialect {});
2941        let sqlite_dialect: Arc<dyn Dialect> = Arc::new(SqliteDialect {});
2942
2943        for (dialect, expected) in [
2944            (default_dialect, "from_unixtime(date_col)"),
2945            (sqlite_dialect, "datetime(`date_col`, 'unixepoch')"),
2946        ] {
2947            let unparser = Unparser::new(dialect.as_ref());
2948            let expr = Expr::ScalarFunction(ScalarFunction {
2949                func: Arc::new(ScalarUDF::from(FromUnixtimeFunc::new())),
2950                args: vec![col("date_col")],
2951            });
2952
2953            let ast = unparser.expr_to_sql(&expr)?;
2954
2955            let actual = ast.to_string();
2956            let expected = expected.to_string();
2957
2958            assert_eq!(actual, expected);
2959        }
2960        Ok(())
2961    }
2962
2963    #[test]
2964    fn test_date_trunc() -> Result<()> {
2965        let default_dialect: Arc<dyn Dialect> = Arc::new(DefaultDialect {});
2966        let sqlite_dialect: Arc<dyn Dialect> = Arc::new(SqliteDialect {});
2967
2968        for (dialect, precision, expected) in [
2969            (
2970                Arc::clone(&default_dialect),
2971                "YEAR",
2972                "date_trunc('YEAR', date_col)",
2973            ),
2974            (
2975                Arc::clone(&sqlite_dialect),
2976                "YEAR",
2977                "strftime('%Y', `date_col`)",
2978            ),
2979            (
2980                Arc::clone(&default_dialect),
2981                "MONTH",
2982                "date_trunc('MONTH', date_col)",
2983            ),
2984            (
2985                Arc::clone(&sqlite_dialect),
2986                "MONTH",
2987                "strftime('%Y-%m', `date_col`)",
2988            ),
2989            (
2990                Arc::clone(&default_dialect),
2991                "DAY",
2992                "date_trunc('DAY', date_col)",
2993            ),
2994            (
2995                Arc::clone(&sqlite_dialect),
2996                "DAY",
2997                "strftime('%Y-%m-%d', `date_col`)",
2998            ),
2999            (
3000                Arc::clone(&default_dialect),
3001                "HOUR",
3002                "date_trunc('HOUR', date_col)",
3003            ),
3004            (
3005                Arc::clone(&sqlite_dialect),
3006                "HOUR",
3007                "strftime('%Y-%m-%d %H', `date_col`)",
3008            ),
3009            (
3010                Arc::clone(&default_dialect),
3011                "MINUTE",
3012                "date_trunc('MINUTE', date_col)",
3013            ),
3014            (
3015                Arc::clone(&sqlite_dialect),
3016                "MINUTE",
3017                "strftime('%Y-%m-%d %H:%M', `date_col`)",
3018            ),
3019            (default_dialect, "SECOND", "date_trunc('SECOND', date_col)"),
3020            (
3021                sqlite_dialect,
3022                "SECOND",
3023                "strftime('%Y-%m-%d %H:%M:%S', `date_col`)",
3024            ),
3025        ] {
3026            let unparser = Unparser::new(dialect.as_ref());
3027            let expr = Expr::ScalarFunction(ScalarFunction {
3028                func: Arc::new(ScalarUDF::from(
3029                    datafusion_functions::datetime::date_trunc::DateTruncFunc::new(),
3030                )),
3031                args: vec![
3032                    Expr::Literal(ScalarValue::Utf8(Some(precision.to_string())), None),
3033                    col("date_col"),
3034                ],
3035            });
3036
3037            let ast = unparser.expr_to_sql(&expr)?;
3038
3039            let actual = ast.to_string();
3040            let expected = expected.to_string();
3041
3042            assert_eq!(actual, expected);
3043        }
3044        Ok(())
3045    }
3046
3047    #[test]
3048    fn test_dictionary_to_sql() -> Result<()> {
3049        let dialect = CustomDialectBuilder::new().build();
3050
3051        let unparser = Unparser::new(&dialect);
3052
3053        let ast_dtype = unparser.arrow_dtype_to_ast_dtype(&DataType::Dictionary(
3054            Box::new(DataType::Int32),
3055            Box::new(DataType::Utf8),
3056        ))?;
3057
3058        assert_eq!(ast_dtype, ast::DataType::Varchar(None));
3059
3060        Ok(())
3061    }
3062
3063    #[test]
3064    fn test_utf8_view_to_sql() -> Result<()> {
3065        let dialect = CustomDialectBuilder::new()
3066            .with_utf8_cast_dtype(ast::DataType::Char(None))
3067            .build();
3068        let unparser = Unparser::new(&dialect);
3069
3070        let ast_dtype = unparser.arrow_dtype_to_ast_dtype(&DataType::Utf8View)?;
3071
3072        assert_eq!(ast_dtype, ast::DataType::Char(None));
3073
3074        let expr = cast(col("a"), DataType::Utf8View);
3075        let ast = unparser.expr_to_sql(&expr)?;
3076
3077        let actual = format!("{ast}");
3078        let expected = r#"CAST(a AS CHAR)"#.to_string();
3079
3080        assert_eq!(actual, expected);
3081
3082        let expr = col("a").eq(lit(ScalarValue::Utf8View(Some("hello".to_string()))));
3083        let ast = unparser.expr_to_sql(&expr)?;
3084
3085        let actual = format!("{ast}");
3086        let expected = r#"(a = 'hello')"#.to_string();
3087
3088        assert_eq!(actual, expected);
3089
3090        let expr = col("a").is_not_null();
3091
3092        let ast = unparser.expr_to_sql(&expr)?;
3093        let actual = format!("{ast}");
3094        let expected = r#"a IS NOT NULL"#.to_string();
3095
3096        assert_eq!(actual, expected);
3097
3098        let expr = col("a").is_null();
3099
3100        let ast = unparser.expr_to_sql(&expr)?;
3101        let actual = format!("{ast}");
3102        let expected = r#"a IS NULL"#.to_string();
3103
3104        assert_eq!(actual, expected);
3105
3106        Ok(())
3107    }
3108
3109    #[test]
3110    fn test_custom_scalar_overrides_duckdb() -> Result<()> {
3111        let duckdb_default = DuckDBDialect::new();
3112        let duckdb_extended = DuckDBDialect::new().with_custom_scalar_overrides(vec![(
3113            "dummy_udf",
3114            Box::new(|unparser: &Unparser, args: &[Expr]| {
3115                unparser.scalar_function_to_sql("smart_udf", args).map(Some)
3116            }) as ScalarFnToSqlHandler,
3117        )]);
3118
3119        for (dialect, expected) in [
3120            (duckdb_default, r#"dummy_udf("a", "b")"#),
3121            (duckdb_extended, r#"smart_udf("a", "b")"#),
3122        ] {
3123            let unparser = Unparser::new(&dialect);
3124            let expr =
3125                ScalarUDF::new_from_impl(DummyUDF::new()).call(vec![col("a"), col("b")]);
3126            let actual = format!("{}", unparser.expr_to_sql(&expr)?);
3127            assert_eq!(actual, expected);
3128        }
3129
3130        Ok(())
3131    }
3132}