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