mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Merge pull request #11670 from vitlibar/rbac-improve-parser-multiple-entities
RBAC: improve syntax
This commit is contained in:
commit
7011401cd4
@ -64,19 +64,23 @@ namespace
|
||||
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
|
||||
{
|
||||
if (ParserCreateUserQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
if (ParserCreateRoleQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
if (ParserCreateRowPolicyQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
if (ParserCreateQuotaQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
if (ParserCreateSettingsProfileQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
if (ParserGrantQuery{}.enableAttachMode(true).parse(pos, node, expected))
|
||||
return true;
|
||||
return false;
|
||||
ParserCreateUserQuery create_user_p;
|
||||
ParserCreateRoleQuery create_role_p;
|
||||
ParserCreateRowPolicyQuery create_policy_p;
|
||||
ParserCreateQuotaQuery create_quota_p;
|
||||
ParserCreateSettingsProfileQuery create_profile_p;
|
||||
ParserGrantQuery grant_p;
|
||||
|
||||
create_user_p.useAttachMode();
|
||||
create_role_p.useAttachMode();
|
||||
create_policy_p.useAttachMode();
|
||||
create_quota_p.useAttachMode();
|
||||
create_profile_p.useAttachMode();
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -45,11 +45,13 @@ struct IAccessEntity
|
||||
struct TypeInfo
|
||||
{
|
||||
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 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 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;
|
||||
|
||||
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 == 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:
|
||||
String name;
|
||||
|
||||
@ -87,44 +101,49 @@ using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
|
||||
|
||||
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_;
|
||||
boost::to_upper(init_name);
|
||||
boost::replace_all(init_name, "_", " ");
|
||||
String init_alias;
|
||||
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_name;
|
||||
String init_names[2] = {raw_name_, plural_raw_name_};
|
||||
String init_aliases[2];
|
||||
for (size_t i = 0; i != std::size(init_names); ++i)
|
||||
{
|
||||
String & init_name = init_names[i];
|
||||
String & init_alias = init_aliases[i];
|
||||
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);
|
||||
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_)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case Type::MAX: break;
|
||||
|
@ -24,16 +24,141 @@ namespace
|
||||
using EntityType = IAccessStorage::EntityType;
|
||||
using EntityTypeInfo = IAccessStorage::EntityTypeInfo;
|
||||
|
||||
bool isNotFoundErrorCode(int error_code)
|
||||
|
||||
String outputID(const UUID & id)
|
||||
{
|
||||
if (error_code == ErrorCodes::ACCESS_ENTITY_NOT_FOUND)
|
||||
return true;
|
||||
return "ID(" + toString(id) + ")";
|
||||
}
|
||||
|
||||
for (auto type : ext::range(EntityType::MAX))
|
||||
if (error_code == EntityTypeInfo::get(type).not_found_error_code)
|
||||
return true;
|
||||
String outputTypeAndNameOrID(const IAccessStorage & storage, const UUID & id)
|
||||
{
|
||||
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
|
||||
{
|
||||
try
|
||||
{
|
||||
return readImpl(id);
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return doTry([&] { return readImpl(id); });
|
||||
}
|
||||
|
||||
|
||||
@ -110,14 +228,7 @@ String IAccessStorage::readName(const UUID & id) const
|
||||
|
||||
std::optional<String> IAccessStorage::tryReadName(const UUID & id) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return readNameImpl(id);
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return doTry([&] { return std::optional<String>{readNameImpl(id)}; });
|
||||
}
|
||||
|
||||
|
||||
@ -129,56 +240,25 @@ UUID IAccessStorage::insert(const AccessEntityPtr & entity)
|
||||
|
||||
std::vector<UUID> IAccessStorage::insert(const std::vector<AccessEntityPtr> & multiple_entities)
|
||||
{
|
||||
std::vector<UUID> ids;
|
||||
ids.reserve(multiple_entities.size());
|
||||
String error_message;
|
||||
for (const auto & entity : multiple_entities)
|
||||
{
|
||||
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;
|
||||
return applyToMultipleEntities</* ignore_errors = */ false>(
|
||||
multiple_entities,
|
||||
[this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ false); },
|
||||
"Couldn't insert {failed_names}. Successfully inserted: {succeeded_names}",
|
||||
[](const AccessEntityPtr & entity) { return entity->outputTypeAndName(); });
|
||||
}
|
||||
|
||||
|
||||
std::optional<UUID> IAccessStorage::tryInsert(const AccessEntityPtr & entity)
|
||||
{
|
||||
try
|
||||
{
|
||||
return insertImpl(entity, false);
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return doTry([&] { return std::optional<UUID>{insertImpl(entity, false)}; });
|
||||
}
|
||||
|
||||
|
||||
std::vector<UUID> IAccessStorage::tryInsert(const std::vector<AccessEntityPtr> & multiple_entities)
|
||||
{
|
||||
std::vector<UUID> ids;
|
||||
ids.reserve(multiple_entities.size());
|
||||
for (const auto & entity : multiple_entities)
|
||||
{
|
||||
try
|
||||
{
|
||||
ids.push_back(insertImpl(entity, false));
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
return applyToMultipleEntities</* ignore_errors = */ true>(
|
||||
multiple_entities,
|
||||
[this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ false); });
|
||||
}
|
||||
|
||||
|
||||
@ -190,11 +270,11 @@ UUID IAccessStorage::insertOrReplace(const AccessEntityPtr & entity)
|
||||
|
||||
std::vector<UUID> IAccessStorage::insertOrReplace(const std::vector<AccessEntityPtr> & multiple_entities)
|
||||
{
|
||||
std::vector<UUID> ids;
|
||||
ids.reserve(multiple_entities.size());
|
||||
for (const auto & entity : multiple_entities)
|
||||
ids.push_back(insertImpl(entity, true));
|
||||
return ids;
|
||||
return applyToMultipleEntities</* ignore_errors = */ false>(
|
||||
multiple_entities,
|
||||
[this](const AccessEntityPtr & entity) { return insertImpl(entity, /* replace_if_exists = */ true); },
|
||||
"Couldn't insert {failed_names}. Successfully inserted: {succeeded_names}",
|
||||
[](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)
|
||||
{
|
||||
String error_message;
|
||||
std::optional<int> error_code;
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
applyToMultipleEntities</* ignore_errors = */ false>(
|
||||
ids,
|
||||
[this](const UUID & id) { removeImpl(id); },
|
||||
"Couldn't remove {failed_names}. Successfully removed: {succeeded_names}",
|
||||
[this](const UUID & id) { return outputTypeAndNameOrID(*this, id); });
|
||||
}
|
||||
|
||||
|
||||
bool IAccessStorage::tryRemove(const UUID & id)
|
||||
{
|
||||
try
|
||||
{
|
||||
removeImpl(id);
|
||||
return true;
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return doTry([&] { removeImpl(id); return true; });
|
||||
}
|
||||
|
||||
|
||||
std::vector<UUID> IAccessStorage::tryRemove(const std::vector<UUID> & ids)
|
||||
{
|
||||
std::vector<UUID> removed;
|
||||
removed.reserve(ids.size());
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
removeImpl(id);
|
||||
removed.push_back(id);
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
return applyToMultipleEntities</* ignore_errors = */ true>(
|
||||
ids,
|
||||
[this](const UUID & id) { removeImpl(id); return id; });
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
String error_message;
|
||||
std::optional<int> error_code;
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
applyToMultipleEntities</* ignore_errors = */ false>(
|
||||
ids,
|
||||
[this, &update_func](const UUID & id) { updateImpl(id, update_func); },
|
||||
"Couldn't update {failed_names}. Successfully updated: {succeeded_names}",
|
||||
[this](const UUID & id) { return outputTypeAndNameOrID(*this, id); });
|
||||
}
|
||||
|
||||
|
||||
bool IAccessStorage::tryUpdate(const UUID & id, const UpdateFunc & update_func)
|
||||
{
|
||||
try
|
||||
{
|
||||
updateImpl(id, update_func);
|
||||
return true;
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return doTry([&] { updateImpl(id, update_func); return true; });
|
||||
}
|
||||
|
||||
|
||||
std::vector<UUID> IAccessStorage::tryUpdate(const std::vector<UUID> & ids, const UpdateFunc & update_func)
|
||||
{
|
||||
std::vector<UUID> updated;
|
||||
updated.reserve(ids.size());
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
updateImpl(id, update_func);
|
||||
updated.push_back(id);
|
||||
}
|
||||
catch (Exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
return applyToMultipleEntities</* ignore_errors = */ true>(
|
||||
ids,
|
||||
[this, &update_func](const UUID & id) { updateImpl(id, update_func); return id; });
|
||||
}
|
||||
|
||||
|
||||
@ -388,7 +398,7 @@ Poco::Logger * IAccessStorage::getLogger() 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
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() + "]",
|
||||
ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#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 <chrono>
|
||||
|
||||
@ -84,14 +86,15 @@ struct Quota : public IAccessEntity
|
||||
struct KeyTypeInfo
|
||||
{
|
||||
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);
|
||||
};
|
||||
|
||||
KeyType key_type = KeyType::NONE;
|
||||
|
||||
/// Which roles or users should use this quota.
|
||||
ExtendedRoleSet to_roles;
|
||||
RolesOrUsersSet to_roles;
|
||||
|
||||
bool equal(const IAccessEntity & other) const override;
|
||||
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_;
|
||||
boost::to_lower(init_name);
|
||||
boost::replace_all(init_name, "_", " ");
|
||||
return KeyTypeInfo{raw_name_, std::move(init_name)};
|
||||
std::vector<KeyType> init_base_types;
|
||||
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)
|
||||
|
@ -39,7 +39,7 @@ private:
|
||||
|
||||
QuotaPtr quota;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/Role.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
@ -20,51 +19,51 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet() = default;
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ExtendedRoleSet & src) = default;
|
||||
ExtendedRoleSet & ExtendedRoleSet::operator =(const ExtendedRoleSet & src) = default;
|
||||
ExtendedRoleSet::ExtendedRoleSet(ExtendedRoleSet && src) = default;
|
||||
ExtendedRoleSet & ExtendedRoleSet::operator =(ExtendedRoleSet && src) = default;
|
||||
RolesOrUsersSet::RolesOrUsersSet() = default;
|
||||
RolesOrUsersSet::RolesOrUsersSet(const RolesOrUsersSet & src) = default;
|
||||
RolesOrUsersSet & RolesOrUsersSet::operator =(const RolesOrUsersSet & src) = default;
|
||||
RolesOrUsersSet::RolesOrUsersSet(RolesOrUsersSet && src) = default;
|
||||
RolesOrUsersSet & RolesOrUsersSet::operator =(RolesOrUsersSet && src) = default;
|
||||
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(AllTag)
|
||||
RolesOrUsersSet::RolesOrUsersSet(AllTag)
|
||||
{
|
||||
all = true;
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const UUID & id)
|
||||
RolesOrUsersSet::RolesOrUsersSet(const UUID & id)
|
||||
{
|
||||
add(id);
|
||||
}
|
||||
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const std::vector<UUID> & ids_)
|
||||
RolesOrUsersSet::RolesOrUsersSet(const std::vector<UUID> & ids_)
|
||||
{
|
||||
add(ids_);
|
||||
}
|
||||
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast)
|
||||
RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager)
|
||||
RolesOrUsersSet::RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -73,20 +72,20 @@ void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlMa
|
||||
if (ast.id_mode)
|
||||
return parse<UUID>(name);
|
||||
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);
|
||||
if (id)
|
||||
return *id;
|
||||
return manager->getID<Role>(name);
|
||||
}
|
||||
else if (ast.can_contain_users)
|
||||
else if (ast.allow_user_names)
|
||||
{
|
||||
return manager->getID<User>(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(ast.can_contain_roles);
|
||||
assert(ast.allow_role_names);
|
||||
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->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;
|
||||
|
||||
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();
|
||||
return serializeAST(*ast);
|
||||
}
|
||||
|
||||
|
||||
String ExtendedRoleSet::toStringWithNames(const AccessControlManager & manager) const
|
||||
String RolesOrUsersSet::toStringWithNames(const AccessControlManager & manager) const
|
||||
{
|
||||
auto ast = toASTWithNames(manager);
|
||||
return serializeAST(*ast);
|
||||
}
|
||||
|
||||
|
||||
Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager) const
|
||||
Strings RolesOrUsersSet::toStringsWithNames(const AccessControlManager & manager) const
|
||||
{
|
||||
if (!all && ids.empty())
|
||||
return {};
|
||||
@ -233,13 +232,13 @@ Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager
|
||||
}
|
||||
|
||||
|
||||
bool ExtendedRoleSet::empty() const
|
||||
bool RolesOrUsersSet::empty() const
|
||||
{
|
||||
return ids.empty() && !all;
|
||||
}
|
||||
|
||||
|
||||
void ExtendedRoleSet::clear()
|
||||
void RolesOrUsersSet::clear()
|
||||
{
|
||||
ids.clear();
|
||||
all = false;
|
||||
@ -247,26 +246,26 @@ void ExtendedRoleSet::clear()
|
||||
}
|
||||
|
||||
|
||||
void ExtendedRoleSet::add(const UUID & id)
|
||||
void RolesOrUsersSet::add(const UUID & 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_)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
{
|
||||
@ -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)
|
||||
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)
|
||||
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);
|
||||
}
|
@ -8,35 +8,35 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRolesOrUsersSet;
|
||||
class AccessControlManager;
|
||||
|
||||
|
||||
/// Represents a set of users/roles like
|
||||
/// {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.
|
||||
struct ExtendedRoleSet
|
||||
/// Similar to ASTRolesOrUsersSet, but with IDs instead of names.
|
||||
struct RolesOrUsersSet
|
||||
{
|
||||
ExtendedRoleSet();
|
||||
ExtendedRoleSet(const ExtendedRoleSet & src);
|
||||
ExtendedRoleSet & operator =(const ExtendedRoleSet & src);
|
||||
ExtendedRoleSet(ExtendedRoleSet && src);
|
||||
ExtendedRoleSet & operator =(ExtendedRoleSet && src);
|
||||
RolesOrUsersSet();
|
||||
RolesOrUsersSet(const RolesOrUsersSet & src);
|
||||
RolesOrUsersSet & operator =(const RolesOrUsersSet & src);
|
||||
RolesOrUsersSet(RolesOrUsersSet && src);
|
||||
RolesOrUsersSet & operator =(RolesOrUsersSet && src);
|
||||
|
||||
struct AllTag {};
|
||||
ExtendedRoleSet(AllTag);
|
||||
RolesOrUsersSet(AllTag);
|
||||
|
||||
ExtendedRoleSet(const UUID & id);
|
||||
ExtendedRoleSet(const std::vector<UUID> & ids_);
|
||||
RolesOrUsersSet(const UUID & id);
|
||||
RolesOrUsersSet(const std::vector<UUID> & ids_);
|
||||
|
||||
/// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`.
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
|
||||
RolesOrUsersSet(const ASTRolesOrUsersSet & ast);
|
||||
RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const std::optional<UUID> & current_user_id);
|
||||
RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager);
|
||||
RolesOrUsersSet(const ASTRolesOrUsersSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> toAST() const;
|
||||
std::shared_ptr<ASTExtendedRoleSet> toASTWithNames(const AccessControlManager & manager) const;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> toAST() const;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> toASTWithNames(const AccessControlManager & manager) const;
|
||||
|
||||
String toString() const;
|
||||
String toStringWithNames(const AccessControlManager & manager) const;
|
||||
@ -47,7 +47,7 @@ struct ExtendedRoleSet
|
||||
void add(const UUID & id);
|
||||
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 & 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.
|
||||
std::vector<UUID> getMatchingIDs(const AccessControlManager & manager) const;
|
||||
|
||||
friend bool operator ==(const ExtendedRoleSet & lhs, const ExtendedRoleSet & rhs);
|
||||
friend bool operator !=(const ExtendedRoleSet & lhs, const ExtendedRoleSet & rhs) { return !(lhs == rhs); }
|
||||
friend bool operator ==(const RolesOrUsersSet & lhs, const RolesOrUsersSet & rhs);
|
||||
friend bool operator !=(const RolesOrUsersSet & lhs, const RolesOrUsersSet & rhs) { return !(lhs == rhs); }
|
||||
|
||||
boost::container::flat_set<UUID> ids;
|
||||
bool all = false;
|
||||
boost::container::flat_set<UUID> except_ids;
|
||||
|
||||
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 = {});
|
||||
};
|
||||
|
||||
}
|
@ -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)
|
||||
{
|
||||
name_parts.database = database;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Access/IAccessEntity.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <array>
|
||||
|
||||
|
||||
@ -23,7 +23,9 @@ struct RowPolicy : public IAccessEntity
|
||||
String database;
|
||||
String table_name;
|
||||
|
||||
bool empty() const { return short_name.empty(); }
|
||||
String getName() const;
|
||||
String toString() const { return getName(); }
|
||||
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(); }
|
||||
@ -89,7 +91,7 @@ struct RowPolicy : public IAccessEntity
|
||||
Type getType() const override { return TYPE; }
|
||||
|
||||
/// Which roles or users should use this row policy.
|
||||
ExtendedRoleSet to_roles;
|
||||
RolesOrUsersSet to_roles;
|
||||
|
||||
private:
|
||||
void setName(const String & name_) override;
|
||||
@ -153,4 +155,20 @@ inline String toString(RowPolicy::ConditionType type)
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ private:
|
||||
void setPolicy(const RowPolicyPtr & policy_);
|
||||
|
||||
RowPolicyPtr policy;
|
||||
const ExtendedRoleSet * roles = nullptr;
|
||||
const RolesOrUsersSet * roles = nullptr;
|
||||
std::shared_ptr<const std::pair<String, String>> database_and_table_name;
|
||||
ASTPtr parsed_conditions[RowPolicy::MAX_CONDITION_TYPE];
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Access/IAccessEntity.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/SettingsProfileElement.h>
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ struct SettingsProfile : public IAccessEntity
|
||||
SettingsProfileElements elements;
|
||||
|
||||
/// Which roles or users should use this settings profile.
|
||||
ExtendedRoleSet to_roles;
|
||||
RolesOrUsersSet to_roles;
|
||||
|
||||
bool equal(const IAccessEntity & other) const override;
|
||||
std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<SettingsProfile>(); }
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <Access/AllowedClientHosts.h>
|
||||
#include <Access/GrantedAccess.h>
|
||||
#include <Access/GrantedRoles.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/SettingsProfileElement.h>
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ struct User : public IAccessEntity
|
||||
AllowedClientHosts allowed_client_hosts = AllowedClientHosts::AnyHostTag{};
|
||||
GrantedAccess access;
|
||||
GrantedRoles granted_roles;
|
||||
ExtendedRoleSet default_roles = ExtendedRoleSet::AllTag{};
|
||||
RolesOrUsersSet default_roles = RolesOrUsersSet::AllTag{};
|
||||
SettingsProfileElements settings;
|
||||
|
||||
bool equal(const IAccessEntity & other) const override;
|
||||
|
@ -17,7 +17,6 @@ SRCS(
|
||||
EnabledRolesInfo.cpp
|
||||
EnabledRowPolicies.cpp
|
||||
EnabledSettings.cpp
|
||||
ExtendedRoleSet.cpp
|
||||
GrantedAccess.cpp
|
||||
GrantedRoles.cpp
|
||||
IAccessEntity.cpp
|
||||
@ -29,6 +28,7 @@ SRCS(
|
||||
QuotaUsage.cpp
|
||||
Role.cpp
|
||||
RoleCache.cpp
|
||||
RolesOrUsersSet.cpp
|
||||
RowPolicy.cpp
|
||||
RowPolicyCache.cpp
|
||||
SettingsConstraints.cpp
|
||||
|
@ -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
|
||||
{
|
||||
switch (kind)
|
||||
|
@ -37,6 +37,8 @@ struct IntervalKind
|
||||
/// Returns an uppercased version of what `toString()` returns.
|
||||
const char * toKeyword() const;
|
||||
|
||||
const char * toLowercasedKeyword() const;
|
||||
|
||||
/// Returns the string which can be passed to the `unit` parameter of the dateDiff() function.
|
||||
/// For example, `IntervalKind{IntervalKind::Day}.getDateDiffParameter()` returns "day".
|
||||
const char * toDateDiffUnit() const;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <Interpreters/InterpreterCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
@ -15,15 +15,18 @@ namespace DB
|
||||
{
|
||||
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 (!query.new_name.empty())
|
||||
quota.setName(query.new_name);
|
||||
}
|
||||
else
|
||||
quota.setName(query.name);
|
||||
if (!override_name.empty())
|
||||
quota.setName(override_name);
|
||||
else if (!query.new_name.empty())
|
||||
quota.setName(query.new_name);
|
||||
else if (query.names.size() == 1)
|
||||
quota.setName(query.names.front());
|
||||
|
||||
if (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];
|
||||
}
|
||||
|
||||
const ExtendedRoleSet * roles = nullptr;
|
||||
std::optional<ExtendedRoleSet> temp_role_set;
|
||||
if (roles_from_query)
|
||||
roles = &*roles_from_query;
|
||||
if (override_to_roles)
|
||||
quota.to_roles = *override_to_roles;
|
||||
else if (query.roles)
|
||||
roles = &temp_role_set.emplace(*query.roles);
|
||||
|
||||
if (roles)
|
||||
quota.to_roles = *roles;
|
||||
quota.to_roles = *query.roles;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,37 +82,42 @@ BlockIO InterpreterCreateQuotaQuery::execute()
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
std::optional<RolesOrUsersSet> roles_from_query;
|
||||
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)
|
||||
{
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
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;
|
||||
};
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<Quota>(query.name))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
auto ids = access_control.find<Quota>(query.names);
|
||||
access_control.tryUpdate(ids, update_func);
|
||||
}
|
||||
else
|
||||
access_control.update(access_control.getID<Quota>(query.name), update_func);
|
||||
access_control.update(access_control.getIDs<Quota>(query.names), update_func);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_quota = std::make_shared<Quota>();
|
||||
updateQuotaFromQueryImpl(*new_quota, query, roles_from_query);
|
||||
std::vector<AccessEntityPtr> new_quotas;
|
||||
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)
|
||||
access_control.tryInsert(new_quota);
|
||||
access_control.tryInsert(new_quotas);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_quota);
|
||||
access_control.insertOrReplace(new_quotas);
|
||||
else
|
||||
access_control.insert(new_quota);
|
||||
access_control.insert(new_quotas);
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -123,7 +126,7 @@ BlockIO InterpreterCreateQuotaQuery::execute()
|
||||
|
||||
void InterpreterCreateQuotaQuery::updateQuotaFromQuery(Quota & quota, const ASTCreateQuotaQuery & query)
|
||||
{
|
||||
updateQuotaFromQueryImpl(quota, query);
|
||||
updateQuotaFromQueryImpl(quota, query, {}, {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,25 +13,20 @@ namespace
|
||||
void updateRoleFromQueryImpl(
|
||||
Role & role,
|
||||
const ASTCreateRoleQuery & query,
|
||||
const std::optional<SettingsProfileElements> & settings_from_query = {})
|
||||
const String & override_name,
|
||||
const std::optional<SettingsProfileElements> & override_settings)
|
||||
{
|
||||
if (query.alter)
|
||||
{
|
||||
if (!query.new_name.empty())
|
||||
role.setName(query.new_name);
|
||||
}
|
||||
else
|
||||
role.setName(query.name);
|
||||
if (!override_name.empty())
|
||||
role.setName(override_name);
|
||||
else if (!query.new_name.empty())
|
||||
role.setName(query.new_name);
|
||||
else if (query.names.size() == 1)
|
||||
role.setName(query.names.front());
|
||||
|
||||
const SettingsProfileElements * settings = nullptr;
|
||||
std::optional<SettingsProfileElements> temp_settings;
|
||||
if (settings_from_query)
|
||||
settings = &*settings_from_query;
|
||||
if (override_settings)
|
||||
role.settings = *override_settings;
|
||||
else if (query.settings)
|
||||
settings = &temp_settings.emplace(*query.settings);
|
||||
|
||||
if (settings)
|
||||
role.settings = *settings;
|
||||
role.settings = *query.settings;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,28 +52,33 @@ BlockIO InterpreterCreateRoleQuery::execute()
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
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;
|
||||
};
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<Role>(query.name))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
auto ids = access_control.find<Role>(query.names);
|
||||
access_control.tryUpdate(ids, update_func);
|
||||
}
|
||||
else
|
||||
access_control.update(access_control.getID<Role>(query.name), update_func);
|
||||
access_control.update(access_control.getIDs<Role>(query.names), update_func);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_role = std::make_shared<Role>();
|
||||
updateRoleFromQueryImpl(*new_role, query, settings_from_query);
|
||||
std::vector<AccessEntityPtr> new_roles;
|
||||
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)
|
||||
access_control.tryInsert(new_role);
|
||||
access_control.tryInsert(new_roles);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_role);
|
||||
access_control.insertOrReplace(new_roles);
|
||||
else
|
||||
access_control.insert(new_role);
|
||||
access_control.insert(new_roles);
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -87,6 +87,6 @@ BlockIO InterpreterCreateRoleQuery::execute()
|
||||
|
||||
void InterpreterCreateRoleQuery::updateRoleFromQuery(Role & role, const ASTCreateRoleQuery & query)
|
||||
{
|
||||
updateRoleFromQueryImpl(role, query);
|
||||
updateRoleFromQueryImpl(role, query, {}, {});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Interpreters/InterpreterCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
@ -16,35 +17,26 @@ namespace
|
||||
void updateRowPolicyFromQueryImpl(
|
||||
RowPolicy & policy,
|
||||
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 (!query.new_short_name.empty())
|
||||
policy.setShortName(query.new_short_name);
|
||||
}
|
||||
else
|
||||
policy.setNameParts(query.name_parts);
|
||||
if (!override_name.empty())
|
||||
policy.setNameParts(override_name);
|
||||
else if (!query.new_short_name.empty())
|
||||
policy.setShortName(query.new_short_name);
|
||||
else if (query.names->name_parts.size() == 1)
|
||||
policy.setNameParts(query.names->name_parts.front());
|
||||
|
||||
if (query.is_restrictive)
|
||||
policy.setRestrictive(*query.is_restrictive);
|
||||
|
||||
for (auto condition_type : ext::range(RowPolicy::MAX_CONDITION_TYPE))
|
||||
{
|
||||
const auto & condition = query.conditions[condition_type];
|
||||
if (condition)
|
||||
policy.conditions[condition_type] = *condition ? serializeAST(**condition) : String{};
|
||||
}
|
||||
for (const auto & [condition_type, condition] : query.conditions)
|
||||
policy.conditions[condition_type] = condition ? serializeAST(*condition) : String{};
|
||||
|
||||
const ExtendedRoleSet * roles = nullptr;
|
||||
std::optional<ExtendedRoleSet> temp_role_set;
|
||||
if (roles_from_query)
|
||||
roles = &*roles_from_query;
|
||||
if (override_to_roles)
|
||||
policy.to_roles = *override_to_roles;
|
||||
else if (query.roles)
|
||||
roles = &temp_role_set.emplace(*query.roles);
|
||||
|
||||
if (roles)
|
||||
policy.to_roles = *roles;
|
||||
policy.to_roles = *query.roles;
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,40 +53,46 @@ BlockIO InterpreterCreateRowPolicyQuery::execute()
|
||||
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)
|
||||
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.name_parts.database = context.getCurrentDatabase();
|
||||
query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
|
||||
|
||||
if (query.alter)
|
||||
{
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
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;
|
||||
};
|
||||
Strings names = query.names->toStrings();
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<RowPolicy>(query.name_parts.getName()))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
auto ids = access_control.find<RowPolicy>(names);
|
||||
access_control.tryUpdate(ids, update_func);
|
||||
}
|
||||
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
|
||||
{
|
||||
auto new_policy = std::make_shared<RowPolicy>();
|
||||
updateRowPolicyFromQueryImpl(*new_policy, query, roles_from_query);
|
||||
std::vector<AccessEntityPtr> new_policies;
|
||||
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)
|
||||
access_control.tryInsert(new_policy);
|
||||
access_control.tryInsert(new_policies);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_policy);
|
||||
access_control.insertOrReplace(new_policies);
|
||||
else
|
||||
access_control.insert(new_policy);
|
||||
access_control.insert(new_policies);
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -103,7 +101,7 @@ BlockIO InterpreterCreateRowPolicyQuery::execute()
|
||||
|
||||
void InterpreterCreateRowPolicyQuery::updateRowPolicyFromQuery(RowPolicy & policy, const ASTCreateRowPolicyQuery & query)
|
||||
{
|
||||
updateRowPolicyFromQueryImpl(policy, query);
|
||||
updateRowPolicyFromQueryImpl(policy, query, {}, {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <Interpreters/InterpreterCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
@ -15,36 +15,26 @@ namespace
|
||||
void updateSettingsProfileFromQueryImpl(
|
||||
SettingsProfile & profile,
|
||||
const ASTCreateSettingsProfileQuery & query,
|
||||
const std::optional<SettingsProfileElements> & settings_from_query = {},
|
||||
const std::optional<ExtendedRoleSet> & roles_from_query = {})
|
||||
const String & override_name,
|
||||
const std::optional<SettingsProfileElements> & override_settings,
|
||||
const std::optional<RolesOrUsersSet> & override_to_roles)
|
||||
{
|
||||
if (query.alter)
|
||||
{
|
||||
if (!query.new_name.empty())
|
||||
profile.setName(query.new_name);
|
||||
}
|
||||
else
|
||||
profile.setName(query.name);
|
||||
if (!override_name.empty())
|
||||
profile.setName(override_name);
|
||||
else if (!query.new_name.empty())
|
||||
profile.setName(query.new_name);
|
||||
else if (query.names.size() == 1)
|
||||
profile.setName(query.names.front());
|
||||
|
||||
const SettingsProfileElements * settings = nullptr;
|
||||
std::optional<SettingsProfileElements> temp_settings;
|
||||
if (settings_from_query)
|
||||
settings = &*settings_from_query;
|
||||
if (override_settings)
|
||||
profile.elements = *override_settings;
|
||||
else if (query.settings)
|
||||
settings = &temp_settings.emplace(*query.settings);
|
||||
profile.elements = *query.settings;
|
||||
|
||||
if (settings)
|
||||
profile.elements = *settings;
|
||||
|
||||
const ExtendedRoleSet * roles = nullptr;
|
||||
std::optional<ExtendedRoleSet> temp_role_set;
|
||||
if (roles_from_query)
|
||||
roles = &*roles_from_query;
|
||||
if (override_to_roles)
|
||||
profile.to_roles = *override_to_roles;
|
||||
else if (query.to_roles)
|
||||
roles = &temp_role_set.emplace(*query.to_roles);
|
||||
|
||||
if (roles)
|
||||
profile.to_roles = *roles;
|
||||
profile.to_roles = *query.to_roles;
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,37 +58,42 @@ BlockIO InterpreterCreateSettingsProfileQuery::execute()
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
std::optional<RolesOrUsersSet> roles_from_query;
|
||||
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)
|
||||
{
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
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;
|
||||
};
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<SettingsProfile>(query.name))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
auto ids = access_control.find<SettingsProfile>(query.names);
|
||||
access_control.tryUpdate(ids, update_func);
|
||||
}
|
||||
else
|
||||
access_control.update(access_control.getID<SettingsProfile>(query.name), update_func);
|
||||
access_control.update(access_control.getIDs<SettingsProfile>(query.names), update_func);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_profile = std::make_shared<SettingsProfile>();
|
||||
updateSettingsProfileFromQueryImpl(*new_profile, query, settings_from_query, roles_from_query);
|
||||
std::vector<AccessEntityPtr> new_profiles;
|
||||
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)
|
||||
access_control.tryInsert(new_profile);
|
||||
access_control.tryInsert(new_profiles);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_profile);
|
||||
access_control.insertOrReplace(new_profiles);
|
||||
else
|
||||
access_control.insert(new_profile);
|
||||
access_control.insert(new_profiles);
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -107,6 +102,6 @@ BlockIO InterpreterCreateSettingsProfileQuery::execute()
|
||||
|
||||
void InterpreterCreateSettingsProfileQuery::updateSettingsProfileFromQuery(SettingsProfile & SettingsProfile, const ASTCreateSettingsProfileQuery & query)
|
||||
{
|
||||
updateSettingsProfileFromQueryImpl(SettingsProfile, query);
|
||||
updateSettingsProfileFromQueryImpl(SettingsProfile, query, {}, {}, {});
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTUserNameWithHost.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
@ -17,51 +18,50 @@ namespace
|
||||
void updateUserFromQueryImpl(
|
||||
User & user,
|
||||
const ASTCreateUserQuery & query,
|
||||
const std::optional<ExtendedRoleSet> & default_roles_from_query = {},
|
||||
const std::optional<SettingsProfileElements> & settings_from_query = {})
|
||||
const std::shared_ptr<ASTUserNameWithHost> & override_name,
|
||||
const std::optional<RolesOrUsersSet> & override_default_roles,
|
||||
const std::optional<SettingsProfileElements> & override_settings)
|
||||
{
|
||||
if (query.alter)
|
||||
{
|
||||
if (!query.new_name.empty())
|
||||
user.setName(query.new_name);
|
||||
}
|
||||
else
|
||||
user.setName(query.name);
|
||||
if (override_name)
|
||||
user.setName(override_name->toString());
|
||||
else if (!query.new_name.empty())
|
||||
user.setName(query.new_name);
|
||||
else if (query.names->size() == 1)
|
||||
user.setName(query.names->front()->toString());
|
||||
|
||||
if (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;
|
||||
|
||||
if (query.remove_hosts)
|
||||
user.allowed_client_hosts.remove(*query.remove_hosts);
|
||||
if (query.add_hosts)
|
||||
user.allowed_client_hosts.add(*query.add_hosts);
|
||||
|
||||
const ExtendedRoleSet * default_roles = nullptr;
|
||||
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)
|
||||
auto set_default_roles = [&](const RolesOrUsersSet & default_roles_)
|
||||
{
|
||||
if (!query.alter && !default_roles->all)
|
||||
user.granted_roles.grant(default_roles->getMatchingIDs());
|
||||
if (!query.alter && !default_roles_.all)
|
||||
user.granted_roles.grant(default_roles_.getMatchingIDs());
|
||||
|
||||
InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, *default_roles);
|
||||
}
|
||||
InterpreterSetRoleQuery::updateUserSetDefaultRoles(user, default_roles_);
|
||||
};
|
||||
|
||||
const SettingsProfileElements * settings = nullptr;
|
||||
std::optional<SettingsProfileElements> temp_settings;
|
||||
if (settings_from_query)
|
||||
settings = &*settings_from_query;
|
||||
if (override_default_roles)
|
||||
set_default_roles(*override_default_roles);
|
||||
else if (query.default_roles)
|
||||
set_default_roles(*query.default_roles);
|
||||
|
||||
if (override_settings)
|
||||
user.settings = *override_settings;
|
||||
else if (query.settings)
|
||||
settings = &temp_settings.emplace(*query.settings);
|
||||
|
||||
if (settings)
|
||||
user.settings = *settings;
|
||||
user.settings = *query.settings;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,10 +73,10 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
auto access = context.getAccess();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for (const UUID & role : default_roles_from_query->getMatchingIDs())
|
||||
@ -96,28 +96,34 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
{
|
||||
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;
|
||||
};
|
||||
Strings names = query.names->toStrings();
|
||||
if (query.if_exists)
|
||||
{
|
||||
if (auto id = access_control.find<User>(query.name))
|
||||
access_control.tryUpdate(*id, update_func);
|
||||
auto ids = access_control.find<User>(names);
|
||||
access_control.tryUpdate(ids, update_func);
|
||||
}
|
||||
else
|
||||
access_control.update(access_control.getID<User>(query.name), update_func);
|
||||
access_control.update(access_control.getIDs<User>(names), update_func);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_user = std::make_shared<User>();
|
||||
updateUserFromQueryImpl(*new_user, query, default_roles_from_query, settings_from_query);
|
||||
std::vector<AccessEntityPtr> new_users;
|
||||
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)
|
||||
access_control.tryInsert(new_user);
|
||||
access_control.tryInsert(new_users);
|
||||
else if (query.or_replace)
|
||||
access_control.insertOrReplace(new_user);
|
||||
access_control.insertOrReplace(new_users);
|
||||
else
|
||||
access_control.insert(new_user);
|
||||
access_control.insert(new_users);
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -126,7 +132,7 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
|
||||
void InterpreterCreateUserQuery::updateUserFromQuery(User & user, const ASTCreateUserQuery & query)
|
||||
{
|
||||
updateUserFromQueryImpl(user, query);
|
||||
updateUserFromQueryImpl(user, query, {}, {}, {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <Interpreters/InterpreterDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
@ -30,26 +31,21 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
if (query.type == EntityType::ROW_POLICY)
|
||||
{
|
||||
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 {};
|
||||
}
|
||||
query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
|
||||
|
||||
if (query.if_exists)
|
||||
access_control.tryRemove(access_control.find(query.type, query.names));
|
||||
auto do_drop = [&](const Strings & 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
|
||||
access_control.remove(access_control.getIDs(query.type, query.names));
|
||||
do_drop(query.names);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <Parsers/ASTSetQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTShowAccessEntitiesQuery.h>
|
||||
#include <Parsers/ASTShowAccessQuery.h>
|
||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/ASTShowGrantsQuery.h>
|
||||
#include <Parsers/ASTShowPrivilegesQuery.h>
|
||||
@ -51,6 +52,7 @@
|
||||
#include <Interpreters/InterpreterSetQuery.h>
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Interpreters/InterpreterShowAccessEntitiesQuery.h>
|
||||
#include <Interpreters/InterpreterShowAccessQuery.h>
|
||||
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
|
||||
#include <Interpreters/InterpreterShowGrantsQuery.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);
|
||||
}
|
||||
else if (query->as<ASTShowAccessQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterShowAccessQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTShowPrivilegesQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterShowPrivilegesQuery>(query, context);
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include <Interpreters/InterpreterGrantQuery.h>
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/Role.h>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
@ -74,7 +74,7 @@ BlockIO InterpreterGrantQuery::execute()
|
||||
std::vector<UUID> roles_from_query;
|
||||
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)
|
||||
access->checkAdminOption(role_from_query);
|
||||
}
|
||||
@ -85,7 +85,7 @@ BlockIO InterpreterGrantQuery::execute()
|
||||
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();
|
||||
|
||||
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||
@ -115,7 +115,7 @@ void InterpreterGrantQuery::updateUserFromQuery(User & user, const ASTGrantQuery
|
||||
{
|
||||
std::vector<UUID> roles_from_query;
|
||||
if (query.roles)
|
||||
roles_from_query = ExtendedRoleSet{*query.roles}.getMatchingIDs();
|
||||
roles_from_query = RolesOrUsersSet{*query.roles}.getMatchingIDs();
|
||||
updateFromQueryImpl(user, query, roles_from_query, {});
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ void InterpreterGrantQuery::updateRoleFromQuery(Role & role, const ASTGrantQuery
|
||||
{
|
||||
std::vector<UUID> roles_from_query;
|
||||
if (query.roles)
|
||||
roles_from_query = ExtendedRoleSet{*query.roles}.getMatchingIDs();
|
||||
roles_from_query = RolesOrUsersSet{*query.roles}.getMatchingIDs();
|
||||
updateFromQueryImpl(role, query, roles_from_query, {});
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/RolesOrUsersSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
|
||||
@ -38,7 +38,7 @@ void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query)
|
||||
}
|
||||
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;
|
||||
if (roles_from_query.all)
|
||||
{
|
||||
@ -65,8 +65,8 @@ void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query)
|
||||
context.checkAccess(AccessType::ALTER_USER);
|
||||
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
std::vector<UUID> to_users = ExtendedRoleSet{*query.to_users, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
||||
ExtendedRoleSet roles_from_query{*query.roles, access_control};
|
||||
std::vector<UUID> to_users = RolesOrUsersSet{*query.to_users, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
||||
RolesOrUsersSet roles_from_query{*query.roles, access_control};
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ namespace DB
|
||||
|
||||
class Context;
|
||||
class ASTSetRoleQuery;
|
||||
struct ExtendedRoleSet;
|
||||
struct RolesOrUsersSet;
|
||||
struct User;
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ public:
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
static void updateUserSetDefaultRoles(User & user, const ExtendedRoleSet & roles_from_query);
|
||||
static void updateUserSetDefaultRoles(User & user, const RolesOrUsersSet & roles_from_query);
|
||||
|
||||
private:
|
||||
void setRole(const ASTSetRoleQuery & query);
|
||||
|
@ -18,7 +18,7 @@ using EntityType = IAccessEntity::Type;
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
const auto & query = query_ptr->as<ASTShowAccessEntitiesQuery &>();
|
||||
auto & query = query_ptr->as<ASTShowAccessEntitiesQuery &>();
|
||||
query.replaceEmptyDatabaseWithCurrent(context.getCurrentDatabase());
|
||||
String origin;
|
||||
String expr = "*";
|
||||
String filter, order;
|
||||
@ -42,14 +43,18 @@ String InterpreterShowAccessEntitiesQuery::getRewrittenQuery() const
|
||||
{
|
||||
origin = "row_policies";
|
||||
expr = "name";
|
||||
const String & table_name = query.table_name;
|
||||
if (!table_name.empty())
|
||||
if (!query.short_name.empty())
|
||||
filter += String{filter.empty() ? "" : " AND "} + "short_name = " + quoteString(query.short_name);
|
||||
if (query.database_and_table_name)
|
||||
{
|
||||
String database = query.database;
|
||||
if (database.empty())
|
||||
database = context.getCurrentDatabase();
|
||||
filter = "database = " + quoteString(database) + " AND table = " + quoteString(table_name);
|
||||
expr = "short_name";
|
||||
const String & database = query.database_and_table_name->first;
|
||||
const String & table_name = query.database_and_table_name->second;
|
||||
if (!database.empty())
|
||||
filter += String{filter.empty() ? "" : " AND "} + "database = " + quoteString(database);
|
||||
if (!table_name.empty())
|
||||
filter += String{filter.empty() ? "" : " AND "} + "table = " + quoteString(table_name);
|
||||
if (!database.empty() && !table_name.empty())
|
||||
expr = "short_name";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -15,15 +15,14 @@ public:
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
bool ignoreQuota() const override { return ignore_quota; }
|
||||
bool ignoreLimits() const override { return ignore_quota; }
|
||||
bool ignoreQuota() const override { return true; }
|
||||
bool ignoreLimits() const override { return true; }
|
||||
|
||||
private:
|
||||
String getRewrittenQuery() const;
|
||||
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
bool ignore_quota = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
89
src/Interpreters/InterpreterShowAccessQuery.cpp
Normal file
89
src/Interpreters/InterpreterShowAccessQuery.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
36
src/Interpreters/InterpreterShowAccessQuery.h
Normal file
36
src/Interpreters/InterpreterShowAccessQuery.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -6,8 +6,10 @@
|
||||
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTUserNameWithHost.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
@ -23,6 +25,7 @@
|
||||
#include <Common/StringUtils/StringUtils.h>
|
||||
#include <Core/Defines.h>
|
||||
#include <ext/range.h>
|
||||
#include <boost/range/algorithm/sort.hpp>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@ -42,13 +45,14 @@ namespace
|
||||
bool attach_mode)
|
||||
{
|
||||
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;
|
||||
|
||||
if (user.allowed_client_hosts != AllowedClientHosts::AnyHostTag{})
|
||||
query->hosts = user.allowed_client_hosts;
|
||||
|
||||
if (user.default_roles != ExtendedRoleSet::AllTag{})
|
||||
if (user.default_roles != RolesOrUsersSet::AllTag{})
|
||||
{
|
||||
if (attach_mode)
|
||||
query->default_roles = user.default_roles.toAST();
|
||||
@ -77,7 +81,7 @@ namespace
|
||||
ASTPtr getCreateQueryImpl(const Role & role, const AccessControlManager * manager, bool attach_mode)
|
||||
{
|
||||
auto query = std::make_shared<ASTCreateRoleQuery>();
|
||||
query->name = role.getName();
|
||||
query->names.emplace_back(role.getName());
|
||||
query->attach = attach_mode;
|
||||
|
||||
if (!role.settings.empty())
|
||||
@ -95,7 +99,7 @@ namespace
|
||||
ASTPtr getCreateQueryImpl(const SettingsProfile & profile, const AccessControlManager * manager, bool attach_mode)
|
||||
{
|
||||
auto query = std::make_shared<ASTCreateSettingsProfileQuery>();
|
||||
query->name = profile.getName();
|
||||
query->names.emplace_back(profile.getName());
|
||||
query->attach = attach_mode;
|
||||
|
||||
if (!profile.elements.empty())
|
||||
@ -126,10 +130,12 @@ namespace
|
||||
bool attach_mode)
|
||||
{
|
||||
auto query = std::make_shared<ASTCreateQuotaQuery>();
|
||||
query->name = quota.getName();
|
||||
query->names.emplace_back(quota.getName());
|
||||
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());
|
||||
|
||||
for (const auto & limits : quota.all_limits)
|
||||
@ -160,7 +166,8 @@ namespace
|
||||
bool attach_mode)
|
||||
{
|
||||
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;
|
||||
|
||||
if (policy.isRestrictive())
|
||||
@ -173,7 +180,7 @@ namespace
|
||||
{
|
||||
ParserExpression parser;
|
||||
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_)
|
||||
: 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()
|
||||
{
|
||||
auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
|
||||
|
||||
/// Build a create query.
|
||||
ASTPtr create_query = getCreateQuery(show_query);
|
||||
/// Build a create queries.
|
||||
ASTs create_queries = getCreateQueries();
|
||||
|
||||
/// Build the result column.
|
||||
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);
|
||||
String create_query_str = create_query_ss.str();
|
||||
column->insert(create_query_str);
|
||||
column->insert(create_query_ss.str());
|
||||
create_query_ss.str("");
|
||||
}
|
||||
|
||||
/// Prepare description of the result column.
|
||||
std::stringstream desc_ss;
|
||||
const auto & show_query = query_ptr->as<const ASTShowCreateAccessEntityQuery &>();
|
||||
formatAST(show_query, desc_ss, false, true);
|
||||
String desc = desc_ss.str();
|
||||
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();
|
||||
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();
|
||||
if (!user)
|
||||
return nullptr;
|
||||
return getCreateQueryImpl(*user, &access_control, false);
|
||||
auto ids = access_control.findAll(show_query.type);
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
if (auto entity = access_control.tryRead(id))
|
||||
entities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_query.current_quota)
|
||||
else if (show_query.current_user)
|
||||
{
|
||||
if (auto user = context.getUser())
|
||||
entities.push_back(user);
|
||||
}
|
||||
else if (show_query.current_quota)
|
||||
{
|
||||
auto usage = context.getQuotaUsage();
|
||||
if (!usage)
|
||||
return nullptr;
|
||||
auto quota = access_control.read<Quota>(usage->quota_id);
|
||||
return getCreateQueryImpl(*quota, &access_control, false);
|
||||
if (usage)
|
||||
entities.push_back(access_control.read<Quota>(usage->quota_id));
|
||||
}
|
||||
|
||||
if (show_query.type == EntityType::ROW_POLICY)
|
||||
else if (show_query.type == EntityType::ROW_POLICY)
|
||||
{
|
||||
if (show_query.row_policy_name_parts.database.empty())
|
||||
show_query.row_policy_name_parts.database = context.getCurrentDatabase();
|
||||
RowPolicyPtr policy = access_control.read<RowPolicy>(show_query.row_policy_name_parts.getName());
|
||||
return getCreateQueryImpl(*policy, &access_control, false);
|
||||
auto ids = access_control.findAll<RowPolicy>();
|
||||
if (show_query.row_policy_names)
|
||||
{
|
||||
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));
|
||||
return getCreateQueryImpl(*entity, &access_control, false);
|
||||
boost::range::sort(entities, IAccessEntity::LessByName{});
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,10 +7,11 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class AccessControlManager;
|
||||
class Context;
|
||||
class ASTShowCreateAccessEntityQuery;
|
||||
class AccessRightsElements;
|
||||
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.
|
||||
@ -22,19 +23,20 @@ public:
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
bool ignoreQuota() const override { return ignore_quota; }
|
||||
bool ignoreLimits() const override { return ignore_quota; }
|
||||
bool ignoreQuota() const override { return true; }
|
||||
bool ignoreLimits() const override { return true; }
|
||||
|
||||
static ASTPtr getCreateQuery(const IAccessEntity & entity, const AccessControlManager & access_control);
|
||||
static ASTPtr getAttachQuery(const IAccessEntity & entity);
|
||||
|
||||
private:
|
||||
BlockInputStreamPtr executeImpl();
|
||||
ASTPtr getCreateQuery(ASTShowCreateAccessEntityQuery & show_query) const;
|
||||
std::vector<AccessEntityPtr> getEntities() const;
|
||||
ASTs getCreateQueries() const;
|
||||
AccessRightsElements getRequiredAccess() const;
|
||||
|
||||
ASTPtr query_ptr;
|
||||
const Context & context;
|
||||
bool ignore_quota = false;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <Interpreters/InterpreterShowGrantsQuery.h>
|
||||
#include <Parsers/ASTShowGrantsQuery.h>
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
@ -10,6 +10,9 @@
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.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
|
||||
@ -29,7 +32,7 @@ namespace
|
||||
{
|
||||
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());
|
||||
|
||||
auto grants_and_partial_revokes = grantee.access.getGrantsAndPartialRevokes();
|
||||
@ -87,9 +90,9 @@ namespace
|
||||
grant_query->admin_option = admin_option;
|
||||
grant_query->to_roles = to_roles;
|
||||
if (attach_mode)
|
||||
grant_query->roles = ExtendedRoleSet{roles}.toAST();
|
||||
grant_query->roles = RolesOrUsersSet{roles}.toAST();
|
||||
else
|
||||
grant_query->roles = ExtendedRoleSet{roles}.toASTWithNames(*manager);
|
||||
grant_query->roles = RolesOrUsersSet{roles}.toASTWithNames(*manager);
|
||||
res.push_back(std::move(grant_query));
|
||||
}
|
||||
|
||||
@ -121,10 +124,8 @@ BlockIO InterpreterShowGrantsQuery::execute()
|
||||
|
||||
BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
|
||||
{
|
||||
const auto & show_query = query_ptr->as<ASTShowGrantsQuery &>();
|
||||
|
||||
/// Build a create query.
|
||||
ASTs grant_queries = getGrantQueries(show_query);
|
||||
ASTs grant_queries = getGrantQueries();
|
||||
|
||||
/// Build the result column.
|
||||
MutableColumnPtr column = ColumnString::create();
|
||||
@ -138,6 +139,7 @@ BlockInputStreamPtr InterpreterShowGrantsQuery::executeImpl()
|
||||
|
||||
/// Prepare description of the result column.
|
||||
std::stringstream desc_ss;
|
||||
const auto & show_query = query_ptr->as<const ASTShowGrantsQuery &>();
|
||||
formatAST(show_query, desc_ss, false, true);
|
||||
String desc = desc_ss.str();
|
||||
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();
|
||||
auto ids = RolesOrUsersSet{*show_query.for_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
||||
|
||||
AccessEntityPtr user_or_role;
|
||||
if (show_query.current_user)
|
||||
user_or_role = context.getUser();
|
||||
else
|
||||
std::vector<AccessEntityPtr> entities;
|
||||
for (const auto & id : ids)
|
||||
{
|
||||
user_or_role = access_control.tryRead<User>(show_query.name);
|
||||
if (!user_or_role)
|
||||
user_or_role = access_control.read<Role>(show_query.name);
|
||||
auto entity = access_control.tryRead(id);
|
||||
if (entity)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class AccessControlManager;
|
||||
class ASTShowGrantsQuery;
|
||||
struct IAccessEntity;
|
||||
using AccessEntityPtr = std::shared_ptr<const IAccessEntity>;
|
||||
|
||||
|
||||
class InterpreterShowGrantsQuery : public IInterpreter
|
||||
@ -18,11 +20,16 @@ public:
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
static ASTs getGrantQueries(const IAccessEntity & user_or_role, const AccessControlManager & access_control);
|
||||
static ASTs getAttachGrantQueries(const IAccessEntity & user_or_role);
|
||||
|
||||
bool ignoreQuota() const override { return true; }
|
||||
bool ignoreLimits() const override { return true; }
|
||||
|
||||
private:
|
||||
BlockInputStreamPtr executeImpl();
|
||||
ASTs getGrantQueries(const ASTShowGrantsQuery & show_query) const;
|
||||
ASTs getGrantQueries() const;
|
||||
std::vector<AccessEntityPtr> getEntities() const;
|
||||
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
|
@ -85,6 +85,7 @@ SRCS(
|
||||
InterpreterSelectWithUnionQuery.cpp
|
||||
InterpreterSetQuery.cpp
|
||||
InterpreterSetRoleQuery.cpp
|
||||
InterpreterShowAccessQuery.cpp
|
||||
InterpreterShowAccessEntitiesQuery.cpp
|
||||
InterpreterShowCreateAccessEntityQuery.cpp
|
||||
InterpreterShowCreateQuery.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Common/quoteString.h>
|
||||
#include <Common/IntervalKind.h>
|
||||
#include <ext/range.h>
|
||||
@ -18,8 +18,41 @@ namespace
|
||||
|
||||
void formatKeyType(const KeyType & key_type, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " KEYED BY " << (settings.hilite ? IAST::hilite_none : "") << "'"
|
||||
<< KeyTypeInfo::get(key_type).name << "'";
|
||||
const auto & type_info = KeyTypeInfo::get(key_type);
|
||||
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);
|
||||
settings.ostr << " " << (settings.hilite ? IAST::hilite_keyword : "") << type_info.keyword
|
||||
<< (settings.hilite ? IAST::hilite_none : "") << " " << type_info.amountToString(max);
|
||||
settings.ostr << " " << type_info.name << " = " << 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());
|
||||
Int64 num_intervals = limits.duration.count() / interval_kind.toAvgSeconds();
|
||||
@ -51,11 +78,11 @@ namespace
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "")
|
||||
<< " FOR"
|
||||
<< (limits.randomize_interval ? " RANDOMIZED" : "")
|
||||
<< " INTERVAL "
|
||||
<< " INTERVAL"
|
||||
<< (settings.hilite ? IAST::hilite_none : "")
|
||||
<< num_intervals << " "
|
||||
<< " " << num_intervals << " "
|
||||
<< (settings.hilite ? IAST::hilite_keyword : "")
|
||||
<< interval_kind.toKeyword()
|
||||
<< interval_kind.toLowercasedKeyword()
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
|
||||
if (limits.drop)
|
||||
@ -68,17 +95,28 @@ namespace
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
if (limits.max[resource_type])
|
||||
{
|
||||
formatLimit(resource_type, *limits.max[resource_type], !limit_found, settings);
|
||||
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 : "");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
for (const auto & limits : all_limits)
|
||||
@ -87,11 +125,11 @@ namespace
|
||||
settings.ostr << ",";
|
||||
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 : "");
|
||||
roles.format(settings);
|
||||
@ -130,8 +168,7 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
else if (or_replace)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatNames(names, settings);
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (!new_name.empty())
|
||||
@ -140,7 +177,7 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
if (key_type)
|
||||
formatKeyType(*key_type, settings);
|
||||
|
||||
formatAllLimits(all_limits, settings);
|
||||
formatIntervalsWithLimits(all_limits, settings);
|
||||
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
|
@ -7,21 +7,21 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
|
||||
/** 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'}]
|
||||
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
|
||||
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
|
||||
* [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}
|
||||
* {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
|
||||
* NO LIMITS | TRACKING ONLY} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*
|
||||
* ALTER QUOTA [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
|
||||
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
|
||||
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
|
||||
* [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}
|
||||
* {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
|
||||
* NO LIMITS | TRACKING ONLY} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
@ -38,7 +38,7 @@ public:
|
||||
using KeyType = Quota::KeyType;
|
||||
using ResourceAmount = Quota::ResourceAmount;
|
||||
|
||||
String name;
|
||||
Strings names;
|
||||
String new_name;
|
||||
std::optional<KeyType> key_type;
|
||||
|
||||
@ -51,7 +51,7 @@ public:
|
||||
};
|
||||
std::vector<Limits> all_limits;
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
|
@ -7,6 +7,18 @@ namespace DB
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatNames(names, format);
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
|
||||
String name;
|
||||
Strings names;
|
||||
String new_name;
|
||||
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Common/quoteString.h>
|
||||
#include <ext/range.h>
|
||||
@ -13,7 +14,6 @@ namespace
|
||||
{
|
||||
using ConditionType = RowPolicy::ConditionType;
|
||||
using ConditionTypeInfo = RowPolicy::ConditionTypeInfo;
|
||||
constexpr auto MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " AS " << (is_restrictive ? "RESTRICTIVE" : "PERMISSIVE")
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " AS " << (settings.hilite ? IAST::hilite_none : "")
|
||||
<< (is_restrictive ? "restrictive" : "permissive");
|
||||
}
|
||||
|
||||
|
||||
void formatConditionalExpression(const ASTPtr & expr, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << " ";
|
||||
if (expr)
|
||||
expr->format(settings);
|
||||
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 : "");
|
||||
bool need_comma = false;
|
||||
@ -51,27 +52,23 @@ namespace
|
||||
}
|
||||
|
||||
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)))
|
||||
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;
|
||||
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];
|
||||
if (condition)
|
||||
{
|
||||
formatConditionalExpression(*condition, temp_settings);
|
||||
conditions_as_strings[condition_type] = temp_sstream.str();
|
||||
temp_sstream.str("");
|
||||
}
|
||||
formatConditionalExpression(condition, temp_settings);
|
||||
conditions_as_strings.emplace_back(condition_type, temp_sstream.str());
|
||||
temp_sstream.str("");
|
||||
}
|
||||
|
||||
boost::container::flat_set<std::string_view> commands;
|
||||
@ -84,9 +81,8 @@ namespace
|
||||
check.clear();
|
||||
|
||||
/// 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())
|
||||
continue;
|
||||
const auto & type_info = ConditionTypeInfo::get(condition_type);
|
||||
@ -105,17 +101,17 @@ namespace
|
||||
continue;
|
||||
}
|
||||
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())
|
||||
formatCondition(commands, filter, check, alter, settings);
|
||||
formatForClause(commands, filter, check, alter, settings);
|
||||
}
|
||||
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 : "");
|
||||
roles.format(settings);
|
||||
@ -154,13 +150,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
else if (or_replace)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
|
||||
|
||||
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) + ".") << table_name;
|
||||
settings.ostr << " ";
|
||||
names->format(settings);
|
||||
|
||||
formatOnCluster(settings);
|
||||
assert(names->cluster.empty());
|
||||
|
||||
if (!new_short_name.empty())
|
||||
formatRenameTo(new_short_name, settings);
|
||||
@ -168,7 +162,7 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
if (is_restrictive)
|
||||
formatAsRestrictiveOrPermissive(*is_restrictive, settings);
|
||||
|
||||
formatMultipleConditions(conditions, alter, settings);
|
||||
formatForClauses(conditions, alter, settings);
|
||||
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
@ -180,4 +174,10 @@ void ASTCreateRowPolicyQuery::replaceCurrentUserTagWithName(const String & curre
|
||||
if (roles)
|
||||
roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
|
||||
void ASTCreateRowPolicyQuery::replaceEmptyDatabaseWithCurrent(const String & current_database) const
|
||||
{
|
||||
if (names)
|
||||
names->replaceEmptyDatabaseWithCurrent(current_database);
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,16 @@
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRowPolicyNames;
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
/** CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
|
||||
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||
* [AS {permissive | restrictive}]
|
||||
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||
* [USING condition]
|
||||
* [WITH CHECK condition] [,...]
|
||||
@ -20,7 +20,7 @@ class ASTExtendedRoleSet;
|
||||
*
|
||||
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
|
||||
* [RENAME TO new_name]
|
||||
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||
* [AS {permissive | restrictive}]
|
||||
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||
* [USING {condition | NONE}]
|
||||
* [WITH CHECK {condition | NONE}] [,...]
|
||||
@ -36,18 +36,20 @@ public:
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
|
||||
RowPolicy::NameParts name_parts;
|
||||
std::shared_ptr<ASTRowPolicyNames> names;
|
||||
String new_short_name;
|
||||
|
||||
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;
|
||||
ASTPtr clone() 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()); }
|
||||
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name) const;
|
||||
void replaceEmptyDatabaseWithCurrent(const String & current_database) const;
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <Parsers/ASTCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
@ -8,6 +8,18 @@ namespace DB
|
||||
{
|
||||
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)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "")
|
||||
@ -20,7 +32,7 @@ namespace
|
||||
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 : "");
|
||||
roles.format(settings);
|
||||
@ -59,8 +71,7 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
|
||||
else if (or_replace)
|
||||
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatNames(names, format);
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace DB
|
||||
{
|
||||
class ASTSettingsProfileElements;
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
|
||||
/** CREATE SETTINGS PROFILE [IF NOT EXISTS | OR REPLACE] name
|
||||
@ -29,12 +29,12 @@ public:
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
|
||||
String name;
|
||||
Strings names;
|
||||
String new_name;
|
||||
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_roles;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTUserNameWithHost.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.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 : "");
|
||||
default_roles.format(settings);
|
||||
@ -213,7 +214,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
else if (or_replace)
|
||||
format.ostr << (format.hilite ? hilite_keyword : "") << " OR REPLACE" << (format.hilite ? hilite_none : "");
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
format.ostr << " ";
|
||||
names->format(format);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTUserNamesWithHost;
|
||||
class ASTRolesOrUsersSet;
|
||||
class ASTSettingsProfileElements;
|
||||
|
||||
/** CREATE USER [IF NOT EXISTS | OR REPLACE] name
|
||||
@ -34,7 +35,7 @@ public:
|
||||
bool if_not_exists = false;
|
||||
bool or_replace = false;
|
||||
|
||||
String name;
|
||||
std::shared_ptr<ASTUserNamesWithHost> names;
|
||||
String new_name;
|
||||
|
||||
std::optional<Authentication> authentication;
|
||||
@ -44,7 +45,7 @@ public:
|
||||
std::optional<AllowedClientHosts> add_hosts;
|
||||
std::optional<AllowedClientHosts> remove_hosts;
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> default_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> default_roles;
|
||||
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
|
||||
|
@ -1,10 +1,25 @@
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
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
|
||||
@ -28,32 +43,19 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
|
||||
|
||||
if (type == EntityType::ROW_POLICY)
|
||||
{
|
||||
bool need_comma = false;
|
||||
for (const auto & name_parts : row_policies_name_parts)
|
||||
{
|
||||
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);
|
||||
}
|
||||
settings.ostr << " ";
|
||||
row_policy_names->format(settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool need_comma = false;
|
||||
for (const auto & name : names)
|
||||
{
|
||||
if (need_comma)
|
||||
settings.ostr << ',';
|
||||
need_comma = true;
|
||||
settings.ostr << ' ' << backQuoteIfNeed(name);
|
||||
}
|
||||
}
|
||||
formatNames(names, settings);
|
||||
|
||||
formatOnCluster(settings);
|
||||
}
|
||||
|
||||
|
||||
void ASTDropAccessEntityQuery::replaceEmptyDatabaseWithCurrent(const String & current_database) const
|
||||
{
|
||||
if (row_policy_names)
|
||||
row_policy_names->replaceEmptyDatabaseWithCurrent(current_database);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTRowPolicyNames;
|
||||
|
||||
/** DROP USER [IF EXISTS] name [,...]
|
||||
* DROP ROLE [IF EXISTS] name [,...]
|
||||
@ -22,11 +23,13 @@ public:
|
||||
EntityType type;
|
||||
bool if_exists = false;
|
||||
Strings names;
|
||||
std::vector<RowPolicy::NameParts> row_policies_name_parts;
|
||||
std::shared_ptr<ASTRowPolicyNames> row_policy_names;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTDropAccessEntityQuery>(clone()); }
|
||||
|
||||
void replaceEmptyDatabaseWithCurrent(const String & current_database) const;
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.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;
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ((kind == Kind::GRANT) ? " TO " : " FROM ")
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
|
||||
/** 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;
|
||||
bool attach = false;
|
||||
AccessRightsElements access_rights_elements;
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_roles;
|
||||
bool grant_option = false;
|
||||
bool admin_option = false;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.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())
|
||||
{
|
||||
@ -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)
|
||||
{
|
@ -7,7 +7,7 @@ namespace DB
|
||||
{
|
||||
/// Represents a set of users/roles like
|
||||
/// {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:
|
||||
Strings names;
|
||||
@ -16,15 +16,15 @@ public:
|
||||
Strings except_names;
|
||||
bool except_current_user = false;
|
||||
|
||||
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 can_contain_users = true; /// true if this set can contain names of users.
|
||||
bool id_mode = false; /// true if `names` and `except_names` keep UUIDs, not names.
|
||||
bool allow_role_names = true; /// true if this set can contain names of roles.
|
||||
bool allow_user_names = true; /// true if this set can contain names of users.
|
||||
|
||||
bool empty() const { return names.empty() && !current_user && !all; }
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
|
||||
String getID(char) const override { return "ExtendedRoleSet"; }
|
||||
ASTPtr clone() const override { return std::make_shared<ASTExtendedRoleSet>(*this); }
|
||||
String getID(char) const override { return "RolesOrUsersSet"; }
|
||||
ASTPtr clone() const override { return std::make_shared<ASTRolesOrUsersSet>(*this); }
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
};
|
||||
}
|
134
src/Parsers/ASTRowPolicyName.cpp
Normal file
134
src/Parsers/ASTRowPolicyName.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
49
src/Parsers/ASTRowPolicyName.h
Normal file
49
src/Parsers/ASTRowPolicyName.h
Normal 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);
|
||||
};
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTExtendedRoleSet;
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
/** SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
|
||||
* SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]
|
||||
@ -21,8 +21,8 @@ public:
|
||||
};
|
||||
Kind kind = Kind::SET_ROLE;
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_users;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_users;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
|
@ -4,49 +4,51 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
}
|
||||
using EntityTypeInfo = IAccessEntity::TypeInfo;
|
||||
|
||||
|
||||
const char * ASTShowAccessEntitiesQuery::getKeyword() const
|
||||
String ASTShowAccessEntitiesQuery::getKeyword() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EntityType::ROW_POLICY:
|
||||
return "SHOW ROW POLICIES";
|
||||
case EntityType::QUOTA:
|
||||
return current_quota ? "SHOW CURRENT QUOTA" : "SHOW QUOTAS";
|
||||
case EntityType::SETTINGS_PROFILE:
|
||||
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);
|
||||
if (current_quota)
|
||||
return "CURRENT QUOTA";
|
||||
if (current_roles)
|
||||
return "CURRENT ROLES";
|
||||
if (enabled_roles)
|
||||
return "ENABLED ROLES";
|
||||
return EntityTypeInfo::get(type).plural_name;
|
||||
}
|
||||
|
||||
|
||||
String ASTShowAccessEntitiesQuery::getID(char) const
|
||||
{
|
||||
return String(getKeyword()) + " query";
|
||||
return "SHOW " + String(getKeyword()) + " query";
|
||||
}
|
||||
|
||||
void ASTShowAccessEntitiesQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||
{
|
||||
const char * keyword = getKeyword();
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << keyword << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW " << getKeyword() << (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 : "");
|
||||
if (!database.empty())
|
||||
settings.ostr << backQuoteIfNeed(database) << ".";
|
||||
settings.ostr << backQuoteIfNeed(table_name);
|
||||
settings.ostr << (database.empty() ? "" : backQuoteIfNeed(database) + ".");
|
||||
settings.ostr << (table_name.empty() ? "*" : 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,32 +7,37 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// SHOW [ROW] POLICIES [ON [database.]table]
|
||||
/// SHOW QUOTAS
|
||||
/// SHOW [CURRENT] QUOTA
|
||||
/// SHOW [SETTINGS] PROFILES
|
||||
/// SHOW USERS
|
||||
/// SHOW [CURRENT|ENABLED] ROLES
|
||||
/// SHOW [SETTINGS] PROFILES
|
||||
/// SHOW [ROW] POLICIES [name | ON [database.]table]
|
||||
/// SHOW QUOTAS
|
||||
/// SHOW [CURRENT] QUOTA
|
||||
class ASTShowAccessEntitiesQuery : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
using EntityType = IAccessEntity::Type;
|
||||
|
||||
EntityType type;
|
||||
String database;
|
||||
String table_name;
|
||||
|
||||
bool all = false;
|
||||
bool current_quota = false;
|
||||
bool current_roles = false;
|
||||
bool enabled_roles = false;
|
||||
|
||||
String short_name;
|
||||
std::optional<std::pair<String, String>> database_and_table_name;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override { return std::make_shared<ASTShowAccessEntitiesQuery>(*this); }
|
||||
|
||||
void replaceEmptyDatabaseWithCurrent(const String & current_database);
|
||||
|
||||
protected:
|
||||
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
|
||||
private:
|
||||
const char * getKeyword() const;
|
||||
String getKeyword() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
17
src/Parsers/ASTShowAccessQuery.h
Normal file
17
src/Parsers/ASTShowAccessQuery.h
Normal 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>;
|
||||
|
||||
}
|
@ -1,15 +1,40 @@
|
||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Common/quoteString.h>
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< "SHOW CREATE " << EntityTypeInfo::get(type).name
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW CREATE " << getKeyword() << (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 & table_name = row_policy_name_parts.table_name;
|
||||
const String & short_name = row_policy_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);
|
||||
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 << (database.empty() ? "" : backQuoteIfNeed(database) + ".");
|
||||
settings.ostr << (table_name.empty() ? "*" : 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,16 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/ASTQueryWithOutput.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Access/IAccessEntity.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/** SHOW CREATE QUOTA [name | CURRENT]
|
||||
* SHOW CREATE [ROW] POLICY name ON [database.]table
|
||||
* SHOW CREATE USER [name | CURRENT_USER]
|
||||
class ASTRowPolicyNames;
|
||||
|
||||
/** 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 QUOTAS [name [, name2 ...]]
|
||||
*/
|
||||
class ASTShowCreateAccessEntityQuery : public ASTQueryWithOutput
|
||||
{
|
||||
@ -18,15 +25,23 @@ public:
|
||||
using EntityType = IAccessEntity::Type;
|
||||
|
||||
EntityType type;
|
||||
String name;
|
||||
Strings names;
|
||||
std::shared_ptr<ASTRowPolicyNames> row_policy_names;
|
||||
|
||||
bool current_quota = 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;
|
||||
ASTPtr clone() const override;
|
||||
|
||||
void replaceEmptyDatabaseWithCurrent(const String & current_database);
|
||||
|
||||
protected:
|
||||
String getKeyword() const;
|
||||
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <Parsers/ASTShowGrantsQuery.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.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.hilite ? hilite_none : "");
|
||||
|
||||
if (!current_user)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FOR " << (settings.hilite ? hilite_none : "")
|
||||
<< backQuoteIfNeed(name);
|
||||
if (for_roles->current_user && !for_roles->all && for_roles->names.empty() && for_roles->except_names.empty()
|
||||
&& !for_roles->except_current_user)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FOR "
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
for_roles->format(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,14 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class ASTRolesOrUsersSet;
|
||||
|
||||
/** SHOW GRANTS [FOR user_name]
|
||||
*/
|
||||
class ASTShowGrantsQuery : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
String name;
|
||||
bool current_user = false;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> for_roles;
|
||||
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
|
74
src/Parsers/ASTUserNameWithHost.cpp
Normal file
74
src/Parsers/ASTUserNameWithHost.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
53
src/Parsers/ASTUserNameWithHost.h
Normal file
53
src/Parsers/ASTUserNameWithHost.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@ -76,41 +76,25 @@ const char * ParserTupleElementExpression::operators[] =
|
||||
|
||||
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);
|
||||
list->children = std::move(elements);
|
||||
node = list;
|
||||
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,6 +26,43 @@ public:
|
||||
, 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:
|
||||
const char * getName() const override { return "list of elements"; }
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
|
@ -3,10 +3,12 @@
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/parseIntervalKind.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <Parsers/ParserExtendedRoleSet.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
#include <Parsers/ExpressionElementParsers.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 <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, [&]
|
||||
{
|
||||
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;
|
||||
|
||||
ASTPtr key_type_ast;
|
||||
if (!ParserStringLiteral().parse(pos, key_type_ast, expected))
|
||||
Strings names;
|
||||
if (!parseIdentifiersOrStringLiterals(pos, expected, names))
|
||||
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))
|
||||
if (boost::iequals(KeyTypeInfo::get(kt).name, key_type_str))
|
||||
if (KeyTypeInfo::get(kt).name == name)
|
||||
{
|
||||
key_type = kt;
|
||||
return true;
|
||||
}
|
||||
|
||||
String all_key_types_str;
|
||||
String all_types_str;
|
||||
for (auto kt : ext::range(Quota::KeyType::MAX))
|
||||
all_key_types_str += String(all_key_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;
|
||||
all_types_str += String(all_types_str.empty() ? "" : ", ") + "'" + KeyTypeInfo::get(kt).name + "'";
|
||||
String msg = "Quota cannot be keyed by '" + name + "'. Expected one of the following identifiers: " + all_types_str;
|
||||
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, [&]
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (ParserKeyword{ResourceTypeInfo::get(rt).keyword.c_str()}.ignore(pos, expected))
|
||||
{
|
||||
res_resource_type = rt;
|
||||
break;
|
||||
resource_type = rt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!res_resource_type)
|
||||
|
||||
ASTPtr ast;
|
||||
if (!ParserIdentifier{}.parse(pos, ast, expected))
|
||||
return false;
|
||||
|
||||
ResourceAmount res_max;
|
||||
ASTPtr max_ast;
|
||||
if (ParserNumber{}.parse(pos, max_ast, expected))
|
||||
String name = getIdentifierName(ast);
|
||||
for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
const Field & max_field = max_ast->as<ASTLiteral &>().value;
|
||||
const auto & type_info = ResourceTypeInfo::get(*res_resource_type);
|
||||
if (type_info.output_denominator == 1)
|
||||
res_max = applyVisitor(FieldVisitorConvertToNumber<ResourceAmount>(), max_field);
|
||||
else
|
||||
res_max = static_cast<ResourceAmount>(
|
||||
applyVisitor(FieldVisitorConvertToNumber<double>(), max_field) * type_info.output_denominator);
|
||||
if (ResourceTypeInfo::get(rt).name == name)
|
||||
{
|
||||
resource_type = rt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
resource_type = *res_resource_type;
|
||||
max = res_max;
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
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))
|
||||
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))
|
||||
return false;
|
||||
ParserKeyword{"INTERVAL"}.ignore(pos, expected);
|
||||
|
||||
ASTPtr num_intervals_ast;
|
||||
if (!ParserNumber{}.parse(pos, num_intervals_ast, expected))
|
||||
@ -139,61 +189,46 @@ namespace
|
||||
if (!parseIntervalKind(pos, expected, interval_kind))
|
||||
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))
|
||||
{
|
||||
new_limits.drop = true;
|
||||
limits.drop = true;
|
||||
}
|
||||
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
|
||||
{
|
||||
ResourceType resource_type;
|
||||
ResourceAmount max;
|
||||
if (!parseLimit(pos, expected, true, resource_type, max))
|
||||
return false;
|
||||
return false;
|
||||
|
||||
new_limits.max[resource_type] = max;
|
||||
while (parseLimit(pos, expected, false, resource_type, max))
|
||||
new_limits.max[resource_type] = max;
|
||||
}
|
||||
|
||||
limits = new_limits;
|
||||
res_all_limits.emplace_back(std::move(limits));
|
||||
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)
|
||||
{
|
||||
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)
|
||||
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
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;
|
||||
|
||||
roles = std::static_pointer_cast<ASTExtendedRoleSet>(node);
|
||||
roles = std::static_pointer_cast<ASTRolesOrUsersSet>(node);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -240,8 +275,8 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
Strings names;
|
||||
if (!parseIdentifiersOrStringLiterals(pos, expected, names))
|
||||
return false;
|
||||
|
||||
String new_name;
|
||||
@ -251,13 +286,20 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
|
||||
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;
|
||||
|
||||
if (!key_type && parseKeyType(pos, expected, key_type))
|
||||
continue;
|
||||
if (!key_type)
|
||||
{
|
||||
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;
|
||||
|
||||
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
|
||||
@ -266,7 +308,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
break;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
parseToRoles(pos, expected, attach_mode, roles);
|
||||
|
||||
if (cluster.empty())
|
||||
@ -280,7 +322,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->names = std::move(names);
|
||||
query->new_name = std::move(new_name);
|
||||
query->key_type = key_type;
|
||||
query->all_limits = std::move(all_limits);
|
||||
|
@ -7,24 +7,24 @@ namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* 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'}]
|
||||
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
|
||||
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} [,...] |
|
||||
* [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}
|
||||
* {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
|
||||
* NO LIMITS | TRACKING ONLY} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*
|
||||
* ALTER QUOTA [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
|
||||
* [FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
|
||||
* {MAX {{QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number} } [,...] |
|
||||
* [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}
|
||||
* {MAX {{queries | errors | result_rows | result_bytes | read_rows | read_bytes | execution_time} = number} [,...] |
|
||||
* NO LIMITS | TRACKING ONLY} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
class ParserCreateQuotaQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserCreateQuotaQuery & enableAttachMode(bool enable_) { attach_mode = enable_; return *this; }
|
||||
void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE QUOTA or ALTER QUOTA query"; }
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ParserSettingsProfileElement.h>
|
||||
#include <Parsers/parseUserName.h>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
|
||||
|
||||
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, [&]
|
||||
{
|
||||
@ -31,13 +32,12 @@ namespace
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
if (!settings)
|
||||
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());
|
||||
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -84,8 +84,8 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (!parseRoleName(pos, expected, name))
|
||||
Strings names;
|
||||
if (!parseRoleNames(pos, expected, names))
|
||||
return false;
|
||||
|
||||
String new_name;
|
||||
@ -94,11 +94,17 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (alter && parseRenameTo(pos, expected, new_name))
|
||||
if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
|
||||
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;
|
||||
}
|
||||
|
||||
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
|
||||
continue;
|
||||
@ -115,7 +121,7 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->names = std::move(names);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace DB
|
||||
class ParserCreateRoleQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserCreateRoleQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; }
|
||||
void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE ROLE or ALTER ROLE query"; }
|
||||
|
@ -1,14 +1,17 @@
|
||||
#include <Parsers/ParserCreateRowPolicyQuery.h>
|
||||
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Parsers/ParserExtendedRoleSet.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/ParserRowPolicyName.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <Parsers/parseDatabaseAndTableName.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/ExpressionElementParsers.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <ext/range.h>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
|
||||
|
||||
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, [&]
|
||||
{
|
||||
@ -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, [&]
|
||||
{
|
||||
@ -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;
|
||||
|
||||
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))
|
||||
{
|
||||
do
|
||||
{
|
||||
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));
|
||||
if (!parseCommands(pos, expected, commands))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
addAllCommands(commands);
|
||||
|
||||
std::optional<ASTPtr> filter;
|
||||
std::optional<ASTPtr> check;
|
||||
if (ParserKeyword{"USING"}.ignore(pos, expected))
|
||||
{
|
||||
if (!parseConditionalExpression(pos, expected, filter))
|
||||
if (!parseConditionalExpression(pos, expected, filter.emplace()))
|
||||
return false;
|
||||
}
|
||||
if (ParserKeyword{"WITH CHECK"}.ignore(pos, expected))
|
||||
{
|
||||
if (!parseConditionalExpression(pos, expected, check))
|
||||
if (!parseConditionalExpression(pos, expected, check.emplace()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!filter && !check)
|
||||
return false;
|
||||
|
||||
if (commands.empty())
|
||||
add_all_commands();
|
||||
|
||||
if (!check && !alter)
|
||||
check = filter;
|
||||
|
||||
@ -143,44 +162,36 @@ namespace
|
||||
if (commands.count(type_info.command))
|
||||
{
|
||||
if (type_info.is_check && check)
|
||||
conditions[condition_type] = check;
|
||||
res_conditions.emplace_back(condition_type, *check);
|
||||
else if (filter)
|
||||
conditions[condition_type] = filter;
|
||||
res_conditions.emplace_back(condition_type, *filter);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
if (!ParserList::parseUtil(pos, expected, parse_for_clause, false))
|
||||
return false;
|
||||
|
||||
conditions = std::move(res_conditions);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseMultipleConditions(
|
||||
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)
|
||||
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected)
|
||||
|| !ParserExtendedRoleSet{}.useIDMode(id_mode).parse(pos, ast, expected))
|
||||
if (!ParserKeyword{"TO"}.ignore(pos, expected))
|
||||
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;
|
||||
});
|
||||
}
|
||||
@ -227,29 +238,40 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
RowPolicy::NameParts name_parts;
|
||||
String & database = name_parts.database;
|
||||
String & table_name = name_parts.table_name;
|
||||
String & short_name = name_parts.short_name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, short_name) || !ParserKeyword{"ON"}.ignore(pos, expected)
|
||||
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||
ParserRowPolicyNames names_parser;
|
||||
names_parser.allowOnCluster();
|
||||
ASTPtr names_ast;
|
||||
if (!names_parser.parse(pos, names_ast, expected))
|
||||
return false;
|
||||
|
||||
auto names = typeid_cast<std::shared_ptr<ASTRowPolicyNames>>(names_ast);
|
||||
String cluster = std::exchange(names->cluster, "");
|
||||
|
||||
String new_short_name;
|
||||
std::optional<bool> is_restrictive;
|
||||
std::array<std::optional<ASTPtr>, MAX_CONDITION_TYPE> conditions;
|
||||
String cluster;
|
||||
std::vector<std::pair<ConditionType, ASTPtr>> conditions;
|
||||
|
||||
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;
|
||||
|
||||
if (!is_restrictive && parseAsRestrictiveOrPermissive(pos, expected, is_restrictive))
|
||||
continue;
|
||||
if (!is_restrictive)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
|
||||
continue;
|
||||
@ -257,7 +279,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
break;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
parseToRoles(pos, expected, attach_mode, roles);
|
||||
|
||||
if (cluster.empty())
|
||||
@ -272,7 +294,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
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->is_restrictive = is_restrictive;
|
||||
query->conditions = std::move(conditions);
|
||||
|
@ -7,7 +7,7 @@ namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
|
||||
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||
* [AS {permissive | restrictive}]
|
||||
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||
* [USING condition]
|
||||
* [WITH CHECK condition] [,...]
|
||||
@ -15,7 +15,7 @@ namespace DB
|
||||
*
|
||||
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
|
||||
* [RENAME TO new_name]
|
||||
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||
* [AS {permissive | restrictive}]
|
||||
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||
* [USING {condition | NONE}]
|
||||
* [WITH CHECK {condition | NONE}] [,...]
|
||||
@ -24,7 +24,7 @@ namespace DB
|
||||
class ParserCreateRowPolicyQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserCreateRowPolicyQuery & enableAttachMode(bool enable_) { attach_mode = enable_; return *this; }
|
||||
void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE ROW POLICY or ALTER ROW POLICY query"; }
|
||||
|
@ -5,9 +5,10 @@
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ParserSettingsProfileElement.h>
|
||||
#include <Parsers/ParserExtendedRoleSet.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
|
||||
|
||||
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, [&]
|
||||
{
|
||||
@ -33,27 +34,30 @@ namespace
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
if (!settings)
|
||||
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());
|
||||
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
|
||||
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, [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected)
|
||||
|| !ParserExtendedRoleSet{}.useIDMode(id_mode).parse(pos, ast, expected))
|
||||
if (!ParserKeyword{"TO"}.ignore(pos, expected))
|
||||
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;
|
||||
});
|
||||
}
|
||||
@ -100,8 +104,8 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
Strings names;
|
||||
if (!parseIdentifiersOrStringLiterals(pos, expected, names))
|
||||
return false;
|
||||
|
||||
String new_name;
|
||||
@ -110,11 +114,17 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (alter && parseRenameTo(pos, expected, new_name))
|
||||
if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
|
||||
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;
|
||||
}
|
||||
|
||||
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
|
||||
continue;
|
||||
@ -122,7 +132,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
break;
|
||||
}
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_roles;
|
||||
parseToRoles(pos, expected, attach_mode, to_roles);
|
||||
|
||||
if (cluster.empty())
|
||||
@ -137,7 +147,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->names = std::move(names);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
query->to_roles = std::move(to_roles);
|
||||
|
@ -16,7 +16,7 @@ namespace DB
|
||||
class ParserCreateSettingsProfileQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserCreateSettingsProfileQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; }
|
||||
void useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE SETTINGS PROFILE or ALTER SETTINGS PROFILE query"; }
|
||||
|
@ -6,21 +6,19 @@
|
||||
#include <Parsers/ExpressionElementParsers.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ParserExtendedRoleSet.h>
|
||||
#include <Parsers/ASTUserNameWithHost.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ParserUserNameWithHost.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ParserSettingsProfileElement.h>
|
||||
#include <ext/range.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
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, [&]
|
||||
{
|
||||
@ -99,97 +97,115 @@ namespace
|
||||
|
||||
authentication = Authentication{*type};
|
||||
if (expect_password)
|
||||
authentication->setPassword(password);
|
||||
authentication.setPassword(password);
|
||||
else if (expect_hash)
|
||||
authentication->setPasswordHashHex(password);
|
||||
authentication.setPasswordHashHex(password);
|
||||
|
||||
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, [&]
|
||||
{
|
||||
if (prefix && !ParserKeyword{prefix}.ignore(pos, expected))
|
||||
if (!prefix.empty() && !ParserKeyword{prefix.c_str()}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (!ParserKeyword{"HOST"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword{"ANY"}.ignore(pos, expected))
|
||||
{
|
||||
if (!hosts)
|
||||
hosts.emplace();
|
||||
hosts->addAnyHost();
|
||||
return true;
|
||||
}
|
||||
AllowedClientHosts res_hosts;
|
||||
if (!parseHostsWithoutPrefix(pos, expected, res_hosts))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword{"NONE"}.ignore(pos, expected))
|
||||
{
|
||||
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);
|
||||
hosts.add(std::move(res_hosts));
|
||||
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, [&]
|
||||
{
|
||||
@ -197,17 +213,19 @@ namespace
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
default_roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast);
|
||||
default_roles->can_contain_users = false;
|
||||
default_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
|
||||
default_roles->allow_user_names = false;
|
||||
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, [&]
|
||||
{
|
||||
@ -215,13 +233,12 @@ namespace
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
if (!settings)
|
||||
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());
|
||||
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -268,30 +285,50 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
or_replace = true;
|
||||
}
|
||||
|
||||
String name;
|
||||
std::optional<String> host_pattern;
|
||||
if (!parseUserName(pos, expected, name, host_pattern))
|
||||
ASTPtr names_ast;
|
||||
if (!ParserUserNamesWithHost{}.parse(pos, names_ast, expected))
|
||||
return false;
|
||||
auto names = typeid_cast<std::shared_ptr<ASTUserNamesWithHost>>(names_ast);
|
||||
auto names_ref = names->names;
|
||||
|
||||
String new_name;
|
||||
std::optional<Authentication> authentication;
|
||||
std::optional<AllowedClientHosts> hosts;
|
||||
std::optional<AllowedClientHosts> add_hosts;
|
||||
std::optional<AllowedClientHosts> remove_hosts;
|
||||
std::shared_ptr<ASTExtendedRoleSet> default_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> default_roles;
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
String cluster;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!authentication && parseAuthentication(pos, expected, authentication))
|
||||
continue;
|
||||
if (!authentication)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!default_roles && parseDefaultRoles(pos, expected, attach_mode, default_roles))
|
||||
continue;
|
||||
@ -301,18 +338,40 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|
||||
if (alter)
|
||||
{
|
||||
if (new_name.empty() && parseRenameTo(pos, expected, new_name))
|
||||
if (new_name.empty() && (names->size() == 1) && parseRenameTo(pos, expected, new_name))
|
||||
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;
|
||||
}
|
||||
|
||||
if (parseHosts(pos, expected, "DROP", new_hosts))
|
||||
{
|
||||
if (!remove_hosts)
|
||||
remove_hosts.emplace();
|
||||
remove_hosts->add(new_hosts);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!alter && !hosts && host_pattern)
|
||||
hosts.emplace().addLikePattern(*host_pattern);
|
||||
if (!alter && !hosts)
|
||||
{
|
||||
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>();
|
||||
node = query;
|
||||
@ -323,7 +382,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->names = std::move(names);
|
||||
query->new_name = std::move(new_name);
|
||||
query->authentication = std::move(authentication);
|
||||
query->hosts = std::move(hosts);
|
||||
|
@ -20,7 +20,7 @@ namespace DB
|
||||
class ParserCreateUserQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserCreateUserQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; }
|
||||
ParserCreateUserQuery & useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; return *this; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "CREATE USER or ALTER USER query"; }
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include <Parsers/ParserDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ParserRowPolicyName.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <Parsers/parseDatabaseAndTableName.h>
|
||||
#include <Parsers/parseUserName.h>
|
||||
#include <ext/range.h>
|
||||
|
||||
@ -14,65 +15,28 @@ namespace
|
||||
using EntityType = IAccessEntity::Type;
|
||||
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;
|
||||
do
|
||||
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)))
|
||||
{
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
res_names.push_back(std::move(name));
|
||||
type = i;
|
||||
return true;
|
||||
}
|
||||
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||
|
||||
names = std::move(res_names);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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, [&]
|
||||
{
|
||||
std::vector<RowPolicy::NameParts> res_name_parts;
|
||||
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;
|
||||
return ParserKeyword{"ON"}.ignore(pos, expected) && ASTQueryWithOnCluster::parse(pos, cluster, expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -83,17 +47,8 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
if (!ParserKeyword{"DROP"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
std::optional<EntityType> type;
|
||||
for (auto type_i : ext::range(EntityType::MAX))
|
||||
{
|
||||
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)
|
||||
EntityType type;
|
||||
if (!parseEntityType(pos, expected, type))
|
||||
return false;
|
||||
|
||||
bool if_exists = false;
|
||||
@ -101,7 +56,8 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
if_exists = true;
|
||||
|
||||
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))
|
||||
{
|
||||
@ -110,30 +66,31 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
}
|
||||
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;
|
||||
row_policy_names = typeid_cast<std::shared_ptr<ASTRowPolicyNames>>(ast);
|
||||
cluster = std::exchange(row_policy_names->cluster, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parseNames(pos, expected, names))
|
||||
if (!parseIdentifiersOrStringLiterals(pos, expected, names))
|
||||
return false;
|
||||
}
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
if (cluster.empty())
|
||||
parseOnCluster(pos, expected, cluster);
|
||||
|
||||
auto query = std::make_shared<ASTDropAccessEntityQuery>();
|
||||
node = query;
|
||||
|
||||
query->type = *type;
|
||||
query->type = type;
|
||||
query->if_exists = if_exists;
|
||||
query->cluster = std::move(cluster);
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
#include <Parsers/ParserGrantQuery.h>
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/CommonParsers.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>
|
||||
|
||||
|
||||
@ -66,15 +68,13 @@ namespace
|
||||
if (!ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected))
|
||||
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;
|
||||
do
|
||||
{
|
||||
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));
|
||||
for (const auto & child : ast->children)
|
||||
res_columns.emplace_back(getIdentifierName(child));
|
||||
|
||||
if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected))
|
||||
return false;
|
||||
@ -84,69 +84,28 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool parseDatabaseAndTableNameOrMaybeAsterisks(
|
||||
IParser::Pos & pos, Expected & expected, String & database_name, bool & any_database, String & table_name, bool & any_table)
|
||||
bool parseAccessTypesWithColumns(IParser::Pos & pos, Expected & expected,
|
||||
std::vector<std::pair<AccessFlags, Strings>> & access_and_columns)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
std::vector<std::pair<AccessFlags, Strings>> res;
|
||||
|
||||
auto parse_access_and_columns = [&]
|
||||
{
|
||||
ASTPtr ast[2];
|
||||
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected))
|
||||
{
|
||||
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))
|
||||
AccessFlags access_flags;
|
||||
if (!parseAccessFlags(pos, expected, access_flags))
|
||||
return false;
|
||||
|
||||
if (ParserToken{TokenType::Dot}.ignore(pos, expected))
|
||||
{
|
||||
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected))
|
||||
{
|
||||
/// <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]);
|
||||
Strings columns;
|
||||
parseColumnNames(pos, expected, columns);
|
||||
res.emplace_back(access_flags, std::move(columns));
|
||||
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, [&]
|
||||
{
|
||||
AccessRightsElements res_elements;
|
||||
do
|
||||
|
||||
auto parse_around_on = [&]
|
||||
{
|
||||
std::vector<std::pair<AccessFlags, Strings>> access_and_columns;
|
||||
do
|
||||
{
|
||||
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 (!parseAccessTypesWithColumns(pos, expected, access_and_columns))
|
||||
return false;
|
||||
|
||||
if (!ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
String database_name, table_name;
|
||||
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;
|
||||
|
||||
for (auto & [access_flags, columns] : access_and_columns)
|
||||
@ -190,8 +141,12 @@ namespace
|
||||
element.table = table_name;
|
||||
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);
|
||||
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, [&]
|
||||
{
|
||||
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;
|
||||
|
||||
roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast);
|
||||
roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
|
||||
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, [&]
|
||||
{
|
||||
@ -230,10 +187,12 @@ namespace
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
to_roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast);
|
||||
to_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -282,14 +241,14 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
}
|
||||
|
||||
AccessRightsElements elements;
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
if (!parseAccessRightsElements(pos, expected, elements) && !parseRoles(pos, expected, attach, roles))
|
||||
return false;
|
||||
|
||||
if (cluster.empty())
|
||||
parseOnCluster(pos, expected, cluster);
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_roles;
|
||||
if (!parseToRoles(pos, expected, kind, to_roles))
|
||||
return false;
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace DB
|
||||
class ParserGrantQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserGrantQuery & enableAttachMode(bool enable) { attach_mode = enable; return *this; }
|
||||
ParserGrantQuery & useAttachMode(bool attach_mode_ = true) { attach_mode = attach_mode_; return *this; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "GRANT or REVOKE query"; }
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <Parsers/ParserSetQuery.h>
|
||||
#include <Parsers/ASTExplainQuery.h>
|
||||
#include <Parsers/ParserShowAccessEntitiesQuery.h>
|
||||
#include <Parsers/ParserShowAccessQuery.h>
|
||||
#include <Parsers/ParserShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/ParserShowGrantsQuery.h>
|
||||
#include <Parsers/ParserShowPrivilegesQuery.h>
|
||||
@ -38,6 +39,7 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
ParserOptimizeQuery optimize_p;
|
||||
ParserKillQueryQuery kill_query_p;
|
||||
ParserWatchQuery watch_p;
|
||||
ParserShowAccessQuery show_access_p;
|
||||
ParserShowAccessEntitiesQuery show_access_entities_p;
|
||||
ParserShowCreateAccessEntityQuery show_create_access_entity_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)
|
||||
|| optimize_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_grants_p.parse(pos, query, expected)
|
||||
|| show_privileges_p.parse(pos, query, expected);
|
||||
|
142
src/Parsers/ParserRolesOrUsersSet.cpp
Normal file
142
src/Parsers/ParserRolesOrUsersSet.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
32
src/Parsers/ParserRolesOrUsersSet.h
Normal file
32
src/Parsers/ParserRolesOrUsersSet.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
196
src/Parsers/ParserRowPolicyName.cpp
Normal file
196
src/Parsers/ParserRowPolicyName.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
47
src/Parsers/ParserRowPolicyName.h
Normal file
47
src/Parsers/ParserRowPolicyName.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@ -1,29 +1,31 @@
|
||||
#include <Parsers/ParserSetRoleQuery.h>
|
||||
#include <Parsers/ASTSetRoleQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/ParserExtendedRoleSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
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, [&]
|
||||
{
|
||||
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;
|
||||
|
||||
roles = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast);
|
||||
roles->can_contain_users = false;
|
||||
roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
|
||||
roles->allow_user_names = false;
|
||||
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, [&]
|
||||
{
|
||||
@ -31,11 +33,13 @@ namespace
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
to_users = typeid_cast<std::shared_ptr<ASTExtendedRoleSet>>(ast);
|
||||
to_users->can_contain_roles = false;
|
||||
to_users = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(ast);
|
||||
to_users->allow_role_names = false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -55,8 +59,8 @@ bool ParserSetRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected
|
||||
else
|
||||
return false;
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> roles;
|
||||
std::shared_ptr<ASTExtendedRoleSet> to_users;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> roles;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> to_users;
|
||||
|
||||
if ((kind == Kind::SET_ROLE) || (kind == Kind::SET_DEFAULT_ROLE))
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <Parsers/ParserSettingsProfileElement.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/ExpressionElementParsers.h>
|
||||
#include <Parsers/ASTSettingsProfileElement.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
@ -11,12 +12,19 @@ namespace DB
|
||||
{
|
||||
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, [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (!parse_id)
|
||||
if (!id_mode)
|
||||
return parseIdentifierOrStringLiteral(pos, expected, res);
|
||||
|
||||
if (!ParserKeyword{"ID"}.ignore(pos, expected))
|
||||
@ -96,52 +104,98 @@ namespace
|
||||
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)
|
||||
{
|
||||
String parent_profile;
|
||||
String setting_name;
|
||||
Field value;
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
std::optional<bool> readonly;
|
||||
std::shared_ptr<ASTSettingsProfileElement> res;
|
||||
if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, false, res))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword{"PROFILE"}.ignore(pos, expected) ||
|
||||
(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;
|
||||
node = res;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -155,15 +209,21 @@ bool ParserSettingsProfileElements::parseImpl(Pos & pos, ASTPtr & node, Expected
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
bool previous_element_was_parent_profile = false;
|
||||
|
||||
auto parse_element = [&]
|
||||
{
|
||||
ASTPtr ast;
|
||||
if (!ParserSettingsProfileElement{}.useIDMode(id_mode).enableInheritKeyword(enable_inherit_keyword).parse(pos, ast, expected))
|
||||
std::shared_ptr<ASTSettingsProfileElement> element;
|
||||
if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, previous_element_was_parent_profile, element))
|
||||
return false;
|
||||
auto element = typeid_cast<std::shared_ptr<ASTSettingsProfileElement>>(ast);
|
||||
elements.push_back(std::move(element));
|
||||
}
|
||||
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||
|
||||
elements.push_back(element);
|
||||
previous_element_was_parent_profile = !element->parent_profile.empty();
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!ParserList::parseUtil(pos, expected, parse_element, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = std::make_shared<ASTSettingsProfileElements>();
|
||||
|
@ -11,8 +11,8 @@ namespace DB
|
||||
class ParserSettingsProfileElement : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserSettingsProfileElement & useIDMode(bool enable_) { id_mode = enable_; return *this; }
|
||||
ParserSettingsProfileElement & enableInheritKeyword(bool enable_) { enable_inherit_keyword = enable_; return *this; }
|
||||
ParserSettingsProfileElement & useIDMode(bool id_mode_ = true) { id_mode = id_mode_; return *this; }
|
||||
ParserSettingsProfileElement & useInheritKeyword(bool use_inherit_keyword_ = true) { use_inherit_keyword = use_inherit_keyword_; return *this; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "SettingsProfileElement"; }
|
||||
@ -20,15 +20,15 @@ protected:
|
||||
|
||||
private:
|
||||
bool id_mode = false;
|
||||
bool enable_inherit_keyword = false;
|
||||
bool use_inherit_keyword = false;
|
||||
};
|
||||
|
||||
|
||||
class ParserSettingsProfileElements : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserSettingsProfileElements & useIDMode(bool enable_) { id_mode = enable_; return *this; }
|
||||
ParserSettingsProfileElements & enableInheritKeyword(bool enable_) { enable_inherit_keyword = enable_; return *this; }
|
||||
ParserSettingsProfileElements & useIDMode(bool id_mode_ = true) { id_mode = id_mode_; return *this; }
|
||||
ParserSettingsProfileElements & useInheritKeyword(bool use_inherit_keyword_ = true) { use_inherit_keyword = use_inherit_keyword_; return *this; }
|
||||
|
||||
protected:
|
||||
const char * getName() const override { return "SettingsProfileElements"; }
|
||||
@ -36,7 +36,7 @@ protected:
|
||||
|
||||
private:
|
||||
bool id_mode = false;
|
||||
bool enable_inherit_keyword = false;
|
||||
bool use_inherit_keyword = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <Parsers/ASTShowAccessEntitiesQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/parseDatabaseAndTableName.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <ext/range.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -9,14 +11,29 @@ namespace DB
|
||||
namespace
|
||||
{
|
||||
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, [&]
|
||||
{
|
||||
database.clear();
|
||||
table_name.clear();
|
||||
return ParserKeyword{"ON"}.ignore(pos, expected) && parseDatabaseAndTableName(pos, expected, database, table_name);
|
||||
return ParserKeyword{"ON"}.ignore(pos, expected)
|
||||
&& parseDatabaseAndTableNameOrAsterisks(pos, expected, database, any_database, table, any_table);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -27,18 +44,15 @@ bool ParserShowAccessEntitiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected
|
||||
if (!ParserKeyword{"SHOW"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
std::optional<EntityType> type;
|
||||
EntityType type;
|
||||
bool all = false;
|
||||
bool current_quota = false;
|
||||
bool current_roles = false;
|
||||
bool enabled_roles = false;
|
||||
|
||||
if (ParserKeyword{"USERS"}.ignore(pos, expected))
|
||||
if (parseEntityType(pos, expected, type))
|
||||
{
|
||||
type = EntityType::USER;
|
||||
}
|
||||
else if (ParserKeyword{"ROLES"}.ignore(pos, expected))
|
||||
{
|
||||
type = EntityType::ROLE;
|
||||
all = true;
|
||||
}
|
||||
else if (ParserKeyword{"CURRENT ROLES"}.ignore(pos, expected))
|
||||
{
|
||||
@ -50,39 +64,44 @@ bool ParserShowAccessEntitiesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected
|
||||
type = EntityType::ROLE;
|
||||
enabled_roles = true;
|
||||
}
|
||||
else if (ParserKeyword{"POLICIES"}.ignore(pos, expected) || ParserKeyword{"ROW POLICIES"}.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))
|
||||
else if (ParserKeyword{"CURRENT QUOTA"}.ignore(pos, expected) || ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
||||
{
|
||||
type = EntityType::QUOTA;
|
||||
current_quota = true;
|
||||
}
|
||||
else if (ParserKeyword{"PROFILES"}.ignore(pos, expected) || ParserKeyword{"SETTINGS PROFILES"}.ignore(pos, expected))
|
||||
{
|
||||
type = EntityType::SETTINGS_PROFILE;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
String database, table_name;
|
||||
String short_name;
|
||||
std::optional<std::pair<String, String>> database_and_table_name;
|
||||
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>();
|
||||
node = query;
|
||||
|
||||
query->type = *type;
|
||||
query->type = type;
|
||||
query->all = all;
|
||||
query->current_quota = current_quota;
|
||||
query->current_roles = current_roles;
|
||||
query->enabled_roles = enabled_roles;
|
||||
query->database = std::move(database);
|
||||
query->table_name = std::move(table_name);
|
||||
query->short_name = std::move(short_name);
|
||||
query->database_and_table_name = std::move(database_and_table_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6,10 +6,12 @@
|
||||
namespace DB
|
||||
{
|
||||
/** Parses queries like
|
||||
* SHOW [ROW] POLICIES [ON [database.]table]
|
||||
SHOW QUOTAS
|
||||
SHOW [CURRENT] QUOTA
|
||||
SHOW [SETTINGS] PROFILES
|
||||
* SHOW USERS
|
||||
* SHOW [CURRENT|ENABLED] ROLES
|
||||
* SHOW [SETTINGS] PROFILES
|
||||
* SHOW [ROW] POLICIES [name | ON [database.]table]
|
||||
* SHOW QUOTAS
|
||||
* SHOW [CURRENT] QUOTA
|
||||
*/
|
||||
class ParserShowAccessEntitiesQuery : public IParserBase
|
||||
{
|
||||
|
32
src/Parsers/ParserShowAccessQuery.h
Normal file
32
src/Parsers/ParserShowAccessQuery.h
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -2,16 +2,65 @@
|
||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||
#include <Parsers/parseDatabaseAndTableName.h>
|
||||
#include <Parsers/ParserRowPolicyName.h>
|
||||
#include <Parsers/ASTRowPolicyName.h>
|
||||
#include <Parsers/parseUserName.h>
|
||||
#include <Parsers/parseDatabaseAndTableName.h>
|
||||
#include <ext/range.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
using EntityType = IAccessEntity::Type;
|
||||
using EntityTypeInfo = IAccessEntity::TypeInfo;
|
||||
namespace ErrorCodes
|
||||
{
|
||||
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)
|
||||
@ -19,65 +68,105 @@ bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expe
|
||||
if (!ParserKeyword{"SHOW CREATE"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
std::optional<EntityType> type;
|
||||
for (auto type_i : ext::range(EntityType::MAX))
|
||||
{
|
||||
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)
|
||||
EntityType type;
|
||||
bool plural;
|
||||
if (!parseEntityType(pos, expected, type, plural))
|
||||
return false;
|
||||
|
||||
String name;
|
||||
Strings names;
|
||||
std::shared_ptr<ASTRowPolicyNames> row_policy_names;
|
||||
bool all = false;
|
||||
bool current_quota = 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))
|
||||
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))
|
||||
case EntityType::USER:
|
||||
{
|
||||
/// SHOW CREATE QUOTA
|
||||
current_quota = true;
|
||||
if (parseCurrentUserTag(pos, expected))
|
||||
current_user = true;
|
||||
else if (parseUserNames(pos, expected, names))
|
||||
{
|
||||
}
|
||||
else if (plural)
|
||||
all = true;
|
||||
else
|
||||
current_user = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == EntityType::SETTINGS_PROFILE)
|
||||
{
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
case EntityType::ROLE:
|
||||
{
|
||||
if (parseRoleNames(pos, expected, names))
|
||||
{
|
||||
}
|
||||
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>();
|
||||
node = query;
|
||||
|
||||
query->type = *type;
|
||||
query->name = std::move(name);
|
||||
query->type = type;
|
||||
query->names = std::move(names);
|
||||
query->current_quota = current_quota;
|
||||
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;
|
||||
}
|
||||
|
@ -6,7 +6,16 @@
|
||||
namespace DB
|
||||
{
|
||||
/** 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 QUOTAS [name [, name2 ...]]
|
||||
*/
|
||||
class ParserShowCreateAccessEntityQuery : public IParserBase
|
||||
{
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include <Parsers/ParserShowGrantsQuery.h>
|
||||
#include <Parsers/ParserRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTRolesOrUsersSet.h>
|
||||
#include <Parsers/ASTShowGrantsQuery.h>
|
||||
#include <Parsers/CommonParsers.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))
|
||||
return false;
|
||||
|
||||
String name;
|
||||
bool current_user = false;
|
||||
std::shared_ptr<ASTRolesOrUsersSet> for_roles;
|
||||
|
||||
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;
|
||||
|
||||
for_roles = typeid_cast<std::shared_ptr<ASTRolesOrUsersSet>>(for_roles_ast);
|
||||
}
|
||||
else
|
||||
current_user = true;
|
||||
{
|
||||
for_roles = std::make_shared<ASTRolesOrUsersSet>();
|
||||
for_roles->current_user = true;
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTShowGrantsQuery>();
|
||||
query->for_roles = std::move(for_roles);
|
||||
node = query;
|
||||
|
||||
query->name = name;
|
||||
query->current_user = current_user;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
77
src/Parsers/ParserUserNameWithHost.cpp
Normal file
77
src/Parsers/ParserUserNameWithHost.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
26
src/Parsers/ParserUserNameWithHost.h
Normal file
26
src/Parsers/ParserUserNameWithHost.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@ -41,4 +41,74 @@ bool parseDatabaseAndTableName(IParser::Pos & pos, Expected & expected, String &
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,10 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Parses [db].name
|
||||
/// Parses [db.]name
|
||||
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);
|
||||
|
||||
}
|
||||
|
@ -3,25 +3,52 @@
|
||||
#include "ExpressionElementParsers.h"
|
||||
#include "ASTLiteral.h"
|
||||
#include "ASTIdentifier.h"
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result)
|
||||
{
|
||||
ASTPtr res;
|
||||
|
||||
if (!ParserIdentifier().parse(pos, res, expected))
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
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;
|
||||
|
||||
result = res->as<ASTLiteral &>().value.safeGet<String>();
|
||||
}
|
||||
else
|
||||
result = getIdentifierName(res);
|
||||
res.emplace_back(std::move(str));
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!ParserList::parseUtil(pos, expected, parse_single_id_or_literal, false))
|
||||
return false;
|
||||
|
||||
result = std::move(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9,4 +9,7 @@ namespace DB
|
||||
* name, `name` or 'name' */
|
||||
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
Loading…
Reference in New Issue
Block a user