Skip to content

Commit 93fc0d1

Browse files
nom-sql: Fix regression in parsing UNIQUE KEY() USING syntax
This commit fixes a regression where surpisingly, the combination of opt(preceded(whitespace0, deferrable(dialect))) will consume the whitespaces even if the deferrable will not match, causing the next parser, in this case the using clause, to fail as it requires at least one whitespace. Fixes: REA-5221 Fixes #1421 Release-Note-Core: Fix regression in parsing UNIQUE KEY() USING syntax for MySQL. Change-Id: Iea06c57c222c901df67bbc5c608af5db8add3fac Reviewed-on: https://gerrit.readyset.name/c/readyset/+/8641 Tested-by: Buildkite CI Reviewed-by: Johnathan Davis <jcd@readyset.io>
1 parent 7c3e0b1 commit 93fc0d1

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

nom-sql/src/create.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ fn primary_key(dialect: Dialect) -> impl Fn(LocatedSpan<&[u8]>) -> NomSqlResult<
536536
preceded(whitespace1, tag_no_case("auto_increment")),
537537
|_| (),
538538
)),
539-
opt(preceded(whitespace1, deferrable(dialect))),
539+
opt(deferrable(dialect, true)),
540540
))(i)?;
541541
let constraint_timing = constraint_timing.unwrap_or(None);
542542

@@ -693,11 +693,17 @@ fn nulls_distinct(
693693

694694
fn deferrable(
695695
dialect: Dialect,
696+
require_whitespace: bool,
696697
) -> impl Fn(LocatedSpan<&[u8]>) -> NomSqlResult<&[u8], Option<ConstraintTiming>> {
697698
move |i| {
698699
if dialect != Dialect::PostgreSQL {
699700
return Ok((i, None));
700701
}
702+
let (i, _) = if require_whitespace {
703+
whitespace1(i)?
704+
} else {
705+
whitespace0(i)?
706+
};
701707
alt((
702708
move |i| {
703709
let (i, _) = tag_no_case("not")(i)?;
@@ -782,7 +788,7 @@ fn unique(dialect: Dialect) -> impl Fn(LocatedSpan<&[u8]>) -> NomSqlResult<&[u8]
782788
tag(")"),
783789
),
784790
)(i)?;
785-
let (i, constraint_timing) = opt(preceded(whitespace0, deferrable(dialect)))(i)?;
791+
let (i, constraint_timing) = opt(deferrable(dialect, false))(i)?;
786792
let constraint_timing = constraint_timing.unwrap_or(None);
787793
let (i, index_type) = opt(using_index)(i)?;
788794
debug_print("after unique", &i);
@@ -1717,7 +1723,38 @@ mod tests {
17171723
}),
17181724
options: Ok(vec![CreateTableOption::AutoIncrement(1001)],)
17191725
}
1720-
)
1726+
);
1727+
// index type
1728+
let qstring = "CREATE TABLE users (id bigint(20), name varchar(255), email varchar(255), \
1729+
UNIQUE KEY id_k (id) USING HASH);";
1730+
1731+
let res = create_table(Dialect::MySQL)(LocatedSpan::new(qstring.as_bytes()));
1732+
assert_eq!(
1733+
res.unwrap().1,
1734+
CreateTableStatement {
1735+
if_not_exists: false,
1736+
table: Relation::from("users"),
1737+
body: Ok(CreateTableBody {
1738+
fields: vec![
1739+
ColumnSpecification::new(Column::from("id"), SqlType::BigInt(Some(20))),
1740+
ColumnSpecification::new(Column::from("name"), SqlType::VarChar(Some(255))),
1741+
ColumnSpecification::new(
1742+
Column::from("email"),
1743+
SqlType::VarChar(Some(255))
1744+
),
1745+
],
1746+
keys: Some(vec![TableKey::UniqueKey {
1747+
constraint_name: None,
1748+
constraint_timing: None,
1749+
index_name: Some("id_k".into()),
1750+
columns: vec![Column::from("id")],
1751+
index_type: Some(IndexType::Hash),
1752+
nulls_distinct: None,
1753+
}]),
1754+
}),
1755+
options: Ok(vec![]),
1756+
}
1757+
);
17211758
}
17221759

17231760
#[test]

0 commit comments

Comments
 (0)