This is an automated email from the ASF dual-hosted git repository.

dataroaring pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git

commit 07af360a088de42436e916b117c8a372ec058c88
Author: wangbo <wan...@apache.org>
AuthorDate: Wed Jul 31 12:11:02 2024 +0800

    [Improment]Add schema table workload_group_privileges (#38436)
    
    ## Proposed changes
    Add schema table workload_group_privileges.
    
    ```
    mysql [information_schema]>desc workload_group_privileges;
    +---------------------+--------------+------+-------+---------+-------+
    | Field               | Type         | Null | Key   | Default | Extra |
    +---------------------+--------------+------+-------+---------+-------+
    | GRANTEE             | varchar(64)  | Yes  | false | NULL    |       |
    | WORKLOAD_GROUP_NAME | varchar(256) | Yes  | false | NULL    |       |
    | PRIVILEGE_TYPE      | varchar(64)  | Yes  | false | NULL    |       |
    | IS_GRANTABLE        | varchar(3)   | Yes  | false | NULL    |       |
    +---------------------+--------------+------+-------+---------+-------+
    4 rows in set (0.01 sec)
    
    
    ```
---
 be/src/exec/schema_scanner.cpp                     |   3 +
 .../schema_workload_group_privileges.cpp           | 136 +++++++++++++++++++++
 .../schema_workload_group_privileges.h             |  52 ++++++++
 .../org/apache/doris/analysis/SchemaTableType.java |   4 +-
 .../java/org/apache/doris/catalog/SchemaTable.java |   8 ++
 .../org/apache/doris/mysql/privilege/Auth.java     |  42 +++++++
 .../apache/doris/mysql/privilege/RoleManager.java  |  26 ++++
 .../doris/tablefunction/MetadataGenerator.java     |  37 ++++++
 gensrc/thrift/Descriptors.thrift                   |   3 +-
 gensrc/thrift/FrontendService.thrift               |   1 +
 .../jdbc/test_mariadb_jdbc_catalog.out             |   1 +
 .../jdbc/test_mysql_jdbc_catalog.out               |   1 +
 .../jdbc/test_mysql_jdbc_catalog_nereids.out       |   1 +
 .../jdbc/test_mysql_jdbc_driver5_catalog.out       |   1 +
 .../data/workload_manager_p0/test_curd_wlg.out     |  49 ++++++++
 .../workload_manager_p0/test_curd_wlg.groovy       |  58 +++++++++
 16 files changed, 421 insertions(+), 2 deletions(-)

diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp
index b78083f39e2..2ddb3db295b 100644
--- a/be/src/exec/schema_scanner.cpp
+++ b/be/src/exec/schema_scanner.cpp
@@ -48,6 +48,7 @@
 #include "exec/schema_scanner/schema_user_scanner.h"
 #include "exec/schema_scanner/schema_variables_scanner.h"
 #include "exec/schema_scanner/schema_views_scanner.h"
+#include "exec/schema_scanner/schema_workload_group_privileges.h"
 #include "exec/schema_scanner/schema_workload_groups_scanner.h"
 #include "exec/schema_scanner/schema_workload_sched_policy_scanner.h"
 #include "olap/hll.h"
@@ -227,6 +228,8 @@ std::unique_ptr<SchemaScanner> 
SchemaScanner::create(TSchemaTableType::type type
         return SchemaWorkloadSchedulePolicyScanner::create_unique();
     case TSchemaTableType::SCH_TABLE_OPTIONS:
         return SchemaTableOptionsScanner::create_unique();
+    case TSchemaTableType::SCH_WORKLOAD_GROUP_PRIVILEGES:
+        return SchemaWorkloadGroupPrivilegesScanner::create_unique();
     default:
         return SchemaDummyScanner::create_unique();
         break;
diff --git a/be/src/exec/schema_scanner/schema_workload_group_privileges.cpp 
b/be/src/exec/schema_scanner/schema_workload_group_privileges.cpp
new file mode 100644
index 00000000000..88baddb550e
--- /dev/null
+++ b/be/src/exec/schema_scanner/schema_workload_group_privileges.cpp
@@ -0,0 +1,136 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "exec/schema_scanner/schema_workload_group_privileges.h"
+
+#include "runtime/client_cache.h"
+#include "runtime/exec_env.h"
+#include "runtime/runtime_state.h"
+#include "util/thrift_rpc_helper.h"
+#include "vec/common/string_ref.h"
+#include "vec/core/block.h"
+#include "vec/data_types/data_type_factory.hpp"
+
+namespace doris {
+std::vector<SchemaScanner::ColumnDesc> 
SchemaWorkloadGroupPrivilegesScanner::_s_tbls_columns = {
+        {"GRANTEE", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"WORKLOAD_GROUP_NAME", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"PRIVILEGE_TYPE", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"IS_GRANTABLE", TYPE_VARCHAR, sizeof(StringRef), true},
+};
+
+SchemaWorkloadGroupPrivilegesScanner::SchemaWorkloadGroupPrivilegesScanner()
+        : SchemaScanner(_s_tbls_columns, 
TSchemaTableType::SCH_WORKLOAD_GROUPS) {}
+
+SchemaWorkloadGroupPrivilegesScanner::~SchemaWorkloadGroupPrivilegesScanner() 
{}
+
+Status SchemaWorkloadGroupPrivilegesScanner::start(RuntimeState* state) {
+    _block_rows_limit = state->batch_size();
+    _rpc_timeout = state->execution_timeout() * 1000;
+    return Status::OK();
+}
+
+Status 
SchemaWorkloadGroupPrivilegesScanner::_get_workload_group_privs_block_from_fe() 
{
+    TNetworkAddress master_addr = 
ExecEnv::GetInstance()->master_info()->network_address;
+
+    TSchemaTableRequestParams schema_table_request_params;
+    for (int i = 0; i < _s_tbls_columns.size(); i++) {
+        schema_table_request_params.__isset.columns_name = true;
+        
schema_table_request_params.columns_name.emplace_back(_s_tbls_columns[i].name);
+    }
+    
schema_table_request_params.__set_current_user_ident(*_param->common_param->current_user_ident);
+
+    TFetchSchemaTableDataRequest request;
+    
request.__set_schema_table_name(TSchemaTableName::WORKLOAD_GROUP_PRIVILEGES);
+    request.__set_schema_table_params(schema_table_request_params);
+
+    TFetchSchemaTableDataResult result;
+
+    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
+            master_addr.hostname, master_addr.port,
+            [&request, &result](FrontendServiceConnection& client) {
+                client->fetchSchemaTableData(result, request);
+            },
+            _rpc_timeout));
+
+    Status status(Status::create(result.status));
+    if (!status.ok()) {
+        LOG(WARNING) << "fetch workload group privileges from FE failed, 
errmsg=" << status;
+        return status;
+    }
+    std::vector<TRow> result_data = result.data_batch;
+
+    _workload_groups_privs_block = vectorized::Block::create_unique();
+    for (int i = 0; i < _s_tbls_columns.size(); ++i) {
+        TypeDescriptor descriptor(_s_tbls_columns[i].type);
+        auto data_type = 
vectorized::DataTypeFactory::instance().create_data_type(descriptor, true);
+        _workload_groups_privs_block->insert(vectorized::ColumnWithTypeAndName(
+                data_type->create_column(), data_type, 
_s_tbls_columns[i].name));
+    }
+
+    if (result_data.size() > 0) {
+        int col_size = result_data[0].column_value.size();
+        if (col_size != _s_tbls_columns.size()) {
+            return Status::InternalError<false>(
+                    "workload group privileges schema is not match for FE and 
BE");
+        }
+    }
+
+    _workload_groups_privs_block->reserve(result_data.size());
+
+    for (int i = 0; i < result_data.size(); i++) {
+        TRow row = result_data[i];
+
+        for (int j = 0; j < _s_tbls_columns.size(); j++) {
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j,
+                                                
_workload_groups_privs_block.get(),
+                                                _s_tbls_columns[j].type));
+        }
+    }
+    return Status::OK();
+}
+
+Status SchemaWorkloadGroupPrivilegesScanner::get_next_block(vectorized::Block* 
block, bool* eos) {
+    if (!_is_init) {
+        return Status::InternalError("Used before initialized.");
+    }
+
+    if (nullptr == block || nullptr == eos) {
+        return Status::InternalError("input pointer is nullptr.");
+    }
+
+    if (_workload_groups_privs_block == nullptr) {
+        RETURN_IF_ERROR(_get_workload_group_privs_block_from_fe());
+        _total_rows = _workload_groups_privs_block->rows();
+    }
+
+    if (_row_idx == _total_rows) {
+        *eos = true;
+        return Status::OK();
+    }
+
+    int current_batch_rows = std::min(_block_rows_limit, _total_rows - 
_row_idx);
+    vectorized::MutableBlock mblock = 
vectorized::MutableBlock::build_mutable_block(block);
+    RETURN_IF_ERROR(
+            mblock.add_rows(_workload_groups_privs_block.get(), _row_idx, 
current_batch_rows));
+    _row_idx += current_batch_rows;
+
+    *eos = _row_idx == _total_rows;
+    return Status::OK();
+}
+
+} // namespace doris
\ No newline at end of file
diff --git a/be/src/exec/schema_scanner/schema_workload_group_privileges.h 
b/be/src/exec/schema_scanner/schema_workload_group_privileges.h
new file mode 100644
index 00000000000..cdf3c9697b1
--- /dev/null
+++ b/be/src/exec/schema_scanner/schema_workload_group_privileges.h
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <vector>
+
+#include "common/status.h"
+#include "exec/schema_scanner.h"
+
+namespace doris {
+class RuntimeState;
+namespace vectorized {
+class Block;
+} // namespace vectorized
+
+class SchemaWorkloadGroupPrivilegesScanner : public SchemaScanner {
+    ENABLE_FACTORY_CREATOR(SchemaWorkloadGroupPrivilegesScanner);
+
+public:
+    SchemaWorkloadGroupPrivilegesScanner();
+    ~SchemaWorkloadGroupPrivilegesScanner() override;
+
+    Status start(RuntimeState* state) override;
+    Status get_next_block(vectorized::Block* block, bool* eos) override;
+
+    static std::vector<SchemaScanner::ColumnDesc> _s_tbls_columns;
+
+private:
+    Status _get_workload_group_privs_block_from_fe();
+
+    int _block_rows_limit = 4096;
+    int _row_idx = 0;
+    int _total_rows = 0;
+    std::unique_ptr<vectorized::Block> _workload_groups_privs_block = nullptr;
+    int _rpc_timeout = 3000;
+};
+}; // namespace doris
\ No newline at end of file
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
index 988953ed4cb..d0a3a3728b2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
@@ -78,7 +78,9 @@ public enum SchemaTableType {
     SCH_WORKLOAD_POLICY("WORKLOAD_POLICY", "WORKLOAD_POLICY",
             TSchemaTableType.SCH_WORKLOAD_POLICY),
     SCH_TABLE_OPTIONS("TABLE_OPTIONS", "TABLE_OPTIONS",
-            TSchemaTableType.SCH_TABLE_OPTIONS);
+            TSchemaTableType.SCH_TABLE_OPTIONS),
+    SCH_WORKLOAD_GROUP_PRIVILEGES("WORKLOAD_GROUP_PRIVILEGES",
+            "WORKLOAD_GROUP_PRIVILEGES", 
TSchemaTableType.SCH_WORKLOAD_GROUP_PRIVILEGES);
 
     private static final String dbName = "INFORMATION_SCHEMA";
     private static SelectList fullSelectLists;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
index 4b76785d9b4..8802d266526 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
@@ -532,6 +532,14 @@ public class SchemaTable extends Table {
                                     .column("PARTITION_NUM", 
ScalarType.createType(PrimitiveType.INT))
                                     .column("PROPERTIES", 
ScalarType.createStringType())
                                     .build()))
+            .put("workload_group_privileges",
+                    new SchemaTable(SystemIdGenerator.getNextId(), 
"workload_group_privileges", TableType.SCHEMA,
+                            builder().column("GRANTEE", 
ScalarType.createVarchar(NAME_CHAR_LEN))
+                                    .column("WORKLOAD_GROUP_NAME", 
ScalarType.createVarchar(256))
+                                    .column("PRIVILEGE_TYPE", 
ScalarType.createVarchar(PRIVILEGE_TYPE_LEN))
+                                    .column("IS_GRANTABLE", 
ScalarType.createVarchar(IS_GRANTABLE_LEN))
+                                    .build())
+            )
             .build();
 
     private boolean fetchAllFe = false;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
index 9fb6d9218b0..2073e33cb4f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java
@@ -82,6 +82,7 @@ import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -1407,6 +1408,47 @@ public class Auth implements Writable {
         userAuthInfos.add(userAuthInfo);
     }
 
+    public void getUserRoleWorkloadGroupPrivs(List<List<String>> result, 
UserIdentity currentUserIdentity) {
+        readLock();
+        try {
+            boolean isCurrentUserAdmin = checkGlobalPriv(currentUserIdentity, 
PrivPredicate.ADMIN);
+            Map<String, List<User>> nameToUsers = userManager.getNameToUsers();
+            for (List<User> users : nameToUsers.values()) {
+                for (User user : users) {
+                    if (!user.isSetByDomainResolver()) {
+                        if (!isCurrentUserAdmin && 
!currentUserIdentity.equals(user.getUserIdentity())) {
+                            continue;
+                        }
+                        String isGrantable = 
checkGlobalPriv(user.getUserIdentity(), PrivPredicate.ADMIN) ? "YES"
+                                : "NO";
+
+                        // workload group
+                        for (PrivEntry entry : 
getUserWorkloadGroupPrivTable(user.getUserIdentity()).entries) {
+                            WorkloadGroupPrivEntry workloadGroupPrivEntry = 
(WorkloadGroupPrivEntry) entry;
+                            PrivBitSet savedPrivs = 
workloadGroupPrivEntry.getPrivSet().copy();
+
+                            List<String> row = Lists.newArrayList();
+                            row.add(user.getUserIdentity().toString());
+                            
row.add(workloadGroupPrivEntry.getOrigWorkloadGroupName());
+                            row.add(savedPrivs.toString());
+                            row.add(isGrantable);
+                            result.add(row);
+                        }
+                    }
+                }
+            }
+
+            Set<String> currentUserRole = null;
+            if (!isCurrentUserAdmin) {
+                currentUserRole = 
userRoleManager.getRolesByUser(currentUserIdentity, false);
+                currentUserRole = currentUserRole == null ? new HashSet<>() : 
currentUserRole;
+            }
+            roleManager.getRoleWorkloadGroupPrivs(result, currentUserRole);
+        } finally {
+            readUnlock();
+        }
+    }
+
     private ResourcePrivTable getUserCloudClusterPrivTable(UserIdentity 
userIdentity) {
         ResourcePrivTable table = new ResourcePrivTable();
         Set<String> roles = userRoleManager.getRolesByUser(userIdentity);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java
index 93bd7f72fdc..6b215982c7d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RoleManager.java
@@ -37,6 +37,7 @@ import org.apache.doris.persist.gson.GsonUtils;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.resource.workloadgroup.WorkloadGroupMgr;
 
+import com.aliyuncs.utils.StringUtils;
 import com.google.common.base.Joiner;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
@@ -211,6 +212,31 @@ public class RoleManager implements Writable, 
GsonPostProcessable {
         }
     }
 
+    public void getRoleWorkloadGroupPrivs(List<List<String>> result, 
Set<String> limitedRole) {
+        for (Role role : roles.values()) {
+            if 
(ClusterNamespace.getNameFromFullName(role.getRoleName()).startsWith(DEFAULT_ROLE_PREFIX))
 {
+                continue;
+            }
+
+            if (limitedRole != null && 
!limitedRole.contains(role.getRoleName())) {
+                continue;
+            }
+            String isGrantable = role.checkGlobalPriv(PrivPredicate.ADMIN) ? 
"YES" : "NO";
+
+            for (Map.Entry<WorkloadGroupPattern, PrivBitSet> entry : 
role.getWorkloadGroupPatternToPrivs().entrySet()) {
+                List<String> row = Lists.newArrayList();
+                row.add(role.getRoleName());
+                row.add(entry.getKey().getworkloadGroupName());
+                if (StringUtils.isEmpty(entry.getValue().toString())) {
+                    continue;
+                }
+                row.add(entry.getValue().toString());
+                row.add(isGrantable);
+                result.add(row);
+            }
+        }
+    }
+
     public Role createDefaultRole(UserIdentity userIdent) throws DdlException {
         String userDefaultRoleName = getUserDefaultRoleName(userIdent);
         if (roles.containsKey(userDefaultRoleName)) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
index 2f27b020cd8..b446cd4210a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
@@ -113,6 +113,8 @@ public class MetadataGenerator {
 
     private static final ImmutableMap<String, Integer> 
TABLE_OPTIONS_COLUMN_TO_INDEX;
 
+    private static final ImmutableMap<String, Integer> 
WORKLOAD_GROUP_PRIVILEGES_COLUMN_TO_INDEX;
+
     static {
         ImmutableMap.Builder<String, Integer> activeQueriesbuilder = new 
ImmutableMap.Builder();
         List<Column> activeQueriesColList = 
SchemaTable.TABLE_MAP.get("active_queries").getFullSchema();
@@ -146,6 +148,13 @@ public class MetadataGenerator {
             optionBuilder.put(optionColList.get(i).getName().toLowerCase(), i);
         }
         TABLE_OPTIONS_COLUMN_TO_INDEX = optionBuilder.build();
+
+        ImmutableMap.Builder<String, Integer> wgPrivsBuilder = new 
ImmutableMap.Builder();
+        List<Column> wgPrivsColList = 
SchemaTable.TABLE_MAP.get("workload_group_privileges").getFullSchema();
+        for (int i = 0; i < wgPrivsColList.size(); i++) {
+            wgPrivsBuilder.put(wgPrivsColList.get(i).getName().toLowerCase(), 
i);
+        }
+        WORKLOAD_GROUP_PRIVILEGES_COLUMN_TO_INDEX = wgPrivsBuilder.build();
     }
 
     public static TFetchSchemaTableDataResult 
getMetadataTable(TFetchSchemaTableDataRequest request) throws TException {
@@ -229,6 +238,10 @@ public class MetadataGenerator {
                 result = tableOptionsMetadataResult(schemaTableParams);
                 columnIndex = TABLE_OPTIONS_COLUMN_TO_INDEX;
                 break;
+            case WORKLOAD_GROUP_PRIVILEGES:
+                result = workloadGroupPrivsMetadataResult(schemaTableParams);
+                columnIndex = WORKLOAD_GROUP_PRIVILEGES_COLUMN_TO_INDEX;
+                break;
             default:
                 return errorResult("invalid schema table name.");
         }
@@ -537,6 +550,30 @@ public class MetadataGenerator {
         return result;
     }
 
+    private static TFetchSchemaTableDataResult 
workloadGroupPrivsMetadataResult(TSchemaTableRequestParams params) {
+        if (!params.isSetCurrentUserIdent()) {
+            return errorResult("current user ident is not set.");
+        }
+        UserIdentity currentUserIdentity = 
UserIdentity.fromThrift(params.getCurrentUserIdent());
+
+        List<List<String>> rows = new ArrayList<>();
+        Env.getCurrentEnv().getAuth().getUserRoleWorkloadGroupPrivs(rows, 
currentUserIdentity);
+        List<TRow> dataBatch = Lists.newArrayList();
+        for (List<String> privRow : rows) {
+            TRow trow = new TRow();
+            String workloadGroupName = privRow.get(1);
+            trow.addToColumnValue(new TCell().setStringVal(privRow.get(0))); 
// GRANTEE
+            trow.addToColumnValue(new 
TCell().setStringVal(workloadGroupName)); // WORKLOAD_GROUP_NAME
+            trow.addToColumnValue(new TCell().setStringVal(privRow.get(2))); 
// PRIVILEGE_TYPE
+            trow.addToColumnValue(new TCell().setStringVal(privRow.get(3))); 
// IS_GRANTABLE
+            dataBatch.add(trow);
+        }
+        TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
+        result.setDataBatch(dataBatch);
+        result.setStatus(new TStatus(TStatusCode.OK));
+        return result;
+    }
+
     private static TFetchSchemaTableDataResult 
queriesMetadataResult(TSchemaTableRequestParams tSchemaTableParams,
             TFetchSchemaTableDataRequest parentRequest) {
         TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
diff --git a/gensrc/thrift/Descriptors.thrift b/gensrc/thrift/Descriptors.thrift
index cb844c93361..20042adc42e 100644
--- a/gensrc/thrift/Descriptors.thrift
+++ b/gensrc/thrift/Descriptors.thrift
@@ -133,7 +133,8 @@ enum TSchemaTableType {
     SCH_USER,
     SCH_PROCS_PRIV,
     SCH_WORKLOAD_POLICY,
-    SCH_TABLE_OPTIONS;    
+    SCH_TABLE_OPTIONS,
+    SCH_WORKLOAD_GROUP_PRIVILEGES;
 }
 
 enum THdfsCompression {
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index 7986c4f7cc6..07ed2c37369 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -1002,6 +1002,7 @@ enum TSchemaTableName {
   ROUTINES_INFO = 4, // db information_schema's table
   WORKLOAD_SCHEDULE_POLICY = 5,
   TABLE_OPTIONS = 6,
+  WORKLOAD_GROUP_PRIVILEGES = 7,
 }
 
 struct TMetadataTableRequestParams {
diff --git 
a/regression-test/data/external_table_p0/jdbc/test_mariadb_jdbc_catalog.out 
b/regression-test/data/external_table_p0/jdbc/test_mariadb_jdbc_catalog.out
index 0eb3e6ed9eb..c828848a8fa 100644
--- a/regression-test/data/external_table_p0/jdbc/test_mariadb_jdbc_catalog.out
+++ b/regression-test/data/external_table_p0/jdbc/test_mariadb_jdbc_catalog.out
@@ -59,6 +59,7 @@ tables
 triggers
 user_privileges
 views
+workload_group_privileges
 workload_groups
 workload_policy
 
diff --git 
a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out 
b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out
index e79545774a1..ee5cb342440 100644
--- a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out
+++ b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out
@@ -223,6 +223,7 @@ tables
 triggers
 user_privileges
 views
+workload_group_privileges
 workload_groups
 workload_policy
 
diff --git 
a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog_nereids.out
 
b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog_nereids.out
index fb9bf51ad93..0d7e953567f 100644
--- 
a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog_nereids.out
+++ 
b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog_nereids.out
@@ -191,6 +191,7 @@ tables
 triggers
 user_privileges
 views
+workload_group_privileges
 workload_groups
 workload_policy
 
diff --git 
a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_driver5_catalog.out
 
b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_driver5_catalog.out
index 7e16cadc3c7..953b425394c 100644
--- 
a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_driver5_catalog.out
+++ 
b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_driver5_catalog.out
@@ -233,6 +233,7 @@ tables
 triggers
 user_privileges
 views
+workload_group_privileges
 workload_groups
 workload_policy
 
diff --git a/regression-test/data/workload_manager_p0/test_curd_wlg.out 
b/regression-test/data/workload_manager_p0/test_curd_wlg.out
index 92de73f3278..5d9629aa440 100644
--- a/regression-test/data/workload_manager_p0/test_curd_wlg.out
+++ b/regression-test/data/workload_manager_p0/test_curd_wlg.out
@@ -97,3 +97,52 @@ tag1_wg3     0%      80%     tag1
 -- !select_remote_scan_num_8 --
 -1     -1
 
+-- !select_wgp_1 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+
+-- !select_wgp_2 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_3 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+
+-- !select_wgp_4 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_5 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_6 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+test_wg_priv_role1     test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_7 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_8 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+test_wg_priv_role1     test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_9 --
+'test_wg_priv_user1'@'%'       %       Usage_priv      NO
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+test_wg_priv_role1     %       Usage_priv      NO
+test_wg_priv_role1     test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_10 --
+'test_wg_priv_user1'@'%'       normal  Usage_priv      NO
+'test_wg_priv_user1'@'%'       test_wg_priv_g1 Usage_priv      NO
+test_wg_priv_role1     test_wg_priv_g1 Usage_priv      NO
+
+-- !select_wgp_11 --
+'test_wg_priv_user2'@'%'       normal  Usage_priv      NO
+
+-- !select_wgp_12 --
+
diff --git a/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy 
b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy
index 0aa60af7fbd..76721728bf2 100644
--- a/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy
+++ b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy
@@ -94,6 +94,7 @@ suite("test_crud_wlg") {
     sql "alter workload group normal properties ( 'scan_thread_num'='-1' );"
     sql "alter workload group normal properties ( 'scan_thread_num'='-1' );"
     sql "alter workload group normal properties ( 
'remote_read_bytes_per_second'='-1' );"
+    sql "alter workload group normal properties ( 'read_bytes_per_second'='-1' 
);"
 
     sql "set workload_group=normal;"
 
@@ -640,4 +641,61 @@ suite("test_crud_wlg") {
     sql "drop workload group tag1_mem_wg3;"
     sql "drop workload group bypass_group;"
 
+    // test workload group privilege table
+    sql "set workload_group=normal;"
+    sql "drop user if exists test_wg_priv_user1"
+    sql "drop user if exists test_wg_priv_user2"
+    sql "drop role if exists test_wg_priv_role1"
+    sql "drop workload group if exists test_wg_priv_g1;"
+    // 1 test grant user
+    sql "create workload group test_wg_priv_g1 properties('cpu_share'='1024')"
+
+    sql "create user test_wg_priv_user1"
+    qt_select_wgp_1 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' TO 
test_wg_priv_user1;"
+    qt_select_wgp_2 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "revoke USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' from 
test_wg_priv_user1;"
+    qt_select_wgp_3 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' TO 
test_wg_priv_user1;"
+    qt_select_wgp_4 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+
+
+    // 2 test grant role
+    sql "create role test_wg_priv_role1;"
+    qt_select_wgp_5 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' TO role 
'test_wg_priv_role1';"
+    qt_select_wgp_6 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "revoke USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' from role 
'test_wg_priv_role1';"
+    qt_select_wgp_7 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP 'test_wg_priv_g1' TO role 
'test_wg_priv_role1';"
+    qt_select_wgp_8 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    // 3 test grant %
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP '%' TO test_wg_priv_user1; "
+    sql "GRANT USAGE_PRIV ON WORKLOAD GROUP '%' TO role 'test_wg_priv_role1'; "
+    qt_select_wgp_9 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+    sql "revoke USAGE_PRIV ON WORKLOAD GROUP '%' from test_wg_priv_user1; "
+    sql "revoke USAGE_PRIV ON WORKLOAD GROUP '%' from role 
'test_wg_priv_role1'; "
+    qt_select_wgp_10 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+
+    //4 test row filter
+    sql "create user test_wg_priv_user2"
+    sql "grant SELECT_PRIV on *.*.* to test_wg_priv_user2"
+    connect(user = 'test_wg_priv_user2', password = '', url = 
context.config.jdbcUrl) {
+        qt_select_wgp_11 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+    }
+
+    sql "drop user test_wg_priv_user1"
+    sql "drop user test_wg_priv_user2"
+    sql "drop role test_wg_priv_role1"
+    qt_select_wgp_12 "select 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE from 
information_schema.workload_group_privileges where grantee like 
'%test_wg_priv%' order by 
GRANTEE,WORKLOAD_GROUP_NAME,PRIVILEGE_TYPE,IS_GRANTABLE; "
+    sql "drop workload group test_wg_priv_g1"
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to