Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1939,7 +1939,7 @@ pub enum ColumnOption {
/// [<constraint_characteristics>]
/// `).
ForeignKey(ForeignKeyConstraint),
/// `CHECK (<expr>)`
/// `CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`
Check(CheckConstraint),
/// Dialect-specific options, such as:
/// - MySQL's `AUTO_INCREMENT` or SQLite's `AUTOINCREMENT`
Expand Down
15 changes: 10 additions & 5 deletions src/ast/table_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub enum TableConstraint {
/// [ON UPDATE <referential_action>] [ON DELETE <referential_action>]
/// }`).
ForeignKey(ForeignKeyConstraint),
/// `[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`
/// `[ CONSTRAINT <name> ] CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`
Check(CheckConstraint),
/// MySQLs [index definition][1] for index creation. Not present on ANSI so, for now, the usage
/// is restricted to MySQL, as no other dialects that support this syntax were found.
Expand Down Expand Up @@ -186,12 +186,15 @@ impl fmt::Display for TableConstraint {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
/// A `CHECK` constraint (`[ CONSTRAINT <name> ] CHECK (<expr>) [[NOT] ENFORCED]`).
/// A `CHECK` constraint (`[ CONSTRAINT <name> ] CHECK (<expr>) [NO INHERIT] [[NOT] ENFORCED]`).
pub struct CheckConstraint {
/// Optional constraint name.
pub name: Option<Ident>,
/// The boolean expression the CHECK constraint enforces.
pub expr: Box<Expr>,
/// PostgreSQL-specific `NO INHERIT` flag: child tables do not inherit the constraint.
/// <https://www.postgresql.org/docs/current/sql-createtable.html>
pub no_inherit: bool,
/// MySQL-specific `ENFORCED` / `NOT ENFORCED` flag.
/// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html>
pub enforced: Option<bool>,
Expand All @@ -206,11 +209,13 @@ impl fmt::Display for CheckConstraint {
display_constraint_name(&self.name),
self.expr
)?;
if self.no_inherit {
write!(f, " NO INHERIT")?;
}
if let Some(b) = self.enforced {
write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })
} else {
Ok(())
write!(f, " {}", if b { "ENFORCED" } else { "NOT ENFORCED" })?;
}
Ok(())
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9672,6 +9672,7 @@ impl<'a> Parser<'a> {
// since `CHECK` requires parentheses, we can parse the inner expression in ParserState::Normal
let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_expr())?;
self.expect_token(&Token::RParen)?;
let no_inherit = self.parse_keywords(&[Keyword::NO, Keyword::INHERIT]);

let enforced = if self.parse_keyword(Keyword::ENFORCED) {
Some(true)
Expand All @@ -9685,6 +9686,7 @@ impl<'a> Parser<'a> {
CheckConstraint {
name: None, // Column-level check constraints don't have names
expr: Box::new(expr),
no_inherit,
enforced,
}
.into(),
Expand Down Expand Up @@ -10148,6 +10150,7 @@ impl<'a> Parser<'a> {
self.expect_token(&Token::LParen)?;
let expr = Box::new(self.parse_expr()?);
self.expect_token(&Token::RParen)?;
let no_inherit = self.parse_keywords(&[Keyword::NO, Keyword::INHERIT]);

let enforced = if self.parse_keyword(Keyword::ENFORCED) {
Some(true)
Expand All @@ -10161,6 +10164,7 @@ impl<'a> Parser<'a> {
CheckConstraint {
name,
expr,
no_inherit,
enforced,
}
.into(),
Expand Down
14 changes: 14 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3983,6 +3983,7 @@ fn parse_create_table() {
option: ColumnOption::Check(CheckConstraint {
name: None,
expr: Box::new(verified_expr("constrained > 0")),
no_inherit: false,
enforced: None,
}),
},
Expand Down Expand Up @@ -17579,6 +17580,19 @@ fn column_check_enforced() {
);
}

#[test]
fn table_check_no_inherit() {
all_dialects().verified_stmt("CREATE TABLE t (a INT, CONSTRAINT c CHECK (a > 0) NO INHERIT)");
all_dialects().verified_stmt("CREATE TABLE t (a INT, CHECK (a > 0) NO INHERIT)");
all_dialects().verified_stmt("CREATE TABLE t (a INT, CHECK (a > 0) NO INHERIT NOT ENFORCED)");
}

#[test]
fn column_check_no_inherit() {
all_dialects().verified_stmt("CREATE TABLE t (x INT CHECK (x > 1) NO INHERIT)");
all_dialects().verified_stmt("CREATE TABLE t (x INT CHECK (x > 1) NO INHERIT NOT ENFORCED)");
}

#[test]
fn join_precedence() {
all_dialects().verified_query_with_canonical(
Expand Down
34 changes: 34 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6531,6 +6531,7 @@ fn parse_create_domain() {
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: false,
enforced: None,
}
.into()],
Expand All @@ -6551,6 +6552,7 @@ fn parse_create_domain() {
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: false,
enforced: None,
}
.into()],
Expand All @@ -6571,6 +6573,7 @@ fn parse_create_domain() {
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: false,
enforced: None,
}
.into()],
Expand All @@ -6591,6 +6594,7 @@ fn parse_create_domain() {
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: false,
enforced: None,
}
.into()],
Expand All @@ -6611,6 +6615,7 @@ fn parse_create_domain() {
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: false,
enforced: None,
}
.into()],
Expand Down Expand Up @@ -9663,3 +9668,32 @@ fn parse_right_deep_join_chain() {
// NATURAL JOIN followed by a constrained join must stay left-associative.
pg().verified_stmt("SELECT * FROM t0 NATURAL JOIN t1 INNER JOIN t2 ON true");
}

#[test]
fn parse_alter_table_constraint_check_no_inherit() {
match pg_and_generic()
.verified_stmt("ALTER TABLE docs ADD CONSTRAINT c CHECK (id > 0) NO INHERIT NOT VALID")
{
Statement::AlterTable(AlterTable { operations, .. }) => {
assert_eq!(
operations,
vec![AlterTableOperation::AddConstraint {
constraint: CheckConstraint {
name: Some("c".into()),
expr: Box::new(Expr::BinaryOp {
left: Box::new(Expr::Identifier(Ident::new("id"))),
op: BinaryOperator::Gt,
right: Box::new(Expr::Value(test_utils::number("0").into())),
}),
no_inherit: true,
enforced: None,
}
.into(),
not_valid: true,
}]
);
}
_ => unreachable!(),
}
pg_and_generic().verified_stmt("ALTER TABLE docs ADD CONSTRAINT c CHECK (id > 0) NO INHERIT");
}
Loading