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