This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 7efa686d Extend snowflake grant options support (#1794)
7efa686d is described below
commit 7efa686d7800dbe5a09a25c12980a7086a58d9aa
Author: Yoav Cohen <[email protected]>
AuthorDate: Thu Apr 3 19:52:23 2025 +0200
Extend snowflake grant options support (#1794)
---
src/ast/mod.rs | 55 ++++++++++++++++++++++++++++++++++++++++----
src/keywords.rs | 1 +
src/parser/mod.rs | 50 +++++++++++++++++++++++++++++-----------
tests/sqlparser_snowflake.rs | 39 ++++++++++++++++++++++++++++++-
4 files changed, 126 insertions(+), 19 deletions(-)
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index f187df99..9456991e 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -6079,10 +6079,10 @@ pub enum Action {
ManageReleases,
ManageVersions,
Modify {
- modify_type: ActionModifyType,
+ modify_type: Option<ActionModifyType>,
},
Monitor {
- monitor_type: ActionMonitorType,
+ monitor_type: Option<ActionMonitorType>,
},
Operate,
OverrideShareRestrictions,
@@ -6115,7 +6115,7 @@ impl fmt::Display for Action {
match self {
Action::AddSearchOptimization => f.write_str("ADD SEARCH
OPTIMIZATION")?,
Action::Apply { apply_type } => write!(f, "APPLY {apply_type}")?,
- Action::ApplyBudget => f.write_str("APPLY BUDGET")?,
+ Action::ApplyBudget => f.write_str("APPLYBUDGET")?,
Action::AttachListing => f.write_str("ATTACH LISTING")?,
Action::AttachPolicy => f.write_str("ATTACH POLICY")?,
Action::Audit => f.write_str("AUDIT")?,
@@ -6143,8 +6143,18 @@ impl fmt::Display for Action {
Action::Manage { manage_type } => write!(f, "MANAGE
{manage_type}")?,
Action::ManageReleases => f.write_str("MANAGE RELEASES")?,
Action::ManageVersions => f.write_str("MANAGE VERSIONS")?,
- Action::Modify { modify_type } => write!(f, "MODIFY
{modify_type}")?,
- Action::Monitor { monitor_type } => write!(f, "MONITOR
{monitor_type}")?,
+ Action::Modify { modify_type } => {
+ write!(f, "MODIFY")?;
+ if let Some(modify_type) = modify_type {
+ write!(f, " {modify_type}")?;
+ }
+ }
+ Action::Monitor { monitor_type } => {
+ write!(f, "MONITOR")?;
+ if let Some(monitor_type) = monitor_type {
+ write!(f, " {monitor_type}")?
+ }
+ }
Action::Operate => f.write_str("OPERATE")?,
Action::OverrideShareRestrictions => f.write_str("OVERRIDE SHARE
RESTRICTIONS")?,
Action::Ownership => f.write_str("OWNERSHIP")?,
@@ -6462,6 +6472,20 @@ pub enum GrantObjects {
Warehouses(Vec<ObjectName>),
/// Grant privileges on specific integrations
Integrations(Vec<ObjectName>),
+ /// Grant privileges on resource monitors
+ ResourceMonitors(Vec<ObjectName>),
+ /// Grant privileges on users
+ Users(Vec<ObjectName>),
+ /// Grant privileges on compute pools
+ ComputePools(Vec<ObjectName>),
+ /// Grant privileges on connections
+ Connections(Vec<ObjectName>),
+ /// Grant privileges on failover groups
+ FailoverGroup(Vec<ObjectName>),
+ /// Grant privileges on replication group
+ ReplicationGroup(Vec<ObjectName>),
+ /// Grant privileges on external volumes
+ ExternalVolumes(Vec<ObjectName>),
}
impl fmt::Display for GrantObjects {
@@ -6502,6 +6526,27 @@ impl fmt::Display for GrantObjects {
display_comma_separated(schemas)
)
}
+ GrantObjects::ResourceMonitors(objects) => {
+ write!(f, "RESOURCE MONITOR {}",
display_comma_separated(objects))
+ }
+ GrantObjects::Users(objects) => {
+ write!(f, "USER {}", display_comma_separated(objects))
+ }
+ GrantObjects::ComputePools(objects) => {
+ write!(f, "COMPUTE POOL {}", display_comma_separated(objects))
+ }
+ GrantObjects::Connections(objects) => {
+ write!(f, "CONNECTION {}", display_comma_separated(objects))
+ }
+ GrantObjects::FailoverGroup(objects) => {
+ write!(f, "FAILOVER GROUP {}",
display_comma_separated(objects))
+ }
+ GrantObjects::ReplicationGroup(objects) => {
+ write!(f, "REPLICATION GROUP {}",
display_comma_separated(objects))
+ }
+ GrantObjects::ExternalVolumes(objects) => {
+ write!(f, "EXTERNAL VOLUME {}",
display_comma_separated(objects))
+ }
}
}
}
diff --git a/src/keywords.rs b/src/keywords.rs
index 8609ec43..1aa2190c 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -738,6 +738,7 @@ define_keywords!(
REPLICATION,
RESET,
RESOLVE,
+ RESOURCE,
RESPECT,
RESTART,
RESTRICT,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 2b61529f..40d6b0ac 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -12875,6 +12875,26 @@ impl<'a> Parser<'a> {
Some(GrantObjects::AllSequencesInSchema {
schemas: self.parse_comma_separated(|p|
p.parse_object_name(false))?,
})
+ } else if self.parse_keywords(&[Keyword::RESOURCE,
Keyword::MONITOR]) {
+ Some(GrantObjects::ResourceMonitors(self.parse_comma_separated(
+ |p| p.parse_object_name_with_wildcards(false, true),
+ )?))
+ } else if self.parse_keywords(&[Keyword::COMPUTE, Keyword::POOL]) {
+ Some(GrantObjects::ComputePools(self.parse_comma_separated(
+ |p| p.parse_object_name_with_wildcards(false, true),
+ )?))
+ } else if self.parse_keywords(&[Keyword::FAILOVER,
Keyword::GROUP]) {
+ Some(GrantObjects::FailoverGroup(self.parse_comma_separated(
+ |p| p.parse_object_name_with_wildcards(false, true),
+ )?))
+ } else if self.parse_keywords(&[Keyword::REPLICATION,
Keyword::GROUP]) {
+ Some(GrantObjects::ReplicationGroup(self.parse_comma_separated(
+ |p| p.parse_object_name_with_wildcards(false, true),
+ )?))
+ } else if self.parse_keywords(&[Keyword::EXTERNAL,
Keyword::VOLUME]) {
+ Some(GrantObjects::ExternalVolumes(self.parse_comma_separated(
+ |p| p.parse_object_name_with_wildcards(false, true),
+ )?))
} else {
let object_type = self.parse_one_of_keywords(&[
Keyword::SEQUENCE,
@@ -12888,6 +12908,8 @@ impl<'a> Parser<'a> {
Keyword::VIEW,
Keyword::WAREHOUSE,
Keyword::INTEGRATION,
+ Keyword::USER,
+ Keyword::CONNECTION,
]);
let objects =
self.parse_comma_separated(|p|
p.parse_object_name_with_wildcards(false, true));
@@ -12898,6 +12920,8 @@ impl<'a> Parser<'a> {
Some(Keyword::WAREHOUSE) =>
Some(GrantObjects::Warehouses(objects?)),
Some(Keyword::INTEGRATION) =>
Some(GrantObjects::Integrations(objects?)),
Some(Keyword::VIEW) => Some(GrantObjects::Views(objects?)),
+ Some(Keyword::USER) => Some(GrantObjects::Users(objects?)),
+ Some(Keyword::CONNECTION) =>
Some(GrantObjects::Connections(objects?)),
Some(Keyword::TABLE) | None =>
Some(GrantObjects::Tables(objects?)),
_ => unreachable!(),
}
@@ -12983,10 +13007,10 @@ impl<'a> Parser<'a> {
let manage_type = self.parse_action_manage_type()?;
Ok(Action::Manage { manage_type })
} else if self.parse_keyword(Keyword::MODIFY) {
- let modify_type = self.parse_action_modify_type()?;
+ let modify_type = self.parse_action_modify_type();
Ok(Action::Modify { modify_type })
} else if self.parse_keyword(Keyword::MONITOR) {
- let monitor_type = self.parse_action_monitor_type()?;
+ let monitor_type = self.parse_action_monitor_type();
Ok(Action::Monitor { monitor_type })
} else if self.parse_keyword(Keyword::OPERATE) {
Ok(Action::Operate)
@@ -13127,29 +13151,29 @@ impl<'a> Parser<'a> {
}
}
- fn parse_action_modify_type(&mut self) -> Result<ActionModifyType,
ParserError> {
+ fn parse_action_modify_type(&mut self) -> Option<ActionModifyType> {
if self.parse_keywords(&[Keyword::LOG, Keyword::LEVEL]) {
- Ok(ActionModifyType::LogLevel)
+ Some(ActionModifyType::LogLevel)
} else if self.parse_keywords(&[Keyword::TRACE, Keyword::LEVEL]) {
- Ok(ActionModifyType::TraceLevel)
+ Some(ActionModifyType::TraceLevel)
} else if self.parse_keywords(&[Keyword::SESSION, Keyword::LOG,
Keyword::LEVEL]) {
- Ok(ActionModifyType::SessionLogLevel)
+ Some(ActionModifyType::SessionLogLevel)
} else if self.parse_keywords(&[Keyword::SESSION, Keyword::TRACE,
Keyword::LEVEL]) {
- Ok(ActionModifyType::SessionTraceLevel)
+ Some(ActionModifyType::SessionTraceLevel)
} else {
- self.expected("GRANT MODIFY type", self.peek_token())
+ None
}
}
- fn parse_action_monitor_type(&mut self) -> Result<ActionMonitorType,
ParserError> {
+ fn parse_action_monitor_type(&mut self) -> Option<ActionMonitorType> {
if self.parse_keyword(Keyword::EXECUTION) {
- Ok(ActionMonitorType::Execution)
+ Some(ActionMonitorType::Execution)
} else if self.parse_keyword(Keyword::SECURITY) {
- Ok(ActionMonitorType::Security)
+ Some(ActionMonitorType::Security)
} else if self.parse_keyword(Keyword::USAGE) {
- Ok(ActionMonitorType::Usage)
+ Some(ActionMonitorType::Usage)
} else {
- self.expected("GRANT MONITOR type", self.peek_token())
+ None
}
}
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index 097af346..62e52e2d 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -3357,7 +3357,7 @@ fn test_timetravel_at_before() {
}
#[test]
-fn test_grant_account_privileges() {
+fn test_grant_account_global_privileges() {
let privileges = vec![
"ALL",
"ALL PRIVILEGES",
@@ -3462,6 +3462,43 @@ fn test_grant_account_privileges() {
}
}
+#[test]
+fn test_grant_account_object_privileges() {
+ let privileges = vec![
+ "ALL",
+ "ALL PRIVILEGES",
+ "APPLYBUDGET",
+ "MODIFY",
+ "MONITOR",
+ "USAGE",
+ "OPERATE",
+ ];
+
+ let objects_types = vec![
+ "USER",
+ "RESOURCE MONITOR",
+ "WAREHOUSE",
+ "COMPUTE POOL",
+ "DATABASE",
+ "INTEGRATION",
+ "CONNECTION",
+ "FAILOVER GROUP",
+ "REPLICATION GROUP",
+ "EXTERNAL VOLUME",
+ ];
+
+ let with_grant_options = vec!["", " WITH GRANT OPTION"];
+
+ for t in &objects_types {
+ for p in &privileges {
+ for wgo in &with_grant_options {
+ let sql = format!("GRANT {p} ON {t} obj1 TO ROLE role1{wgo}");
+ snowflake_and_generic().verified_stmt(&sql);
+ }
+ }
+ }
+}
+
#[test]
fn test_grant_role_to() {
snowflake_and_generic().verified_stmt("GRANT ROLE r1 TO ROLE r2");
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]