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