mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-11 14:32:04 +00:00
Implements DROP POLICY syntax for PostgreSQL (#1445)
This commit is contained in:
parent
08fc6d3813
commit
2af981e4e6
3 changed files with 98 additions and 11 deletions
|
@ -2546,6 +2546,16 @@ pub enum Statement {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
storage_specifier: Option<Ident>,
|
storage_specifier: Option<Ident>,
|
||||||
},
|
},
|
||||||
|
///```sql
|
||||||
|
/// DROP POLICY
|
||||||
|
/// ```
|
||||||
|
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-droppolicy.html)
|
||||||
|
DropPolicy {
|
||||||
|
if_exists: bool,
|
||||||
|
name: Ident,
|
||||||
|
table_name: ObjectName,
|
||||||
|
option: Option<ReferentialAction>,
|
||||||
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// DECLARE
|
/// DECLARE
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -4258,6 +4268,22 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Statement::DropPolicy {
|
||||||
|
if_exists,
|
||||||
|
name,
|
||||||
|
table_name,
|
||||||
|
option,
|
||||||
|
} => {
|
||||||
|
write!(f, "DROP POLICY")?;
|
||||||
|
if *if_exists {
|
||||||
|
write!(f, " IF EXISTS")?;
|
||||||
|
}
|
||||||
|
write!(f, " {name} ON {table_name}")?;
|
||||||
|
if let Some(option) = option {
|
||||||
|
write!(f, " {option}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Statement::Discard { object_type } => {
|
Statement::Discard { object_type } => {
|
||||||
write!(f, "DISCARD {object_type}")?;
|
write!(f, "DISCARD {object_type}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4887,6 +4887,8 @@ impl<'a> Parser<'a> {
|
||||||
ObjectType::Stage
|
ObjectType::Stage
|
||||||
} else if self.parse_keyword(Keyword::FUNCTION) {
|
} else if self.parse_keyword(Keyword::FUNCTION) {
|
||||||
return self.parse_drop_function();
|
return self.parse_drop_function();
|
||||||
|
} else if self.parse_keyword(Keyword::POLICY) {
|
||||||
|
return self.parse_drop_policy();
|
||||||
} else if self.parse_keyword(Keyword::PROCEDURE) {
|
} else if self.parse_keyword(Keyword::PROCEDURE) {
|
||||||
return self.parse_drop_procedure();
|
return self.parse_drop_procedure();
|
||||||
} else if self.parse_keyword(Keyword::SECRET) {
|
} else if self.parse_keyword(Keyword::SECRET) {
|
||||||
|
@ -4928,6 +4930,14 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_optional_referential_action(&mut self) -> Option<ReferentialAction> {
|
||||||
|
match self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]) {
|
||||||
|
Some(Keyword::CASCADE) => Some(ReferentialAction::Cascade),
|
||||||
|
Some(Keyword::RESTRICT) => Some(ReferentialAction::Restrict),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...]
|
/// DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...]
|
||||||
/// [ CASCADE | RESTRICT ]
|
/// [ CASCADE | RESTRICT ]
|
||||||
|
@ -4935,11 +4945,7 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_drop_function(&mut self) -> Result<Statement, ParserError> {
|
fn parse_drop_function(&mut self) -> Result<Statement, ParserError> {
|
||||||
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||||
let func_desc = self.parse_comma_separated(Parser::parse_function_desc)?;
|
let func_desc = self.parse_comma_separated(Parser::parse_function_desc)?;
|
||||||
let option = match self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]) {
|
let option = self.parse_optional_referential_action();
|
||||||
Some(Keyword::CASCADE) => Some(ReferentialAction::Cascade),
|
|
||||||
Some(Keyword::RESTRICT) => Some(ReferentialAction::Restrict),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
Ok(Statement::DropFunction {
|
Ok(Statement::DropFunction {
|
||||||
if_exists,
|
if_exists,
|
||||||
func_desc,
|
func_desc,
|
||||||
|
@ -4947,6 +4953,25 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ```sql
|
||||||
|
/// DROP POLICY [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-droppolicy.html)
|
||||||
|
fn parse_drop_policy(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||||
|
let name = self.parse_identifier(false)?;
|
||||||
|
self.expect_keyword(Keyword::ON)?;
|
||||||
|
let table_name = self.parse_object_name(false)?;
|
||||||
|
let option = self.parse_optional_referential_action();
|
||||||
|
Ok(Statement::DropPolicy {
|
||||||
|
if_exists,
|
||||||
|
name,
|
||||||
|
table_name,
|
||||||
|
option,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// DROP PROCEDURE [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...]
|
/// DROP PROCEDURE [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...]
|
||||||
/// [ CASCADE | RESTRICT ]
|
/// [ CASCADE | RESTRICT ]
|
||||||
|
@ -4954,12 +4979,7 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_drop_procedure(&mut self) -> Result<Statement, ParserError> {
|
fn parse_drop_procedure(&mut self) -> Result<Statement, ParserError> {
|
||||||
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||||
let proc_desc = self.parse_comma_separated(Parser::parse_function_desc)?;
|
let proc_desc = self.parse_comma_separated(Parser::parse_function_desc)?;
|
||||||
let option = match self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]) {
|
let option = self.parse_optional_referential_action();
|
||||||
Some(Keyword::CASCADE) => Some(ReferentialAction::Cascade),
|
|
||||||
Some(Keyword::RESTRICT) => Some(ReferentialAction::Restrict),
|
|
||||||
Some(_) => unreachable!(), // parse_one_of_keywords does not return other keywords
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
Ok(Statement::DropProcedure {
|
Ok(Statement::DropProcedure {
|
||||||
if_exists,
|
if_exists,
|
||||||
proc_desc,
|
proc_desc,
|
||||||
|
|
|
@ -11089,3 +11089,44 @@ fn test_create_policy() {
|
||||||
"sql parser error: Expected: (, found: EOF"
|
"sql parser error: Expected: (, found: EOF"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drop_policy() {
|
||||||
|
let sql = "DROP POLICY IF EXISTS my_policy ON my_table RESTRICT";
|
||||||
|
match all_dialects().verified_stmt(sql) {
|
||||||
|
Statement::DropPolicy {
|
||||||
|
if_exists,
|
||||||
|
name,
|
||||||
|
table_name,
|
||||||
|
option,
|
||||||
|
} => {
|
||||||
|
assert_eq!(if_exists, true);
|
||||||
|
assert_eq!(name.to_string(), "my_policy");
|
||||||
|
assert_eq!(table_name.to_string(), "my_table");
|
||||||
|
assert_eq!(option, Some(ReferentialAction::Restrict));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// omit IF EXISTS is allowed
|
||||||
|
all_dialects().verified_stmt("DROP POLICY my_policy ON my_table CASCADE");
|
||||||
|
// omit option is allowed
|
||||||
|
all_dialects().verified_stmt("DROP POLICY my_policy ON my_table");
|
||||||
|
|
||||||
|
// missing table name
|
||||||
|
assert_eq!(
|
||||||
|
all_dialects()
|
||||||
|
.parse_sql_statements("DROP POLICY my_policy")
|
||||||
|
.unwrap_err()
|
||||||
|
.to_string(),
|
||||||
|
"sql parser error: Expected: ON, found: EOF"
|
||||||
|
);
|
||||||
|
// Wrong option name
|
||||||
|
assert_eq!(
|
||||||
|
all_dialects()
|
||||||
|
.parse_sql_statements("DROP POLICY my_policy ON my_table WRONG")
|
||||||
|
.unwrap_err()
|
||||||
|
.to_string(),
|
||||||
|
"sql parser error: Expected: end of statement, found: WRONG"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue