1use std::{collections::HashMap, sync::Arc};
19
20use super::{utils::character_length_to_sql, utils::date_part_to_sql, Unparser};
21use arrow::datatypes::TimeUnit;
22use datafusion_common::Result;
23use datafusion_expr::Expr;
24use regex::Regex;
25use sqlparser::tokenizer::Span;
26use sqlparser::{
27 ast::{
28 self, BinaryOperator, Function, Ident, ObjectName, TimezoneInfo, WindowFrameBound,
29 },
30 keywords::ALL_KEYWORDS,
31};
32
33pub type ScalarFnToSqlHandler =
34 Box<dyn Fn(&Unparser, &[Expr]) -> Result<Option<ast::Expr>> + Send + Sync>;
35
36pub trait Dialect: Send + Sync {
46 fn identifier_quote_style(&self, _identifier: &str) -> Option<char>;
48
49 fn supports_nulls_first_in_sort(&self) -> bool {
51 true
52 }
53
54 fn use_timestamp_for_date64(&self) -> bool {
57 false
58 }
59
60 fn interval_style(&self) -> IntervalStyle {
61 IntervalStyle::PostgresVerbose
62 }
63
64 fn float64_ast_dtype(&self) -> ast::DataType {
67 ast::DataType::Double(ast::ExactNumberInfo::None)
68 }
69
70 fn utf8_cast_dtype(&self) -> ast::DataType {
73 ast::DataType::Varchar(None)
74 }
75
76 fn large_utf8_cast_dtype(&self) -> ast::DataType {
79 ast::DataType::Text
80 }
81
82 fn date_field_extract_style(&self) -> DateFieldExtractStyle {
84 DateFieldExtractStyle::DatePart
85 }
86
87 fn character_length_style(&self) -> CharacterLengthStyle {
89 CharacterLengthStyle::CharacterLength
90 }
91
92 fn int64_cast_dtype(&self) -> ast::DataType {
95 ast::DataType::BigInt(None)
96 }
97
98 fn int32_cast_dtype(&self) -> ast::DataType {
101 ast::DataType::Integer(None)
102 }
103
104 fn timestamp_cast_dtype(
108 &self,
109 _time_unit: &TimeUnit,
110 tz: &Option<Arc<str>>,
111 ) -> ast::DataType {
112 let tz_info = match tz {
113 Some(_) => TimezoneInfo::WithTimeZone,
114 None => TimezoneInfo::None,
115 };
116
117 ast::DataType::Timestamp(None, tz_info)
118 }
119
120 fn date32_cast_dtype(&self) -> ast::DataType {
123 ast::DataType::Date
124 }
125
126 fn supports_column_alias_in_table_alias(&self) -> bool {
129 true
130 }
131
132 fn requires_derived_table_alias(&self) -> bool {
135 false
136 }
137
138 fn division_operator(&self) -> BinaryOperator {
142 BinaryOperator::Divide
143 }
144
145 fn scalar_function_to_sql_overrides(
149 &self,
150 _unparser: &Unparser,
151 _func_name: &str,
152 _args: &[Expr],
153 ) -> Result<Option<ast::Expr>> {
154 Ok(None)
155 }
156
157 fn window_func_support_window_frame(
161 &self,
162 _func_name: &str,
163 _start_bound: &WindowFrameBound,
164 _end_bound: &WindowFrameBound,
165 ) -> bool {
166 true
167 }
168
169 fn with_custom_scalar_overrides(
172 self,
173 _handlers: Vec<(&str, ScalarFnToSqlHandler)>,
174 ) -> Self
175 where
176 Self: Sized,
177 {
178 unimplemented!("Custom scalar overrides are not supported by this dialect yet");
179 }
180
181 fn full_qualified_col(&self) -> bool {
186 false
187 }
188
189 fn unnest_as_table_factor(&self) -> bool {
195 false
196 }
197}
198
199#[derive(Clone, Copy)]
208pub enum IntervalStyle {
209 PostgresVerbose,
210 SQLStandard,
211 MySQL,
212}
213
214#[derive(Clone, Copy, PartialEq)]
222pub enum DateFieldExtractStyle {
223 DatePart,
224 Extract,
225 Strftime,
226}
227
228#[derive(Clone, Copy, PartialEq)]
234pub enum CharacterLengthStyle {
235 Length,
236 CharacterLength,
237}
238
239pub struct DefaultDialect {}
240
241impl Dialect for DefaultDialect {
242 fn identifier_quote_style(&self, identifier: &str) -> Option<char> {
243 let identifier_regex = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap();
244 let id_upper = identifier.to_uppercase();
245 if (id_upper != "ID" && ALL_KEYWORDS.contains(&id_upper.as_str()))
248 || !identifier_regex.is_match(identifier)
249 {
250 Some('"')
251 } else {
252 None
253 }
254 }
255}
256
257pub struct PostgreSqlDialect {}
258
259impl Dialect for PostgreSqlDialect {
260 fn identifier_quote_style(&self, _: &str) -> Option<char> {
261 Some('"')
262 }
263
264 fn interval_style(&self) -> IntervalStyle {
265 IntervalStyle::PostgresVerbose
266 }
267
268 fn float64_ast_dtype(&self) -> ast::DataType {
269 ast::DataType::DoublePrecision
270 }
271
272 fn scalar_function_to_sql_overrides(
273 &self,
274 unparser: &Unparser,
275 func_name: &str,
276 args: &[Expr],
277 ) -> Result<Option<ast::Expr>> {
278 if func_name == "round" {
279 return Ok(Some(
280 self.round_to_sql_enforce_numeric(unparser, func_name, args)?,
281 ));
282 }
283
284 Ok(None)
285 }
286}
287
288impl PostgreSqlDialect {
289 fn round_to_sql_enforce_numeric(
290 &self,
291 unparser: &Unparser,
292 func_name: &str,
293 args: &[Expr],
294 ) -> Result<ast::Expr> {
295 let mut args = unparser.function_args_to_sql(args)?;
296
297 if let Some(ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(expr))) =
299 args.first_mut()
300 {
301 if let ast::Expr::Cast { data_type, .. } = expr {
302 *data_type = ast::DataType::Numeric(ast::ExactNumberInfo::None);
304 } else {
305 *expr = ast::Expr::Cast {
307 kind: ast::CastKind::Cast,
308 expr: Box::new(expr.clone()),
309 data_type: ast::DataType::Numeric(ast::ExactNumberInfo::None),
310 format: None,
311 };
312 }
313 }
314
315 Ok(ast::Expr::Function(Function {
316 name: ObjectName(vec![Ident {
317 value: func_name.to_string(),
318 quote_style: None,
319 span: Span::empty(),
320 }]),
321 args: ast::FunctionArguments::List(ast::FunctionArgumentList {
322 duplicate_treatment: None,
323 args,
324 clauses: vec![],
325 }),
326 filter: None,
327 null_treatment: None,
328 over: None,
329 within_group: vec![],
330 parameters: ast::FunctionArguments::None,
331 uses_odbc_syntax: false,
332 }))
333 }
334}
335
336#[derive(Default)]
337pub struct DuckDBDialect {
338 custom_scalar_fn_overrides: HashMap<String, ScalarFnToSqlHandler>,
339}
340
341impl DuckDBDialect {
342 #[must_use]
343 pub fn new() -> Self {
344 Self {
345 custom_scalar_fn_overrides: HashMap::new(),
346 }
347 }
348}
349
350impl Dialect for DuckDBDialect {
351 fn identifier_quote_style(&self, _: &str) -> Option<char> {
352 Some('"')
353 }
354
355 fn character_length_style(&self) -> CharacterLengthStyle {
356 CharacterLengthStyle::Length
357 }
358
359 fn division_operator(&self) -> BinaryOperator {
360 BinaryOperator::DuckIntegerDivide
361 }
362
363 fn with_custom_scalar_overrides(
364 mut self,
365 handlers: Vec<(&str, ScalarFnToSqlHandler)>,
366 ) -> Self {
367 for (func_name, handler) in handlers {
368 self.custom_scalar_fn_overrides
369 .insert(func_name.to_string(), handler);
370 }
371 self
372 }
373
374 fn scalar_function_to_sql_overrides(
375 &self,
376 unparser: &Unparser,
377 func_name: &str,
378 args: &[Expr],
379 ) -> Result<Option<ast::Expr>> {
380 if let Some(handler) = self.custom_scalar_fn_overrides.get(func_name) {
381 return handler(unparser, args);
382 }
383
384 if func_name == "character_length" {
385 return character_length_to_sql(
386 unparser,
387 self.character_length_style(),
388 args,
389 );
390 }
391
392 Ok(None)
393 }
394}
395
396pub struct MySqlDialect {}
397
398impl Dialect for MySqlDialect {
399 fn identifier_quote_style(&self, _: &str) -> Option<char> {
400 Some('`')
401 }
402
403 fn supports_nulls_first_in_sort(&self) -> bool {
404 false
405 }
406
407 fn interval_style(&self) -> IntervalStyle {
408 IntervalStyle::MySQL
409 }
410
411 fn utf8_cast_dtype(&self) -> ast::DataType {
412 ast::DataType::Char(None)
413 }
414
415 fn large_utf8_cast_dtype(&self) -> ast::DataType {
416 ast::DataType::Char(None)
417 }
418
419 fn date_field_extract_style(&self) -> DateFieldExtractStyle {
420 DateFieldExtractStyle::Extract
421 }
422
423 fn int64_cast_dtype(&self) -> ast::DataType {
424 ast::DataType::Custom(ObjectName(vec![Ident::new("SIGNED")]), vec![])
425 }
426
427 fn int32_cast_dtype(&self) -> ast::DataType {
428 ast::DataType::Custom(ObjectName(vec![Ident::new("SIGNED")]), vec![])
429 }
430
431 fn timestamp_cast_dtype(
432 &self,
433 _time_unit: &TimeUnit,
434 _tz: &Option<Arc<str>>,
435 ) -> ast::DataType {
436 ast::DataType::Datetime(None)
437 }
438
439 fn requires_derived_table_alias(&self) -> bool {
440 true
441 }
442
443 fn scalar_function_to_sql_overrides(
444 &self,
445 unparser: &Unparser,
446 func_name: &str,
447 args: &[Expr],
448 ) -> Result<Option<ast::Expr>> {
449 if func_name == "date_part" {
450 return date_part_to_sql(unparser, self.date_field_extract_style(), args);
451 }
452
453 Ok(None)
454 }
455}
456
457pub struct SqliteDialect {}
458
459impl Dialect for SqliteDialect {
460 fn identifier_quote_style(&self, _: &str) -> Option<char> {
461 Some('`')
462 }
463
464 fn date_field_extract_style(&self) -> DateFieldExtractStyle {
465 DateFieldExtractStyle::Strftime
466 }
467
468 fn date32_cast_dtype(&self) -> ast::DataType {
469 ast::DataType::Text
470 }
471
472 fn character_length_style(&self) -> CharacterLengthStyle {
473 CharacterLengthStyle::Length
474 }
475
476 fn supports_column_alias_in_table_alias(&self) -> bool {
477 false
478 }
479
480 fn scalar_function_to_sql_overrides(
481 &self,
482 unparser: &Unparser,
483 func_name: &str,
484 args: &[Expr],
485 ) -> Result<Option<ast::Expr>> {
486 match func_name {
487 "date_part" => {
488 date_part_to_sql(unparser, self.date_field_extract_style(), args)
489 }
490 "character_length" => {
491 character_length_to_sql(unparser, self.character_length_style(), args)
492 }
493 _ => Ok(None),
494 }
495 }
496}
497
498pub struct CustomDialect {
499 identifier_quote_style: Option<char>,
500 supports_nulls_first_in_sort: bool,
501 use_timestamp_for_date64: bool,
502 interval_style: IntervalStyle,
503 float64_ast_dtype: ast::DataType,
504 utf8_cast_dtype: ast::DataType,
505 large_utf8_cast_dtype: ast::DataType,
506 date_field_extract_style: DateFieldExtractStyle,
507 character_length_style: CharacterLengthStyle,
508 int64_cast_dtype: ast::DataType,
509 int32_cast_dtype: ast::DataType,
510 timestamp_cast_dtype: ast::DataType,
511 timestamp_tz_cast_dtype: ast::DataType,
512 date32_cast_dtype: ast::DataType,
513 supports_column_alias_in_table_alias: bool,
514 requires_derived_table_alias: bool,
515 division_operator: BinaryOperator,
516 window_func_support_window_frame: bool,
517 full_qualified_col: bool,
518 unnest_as_table_factor: bool,
519}
520
521impl Default for CustomDialect {
522 fn default() -> Self {
523 Self {
524 identifier_quote_style: None,
525 supports_nulls_first_in_sort: true,
526 use_timestamp_for_date64: false,
527 interval_style: IntervalStyle::SQLStandard,
528 float64_ast_dtype: ast::DataType::Double(ast::ExactNumberInfo::None),
529 utf8_cast_dtype: ast::DataType::Varchar(None),
530 large_utf8_cast_dtype: ast::DataType::Text,
531 date_field_extract_style: DateFieldExtractStyle::DatePart,
532 character_length_style: CharacterLengthStyle::CharacterLength,
533 int64_cast_dtype: ast::DataType::BigInt(None),
534 int32_cast_dtype: ast::DataType::Integer(None),
535 timestamp_cast_dtype: ast::DataType::Timestamp(None, TimezoneInfo::None),
536 timestamp_tz_cast_dtype: ast::DataType::Timestamp(
537 None,
538 TimezoneInfo::WithTimeZone,
539 ),
540 date32_cast_dtype: ast::DataType::Date,
541 supports_column_alias_in_table_alias: true,
542 requires_derived_table_alias: false,
543 division_operator: BinaryOperator::Divide,
544 window_func_support_window_frame: true,
545 full_qualified_col: false,
546 unnest_as_table_factor: false,
547 }
548 }
549}
550
551impl CustomDialect {
552 #[deprecated(since = "41.0.0", note = "please use `CustomDialectBuilder` instead")]
554 pub fn new(identifier_quote_style: Option<char>) -> Self {
555 Self {
556 identifier_quote_style,
557 ..Default::default()
558 }
559 }
560}
561
562impl Dialect for CustomDialect {
563 fn identifier_quote_style(&self, _: &str) -> Option<char> {
564 self.identifier_quote_style
565 }
566
567 fn supports_nulls_first_in_sort(&self) -> bool {
568 self.supports_nulls_first_in_sort
569 }
570
571 fn use_timestamp_for_date64(&self) -> bool {
572 self.use_timestamp_for_date64
573 }
574
575 fn interval_style(&self) -> IntervalStyle {
576 self.interval_style
577 }
578
579 fn float64_ast_dtype(&self) -> ast::DataType {
580 self.float64_ast_dtype.clone()
581 }
582
583 fn utf8_cast_dtype(&self) -> ast::DataType {
584 self.utf8_cast_dtype.clone()
585 }
586
587 fn large_utf8_cast_dtype(&self) -> ast::DataType {
588 self.large_utf8_cast_dtype.clone()
589 }
590
591 fn date_field_extract_style(&self) -> DateFieldExtractStyle {
592 self.date_field_extract_style
593 }
594
595 fn character_length_style(&self) -> CharacterLengthStyle {
596 self.character_length_style
597 }
598
599 fn int64_cast_dtype(&self) -> ast::DataType {
600 self.int64_cast_dtype.clone()
601 }
602
603 fn int32_cast_dtype(&self) -> ast::DataType {
604 self.int32_cast_dtype.clone()
605 }
606
607 fn timestamp_cast_dtype(
608 &self,
609 _time_unit: &TimeUnit,
610 tz: &Option<Arc<str>>,
611 ) -> ast::DataType {
612 if tz.is_some() {
613 self.timestamp_tz_cast_dtype.clone()
614 } else {
615 self.timestamp_cast_dtype.clone()
616 }
617 }
618
619 fn date32_cast_dtype(&self) -> ast::DataType {
620 self.date32_cast_dtype.clone()
621 }
622
623 fn supports_column_alias_in_table_alias(&self) -> bool {
624 self.supports_column_alias_in_table_alias
625 }
626
627 fn scalar_function_to_sql_overrides(
628 &self,
629 unparser: &Unparser,
630 func_name: &str,
631 args: &[Expr],
632 ) -> Result<Option<ast::Expr>> {
633 match func_name {
634 "date_part" => {
635 date_part_to_sql(unparser, self.date_field_extract_style(), args)
636 }
637 "character_length" => {
638 character_length_to_sql(unparser, self.character_length_style(), args)
639 }
640 _ => Ok(None),
641 }
642 }
643
644 fn requires_derived_table_alias(&self) -> bool {
645 self.requires_derived_table_alias
646 }
647
648 fn division_operator(&self) -> BinaryOperator {
649 self.division_operator.clone()
650 }
651
652 fn window_func_support_window_frame(
653 &self,
654 _func_name: &str,
655 _start_bound: &WindowFrameBound,
656 _end_bound: &WindowFrameBound,
657 ) -> bool {
658 self.window_func_support_window_frame
659 }
660
661 fn full_qualified_col(&self) -> bool {
662 self.full_qualified_col
663 }
664
665 fn unnest_as_table_factor(&self) -> bool {
666 self.unnest_as_table_factor
667 }
668}
669
670pub struct CustomDialectBuilder {
685 identifier_quote_style: Option<char>,
686 supports_nulls_first_in_sort: bool,
687 use_timestamp_for_date64: bool,
688 interval_style: IntervalStyle,
689 float64_ast_dtype: ast::DataType,
690 utf8_cast_dtype: ast::DataType,
691 large_utf8_cast_dtype: ast::DataType,
692 date_field_extract_style: DateFieldExtractStyle,
693 character_length_style: CharacterLengthStyle,
694 int64_cast_dtype: ast::DataType,
695 int32_cast_dtype: ast::DataType,
696 timestamp_cast_dtype: ast::DataType,
697 timestamp_tz_cast_dtype: ast::DataType,
698 date32_cast_dtype: ast::DataType,
699 supports_column_alias_in_table_alias: bool,
700 requires_derived_table_alias: bool,
701 division_operator: BinaryOperator,
702 window_func_support_window_frame: bool,
703 full_qualified_col: bool,
704 unnest_as_table_factor: bool,
705}
706
707impl Default for CustomDialectBuilder {
708 fn default() -> Self {
709 Self::new()
710 }
711}
712
713impl CustomDialectBuilder {
714 pub fn new() -> Self {
715 Self {
716 identifier_quote_style: None,
717 supports_nulls_first_in_sort: true,
718 use_timestamp_for_date64: false,
719 interval_style: IntervalStyle::PostgresVerbose,
720 float64_ast_dtype: ast::DataType::Double(ast::ExactNumberInfo::None),
721 utf8_cast_dtype: ast::DataType::Varchar(None),
722 large_utf8_cast_dtype: ast::DataType::Text,
723 date_field_extract_style: DateFieldExtractStyle::DatePart,
724 character_length_style: CharacterLengthStyle::CharacterLength,
725 int64_cast_dtype: ast::DataType::BigInt(None),
726 int32_cast_dtype: ast::DataType::Integer(None),
727 timestamp_cast_dtype: ast::DataType::Timestamp(None, TimezoneInfo::None),
728 timestamp_tz_cast_dtype: ast::DataType::Timestamp(
729 None,
730 TimezoneInfo::WithTimeZone,
731 ),
732 date32_cast_dtype: ast::DataType::Date,
733 supports_column_alias_in_table_alias: true,
734 requires_derived_table_alias: false,
735 division_operator: BinaryOperator::Divide,
736 window_func_support_window_frame: true,
737 full_qualified_col: false,
738 unnest_as_table_factor: false,
739 }
740 }
741
742 pub fn build(self) -> CustomDialect {
743 CustomDialect {
744 identifier_quote_style: self.identifier_quote_style,
745 supports_nulls_first_in_sort: self.supports_nulls_first_in_sort,
746 use_timestamp_for_date64: self.use_timestamp_for_date64,
747 interval_style: self.interval_style,
748 float64_ast_dtype: self.float64_ast_dtype,
749 utf8_cast_dtype: self.utf8_cast_dtype,
750 large_utf8_cast_dtype: self.large_utf8_cast_dtype,
751 date_field_extract_style: self.date_field_extract_style,
752 character_length_style: self.character_length_style,
753 int64_cast_dtype: self.int64_cast_dtype,
754 int32_cast_dtype: self.int32_cast_dtype,
755 timestamp_cast_dtype: self.timestamp_cast_dtype,
756 timestamp_tz_cast_dtype: self.timestamp_tz_cast_dtype,
757 date32_cast_dtype: self.date32_cast_dtype,
758 supports_column_alias_in_table_alias: self
759 .supports_column_alias_in_table_alias,
760 requires_derived_table_alias: self.requires_derived_table_alias,
761 division_operator: self.division_operator,
762 window_func_support_window_frame: self.window_func_support_window_frame,
763 full_qualified_col: self.full_qualified_col,
764 unnest_as_table_factor: self.unnest_as_table_factor,
765 }
766 }
767
768 pub fn with_identifier_quote_style(mut self, identifier_quote_style: char) -> Self {
770 self.identifier_quote_style = Some(identifier_quote_style);
771 self
772 }
773
774 pub fn with_supports_nulls_first_in_sort(
776 mut self,
777 supports_nulls_first_in_sort: bool,
778 ) -> Self {
779 self.supports_nulls_first_in_sort = supports_nulls_first_in_sort;
780 self
781 }
782
783 pub fn with_use_timestamp_for_date64(
785 mut self,
786 use_timestamp_for_date64: bool,
787 ) -> Self {
788 self.use_timestamp_for_date64 = use_timestamp_for_date64;
789 self
790 }
791
792 pub fn with_interval_style(mut self, interval_style: IntervalStyle) -> Self {
794 self.interval_style = interval_style;
795 self
796 }
797
798 pub fn with_character_length_style(
800 mut self,
801 character_length_style: CharacterLengthStyle,
802 ) -> Self {
803 self.character_length_style = character_length_style;
804 self
805 }
806
807 pub fn with_float64_ast_dtype(mut self, float64_ast_dtype: ast::DataType) -> Self {
809 self.float64_ast_dtype = float64_ast_dtype;
810 self
811 }
812
813 pub fn with_utf8_cast_dtype(mut self, utf8_cast_dtype: ast::DataType) -> Self {
815 self.utf8_cast_dtype = utf8_cast_dtype;
816 self
817 }
818
819 pub fn with_large_utf8_cast_dtype(
821 mut self,
822 large_utf8_cast_dtype: ast::DataType,
823 ) -> Self {
824 self.large_utf8_cast_dtype = large_utf8_cast_dtype;
825 self
826 }
827
828 pub fn with_date_field_extract_style(
830 mut self,
831 date_field_extract_style: DateFieldExtractStyle,
832 ) -> Self {
833 self.date_field_extract_style = date_field_extract_style;
834 self
835 }
836
837 pub fn with_int64_cast_dtype(mut self, int64_cast_dtype: ast::DataType) -> Self {
839 self.int64_cast_dtype = int64_cast_dtype;
840 self
841 }
842
843 pub fn with_int32_cast_dtype(mut self, int32_cast_dtype: ast::DataType) -> Self {
845 self.int32_cast_dtype = int32_cast_dtype;
846 self
847 }
848
849 pub fn with_timestamp_cast_dtype(
851 mut self,
852 timestamp_cast_dtype: ast::DataType,
853 timestamp_tz_cast_dtype: ast::DataType,
854 ) -> Self {
855 self.timestamp_cast_dtype = timestamp_cast_dtype;
856 self.timestamp_tz_cast_dtype = timestamp_tz_cast_dtype;
857 self
858 }
859
860 pub fn with_date32_cast_dtype(mut self, date32_cast_dtype: ast::DataType) -> Self {
861 self.date32_cast_dtype = date32_cast_dtype;
862 self
863 }
864
865 pub fn with_supports_column_alias_in_table_alias(
867 mut self,
868 supports_column_alias_in_table_alias: bool,
869 ) -> Self {
870 self.supports_column_alias_in_table_alias = supports_column_alias_in_table_alias;
871 self
872 }
873
874 pub fn with_requires_derived_table_alias(
875 mut self,
876 requires_derived_table_alias: bool,
877 ) -> Self {
878 self.requires_derived_table_alias = requires_derived_table_alias;
879 self
880 }
881
882 pub fn with_division_operator(mut self, division_operator: BinaryOperator) -> Self {
883 self.division_operator = division_operator;
884 self
885 }
886
887 pub fn with_window_func_support_window_frame(
888 mut self,
889 window_func_support_window_frame: bool,
890 ) -> Self {
891 self.window_func_support_window_frame = window_func_support_window_frame;
892 self
893 }
894
895 pub fn with_full_qualified_col(mut self, full_qualified_col: bool) -> Self {
897 self.full_qualified_col = full_qualified_col;
898 self
899 }
900
901 pub fn with_unnest_as_table_factor(mut self, _unnest_as_table_factor: bool) -> Self {
902 self.unnest_as_table_factor = _unnest_as_table_factor;
903 self
904 }
905}