mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-28 09:54:15 +00:00
Support MySQL UNIQUE
table constraint (#1164)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
6da8828c1b
commit
8f67d1a713
4 changed files with 441 additions and 94 deletions
|
@ -500,63 +500,186 @@ fn parse_create_table_auto_increment() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_unique_key() {
|
||||
let sql = "CREATE TABLE foo (id INT PRIMARY KEY AUTO_INCREMENT, bar INT NOT NULL, UNIQUE KEY bar_key (bar))";
|
||||
let canonical = "CREATE TABLE foo (id INT PRIMARY KEY AUTO_INCREMENT, bar INT NOT NULL, CONSTRAINT bar_key UNIQUE (bar))";
|
||||
match mysql().one_statement_parses_to(sql, canonical) {
|
||||
Statement::CreateTable {
|
||||
/// if `unique_index_type_display` is `Some` create `TableConstraint::Unique`
|
||||
/// otherwise create `TableConstraint::Primary`
|
||||
fn table_constraint_unique_primary_ctor(
|
||||
name: Option<Ident>,
|
||||
index_name: Option<Ident>,
|
||||
index_type: Option<IndexType>,
|
||||
columns: Vec<Ident>,
|
||||
index_options: Vec<IndexOption>,
|
||||
characteristics: Option<ConstraintCharacteristics>,
|
||||
unique_index_type_display: Option<KeyOrIndexDisplay>,
|
||||
) -> TableConstraint {
|
||||
match unique_index_type_display {
|
||||
Some(index_type_display) => TableConstraint::Unique {
|
||||
name,
|
||||
index_name,
|
||||
index_type_display,
|
||||
index_type,
|
||||
columns,
|
||||
constraints,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(name.to_string(), "foo");
|
||||
assert_eq!(
|
||||
vec![TableConstraint::Unique {
|
||||
name: Some(Ident::new("bar_key")),
|
||||
columns: vec![Ident::new("bar")],
|
||||
is_primary: false,
|
||||
characteristics: None,
|
||||
}],
|
||||
constraints
|
||||
);
|
||||
assert_eq!(
|
||||
vec![
|
||||
ColumnDef {
|
||||
name: Ident::new("id"),
|
||||
data_type: DataType::Int(None),
|
||||
collation: None,
|
||||
options: vec![
|
||||
ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Unique {
|
||||
is_primary: true,
|
||||
characteristics: None
|
||||
index_options,
|
||||
characteristics,
|
||||
},
|
||||
None => TableConstraint::PrimaryKey {
|
||||
name,
|
||||
index_name,
|
||||
index_type,
|
||||
columns,
|
||||
index_options,
|
||||
characteristics,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_primary_and_unique_key() {
|
||||
let sqls = ["UNIQUE KEY", "PRIMARY KEY"]
|
||||
.map(|key_ty|format!("CREATE TABLE foo (id INT PRIMARY KEY AUTO_INCREMENT, bar INT NOT NULL, CONSTRAINT bar_key {key_ty} (bar))"));
|
||||
|
||||
let index_type_display = [Some(KeyOrIndexDisplay::Key), None];
|
||||
|
||||
for (sql, index_type_display) in sqls.iter().zip(index_type_display) {
|
||||
match mysql().one_statement_parses_to(sql, "") {
|
||||
Statement::CreateTable {
|
||||
name,
|
||||
columns,
|
||||
constraints,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(name.to_string(), "foo");
|
||||
|
||||
let expected_constraint = table_constraint_unique_primary_ctor(
|
||||
Some(Ident::new("bar_key")),
|
||||
None,
|
||||
None,
|
||||
vec![Ident::new("bar")],
|
||||
vec![],
|
||||
None,
|
||||
index_type_display,
|
||||
);
|
||||
assert_eq!(vec![expected_constraint], constraints);
|
||||
|
||||
assert_eq!(
|
||||
vec![
|
||||
ColumnDef {
|
||||
name: Ident::new("id"),
|
||||
data_type: DataType::Int(None),
|
||||
collation: None,
|
||||
options: vec![
|
||||
ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::Unique {
|
||||
is_primary: true,
|
||||
characteristics: None
|
||||
},
|
||||
},
|
||||
},
|
||||
ColumnOptionDef {
|
||||
ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::DialectSpecific(vec![
|
||||
Token::make_keyword("AUTO_INCREMENT")
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
ColumnDef {
|
||||
name: Ident::new("bar"),
|
||||
data_type: DataType::Int(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::DialectSpecific(vec![Token::make_keyword(
|
||||
"AUTO_INCREMENT"
|
||||
)]),
|
||||
},
|
||||
],
|
||||
},
|
||||
ColumnDef {
|
||||
name: Ident::new("bar"),
|
||||
data_type: DataType::Int(None),
|
||||
collation: None,
|
||||
options: vec![ColumnOptionDef {
|
||||
name: None,
|
||||
option: ColumnOption::NotNull,
|
||||
},],
|
||||
},
|
||||
],
|
||||
columns
|
||||
);
|
||||
option: ColumnOption::NotNull,
|
||||
},],
|
||||
},
|
||||
],
|
||||
columns
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_primary_and_unique_key_with_index_options() {
|
||||
let sqls = ["UNIQUE INDEX", "PRIMARY KEY"]
|
||||
.map(|key_ty|format!("CREATE TABLE foo (bar INT, var INT, CONSTRAINT constr {key_ty} index_name (bar, var) USING HASH COMMENT 'yes, ' USING BTREE COMMENT 'MySQL allows')"));
|
||||
|
||||
let index_type_display = [Some(KeyOrIndexDisplay::Index), None];
|
||||
|
||||
for (sql, index_type_display) in sqls.iter().zip(index_type_display) {
|
||||
match mysql_and_generic().one_statement_parses_to(sql, "") {
|
||||
Statement::CreateTable {
|
||||
name, constraints, ..
|
||||
} => {
|
||||
assert_eq!(name.to_string(), "foo");
|
||||
|
||||
let expected_constraint = table_constraint_unique_primary_ctor(
|
||||
Some(Ident::new("constr")),
|
||||
Some(Ident::new("index_name")),
|
||||
None,
|
||||
vec![Ident::new("bar"), Ident::new("var")],
|
||||
vec![
|
||||
IndexOption::Using(IndexType::Hash),
|
||||
IndexOption::Comment("yes, ".into()),
|
||||
IndexOption::Using(IndexType::BTree),
|
||||
IndexOption::Comment("MySQL allows".into()),
|
||||
],
|
||||
None,
|
||||
index_type_display,
|
||||
);
|
||||
assert_eq!(vec![expected_constraint], constraints);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
mysql_and_generic().verified_stmt(sql);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_primary_and_unique_key_with_index_type() {
|
||||
let sqls = ["UNIQUE", "PRIMARY KEY"].map(|key_ty| {
|
||||
format!("CREATE TABLE foo (bar INT, {key_ty} index_name USING BTREE (bar) USING HASH)")
|
||||
});
|
||||
|
||||
let index_type_display = [Some(KeyOrIndexDisplay::None), None];
|
||||
|
||||
for (sql, index_type_display) in sqls.iter().zip(index_type_display) {
|
||||
match mysql_and_generic().one_statement_parses_to(sql, "") {
|
||||
Statement::CreateTable {
|
||||
name, constraints, ..
|
||||
} => {
|
||||
assert_eq!(name.to_string(), "foo");
|
||||
|
||||
let expected_constraint = table_constraint_unique_primary_ctor(
|
||||
None,
|
||||
Some(Ident::new("index_name")),
|
||||
Some(IndexType::BTree),
|
||||
vec![Ident::new("bar")],
|
||||
vec![IndexOption::Using(IndexType::Hash)],
|
||||
None,
|
||||
index_type_display,
|
||||
);
|
||||
assert_eq!(vec![expected_constraint], constraints);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
mysql_and_generic().verified_stmt(sql);
|
||||
}
|
||||
|
||||
let sql = "CREATE TABLE foo (bar INT, UNIQUE INDEX index_name USING BTREE (bar) USING HASH)";
|
||||
mysql_and_generic().verified_stmt(sql);
|
||||
let sql = "CREATE TABLE foo (bar INT, PRIMARY KEY index_name USING BTREE (bar) USING HASH)";
|
||||
mysql_and_generic().verified_stmt(sql);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_primary_and_unique_key_characteristic_test() {
|
||||
let sqls = ["UNIQUE INDEX", "PRIMARY KEY"]
|
||||
.map(|key_ty|format!("CREATE TABLE x (y INT, CONSTRAINT constr {key_ty} (y) NOT DEFERRABLE INITIALLY IMMEDIATE)"));
|
||||
for sql in &sqls {
|
||||
mysql_and_generic().verified_stmt(sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2333,6 +2456,15 @@ fn parse_create_table_with_index_definition() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_unallow_constraint_then_index() {
|
||||
let sql = "CREATE TABLE foo (bar INT, CONSTRAINT constr INDEX index (bar))";
|
||||
assert!(mysql_and_generic().parse_sql_statements(sql).is_err());
|
||||
|
||||
let sql = "CREATE TABLE foo (bar INT, INDEX index (bar))";
|
||||
assert!(mysql_and_generic().parse_sql_statements(sql).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_with_fulltext_definition() {
|
||||
mysql_and_generic().verified_stmt("CREATE TABLE tb (id INT, FULLTEXT (id))");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue