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