Merge pull request #11670 from vitlibar/rbac-improve-parser-multiple-entities

RBAC: improve syntax
This commit is contained in:
Vitaly Baranov 2020-06-17 16:26:02 +03:00 committed by GitHub
commit 7011401cd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
131 changed files with 4330 additions and 1718 deletions

View File

@ -64,19 +64,23 @@ namespace
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{ {
if (ParserCreateUserQuery{}.enableAttachMode(true).parse(pos, node, expected)) ParserCreateUserQuery create_user_p;
return true; ParserCreateRoleQuery create_role_p;
if (ParserCreateRoleQuery{}.enableAttachMode(true).parse(pos, node, expected)) ParserCreateRowPolicyQuery create_policy_p;
return true; ParserCreateQuotaQuery create_quota_p;
if (ParserCreateRowPolicyQuery{}.enableAttachMode(true).parse(pos, node, expected)) ParserCreateSettingsProfileQuery create_profile_p;
return true; ParserGrantQuery grant_p;
if (ParserCreateQuotaQuery{}.enableAttachMode(true).parse(pos, node, expected))
return true; create_user_p.useAttachMode();
if (ParserCreateSettingsProfileQuery{}.enableAttachMode(true).parse(pos, node, expected)) create_role_p.useAttachMode();
return true; create_policy_p.useAttachMode();
if (ParserGrantQuery{}.enableAttachMode(true).parse(pos, node, expected)) create_quota_p.useAttachMode();
return true; create_profile_p.useAttachMode();
return false; grant_p.useAttachMode();
return create_user_p.parse(pos, node, expected) || create_role_p.parse(pos, node, expected)
|| create_policy_p.parse(pos, node, expected) || create_quota_p.parse(pos, node, expected)
|| create_profile_p.parse(pos, node, expected) || grant_p.parse(pos, node, expected);
} }
}; };
@ -261,7 +265,9 @@ namespace
/// Calculates the path for storing a map of name of access entity to UUID for access entities of some type. /// Calculates the path for storing a map of name of access entity to UUID for access entities of some type.
std::filesystem::path getListFilePath(const String & directory_path, EntityType type) std::filesystem::path getListFilePath(const String & directory_path, EntityType type)
{ {
std::string_view file_name = EntityTypeInfo::get(type).list_filename; String file_name = EntityTypeInfo::get(type).plural_raw_name;
boost::to_lower(file_name);
file_name += ".list";
return std::filesystem::path(directory_path).append(file_name); return std::filesystem::path(directory_path).append(file_name);
} }

View File

@ -45,11 +45,13 @@ struct IAccessEntity
struct TypeInfo struct TypeInfo
{ {
const char * const raw_name; const char * const raw_name;
const char * const plural_raw_name;
const String name; /// Uppercased with spaces instead of underscores, e.g. "SETTINGS PROFILE". const String name; /// Uppercased with spaces instead of underscores, e.g. "SETTINGS PROFILE".
const String alias; /// Alias of the keyword or empty string, e.g. "PROFILE". const String alias; /// Alias of the keyword or empty string, e.g. "PROFILE".
const String plural_name; /// Uppercased with spaces plural name, e.g. "SETTINGS PROFILES".
const String plural_alias; /// Uppercased with spaces plural name alias, e.g. "PROFILES".
const String name_for_output_with_entity_name; /// Lowercased with spaces instead of underscores, e.g. "settings profile". const String name_for_output_with_entity_name; /// Lowercased with spaces instead of underscores, e.g. "settings profile".
const char unique_char; /// Unique character for this type. E.g. 'P' for SETTINGS_PROFILE. const char unique_char; /// Unique character for this type. E.g. 'P' for SETTINGS_PROFILE.
const String list_filename; /// Name of the file containing list of objects of this type, including the file extension ".list".
const int not_found_error_code; const int not_found_error_code;
static const TypeInfo & get(Type type_); static const TypeInfo & get(Type type_);
@ -69,6 +71,18 @@ struct IAccessEntity
friend bool operator ==(const IAccessEntity & lhs, const IAccessEntity & rhs) { return lhs.equal(rhs); } friend bool operator ==(const IAccessEntity & lhs, const IAccessEntity & rhs) { return lhs.equal(rhs); }
friend bool operator !=(const IAccessEntity & lhs, const IAccessEntity & rhs) { return !(lhs == rhs); } friend bool operator !=(const IAccessEntity & lhs, const IAccessEntity & rhs) { return !(lhs == rhs); }
struct LessByName
{
bool operator()(const IAccessEntity & lhs, const IAccessEntity & rhs) const { return (lhs.getName() < rhs.getName()); }
bool operator()(const std::shared_ptr<const IAccessEntity> & lhs, const std::shared_ptr<const IAccessEntity> & rhs) const { return operator()(*lhs, *rhs); }
};
struct LessByTypeAndName
{
bool operator()(const IAccessEntity & lhs, const IAccessEntity & rhs) const { return (lhs.getType() < rhs.getType()) || ((lhs.getType() == rhs.getType()) && (lhs.getName() < rhs.getName())); }
bool operator()(const std::shared_ptr<const IAccessEntity> & lhs, const std::shared_ptr<const IAccessEntity> & rhs) const { return operator()(*lhs, *rhs); }
};
protected: protected:
String name; String name;
@ -87,44 +101,49 @@ using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
inline const IAccessEntity::TypeInfo & IAccessEntity::TypeInfo::get(Type type_) inline const IAccessEntity::TypeInfo & IAccessEntity::TypeInfo::get(Type type_)
{ {
static constexpr auto make_info = [](const char * raw_name_, char unique_char_, const char * list_filename_, int not_found_error_code_) static constexpr auto make_info = [](const char * raw_name_, const char * plural_raw_name_, char unique_char_, int not_found_error_code_)
{ {
String init_name = raw_name_; String init_names[2] = {raw_name_, plural_raw_name_};
boost::to_upper(init_name); String init_aliases[2];
boost::replace_all(init_name, "_", " "); for (size_t i = 0; i != std::size(init_names); ++i)
String init_alias; {
if (auto underscore_pos = init_name.find_first_of(" "); underscore_pos != String::npos) String & init_name = init_names[i];
init_alias = init_name.substr(underscore_pos + 1); String & init_alias = init_aliases[i];
String init_name_for_output_with_entity_name = init_name; boost::to_upper(init_name);
boost::replace_all(init_name, "_", " ");
if (auto underscore_pos = init_name.find_first_of(" "); underscore_pos != String::npos)
init_alias = init_name.substr(underscore_pos + 1);
}
String init_name_for_output_with_entity_name = init_names[0];
boost::to_lower(init_name_for_output_with_entity_name); boost::to_lower(init_name_for_output_with_entity_name);
return TypeInfo{raw_name_, std::move(init_name), std::move(init_alias), std::move(init_name_for_output_with_entity_name), unique_char_, list_filename_, not_found_error_code_}; return TypeInfo{raw_name_, plural_raw_name_, std::move(init_names[0]), std::move(init_aliases[0]), std::move(init_names[1]), std::move(init_aliases[1]), std::move(init_name_for_output_with_entity_name), unique_char_, not_found_error_code_};
}; };
switch (type_) switch (type_)
{ {
case Type::USER: case Type::USER:
{ {
static const auto info = make_info("USER", 'U', "users.list", ErrorCodes::UNKNOWN_USER); static const auto info = make_info("USER", "USERS", 'U', ErrorCodes::UNKNOWN_USER);
return info; return info;
} }
case Type::ROLE: case Type::ROLE:
{ {
static const auto info = make_info("ROLE", 'R', "roles.list", ErrorCodes::UNKNOWN_ROLE); static const auto info = make_info("ROLE", "ROLES", 'R', ErrorCodes::UNKNOWN_ROLE);
return info; return info;
} }
case Type::SETTINGS_PROFILE: case Type::SETTINGS_PROFILE:
{ {
static const auto info = make_info("SETTINGS_PROFILE", 'S', "settings_profiles.list", ErrorCodes::THERE_IS_NO_PROFILE); static const auto info = make_info("SETTINGS_PROFILE", "SETTINGS_PROFILES", 'S', ErrorCodes::THERE_IS_NO_PROFILE);
return info; return info;
} }
case Type::ROW_POLICY: case Type::ROW_POLICY:
{ {
static const auto info = make_info("ROW_POLICY", 'P', "row_policies.list", ErrorCodes::UNKNOWN_ROW_POLICY); static const auto info = make_info("ROW_POLICY", "ROW_POLICIES", 'P', ErrorCodes::UNKNOWN_ROW_POLICY);
return info; return info;
} }
case Type::QUOTA: case Type::QUOTA:
{ {
static const auto info = make_info("QUOTA", 'Q', "quotas.list", ErrorCodes::UNKNOWN_QUOTA); static const auto info = make_info("QUOTA", "QUOTAS", 'Q', ErrorCodes::UNKNOWN_QUOTA);
return info; return info;
} }
case Type::MAX: break; case Type::MAX: break;

View File

@ -24,16 +24,141 @@ namespace
using EntityType = IAccessStorage::EntityType; using EntityType = IAccessStorage::EntityType;
using EntityTypeInfo = IAccessStorage::EntityTypeInfo; using EntityTypeInfo = IAccessStorage::EntityTypeInfo;
bool isNotFoundErrorCode(int error_code)
String outputID(const UUID & id)
{ {
if (error_code == ErrorCodes::ACCESS_ENTITY_NOT_FOUND) return "ID(" + toString(id) + ")";
return true; }
for (auto type : ext::range(EntityType::MAX)) String outputTypeAndNameOrID(const IAccessStorage & storage, const UUID & id)
if (error_code == EntityTypeInfo::get(type).not_found_error_code) {
return true; auto entity = storage.tryRead(id);
if (entity)
return entity->outputTypeAndName();
return outputID(id);
}
return false;
template <typename Func, typename ResultType = std::result_of_t<Func()>>
ResultType doTry(const Func & func)
{
try
{
return func();
}
catch (Exception &)
{
return {};
}
}
template <bool ignore_errors, typename T, typename ApplyFunc, typename GetNameFunc = std::nullptr_t,
typename ResultTypeOfApplyFunc = std::result_of_t<ApplyFunc(T)>,
typename ResultType = std::conditional_t<std::is_same_v<ResultTypeOfApplyFunc, void>, void, std::vector<ResultTypeOfApplyFunc>>>
ResultType applyToMultipleEntities(
const std::vector<T> & multiple_entities,
const ApplyFunc & apply_function,
const char * error_message_format [[maybe_unused]] = nullptr,
const GetNameFunc & get_name_function [[maybe_unused]] = nullptr)
{
std::optional<Exception> exception;
std::vector<bool> success;
auto helper = [&](const auto & apply_and_store_result_function)
{
for (size_t i = 0; i != multiple_entities.size(); ++i)
{
try
{
apply_and_store_result_function(multiple_entities[i]);
if constexpr (!ignore_errors)
success[i] = true;
}
catch (Exception & e)
{
if (!ignore_errors && !exception)
exception.emplace(e);
}
catch (Poco::Exception & e)
{
if (!ignore_errors && !exception)
exception.emplace(Exception::CreateFromPocoTag{}, e);
}
catch (std::exception & e)
{
if (!ignore_errors && !exception)
exception.emplace(Exception::CreateFromSTDTag{}, e);
}
}
};
if constexpr (std::is_same_v<ResultType, void>)
{
if (multiple_entities.empty())
return;
if (multiple_entities.size() == 1)
{
apply_function(multiple_entities.front());
return;
}
if constexpr (!ignore_errors)
success.resize(multiple_entities.size(), false);
helper(apply_function);
if (ignore_errors || !exception)
return;
}
else
{
ResultType result;
if (multiple_entities.empty())
return result;
if (multiple_entities.size() == 1)
{
result.emplace_back(apply_function(multiple_entities.front()));
return result;
}
result.reserve(multiple_entities.size());
if constexpr (!ignore_errors)
success.resize(multiple_entities.size(), false);
helper([&](const T & entity) { result.emplace_back(apply_function(entity)); });
if (ignore_errors || !exception)
return result;
}
if constexpr (!ignore_errors)
{
Strings succeeded_names_list;
Strings failed_names_list;
for (size_t i = 0; i != multiple_entities.size(); ++i)
{
const auto & entity = multiple_entities[i];
String name = get_name_function(entity);
if (success[i])
succeeded_names_list.emplace_back(name);
else
failed_names_list.emplace_back(name);
}
String succeeded_names = boost::algorithm::join(succeeded_names_list, ", ");
String failed_names = boost::algorithm::join(failed_names_list, ", ");
if (succeeded_names.empty())
succeeded_names = "none";
String error_message = error_message_format;
boost::replace_all(error_message, "{succeeded_names}", succeeded_names);
boost::replace_all(error_message, "{failed_names}", failed_names);
exception->addMessage(error_message);
exception->rethrow();
}
__builtin_unreachable();
} }
} }
@ -91,14 +216,7 @@ bool IAccessStorage::exists(const UUID & id) const
AccessEntityPtr IAccessStorage::tryReadBase(const UUID & id) const AccessEntityPtr IAccessStorage::tryReadBase(const UUID & id) const
{ {
try return doTry([&] { return readImpl(id); });
{
return readImpl(id);
}
catch (Exception &)
{
return nullptr;
}
} }
@ -110,14 +228,7 @@ String IAccessStorage::readName(const UUID & id) const
std::optional<String> IAccessStorage::tryReadName(const UUID & id) const std::optional<String> IAccessStorage::tryReadName(const UUID & id) const
{ {
try return doTry([&] { return std::optional<String>{readNameImpl(id)}; });
{
return readNameImpl(id);
}
catch (Exception &)
{
return {};
}
} }
@ -129,56 +240,25 @@ UUID IAccessStorage::insert(const AccessEntityPtr & entity)
std::vector<UUID> IAccessStorage::insert(const std::vector<AccessEntityPtr> & multiple_entities) std::vector<UUID> IAccessStorage::insert(const std::vector<AccessEntityPtr> & multiple_entities)
{ {
std::vector<UUID> ids; return applyToMultipleEntities</* ignore_errors = */ false>(
ids.reserve(multiple_entities.size()); multiple_entities,
String error_message; [this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ false); },
for (const auto & entity : multiple_entities) "Couldn't insert {failed_names}. Successfully inserted: {succeeded_names}",
{ [](const AccessEntityPtr & entity) { return entity->outputTypeAndName(); });
try
{
ids.push_back(insertImpl(entity, false));
}
catch (Exception & e)
{
if (e.code() != ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS)
throw;
error_message += (error_message.empty() ? "" : ". ") + e.message();
}
}
if (!error_message.empty())
throw Exception(error_message, ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS);
return ids;
} }
std::optional<UUID> IAccessStorage::tryInsert(const AccessEntityPtr & entity) std::optional<UUID> IAccessStorage::tryInsert(const AccessEntityPtr & entity)
{ {
try return doTry([&] { return std::optional<UUID>{insertImpl(entity, false)}; });
{
return insertImpl(entity, false);
}
catch (Exception &)
{
return {};
}
} }
std::vector<UUID> IAccessStorage::tryInsert(const std::vector<AccessEntityPtr> & multiple_entities) std::vector<UUID> IAccessStorage::tryInsert(const std::vector<AccessEntityPtr> & multiple_entities)
{ {
std::vector<UUID> ids; return applyToMultipleEntities</* ignore_errors = */ true>(
ids.reserve(multiple_entities.size()); multiple_entities,
for (const auto & entity : multiple_entities) [this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ false); });
{
try
{
ids.push_back(insertImpl(entity, false));
}
catch (Exception &)
{
}
}
return ids;
} }
@ -190,11 +270,11 @@ UUID IAccessStorage::insertOrReplace(const AccessEntityPtr & entity)
std::vector<UUID> IAccessStorage::insertOrReplace(const std::vector<AccessEntityPtr> & multiple_entities) std::vector<UUID> IAccessStorage::insertOrReplace(const std::vector<AccessEntityPtr> & multiple_entities)
{ {
std::vector<UUID> ids; return applyToMultipleEntities</* ignore_errors = */ false>(
ids.reserve(multiple_entities.size()); multiple_entities,
for (const auto & entity : multiple_entities) [this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ true); },
ids.push_back(insertImpl(entity, true)); "Couldn't insert {failed_names}. Successfully inserted: {succeeded_names}",
return ids; [](const AccessEntityPtr & entity) -> String { return entity->outputTypeAndName(); });
} }
@ -206,60 +286,25 @@ void IAccessStorage::remove(const UUID & id)
void IAccessStorage::remove(const std::vector<UUID> & ids) void IAccessStorage::remove(const std::vector<UUID> & ids)
{ {
String error_message; applyToMultipleEntities</* ignore_errors = */ false>(
std::optional<int> error_code; ids,
for (const auto & id : ids) [this](const UUID & id) { removeImpl(id); },
{ "Couldn't remove {failed_names}. Successfully removed: {succeeded_names}",
try [this](const UUID & id) { return outputTypeAndNameOrID(*this, id); });
{
removeImpl(id);
}
catch (Exception & e)
{
if (!isNotFoundErrorCode(e.code()))
throw;
error_message += (error_message.empty() ? "" : ". ") + e.message();
if (error_code && (*error_code != e.code()))
error_code = ErrorCodes::ACCESS_ENTITY_NOT_FOUND;
else
error_code = e.code();
}
}
if (!error_message.empty())
throw Exception(error_message, *error_code);
} }
bool IAccessStorage::tryRemove(const UUID & id) bool IAccessStorage::tryRemove(const UUID & id)
{ {
try return doTry([&] { removeImpl(id); return true; });
{
removeImpl(id);
return true;
}
catch (Exception &)
{
return false;
}
} }
std::vector<UUID> IAccessStorage::tryRemove(const std::vector<UUID> & ids) std::vector<UUID> IAccessStorage::tryRemove(const std::vector<UUID> & ids)
{ {
std::vector<UUID> removed; return applyToMultipleEntities</* ignore_errors = */ true>(
removed.reserve(ids.size()); ids,
for (const auto & id : ids) [this](const UUID & id) { removeImpl(id); return id; });
{
try
{
removeImpl(id);
removed.push_back(id);
}
catch (Exception &)
{
}
}
return removed;
} }
@ -271,60 +316,25 @@ void IAccessStorage::update(const UUID & id, const UpdateFunc & update_func)
void IAccessStorage::update(const std::vector<UUID> & ids, const UpdateFunc & update_func) void IAccessStorage::update(const std::vector<UUID> & ids, const UpdateFunc & update_func)
{ {
String error_message; applyToMultipleEntities</* ignore_errors = */ false>(
std::optional<int> error_code; ids,
for (const auto & id : ids) [this, &update_func](const UUID & id) { updateImpl(id, update_func); },
{ "Couldn't update {failed_names}. Successfully updated: {succeeded_names}",
try [this](const UUID & id) { return outputTypeAndNameOrID(*this, id); });
{
updateImpl(id, update_func);
}
catch (Exception & e)
{
if (!isNotFoundErrorCode(e.code()))
throw;
error_message += (error_message.empty() ? "" : ". ") + e.message();
if (error_code && (*error_code != e.code()))
error_code = ErrorCodes::ACCESS_ENTITY_NOT_FOUND;
else
error_code = e.code();
}
}
if (!error_message.empty())
throw Exception(error_message, *error_code);
} }
bool IAccessStorage::tryUpdate(const UUID & id, const UpdateFunc & update_func) bool IAccessStorage::tryUpdate(const UUID & id, const UpdateFunc & update_func)
{ {
try return doTry([&] { updateImpl(id, update_func); return true; });
{
updateImpl(id, update_func);
return true;
}
catch (Exception &)
{
return false;
}
} }
std::vector<UUID> IAccessStorage::tryUpdate(const std::vector<UUID> & ids, const UpdateFunc & update_func) std::vector<UUID> IAccessStorage::tryUpdate(const std::vector<UUID> & ids, const UpdateFunc & update_func)
{ {
std::vector<UUID> updated; return applyToMultipleEntities</* ignore_errors = */ true>(
updated.reserve(ids.size()); ids,
for (const auto & id : ids) [this, &update_func](const UUID & id) { updateImpl(id, update_func); return id; });
{
try
{
updateImpl(id, update_func);
updated.push_back(id);
}
catch (Exception &)
{
}
}
return updated;
} }
@ -388,7 +398,7 @@ Poco::Logger * IAccessStorage::getLogger() const
void IAccessStorage::throwNotFound(const UUID & id) const void IAccessStorage::throwNotFound(const UUID & id) const
{ {
throw Exception("ID {" + toString(id) + "} not found in [" + getStorageName() + "]", ErrorCodes::ACCESS_ENTITY_NOT_FOUND); throw Exception(outputID(id) + " not found in [" + getStorageName() + "]", ErrorCodes::ACCESS_ENTITY_NOT_FOUND);
} }
@ -402,7 +412,7 @@ void IAccessStorage::throwNotFound(EntityType type, const String & name) const
void IAccessStorage::throwBadCast(const UUID & id, EntityType type, const String & name, EntityType required_type) void IAccessStorage::throwBadCast(const UUID & id, EntityType type, const String & name, EntityType required_type)
{ {
throw Exception( throw Exception(
"ID {" + toString(id) + "}: " + outputEntityTypeAndName(type, name) + " expected to be of type " + toString(required_type), outputID(id) + ": " + outputEntityTypeAndName(type, name) + " expected to be of type " + toString(required_type),
ErrorCodes::LOGICAL_ERROR); ErrorCodes::LOGICAL_ERROR);
} }
@ -410,7 +420,7 @@ void IAccessStorage::throwBadCast(const UUID & id, EntityType type, const String
void IAccessStorage::throwIDCollisionCannotInsert(const UUID & id, EntityType type, const String & name, EntityType existing_type, const String & existing_name) const void IAccessStorage::throwIDCollisionCannotInsert(const UUID & id, EntityType type, const String & name, EntityType existing_type, const String & existing_name) const
{ {
throw Exception( throw Exception(
outputEntityTypeAndName(type, name) + ": cannot insert because the ID {" + toString(id) + "} is already used by " outputEntityTypeAndName(type, name) + ": cannot insert because the " + outputID(id) + " is already used by "
+ outputEntityTypeAndName(existing_type, existing_name) + " in [" + getStorageName() + "]", + outputEntityTypeAndName(existing_type, existing_name) + " in [" + getStorageName() + "]",
ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS); ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS);
} }

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <Access/IAccessEntity.h> #include <Access/IAccessEntity.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <ext/range.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <chrono> #include <chrono>
@ -84,14 +86,15 @@ struct Quota : public IAccessEntity
struct KeyTypeInfo struct KeyTypeInfo
{ {
const char * const raw_name; const char * const raw_name;
const String name; /// Lowercased with spaces, e.g. "client key". const String name; /// Lowercased with underscores, e.g. "client_key".
const std::vector<KeyType> base_types; /// For combined types keeps base types, e.g. for CLIENT_KEY_OR_USER_NAME it keeps [KeyType::CLIENT_KEY, KeyType::USER_NAME].
static const KeyTypeInfo & get(KeyType type); static const KeyTypeInfo & get(KeyType type);
}; };
KeyType key_type = KeyType::NONE; KeyType key_type = KeyType::NONE;
/// Which roles or users should use this quota. /// Which roles or users should use this quota.
ExtendedRoleSet to_roles; RolesOrUsersSet to_roles;
bool equal(const IAccessEntity & other) const override; bool equal(const IAccessEntity & other) const override;
std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<Quota>(); } std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<Quota>(); }
@ -195,8 +198,21 @@ inline const Quota::KeyTypeInfo & Quota::KeyTypeInfo::get(KeyType type)
{ {
String init_name = raw_name_; String init_name = raw_name_;
boost::to_lower(init_name); boost::to_lower(init_name);
boost::replace_all(init_name, "_", " "); std::vector<KeyType> init_base_types;
return KeyTypeInfo{raw_name_, std::move(init_name)}; String replaced = boost::algorithm::replace_all_copy(init_name, "_or_", "|");
Strings tokens;
boost::algorithm::split(tokens, replaced, boost::is_any_of("|"));
if (tokens.size() > 1)
{
for (const auto & token : tokens)
for (auto kt : ext::range(KeyType::MAX))
if (KeyTypeInfo::get(kt).name == token)
{
init_base_types.push_back(kt);
break;
}
}
return KeyTypeInfo{raw_name_, std::move(init_name), std::move(init_base_types)};
}; };
switch (type) switch (type)

View File

@ -39,7 +39,7 @@ private:
QuotaPtr quota; QuotaPtr quota;
UUID quota_id; UUID quota_id;
const ExtendedRoleSet * roles = nullptr; const RolesOrUsersSet * roles = nullptr;
std::unordered_map<String /* quota key */, boost::shared_ptr<const Intervals>> key_to_intervals; std::unordered_map<String /* quota key */, boost::shared_ptr<const Intervals>> key_to_intervals;
}; };

View File

@ -1,9 +1,8 @@
#include <Access/RolesOrUsersSet.h>
#include <Access/ExtendedRoleSet.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/User.h> #include <Access/User.h>
#include <Access/Role.h> #include <Access/Role.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <IO/ReadHelpers.h> #include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
@ -20,51 +19,51 @@ namespace ErrorCodes
} }
ExtendedRoleSet::ExtendedRoleSet() = default; RolesOrUsersSet::RolesOrUsersSet() = default;
ExtendedRoleSet::ExtendedRoleSet(const ExtendedRoleSet & src) = default; RolesOrUsersSet::RolesOrUsersSet(const RolesOrUsersSet & src) = default;
ExtendedRoleSet & ExtendedRoleSet::operator =(const ExtendedRoleSet & src) = default; RolesOrUsersSet & RolesOrUsersSet::operator =(const RolesOrUsersSet & src) = default;
ExtendedRoleSet::ExtendedRoleSet(ExtendedRoleSet && src) = default; RolesOrUsersSet::RolesOrUsersSet(RolesOrUsersSet && src) = default;
ExtendedRoleSet & ExtendedRoleSet::operator =(ExtendedRoleSet && src) = default; RolesOrUsersSet & RolesOrUsersSet::operator =(RolesOrUsersSet && src) = default;
ExtendedRoleSet::ExtendedRoleSet(AllTag) RolesOrUsersSet::RolesOrUsersSet(AllTag)
{ {
all = true; all = true;
} }
ExtendedRoleSet::ExtendedRoleSet(const UUID & id) RolesOrUsersSet::RolesOrUsersSet(const UUID & id)
{ {
add(id); add(id);
} }
ExtendedRoleSet::ExtendedRoleSet(const std::vector<UUID> & ids_) RolesOrUsersSet::RolesOrUsersSet(const std::vector<UUID> & ids_)
{ {
add(ids_); add(ids_);
} }
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast) RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast)
{ {
init(ast, nullptr); init(ast, nullptr);
} }
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id) RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const std::optional<UUID> & current_user_id)
{ {
init(ast, nullptr, current_user_id); init(ast, nullptr, current_user_id);
} }
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager) RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager)
{ {
init(ast, &manager); init(ast, &manager);
} }
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id) RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id)
{ {
init(ast, &manager, current_user_id); init(ast, &manager, current_user_id);
} }
void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const std::optional<UUID> & current_user_id) void RolesOrUsersSet::init(const ASTRolesOrUsersSet & ast, const AccessControlManager * manager, const std::optional<UUID> & current_user_id)
{ {
all = ast.all; all = ast.all;
@ -73,20 +72,20 @@ void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlMa
if (ast.id_mode) if (ast.id_mode)
return parse<UUID>(name); return parse<UUID>(name);
assert(manager); assert(manager);
if (ast.can_contain_users && ast.can_contain_roles) if (ast.allow_user_names && ast.allow_role_names)
{ {
auto id = manager->find<User>(name); auto id = manager->find<User>(name);
if (id) if (id)
return *id; return *id;
return manager->getID<Role>(name); return manager->getID<Role>(name);
} }
else if (ast.can_contain_users) else if (ast.allow_user_names)
{ {
return manager->getID<User>(name); return manager->getID<User>(name);
} }
else else
{ {
assert(ast.can_contain_roles); assert(ast.allow_role_names);
return manager->getID<Role>(name); return manager->getID<Role>(name);
} }
}; };
@ -122,9 +121,9 @@ void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlMa
} }
std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toAST() const std::shared_ptr<ASTRolesOrUsersSet> RolesOrUsersSet::toAST() const
{ {
auto ast = std::make_shared<ASTExtendedRoleSet>(); auto ast = std::make_shared<ASTRolesOrUsersSet>();
ast->id_mode = true; ast->id_mode = true;
ast->all = all; ast->all = all;
@ -148,9 +147,9 @@ std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toAST() const
} }
std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toASTWithNames(const AccessControlManager & manager) const std::shared_ptr<ASTRolesOrUsersSet> RolesOrUsersSet::toASTWithNames(const AccessControlManager & manager) const
{ {
auto ast = std::make_shared<ASTExtendedRoleSet>(); auto ast = std::make_shared<ASTRolesOrUsersSet>();
ast->all = all; ast->all = all;
if (!ids.empty()) if (!ids.empty())
@ -181,21 +180,21 @@ std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toASTWithNames(const Access
} }
String ExtendedRoleSet::toString() const String RolesOrUsersSet::toString() const
{ {
auto ast = toAST(); auto ast = toAST();
return serializeAST(*ast); return serializeAST(*ast);
} }
String ExtendedRoleSet::toStringWithNames(const AccessControlManager & manager) const String RolesOrUsersSet::toStringWithNames(const AccessControlManager & manager) const
{ {
auto ast = toASTWithNames(manager); auto ast = toASTWithNames(manager);
return serializeAST(*ast); return serializeAST(*ast);
} }
Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager) const Strings RolesOrUsersSet::toStringsWithNames(const AccessControlManager & manager) const
{ {
if (!all && ids.empty()) if (!all && ids.empty())
return {}; return {};
@ -233,13 +232,13 @@ Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager
} }
bool ExtendedRoleSet::empty() const bool RolesOrUsersSet::empty() const
{ {
return ids.empty() && !all; return ids.empty() && !all;
} }
void ExtendedRoleSet::clear() void RolesOrUsersSet::clear()
{ {
ids.clear(); ids.clear();
all = false; all = false;
@ -247,26 +246,26 @@ void ExtendedRoleSet::clear()
} }
void ExtendedRoleSet::add(const UUID & id) void RolesOrUsersSet::add(const UUID & id)
{ {
ids.insert(id); ids.insert(id);
} }
void ExtendedRoleSet::add(const std::vector<UUID> & ids_) void RolesOrUsersSet::add(const std::vector<UUID> & ids_)
{ {
for (const auto & id : ids_) for (const auto & id : ids_)
add(id); add(id);
} }
bool ExtendedRoleSet::match(const UUID & id) const bool RolesOrUsersSet::match(const UUID & id) const
{ {
return (all || ids.count(id)) && !except_ids.count(id); return (all || ids.count(id)) && !except_ids.count(id);
} }
bool ExtendedRoleSet::match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const bool RolesOrUsersSet::match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const
{ {
if (!all && !ids.count(user_id)) if (!all && !ids.count(user_id))
{ {
@ -285,7 +284,7 @@ bool ExtendedRoleSet::match(const UUID & user_id, const boost::container::flat_s
} }
std::vector<UUID> ExtendedRoleSet::getMatchingIDs() const std::vector<UUID> RolesOrUsersSet::getMatchingIDs() const
{ {
if (all) if (all)
throw Exception("getAllMatchingIDs() can't get ALL ids without manager", ErrorCodes::LOGICAL_ERROR); throw Exception("getAllMatchingIDs() can't get ALL ids without manager", ErrorCodes::LOGICAL_ERROR);
@ -295,7 +294,7 @@ std::vector<UUID> ExtendedRoleSet::getMatchingIDs() const
} }
std::vector<UUID> ExtendedRoleSet::getMatchingIDs(const AccessControlManager & manager) const std::vector<UUID> RolesOrUsersSet::getMatchingIDs(const AccessControlManager & manager) const
{ {
if (!all) if (!all)
return getMatchingIDs(); return getMatchingIDs();
@ -316,7 +315,7 @@ std::vector<UUID> ExtendedRoleSet::getMatchingIDs(const AccessControlManager & m
} }
bool operator ==(const ExtendedRoleSet & lhs, const ExtendedRoleSet & rhs) bool operator ==(const RolesOrUsersSet & lhs, const RolesOrUsersSet & rhs)
{ {
return (lhs.all == rhs.all) && (lhs.ids == rhs.ids) && (lhs.except_ids == rhs.except_ids); return (lhs.all == rhs.all) && (lhs.ids == rhs.ids) && (lhs.except_ids == rhs.except_ids);
} }

View File

@ -8,35 +8,35 @@
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTRolesOrUsersSet;
class AccessControlManager; class AccessControlManager;
/// Represents a set of users/roles like /// Represents a set of users/roles like
/// {user_name | role_name | CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] /// {user_name | role_name | CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
/// Similar to ASTExtendedRoleSet, but with IDs instead of names. /// Similar to ASTRolesOrUsersSet, but with IDs instead of names.
struct ExtendedRoleSet struct RolesOrUsersSet
{ {
ExtendedRoleSet(); RolesOrUsersSet();
ExtendedRoleSet(const ExtendedRoleSet & src); RolesOrUsersSet(const RolesOrUsersSet & src);
ExtendedRoleSet & operator =(const ExtendedRoleSet & src); RolesOrUsersSet & operator =(const RolesOrUsersSet & src);
ExtendedRoleSet(ExtendedRoleSet && src); RolesOrUsersSet(RolesOrUsersSet && src);
ExtendedRoleSet & operator =(ExtendedRoleSet && src); RolesOrUsersSet & operator =(RolesOrUsersSet && src);
struct AllTag {}; struct AllTag {};
ExtendedRoleSet(AllTag); RolesOrUsersSet(AllTag);
ExtendedRoleSet(const UUID & id); RolesOrUsersSet(const UUID & id);
ExtendedRoleSet(const std::vector<UUID> & ids_); RolesOrUsersSet(const std::vector<UUID> & ids_);
/// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`. /// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`.
ExtendedRoleSet(const ASTExtendedRoleSet & ast); RolesOrUsersSet(const ASTRolesOrUsersSet & ast);
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id); RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const std::optional<UUID> & current_user_id);
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager); RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager);
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id); RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
std::shared_ptr<ASTExtendedRoleSet> toAST() const; std::shared_ptr<ASTRolesOrUsersSet> toAST() const;
std::shared_ptr<ASTExtendedRoleSet> toASTWithNames(const AccessControlManager & manager) const; std::shared_ptr<ASTRolesOrUsersSet> toASTWithNames(const AccessControlManager & manager) const;
String toString() const; String toString() const;
String toStringWithNames(const AccessControlManager & manager) const; String toStringWithNames(const AccessControlManager & manager) const;
@ -47,7 +47,7 @@ struct ExtendedRoleSet
void add(const UUID & id); void add(const UUID & id);
void add(const std::vector<UUID> & ids_); void add(const std::vector<UUID> & ids_);
/// Checks if a specified ID matches this ExtendedRoleSet. /// Checks if a specified ID matches this RolesOrUsersSet.
bool match(const UUID & id) const; bool match(const UUID & id) const;
bool match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const; bool match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const;
@ -57,15 +57,15 @@ struct ExtendedRoleSet
/// Returns a list of matching users and roles. /// Returns a list of matching users and roles.
std::vector<UUID> getMatchingIDs(const AccessControlManager & manager) const; std::vector<UUID> getMatchingIDs(const AccessControlManager & manager) const;
friend bool operator ==(const ExtendedRoleSet & lhs, const ExtendedRoleSet & rhs); friend bool operator ==(const RolesOrUsersSet & lhs, const RolesOrUsersSet & rhs);
friend bool operator !=(const ExtendedRoleSet & lhs, const ExtendedRoleSet & rhs) { return !(lhs == rhs); } friend bool operator !=(const RolesOrUsersSet & lhs, const RolesOrUsersSet & rhs) { return !(lhs == rhs); }
boost::container::flat_set<UUID> ids; boost::container::flat_set<UUID> ids;
bool all = false; bool all = false;
boost::container::flat_set<UUID> except_ids; boost::container::flat_set<UUID> except_ids;
private: private:
void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const std::optional<UUID> & current_user_id = {}); void init(const ASTRolesOrUsersSet & ast, const AccessControlManager * manager = nullptr, const std::optional<UUID> & current_user_id = {});
}; };
} }

View File

@ -11,22 +11,6 @@ namespace ErrorCodes
} }
String RowPolicy::NameParts::getName() const
{
String name;
name.reserve(database.length() + table_name.length() + short_name.length() + 6);
name += backQuoteIfNeed(short_name);
name += " ON ";
if (!database.empty())
{
name += backQuoteIfNeed(database);
name += '.';
}
name += backQuoteIfNeed(table_name);
return name;
}
void RowPolicy::setDatabase(const String & database) void RowPolicy::setDatabase(const String & database)
{ {
name_parts.database = database; name_parts.database = database;

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <Access/IAccessEntity.h> #include <Access/IAccessEntity.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <array> #include <array>
@ -23,7 +23,9 @@ struct RowPolicy : public IAccessEntity
String database; String database;
String table_name; String table_name;
bool empty() const { return short_name.empty(); }
String getName() const; String getName() const;
String toString() const { return getName(); }
auto toTuple() const { return std::tie(short_name, database, table_name); } auto toTuple() const { return std::tie(short_name, database, table_name); }
friend bool operator ==(const NameParts & left, const NameParts & right) { return left.toTuple() == right.toTuple(); } friend bool operator ==(const NameParts & left, const NameParts & right) { return left.toTuple() == right.toTuple(); }
friend bool operator !=(const NameParts & left, const NameParts & right) { return left.toTuple() != right.toTuple(); } friend bool operator !=(const NameParts & left, const NameParts & right) { return left.toTuple() != right.toTuple(); }
@ -89,7 +91,7 @@ struct RowPolicy : public IAccessEntity
Type getType() const override { return TYPE; } Type getType() const override { return TYPE; }
/// Which roles or users should use this row policy. /// Which roles or users should use this row policy.
ExtendedRoleSet to_roles; RolesOrUsersSet to_roles;
private: private:
void setName(const String & name_) override; void setName(const String & name_) override;
@ -153,4 +155,20 @@ inline String toString(RowPolicy::ConditionType type)
return RowPolicy::ConditionTypeInfo::get(type).raw_name; return RowPolicy::ConditionTypeInfo::get(type).raw_name;
} }
inline String RowPolicy::NameParts::getName() const
{
String name;
name.reserve(database.length() + table_name.length() + short_name.length() + 6);
name += backQuoteIfNeed(short_name);
name += " ON ";
if (!database.empty())
{
name += backQuoteIfNeed(database);
name += '.';
}
name += backQuoteIfNeed(table_name);
return name;
}
} }

View File

@ -27,7 +27,7 @@ private:
void setPolicy(const RowPolicyPtr & policy_); void setPolicy(const RowPolicyPtr & policy_);
RowPolicyPtr policy; RowPolicyPtr policy;
const ExtendedRoleSet * roles = nullptr; const RolesOrUsersSet * roles = nullptr;
std::shared_ptr<const std::pair<String, String>> database_and_table_name; std::shared_ptr<const std::pair<String, String>> database_and_table_name;
ASTPtr parsed_conditions[RowPolicy::MAX_CONDITION_TYPE]; ASTPtr parsed_conditions[RowPolicy::MAX_CONDITION_TYPE];
}; };

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <Access/IAccessEntity.h> #include <Access/IAccessEntity.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <Access/SettingsProfileElement.h> #include <Access/SettingsProfileElement.h>
@ -14,7 +14,7 @@ struct SettingsProfile : public IAccessEntity
SettingsProfileElements elements; SettingsProfileElements elements;
/// Which roles or users should use this settings profile. /// Which roles or users should use this settings profile.
ExtendedRoleSet to_roles; RolesOrUsersSet to_roles;
bool equal(const IAccessEntity & other) const override; bool equal(const IAccessEntity & other) const override;
std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<SettingsProfile>(); } std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<SettingsProfile>(); }

View File

@ -5,7 +5,7 @@
#include <Access/AllowedClientHosts.h> #include <Access/AllowedClientHosts.h>
#include <Access/GrantedAccess.h> #include <Access/GrantedAccess.h>
#include <Access/GrantedRoles.h> #include <Access/GrantedRoles.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <Access/SettingsProfileElement.h> #include <Access/SettingsProfileElement.h>
@ -19,7 +19,7 @@ struct User : public IAccessEntity
AllowedClientHosts allowed_client_hosts = AllowedClientHosts::AnyHostTag{}; AllowedClientHosts allowed_client_hosts = AllowedClientHosts::AnyHostTag{};
GrantedAccess access; GrantedAccess access;
GrantedRoles granted_roles; GrantedRoles granted_roles;
ExtendedRoleSet default_roles = ExtendedRoleSet::AllTag{}; RolesOrUsersSet default_roles = RolesOrUsersSet::AllTag{};
SettingsProfileElements settings; SettingsProfileElements settings;
bool equal(const IAccessEntity & other) const override; bool equal(const IAccessEntity & other) const override;

View File

@ -17,7 +17,6 @@ SRCS(
EnabledRolesInfo.cpp EnabledRolesInfo.cpp
EnabledRowPolicies.cpp EnabledRowPolicies.cpp
EnabledSettings.cpp EnabledSettings.cpp
ExtendedRoleSet.cpp
GrantedAccess.cpp GrantedAccess.cpp
GrantedRoles.cpp GrantedRoles.cpp
IAccessEntity.cpp IAccessEntity.cpp
@ -29,6 +28,7 @@ SRCS(
QuotaUsage.cpp QuotaUsage.cpp
Role.cpp Role.cpp
RoleCache.cpp RoleCache.cpp
RolesOrUsersSet.cpp
RowPolicy.cpp RowPolicy.cpp
RowPolicyCache.cpp RowPolicyCache.cpp
SettingsConstraints.cpp SettingsConstraints.cpp

View File

@ -83,6 +83,23 @@ const char * IntervalKind::toKeyword() const
} }
const char * IntervalKind::toLowercasedKeyword() const
{
switch (kind)
{
case IntervalKind::Second: return "second";
case IntervalKind::Minute: return "minute";
case IntervalKind::Hour: return "hour";
case IntervalKind::Day: return "day";
case IntervalKind::Week: return "week";
case IntervalKind::Month: return "month";
case IntervalKind::Quarter: return "quarter";
case IntervalKind::Year: return "year";
}
__builtin_unreachable();
}
const char * IntervalKind::toDateDiffUnit() const const char * IntervalKind::toDateDiffUnit() const
{ {
switch (kind) switch (kind)

View File

@ -37,6 +37,8 @@ struct IntervalKind
/// Returns an uppercased version of what `toString()` returns. /// Returns an uppercased version of what `toString()` returns.
const char * toKeyword() const; const char * toKeyword() const;
const char * toLowercasedKeyword() const;
/// Returns the string which can be passed to the `unit` parameter of the dateDiff() function. /// Returns the string which can be passed to the `unit` parameter of the dateDiff() function.
/// For example, `IntervalKind{IntervalKind::Day}.getDateDiffParameter()` returns "day". /// For example, `IntervalKind{IntervalKind::Day}.getDateDiffParameter()` returns "day".
const char * toDateDiffUnit() const; const char * toDateDiffUnit() const;

View File

@ -1,6 +1,6 @@
#include <Interpreters/InterpreterCreateQuotaQuery.h> #include <Interpreters/InterpreterCreateQuotaQuery.h>
#include <Parsers/ASTCreateQuotaQuery.h> #include <Parsers/ASTCreateQuotaQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
@ -15,15 +15,18 @@ namespace DB
{ {
namespace namespace
{ {
void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query, const std::optional<ExtendedRoleSet> & roles_from_query = {}) void updateQuotaFromQueryImpl(
Quota & quota,
const ASTCreateQuotaQuery & query,
const String & override_name,
const std::optional<RolesOrUsersSet> & override_to_roles)
{ {
if (query.alter) if (!override_name.empty())
{ quota.setName(override_name);
if (!query.new_name.empty()) else if (!query.new_name.empty())
quota.setName(query.new_name); quota.setName(query.new_name);
} else if (query.names.size() == 1)
else quota.setName(query.names.front());
quota.setName(query.name);
if (query.key_type) if (query.key_type)
quota.key_type = *query.key_type; quota.key_type = *query.key_type;
@ -59,15 +62,10 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query,
quota_limits.max[resource_type] = query_limits.max[resource_type]; quota_limits.max[resource_type] = query_limits.max[resource_type];
} }
const ExtendedRoleSet * roles = nullptr; if (override_to_roles)
std::optional<ExtendedRoleSet> temp_role_set; quota.to_roles = *override_to_roles;
if (roles_from_query)
roles = &*roles_from_query;
else if (query.roles) else if (query.roles)
roles = &temp_role_set.emplace(*query.roles); quota.to_roles = *query.roles;
if (roles)
quota.to_roles = *roles;
} }
} }
@ -84,37 +82,42 @@ BlockIO InterpreterCreateQuotaQuery::execute()
return executeDDLQueryOnCluster(query_ptr, context); return executeDDLQueryOnCluster(query_ptr, context);
} }
std::optional<ExtendedRoleSet> roles_from_query; std::optional<RolesOrUsersSet> roles_from_query;
if (query.roles) if (query.roles)
roles_from_query = ExtendedRoleSet{*query.roles, access_control, context.getUserID()}; roles_from_query = RolesOrUsersSet{*query.roles, access_control, context.getUserID()};
if (query.alter) if (query.alter)
{ {
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
auto updated_quota = typeid_cast<std::shared_ptr<Quota>>(entity->clone()); auto updated_quota = typeid_cast<std::shared_ptr<Quota>>(entity->clone());
updateQuotaFromQueryImpl(*updated_quota, query, roles_from_query); updateQuotaFromQueryImpl(*updated_quota, query, {}, roles_from_query);
return updated_quota; return updated_quota;
}; };
if (query.if_exists) if (query.if_exists)
{ {
if (auto id = access_control.find<Quota>(query.name)) auto ids = access_control.find<Quota>(query.names);
access_control.tryUpdate(*id, update_func); access_control.tryUpdate(ids, update_func);
} }
else else
access_control.update(access_control.getID<Quota>(query.name), update_func); access_control.update(access_control.getIDs<Quota>(query.names), update_func);
} }
else else
{ {
auto new_quota = std::make_shared<Quota>(); std::vector<AccessEntityPtr> new_quotas;
updateQuotaFromQueryImpl(*new_quota, query, roles_from_query); for (const String & name : query.names)
{
auto new_quota = std::make_shared<Quota>();
updateQuotaFromQueryImpl(*new_quota, query, name, roles_from_query);
new_quotas.emplace_back(std::move(new_quota));
}
if (query.if_not_exists) if (query.if_not_exists)
access_control.tryInsert(new_quota); access_control.tryInsert(new_quotas);
else if (query.or_replace) else if (query.or_replace)
access_control.insertOrReplace(new_quota); access_control.insertOrReplace(new_quotas);
else else
access_control.insert(new_quota); access_control.insert(new_quotas);
} }
return {}; return {};
@ -123,7 +126,7 @@ BlockIO InterpreterCreateQuotaQuery::execute()
void InterpreterCreateQuotaQuery::updateQuotaFromQuery(Quota & quota, const ASTCreateQuotaQuery & query) void InterpreterCreateQuotaQuery::updateQuotaFromQuery(Quota & quota, const ASTCreateQuotaQuery & query)
{ {
updateQuotaFromQueryImpl(quota, query); updateQuotaFromQueryImpl(quota, query, {}, {});
} }
} }

View File

@ -13,25 +13,20 @@ namespace
void updateRoleFromQueryImpl( void updateRoleFromQueryImpl(
Role & role, Role & role,
const ASTCreateRoleQuery & query, const ASTCreateRoleQuery & query,
const std::optional<SettingsProfileElements> & settings_from_query = {}) const String & override_name,
const std::optional<SettingsProfileElements> & override_settings)
{ {
if (query.alter) if (!override_name.empty())
{ role.setName(override_name);
if (!query.new_name.empty()) else if (!query.new_name.empty())
role.setName(query.new_name); role.setName(query.new_name);
} else if (query.names.size() == 1)
else role.setName(query.names.front());
role.setName(query.name);
const SettingsProfileElements * settings = nullptr; if (override_settings)
std::optional<SettingsProfileElements> temp_settings; role.settings = *override_settings;
if (settings_from_query)
settings = &*settings_from_query;
else if (query.settings) else if (query.settings)
settings = &temp_settings.emplace(*query.settings); role.settings = *query.settings;
if (settings)
role.settings = *settings;
} }
} }
@ -57,28 +52,33 @@ BlockIO InterpreterCreateRoleQuery::execute()
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
auto updated_role = typeid_cast<std::shared_ptr<Role>>(entity->clone()); auto updated_role = typeid_cast<std::shared_ptr<Role>>(entity->clone());
updateRoleFromQueryImpl(*updated_role, query, settings_from_query); updateRoleFromQueryImpl(*updated_role, query, {}, settings_from_query);
return updated_role; return updated_role;
}; };
if (query.if_exists) if (query.if_exists)
{ {
if (auto id = access_control.find<Role>(query.name)) auto ids = access_control.find<Role>(query.names);
access_control.tryUpdate(*id, update_func); access_control.tryUpdate(ids, update_func);
} }
else else
access_control.update(access_control.getID<Role>(query.name), update_func); access_control.update(access_control.getIDs<Role>(query.names), update_func);
} }
else else
{ {
auto new_role = std::make_shared<Role>(); std::vector<AccessEntityPtr> new_roles;
updateRoleFromQueryImpl(*new_role, query, settings_from_query); for (const auto & name : query.names)
{
auto new_role = std::make_shared<Role>();
updateRoleFromQueryImpl(*new_role, query, name, settings_from_query);
new_roles.emplace_back(std::move(new_role));
}
if (query.if_not_exists) if (query.if_not_exists)
access_control.tryInsert(new_role); access_control.tryInsert(new_roles);
else if (query.or_replace) else if (query.or_replace)
access_control.insertOrReplace(new_role); access_control.insertOrReplace(new_roles);
else else
access_control.insert(new_role); access_control.insert(new_roles);
} }
return {}; return {};
@ -87,6 +87,6 @@ BlockIO InterpreterCreateRoleQuery::execute()
void InterpreterCreateRoleQuery::updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query) void InterpreterCreateRoleQuery::updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query)
{ {
updateRoleFromQueryImpl(role, query); updateRoleFromQueryImpl(role, query, {}, {});
} }
} }

View File

@ -1,6 +1,7 @@
#include <Interpreters/InterpreterCreateRowPolicyQuery.h> #include <Interpreters/InterpreterCreateRowPolicyQuery.h>
#include <Parsers/ASTCreateRowPolicyQuery.h> #include <Parsers/ASTCreateRowPolicyQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRowPolicyName.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
@ -16,35 +17,26 @@ namespace
void updateRowPolicyFromQueryImpl( void updateRowPolicyFromQueryImpl(
RowPolicy & policy, RowPolicy & policy,
const ASTCreateRowPolicyQuery & query, const ASTCreateRowPolicyQuery & query,
const std::optional<ExtendedRoleSet> & roles_from_query = {}) const RowPolicy::NameParts & override_name,
const std::optional<RolesOrUsersSet> & override_to_roles)
{ {
if (query.alter) if (!override_name.empty())
{ policy.setNameParts(override_name);
if (!query.new_short_name.empty()) else if (!query.new_short_name.empty())
policy.setShortName(query.new_short_name); policy.setShortName(query.new_short_name);
} else if (query.names->name_parts.size() == 1)
else policy.setNameParts(query.names->name_parts.front());
policy.setNameParts(query.name_parts);
if (query.is_restrictive) if (query.is_restrictive)
policy.setRestrictive(*query.is_restrictive); policy.setRestrictive(*query.is_restrictive);
for (auto condition_type : ext::range(RowPolicy::MAX_CONDITION_TYPE)) for (const auto & [condition_type, condition] : query.conditions)
{ policy.conditions[condition_type] = condition ? serializeAST(*condition) : String{};
const auto & condition = query.conditions[condition_type];
if (condition)
policy.conditions[condition_type] = *condition ? serializeAST(**condition) : String{};
}
const ExtendedRoleSet * roles = nullptr; if (override_to_roles)
std::optional<ExtendedRoleSet> temp_role_set; policy.to_roles = *override_to_roles;
if (roles_from_query)
roles = &*roles_from_query;
else if (query.roles) else if (query.roles)
roles = &temp_role_set.emplace(*query.roles); policy.to_roles = *query.roles;
if (roles)
policy.to_roles = *roles;
} }
} }
@ -61,40 +53,46 @@ BlockIO InterpreterCreateRowPolicyQuery::execute()
return executeDDLQueryOnCluster(query_ptr, context); return executeDDLQueryOnCluster(query_ptr, context);
} }
std::optional<ExtendedRoleSet> roles_from_query; assert(query.names->cluster.empty());
std::optional<RolesOrUsersSet> roles_from_query;
if (query.roles) if (query.roles)
roles_from_query = ExtendedRoleSet{*query.roles, access_control, context.getUserID()}; roles_from_query = RolesOrUsersSet{*query.roles, access_control, context.getUserID()};
if (query.name_parts.database.empty()) query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
query.name_parts.database = context.getCurrentDatabase();
if (query.alter) if (query.alter)
{ {
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
auto updated_policy = typeid_cast<std::shared_ptr<RowPolicy>>(entity->clone()); auto updated_policy = typeid_cast<std::shared_ptr<RowPolicy>>(entity->clone());
updateRowPolicyFromQueryImpl(*updated_policy, query, roles_from_query); updateRowPolicyFromQueryImpl(*updated_policy, query, {}, roles_from_query);
return updated_policy; return updated_policy;
}; };
Strings names = query.names->toStrings();
if (query.if_exists) if (query.if_exists)
{ {
if (auto id = access_control.find<RowPolicy>(query.name_parts.getName())) auto ids = access_control.find<RowPolicy>(names);
access_control.tryUpdate(*id, update_func); access_control.tryUpdate(ids, update_func);
} }
else else
access_control.update(access_control.getID<RowPolicy>(query.name_parts.getName()), update_func); access_control.update(access_control.getIDs<RowPolicy>(names), update_func);
} }
else else
{ {
auto new_policy = std::make_shared<RowPolicy>(); std::vector<AccessEntityPtr> new_policies;
updateRowPolicyFromQueryImpl(*new_policy, query, roles_from_query); for (const auto & name_parts : query.names->name_parts)
{
auto new_policy = std::make_shared<RowPolicy>();
updateRowPolicyFromQueryImpl(*new_policy, query, name_parts, roles_from_query);
new_policies.emplace_back(std::move(new_policy));
}
if (query.if_not_exists) if (query.if_not_exists)
access_control.tryInsert(new_policy); access_control.tryInsert(new_policies);
else if (query.or_replace) else if (query.or_replace)
access_control.insertOrReplace(new_policy); access_control.insertOrReplace(new_policies);
else else
access_control.insert(new_policy); access_control.insert(new_policies);
} }
return {}; return {};
@ -103,7 +101,7 @@ BlockIO InterpreterCreateRowPolicyQuery::execute()
void InterpreterCreateRowPolicyQuery::updateRowPolicyFromQuery(RowPolicy & policy, const ASTCreateRowPolicyQuery & query) void InterpreterCreateRowPolicyQuery::updateRowPolicyFromQuery(RowPolicy & policy, const ASTCreateRowPolicyQuery & query)
{ {
updateRowPolicyFromQueryImpl(policy, query); updateRowPolicyFromQueryImpl(policy, query, {}, {});
} }
} }

View File

@ -1,6 +1,6 @@
#include <Interpreters/InterpreterCreateSettingsProfileQuery.h> #include <Interpreters/InterpreterCreateSettingsProfileQuery.h>
#include <Parsers/ASTCreateSettingsProfileQuery.h> #include <Parsers/ASTCreateSettingsProfileQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
@ -15,36 +15,26 @@ namespace
void updateSettingsProfileFromQueryImpl( void updateSettingsProfileFromQueryImpl(
SettingsProfile & profile, SettingsProfile & profile,
const ASTCreateSettingsProfileQuery & query, const ASTCreateSettingsProfileQuery & query,
const std::optional<SettingsProfileElements> & settings_from_query = {}, const String & override_name,
const std::optional<ExtendedRoleSet> & roles_from_query = {}) const std::optional<SettingsProfileElements> & override_settings,
const std::optional<RolesOrUsersSet> & override_to_roles)
{ {
if (query.alter) if (!override_name.empty())
{ profile.setName(override_name);
if (!query.new_name.empty()) else if (!query.new_name.empty())
profile.setName(query.new_name); profile.setName(query.new_name);
} else if (query.names.size() == 1)
else profile.setName(query.names.front());
profile.setName(query.name);
const SettingsProfileElements * settings = nullptr; if (override_settings)
std::optional<SettingsProfileElements> temp_settings; profile.elements = *override_settings;
if (settings_from_query)
settings = &*settings_from_query;
else if (query.settings) else if (query.settings)
settings = &temp_settings.emplace(*query.settings); profile.elements = *query.settings;
if (settings) if (override_to_roles)
profile.elements = *settings; profile.to_roles = *override_to_roles;
const ExtendedRoleSet * roles = nullptr;
std::optional<ExtendedRoleSet> temp_role_set;
if (roles_from_query)
roles = &*roles_from_query;
else if (query.to_roles) else if (query.to_roles)
roles = &temp_role_set.emplace(*query.to_roles); profile.to_roles = *query.to_roles;
if (roles)
profile.to_roles = *roles;
} }
} }
@ -68,37 +58,42 @@ BlockIO InterpreterCreateSettingsProfileQuery::execute()
if (query.settings) if (query.settings)
settings_from_query = SettingsProfileElements{*query.settings, access_control}; settings_from_query = SettingsProfileElements{*query.settings, access_control};
std::optional<ExtendedRoleSet> roles_from_query; std::optional<RolesOrUsersSet> roles_from_query;
if (query.to_roles) if (query.to_roles)
roles_from_query = ExtendedRoleSet{*query.to_roles, access_control, context.getUserID()}; roles_from_query = RolesOrUsersSet{*query.to_roles, access_control, context.getUserID()};
if (query.alter) if (query.alter)
{ {
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
auto updated_profile = typeid_cast<std::shared_ptr<SettingsProfile>>(entity->clone()); auto updated_profile = typeid_cast<std::shared_ptr<SettingsProfile>>(entity->clone());
updateSettingsProfileFromQueryImpl(*updated_profile, query, settings_from_query, roles_from_query); updateSettingsProfileFromQueryImpl(*updated_profile, query, {}, settings_from_query, roles_from_query);
return updated_profile; return updated_profile;
}; };
if (query.if_exists) if (query.if_exists)
{ {
if (auto id = access_control.find<SettingsProfile>(query.name)) auto ids = access_control.find<SettingsProfile>(query.names);
access_control.tryUpdate(*id, update_func); access_control.tryUpdate(ids, update_func);
} }
else else
access_control.update(access_control.getID<SettingsProfile>(query.name), update_func); access_control.update(access_control.getIDs<SettingsProfile>(query.names), update_func);
} }
else else
{ {
auto new_profile = std::make_shared<SettingsProfile>(); std::vector<AccessEntityPtr> new_profiles;
updateSettingsProfileFromQueryImpl(*new_profile, query, settings_from_query, roles_from_query); for (const auto & name : query.names)
{
auto new_profile = std::make_shared<SettingsProfile>();
updateSettingsProfileFromQueryImpl(*new_profile, query, name, settings_from_query, roles_from_query);
new_profiles.emplace_back(std::move(new_profile));
}
if (query.if_not_exists) if (query.if_not_exists)
access_control.tryInsert(new_profile); access_control.tryInsert(new_profiles);
else if (query.or_replace) else if (query.or_replace)
access_control.insertOrReplace(new_profile); access_control.insertOrReplace(new_profiles);
else else
access_control.insert(new_profile); access_control.insert(new_profiles);
} }
return {}; return {};
@ -107,6 +102,6 @@ BlockIO InterpreterCreateSettingsProfileQuery::execute()
void InterpreterCreateSettingsProfileQuery::updateSettingsProfileFromQuery(SettingsProfile & SettingsProfile, const ASTCreateSettingsProfileQuery & query) void InterpreterCreateSettingsProfileQuery::updateSettingsProfileFromQuery(SettingsProfile & SettingsProfile, const ASTCreateSettingsProfileQuery & query)
{ {
updateSettingsProfileFromQueryImpl(SettingsProfile, query); updateSettingsProfileFromQueryImpl(SettingsProfile, query, {}, {}, {});
} }
} }

View File

@ -3,7 +3,8 @@
#include <Interpreters/InterpreterSetRoleQuery.h> #include <Interpreters/InterpreterSetRoleQuery.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
#include <Parsers/ASTCreateUserQuery.h> #include <Parsers/ASTCreateUserQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/User.h> #include <Access/User.h>
#include <Access/ContextAccess.h> #include <Access/ContextAccess.h>
@ -17,51 +18,50 @@ namespace
void updateUserFromQueryImpl( void updateUserFromQueryImpl(
User & user, User & user,
const ASTCreateUserQuery & query, const ASTCreateUserQuery & query,
const std::optional<ExtendedRoleSet> & default_roles_from_query = {}, const std::shared_ptr<ASTUserNameWithHost> & override_name,
const std::optional<SettingsProfileElements> & settings_from_query = {}) const std::optional<RolesOrUsersSet> & override_default_roles,
const std::optional<SettingsProfileElements> & override_settings)
{ {
if (query.alter) if (override_name)
{ user.setName(override_name->toString());
if (!query.new_name.empty()) else if (!query.new_name.empty())
user.setName(query.new_name); user.setName(query.new_name);
} else if (query.names->size() == 1)
else user.setName(query.names->front()->toString());
user.setName(query.name);
if (query.authentication) if (query.authentication)
user.authentication = *query.authentication; user.authentication = *query.authentication;
if (query.hosts) if (override_name && !override_name->host_pattern.empty())
{
user.allowed_client_hosts = AllowedClientHosts{};
user.allowed_client_hosts.addLikePattern(override_name->host_pattern);
}
else if (query.hosts)
user.allowed_client_hosts = *query.hosts; user.allowed_client_hosts = *query.hosts;
if (query.remove_hosts) if (query.remove_hosts)
user.allowed_client_hosts.remove(*query.remove_hosts); user.allowed_client_hosts.remove(*query.remove_hosts);
if (query.add_hosts) if (query.add_hosts)
user.allowed_client_hosts.add(*query.add_hosts); user.allowed_client_hosts.add(*query.add_hosts);
const ExtendedRoleSet * default_roles = nullptr; auto set_default_roles = [&](const RolesOrUsersSet & default_roles_)
std::optional<ExtendedRoleSet> temp_role_set;
if (default_roles_from_query)
default_roles = &*default_roles_from_query;
else if (query.default_roles)
default_roles = &temp_role_set.emplace(*query.default_roles);
if (default_roles)
{ {
if (!query.alter && !default_roles->all) if (!query.alter && !default_roles_.all)
user.granted_roles.grant(default_roles->getMatchingIDs()); user.granted_roles.grant(default_roles_.getMatchingIDs());
InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, *default_roles); InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, default_roles_);
} };
const SettingsProfileElements * settings = nullptr; if (override_default_roles)
std::optional<SettingsProfileElements> temp_settings; set_default_roles(*override_default_roles);
if (settings_from_query) else if (query.default_roles)
settings = &*settings_from_query; set_default_roles(*query.default_roles);
if (override_settings)
user.settings = *override_settings;
else if (query.settings) else if (query.settings)
settings = &temp_settings.emplace(*query.settings); user.settings = *query.settings;
if (settings)
user.settings = *settings;
} }
} }
@ -73,10 +73,10 @@ BlockIO InterpreterCreateUserQuery::execute()
auto access = context.getAccess(); auto access = context.getAccess();
access->checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER); access->checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER);
std::optional<ExtendedRoleSet> default_roles_from_query; std::optional<RolesOrUsersSet> default_roles_from_query;
if (query.default_roles) if (query.default_roles)
{ {
default_roles_from_query = ExtendedRoleSet{*query.default_roles, access_control}; default_roles_from_query = RolesOrUsersSet{*query.default_roles, access_control};
if (!query.alter && !default_roles_from_query->all) if (!query.alter && !default_roles_from_query->all)
{ {
for (const UUID & role : default_roles_from_query->getMatchingIDs()) for (const UUID & role : default_roles_from_query->getMatchingIDs())
@ -96,28 +96,34 @@ BlockIO InterpreterCreateUserQuery::execute()
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
auto updated_user = typeid_cast<std::shared_ptr<User>>(entity->clone()); auto updated_user = typeid_cast<std::shared_ptr<User>>(entity->clone());
updateUserFromQueryImpl(*updated_user, query, default_roles_from_query, settings_from_query); updateUserFromQueryImpl(*updated_user, query, {}, default_roles_from_query, settings_from_query);
return updated_user; return updated_user;
}; };
Strings names = query.names->toStrings();
if (query.if_exists) if (query.if_exists)
{ {
if (auto id = access_control.find<User>(query.name)) auto ids = access_control.find<User>(names);
access_control.tryUpdate(*id, update_func); access_control.tryUpdate(ids, update_func);
} }
else else
access_control.update(access_control.getID<User>(query.name), update_func); access_control.update(access_control.getIDs<User>(names), update_func);
} }
else else
{ {
auto new_user = std::make_shared<User>(); std::vector<AccessEntityPtr> new_users;
updateUserFromQueryImpl(*new_user, query, default_roles_from_query, settings_from_query); for (const auto & name : *query.names)
{
auto new_user = std::make_shared<User>();
updateUserFromQueryImpl(*new_user, query, name, default_roles_from_query, settings_from_query);
new_users.emplace_back(std::move(new_user));
}
if (query.if_not_exists) if (query.if_not_exists)
access_control.tryInsert(new_user); access_control.tryInsert(new_users);
else if (query.or_replace) else if (query.or_replace)
access_control.insertOrReplace(new_user); access_control.insertOrReplace(new_users);
else else
access_control.insert(new_user); access_control.insert(new_users);
} }
return {}; return {};
@ -126,7 +132,7 @@ BlockIO InterpreterCreateUserQuery::execute()
void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query) void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query)
{ {
updateUserFromQueryImpl(user, query); updateUserFromQueryImpl(user, query, {}, {}, {});
} }
} }

View File

@ -1,5 +1,6 @@
#include <Interpreters/InterpreterDropAccessEntityQuery.h> #include <Interpreters/InterpreterDropAccessEntityQuery.h>
#include <Parsers/ASTDropAccessEntityQuery.h> #include <Parsers/ASTDropAccessEntityQuery.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
@ -30,26 +31,21 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
if (!query.cluster.empty()) if (!query.cluster.empty())
return executeDDLQueryOnCluster(query_ptr, context); return executeDDLQueryOnCluster(query_ptr, context);
if (query.type == EntityType::ROW_POLICY) query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
{
Strings names;
for (auto & name_parts : query.row_policies_name_parts)
{
if (name_parts.database.empty())
name_parts.database = context.getCurrentDatabase();
names.emplace_back(name_parts.getName());
}
if (query.if_exists)
access_control.tryRemove(access_control.find<RowPolicy>(names));
else
access_control.remove(access_control.getIDs<RowPolicy>(names));
return {};
}
if (query.if_exists) auto do_drop = [&](const Strings & names)
access_control.tryRemove(access_control.find(query.type, query.names)); {
if (query.if_exists)
access_control.tryRemove(access_control.find(query.type, names));
else
access_control.remove(access_control.getIDs(query.type, names));
};
if (query.type == EntityType::ROW_POLICY)
do_drop(query.row_policy_names->toStrings());
else else
access_control.remove(access_control.getIDs(query.type, query.names)); do_drop(query.names);
return {}; return {};
} }

View File

@ -17,6 +17,7 @@
#include <Parsers/ASTSetQuery.h> #include <Parsers/ASTSetQuery.h>
#include <Parsers/ASTSetRoleQuery.h> #include <Parsers/ASTSetRoleQuery.h>
#include <Parsers/ASTShowAccessEntitiesQuery.h> #include <Parsers/ASTShowAccessEntitiesQuery.h>
#include <Parsers/ASTShowAccessQuery.h>
#include <Parsers/ASTShowCreateAccessEntityQuery.h> #include <Parsers/ASTShowCreateAccessEntityQuery.h>
#include <Parsers/ASTShowGrantsQuery.h> #include <Parsers/ASTShowGrantsQuery.h>
#include <Parsers/ASTShowPrivilegesQuery.h> #include <Parsers/ASTShowPrivilegesQuery.h>
@ -51,6 +52,7 @@
#include <Interpreters/InterpreterSetQuery.h> #include <Interpreters/InterpreterSetQuery.h>
#include <Interpreters/InterpreterSetRoleQuery.h> #include <Interpreters/InterpreterSetRoleQuery.h>
#include <Interpreters/InterpreterShowAccessEntitiesQuery.h> #include <Interpreters/InterpreterShowAccessEntitiesQuery.h>
#include <Interpreters/InterpreterShowAccessQuery.h>
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h> #include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
#include <Interpreters/InterpreterShowGrantsQuery.h> #include <Interpreters/InterpreterShowGrantsQuery.h>
#include <Interpreters/InterpreterShowPrivilegesQuery.h> #include <Interpreters/InterpreterShowPrivilegesQuery.h>
@ -231,6 +233,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, Context &
{ {
return std::make_unique<InterpreterShowAccessEntitiesQuery>(query, context); return std::make_unique<InterpreterShowAccessEntitiesQuery>(query, context);
} }
else if (query->as<ASTShowAccessQuery>())
{
return std::make_unique<InterpreterShowAccessQuery>(query, context);
}
else if (query->as<ASTShowPrivilegesQuery>()) else if (query->as<ASTShowPrivilegesQuery>())
{ {
return std::make_unique<InterpreterShowPrivilegesQuery>(query, context); return std::make_unique<InterpreterShowPrivilegesQuery>(query, context);

View File

@ -1,11 +1,11 @@
#include <Interpreters/InterpreterGrantQuery.h> #include <Interpreters/InterpreterGrantQuery.h>
#include <Parsers/ASTGrantQuery.h> #include <Parsers/ASTGrantQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Interpreters/DDLWorker.h> #include <Interpreters/DDLWorker.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/ContextAccess.h> #include <Access/ContextAccess.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <Access/User.h> #include <Access/User.h>
#include <Access/Role.h> #include <Access/Role.h>
#include <boost/range/algorithm/copy.hpp> #include <boost/range/algorithm/copy.hpp>
@ -74,7 +74,7 @@ BlockIO InterpreterGrantQuery::execute()
std::vector<UUID> roles_from_query; std::vector<UUID> roles_from_query;
if (query.roles) if (query.roles)
{ {
roles_from_query = ExtendedRoleSet{*query.roles, access_control}.getMatchingIDs(access_control); roles_from_query = RolesOrUsersSet{*query.roles, access_control}.getMatchingIDs(access_control);
for (const UUID & role_from_query : roles_from_query) for (const UUID & role_from_query : roles_from_query)
access->checkAdminOption(role_from_query); access->checkAdminOption(role_from_query);
} }
@ -85,7 +85,7 @@ BlockIO InterpreterGrantQuery::execute()
return executeDDLQueryOnCluster(query_ptr, context); return executeDDLQueryOnCluster(query_ptr, context);
} }
std::vector<UUID> to_roles = ExtendedRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control); std::vector<UUID> to_roles = RolesOrUsersSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
String current_database = context.getCurrentDatabase(); String current_database = context.getCurrentDatabase();
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
@ -115,7 +115,7 @@ void InterpreterGrantQuery::updateUserFromQuery(User & user, const ASTGrantQuery
{ {
std::vector<UUID> roles_from_query; std::vector<UUID> roles_from_query;
if (query.roles) if (query.roles)
roles_from_query = ExtendedRoleSet{*query.roles}.getMatchingIDs(); roles_from_query = RolesOrUsersSet{*query.roles}.getMatchingIDs();
updateFromQueryImpl(user, query, roles_from_query, {}); updateFromQueryImpl(user, query, roles_from_query, {});
} }
@ -124,7 +124,7 @@ void InterpreterGrantQuery::updateRoleFromQuery(Role & role, const ASTGrantQuery
{ {
std::vector<UUID> roles_from_query; std::vector<UUID> roles_from_query;
if (query.roles) if (query.roles)
roles_from_query = ExtendedRoleSet{*query.roles}.getMatchingIDs(); roles_from_query = RolesOrUsersSet{*query.roles}.getMatchingIDs();
updateFromQueryImpl(role, query, roles_from_query, {}); updateFromQueryImpl(role, query, roles_from_query, {});
} }

View File

@ -1,8 +1,8 @@
#include <Interpreters/InterpreterSetRoleQuery.h> #include <Interpreters/InterpreterSetRoleQuery.h>
#include <Parsers/ASTSetRoleQuery.h> #include <Parsers/ASTSetRoleQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Access/ExtendedRoleSet.h> #include <Access/RolesOrUsersSet.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/User.h> #include <Access/User.h>
@ -38,7 +38,7 @@ void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query)
} }
else else
{ {
ExtendedRoleSet roles_from_query{*query.roles, access_control}; RolesOrUsersSet roles_from_query{*query.roles, access_control};
boost::container::flat_set<UUID> new_current_roles; boost::container::flat_set<UUID> new_current_roles;
if (roles_from_query.all) if (roles_from_query.all)
{ {
@ -65,8 +65,8 @@ void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query)
context.checkAccess(AccessType::ALTER_USER); context.checkAccess(AccessType::ALTER_USER);
auto & access_control = context.getAccessControlManager(); auto & access_control = context.getAccessControlManager();
std::vector<UUID> to_users = ExtendedRoleSet{*query.to_users, access_control, context.getUserID()}.getMatchingIDs(access_control); std::vector<UUID> to_users = RolesOrUsersSet{*query.to_users, access_control, context.getUserID()}.getMatchingIDs(access_control);
ExtendedRoleSet roles_from_query{*query.roles, access_control}; RolesOrUsersSet roles_from_query{*query.roles, access_control};
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
{ {
@ -79,7 +79,7 @@ void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query)
} }
void InterpreterSetRoleQuery::updateUserSetDefaultRoles(User & user, const ExtendedRoleSet & roles_from_query) void InterpreterSetRoleQuery::updateUserSetDefaultRoles(User & user, const RolesOrUsersSet & roles_from_query)
{ {
if (!roles_from_query.all) if (!roles_from_query.all)
{ {

View File

@ -9,7 +9,7 @@ namespace DB
class Context; class Context;
class ASTSetRoleQuery; class ASTSetRoleQuery;
struct ExtendedRoleSet; struct RolesOrUsersSet;
struct User; struct User;
@ -20,7 +20,7 @@ public:
BlockIO execute() override; BlockIO execute() override;
static void updateUserSetDefaultRoles(User & user, const ExtendedRoleSet & roles_from_query); static void updateUserSetDefaultRoles(User & user, const RolesOrUsersSet & roles_from_query);
private: private:
void setRole(const ASTSetRoleQuery & query); void setRole(const ASTSetRoleQuery & query);

View File

@ -18,7 +18,7 @@ using EntityType = IAccessEntity::Type;
InterpreterShowAccessEntitiesQuery::InterpreterShowAccessEntitiesQuery(const ASTPtr & query_ptr_, Context & context_) InterpreterShowAccessEntitiesQuery::InterpreterShowAccessEntitiesQuery(const ASTPtr & query_ptr_, Context & context_)
: query_ptr(query_ptr_), context(context_), ignore_quota(query_ptr->as<ASTShowAccessEntitiesQuery &>().type == EntityType::QUOTA) : query_ptr(query_ptr_), context(context_)
{ {
} }
@ -31,7 +31,8 @@ BlockIO InterpreterShowAccessEntitiesQuery::execute()
String InterpreterShowAccessEntitiesQuery::getRewrittenQuery() const String InterpreterShowAccessEntitiesQuery::getRewrittenQuery() const
{ {
const auto & query = query_ptr->as<ASTShowAccessEntitiesQuery &>(); auto & query = query_ptr->as<ASTShowAccessEntitiesQuery &>();
query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
String origin; String origin;
String expr = "*"; String expr = "*";
String filter, order; String filter, order;
@ -42,14 +43,18 @@ String InterpreterShowAccessEntitiesQuery::getRewrittenQuery() const
{ {
origin = "row_policies"; origin = "row_policies";
expr = "name"; expr = "name";
const String & table_name = query.table_name; if (!query.short_name.empty())
if (!table_name.empty()) filter += String{filter.empty() ? "" : " AND "} + "short_name = " + quoteString(query.short_name);
if (query.database_and_table_name)
{ {
String database = query.database; const String & database = query.database_and_table_name->first;
if (database.empty()) const String & table_name = query.database_and_table_name->second;
database = context.getCurrentDatabase(); if (!database.empty())
filter = "database = " + quoteString(database) + " AND table = " + quoteString(table_name); filter += String{filter.empty() ? "" : " AND "} + "database = " + quoteString(database);
expr = "short_name"; if (!table_name.empty())
filter += String{filter.empty() ? "" : " AND "} + "table = " + quoteString(table_name);
if (!database.empty() && !table_name.empty())
expr = "short_name";
} }
break; break;
} }

View File

@ -15,15 +15,14 @@ public:
BlockIO execute() override; BlockIO execute() override;
bool ignoreQuota() const override { return ignore_quota; } bool ignoreQuota() const override { return true; }
bool ignoreLimits() const override { return ignore_quota; } bool ignoreLimits() const override { return true; }
private: private:
String getRewrittenQuery() const; String getRewrittenQuery() const;
ASTPtr query_ptr; ASTPtr query_ptr;
Context & context; Context & context;
bool ignore_quota = false;
}; };
} }

View File

@ -0,0 +1,89 @@
#include <Interpreters/InterpreterShowAccessQuery.h>
#include <Parsers/formatAST.h>
#include <Interpreters/Context.h>
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
#include <Interpreters/InterpreterShowGrantsQuery.h>
#include <Columns/ColumnString.h>
#include <DataStreams/OneBlockInputStream.h>
#include <DataTypes/DataTypeString.h>
#include <Access/AccessFlags.h>
#include <Access/AccessControlManager.h>
#include <ext/range.h>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB
{
using EntityType = IAccessEntity::Type;
BlockIO InterpreterShowAccessQuery::execute()
{
BlockIO res;
res.in = executeImpl();
return res;
}
BlockInputStreamPtr InterpreterShowAccessQuery::executeImpl() const
{
/// Build a create query.
ASTs queries = getCreateAndGrantQueries();
/// Build the result column.
MutableColumnPtr column = ColumnString::create();
std::stringstream ss;
for (const auto & query : queries)
{
ss.str("");
formatAST(*query, ss, false, true);
column->insert(ss.str());
}
String desc = "ACCESS";
return std::make_shared<OneBlockInputStream>(Block{{std::move(column), std::make_shared<DataTypeString>(), desc}});
}
std::vector<AccessEntityPtr> InterpreterShowAccessQuery::getEntities() const
{
const auto & access_control = context.getAccessControlManager();
context.checkAccess(AccessType::SHOW_ACCESS);
std::vector<AccessEntityPtr> entities;
for (auto type : ext::range(EntityType::MAX))
{
auto ids = access_control.findAll(type);
for (const auto & id : ids)
{
if (auto entity = access_control.tryRead(id))
entities.push_back(entity);
}
}
boost::range::sort(entities, IAccessEntity::LessByTypeAndName{});
return entities;
}
ASTs InterpreterShowAccessQuery::getCreateAndGrantQueries() const
{
auto entities = getEntities();
const auto & access_control = context.getAccessControlManager();
ASTs create_queries, grant_queries;
for (const auto & entity : entities)
{
create_queries.push_back(InterpreterShowCreateAccessEntityQuery::getCreateQuery(*entity, access_control));
if (entity->isTypeOf(EntityType::USER) || entity->isTypeOf(EntityType::USER))
boost::range::push_back(grant_queries, InterpreterShowGrantsQuery::getGrantQueries(*entity, access_control));
}
ASTs result = std::move(create_queries);
boost::range::push_back(result, std::move(grant_queries));
return result;
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <Interpreters/IInterpreter.h>
#include <Parsers/IAST_fwd.h>
namespace DB
{
class Context;
struct IAccessEntity;
using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
/** Return all queries for creating access entities and grants.
*/
class InterpreterShowAccessQuery : public IInterpreter
{
public:
InterpreterShowAccessQuery(const ASTPtr & query_ptr_, Context & context_)
: query_ptr(query_ptr_), context(context_) {}
BlockIO execute() override;
bool ignoreQuota() const override { return true; }
bool ignoreLimits() const override { return true; }
private:
BlockInputStreamPtr executeImpl() const;
ASTs getCreateAndGrantQueries() const;
std::vector<AccessEntityPtr> getEntities() const;
ASTPtr query_ptr;
Context & context;
};
}

View File

@ -6,8 +6,10 @@
#include <Parsers/ASTCreateRowPolicyQuery.h> #include <Parsers/ASTCreateRowPolicyQuery.h>
#include <Parsers/ASTCreateSettingsProfileQuery.h> #include <Parsers/ASTCreateSettingsProfileQuery.h>
#include <Parsers/ASTShowCreateAccessEntityQuery.h> #include <Parsers/ASTShowCreateAccessEntityQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <Parsers/parseQuery.h> #include <Parsers/parseQuery.h>
@ -23,6 +25,7 @@
#include <Common/StringUtils/StringUtils.h> #include <Common/StringUtils/StringUtils.h>
#include <Core/Defines.h> #include <Core/Defines.h>
#include <ext/range.h> #include <ext/range.h>
#include <boost/range/algorithm/sort.hpp>
#include <sstream> #include <sstream>
@ -42,13 +45,14 @@ namespace
bool attach_mode) bool attach_mode)
{ {
auto query = std::make_shared<ASTCreateUserQuery>(); auto query = std::make_shared<ASTCreateUserQuery>();
query->name = user.getName(); query->names = std::make_shared<ASTUserNamesWithHost>();
query->names->push_back(user.getName());
query->attach = attach_mode; query->attach = attach_mode;
if (user.allowed_client_hosts != AllowedClientHosts::AnyHostTag{}) if (user.allowed_client_hosts != AllowedClientHosts::AnyHostTag{})
query->hosts = user.allowed_client_hosts; query->hosts = user.allowed_client_hosts;
if (user.default_roles != ExtendedRoleSet::AllTag{}) if (user.default_roles != RolesOrUsersSet::AllTag{})
{ {
if (attach_mode) if (attach_mode)
query->default_roles = user.default_roles.toAST(); query->default_roles = user.default_roles.toAST();
@ -77,7 +81,7 @@ namespace
ASTPtr getCreateQueryImpl(const Role & role, const AccessControlManager * manager, bool attach_mode) ASTPtr getCreateQueryImpl(const Role & role, const AccessControlManager * manager, bool attach_mode)
{ {
auto query = std::make_shared<ASTCreateRoleQuery>(); auto query = std::make_shared<ASTCreateRoleQuery>();
query->name = role.getName(); query->names.emplace_back(role.getName());
query->attach = attach_mode; query->attach = attach_mode;
if (!role.settings.empty()) if (!role.settings.empty())
@ -95,7 +99,7 @@ namespace
ASTPtr getCreateQueryImpl(const SettingsProfile & profile, const AccessControlManager * manager, bool attach_mode) ASTPtr getCreateQueryImpl(const SettingsProfile & profile, const AccessControlManager * manager, bool attach_mode)
{ {
auto query = std::make_shared<ASTCreateSettingsProfileQuery>(); auto query = std::make_shared<ASTCreateSettingsProfileQuery>();
query->name = profile.getName(); query->names.emplace_back(profile.getName());
query->attach = attach_mode; query->attach = attach_mode;
if (!profile.elements.empty()) if (!profile.elements.empty())
@ -126,10 +130,12 @@ namespace
bool attach_mode) bool attach_mode)
{ {
auto query = std::make_shared<ASTCreateQuotaQuery>(); auto query = std::make_shared<ASTCreateQuotaQuery>();
query->name = quota.getName(); query->names.emplace_back(quota.getName());
query->attach = attach_mode; query->attach = attach_mode;
query->key_type = quota.key_type; if (quota.key_type != Quota::KeyType::NONE)
query->key_type = quota.key_type;
query->all_limits.reserve(quota.all_limits.size()); query->all_limits.reserve(quota.all_limits.size());
for (const auto & limits : quota.all_limits) for (const auto & limits : quota.all_limits)
@ -160,7 +166,8 @@ namespace
bool attach_mode) bool attach_mode)
{ {
auto query = std::make_shared<ASTCreateRowPolicyQuery>(); auto query = std::make_shared<ASTCreateRowPolicyQuery>();
query->name_parts = policy.getNameParts(); query->names = std::make_shared<ASTRowPolicyNames>();
query->names->name_parts.emplace_back(policy.getNameParts());
query->attach = attach_mode; query->attach = attach_mode;
if (policy.isRestrictive()) if (policy.isRestrictive())
@ -173,7 +180,7 @@ namespace
{ {
ParserExpression parser; ParserExpression parser;
ASTPtr expr = parseQuery(parser, condition, 0, DBMS_DEFAULT_MAX_PARSER_DEPTH); ASTPtr expr = parseQuery(parser, condition, 0, DBMS_DEFAULT_MAX_PARSER_DEPTH);
query->conditions[static_cast<size_t>(type)] = expr; query->conditions.emplace_back(type, std::move(expr));
} }
} }
@ -211,7 +218,7 @@ namespace
InterpreterShowCreateAccessEntityQuery::InterpreterShowCreateAccessEntityQuery(const ASTPtr & query_ptr_, const Context & context_) InterpreterShowCreateAccessEntityQuery::InterpreterShowCreateAccessEntityQuery(const ASTPtr & query_ptr_, const Context & context_)
: query_ptr(query_ptr_), context(context_), ignore_quota(query_ptr->as<ASTShowCreateAccessEntityQuery &>().type == EntityType::QUOTA) : query_ptr(query_ptr_), context(context_)
{ {
} }
@ -226,23 +233,22 @@ BlockIO InterpreterShowCreateAccessEntityQuery::execute()
BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl() BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
{ {
auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>(); /// Build a create queries.
ASTs create_queries = getCreateQueries();
/// Build a create query.
ASTPtr create_query = getCreateQuery(show_query);
/// Build the result column. /// Build the result column.
MutableColumnPtr column = ColumnString::create(); MutableColumnPtr column = ColumnString::create();
if (create_query) std::stringstream create_query_ss;
for (const auto & create_query : create_queries)
{ {
std::stringstream create_query_ss;
formatAST(*create_query, create_query_ss, false, true); formatAST(*create_query, create_query_ss, false, true);
String create_query_str = create_query_ss.str(); column->insert(create_query_ss.str());
column->insert(create_query_str); create_query_ss.str("");
} }
/// Prepare description of the result column. /// Prepare description of the result column.
std::stringstream desc_ss; std::stringstream desc_ss;
const auto & show_query = query_ptr->as<const ASTShowCreateAccessEntityQuery &>();
formatAST(show_query, desc_ss, false, true); formatAST(show_query, desc_ss, false, true);
String desc = desc_ss.str(); String desc = desc_ss.str();
String prefix = "SHOW "; String prefix = "SHOW ";
@ -253,38 +259,91 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
} }
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(ASTShowCreateAccessEntityQuery & show_query) const std::vector<AccessEntityPtr> InterpreterShowCreateAccessEntityQuery::getEntities() const
{ {
auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
const auto & access_control = context.getAccessControlManager(); const auto & access_control = context.getAccessControlManager();
context.checkAccess(getRequiredAccess()); context.checkAccess(getRequiredAccess());
show_query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
std::vector<AccessEntityPtr> entities;
if (show_query.current_user) if (show_query.all)
{ {
auto user = context.getUser(); auto ids = access_control.findAll(show_query.type);
if (!user) for (const auto & id : ids)
return nullptr; {
return getCreateQueryImpl(*user, &access_control, false); if (auto entity = access_control.tryRead(id))
entities.push_back(entity);
}
} }
else if (show_query.current_user)
if (show_query.current_quota) {
if (auto user = context.getUser())
entities.push_back(user);
}
else if (show_query.current_quota)
{ {
auto usage = context.getQuotaUsage(); auto usage = context.getQuotaUsage();
if (!usage) if (usage)
return nullptr; entities.push_back(access_control.read<Quota>(usage->quota_id));
auto quota = access_control.read<Quota>(usage->quota_id);
return getCreateQueryImpl(*quota, &access_control, false);
} }
else if (show_query.type == EntityType::ROW_POLICY)
if (show_query.type == EntityType::ROW_POLICY)
{ {
if (show_query.row_policy_name_parts.database.empty()) auto ids = access_control.findAll<RowPolicy>();
show_query.row_policy_name_parts.database = context.getCurrentDatabase(); if (show_query.row_policy_names)
RowPolicyPtr policy = access_control.read<RowPolicy>(show_query.row_policy_name_parts.getName()); {
return getCreateQueryImpl(*policy, &access_control, false); for (const String & name : show_query.row_policy_names->toStrings())
entities.push_back(access_control.read<RowPolicy>(name));
}
else
{
for (const auto & id : ids)
{
auto policy = access_control.tryRead<RowPolicy>(id);
if (!policy)
continue;
if (!show_query.short_name.empty() && (policy->getShortName() != show_query.short_name))
continue;
if (show_query.database_and_table_name)
{
const String & database = show_query.database_and_table_name->first;
const String & table_name = show_query.database_and_table_name->second;
if (!database.empty() && (policy->getDatabase() != database))
continue;
if (!table_name.empty() && (policy->getTableName() != table_name))
continue;
}
entities.push_back(policy);
}
}
}
else
{
for (const String & name : show_query.names)
entities.push_back(access_control.read(access_control.getID(show_query.type, name)));
} }
auto entity = access_control.read(access_control.getID(show_query.type, show_query.name)); boost::range::sort(entities, IAccessEntity::LessByName{});
return getCreateQueryImpl(*entity, &access_control, false); return entities;
}
ASTs InterpreterShowCreateAccessEntityQuery::getCreateQueries() const
{
auto entities = getEntities();
ASTs list;
const auto & access_control = context.getAccessControlManager();
for (const auto & entity : entities)
list.push_back(getCreateQuery(*entity, access_control));
return list;
}
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const IAccessEntity & entity, const AccessControlManager & access_control)
{
return getCreateQueryImpl(entity, &access_control, false);
} }

View File

@ -7,10 +7,11 @@
namespace DB namespace DB
{ {
class AccessControlManager;
class Context; class Context;
class ASTShowCreateAccessEntityQuery;
class AccessRightsElements; class AccessRightsElements;
struct IAccessEntity; struct IAccessEntity;
using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
/** Returns a single item containing a statement which could be used to create a specified role. /** Returns a single item containing a statement which could be used to create a specified role.
@ -22,19 +23,20 @@ public:
BlockIO execute() override; BlockIO execute() override;
bool ignoreQuota() const override { return ignore_quota; } bool ignoreQuota() const override { return true; }
bool ignoreLimits() const override { return ignore_quota; } bool ignoreLimits() const override { return true; }
static ASTPtr getCreateQuery(const IAccessEntity & entity, const AccessControlManager & access_control);
static ASTPtr getAttachQuery(const IAccessEntity & entity); static ASTPtr getAttachQuery(const IAccessEntity & entity);
private: private:
BlockInputStreamPtr executeImpl(); BlockInputStreamPtr executeImpl();
ASTPtr getCreateQuery(ASTShowCreateAccessEntityQuery & show_query) const; std::vector<AccessEntityPtr> getEntities() const;
ASTs getCreateQueries() const;
AccessRightsElements getRequiredAccess() const; AccessRightsElements getRequiredAccess() const;
ASTPtr query_ptr; ASTPtr query_ptr;
const Context & context; const Context & context;
bool ignore_quota = false;
}; };

View File

@ -1,7 +1,7 @@
#include <Interpreters/InterpreterShowGrantsQuery.h> #include <Interpreters/InterpreterShowGrantsQuery.h>
#include <Parsers/ASTShowGrantsQuery.h> #include <Parsers/ASTShowGrantsQuery.h>
#include <Parsers/ASTGrantQuery.h> #include <Parsers/ASTGrantQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <Interpreters/Context.h> #include <Interpreters/Context.h>
#include <Columns/ColumnString.h> #include <Columns/ColumnString.h>
@ -10,6 +10,9 @@
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/User.h> #include <Access/User.h>
#include <Access/Role.h> #include <Access/Role.h>
#include <Access/RolesOrUsersSet.h>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB namespace DB
@ -29,7 +32,7 @@ namespace
{ {
ASTs res; ASTs res;
std::shared_ptr<ASTExtendedRoleSet> to_roles = std::make_shared<ASTExtendedRoleSet>(); std::shared_ptr<ASTRolesOrUsersSet> to_roles = std::make_shared<ASTRolesOrUsersSet>();
to_roles->names.push_back(grantee.getName()); to_roles->names.push_back(grantee.getName());
auto grants_and_partial_revokes = grantee.access.getGrantsAndPartialRevokes(); auto grants_and_partial_revokes = grantee.access.getGrantsAndPartialRevokes();
@ -87,9 +90,9 @@ namespace
grant_query->admin_option = admin_option; grant_query->admin_option = admin_option;
grant_query->to_roles = to_roles; grant_query->to_roles = to_roles;
if (attach_mode) if (attach_mode)
grant_query->roles = ExtendedRoleSet{roles}.toAST(); grant_query->roles = RolesOrUsersSet{roles}.toAST();
else else
grant_query->roles = ExtendedRoleSet{roles}.toASTWithNames(*manager); grant_query->roles = RolesOrUsersSet{roles}.toASTWithNames(*manager);
res.push_back(std::move(grant_query)); res.push_back(std::move(grant_query));
} }
@ -121,10 +124,8 @@ BlockIO InterpreterShowGrantsQuery::execute()
BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl() BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
{ {
const auto & show_query = query_ptr->as<ASTShowGrantsQuery &>();
/// Build a create query. /// Build a create query.
ASTs grant_queries = getGrantQueries(show_query); ASTs grant_queries = getGrantQueries();
/// Build the result column. /// Build the result column.
MutableColumnPtr column = ColumnString::create(); MutableColumnPtr column = ColumnString::create();
@ -138,6 +139,7 @@ BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
/// Prepare description of the result column. /// Prepare description of the result column.
std::stringstream desc_ss; std::stringstream desc_ss;
const auto & show_query = query_ptr->as<const ASTShowGrantsQuery &>();
formatAST(show_query, desc_ss, false, true); formatAST(show_query, desc_ss, false, true);
String desc = desc_ss.str(); String desc = desc_ss.str();
String prefix = "SHOW "; String prefix = "SHOW ";
@ -148,21 +150,41 @@ BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
} }
ASTs InterpreterShowGrantsQuery::getGrantQueries(const ASTShowGrantsQuery & show_query) const std::vector<AccessEntityPtr> InterpreterShowGrantsQuery::getEntities() const
{ {
const auto & show_query = query_ptr->as<ASTShowGrantsQuery &>();
const auto & access_control = context.getAccessControlManager(); const auto & access_control = context.getAccessControlManager();
auto ids = RolesOrUsersSet{*show_query.for_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
AccessEntityPtr user_or_role; std::vector<AccessEntityPtr> entities;
if (show_query.current_user) for (const auto & id : ids)
user_or_role = context.getUser();
else
{ {
user_or_role = access_control.tryRead<User>(show_query.name); auto entity = access_control.tryRead(id);
if (!user_or_role) if (entity)
user_or_role = access_control.read<Role>(show_query.name); entities.push_back(entity);
} }
return getGrantQueriesImpl(*user_or_role, &access_control); boost::range::sort(entities, IAccessEntity::LessByTypeAndName{});
return entities;
}
ASTs InterpreterShowGrantsQuery::getGrantQueries() const
{
auto entities = getEntities();
const auto & access_control = context.getAccessControlManager();
ASTs grant_queries;
for (const auto & entity : entities)
boost::range::push_back(grant_queries, getGrantQueries(*entity, access_control));
return grant_queries;
}
ASTs InterpreterShowGrantsQuery::getGrantQueries(const IAccessEntity & user_or_role, const AccessControlManager & access_control)
{
return getGrantQueriesImpl(user_or_role, &access_control, false);
} }

View File

@ -7,8 +7,10 @@
namespace DB namespace DB
{ {
class AccessControlManager;
class ASTShowGrantsQuery; class ASTShowGrantsQuery;
struct IAccessEntity; struct IAccessEntity;
using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
class InterpreterShowGrantsQuery : public IInterpreter class InterpreterShowGrantsQuery : public IInterpreter
@ -18,11 +20,16 @@ public:
BlockIO execute() override; BlockIO execute() override;
static ASTs getGrantQueries(const IAccessEntity & user_or_role, const AccessControlManager & access_control);
static ASTs getAttachGrantQueries(const IAccessEntity & user_or_role); static ASTs getAttachGrantQueries(const IAccessEntity & user_or_role);
bool ignoreQuota() const override { return true; }
bool ignoreLimits() const override { return true; }
private: private:
BlockInputStreamPtr executeImpl(); BlockInputStreamPtr executeImpl();
ASTs getGrantQueries(const ASTShowGrantsQuery & show_query) const; ASTs getGrantQueries() const;
std::vector<AccessEntityPtr> getEntities() const;
ASTPtr query_ptr; ASTPtr query_ptr;
Context & context; Context & context;

View File

@ -85,6 +85,7 @@ SRCS(
InterpreterSelectWithUnionQuery.cpp InterpreterSelectWithUnionQuery.cpp
InterpreterSetQuery.cpp InterpreterSetQuery.cpp
InterpreterSetRoleQuery.cpp InterpreterSetRoleQuery.cpp
InterpreterShowAccessQuery.cpp
InterpreterShowAccessEntitiesQuery.cpp InterpreterShowAccessEntitiesQuery.cpp
InterpreterShowCreateAccessEntityQuery.cpp InterpreterShowCreateAccessEntityQuery.cpp
InterpreterShowCreateQuery.cpp InterpreterShowCreateQuery.cpp

View File

@ -1,5 +1,5 @@
#include <Parsers/ASTCreateQuotaQuery.h> #include <Parsers/ASTCreateQuotaQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
#include <Common/IntervalKind.h> #include <Common/IntervalKind.h>
#include <ext/range.h> #include <ext/range.h>
@ -18,8 +18,41 @@ namespace
void formatKeyType(const KeyType & key_type, const IAST::FormatSettings & settings) void formatKeyType(const KeyType & key_type, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " KEYED BY " << (settings.hilite ? IAST::hilite_none : "") << "'" const auto & type_info = KeyTypeInfo::get(key_type);
<< KeyTypeInfo::get(key_type).name << "'"; if (key_type == KeyType::NONE)
{
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " NOT KEYED" << (settings.hilite ? IAST::hilite_none : "");
return;
}
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " KEYED BY " << (settings.hilite ? IAST::hilite_none : "");
if (!type_info.base_types.empty())
{
bool need_comma = false;
for (const auto & base_type : type_info.base_types)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
settings.ostr << KeyTypeInfo::get(base_type).name;
}
return;
}
settings.ostr << type_info.name;
}
void formatNames(const Strings & names, const IAST::FormatSettings & settings)
{
settings.ostr << " ";
bool need_comma = false;
for (const String & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
settings.ostr << backQuoteIfNeed(name);
}
} }
@ -30,20 +63,14 @@ namespace
} }
void formatLimit(ResourceType resource_type, ResourceAmount max, bool first, const IAST::FormatSettings & settings) void formatLimit(ResourceType resource_type, ResourceAmount max, const IAST::FormatSettings & settings)
{ {
if (first)
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " MAX" << (settings.hilite ? IAST::hilite_none : "");
else
settings.ostr << ",";
const auto & type_info = ResourceTypeInfo::get(resource_type); const auto & type_info = ResourceTypeInfo::get(resource_type);
settings.ostr << " " << (settings.hilite ? IAST::hilite_keyword : "") << type_info.keyword settings.ostr << " " << type_info.name << " = " << type_info.amountToString(max);
<< (settings.hilite ? IAST::hilite_none : "") << " " << type_info.amountToString(max);
} }
void formatLimits(const ASTCreateQuotaQuery::Limits & limits, const IAST::FormatSettings & settings) void formatIntervalWithLimits(const ASTCreateQuotaQuery::Limits & limits, const IAST::FormatSettings & settings)
{ {
auto interval_kind = IntervalKind::fromAvgSeconds(limits.duration.count()); auto interval_kind = IntervalKind::fromAvgSeconds(limits.duration.count());
Int64 num_intervals = limits.duration.count() / interval_kind.toAvgSeconds(); Int64 num_intervals = limits.duration.count() / interval_kind.toAvgSeconds();
@ -51,11 +78,11 @@ namespace
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") settings.ostr << (settings.hilite ? IAST::hilite_keyword : "")
<< " FOR" << " FOR"
<< (limits.randomize_interval ? " RANDOMIZED" : "") << (limits.randomize_interval ? " RANDOMIZED" : "")
<< " INTERVAL " << " INTERVAL"
<< (settings.hilite ? IAST::hilite_none : "") << (settings.hilite ? IAST::hilite_none : "")
<< num_intervals << " " << " " << num_intervals << " "
<< (settings.hilite ? IAST::hilite_keyword : "") << (settings.hilite ? IAST::hilite_keyword : "")
<< interval_kind.toKeyword() << interval_kind.toLowercasedKeyword()
<< (settings.hilite ? IAST::hilite_none : ""); << (settings.hilite ? IAST::hilite_none : "");
if (limits.drop) if (limits.drop)
@ -68,17 +95,28 @@ namespace
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
{ {
if (limits.max[resource_type]) if (limits.max[resource_type])
{
formatLimit(resource_type, *limits.max[resource_type], !limit_found, settings);
limit_found = true; limit_found = true;
}
if (limit_found)
{
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " MAX" << (settings.hilite ? IAST::hilite_none : "");
bool need_comma = false;
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
{
if (limits.max[resource_type])
{
if (std::exchange(need_comma, true))
settings.ostr << ",";
formatLimit(resource_type, *limits.max[resource_type], settings);
}
} }
} }
if (!limit_found) else
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TRACKING ONLY" << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TRACKING ONLY" << (settings.hilite ? IAST::hilite_none : "");
} }
} }
void formatAllLimits(const std::vector<ASTCreateQuotaQuery::Limits> & all_limits, const IAST::FormatSettings & settings) void formatIntervalsWithLimits(const std::vector<ASTCreateQuotaQuery::Limits> & all_limits, const IAST::FormatSettings & settings)
{ {
bool need_comma = false; bool need_comma = false;
for (const auto & limits : all_limits) for (const auto & limits : all_limits)
@ -87,11 +125,11 @@ namespace
settings.ostr << ","; settings.ostr << ",";
need_comma = true; need_comma = true;
formatLimits(limits, settings); formatIntervalWithLimits(limits, settings);
} }
} }
void formatToRoles(const ASTExtendedRoleSet & roles, const IAST::FormatSettings & settings) void formatToRoles(const ASTRolesOrUsersSet & roles, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : "");
roles.format(settings); roles.format(settings);
@ -130,8 +168,7 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
else if (or_replace) else if (or_replace)
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : ""); settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
settings.ostr << " " << backQuoteIfNeed(name); formatNames(names, settings);
formatOnCluster(settings); formatOnCluster(settings);
if (!new_name.empty()) if (!new_name.empty())
@ -140,7 +177,7 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
if (key_type) if (key_type)
formatKeyType(*key_type, settings); formatKeyType(*key_type, settings);
formatAllLimits(all_limits, settings); formatIntervalsWithLimits(all_limits, settings);
if (roles && (!roles->empty() || alter)) if (roles && (!roles->empty() || alter))
formatToRoles(*roles, settings); formatToRoles(*roles, settings);

View File

@ -7,21 +7,21 @@
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTRolesOrUsersSet;
/** CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name /** CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {none | user_name | ip_address | client_key | client_key, user_name | client_key, ip_address} | NOT KEYED]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {second | minute | hour | day}
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] | * {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
* NO LIMITS | TRACKING ONLY} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
* *
* ALTER QUOTA [IF EXISTS] name * ALTER QUOTA [IF EXISTS] name
* [RENAME TO new_name] * [RENAME TO new_name]
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {none | user_name | ip_address | client_key | client_key, user_name | client_key, ip_address} | NOT KEYED]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {second | minute | hour | day}
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] | * {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
* NO LIMITS | TRACKING ONLY} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
*/ */
@ -38,7 +38,7 @@ public:
using KeyType = Quota::KeyType; using KeyType = Quota::KeyType;
using ResourceAmount = Quota::ResourceAmount; using ResourceAmount = Quota::ResourceAmount;
String name; Strings names;
String new_name; String new_name;
std::optional<KeyType> key_type; std::optional<KeyType> key_type;
@ -51,7 +51,7 @@ public:
}; };
std::vector<Limits> all_limits; std::vector<Limits> all_limits;
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;

View File

@ -7,6 +7,18 @@ namespace DB
{ {
namespace namespace
{ {
void formatNames(const Strings & names, const IAST::FormatSettings & settings)
{
settings.ostr << " ";
bool need_comma = false;
for (const String & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
settings.ostr << backQuoteIfNeed(name);
}
}
void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings) void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "") settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "")
@ -52,8 +64,7 @@ void ASTCreateRoleQuery::formatImpl(const FormatSettings & format, FormatState &
else if (or_replace) else if (or_replace)
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : ""); format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
format.ostr << " " << backQuoteIfNeed(name); formatNames(names, format);
formatOnCluster(format); formatOnCluster(format);
if (!new_name.empty()) if (!new_name.empty())

View File

@ -26,7 +26,7 @@ public:
bool if_not_exists = false; bool if_not_exists = false;
bool or_replace = false; bool or_replace = false;
String name; Strings names;
String new_name; String new_name;
std::shared_ptr<ASTSettingsProfileElements> settings; std::shared_ptr<ASTSettingsProfileElements> settings;

View File

@ -1,5 +1,6 @@
#include <Parsers/ASTCreateRowPolicyQuery.h> #include <Parsers/ASTCreateRowPolicyQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRowPolicyName.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/formatAST.h> #include <Parsers/formatAST.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
#include <ext/range.h> #include <ext/range.h>
@ -13,7 +14,6 @@ namespace
{ {
using ConditionType = RowPolicy::ConditionType; using ConditionType = RowPolicy::ConditionType;
using ConditionTypeInfo = RowPolicy::ConditionTypeInfo; using ConditionTypeInfo = RowPolicy::ConditionTypeInfo;
constexpr auto MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
void formatRenameTo(const String & new_short_name, const IAST::FormatSettings & settings) void formatRenameTo(const String & new_short_name, const IAST::FormatSettings & settings)
@ -25,21 +25,22 @@ namespace
void formatAsRestrictiveOrPermissive(bool is_restrictive, const IAST::FormatSettings & settings) void formatAsRestrictiveOrPermissive(bool is_restrictive, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " AS " << (is_restrictive ? "RESTRICTIVE" : "PERMISSIVE") settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " AS " << (settings.hilite ? IAST::hilite_none : "")
<< (settings.hilite ? IAST::hilite_none : ""); << (is_restrictive ? "restrictive" : "permissive");
} }
void formatConditionalExpression(const ASTPtr & expr, const IAST::FormatSettings & settings) void formatConditionalExpression(const ASTPtr & expr, const IAST::FormatSettings & settings)
{ {
settings.ostr << " ";
if (expr) if (expr)
expr->format(settings); expr->format(settings);
else else
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " NONE" << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << "NONE" << (settings.hilite ? IAST::hilite_none : "");
} }
void formatCondition(const boost::container::flat_set<std::string_view> & commands, const String & filter, const String & check, bool alter, const IAST::FormatSettings & settings) void formatForClause(const boost::container::flat_set<std::string_view> & commands, const String & filter, const String & check, bool alter, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " FOR " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " FOR " << (settings.hilite ? IAST::hilite_none : "");
bool need_comma = false; bool need_comma = false;
@ -51,27 +52,23 @@ namespace
} }
if (!filter.empty()) if (!filter.empty())
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " USING " << (settings.hilite ? IAST::hilite_none : "") << filter; settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " USING" << (settings.hilite ? IAST::hilite_none : "") << filter;
if (!check.empty() && (alter || (check != filter))) if (!check.empty() && (alter || (check != filter)))
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " WITH CHECK " << (settings.hilite ? IAST::hilite_none : "") << check; settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " WITH CHECK" << (settings.hilite ? IAST::hilite_none : "") << check;
} }
void formatMultipleConditions(const std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> & conditions, bool alter, const IAST::FormatSettings & settings) void formatForClauses(const std::vector<std::pair<ConditionType, ASTPtr>> & conditions, bool alter, const IAST::FormatSettings & settings)
{ {
std::array<String, MAX_CONDITION_TYPE> conditions_as_strings; std::vector<std::pair<ConditionType, String>> conditions_as_strings;
std::stringstream temp_sstream; std::stringstream temp_sstream;
IAST::FormatSettings temp_settings(temp_sstream, settings); IAST::FormatSettings temp_settings(temp_sstream, settings);
for (auto condition_type : ext::range(MAX_CONDITION_TYPE)) for (const auto & [condition_type, condition] : conditions)
{ {
const auto & condition = conditions[condition_type]; formatConditionalExpression(condition, temp_settings);
if (condition) conditions_as_strings.emplace_back(condition_type, temp_sstream.str());
{ temp_sstream.str("");
formatConditionalExpression(*condition, temp_settings);
conditions_as_strings[condition_type] = temp_sstream.str();
temp_sstream.str("");
}
} }
boost::container::flat_set<std::string_view> commands; boost::container::flat_set<std::string_view> commands;
@ -84,9 +81,8 @@ namespace
check.clear(); check.clear();
/// Collect commands using the same filter and check conditions. /// Collect commands using the same filter and check conditions.
for (auto condition_type : ext::range(MAX_CONDITION_TYPE)) for (auto & [condition_type, condition] : conditions_as_strings)
{ {
const String & condition = conditions_as_strings[condition_type];
if (condition.empty()) if (condition.empty())
continue; continue;
const auto & type_info = ConditionTypeInfo::get(condition_type); const auto & type_info = ConditionTypeInfo::get(condition_type);
@ -105,17 +101,17 @@ namespace
continue; continue;
} }
commands.emplace(type_info.command); commands.emplace(type_info.command);
conditions_as_strings[condition_type].clear(); /// Skip this condition on the next iteration. condition.clear(); /// Skip this condition on the next iteration.
} }
if (!filter.empty() || !check.empty()) if (!filter.empty() || !check.empty())
formatCondition(commands, filter, check, alter, settings); formatForClause(commands, filter, check, alter, settings);
} }
while (!filter.empty() || !check.empty()); while (!filter.empty() || !check.empty());
} }
void formatToRoles(const ASTExtendedRoleSet & roles, const IAST::FormatSettings & settings) void formatToRoles(const ASTRolesOrUsersSet & roles, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : "");
roles.format(settings); roles.format(settings);
@ -154,13 +150,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
else if (or_replace) else if (or_replace)
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : ""); settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
const String & database = name_parts.database; settings.ostr << " ";
const String & table_name = name_parts.table_name; names->format(settings);
const String & short_name = name_parts.short_name;
settings.ostr << " " << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON "
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") << table_name;
formatOnCluster(settings); formatOnCluster(settings);
assert(names->cluster.empty());
if (!new_short_name.empty()) if (!new_short_name.empty())
formatRenameTo(new_short_name, settings); formatRenameTo(new_short_name, settings);
@ -168,7 +162,7 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
if (is_restrictive) if (is_restrictive)
formatAsRestrictiveOrPermissive(*is_restrictive, settings); formatAsRestrictiveOrPermissive(*is_restrictive, settings);
formatMultipleConditions(conditions, alter, settings); formatForClauses(conditions, alter, settings);
if (roles && (!roles->empty() || alter)) if (roles && (!roles->empty() || alter))
formatToRoles(*roles, settings); formatToRoles(*roles, settings);
@ -180,4 +174,10 @@ void ASTCreateRowPolicyQuery::replaceCurrentUserTagWithName(const String & curre
if (roles) if (roles)
roles->replaceCurrentUserTagWithName(current_user_name); roles->replaceCurrentUserTagWithName(current_user_name);
} }
void ASTCreateRowPolicyQuery::replaceEmptyDatabaseWithCurrent(const String & current_database) const
{
if (names)
names->replaceEmptyDatabaseWithCurrent(current_database);
}
} }

View File

@ -3,16 +3,16 @@
#include <Parsers/IAST.h> #include <Parsers/IAST.h>
#include <Parsers/ASTQueryWithOnCluster.h> #include <Parsers/ASTQueryWithOnCluster.h>
#include <Access/RowPolicy.h> #include <Access/RowPolicy.h>
#include <array>
#include <optional> #include <optional>
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTRowPolicyNames;
class ASTRolesOrUsersSet;
/** CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table /** CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
* [AS {PERMISSIVE | RESTRICTIVE}] * [AS {permissive | restrictive}]
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}] * [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
* [USING condition] * [USING condition]
* [WITH CHECK condition] [,...] * [WITH CHECK condition] [,...]
@ -20,7 +20,7 @@ class ASTExtendedRoleSet;
* *
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table * ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
* [RENAME TO new_name] * [RENAME TO new_name]
* [AS {PERMISSIVE | RESTRICTIVE}] * [AS {permissive | restrictive}]
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}] * [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
* [USING {condition | NONE}] * [USING {condition | NONE}]
* [WITH CHECK {condition | NONE}] [,...] * [WITH CHECK {condition | NONE}] [,...]
@ -36,18 +36,20 @@ public:
bool if_not_exists = false; bool if_not_exists = false;
bool or_replace = false; bool or_replace = false;
RowPolicy::NameParts name_parts; std::shared_ptr<ASTRowPolicyNames> names;
String new_short_name; String new_short_name;
std::optional<bool> is_restrictive; std::optional<bool> is_restrictive;
std::array<std::optional<ASTPtr>, RowPolicy::MAX_CONDITION_TYPE> conditions; /// `nullopt` means "not set", `nullptr` means set to NONE. std::vector<std::pair<RowPolicy::ConditionType, ASTPtr>> conditions; /// `nullptr` means set to NONE.
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
void replaceCurrentUserTagWithName(const String & current_user_name) const;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRowPolicyQuery>(clone()); } ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRowPolicyQuery>(clone()); }
void replaceCurrentUserTagWithName(const String & current_user_name) const;
void replaceEmptyDatabaseWithCurrent(const String & current_database) const;
}; };
} }

View File

@ -1,6 +1,6 @@
#include <Parsers/ASTCreateSettingsProfileQuery.h> #include <Parsers/ASTCreateSettingsProfileQuery.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
@ -8,6 +8,18 @@ namespace DB
{ {
namespace namespace
{ {
void formatNames(const Strings & names, const IAST::FormatSettings & settings)
{
settings.ostr << " ";
bool need_comma = false;
for (const String & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
settings.ostr << backQuoteIfNeed(name);
}
}
void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings) void formatRenameTo(const String & new_name, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "") settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "")
@ -20,7 +32,7 @@ namespace
settings.format(format); settings.format(format);
} }
void formatToRoles(const ASTExtendedRoleSet & roles, const IAST::FormatSettings & settings) void formatToRoles(const ASTRolesOrUsersSet & roles, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : "");
roles.format(settings); roles.format(settings);
@ -59,8 +71,7 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
else if (or_replace) else if (or_replace)
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : ""); format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
format.ostr << " " << backQuoteIfNeed(name); formatNames(names, format);
formatOnCluster(format); formatOnCluster(format);
if (!new_name.empty()) if (!new_name.empty())

View File

@ -7,7 +7,7 @@
namespace DB namespace DB
{ {
class ASTSettingsProfileElements; class ASTSettingsProfileElements;
class ASTExtendedRoleSet; class ASTRolesOrUsersSet;
/** CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name /** CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name
@ -29,12 +29,12 @@ public:
bool if_not_exists = false; bool if_not_exists = false;
bool or_replace = false; bool or_replace = false;
String name; Strings names;
String new_name; String new_name;
std::shared_ptr<ASTSettingsProfileElements> settings; std::shared_ptr<ASTSettingsProfileElements> settings;
std::shared_ptr<ASTExtendedRoleSet> to_roles; std::shared_ptr<ASTRolesOrUsersSet> to_roles;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;

View File

@ -1,5 +1,6 @@
#include <Parsers/ASTCreateUserQuery.h> #include <Parsers/ASTCreateUserQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
@ -167,7 +168,7 @@ namespace
} }
void formatDefaultRoles(const ASTExtendedRoleSet & default_roles, const IAST::FormatSettings & settings) void formatDefaultRoles(const ASTRolesOrUsersSet & default_roles, const IAST::FormatSettings & settings)
{ {
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " DEFAULT ROLE " << (settings.hilite ? IAST::hilite_none : ""); settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " DEFAULT ROLE " << (settings.hilite ? IAST::hilite_none : "");
default_roles.format(settings); default_roles.format(settings);
@ -213,7 +214,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
else if (or_replace) else if (or_replace)
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : ""); format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
format.ostr << " " << backQuoteIfNeed(name); format.ostr << " ";
names->format(format);
formatOnCluster(format); formatOnCluster(format);

View File

@ -8,7 +8,8 @@
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTUserNamesWithHost;
class ASTRolesOrUsersSet;
class ASTSettingsProfileElements; class ASTSettingsProfileElements;
/** CREATE USER [IF NOT EXISTS | OR REPLACE] name /** CREATE USER [IF NOT EXISTS | OR REPLACE] name
@ -34,7 +35,7 @@ public:
bool if_not_exists = false; bool if_not_exists = false;
bool or_replace = false; bool or_replace = false;
String name; std::shared_ptr<ASTUserNamesWithHost> names;
String new_name; String new_name;
std::optional<Authentication> authentication; std::optional<Authentication> authentication;
@ -44,7 +45,7 @@ public:
std::optional<AllowedClientHosts> add_hosts; std::optional<AllowedClientHosts> add_hosts;
std::optional<AllowedClientHosts> remove_hosts; std::optional<AllowedClientHosts> remove_hosts;
std::shared_ptr<ASTExtendedRoleSet> default_roles; std::shared_ptr<ASTRolesOrUsersSet> default_roles;
std::shared_ptr<ASTSettingsProfileElements> settings; std::shared_ptr<ASTSettingsProfileElements> settings;

View File

@ -1,10 +1,25 @@
#include <Parsers/ASTDropAccessEntityQuery.h> #include <Parsers/ASTDropAccessEntityQuery.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
namespace DB namespace DB
{ {
using EntityTypeInfo = IAccessEntity::TypeInfo; namespace
{
using EntityTypeInfo = IAccessEntity::TypeInfo;
void formatNames(const Strings & names, const IAST::FormatSettings & settings)
{
bool need_comma = false;
for (const auto & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ',';
settings.ostr << ' ' << backQuoteIfNeed(name);
}
}
}
String ASTDropAccessEntityQuery::getID(char) const String ASTDropAccessEntityQuery::getID(char) const
@ -28,32 +43,19 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
if (type == EntityType::ROW_POLICY) if (type == EntityType::ROW_POLICY)
{ {
bool need_comma = false; settings.ostr << " ";
for (const auto & name_parts : row_policies_name_parts) row_policy_names->format(settings);
{
if (need_comma)
settings.ostr << ',';
need_comma = true;
const String & database = name_parts.database;
const String & table_name = name_parts.table_name;
const String & short_name = name_parts.short_name;
settings.ostr << ' ' << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON "
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".")
<< backQuoteIfNeed(table_name);
}
} }
else else
{ formatNames(names, settings);
bool need_comma = false;
for (const auto & name : names)
{
if (need_comma)
settings.ostr << ',';
need_comma = true;
settings.ostr << ' ' << backQuoteIfNeed(name);
}
}
formatOnCluster(settings); formatOnCluster(settings);
} }
void ASTDropAccessEntityQuery::replaceEmptyDatabaseWithCurrent(const String & current_database) const
{
if (row_policy_names)
row_policy_names->replaceEmptyDatabaseWithCurrent(current_database);
}
} }

View File

@ -7,6 +7,7 @@
namespace DB namespace DB
{ {
class ASTRowPolicyNames;
/** DROP USER [IF EXISTS] name [,...] /** DROP USER [IF EXISTS] name [,...]
* DROP ROLE [IF EXISTS] name [,...] * DROP ROLE [IF EXISTS] name [,...]
@ -22,11 +23,13 @@ public:
EntityType type; EntityType type;
bool if_exists = false; bool if_exists = false;
Strings names; Strings names;
std::vector<RowPolicy::NameParts> row_policies_name_parts; std::shared_ptr<ASTRowPolicyNames> row_policy_names;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTDropAccessEntityQuery>(clone()); } ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTDropAccessEntityQuery>(clone()); }
void replaceEmptyDatabaseWithCurrent(const String & current_database) const;
}; };
} }

View File

@ -1,5 +1,5 @@
#include <Parsers/ASTGrantQuery.h> #include <Parsers/ASTGrantQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
@ -75,7 +75,7 @@ namespace
} }
void formatToRoles(const ASTExtendedRoleSet & to_roles, ASTGrantQuery::Kind kind, const IAST::FormatSettings & settings) void formatToRoles(const ASTRolesOrUsersSet & to_roles, ASTGrantQuery::Kind kind, const IAST::FormatSettings & settings)
{ {
using Kind = ASTGrantQuery::Kind; using Kind = ASTGrantQuery::Kind;
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ((kind == Kind::GRANT) ? " TO " : " FROM ") settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ((kind == Kind::GRANT) ? " TO " : " FROM ")

View File

@ -7,7 +7,7 @@
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTRolesOrUsersSet;
/** GRANT access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user_name | CURRENT_USER} [,...] [WITH GRANT OPTION] /** GRANT access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user_name | CURRENT_USER} [,...] [WITH GRANT OPTION]
@ -27,8 +27,8 @@ public:
Kind kind = Kind::GRANT; Kind kind = Kind::GRANT;
bool attach = false; bool attach = false;
AccessRightsElements access_rights_elements; AccessRightsElements access_rights_elements;
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
std::shared_ptr<ASTExtendedRoleSet> to_roles; std::shared_ptr<ASTRolesOrUsersSet> to_roles;
bool grant_option = false; bool grant_option = false;
bool admin_option = false; bool admin_option = false;

View File

@ -1,4 +1,4 @@
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
@ -20,7 +20,7 @@ namespace
} }
} }
void ASTExtendedRoleSet::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const void ASTRolesOrUsersSet::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{ {
if (empty()) if (empty())
{ {
@ -74,7 +74,7 @@ void ASTExtendedRoleSet::formatImpl(const FormatSettings & settings, FormatState
} }
void ASTExtendedRoleSet::replaceCurrentUserTagWithName(const String & current_user_name) void ASTRolesOrUsersSet::replaceCurrentUserTagWithName(const String & current_user_name)
{ {
if (current_user) if (current_user)
{ {

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/// Represents a set of users/roles like /// Represents a set of users/roles like
/// {user_name | role_name | CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] /// {user_name | role_name | CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
class ASTExtendedRoleSet : public IAST class ASTRolesOrUsersSet : public IAST
{ {
public: public:
Strings names; Strings names;
@ -16,15 +16,15 @@ public:
Strings except_names; Strings except_names;
bool except_current_user = false; bool except_current_user = false;
bool id_mode = false; /// true if `names` and `except_names` keep UUIDs, not names. bool id_mode = false; /// true if `names` and `except_names` keep UUIDs, not names.
bool can_contain_roles = true; /// true if this set can contain names of roles. bool allow_role_names = true; /// true if this set can contain names of roles.
bool can_contain_users = true; /// true if this set can contain names of users. bool allow_user_names = true; /// true if this set can contain names of users.
bool empty() const { return names.empty() && !current_user && !all; } bool empty() const { return names.empty() && !current_user && !all; }
void replaceCurrentUserTagWithName(const String & current_user_name); void replaceCurrentUserTagWithName(const String & current_user_name);
String getID(char) const override { return "ExtendedRoleSet"; } String getID(char) const override { return "RolesOrUsersSet"; }
ASTPtr clone() const override { return std::make_shared<ASTExtendedRoleSet>(*this); } ASTPtr clone() const override { return std::make_shared<ASTRolesOrUsersSet>(*this); }
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
}; };
} }

View File

@ -0,0 +1,134 @@
#include <Parsers/ASTRowPolicyName.h>
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
void ASTRowPolicyName::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{
const String & database = name_parts.database;
const String & table_name = name_parts.table_name;
const String & short_name = name_parts.short_name;
settings.ostr << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON "
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".")
<< backQuoteIfNeed(table_name);
formatOnCluster(settings);
}
void ASTRowPolicyName::replaceEmptyDatabaseWithCurrent(const String & current_database)
{
if (name_parts.database.empty())
name_parts.database = current_database;
}
void ASTRowPolicyNames::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{
if (name_parts.empty())
throw Exception("No names of row policies in AST", ErrorCodes::LOGICAL_ERROR);
bool same_short_name = true;
if (name_parts.size() > 1)
{
for (size_t i = 1; i != name_parts.size(); ++i)
if (name_parts[i].short_name != name_parts[0].short_name)
{
same_short_name = false;
break;
}
}
bool same_db_and_table_name = true;
if (name_parts.size() > 1)
{
for (size_t i = 1; i != name_parts.size(); ++i)
if ((name_parts[i].database != name_parts[0].database) || (name_parts[i].table_name != name_parts[0].table_name))
{
same_db_and_table_name = false;
break;
}
}
if (same_short_name)
{
const String & short_name = name_parts[0].short_name;
settings.ostr << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON "
<< (settings.hilite ? hilite_none : "");
bool need_comma = false;
for (const auto & np : name_parts)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
const String & database = np.database;
const String & table_name = np.table_name;
if (!database.empty())
settings.ostr << backQuoteIfNeed(database) + ".";
settings.ostr << backQuoteIfNeed(table_name);
}
}
else if (same_db_and_table_name)
{
bool need_comma = false;
for (const auto & np : name_parts)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
const String & short_name = np.short_name;
settings.ostr << backQuoteIfNeed(short_name);
}
const String & database = name_parts[0].database;
const String & table_name = name_parts[0].table_name;
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "");
if (!database.empty())
settings.ostr << backQuoteIfNeed(database) + ".";
settings.ostr << backQuoteIfNeed(table_name);
}
else
{
bool need_comma = false;
for (const auto & np : name_parts)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
const String & short_name = np.short_name;
const String & database = np.database;
const String & table_name = np.table_name;
settings.ostr << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON "
<< (settings.hilite ? hilite_none : "");
if (!database.empty())
settings.ostr << backQuoteIfNeed(database) + ".";
settings.ostr << backQuoteIfNeed(table_name);
}
}
formatOnCluster(settings);
}
Strings ASTRowPolicyNames::toStrings() const
{
Strings res;
res.reserve(name_parts.size());
for (const auto & np : name_parts)
res.emplace_back(np.toString());
return res;
}
void ASTRowPolicyNames::replaceEmptyDatabaseWithCurrent(const String & current_database)
{
for (auto & np : name_parts)
if (np.database.empty())
np.database = current_database;
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <Parsers/IAST.h>
#include <Parsers/ASTQueryWithOnCluster.h>
#include <Access/RowPolicy.h>
namespace DB
{
/** Represents a row policy's name in one of the following forms:
* short_name ON [db.]table_name [ON CLUSTER 'cluster_name']
* short_name [ON CLUSTER 'cluster_name'] ON [db.]table_name
*/
class ASTRowPolicyName : public IAST, public ASTQueryWithOnCluster
{
public:
RowPolicy::NameParts name_parts;
String toString() const { return name_parts.getName(); }
String getID(char) const override { return "RowPolicyName"; }
ASTPtr clone() const override { return std::make_shared<ASTRowPolicyName>(*this); }
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTRowPolicyName>(clone()); }
void replaceEmptyDatabaseWithCurrent(const String & current_database);
};
/** Represents multiple names of row policies, comma-separated, in one of the following forms:
* short_name1 ON [db1.]table_name1 [, short_name2 ON [db2.]table_name2 ...] [ON CLUSTER 'cluster_name']
* short_name1 [, short_name2 ...] ON [db.]table_name [ON CLUSTER 'cluster_name']
* short_name1 [, short_name2 ...] [ON CLUSTER 'cluster_name'] ON [db.]table_name
* short_name ON [db1.]table_name1 [, [db2.]table_name2 ...] [ON CLUSTER 'cluster_name']
* short_name [ON CLUSTER 'cluster_name'] ON [db1.]table_name1 [, [db2.]table_name2 ...]
*/
class ASTRowPolicyNames : public IAST, public ASTQueryWithOnCluster
{
public:
std::vector<RowPolicy::NameParts> name_parts;
Strings toStrings() const;
String getID(char) const override { return "RowPolicyNames"; }
ASTPtr clone() const override { return std::make_shared<ASTRowPolicyNames>(*this); }
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTRowPolicyNames>(clone()); }
void replaceEmptyDatabaseWithCurrent(const String & current_database);
};
}

View File

@ -1,5 +1,5 @@
#include <Parsers/ASTSetRoleQuery.h> #include <Parsers/ASTSetRoleQuery.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>

View File

@ -5,7 +5,7 @@
namespace DB namespace DB
{ {
class ASTExtendedRoleSet; class ASTRolesOrUsersSet;
/** SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]} /** SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
* SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...] * SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]
@ -21,8 +21,8 @@ public:
}; };
Kind kind = Kind::SET_ROLE; Kind kind = Kind::SET_ROLE;
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
std::shared_ptr<ASTExtendedRoleSet> to_users; std::shared_ptr<ASTRolesOrUsersSet> to_users;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;

View File

@ -4,49 +4,51 @@
namespace DB namespace DB
{ {
namespace ErrorCodes using EntityTypeInfo = IAccessEntity::TypeInfo;
{
extern const int NOT_IMPLEMENTED;
}
const char * ASTShowAccessEntitiesQuery::getKeyword() const String ASTShowAccessEntitiesQuery::getKeyword() const
{ {
switch (type) if (current_quota)
{ return "CURRENT QUOTA";
case EntityType::ROW_POLICY: if (current_roles)
return "SHOW ROW POLICIES"; return "CURRENT ROLES";
case EntityType::QUOTA: if (enabled_roles)
return current_quota ? "SHOW CURRENT QUOTA" : "SHOW QUOTAS"; return "ENABLED ROLES";
case EntityType::SETTINGS_PROFILE: return EntityTypeInfo::get(type).plural_name;
return "SHOW SETTINGS PROFILES";
case EntityType::USER:
return "SHOW USERS";
case EntityType::ROLE:
return current_roles ? "SHOW CURRENT ROLES" : (enabled_roles ? "SHOW ENABLED ROLES" : "SHOW ROLES");
case EntityType::MAX:
break;
}
throw Exception(toString(type) + ": type is not supported by SHOW query", ErrorCodes::NOT_IMPLEMENTED);
} }
String ASTShowAccessEntitiesQuery::getID(char) const String ASTShowAccessEntitiesQuery::getID(char) const
{ {
return String(getKeyword()) + " query"; return "SHOW " + String(getKeyword()) + " query";
} }
void ASTShowAccessEntitiesQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const void ASTShowAccessEntitiesQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{ {
const char * keyword = getKeyword(); settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW " << getKeyword() << (settings.hilite ? hilite_none : "");
settings.ostr << (settings.hilite ? hilite_keyword : "") << keyword << (settings.hilite ? hilite_none : "");
if ((type == EntityType::ROW_POLICY) && !table_name.empty()) if (!short_name.empty())
settings.ostr << " " << backQuoteIfNeed(short_name);
if (database_and_table_name)
{ {
const String & database = database_and_table_name->first;
const String & table_name = database_and_table_name->second;
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : ""); settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "");
if (!database.empty()) settings.ostr << (database.empty() ? "" : backQuoteIfNeed(database) + ".");
settings.ostr << backQuoteIfNeed(database) << "."; settings.ostr << (table_name.empty() ? "*" : backQuoteIfNeed(table_name));
settings.ostr << backQuoteIfNeed(table_name); }
}
void ASTShowAccessEntitiesQuery::replaceEmptyDatabaseWithCurrent(const String & current_database)
{
if (database_and_table_name)
{
String & database = database_and_table_name->first;
if (database.empty())
database = current_database;
} }
} }

View File

@ -7,32 +7,37 @@
namespace DB namespace DB
{ {
/// SHOW [ROW] POLICIES [ON [database.]table]
/// SHOW QUOTAS
/// SHOW [CURRENT] QUOTA
/// SHOW [SETTINGS] PROFILES
/// SHOW USERS /// SHOW USERS
/// SHOW [CURRENT|ENABLED] ROLES /// SHOW [CURRENT|ENABLED] ROLES
/// SHOW [SETTINGS] PROFILES
/// SHOW [ROW] POLICIES [name | ON [database.]table]
/// SHOW QUOTAS
/// SHOW [CURRENT] QUOTA
class ASTShowAccessEntitiesQuery : public ASTQueryWithOutput class ASTShowAccessEntitiesQuery : public ASTQueryWithOutput
{ {
public: public:
using EntityType = IAccessEntity::Type; using EntityType = IAccessEntity::Type;
EntityType type; EntityType type;
String database;
String table_name; bool all = false;
bool current_quota = false; bool current_quota = false;
bool current_roles = false; bool current_roles = false;
bool enabled_roles = false; bool enabled_roles = false;
String short_name;
std::optional<std::pair<String, String>> database_and_table_name;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override { return std::make_shared<ASTShowAccessEntitiesQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTShowAccessEntitiesQuery>(*this); }
void replaceEmptyDatabaseWithCurrent(const String & current_database);
protected: protected:
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
private: private:
const char * getKeyword() const; String getKeyword() const;
}; };
} }

View File

@ -0,0 +1,17 @@
#pragma once
#include <Parsers/ASTQueryWithOutput.h>
namespace DB
{
struct ASTShowAccessQueryNames
{
static constexpr auto ID = "ShowAccessQuery";
static constexpr auto Query = "SHOW ACCESS";
};
using ASTShowAccessQuery = ASTQueryWithOutputImpl<ASTShowAccessQueryNames>;
}

View File

@ -1,15 +1,40 @@
#include <Parsers/ASTShowCreateAccessEntityQuery.h> #include <Parsers/ASTShowCreateAccessEntityQuery.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
namespace DB namespace DB
{ {
using EntityTypeInfo = IAccessEntity::TypeInfo; namespace
{
using EntityType = IAccessEntity::Type;
using EntityTypeInfo = IAccessEntity::TypeInfo;
void formatNames(const Strings & names, const IAST::FormatSettings & settings)
{
bool need_comma = false;
for (const auto & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ',';
settings.ostr << ' ' << backQuoteIfNeed(name);
}
}
}
String ASTShowCreateAccessEntityQuery::getKeyword() const
{
size_t total_count = (names.size()) + (row_policy_names ? row_policy_names->size() : 0) + current_user + current_quota;
bool multiple = (total_count != 1) || all || !short_name.empty() || database_and_table_name;
const auto & type_info = EntityTypeInfo::get(type);
return multiple ? type_info.plural_name : type_info.name;
}
String ASTShowCreateAccessEntityQuery::getID(char) const String ASTShowCreateAccessEntityQuery::getID(char) const
{ {
return String("SHOW CREATE ") + toString(type) + " query"; return String("SHOW CREATE ") + getKeyword() + " query";
} }
@ -21,23 +46,42 @@ ASTPtr ASTShowCreateAccessEntityQuery::clone() const
void ASTShowCreateAccessEntityQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const void ASTShowCreateAccessEntityQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{ {
settings.ostr << (settings.hilite ? hilite_keyword : "") settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW CREATE " << getKeyword() << (settings.hilite ? hilite_none : "");
<< "SHOW CREATE " << EntityTypeInfo::get(type).name
<< (settings.hilite ? hilite_none : "");
if (current_user || current_quota) if (!names.empty())
formatNames(names, settings);
if (row_policy_names)
{ {
settings.ostr << " ";
row_policy_names->format(settings);
} }
else if (type == EntityType::ROW_POLICY)
if (!short_name.empty())
settings.ostr << " " << backQuoteIfNeed(short_name);
if (database_and_table_name)
{ {
const String & database = row_policy_name_parts.database; const String & database = database_and_table_name->first;
const String & table_name = row_policy_name_parts.table_name; const String & table_name = database_and_table_name->second;
const String & short_name = row_policy_name_parts.short_name; settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "");
settings.ostr << ' ' << backQuoteIfNeed(short_name) << (settings.hilite ? hilite_keyword : "") << " ON " settings.ostr << (database.empty() ? "" : backQuoteIfNeed(database) + ".");
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") settings.ostr << (table_name.empty() ? "*" : backQuoteIfNeed(table_name));
<< backQuoteIfNeed(table_name);
} }
else
settings.ostr << " " << backQuoteIfNeed(name);
} }
void ASTShowCreateAccessEntityQuery::replaceEmptyDatabaseWithCurrent(const String & current_database)
{
if (row_policy_names)
row_policy_names->replaceEmptyDatabaseWithCurrent(current_database);
if (database_and_table_name)
{
String & database = database_and_table_name->first;
if (database.empty())
database = current_database;
}
}
} }

View File

@ -1,16 +1,23 @@
#pragma once #pragma once
#include <Parsers/ASTQueryWithOutput.h> #include <Parsers/ASTQueryWithOutput.h>
#include <Access/RowPolicy.h> #include <Access/IAccessEntity.h>
namespace DB namespace DB
{ {
/** SHOW CREATE QUOTA [name | CURRENT] class ASTRowPolicyNames;
* SHOW CREATE [ROW] POLICY name ON [database.]table
* SHOW CREATE USER [name | CURRENT_USER] /** SHOW CREATE USER [name | CURRENT_USER]
* SHOW CREATE USERS [name [, name2 ...]
* SHOW CREATE ROLE name * SHOW CREATE ROLE name
* SHOW CREATE ROLES [name [, name2 ...]]
* SHOW CREATE [SETTINGS] PROFILE name * SHOW CREATE [SETTINGS] PROFILE name
* SHOW CREATE [SETTINGS] PROFILES [name [, name2 ...]]
* SHOW CREATE [ROW] POLICY name ON [database.]table
* SHOW CREATE [ROW] POLICIES [name ON [database.]table [, name2 ON database2.table2 ...] | name | ON database.table]
* SHOW CREATE QUOTA [name]
* SHOW CREATE QUOTAS [name [, name2 ...]]
*/ */
class ASTShowCreateAccessEntityQuery : public ASTQueryWithOutput class ASTShowCreateAccessEntityQuery : public ASTQueryWithOutput
{ {
@ -18,15 +25,23 @@ public:
using EntityType = IAccessEntity::Type; using EntityType = IAccessEntity::Type;
EntityType type; EntityType type;
String name; Strings names;
std::shared_ptr<ASTRowPolicyNames> row_policy_names;
bool current_quota = false; bool current_quota = false;
bool current_user = false; bool current_user = false;
RowPolicy::NameParts row_policy_name_parts; bool all = false;
String short_name;
std::optional<std::pair<String, String>> database_and_table_name;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;
void replaceEmptyDatabaseWithCurrent(const String & current_database);
protected: protected:
String getKeyword() const;
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
}; };

View File

@ -1,4 +1,5 @@
#include <Parsers/ASTShowGrantsQuery.h> #include <Parsers/ASTShowGrantsQuery.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Common/quoteString.h> #include <Common/quoteString.h>
@ -21,8 +22,15 @@ void ASTShowGrantsQuery::formatQueryImpl(const FormatSettings & settings, Format
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW GRANTS" settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW GRANTS"
<< (settings.hilite ? hilite_none : ""); << (settings.hilite ? hilite_none : "");
if (!current_user) if (for_roles->current_user && !for_roles->all && for_roles->names.empty() && for_roles->except_names.empty()
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FOR " << (settings.hilite ? hilite_none : "") && !for_roles->except_current_user)
<< backQuoteIfNeed(name); {
}
else
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FOR "
<< (settings.hilite ? hilite_none : "");
for_roles->format(settings);
}
} }
} }

View File

@ -5,13 +5,14 @@
namespace DB namespace DB
{ {
class ASTRolesOrUsersSet;
/** SHOW GRANTS [FOR user_name] /** SHOW GRANTS [FOR user_name]
*/ */
class ASTShowGrantsQuery : public ASTQueryWithOutput class ASTShowGrantsQuery : public ASTQueryWithOutput
{ {
public: public:
String name; std::shared_ptr<ASTRolesOrUsersSet> for_roles;
bool current_user = false;
String getID(char) const override; String getID(char) const override;
ASTPtr clone() const override; ASTPtr clone() const override;

View File

@ -0,0 +1,74 @@
#include <Parsers/ASTUserNameWithHost.h>
#include <Common/quoteString.h>
namespace DB
{
void ASTUserNameWithHost::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{
settings.ostr << backQuoteIfNeed(base_name);
if (!host_pattern.empty())
settings.ostr << "@" << backQuoteIfNeed(host_pattern);
}
String ASTUserNameWithHost::toString() const
{
String res = base_name;
if (!host_pattern.empty())
res += '@' + host_pattern;
return res;
}
void ASTUserNameWithHost::concatParts()
{
base_name = toString();
host_pattern.clear();
}
void ASTUserNamesWithHost::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
{
assert(!names.empty());
bool need_comma = false;
for (const auto & name : names)
{
if (std::exchange(need_comma, true))
settings.ostr << ", ";
name->format(settings);
}
}
Strings ASTUserNamesWithHost::toStrings() const
{
Strings res;
res.reserve(names.size());
for (const auto & name : names)
res.emplace_back(name->toString());
return res;
}
void ASTUserNamesWithHost::concatParts()
{
for (auto & name : names)
name->concatParts();
}
bool ASTUserNamesWithHost::getHostPatternIfCommon(String & out_common_host_pattern) const
{
out_common_host_pattern.clear();
if (names.empty())
return true;
for (size_t i = 1; i != names.size(); ++i)
if (names[i]->host_pattern != names[0]->host_pattern)
return false;
out_common_host_pattern = names[0]->host_pattern;
return true;
}
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <Parsers/IParser.h>
namespace DB
{
/** Represents a user name.
* It can be a simple string or identifier or something like `name@host`.
* In the last case `host` specifies the hosts user is allowed to connect from.
* The `host` can be an ip address, ip subnet, or a host name.
* The % and _ wildcard characters are permitted in `host`.
* These have the same meaning as for pattern-matching operations performed with the LIKE operator.
*/
class ASTUserNameWithHost : public IAST
{
public:
String base_name;
String host_pattern;
String toString() const;
void concatParts();
ASTUserNameWithHost() = default;
ASTUserNameWithHost(const String & name_) : base_name(name_) {}
String getID(char) const override { return "UserNameWithHost"; }
ASTPtr clone() const override { return std::make_shared<ASTUserNameWithHost>(*this); }
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
};
class ASTUserNamesWithHost : public IAST
{
public:
std::vector<std::shared_ptr<ASTUserNameWithHost>> names;
size_t size() const { return names.size(); }
auto begin() const { return names.begin(); }
auto end() const { return names.end(); }
auto front() const { return *begin(); }
void push_back(const String & name_) { names.push_back(std::make_shared<ASTUserNameWithHost>(name_)); }
Strings toStrings() const;
void concatParts();
bool getHostPatternIfCommon(String & out_common_host_pattern) const;
String getID(char) const override { return "UserNamesWithHost"; }
ASTPtr clone() const override { return std::make_shared<ASTUserNamesWithHost>(*this); }
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
};
}

View File

@ -76,41 +76,25 @@ const char * ParserTupleElementExpression::operators[] =
bool ParserList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) bool ParserList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{ {
bool first = true; ASTs elements;
auto parse_element = [&]
{
ASTPtr element;
if (!elem_parser->parse(pos, element, expected))
return false;
elements.push_back(element);
return true;
};
if (!parseUtil(pos, expected, parse_element, *separator_parser, allow_empty))
return false;
auto list = std::make_shared<ASTExpressionList>(result_separator); auto list = std::make_shared<ASTExpressionList>(result_separator);
list->children = std::move(elements);
node = list; node = list;
return true;
while (true)
{
if (first)
{
ASTPtr elem;
if (!elem_parser->parse(pos, elem, expected))
break;
list->children.push_back(elem);
first = false;
}
else
{
auto prev_pos = pos;
if (!separator_parser->ignore(pos, expected))
break;
ASTPtr elem;
if (!elem_parser->parse(pos, elem, expected))
{
pos = prev_pos;
break;
}
list->children.push_back(elem);
}
}
return allow_empty || !first;
} }

View File

@ -26,6 +26,43 @@ public:
, result_separator(result_separator_) , result_separator(result_separator_)
{ {
} }
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, IParser & separator_parser_, bool allow_empty_ = true)
{
Pos begin = pos;
if (!parse_element())
{
pos = begin;
return allow_empty_;
}
while (true)
{
begin = pos;
if (!separator_parser_.ignore(pos, expected) || !parse_element())
{
pos = begin;
return true;
}
}
return false;
}
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, TokenType separator, bool allow_empty_ = true)
{
ParserToken sep_parser{separator};
return parseUtil(pos, expected, parse_element, sep_parser, allow_empty_);
}
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, bool allow_empty_ = true)
{
return parseUtil(pos, expected, parse_element, TokenType::Comma, allow_empty_);
}
protected: protected:
const char * getName() const override { return "list of elements"; } const char * getName() const override { return "list of elements"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;

View File

@ -3,10 +3,12 @@
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/parseIntervalKind.h> #include <Parsers/parseIntervalKind.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ExpressionListParsers.h>
#include <ext/range.h> #include <ext/range.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@ -39,95 +41,143 @@ namespace
}); });
} }
bool parseKeyType(IParserBase::Pos & pos, Expected & expected, std::optional<Quota::KeyType> & key_type) bool parseKeyType(IParserBase::Pos & pos, Expected & expected, KeyType & key_type)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
if (!ParserKeyword{"KEYED BY"}.ignore(pos, expected)) if (ParserKeyword{"NOT KEYED"}.ignore(pos, expected))
{
key_type = KeyType::NONE;
return true;
}
if (!ParserKeyword{"KEY BY"}.ignore(pos, expected) && !ParserKeyword{"KEYED BY"}.ignore(pos, expected))
return false; return false;
ASTPtr key_type_ast; Strings names;
if (!ParserStringLiteral().parse(pos, key_type_ast, expected)) if (!parseIdentifiersOrStringLiterals(pos, expected, names))
return false; return false;
const String & key_type_str = key_type_ast->as<ASTLiteral &>().value.safeGet<const String &>(); String name = boost::algorithm::join(names, "_or_");
boost::to_lower(name);
boost::replace_all(name, " ", "_");
for (auto kt : ext::range(Quota::KeyType::MAX)) for (auto kt : ext::range(Quota::KeyType::MAX))
if (boost::iequals(KeyTypeInfo::get(kt).name, key_type_str)) if (KeyTypeInfo::get(kt).name == name)
{ {
key_type = kt; key_type = kt;
return true; return true;
} }
String all_key_types_str; String all_types_str;
for (auto kt : ext::range(Quota::KeyType::MAX)) for (auto kt : ext::range(Quota::KeyType::MAX))
all_key_types_str += String(all_key_types_str.empty() ? "" : ", ") + "'" + KeyTypeInfo::get(kt).name + "'"; all_types_str += String(all_types_str.empty() ? "" : ", ") + "'" + KeyTypeInfo::get(kt).name + "'";
String msg = "Quota cannot be keyed by '" + key_type_str + "'. Expected one of these literals: " + all_key_types_str; String msg = "Quota cannot be keyed by '" + name + "'. Expected one of the following identifiers: " + all_types_str;
throw Exception(msg, ErrorCodes::SYNTAX_ERROR); throw Exception(msg, ErrorCodes::SYNTAX_ERROR);
}); });
} }
bool parseLimit(IParserBase::Pos & pos, Expected & expected, bool first, ResourceType & resource_type, ResourceAmount & max)
bool parseResourceType(IParserBase::Pos & pos, Expected & expected, ResourceType & resource_type)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
if (first)
{
if (!ParserKeyword{"MAX"}.ignore(pos, expected))
return false;
}
else
{
if (!ParserToken{TokenType::Comma}.ignore(pos, expected))
return false;
ParserKeyword{"MAX"}.ignore(pos, expected);
}
std::optional<ResourceType> res_resource_type;
for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE)) for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE))
{ {
if (ParserKeyword{ResourceTypeInfo::get(rt).keyword.c_str()}.ignore(pos, expected)) if (ParserKeyword{ResourceTypeInfo::get(rt).keyword.c_str()}.ignore(pos, expected))
{ {
res_resource_type = rt; resource_type = rt;
break; return true;
} }
} }
if (!res_resource_type)
ASTPtr ast;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false; return false;
ResourceAmount res_max; String name = getIdentifierName(ast);
ASTPtr max_ast; for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE))
if (ParserNumber{}.parse(pos, max_ast, expected))
{ {
const Field & max_field = max_ast->as<ASTLiteral &>().value; if (ResourceTypeInfo::get(rt).name == name)
const auto & type_info = ResourceTypeInfo::get(*res_resource_type); {
if (type_info.output_denominator == 1) resource_type = rt;
res_max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field); return true;
else }
res_max = static_cast<ResourceAmount>(
applyVisitor(FieldVisitorConvertToNumber<double>(), max_field) * type_info.output_denominator);
} }
else
return false;
resource_type = *res_resource_type; return false;
max = res_max;
return true;
}); });
} }
bool parseLimits(IParserBase::Pos & pos, Expected & expected, ASTCreateQuotaQuery::Limits & limits)
bool parseMaxAmount(IParserBase::Pos & pos, Expected & expected, ResourceType resource_type, ResourceAmount & max)
{ {
return IParserBase::wrapParseImpl(pos, [&] ASTPtr ast;
if (!ParserNumber{}.parse(pos, ast, expected))
return false;
const Field & max_field = ast->as<ASTLiteral &>().value;
const auto & type_info = ResourceTypeInfo::get(resource_type);
if (type_info.output_denominator == 1)
max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field);
else
max = static_cast<ResourceAmount>(
applyVisitor(FieldVisitorConvertToNumber<double>(), max_field) * type_info.output_denominator);
return true;
}
bool parseLimits(IParserBase::Pos & pos, Expected & expected, std::vector<std::pair<ResourceType, ResourceAmount>> & limits)
{
std::vector<std::pair<ResourceType, ResourceAmount>> res_limits;
bool max_prefix_encountered = false;
auto parse_limit = [&]
{
max_prefix_encountered |= ParserKeyword{"MAX"}.ignore(pos, expected);
ResourceType resource_type;
if (!parseResourceType(pos, expected, resource_type))
return false;
if (max_prefix_encountered)
{
ParserToken{TokenType::Equals}.ignore(pos, expected);
}
else
{
if (!ParserKeyword{"MAX"}.ignore(pos, expected))
return false;
}
ResourceAmount max;
if (!parseMaxAmount(pos, expected, resource_type, max))
return false;
res_limits.emplace_back(resource_type, max);
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_limit, false))
return false;
limits = std::move(res_limits);
return true;
}
bool parseIntervalsWithLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits)
{
std::vector<ASTCreateQuotaQuery::Limits> res_all_limits;
auto parse_interval_with_limits = [&]
{ {
ASTCreateQuotaQuery::Limits new_limits;
if (!ParserKeyword{"FOR"}.ignore(pos, expected)) if (!ParserKeyword{"FOR"}.ignore(pos, expected))
return false; return false;
new_limits.randomize_interval = ParserKeyword{"RANDOMIZED"}.ignore(pos, expected); ASTCreateQuotaQuery::Limits limits;
limits.randomize_interval = ParserKeyword{"RANDOMIZED"}.ignore(pos, expected);
if (!ParserKeyword{"INTERVAL"}.ignore(pos, expected)) ParserKeyword{"INTERVAL"}.ignore(pos, expected);
return false;
ASTPtr num_intervals_ast; ASTPtr num_intervals_ast;
if (!ParserNumber{}.parse(pos, num_intervals_ast, expected)) if (!ParserNumber{}.parse(pos, num_intervals_ast, expected))
@ -139,61 +189,46 @@ namespace
if (!parseIntervalKind(pos, expected, interval_kind)) if (!parseIntervalKind(pos, expected, interval_kind))
return false; return false;
new_limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds())); limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds()));
std::vector<std::pair<ResourceType, ResourceAmount>> maxs;
if (ParserKeyword{"NO LIMITS"}.ignore(pos, expected)) if (ParserKeyword{"NO LIMITS"}.ignore(pos, expected))
{ {
new_limits.drop = true; limits.drop = true;
} }
else if (ParserKeyword{"TRACKING ONLY"}.ignore(pos, expected)) else if (ParserKeyword{"TRACKING ONLY"}.ignore(pos, expected))
{ {
} }
else if (parseLimits(pos, expected, maxs))
{
for (const auto & [resource_type, max] : maxs)
limits.max[resource_type] = max;
}
else else
{ return false;
ResourceType resource_type;
ResourceAmount max;
if (!parseLimit(pos, expected, true, resource_type, max))
return false;
new_limits.max[resource_type] = max; res_all_limits.emplace_back(std::move(limits));
while (parseLimit(pos, expected, false, resource_type, max))
new_limits.max[resource_type] = max;
}
limits = new_limits;
return true; return true;
}); };
if (!ParserList::parseUtil(pos, expected, parse_interval_with_limits, false))
return false;
all_limits = std::move(res_all_limits);
return true;
} }
bool parseAllLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits) bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
{
return IParserBase::wrapParseImpl(pos, [&]
{
size_t old_size = all_limits.size();
do
{
ASTCreateQuotaQuery::Limits limits;
if (!parseLimits(pos, expected, limits))
{
all_limits.resize(old_size);
return false;
}
all_limits.push_back(limits);
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
return true;
});
}
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTExtendedRoleSet> & roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr node; ASTPtr node;
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected) || !ParserExtendedRoleSet{}.useIDMode(id_mode).parse(pos, node, expected)) ParserRolesOrUsersSet roles_p;
roles_p.allowAll().allowRoleNames().allowUserNames().allowCurrentUser().useIDMode(id_mode);
if (!ParserKeyword{"TO"}.ignore(pos, expected) || !roles_p.parse(pos, node, expected))
return false; return false;
roles = std::static_pointer_cast<ASTExtendedRoleSet>(node); roles = std::static_pointer_cast<ASTRolesOrUsersSet>(node);
return true; return true;
}); });
} }
@ -240,8 +275,8 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
or_replace = true; or_replace = true;
} }
String name; Strings names;
if (!parseIdentifierOrStringLiteral(pos, expected, name)) if (!parseIdentifiersOrStringLiterals(pos, expected, names))
return false; return false;
String new_name; String new_name;
@ -251,13 +286,20 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
while (true) while (true)
{ {
if (alter && new_name.empty() && parseRenameTo(pos, expected, new_name)) if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
continue; continue;
if (!key_type && parseKeyType(pos, expected, key_type)) if (!key_type)
continue; {
KeyType new_key_type;
if (parseKeyType(pos, expected, new_key_type))
{
key_type = new_key_type;
continue;
}
}
if (parseAllLimits(pos, expected, all_limits)) if (parseIntervalsWithLimits(pos, expected, all_limits))
continue; continue;
if (cluster.empty() && parseOnCluster(pos, expected, cluster)) if (cluster.empty() && parseOnCluster(pos, expected, cluster))
@ -266,7 +308,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
break; break;
} }
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
parseToRoles(pos, expected, attach_mode, roles); parseToRoles(pos, expected, attach_mode, roles);
if (cluster.empty()) if (cluster.empty())
@ -280,7 +322,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
query->if_not_exists = if_not_exists; query->if_not_exists = if_not_exists;
query->or_replace = or_replace; query->or_replace = or_replace;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->name = std::move(name); query->names = std::move(names);
query->new_name = std::move(new_name); query->new_name = std::move(new_name);
query->key_type = key_type; query->key_type = key_type;
query->all_limits = std::move(all_limits); query->all_limits = std::move(all_limits);

View File

@ -7,24 +7,24 @@ namespace DB
{ {
/** Parses queries like /** Parses queries like
* CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name * CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {none | user_name | ip_address | client_key | client_key, user_name | client_key, ip_address} | NOT KEYED]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {second | minute | hour | day}
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] | * {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
* NO LIMITS | TRACKING ONLY} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
* *
* ALTER QUOTA [IF EXISTS] name * ALTER QUOTA [IF EXISTS] name
* [RENAME TO new_name] * [RENAME TO new_name]
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}] * [KEYED BY {none | user_name | ip_address | client_key | client_key, user_name | client_key, ip_address} | NOT KEYED]
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY} * [FOR [RANDOMIZED] INTERVAL number {second | minute | hour | day}
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} } [,...] | * {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
* NO LIMITS | TRACKING ONLY} [,...]] * NO LIMITS | TRACKING ONLY} [,...]]
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
*/ */
class ParserCreateQuotaQuery : public IParserBase class ParserCreateQuotaQuery : public IParserBase
{ {
public: public:
ParserCreateQuotaQuery & enableAttachMode(bool enable_) { attach_mode = enable_; return *this; } void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
protected: protected:
const char * getName() const override { return "CREATE QUOTA or ALTER QUOTA query"; } const char * getName() const override { return "CREATE QUOTA or ALTER QUOTA query"; }

View File

@ -6,6 +6,7 @@
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ParserSettingsProfileElement.h> #include <Parsers/ParserSettingsProfileElement.h>
#include <Parsers/parseUserName.h> #include <Parsers/parseUserName.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB namespace DB
@ -23,7 +24,7 @@ namespace
}); });
} }
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings) bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -31,13 +32,12 @@ namespace
return false; return false;
ASTPtr new_settings_ast; ASTPtr new_settings_ast;
if (!ParserSettingsProfileElements{}.useIDMode(id_mode).parse(pos, new_settings_ast, expected)) ParserSettingsProfileElements elements_p;
elements_p.useIDMode(id_mode);
if (!elements_p.parse(pos, new_settings_ast, expected))
return false; return false;
if (!settings) settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
return true; return true;
}); });
} }
@ -84,8 +84,8 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
or_replace = true; or_replace = true;
} }
String name; Strings names;
if (!parseRoleName(pos, expected, name)) if (!parseRoleNames(pos, expected, names))
return false; return false;
String new_name; String new_name;
@ -94,11 +94,17 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
while (true) while (true)
{ {
if (alter && parseRenameTo(pos, expected, new_name)) if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
continue; continue;
if (parseSettings(pos, expected, attach_mode, settings)) std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue; continue;
}
if (cluster.empty() && parseOnCluster(pos, expected, cluster)) if (cluster.empty() && parseOnCluster(pos, expected, cluster))
continue; continue;
@ -115,7 +121,7 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
query->if_not_exists = if_not_exists; query->if_not_exists = if_not_exists;
query->or_replace = or_replace; query->or_replace = or_replace;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->name = std::move(name); query->names = std::move(names);
query->new_name = std::move(new_name); query->new_name = std::move(new_name);
query->settings = std::move(settings); query->settings = std::move(settings);

View File

@ -16,7 +16,7 @@ namespace DB
class ParserCreateRoleQuery : public IParserBase class ParserCreateRoleQuery : public IParserBase
{ {
public: public:
ParserCreateRoleQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; } void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
protected: protected:
const char * getName() const override { return "CREATE ROLE or ALTER ROLE query"; } const char * getName() const override { return "CREATE ROLE or ALTER ROLE query"; }

View File

@ -1,14 +1,17 @@
#include <Parsers/ParserCreateRowPolicyQuery.h> #include <Parsers/ParserCreateRowPolicyQuery.h>
#include <Parsers/ASTCreateRowPolicyQuery.h> #include <Parsers/ASTCreateRowPolicyQuery.h>
#include <Access/RowPolicy.h> #include <Access/RowPolicy.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ASTRowPolicyName.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ParserRowPolicyName.h>
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/parseDatabaseAndTableName.h> #include <Parsers/parseDatabaseAndTableName.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <ext/range.h> #include <ext/range.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB namespace DB
@ -31,7 +34,7 @@ namespace
}); });
} }
bool parseAsRestrictiveOrPermissive(IParserBase::Pos & pos, Expected & expected, std::optional<bool> & is_restrictive) bool parseAsRestrictiveOrPermissive(IParserBase::Pos & pos, Expected & expected, bool & is_restrictive)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -52,7 +55,7 @@ namespace
}); });
} }
bool parseConditionalExpression(IParserBase::Pos & pos, Expected & expected, std::optional<ASTPtr> & expr) bool parseConditionalExpression(IParserBase::Pos & pos, Expected & expected, ASTPtr & expr)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -72,68 +75,84 @@ namespace
}); });
} }
bool parseConditions(
IParserBase::Pos & pos, Expected & expected, bool alter, std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> & conditions) void addAllCommands(boost::container::flat_set<std::string_view> & commands)
{ {
return IParserBase::wrapParseImpl(pos, [&] for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
{
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
commands.emplace(command);
}
}
bool parseCommands(IParserBase::Pos & pos, Expected & expected,
boost::container::flat_set<std::string_view> & commands)
{
boost::container::flat_set<std::string_view> res_commands;
auto parse_command = [&]
{
if (ParserKeyword{"ALL"}.ignore(pos, expected))
{
addAllCommands(res_commands);
return true;
}
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
{
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
if (ParserKeyword{command.data()}.ignore(pos, expected))
{
res_commands.emplace(command);
return true;
}
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_command, false))
return false;
commands = std::move(res_commands);
return true;
}
bool
parseForClauses(IParserBase::Pos & pos, Expected & expected, bool alter, std::vector<std::pair<ConditionType, ASTPtr>> & conditions)
{
std::vector<std::pair<ConditionType, ASTPtr>> res_conditions;
auto parse_for_clause = [&]
{ {
boost::container::flat_set<std::string_view> commands; boost::container::flat_set<std::string_view> commands;
auto add_all_commands = [&]
{
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
{
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
commands.emplace(command);
}
};
if (ParserKeyword{"FOR"}.ignore(pos, expected)) if (ParserKeyword{"FOR"}.ignore(pos, expected))
{ {
do if (!parseCommands(pos, expected, commands))
{ return false;
size_t old_size = commands.size();
if (ParserKeyword{"ALL"}.ignore(pos, expected))
{
add_all_commands();
}
else
{
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
{
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
if (ParserKeyword{command.data()}.ignore(pos, expected))
{
commands.emplace(command);
break;
}
}
}
if (commands.size() == old_size)
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
} }
else
addAllCommands(commands);
std::optional<ASTPtr> filter; std::optional<ASTPtr> filter;
std::optional<ASTPtr> check; std::optional<ASTPtr> check;
if (ParserKeyword{"USING"}.ignore(pos, expected)) if (ParserKeyword{"USING"}.ignore(pos, expected))
{ {
if (!parseConditionalExpression(pos, expected, filter)) if (!parseConditionalExpression(pos, expected, filter.emplace()))
return false; return false;
} }
if (ParserKeyword{"WITH CHECK"}.ignore(pos, expected)) if (ParserKeyword{"WITH CHECK"}.ignore(pos, expected))
{ {
if (!parseConditionalExpression(pos, expected, check)) if (!parseConditionalExpression(pos, expected, check.emplace()))
return false; return false;
} }
if (!filter && !check) if (!filter && !check)
return false; return false;
if (commands.empty())
add_all_commands();
if (!check && !alter) if (!check && !alter)
check = filter; check = filter;
@ -143,44 +162,36 @@ namespace
if (commands.count(type_info.command)) if (commands.count(type_info.command))
{ {
if (type_info.is_check && check) if (type_info.is_check && check)
conditions[condition_type] = check; res_conditions.emplace_back(condition_type, *check);
else if (filter) else if (filter)
conditions[condition_type] = filter; res_conditions.emplace_back(condition_type, *filter);
} }
} }
return true; return true;
}); };
if (!ParserList::parseUtil(pos, expected, parse_for_clause, false))
return false;
conditions = std::move(res_conditions);
return true;
} }
bool parseMultipleConditions( bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
IParserBase::Pos & pos, Expected & expected, bool alter, std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> & conditions)
{
return IParserBase::wrapParseImpl(pos, [&]
{
std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> res_conditions;
do
{
if (!parseConditions(pos, expected, alter, res_conditions))
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
conditions = std::move(res_conditions);
return true;
});
}
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTExtendedRoleSet> & roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr ast; ASTPtr ast;
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected) if (!ParserKeyword{"TO"}.ignore(pos, expected))
|| !ParserExtendedRoleSet{}.useIDMode(id_mode).parse(pos, ast, expected))
return false; return false;
roles = std::static_pointer_cast<ASTExtendedRoleSet>(ast); ParserRolesOrUsersSet roles_p;
roles_p.allowAll().allowRoleNames().allowUserNames().allowCurrentUser().useIDMode(id_mode);
if (!roles_p.parse(pos, ast, expected))
return false;
roles = std::static_pointer_cast<ASTRolesOrUsersSet>(ast);
return true; return true;
}); });
} }
@ -227,29 +238,40 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
or_replace = true; or_replace = true;
} }
RowPolicy::NameParts name_parts; ParserRowPolicyNames names_parser;
String & database = name_parts.database; names_parser.allowOnCluster();
String & table_name = name_parts.table_name; ASTPtr names_ast;
String & short_name = name_parts.short_name; if (!names_parser.parse(pos, names_ast, expected))
if (!parseIdentifierOrStringLiteral(pos, expected, short_name) || !ParserKeyword{"ON"}.ignore(pos, expected)
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
return false; return false;
auto names = typeid_cast<std::shared_ptr<ASTRowPolicyNames>>(names_ast);
String cluster = std::exchange(names->cluster, "");
String new_short_name; String new_short_name;
std::optional<bool> is_restrictive; std::optional<bool> is_restrictive;
std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> conditions; std::vector<std::pair<ConditionType, ASTPtr>> conditions;
String cluster;
while (true) while (true)
{ {
if (alter && new_short_name.empty() && parseRenameTo(pos, expected, new_short_name)) if (alter && new_short_name.empty() && (names->name_parts.size() == 1) && parseRenameTo(pos, expected, new_short_name))
continue; continue;
if (!is_restrictive && parseAsRestrictiveOrPermissive(pos, expected, is_restrictive)) if (!is_restrictive)
continue; {
bool new_is_restrictive;
if (parseAsRestrictiveOrPermissive(pos, expected, new_is_restrictive))
{
is_restrictive = new_is_restrictive;
continue;
}
}
if (parseMultipleConditions(pos, expected, alter, conditions)) std::vector<std::pair<ConditionType, ASTPtr>> new_conditions;
if (parseForClauses(pos, expected, alter, new_conditions))
{
boost::range::push_back(conditions, std::move(new_conditions));
continue; continue;
}
if (cluster.empty() && parseOnCluster(pos, expected, cluster)) if (cluster.empty() && parseOnCluster(pos, expected, cluster))
continue; continue;
@ -257,7 +279,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
break; break;
} }
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
parseToRoles(pos, expected, attach_mode, roles); parseToRoles(pos, expected, attach_mode, roles);
if (cluster.empty()) if (cluster.empty())
@ -272,7 +294,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
query->if_not_exists = if_not_exists; query->if_not_exists = if_not_exists;
query->or_replace = or_replace; query->or_replace = or_replace;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->name_parts = std::move(name_parts); query->names = std::move(names);
query->new_short_name = std::move(new_short_name); query->new_short_name = std::move(new_short_name);
query->is_restrictive = is_restrictive; query->is_restrictive = is_restrictive;
query->conditions = std::move(conditions); query->conditions = std::move(conditions);

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** Parses queries like /** Parses queries like
* CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table * CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
* [AS {PERMISSIVE | RESTRICTIVE}] * [AS {permissive | restrictive}]
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}] * [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
* [USING condition] * [USING condition]
* [WITH CHECK condition] [,...] * [WITH CHECK condition] [,...]
@ -15,7 +15,7 @@ namespace DB
* *
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table * ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
* [RENAME TO new_name] * [RENAME TO new_name]
* [AS {PERMISSIVE | RESTRICTIVE}] * [AS {permissive | restrictive}]
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}] * [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
* [USING {condition | NONE}] * [USING {condition | NONE}]
* [WITH CHECK {condition | NONE}] [,...] * [WITH CHECK {condition | NONE}] [,...]
@ -24,7 +24,7 @@ namespace DB
class ParserCreateRowPolicyQuery : public IParserBase class ParserCreateRowPolicyQuery : public IParserBase
{ {
public: public:
ParserCreateRowPolicyQuery & enableAttachMode(bool enable_) { attach_mode = enable_; return *this; } void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
protected: protected:
const char * getName() const override { return "CREATE ROW POLICY or ALTER ROW POLICY query"; } const char * getName() const override { return "CREATE ROW POLICY or ALTER ROW POLICY query"; }

View File

@ -5,9 +5,10 @@
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ParserSettingsProfileElement.h> #include <Parsers/ParserSettingsProfileElement.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB namespace DB
@ -25,7 +26,7 @@ namespace
}); });
} }
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings) bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -33,27 +34,30 @@ namespace
return false; return false;
ASTPtr new_settings_ast; ASTPtr new_settings_ast;
if (!ParserSettingsProfileElements{}.useIDMode(id_mode).enableInheritKeyword(true).parse(pos, new_settings_ast, expected)) ParserSettingsProfileElements elements_p;
elements_p.useInheritKeyword(true).useIDMode(id_mode);
if (!elements_p.parse(pos, new_settings_ast, expected))
return false; return false;
if (!settings) settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
return true; return true;
}); });
} }
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTExtendedRoleSet> & roles) bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr ast; ASTPtr ast;
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected) if (!ParserKeyword{"TO"}.ignore(pos, expected))
|| !ParserExtendedRoleSet{}.useIDMode(id_mode).parse(pos, ast, expected))
return false; return false;
roles = std::static_pointer_cast<ASTExtendedRoleSet>(ast); ParserRolesOrUsersSet roles_p;
roles_p.allowAll().allowRoleNames().allowUserNames().allowCurrentUser().useIDMode(id_mode);
if (!roles_p.parse(pos, ast, expected))
return false;
roles = std::static_pointer_cast<ASTRolesOrUsersSet>(ast);
return true; return true;
}); });
} }
@ -100,8 +104,8 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
or_replace = true; or_replace = true;
} }
String name; Strings names;
if (!parseIdentifierOrStringLiteral(pos, expected, name)) if (!parseIdentifiersOrStringLiterals(pos, expected, names))
return false; return false;
String new_name; String new_name;
@ -110,11 +114,17 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
while (true) while (true)
{ {
if (alter && parseRenameTo(pos, expected, new_name)) if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
continue; continue;
if (parseSettings(pos, expected, attach_mode, settings)) std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue; continue;
}
if (cluster.empty() && parseOnCluster(pos, expected, cluster)) if (cluster.empty() && parseOnCluster(pos, expected, cluster))
continue; continue;
@ -122,7 +132,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
break; break;
} }
std::shared_ptr<ASTExtendedRoleSet> to_roles; std::shared_ptr<ASTRolesOrUsersSet> to_roles;
parseToRoles(pos, expected, attach_mode, to_roles); parseToRoles(pos, expected, attach_mode, to_roles);
if (cluster.empty()) if (cluster.empty())
@ -137,7 +147,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
query->if_not_exists = if_not_exists; query->if_not_exists = if_not_exists;
query->or_replace = or_replace; query->or_replace = or_replace;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->name = std::move(name); query->names = std::move(names);
query->new_name = std::move(new_name); query->new_name = std::move(new_name);
query->settings = std::move(settings); query->settings = std::move(settings);
query->to_roles = std::move(to_roles); query->to_roles = std::move(to_roles);

View File

@ -16,7 +16,7 @@ namespace DB
class ParserCreateSettingsProfileQuery : public IParserBase class ParserCreateSettingsProfileQuery : public IParserBase
{ {
public: public:
ParserCreateSettingsProfileQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; } void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
protected: protected:
const char * getName() const override { return "CREATE SETTINGS PROFILE or ALTER SETTINGS PROFILE query"; } const char * getName() const override { return "CREATE SETTINGS PROFILE or ALTER SETTINGS PROFILE query"; }

View File

@ -6,21 +6,19 @@
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ParserUserNameWithHost.h>
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ParserSettingsProfileElement.h> #include <Parsers/ParserSettingsProfileElement.h>
#include <ext/range.h> #include <ext/range.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB namespace DB
{ {
namespace ErrorCodes
{
}
namespace namespace
{ {
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name) bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name)
@ -35,7 +33,7 @@ namespace
} }
bool parseAuthentication(IParserBase::Pos & pos, Expected & expected, std::optional<Authentication> & authentication) bool parseAuthentication(IParserBase::Pos & pos, Expected & expected, Authentication & authentication)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -99,97 +97,115 @@ namespace
authentication = Authentication{*type}; authentication = Authentication{*type};
if (expect_password) if (expect_password)
authentication->setPassword(password); authentication.setPassword(password);
else if (expect_hash) else if (expect_hash)
authentication->setPasswordHashHex(password); authentication.setPasswordHashHex(password);
return true; return true;
}); });
} }
bool parseHosts(IParserBase::Pos & pos, Expected & expected, const char * prefix, std::optional<AllowedClientHosts> & hosts) bool parseHostsWithoutPrefix(IParserBase::Pos & pos, Expected & expected, AllowedClientHosts & hosts)
{
AllowedClientHosts res_hosts;
auto parse_host = [&]
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
return true;
if (ParserKeyword{"ANY"}.ignore(pos, expected))
{
res_hosts.addAnyHost();
return true;
}
if (ParserKeyword{"LOCAL"}.ignore(pos, expected))
{
res_hosts.addLocalHost();
return true;
}
if (ParserKeyword{"REGEXP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_regexp_ast : ast->children)
res_hosts.addNameRegexp(name_regexp_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"NAME"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_ast : ast->children)
res_hosts.addName(name_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"IP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & subnet_ast : ast->children)
res_hosts.addSubnet(subnet_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"LIKE"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & pattern_ast : ast->children)
res_hosts.addLikePattern(pattern_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_host, false))
return false;
hosts = std::move(res_hosts);
return true;
}
bool parseHosts(IParserBase::Pos & pos, Expected & expected, const String & prefix, AllowedClientHosts & hosts)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
if (prefix && !ParserKeyword{prefix}.ignore(pos, expected)) if (!prefix.empty() && !ParserKeyword{prefix.c_str()}.ignore(pos, expected))
return false; return false;
if (!ParserKeyword{"HOST"}.ignore(pos, expected)) if (!ParserKeyword{"HOST"}.ignore(pos, expected))
return false; return false;
if (ParserKeyword{"ANY"}.ignore(pos, expected)) AllowedClientHosts res_hosts;
{ if (!parseHostsWithoutPrefix(pos, expected, res_hosts))
if (!hosts) return false;
hosts.emplace();
hosts->addAnyHost();
return true;
}
if (ParserKeyword{"NONE"}.ignore(pos, expected)) hosts.add(std::move(res_hosts));
{
if (!hosts)
hosts.emplace();
return true;
}
AllowedClientHosts new_hosts;
do
{
if (ParserKeyword{"LOCAL"}.ignore(pos, expected))
{
new_hosts.addLocalHost();
}
else if (ParserKeyword{"REGEXP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_regexp_ast : ast->children)
new_hosts.addNameRegexp(name_regexp_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"NAME"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_ast : ast->children)
new_hosts.addName(name_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"IP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & subnet_ast : ast->children)
new_hosts.addSubnet(subnet_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"LIKE"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & pattern_ast : ast->children)
new_hosts.addLikePattern(pattern_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!hosts)
hosts.emplace();
hosts->add(new_hosts);
return true; return true;
}); });
} }
bool parseDefaultRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTExtendedRoleSet> & default_roles) bool parseDefaultRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & default_roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -197,17 +213,19 @@ namespace
return false; return false;
ASTPtr ast; ASTPtr ast;
if (!ParserExtendedRoleSet{}.enableCurrentUserKeyword(false).useIDMode(id_mode).parse(pos, ast, expected)) ParserRolesOrUsersSet default_roles_p;
default_roles_p.allowAll().allowRoleNames().useIDMode(id_mode);
if (!default_roles_p.parse(pos, ast, expected))
return false; return false;
default_roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast); default_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
default_roles->can_contain_users = false; default_roles->allow_user_names = false;
return true; return true;
}); });
} }
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings) bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -215,13 +233,12 @@ namespace
return false; return false;
ASTPtr new_settings_ast; ASTPtr new_settings_ast;
if (!ParserSettingsProfileElements{}.useIDMode(id_mode).parse(pos, new_settings_ast, expected)) ParserSettingsProfileElements elements_p;
elements_p.useIDMode(id_mode);
if (!elements_p.parse(pos, new_settings_ast, expected))
return false; return false;
if (!settings) settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
return true; return true;
}); });
} }
@ -268,30 +285,50 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
or_replace = true; or_replace = true;
} }
String name; ASTPtr names_ast;
std::optional<String> host_pattern; if (!ParserUserNamesWithHost{}.parse(pos, names_ast, expected))
if (!parseUserName(pos, expected, name, host_pattern))
return false; return false;
auto names = typeid_cast<std::shared_ptr<ASTUserNamesWithHost>>(names_ast);
auto names_ref = names->names;
String new_name; String new_name;
std::optional<Authentication> authentication; std::optional<Authentication> authentication;
std::optional<AllowedClientHosts> hosts; std::optional<AllowedClientHosts> hosts;
std::optional<AllowedClientHosts> add_hosts; std::optional<AllowedClientHosts> add_hosts;
std::optional<AllowedClientHosts> remove_hosts; std::optional<AllowedClientHosts> remove_hosts;
std::shared_ptr<ASTExtendedRoleSet> default_roles; std::shared_ptr<ASTRolesOrUsersSet> default_roles;
std::shared_ptr<ASTSettingsProfileElements> settings; std::shared_ptr<ASTSettingsProfileElements> settings;
String cluster; String cluster;
while (true) while (true)
{ {
if (!authentication && parseAuthentication(pos, expected, authentication)) if (!authentication)
continue; {
Authentication new_authentication;
if (parseAuthentication(pos, expected, new_authentication))
{
authentication = std::move(new_authentication);
continue;
}
}
if (parseHosts(pos, expected, nullptr, hosts)) AllowedClientHosts new_hosts;
if (parseHosts(pos, expected, "", new_hosts))
{
if (!hosts)
hosts.emplace();
hosts->add(new_hosts);
continue; continue;
}
if (parseSettings(pos, expected, attach_mode, settings)) std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue; continue;
}
if (!default_roles && parseDefaultRoles(pos, expected, attach_mode, default_roles)) if (!default_roles && parseDefaultRoles(pos, expected, attach_mode, default_roles))
continue; continue;
@ -301,18 +338,40 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
if (alter) if (alter)
{ {
if (new_name.empty() && parseRenameTo(pos, expected, new_name)) if (new_name.empty() && (names->size() == 1) && parseRenameTo(pos, expected, new_name))
continue; continue;
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "DROP", remove_hosts)) if (parseHosts(pos, expected, "ADD", new_hosts))
{
if (!add_hosts)
add_hosts.emplace();
add_hosts->add(new_hosts);
continue; continue;
}
if (parseHosts(pos, expected, "DROP", new_hosts))
{
if (!remove_hosts)
remove_hosts.emplace();
remove_hosts->add(new_hosts);
continue;
}
} }
break; break;
} }
if (!alter && !hosts && host_pattern) if (!alter && !hosts)
hosts.emplace().addLikePattern(*host_pattern); {
String common_host_pattern;
if (names->getHostPatternIfCommon(common_host_pattern) && !common_host_pattern.empty())
{
hosts.emplace().addLikePattern(common_host_pattern);
names->concatParts();
}
}
else if (alter)
names->concatParts();
auto query = std::make_shared<ASTCreateUserQuery>(); auto query = std::make_shared<ASTCreateUserQuery>();
node = query; node = query;
@ -323,7 +382,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
query->if_not_exists = if_not_exists; query->if_not_exists = if_not_exists;
query->or_replace = or_replace; query->or_replace = or_replace;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->name = std::move(name); query->names = std::move(names);
query->new_name = std::move(new_name); query->new_name = std::move(new_name);
query->authentication = std::move(authentication); query->authentication = std::move(authentication);
query->hosts = std::move(hosts); query->hosts = std::move(hosts);

View File

@ -20,7 +20,7 @@ namespace DB
class ParserCreateUserQuery : public IParserBase class ParserCreateUserQuery : public IParserBase
{ {
public: public:
ParserCreateUserQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; } ParserCreateUserQuery & useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; return *this; }
protected: protected:
const char * getName() const override { return "CREATE USER or ALTER USER query"; } const char * getName() const override { return "CREATE USER or ALTER USER query"; }

View File

@ -1,8 +1,9 @@
#include <Parsers/ParserDropAccessEntityQuery.h> #include <Parsers/ParserDropAccessEntityQuery.h>
#include <Parsers/ASTDropAccessEntityQuery.h> #include <Parsers/ASTDropAccessEntityQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ParserRowPolicyName.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/parseDatabaseAndTableName.h>
#include <Parsers/parseUserName.h> #include <Parsers/parseUserName.h>
#include <ext/range.h> #include <ext/range.h>
@ -14,65 +15,28 @@ namespace
using EntityType = IAccessEntity::Type; using EntityType = IAccessEntity::Type;
using EntityTypeInfo = IAccessEntity::TypeInfo; using EntityTypeInfo = IAccessEntity::TypeInfo;
bool parseNames(IParserBase::Pos & pos, Expected & expected, Strings & names)
bool parseEntityType(IParserBase::Pos & pos, Expected & expected, EntityType & type)
{ {
return IParserBase::wrapParseImpl(pos, [&] for (auto i : ext::range(EntityType::MAX))
{ {
Strings res_names; const auto & type_info = EntityTypeInfo::get(i);
do if (ParserKeyword{type_info.name.c_str()}.ignore(pos, expected)
|| (!type_info.alias.empty() && ParserKeyword{type_info.alias.c_str()}.ignore(pos, expected)))
{ {
String name; type = i;
if (!parseIdentifierOrStringLiteral(pos, expected, name)) return true;
return false;
res_names.push_back(std::move(name));
} }
while (ParserToken{TokenType::Comma}.ignore(pos, expected)); }
return false;
names = std::move(res_names);
return true;
});
} }
bool parseRowPolicyNames(IParserBase::Pos & pos, Expected & expected, std::vector<RowPolicy::NameParts> & name_parts)
bool parseOnCluster(IParserBase::Pos & pos, Expected & expected, String & cluster)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
std::vector<RowPolicy::NameParts> res_name_parts; return ParserKeyword{"ON"}.ignore(pos, expected) && ASTQueryWithOnCluster::parse(pos, cluster, expected);
do
{
Strings short_names;
if (!parseNames(pos, expected, short_names))
return false;
String database, table_name;
if (!ParserKeyword{"ON"}.ignore(pos, expected) || !parseDatabaseAndTableName(pos, expected, database, table_name))
return false;
for (String & short_name : short_names)
res_name_parts.push_back({std::move(short_name), database, table_name});
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
name_parts = std::move(res_name_parts);
return true;
});
}
bool parseUserNames(IParserBase::Pos & pos, Expected & expected, Strings & names)
{
return IParserBase::wrapParseImpl(pos, [&]
{
Strings res_names;
do
{
String name;
if (!parseUserName(pos, expected, name))
return false;
res_names.emplace_back(std::move(name));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
names = std::move(res_names);
return true;
}); });
} }
} }
@ -83,17 +47,8 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
if (!ParserKeyword{"DROP"}.ignore(pos, expected)) if (!ParserKeyword{"DROP"}.ignore(pos, expected))
return false; return false;
std::optional<EntityType> type; EntityType type;
for (auto type_i : ext::range(EntityType::MAX)) if (!parseEntityType(pos, expected, type))
{
const auto & type_info = EntityTypeInfo::get(type_i);
if (ParserKeyword{type_info.name.c_str()}.ignore(pos, expected)
|| (!type_info.alias.empty() && ParserKeyword{type_info.alias.c_str()}.ignore(pos, expected)))
{
type = type_i;
}
}
if (!type)
return false; return false;
bool if_exists = false; bool if_exists = false;
@ -101,7 +56,8 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
if_exists = true; if_exists = true;
Strings names; Strings names;
std::vector<RowPolicy::NameParts> row_policies_name_parts; std::shared_ptr<ASTRowPolicyNames> row_policy_names;
String cluster;
if ((type == EntityType::USER) || (type == EntityType::ROLE)) if ((type == EntityType::USER) || (type == EntityType::ROLE))
{ {
@ -110,30 +66,31 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
} }
else if (type == EntityType::ROW_POLICY) else if (type == EntityType::ROW_POLICY)
{ {
if (!parseRowPolicyNames(pos, expected, row_policies_name_parts)) ParserRowPolicyNames parser;
ASTPtr ast;
parser.allowOnCluster();
if (!parser.parse(pos, ast, expected))
return false; return false;
row_policy_names = typeid_cast<std::shared_ptr<ASTRowPolicyNames>>(ast);
cluster = std::exchange(row_policy_names->cluster, "");
} }
else else
{ {
if (!parseNames(pos, expected, names)) if (!parseIdentifiersOrStringLiterals(pos, expected, names))
return false; return false;
} }
String cluster; if (cluster.empty())
if (ParserKeyword{"ON"}.ignore(pos, expected)) parseOnCluster(pos, expected, cluster);
{
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
return false;
}
auto query = std::make_shared<ASTDropAccessEntityQuery>(); auto query = std::make_shared<ASTDropAccessEntityQuery>();
node = query; node = query;
query->type = *type; query->type = type;
query->if_exists = if_exists; query->if_exists = if_exists;
query->cluster = std::move(cluster); query->cluster = std::move(cluster);
query->names = std::move(names); query->names = std::move(names);
query->row_policies_name_parts = std::move(row_policies_name_parts); query->row_policy_names = std::move(row_policy_names);
return true; return true;
} }

View File

@ -1,139 +0,0 @@
#include <Parsers/ParserExtendedRoleSet.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTExtendedRoleSet.h>
#include <Parsers/parseUserName.h>
#include <boost/range/algorithm/find.hpp>
namespace DB
{
namespace
{
bool parseRoleNameOrID(IParserBase::Pos & pos, Expected & expected, bool parse_id, String & res)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!parse_id)
return parseRoleName(pos, expected, res);
if (!ParserKeyword{"ID"}.ignore(pos, expected))
return false;
if (!ParserToken(TokenType::OpeningRoundBracket).ignore(pos, expected))
return false;
ASTPtr ast;
if (!ParserStringLiteral{}.parse(pos, ast, expected))
return false;
String id = ast->as<ASTLiteral &>().value.safeGet<String>();
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
res = std::move(id);
return true;
});
}
bool parseBeforeExcept(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool all_keyword_enabled,
bool current_user_keyword_enabled,
Strings & names,
bool & all,
bool & current_user)
{
return IParserBase::wrapParseImpl(pos, [&]
{
bool res_all = false;
bool res_current_user = false;
Strings res_names;
while (true)
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
{
}
else if (
current_user_keyword_enabled
&& (ParserKeyword{"CURRENT_USER"}.ignore(pos, expected) || ParserKeyword{"currentUser"}.ignore(pos, expected)))
{
if (ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected))
{
if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected))
return false;
}
res_current_user = true;
}
else if (all_keyword_enabled && ParserKeyword{"ALL"}.ignore(pos, expected))
{
res_all = true;
}
else
{
String name;
if (!parseRoleNameOrID(pos, expected, id_mode, name))
return false;
res_names.push_back(name);
}
if (!ParserToken{TokenType::Comma}.ignore(pos, expected))
break;
}
all = res_all;
current_user = res_current_user;
names = std::move(res_names);
return true;
});
}
bool parseExceptAndAfterExcept(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool current_user_keyword_enabled,
Strings & except_names,
bool & except_current_user)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"EXCEPT"}.ignore(pos, expected))
return false;
bool dummy;
return parseBeforeExcept(pos, expected, id_mode, false, current_user_keyword_enabled, except_names, dummy, except_current_user);
});
}
}
bool ParserExtendedRoleSet::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Strings names;
bool current_user = false;
bool all = false;
Strings except_names;
bool except_current_user = false;
if (!parseBeforeExcept(pos, expected, id_mode, all_keyword, current_user_keyword, names, all, current_user))
return false;
parseExceptAndAfterExcept(pos, expected, id_mode, current_user_keyword, except_names, except_current_user);
if (all)
names.clear();
auto result = std::make_shared<ASTExtendedRoleSet>();
result->names = std::move(names);
result->current_user = current_user;
result->all = all;
result->except_names = std::move(except_names);
result->except_current_user = except_current_user;
result->id_mode = id_mode;
node = result;
return true;
}
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
/** Parses a string like this:
* {role|CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {role|CURRENT_USER} [,...]
*/
class ParserExtendedRoleSet : public IParserBase
{
public:
ParserExtendedRoleSet & enableAllKeyword(bool enable_) { all_keyword = enable_; return *this; }
ParserExtendedRoleSet & enableCurrentUserKeyword(bool enable_) { current_user_keyword = enable_; return *this; }
ParserExtendedRoleSet & useIDMode(bool enable_) { id_mode = enable_; return *this; }
protected:
const char * getName() const override { return "ExtendedRoleSet"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool all_keyword = true;
bool current_user_keyword = true;
bool id_mode = false;
};
}

View File

@ -1,10 +1,12 @@
#include <Parsers/ParserGrantQuery.h> #include <Parsers/ParserGrantQuery.h>
#include <Parsers/ASTGrantQuery.h> #include <Parsers/ASTGrantQuery.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTExtendedRoleSet.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ExpressionListParsers.h>
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/parseDatabaseAndTableName.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@ -66,15 +68,13 @@ namespace
if (!ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected)) if (!ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected))
return false; return false;
ASTPtr ast;
if (!ParserList{std::make_unique<ParserIdentifier>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
Strings res_columns; Strings res_columns;
do for (const auto & child : ast->children)
{ res_columns.emplace_back(getIdentifierName(child));
ASTPtr column_ast;
if (!ParserIdentifier().parse(pos, column_ast, expected))
return false;
res_columns.emplace_back(getIdentifierName(column_ast));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected)) if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected))
return false; return false;
@ -84,69 +84,28 @@ namespace
}); });
} }
bool parseAccessTypesWithColumns(IParser::Pos & pos, Expected & expected,
bool parseDatabaseAndTableNameOrMaybeAsterisks( std::vector<std::pair<AccessFlags, Strings>> & access_and_columns)
IParser::Pos & pos, Expected & expected, String & database_name, bool & any_database, String & table_name, bool & any_table)
{ {
return IParserBase::wrapParseImpl(pos, [&] std::vector<std::pair<AccessFlags, Strings>> res;
auto parse_access_and_columns = [&]
{ {
ASTPtr ast[2]; AccessFlags access_flags;
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected)) if (!parseAccessFlags(pos, expected, access_flags))
{
if (ParserToken{TokenType::Dot}.ignore(pos, expected))
{
if (!ParserToken{TokenType::Asterisk}.ignore(pos, expected))
return false;
/// *.* (any table in any database)
any_database = true;
database_name.clear();
any_table = true;
table_name.clear();
return true;
}
/// * (any table in the current database)
any_database = false;
database_name.clear();
any_table = true;
table_name.clear();
return true;
}
if (!ParserIdentifier().parse(pos, ast[0], expected))
return false; return false;
if (ParserToken{TokenType::Dot}.ignore(pos, expected)) Strings columns;
{ parseColumnNames(pos, expected, columns);
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected)) res.emplace_back(access_flags, std::move(columns));
{
/// <database_name>.*
any_database = false;
database_name = getIdentifierName(ast[0]);
any_table = true;
table_name.clear();
return true;
}
if (!ParserIdentifier().parse(pos, ast[1], expected))
return false;
/// <database_name>.<table_name>
any_database = false;
database_name = getIdentifierName(ast[0]);
any_table = false;
table_name = getIdentifierName(ast[1]);
return true;
}
/// <table_name> - the current database, specified table
any_database = false;
database_name.clear();
any_table = false;
table_name = getIdentifierName(ast[0]);
return true; return true;
}); };
if (!ParserList::parseUtil(pos, expected, parse_access_and_columns, false))
return false;
access_and_columns = std::move(res);
return true;
} }
@ -155,27 +114,19 @@ namespace
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
AccessRightsElements res_elements; AccessRightsElements res_elements;
do
auto parse_around_on = [&]
{ {
std::vector<std::pair<AccessFlags, Strings>> access_and_columns; std::vector<std::pair<AccessFlags, Strings>> access_and_columns;
do if (!parseAccessTypesWithColumns(pos, expected, access_and_columns))
{ return false;
AccessFlags access_flags;
if (!parseAccessFlags(pos, expected, access_flags))
return false;
Strings columns;
parseColumnNames(pos, expected, columns);
access_and_columns.emplace_back(access_flags, std::move(columns));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!ParserKeyword{"ON"}.ignore(pos, expected)) if (!ParserKeyword{"ON"}.ignore(pos, expected))
return false; return false;
String database_name, table_name; String database_name, table_name;
bool any_database = false, any_table = false; bool any_database = false, any_table = false;
if (!parseDatabaseAndTableNameOrMaybeAsterisks(pos, expected, database_name, any_database, table_name, any_table)) if (!parseDatabaseAndTableNameOrAsterisks(pos, expected, database_name, any_database, table_name, any_table))
return false; return false;
for (auto & [access_flags, columns] : access_and_columns) for (auto & [access_flags, columns] : access_and_columns)
@ -190,8 +141,12 @@ namespace
element.table = table_name; element.table = table_name;
res_elements.emplace_back(std::move(element)); res_elements.emplace_back(std::move(element));
} }
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected)); return true;
};
if (!ParserList::parseUtil(pos, expected, parse_around_on, false))
return false;
elements = std::move(res_elements); elements = std::move(res_elements);
return true; return true;
@ -199,21 +154,23 @@ namespace
} }
bool parseRoles(IParser::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTExtendedRoleSet> & roles) bool parseRoles(IParser::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr ast; ASTPtr ast;
if (!ParserExtendedRoleSet{}.enableAllKeyword(false).enableCurrentUserKeyword(false).useIDMode(id_mode).parse(pos, ast, expected)) ParserRolesOrUsersSet roles_p;
roles_p.allowRoleNames().useIDMode(id_mode);
if (!roles_p.parse(pos, ast, expected))
return false; return false;
roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast); roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
return true; return true;
}); });
} }
bool parseToRoles(IParser::Pos & pos, Expected & expected, ASTGrantQuery::Kind kind, std::shared_ptr<ASTExtendedRoleSet> & to_roles) bool parseToRoles(IParser::Pos & pos, Expected & expected, ASTGrantQuery::Kind kind, std::shared_ptr<ASTRolesOrUsersSet> & to_roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -230,10 +187,12 @@ namespace
} }
ASTPtr ast; ASTPtr ast;
if (!ParserExtendedRoleSet{}.enableAllKeyword(kind == Kind::REVOKE).parse(pos, ast, expected)) ParserRolesOrUsersSet roles_p;
roles_p.allowRoleNames().allowUserNames().allowCurrentUser().allowAll(kind == Kind::REVOKE);
if (!roles_p.parse(pos, ast, expected))
return false; return false;
to_roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast); to_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
return true; return true;
}); });
} }
@ -282,14 +241,14 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
} }
AccessRightsElements elements; AccessRightsElements elements;
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
if (!parseAccessRightsElements(pos, expected, elements) && !parseRoles(pos, expected, attach, roles)) if (!parseAccessRightsElements(pos, expected, elements) && !parseRoles(pos, expected, attach, roles))
return false; return false;
if (cluster.empty()) if (cluster.empty())
parseOnCluster(pos, expected, cluster); parseOnCluster(pos, expected, cluster);
std::shared_ptr<ASTExtendedRoleSet> to_roles; std::shared_ptr<ASTRolesOrUsersSet> to_roles;
if (!parseToRoles(pos, expected, kind, to_roles)) if (!parseToRoles(pos, expected, kind, to_roles))
return false; return false;

View File

@ -12,7 +12,7 @@ namespace DB
class ParserGrantQuery : public IParserBase class ParserGrantQuery : public IParserBase
{ {
public: public:
ParserGrantQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; } ParserGrantQuery & useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; return *this; }
protected: protected:
const char * getName() const override { return "GRANT or REVOKE query"; } const char * getName() const override { return "GRANT or REVOKE query"; }

View File

@ -15,6 +15,7 @@
#include <Parsers/ParserSetQuery.h> #include <Parsers/ParserSetQuery.h>
#include <Parsers/ASTExplainQuery.h> #include <Parsers/ASTExplainQuery.h>
#include <Parsers/ParserShowAccessEntitiesQuery.h> #include <Parsers/ParserShowAccessEntitiesQuery.h>
#include <Parsers/ParserShowAccessQuery.h>
#include <Parsers/ParserShowCreateAccessEntityQuery.h> #include <Parsers/ParserShowCreateAccessEntityQuery.h>
#include <Parsers/ParserShowGrantsQuery.h> #include <Parsers/ParserShowGrantsQuery.h>
#include <Parsers/ParserShowPrivilegesQuery.h> #include <Parsers/ParserShowPrivilegesQuery.h>
@ -38,6 +39,7 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
ParserOptimizeQuery optimize_p; ParserOptimizeQuery optimize_p;
ParserKillQueryQuery kill_query_p; ParserKillQueryQuery kill_query_p;
ParserWatchQuery watch_p; ParserWatchQuery watch_p;
ParserShowAccessQuery show_access_p;
ParserShowAccessEntitiesQuery show_access_entities_p; ParserShowAccessEntitiesQuery show_access_entities_p;
ParserShowCreateAccessEntityQuery show_create_access_entity_p; ParserShowCreateAccessEntityQuery show_create_access_entity_p;
ParserShowGrantsQuery show_grants_p; ParserShowGrantsQuery show_grants_p;
@ -70,6 +72,7 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|| kill_query_p.parse(pos, query, expected) || kill_query_p.parse(pos, query, expected)
|| optimize_p.parse(pos, query, expected) || optimize_p.parse(pos, query, expected)
|| watch_p.parse(pos, query, expected) || watch_p.parse(pos, query, expected)
|| show_access_p.parse(pos, query, expected)
|| show_access_entities_p.parse(pos, query, expected) || show_access_entities_p.parse(pos, query, expected)
|| show_grants_p.parse(pos, query, expected) || show_grants_p.parse(pos, query, expected)
|| show_privileges_p.parse(pos, query, expected); || show_privileges_p.parse(pos, query, expected);

View File

@ -0,0 +1,142 @@
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/parseUserName.h>
#include <Parsers/ExpressionListParsers.h>
#include <boost/range/algorithm/find.hpp>
namespace DB
{
namespace
{
bool parseRoleNameOrID(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
String & res)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!id_mode)
return parseRoleName(pos, expected, res);
if (!ParserKeyword{"ID"}.ignore(pos, expected))
return false;
if (!ParserToken(TokenType::OpeningRoundBracket).ignore(pos, expected))
return false;
ASTPtr ast;
if (!ParserStringLiteral{}.parse(pos, ast, expected))
return false;
String id = ast->as<ASTLiteral &>().value.safeGet<String>();
if (!ParserToken(TokenType::ClosingRoundBracket).ignore(pos, expected))
return false;
res = std::move(id);
return true;
});
}
bool parseBeforeExcept(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool allow_all,
bool allow_current_user,
Strings & names,
bool & all,
bool & current_user)
{
bool res_all = false;
bool res_current_user = false;
Strings res_names;
auto parse_element = [&]
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
return true;
if (allow_all && ParserKeyword{"ALL"}.ignore(pos, expected))
{
res_all = true;
return true;
}
if (allow_current_user && parseCurrentUserTag(pos, expected))
{
res_current_user = true;
return true;
}
String name;
if (parseRoleNameOrID(pos, expected, id_mode, name))
{
res_names.emplace_back(std::move(name));
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_element, false))
return false;
names = std::move(res_names);
all = res_all;
current_user = res_current_user;
return true;
}
bool parseExceptAndAfterExcept(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool allow_current_user,
Strings & except_names,
bool & except_current_user)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"EXCEPT"}.ignore(pos, expected))
return false;
bool unused;
return parseBeforeExcept(pos, expected, id_mode, false, allow_current_user, except_names, unused, except_current_user);
});
}
}
bool ParserRolesOrUsersSet::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Strings names;
bool current_user = false;
bool all = false;
Strings except_names;
bool except_current_user = false;
if (!parseBeforeExcept(pos, expected, id_mode, allow_all, allow_current_user, names, all, current_user))
return false;
parseExceptAndAfterExcept(pos, expected, id_mode, allow_current_user, except_names, except_current_user);
if (all)
names.clear();
auto result = std::make_shared<ASTRolesOrUsersSet>();
result->names = std::move(names);
result->current_user = current_user;
result->all = all;
result->except_names = std::move(except_names);
result->except_current_user = except_current_user;
result->id_mode = id_mode;
result->allow_user_names = allow_user_names;
result->allow_role_names = allow_role_names;
node = result;
return true;
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
/** Parses a string like this:
* {role|CURRENT_USER} [,...] | NONE | ALL | ALL EXCEPT {role|CURRENT_USER} [,...]
*/
class ParserRolesOrUsersSet : public IParserBase
{
public:
ParserRolesOrUsersSet & allowAll(bool allow_all_ = true) { allow_all = allow_all_; return *this; }
ParserRolesOrUsersSet & allowUserNames(bool allow_user_names_ = true) { allow_user_names = allow_user_names_; return *this; }
ParserRolesOrUsersSet & allowRoleNames(bool allow_role_names_ = true) { allow_role_names = allow_role_names_; return *this; }
ParserRolesOrUsersSet & allowCurrentUser(bool allow_current_user_ = true) { allow_current_user = allow_current_user_; return *this; }
ParserRolesOrUsersSet & useIDMode(bool id_mode_ = true) { id_mode = id_mode_; return *this; }
protected:
const char * getName() const override { return "RolesOrUsersSet"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool allow_all = false;
bool allow_user_names = false;
bool allow_role_names = false;
bool allow_current_user = false;
bool id_mode = false;
};
}

View File

@ -0,0 +1,196 @@
#include <Parsers/ParserRowPolicyName.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/parseDatabaseAndTableName.h>
#include <Parsers/ASTQueryWithOnCluster.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB
{
namespace
{
bool parseOnCluster(IParserBase::Pos & pos, Expected & expected, String & cluster)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"ON"}.ignore(pos, expected) && ASTQueryWithOnCluster::parse(pos, cluster, expected);
});
}
bool parseDBAndTableName(IParser::Pos & pos, Expected & expected, String & database, String & table_name)
{
return IParserBase::wrapParseImpl(pos, [&]
{
String res_database, res_table_name;
if (!parseDatabaseAndTableName(pos, expected, res_database, res_table_name))
return false;
/// If table is specified without DB it cannot be followed by "ON"
/// (but can be followed by "ON CLUSTER").
/// The following code is necessary to figure out while parsing something like
/// policy1 ON table1, policy2 ON table2
/// that policy2 is another policy, not another table.
auto end_pos = pos;
if (res_database.empty() && ParserKeyword{"ON"}.ignore(pos, expected))
{
String unused;
if (ASTQueryWithOnCluster::parse(pos, unused, expected))
pos = end_pos;
else
return false;
}
database = std::move(res_database);
table_name = std::move(res_table_name);
return true;
});
}
bool parseOnDBAndTableName(IParser::Pos & pos, Expected & expected, String & database, String & table_name)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"ON"}.ignore(pos, expected) && parseDBAndTableName(pos, expected, database, table_name);
});
}
bool parseOnDBAndTableNames(IParser::Pos & pos, Expected & expected, std::vector<std::pair<String, String>> & database_and_table_names)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"ON"}.ignore(pos, expected))
return false;
std::vector<std::pair<String, String>> res;
auto parse_db_and_table_name = [&]
{
String database, table_name;
if (!parseDBAndTableName(pos, expected, database, table_name))
return false;
res.emplace_back(std::move(database), std::move(table_name));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_db_and_table_name, false))
return false;
database_and_table_names = std::move(res);
return true;
});
}
bool parseRowPolicyNamesAroundON(IParser::Pos & pos, Expected & expected,
bool allow_multiple_short_names,
bool allow_multiple_tables,
bool allow_on_cluster,
std::vector<RowPolicy::NameParts> & name_parts,
String & cluster)
{
return IParserBase::wrapParseImpl(pos, [&]
{
std::vector<String> short_names;
if (allow_multiple_short_names)
{
if (!parseIdentifiersOrStringLiterals(pos, expected, short_names))
return false;
}
else
{
if (!parseIdentifierOrStringLiteral(pos, expected, short_names.emplace_back()))
return false;
}
String res_cluster;
if (allow_on_cluster)
parseOnCluster(pos, expected, res_cluster);
std::vector<std::pair<String, String>> database_and_table_names;
if (allow_multiple_tables && (short_names.size() == 1))
{
if (!parseOnDBAndTableNames(pos, expected, database_and_table_names))
return false;
}
else
{
String database, table_name;
if (!parseOnDBAndTableName(pos, expected, database, table_name))
return false;
database_and_table_names.emplace_back(std::move(database), std::move(table_name));
}
if (allow_on_cluster && res_cluster.empty())
parseOnCluster(pos, expected, res_cluster);
assert(!short_names.empty());
assert(!database_and_table_names.empty());
name_parts.clear();
for (const String & short_name : short_names)
for (const auto & [database, table_name] : database_and_table_names)
name_parts.push_back({short_name, database, table_name});
cluster = std::move(res_cluster);
return true;
});
}
}
bool ParserRowPolicyName::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::vector<RowPolicy::NameParts> name_parts;
String cluster;
if (!parseRowPolicyNamesAroundON(pos, expected, false, false, allow_on_cluster, name_parts, cluster))
return false;
assert(name_parts.size() == 1);
auto result = std::make_shared<ASTRowPolicyName>();
result->name_parts = std::move(name_parts.front());
result->cluster = std::move(cluster);
node = result;
return true;
}
bool ParserRowPolicyNames::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::vector<RowPolicy::NameParts> name_parts;
size_t num_added_names_last_time = 0;
String cluster;
auto parse_around_on = [&]
{
if (!name_parts.empty())
{
if ((num_added_names_last_time != 1) || !cluster.empty())
return false;
}
std::vector<RowPolicy::NameParts> new_name_parts;
if (!parseRowPolicyNamesAroundON(pos, expected, name_parts.empty(), name_parts.empty(), allow_on_cluster, new_name_parts, cluster))
return false;
num_added_names_last_time = new_name_parts.size();
boost::range::push_back(name_parts, std::move(new_name_parts));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_around_on, false))
return false;
auto result = std::make_shared<ASTRowPolicyNames>();
result->name_parts = std::move(name_parts);
result->cluster = std::move(cluster);
node = result;
return true;
}
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <Parsers/IParserBase.h>
#include <Access/RowPolicy.h>
namespace DB
{
/** Parses a string in one of the following form:
* short_name ON [db.]table_name [ON CLUSTER 'cluster_name']
* short_name [ON CLUSTER 'cluster_name'] ON [db.]table_name
*/
class ParserRowPolicyName : public IParserBase
{
public:
void allowOnCluster(bool allow = true) { allow_on_cluster = allow; }
protected:
const char * getName() const override { return "RowPolicyName"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool allow_on_cluster = false;
};
/** Parses a string in one of the following form:
* short_name1 ON [db1.]table_name1 [, short_name2 ON [db2.]table_name2 ...] [ON CLUSTER 'cluster_name']
* short_name1 [, short_name2 ...] ON [db.]table_name [ON CLUSTER 'cluster_name']
* short_name1 [, short_name2 ...] [ON CLUSTER 'cluster_name'] ON [db.]table_name
* short_name ON [db1.]table_name1 [, [db2.]table_name2 ...] [ON CLUSTER 'cluster_name']
* short_name [ON CLUSTER 'cluster_name'] ON [db1.]table_name1 [, [db2.]table_name2 ...]
*/
class ParserRowPolicyNames : public IParserBase
{
public:
void allowOnCluster(bool allow = true) { allow_on_cluster = allow; }
protected:
const char * getName() const override { return "SettingsProfileElements"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
private:
bool allow_on_cluster = false;
};
}

View File

@ -1,29 +1,31 @@
#include <Parsers/ParserSetRoleQuery.h> #include <Parsers/ParserSetRoleQuery.h>
#include <Parsers/ASTSetRoleQuery.h> #include <Parsers/ASTSetRoleQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ASTExtendedRoleSet.h> #include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ParserExtendedRoleSet.h> #include <Parsers/ParserRolesOrUsersSet.h>
namespace DB namespace DB
{ {
namespace namespace
{ {
bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTExtendedRoleSet> & roles) bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTRolesOrUsersSet> & roles)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr ast; ASTPtr ast;
if (!ParserExtendedRoleSet{}.enableCurrentUserKeyword(false).parse(pos, ast, expected)) ParserRolesOrUsersSet roles_p;
roles_p.allowRoleNames().allowAll();
if (!roles_p.parse(pos, ast, expected))
return false; return false;
roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast); roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
roles->can_contain_users = false; roles->allow_user_names = false;
return true; return true;
}); });
} }
bool parseToUsers(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTExtendedRoleSet> & to_users) bool parseToUsers(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTRolesOrUsersSet> & to_users)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
@ -31,11 +33,13 @@ namespace
return false; return false;
ASTPtr ast; ASTPtr ast;
if (!ParserExtendedRoleSet{}.enableAllKeyword(false).parse(pos, ast, expected)) ParserRolesOrUsersSet users_p;
users_p.allowUserNames().allowCurrentUser();
if (!users_p.parse(pos, ast, expected))
return false; return false;
to_users = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast); to_users = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
to_users->can_contain_roles = false; to_users->allow_role_names = false;
return true; return true;
}); });
} }
@ -55,8 +59,8 @@ bool ParserSetRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
else else
return false; return false;
std::shared_ptr<ASTExtendedRoleSet> roles; std::shared_ptr<ASTRolesOrUsersSet> roles;
std::shared_ptr<ASTExtendedRoleSet> to_users; std::shared_ptr<ASTRolesOrUsersSet> to_users;
if ((kind == Kind::SET_ROLE) || (kind == Kind::SET_DEFAULT_ROLE)) if ((kind == Kind::SET_ROLE) || (kind == Kind::SET_DEFAULT_ROLE))
{ {

View File

@ -1,5 +1,6 @@
#include <Parsers/ParserSettingsProfileElement.h> #include <Parsers/ParserSettingsProfileElement.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h> #include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTSettingsProfileElement.h> #include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ASTLiteral.h> #include <Parsers/ASTLiteral.h>
@ -11,12 +12,19 @@ namespace DB
{ {
namespace namespace
{ {
bool parseProfileNameOrID(IParserBase::Pos & pos, Expected & expected, bool parse_id, String & res) bool parseProfileKeyword(IParserBase::Pos & pos, Expected & expected, bool use_inherit_keyword)
{
return ParserKeyword{"PROFILE"}.ignore(pos, expected) ||
(use_inherit_keyword && ParserKeyword{"INHERIT"}.ignore(pos, expected));
}
bool parseProfileNameOrID(IParserBase::Pos & pos, Expected & expected, bool id_mode, String & res)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
ASTPtr ast; ASTPtr ast;
if (!parse_id) if (!id_mode)
return parseIdentifierOrStringLiteral(pos, expected, res); return parseIdentifierOrStringLiteral(pos, expected, res);
if (!ParserKeyword{"ID"}.ignore(pos, expected)) if (!ParserKeyword{"ID"}.ignore(pos, expected))
@ -96,52 +104,98 @@ namespace
return false; return false;
}); });
} }
bool parseSettingNameWithValueOrConstraints(
IParserBase::Pos & pos,
Expected & expected,
String & setting_name,
Field & value,
Field & min_value,
Field & max_value,
std::optional<bool> & readonly)
{
return IParserBase::wrapParseImpl(pos, [&]
{
ASTPtr name_ast;
if (!ParserIdentifier{}.parse(pos, name_ast, expected))
return false;
String res_setting_name = getIdentifierName(name_ast);
Field res_value;
Field res_min_value;
Field res_max_value;
std::optional<bool> res_readonly;
bool has_value_or_constraint = false;
while (parseValue(pos, expected, res_value) || parseMinMaxValue(pos, expected, res_min_value, res_max_value)
|| parseReadonlyOrWritableKeyword(pos, expected, res_readonly))
{
has_value_or_constraint = true;
}
if (!has_value_or_constraint)
return false;
setting_name = std::move(res_setting_name);
value = std::move(res_value);
min_value = std::move(res_min_value);
max_value = std::move(res_max_value);
readonly = res_readonly;
return true;
});
}
bool parseSettingsProfileElement(IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool use_inherit_keyword,
bool previous_element_was_parent_profile,
std::shared_ptr<ASTSettingsProfileElement> & result)
{
return IParserBase::wrapParseImpl(pos, [&]
{
String parent_profile;
String setting_name;
Field value;
Field min_value;
Field max_value;
std::optional<bool> readonly;
if (parseSettingNameWithValueOrConstraints(pos, expected, setting_name, value, min_value, max_value, readonly))
{
}
else if (parseProfileKeyword(pos, expected, use_inherit_keyword) || previous_element_was_parent_profile)
{
if (!parseProfileNameOrID(pos, expected, id_mode, parent_profile))
return false;
}
else
return false;
result = std::make_shared<ASTSettingsProfileElement>();
result->parent_profile = std::move(parent_profile);
result->setting_name = std::move(setting_name);
result->value = std::move(value);
result->min_value = std::move(min_value);
result->max_value = std::move(max_value);
result->readonly = readonly;
result->id_mode = id_mode;
result->use_inherit_keyword = use_inherit_keyword;
return true;
});
}
} }
bool ParserSettingsProfileElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) bool ParserSettingsProfileElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{ {
String parent_profile; std::shared_ptr<ASTSettingsProfileElement> res;
String setting_name; if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, false, res))
Field value; return false;
Field min_value;
Field max_value;
std::optional<bool> readonly;
if (ParserKeyword{"PROFILE"}.ignore(pos, expected) || node = res;
(enable_inherit_keyword && ParserKeyword{"INHERIT"}.ignore(pos, expected)))
{
if (!parseProfileNameOrID(pos, expected, id_mode, parent_profile))
return false;
}
else
{
ASTPtr name_ast;
if (!ParserIdentifier{}.parse(pos, name_ast, expected))
return false;
setting_name = getIdentifierName(name_ast);
bool has_value_or_constraint = false;
while (parseValue(pos, expected, value) || parseMinMaxValue(pos, expected, min_value, max_value)
|| parseReadonlyOrWritableKeyword(pos, expected, readonly))
{
has_value_or_constraint = true;
}
if (!has_value_or_constraint)
return false;
}
auto result = std::make_shared<ASTSettingsProfileElement>();
result->parent_profile = std::move(parent_profile);
result->setting_name = std::move(setting_name);
result->value = std::move(value);
result->min_value = std::move(min_value);
result->max_value = std::move(max_value);
result->readonly = readonly;
result->id_mode = id_mode;
result->use_inherit_keyword = enable_inherit_keyword;
node = result;
return true; return true;
} }
@ -155,15 +209,21 @@ bool ParserSettingsProfileElements::parseImpl(Pos & pos, ASTPtr & node, Expected
} }
else else
{ {
do bool previous_element_was_parent_profile = false;
auto parse_element = [&]
{ {
ASTPtr ast; std::shared_ptr<ASTSettingsProfileElement> element;
if (!ParserSettingsProfileElement{}.useIDMode(id_mode).enableInheritKeyword(enable_inherit_keyword).parse(pos, ast, expected)) if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, previous_element_was_parent_profile, element))
return false; return false;
auto element = typeid_cast<std::shared_ptr<ASTSettingsProfileElement>>(ast);
elements.push_back(std::move(element)); elements.push_back(element);
} previous_element_was_parent_profile = !element->parent_profile.empty();
while (ParserToken{TokenType::Comma}.ignore(pos, expected)); return true;
};
if (!ParserList::parseUtil(pos, expected, parse_element, false))
return false;
} }
auto result = std::make_shared<ASTSettingsProfileElements>(); auto result = std::make_shared<ASTSettingsProfileElements>();

View File

@ -11,8 +11,8 @@ namespace DB
class ParserSettingsProfileElement : public IParserBase class ParserSettingsProfileElement : public IParserBase
{ {
public: public:
ParserSettingsProfileElement & useIDMode(bool enable_) { id_mode = enable_; return *this; } ParserSettingsProfileElement & useIDMode(bool id_mode_ = true) { id_mode = id_mode_; return *this; }
ParserSettingsProfileElement & enableInheritKeyword(bool enable_) { enable_inherit_keyword = enable_; return *this; } ParserSettingsProfileElement & useInheritKeyword(bool use_inherit_keyword_ = true) { use_inherit_keyword = use_inherit_keyword_; return *this; }
protected: protected:
const char * getName() const override { return "SettingsProfileElement"; } const char * getName() const override { return "SettingsProfileElement"; }
@ -20,15 +20,15 @@ protected:
private: private:
bool id_mode = false; bool id_mode = false;
bool enable_inherit_keyword = false; bool use_inherit_keyword = false;
}; };
class ParserSettingsProfileElements : public IParserBase class ParserSettingsProfileElements : public IParserBase
{ {
public: public:
ParserSettingsProfileElements & useIDMode(bool enable_) { id_mode = enable_; return *this; } ParserSettingsProfileElements & useIDMode(bool id_mode_ = true) { id_mode = id_mode_; return *this; }
ParserSettingsProfileElements & enableInheritKeyword(bool enable_) { enable_inherit_keyword = enable_; return *this; } ParserSettingsProfileElements & useInheritKeyword(bool use_inherit_keyword_ = true) { use_inherit_keyword = use_inherit_keyword_; return *this; }
protected: protected:
const char * getName() const override { return "SettingsProfileElements"; } const char * getName() const override { return "SettingsProfileElements"; }
@ -36,7 +36,7 @@ protected:
private: private:
bool id_mode = false; bool id_mode = false;
bool enable_inherit_keyword = false; bool use_inherit_keyword = false;
}; };
} }

View File

@ -2,6 +2,8 @@
#include <Parsers/ASTShowAccessEntitiesQuery.h> #include <Parsers/ASTShowAccessEntitiesQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/parseDatabaseAndTableName.h> #include <Parsers/parseDatabaseAndTableName.h>
#include <Parsers/parseIdentifierOrStringLiteral.h>
#include <ext/range.h>
namespace DB namespace DB
@ -9,14 +11,29 @@ namespace DB
namespace namespace
{ {
using EntityType = IAccessEntity::Type; using EntityType = IAccessEntity::Type;
using EntityTypeInfo = IAccessEntity::TypeInfo;
bool parseONDatabaseAndTableName(IParserBase::Pos & pos, Expected & expected, String & database, String & table_name) bool parseEntityType(IParserBase::Pos & pos, Expected & expected, EntityType & type)
{
for (auto i : ext::range(EntityType::MAX))
{
const auto & type_info = EntityTypeInfo::get(i);
if (ParserKeyword{type_info.plural_name.c_str()}.ignore(pos, expected)
|| (!type_info.plural_alias.empty() && ParserKeyword{type_info.plural_alias.c_str()}.ignore(pos, expected)))
{
type = i;
return true;
}
}
return false;
}
bool parseOnDBAndTableName(IParserBase::Pos & pos, Expected & expected, String & database, bool & any_database, String & table, bool & any_table)
{ {
return IParserBase::wrapParseImpl(pos, [&] return IParserBase::wrapParseImpl(pos, [&]
{ {
database.clear(); return ParserKeyword{"ON"}.ignore(pos, expected)
table_name.clear(); && parseDatabaseAndTableNameOrAsterisks(pos, expected, database, any_database, table, any_table);
return ParserKeyword{"ON"}.ignore(pos, expected) && parseDatabaseAndTableName(pos, expected, database, table_name);
}); });
} }
} }
@ -27,18 +44,15 @@ bool ParserShowAccessEntitiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected
if (!ParserKeyword{"SHOW"}.ignore(pos, expected)) if (!ParserKeyword{"SHOW"}.ignore(pos, expected))
return false; return false;
std::optional<EntityType> type; EntityType type;
bool all = false;
bool current_quota = false; bool current_quota = false;
bool current_roles = false; bool current_roles = false;
bool enabled_roles = false; bool enabled_roles = false;
if (ParserKeyword{"USERS"}.ignore(pos, expected)) if (parseEntityType(pos, expected, type))
{ {
type = EntityType::USER; all = true;
}
else if (ParserKeyword{"ROLES"}.ignore(pos, expected))
{
type = EntityType::ROLE;
} }
else if (ParserKeyword{"CURRENT ROLES"}.ignore(pos, expected)) else if (ParserKeyword{"CURRENT ROLES"}.ignore(pos, expected))
{ {
@ -50,39 +64,44 @@ bool ParserShowAccessEntitiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected
type = EntityType::ROLE; type = EntityType::ROLE;
enabled_roles = true; enabled_roles = true;
} }
else if (ParserKeyword{"POLICIES"}.ignore(pos, expected) || ParserKeyword{"ROW POLICIES"}.ignore(pos, expected)) else if (ParserKeyword{"CURRENT QUOTA"}.ignore(pos, expected) || ParserKeyword{"QUOTA"}.ignore(pos, expected))
{
type = EntityType::ROW_POLICY;
}
else if (ParserKeyword{"QUOTAS"}.ignore(pos, expected))
{
type = EntityType::QUOTA;
}
else if (ParserKeyword{"QUOTA"}.ignore(pos, expected) || ParserKeyword{"CURRENT QUOTA"}.ignore(pos, expected))
{ {
type = EntityType::QUOTA; type = EntityType::QUOTA;
current_quota = true; current_quota = true;
} }
else if (ParserKeyword{"PROFILES"}.ignore(pos, expected) || ParserKeyword{"SETTINGS PROFILES"}.ignore(pos, expected))
{
type = EntityType::SETTINGS_PROFILE;
}
else else
return false; return false;
String database, table_name; String short_name;
std::optional<std::pair<String, String>> database_and_table_name;
if (type == EntityType::ROW_POLICY) if (type == EntityType::ROW_POLICY)
parseONDatabaseAndTableName(pos, expected, database, table_name); {
String database, table_name;
bool any_database, any_table;
if (parseOnDBAndTableName(pos, expected, database, any_database, table_name, any_table))
{
if (any_database)
all = true;
else
database_and_table_name.emplace(database, table_name);
}
else if (parseIdentifierOrStringLiteral(pos, expected, short_name))
{
}
else
all = true;
}
auto query = std::make_shared<ASTShowAccessEntitiesQuery>(); auto query = std::make_shared<ASTShowAccessEntitiesQuery>();
node = query; node = query;
query->type = *type; query->type = type;
query->all = all;
query->current_quota = current_quota; query->current_quota = current_quota;
query->current_roles = current_roles; query->current_roles = current_roles;
query->enabled_roles = enabled_roles; query->enabled_roles = enabled_roles;
query->database = std::move(database); query->short_name = std::move(short_name);
query->table_name = std::move(table_name); query->database_and_table_name = std::move(database_and_table_name);
return true; return true;
} }

View File

@ -6,10 +6,12 @@
namespace DB namespace DB
{ {
/** Parses queries like /** Parses queries like
* SHOW [ROW] POLICIES [ON [database.]table] * SHOW USERS
SHOW QUOTAS * SHOW [CURRENT|ENABLED] ROLES
SHOW [CURRENT] QUOTA * SHOW [SETTINGS] PROFILES
SHOW [SETTINGS] PROFILES * SHOW [ROW] POLICIES [name | ON [database.]table]
* SHOW QUOTAS
* SHOW [CURRENT] QUOTA
*/ */
class ParserShowAccessEntitiesQuery : public IParserBase class ParserShowAccessEntitiesQuery : public IParserBase
{ {

View File

@ -0,0 +1,32 @@
#pragma once
#include <Parsers/IParserBase.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTShowAccessQuery.h>
namespace DB
{
/** Query SHOW ACCESS
*/
class ParserShowAccessQuery : public IParserBase
{
protected:
const char * getName() const override { return "SHOW ACCESS query"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
auto query = std::make_shared<ASTShowAccessQuery>();
if (!ParserKeyword("SHOW ACCESS").ignore(pos, expected))
return false;
node = query;
return true;
}
};
}

View File

@ -2,16 +2,65 @@
#include <Parsers/ASTShowCreateAccessEntityQuery.h> #include <Parsers/ASTShowCreateAccessEntityQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/parseIdentifierOrStringLiteral.h> #include <Parsers/parseIdentifierOrStringLiteral.h>
#include <Parsers/parseDatabaseAndTableName.h> #include <Parsers/ParserRowPolicyName.h>
#include <Parsers/ASTRowPolicyName.h>
#include <Parsers/parseUserName.h> #include <Parsers/parseUserName.h>
#include <Parsers/parseDatabaseAndTableName.h>
#include <ext/range.h> #include <ext/range.h>
#include <assert.h> #include <assert.h>
namespace DB namespace DB
{ {
using EntityType = IAccessEntity::Type; namespace ErrorCodes
using EntityTypeInfo = IAccessEntity::TypeInfo; {
extern const int NOT_IMPLEMENTED;
}
namespace
{
using EntityType = IAccessEntity::Type;
using EntityTypeInfo = IAccessEntity::TypeInfo;
bool parseEntityType(IParserBase::Pos & pos, Expected & expected, EntityType & type, bool & plural)
{
for (auto i : ext::range(EntityType::MAX))
{
const auto & type_info = EntityTypeInfo::get(i);
if (ParserKeyword{type_info.name.c_str()}.ignore(pos, expected)
|| (!type_info.alias.empty() && ParserKeyword{type_info.alias.c_str()}.ignore(pos, expected)))
{
type = i;
plural = false;
return true;
}
}
for (auto i : ext::range(EntityType::MAX))
{
const auto & type_info = EntityTypeInfo::get(i);
if (ParserKeyword{type_info.plural_name.c_str()}.ignore(pos, expected)
|| (!type_info.plural_alias.empty() && ParserKeyword{type_info.plural_alias.c_str()}.ignore(pos, expected)))
{
type = i;
plural = true;
return true;
}
}
return false;
}
bool parseOnDBAndTableName(IParserBase::Pos & pos, Expected & expected, String & database, bool & any_database, String & table, bool & any_table)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"ON"}.ignore(pos, expected)
&& parseDatabaseAndTableNameOrAsterisks(pos, expected, database, any_database, table, any_table);
});
}
}
bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
@ -19,65 +68,105 @@ bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expe
if (!ParserKeyword{"SHOW CREATE"}.ignore(pos, expected)) if (!ParserKeyword{"SHOW CREATE"}.ignore(pos, expected))
return false; return false;
std::optional<EntityType> type; EntityType type;
for (auto type_i : ext::range(EntityType::MAX)) bool plural;
{ if (!parseEntityType(pos, expected, type, plural))
const auto & type_info = EntityTypeInfo::get(type_i);
if (ParserKeyword{type_info.name.c_str()}.ignore(pos, expected)
|| (!type_info.alias.empty() && ParserKeyword{type_info.alias.c_str()}.ignore(pos, expected)))
{
type = type_i;
}
}
if (!type)
return false; return false;
String name; Strings names;
std::shared_ptr<ASTRowPolicyNames> row_policy_names;
bool all = false;
bool current_quota = false; bool current_quota = false;
bool current_user = false; bool current_user = false;
RowPolicy::NameParts row_policy_name_parts; String short_name;
std::optional<std::pair<String, String>> database_and_table_name;
if (type == EntityType::USER) switch (type)
{ {
if (!parseUserNameOrCurrentUserTag(pos, expected, name, current_user)) case EntityType::USER:
current_user = true;
}
else if (type == EntityType::ROLE)
{
if (!parseRoleName(pos, expected, name))
return false;
}
else if (type == EntityType::ROW_POLICY)
{
String & database = row_policy_name_parts.database;
String & table_name = row_policy_name_parts.table_name;
String & short_name = row_policy_name_parts.short_name;
if (!parseIdentifierOrStringLiteral(pos, expected, short_name) || !ParserKeyword{"ON"}.ignore(pos, expected)
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
return false;
}
else if (type == EntityType::QUOTA)
{
if (!parseIdentifierOrStringLiteral(pos, expected, name))
{ {
/// SHOW CREATE QUOTA if (parseCurrentUserTag(pos, expected))
current_quota = true; current_user = true;
else if (parseUserNames(pos, expected, names))
{
}
else if (plural)
all = true;
else
current_user = true;
break;
} }
} case EntityType::ROLE:
else if (type == EntityType::SETTINGS_PROFILE) {
{ if (parseRoleNames(pos, expected, names))
if (!parseIdentifierOrStringLiteral(pos, expected, name)) {
return false; }
else if (plural)
all = true;
else
return false;
break;
}
case EntityType::ROW_POLICY:
{
ASTPtr ast;
String database, table_name;
bool any_database, any_table;
if (ParserRowPolicyNames{}.parse(pos, ast, expected))
row_policy_names = typeid_cast<std::shared_ptr<ASTRowPolicyNames>>(ast);
else if (parseOnDBAndTableName(pos, expected, database, any_database, table_name, any_table))
{
if (any_database)
all = true;
else
database_and_table_name.emplace(database, table_name);
}
else if (parseIdentifierOrStringLiteral(pos, expected, short_name))
{
}
else if (plural)
all = true;
else
return false;
break;
}
case EntityType::SETTINGS_PROFILE:
{
if (parseIdentifiersOrStringLiterals(pos, expected, names))
{
}
else if (plural)
all = true;
else
return false;
break;
}
case EntityType::QUOTA:
{
if (parseIdentifiersOrStringLiterals(pos, expected, names))
{
}
else if (plural)
all = true;
else
current_quota = true;
break;
}
case EntityType::MAX:
throw Exception("Type " + toString(type) + " is not implemented in SHOW CREATE query", ErrorCodes::NOT_IMPLEMENTED);
} }
auto query = std::make_shared<ASTShowCreateAccessEntityQuery>(); auto query = std::make_shared<ASTShowCreateAccessEntityQuery>();
node = query; node = query;
query->type = *type; query->type = type;
query->name = std::move(name); query->names = std::move(names);
query->current_quota = current_quota; query->current_quota = current_quota;
query->current_user = current_user; query->current_user = current_user;
query->row_policy_name_parts = std::move(row_policy_name_parts); query->row_policy_names = std::move(row_policy_names);
query->all = all;
query->short_name = std::move(short_name);
query->database_and_table_name = std::move(database_and_table_name);
return true; return true;
} }

View File

@ -6,7 +6,16 @@
namespace DB namespace DB
{ {
/** Parses queries like /** Parses queries like
* SHOW CREATE USER [name | CURRENT_USER]
* SHOW CREATE USERS [name [, name2 ...]
* SHOW CREATE ROLE name
* SHOW CREATE ROLES [name [, name2 ...]]
* SHOW CREATE [SETTINGS] PROFILE name
* SHOW CREATE [SETTINGS] PROFILES [name [, name2 ...]]
* SHOW CREATE [ROW] POLICY name ON [database.]table
* SHOW CREATE [ROW] POLICIES [name ON [database.]table [, name2 ON database2.table2 ...] | name | ON database.table]
* SHOW CREATE QUOTA [name] * SHOW CREATE QUOTA [name]
* SHOW CREATE QUOTAS [name [, name2 ...]]
*/ */
class ParserShowCreateAccessEntityQuery : public IParserBase class ParserShowCreateAccessEntityQuery : public IParserBase
{ {

View File

@ -1,4 +1,6 @@
#include <Parsers/ParserShowGrantsQuery.h> #include <Parsers/ParserShowGrantsQuery.h>
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ASTShowGrantsQuery.h> #include <Parsers/ASTShowGrantsQuery.h>
#include <Parsers/CommonParsers.h> #include <Parsers/CommonParsers.h>
#include <Parsers/parseUserName.h> #include <Parsers/parseUserName.h>
@ -11,23 +13,28 @@ bool ParserShowGrantsQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
if (!ParserKeyword{"SHOW GRANTS"}.ignore(pos, expected)) if (!ParserKeyword{"SHOW GRANTS"}.ignore(pos, expected))
return false; return false;
String name; std::shared_ptr<ASTRolesOrUsersSet> for_roles;
bool current_user = false;
if (ParserKeyword{"FOR"}.ignore(pos, expected)) if (ParserKeyword{"FOR"}.ignore(pos, expected))
{ {
if (!parseUserNameOrCurrentUserTag(pos, expected, name, current_user)) ASTPtr for_roles_ast;
ParserRolesOrUsersSet for_roles_p;
for_roles_p.allowUserNames().allowRoleNames().allowAll().allowCurrentUser();
if (!for_roles_p.parse(pos, for_roles_ast, expected))
return false; return false;
for_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(for_roles_ast);
} }
else else
current_user = true; {
for_roles = std::make_shared<ASTRolesOrUsersSet>();
for_roles->current_user = true;
}
auto query = std::make_shared<ASTShowGrantsQuery>(); auto query = std::make_shared<ASTShowGrantsQuery>();
query->for_roles = std::move(for_roles);
node = query; node = query;
query->name = name;
query->current_user = current_user;
return true; return true;
} }
} }

View File

@ -0,0 +1,77 @@
#include <Parsers/ParserUserNameWithHost.h>
#include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseIdentifierOrStringLiteral.h>
#include <boost/algorithm/string.hpp>
namespace DB
{
namespace
{
bool parseUserNameWithHost(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTUserNameWithHost> & ast)
{
return IParserBase::wrapParseImpl(pos, [&]
{
String base_name;
if (!parseIdentifierOrStringLiteral(pos, expected, base_name))
return false;
boost::algorithm::trim(base_name);
String host_pattern;
if (ParserToken{TokenType::At}.ignore(pos, expected))
{
if (!parseIdentifierOrStringLiteral(pos, expected, host_pattern))
return false;
boost::algorithm::trim(host_pattern);
if (host_pattern == "%")
host_pattern.clear();
}
ast = std::make_shared<ASTUserNameWithHost>();
ast->base_name = std::move(base_name);
ast->host_pattern = std::move(host_pattern);
return true;
});
}
}
bool ParserUserNameWithHost::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::shared_ptr<ASTUserNameWithHost> res;
if (!parseUserNameWithHost(pos, expected, res))
return false;
node = res;
return true;
}
bool ParserUserNamesWithHost::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::vector<std::shared_ptr<ASTUserNameWithHost>> names;
auto parse_single_name = [&]
{
std::shared_ptr<ASTUserNameWithHost> ast;
if (!parseUserNameWithHost(pos, expected, ast))
return false;
names.emplace_back(std::move(ast));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_single_name, false))
return false;
auto result = std::make_shared<ASTUserNamesWithHost>();
result->names = std::move(names);
node = result;
return true;
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Parsers/IParserBase.h>
namespace DB
{
/** Parses a user name.
* It can be a simple string or identifier or something like `name@host`.
*/
class ParserUserNameWithHost : public IParserBase
{
protected:
const char * getName() const override { return "UserNameWithHost"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
class ParserUserNamesWithHost : public IParserBase
{
protected:
const char * getName() const override { return "UserNamesWithHost"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};
}

View File

@ -41,4 +41,74 @@ bool parseDatabaseAndTableName(IParser::Pos & pos, Expected & expected, String &
return true; return true;
} }
bool parseDatabaseAndTableNameOrAsterisks(IParser::Pos & pos, Expected & expected, String & database, bool & any_database, String & table, bool & any_table)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected))
{
auto pos_before_dot = pos;
if (ParserToken{TokenType::Dot}.ignore(pos, expected)
&& ParserToken{TokenType::Asterisk}.ignore(pos, expected))
{
/// *.*
any_database = true;
database.clear();
any_table = true;
table.clear();
return true;
}
/// *
pos = pos_before_dot;
any_database = false;
database.clear();
any_table = true;
table.clear();
return true;
}
ASTPtr ast;
ParserIdentifier identifier_parser;
if (identifier_parser.parse(pos, ast, expected))
{
String first_identifier = getIdentifierName(ast);
auto pos_before_dot = pos;
if (ParserToken{TokenType::Dot}.ignore(pos, expected))
{
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected))
{
/// db.*
any_database = false;
database = std::move(first_identifier);
any_table = true;
table.clear();
return true;
}
else if (identifier_parser.parse(pos, ast, expected))
{
/// db.table
any_database = false;
database = std::move(first_identifier);
any_table = false;
table = getIdentifierName(ast);
return true;
}
}
/// table
pos = pos_before_dot;
any_database = false;
database.clear();
any_table = false;
table = std::move(first_identifier);
return true;
}
return false;
});
}
} }

View File

@ -4,7 +4,10 @@
namespace DB namespace DB
{ {
/// Parses [db].name /// Parses [db.]name
bool parseDatabaseAndTableName(IParser::Pos & pos, Expected & expected, String & database_str, String & table_str); bool parseDatabaseAndTableName(IParser::Pos & pos, Expected & expected, String & database_str, String & table_str);
/// Parses [db.]name or [db.]* or [*.]*
bool parseDatabaseAndTableNameOrAsterisks(IParser::Pos & pos, Expected & expected, String & database, bool & any_database, String & table, bool & any_table);
} }

View File

@ -3,25 +3,52 @@
#include "ExpressionElementParsers.h" #include "ExpressionElementParsers.h"
#include "ASTLiteral.h" #include "ASTLiteral.h"
#include "ASTIdentifier.h" #include "ASTIdentifier.h"
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Common/typeid_cast.h> #include <Common/typeid_cast.h>
namespace DB namespace DB
{ {
bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result) bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result)
{ {
ASTPtr res; return IParserBase::wrapParseImpl(pos, [&]
if (!ParserIdentifier().parse(pos, res, expected))
{ {
if (!ParserStringLiteral().parse(pos, res, expected)) ASTPtr ast;
if (ParserIdentifier().parse(pos, ast, expected))
{
result = getIdentifierName(ast);
return true;
}
if (ParserStringLiteral().parse(pos, ast, expected))
{
result = ast->as<ASTLiteral &>().value.safeGet<String>();
return true;
}
return false;
});
}
bool parseIdentifiersOrStringLiterals(IParser::Pos & pos, Expected & expected, Strings & result)
{
Strings res;
auto parse_single_id_or_literal = [&]
{
String str;
if (!parseIdentifierOrStringLiteral(pos, expected, str))
return false; return false;
result = res->as<ASTLiteral &>().value.safeGet<String>(); res.emplace_back(std::move(str));
} return true;
else };
result = getIdentifierName(res);
if (!ParserList::parseUtil(pos, expected, parse_single_id_or_literal, false))
return false;
result = std::move(res);
return true; return true;
} }

View File

@ -9,4 +9,7 @@ namespace DB
* name, `name` or 'name' */ * name, `name` or 'name' */
bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result); bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result);
/** Parse a list of identifiers or string literals. */
bool parseIdentifiersOrStringLiterals(IParser::Pos & pos, Expected & expected, Strings & result);
} }

Some files were not shown because too many files have changed in this diff Show More