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