#[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, ObjectName, StructField};
use super::value::escape_single_quote_string;
#[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 {
Character(Option<CharacterLength>),
Char(Option<CharacterLength>),
CharacterVarying(Option<CharacterLength>),
CharVarying(Option<CharacterLength>),
Varchar(Option<CharacterLength>),
Nvarchar(Option<u64>),
Uuid,
CharacterLargeObject(Option<u64>),
CharLargeObject(Option<u64>),
Clob(Option<u64>),
Binary(Option<u64>),
Varbinary(Option<u64>),
Blob(Option<u64>),
Bytes(Option<u64>),
Numeric(ExactNumberInfo),
Decimal(ExactNumberInfo),
BigNumeric(ExactNumberInfo),
BigDecimal(ExactNumberInfo),
Dec(ExactNumberInfo),
Float(Option<u64>),
TinyInt(Option<u64>),
UnsignedTinyInt(Option<u64>),
Int2(Option<u64>),
UnsignedInt2(Option<u64>),
SmallInt(Option<u64>),
UnsignedSmallInt(Option<u64>),
MediumInt(Option<u64>),
UnsignedMediumInt(Option<u64>),
Int(Option<u64>),
Int4(Option<u64>),
Int64,
Integer(Option<u64>),
UnsignedInt(Option<u64>),
UnsignedInt4(Option<u64>),
UnsignedInteger(Option<u64>),
BigInt(Option<u64>),
UnsignedBigInt(Option<u64>),
Int8(Option<u64>),
UnsignedInt8(Option<u64>),
Float4,
Float64,
Real,
Float8,
Double,
DoublePrecision,
Bool,
Boolean,
Date,
Time(Option<u64>, TimezoneInfo),
Datetime(Option<u64>),
Timestamp(Option<u64>, TimezoneInfo),
Interval,
JSON,
JSONB,
Regclass,
Text,
String(Option<u64>),
Bytea,
Custom(ObjectName, Vec<String>),
Array(ArrayElemTypeDef),
Enum(Vec<String>),
Set(Vec<String>),
Struct(Vec<StructField>),
Unspecified,
}
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_type_with_optional_length(f, "NVARCHAR", size, false)
}
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_type_with_optional_length(f, "VARBINARY", size, false)
}
DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false),
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::UnsignedTinyInt(zerofill) => {
format_type_with_optional_length(f, "TINYINT", zerofill, true)
}
DataType::Int2(zerofill) => {
format_type_with_optional_length(f, "INT2", zerofill, false)
}
DataType::UnsignedInt2(zerofill) => {
format_type_with_optional_length(f, "INT2", zerofill, true)
}
DataType::SmallInt(zerofill) => {
format_type_with_optional_length(f, "SMALLINT", zerofill, false)
}
DataType::UnsignedSmallInt(zerofill) => {
format_type_with_optional_length(f, "SMALLINT", zerofill, true)
}
DataType::MediumInt(zerofill) => {
format_type_with_optional_length(f, "MEDIUMINT", zerofill, false)
}
DataType::UnsignedMediumInt(zerofill) => {
format_type_with_optional_length(f, "MEDIUMINT", zerofill, true)
}
DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false),
DataType::UnsignedInt(zerofill) => {
format_type_with_optional_length(f, "INT", zerofill, true)
}
DataType::Int4(zerofill) => {
format_type_with_optional_length(f, "INT4", zerofill, false)
}
DataType::Int64 => {
write!(f, "INT64")
}
DataType::UnsignedInt4(zerofill) => {
format_type_with_optional_length(f, "INT4", zerofill, true)
}
DataType::Integer(zerofill) => {
format_type_with_optional_length(f, "INTEGER", zerofill, false)
}
DataType::UnsignedInteger(zerofill) => {
format_type_with_optional_length(f, "INTEGER", zerofill, true)
}
DataType::BigInt(zerofill) => {
format_type_with_optional_length(f, "BIGINT", zerofill, false)
}
DataType::UnsignedBigInt(zerofill) => {
format_type_with_optional_length(f, "BIGINT", zerofill, true)
}
DataType::Int8(zerofill) => {
format_type_with_optional_length(f, "INT8", zerofill, false)
}
DataType::UnsignedInt8(zerofill) => {
format_type_with_optional_length(f, "INT8", zerofill, true)
}
DataType::Real => write!(f, "REAL"),
DataType::Float4 => write!(f, "FLOAT4"),
DataType::Float64 => write!(f, "FLOAT64"),
DataType::Double => write!(f, "DOUBLE"),
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::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::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::String(size) => format_type_with_optional_length(f, "STRING", size, false),
DataType::Bytea => write!(f, "BYTEA"),
DataType::Array(ty) => match ty {
ArrayElemTypeDef::None => write!(f, "ARRAY"),
ArrayElemTypeDef::SquareBracket(t) => write!(f, "{t}[]"),
ArrayElemTypeDef::AngleBracket(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) => {
write!(f, "ENUM(")?;
for (i, v) in vals.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "'{}'", escape_single_quote_string(v))?;
}
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) => {
if !fields.is_empty() {
write!(f, "STRUCT<{}>", display_comma_separated(fields))
} else {
write!(f, "STRUCT")
}
}
DataType::Unspecified => Ok(()),
}
}
}
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_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(())
}
#[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 {
None,
WithTimeZone,
WithoutTimeZone,
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 => {
write!(f, "TZ")
}
}
}
}
#[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 {
None,
Precision(u64),
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})")
}
}
}
}
#[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 {
length: u64,
unit: Option<CharLengthUnits>,
},
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(())
}
}
#[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,
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, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ArrayElemTypeDef {
None,
AngleBracket(Box<DataType>),
SquareBracket(Box<DataType>),
}