Skip to main content

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