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