Skip to main content

qusql_parse/
data_type.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use alloc::{boxed::Box, vec::Vec};
14
15use crate::{
16    Identifier, InvalidExpression, SString, Span, Spanned,
17    alter_table::{ForeignKeyMatch, ForeignKeyOn, ForeignKeyOnAction, ForeignKeyOnType},
18    expression::{Expression, PRIORITY_MAX, parse_expression_unreserved},
19    keywords::Keyword,
20    lexer::{StringType, Token},
21    parser::{ParseError, Parser},
22    span::OptSpanned,
23};
24
25/// A property on a datatype
26#[derive(Debug, Clone)]
27pub enum DataTypeProperty<'a> {
28    Signed(Span),
29    Unsigned(Span),
30    Zerofill(Span),
31    Null(Span),
32    NotNull(Span),
33    Default(Expression<'a>),
34    Comment(SString<'a>),
35    Charset(Identifier<'a>),
36    Collate(Identifier<'a>),
37    Virtual(Span),
38    Persistent(Span),
39    Stored(Span),
40    Unique(Span),
41    UniqueKey(Span),
42    GeneratedAlways(Span),
43    AutoIncrement(Span),
44    PrimaryKey(Span),
45    As((Span, Expression<'a>)),
46    Check((Span, Expression<'a>)),
47    OnUpdate((Span, Expression<'a>)),
48    References {
49        /// Span of the `REFERENCES` keyword
50        span: Span,
51        /// Referenced table
52        table: Identifier<'a>,
53        /// Referenced columns (may be empty if omitted)
54        columns: Vec<Identifier<'a>>,
55        /// Optional MATCH FULL / MATCH SIMPLE / MATCH PARTIAL
56        match_type: Option<ForeignKeyMatch>,
57        /// Optional ON DELETE / ON UPDATE actions
58        ons: Vec<ForeignKeyOn>,
59    },
60}
61
62impl<'a> Spanned for DataTypeProperty<'a> {
63    fn span(&self) -> Span {
64        match &self {
65            DataTypeProperty::Signed(v) => v.span(),
66            DataTypeProperty::Unsigned(v) => v.span(),
67            DataTypeProperty::Zerofill(v) => v.span(),
68            DataTypeProperty::Null(v) => v.span(),
69            DataTypeProperty::NotNull(v) => v.span(),
70            DataTypeProperty::Default(v) => v.span(),
71            DataTypeProperty::Comment(v) => v.span(),
72            DataTypeProperty::Charset(v) => v.span(),
73            DataTypeProperty::Collate(v) => v.span(),
74            DataTypeProperty::Virtual(v) => v.span(),
75            DataTypeProperty::Persistent(v) => v.span(),
76            DataTypeProperty::Stored(v) => v.span(),
77            DataTypeProperty::Unique(v) => v.span(),
78            DataTypeProperty::UniqueKey(v) => v.span(),
79            DataTypeProperty::GeneratedAlways(v) => v.span(),
80            DataTypeProperty::AutoIncrement(v) => v.span(),
81            DataTypeProperty::As((s, v)) => s.join_span(v),
82            DataTypeProperty::Check((s, v)) => s.join_span(v),
83            DataTypeProperty::PrimaryKey(v) => v.span(),
84            DataTypeProperty::OnUpdate((s, v)) => s.join_span(v),
85            DataTypeProperty::References {
86                span,
87                table,
88                columns,
89                match_type,
90                ons,
91            } => span
92                .join_span(table)
93                .join_span(columns)
94                .join_span(match_type)
95                .join_span(ons),
96        }
97    }
98}
99
100#[derive(Debug, Clone)]
101pub struct Timestamp {
102    pub width: Option<(usize, Span)>,
103    pub with_time_zone: Option<Span>,
104}
105
106impl OptSpanned for Timestamp {
107    fn opt_span(&self) -> Option<Span> {
108        self.width.opt_span().opt_join_span(&self.with_time_zone)
109    }
110}
111
112/// Subtype for a built-in PostgreSQL range or multirange type.
113#[derive(Debug, Clone)]
114pub enum RangeSubtype {
115    Int4,
116    Int8,
117    Num,
118    Ts,
119    Tstz,
120    Date,
121}
122
123/// A single field qualifier for an `INTERVAL` type.
124#[derive(Debug, Clone)]
125pub enum IntervalField {
126    Year,
127    Month,
128    Day,
129    Hour,
130    Minute,
131    Second,
132}
133
134/// Interior of `Type::Interval`.
135#[derive(Debug, Clone)]
136pub struct Interval {
137    /// The first (or only) field qualifier, e.g. `YEAR` in `INTERVAL YEAR TO MONTH`.
138    pub start_field: Option<(IntervalField, Span)>,
139    /// The upper-bound field, e.g. `MONTH` in `INTERVAL YEAR TO MONTH`.
140    pub end_field: Option<(IntervalField, Span)>,
141    /// Fractional-seconds precision; only meaningful when the rightmost unit is `SECOND`.
142    pub precision: Option<(usize, Span)>,
143}
144
145impl OptSpanned for Interval {
146    fn opt_span(&self) -> Option<Span> {
147        let s = self.start_field.as_ref().map(|(_, s)| s.clone());
148        let e = self.end_field.as_ref().map(|(_, s)| s.clone());
149        s.opt_join_span(&e).opt_join_span(&self.precision)
150    }
151}
152
153/// Type of datatype
154#[derive(Debug, Clone)]
155pub enum Type<'a> {
156    Array(Box<Type<'a>>, Span),
157    BigInt(Option<(usize, Span)>),
158    BigSerial,
159    Binary(Option<(usize, Span)>),
160    Bit(usize, Span),
161    Blob(Option<(usize, Span)>),
162    Boolean,
163    Box,
164    Bytea,
165    Char(Option<(usize, Span)>),
166    Cidr,
167    Circle,
168    Date,
169    DateTime(Option<(usize, Span)>),
170    Decimal(Option<(usize, usize, Span)>),
171    Double(Option<(usize, usize, Span)>),
172    Enum(Vec<SString<'a>>),
173    Float(Option<(usize, usize, Span)>),
174    Float8,
175    Inet4,
176    Inet6,
177    InetAddr,
178    Int(Option<(usize, Span)>),
179    Integer(Option<(usize, Span)>),
180    Interval(Interval),
181    Json,
182    Jsonb,
183    Line,
184    LongBlob(Option<(usize, Span)>),
185    LongText(Option<(usize, Span)>),
186    Lseg,
187    Macaddr,
188    Macaddr8,
189    MediumBlob(Option<(usize, Span)>),
190    MediumInt(Option<(usize, Span)>),
191    MediumText(Option<(usize, Span)>),
192    Money,
193    Named(Span),
194    Path,
195    Numeric(Option<(usize, usize, Span)>),
196    Range(RangeSubtype),
197    MultiRange(RangeSubtype),
198    Serial,
199    Set(Vec<SString<'a>>),
200    Point,
201    Polygon,
202    SmallInt(Option<(usize, Span)>),
203    SmallSerial,
204    Table(Span, Vec<(Identifier<'a>, DataType<'a>)>),
205    Text(Option<(usize, Span)>),
206    Time(Option<(usize, Span)>),
207    Timestamp(Timestamp),
208    Timestamptz,
209    Timetz(Option<(usize, Span)>),
210    TsQuery,
211    TsVector,
212    TinyBlob(Option<(usize, Span)>),
213    TinyInt(Option<(usize, Span)>),
214    TinyText(Option<(usize, Span)>),
215    VarBinary((usize, Span)),
216    VarBit(Option<(usize, Span)>),
217    VarChar(Option<(usize, Span)>),
218    Uuid,
219    Xml,
220}
221
222impl<'a> OptSpanned for Type<'a> {
223    fn opt_span(&self) -> Option<Span> {
224        match &self {
225            Type::Array(inner, span) => Some(span.join_span(inner.as_ref())),
226            Type::BigInt(v) => v.opt_span(),
227            Type::BigSerial => None,
228            Type::Binary(v) => v.opt_span(),
229            Type::Bit(_, b) => b.opt_span(),
230            Type::Blob(v) => v.opt_span(),
231            Type::Boolean => None,
232            Type::Box => None,
233            Type::Bytea => None,
234            Type::Char(v) => v.opt_span(),
235            Type::Cidr => None,
236            Type::Circle => None,
237            Type::Date => None,
238            Type::DateTime(v) => v.opt_span(),
239            Type::Decimal(v) => v.opt_span(),
240            Type::Double(v) => v.opt_span(),
241            Type::Enum(v) => v.opt_span(),
242            Type::Float(v) => v.opt_span(),
243            Type::Float8 => None,
244            Type::Inet4 => None,
245            Type::Inet6 => None,
246            Type::InetAddr => None,
247            Type::Int(v) => v.opt_span(),
248            Type::Integer(v) => v.opt_span(),
249            Type::Interval(v) => v.opt_span(),
250            Type::Json => None,
251            Type::Jsonb => None,
252            Type::Line => None,
253            Type::LongBlob(v) => v.opt_span(),
254            Type::LongText(v) => v.opt_span(),
255            Type::Lseg => None,
256            Type::Macaddr => None,
257            Type::Macaddr8 => None,
258            Type::MediumBlob(v) => v.opt_span(),
259            Type::MediumInt(v) => v.opt_span(),
260            Type::MediumText(v) => v.opt_span(),
261            Type::Money => None,
262            Type::Named(v) => v.opt_span(),
263            Type::Path => None,
264            Type::Numeric(v) => v.opt_span(),
265            Type::Range(_) => None,
266            Type::MultiRange(_) => None,
267            Type::Serial => None,
268            Type::Set(v) => v.opt_span(),
269            Type::Point => None,
270            Type::Polygon => None,
271            Type::SmallInt(v) => v.opt_span(),
272            Type::SmallSerial => None,
273            Type::Table(span, _) => Some(span.clone()),
274            Type::Text(v) => v.opt_span(),
275            Type::Time(v) => v.opt_span(),
276            Type::Timestamp(v) => v.opt_span(),
277            Type::Timestamptz => None,
278            Type::Timetz(v) => v.opt_span(),
279            Type::TsQuery => None,
280            Type::TsVector => None,
281            Type::TinyBlob(v) => v.opt_span(),
282            Type::TinyInt(v) => v.opt_span(),
283            Type::TinyText(v) => v.opt_span(),
284            Type::VarBinary(v) => v.opt_span(),
285            Type::VarBit(v) => v.opt_span(),
286            Type::VarChar(v) => v.opt_span(),
287            Type::Uuid => None,
288            Type::Xml => None,
289        }
290    }
291}
292
293/// Type of data
294#[derive(Debug, Clone)]
295pub struct DataType<'a> {
296    /// Span of type_ identifier
297    pub identifier: Span,
298    /// Type with width
299    pub type_: Type<'a>,
300    /// Properties on type
301    pub properties: Vec<DataTypeProperty<'a>>,
302}
303
304impl<'a> Spanned for DataType<'a> {
305    fn span(&self) -> Span {
306        self.identifier
307            .join_span(&self.type_)
308            .join_span(&self.properties)
309    }
310}
311fn parse_width(parser: &mut Parser<'_, '_>) -> Result<Option<(usize, Span)>, ParseError> {
312    if !matches!(parser.token, Token::LParen) {
313        return Ok(None);
314    }
315    parser.consume_token(Token::LParen)?;
316    let value = parser.recovered(")", &|t| t == &Token::RParen, |parser| parser.consume_int())?;
317    parser.consume_token(Token::RParen)?;
318    Ok(Some(value))
319}
320
321fn parse_width_req(parser: &mut Parser<'_, '_>) -> Result<(usize, Span), ParseError> {
322    if !matches!(parser.token, Token::LParen) {
323        return parser.expected_failure("'('");
324    }
325    Ok(parse_width(parser)?.expect("width"))
326}
327
328fn parse_precision_scale(
329    parser: &mut Parser<'_, '_>,
330) -> Result<Option<(usize, usize, Span)>, ParseError> {
331    if !matches!(parser.token, Token::LParen) {
332        return Ok(None);
333    }
334    let left = parser.consume_token(Token::LParen)?;
335    let (precision, s1) = parser.consume_int()?;
336    let scale = if parser.skip_token(Token::Comma).is_some() {
337        let (v, _) = parser.consume_int()?;
338        v
339    } else {
340        0
341    };
342    let right = parser.consume_token(Token::RParen)?;
343    let span = left.join_span(&s1).join_span(&right);
344    Ok(Some((precision, scale, span)))
345}
346
347fn parse_enum_set_values<'a>(parser: &mut Parser<'a, '_>) -> Result<Vec<SString<'a>>, ParseError> {
348    parser.consume_token(Token::LParen)?;
349    let mut ans = Vec::new();
350    parser.recovered(")", &|t| t == &Token::RParen, |parser| {
351        loop {
352            ans.push(parser.consume_string()?);
353            match &parser.token {
354                Token::Comma => {
355                    parser.consume_token(Token::Comma)?;
356                }
357                Token::RParen => break,
358                _ => parser.expected_failure("',' or ')'")?,
359            }
360        }
361        Ok(())
362    })?;
363    parser.consume_token(Token::RParen)?;
364    Ok(ans)
365}
366
367fn parse_interval_field(
368    parser: &mut Parser<'_, '_>,
369) -> Result<Option<(IntervalField, Span)>, ParseError> {
370    let (field, kw) = match &parser.token {
371        Token::Ident(_, Keyword::YEAR) => (IntervalField::Year, Keyword::YEAR),
372        Token::Ident(_, Keyword::MONTH) => (IntervalField::Month, Keyword::MONTH),
373        Token::Ident(_, Keyword::DAY) => (IntervalField::Day, Keyword::DAY),
374        Token::Ident(_, Keyword::HOUR) => (IntervalField::Hour, Keyword::HOUR),
375        Token::Ident(_, Keyword::MINUTE) => (IntervalField::Minute, Keyword::MINUTE),
376        Token::Ident(_, Keyword::SECOND) => (IntervalField::Second, Keyword::SECOND),
377        _ => return Ok(None),
378    };
379    let span = parser.consume_keyword(kw)?;
380    Ok(Some((field, span)))
381}
382
383/// The context in which a data type is being parsed.
384///
385/// This controls which [`DataTypeProperty`] variants are syntactically accepted
386/// and enables future per-context validation.
387#[derive(Clone, Copy, PartialEq, Eq)]
388pub(crate) enum DataTypeContext {
389    /// Column definition in `CREATE TABLE`, `ALTER TABLE ADD/MODIFY COLUMN`,
390    /// or composite type attributes (`ALTER TYPE … ADD/ALTER ATTRIBUTE`).
391    /// All properties are allowed, including the `AS (expr)` generated-column syntax.
392    Column,
393    /// Function or procedure parameter type (`CREATE FUNCTION f(a INT …)`).
394    /// The `AS (expr)` generated-column syntax is not accepted here.
395    FunctionParam,
396    /// Function return type (`RETURNS …`), or a `JSON_TABLE` column path type.
397    /// The `AS (expr)` generated-column syntax is not accepted here.
398    FunctionReturn,
399    /// Type reference in an expression context: `CAST(… AS type)`, `expr::type`,
400    /// `CONVERT(expr, type)`, or operator/function argument types in `DROP`.
401    /// The `AS (expr)` generated-column syntax is not accepted here.
402    TypeRef,
403}
404
405pub(crate) fn parse_data_type<'a>(
406    parser: &mut Parser<'a, '_>,
407    ctx: DataTypeContext,
408) -> Result<DataType<'a>, ParseError> {
409    let (identifier, type_) = match &parser.token {
410        Token::Ident(_, Keyword::BOOLEAN) => {
411            (parser.consume_keyword(Keyword::BOOLEAN)?, Type::Boolean)
412        }
413        Token::Ident(_, Keyword::BOOL) => (parser.consume_keyword(Keyword::BOOL)?, Type::Boolean),
414        Token::Ident(_, Keyword::TINYINT) => (
415            parser.consume_keyword(Keyword::TINYINT)?,
416            Type::TinyInt(parse_width(parser)?),
417        ),
418        Token::Ident(_, Keyword::SMALLINT) => (
419            parser.consume_keyword(Keyword::SMALLINT)?,
420            Type::SmallInt(parse_width(parser)?),
421        ),
422        Token::Ident(_, Keyword::MEDIUMINT) => (
423            parser.consume_keyword(Keyword::MEDIUMINT)?,
424            Type::MediumInt(parse_width(parser)?),
425        ),
426        Token::Ident(_, Keyword::INTEGER) => (
427            parser.consume_keyword(Keyword::INTEGER)?,
428            Type::Integer(parse_width(parser)?),
429        ),
430        Token::Ident(_, Keyword::INT) => (
431            parser.consume_keyword(Keyword::INT)?,
432            Type::Int(parse_width(parser)?),
433        ),
434        Token::Ident(_, Keyword::BIGINT) => (
435            parser.consume_keyword(Keyword::BIGINT)?,
436            Type::BigInt(parse_width(parser)?),
437        ),
438        Token::Ident(_, Keyword::INET4) => (parser.consume_keyword(Keyword::INET4)?, Type::Inet4),
439        Token::Ident(_, Keyword::INET6) => (parser.consume_keyword(Keyword::INET6)?, Type::Inet6),
440        Token::Ident(_, Keyword::INET) if parser.options.dialect.is_postgresql() => {
441            (parser.consume_keyword(Keyword::INET)?, Type::InetAddr)
442        }
443        Token::Ident(_, Keyword::CIDR) if parser.options.dialect.is_postgresql() => {
444            (parser.consume_keyword(Keyword::CIDR)?, Type::Cidr)
445        }
446        Token::Ident(_, Keyword::MACADDR) if parser.options.dialect.is_postgresql() => {
447            (parser.consume_keyword(Keyword::MACADDR)?, Type::Macaddr)
448        }
449        Token::Ident(_, Keyword::MACADDR8) if parser.options.dialect.is_postgresql() => {
450            (parser.consume_keyword(Keyword::MACADDR8)?, Type::Macaddr8)
451        }
452        Token::Ident(_, Keyword::INT2) => {
453            (parser.consume_keyword(Keyword::INT2)?, Type::SmallInt(None))
454        }
455        Token::Ident(_, Keyword::INT4) => (parser.consume_keyword(Keyword::INT4)?, Type::Int(None)),
456        Token::Ident(_, Keyword::INT8) => {
457            (parser.consume_keyword(Keyword::INT8)?, Type::BigInt(None))
458        }
459        Token::Ident(_, Keyword::FLOAT4) => {
460            (parser.consume_keyword(Keyword::FLOAT4)?, Type::Float(None))
461        }
462        Token::Ident(_, Keyword::SERIAL) if parser.options.dialect.is_postgresql() => {
463            (parser.consume_keyword(Keyword::SERIAL)?, Type::Serial)
464        }
465        Token::Ident(_, Keyword::SMALLSERIAL) if parser.options.dialect.is_postgresql() => (
466            parser.consume_keyword(Keyword::SMALLSERIAL)?,
467            Type::SmallSerial,
468        ),
469        Token::Ident(_, Keyword::BIGSERIAL) if parser.options.dialect.is_postgresql() => {
470            (parser.consume_keyword(Keyword::BIGSERIAL)?, Type::BigSerial)
471        }
472        Token::Ident(_, Keyword::MONEY) if parser.options.dialect.is_postgresql() => {
473            (parser.consume_keyword(Keyword::MONEY)?, Type::Money)
474        }
475        Token::Ident(_, Keyword::TINYTEXT) => (
476            parser.consume_keyword(Keyword::TINYTEXT)?,
477            Type::TinyText(parse_width(parser)?),
478        ),
479        Token::Ident(_, Keyword::CHAR) => (
480            parser.consume_keyword(Keyword::CHAR)?,
481            Type::Char(parse_width(parser)?),
482        ),
483        Token::Ident(_, Keyword::CHARACTER) => {
484            let char_span = parser.consume_keyword(Keyword::CHARACTER)?;
485            if let Some(varying_span) = parser.skip_keyword(Keyword::VARYING) {
486                (
487                    char_span.join_span(&varying_span),
488                    Type::VarChar(parse_width(parser)?),
489                )
490            } else {
491                (char_span, Type::Char(parse_width(parser)?))
492            }
493        }
494        Token::Ident(_, Keyword::BPCHAR) => (
495            parser.consume_keyword(Keyword::BPCHAR)?,
496            Type::Char(parse_width(parser)?),
497        ),
498        Token::Ident(_, Keyword::NCHAR) => (
499            parser.consume_keyword(Keyword::NCHAR)?,
500            Type::Char(parse_width(parser)?),
501        ),
502        Token::Ident(_, Keyword::TEXT) => (
503            parser.consume_keyword(Keyword::TEXT)?,
504            Type::Text(parse_width(parser)?),
505        ),
506        Token::Ident(_, Keyword::MEDIUMTEXT) => (
507            parser.consume_keyword(Keyword::MEDIUMTEXT)?,
508            Type::MediumText(parse_width(parser)?),
509        ),
510        Token::Ident(_, Keyword::LONGTEXT) => (
511            parser.consume_keyword(Keyword::LONGTEXT)?,
512            Type::LongText(parse_width(parser)?),
513        ),
514        Token::Ident(_, Keyword::VARCHAR) => (
515            parser.consume_keyword(Keyword::VARCHAR)?,
516            Type::VarChar(parse_width(parser)?),
517        ),
518        Token::Ident(_, Keyword::VARCHARACTER) => (
519            parser.consume_keyword(Keyword::VARCHARACTER)?,
520            Type::VarChar(parse_width(parser)?),
521        ),
522        Token::Ident(_, Keyword::NVARCHAR) => (
523            parser.consume_keyword(Keyword::NVARCHAR)?,
524            Type::VarChar(parse_width(parser)?),
525        ),
526        Token::Ident(_, Keyword::TINYBLOB) => (
527            parser.consume_keyword(Keyword::TINYBLOB)?,
528            Type::TinyBlob(parse_width(parser)?),
529        ),
530        Token::Ident(_, Keyword::BLOB) => (
531            parser.consume_keyword(Keyword::BLOB)?,
532            Type::Blob(parse_width(parser)?),
533        ),
534        Token::Ident(_, Keyword::MEDIUMBLOB) => (
535            parser.consume_keyword(Keyword::MEDIUMBLOB)?,
536            Type::MediumBlob(parse_width(parser)?),
537        ),
538        Token::Ident(_, Keyword::LONGBLOB) => (
539            parser.consume_keyword(Keyword::LONGBLOB)?,
540            Type::LongBlob(parse_width(parser)?),
541        ),
542        Token::Ident(_, Keyword::VARBINARY) => (
543            parser.consume_keyword(Keyword::VARBINARY)?,
544            Type::VarBinary(parse_width_req(parser)?),
545        ),
546        Token::Ident(_, Keyword::BINARY) => (
547            parser.consume_keyword(Keyword::BINARY)?,
548            Type::Binary(parse_width(parser)?),
549        ),
550        Token::Ident(_, Keyword::FLOAT8) => {
551            (parser.consume_keyword(Keyword::FLOAT8)?, Type::Float8)
552        }
553        Token::Ident(_, Keyword::REAL) => {
554            let i = parser.consume_keyword(Keyword::REAL)?;
555            if parser.options.dialect.is_sqlite() {
556                (i, Type::Double(None))
557            } else {
558                (i, Type::Float(None))
559            }
560        }
561        Token::Ident(_, Keyword::FLOAT) => {
562            let i = parser.consume_keyword(Keyword::FLOAT)?;
563            (i, Type::Float(parse_precision_scale(parser)?))
564        }
565        Token::Ident(_, Keyword::DOUBLE) => {
566            let i = if parser.options.dialect.is_postgresql() {
567                parser.consume_keywords(&[Keyword::DOUBLE, Keyword::PRECISION])?
568            } else {
569                let double_span = parser.consume_keyword(Keyword::DOUBLE)?;
570                // MySQL also supports optional PRECISION keyword
571                if let Some(precision_span) = parser.skip_keyword(Keyword::PRECISION) {
572                    double_span.join_span(&precision_span)
573                } else {
574                    double_span
575                }
576            };
577            (i, Type::Double(parse_precision_scale(parser)?))
578        }
579        Token::Ident(_, Keyword::NUMERIC) => {
580            let numeric = parser.consume_keyword(Keyword::NUMERIC)?;
581            (numeric, Type::Numeric(parse_precision_scale(parser)?))
582        }
583        Token::Ident(_, Keyword::DECIMAL) => {
584            let decimal = parser.consume_keyword(Keyword::DECIMAL)?;
585            (decimal, Type::Decimal(parse_precision_scale(parser)?))
586        }
587        Token::Ident(_, Keyword::DEC) => {
588            let dec = parser.consume_keyword(Keyword::DEC)?;
589            (dec, Type::Decimal(parse_precision_scale(parser)?))
590        }
591        Token::Ident(_, Keyword::DATETIME) => (
592            parser.consume_keyword(Keyword::DATETIME)?,
593            Type::DateTime(parse_width(parser)?),
594        ),
595        Token::Ident(_, Keyword::TIMETZ) if parser.options.dialect.is_postgresql() => {
596            (parser.consume_keyword(Keyword::TIMETZ)?, Type::Timetz(None))
597        }
598        Token::Ident(_, Keyword::TIME) => {
599            let time_span = parser.consume_keyword(Keyword::TIME)?;
600            let width = parse_width(parser)?;
601            if parser.options.dialect.is_postgresql() {
602                if parser.skip_keyword(Keyword::WITH).is_some() {
603                    parser.consume_keywords(&[Keyword::TIME, Keyword::ZONE])?;
604                    (time_span, Type::Timetz(width))
605                } else if parser.skip_keyword(Keyword::WITHOUT).is_some() {
606                    parser.consume_keywords(&[Keyword::TIME, Keyword::ZONE])?;
607                    (time_span, Type::Time(width))
608                } else {
609                    (time_span, Type::Time(width))
610                }
611            } else {
612                (time_span, Type::Time(width))
613            }
614        }
615        Token::Ident(_, Keyword::TIMESTAMPTZ) => (
616            parser.consume_keyword(Keyword::TIMESTAMPTZ)?,
617            Type::Timestamptz,
618        ),
619        Token::Ident(_, Keyword::TIMESTAMP) => {
620            let timestamp_span = parser.consume_keyword(Keyword::TIMESTAMP)?;
621            let width = parse_width(parser)?;
622            let with_time_zone = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
623                Some(
624                    with_span.join_span(&parser.consume_keywords(&[Keyword::TIME, Keyword::ZONE])?),
625                )
626            } else {
627                if parser.skip_keyword(Keyword::WITHOUT).is_some() {
628                    parser.consume_keywords(&[Keyword::TIME, Keyword::ZONE])?;
629                }
630                None
631            };
632            let timestamp = Timestamp {
633                width,
634                with_time_zone,
635            };
636            (timestamp_span, Type::Timestamp(timestamp))
637        }
638        Token::Ident(_, Keyword::DATE) => (parser.consume_keyword(Keyword::DATE)?, Type::Date),
639        Token::Ident(_, Keyword::BOX) if parser.options.dialect.is_postgresql() => {
640            (parser.consume_keyword(Keyword::BOX)?, Type::Box)
641        }
642        Token::Ident(_, Keyword::CIRCLE) if parser.options.dialect.is_postgresql() => {
643            (parser.consume_keyword(Keyword::CIRCLE)?, Type::Circle)
644        }
645        Token::Ident(_, Keyword::LINE) if parser.options.dialect.is_postgresql() => {
646            (parser.consume_keyword(Keyword::LINE)?, Type::Line)
647        }
648        Token::Ident(_, Keyword::LSEG) if parser.options.dialect.is_postgresql() => {
649            (parser.consume_keyword(Keyword::LSEG)?, Type::Lseg)
650        }
651        Token::Ident(_, Keyword::PATH) if parser.options.dialect.is_postgresql() => {
652            (parser.consume_keyword(Keyword::PATH)?, Type::Path)
653        }
654        Token::Ident(_, Keyword::POINT) if parser.options.dialect.is_postgresql() => {
655            (parser.consume_keyword(Keyword::POINT)?, Type::Point)
656        }
657        Token::Ident(_, Keyword::POLYGON) if parser.options.dialect.is_postgresql() => {
658            (parser.consume_keyword(Keyword::POLYGON)?, Type::Polygon)
659        }
660        Token::Ident(_, Keyword::INTERVAL) if parser.options.dialect.is_postgresql() => {
661            let interval_span = parser.consume_keyword(Keyword::INTERVAL)?;
662            let start_field = parse_interval_field(parser)?;
663            let end_field = if start_field.is_some() && parser.skip_keyword(Keyword::TO).is_some() {
664                parse_interval_field(parser)?
665            } else {
666                None
667            };
668            let precision = parse_width(parser)?;
669            (
670                interval_span,
671                Type::Interval(Interval {
672                    start_field,
673                    end_field,
674                    precision,
675                }),
676            )
677        }
678        Token::Ident(_, Keyword::ENUM) => (
679            parser.consume_keyword(Keyword::ENUM)?,
680            Type::Enum(parse_enum_set_values(parser)?),
681        ),
682        Token::Ident(_, Keyword::SET) => (
683            parser.consume_keyword(Keyword::SET)?,
684            Type::Set(parse_enum_set_values(parser)?),
685        ),
686        Token::Ident(_, Keyword::JSON) => (parser.consume_keyword(Keyword::JSON)?, Type::Json),
687        Token::Ident(_, Keyword::JSONB) if parser.options.dialect.is_postgresql() => {
688            (parser.consume_keyword(Keyword::JSONB)?, Type::Jsonb)
689        }
690        Token::Ident(_, Keyword::BYTEA) => (parser.consume_keyword(Keyword::BYTEA)?, Type::Bytea),
691        Token::Ident(_, Keyword::INT4RANGE) if parser.options.dialect.is_postgresql() => (
692            parser.consume_keyword(Keyword::INT4RANGE)?,
693            Type::Range(RangeSubtype::Int4),
694        ),
695        Token::Ident(_, Keyword::INT8RANGE) if parser.options.dialect.is_postgresql() => (
696            parser.consume_keyword(Keyword::INT8RANGE)?,
697            Type::Range(RangeSubtype::Int8),
698        ),
699        Token::Ident(_, Keyword::NUMRANGE) if parser.options.dialect.is_postgresql() => (
700            parser.consume_keyword(Keyword::NUMRANGE)?,
701            Type::Range(RangeSubtype::Num),
702        ),
703        Token::Ident(_, Keyword::TSRANGE) if parser.options.dialect.is_postgresql() => (
704            parser.consume_keyword(Keyword::TSRANGE)?,
705            Type::Range(RangeSubtype::Ts),
706        ),
707        Token::Ident(_, Keyword::TSTZRANGE) if parser.options.dialect.is_postgresql() => (
708            parser.consume_keyword(Keyword::TSTZRANGE)?,
709            Type::Range(RangeSubtype::Tstz),
710        ),
711        Token::Ident(_, Keyword::DATERANGE) if parser.options.dialect.is_postgresql() => (
712            parser.consume_keyword(Keyword::DATERANGE)?,
713            Type::Range(RangeSubtype::Date),
714        ),
715        Token::Ident(_, Keyword::INT4MULTIRANGE) if parser.options.dialect.is_postgresql() => (
716            parser.consume_keyword(Keyword::INT4MULTIRANGE)?,
717            Type::MultiRange(RangeSubtype::Int4),
718        ),
719        Token::Ident(_, Keyword::INT8MULTIRANGE) if parser.options.dialect.is_postgresql() => (
720            parser.consume_keyword(Keyword::INT8MULTIRANGE)?,
721            Type::MultiRange(RangeSubtype::Int8),
722        ),
723        Token::Ident(_, Keyword::NUMMULTIRANGE) if parser.options.dialect.is_postgresql() => (
724            parser.consume_keyword(Keyword::NUMMULTIRANGE)?,
725            Type::MultiRange(RangeSubtype::Num),
726        ),
727        Token::Ident(_, Keyword::TSMULTIRANGE) if parser.options.dialect.is_postgresql() => (
728            parser.consume_keyword(Keyword::TSMULTIRANGE)?,
729            Type::MultiRange(RangeSubtype::Ts),
730        ),
731        Token::Ident(_, Keyword::TSTZMULTIRANGE) if parser.options.dialect.is_postgresql() => (
732            parser.consume_keyword(Keyword::TSTZMULTIRANGE)?,
733            Type::MultiRange(RangeSubtype::Tstz),
734        ),
735        Token::Ident(_, Keyword::DATEMULTIRANGE) if parser.options.dialect.is_postgresql() => (
736            parser.consume_keyword(Keyword::DATEMULTIRANGE)?,
737            Type::MultiRange(RangeSubtype::Date),
738        ),
739        Token::Ident(_, Keyword::UUID) if parser.options.dialect.is_postgresql() => {
740            (parser.consume_keyword(Keyword::UUID)?, Type::Uuid)
741        }
742        Token::Ident(_, Keyword::XML) if parser.options.dialect.is_postgresql() => {
743            (parser.consume_keyword(Keyword::XML)?, Type::Xml)
744        }
745        Token::Ident(_, Keyword::TSQUERY) if parser.options.dialect.is_postgresql() => {
746            (parser.consume_keyword(Keyword::TSQUERY)?, Type::TsQuery)
747        }
748        Token::Ident(_, Keyword::TSVECTOR) if parser.options.dialect.is_postgresql() => {
749            (parser.consume_keyword(Keyword::TSVECTOR)?, Type::TsVector)
750        }
751        Token::Ident(_, Keyword::BIT) => {
752            let t = parser.consume_keyword(Keyword::BIT)?;
753            if parser.options.dialect.is_postgresql() {
754                if parser.skip_keyword(Keyword::VARYING).is_some() {
755                    (t, Type::VarBit(parse_width(parser)?))
756                } else {
757                    let width = parse_width(parser)?;
758                    let (w, ws) = width.unwrap_or((1, t.clone()));
759                    (t, Type::Bit(w, ws))
760                }
761            } else {
762                let (w, ws) = parse_width_req(parser)?;
763                (t, Type::Bit(w, ws))
764            }
765        }
766        Token::Ident(_, Keyword::VARBIT) => {
767            let t = parser.consume_keyword(Keyword::VARBIT)?;
768            parser.postgres_only(&t);
769            (t, Type::VarBit(parse_width(parser)?))
770        }
771        Token::Ident(_, Keyword::TABLE)
772            if parser.options.dialect.is_postgresql() && ctx == DataTypeContext::FunctionReturn =>
773        {
774            let table_span = parser.consume_keyword(Keyword::TABLE)?;
775            let lparen = parser.consume_token(Token::LParen)?;
776            let mut columns = Vec::new();
777            parser.recovered(")", &|t| t == &Token::RParen, |parser| {
778                loop {
779                    let name = parser.consume_plain_identifier_unreserved()?;
780                    let col_type = parse_data_type(parser, DataTypeContext::FunctionParam)?;
781                    columns.push((name, col_type));
782                    if parser.skip_token(Token::Comma).is_none() {
783                        break;
784                    }
785                }
786                Ok(())
787            })?;
788            let rparen = parser.consume_token(Token::RParen)?;
789            let paren_span = lparen.join_span(&rparen);
790            (table_span, Type::Table(paren_span, columns))
791        }
792        Token::String(_, StringType::DoubleQuoted) if parser.options.dialect.is_postgresql() => {
793            let name = parser.consume();
794            (name.clone(), Type::Named(name))
795        }
796        Token::Ident(_, _) if parser.options.dialect.is_postgresql() => {
797            let name = parser.consume();
798            (name.clone(), Type::Named(name))
799        }
800        _ => parser.expected_failure("type")?,
801    };
802
803    // Check for PostgreSQL array type syntax: TYPE[] or TYPE[][] etc.
804    let (identifier, type_) = {
805        let mut identifier = identifier;
806        let mut type_ = type_;
807        while parser.options.dialect.is_postgresql() && matches!(parser.token, Token::LBracket) {
808            let lbracket = parser.consume_token(Token::LBracket)?;
809            let rbracket = parser.consume_token(Token::RBracket)?;
810            let array_span = lbracket.join_span(&rbracket);
811            identifier = identifier.join_span(&array_span);
812            type_ = Type::Array(Box::new(type_), array_span);
813        }
814        (identifier, type_)
815    };
816
817    let mut properties = Vec::new();
818    loop {
819        // Each arm tuple is (&parser.token, ctx).  The wildcard arm stops
820        // property parsing for both "unknown token" and "property not allowed
821        // in this context", so callers never silently swallow tokens.
822        use DataTypeContext::*;
823        match (&parser.token, ctx) {
824            // ── Properties valid in column definitions and function signatures ──
825            (Token::Ident(_, Keyword::SIGNED), Column | FunctionParam | FunctionReturn) => {
826                properties.push(DataTypeProperty::Signed(
827                    parser.consume_keyword(Keyword::SIGNED)?,
828                ));
829            }
830            (Token::Ident(_, Keyword::UNSIGNED), Column | FunctionParam | FunctionReturn) => {
831                properties.push(DataTypeProperty::Unsigned(
832                    parser.consume_keyword(Keyword::UNSIGNED)?,
833                ));
834            }
835            (Token::Ident(_, Keyword::ZEROFILL), Column | FunctionParam | FunctionReturn) => {
836                properties.push(DataTypeProperty::Zerofill(
837                    parser.consume_keyword(Keyword::ZEROFILL)?,
838                ));
839            }
840            (
841                Token::Ident(_, Keyword::CHARACTER),
842                Column | FunctionParam | FunctionReturn | TypeRef,
843            ) => {
844                parser.consume_keywords(&[Keyword::CHARACTER, Keyword::SET])?;
845                properties.push(DataTypeProperty::Charset(
846                    parser.consume_plain_identifier_unreserved()?,
847                ));
848            }
849            (
850                Token::Ident(_, Keyword::CHARSET),
851                Column | FunctionParam | FunctionReturn | TypeRef,
852            ) => {
853                parser.consume_keyword(Keyword::CHARSET)?;
854                properties.push(DataTypeProperty::Charset(
855                    parser.consume_plain_identifier_unreserved()?,
856                ));
857            }
858            (
859                Token::Ident(_, Keyword::COLLATE),
860                Column | FunctionParam | FunctionReturn | TypeRef,
861            ) => {
862                parser.consume_keyword(Keyword::COLLATE)?;
863                properties.push(DataTypeProperty::Collate(
864                    parser.consume_plain_identifier_unreserved()?,
865                ));
866            }
867
868            // ── Column-only properties ──
869            (Token::Ident(_, Keyword::NULL), Column) => {
870                properties.push(DataTypeProperty::Null(
871                    parser.consume_keyword(Keyword::NULL)?,
872                ));
873            }
874            (Token::Ident(_, Keyword::NOT), Column) => {
875                let start = parser.consume_keyword(Keyword::NOT)?.start;
876                properties.push(DataTypeProperty::NotNull(
877                    start..parser.consume_keyword(Keyword::NULL)?.end,
878                ));
879            }
880            (Token::Ident(_, Keyword::COMMENT), Column) => {
881                parser.consume_keyword(Keyword::COMMENT)?;
882                properties.push(DataTypeProperty::Comment(parser.consume_string()?));
883            }
884            (Token::Ident(_, Keyword::DEFAULT), Column) => {
885                parser.consume_keyword(Keyword::DEFAULT)?;
886                properties.push(DataTypeProperty::Default(parse_expression_unreserved(
887                    parser,
888                    PRIORITY_MAX,
889                )?));
890            }
891            (Token::Ident(_, Keyword::AUTO_INCREMENT), Column) => {
892                properties.push(DataTypeProperty::AutoIncrement(
893                    parser.consume_keyword(Keyword::AUTO_INCREMENT)?,
894                ));
895            }
896            (Token::Ident(_, Keyword::VIRTUAL), Column) => {
897                properties.push(DataTypeProperty::Virtual(
898                    parser.consume_keyword(Keyword::VIRTUAL)?,
899                ));
900            }
901            (Token::Ident(_, Keyword::PERSISTENT), Column) => {
902                properties.push(DataTypeProperty::Persistent(
903                    parser.consume_keyword(Keyword::PERSISTENT)?,
904                ));
905            }
906            (Token::Ident(_, Keyword::STORED), Column) => {
907                properties.push(DataTypeProperty::Stored(
908                    parser.consume_keyword(Keyword::STORED)?,
909                ));
910            }
911            (Token::Ident(_, Keyword::UNIQUE), Column) => {
912                let span = parser.consume_keyword(Keyword::UNIQUE)?;
913                if let Some(s2) = parser.skip_keyword(Keyword::KEY) {
914                    properties.push(DataTypeProperty::UniqueKey(s2.join_span(&span)));
915                } else {
916                    properties.push(DataTypeProperty::Unique(span));
917                }
918            }
919            (Token::Ident(_, Keyword::GENERATED), Column) => {
920                if parser.options.dialect.is_postgresql() {
921                    properties.push(DataTypeProperty::GeneratedAlways(parser.consume_keywords(
922                        &[
923                            Keyword::GENERATED,
924                            Keyword::ALWAYS,
925                            Keyword::AS,
926                            Keyword::IDENTITY,
927                        ],
928                    )?));
929                } else {
930                    properties.push(DataTypeProperty::GeneratedAlways(
931                        parser.consume_keywords(&[Keyword::GENERATED, Keyword::ALWAYS])?,
932                    ));
933                }
934            }
935            (Token::Ident(_, Keyword::AS), Column) => {
936                let span = parser.consume_keyword(Keyword::AS)?;
937                let s1 = parser.consume_token(Token::LParen)?;
938                let e = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
939                    Ok(Some(parse_expression_unreserved(parser, PRIORITY_MAX)?))
940                })?;
941                let s2 = parser.consume_token(Token::RParen)?;
942                let e = e.unwrap_or_else(|| {
943                    Expression::Invalid(Box::new(InvalidExpression {
944                        span: s1.join_span(&s2),
945                    }))
946                });
947                properties.push(DataTypeProperty::As((span, e)));
948            }
949            (Token::Ident(_, Keyword::PRIMARY), Column) => {
950                properties.push(DataTypeProperty::PrimaryKey(
951                    parser.consume_keywords(&[Keyword::PRIMARY, Keyword::KEY])?,
952                ));
953            }
954            (Token::Ident(_, Keyword::CHECK), Column) => {
955                let span = parser.consume_keyword(Keyword::CHECK)?;
956                let s1 = parser.consume_token(Token::LParen)?;
957                let e = parser.recovered(")", &|t| t == &Token::RParen, |parser| {
958                    Ok(Some(parse_expression_unreserved(parser, PRIORITY_MAX)?))
959                })?;
960                let s2 = parser.consume_token(Token::RParen)?;
961                let e = e.unwrap_or_else(|| {
962                    Expression::Invalid(Box::new(InvalidExpression {
963                        span: s1.join_span(&s2),
964                    }))
965                });
966                properties.push(DataTypeProperty::Check((span, e)));
967            }
968            (Token::Ident(_, Keyword::ON), Column) => {
969                let span = parser.consume_keywords(&[Keyword::ON, Keyword::UPDATE])?;
970                let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
971                properties.push(DataTypeProperty::OnUpdate((span, expr)));
972            }
973            (Token::Ident(_, Keyword::REFERENCES), Column) => {
974                let span = parser.consume_keyword(Keyword::REFERENCES)?;
975                let table = parser.consume_plain_identifier_unreserved()?;
976                let mut columns = Vec::new();
977                if matches!(parser.token, Token::LParen) {
978                    parser.consume_token(Token::LParen)?;
979                    loop {
980                        columns.push(parser.consume_plain_identifier_unreserved()?);
981                        if parser.skip_token(Token::Comma).is_none() {
982                            break;
983                        }
984                    }
985                    parser.consume_token(Token::RParen)?;
986                }
987                let match_type = if parser.skip_keyword(Keyword::MATCH).is_some() {
988                    match &parser.token {
989                        Token::Ident(_, Keyword::FULL) => {
990                            Some(ForeignKeyMatch::Full(parser.consume()))
991                        }
992                        Token::Ident(_, Keyword::SIMPLE) => {
993                            Some(ForeignKeyMatch::Simple(parser.consume()))
994                        }
995                        Token::Ident(_, Keyword::PARTIAL) => {
996                            Some(ForeignKeyMatch::Partial(parser.consume()))
997                        }
998                        _ => None,
999                    }
1000                } else {
1001                    None
1002                };
1003                let mut ons = Vec::new();
1004                while parser.skip_keyword(Keyword::ON).is_some() {
1005                    let on_type = match &parser.token {
1006                        Token::Ident(_, Keyword::UPDATE) => {
1007                            ForeignKeyOnType::Update(parser.consume_keyword(Keyword::UPDATE)?)
1008                        }
1009                        Token::Ident(_, Keyword::DELETE) => {
1010                            ForeignKeyOnType::Delete(parser.consume_keyword(Keyword::DELETE)?)
1011                        }
1012                        _ => parser.expected_failure("UPDATE or DELETE")?,
1013                    };
1014                    let on_action = match &parser.token {
1015                        Token::Ident(_, Keyword::CASCADE) => {
1016                            ForeignKeyOnAction::Cascade(parser.consume_keyword(Keyword::CASCADE)?)
1017                        }
1018                        Token::Ident(_, Keyword::RESTRICT) => {
1019                            ForeignKeyOnAction::Restrict(parser.consume_keyword(Keyword::RESTRICT)?)
1020                        }
1021                        Token::Ident(_, Keyword::SET) => {
1022                            let set_span = parser.consume_keyword(Keyword::SET)?;
1023                            if parser.skip_keyword(Keyword::NULL).is_some() {
1024                                ForeignKeyOnAction::SetNull(set_span)
1025                            } else if parser.skip_keyword(Keyword::DEFAULT).is_some() {
1026                                ForeignKeyOnAction::SetDefault(set_span)
1027                            } else {
1028                                parser.expected_failure("NULL or DEFAULT after SET")?
1029                            }
1030                        }
1031                        Token::Ident(_, Keyword::NO) => {
1032                            let no_span = parser.consume_keyword(Keyword::NO)?;
1033                            parser.consume_keyword(Keyword::ACTION)?;
1034                            ForeignKeyOnAction::NoAction(no_span)
1035                        }
1036                        _ => parser.expected_failure(
1037                            "CASCADE, RESTRICT, SET NULL, SET DEFAULT, or NO ACTION",
1038                        )?,
1039                    };
1040                    ons.push(ForeignKeyOn {
1041                        type_: on_type,
1042                        action: on_action,
1043                    });
1044                }
1045                properties.push(DataTypeProperty::References {
1046                    span,
1047                    table,
1048                    columns,
1049                    match_type,
1050                    ons,
1051                });
1052            }
1053
1054            // End of properties (or property not valid in this context)
1055            _ => break,
1056        }
1057    }
1058    Ok(DataType {
1059        identifier,
1060        type_,
1061        properties,
1062    })
1063}