iffyio commented on code in PR #2062:
URL:
https://github.com/apache/datafusion-sqlparser-rs/pull/2062#discussion_r2419535421
##########
src/ast/mod.rs:
##########
@@ -655,6 +655,40 @@ pub enum CastKind {
DoubleColon,
}
+/// The MATCH option for foreign key constraints.
+///
+/// Specifies how to match composite foreign keys against the referenced table.
+/// A value inserted into the referencing column(s) is matched against the
values
+/// of the referenced table and referenced columns using the given match type.
Review Comment:
```suggestion
/// `MATCH` type for constraint references
```
We can avoid defining semantics and leave the description generic so that it
can be reused correctly in other context (like table constraint references)
##########
src/ast/mod.rs:
##########
@@ -655,6 +655,40 @@ pub enum CastKind {
DoubleColon,
}
+/// The MATCH option for foreign key constraints.
+///
+/// Specifies how to match composite foreign keys against the referenced table.
+/// A value inserted into the referencing column(s) is matched against the
values
+/// of the referenced table and referenced columns using the given match type.
+///
+/// See:
<https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-REFERENCES>
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum MatchKind {
Review Comment:
```suggestion
pub enum ConstraintReferenceMatchKind {
```
Thinking `MATCH` might be too generic and likely to conflict naming wise in
other contexts as a result
##########
src/parser/mod.rs:
##########
@@ -7929,22 +7929,22 @@ impl<'a> Parser<'a> {
loop {
if self.parse_keyword(Keyword::CONSTRAINT) {
let name = Some(self.parse_identifier()?);
- if let Some(option) = self.parse_optional_column_option()? {
+ if let Some(option) =
self.parse_optional_column_option(&col_name)? {
Review Comment:
not sure what this change implies, it looks like we'd be storing the column
name twice in the AST node which doesn't seem ideal?
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
Review Comment:
```suggestion
```
The comment read superfluous since the fact should be clear from the test
name
##########
src/ast/mod.rs:
##########
@@ -655,6 +655,40 @@ pub enum CastKind {
DoubleColon,
}
+/// The MATCH option for foreign key constraints.
+///
+/// Specifies how to match composite foreign keys against the referenced table.
+/// A value inserted into the referencing column(s) is matched against the
values
+/// of the referenced table and referenced columns using the given match type.
+///
+/// See:
<https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-REFERENCES>
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum MatchKind {
+ /// `MATCH FULL` - Will not allow one column of a multicolumn foreign key
to be null
+ /// unless all foreign key columns are null; if they are all null, the row
is not
+ /// required to have a match in the referenced table.
+ Full,
+ /// `MATCH PARTIAL` - Not yet implemented by most databases (part of SQL
standard).
+ /// Would allow partial matches in multicolumn foreign keys.
+ Partial,
+ /// `MATCH SIMPLE` - The default behavior. Allows any of the foreign key
columns
+ /// to be null; if any of them are null, the row is not required to have a
match
+ /// in the referenced table.
Review Comment:
```suggestion
/// `MATCH FULL`
Full,
/// `MATCH PARTIAL`
Partial,
/// `MATCH SIMPLE`
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_simple() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH SIMPLE, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH SIMPLE)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH SIMPLE
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH PARTIAL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_partial() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH PARTIAL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH PARTIAL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH PARTIAL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind,
Some(MatchKind::Partial));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH PARTIAL
Review Comment:
```suggestion
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
Review Comment:
```suggestion
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_simple() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH SIMPLE, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH SIMPLE)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH SIMPLE
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH PARTIAL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_partial() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH PARTIAL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH PARTIAL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH PARTIAL
Review Comment:
```suggestion
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_simple() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH SIMPLE, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH SIMPLE)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH SIMPLE
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH PARTIAL` syntax for foreign keys is parsed
correctly.
Review Comment:
```suggestion
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_simple() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH SIMPLE, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH SIMPLE)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH SIMPLE
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH PARTIAL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_partial() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH PARTIAL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH PARTIAL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH PARTIAL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind,
Some(MatchKind::Partial));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH PARTIAL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind,
Some(MatchKind::Partial));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify foreign key MATCH syntax combined with ON DELETE/ON UPDATE
actions
Review Comment:
```suggestion
```
##########
tests/sqlparser_postgres.rs:
##########
@@ -6646,3 +6647,144 @@ fn parse_alter_schema() {
_ => unreachable!(),
}
}
+
+#[test]
+/// Test to verify whether `MATCH FULL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_full() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH FULL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH FULL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH FULL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH SIMPLE` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_simple() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH SIMPLE, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH SIMPLE)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH SIMPLE
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify whether `MATCH PARTIAL` syntax for foreign keys is parsed
correctly.
+fn parse_foreign_key_match_partial() {
+ let sql = "CREATE TABLE orders (order_id INT PRIMARY KEY REFERENCES
another_table (id) MATCH PARTIAL, customer_id INT, FOREIGN KEY (customer_id)
REFERENCES customers(customer_id) MATCH PARTIAL)";
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH PARTIAL
+ assert_eq!(columns[0].name.value, "order_id");
+ match &columns[0].options[1].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind,
Some(MatchKind::Partial));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH PARTIAL
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind,
Some(MatchKind::Partial));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
+}
+
+#[test]
+/// Test to verify foreign key MATCH syntax combined with ON DELETE/ON UPDATE
actions
+fn parse_foreign_key_match_with_actions() {
+ let sql = "CREATE TABLE orders (order_id INT REFERENCES another_table (id)
MATCH FULL ON DELETE CASCADE ON UPDATE RESTRICT, customer_id INT, CONSTRAINT
fk_customer FOREIGN KEY (customer_id) REFERENCES customers(customer_id) MATCH
SIMPLE ON DELETE SET NULL ON UPDATE CASCADE)";
+
+ let statement = pg_and_generic().verified_stmt(sql);
+ match statement {
+ Statement::CreateTable(CreateTable {
+ columns,
+ constraints,
+ ..
+ }) => {
+ // Check column-level foreign key with MATCH FULL and actions
+ match &columns[0].options[0].option {
+ ColumnOption::ForeignKey(constraint) => {
+ assert_eq!(constraint.foreign_table.to_string(),
"another_table");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Full));
+ assert_eq!(constraint.on_delete,
Some(ReferentialAction::Cascade));
+ assert_eq!(constraint.on_update,
Some(ReferentialAction::Restrict));
+ }
+ _ => panic!("Expected ColumnOption::ForeignKey"),
+ }
+
+ // Check table-level foreign key constraint with MATCH SIMPLE and
actions
+ match &constraints[0] {
+ TableConstraint::ForeignKey(constraint) => {
+ assert_eq!(constraint.name.as_ref().unwrap().value,
"fk_customer");
+ assert_eq!(constraint.foreign_table.to_string(),
"customers");
+ assert_eq!(constraint.match_kind, Some(MatchKind::Simple));
+ assert_eq!(constraint.on_delete,
Some(ReferentialAction::SetNull));
+ assert_eq!(constraint.on_update,
Some(ReferentialAction::Cascade));
+ }
+ _ => panic!("Expected TableConstraint::ForeignKey"),
+ }
+ }
+ _ => unreachable!("{:?} should parse to Statement::CreateTable", sql),
+ }
Review Comment:
```suggestion
pg_and_generic().verified_stmt(sql);
```
I think in scenarios like these where we want to verify more complicated
combinations (or different variant of the same component) and each component
has already been asserted previously we can rely solely on the verified_stmt
assertions to keep the tests leaner. Similarly, given that we've asserted the
returned AST on say `MATCH FULL` test scenario, we can rely on verified_stmt
only for the othe variants like `MATCH SIMPLE/PARTIAL`. Leads to significantly
less test code to maintain going forward
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]