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