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