sqltk_parser/ast/
data_type.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
18#[cfg(not(feature = "std"))]
19use alloc::{boxed::Box, format, string::String, vec::Vec};
20use core::fmt;
21
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25#[cfg(feature = "visitor")]
26use sqltk_parser_derive::{Visit, VisitMut};
27
28use crate::ast::{display_comma_separated, ObjectName, StructField, UnionField};
29
30use super::{value::escape_single_quote_string, ColumnDef};
31
32/// SQL data types
33#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
36pub enum DataType {
37    /// Fixed-length character type e.g. CHARACTER(10)
38    Character(Option<CharacterLength>),
39    /// Fixed-length char type e.g. CHAR(10)
40    Char(Option<CharacterLength>),
41    /// Character varying type e.g. CHARACTER VARYING(10)
42    CharacterVarying(Option<CharacterLength>),
43    /// Char varying type e.g. CHAR VARYING(10)
44    CharVarying(Option<CharacterLength>),
45    /// Variable-length character type e.g. VARCHAR(10)
46    Varchar(Option<CharacterLength>),
47    /// Variable-length character type e.g. NVARCHAR(10)
48    Nvarchar(Option<CharacterLength>),
49    /// Uuid type
50    Uuid,
51    /// Large character object with optional length e.g. CHARACTER LARGE OBJECT, CHARACTER LARGE OBJECT(1000), [standard]
52    ///
53    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type
54    CharacterLargeObject(Option<u64>),
55    /// Large character object with optional length e.g. CHAR LARGE OBJECT, CHAR LARGE OBJECT(1000), [standard]
56    ///
57    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type
58    CharLargeObject(Option<u64>),
59    /// Large character object with optional length e.g. CLOB, CLOB(1000), [standard]
60    ///
61    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type
62    /// [Oracle]: https://docs.oracle.com/javadb/10.10.1.2/ref/rrefclob.html
63    Clob(Option<u64>),
64    /// Fixed-length binary type with optional length e.g.  [standard], [MS SQL Server]
65    ///
66    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type
67    /// [MS SQL Server]: https://learn.microsoft.com/pt-br/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16
68    Binary(Option<u64>),
69    /// Variable-length binary with optional length type e.g. [standard], [MS SQL Server]
70    ///
71    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type
72    /// [MS SQL Server]: https://learn.microsoft.com/pt-br/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16
73    Varbinary(Option<u64>),
74    /// Large binary object with optional length e.g. BLOB, BLOB(1000), [standard], [Oracle]
75    ///
76    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-large-object-string-type
77    /// [Oracle]: https://docs.oracle.com/javadb/10.8.3.0/ref/rrefblob.html
78    Blob(Option<u64>),
79    /// Variable-length binary data with optional length.
80    ///
81    /// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#bytes_type
82    Bytes(Option<u64>),
83    /// Numeric type with optional precision and scale e.g. NUMERIC(10,2), [standard][1]
84    ///
85    /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
86    Numeric(ExactNumberInfo),
87    /// Decimal type with optional precision and scale e.g. DECIMAL(10,2), [standard][1]
88    ///
89    /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
90    Decimal(ExactNumberInfo),
91    /// [BigNumeric] type used in BigQuery
92    ///
93    /// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals
94    BigNumeric(ExactNumberInfo),
95    /// This is alias for `BigNumeric` type used in BigQuery
96    ///
97    /// [BigDecimal]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#decimal_types
98    BigDecimal(ExactNumberInfo),
99    /// Dec type with optional precision and scale e.g. DEC(10,2), [standard][1]
100    ///
101    /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
102    Dec(ExactNumberInfo),
103    /// Floating point with optional precision e.g. FLOAT(8)
104    Float(Option<u64>),
105    /// Tiny integer with optional display width e.g. TINYINT or TINYINT(3)
106    TinyInt(Option<u64>),
107    /// Unsigned tiny integer with optional display width e.g. TINYINT UNSIGNED or TINYINT(3) UNSIGNED
108    UnsignedTinyInt(Option<u64>),
109    /// Int2 as alias for SmallInt in [postgresql]
110    /// Note: Int2 mean 2 bytes in postgres (not 2 bits)
111    /// Int2 with optional display width e.g. INT2 or INT2(5)
112    ///
113    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
114    Int2(Option<u64>),
115    /// Unsigned Int2 with optional display width e.g. INT2 Unsigned or INT2(5) Unsigned
116    UnsignedInt2(Option<u64>),
117    /// Small integer with optional display width e.g. SMALLINT or SMALLINT(5)
118    SmallInt(Option<u64>),
119    /// Unsigned small integer with optional display width e.g. SMALLINT UNSIGNED or SMALLINT(5) UNSIGNED
120    UnsignedSmallInt(Option<u64>),
121    /// MySQL medium integer ([1]) with optional display width e.g. MEDIUMINT or MEDIUMINT(5)
122    ///
123    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
124    MediumInt(Option<u64>),
125    /// Unsigned medium integer ([1]) with optional display width e.g. MEDIUMINT UNSIGNED or MEDIUMINT(5) UNSIGNED
126    ///
127    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
128    UnsignedMediumInt(Option<u64>),
129    /// Int with optional display width e.g. INT or INT(11)
130    Int(Option<u64>),
131    /// Int4 as alias for Integer in [postgresql]
132    /// Note: Int4 mean 4 bytes in postgres (not 4 bits)
133    /// Int4 with optional display width e.g. Int4 or Int4(11)
134    ///
135    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
136    Int4(Option<u64>),
137    /// Int8 as alias for Bigint in [postgresql] and integer type in [clickhouse]
138    /// Note: Int8 mean 8 bytes in [postgresql] (not 8 bits)
139    /// Int8 with optional display width e.g. INT8 or INT8(11)
140    /// Note: Int8 mean 8 bits in [clickhouse]
141    ///
142    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
143    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
144    Int8(Option<u64>),
145    /// Integer type in [clickhouse]
146    /// Note: Int16 mean 16 bits in [clickhouse]
147    ///
148    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
149    Int16,
150    /// Integer type in [clickhouse]
151    /// Note: Int16 mean 32 bits in [clickhouse]
152    ///
153    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
154    Int32,
155    /// Integer type in [bigquery], [clickhouse]
156    ///
157    /// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#integer_types
158    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
159    Int64,
160    /// Integer type in [clickhouse]
161    /// Note: Int128 mean 128 bits in [clickhouse]
162    ///
163    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
164    Int128,
165    /// Integer type in [clickhouse]
166    /// Note: Int256 mean 256 bits in [clickhouse]
167    ///
168    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
169    Int256,
170    /// Integer with optional display width e.g. INTEGER or INTEGER(11)
171    Integer(Option<u64>),
172    /// Unsigned int with optional display width e.g. INT UNSIGNED or INT(11) UNSIGNED
173    UnsignedInt(Option<u64>),
174    /// Unsigned int4 with optional display width e.g. INT4 UNSIGNED or INT4(11) UNSIGNED
175    UnsignedInt4(Option<u64>),
176    /// Unsigned integer with optional display width e.g. INTEGER UNSIGNED or INTEGER(11) UNSIGNED
177    UnsignedInteger(Option<u64>),
178    /// Unsigned integer type in [clickhouse]
179    /// Note: UInt8 mean 8 bits in [clickhouse]
180    ///
181    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
182    UInt8,
183    /// Unsigned integer type in [clickhouse]
184    /// Note: UInt16 mean 16 bits in [clickhouse]
185    ///
186    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
187    UInt16,
188    /// Unsigned integer type in [clickhouse]
189    /// Note: UInt32 mean 32 bits in [clickhouse]
190    ///
191    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
192    UInt32,
193    /// Unsigned integer type in [clickhouse]
194    /// Note: UInt64 mean 64 bits in [clickhouse]
195    ///
196    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
197    UInt64,
198    /// Unsigned integer type in [clickhouse]
199    /// Note: UInt128 mean 128 bits in [clickhouse]
200    ///
201    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
202    UInt128,
203    /// Unsigned integer type in [clickhouse]
204    /// Note: UInt256 mean 256 bits in [clickhouse]
205    ///
206    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint
207    UInt256,
208    /// Big integer with optional display width e.g. BIGINT or BIGINT(20)
209    BigInt(Option<u64>),
210    /// Unsigned big integer with optional display width e.g. BIGINT UNSIGNED or BIGINT(20) UNSIGNED
211    UnsignedBigInt(Option<u64>),
212    /// Unsigned Int8 with optional display width e.g. INT8 UNSIGNED or INT8(11) UNSIGNED
213    UnsignedInt8(Option<u64>),
214    /// Float4 as alias for Real in [postgresql]
215    ///
216    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
217    Float4,
218    /// Floating point in [clickhouse]
219    ///
220    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/float
221    Float32,
222    /// Floating point in [bigquery]
223    ///
224    /// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#floating_point_types
225    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/float
226    Float64,
227    /// Floating point e.g. REAL
228    Real,
229    /// Float8 as alias for Double in [postgresql]
230    ///
231    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
232    Float8,
233    /// Double
234    Double,
235    /// Double PRECISION e.g. [standard], [postgresql]
236    ///
237    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
238    /// [postgresql]: https://www.postgresql.org/docs/current/datatype-numeric.html
239    DoublePrecision,
240    /// Bool as alias for Boolean in [postgresql]
241    ///
242    /// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
243    Bool,
244    /// Boolean
245    Boolean,
246    /// Date
247    Date,
248    /// Date32 with the same range as Datetime64
249    ///
250    /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/date32
251    Date32,
252    /// Time with optional time precision and time zone information e.g. [standard][1].
253    ///
254    /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type
255    Time(Option<u64>, TimezoneInfo),
256    /// Datetime with optional time precision e.g. [MySQL][1].
257    ///
258    /// [1]: https://dev.mysql.com/doc/refman/8.0/en/datetime.html
259    Datetime(Option<u64>),
260    /// Datetime with time precision and optional timezone e.g. [ClickHouse][1].
261    ///
262    /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/datetime64
263    Datetime64(u64, Option<String>),
264    /// Timestamp with optional time precision and time zone information e.g. [standard][1].
265    ///
266    /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type
267    Timestamp(Option<u64>, TimezoneInfo),
268    /// Interval
269    Interval,
270    /// JSON type
271    JSON,
272    /// Binary JSON type
273    JSONB,
274    /// Regclass used in postgresql serial
275    Regclass,
276    /// Text
277    Text,
278    /// String with optional length.
279    String(Option<u64>),
280    /// A fixed-length string e.g [ClickHouse][1].
281    ///
282    /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/fixedstring
283    FixedString(u64),
284    /// Bytea
285    Bytea,
286    /// Custom type such as enums
287    Custom(ObjectName, Vec<String>),
288    /// Arrays
289    Array(ArrayElemTypeDef),
290    /// Map
291    ///
292    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/map
293    Map(Box<DataType>, Box<DataType>),
294    /// Tuple
295    ///
296    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/tuple
297    Tuple(Vec<StructField>),
298    /// Nested
299    ///
300    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/nested-data-structures/nested
301    Nested(Vec<ColumnDef>),
302    /// Enums
303    Enum(Vec<String>),
304    /// Set
305    Set(Vec<String>),
306    /// Struct
307    ///
308    /// [hive]: https://docs.cloudera.com/cdw-runtime/cloud/impala-sql-reference/topics/impala-struct.html
309    /// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
310    Struct(Vec<StructField>, StructBracketKind),
311    /// Union
312    ///
313    /// [duckdb]: https://duckdb.org/docs/sql/data_types/union.html
314    Union(Vec<UnionField>),
315    /// Nullable - special marker NULL represents in ClickHouse as a data type.
316    ///
317    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/nullable
318    Nullable(Box<DataType>),
319    /// LowCardinality - changes the internal representation of other data types to be dictionary-encoded.
320    ///
321    /// [clickhouse]: https://clickhouse.com/docs/en/sql-reference/data-types/lowcardinality
322    LowCardinality(Box<DataType>),
323    /// No type specified - only used with
324    /// [`SQLiteDialect`](crate::dialect::SQLiteDialect), from statements such
325    /// as `CREATE TABLE t1 (a)`.
326    Unspecified,
327    /// Trigger data type, returned by functions associated with triggers
328    ///
329    /// [postgresql]: https://www.postgresql.org/docs/current/plpgsql-trigger.html
330    Trigger,
331}
332
333impl fmt::Display for DataType {
334    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335        match self {
336            DataType::Character(size) => format_character_string_type(f, "CHARACTER", size),
337            DataType::Char(size) => format_character_string_type(f, "CHAR", size),
338            DataType::CharacterVarying(size) => {
339                format_character_string_type(f, "CHARACTER VARYING", size)
340            }
341
342            DataType::CharVarying(size) => format_character_string_type(f, "CHAR VARYING", size),
343            DataType::Varchar(size) => format_character_string_type(f, "VARCHAR", size),
344            DataType::Nvarchar(size) => format_character_string_type(f, "NVARCHAR", size),
345            DataType::Uuid => write!(f, "UUID"),
346            DataType::CharacterLargeObject(size) => {
347                format_type_with_optional_length(f, "CHARACTER LARGE OBJECT", size, false)
348            }
349            DataType::CharLargeObject(size) => {
350                format_type_with_optional_length(f, "CHAR LARGE OBJECT", size, false)
351            }
352            DataType::Clob(size) => format_type_with_optional_length(f, "CLOB", size, false),
353            DataType::Binary(size) => format_type_with_optional_length(f, "BINARY", size, false),
354            DataType::Varbinary(size) => {
355                format_type_with_optional_length(f, "VARBINARY", size, false)
356            }
357            DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false),
358            DataType::Bytes(size) => format_type_with_optional_length(f, "BYTES", size, false),
359            DataType::Numeric(info) => {
360                write!(f, "NUMERIC{info}")
361            }
362            DataType::Decimal(info) => {
363                write!(f, "DECIMAL{info}")
364            }
365            DataType::Dec(info) => {
366                write!(f, "DEC{info}")
367            }
368            DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"),
369            DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"),
370            DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
371            DataType::TinyInt(zerofill) => {
372                format_type_with_optional_length(f, "TINYINT", zerofill, false)
373            }
374            DataType::UnsignedTinyInt(zerofill) => {
375                format_type_with_optional_length(f, "TINYINT", zerofill, true)
376            }
377            DataType::Int2(zerofill) => {
378                format_type_with_optional_length(f, "INT2", zerofill, false)
379            }
380            DataType::UnsignedInt2(zerofill) => {
381                format_type_with_optional_length(f, "INT2", zerofill, true)
382            }
383            DataType::SmallInt(zerofill) => {
384                format_type_with_optional_length(f, "SMALLINT", zerofill, false)
385            }
386            DataType::UnsignedSmallInt(zerofill) => {
387                format_type_with_optional_length(f, "SMALLINT", zerofill, true)
388            }
389            DataType::MediumInt(zerofill) => {
390                format_type_with_optional_length(f, "MEDIUMINT", zerofill, false)
391            }
392            DataType::UnsignedMediumInt(zerofill) => {
393                format_type_with_optional_length(f, "MEDIUMINT", zerofill, true)
394            }
395            DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false),
396            DataType::UnsignedInt(zerofill) => {
397                format_type_with_optional_length(f, "INT", zerofill, true)
398            }
399            DataType::Int4(zerofill) => {
400                format_type_with_optional_length(f, "INT4", zerofill, false)
401            }
402            DataType::Int8(zerofill) => {
403                format_type_with_optional_length(f, "INT8", zerofill, false)
404            }
405            DataType::Int16 => {
406                write!(f, "Int16")
407            }
408            DataType::Int32 => {
409                write!(f, "Int32")
410            }
411            DataType::Int64 => {
412                write!(f, "INT64")
413            }
414            DataType::Int128 => {
415                write!(f, "Int128")
416            }
417            DataType::Int256 => {
418                write!(f, "Int256")
419            }
420            DataType::UnsignedInt4(zerofill) => {
421                format_type_with_optional_length(f, "INT4", zerofill, true)
422            }
423            DataType::Integer(zerofill) => {
424                format_type_with_optional_length(f, "INTEGER", zerofill, false)
425            }
426            DataType::UnsignedInteger(zerofill) => {
427                format_type_with_optional_length(f, "INTEGER", zerofill, true)
428            }
429            DataType::BigInt(zerofill) => {
430                format_type_with_optional_length(f, "BIGINT", zerofill, false)
431            }
432            DataType::UnsignedBigInt(zerofill) => {
433                format_type_with_optional_length(f, "BIGINT", zerofill, true)
434            }
435            DataType::UnsignedInt8(zerofill) => {
436                format_type_with_optional_length(f, "INT8", zerofill, true)
437            }
438            DataType::UInt8 => {
439                write!(f, "UInt8")
440            }
441            DataType::UInt16 => {
442                write!(f, "UInt16")
443            }
444            DataType::UInt32 => {
445                write!(f, "UInt32")
446            }
447            DataType::UInt64 => {
448                write!(f, "UInt64")
449            }
450            DataType::UInt128 => {
451                write!(f, "UInt128")
452            }
453            DataType::UInt256 => {
454                write!(f, "UInt256")
455            }
456            DataType::Real => write!(f, "REAL"),
457            DataType::Float4 => write!(f, "FLOAT4"),
458            DataType::Float32 => write!(f, "Float32"),
459            DataType::Float64 => write!(f, "FLOAT64"),
460            DataType::Double => write!(f, "DOUBLE"),
461            DataType::Float8 => write!(f, "FLOAT8"),
462            DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
463            DataType::Bool => write!(f, "BOOL"),
464            DataType::Boolean => write!(f, "BOOLEAN"),
465            DataType::Date => write!(f, "DATE"),
466            DataType::Date32 => write!(f, "Date32"),
467            DataType::Time(precision, timezone_info) => {
468                format_datetime_precision_and_tz(f, "TIME", precision, timezone_info)
469            }
470            DataType::Datetime(precision) => {
471                format_type_with_optional_length(f, "DATETIME", precision, false)
472            }
473            DataType::Timestamp(precision, timezone_info) => {
474                format_datetime_precision_and_tz(f, "TIMESTAMP", precision, timezone_info)
475            }
476            DataType::Datetime64(precision, timezone) => {
477                format_clickhouse_datetime_precision_and_timezone(
478                    f,
479                    "DateTime64",
480                    precision,
481                    timezone,
482                )
483            }
484            DataType::Interval => write!(f, "INTERVAL"),
485            DataType::JSON => write!(f, "JSON"),
486            DataType::JSONB => write!(f, "JSONB"),
487            DataType::Regclass => write!(f, "REGCLASS"),
488            DataType::Text => write!(f, "TEXT"),
489            DataType::String(size) => format_type_with_optional_length(f, "STRING", size, false),
490            DataType::Bytea => write!(f, "BYTEA"),
491            DataType::Array(ty) => match ty {
492                ArrayElemTypeDef::None => write!(f, "ARRAY"),
493                ArrayElemTypeDef::SquareBracket(t, None) => write!(f, "{t}[]"),
494                ArrayElemTypeDef::SquareBracket(t, Some(size)) => write!(f, "{t}[{size}]"),
495                ArrayElemTypeDef::AngleBracket(t) => write!(f, "ARRAY<{t}>"),
496                ArrayElemTypeDef::Parenthesis(t) => write!(f, "Array({t})"),
497            },
498            DataType::Custom(ty, modifiers) => {
499                if modifiers.is_empty() {
500                    write!(f, "{ty}")
501                } else {
502                    write!(f, "{}({})", ty, modifiers.join(", "))
503                }
504            }
505            DataType::Enum(vals) => {
506                write!(f, "ENUM(")?;
507                for (i, v) in vals.iter().enumerate() {
508                    if i != 0 {
509                        write!(f, ", ")?;
510                    }
511                    write!(f, "'{}'", escape_single_quote_string(v))?;
512                }
513                write!(f, ")")
514            }
515            DataType::Set(vals) => {
516                write!(f, "SET(")?;
517                for (i, v) in vals.iter().enumerate() {
518                    if i != 0 {
519                        write!(f, ", ")?;
520                    }
521                    write!(f, "'{}'", escape_single_quote_string(v))?;
522                }
523                write!(f, ")")
524            }
525            DataType::Struct(fields, bracket) => {
526                if !fields.is_empty() {
527                    match bracket {
528                        StructBracketKind::Parentheses => {
529                            write!(f, "STRUCT({})", display_comma_separated(fields))
530                        }
531                        StructBracketKind::AngleBrackets => {
532                            write!(f, "STRUCT<{}>", display_comma_separated(fields))
533                        }
534                    }
535                } else {
536                    write!(f, "STRUCT")
537                }
538            }
539            DataType::Union(fields) => {
540                write!(f, "UNION({})", display_comma_separated(fields))
541            }
542            // ClickHouse
543            DataType::Nullable(data_type) => {
544                write!(f, "Nullable({})", data_type)
545            }
546            DataType::FixedString(character_length) => {
547                write!(f, "FixedString({})", character_length)
548            }
549            DataType::LowCardinality(data_type) => {
550                write!(f, "LowCardinality({})", data_type)
551            }
552            DataType::Map(key_data_type, value_data_type) => {
553                write!(f, "Map({}, {})", key_data_type, value_data_type)
554            }
555            DataType::Tuple(fields) => {
556                write!(f, "Tuple({})", display_comma_separated(fields))
557            }
558            DataType::Nested(fields) => {
559                write!(f, "Nested({})", display_comma_separated(fields))
560            }
561            DataType::Unspecified => Ok(()),
562            DataType::Trigger => write!(f, "TRIGGER"),
563        }
564    }
565}
566
567fn format_type_with_optional_length(
568    f: &mut fmt::Formatter,
569    sql_type: &'static str,
570    len: &Option<u64>,
571    unsigned: bool,
572) -> fmt::Result {
573    write!(f, "{sql_type}")?;
574    if let Some(len) = len {
575        write!(f, "({len})")?;
576    }
577    if unsigned {
578        write!(f, " UNSIGNED")?;
579    }
580    Ok(())
581}
582
583fn format_character_string_type(
584    f: &mut fmt::Formatter,
585    sql_type: &str,
586    size: &Option<CharacterLength>,
587) -> fmt::Result {
588    write!(f, "{sql_type}")?;
589    if let Some(size) = size {
590        write!(f, "({size})")?;
591    }
592    Ok(())
593}
594
595fn format_datetime_precision_and_tz(
596    f: &mut fmt::Formatter,
597    sql_type: &'static str,
598    len: &Option<u64>,
599    time_zone: &TimezoneInfo,
600) -> fmt::Result {
601    write!(f, "{sql_type}")?;
602    let len_fmt = len.as_ref().map(|l| format!("({l})")).unwrap_or_default();
603
604    match time_zone {
605        TimezoneInfo::Tz => {
606            write!(f, "{time_zone}{len_fmt}")?;
607        }
608        _ => {
609            write!(f, "{len_fmt}{time_zone}")?;
610        }
611    }
612
613    Ok(())
614}
615
616fn format_clickhouse_datetime_precision_and_timezone(
617    f: &mut fmt::Formatter,
618    sql_type: &'static str,
619    len: &u64,
620    time_zone: &Option<String>,
621) -> fmt::Result {
622    write!(f, "{sql_type}({len}")?;
623
624    if let Some(time_zone) = time_zone {
625        write!(f, ", '{time_zone}'")?;
626    }
627
628    write!(f, ")")?;
629
630    Ok(())
631}
632
633/// Type of brackets used for `STRUCT` literals.
634#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
635#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
636#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
637pub enum StructBracketKind {
638    /// Example: `STRUCT(a INT, b STRING)`
639    Parentheses,
640    /// Example: `STRUCT<a INT, b STRING>`
641    AngleBrackets,
642}
643
644/// Timestamp and Time data types information about TimeZone formatting.
645///
646/// This is more related to a display information than real differences between each variant. To
647/// guarantee compatibility with the input query we must maintain its exact information.
648#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
649#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
650#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
651pub enum TimezoneInfo {
652    /// No information about time zone. E.g., TIMESTAMP
653    None,
654    /// Temporal type 'WITH TIME ZONE'. E.g., TIMESTAMP WITH TIME ZONE, [standard], [Oracle]
655    ///
656    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type
657    /// [Oracle]: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/nlspg/datetime-data-types-and-time-zone-support.html#GUID-3F1C388E-C651-43D5-ADBC-1A49E5C2CA05
658    WithTimeZone,
659    /// Temporal type 'WITHOUT TIME ZONE'. E.g., TIME WITHOUT TIME ZONE, [standard], [Postgresql]
660    ///
661    /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type
662    /// [Postgresql]: https://www.postgresql.org/docs/current/datatype-datetime.html
663    WithoutTimeZone,
664    /// Postgresql specific `WITH TIME ZONE` formatting, for both TIME and TIMESTAMP. E.g., TIMETZ, [Postgresql]
665    ///
666    /// [Postgresql]: https://www.postgresql.org/docs/current/datatype-datetime.html
667    Tz,
668}
669
670impl fmt::Display for TimezoneInfo {
671    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672        match self {
673            TimezoneInfo::None => {
674                write!(f, "")
675            }
676            TimezoneInfo::WithTimeZone => {
677                write!(f, " WITH TIME ZONE")
678            }
679            TimezoneInfo::WithoutTimeZone => {
680                write!(f, " WITHOUT TIME ZONE")
681            }
682            TimezoneInfo::Tz => {
683                // TZ is the only one that is displayed BEFORE the precision, so the datatype display
684                // must be aware of that. Check <https://www.postgresql.org/docs/14/datatype-datetime.html>
685                // for more information
686                write!(f, "TZ")
687            }
688        }
689    }
690}
691
692/// Additional information for `NUMERIC`, `DECIMAL`, and `DEC` data types
693/// following the 2016 [standard].
694///
695/// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
696#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
697#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
698#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
699pub enum ExactNumberInfo {
700    /// No additional information e.g. `DECIMAL`
701    None,
702    /// Only precision information e.g. `DECIMAL(10)`
703    Precision(u64),
704    /// Precision and scale information e.g. `DECIMAL(10,2)`
705    PrecisionAndScale(u64, u64),
706}
707
708impl fmt::Display for ExactNumberInfo {
709    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
710        match self {
711            ExactNumberInfo::None => {
712                write!(f, "")
713            }
714            ExactNumberInfo::Precision(p) => {
715                write!(f, "({p})")
716            }
717            ExactNumberInfo::PrecisionAndScale(p, s) => {
718                write!(f, "({p},{s})")
719            }
720        }
721    }
722}
723
724/// Information about [character length][1], including length and possibly unit.
725///
726/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-length
727#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
728#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
729#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
730pub enum CharacterLength {
731    IntegerLength {
732        /// Default (if VARYING) or maximum (if not VARYING) length
733        length: u64,
734        /// Optional unit. If not informed, the ANSI handles it as CHARACTERS implicitly
735        unit: Option<CharLengthUnits>,
736    },
737    /// VARCHAR(MAX) or NVARCHAR(MAX), used in T-SQL (Microsoft SQL Server)
738    Max,
739}
740
741impl fmt::Display for CharacterLength {
742    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
743        match self {
744            CharacterLength::IntegerLength { length, unit } => {
745                write!(f, "{}", length)?;
746                if let Some(unit) = unit {
747                    write!(f, " {unit}")?;
748                }
749            }
750            CharacterLength::Max => {
751                write!(f, "MAX")?;
752            }
753        }
754        Ok(())
755    }
756}
757
758/// Possible units for characters, initially based on 2016 ANSI [standard][1].
759///
760/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#char-length-units
761#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
762#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
763#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
764pub enum CharLengthUnits {
765    /// CHARACTERS unit
766    Characters,
767    /// OCTETS unit
768    Octets,
769}
770
771impl fmt::Display for CharLengthUnits {
772    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
773        match self {
774            Self::Characters => {
775                write!(f, "CHARACTERS")
776            }
777            Self::Octets => {
778                write!(f, "OCTETS")
779            }
780        }
781    }
782}
783
784/// Represents the data type of the elements in an array (if any) as well as
785/// the syntax used to declare the array.
786///
787/// For example: Bigquery/Hive use `ARRAY<INT>` whereas snowflake uses ARRAY.
788#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
789#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
790#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
791pub enum ArrayElemTypeDef {
792    /// `ARRAY`
793    None,
794    /// `ARRAY<INT>`
795    AngleBracket(Box<DataType>),
796    /// `INT[]` or `INT[2]`
797    SquareBracket(Box<DataType>, Option<u64>),
798    /// `Array(Int64)`
799    Parenthesis(Box<DataType>),
800}