diff --git a/base/ext/range.h b/base/ext/range.h index c379d453f7b..266016f5779 100644 --- a/base/ext/range.h +++ b/base/ext/range.h @@ -1,42 +1,62 @@ #pragma once -#include #include #include +#include namespace ext { - /// For loop adaptor which is used to iterate through a half-closed interval [begin, end). - template - inline auto range(BeginType begin, EndType end) +namespace internal +{ + template + auto rangeImpl(BeginType begin, EndType end) { - using CommonType = typename std::common_type::type; - return boost::counting_range(begin, end); - } - - template - inline auto range(Type end) - { - return range(static_cast(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 - inline auto range_with_static_cast(BeginType begin, EndType end) - { - using CommonType = typename std::common_type::type; - if constexpr (std::is_same_v) - return boost::counting_range(begin, end); + if constexpr (std::is_same_v) + return boost::counting_range(static_cast(begin), static_cast(end)); else - return boost::counting_range(begin, end) - | boost::adaptors::transformed([](CommonType x) -> ValueType { return static_cast(x); }); - } - - template - inline auto range_with_static_cast(EndType end) - { - return range_with_static_cast(static_cast(0), end); + return boost::counting_range(static_cast(begin), static_cast(end)) + | boost::adaptors::transformed([](CountingType x) { return static_cast(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 || std::is_enum_v) && + (std::is_integral_v || std::is_enum_v) && + (!std::is_enum_v || !std::is_enum_v || std::is_same_v), void>> +inline auto range(BeginType begin, EndType end) +{ + if constexpr (std::is_integral_v && std::is_integral_v) + { + using CommonType = std::common_type_t; + return internal::rangeImpl(begin, end); + } + else if constexpr (std::is_enum_v) + { + return internal::rangeImpl>(begin, end); + } + else + { + return internal::rangeImpl>(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 || std::is_enum_v, void>> +inline auto range(Type end) +{ + if constexpr (std::is_integral_v) + return internal::rangeImpl(0, end); + else + return internal::rangeImpl>(0, end); +} +} diff --git a/src/Access/EnabledQuota.cpp b/src/Access/EnabledQuota.cpp index 92257ce0002..6b3ec33ce6b 100644 --- a/src/Access/EnabledQuota.cpp +++ b/src/Access/EnabledQuota.cpp @@ -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::MAX_RESOURCE_TYPE)) + for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) checkExceeded(user_name, intervals, resource_type, current_time); } }; diff --git a/src/Access/EnabledQuota.h b/src/Access/EnabledQuota.h index e0a04b02206..965d7ea6da9 100644 --- a/src/Access/EnabledQuota.h +++ b/src/Access/EnabledQuota.h @@ -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 { diff --git a/src/Access/EnabledRowPolicies.h b/src/Access/EnabledRowPolicies.h index 6274850363c..5255b2a791c 100644 --- a/src/Access/EnabledRowPolicies.h +++ b/src/Access/EnabledRowPolicies.h @@ -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; + using ParsedConditions = std::array; struct MixedConditions { std::unique_ptr database_and_table_name_keeper; diff --git a/src/Access/Quota.cpp b/src/Access/Quota.cpp index e3a9e11eb10..a5afe5fda4f 100644 --- a/src/Access/Quota.cpp +++ b/src/Access/Quota.cpp @@ -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(resource_type)), ErrorCodes::LOGICAL_ERROR); } } diff --git a/src/Access/Quota.h b/src/Access/Quota.h index 714d582e98f..a3666aa9b52 100644 --- a/src/Access/Quota.h +++ b/src/Access/Quota.h @@ -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(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(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(key_type)), ErrorCodes::LOGICAL_ERROR); } diff --git a/src/Access/QuotaCache.cpp b/src/Access/QuotaCache.cpp index 2939d2d1ef2..842106b3ba9 100644 --- a/src/Access/QuotaCache.cpp +++ b/src/Access/QuotaCache.cpp @@ -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(quota->key_type)), ErrorCodes::LOGICAL_ERROR); } @@ -101,7 +103,7 @@ boost::shared_ptr 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(); diff --git a/src/Access/QuotaUsageInfo.h b/src/Access/QuotaUsageInfo.h index 94e16fb9f69..45ee7898145 100644 --- a/src/Access/QuotaUsageInfo.h +++ b/src/Access/QuotaUsageInfo.h @@ -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 { diff --git a/src/Access/RowPolicy.cpp b/src/Access/RowPolicy.cpp index 65b9451a453..d087705da22 100644 --- a/src/Access/RowPolicy.cpp +++ b/src/Access/RowPolicy.cpp @@ -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(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(index)), ErrorCodes::LOGICAL_ERROR); } } diff --git a/src/Access/RowPolicy.h b/src/Access/RowPolicy.h index 08219edb46b..71f8d14cdb4 100644 --- a/src/Access/RowPolicy.h +++ b/src/Access/RowPolicy.h @@ -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); diff --git a/src/Access/RowPolicyCache.cpp b/src/Access/RowPolicyCache.cpp index 06ccf021dad..b342b735879 100644 --- a/src/Access/RowPolicyCache.cpp +++ b/src/Access/RowPolicyCache.cpp @@ -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(0, MAX_CONDITION_TYPE)) + for (auto type : ext::range(0, MAX_CONDITION_TYPE)) { parsed_conditions[type] = nullptr; const String & condition = policy->conditions[type]; diff --git a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp index 0d3b88facce..469a2f1196b 100644 --- a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp +++ b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp @@ -166,7 +166,7 @@ namespace if (policy.isRestrictive()) query->is_restrictive = policy.isRestrictive(); - for (auto index : ext::range_with_static_cast(RowPolicy::MAX_CONDITION_TYPE)) + for (auto index : ext::range(RowPolicy::MAX_CONDITION_TYPE)) { const auto & condition = policy.conditions[index]; if (!condition.empty()) diff --git a/src/Interpreters/InterpreterShowQuotasQuery.cpp b/src/Interpreters/InterpreterShowQuotasQuery.cpp index 73653e26781..4500046577c 100644 --- a/src/Interpreters/InterpreterShowQuotasQuery.cpp +++ b/src/Interpreters/InterpreterShowQuotasQuery.cpp @@ -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::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 + ")"; diff --git a/src/Parsers/ASTCreateQuotaQuery.cpp b/src/Parsers/ASTCreateQuotaQuery.cpp index edb510d1a2e..e990b9939bc 100644 --- a/src/Parsers/ASTCreateQuotaQuery.cpp +++ b/src/Parsers/ASTCreateQuotaQuery.cpp @@ -67,7 +67,7 @@ namespace else { bool limit_found = false; - for (auto resource_type : ext::range_with_static_cast(Quota::MAX_RESOURCE_TYPE)) + for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) { if (limits.max[resource_type]) { diff --git a/src/Parsers/ASTCreateQuotaQuery.h b/src/Parsers/ASTCreateQuotaQuery.h index b001ec44a0c..ad20348a139 100644 --- a/src/Parsers/ASTCreateQuotaQuery.h +++ b/src/Parsers/ASTCreateQuotaQuery.h @@ -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 { diff --git a/src/Parsers/ParserCreateQuotaQuery.cpp b/src/Parsers/ParserCreateQuotaQuery.cpp index 6007d6206ec..4d29a135131 100644 --- a/src/Parsers/ParserCreateQuotaQuery.cpp +++ b/src/Parsers/ParserCreateQuotaQuery.cpp @@ -48,7 +48,7 @@ namespace return false; const String & key_type_str = key_type_ast->as().value.safeGet(); - for (auto kt : ext::range_with_static_cast(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::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::MAX_RESOURCE_TYPE)) + for (auto rt : ext::range(Quota::MAX_RESOURCE_TYPE)) { if (ParserKeyword{Quota::resourceTypeToKeyword(rt)}.ignore(pos, expected)) { diff --git a/src/Storages/System/StorageSystemQuotaUsage.cpp b/src/Storages/System/StorageSystemQuotaUsage.cpp index 1f943d02446..27400329b27 100644 --- a/src/Storages/System/StorageSystemQuotaUsage.cpp +++ b/src/Storages/System/StorageSystemQuotaUsage.cpp @@ -23,7 +23,7 @@ NamesAndTypesList StorageSystemQuotaUsage::getNamesAndTypes() {"duration", std::make_shared(std::make_shared())}, {"end_of_interval", std::make_shared(std::make_shared())}}; - for (auto resource_type : ext::range_with_static_cast(Quota::MAX_RESOURCE_TYPE)) + for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) { DataTypePtr data_type; if (resource_type == Quota::EXECUTION_TIME) diff --git a/src/Storages/System/StorageSystemQuotas.cpp b/src/Storages/System/StorageSystemQuotas.cpp index a22bb11bbc3..1da7725fe15 100644 --- a/src/Storages/System/StorageSystemQuotas.cpp +++ b/src/Storages/System/StorageSystemQuotas.cpp @@ -20,7 +20,7 @@ namespace DataTypeEnum8::Values getKeyTypeEnumValues() { DataTypeEnum8::Values enum_values; - for (auto key_type : ext::range_with_static_cast(Quota::MAX_KEY_TYPE)) + for (auto key_type : ext::range(Quota::KeyType::MAX)) enum_values.push_back({Quota::getNameOfKeyType(key_type), static_cast(key_type)}); return enum_values; } @@ -38,7 +38,7 @@ NamesAndTypesList StorageSystemQuotas::getNamesAndTypes() {"intervals.duration", std::make_shared(std::make_shared())}, {"intervals.randomize_interval", std::make_shared(std::make_shared())}}; - for (auto resource_type : ext::range_with_static_cast(Quota::MAX_RESOURCE_TYPE)) + for (auto resource_type : ext::range(Quota::MAX_RESOURCE_TYPE)) { DataTypePtr data_type; if (resource_type == Quota::EXECUTION_TIME) diff --git a/src/Storages/System/StorageSystemRowPolicies.cpp b/src/Storages/System/StorageSystemRowPolicies.cpp index 12221cc52de..39fdf926f92 100644 --- a/src/Storages/System/StorageSystemRowPolicies.cpp +++ b/src/Storages/System/StorageSystemRowPolicies.cpp @@ -25,7 +25,7 @@ NamesAndTypesList StorageSystemRowPolicies::getNamesAndTypes() {"restrictive", std::make_shared()}, }; - for (auto index : ext::range_with_static_cast(RowPolicy::MAX_CONDITION_TYPE)) + for (auto index : ext::range(RowPolicy::MAX_CONDITION_TYPE)) names_and_types.push_back({RowPolicy::conditionTypeToColumnName(index), std::make_shared()}); return names_and_types;