@@ -1830,7 +1830,7 @@ impl<'a> Parser<'a> {
18301830 uses_odbc_syntax: false,
18311831 }))
18321832 }
1833- DataType::Custom(..) => parser_err!("dummy", loc),
1833+ DataType::Custom(..) | DataType::CustomMultiWord(..) => parser_err!("dummy", loc),
18341834 // MySQL supports using the `BINARY` keyword as a cast to binary type.
18351835 DataType::Binary(..) if self.dialect.supports_binary_kw_as_cast() => {
18361836 Ok(Expr::Cast {
@@ -9630,7 +9630,9 @@ impl<'a> Parser<'a> {
96309630 | Keyword::GENERATED
96319631 | Keyword::AS
96329632 ),
9633- _ => true, // e.g. comma immediately after column name
9633+ // A single-quoted string is a valid type name in SQLite's ids grammar.
9634+ Token::SingleQuotedString(_) => false,
9635+ _ => true,
96349636 }
96359637 } else {
96369638 false
@@ -13351,13 +13353,21 @@ impl<'a> Parser<'a> {
1335113353 }
1335213354 }
1335313355 Keyword::SIGNED => {
13356+ if self.dialect.supports_multiword_type_names() {
13357+ self.prev_token();
13358+ return self.parse_multiword_type_name();
13359+ }
1335413360 if self.parse_keyword(Keyword::INTEGER) {
1335513361 Ok(DataType::SignedInteger)
1335613362 } else {
1335713363 Ok(DataType::Signed)
1335813364 }
1335913365 }
1336013366 Keyword::UNSIGNED => {
13367+ if self.dialect.supports_multiword_type_names() {
13368+ self.prev_token();
13369+ return self.parse_multiword_type_name();
13370+ }
1336113371 if self.parse_keyword(Keyword::INTEGER) {
1336213372 Ok(DataType::UnsignedInteger)
1336313373 } else {
@@ -13372,6 +13382,9 @@ impl<'a> Parser<'a> {
1337213382 }
1337313383 _ => {
1337413384 self.prev_token();
13385+ if self.dialect.supports_multiword_type_names() {
13386+ return self.parse_multiword_type_name();
13387+ }
1337513388 let type_name = self.parse_object_name(false)?;
1337613389 if let Some(modifiers) = self.parse_optional_type_modifiers()? {
1337713390 Ok(DataType::Custom(type_name, modifiers))
@@ -13380,6 +13393,10 @@ impl<'a> Parser<'a> {
1338013393 }
1338113394 }
1338213395 },
13396+ Token::SingleQuotedString(_) if self.dialect.supports_multiword_type_names() => {
13397+ self.prev_token();
13398+ return self.parse_multiword_type_name();
13399+ }
1338313400 _ => self.expected_at("a data type name", next_token_index),
1338413401 }?;
1338513402
@@ -14511,6 +14528,125 @@ impl<'a> Parser<'a> {
1451114528 }
1451214529 }
1451314530
14531+ /// Parse a space-separated multi-word typename per SQLite's `typename` grammar.
14532+ fn parse_multiword_type_name(
14533+ &mut self,
14534+ ) -> Result<(DataType, MatchedTrailingBracket), ParserError> {
14535+ let mut parts: Vec<Ident> = vec![];
14536+ let first = self.next_token();
14537+ match first.token {
14538+ Token::Word(w) => parts.push(w.into_ident(first.span)),
14539+ Token::SingleQuotedString(s) => parts.push(Ident::with_quote('\'', s)),
14540+ _ => return self.expected("a data type name", first),
14541+ }
14542+ loop {
14543+ let can_extend = {
14544+ let peeked = self.peek_token_ref();
14545+ match &peeked.token {
14546+ Token::Word(w) if w.keyword == Keyword::GENERATED => {
14547+ // `GENERATED` starts a constraint only when followed
14548+ // by `ALWAYS`, otherwise it is a type name word.
14549+ !matches!(
14550+ self.peek_nth_token(1).token,
14551+ Token::Word(w) if w.keyword == Keyword::ALWAYS
14552+ )
14553+ }
14554+ Token::Word(w) => {
14555+ // Fully-reserved keywords end the type name, see
14556+ // <https://www.sqlite.org/lang_keywords.html>
14557+ !matches!(
14558+ w.keyword,
14559+ Keyword::ADD
14560+ | Keyword::ALL
14561+ | Keyword::ALTER
14562+ | Keyword::AND
14563+ | Keyword::AS
14564+ | Keyword::AUTOINCREMENT
14565+ | Keyword::BETWEEN
14566+ | Keyword::CASE
14567+ | Keyword::CHECK
14568+ | Keyword::COLLATE
14569+ | Keyword::COMMIT
14570+ | Keyword::CONSTRAINT
14571+ | Keyword::CREATE
14572+ | Keyword::CROSS
14573+ | Keyword::DEFAULT
14574+ | Keyword::DELETE
14575+ | Keyword::DEFERRABLE
14576+ | Keyword::DISTINCT
14577+ | Keyword::DROP
14578+ | Keyword::ELSE
14579+ | Keyword::ESCAPE
14580+ | Keyword::EXCEPT
14581+ | Keyword::EXISTS
14582+ | Keyword::FOREIGN
14583+ | Keyword::FROM
14584+ | Keyword::FULL
14585+ | Keyword::GROUP
14586+ | Keyword::HAVING
14587+ | Keyword::IN
14588+ | Keyword::INDEX
14589+ | Keyword::INNER
14590+ | Keyword::INSERT
14591+ | Keyword::INTERSECT
14592+ | Keyword::INTO
14593+ | Keyword::IS
14594+ | Keyword::JOIN
14595+ | Keyword::LEFT
14596+ | Keyword::LIMIT
14597+ | Keyword::NATURAL
14598+ | Keyword::NOT
14599+ | Keyword::NULL
14600+ | Keyword::NOTHING
14601+ | Keyword::NOTNULL
14602+ | Keyword::ON
14603+ | Keyword::OR
14604+ | Keyword::ORDER
14605+ | Keyword::OUTER
14606+ | Keyword::PRIMARY
14607+ | Keyword::REFERENCES
14608+ | Keyword::RETURNING
14609+ | Keyword::RIGHT
14610+ | Keyword::SELECT
14611+ | Keyword::SET
14612+ | Keyword::TABLE
14613+ | Keyword::THEN
14614+ | Keyword::TO
14615+ | Keyword::TRANSACTION
14616+ | Keyword::UNIQUE
14617+ | Keyword::UNION
14618+ | Keyword::UPDATE
14619+ | Keyword::USING
14620+ | Keyword::VALUES
14621+ | Keyword::WHEN
14622+ | Keyword::WHERE
14623+ )
14624+ }
14625+ Token::SingleQuotedString(_) => true,
14626+ _ => false,
14627+ }
14628+ };
14629+ if !can_extend {
14630+ break;
14631+ }
14632+ let next = self.next_token();
14633+ match next.token {
14634+ Token::Word(w) => parts.push(w.into_ident(next.span)),
14635+ Token::SingleQuotedString(s) => parts.push(Ident::with_quote('\'', s)),
14636+ _ => break,
14637+ }
14638+ }
14639+ let modifiers = self.parse_optional_type_modifiers()?.unwrap_or_default();
14640+ if parts.len() == 1 {
14641+ Ok((
14642+ DataType::Custom(ObjectName::from(vec![parts.remove(0)]), modifiers),
14643+ false.into(),
14644+ ))
14645+ } else {
14646+ Ok((DataType::CustomMultiWord(parts, modifiers), false.into()))
14647+ }
14648+ }
14649+
1451414650 fn parse_structured_object_type_def(&mut self) -> Result<Vec<ColumnDef>, ParserError> {
1451514651 self.expect_token(&Token::LParen)?;
1451614652 if self.consume_token(&Token::RParen) {
0 commit comments