use alloc::{boxed::Box, vec::Vec};
use crate::{
expression::{parse_expression, Expression},
keywords::Keyword,
lexer::Token,
parser::{ParseError, Parser},
span::OptSpanned,
Identifier, SString, Span, Spanned,
};
#[derive(Debug, Clone)]
pub enum DataTypeProperty<'a> {
Signed(Span),
Unsigned(Span),
Zerofill(Span),
Null(Span),
NotNull(Span),
Default(Box<Expression<'a>>),
Comment(SString<'a>),
Charset(Identifier<'a>),
Collate(Identifier<'a>),
Virtual(Span),
Persistent(Span),
Stored(Span),
Unique(Span),
UniqueKey(Span),
GeneratedAlways(Span),
AutoIncrement(Span),
PrimaryKey(Span),
As((Span, Box<Expression<'a>>)),
Check((Span, Box<Expression<'a>>)),
}
impl<'a> Spanned for DataTypeProperty<'a> {
fn span(&self) -> Span {
match &self {
DataTypeProperty::Signed(v) => v.span(),
DataTypeProperty::Unsigned(v) => v.span(),
DataTypeProperty::Zerofill(v) => v.span(),
DataTypeProperty::Null(v) => v.span(),
DataTypeProperty::NotNull(v) => v.span(),
DataTypeProperty::Default(v) => v.span(),
DataTypeProperty::Comment(v) => v.span(),
DataTypeProperty::Charset(v) => v.span(),
DataTypeProperty::Collate(v) => v.span(),
DataTypeProperty::Virtual(v) => v.span(),
DataTypeProperty::Persistent(v) => v.span(),
DataTypeProperty::Stored(v) => v.span(),
DataTypeProperty::Unique(v) => v.span(),
DataTypeProperty::UniqueKey(v) => v.span(),
DataTypeProperty::GeneratedAlways(v) => v.span(),
DataTypeProperty::AutoIncrement(v) => v.span(),
DataTypeProperty::As((s, v)) => s.join_span(v),
DataTypeProperty::Check((s, v)) => s.join_span(v),
DataTypeProperty::PrimaryKey(v) => v.span(),
}
}
}
#[derive(Debug, Clone)]
pub struct Timestamp {
pub width: Option<(usize, Span)>,
pub with_time_zone: Option<Span>,
}
impl OptSpanned for Timestamp {
fn opt_span(&self) -> Option<Span> {
self.width.opt_span().opt_join_span(&self.with_time_zone)
}
}
#[derive(Debug, Clone)]
pub enum Type<'a> {
Boolean,
TinyInt(Option<(usize, Span)>),
SmallInt(Option<(usize, Span)>),
Integer(Option<(usize, Span)>),
Int(Option<(usize, Span)>),
BigInt(Option<(usize, Span)>),
Char(Option<(usize, Span)>),
VarChar(Option<(usize, Span)>),
TinyText(Option<(usize, Span)>),
MediumText(Option<(usize, Span)>),
Text(Option<(usize, Span)>),
LongText(Option<(usize, Span)>),
Enum(Vec<SString<'a>>),
Set(Vec<SString<'a>>),
Float8,
Float(Option<(usize, usize, Span)>),
Double(Option<(usize, usize, Span)>),
Numeric(usize, usize, Span),
DateTime(Option<(usize, Span)>),
Timestamp(Timestamp),
Timestamptz,
Time(Option<(usize, Span)>),
TinyBlob(Option<(usize, Span)>),
MediumBlob(Option<(usize, Span)>),
Date,
Blob(Option<(usize, Span)>),
LongBlob(Option<(usize, Span)>),
VarBinary((usize, Span)),
Binary(Option<(usize, Span)>),
Named(Span),
Json,
Bit(usize, Span),
Bytea,
Inet4,
Inet6,
}
impl<'a> OptSpanned for Type<'a> {
fn opt_span(&self) -> Option<Span> {
match &self {
Type::Boolean => None,
Type::TinyInt(v) => v.opt_span(),
Type::SmallInt(v) => v.opt_span(),
Type::Integer(v) => v.opt_span(),
Type::Int(v) => v.opt_span(),
Type::BigInt(v) => v.opt_span(),
Type::Char(v) => v.opt_span(),
Type::VarChar(v) => v.opt_span(),
Type::TinyText(v) => v.opt_span(),
Type::MediumText(v) => v.opt_span(),
Type::Text(v) => v.opt_span(),
Type::LongText(v) => v.opt_span(),
Type::Enum(v) => v.opt_span(),
Type::Set(v) => v.opt_span(),
Type::Float8 => None,
Type::Float(v) => v.opt_span(),
Type::Double(v) => v.opt_span(),
Type::Numeric(_, _, v) => v.opt_span(),
Type::DateTime(v) => v.opt_span(),
Type::Timestamp(v) => v.opt_span(),
Type::Time(v) => v.opt_span(),
Type::TinyBlob(v) => v.opt_span(),
Type::MediumBlob(v) => v.opt_span(),
Type::Date => None,
Type::Blob(v) => v.opt_span(),
Type::LongBlob(v) => v.opt_span(),
Type::VarBinary(v) => v.opt_span(),
Type::Binary(v) => v.opt_span(),
Type::Timestamptz => None,
Type::Named(v) => v.opt_span(),
Type::Json => None,
Type::Bit(_, b) => b.opt_span(),
Type::Bytea => None,
Type::Inet4 => None,
Type::Inet6 => None,
}
}
}
#[derive(Debug, Clone)]
pub struct DataType<'a> {
pub identifier: Span,
pub type_: Type<'a>,
pub properties: Vec<DataTypeProperty<'a>>,
}
impl<'a> Spanned for DataType<'a> {
fn span(&self) -> Span {
self.identifier
.join_span(&self.type_)
.join_span(&self.properties)
}
}
fn parse_width(parser: &mut Parser<'_, '_>) -> Result<Option<(usize, Span)>, ParseError> {
if !matches!(parser.token, Token::LParen) {
return Ok(None);
}
parser.consume_token(Token::LParen)?;
let value = parser.recovered(")", &|t| t == &Token::RParen, |parser| parser.consume_int())?;
parser.consume_token(Token::RParen)?;
Ok(Some(value))
}
fn parse_width_req(parser: &mut Parser<'_, '_>) -> Result<(usize, Span), ParseError> {
if !matches!(parser.token, Token::LParen) {
return parser.expected_failure("'('");
}
Ok(parse_width(parser)?.expect("width"))
}
fn parse_enum_set_values<'a>(parser: &mut Parser<'a, '_>) -> Result<Vec<SString<'a>>, ParseError> {
parser.consume_token(Token::LParen)?;
let mut ans = Vec::new();
parser.recovered(")", &|t| t == &Token::RParen, |parser| {
loop {
ans.push(parser.consume_string()?);
match &parser.token {
Token::Comma => {
parser.consume_token(Token::Comma)?;
}
Token::RParen => break,
_ => parser.expected_failure("',' or ')'")?,
}
}
Ok(())
})?;
parser.consume_token(Token::RParen)?;
Ok(ans)
}
pub(crate) fn parse_data_type<'a>(
parser: &mut Parser<'a, '_>,
no_as: bool,
) -> Result<DataType<'a>, ParseError> {
let (identifier, type_) = match &parser.token {
Token::Ident(_, Keyword::BOOLEAN) => {
(parser.consume_keyword(Keyword::BOOLEAN)?, Type::Boolean)
}
Token::Ident(_, Keyword::TINYINT) => (
parser.consume_keyword(Keyword::TINYINT)?,
Type::TinyInt(parse_width(parser)?),
),
Token::Ident(_, Keyword::SMALLINT) => (
parser.consume_keyword(Keyword::SMALLINT)?,
Type::SmallInt(parse_width(parser)?),
),
Token::Ident(_, Keyword::INTEGER) => (
parser.consume_keyword(Keyword::INTEGER)?,
Type::Integer(parse_width(parser)?),
),
Token::Ident(_, Keyword::INT) => (
parser.consume_keyword(Keyword::INT)?,
Type::Int(parse_width(parser)?),
),
Token::Ident(_, Keyword::BIGINT) => (
parser.consume_keyword(Keyword::BIGINT)?,
Type::BigInt(parse_width(parser)?),
),
Token::Ident(_, Keyword::INET4) => (parser.consume_keyword(Keyword::INET4)?, Type::Inet4),
Token::Ident(_, Keyword::INET6) => (parser.consume_keyword(Keyword::INET6)?, Type::Inet6),
Token::Ident(_, Keyword::TINYTEXT) => (
parser.consume_keyword(Keyword::TINYTEXT)?,
Type::TinyText(parse_width(parser)?),
),
Token::Ident(_, Keyword::CHAR) => (
parser.consume_keyword(Keyword::CHAR)?,
Type::Char(parse_width(parser)?),
),
Token::Ident(_, Keyword::TEXT) => (
parser.consume_keyword(Keyword::TEXT)?,
Type::Text(parse_width(parser)?),
),
Token::Ident(_, Keyword::MEDIUMTEXT) => (
parser.consume_keyword(Keyword::MEDIUMTEXT)?,
Type::MediumText(parse_width(parser)?),
),
Token::Ident(_, Keyword::LONGTEXT) => (
parser.consume_keyword(Keyword::LONGTEXT)?,
Type::LongText(parse_width(parser)?),
),
Token::Ident(_, Keyword::VARCHAR) => (
parser.consume_keyword(Keyword::VARCHAR)?,
Type::VarChar(parse_width(parser)?),
),
Token::Ident(_, Keyword::TINYBLOB) => (
parser.consume_keyword(Keyword::TINYBLOB)?,
Type::TinyBlob(parse_width(parser)?),
),
Token::Ident(_, Keyword::BLOB) => (
parser.consume_keyword(Keyword::BLOB)?,
Type::Blob(parse_width(parser)?),
),
Token::Ident(_, Keyword::MEDIUMBLOB) => (
parser.consume_keyword(Keyword::MEDIUMBLOB)?,
Type::MediumBlob(parse_width(parser)?),
),
Token::Ident(_, Keyword::LONGBLOB) => (
parser.consume_keyword(Keyword::LONGBLOB)?,
Type::LongBlob(parse_width(parser)?),
),
Token::Ident(_, Keyword::VARBINARY) => (
parser.consume_keyword(Keyword::VARBINARY)?,
Type::VarBinary(parse_width_req(parser)?),
),
Token::Ident(_, Keyword::BINARY) => (
parser.consume_keyword(Keyword::BINARY)?,
Type::Binary(parse_width(parser)?),
),
Token::Ident(_, Keyword::FLOAT8) => {
(parser.consume_keyword(Keyword::FLOAT8)?, Type::Float8)
}
Token::Ident(_, Keyword::REAL) => {
(parser.consume_keyword(Keyword::FLOAT)?, Type::Float(None)) }
Token::Ident(_, Keyword::FLOAT) => {
(parser.consume_keyword(Keyword::FLOAT)?, Type::Float(None)) }
Token::Ident(_, Keyword::DOUBLE) => {
let i = if parser.options.dialect.is_postgresql() {
parser.consume_keywords(&[Keyword::DOUBLE, Keyword::PRECISION])?
} else {
parser.consume_keyword(Keyword::DOUBLE)?
};
(i, Type::Double(None)) }
Token::Ident(_, Keyword::NUMERIC) => {
let numeric = parser.consume_keyword(Keyword::NUMERIC)?;
let left = parser.consume_token(Token::LParen)?;
let (v1, s1) = parser.consume_int()?;
let comma = parser.consume_token(Token::Comma)?;
let (v2, s2) = parser.consume_int()?;
let right = parser.consume_token(Token::RParen)?;
(
numeric,
Type::Numeric(
v1,
v2,
left.join_span(&s1)
.join_span(&comma)
.join_span(&s2)
.join_span(&right),
),
)
}
Token::Ident(_, Keyword::DATETIME) => (
parser.consume_keyword(Keyword::DATETIME)?,
Type::DateTime(parse_width(parser)?),
),
Token::Ident(_, Keyword::TIME) => (
parser.consume_keyword(Keyword::TIME)?,
Type::Time(parse_width(parser)?),
),
Token::Ident(_, Keyword::TIMESTAMPTZ) => (
parser.consume_keyword(Keyword::TIMESTAMPTZ)?,
Type::Timestamptz,
),
Token::Ident(_, Keyword::TIMESTAMP) => {
let timestamp_span = parser.consume_keyword(Keyword::TIMESTAMP)?;
let width = parse_width(parser)?;
let with_time_zone = match parser.skip_keyword(Keyword::WITH) {
Some(with_span) => Some(
with_span.join_span(&parser.consume_keywords(&[Keyword::TIME, Keyword::ZONE])?),
),
None => None,
};
let timestamp = Timestamp {
width,
with_time_zone,
};
(timestamp_span, Type::Timestamp(timestamp))
}
Token::Ident(_, Keyword::DATE) => (parser.consume_keyword(Keyword::DATE)?, Type::Date),
Token::Ident(_, Keyword::ENUM) => (
parser.consume_keyword(Keyword::ENUM)?,
Type::Enum(parse_enum_set_values(parser)?),
),
Token::Ident(_, Keyword::SET) => (
parser.consume_keyword(Keyword::SET)?,
Type::Set(parse_enum_set_values(parser)?),
),
Token::Ident(_, Keyword::JSON) => (parser.consume_keyword(Keyword::JSON)?, Type::Json),
Token::Ident(_, Keyword::BYTEA) => (parser.consume_keyword(Keyword::BYTEA)?, Type::Bytea),
Token::Ident(_, Keyword::BIT) => {
let t = parser.consume_keyword(Keyword::BIT)?;
let (w, ws) = parse_width_req(parser)?;
(t, Type::Bit(w, ws))
}
Token::Ident(_, _) if parser.options.dialect.is_postgresql() => {
let name = parser.consume();
(name.clone(), Type::Named(name))
}
_ => parser.expected_failure("type")?,
};
let mut properties = Vec::new();
loop {
match parser.token {
Token::Ident(_, Keyword::SIGNED) => properties.push(DataTypeProperty::Signed(
parser.consume_keyword(Keyword::SIGNED)?,
)),
Token::Ident(_, Keyword::AUTO_INCREMENT) => properties.push(
DataTypeProperty::AutoIncrement(parser.consume_keyword(Keyword::AUTO_INCREMENT)?),
),
Token::Ident(_, Keyword::UNSIGNED) => properties.push(DataTypeProperty::Unsigned(
parser.consume_keyword(Keyword::UNSIGNED)?,
)),
Token::Ident(_, Keyword::ZEROFILL) => properties.push(DataTypeProperty::Zerofill(
parser.consume_keyword(Keyword::ZEROFILL)?,
)),
Token::Ident(_, Keyword::NULL) => properties.push(DataTypeProperty::Null(
parser.consume_keyword(Keyword::NULL)?,
)),
Token::Ident(_, Keyword::NOT) => {
let start = parser.consume_keyword(Keyword::NOT)?.start;
properties.push(DataTypeProperty::NotNull(
start..parser.consume_keyword(Keyword::NULL)?.end,
));
}
Token::Ident(_, Keyword::CHARACTER) => {
parser.consume_keywords(&[Keyword::CHARACTER, Keyword::SET])?;
properties.push(DataTypeProperty::Charset(
parser.consume_plain_identifier()?,
));
}
Token::Ident(_, Keyword::COLLATE) => {
parser.consume_keyword(Keyword::COLLATE)?;
properties.push(DataTypeProperty::Charset(
parser.consume_plain_identifier()?,
));
}
Token::Ident(_, Keyword::COMMENT) => {
parser.consume_keyword(Keyword::COMMENT)?;
properties.push(DataTypeProperty::Comment(parser.consume_string()?));
}
Token::Ident(_, Keyword::DEFAULT) => {
parser.consume_keyword(Keyword::DEFAULT)?;
properties.push(DataTypeProperty::Default(Box::new(parse_expression(
parser, true,
)?)));
}
Token::Ident(_, Keyword::VIRTUAL) => properties.push(DataTypeProperty::Virtual(
parser.consume_keyword(Keyword::VIRTUAL)?,
)),
Token::Ident(_, Keyword::PERSISTENT) => properties.push(DataTypeProperty::Persistent(
parser.consume_keyword(Keyword::PERSISTENT)?,
)),
Token::Ident(_, Keyword::STORED) => properties.push(DataTypeProperty::Stored(
parser.consume_keyword(Keyword::STORED)?,
)),
Token::Ident(_, Keyword::UNIQUE) => {
let span = parser.consume_keyword(Keyword::UNIQUE)?;
if let Some(s2) = parser.skip_keyword(Keyword::KEY) {
properties.push(DataTypeProperty::UniqueKey(s2.join_span(&span)));
} else {
properties.push(DataTypeProperty::Unique(span));
}
}
Token::Ident(_, Keyword::GENERATED) => {
if parser.options.dialect.is_postgresql() {
properties.push(DataTypeProperty::GeneratedAlways(parser.consume_keywords(
&[
Keyword::GENERATED,
Keyword::ALWAYS,
Keyword::AS,
Keyword::IDENTITY,
],
)?))
} else {
properties.push(DataTypeProperty::GeneratedAlways(
parser.consume_keywords(&[Keyword::GENERATED, Keyword::ALWAYS])?,
))
}
}
Token::Ident(_, Keyword::AS) if !no_as => {
let span = parser.consume_keyword(Keyword::AS)?;
let s1 = parser.consume_token(Token::LParen)?;
let e = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
Ok(Some(parse_expression(parser, false)?))
})?;
let s2 = parser.consume_token(Token::RParen)?;
let e = e.unwrap_or_else(|| Expression::Invalid(s1.join_span(&s2)));
properties.push(DataTypeProperty::As((span, Box::new(e))));
}
Token::Ident(_, Keyword::PRIMARY) => properties.push(DataTypeProperty::PrimaryKey(
parser.consume_keywords(&[Keyword::PRIMARY, Keyword::KEY])?,
)),
Token::Ident(_, Keyword::CHECK) => {
let span = parser.consume_keyword(Keyword::CHECK)?;
let s1 = parser.consume_token(Token::LParen)?;
let e = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
Ok(Some(parse_expression(parser, false)?))
})?;
let s2 = parser.consume_token(Token::RParen)?;
let e = e.unwrap_or_else(|| Expression::Invalid(s1.join_span(&s2)));
properties.push(DataTypeProperty::Check((span, Box::new(e))));
}
_ => break,
}
}
Ok(DataType {
identifier,
type_,
properties,
})
}