Skip to content

Commit 6b4fdbf

Browse files
committed
fix(catalog): grant view when grant table
1 parent c6995a8 commit 6b4fdbf

File tree

11 files changed

+116
-21
lines changed

11 files changed

+116
-21
lines changed

e2e_test/batch/catalog/has_privilege.slt.part

+39-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ GRANT ALL PRIVILEGES ON foo TO test_user GRANTED BY root;
3232
statement ok
3333
GRANT INSERT ON bar TO test_user WITH GRANT OPTION GRANTED BY root;
3434

35+
statement ok
36+
GRANT INSERT ON foo_view TO test_user WITH GRANT OPTION GRANTED BY root;
37+
3538
statement ok
3639
GRANT SELECT ON ALL TABLES IN SCHEMA public TO test_user WITH GRANT OPTION GRANTED BY root;
3740

@@ -44,6 +47,9 @@ GRANT SELECT ON ALL SOURCES IN SCHEMA public TO test_user WITH GRANT OPTION GRAN
4447
statement ok
4548
GRANT CREATE ON SCHEMA test_schema TO test_user;
4649

50+
query error table not found: bar_err
51+
GRANT INSERT ON bar_err TO test_user WITH GRANT OPTION GRANTED BY root;
52+
4753
query error Invalid parameter user: User test_user_err not found
4854
SELECT has_table_privilege('test_user_err', 'foo', 'SELECT');
4955

@@ -101,21 +107,25 @@ SELECT has_table_privilege('test_user', 'foo', 'DELETE WITH GRANT OPTION, INSERT
101107
----
102108
f
103109

104-
# FIXME(Kexiang): Currently, RW's grant privilege on all table doesn't apply to VIEWS.
105110
query I
106111
SELECT has_table_privilege('test_user', 'foo_view', 'SELECT');
107112
----
108-
f
113+
t
109114

110115
query I
111116
SELECT has_table_privilege('test_user', 'foo_view'::regclass, 'INSERT');
112117
----
118+
t
119+
120+
query I
121+
SELECT has_table_privilege('test_user', 'foo_view'::regclass, 'UPDATE');
122+
----
113123
f
114124

115125
query I
116126
SELECT has_any_column_privilege('test_user', 'foo_view'::regclass, 'INSERT');
117127
----
118-
f
128+
t
119129

120130
query I
121131
SELECT has_table_privilege('test_user', 'foo_mv', 'SELECT');
@@ -203,6 +213,32 @@ SELECT has_schema_privilege('test_user', 'test_schema', 'CREATE');
203213
----
204214
t
205215

216+
statement ok
217+
REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM test_user GRANTED BY root;
218+
219+
query I
220+
SELECT has_table_privilege('test_user', 'bar'::regclass, 'SELECT');
221+
----
222+
f
223+
224+
query I
225+
SELECT has_table_privilege('test_user', 'foo_view', 'SELECT');
226+
----
227+
f
228+
229+
query I
230+
SELECT has_table_privilege('test_user', 'foo_view', 'INSERT');
231+
----
232+
t
233+
234+
statement ok
235+
REVOKE INSERT ON foo_view FROM test_user GRANTED BY root;
236+
237+
query I
238+
SELECT has_table_privilege('test_user', 'foo_view', 'INSERT');
239+
----
240+
f
241+
206242
statement ok
207243
DROP SOURCE foo_source;
208244

proto/user.proto

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ message GrantPrivilege {
6666

6767
uint32 all_tables_schema_id = 11;
6868
uint32 all_sources_schema_id = 12;
69-
uint32 all_dml_tables_schema_id = 13;
69+
uint32 all_dml_relations_schema_id = 13;
7070
uint32 subscription_id = 14;
7171
}
7272
repeated ActionWithGrantOption action_with_opts = 7;

src/common/src/acl/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ pub static ALL_AVAILABLE_DATABASE_MODES: LazyLock<AclModeSet> =
100100
LazyLock::new(|| make_bitflags!(AclMode::{Create | Connect}).into());
101101
pub static ALL_AVAILABLE_SCHEMA_MODES: LazyLock<AclModeSet> =
102102
LazyLock::new(|| make_bitflags!(AclMode::{Create | Usage}).into());
103+
// Including TABLES and VIEWS
103104
pub static ALL_AVAILABLE_TABLE_MODES: LazyLock<AclModeSet> =
104105
LazyLock::new(|| make_bitflags!(AclMode::{Select | Insert | Update | Delete}).into());
105106
pub static ALL_AVAILABLE_SOURCE_MODES: LazyLock<AclModeSet> = LazyLock::new(AclModeSet::readonly);
106107
pub static ALL_AVAILABLE_MVIEW_MODES: LazyLock<AclModeSet> = LazyLock::new(AclModeSet::readonly);
107-
pub static ALL_AVAILABLE_VIEW_MODES: LazyLock<AclModeSet> = LazyLock::new(AclModeSet::readonly);
108108
pub static ALL_AVAILABLE_SINK_MODES: LazyLock<AclModeSet> = LazyLock::new(AclModeSet::empty);
109109
pub static ALL_AVAILABLE_SUBSCRIPTION_MODES: LazyLock<AclModeSet> =
110110
LazyLock::new(AclModeSet::empty);

src/frontend/src/handler/handle_privilege.rs

+25-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use super::RwPgResponse;
2121
use crate::binder::Binder;
2222
use crate::catalog::root_catalog::SchemaPath;
2323
use crate::catalog::table_catalog::TableType;
24+
use crate::catalog::CatalogError;
2425
use crate::error::{ErrorCode, Result};
2526
use crate::handler::HandlerArgs;
2627
use crate::session::SessionImpl;
@@ -93,17 +94,31 @@ fn make_prost_privilege(
9394
Binder::resolve_schema_qualified_name(db_name, name)?;
9495
let schema_path = SchemaPath::new(schema_name.as_deref(), &search_path, user_name);
9596

96-
let (table, _) = reader.get_table_by_name(db_name, schema_path, &table_name)?;
97-
match table.table_type() {
98-
TableType::Table => {}
99-
_ => {
100-
return Err(ErrorCode::InvalidInputSyntax(format!(
101-
"{table_name} is not a table",
102-
))
103-
.into());
97+
match reader.get_table_by_name(db_name, schema_path, &table_name) {
98+
Ok((table, _)) => {
99+
match table.table_type() {
100+
TableType::Table => {
101+
grant_objs.push(PbObject::TableId(table.id().table_id));
102+
continue;
103+
}
104+
_ => {
105+
return Err(ErrorCode::InvalidInputSyntax(format!(
106+
"{table_name} is not a table",
107+
))
108+
.into());
109+
}
110+
};
111+
}
112+
Err(CatalogError::NotFound("table", _)) => {
113+
let (view, _) = reader
114+
.get_view_by_name(db_name, schema_path, &table_name)
115+
.map_err(|_| CatalogError::NotFound("table", table_name))?;
116+
grant_objs.push(PbObject::ViewId(view.id));
117+
}
118+
Err(e) => {
119+
return Err(e.into());
104120
}
105121
}
106-
grant_objs.push(PbObject::TableId(table.id().table_id));
107122
}
108123
}
109124
GrantObjects::Sources(sources) => {
@@ -138,7 +153,7 @@ fn make_prost_privilege(
138153
for schema in schemas {
139154
let schema_name = Binder::resolve_schema_name(schema)?;
140155
let schema = reader.get_schema_by_name(session.database(), &schema_name)?;
141-
grant_objs.push(PbObject::AllDmlTablesSchemaId(schema.id()));
156+
grant_objs.push(PbObject::AllDmlRelationsSchemaId(schema.id()));
142157
}
143158
}
144159
o => {

src/frontend/src/user/user_catalog.rs

-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ impl UserCatalog {
190190

191191
for (&key, found) in action_map.iter_mut() {
192192
let (required_action, required_grant_option) = *key;
193-
194193
if action == required_action && (!required_grant_option | with_grant_option) {
195194
*found = true;
196195
}

src/frontend/src/user/user_privilege.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub fn available_prost_privilege(object: PbObject, for_dml_table: bool) -> PbGra
9494
&acl::ALL_AVAILABLE_MVIEW_MODES
9595
}
9696
}
97-
PbObject::ViewId(_) => &acl::ALL_AVAILABLE_VIEW_MODES,
97+
PbObject::ViewId(_) => &acl::ALL_AVAILABLE_TABLE_MODES,
9898
PbObject::SinkId(_) => &acl::ALL_AVAILABLE_SINK_MODES,
9999
PbObject::SubscriptionId(_) => &acl::ALL_AVAILABLE_SUBSCRIPTION_MODES,
100100
PbObject::FunctionId(_) => &acl::ALL_AVAILABLE_FUNCTION_MODES,

src/meta/service/src/user_service.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl UserServiceImpl {
7676
}
7777
expanded_privileges.push(privilege);
7878
}
79-
} else if let Some(Object::AllDmlTablesSchemaId(schema_id)) = &privilege.object {
79+
} else if let Some(Object::AllDmlRelationsSchemaId(schema_id)) = &privilege.object {
8080
let tables = match &self.metadata_manager {
8181
MetadataManager::V1(mgr) => {
8282
mgr.catalog_manager.list_dml_table_ids(*schema_id).await
@@ -89,6 +89,16 @@ impl UserServiceImpl {
8989
.map(|id| id as _)
9090
.collect(),
9191
};
92+
let views = match &self.metadata_manager {
93+
MetadataManager::V1(mgr) => mgr.catalog_manager.list_view_ids(*schema_id).await,
94+
MetadataManager::V2(mgr) => mgr
95+
.catalog_controller
96+
.list_view_ids(*schema_id as _)
97+
.await?
98+
.into_iter()
99+
.map(|id| id as _)
100+
.collect(),
101+
};
92102
for table_id in tables {
93103
let mut privilege = privilege.clone();
94104
privilege.object = Some(Object::TableId(table_id));
@@ -100,6 +110,17 @@ impl UserServiceImpl {
100110
}
101111
expanded_privileges.push(privilege);
102112
}
113+
for view_id in views {
114+
let mut privilege = privilege.clone();
115+
privilege.object = Some(Object::ViewId(view_id));
116+
if let Some(true) = with_grant_option {
117+
privilege
118+
.action_with_opts
119+
.iter_mut()
120+
.for_each(|p| p.with_grant_option = true);
121+
}
122+
expanded_privileges.push(privilege);
123+
}
103124
} else if let Some(Object::AllSourcesSchemaId(schema_id)) = &privilege.object {
104125
let sources = match &self.metadata_manager {
105126
MetadataManager::V1(mgr) => {

src/meta/src/controller/catalog.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use risingwave_meta_model_v2::{
3131
ActorUpstreamActors, ColumnCatalogArray, ConnectionId, CreateType, DatabaseId, FragmentId,
3232
FunctionId, I32Array, IndexId, JobStatus, ObjectId, PrivateLinkService, Property, SchemaId,
3333
SinkId, SourceId, StreamNode, StreamSourceInfo, StreamingParallelism, SubscriptionId, TableId,
34-
UserId,
34+
UserId, ViewId,
3535
};
3636
use risingwave_pb::catalog::subscription::SubscriptionState;
3737
use risingwave_pb::catalog::table::PbTableType;
@@ -2428,6 +2428,19 @@ impl CatalogController {
24282428
Ok(table_ids)
24292429
}
24302430

2431+
pub async fn list_view_ids(&self, schema_id: SchemaId) -> MetaResult<Vec<ViewId>> {
2432+
let inner = self.inner.read().await;
2433+
let view_ids: Vec<ViewId> = View::find()
2434+
.select_only()
2435+
.column(view::Column::ViewId)
2436+
.join(JoinType::InnerJoin, view::Relation::Object.def())
2437+
.filter(object::Column::SchemaId.eq(schema_id))
2438+
.into_tuple()
2439+
.all(&inner.db)
2440+
.await?;
2441+
Ok(view_ids)
2442+
}
2443+
24312444
pub async fn list_tables_by_type(&self, table_type: TableType) -> MetaResult<Vec<PbTable>> {
24322445
let inner = self.inner.read().await;
24332446
let table_objs = Table::find()

src/meta/src/controller/utils.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -754,12 +754,11 @@ where
754754
let obj = match object.obj_type {
755755
ObjectType::Database => PbObject::DatabaseId(oid),
756756
ObjectType::Schema => PbObject::SchemaId(oid),
757-
ObjectType::Table => PbObject::TableId(oid),
757+
ObjectType::Table | ObjectType::Index => PbObject::TableId(oid),
758758
ObjectType::Source => PbObject::SourceId(oid),
759759
ObjectType::Sink => PbObject::SinkId(oid),
760760
ObjectType::View => PbObject::ViewId(oid),
761761
ObjectType::Function => PbObject::FunctionId(oid),
762-
ObjectType::Index => unreachable!("index is not supported yet"),
763762
ObjectType::Connection => unreachable!("connection is not supported yet"),
764763
ObjectType::Subscription => PbObject::SubscriptionId(oid),
765764
};

src/meta/src/manager/catalog/database.rs

+8
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,14 @@ impl DatabaseManager {
363363
.collect_vec()
364364
}
365365

366+
pub fn list_view_ids(&self, schema_id: SchemaId) -> Vec<ViewId> {
367+
self.views
368+
.values()
369+
.filter(|view| view.schema_id == schema_id)
370+
.map(|view| view.id)
371+
.collect_vec()
372+
}
373+
366374
pub fn list_sources(&self) -> Vec<Source> {
367375
self.sources.values().cloned().collect_vec()
368376
}

src/meta/src/manager/catalog/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3608,6 +3608,10 @@ impl CatalogManager {
36083608
.list_dml_table_ids(schema_id)
36093609
}
36103610

3611+
pub async fn list_view_ids(&self, schema_id: SchemaId) -> Vec<TableId> {
3612+
self.core.lock().await.database.list_view_ids(schema_id)
3613+
}
3614+
36113615
pub async fn list_sources(&self) -> Vec<Source> {
36123616
self.core.lock().await.database.list_sources()
36133617
}

0 commit comments

Comments
 (0)