Skip to content

Commit 7a5b01a

Browse files
committed
chore: use Usage privilege optimize USEDB Plan
1 parent e929ea2 commit 7a5b01a

File tree

5 files changed

+121
-13
lines changed

5 files changed

+121
-13
lines changed

src/meta/app/src/principal/user_privilege.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,9 @@ impl UserPrivilegeSet {
220220
/// Currently the privileges available to a database and a table are the same, it might becomes
221221
/// some differences in the future.
222222
pub fn available_privileges_on_database(available_ownership: bool) -> Self {
223-
UserPrivilegeSet::available_privileges_on_table(available_ownership)
223+
(UserPrivilegeSet::available_privileges_on_table(available_ownership).privileges
224+
| make_bitflags!(UserPrivilegeType::{ Usage }))
225+
.into()
224226
}
225227

226228
/// The all privileges global which available to the table object

src/query/service/src/interpreters/access/privilege_access.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ impl AccessChecker for PrivilegeAccess {
758758
ObjectId::Database(db_id) => { (db_id, None) }
759759
};
760760

761-
if has_priv(&tenant, database, None, show_db_id, table_id, grant_set).await? {
761+
if has_priv(&tenant, database, None, show_db_id, table_id, grant_set, false).await? {
762762
return Ok(())
763763
}
764764

@@ -777,7 +777,7 @@ impl AccessChecker for PrivilegeAccess {
777777
ObjectId::Table(db_id, table_id) => { (db_id, Some(table_id)) }
778778
ObjectId::Database(db_id) => { (db_id, None) }
779779
};
780-
if has_priv(&tenant, database, None, show_db_id, table_id, grant_set).await? {
780+
if has_priv(&tenant, database, None, show_db_id, table_id, grant_set, true).await? {
781781
return Ok(());
782782
}
783783
let user_api = UserApiProvider::instance();
@@ -803,7 +803,7 @@ impl AccessChecker for PrivilegeAccess {
803803
ObjectId::Table(db_id, table_id) => { (db_id, Some(table_id)) }
804804
ObjectId::Database(db_id) => { (db_id, None) }
805805
};
806-
let has_priv = has_priv(&tenant, database, Some(table), db_id, table_id, grant_set).await?;
806+
let has_priv = has_priv(&tenant, database, Some(table), db_id, table_id, grant_set, false).await?;
807807
return if has_priv {
808808
Ok(())
809809
} else {
@@ -932,7 +932,7 @@ impl AccessChecker for PrivilegeAccess {
932932
ObjectId::Table(db_id, table_id) => { (db_id, Some(table_id)) }
933933
ObjectId::Database(db_id) => { (db_id, None) }
934934
};
935-
if has_priv(&tenant, &plan.database, None, show_db_id, None, grant_set).await? {
935+
if has_priv(&tenant, &plan.database, None, show_db_id, None, grant_set, true).await? {
936936
return Ok(());
937937
}
938938
let user_api = UserApiProvider::instance();
@@ -1434,6 +1434,7 @@ async fn has_priv(
14341434
db_id: u64,
14351435
table_id: Option<u64>,
14361436
grant_set: UserGrantSet,
1437+
valid_usage_priv: bool,
14371438
) -> Result<bool> {
14381439
if db_name.to_lowercase() == "information_schema" {
14391440
return Ok(true);
@@ -1461,13 +1462,38 @@ async fn has_priv(
14611462
if db_name.to_lowercase() == "system" {
14621463
return true;
14631464
}
1464-
e.privileges().iter().any(|privilege| {
1465-
UserPrivilegeSet::available_privileges_on_database(false)
1466-
.has_privilege(privilege)
1467-
})
1465+
if valid_usage_priv {
1466+
e.privileges().iter().any(|privilege| {
1467+
UserPrivilegeSet::available_privileges_on_database(false)
1468+
.has_privilege(privilege)
1469+
})
1470+
} else {
1471+
!(e.privileges().len() == 1
1472+
&& e.privileges().contains(UserPrivilegeType::Usage))
1473+
&& e.privileges().iter().any(|privilege| {
1474+
UserPrivilegeSet::available_privileges_on_database(false)
1475+
.has_privilege(privilege)
1476+
})
1477+
}
1478+
}
1479+
GrantObject::Database(_, ldb) => {
1480+
if valid_usage_priv {
1481+
*ldb == db_name
1482+
} else {
1483+
!(e.privileges().len() == 1
1484+
&& e.privileges().contains(UserPrivilegeType::Usage))
1485+
&& *ldb == db_name
1486+
}
1487+
}
1488+
GrantObject::DatabaseById(_, ldb) => {
1489+
if valid_usage_priv {
1490+
*ldb == db_id
1491+
} else {
1492+
!(e.privileges().len() == 1
1493+
&& e.privileges().contains(UserPrivilegeType::Usage))
1494+
&& *ldb == db_id
1495+
}
14681496
}
1469-
GrantObject::Database(_, ldb) => *ldb == db_name,
1470-
GrantObject::DatabaseById(_, ldb) => *ldb == db_id,
14711497
GrantObject::Table(_, ldb, ltab) => {
14721498
if let Some(table) = table_name {
14731499
*ldb == db_name && *ltab == table

src/query/users/src/visibility_checker.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,19 @@ impl GrantObjectVisibilityChecker {
133133
);
134134
}
135135
GrantObject::Database(catalog, db) => {
136-
granted_databases.insert((catalog.to_string(), db.to_string()));
136+
if !(ent.privileges().len() == 1
137+
&& ent.privileges().contains(UserPrivilegeType::Usage))
138+
{
139+
granted_databases.insert((catalog.to_string(), db.to_string()));
140+
}
137141
}
138142
GrantObject::DatabaseById(catalog, db) => {
139-
granted_databases_id.insert((catalog.to_string(), *db));
143+
// If only has db level usage privilege means only support use db.
144+
if !(ent.privileges().len() == 1
145+
&& ent.privileges().contains(UserPrivilegeType::Usage))
146+
{
147+
granted_databases_id.insert((catalog.to_string(), *db));
148+
}
140149
}
141150
GrantObject::Table(catalog, db, table) => {
142151
granted_tables.insert((
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== show db ===
2+
a
3+
b
4+
information_schema
5+
system
6+
=== use db ===
7+
=== show tables from a ===
8+
t1
9+
=== show tables from b ===
10+
t
11+
=== show columns ===
12+
Error: APIError: QueryFailed: [1063]Permission denied: User 'test'@'%' does not have the required privileges for table 'a.t'
13+
ida1 INT YES NULL NULL
14+
idb INT YES NULL NULL
15+
Error: APIError: QueryFailed: [1063]Permission denied: User 'test'@'%' does not have the required privileges for table 'b.t1'
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
3+
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
4+
. "$CURDIR"/../../../shell_env.sh
5+
6+
7+
export TEST_USER_PASSWORD="password"
8+
export USER_TEST_CONNECT="bendsql --user=test --password=password --host=${QUERY_MYSQL_HANDLER_HOST} --port ${QUERY_HTTP_HANDLER_PORT}"
9+
10+
11+
echo "drop user if exists test" | $BENDSQL_CLIENT_CONNECT
12+
echo "create user test identified by '$TEST_USER_PASSWORD'" | $BENDSQL_CLIENT_CONNECT
13+
14+
echo "create or replace database a" | $BENDSQL_CLIENT_CONNECT
15+
echo "create or replace database b" | $BENDSQL_CLIENT_CONNECT
16+
echo "create or replace database c" | $BENDSQL_CLIENT_CONNECT
17+
echo "create or replace table a.t(ida int)" | $BENDSQL_CLIENT_CONNECT
18+
echo "create or replace table a.t1(ida1 int)" | $BENDSQL_CLIENT_CONNECT
19+
echo "create or replace table b.t(idb int)" | $BENDSQL_CLIENT_CONNECT
20+
echo "create or replace table b.t1(idb1 int)" | $BENDSQL_CLIENT_CONNECT
21+
echo "drop role if exists test_role1" | $BENDSQL_CLIENT_CONNECT
22+
echo "drop role if exists test_role2" | $BENDSQL_CLIENT_CONNECT
23+
echo "create role test_role1" | $BENDSQL_CLIENT_CONNECT
24+
echo "create role test_role2" | $BENDSQL_CLIENT_CONNECT
25+
echo "grant usage on a.* to role test_role1" | $BENDSQL_CLIENT_CONNECT
26+
echo "grant usage on b.* to role test_role1" | $BENDSQL_CLIENT_CONNECT
27+
echo "grant ownership on b.t to role test_role1" | $BENDSQL_CLIENT_CONNECT
28+
29+
echo "grant role test_role1 to test" | $BENDSQL_CLIENT_CONNECT
30+
echo "grant select on a.t1 to test" | $BENDSQL_CLIENT_CONNECT
31+
32+
echo "=== show db ==="
33+
echo "show databases" | $USER_TEST_CONNECT
34+
35+
36+
echo "=== use db ==="
37+
echo "use a" | $USER_TEST_CONNECT
38+
echo "use b" | $USER_TEST_CONNECT
39+
40+
echo "=== show tables from a ==="
41+
echo "show tables from a" | $USER_TEST_CONNECT # only display a.t1
42+
echo "=== show tables from b ==="
43+
echo "show tables from b" | $USER_TEST_CONNECT # only display b.t
44+
45+
echo "=== show columns ==="
46+
echo "show columns from t from a" | $USER_TEST_CONNECT
47+
echo "show columns from t1 from a" | $USER_TEST_CONNECT
48+
echo "show columns from t from b" | $USER_TEST_CONNECT
49+
echo "show columns from t1 from b" | $USER_TEST_CONNECT
50+
51+
echo "drop user if exists test" | $BENDSQL_CLIENT_CONNECT
52+
echo "drop role if exists test_role1" | $BENDSQL_CLIENT_CONNECT
53+
echo "drop role if exists test_role2" | $BENDSQL_CLIENT_CONNECT
54+
echo "drop database a" | $BENDSQL_CLIENT_CONNECT
55+
echo "drop database b" | $BENDSQL_CLIENT_CONNECT
56+
echo "drop database c" | $BENDSQL_CLIENT_CONNECT

0 commit comments

Comments
 (0)