datafusion_sql/unparser/
dialect.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use 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
36/// `Dialect` to use for Unparsing
37///
38/// The default dialect tries to avoid quoting identifiers unless necessary (e.g. `a` instead of `"a"`)
39/// but this behavior can be overridden as needed
40///
41/// **Note**: This trait will eventually be replaced by the Dialect in the SQLparser package
42///
43/// See <https://github.com/sqlparser-rs/sqlparser-rs/pull/1170>
44/// See also the discussion in <https://github.com/apache/datafusion/pull/10625>
45pub trait Dialect: Send + Sync {
46    /// Return the character used to quote identifiers.
47    fn identifier_quote_style(&self, _identifier: &str) -> Option<char>;
48
49    /// Does the dialect support specifying `NULLS FIRST/LAST` in `ORDER BY` clauses?
50    fn supports_nulls_first_in_sort(&self) -> bool {
51        true
52    }
53
54    /// Does the dialect use TIMESTAMP to represent Date64 rather than DATETIME?
55    /// E.g. Trino, Athena and Dremio does not have DATETIME data type
56    fn use_timestamp_for_date64(&self) -> bool {
57        false
58    }
59
60    fn interval_style(&self) -> IntervalStyle {
61        IntervalStyle::PostgresVerbose
62    }
63
64    /// Does the dialect use DOUBLE PRECISION to represent Float64 rather than DOUBLE?
65    /// E.g. Postgres uses DOUBLE PRECISION instead of DOUBLE
66    fn float64_ast_dtype(&self) -> ast::DataType {
67        ast::DataType::Double(ast::ExactNumberInfo::None)
68    }
69
70    /// The SQL type to use for Arrow Utf8 unparsing
71    /// Most dialects use VARCHAR, but some, like MySQL, require CHAR
72    fn utf8_cast_dtype(&self) -> ast::DataType {
73        ast::DataType::Varchar(None)
74    }
75
76    /// The SQL type to use for Arrow LargeUtf8 unparsing
77    /// Most dialects use TEXT, but some, like MySQL, require CHAR
78    fn large_utf8_cast_dtype(&self) -> ast::DataType {
79        ast::DataType::Text
80    }
81
82    /// The date field extract style to use: `DateFieldExtractStyle`
83    fn date_field_extract_style(&self) -> DateFieldExtractStyle {
84        DateFieldExtractStyle::DatePart
85    }
86
87    /// The character length extraction style to use: `CharacterLengthStyle`
88    fn character_length_style(&self) -> CharacterLengthStyle {
89        CharacterLengthStyle::CharacterLength
90    }
91
92    /// The SQL type to use for Arrow Int64 unparsing
93    /// Most dialects use BigInt, but some, like MySQL, require SIGNED
94    fn int64_cast_dtype(&self) -> ast::DataType {
95        ast::DataType::BigInt(None)
96    }
97
98    /// The SQL type to use for Arrow Int32 unparsing
99    /// Most dialects use Integer, but some, like MySQL, require SIGNED
100    fn int32_cast_dtype(&self) -> ast::DataType {
101        ast::DataType::Integer(None)
102    }
103
104    /// The SQL type to use for Timestamp unparsing
105    /// Most dialects use Timestamp, but some, like MySQL, require Datetime
106    /// Some dialects like Dremio does not support WithTimeZone and requires always Timestamp
107    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    /// The SQL type to use for Arrow Date32 unparsing
121    /// Most dialects use Date, but some, like SQLite require TEXT
122    fn date32_cast_dtype(&self) -> ast::DataType {
123        ast::DataType::Date
124    }
125
126    /// Does the dialect support specifying column aliases as part of alias table definition?
127    /// (SELECT col1, col2 from my_table) AS my_table_alias(col1_alias, col2_alias)
128    fn supports_column_alias_in_table_alias(&self) -> bool {
129        true
130    }
131
132    /// Whether the dialect requires a table alias for any subquery in the FROM clause
133    /// This affects behavior when deriving logical plans for Sort, Limit, etc.
134    fn requires_derived_table_alias(&self) -> bool {
135        false
136    }
137
138    /// The division operator for the dialect
139    /// Most dialect uses ` BinaryOperator::Divide` (/)
140    /// But DuckDB dialect uses `BinaryOperator::DuckIntegerDivide` (//)
141    fn division_operator(&self) -> BinaryOperator {
142        BinaryOperator::Divide
143    }
144
145    /// Allows the dialect to override scalar function unparsing if the dialect has specific rules.
146    /// Returns None if the default unparsing should be used, or Some(ast::Expr) if there is
147    /// a custom implementation for the function.
148    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    /// Allows the dialect to choose to omit window frame in unparsing
158    /// based on function name and window frame bound
159    /// Returns false if specific function name / window frame bound indicates no window frame is needed in unparsing
160    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    /// Extends the dialect's default rules for unparsing scalar functions.
170    /// This is useful for supporting application-specific UDFs or custom engine extensions.
171    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    /// Allow to unparse a qualified column with a full qualified name
182    /// (e.g. catalog_name.schema_name.table_name.column_name)
183    /// Otherwise, the column will be unparsed with only the table name and column name
184    /// (e.g. table_name.column_name)
185    fn full_qualified_col(&self) -> bool {
186        false
187    }
188
189    /// Allow to unparse the unnest plan as [ast::TableFactor::UNNEST].
190    ///
191    /// Some dialects like BigQuery require UNNEST to be used in the FROM clause but
192    /// the LogicalPlan planner always puts UNNEST in the SELECT clause. This flag allows
193    /// to unparse the UNNEST plan as [ast::TableFactor::UNNEST] instead of a subquery.
194    fn unnest_as_table_factor(&self) -> bool {
195        false
196    }
197}
198
199/// `IntervalStyle` to use for unparsing
200///
201/// <https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT>
202/// different DBMS follows different standards, popular ones are:
203/// postgres_verbose: '2 years 15 months 100 weeks 99 hours 123456789 milliseconds' which is
204/// compatible with arrow display format, as well as duckdb
205/// sql standard format is '1-2' for year-month, or '1 10:10:10.123456' for day-time
206/// <https://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt>
207#[derive(Clone, Copy)]
208pub enum IntervalStyle {
209    PostgresVerbose,
210    SQLStandard,
211    MySQL,
212}
213
214/// Datetime subfield extraction style for unparsing
215///
216/// `<https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT>`
217/// Different DBMSs follow different standards; popular ones are:
218/// date_part('YEAR', date '2001-02-16')
219/// EXTRACT(YEAR from date '2001-02-16')
220/// Some DBMSs, like Postgres, support both, whereas others like MySQL require EXTRACT.
221#[derive(Clone, Copy, PartialEq)]
222pub enum DateFieldExtractStyle {
223    DatePart,
224    Extract,
225    Strftime,
226}
227
228/// `CharacterLengthStyle` to use for unparsing
229///
230/// Different DBMSs uses different names for function calculating the number of characters in the string
231/// `Length` style uses length(x)
232/// `SQLStandard` style uses character_length(x)
233#[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        // Special case ignore "ID", see https://github.com/sqlparser-rs/sqlparser-rs/issues/1382
246        // ID is a keyword in ClickHouse, but we don't want to quote it when unparsing SQL here
247        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        // Enforce the first argument to be Numeric
298        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                // Don't create an additional cast wrapper if we can update the existing one
303                *data_type = ast::DataType::Numeric(ast::ExactNumberInfo::None);
304            } else {
305                // Wrap the expression in a new cast
306                *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    // Create a CustomDialect
553    #[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
670/// `CustomDialectBuilder` to build `CustomDialect` using builder pattern
671///
672///
673/// # Examples
674///
675/// Building a custom dialect with all default options set in CustomDialectBuilder::new()
676/// but with `use_timestamp_for_date64` overridden to `true`
677///
678/// ```
679/// use datafusion_sql::unparser::dialect::CustomDialectBuilder;
680/// let dialect = CustomDialectBuilder::new()
681///     .with_use_timestamp_for_date64(true)
682///     .build();
683/// ```
684pub 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    /// Customize the dialect with a specific identifier quote style, e.g. '`', '"'
769    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    /// Customize the dialect to support `NULLS FIRST` in `ORDER BY` clauses
775    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    /// Customize the dialect to uses TIMESTAMP when casting Date64 rather than DATETIME
784    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    /// Customize the dialect with a specific interval style listed in `IntervalStyle`
793    pub fn with_interval_style(mut self, interval_style: IntervalStyle) -> Self {
794        self.interval_style = interval_style;
795        self
796    }
797
798    /// Customize the dialect with a specific character_length_style listed in `CharacterLengthStyle`
799    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    /// Customize the dialect with a specific SQL type for Float64 casting: DOUBLE, DOUBLE PRECISION, etc.
808    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    /// Customize the dialect with a specific SQL type for Utf8 casting: VARCHAR, CHAR, etc.
814    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    /// Customize the dialect with a specific SQL type for LargeUtf8 casting: TEXT, CHAR, etc.
820    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    /// Customize the dialect with a specific date field extract style listed in `DateFieldExtractStyle`
829    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    /// Customize the dialect with a specific SQL type for Int64 casting: BigInt, SIGNED, etc.
838    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    /// Customize the dialect with a specific SQL type for Int32 casting: Integer, SIGNED, etc.
844    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    /// Customize the dialect with a specific SQL type for Timestamp casting: Timestamp, Datetime, etc.
850    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    /// Customize the dialect to support column aliases as part of alias table definition
866    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    /// Customize the dialect to allow full qualified column names
896    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}