src/ast/data_type.rs (663 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #[cfg(not(feature = "std"))] use alloc::{boxed::Box, format, string::String, vec::Vec}; use core::fmt; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; use crate::ast::{display_comma_separated, Expr, ObjectName, StructField, UnionField}; use super::{value::escape_single_quote_string, ColumnDef}; #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum EnumMember { Name(String), /// ClickHouse allows to specify an integer value for each enum value. /// /// [ClickHouse](https://clickhouse.com/docs/en/sql-reference/data-types/enum) NamedValue(String, Expr), } /// SQL data types #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DataType { /// Table type in [PostgreSQL], e.g. CREATE FUNCTION RETURNS TABLE(...). /// /// [PostgreSQL]: https://www.postgresql.org/docs/15/sql-createfunction.html Table(Vec<ColumnDef>), /// Fixed-length character type, e.g. CHARACTER(10). Character(Option<CharacterLength>), /// Fixed-length char type, e.g. CHAR(10). Char(Option<CharacterLength>), /// Character varying type, e.g. CHARACTER VARYING(10). CharacterVarying(Option<CharacterLength>), /// Char varying type, e.g. CHAR VARYING(10). CharVarying(Option<CharacterLength>), /// Variable-length character type, e.g. VARCHAR(10). Varchar(Option<CharacterLength>), /// Variable-length character type, e.g. NVARCHAR(10). Nvarchar(Option<CharacterLength>), /// Uuid type. Uuid, /// Large character object with optional length, /// e.g. CHARACTER LARGE OBJECT, CHARACTER LARGE OBJECT(1000), [SQL Standard]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type CharacterLargeObject(Option<u64>), /// Large character object with optional length, /// e.g. CHAR LARGE OBJECT, CHAR LARGE OBJECT(1000), [SQL Standard]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type CharLargeObject(Option<u64>), /// Large character object with optional length, /// e.g. CLOB, CLOB(1000), [SQL Standard]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type /// [Oracle]: https://docs.oracle.com/javadb/10.10.1.2/ref/rrefclob.html Clob(Option<u64>), /// Fixed-length binary type with optional length, /// see [SQL Standard], [MS SQL Server]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type /// [MS SQL Server]: https://learn.microsoft.com/pt-br/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16 Binary(Option<u64>), /// Variable-length binary with optional length type, /// see [SQL Standard], [MS SQL Server]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type /// [MS SQL Server]: https://learn.microsoft.com/pt-br/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16 Varbinary(Option<BinaryLength>), /// Large binary object with optional length, /// see [SQL Standard], [Oracle]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-large-object-string-type /// [Oracle]: https://docs.oracle.com/javadb/10.8.3.0/ref/rrefblob.html Blob(Option<u64>), /// [MySQL] blob with up to 2**8 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html TinyBlob, /// [MySQL] blob with up to 2**24 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html MediumBlob, /// [MySQL] blob with up to 2**32 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html LongBlob, /// Variable-length binary data with optional length. /// /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#bytes_type Bytes(Option<u64>), /// Numeric type with optional precision and scale, e.g. NUMERIC(10,2), [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type Numeric(ExactNumberInfo), /// Decimal type with optional precision and scale, e.g. DECIMAL(10,2), [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type Decimal(ExactNumberInfo), /// [BigNumeric] type used in BigQuery. /// /// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals BigNumeric(ExactNumberInfo), /// This is alias for `BigNumeric` type used in BigQuery. /// /// [BigDecimal]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#decimal_types BigDecimal(ExactNumberInfo), /// Dec type with optional precision and scale, e.g. DEC(10,2), [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type Dec(ExactNumberInfo), /// Floating point with optional precision, e.g. FLOAT(8). Float(Option<u64>), /// Tiny integer with optional display width, e.g. TINYINT or TINYINT(3). TinyInt(Option<u64>), /// Unsigned tiny integer with optional display width, /// e.g. TINYINT UNSIGNED or TINYINT(3) UNSIGNED. TinyIntUnsigned(Option<u64>), /// Unsigned tiny integer, e.g. UTINYINT UTinyInt, /// Int2 is an alias for SmallInt in [PostgreSQL]. /// Note: Int2 means 2 bytes in PostgreSQL (not 2 bits). /// Int2 with optional display width, e.g. INT2 or INT2(5). /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Int2(Option<u64>), /// Unsigned Int2 with optional display width, e.g. INT2 UNSIGNED or INT2(5) UNSIGNED. Int2Unsigned(Option<u64>), /// Small integer with optional display width, e.g. SMALLINT or SMALLINT(5). SmallInt(Option<u64>), /// Unsigned small integer with optional display width, /// e.g. SMALLINT UNSIGNED or SMALLINT(5) UNSIGNED. SmallIntUnsigned(Option<u64>), /// Unsigned small integer, e.g. USMALLINT. USmallInt, /// MySQL medium integer ([1]) with optional display width, /// e.g. MEDIUMINT or MEDIUMINT(5). /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html MediumInt(Option<u64>), /// Unsigned medium integer ([1]) with optional display width, /// e.g. MEDIUMINT UNSIGNED or MEDIUMINT(5) UNSIGNED. /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html MediumIntUnsigned(Option<u64>), /// Int with optional display width, e.g. INT or INT(11). Int(Option<u64>), /// Int4 is an alias for Integer in [PostgreSQL]. /// Note: Int4 means 4 bytes in PostgreSQL (not 4 bits). /// Int4 with optional display width, e.g. Int4 or Int4(11). /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Int4(Option<u64>), /// Int8 is an alias for BigInt in [PostgreSQL] and Integer type in [ClickHouse]. /// Int8 with optional display width, e.g. INT8 or INT8(11). /// Note: Int8 means 8 bytes in [PostgreSQL], but 8 bits in [ClickHouse]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int8(Option<u64>), /// Integer type in [ClickHouse]. /// Note: Int16 means 16 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int16, /// Integer type in [ClickHouse]. /// Note: Int32 means 32 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int32, /// Integer type in [BigQuery], [ClickHouse]. /// /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#integer_types /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int64, /// Integer type in [ClickHouse]. /// Note: Int128 means 128 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int128, /// Integer type in [ClickHouse]. /// Note: Int256 means 256 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint Int256, /// Integer with optional display width, e.g. INTEGER or INTEGER(11). Integer(Option<u64>), /// Unsigned int with optional display width, e.g. INT UNSIGNED or INT(11) UNSIGNED. IntUnsigned(Option<u64>), /// Unsigned int4 with optional display width, e.g. INT4 UNSIGNED or INT4(11) UNSIGNED. Int4Unsigned(Option<u64>), /// Unsigned integer with optional display width, e.g. INTEGER UNSIGNED or INTEGER(11) UNSIGNED. IntegerUnsigned(Option<u64>), /// 128-bit integer type, e.g. HUGEINT. HugeInt, /// Unsigned 128-bit integer type, e.g. UHUGEINT. UHugeInt, /// Unsigned integer type in [ClickHouse]. /// Note: UInt8 means 8 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt8, /// Unsigned integer type in [ClickHouse]. /// Note: UInt16 means 16 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt16, /// Unsigned integer type in [ClickHouse]. /// Note: UInt32 means 32 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt32, /// Unsigned integer type in [ClickHouse]. /// Note: UInt64 means 64 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt64, /// Unsigned integer type in [ClickHouse]. /// Note: UInt128 means 128 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt128, /// Unsigned integer type in [ClickHouse]. /// Note: UInt256 means 256 bits in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/int-uint UInt256, /// Big integer with optional display width, e.g. BIGINT or BIGINT(20). BigInt(Option<u64>), /// Unsigned big integer with optional display width, e.g. BIGINT UNSIGNED or BIGINT(20) UNSIGNED. BigIntUnsigned(Option<u64>), /// Unsigned big integer, e.g. UBIGINT. UBigInt, /// Unsigned Int8 with optional display width, e.g. INT8 UNSIGNED or INT8(11) UNSIGNED. Int8Unsigned(Option<u64>), /// Signed integer as used in [MySQL CAST] target types, without optional `INTEGER` suffix, /// e.g. `SIGNED` /// /// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html Signed, /// Signed integer as used in [MySQL CAST] target types, with optional `INTEGER` suffix, /// e.g. `SIGNED INTEGER` /// /// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html SignedInteger, /// Signed integer as used in [MySQL CAST] target types, without optional `INTEGER` suffix, /// e.g. `SIGNED` /// /// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html Unsigned, /// Unsigned integer as used in [MySQL CAST] target types, with optional `INTEGER` suffix, /// e.g. `UNSIGNED INTEGER`. /// /// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html UnsignedInteger, /// Float4 is an alias for Real in [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Float4, /// Floating point in [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/float Float32, /// Floating point in [BigQuery]. /// /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#floating_point_types /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/float Float64, /// Floating point, e.g. REAL. Real, /// Float8 is an alias for Double in [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Float8, /// Double Double(ExactNumberInfo), /// Double Precision, see [SQL Standard], [PostgreSQL]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-numeric.html DoublePrecision, /// Bool is an alias for Boolean, see [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Bool, /// Boolean type. Boolean, /// Date type. Date, /// Date32 with the same range as Datetime64. /// /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/date32 Date32, /// Time with optional time precision and time zone information, see [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type Time(Option<u64>, TimezoneInfo), /// Datetime with optional time precision, see [MySQL][1]. /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/datetime.html Datetime(Option<u64>), /// Datetime with time precision and optional timezone, see [ClickHouse][1]. /// /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/datetime64 Datetime64(u64, Option<String>), /// Timestamp with optional time precision and time zone information, see [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type Timestamp(Option<u64>, TimezoneInfo), /// Databricks timestamp without time zone. See [1]. /// /// [1]: https://docs.databricks.com/aws/en/sql/language-manual/data-types/timestamp-ntz-type TimestampNtz, /// Interval type. Interval, /// JSON type. JSON, /// Binary JSON type. JSONB, /// Regclass used in [PostgreSQL] serial. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html Regclass, /// Text type. Text, /// [MySQL] text with up to 2**8 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html TinyText, /// [MySQL] text with up to 2**24 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html MediumText, /// [MySQL] text with up to 2**32 bytes. /// /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/blob.html LongText, /// String with optional length. String(Option<u64>), /// A fixed-length string e.g [ClickHouse][1]. /// /// [1]: https://clickhouse.com/docs/en/sql-reference/data-types/fixedstring FixedString(u64), /// Bytea type, see [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-bit.html Bytea, /// Bit string, see [PostgreSQL], [MySQL], or [MSSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-bit.html /// [MySQL]: https://dev.mysql.com/doc/refman/9.1/en/bit-type.html /// [MSSQL]: https://learn.microsoft.com/en-us/sql/t-sql/data-types/bit-transact-sql?view=sql-server-ver16 Bit(Option<u64>), /// `BIT VARYING(n)`: Variable-length bit string, see [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-bit.html BitVarying(Option<u64>), /// `VARBIT(n)`: Variable-length bit string. [PostgreSQL] alias for `BIT VARYING`. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html VarBit(Option<u64>), /// Custom types. Custom(ObjectName, Vec<String>), /// Arrays. Array(ArrayElemTypeDef), /// Map, see [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/map Map(Box<DataType>, Box<DataType>), /// Tuple, see [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/tuple Tuple(Vec<StructField>), /// Nested type, see [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/nested-data-structures/nested Nested(Vec<ColumnDef>), /// Enum type. Enum(Vec<EnumMember>, Option<u8>), /// Set type. Set(Vec<String>), /// Struct type, see [Hive], [BigQuery]. /// /// [Hive]: https://docs.cloudera.com/cdw-runtime/cloud/impala-sql-reference/topics/impala-struct.html /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type Struct(Vec<StructField>, StructBracketKind), /// Union type, see [DuckDB]. /// /// [DuckDB]: https://duckdb.org/docs/sql/data_types/union.html Union(Vec<UnionField>), /// Nullable - special marker NULL represents in ClickHouse as a data type. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/nullable Nullable(Box<DataType>), /// LowCardinality - changes the internal representation of other data types to be dictionary-encoded. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/lowcardinality LowCardinality(Box<DataType>), /// No type specified - only used with /// [`SQLiteDialect`](crate::dialect::SQLiteDialect), from statements such /// as `CREATE TABLE t1 (a)`. Unspecified, /// Trigger data type, returned by functions associated with triggers, see [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/current/plpgsql-trigger.html Trigger, /// Any data type, used in BigQuery UDF definitions for templated parameters, see [BigQuery]. /// /// [BigQuery]: https://cloud.google.com/bigquery/docs/user-defined-functions#templated-sql-udf-parameters AnyType, /// Geometric type, see [PostgreSQL]. /// /// [PostgreSQL]: https://www.postgresql.org/docs/9.5/functions-geometry.html GeometricType(GeometricTypeKind), } impl fmt::Display for DataType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { DataType::Character(size) => format_character_string_type(f, "CHARACTER", size), DataType::Char(size) => format_character_string_type(f, "CHAR", size), DataType::CharacterVarying(size) => { format_character_string_type(f, "CHARACTER VARYING", size) } DataType::CharVarying(size) => format_character_string_type(f, "CHAR VARYING", size), DataType::Varchar(size) => format_character_string_type(f, "VARCHAR", size), DataType::Nvarchar(size) => format_character_string_type(f, "NVARCHAR", size), DataType::Uuid => write!(f, "UUID"), DataType::CharacterLargeObject(size) => { format_type_with_optional_length(f, "CHARACTER LARGE OBJECT", size, false) } DataType::CharLargeObject(size) => { format_type_with_optional_length(f, "CHAR LARGE OBJECT", size, false) } DataType::Clob(size) => format_type_with_optional_length(f, "CLOB", size, false), DataType::Binary(size) => format_type_with_optional_length(f, "BINARY", size, false), DataType::Varbinary(size) => format_varbinary_type(f, "VARBINARY", size), DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false), DataType::TinyBlob => write!(f, "TINYBLOB"), DataType::MediumBlob => write!(f, "MEDIUMBLOB"), DataType::LongBlob => write!(f, "LONGBLOB"), DataType::Bytes(size) => format_type_with_optional_length(f, "BYTES", size, false), DataType::Numeric(info) => { write!(f, "NUMERIC{info}") } DataType::Decimal(info) => { write!(f, "DECIMAL{info}") } DataType::Dec(info) => { write!(f, "DEC{info}") } DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"), DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"), DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false), DataType::TinyInt(zerofill) => { format_type_with_optional_length(f, "TINYINT", zerofill, false) } DataType::TinyIntUnsigned(zerofill) => { format_type_with_optional_length(f, "TINYINT", zerofill, true) } DataType::Int2(zerofill) => { format_type_with_optional_length(f, "INT2", zerofill, false) } DataType::Int2Unsigned(zerofill) => { format_type_with_optional_length(f, "INT2", zerofill, true) } DataType::SmallInt(zerofill) => { format_type_with_optional_length(f, "SMALLINT", zerofill, false) } DataType::SmallIntUnsigned(zerofill) => { format_type_with_optional_length(f, "SMALLINT", zerofill, true) } DataType::MediumInt(zerofill) => { format_type_with_optional_length(f, "MEDIUMINT", zerofill, false) } DataType::MediumIntUnsigned(zerofill) => { format_type_with_optional_length(f, "MEDIUMINT", zerofill, true) } DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false), DataType::IntUnsigned(zerofill) => { format_type_with_optional_length(f, "INT", zerofill, true) } DataType::Int4(zerofill) => { format_type_with_optional_length(f, "INT4", zerofill, false) } DataType::Int8(zerofill) => { format_type_with_optional_length(f, "INT8", zerofill, false) } DataType::Int16 => { write!(f, "Int16") } DataType::Int32 => { write!(f, "Int32") } DataType::Int64 => { write!(f, "INT64") } DataType::Int128 => { write!(f, "Int128") } DataType::Int256 => { write!(f, "Int256") } DataType::HugeInt => { write!(f, "HUGEINT") } DataType::Int4Unsigned(zerofill) => { format_type_with_optional_length(f, "INT4", zerofill, true) } DataType::Integer(zerofill) => { format_type_with_optional_length(f, "INTEGER", zerofill, false) } DataType::IntegerUnsigned(zerofill) => { format_type_with_optional_length(f, "INTEGER", zerofill, true) } DataType::BigInt(zerofill) => { format_type_with_optional_length(f, "BIGINT", zerofill, false) } DataType::BigIntUnsigned(zerofill) => { format_type_with_optional_length(f, "BIGINT", zerofill, true) } DataType::Int8Unsigned(zerofill) => { format_type_with_optional_length(f, "INT8", zerofill, true) } DataType::UTinyInt => { write!(f, "UTINYINT") } DataType::USmallInt => { write!(f, "USMALLINT") } DataType::UBigInt => { write!(f, "UBIGINT") } DataType::UHugeInt => { write!(f, "UHUGEINT") } DataType::UInt8 => { write!(f, "UInt8") } DataType::UInt16 => { write!(f, "UInt16") } DataType::UInt32 => { write!(f, "UInt32") } DataType::UInt64 => { write!(f, "UInt64") } DataType::UInt128 => { write!(f, "UInt128") } DataType::UInt256 => { write!(f, "UInt256") } DataType::Signed => { write!(f, "SIGNED") } DataType::SignedInteger => { write!(f, "SIGNED INTEGER") } DataType::Unsigned => { write!(f, "UNSIGNED") } DataType::UnsignedInteger => { write!(f, "UNSIGNED INTEGER") } DataType::Real => write!(f, "REAL"), DataType::Float4 => write!(f, "FLOAT4"), DataType::Float32 => write!(f, "Float32"), DataType::Float64 => write!(f, "FLOAT64"), DataType::Double(info) => write!(f, "DOUBLE{info}"), DataType::Float8 => write!(f, "FLOAT8"), DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"), DataType::Bool => write!(f, "BOOL"), DataType::Boolean => write!(f, "BOOLEAN"), DataType::Date => write!(f, "DATE"), DataType::Date32 => write!(f, "Date32"), DataType::Time(precision, timezone_info) => { format_datetime_precision_and_tz(f, "TIME", precision, timezone_info) } DataType::Datetime(precision) => { format_type_with_optional_length(f, "DATETIME", precision, false) } DataType::Timestamp(precision, timezone_info) => { format_datetime_precision_and_tz(f, "TIMESTAMP", precision, timezone_info) } DataType::TimestampNtz => write!(f, "TIMESTAMP_NTZ"), DataType::Datetime64(precision, timezone) => { format_clickhouse_datetime_precision_and_timezone( f, "DateTime64", precision, timezone, ) } DataType::Interval => write!(f, "INTERVAL"), DataType::JSON => write!(f, "JSON"), DataType::JSONB => write!(f, "JSONB"), DataType::Regclass => write!(f, "REGCLASS"), DataType::Text => write!(f, "TEXT"), DataType::TinyText => write!(f, "TINYTEXT"), DataType::MediumText => write!(f, "MEDIUMTEXT"), DataType::LongText => write!(f, "LONGTEXT"), DataType::String(size) => format_type_with_optional_length(f, "STRING", size, false), DataType::Bytea => write!(f, "BYTEA"), DataType::Bit(size) => format_type_with_optional_length(f, "BIT", size, false), DataType::BitVarying(size) => { format_type_with_optional_length(f, "BIT VARYING", size, false) } DataType::VarBit(size) => format_type_with_optional_length(f, "VARBIT", size, false), DataType::Array(ty) => match ty { ArrayElemTypeDef::None => write!(f, "ARRAY"), ArrayElemTypeDef::SquareBracket(t, None) => write!(f, "{t}[]"), ArrayElemTypeDef::SquareBracket(t, Some(size)) => write!(f, "{t}[{size}]"), ArrayElemTypeDef::AngleBracket(t) => write!(f, "ARRAY<{t}>"), ArrayElemTypeDef::Parenthesis(t) => write!(f, "Array({t})"), }, DataType::Custom(ty, modifiers) => { if modifiers.is_empty() { write!(f, "{ty}") } else { write!(f, "{}({})", ty, modifiers.join(", ")) } } DataType::Enum(vals, bits) => { match bits { Some(bits) => write!(f, "ENUM{}", bits), None => write!(f, "ENUM"), }?; write!(f, "(")?; for (i, v) in vals.iter().enumerate() { if i != 0 { write!(f, ", ")?; } match v { EnumMember::Name(name) => { write!(f, "'{}'", escape_single_quote_string(name))? } EnumMember::NamedValue(name, value) => { write!(f, "'{}' = {}", escape_single_quote_string(name), value)? } } } write!(f, ")") } DataType::Set(vals) => { write!(f, "SET(")?; for (i, v) in vals.iter().enumerate() { if i != 0 { write!(f, ", ")?; } write!(f, "'{}'", escape_single_quote_string(v))?; } write!(f, ")") } DataType::Struct(fields, bracket) => { if !fields.is_empty() { match bracket { StructBracketKind::Parentheses => { write!(f, "STRUCT({})", display_comma_separated(fields)) } StructBracketKind::AngleBrackets => { write!(f, "STRUCT<{}>", display_comma_separated(fields)) } } } else { write!(f, "STRUCT") } } DataType::Union(fields) => { write!(f, "UNION({})", display_comma_separated(fields)) } // ClickHouse DataType::Nullable(data_type) => { write!(f, "Nullable({})", data_type) } DataType::FixedString(character_length) => { write!(f, "FixedString({})", character_length) } DataType::LowCardinality(data_type) => { write!(f, "LowCardinality({})", data_type) } DataType::Map(key_data_type, value_data_type) => { write!(f, "Map({}, {})", key_data_type, value_data_type) } DataType::Tuple(fields) => { write!(f, "Tuple({})", display_comma_separated(fields)) } DataType::Nested(fields) => { write!(f, "Nested({})", display_comma_separated(fields)) } DataType::Unspecified => Ok(()), DataType::Trigger => write!(f, "TRIGGER"), DataType::AnyType => write!(f, "ANY TYPE"), DataType::Table(fields) => write!(f, "TABLE({})", display_comma_separated(fields)), DataType::GeometricType(kind) => write!(f, "{}", kind), } } } fn format_type_with_optional_length( f: &mut fmt::Formatter, sql_type: &'static str, len: &Option<u64>, unsigned: bool, ) -> fmt::Result { write!(f, "{sql_type}")?; if let Some(len) = len { write!(f, "({len})")?; } if unsigned { write!(f, " UNSIGNED")?; } Ok(()) } fn format_character_string_type( f: &mut fmt::Formatter, sql_type: &str, size: &Option<CharacterLength>, ) -> fmt::Result { write!(f, "{sql_type}")?; if let Some(size) = size { write!(f, "({size})")?; } Ok(()) } fn format_varbinary_type( f: &mut fmt::Formatter, sql_type: &str, size: &Option<BinaryLength>, ) -> fmt::Result { write!(f, "{sql_type}")?; if let Some(size) = size { write!(f, "({size})")?; } Ok(()) } fn format_datetime_precision_and_tz( f: &mut fmt::Formatter, sql_type: &'static str, len: &Option<u64>, time_zone: &TimezoneInfo, ) -> fmt::Result { write!(f, "{sql_type}")?; let len_fmt = len.as_ref().map(|l| format!("({l})")).unwrap_or_default(); match time_zone { TimezoneInfo::Tz => { write!(f, "{time_zone}{len_fmt}")?; } _ => { write!(f, "{len_fmt}{time_zone}")?; } } Ok(()) } fn format_clickhouse_datetime_precision_and_timezone( f: &mut fmt::Formatter, sql_type: &'static str, len: &u64, time_zone: &Option<String>, ) -> fmt::Result { write!(f, "{sql_type}({len}")?; if let Some(time_zone) = time_zone { write!(f, ", '{time_zone}'")?; } write!(f, ")")?; Ok(()) } /// Type of brackets used for `STRUCT` literals. #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum StructBracketKind { /// Example: `STRUCT(a INT, b STRING)` Parentheses, /// Example: `STRUCT<a INT, b STRING>` AngleBrackets, } /// Timestamp and Time data types information about TimeZone formatting. /// /// This is more related to a display information than real differences between each variant. To /// guarantee compatibility with the input query we must maintain its exact information. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TimezoneInfo { /// No information about time zone, e.g. TIMESTAMP None, /// Temporal type 'WITH TIME ZONE', e.g. TIMESTAMP WITH TIME ZONE, [SQL Standard], [Oracle] /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type /// [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 WithTimeZone, /// Temporal type 'WITHOUT TIME ZONE', e.g. TIME WITHOUT TIME ZONE, [SQL Standard], [Postgresql] /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type /// [Postgresql]: https://www.postgresql.org/docs/current/datatype-datetime.html WithoutTimeZone, /// Postgresql specific `WITH TIME ZONE` formatting, for both TIME and TIMESTAMP, e.g. TIMETZ, [Postgresql] /// /// [Postgresql]: https://www.postgresql.org/docs/current/datatype-datetime.html Tz, } impl fmt::Display for TimezoneInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TimezoneInfo::None => { write!(f, "") } TimezoneInfo::WithTimeZone => { write!(f, " WITH TIME ZONE") } TimezoneInfo::WithoutTimeZone => { write!(f, " WITHOUT TIME ZONE") } TimezoneInfo::Tz => { // TZ is the only one that is displayed BEFORE the precision, so the datatype display // must be aware of that. Check <https://www.postgresql.org/docs/14/datatype-datetime.html> // for more information write!(f, "TZ") } } } } /// Additional information for `NUMERIC`, `DECIMAL`, and `DEC` data types /// following the 2016 [SQL Standard]. /// /// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ExactNumberInfo { /// No additional information, e.g. `DECIMAL` None, /// Only precision information, e.g. `DECIMAL(10)` Precision(u64), /// Precision and scale information, e.g. `DECIMAL(10,2)` PrecisionAndScale(u64, u64), } impl fmt::Display for ExactNumberInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ExactNumberInfo::None => { write!(f, "") } ExactNumberInfo::Precision(p) => { write!(f, "({p})") } ExactNumberInfo::PrecisionAndScale(p, s) => { write!(f, "({p},{s})") } } } } /// Information about [character length][1], including length and possibly unit. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-length #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CharacterLength { IntegerLength { /// Default (if VARYING) or maximum (if not VARYING) length length: u64, /// Optional unit. If not informed, the ANSI handles it as CHARACTERS implicitly unit: Option<CharLengthUnits>, }, /// VARCHAR(MAX) or NVARCHAR(MAX), used in T-SQL (Microsoft SQL Server) Max, } impl fmt::Display for CharacterLength { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { CharacterLength::IntegerLength { length, unit } => { write!(f, "{}", length)?; if let Some(unit) = unit { write!(f, " {unit}")?; } } CharacterLength::Max => { write!(f, "MAX")?; } } Ok(()) } } /// Possible units for characters, initially based on 2016 ANSI [SQL Standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#char-length-units #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CharLengthUnits { /// CHARACTERS unit Characters, /// OCTETS unit Octets, } impl fmt::Display for CharLengthUnits { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Characters => { write!(f, "CHARACTERS") } Self::Octets => { write!(f, "OCTETS") } } } } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum BinaryLength { IntegerLength { /// Default (if VARYING) length: u64, }, /// VARBINARY(MAX) used in T-SQL (Microsoft SQL Server) Max, } impl fmt::Display for BinaryLength { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { BinaryLength::IntegerLength { length } => { write!(f, "{}", length)?; } BinaryLength::Max => { write!(f, "MAX")?; } } Ok(()) } } /// Represents the data type of the elements in an array (if any) as well as /// the syntax used to declare the array. /// /// For example: Bigquery/Hive use `ARRAY<INT>` whereas snowflake uses ARRAY. #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ArrayElemTypeDef { /// `ARRAY` None, /// `ARRAY<INT>` AngleBracket(Box<DataType>), /// `INT[]` or `INT[2]` SquareBracket(Box<DataType>, Option<u64>), /// `Array(Int64)` Parenthesis(Box<DataType>), } /// Represents different types of geometric shapes which are commonly used in /// PostgreSQL/Redshift for spatial operations and geometry-related computations. /// /// [PostgreSQL]: https://www.postgresql.org/docs/9.5/functions-geometry.html #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum GeometricTypeKind { Point, Line, LineSegment, GeometricBox, GeometricPath, Polygon, Circle, } impl fmt::Display for GeometricTypeKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { GeometricTypeKind::Point => write!(f, "point"), GeometricTypeKind::Line => write!(f, "line"), GeometricTypeKind::LineSegment => write!(f, "lseg"), GeometricTypeKind::GeometricBox => write!(f, "box"), GeometricTypeKind::GeometricPath => write!(f, "path"), GeometricTypeKind::Polygon => write!(f, "polygon"), GeometricTypeKind::Circle => write!(f, "circle"), } } }