Skip to content

Commit 777a166

Browse files
Support NO INHERIT modifier on CHECK constraints (apache#2435)
1 parent 80a211f commit 777a166

5 files changed

Lines changed: 63 additions & 6 deletions

File tree

src/ast/ddl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1939,7 +1939,7 @@ pub enum ColumnOption {
19391939
/// [<constraint_characteristics>]
19401940
/// `).
19411941
ForeignKey(ForeignKeyConstraint),
1942-
/// `CHECK (<expr>)`
1942+
/// `CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`
19431943
Check(CheckConstraint),
19441944
/// Dialect-specific options, such as:
19451945
/// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`

src/ast/table_constraints.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub enum TableConstraint {
7878
/// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
7979
/// }`).
8080
ForeignKey(ForeignKeyConstraint),
81-
/// `[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`
81+
/// `[ CONSTRAINT <name> ] CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`
8282
Check(CheckConstraint),
8383
/// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
8484
/// is restricted to MySQL, as no other dialects that support this syntax were found.
@@ -186,12 +186,15 @@ impl fmt::Display for TableConstraint {
186186
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
187187
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
188188
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
189-
/// A `CHECK` constraint (`[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`).
189+
/// A `CHECK` constraint (`[ CONSTRAINT <name> ] CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`).
190190
pub struct CheckConstraint {
191191
/// Optional constraint name.
192192
pub name: Option<Ident>,
193193
/// The boolean expression the CHECK constraint enforces.
194194
pub expr: Box<Expr>,
195+
/// PostgreSQL-specific `NO INHERIT` flag: child tables do not inherit the constraint.
196+
/// <https://www.postgresql.org/docs/current/sql-createtable.html>
197+
pub no_inherit: bool,
195198
/// MySQL-specific `ENFORCED` / `NOT ENFORCED` flag.
196199
/// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
197200
pub enforced: Option<bool>,
@@ -206,11 +209,13 @@ impl fmt::Display for CheckConstraint {
206209
display_constraint_name(&self.name),
207210
self.expr
208211
)?;
212+
if self.no_inherit {
213+
write!(f, " NO INHERIT")?;
214+
}
209215
if let Some(b) = self.enforced {
210-
write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })
211-
} else {
212-
Ok(())
216+
write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })?;
213217
}
218+
Ok(())
214219
}
215220
}
216221

src/parser/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9695,6 +9695,7 @@ impl<'a> Parser<'a> {
96959695
// since `CHECK` requires parentheses, we can parse the inner expression in ParserState::Normal
96969696
let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_expr())?;
96979697
self.expect_token(&Token::RParen)?;
9698+
let no_inherit = self.parse_keywords(&[Keyword::NO, Keyword::INHERIT]);
96989699

96999700
let enforced = if self.parse_keyword(Keyword::ENFORCED) {
97009701
Some(true)
@@ -9708,6 +9709,7 @@ impl<'a> Parser<'a> {
97089709
CheckConstraint {
97099710
name: None, // Column-level check constraints don't have names
97109711
expr: Box::new(expr),
9712+
no_inherit,
97119713
enforced,
97129714
}
97139715
.into(),
@@ -10171,6 +10173,7 @@ impl<'a> Parser<'a> {
1017110173
self.expect_token(&Token::LParen)?;
1017210174
let expr = Box::new(self.parse_expr()?);
1017310175
self.expect_token(&Token::RParen)?;
10176+
let no_inherit = self.parse_keywords(&[Keyword::NO, Keyword::INHERIT]);
1017410177

1017510178
let enforced = if self.parse_keyword(Keyword::ENFORCED) {
1017610179
Some(true)
@@ -10184,6 +10187,7 @@ impl<'a> Parser<'a> {
1018410187
CheckConstraint {
1018510188
name,
1018610189
expr,
10190+
no_inherit,
1018710191
enforced,
1018810192
}
1018910193
.into(),

tests/sqlparser_common.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3998,6 +3998,7 @@ fn parse_create_table() {
39983998
option: ColumnOption::Check(CheckConstraint {
39993999
name: None,
40004000
expr: Box::new(verified_expr("constrained > 0")),
4001+
no_inherit: false,
40014002
enforced: None,
40024003
}),
40034004
},
@@ -17594,6 +17595,19 @@ fn column_check_enforced() {
1759417595
);
1759517596
}
1759617597

17598+
#[test]
17599+
fn table_check_no_inherit() {
17600+
all_dialects().verified_stmt("CREATE TABLE t (a INT, CONSTRAINT c CHECK (a > 0) NO INHERIT)");
17601+
all_dialects().verified_stmt("CREATE TABLE t (a INT, CHECK (a > 0) NO INHERIT)");
17602+
all_dialects().verified_stmt("CREATE TABLE t (a INT, CHECK (a > 0) NO INHERIT NOT ENFORCED)");
17603+
}
17604+
17605+
#[test]
17606+
fn column_check_no_inherit() {
17607+
all_dialects().verified_stmt("CREATE TABLE t (x INT CHECK (x > 1) NO INHERIT)");
17608+
all_dialects().verified_stmt("CREATE TABLE t (x INT CHECK (x > 1) NO INHERIT NOT ENFORCED)");
17609+
}
17610+
1759717611
#[test]
1759817612
fn join_precedence() {
1759917613
all_dialects().verified_query_with_canonical(

tests/sqlparser_postgres.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6546,6 +6546,7 @@ fn parse_create_domain() {
65466546
op: BinaryOperator::Gt,
65476547
right: Box::new(Expr::Value(test_utils::number("0").into())),
65486548
}),
6549+
no_inherit: false,
65496550
enforced: None,
65506551
}
65516552
.into()],
@@ -6566,6 +6567,7 @@ fn parse_create_domain() {
65666567
op: BinaryOperator::Gt,
65676568
right: Box::new(Expr::Value(test_utils::number("0").into())),
65686569
}),
6570+
no_inherit: false,
65696571
enforced: None,
65706572
}
65716573
.into()],
@@ -6586,6 +6588,7 @@ fn parse_create_domain() {
65866588
op: BinaryOperator::Gt,
65876589
right: Box::new(Expr::Value(test_utils::number("0").into())),
65886590
}),
6591+
no_inherit: false,
65896592
enforced: None,
65906593
}
65916594
.into()],
@@ -6606,6 +6609,7 @@ fn parse_create_domain() {
66066609
op: BinaryOperator::Gt,
66076610
right: Box::new(Expr::Value(test_utils::number("0").into())),
66086611
}),
6612+
no_inherit: false,
66096613
enforced: None,
66106614
}
66116615
.into()],
@@ -6626,6 +6630,7 @@ fn parse_create_domain() {
66266630
op: BinaryOperator::Gt,
66276631
right: Box::new(Expr::Value(test_utils::number("0").into())),
66286632
}),
6633+
no_inherit: false,
66296634
enforced: None,
66306635
}
66316636
.into()],
@@ -9818,3 +9823,32 @@ fn parse_quoted_argument_names_in_function_signatures() {
98189823
}])
98199824
);
98209825
}
9826+
9827+
#[test]
9828+
fn parse_alter_table_constraint_check_no_inherit() {
9829+
match pg_and_generic()
9830+
.verified_stmt("ALTER TABLE docs ADD CONSTRAINT c CHECK (id > 0) NO INHERIT NOT VALID")
9831+
{
9832+
Statement::AlterTable(AlterTable { operations, .. }) => {
9833+
assert_eq!(
9834+
operations,
9835+
vec![AlterTableOperation::AddConstraint {
9836+
constraint: CheckConstraint {
9837+
name: Some("c".into()),
9838+
expr: Box::new(Expr::BinaryOp {
9839+
left: Box::new(Expr::Identifier(Ident::new("id"))),
9840+
op: BinaryOperator::Gt,
9841+
right: Box::new(Expr::Value(test_utils::number("0").into())),
9842+
}),
9843+
no_inherit: true,
9844+
enforced: None,
9845+
}
9846+
.into(),
9847+
not_valid: true,
9848+
}]
9849+
);
9850+
}
9851+
_ => unreachable!(),
9852+
}
9853+
pg_and_generic().verified_stmt("ALTER TABLE docs ADD CONSTRAINT c CHECK (id > 0) NO INHERIT");
9854+
}

0 commit comments

Comments
 (0)