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