Skip to content

Commit 2c6c295

Browse files
authored
Refactor <column definition> parsing (#251)
2 parents 1b46e82 + 66505eb commit 2c6c295

File tree

2 files changed

+56
-44
lines changed

2 files changed

+56
-44
lines changed

src/parser.rs

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,29 +1191,6 @@ impl<'a> Parser<'a> {
11911191
})
11921192
}
11931193

1194-
fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
1195-
let name = self.parse_identifier()?;
1196-
let data_type = self.parse_data_type()?;
1197-
let collation = if self.parse_keyword(Keyword::COLLATE) {
1198-
Some(self.parse_object_name()?)
1199-
} else {
1200-
None
1201-
};
1202-
let mut options = vec![];
1203-
loop {
1204-
match self.peek_token() {
1205-
Token::EOF | Token::Comma | Token::RParen | Token::SemiColon => break,
1206-
_ => options.push(self.parse_column_option_def()?),
1207-
}
1208-
}
1209-
Ok(ColumnDef {
1210-
name,
1211-
data_type,
1212-
collation,
1213-
options,
1214-
})
1215-
}
1216-
12171194
fn parse_columns(&mut self) -> Result<(Vec<ColumnDef>, Vec<TableConstraint>), ParserError> {
12181195
let mut columns = vec![];
12191196
let mut constraints = vec![];
@@ -1225,8 +1202,7 @@ impl<'a> Parser<'a> {
12251202
if let Some(constraint) = self.parse_optional_table_constraint()? {
12261203
constraints.push(constraint);
12271204
} else if let Token::Word(_) = self.peek_token() {
1228-
let column_def = self.parse_column_def()?;
1229-
columns.push(column_def);
1205+
columns.push(self.parse_column_def()?);
12301206
} else {
12311207
return self.expected("column name or constraint definition", self.peek_token());
12321208
}
@@ -1242,23 +1218,51 @@ impl<'a> Parser<'a> {
12421218
Ok((columns, constraints))
12431219
}
12441220

1245-
pub fn parse_column_option_def(&mut self) -> Result<ColumnOptionDef, ParserError> {
1246-
let name = if self.parse_keyword(Keyword::CONSTRAINT) {
1247-
Some(self.parse_identifier()?)
1221+
fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
1222+
let name = self.parse_identifier()?;
1223+
let data_type = self.parse_data_type()?;
1224+
let collation = if self.parse_keyword(Keyword::COLLATE) {
1225+
Some(self.parse_object_name()?)
12481226
} else {
12491227
None
12501228
};
1229+
let mut options = vec![];
1230+
loop {
1231+
if self.parse_keyword(Keyword::CONSTRAINT) {
1232+
let name = Some(self.parse_identifier()?);
1233+
if let Some(option) = self.parse_optional_column_option()? {
1234+
options.push(ColumnOptionDef { name, option });
1235+
} else {
1236+
return self.expected(
1237+
"constraint details after CONSTRAINT <name>",
1238+
self.peek_token(),
1239+
);
1240+
}
1241+
} else if let Some(option) = self.parse_optional_column_option()? {
1242+
options.push(ColumnOptionDef { name: None, option });
1243+
} else {
1244+
break;
1245+
};
1246+
}
1247+
Ok(ColumnDef {
1248+
name,
1249+
data_type,
1250+
collation,
1251+
options,
1252+
})
1253+
}
12511254

1252-
let option = if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) {
1253-
ColumnOption::NotNull
1255+
pub fn parse_optional_column_option(&mut self) -> Result<Option<ColumnOption>, ParserError> {
1256+
if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) {
1257+
Ok(Some(ColumnOption::NotNull))
12541258
} else if self.parse_keyword(Keyword::NULL) {
1255-
ColumnOption::Null
1259+
Ok(Some(ColumnOption::Null))
12561260
} else if self.parse_keyword(Keyword::DEFAULT) {
1257-
ColumnOption::Default(self.parse_expr()?)
1261+
Ok(Some(ColumnOption::Default(self.parse_expr()?)))
12581262
} else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) {
1259-
ColumnOption::Unique { is_primary: true }
1263+
Ok(Some(ColumnOption::Unique { is_primary: true }))
12601264
} else if self.parse_keyword(Keyword::UNIQUE) {
1261-
ColumnOption::Unique { is_primary: false }
1265+
Ok(Some(ColumnOption::Unique { is_primary: false }))
12621266
} else if self.parse_keyword(Keyword::REFERENCES) {
12631267
let foreign_table = self.parse_object_name()?;
12641268
// PostgreSQL allows omitting the column list and
@@ -1277,32 +1281,34 @@ impl<'a> Parser<'a> {
12771281
break;
12781282
}
12791283
}
1280-
ColumnOption::ForeignKey {
1284+
Ok(Some(ColumnOption::ForeignKey {
12811285
foreign_table,
12821286
referred_columns,
12831287
on_delete,
12841288
on_update,
1285-
}
1289+
}))
12861290
} else if self.parse_keyword(Keyword::CHECK) {
12871291
self.expect_token(&Token::LParen)?;
12881292
let expr = self.parse_expr()?;
12891293
self.expect_token(&Token::RParen)?;
1290-
ColumnOption::Check(expr)
1294+
Ok(Some(ColumnOption::Check(expr)))
12911295
} else if self.parse_keyword(Keyword::AUTO_INCREMENT)
12921296
&& dialect_of!(self is MySqlDialect | GenericDialect)
12931297
{
12941298
// Support AUTO_INCREMENT for MySQL
1295-
ColumnOption::DialectSpecific(vec![Token::make_keyword("AUTO_INCREMENT")])
1299+
Ok(Some(ColumnOption::DialectSpecific(vec![
1300+
Token::make_keyword("AUTO_INCREMENT"),
1301+
])))
12961302
} else if self.parse_keyword(Keyword::AUTOINCREMENT)
12971303
&& dialect_of!(self is SQLiteDialect | GenericDialect)
12981304
{
12991305
// Support AUTOINCREMENT for SQLite
1300-
ColumnOption::DialectSpecific(vec![Token::make_keyword("AUTOINCREMENT")])
1306+
Ok(Some(ColumnOption::DialectSpecific(vec![
1307+
Token::make_keyword("AUTOINCREMENT"),
1308+
])))
13011309
} else {
1302-
return self.expected("column option", self.peek_token());
1303-
};
1304-
1305-
Ok(ColumnOptionDef { name, option })
1310+
Ok(None)
1311+
}
13061312
}
13071313

13081314
pub fn parse_referential_action(&mut self) -> Result<ReferentialAction, ParserError> {

tests/sqlparser_common.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,13 @@ fn parse_create_table() {
11421142
assert!(res
11431143
.unwrap_err()
11441144
.to_string()
1145-
.contains("Expected column option, found: GARBAGE"));
1145+
.contains("Expected \',\' or \')\' after column definition, found: GARBAGE"));
1146+
1147+
let res = parse_sql_statements("CREATE TABLE t (a int NOT NULL CONSTRAINT foo)");
1148+
assert!(res
1149+
.unwrap_err()
1150+
.to_string()
1151+
.contains("Expected constraint details after CONSTRAINT <name>"));
11461152
}
11471153

11481154
#[test]

0 commit comments

Comments
 (0)