mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
Improve the function range() to allow iterating through enum values.
This commit is contained in:
parent
c7213ab607
commit
6f15a0d443
@ -1,42 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/range/counting_range.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace ext
|
||||
{
|
||||
/// For loop adaptor which is used to iterate through a half-closed interval [begin, end).
|
||||
template <typename BeginType, typename EndType>
|
||||
inline auto range(BeginType begin, EndType end)
|
||||
namespace internal
|
||||
{
|
||||
template <typename ResultType, typename CountingType, typename BeginType, typename EndType>
|
||||
auto rangeImpl(BeginType begin, EndType end)
|
||||
{
|
||||
using CommonType = typename std::common_type<BeginType, EndType>::type;
|
||||
return boost::counting_range<CommonType>(begin, end);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline auto range(Type end)
|
||||
{
|
||||
return range<Type, Type>(static_cast<Type>(0), end);
|
||||
}
|
||||
|
||||
/// The same as range(), but every value is casted statically to a specified `ValueType`.
|
||||
/// This is useful to iterate through all constants of a enum.
|
||||
template <typename ValueType, typename BeginType, typename EndType>
|
||||
inline auto range_with_static_cast(BeginType begin, EndType end)
|
||||
{
|
||||
using CommonType = typename std::common_type<BeginType, EndType>::type;
|
||||
if constexpr (std::is_same_v<ValueType, CommonType>)
|
||||
return boost::counting_range<CommonType>(begin, end);
|
||||
if constexpr (std::is_same_v<ResultType, CountingType>)
|
||||
return boost::counting_range<CountingType>(static_cast<CountingType>(begin), static_cast<CountingType>(end));
|
||||
else
|
||||
return boost::counting_range<CommonType>(begin, end)
|
||||
| boost::adaptors::transformed([](CommonType x) -> ValueType { return static_cast<ValueType>(x); });
|
||||
}
|
||||
|
||||
template <typename ValueType, typename EndType>
|
||||
inline auto range_with_static_cast(EndType end)
|
||||
{
|
||||
return range_with_static_cast<ValueType, EndType, EndType>(static_cast<EndType>(0), end);
|
||||
return boost::counting_range<CountingType>(static_cast<CountingType>(begin), static_cast<CountingType>(end))
|
||||
| boost::adaptors::transformed([](CountingType x) { return static_cast<ResultType>(x); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// For loop adaptor which is used to iterate through a half-closed interval [begin, end).
|
||||
/// The parameters `begin` and `end` can have any integral or enum types.
|
||||
template <typename BeginType,
|
||||
typename EndType,
|
||||
typename = std::enable_if_t<
|
||||
(std::is_integral_v<BeginType> || std::is_enum_v<BeginType>) &&
|
||||
(std::is_integral_v<EndType> || std::is_enum_v<EndType>) &&
|
||||
(!std::is_enum_v<BeginType> || !std::is_enum_v<EndType> || std::is_same_v<BeginType, EndType>), void>>
|
||||
inline auto range(BeginType begin, EndType end)
|
||||
{
|
||||
if constexpr (std::is_integral_v<BeginType> && std::is_integral_v<EndType>)
|
||||
{
|
||||
using CommonType = std::common_type_t<BeginType, EndType>;
|
||||
return internal::rangeImpl<CommonType, CommonType>(begin, end);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<BeginType>)
|
||||
{
|
||||
return internal::rangeImpl<BeginType, std::underlying_type_t<BeginType>>(begin, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
return internal::rangeImpl<EndType, std::underlying_type_t<EndType>>(begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// For loop adaptor which is used to iterate through a half-closed interval [0, end).
|
||||
/// The parameter `end` can have any integral or enum type.
|
||||
/// The same as range(0, end).
|
||||
template <typename Type,
|
||||
typename = std::enable_if_t<std::is_integral_v<Type> || std::is_enum_v<Type>, void>>
|
||||
inline auto range(Type end)
|
||||
{
|
||||
if constexpr (std::is_integral_v<Type>)
|
||||
return internal::rangeImpl<Type, Type>(0, end);
|
||||
else
|
||||
return internal::rangeImpl<Type, std::underlying_type_t<Type>>(0, end);
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ struct EnabledQuota::Impl
|
||||
const Intervals & intervals,
|
||||
std::chrono::system_clock::time_point current_time)
|
||||
{
|
||||
for (auto resource_type : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
checkExceeded(user_name, intervals, resource_type, current_time);
|
||||
}
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ private:
|
||||
|
||||
const String & getUserName() const { return params.user_name; }
|
||||
|
||||
static constexpr size_t MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
static constexpr auto MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
|
||||
struct Interval
|
||||
{
|
||||
|
@ -58,8 +58,7 @@ private:
|
||||
{
|
||||
size_t operator()(const DatabaseAndTableNameRef & database_and_table_name) const;
|
||||
};
|
||||
static constexpr size_t MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
|
||||
using ParsedConditions = std::array<ASTPtr, MAX_CONDITION_TYPE>;
|
||||
using ParsedConditions = std::array<ASTPtr, RowPolicy::MAX_CONDITION_TYPE>;
|
||||
struct MixedConditions
|
||||
{
|
||||
std::unique_ptr<DatabaseAndTableName> database_and_table_name_keeper;
|
||||
|
@ -5,6 +5,12 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Quota::Limits::Limits()
|
||||
{
|
||||
boost::range::fill(max, 0);
|
||||
@ -38,8 +44,9 @@ const char * Quota::resourceTypeToColumnName(ResourceType resource_type)
|
||||
case Quota::READ_ROWS: return "read_rows";
|
||||
case Quota::READ_BYTES: return "read_bytes";
|
||||
case Quota::EXECUTION_TIME: return "execution_time";
|
||||
case Quota::MAX_RESOURCE_TYPE: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected resource type: " + std::to_string(static_cast<int>(resource_type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,12 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/** Quota for resources consumption for specific interval.
|
||||
* Used to limit resource usage by user.
|
||||
* Quota is applied "softly" - could be slightly exceed, because it is checked usually only on each block of processed data.
|
||||
@ -26,8 +32,9 @@ struct Quota : public IAccessEntity
|
||||
READ_ROWS, /// Number of rows read from tables.
|
||||
READ_BYTES, /// Number of bytes read from tables.
|
||||
EXECUTION_TIME, /// Total amount of query execution time in nanoseconds.
|
||||
|
||||
MAX_RESOURCE_TYPE
|
||||
};
|
||||
static constexpr size_t MAX_RESOURCE_TYPE = 7;
|
||||
|
||||
using ResourceAmount = UInt64;
|
||||
static constexpr ResourceAmount UNLIMITED = 0; /// 0 means unlimited.
|
||||
@ -58,8 +65,9 @@ struct Quota : public IAccessEntity
|
||||
CLIENT_KEY, /// Client should explicitly supply a key to use.
|
||||
CLIENT_KEY_OR_USER_NAME, /// Same as CLIENT_KEY, but use USER_NAME if the client doesn't supply a key.
|
||||
CLIENT_KEY_OR_IP_ADDRESS, /// Same as CLIENT_KEY, but use IP_ADDRESS if the client doesn't supply a key.
|
||||
|
||||
MAX
|
||||
};
|
||||
static constexpr size_t MAX_KEY_TYPE = 6;
|
||||
KeyType key_type = KeyType::NONE;
|
||||
|
||||
/// Which roles or users should use this quota.
|
||||
@ -88,8 +96,9 @@ inline const char * Quota::getNameOfResourceType(ResourceType resource_type)
|
||||
case Quota::READ_ROWS: return "read rows";
|
||||
case Quota::READ_BYTES: return "read bytes";
|
||||
case Quota::EXECUTION_TIME: return "execution time";
|
||||
case Quota::MAX_RESOURCE_TYPE: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected resource type: " + std::to_string(static_cast<int>(resource_type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@ -104,8 +113,9 @@ inline const char * Quota::resourceTypeToKeyword(ResourceType resource_type)
|
||||
case Quota::READ_ROWS: return "READ ROWS";
|
||||
case Quota::READ_BYTES: return "READ BYTES";
|
||||
case Quota::EXECUTION_TIME: return "EXECUTION TIME";
|
||||
case Quota::MAX_RESOURCE_TYPE: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected resource type: " + std::to_string(static_cast<int>(resource_type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@ -119,8 +129,9 @@ inline const char * Quota::getNameOfKeyType(KeyType key_type)
|
||||
case KeyType::CLIENT_KEY: return "client key";
|
||||
case KeyType::CLIENT_KEY_OR_USER_NAME: return "client key or user name";
|
||||
case KeyType::CLIENT_KEY_OR_IP_ADDRESS: return "client key or ip address";
|
||||
case KeyType::MAX: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected quota key type: " + std::to_string(static_cast<int>(key_type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int QUOTA_REQUIRES_CLIENT_KEY;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -72,8 +73,9 @@ String QuotaCache::QuotaInfo::calculateKey(const EnabledQuota & enabled) const
|
||||
return params.client_key;
|
||||
return params.client_address.toString();
|
||||
}
|
||||
case KeyType::MAX: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected quota key type: " + std::to_string(static_cast<int>(quota->key_type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@ -101,7 +103,7 @@ boost::shared_ptr<const EnabledQuota::Intervals> QuotaCache::QuotaInfo::rebuildI
|
||||
new_intervals->quota_key = key;
|
||||
auto & intervals = new_intervals->intervals;
|
||||
intervals.reserve(quota->all_limits.size());
|
||||
static constexpr size_t MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
static constexpr auto MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
for (const auto & limits : quota->all_limits)
|
||||
{
|
||||
intervals.emplace_back();
|
||||
|
@ -11,7 +11,7 @@ struct QuotaUsageInfo
|
||||
{
|
||||
using ResourceType = Quota::ResourceType;
|
||||
using ResourceAmount = Quota::ResourceAmount;
|
||||
static constexpr size_t MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
static constexpr auto MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
|
||||
struct Interval
|
||||
{
|
||||
|
@ -6,6 +6,12 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
void generateFullNameImpl(const String & database_, const String & table_name_, const String & policy_name_, String & full_name_)
|
||||
@ -90,8 +96,9 @@ const char * RowPolicy::conditionTypeToString(ConditionType index)
|
||||
case UPDATE_FILTER: return "UPDATE_FILTER";
|
||||
case UPDATE_CHECK: return "UPDATE_CHECK";
|
||||
case DELETE_FILTER: return "DELETE_FILTER";
|
||||
case MAX_CONDITION_TYPE: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected condition type: " + std::to_string(static_cast<int>(index)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@ -104,8 +111,9 @@ const char * RowPolicy::conditionTypeToColumnName(ConditionType index)
|
||||
case UPDATE_FILTER: return "update_filter";
|
||||
case UPDATE_CHECK: return "update_check";
|
||||
case DELETE_FILTER: return "delete_filter";
|
||||
case MAX_CONDITION_TYPE: break;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
throw Exception("Unexpected condition type: " + std::to_string(static_cast<int>(index)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,8 +44,9 @@ struct RowPolicy : public IAccessEntity
|
||||
UPDATE_FILTER,
|
||||
UPDATE_CHECK,
|
||||
DELETE_FILTER,
|
||||
|
||||
MAX_CONDITION_TYPE
|
||||
};
|
||||
static constexpr size_t MAX_CONDITION_TYPE = 5;
|
||||
static const char * conditionTypeToString(ConditionType index);
|
||||
static const char * conditionTypeToColumnName(ConditionType index);
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace DB
|
||||
namespace
|
||||
{
|
||||
using ConditionType = RowPolicy::ConditionType;
|
||||
constexpr size_t MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
|
||||
constexpr auto MAX_CONDITION_TYPE = RowPolicy::MAX_CONDITION_TYPE;
|
||||
|
||||
|
||||
/// Accumulates conditions from multiple row policies and joins them using the AND logical operation.
|
||||
@ -58,7 +58,7 @@ void RowPolicyCache::PolicyInfo::setPolicy(const RowPolicyPtr & policy_)
|
||||
policy = policy_;
|
||||
roles = &policy->to_roles;
|
||||
|
||||
for (auto type : ext::range_with_static_cast<ConditionType>(0, MAX_CONDITION_TYPE))
|
||||
for (auto type : ext::range(0, MAX_CONDITION_TYPE))
|
||||
{
|
||||
parsed_conditions[type] = nullptr;
|
||||
const String & condition = policy->conditions[type];
|
||||
|
@ -166,7 +166,7 @@ namespace
|
||||
if (policy.isRestrictive())
|
||||
query->is_restrictive = policy.isRestrictive();
|
||||
|
||||
for (auto index : ext::range_with_static_cast<RowPolicy::ConditionType>(RowPolicy::MAX_CONDITION_TYPE))
|
||||
for (auto index : ext::range(RowPolicy::MAX_CONDITION_TYPE))
|
||||
{
|
||||
const auto & condition = policy.conditions[index];
|
||||
if (!condition.empty())
|
||||
|
@ -30,7 +30,7 @@ String InterpreterShowQuotasQuery::getRewrittenQuery()
|
||||
expr = "name || ' key=\\'' || key || '\\'' || if(isNull(end_of_interval), '', ' interval=[' || "
|
||||
"toString(end_of_interval - duration) || ' .. ' || "
|
||||
"toString(end_of_interval) || ']'";
|
||||
for (auto resource_type : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
String column_name = Quota::resourceTypeToColumnName(resource_type);
|
||||
expr += String{" || ' "} + column_name + "=' || toString(" + column_name + ")";
|
||||
|
@ -67,7 +67,7 @@ namespace
|
||||
else
|
||||
{
|
||||
bool limit_found = false;
|
||||
for (auto resource_type : ext::range_with_static_cast<ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
if (limits.max[resource_type])
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
|
||||
using ResourceType = Quota::ResourceType;
|
||||
using ResourceAmount = Quota::ResourceAmount;
|
||||
static constexpr size_t MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
static constexpr auto MAX_RESOURCE_TYPE = Quota::MAX_RESOURCE_TYPE;
|
||||
|
||||
struct Limits
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ namespace
|
||||
return false;
|
||||
|
||||
const String & key_type_str = key_type_ast->as<ASTLiteral &>().value.safeGet<const String &>();
|
||||
for (auto kt : ext::range_with_static_cast<Quota::KeyType>(Quota::MAX_KEY_TYPE))
|
||||
for (auto kt : ext::range(Quota::KeyType::MAX))
|
||||
if (boost::iequals(Quota::getNameOfKeyType(kt), key_type_str))
|
||||
{
|
||||
key_type = kt;
|
||||
@ -56,7 +56,7 @@ namespace
|
||||
}
|
||||
|
||||
String all_key_types_str;
|
||||
for (auto kt : ext::range_with_static_cast<Quota::KeyType>(Quota::MAX_KEY_TYPE))
|
||||
for (auto kt : ext::range(Quota::KeyType::MAX))
|
||||
all_key_types_str += String(all_key_types_str.empty() ? "" : ", ") + "'" + Quota::getNameOfKeyType(kt) + "'";
|
||||
String msg = "Quota cannot be keyed by '" + key_type_str + "'. Expected one of these literals: " + all_key_types_str;
|
||||
throw Exception(msg, ErrorCodes::SYNTAX_ERROR);
|
||||
@ -81,7 +81,7 @@ namespace
|
||||
}
|
||||
|
||||
bool resource_type_set = false;
|
||||
for (auto rt : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
if (ParserKeyword{Quota::resourceTypeToKeyword(rt)}.ignore(pos, expected))
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ NamesAndTypesList StorageSystemQuotaUsage::getNamesAndTypes()
|
||||
{"duration", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
|
||||
{"end_of_interval", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeDateTime>())}};
|
||||
|
||||
for (auto resource_type : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
DataTypePtr data_type;
|
||||
if (resource_type == Quota::EXECUTION_TIME)
|
||||
|
@ -20,7 +20,7 @@ namespace
|
||||
DataTypeEnum8::Values getKeyTypeEnumValues()
|
||||
{
|
||||
DataTypeEnum8::Values enum_values;
|
||||
for (auto key_type : ext::range_with_static_cast<Quota::KeyType>(Quota::MAX_KEY_TYPE))
|
||||
for (auto key_type : ext::range(Quota::KeyType::MAX))
|
||||
enum_values.push_back({Quota::getNameOfKeyType(key_type), static_cast<UInt8>(key_type)});
|
||||
return enum_values;
|
||||
}
|
||||
@ -38,7 +38,7 @@ NamesAndTypesList StorageSystemQuotas::getNamesAndTypes()
|
||||
{"intervals.duration", std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>())},
|
||||
{"intervals.randomize_interval", std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt8>())}};
|
||||
|
||||
for (auto resource_type : ext::range_with_static_cast<Quota::ResourceType>(Quota::MAX_RESOURCE_TYPE))
|
||||
for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE))
|
||||
{
|
||||
DataTypePtr data_type;
|
||||
if (resource_type == Quota::EXECUTION_TIME)
|
||||
|
@ -25,7 +25,7 @@ NamesAndTypesList StorageSystemRowPolicies::getNamesAndTypes()
|
||||
{"restrictive", std::make_shared<DataTypeUInt8>()},
|
||||
};
|
||||
|
||||
for (auto index : ext::range_with_static_cast<RowPolicy::ConditionType>(RowPolicy::MAX_CONDITION_TYPE))
|
||||
for (auto index : ext::range(RowPolicy::MAX_CONDITION_TYPE))
|
||||
names_and_types.push_back({RowPolicy::conditionTypeToColumnName(index), std::make_shared<DataTypeString>()});
|
||||
|
||||
return names_and_types;
|
||||
|
Loading…
Reference in New Issue
Block a user