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
10 changes: 9 additions & 1 deletion src/ast/dcl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,14 @@ impl From<Grant> for crate::ast::Statement {
}

/// REVOKE privileges ON objects FROM grantees
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-revoke.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 Revoke {
/// Whether `GRANT OPTION FOR` is present, withdrawing the right to grant
/// the privileges rather than the privileges themselves.
pub grant_option_for: bool,
/// Privileges to revoke.
pub privileges: Privileges,
/// Optional objects from which to revoke.
Expand All @@ -506,7 +510,11 @@ pub struct Revoke {

impl fmt::Display for Revoke {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "REVOKE {privileges}", privileges = self.privileges)?;
write!(f, "REVOKE ")?;
if self.grant_option_for {
write!(f, "GRANT OPTION FOR ")?;
}
write!(f, "{}", self.privileges)?;
if let Some(ref objects) = self.objects {
write!(f, " ON {objects}")?;
}
Expand Down
4 changes: 4 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18339,6 +18339,9 @@ impl<'a> Parser<'a> {

/// Parse a REVOKE statement
pub fn parse_revoke(&mut self) -> Result<Revoke, ParserError> {
let grant_option_for =
self.parse_keywords(&[Keyword::GRANT, Keyword::OPTION, Keyword::FOR]);

let (privileges, objects) = self.parse_grant_deny_revoke_privileges_objects()?;

self.expect_keyword_is(Keyword::FROM)?;
Expand All @@ -18353,6 +18356,7 @@ impl<'a> Parser<'a> {
let cascade = self.parse_cascade_option();

Ok(Revoke {
grant_option_for,
privileges,
objects,
grantees,
Expand Down
24 changes: 23 additions & 1 deletion tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10096,6 +10096,7 @@ fn test_revoke() {
let sql = "REVOKE ALL PRIVILEGES ON users, auth FROM analyst";
match verified_stmt(sql) {
Statement::Revoke(Revoke {
grant_option_for: false,
privileges,
objects: Some(GrantObjects::Tables(tables)),
grantees,
Expand All @@ -10120,8 +10121,9 @@ fn test_revoke() {
#[test]
fn test_revoke_with_cascade() {
let sql = "REVOKE ALL PRIVILEGES ON users, auth FROM analyst CASCADE";
match all_dialects_except(|d| d.is::<MySqlDialect>()).verified_stmt(sql) {
match verified_stmt(sql) {
Statement::Revoke(Revoke {
grant_option_for: false,
privileges,
objects: Some(GrantObjects::Tables(tables)),
grantees,
Expand All @@ -10143,6 +10145,26 @@ fn test_revoke_with_cascade() {
}
}

#[test]
fn test_revoke_grant_option_for() {
let Statement::Revoke(mut revoke) = verified_stmt("REVOKE GRANT OPTION FOR SELECT ON t FROM r")
else {
unreachable!()
};
assert!(revoke.grant_option_for);

// Clearing the flag must yield exactly the plain revoke.
revoke.grant_option_for = false;
assert_eq!(
Statement::Revoke(revoke),
verified_stmt("REVOKE SELECT ON t FROM r")
);

verified_stmt("REVOKE GRANT OPTION FOR ALL ON t FROM r");
verified_stmt("REVOKE GRANT OPTION FOR SELECT ON t FROM r CASCADE");
verified_stmt("REVOKE GRANT OPTION FOR SELECT ON t FROM r RESTRICT");
}

#[test]
fn parse_merge() {
let sql = "MERGE INTO s.bar AS dest USING (SELECT * FROM s.foo) AS stg ON dest.D = stg.D AND dest.E = stg.E WHEN NOT MATCHED THEN INSERT (A, B, C) VALUES (stg.A, stg.B, stg.C) WHEN MATCHED AND dest.A = 'a' THEN UPDATE SET dest.F = stg.F, dest.G = stg.G WHEN MATCHED THEN DELETE";
Expand Down
1 change: 1 addition & 0 deletions tests/sqlparser_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4013,6 +4013,7 @@ fn parse_revoke() {
let sql = "REVOKE ALL ON db1.* FROM 'jeffrey'@'%'";
let stmt = mysql_and_generic().verified_stmt(sql);
if let Statement::Revoke(Revoke {
grant_option_for: false,
privileges,
objects,
grantees,
Expand Down
Loading