diff --git a/be/src/exec/CMakeLists.txt b/be/src/exec/CMakeLists.txt index 044f82d507c370..5bf54673cb144d 100644 --- a/be/src/exec/CMakeLists.txt +++ b/be/src/exec/CMakeLists.txt @@ -85,6 +85,10 @@ set(EXEC_FILES schema_scanner/schema_collations_scanner.cpp schema_scanner/schema_helper.cpp schema_scanner/schema_views_scanner.cpp + schema_scanner/schema_table_privileges_scanner.cpp + schema_scanner/schema_schema_privileges_scanner.cpp + schema_scanner/schema_user_privileges_scanner.cpp + partitioned_hash_table.cc partitioned_hash_table_ir.cc partitioned_aggregation_node.cc diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp index 4c25f9c0c0dfbd..f9d4e833738b43 100644 --- a/be/src/exec/schema_scanner.cpp +++ b/be/src/exec/schema_scanner.cpp @@ -24,6 +24,11 @@ #include "exec/schema_scanner/schema_charsets_scanner.h" #include "exec/schema_scanner/schema_collations_scanner.h" #include "exec/schema_scanner/schema_views_scanner.h" +#include "exec/schema_scanner/schema_table_privileges_scanner.h" +#include "exec/schema_scanner/schema_schema_privileges_scanner.h" +#include "exec/schema_scanner/schema_user_privileges_scanner.h" + + namespace doris { @@ -96,6 +101,12 @@ SchemaScanner* SchemaScanner::create(TSchemaTableType::type type) { return new(std::nothrow) SchemaVariablesScanner(TVarType::SESSION); case TSchemaTableType::SCH_VIEWS: return new(std::nothrow) SchemaViewsScanner(); + case TSchemaTableType::SCH_TABLE_PRIVILEGES: + return new(std::nothrow) SchemaTablePrivilegesScanner(); + case TSchemaTableType::SCH_SCHEMA_PRIVILEGES: + return new(std::nothrow) SchemaSchemaPrivilegesScanner(); + case TSchemaTableType::SCH_USER_PRIVILEGES: + return new(std::nothrow) SchemaUserPrivilegesScanner(); default: return new(std::nothrow) SchemaDummyScanner(); break; diff --git a/be/src/exec/schema_scanner/schema_helper.cpp b/be/src/exec/schema_scanner/schema_helper.cpp index edd03d3746a3ab..f35063fcb20d2a 100644 --- a/be/src/exec/schema_scanner/schema_helper.cpp +++ b/be/src/exec/schema_scanner/schema_helper.cpp @@ -98,6 +98,39 @@ Status SchemaHelper::show_variables( }); } +Status SchemaHelper::list_table_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &request, + TListPrivilegesResult *result) { + return ThriftRpcHelper::rpc(ip, port, + [&request, &result] (FrontendServiceConnection& client) { + client->listTablePrivilegeStatus(*result, request); + }); +} + +Status SchemaHelper::list_schema_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &request, + TListPrivilegesResult *result) { + return ThriftRpcHelper::rpc(ip, port, + [&request, &result] (FrontendServiceConnection& client) { + client->listSchemaPrivilegeStatus(*result, request); + }); +} + +Status SchemaHelper::list_user_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &request, + TListPrivilegesResult *result) { + return ThriftRpcHelper::rpc(ip, port, + [&request, &result] (FrontendServiceConnection& client) { + client->listUserPrivilegeStatus(*result, request); + }); +} + std::string SchemaHelper::extract_db_name(const std::string& full_name) { auto found = full_name.find(':'); if (found == std::string::npos) { diff --git a/be/src/exec/schema_scanner/schema_helper.h b/be/src/exec/schema_scanner/schema_helper.h index 964329dd0a5d1a..b9e7ed9a0c8b67 100644 --- a/be/src/exec/schema_scanner/schema_helper.h +++ b/be/src/exec/schema_scanner/schema_helper.h @@ -55,6 +55,24 @@ class SchemaHelper { const TShowVariableRequest &var_params, TShowVariableResult *var_result); + static Status list_table_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &table_params, + TListPrivilegesResult *privileges_result); + + static Status list_schema_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &table_params, + TListPrivilegesResult *privileges_result); + + static Status list_user_privilege_status( + const std::string& ip, + const int32_t port, + const TGetTablesParams &table_params, + TListPrivilegesResult *privileges_result); + static std::string extract_db_name(const std::string& full_name); }; diff --git a/be/src/exec/schema_scanner/schema_schema_privileges_scanner.cpp b/be/src/exec/schema_scanner/schema_schema_privileges_scanner.cpp new file mode 100644 index 00000000000000..b5589ee4de56a1 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_schema_privileges_scanner.cpp @@ -0,0 +1,160 @@ +// 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_helper.h" +#include "exec/schema_scanner/schema_schema_privileges_scanner.h" +#include "runtime/primitive_type.h" +#include "runtime/string_value.h" +//#include "runtime/datetime_value.h" + +namespace doris +{ + +SchemaScanner::ColumnDesc SchemaSchemaPrivilegesScanner::_s_tbls_columns[] = { + // name, type, size, is_null + { "GRANTEE", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_CATALOG", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_SCHEMA", TYPE_VARCHAR, sizeof(StringValue), false}, + { "PRIVILEGE_TYPE", TYPE_VARCHAR, sizeof(StringValue), false}, + { "IS_GRANTABLE", TYPE_VARCHAR, sizeof(StringValue), true}, +}; + +SchemaSchemaPrivilegesScanner::SchemaSchemaPrivilegesScanner() + : SchemaScanner(_s_tbls_columns, + sizeof(_s_tbls_columns) / sizeof(SchemaScanner::ColumnDesc)), + _priv_index(0) { +} + +SchemaSchemaPrivilegesScanner::~SchemaSchemaPrivilegesScanner() { +} + +Status SchemaSchemaPrivilegesScanner::start(RuntimeState *state) { + if (!_is_init) { + return Status::InternalError("used before initialized."); + } + RETURN_IF_ERROR(get_new_table()); + return Status::OK(); +} + +Status SchemaSchemaPrivilegesScanner::fill_one_row(Tuple *tuple, MemPool *pool) { + // set all bit to not null + memset((void *)tuple, 0, _tuple_desc->num_null_bytes()); + const TPrivilegeStatus& priv_status = _priv_result.privileges[_priv_index]; + // grantee + { + Status status = fill_one_col(&priv_status.grantee, pool, + tuple->get_slot(_tuple_desc->slots()[0]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // catalog + // This value is always def. + { + std::string definer = "def"; + Status status = fill_one_col(&definer, pool, + tuple->get_slot(_tuple_desc->slots()[1]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // schema + { + Status status = fill_one_col(&priv_status.schema, pool, + tuple->get_slot(_tuple_desc->slots()[2]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // privilege type + { + Status status = fill_one_col(&priv_status.privilege_type, pool, + tuple->get_slot(_tuple_desc->slots()[3]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // is grantable + { + Status status = fill_one_col(&priv_status.is_grantable, pool, + tuple->get_slot(_tuple_desc->slots()[4]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + _priv_index++; + return Status::OK(); +} + +Status SchemaSchemaPrivilegesScanner::fill_one_col(const std::string* src, + MemPool *pool, void *slot) { + if (NULL == slot || NULL == pool || NULL == src) { + return Status::InternalError("input pointer is NULL."); + } + StringValue* str_slot = reinterpret_cast(slot); + str_slot->len = src->length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, src->c_str(), str_slot->len); + return Status::OK(); +} + + +Status SchemaSchemaPrivilegesScanner::get_new_table() { + TGetTablesParams table_params; + if (NULL != _param->wild) { + table_params.__set_pattern(*(_param->wild)); + } + if (NULL != _param->current_user_ident) { + table_params.__set_current_user_ident(*(_param->current_user_ident)); + } else { + if (NULL != _param->user) { + table_params.__set_user(*(_param->user)); + } + if (NULL != _param->user_ip) { + table_params.__set_user_ip(*(_param->user_ip)); + } + } + + if (NULL != _param->ip && 0 != _param->port) { + RETURN_IF_ERROR(SchemaHelper::list_schema_privilege_status(*(_param->ip), + _param->port, table_params, &_priv_result)); + } else { + return Status::InternalError("IP or port doesn't exists"); + } + _priv_index = 0; + return Status::OK(); +} + +Status SchemaSchemaPrivilegesScanner::get_next_row(Tuple *tuple, MemPool *pool, bool *eos) { + if (!_is_init) { + return Status::InternalError("Used before initialized."); + } + if (NULL == tuple || NULL == pool || NULL == eos) { + return Status::InternalError("input pointer is NULL."); + } + if (_priv_index >= _priv_result.privileges.size()) { + *eos = true; + return Status::OK(); + } + *eos = false; + return fill_one_row(tuple, pool); +} + +} \ No newline at end of file diff --git a/be/src/exec/schema_scanner/schema_schema_privileges_scanner.h b/be/src/exec/schema_scanner/schema_schema_privileges_scanner.h new file mode 100644 index 00000000000000..6d9fc03867b443 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_schema_privileges_scanner.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_SCHEMA_PRIVILEGES_SCANNER_H +#define DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_SCHEMA_PRIVILEGES_SCANNER_H + +#include "exec/schema_scanner.h" +#include "gen_cpp/FrontendService_types.h" + +namespace doris { + +class SchemaSchemaPrivilegesScanner : public SchemaScanner { +public: + SchemaSchemaPrivilegesScanner(); + virtual ~SchemaSchemaPrivilegesScanner(); + + virtual Status start(RuntimeState *state); + virtual Status get_next_row(Tuple *tuple, MemPool *pool, bool *eos); + +private: + Status get_new_table(); + Status fill_one_row(Tuple *tuple, MemPool *pool); + Status fill_one_col(const std::string* src, MemPool *pool, void* slot); + + int _priv_index; + TListPrivilegesResult _priv_result; + static SchemaScanner::ColumnDesc _s_tbls_columns[]; +}; + +} + +#endif diff --git a/be/src/exec/schema_scanner/schema_table_privileges_scanner.cpp b/be/src/exec/schema_scanner/schema_table_privileges_scanner.cpp new file mode 100644 index 00000000000000..6d3d39000450a8 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_table_privileges_scanner.cpp @@ -0,0 +1,168 @@ +// 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_helper.h" +#include "exec/schema_scanner/schema_table_privileges_scanner.h" +#include "runtime/primitive_type.h" +#include "runtime/string_value.h" +//#include "runtime/datetime_value.h" + +namespace doris +{ + +SchemaScanner::ColumnDesc SchemaTablePrivilegesScanner::_s_tbls_columns[] = { + // name, type, size, is_null + { "GRANTEE", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_CATALOG", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_SCHEMA", TYPE_VARCHAR, sizeof(StringValue), false}, + { "TABLE_NAME", TYPE_VARCHAR, sizeof(StringValue), false}, + { "PRIVILEGE_TYPE", TYPE_VARCHAR, sizeof(StringValue), false}, + { "IS_GRANTABLE", TYPE_VARCHAR, sizeof(StringValue), true}, +}; + +SchemaTablePrivilegesScanner::SchemaTablePrivilegesScanner() + : SchemaScanner(_s_tbls_columns, + sizeof(_s_tbls_columns) / sizeof(SchemaScanner::ColumnDesc)), + _priv_index(0) { +} + +SchemaTablePrivilegesScanner::~SchemaTablePrivilegesScanner() { +} + +Status SchemaTablePrivilegesScanner::start(RuntimeState *state) { + if (!_is_init) { + return Status::InternalError("used before initialized."); + } + RETURN_IF_ERROR(get_new_table()); + return Status::OK(); +} + +Status SchemaTablePrivilegesScanner::fill_one_row(Tuple *tuple, MemPool *pool) { + // set all bit to not null + memset((void *)tuple, 0, _tuple_desc->num_null_bytes()); + const TPrivilegeStatus& priv_status = _priv_result.privileges[_priv_index]; + // grantee + { + Status status = fill_one_col(&priv_status.grantee, pool, + tuple->get_slot(_tuple_desc->slots()[0]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // catalog + // This value is always def. + { + std::string definer = "def"; + Status status = fill_one_col(&definer, pool, + tuple->get_slot(_tuple_desc->slots()[1]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // schema + { + Status status = fill_one_col(&priv_status.schema, pool, + tuple->get_slot(_tuple_desc->slots()[2]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // table name + { + Status status = fill_one_col(&priv_status.table_name, pool, + tuple->get_slot(_tuple_desc->slots()[3]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // privilege type + { + Status status = fill_one_col(&priv_status.privilege_type, pool, + tuple->get_slot(_tuple_desc->slots()[4]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // is grantable + { + Status status = fill_one_col(&priv_status.is_grantable, pool, + tuple->get_slot(_tuple_desc->slots()[5]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + _priv_index++; + return Status::OK(); +} + +Status SchemaTablePrivilegesScanner::fill_one_col(const std::string* src, + MemPool *pool, void* slot) { + if (NULL == slot || NULL == pool || NULL == src) { + return Status::InternalError("input pointer is NULL."); + } + StringValue* str_slot = reinterpret_cast(slot); + str_slot->len = src->length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, src->c_str(), str_slot->len); + return Status::OK(); +} + +Status SchemaTablePrivilegesScanner::get_new_table() { + TGetTablesParams table_params; + if (NULL != _param->wild) { + table_params.__set_pattern(*(_param->wild)); + } + if (NULL != _param->current_user_ident) { + table_params.__set_current_user_ident(*(_param->current_user_ident)); + } else { + if (NULL != _param->user) { + table_params.__set_user(*(_param->user)); + } + if (NULL != _param->user_ip) { + table_params.__set_user_ip(*(_param->user_ip)); + } + } + + if (NULL != _param->ip && 0 != _param->port) { + RETURN_IF_ERROR(SchemaHelper::list_table_privilege_status(*(_param->ip), + _param->port, table_params, &_priv_result)); + } else { + return Status::InternalError("IP or port doesn't exists"); + } + _priv_index = 0; + return Status::OK(); +} + +Status SchemaTablePrivilegesScanner::get_next_row(Tuple *tuple, MemPool *pool, bool *eos) { + if (!_is_init) { + return Status::InternalError("Used before initialized."); + } + if (NULL == tuple || NULL == pool || NULL == eos) { + return Status::InternalError("input pointer is NULL."); + } + if (_priv_index >= _priv_result.privileges.size()) { + *eos = true; + return Status::OK(); + } + *eos = false; + return fill_one_row(tuple, pool); +} + +} \ No newline at end of file diff --git a/be/src/exec/schema_scanner/schema_table_privileges_scanner.h b/be/src/exec/schema_scanner/schema_table_privileges_scanner.h new file mode 100644 index 00000000000000..1e5f2e6e864b34 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_table_privileges_scanner.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_TABLE_PRIVILEGES_SCANNER_H +#define DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_TABLE_PRIVILEGES_SCANNER_H + +#include "exec/schema_scanner.h" +#include "gen_cpp/FrontendService_types.h" + +namespace doris { + +class SchemaTablePrivilegesScanner : public SchemaScanner { +public: + SchemaTablePrivilegesScanner(); + virtual ~SchemaTablePrivilegesScanner(); + + virtual Status start(RuntimeState *state); + virtual Status get_next_row(Tuple *tuple, MemPool *pool, bool *eos); + +private: + Status get_new_table(); + Status fill_one_row(Tuple *tuple, MemPool *pool); + Status fill_one_col(const std::string* src, MemPool *pool, void* slot); + + int _priv_index; + TListPrivilegesResult _priv_result; + static SchemaScanner::ColumnDesc _s_tbls_columns[]; +}; + +} + +#endif diff --git a/be/src/exec/schema_scanner/schema_user_privileges_scanner.cpp b/be/src/exec/schema_scanner/schema_user_privileges_scanner.cpp new file mode 100644 index 00000000000000..3d56b89dd9f706 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_user_privileges_scanner.cpp @@ -0,0 +1,150 @@ +// 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_helper.h" +#include "exec/schema_scanner/schema_user_privileges_scanner.h" +#include "runtime/primitive_type.h" +#include "runtime/string_value.h" +//#include "runtime/datetime_value.h" + +namespace doris +{ + +SchemaScanner::ColumnDesc SchemaUserPrivilegesScanner::_s_tbls_columns[] = { + // name, type, size, is_null + { "GRANTEE", TYPE_VARCHAR, sizeof(StringValue), true}, + { "TABLE_CATALOG", TYPE_VARCHAR, sizeof(StringValue), true}, + { "PRIVILEGE_TYPE", TYPE_VARCHAR, sizeof(StringValue), false}, + { "IS_GRANTABLE", TYPE_VARCHAR, sizeof(StringValue), true}, +}; + +SchemaUserPrivilegesScanner::SchemaUserPrivilegesScanner() + : SchemaScanner(_s_tbls_columns, + sizeof(_s_tbls_columns) / sizeof(SchemaScanner::ColumnDesc)), + _priv_index(0) { +} + +SchemaUserPrivilegesScanner::~SchemaUserPrivilegesScanner() { +} + +Status SchemaUserPrivilegesScanner::start(RuntimeState *state) { + if (!_is_init) { + return Status::InternalError("used before initialized."); + } + RETURN_IF_ERROR(get_new_table()); + return Status::OK(); +} + +Status SchemaUserPrivilegesScanner::fill_one_row(Tuple *tuple, MemPool *pool) { + // set all bit to not null + memset((void *)tuple, 0, _tuple_desc->num_null_bytes()); + const TPrivilegeStatus& priv_status = _priv_result.privileges[_priv_index]; + // grantee + { + Status status = fill_one_col(&priv_status.grantee, pool, + tuple->get_slot(_tuple_desc->slots()[0]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // catalog + // This value is always def. + { + std::string definer = "def"; + Status status = fill_one_col(&definer, pool, + tuple->get_slot(_tuple_desc->slots()[1]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // privilege type + { + Status status = fill_one_col(&priv_status.privilege_type, pool, + tuple->get_slot(_tuple_desc->slots()[2]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + // is grantable + { + Status status = fill_one_col(&priv_status.is_grantable, pool, + tuple->get_slot(_tuple_desc->slots()[3]->tuple_offset())); + if (!status.ok()) { + return status; + } + } + _priv_index++; + return Status::OK(); +} + +Status SchemaUserPrivilegesScanner::fill_one_col(const std::string* src, + MemPool *pool, void *slot) { + if (NULL == slot || NULL == pool || NULL == src) { + return Status::InternalError("input pointer is NULL."); + } + StringValue* str_slot = reinterpret_cast(slot); + str_slot->len = src->length(); + str_slot->ptr = (char *)pool->allocate(str_slot->len); + if (NULL == str_slot->ptr) { + return Status::InternalError("Allocate memcpy failed."); + } + memcpy(str_slot->ptr, src->c_str(), str_slot->len); + return Status::OK(); +} + +Status SchemaUserPrivilegesScanner::get_new_table() { + TGetTablesParams table_params; + if (NULL != _param->wild) { + table_params.__set_pattern(*(_param->wild)); + } + if (NULL != _param->current_user_ident) { + table_params.__set_current_user_ident(*(_param->current_user_ident)); + } else { + if (NULL != _param->user) { + table_params.__set_user(*(_param->user)); + } + if (NULL != _param->user_ip) { + table_params.__set_user_ip(*(_param->user_ip)); + } + } + + if (NULL != _param->ip && 0 != _param->port) { + RETURN_IF_ERROR(SchemaHelper::list_user_privilege_status(*(_param->ip), + _param->port, table_params, &_priv_result)); + } else { + return Status::InternalError("IP or port doesn't exists"); + } + _priv_index = 0; + return Status::OK(); +} + +Status SchemaUserPrivilegesScanner::get_next_row(Tuple *tuple, MemPool *pool, bool *eos) { + if (!_is_init) { + return Status::InternalError("Used before initialized."); + } + if (NULL == tuple || NULL == pool || NULL == eos) { + return Status::InternalError("input pointer is NULL."); + } + if (_priv_index >= _priv_result.privileges.size()) { + *eos = true; + return Status::OK(); + } + *eos = false; + return fill_one_row(tuple, pool); +} + +} diff --git a/be/src/exec/schema_scanner/schema_user_privileges_scanner.h b/be/src/exec/schema_scanner/schema_user_privileges_scanner.h new file mode 100644 index 00000000000000..aada2e7b69c782 --- /dev/null +++ b/be/src/exec/schema_scanner/schema_user_privileges_scanner.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_USER_PRIVILEGES_SCANNER_H +#define DORIS_BE_SRC_QUERY_EXEC_SCHEMA_SCANNER_SCHEMA_USER_PRIVILEGES_SCANNER_H + +#include "exec/schema_scanner.h" +#include "gen_cpp/FrontendService_types.h" + +namespace doris { + +class SchemaUserPrivilegesScanner : public SchemaScanner { +public: + SchemaUserPrivilegesScanner(); + virtual ~SchemaUserPrivilegesScanner(); + + virtual Status start(RuntimeState *state); + virtual Status get_next_row(Tuple *tuple, MemPool *pool, bool *eos); + +private: + Status get_new_table(); + Status fill_one_row(Tuple *tuple, MemPool *pool); + Status fill_one_col(const std::string* src, MemPool *pool, void* slot); + + int _priv_index; + TListPrivilegesResult _priv_result; + static SchemaScanner::ColumnDesc _s_tbls_columns[]; +}; + +} + +#endif 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 97ec5be3144b0c..01da908510df2c 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 @@ -40,6 +40,9 @@ public class SchemaTable extends Table { private final static int NAME_CHAR_LEN = 64; private final static int MAX_FIELD_VARCHARLENGTH = 65535; private final static int MY_CS_NAME_SIZE = 32; + private final static int GRANTEE_len = 81; + private final static int PRIVILEGE_TYPE_LEN = 64; + private final static int IS_GRANTABLE_LEN = 3; private SchemaTableType schemaTableType; protected SchemaTable(long id, String name, TableType type, List baseSchema) { @@ -103,12 +106,33 @@ public static Builder builder() { "table_privileges", TableType.SCHEMA, builder() - .column("GRANTEE", ScalarType.createVarchar(NAME_CHAR_LEN)) - .column("TABLE_CATALOG", ScalarType.createVarchar(NAME_CHAR_LEN)) + .column("GRANTEE", ScalarType.createVarchar(GRANTEE_len)) + .column("TABLE_CATALOG", ScalarType.createVarchar(FN_REFLEN)) .column("TABLE_SCHEMA", ScalarType.createVarchar(NAME_CHAR_LEN)) .column("TABLE_NAME", ScalarType.createVarchar(NAME_CHAR_LEN)) - .column("PRIVILEGE_TYPE", ScalarType.createVarchar(NAME_CHAR_LEN)) - .column("IS_GRANTABLE", ScalarType.createVarchar(NAME_CHAR_LEN)) + .column("PRIVILEGE_TYPE", ScalarType.createVarchar(PRIVILEGE_TYPE_LEN)) + .column("IS_GRANTABLE", ScalarType.createVarchar(IS_GRANTABLE_LEN)) + .build())) + .put("schema_privileges", new SchemaTable( + SystemIdGenerator.getNextId(), + "schema_privileges", + TableType.SCHEMA, + builder() + .column("GRANTEE", ScalarType.createVarchar(GRANTEE_len)) + .column("TABLE_CATALOG", ScalarType.createVarchar(FN_REFLEN)) + .column("TABLE_SCHEMA", ScalarType.createVarchar(NAME_CHAR_LEN)) + .column("PRIVILEGE_TYPE", ScalarType.createVarchar(PRIVILEGE_TYPE_LEN)) + .column("IS_GRANTABLE", ScalarType.createVarchar(IS_GRANTABLE_LEN)) + .build())) + .put("user_privileges", new SchemaTable( + SystemIdGenerator.getNextId(), + "user_privileges", + TableType.SCHEMA, + builder() + .column("GRANTEE", ScalarType.createVarchar(GRANTEE_len)) + .column("TABLE_CATALOG", ScalarType.createVarchar(FN_REFLEN)) + .column("PRIVILEGE_TYPE", ScalarType.createVarchar(PRIVILEGE_TYPE_LEN)) + .column("IS_GRANTABLE", ScalarType.createVarchar(IS_GRANTABLE_LEN)) .build())) .put("referential_constraints", new SchemaTable( SystemIdGenerator.getNextId(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java index 9154c7c7af743b..4cbe28cfce70b5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java @@ -43,6 +43,7 @@ import org.apache.doris.persist.PrivInfo; import org.apache.doris.qe.ConnectContext; import org.apache.doris.thrift.TFetchResourceResult; +import org.apache.doris.thrift.TPrivilegeStatus; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; @@ -1300,6 +1301,113 @@ public List> getRoleInfo() { } } + // Used for creating table_privileges table in information_schema. + public void getTablePrivStatus(List tblPrivResult, UserIdentity currentUser) { + readLock(); + try { + for (PrivEntry entry : tablePrivTable.getEntries()) { + TablePrivEntry tblPrivEntry = (TablePrivEntry) entry; + String dbName = ClusterNamespace.getNameFromFullName(tblPrivEntry.getOrigDb()); + String tblName = tblPrivEntry.getOrigTbl(); + + if (dbName.equals("information_schema" /* Don't show privileges in information_schema */) + || !checkTblPriv(currentUser, tblPrivEntry.getOrigDb(), tblName, PrivPredicate.SHOW)) { + continue; + } + + String grantee = new String("\'").concat(ClusterNamespace.getNameFromFullName(tblPrivEntry.getOrigUser())) + .concat("\'@\'").concat(tblPrivEntry.getOrigHost()).concat("\'"); + String isGrantable = tblPrivEntry.getPrivSet().get(2) ? "YES" : "NO"; // GRANT_PRIV + for (PaloPrivilege paloPriv : tblPrivEntry.getPrivSet().toPrivilegeList()) { + if (!PaloPrivilege.privInPaloToMysql.containsKey(paloPriv)) { + continue; + } + TPrivilegeStatus status = new TPrivilegeStatus(); + status.setTableName(tblName); + status.setPrivilegeType(PaloPrivilege.privInPaloToMysql.get(paloPriv)); + status.setGrantee(grantee); + status.setSchema(dbName); + status.setIsGrantable(isGrantable); + tblPrivResult.add(status); + } + } + } finally { + readUnlock(); + } + } + + // Used for creating schema_privileges table in information_schema. + public void getSchemaPrivStatus(List dbPrivResult, UserIdentity currentUser) { + readLock(); + try { + for (PrivEntry entry : dbPrivTable.getEntries()) { + DbPrivEntry dbPrivEntry = (DbPrivEntry) entry; + String origDb = dbPrivEntry.getOrigDb(); + String dbName = ClusterNamespace.getNameFromFullName(dbPrivEntry.getOrigDb()); + + if (dbName.equals("information_schema" /* Don't show privileges in information_schema */) + || !checkDbPriv(currentUser, origDb, PrivPredicate.SHOW)) { + continue; + } + + String grantee = new String("\'").concat(ClusterNamespace.getNameFromFullName(dbPrivEntry.getOrigUser())) + .concat("\'@\'").concat(dbPrivEntry.getOrigHost()).concat("\'"); + String isGrantable = dbPrivEntry.getPrivSet().get(2) ? "YES" : "NO"; // GRANT_PRIV + for (PaloPrivilege paloPriv : dbPrivEntry.getPrivSet().toPrivilegeList()) { + if (!PaloPrivilege.privInPaloToMysql.containsKey(paloPriv)) { + continue; + } + TPrivilegeStatus status = new TPrivilegeStatus(); + status.setPrivilegeType(PaloPrivilege.privInPaloToMysql.get(paloPriv)); + status.setGrantee(grantee); + status.setSchema(dbName); + status.setIsGrantable(isGrantable); + dbPrivResult.add(status); + } + } + } finally { + readUnlock(); + } + } + + // Used for creating user_privileges table in information_schema. + public void getGlobalPrivStatus(List userPrivResult, UserIdentity currentUser) { + readLock(); + try { + if (!checkGlobalPriv(currentUser, PrivPredicate.SHOW)) { + return; + } + + for (PrivEntry userPrivEntry : userPrivTable.getEntries()) { + String grantee = new String("\'").concat(ClusterNamespace.getNameFromFullName(userPrivEntry.getOrigUser())) + .concat("\'@\'").concat(userPrivEntry.getOrigHost()).concat("\'"); + String isGrantable = userPrivEntry.getPrivSet().get(2) ? "YES" : "NO"; // GRANT_PRIV + for (PaloPrivilege paloPriv : userPrivEntry.getPrivSet().toPrivilegeList()) { + if (paloPriv == PaloPrivilege.ADMIN_PRIV) { + for (String priv : PaloPrivilege.privInPaloToMysql.values()) { // ADMIN_PRIV includes all privileges of table and resource. + TPrivilegeStatus status = new TPrivilegeStatus(); + status.setPrivilegeType(priv); + status.setGrantee(grantee); + status.setIsGrantable("YES"); + userPrivResult.add(status); + } + break; + } + if (!PaloPrivilege.privInPaloToMysql.containsKey(paloPriv)) { + continue; + } + TPrivilegeStatus status = new TPrivilegeStatus(); + status.setPrivilegeType(PaloPrivilege.privInPaloToMysql.get(paloPriv)); + status.setGrantee(grantee); + status.setIsGrantable(isGrantable); + userPrivResult.add(status); + } + } + } finally { + readUnlock(); + } + } + public static PaloAuth read(DataInput in) throws IOException { PaloAuth auth = new PaloAuth(); auth.readFields(in); diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloPrivilege.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloPrivilege.java index 120adbf3466336..fb4599c233b56c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloPrivilege.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloPrivilege.java @@ -17,6 +17,10 @@ package org.apache.doris.mysql.privilege; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + public enum PaloPrivilege { NODE_PRIV("Node_priv", 0, "Privilege for cluster node operations"), ADMIN_PRIV("Admin_priv", 1, "Privilege for admin user"), @@ -40,6 +44,16 @@ public enum PaloPrivilege { USAGE_PRIV }; + public static Map privInPaloToMysql = + ImmutableMap.builder() // No NODE_PRIV and ADMIN_PRIV in the mysql + .put(SELECT_PRIV, "SELECT") + .put(LOAD_PRIV, "INSERT") + .put(ALTER_PRIV, "ALTER") + .put(CREATE_PRIV, "CREATE") + .put(DROP_PRIV, "DROP") + .put(USAGE_PRIV, "USAGE") + .build(); + private String name; private int idx; private String desc; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivTable.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivTable.java index 423dfed4f14a96..7c3b042713ab54 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PrivTable.java @@ -83,6 +83,10 @@ public PrivEntry addEntry(PrivEntry newEntry, boolean errOnExist, boolean errOnN } } + public List getEntries() { + return entries; + } + public void dropEntry(PrivEntry entry) { Iterator iter = entries.iterator(); while (iter.hasNext()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java index c44d2730351f79..1892e7f560ab9b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java @@ -70,6 +70,7 @@ import org.apache.doris.thrift.TGetTablesResult; import org.apache.doris.thrift.TIsMethodSupportedRequest; import org.apache.doris.thrift.TListTableStatusResult; +import org.apache.doris.thrift.TListPrivilegesResult; import org.apache.doris.thrift.TLoadCheckRequest; import org.apache.doris.thrift.TLoadTxnBeginRequest; import org.apache.doris.thrift.TLoadTxnBeginResult; @@ -96,6 +97,7 @@ import org.apache.doris.thrift.TStreamLoadPutRequest; import org.apache.doris.thrift.TStreamLoadPutResult; import org.apache.doris.thrift.TTableStatus; +import org.apache.doris.thrift.TPrivilegeStatus; import org.apache.doris.thrift.TUniqueId; import org.apache.doris.thrift.TUpdateExportTaskStatusRequest; import org.apache.doris.thrift.TUpdateMiniEtlTaskStatusRequest; @@ -286,6 +288,57 @@ public TListTableStatusResult listTableStatus(TGetTablesParams params) throws TE return result; } + @Override + public TListPrivilegesResult listTablePrivilegeStatus(TGetTablesParams params) throws TException { + LOG.debug("get list table privileges request: {}", params); + TListPrivilegesResult result = new TListPrivilegesResult(); + List tblPrivResult = Lists.newArrayList(); + result.setPrivileges(tblPrivResult); + + UserIdentity currentUser = null; + if (params.isSetCurrentUserIdent()) { + currentUser = UserIdentity.fromThrift(params.current_user_ident); + } else { + currentUser = UserIdentity.createAnalyzedUserIdentWithIp(params.user, params.user_ip); + } + Catalog.getCurrentCatalog().getAuth().getTablePrivStatus(tblPrivResult, currentUser); + return result; + } + + @Override + public TListPrivilegesResult listSchemaPrivilegeStatus(TGetTablesParams params) throws TException { + LOG.debug("get list schema privileges request: {}", params); + TListPrivilegesResult result = new TListPrivilegesResult(); + List tblPrivResult = Lists.newArrayList(); + result.setPrivileges(tblPrivResult); + + UserIdentity currentUser = null; + if (params.isSetCurrentUserIdent()) { + currentUser = UserIdentity.fromThrift(params.current_user_ident); + } else { + currentUser = UserIdentity.createAnalyzedUserIdentWithIp(params.user, params.user_ip); + } + Catalog.getCurrentCatalog().getAuth().getSchemaPrivStatus(tblPrivResult, currentUser); + return result; + } + + @Override + public TListPrivilegesResult listUserPrivilegeStatus(TGetTablesParams params) throws TException { + LOG.debug("get list user privileges request: {}", params); + TListPrivilegesResult result = new TListPrivilegesResult(); + List userPrivResult = Lists.newArrayList(); + result.setPrivileges(userPrivResult); + + UserIdentity currentUser = null; + if (params.isSetCurrentUserIdent()) { + currentUser = UserIdentity.fromThrift(params.current_user_ident); + } else { + currentUser = UserIdentity.createAnalyzedUserIdentWithIp(params.user, params.user_ip); + } + Catalog.getCurrentCatalog().getAuth().getGlobalPrivStatus(userPrivResult, currentUser); + return result; + } + @Override public TFeResult updateExportTaskStatus(TUpdateExportTaskStatusRequest request) throws TException { TStatus status = new TStatus(TStatusCode.OK); diff --git a/gensrc/thrift/FrontendService.thrift b/gensrc/thrift/FrontendService.thrift index 71b969c79bb798..33b25fb135701d 100644 --- a/gensrc/thrift/FrontendService.thrift +++ b/gensrc/thrift/FrontendService.thrift @@ -324,6 +324,18 @@ struct TGetTablesResult { 1: list tables } +struct TPrivilegeStatus { + 1: optional string table_name + 2: optional string privilege_type + 3: optional string grantee + 4: optional string schema + 5: optional string is_grantable +} + +struct TListPrivilegesResult{ + 1: required list privileges +} + struct TReportExecStatusResult { // required in V1 1: optional Status.TStatus status @@ -662,6 +674,9 @@ service FrontendService { TMasterOpResult forward(TMasterOpRequest params) TListTableStatusResult listTableStatus(1:TGetTablesParams params) + TListPrivilegesResult listTablePrivilegeStatus(1:TGetTablesParams params) + TListPrivilegesResult listSchemaPrivilegeStatus(1:TGetTablesParams params) + TListPrivilegesResult listUserPrivilegeStatus(1:TGetTablesParams params) TFeResult updateExportTaskStatus(1:TUpdateExportTaskStatusRequest request)