Skip to content

Commit 8f1414e

Browse files
authored
Add support for granting privileges to procedures and functions in Snowflake (#1930)
1 parent b1a6d11 commit 8f1414e

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

src/ast/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7023,6 +7023,25 @@ pub enum GrantObjects {
70237023
ReplicationGroup(Vec<ObjectName>),
70247024
/// Grant privileges on external volumes
70257025
ExternalVolumes(Vec<ObjectName>),
7026+
/// Grant privileges on a procedure. In dialects that
7027+
/// support overloading, the argument types must be specified.
7028+
///
7029+
/// For example:
7030+
/// `GRANT USAGE ON PROCEDURE foo(varchar) TO ROLE role1`
7031+
Procedure {
7032+
name: ObjectName,
7033+
arg_types: Vec<DataType>,
7034+
},
7035+
7036+
/// Grant privileges on a function. In dialects that
7037+
/// support overloading, the argument types must be specified.
7038+
///
7039+
/// For example:
7040+
/// `GRANT USAGE ON FUNCTION foo(varchar) TO ROLE role1`
7041+
Function {
7042+
name: ObjectName,
7043+
arg_types: Vec<DataType>,
7044+
},
70267045
}
70277046

70287047
impl fmt::Display for GrantObjects {
@@ -7147,6 +7166,20 @@ impl fmt::Display for GrantObjects {
71477166
GrantObjects::ExternalVolumes(objects) => {
71487167
write!(f, "EXTERNAL VOLUME {}", display_comma_separated(objects))
71497168
}
7169+
GrantObjects::Procedure { name, arg_types } => {
7170+
write!(f, "PROCEDURE {name}")?;
7171+
if !arg_types.is_empty() {
7172+
write!(f, "({})", display_comma_separated(arg_types))?;
7173+
}
7174+
Ok(())
7175+
}
7176+
GrantObjects::Function { name, arg_types } => {
7177+
write!(f, "FUNCTION {name}")?;
7178+
if !arg_types.is_empty() {
7179+
write!(f, "({})", display_comma_separated(arg_types))?;
7180+
}
7181+
Ok(())
7182+
}
71507183
}
71517184
}
71527185
}

src/parser/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14061,6 +14061,8 @@ impl<'a> Parser<'a> {
1406114061
Keyword::INTEGRATION,
1406214062
Keyword::USER,
1406314063
Keyword::CONNECTION,
14064+
Keyword::PROCEDURE,
14065+
Keyword::FUNCTION,
1406414066
]);
1406514067
let objects =
1406614068
self.parse_comma_separated(|p| p.parse_object_name_inner(false, true));
@@ -14073,6 +14075,13 @@ impl<'a> Parser<'a> {
1407314075
Some(Keyword::VIEW) => Some(GrantObjects::Views(objects?)),
1407414076
Some(Keyword::USER) => Some(GrantObjects::Users(objects?)),
1407514077
Some(Keyword::CONNECTION) => Some(GrantObjects::Connections(objects?)),
14078+
kw @ (Some(Keyword::PROCEDURE) | Some(Keyword::FUNCTION)) => {
14079+
if let Some(name) = objects?.first() {
14080+
self.parse_grant_procedure_or_function(name, &kw)?
14081+
} else {
14082+
self.expected("procedure or function name", self.peek_token())?
14083+
}
14084+
}
1407614085
Some(Keyword::TABLE) | None => Some(GrantObjects::Tables(objects?)),
1407714086
_ => unreachable!(),
1407814087
}
@@ -14084,6 +14093,31 @@ impl<'a> Parser<'a> {
1408414093
Ok((privileges, objects))
1408514094
}
1408614095

14096+
fn parse_grant_procedure_or_function(
14097+
&mut self,
14098+
name: &ObjectName,
14099+
kw: &Option<Keyword>,
14100+
) -> Result<Option<GrantObjects>, ParserError> {
14101+
let arg_types = if self.consume_token(&Token::LParen) {
14102+
let list = self.parse_comma_separated0(Self::parse_data_type, Token::RParen)?;
14103+
self.expect_token(&Token::RParen)?;
14104+
list
14105+
} else {
14106+
vec![]
14107+
};
14108+
match kw {
14109+
Some(Keyword::PROCEDURE) => Ok(Some(GrantObjects::Procedure {
14110+
name: name.clone(),
14111+
arg_types,
14112+
})),
14113+
Some(Keyword::FUNCTION) => Ok(Some(GrantObjects::Function {
14114+
name: name.clone(),
14115+
arg_types,
14116+
})),
14117+
_ => self.expected("procedure or function keywords", self.peek_token())?,
14118+
}
14119+
}
14120+
1408714121
pub fn parse_grant_permission(&mut self) -> Result<Action, ParserError> {
1408814122
fn parse_columns(parser: &mut Parser) -> Result<Option<Vec<Ident>>, ParserError> {
1408914123
let columns = parser.parse_parenthesized_column_list(Optional, false)?;

tests/sqlparser_common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9460,6 +9460,8 @@ fn parse_grant() {
94609460
verified_stmt("GRANT SELECT ON FUTURE VIEWS IN SCHEMA db1.sc1 TO ROLE role1");
94619461
verified_stmt("GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA db1.sc1 TO ROLE role1");
94629462
verified_stmt("GRANT SELECT ON FUTURE SEQUENCES IN SCHEMA db1.sc1 TO ROLE role1");
9463+
verified_stmt("GRANT USAGE ON PROCEDURE db1.sc1.foo(INT) TO ROLE role1");
9464+
verified_stmt("GRANT USAGE ON FUNCTION db1.sc1.foo(INT) TO ROLE role1");
94639465
}
94649466

94659467
#[test]

0 commit comments

Comments
 (0)