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