From e017bacc48450a657802b2c6f7276e45670bc54a Mon Sep 17 00:00:00 2001 From: Vitaly Baranov Date: Mon, 17 Feb 2020 05:59:56 +0300 Subject: [PATCH] Implement SQL queries for creating and controlling roles. --- dbms/src/Common/ErrorCodes.cpp | 1 + .../InterpreterCreateRoleQuery.cpp | 62 ++++++++++++ .../Interpreters/InterpreterCreateRoleQuery.h | 26 +++++ .../InterpreterCreateUserQuery.cpp | 40 +++++++- .../Interpreters/InterpreterCreateUserQuery.h | 3 +- .../InterpreterDropAccessEntityQuery.cpp | 13 ++- dbms/src/Interpreters/InterpreterFactory.cpp | 12 +++ .../Interpreters/InterpreterGrantQuery.cpp | 87 ++++++++++++++--- .../Interpreters/InterpreterSetRoleQuery.cpp | 95 +++++++++++++++++++ .../Interpreters/InterpreterSetRoleQuery.h | 30 ++++++ ...InterpreterShowCreateAccessEntityQuery.cpp | 3 + .../InterpreterShowGrantsQuery.cpp | 53 ++++++++++- dbms/src/Parsers/ASTCreateRoleQuery.cpp | 46 +++++++++ dbms/src/Parsers/ASTCreateRoleQuery.h | 29 ++++++ dbms/src/Parsers/ASTCreateUserQuery.cpp | 11 +++ dbms/src/Parsers/ASTCreateUserQuery.h | 6 ++ dbms/src/Parsers/ASTDropAccessEntityQuery.cpp | 1 + dbms/src/Parsers/ASTDropAccessEntityQuery.h | 6 +- dbms/src/Parsers/ASTGrantQuery.cpp | 32 ++++++- dbms/src/Parsers/ASTGrantQuery.h | 5 + dbms/src/Parsers/ASTSetRoleQuery.cpp | 43 +++++++++ dbms/src/Parsers/ASTSetRoleQuery.h | 31 ++++++ dbms/src/Parsers/ParserCreateRoleQuery.cpp | 70 ++++++++++++++ dbms/src/Parsers/ParserCreateRoleQuery.h | 20 ++++ dbms/src/Parsers/ParserCreateUserQuery.cpp | 22 +++++ .../Parsers/ParserDropAccessEntityQuery.cpp | 10 +- .../src/Parsers/ParserDropAccessEntityQuery.h | 3 +- dbms/src/Parsers/ParserGrantQuery.cpp | 37 +++++++- dbms/src/Parsers/ParserQuery.cpp | 6 ++ dbms/src/Parsers/ParserSetRoleQuery.cpp | 80 ++++++++++++++++ dbms/src/Parsers/ParserSetRoleQuery.h | 18 ++++ 31 files changed, 864 insertions(+), 37 deletions(-) create mode 100644 dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp create mode 100644 dbms/src/Interpreters/InterpreterCreateRoleQuery.h create mode 100644 dbms/src/Interpreters/InterpreterSetRoleQuery.cpp create mode 100644 dbms/src/Interpreters/InterpreterSetRoleQuery.h create mode 100644 dbms/src/Parsers/ASTCreateRoleQuery.cpp create mode 100644 dbms/src/Parsers/ASTCreateRoleQuery.h create mode 100644 dbms/src/Parsers/ASTSetRoleQuery.cpp create mode 100644 dbms/src/Parsers/ASTSetRoleQuery.h create mode 100644 dbms/src/Parsers/ParserCreateRoleQuery.cpp create mode 100644 dbms/src/Parsers/ParserCreateRoleQuery.h create mode 100644 dbms/src/Parsers/ParserSetRoleQuery.cpp create mode 100644 dbms/src/Parsers/ParserSetRoleQuery.h diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index fe2c95fd6b..8330167116 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -483,6 +483,7 @@ namespace ErrorCodes extern const int INVALID_GRANT = 509; extern const int CACHE_DICTIONARY_UPDATE_FAIL = 510; extern const int UNKNOWN_ROLE = 511; + extern const int SET_NON_GRANTED_ROLE = 512; extern const int KEEPER_EXCEPTION = 999; extern const int POCO_EXCEPTION = 1000; diff --git a/dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp b/dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp new file mode 100644 index 0000000000..f1c58f9d9b --- /dev/null +++ b/dbms/src/Interpreters/InterpreterCreateRoleQuery.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ +BlockIO InterpreterCreateRoleQuery::execute() +{ + const auto & query = query_ptr->as(); + auto & access_control = context.getAccessControlManager(); + if (query.alter) + context.checkAccess(AccessType::CREATE_ROLE | AccessType::DROP_ROLE); + else + context.checkAccess(AccessType::CREATE_ROLE); + + if (query.alter) + { + auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr + { + auto updated_role = typeid_cast>(entity->clone()); + updateRoleFromQuery(*updated_role, query); + return updated_role; + }; + if (query.if_exists) + { + if (auto id = access_control.find(query.name)) + access_control.tryUpdate(*id, update_func); + } + else + access_control.update(access_control.getID(query.name), update_func); + } + else + { + auto new_role = std::make_shared(); + updateRoleFromQuery(*new_role, query); + + if (query.if_not_exists) + access_control.tryInsert(new_role); + else if (query.or_replace) + access_control.insertOrReplace(new_role); + else + access_control.insert(new_role); + } + + return {}; +} + + +void InterpreterCreateRoleQuery::updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query) +{ + if (query.alter) + { + if (!query.new_name.empty()) + role.setName(query.new_name); + } + else + role.setName(query.name); +} +} diff --git a/dbms/src/Interpreters/InterpreterCreateRoleQuery.h b/dbms/src/Interpreters/InterpreterCreateRoleQuery.h new file mode 100644 index 0000000000..8ceb645ea7 --- /dev/null +++ b/dbms/src/Interpreters/InterpreterCreateRoleQuery.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + + +namespace DB +{ +class ASTCreateRoleQuery; +struct Role; + + +class InterpreterCreateRoleQuery : public IInterpreter +{ +public: + InterpreterCreateRoleQuery(const ASTPtr & query_ptr_, Context & context_) : query_ptr(query_ptr_), context(context_) {} + + BlockIO execute() override; + +private: + void updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query); + + ASTPtr query_ptr; + Context & context; +}; +} diff --git a/dbms/src/Interpreters/InterpreterCreateUserQuery.cpp b/dbms/src/Interpreters/InterpreterCreateUserQuery.cpp index 8f3c8a9f2b..db7f34a218 100644 --- a/dbms/src/Interpreters/InterpreterCreateUserQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateUserQuery.cpp @@ -1,24 +1,47 @@ #include -#include #include +#include +#include #include #include +#include +#include +#include namespace DB { +namespace ErrorCodes +{ + extern const int SET_NON_GRANTED_ROLE; +} + + BlockIO InterpreterCreateUserQuery::execute() { const auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); context.checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER); + GenericRoleSet * default_roles_from_query = nullptr; + GenericRoleSet temp_role_set; + if (query.default_roles) + { + default_roles_from_query = &temp_role_set; + *default_roles_from_query = GenericRoleSet{*query.default_roles, access_control}; + if (!query.alter && !default_roles_from_query->all) + { + for (const UUID & role : default_roles_from_query->getMatchingIDs()) + context.getAccessRights()->checkAdminOption(role); + } + } + if (query.alter) { auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr { auto updated_user = typeid_cast>(entity->clone()); - updateUserFromQuery(*updated_user, query); + updateUserFromQuery(*updated_user, query, default_roles_from_query); return updated_user; }; if (query.if_exists) @@ -32,7 +55,7 @@ BlockIO InterpreterCreateUserQuery::execute() else { auto new_user = std::make_shared(); - updateUserFromQuery(*new_user, query); + updateUserFromQuery(*new_user, query, default_roles_from_query); if (query.if_not_exists) access_control.tryInsert(new_user); @@ -46,7 +69,7 @@ BlockIO InterpreterCreateUserQuery::execute() } -void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query) +void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query, const GenericRoleSet * default_roles_from_query) { if (query.alter) { @@ -66,7 +89,16 @@ void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreat if (query.add_hosts) user.allowed_client_hosts.add(*query.add_hosts); + if (default_roles_from_query) + { + if (!query.alter && !default_roles_from_query->all) + boost::range::copy(default_roles_from_query->getMatchingIDs(), std::inserter(user.granted_roles, user.granted_roles.end())); + + InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, *default_roles_from_query); + } + if (query.profile) user.profile = *query.profile; } + } diff --git a/dbms/src/Interpreters/InterpreterCreateUserQuery.h b/dbms/src/Interpreters/InterpreterCreateUserQuery.h index f040a23a7c..c2a6fc46f6 100644 --- a/dbms/src/Interpreters/InterpreterCreateUserQuery.h +++ b/dbms/src/Interpreters/InterpreterCreateUserQuery.h @@ -7,6 +7,7 @@ namespace DB { class ASTCreateUserQuery; +class GenericRoleSet; struct User; @@ -18,7 +19,7 @@ public: BlockIO execute() override; private: - void updateUserFromQuery(User & user, const ASTCreateUserQuery & query); + void updateUserFromQuery(User & user, const ASTCreateUserQuery & query, const GenericRoleSet * default_roles_from_query); ASTPtr query_ptr; Context & context; diff --git a/dbms/src/Interpreters/InterpreterDropAccessEntityQuery.cpp b/dbms/src/Interpreters/InterpreterDropAccessEntityQuery.cpp index 791314a99f..c69ce3ade4 100644 --- a/dbms/src/Interpreters/InterpreterDropAccessEntityQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDropAccessEntityQuery.cpp @@ -3,9 +3,10 @@ #include #include #include +#include +#include #include #include -#include #include @@ -29,6 +30,16 @@ BlockIO InterpreterDropAccessEntityQuery::execute() return {}; } + case Kind::ROLE: + { + context.checkAccess(AccessType::DROP_ROLE); + if (query.if_exists) + access_control.tryRemove(access_control.find(query.names)); + else + access_control.remove(access_control.getIDs(query.names)); + return {}; + } + case Kind::QUOTA: { context.checkAccess(AccessType::DROP_QUOTA); diff --git a/dbms/src/Interpreters/InterpreterFactory.cpp b/dbms/src/Interpreters/InterpreterFactory.cpp index 87c2d04b2e..0e241aab12 100644 --- a/dbms/src/Interpreters/InterpreterFactory.cpp +++ b/dbms/src/Interpreters/InterpreterFactory.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +130,10 @@ std::unique_ptr InterpreterFactory::get(ASTPtr & query, Context & /// readonly is checked inside InterpreterSetQuery return std::make_unique(query, context); } + else if (query->as()) + { + return std::make_unique(query, context); + } else if (query->as()) { return std::make_unique(query, context); @@ -186,6 +194,10 @@ std::unique_ptr InterpreterFactory::get(ASTPtr & query, Context & { return std::make_unique(query, context); } + else if (query->as()) + { + return std::make_unique(query, context); + } else if (query->as()) { return std::make_unique(query, context); diff --git a/dbms/src/Interpreters/InterpreterGrantQuery.cpp b/dbms/src/Interpreters/InterpreterGrantQuery.cpp index 58bb104de6..36cba3a801 100644 --- a/dbms/src/Interpreters/InterpreterGrantQuery.cpp +++ b/dbms/src/Interpreters/InterpreterGrantQuery.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include namespace DB @@ -16,32 +18,89 @@ BlockIO InterpreterGrantQuery::execute() context.getAccessRights()->checkGrantOption(query.access_rights_elements); using Kind = ASTGrantQuery::Kind; - std::vector to_roles = GenericRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingUsers(access_control); + std::vector roles; + if (query.roles) + { + roles = GenericRoleSet{*query.roles, access_control}.getMatchingRoles(access_control); + for (const UUID & role : roles) + context.getAccessRights()->checkAdminOption(role); + } + + std::vector to_roles = GenericRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingUsersAndRoles(access_control); String current_database = context.getCurrentDatabase(); using Kind = ASTGrantQuery::Kind; auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr { - auto updated_user = typeid_cast>(entity->clone()); - if (query.kind == Kind::GRANT) + auto clone = entity->clone(); + AccessRights * access = nullptr; + AccessRights * access_with_grant_option = nullptr; + boost::container::flat_set * granted_roles = nullptr; + boost::container::flat_set * granted_roles_with_admin_option = nullptr; + GenericRoleSet * default_roles = nullptr; + if (auto user = typeid_cast>(clone)) { - updated_user->access.grant(query.access_rights_elements, current_database); - if (query.grant_option) - updated_user->access_with_grant_option.grant(query.access_rights_elements, current_database); + access = &user->access; + access_with_grant_option = &user->access_with_grant_option; + granted_roles = &user->granted_roles; + granted_roles_with_admin_option = &user->granted_roles_with_admin_option; + default_roles = &user->default_roles; } - else if (context.getSettingsRef().partial_revokes) + else if (auto role = typeid_cast>(clone)) { - updated_user->access_with_grant_option.partialRevoke(query.access_rights_elements, current_database); - if (!query.grant_option) - updated_user->access.partialRevoke(query.access_rights_elements, current_database); + access = &role->access; + access_with_grant_option = &role->access_with_grant_option; + granted_roles = &role->granted_roles; + granted_roles_with_admin_option = &role->granted_roles_with_admin_option; } else + return entity; + + if (!query.access_rights_elements.empty()) + { + if (query.kind == Kind::GRANT) + { + access->grant(query.access_rights_elements, current_database); + if (query.grant_option) + access_with_grant_option->grant(query.access_rights_elements, current_database); + } + else if (context.getSettingsRef().partial_revokes) + { + access_with_grant_option->partialRevoke(query.access_rights_elements, current_database); + if (!query.grant_option) + access->partialRevoke(query.access_rights_elements, current_database); + } + else + { + access_with_grant_option->revoke(query.access_rights_elements, current_database); + if (!query.grant_option) + access->revoke(query.access_rights_elements, current_database); + } + } + + if (!roles.empty()) { - updated_user->access_with_grant_option.revoke(query.access_rights_elements, current_database); - if (!query.grant_option) - updated_user->access.revoke(query.access_rights_elements, current_database); + if (query.kind == Kind::GRANT) + { + boost::range::copy(roles, std::inserter(*granted_roles, granted_roles->end())); + if (query.admin_option) + boost::range::copy(roles, std::inserter(*granted_roles_with_admin_option, granted_roles_with_admin_option->end())); + } + else + { + for (const UUID & role : roles) + { + granted_roles_with_admin_option->erase(role); + if (!query.admin_option) + { + granted_roles->erase(role); + if (default_roles) + default_roles->ids.erase(role); + } + } + } } - return updated_user; + return clone; }; access_control.update(to_roles, update_func); diff --git a/dbms/src/Interpreters/InterpreterSetRoleQuery.cpp b/dbms/src/Interpreters/InterpreterSetRoleQuery.cpp new file mode 100644 index 0000000000..567c626cb9 --- /dev/null +++ b/dbms/src/Interpreters/InterpreterSetRoleQuery.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include + + +namespace DB +{ +namespace ErrorCodes +{ + extern const int SET_NON_GRANTED_ROLE; +} + + +BlockIO InterpreterSetRoleQuery::execute() +{ + const auto & query = query_ptr->as(); + if (query.kind == ASTSetRoleQuery::Kind::SET_DEFAULT_ROLE) + setDefaultRole(query); + else + setRole(query); + return {}; +} + + +void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query) +{ + auto & access_control = context.getAccessControlManager(); + auto & session_context = context.getSessionContext(); + auto user = session_context.getUser(); + + if (query.kind == ASTSetRoleQuery::Kind::SET_ROLE_DEFAULT) + { + session_context.setCurrentRolesDefault(); + } + else + { + GenericRoleSet roles_from_query{*query.roles, access_control}; + std::vector new_current_roles; + if (roles_from_query.all) + { + for (const auto & id : user->granted_roles) + if (roles_from_query.match(id)) + new_current_roles.push_back(id); + } + else + { + for (const auto & id : roles_from_query.getMatchingIDs()) + { + if (!user->granted_roles.contains(id)) + throw Exception("Role should be granted to set current", ErrorCodes::SET_NON_GRANTED_ROLE); + new_current_roles.push_back(id); + } + } + session_context.setCurrentRoles(new_current_roles); + } +} + + +void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query) +{ + context.checkAccess(AccessType::CREATE_USER | AccessType::DROP_USER); + + auto & access_control = context.getAccessControlManager(); + std::vector to_users = GenericRoleSet{*query.to_users, access_control, context.getUserID()}.getMatchingUsers(access_control); + GenericRoleSet roles_from_query{*query.roles, access_control}; + + auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr + { + auto updated_user = typeid_cast>(entity->clone()); + updateUserSetDefaultRoles(*updated_user, roles_from_query); + return updated_user; + }; + + access_control.update(to_users, update_func); +} + + +void InterpreterSetRoleQuery::updateUserSetDefaultRoles(User & user, const GenericRoleSet & roles_from_query) +{ + if (!roles_from_query.all) + { + for (const auto & id : roles_from_query.getMatchingIDs()) + { + if (!user.granted_roles.contains(id)) + throw Exception("Role should be granted to set default", ErrorCodes::SET_NON_GRANTED_ROLE); + } + } + user.default_roles = roles_from_query; +} + +} diff --git a/dbms/src/Interpreters/InterpreterSetRoleQuery.h b/dbms/src/Interpreters/InterpreterSetRoleQuery.h new file mode 100644 index 0000000000..e28aec9236 --- /dev/null +++ b/dbms/src/Interpreters/InterpreterSetRoleQuery.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + + +namespace DB +{ +class ASTSetRoleQuery; +class GenericRoleSet; +struct User; + + +class InterpreterSetRoleQuery : public IInterpreter +{ +public: + InterpreterSetRoleQuery(const ASTPtr & query_ptr_, Context & context_) : query_ptr(query_ptr_), context(context_) {} + + BlockIO execute() override; + + static void updateUserSetDefaultRoles(User & user, const GenericRoleSet & roles_from_query); + +private: + void setRole(const ASTSetRoleQuery & query); + void setDefaultRole(const ASTSetRoleQuery & query); + + ASTPtr query_ptr; + Context & context; +}; +} diff --git a/dbms/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp b/dbms/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp index 359b76ec75..dcf0387a9c 100644 --- a/dbms/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp +++ b/dbms/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp @@ -85,6 +85,9 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateUserQuery(const ASTShowC if (!user->profile.empty()) create_query->profile = user->profile; + if (user->default_roles != GenericRoleSet::AllTag{}) + create_query->default_roles = GenericRoleSet{user->default_roles}.toAST(context.getAccessControlManager()); + return create_query; } diff --git a/dbms/src/Interpreters/InterpreterShowGrantsQuery.cpp b/dbms/src/Interpreters/InterpreterShowGrantsQuery.cpp index c1d430586b..faa51ce1e0 100644 --- a/dbms/src/Interpreters/InterpreterShowGrantsQuery.cpp +++ b/dbms/src/Interpreters/InterpreterShowGrantsQuery.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -88,19 +89,44 @@ BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl() ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show_query) const { + const auto & access_control = context.getAccessControlManager(); UserPtr user; + RolePtr role; if (show_query.current_user) user = context.getUser(); else - user = context.getAccessControlManager().read(show_query.name); + { + user = access_control.tryRead(show_query.name); + if (!user) + role = access_control.read(show_query.name); + } + + const AccessRights * access = nullptr; + const AccessRights * access_with_grant_option = nullptr; + const boost::container::flat_set * granted_roles = nullptr; + const boost::container::flat_set * granted_roles_with_admin_option = nullptr; + if (user) + { + access = &user->access; + access_with_grant_option = &user->access_with_grant_option; + granted_roles = &user->granted_roles; + granted_roles_with_admin_option = &user->granted_roles_with_admin_option; + } + else + { + access = &role->access; + access_with_grant_option = &role->access_with_grant_option; + granted_roles = &role->granted_roles; + granted_roles_with_admin_option = &role->granted_roles_with_admin_option; + } ASTs res; for (bool grant_option : {true, false}) { - if (!grant_option && (user->access == user->access_with_grant_option)) + if (!grant_option && (*access == *access_with_grant_option)) continue; - const auto & access_rights = grant_option ? user->access_with_grant_option : user->access; + const auto & access_rights = grant_option ? *access_with_grant_option : *access; const auto grouped_elements = groupByTable(access_rights.getElements()); using Kind = ASTGrantQuery::Kind; @@ -112,13 +138,32 @@ ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show grant_query->kind = kind; grant_query->grant_option = grant_option; grant_query->to_roles = std::make_shared(); - grant_query->to_roles->names.push_back(user->getName()); + grant_query->to_roles->names.push_back(show_query.name); grant_query->access_rights_elements = elements; res.push_back(std::move(grant_query)); } } } + for (bool admin_option : {true, false}) + { + if (!admin_option && (*granted_roles == *granted_roles_with_admin_option)) + continue; + + const auto & roles = admin_option ? *granted_roles_with_admin_option : *granted_roles; + if (roles.empty()) + continue; + + auto grant_query = std::make_shared(); + using Kind = ASTGrantQuery::Kind; + grant_query->kind = Kind::GRANT; + grant_query->admin_option = admin_option; + grant_query->to_roles = std::make_shared(); + grant_query->to_roles->names.push_back(show_query.name); + grant_query->roles = GenericRoleSet{roles}.toAST(access_control); + res.push_back(std::move(grant_query)); + } + return res; } } diff --git a/dbms/src/Parsers/ASTCreateRoleQuery.cpp b/dbms/src/Parsers/ASTCreateRoleQuery.cpp new file mode 100644 index 0000000000..c11da41b2e --- /dev/null +++ b/dbms/src/Parsers/ASTCreateRoleQuery.cpp @@ -0,0 +1,46 @@ +#include +#include + + +namespace DB +{ +namespace +{ + void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings) + { + settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "") + << quoteString(new_name); + } +} + + +String ASTCreateRoleQuery::getID(char) const +{ + return "CreateRoleQuery"; +} + + +ASTPtr ASTCreateRoleQuery::clone() const +{ + return std::make_shared(*this); +} + + +void ASTCreateRoleQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const +{ + settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER ROLE" : "CREATE ROLE") + << (settings.hilite ? hilite_none : ""); + + if (if_exists) + settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF EXISTS" << (settings.hilite ? hilite_none : ""); + else if (if_not_exists) + settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF NOT EXISTS" << (settings.hilite ? hilite_none : ""); + else if (or_replace) + settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : ""); + + settings.ostr << " " << backQuoteIfNeed(name); + + if (!new_name.empty()) + formatRenameTo(new_name, settings); +} +} diff --git a/dbms/src/Parsers/ASTCreateRoleQuery.h b/dbms/src/Parsers/ASTCreateRoleQuery.h new file mode 100644 index 0000000000..ac0a93b5d7 --- /dev/null +++ b/dbms/src/Parsers/ASTCreateRoleQuery.h @@ -0,0 +1,29 @@ +#pragma once + +#include + + +namespace DB +{ +/** CREATE ROLE [IF NOT EXISTS | OR REPLACE] name + * + * ALTER ROLE [IF EXISTS] name + * [RENAME TO new_name] + */ +class ASTCreateRoleQuery : public IAST +{ +public: + bool alter = false; + + bool if_exists = false; + bool if_not_exists = false; + bool or_replace = false; + + String name; + String new_name; + + String getID(char) const override; + ASTPtr clone() const override; + void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; +}; +} diff --git a/dbms/src/Parsers/ASTCreateUserQuery.cpp b/dbms/src/Parsers/ASTCreateUserQuery.cpp index fd2ca6d3de..cbe5de0db8 100644 --- a/dbms/src/Parsers/ASTCreateUserQuery.cpp +++ b/dbms/src/Parsers/ASTCreateUserQuery.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -134,6 +135,13 @@ namespace } + void formatDefaultRoles(const ASTGenericRoleSet & default_roles, const IAST::FormatSettings & settings) + { + settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " DEFAULT ROLE " << (settings.hilite ? IAST::hilite_none : ""); + default_roles.format(settings); + } + + void formatProfile(const String & profile_name, const IAST::FormatSettings & settings) { settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " PROFILE " << (settings.hilite ? IAST::hilite_none : "") @@ -181,6 +189,9 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & settings, FormatState if (remove_hosts) formatHosts("REMOVE", *remove_hosts, settings); + if (default_roles) + formatDefaultRoles(*default_roles, settings); + if (profile) formatProfile(*profile, settings); } diff --git a/dbms/src/Parsers/ASTCreateUserQuery.h b/dbms/src/Parsers/ASTCreateUserQuery.h index 055f571144..e93df2f690 100644 --- a/dbms/src/Parsers/ASTCreateUserQuery.h +++ b/dbms/src/Parsers/ASTCreateUserQuery.h @@ -7,15 +7,19 @@ namespace DB { +class ASTGenericRoleSet; + /** CREATE USER [IF NOT EXISTS | OR REPLACE] name * [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}] * [HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] + * [DEFAULT ROLE role [,...]] * [PROFILE 'profile_name'] * * ALTER USER [IF EXISTS] name * [RENAME TO new_name] * [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}] * [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] + * [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ] * [PROFILE 'profile_name'] */ class ASTCreateUserQuery : public IAST @@ -36,6 +40,8 @@ public: std::optional add_hosts; std::optional remove_hosts; + std::shared_ptr default_roles; + std::optional profile; String getID(char) const override; diff --git a/dbms/src/Parsers/ASTDropAccessEntityQuery.cpp b/dbms/src/Parsers/ASTDropAccessEntityQuery.cpp index db67a56e55..0b6bae7575 100644 --- a/dbms/src/Parsers/ASTDropAccessEntityQuery.cpp +++ b/dbms/src/Parsers/ASTDropAccessEntityQuery.cpp @@ -13,6 +13,7 @@ namespace switch (kind) { case Kind::USER: return "USER"; + case Kind::ROLE: return "ROLE"; case Kind::QUOTA: return "QUOTA"; case Kind::ROW_POLICY: return "POLICY"; } diff --git a/dbms/src/Parsers/ASTDropAccessEntityQuery.h b/dbms/src/Parsers/ASTDropAccessEntityQuery.h index 6535fb1883..eea40fd534 100644 --- a/dbms/src/Parsers/ASTDropAccessEntityQuery.h +++ b/dbms/src/Parsers/ASTDropAccessEntityQuery.h @@ -7,9 +7,10 @@ namespace DB { -/** DROP QUOTA [IF EXISTS] name [,...] +/** DROP USER [IF EXISTS] name [,...] + * DROP ROLE [IF EXISTS] name [,...] + * DROP QUOTA [IF EXISTS] name [,...] * DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] - * DROP USER [IF EXISTS] name [,...] */ class ASTDropAccessEntityQuery : public IAST { @@ -17,6 +18,7 @@ public: enum class Kind { USER, + ROLE, QUOTA, ROW_POLICY, }; diff --git a/dbms/src/Parsers/ASTGrantQuery.cpp b/dbms/src/Parsers/ASTGrantQuery.cpp index c5132c8359..1aaf7583e9 100644 --- a/dbms/src/Parsers/ASTGrantQuery.cpp +++ b/dbms/src/Parsers/ASTGrantQuery.cpp @@ -9,6 +9,11 @@ namespace DB { +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + namespace { using KeywordToColumnsMap = std::map /* columns */>; @@ -119,13 +124,30 @@ void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, F settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ((kind == Kind::GRANT) ? "GRANT" : "REVOKE") << (settings.hilite ? IAST::hilite_none : "") << " "; - if (grant_option && (kind == Kind::REVOKE)) - settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : ""); + if (kind == Kind::REVOKE) + { + if (grant_option) + settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : ""); + else if (admin_option) + settings.ostr << (settings.hilite ? hilite_keyword : "") << "ADMIN OPTION FOR " << (settings.hilite ? hilite_none : ""); + } + + if ((!!roles + !access_rights_elements.empty()) != 1) + throw Exception("Either roles or access rights elements should be set", ErrorCodes::LOGICAL_ERROR); + + if (roles) + roles->format(settings); + else + formatAccessRightsElements(access_rights_elements, settings); - formatAccessRightsElements(access_rights_elements, settings); formatToRoles(*to_roles, kind, settings); - if (grant_option && (kind == Kind::GRANT)) - settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH GRANT OPTION" << (settings.hilite ? hilite_none : ""); + if (kind == Kind::GRANT) + { + if (grant_option) + settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH GRANT OPTION" << (settings.hilite ? hilite_none : ""); + else if (admin_option) + settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH ADMIN OPTION" << (settings.hilite ? hilite_none : ""); + } } } diff --git a/dbms/src/Parsers/ASTGrantQuery.h b/dbms/src/Parsers/ASTGrantQuery.h index 56663d8462..5754ef22ac 100644 --- a/dbms/src/Parsers/ASTGrantQuery.h +++ b/dbms/src/Parsers/ASTGrantQuery.h @@ -11,6 +11,9 @@ class ASTGenericRoleSet; /** GRANT access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user_name | CURRENT_USER} [,...] [WITH GRANT OPTION] * REVOKE access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} FROM {user_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | CURRENT_USER} [,...] + * + * GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION] + * REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] */ class ASTGrantQuery : public IAST { @@ -22,8 +25,10 @@ public: }; Kind kind = Kind::GRANT; AccessRightsElements access_rights_elements; + std::shared_ptr roles; std::shared_ptr to_roles; bool grant_option = false; + bool admin_option = false; String getID(char) const override; ASTPtr clone() const override; diff --git a/dbms/src/Parsers/ASTSetRoleQuery.cpp b/dbms/src/Parsers/ASTSetRoleQuery.cpp new file mode 100644 index 0000000000..de61f5a311 --- /dev/null +++ b/dbms/src/Parsers/ASTSetRoleQuery.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + + +namespace DB +{ +String ASTSetRoleQuery::getID(char) const +{ + return "SetRoleQuery"; +} + + +ASTPtr ASTSetRoleQuery::clone() const +{ + return std::make_shared(*this); +} + + +void ASTSetRoleQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const +{ + settings.ostr << (settings.hilite ? hilite_keyword : ""); + switch (kind) + { + case Kind::SET_ROLE: settings.ostr << "SET ROLE"; break; + case Kind::SET_ROLE_DEFAULT: settings.ostr << "SET ROLE DEFAULT"; break; + case Kind::SET_DEFAULT_ROLE: settings.ostr << "SET DEFAULT ROLE"; break; + } + settings.ostr << (settings.hilite ? hilite_none : ""); + + if (kind == Kind::SET_ROLE_DEFAULT) + return; + + settings.ostr << " "; + roles->format(settings); + + if (kind == Kind::SET_ROLE) + return; + + settings.ostr << (settings.hilite ? hilite_keyword : "") << " TO " << (settings.hilite ? hilite_none : ""); + to_users->format(settings); +} +} diff --git a/dbms/src/Parsers/ASTSetRoleQuery.h b/dbms/src/Parsers/ASTSetRoleQuery.h new file mode 100644 index 0000000000..ad22d30e28 --- /dev/null +++ b/dbms/src/Parsers/ASTSetRoleQuery.h @@ -0,0 +1,31 @@ +#pragma once + +#include + + +namespace DB +{ +class ASTGenericRoleSet; + +/** SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} + * SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...] + */ +class ASTSetRoleQuery : public IAST +{ +public: + enum class Kind + { + SET_ROLE, + SET_ROLE_DEFAULT, + SET_DEFAULT_ROLE, + }; + Kind kind = Kind::SET_ROLE; + + std::shared_ptr roles; + std::shared_ptr to_users; + + String getID(char) const override; + ASTPtr clone() const override; + void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; +}; +} diff --git a/dbms/src/Parsers/ParserCreateRoleQuery.cpp b/dbms/src/Parsers/ParserCreateRoleQuery.cpp new file mode 100644 index 0000000000..a60394d84d --- /dev/null +++ b/dbms/src/Parsers/ParserCreateRoleQuery.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + + +namespace DB +{ +namespace +{ + bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name) + { + return IParserBase::wrapParseImpl(pos, [&] + { + if (!ParserKeyword{"RENAME TO"}.ignore(pos, expected)) + return false; + + return parseRoleName(pos, expected, new_name); + }); + } +} + + +bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) +{ + bool alter; + if (ParserKeyword{"CREATE ROLE"}.ignore(pos, expected)) + alter = false; + else if (ParserKeyword{"ALTER ROLE"}.ignore(pos, expected)) + alter = true; + else + return false; + + bool if_exists = false; + bool if_not_exists = false; + bool or_replace = false; + if (alter) + { + if (ParserKeyword{"IF EXISTS"}.ignore(pos, expected)) + if_exists = true; + } + else + { + if (ParserKeyword{"IF NOT EXISTS"}.ignore(pos, expected)) + if_not_exists = true; + else if (ParserKeyword{"OR REPLACE"}.ignore(pos, expected)) + or_replace = true; + } + + String name; + if (!parseRoleName(pos, expected, name)) + return false; + + String new_name; + if (alter) + parseRenameTo(pos, expected, new_name); + + auto query = std::make_shared(); + node = query; + + query->alter = alter; + query->if_exists = if_exists; + query->if_not_exists = if_not_exists; + query->or_replace = or_replace; + query->name = std::move(name); + query->new_name = std::move(new_name); + + return true; +} +} diff --git a/dbms/src/Parsers/ParserCreateRoleQuery.h b/dbms/src/Parsers/ParserCreateRoleQuery.h new file mode 100644 index 0000000000..4a7a82617b --- /dev/null +++ b/dbms/src/Parsers/ParserCreateRoleQuery.h @@ -0,0 +1,20 @@ +#pragma once + +#include + + +namespace DB +{ +/** Parses queries like + * CREATE ROLE [IF NOT EXISTS | OR REPLACE] name + * + * ALTER ROLE [IF EXISTS] name + * [RENAME TO new_name] + */ +class ParserCreateRoleQuery : public IParserBase +{ +protected: + const char * getName() const override { return "CREATE ROLE or ALTER ROLE query"; } + bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; +}; +} diff --git a/dbms/src/Parsers/ParserCreateUserQuery.cpp b/dbms/src/Parsers/ParserCreateUserQuery.cpp index 9b188d0c93..bf3515489f 100644 --- a/dbms/src/Parsers/ParserCreateUserQuery.cpp +++ b/dbms/src/Parsers/ParserCreateUserQuery.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -208,6 +209,23 @@ namespace } + bool parseDefaultRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr & default_roles) + { + return IParserBase::wrapParseImpl(pos, [&] + { + if (!ParserKeyword{"DEFAULT ROLE"}.ignore(pos, expected)) + return false; + + ASTPtr ast; + if (!ParserGenericRoleSet{}.allowCurrentUser(false).parse(pos, ast, expected)) + return false; + + default_roles = typeid_cast>(ast); + return true; + }); + } + + bool parseProfileName(IParserBase::Pos & pos, Expected & expected, std::optional & profile) { return IParserBase::wrapParseImpl(pos, [&] @@ -263,6 +281,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec std::optional hosts; std::optional add_hosts; std::optional remove_hosts; + std::shared_ptr default_roles; std::optional profile; while (true) @@ -276,6 +295,9 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (!profile && parseProfileName(pos, expected, profile)) continue; + if (!default_roles && parseDefaultRoles(pos, expected, default_roles)) + continue; + if (alter) { if (new_name.empty() && parseRenameTo(pos, expected, new_name, new_host_pattern)) diff --git a/dbms/src/Parsers/ParserDropAccessEntityQuery.cpp b/dbms/src/Parsers/ParserDropAccessEntityQuery.cpp index b0b7aa6f83..f257dc0fd6 100644 --- a/dbms/src/Parsers/ParserDropAccessEntityQuery.cpp +++ b/dbms/src/Parsers/ParserDropAccessEntityQuery.cpp @@ -82,12 +82,14 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & using Kind = ASTDropAccessEntityQuery::Kind; Kind kind; - if (ParserKeyword{"QUOTA"}.ignore(pos, expected)) + if (ParserKeyword{"USER"}.ignore(pos, expected)) + kind = Kind::USER; + else if (ParserKeyword{"ROLE"}.ignore(pos, expected)) + kind = Kind::ROLE; + else if (ParserKeyword{"QUOTA"}.ignore(pos, expected)) kind = Kind::QUOTA; else if (ParserKeyword{"POLICY"}.ignore(pos, expected) || ParserKeyword{"ROW POLICY"}.ignore(pos, expected)) kind = Kind::ROW_POLICY; - else if (ParserKeyword{"USER"}.ignore(pos, expected)) - kind = Kind::USER; else return false; @@ -98,7 +100,7 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & Strings names; std::vector row_policies_names; - if (kind == Kind::USER) + if ((kind == Kind::USER) || (kind == Kind::ROLE)) { if (!parseUserNames(pos, expected, names)) return false; diff --git a/dbms/src/Parsers/ParserDropAccessEntityQuery.h b/dbms/src/Parsers/ParserDropAccessEntityQuery.h index 5e8739c292..e4fb323d5f 100644 --- a/dbms/src/Parsers/ParserDropAccessEntityQuery.h +++ b/dbms/src/Parsers/ParserDropAccessEntityQuery.h @@ -6,9 +6,10 @@ namespace DB { /** Parses queries like + * DROP USER [IF EXISTS] name [,...] + * DROP ROLE [IF EXISTS] name [,...] * DROP QUOTA [IF EXISTS] name [,...] * DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] - * DROP USER [IF EXISTS] name [,...] */ class ParserDropAccessEntityQuery : public IParserBase { diff --git a/dbms/src/Parsers/ParserGrantQuery.cpp b/dbms/src/Parsers/ParserGrantQuery.cpp index 770f5bee52..967a3150af 100644 --- a/dbms/src/Parsers/ParserGrantQuery.cpp +++ b/dbms/src/Parsers/ParserGrantQuery.cpp @@ -10,6 +10,11 @@ namespace DB { +namespace ErrorCodes +{ + extern const int SYNTAX_ERROR; +} + namespace { bool parseRoundBrackets(IParser::Pos & pos, Expected & expected) @@ -206,6 +211,20 @@ namespace } + bool parseRoles(IParser::Pos & pos, Expected & expected, std::shared_ptr & roles) + { + return IParserBase::wrapParseImpl(pos, [&] + { + ASTPtr ast; + if (!ParserGenericRoleSet{}.allowAll(false).allowCurrentUser(false).parse(pos, ast, expected)) + return false; + + roles = typeid_cast>(ast); + return true; + }); + } + + bool parseToRoles(IParser::Pos & pos, Expected & expected, ASTGrantQuery::Kind kind, std::shared_ptr & to_roles) { return IParserBase::wrapParseImpl(pos, [&] @@ -245,30 +264,46 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return false; bool grant_option = false; + bool admin_option = false; if (kind == Kind::REVOKE) { if (ParserKeyword{"GRANT OPTION FOR"}.ignore(pos, expected)) grant_option = true; + else if (ParserKeyword{"ADMIN OPTION FOR"}.ignore(pos, expected)) + admin_option = true; } AccessRightsElements elements; + std::shared_ptr roles; + if (!parseAccessRightsElements(pos, expected, elements) && !parseRoles(pos, expected, roles)) + return false; + std::shared_ptr to_roles; - if (!parseAccessRightsElements(pos, expected, elements) && !parseToRoles(pos, expected, kind, to_roles)) + if (!parseToRoles(pos, expected, kind, to_roles)) return false; if (kind == Kind::GRANT) { if (ParserKeyword{"WITH GRANT OPTION"}.ignore(pos, expected)) grant_option = true; + else if (ParserKeyword{"WITH ADMIN OPTION"}.ignore(pos, expected)) + admin_option = true; } + if (grant_option && roles) + throw Exception("GRANT OPTION should be specified for access types", ErrorCodes::SYNTAX_ERROR); + if (admin_option && !elements.empty()) + throw Exception("ADMIN OPTION should be specified for roles", ErrorCodes::SYNTAX_ERROR); + auto query = std::make_shared(); node = query; query->kind = kind; query->access_rights_elements = std::move(elements); + query->roles = std::move(roles); query->to_roles = std::move(to_roles); query->grant_option = grant_option; + query->admin_option = admin_option; return true; } diff --git a/dbms/src/Parsers/ParserQuery.cpp b/dbms/src/Parsers/ParserQuery.cpp index d7f769069e..a157a3ca35 100644 --- a/dbms/src/Parsers/ParserQuery.cpp +++ b/dbms/src/Parsers/ParserQuery.cpp @@ -7,9 +7,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -28,17 +30,21 @@ bool ParserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ParserSetQuery set_p; ParserSystemQuery system_p; ParserCreateUserQuery create_user_p; + ParserCreateRoleQuery create_role_p; ParserCreateQuotaQuery create_quota_p; ParserCreateRowPolicyQuery create_row_policy_p; ParserDropAccessEntityQuery drop_access_entity_p; ParserGrantQuery grant_p; + ParserSetRoleQuery set_role_p; bool res = query_with_output_p.parse(pos, node, expected) || insert_p.parse(pos, node, expected) || use_p.parse(pos, node, expected) + || set_role_p.parse(pos, node, expected) || set_p.parse(pos, node, expected) || system_p.parse(pos, node, expected) || create_user_p.parse(pos, node, expected) + || create_role_p.parse(pos, node, expected) || create_quota_p.parse(pos, node, expected) || create_row_policy_p.parse(pos, node, expected) || drop_access_entity_p.parse(pos, node, expected) diff --git a/dbms/src/Parsers/ParserSetRoleQuery.cpp b/dbms/src/Parsers/ParserSetRoleQuery.cpp new file mode 100644 index 0000000000..5239628f30 --- /dev/null +++ b/dbms/src/Parsers/ParserSetRoleQuery.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + + +namespace DB +{ +namespace +{ + bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr & roles) + { + return IParserBase::wrapParseImpl(pos, [&] + { + ASTPtr ast; + if (!ParserGenericRoleSet{}.allowCurrentUser(false).parse(pos, ast, expected)) + return false; + + roles = typeid_cast>(ast); + return true; + }); + } + + bool parseToUsers(IParserBase::Pos & pos, Expected & expected, std::shared_ptr & to_users) + { + return IParserBase::wrapParseImpl(pos, [&] + { + if (!ParserKeyword{"TO"}.ignore(pos, expected)) + return false; + + ASTPtr ast; + if (!ParserGenericRoleSet{}.allowAll(false).parse(pos, ast, expected)) + return false; + + to_users = typeid_cast>(ast); + return true; + }); + } +} + + +bool ParserSetRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) +{ + using Kind = ASTSetRoleQuery::Kind; + Kind kind; + if (ParserKeyword{"SET ROLE DEFAULT"}.ignore(pos, expected)) + kind = Kind::SET_ROLE_DEFAULT; + else if (ParserKeyword{"SET ROLE"}.ignore(pos, expected)) + kind = Kind::SET_ROLE; + else if (ParserKeyword{"SET DEFAULT ROLE"}.ignore(pos, expected)) + kind = Kind::SET_DEFAULT_ROLE; + else + return false; + + std::shared_ptr roles; + std::shared_ptr to_users; + + if ((kind == Kind::SET_ROLE) || (kind == Kind::SET_DEFAULT_ROLE)) + { + if (!parseRoles(pos, expected, roles)) + return false; + + if (kind == Kind::SET_DEFAULT_ROLE) + { + if (!parseToUsers(pos, expected, to_users)) + return false; + } + } + + auto query = std::make_shared(); + node = query; + + query->kind = kind; + query->roles = std::move(roles); + query->to_users = std::move(to_users); + + return true; +} +} diff --git a/dbms/src/Parsers/ParserSetRoleQuery.h b/dbms/src/Parsers/ParserSetRoleQuery.h new file mode 100644 index 0000000000..7e59f08e7b --- /dev/null +++ b/dbms/src/Parsers/ParserSetRoleQuery.h @@ -0,0 +1,18 @@ +#pragma once + +#include + + +namespace DB +{ +/** Parses queries like + * SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} + * SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...] + */ +class ParserSetRoleQuery : public IParserBase +{ +protected: + const char * getName() const override { return "SET ROLE or SET DEFAULT ROLE query"; } + bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; +}; +} -- GitLab