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