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