datafusion_sql/unparser/
expr.rs

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