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
44 changes: 44 additions & 0 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5994,3 +5994,47 @@ impl From<AlterPolicy> for crate::ast::Statement {
crate::ast::Statement::AlterPolicy(v)
}
}

/// DROP RULE statement.
///
/// ```sql
/// DROP RULE [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
/// ```
///
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droprule.html)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct DropRule {
/// `true` when `IF EXISTS` was present.
pub if_exists: bool,
/// Name of the rule to drop.
pub name: Ident,
/// Name of the table the rule applies to.
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub table_name: ObjectName,
/// Optional drop behavior (`CASCADE` or `RESTRICT`).
pub drop_behavior: Option<DropBehavior>,
}

impl fmt::Display for DropRule {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DROP RULE {if_exists}{name} ON {table_name}",
if_exists = if self.if_exists { "IF EXISTS " } else { "" },
name = self.name,
table_name = self.table_name
)?;
if let Some(behavior) = &self.drop_behavior {
write!(f, " {behavior}")?;
}
Ok(())
}
}

impl From<DropRule> for crate::ast::Statement {
fn from(v: DropRule) -> Self {
crate::ast::Statement::DropRule(v)
}
}
8 changes: 7 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub use self::ddl::{
CreateOperatorClass, CreateOperatorFamily, CreatePolicy, CreatePolicyCommand, CreatePolicyType,
CreateTable, CreateTextSearch, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
DistStyle, DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorClass,
DropOperatorFamily, DropOperatorSignature, DropPolicy, DropTrigger, ForValues,
DropOperatorFamily, DropOperatorSignature, DropPolicy, DropRule, DropTrigger, ForValues,
FunctionReturnType, GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,
Expand Down Expand Up @@ -4018,6 +4018,11 @@ pub enum Statement {
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
DropPolicy(DropPolicy),
/// ```sql
/// DROP RULE
/// ```
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droprule.html)
DropRule(DropRule),
/// ```sql
/// DROP CONNECTOR
/// ```
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-DropConnector)
Expand Down Expand Up @@ -5797,6 +5802,7 @@ impl fmt::Display for Statement {
Ok(())
}
Statement::DropPolicy(policy) => write!(f, "{policy}"),
Statement::DropRule(rule) => write!(f, "{rule}"),
Statement::DropConnector { if_exists, name } => {
write!(
f,
Expand Down
1 change: 1 addition & 0 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ impl Spanned for Statement {
Statement::AlterPolicy { .. } => Span::empty(),
Statement::AlterConnector { .. } => Span::empty(),
Statement::DropPolicy { .. } => Span::empty(),
Statement::DropRule { .. } => Span::empty(),
Statement::DropConnector { .. } => Span::empty(),
Statement::ShowCatalogs { .. } => Span::empty(),
Statement::ShowDatabases { .. } => Span::empty(),
Expand Down
24 changes: 23 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7607,6 +7607,8 @@ impl<'a> Parser<'a> {
return self.parse_drop_function().map(Into::into);
} else if self.parse_keyword(Keyword::POLICY) {
return self.parse_drop_policy().map(Into::into);
} else if self.parse_keyword(Keyword::RULE) {
return self.parse_drop_rule().map(Into::into);
} else if self.parse_keyword(Keyword::CONNECTOR) {
return self.parse_drop_connector();
} else if self.parse_keyword(Keyword::DOMAIN) {
Expand All @@ -7630,7 +7632,7 @@ impl<'a> Parser<'a> {
};
} else {
return self.expected_ref(
"COLLATION, CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW, USER or WAREHOUSE after DROP",
"COLLATION, CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, RULE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW, USER or WAREHOUSE after DROP",
self.peek_token_ref(),
);
};
Expand Down Expand Up @@ -7710,6 +7712,26 @@ impl<'a> Parser<'a> {
drop_behavior,
})
}

/// ```sql
/// DROP RULE [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
/// ```
///
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-droprule.html)
fn parse_drop_rule(&mut self) -> Result<DropRule, ParserError> {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let name = self.parse_identifier()?;
self.expect_keyword_is(Keyword::ON)?;
let table_name = self.parse_object_name(false)?;
let drop_behavior = self.parse_optional_drop_behavior();
Ok(DropRule {
if_exists,
name,
table_name,
drop_behavior,
})
}

/// ```sql
/// DROP CONNECTOR [IF EXISTS] name
/// ```
Expand Down
31 changes: 31 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19679,3 +19679,34 @@ fn parse_function_arg_call_chain_no_exponential_blowup() {
rx.recv_timeout(Duration::from_secs(5))
.expect("parser should reject this quickly, not loop exponentially");
}

#[test]
fn parse_drop_rule() {
let sql = "DROP RULE r ON t";
match all_dialects().verified_stmt(sql) {
Statement::DropRule(DropRule {
if_exists,
name,
table_name,
drop_behavior,
}) => {
assert!(!if_exists);
assert_eq!(name.to_string(), "r");
assert_eq!(table_name.to_string(), "t");
assert_eq!(drop_behavior, None);
}
_ => unreachable!("Expected DROP RULE"),
}

all_dialects().verified_stmt("DROP RULE IF EXISTS r ON s1.t CASCADE");
all_dialects().verified_stmt("DROP RULE r ON t RESTRICT");

// the table name is mandatory
assert_eq!(
all_dialects()
.parse_sql_statements("DROP RULE r")
.unwrap_err()
.to_string(),
"sql parser error: Expected: ON, found: EOF"
);
}
Loading