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