Skip to content

Commit

Permalink
sql: Implement SHOW PRIVILEGES command (#22393)
Browse files Browse the repository at this point in the history
This commit implements a SHOW PRIVILEGES command that allow users to
display all privileges. The command allows optional filtering on object
type or role grantee.

Works towards resolving #20452
  • Loading branch information
jkosh44 authored Oct 16, 2023
1 parent fda6738 commit 32e48bd
Show file tree
Hide file tree
Showing 10 changed files with 479 additions and 2 deletions.
1 change: 1 addition & 0 deletions doc/user/content/sql/grant-privilege.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ The privileges required to execute this statement are:

## Related pages

- [SHOW PRIVILEGES](../show-privileges)
- [CREATE ROLE](../create-role)
- [ALTER ROLE](../alter-role)
- [DROP ROLE](../drop-role)
Expand Down
1 change: 1 addition & 0 deletions doc/user/content/sql/revoke-privilege.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ The privileges required to execute this statement are:

## Related pages

- [SHOW PRIVILEGES](../show-privileges)
- [CREATE ROLE](../create-role)
- [ALTER ROLE](../alter-role)
- [DROP ROLE](../drop-role)
Expand Down
78 changes: 78 additions & 0 deletions doc/user/content/sql/show-privileges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: "SHOW PRIVILEGES"
description: "`SHOW PRIVILEGES` lists the privileges granted in Materialize."
menu:
main:
parent: 'commands'

---

`SHOW PRIVILEGES` lists the privileges granted as part of [access control](/manage/access-control/) in Materialize.

## Syntax

{{< diagram "show-privileges.svg" >}}

Field | Use
----------------------------------------------------|--------------------------------------------------
_object_name_ | Only shows privileges for a specific object type.
_role_name_ | Only shows privileges granted directly or indirectly to _role_name_.

## Examples

```sql
SHOW PRIVILEGES;
```

```nofmt
grantor | grantee | database | schema | name | object_type | privilege_type
-----------+-------------+-------------+--------+-------------+-------------+----------------
mz_system | PUBLIC | materialize | | public | schema | USAGE
mz_system | PUBLIC | | | default | cluster | USAGE
mz_system | PUBLIC | | | materialize | database | USAGE
mz_system | materialize | materialize | | public | schema | CREATE
mz_system | materialize | materialize | | public | schema | USAGE
mz_system | materialize | | | default | cluster | CREATE
mz_system | materialize | | | default | cluster | USAGE
mz_system | materialize | | | materialize | database | CREATE
mz_system | materialize | | | materialize | database | USAGE
mz_system | materialize | | | | system | CREATECLUSTER
mz_system | materialize | | | | system | CREATEDB
mz_system | materialize | | | | system | CREATEROLE
```

```sql
SHOW PRIVILEGES ON SCHEMAS;
```

```nofmt
grantor | grantee | database | schema | name | object_type | privilege_type
-----------+-------------+-------------+--------+--------+-------------+----------------
mz_system | PUBLIC | materialize | | public | schema | USAGE
mz_system | materialize | materialize | | public | schema | CREATE
mz_system | materialize | materialize | | public | schema | USAGE
```

```sql
SHOW PRIVILEGES FOR materialize;
```

```nofmt
grantor | grantee | database | schema | name | object_type | privilege_type
-----------+-------------+-------------+--------+-------------+-------------+----------------
mz_system | materialize | materialize | | public | schema | CREATE
mz_system | materialize | materialize | | public | schema | USAGE
mz_system | materialize | | | default | cluster | CREATE
mz_system | materialize | | | default | cluster | USAGE
mz_system | materialize | | | materialize | database | CREATE
mz_system | materialize | | | materialize | database | USAGE
mz_system | materialize | | | | system | CREATECLUSTER
mz_system | materialize | | | | system | CREATEDB
mz_system | materialize | | | | system | CREATEROLE
```

## Related pages

- [GRANT PRIVILEGE](../grant-privilege)
- [REVOKE PRIVILEGE](../revoke-privilege)
- [access control](/manage/access-control/)
107 changes: 107 additions & 0 deletions doc/user/layouts/partials/sql-grammar/show-privileges.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions doc/user/sql-grammar/sql-grammar.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ show_views ::=
'SHOW' 'VIEWS' ('FROM' schema_name)?
show_objects ::=
'SHOW' 'OBJECTS' ('FROM' schema_name)?
show_privileges ::=
'SHOW' 'PRIVILEGES' ('ON' ('TABLES' | 'TYPES' | 'SECRETS' | 'CONNECTIONS' | 'DATABASES' | 'SCHEMAS' | 'CLUSTERS' | 'SYSTEM'))? ('FOR' role_name)?
string_agg ::=
'string_agg' '(' value ',' delimiter ( 'ORDER' 'BY' col_ref ( 'ASC' | 'DESC' )? ( 'NULLS LAST' | 'NULLS FIRST' )? ( ',' col_ref ( 'ASC' | 'DESC' )? ( 'NULLS LAST' | 'NULLS FIRST' )? )* )? ')' ('FILTER' '(' 'WHERE' filter_clause ')')?
subscribe_stmt ::=
Expand Down
38 changes: 37 additions & 1 deletion src/sql-parser/src/ast/defs/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2448,6 +2448,10 @@ pub enum ShowObjectType<T: AstInfo> {
Subsource {
on_source: Option<T::ItemName>,
},
Privileges {
object_type: Option<SystemObjectType>,
role: Option<T::RoleName>,
},
}
/// `SHOW <object>S`
///
Expand All @@ -2468,6 +2472,7 @@ impl<T: AstInfo> AstDisplay for ShowObjectsStatement<T> {
fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
f.write_str("SHOW");
f.write_str(" ");

f.write_str(match &self.object_type {
ShowObjectType::Table => "TABLES",
ShowObjectType::View => "VIEWS",
Expand All @@ -2485,6 +2490,7 @@ impl<T: AstInfo> AstDisplay for ShowObjectsStatement<T> {
ShowObjectType::Database => "DATABASES",
ShowObjectType::Schema { .. } => "SCHEMAS",
ShowObjectType::Subsource { .. } => "SUBSOURCES",
ShowObjectType::Privileges { .. } => "PRIVILEGES",
});

if let ShowObjectType::Index { on_object, .. } = &self.object_type {
Expand Down Expand Up @@ -2525,6 +2531,20 @@ impl<T: AstInfo> AstDisplay for ShowObjectsStatement<T> {
}
}

if let ShowObjectType::Privileges { object_type, role } = &self.object_type {
if let Some(object_type) = object_type {
f.write_str(" ON ");
f.write_node(object_type);
if let SystemObjectType::Object(_) = object_type {
f.write_str("S");
}
}
if let Some(role) = role {
f.write_str(" FOR ");
f.write_node(role);
}
}

if let Some(filter) = &self.filter {
f.write_str(" ");
f.write_node(filter);
Expand Down Expand Up @@ -2864,7 +2884,7 @@ impl<T: AstInfo> AstDisplay for InsertSource<T> {
}
impl_display_t!(InsertSource);

#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
pub enum ObjectType {
Table,
View,
Expand Down Expand Up @@ -2931,6 +2951,22 @@ impl AstDisplay for ObjectType {
}
impl_display!(ObjectType);

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
pub enum SystemObjectType {
System,
Object(ObjectType),
}

impl AstDisplay for SystemObjectType {
fn fmt<W: fmt::Write>(&self, f: &mut AstFormatter<W>) {
match self {
SystemObjectType::System => f.write_str("SYSTEM"),
SystemObjectType::Object(object) => f.write_node(object),
}
}
}
impl_display!(SystemObjectType);

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ShowStatementFilter<T: AstInfo> {
Like(String),
Expand Down
65 changes: 65 additions & 0 deletions src/sql-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6345,6 +6345,8 @@ impl<'a> Parser<'a> {
Ok(ShowStatement::ShowVariable(ShowVariableStatement {
variable: Ident::from("cluster"),
}))
} else if self.parse_keyword(PRIVILEGES) {
self.parse_show_privileges()
} else if self.parse_keywords(&[CREATE, VIEW]) {
Ok(ShowStatement::ShowCreateView(ShowCreateViewStatement {
view_name: self.parse_raw_name()?,
Expand Down Expand Up @@ -6418,6 +6420,24 @@ impl<'a> Parser<'a> {
}
}

fn parse_show_privileges(&mut self) -> Result<ShowStatement<Raw>, ParserError> {
let object_type = if self.parse_keyword(ON) {
Some(self.expect_plural_system_object_type_for_privileges()?)
} else {
None
};
let role = if self.parse_keyword(FOR) {
Some(self.parse_identifier()?)
} else {
None
};
Ok(ShowStatement::ShowObjects(ShowObjectsStatement {
object_type: ShowObjectType::Privileges { object_type, role },
from: None,
filter: self.parse_show_statement_filter()?,
}))
}

fn parse_inspect(&mut self) -> Result<ShowStatement<Raw>, ParserError> {
self.expect_keyword(SHARD)?;
let id = self.parse_literal_string()?;
Expand Down Expand Up @@ -7678,6 +7698,51 @@ impl<'a> Parser<'a> {
)
}

/// Bail out if the current token is not a privilege object type in the plural form, or consume and
/// return it if it is.
fn expect_plural_system_object_type_for_privileges(
&mut self,
) -> Result<SystemObjectType, ParserError> {
if let Some(object_type) = self.parse_one_of_keywords(&[VIEWS, SOURCES]) {
return parser_err!(
self,
self.peek_prev_pos(),
format!("For object type {object_type}, you must specify 'TABLES'")
);
}
if self.parse_keywords(&[MATERIALIZED, VIEWS]) {
self.prev_token();
return parser_err!(
self,
self.peek_prev_pos(),
format!("For object type MATERIALIZED VIEWS, you must specify 'TABLES'")
);
}

Ok(
match self.expect_one_of_keywords(&[
SYSTEM,
TABLES,
TYPES,
CLUSTERS,
SECRETS,
CONNECTIONS,
DATABASES,
SCHEMAS,
])? {
SYSTEM => SystemObjectType::System,
TABLES => SystemObjectType::Object(ObjectType::Table),
TYPES => SystemObjectType::Object(ObjectType::Type),
CLUSTERS => SystemObjectType::Object(ObjectType::Cluster),
SECRETS => SystemObjectType::Object(ObjectType::Secret),
CONNECTIONS => SystemObjectType::Object(ObjectType::Connection),
DATABASES => SystemObjectType::Object(ObjectType::Database),
SCHEMAS => SystemObjectType::Object(ObjectType::Schema),
_ => unreachable!(),
},
)
}

/// Look for a privilege and return it if it matches.
fn parse_privilege(&mut self) -> Option<Privilege> {
Some(
Expand Down
Loading

0 comments on commit 32e48bd

Please sign in to comment.