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}