ClickHouse/src/Storages/NamedCollectionsHelpers.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

159 lines
5.5 KiB
C++
Raw Normal View History

#pragma once
#include <Parsers/IAST_fwd.h>
#include <IO/HTTPHeaderEntries.h>
2022-12-21 23:27:22 +00:00
#include <Common/NamedCollections/NamedCollections.h>
2022-12-29 20:35:20 +00:00
#include <Common/quoteString.h>
#include <unordered_set>
#include <string_view>
2022-12-21 23:27:22 +00:00
#include <fmt/format.h>
#include <regex>
2022-12-21 23:27:22 +00:00
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
namespace DB
{
2023-02-20 20:37:38 +00:00
/// Helper function to get named collection for table engine.
/// Table engines have collection name as first argument of ast and other arguments are key-value overrides.
2023-03-05 21:12:51 +00:00
MutableNamedCollectionPtr tryGetNamedCollectionWithOverrides(
ASTs asts, ContextPtr context, bool throw_unknown_collection = true, std::vector<std::pair<std::string, ASTPtr>> * complex_args = nullptr);
2023-02-20 20:37:38 +00:00
/// Helper function to get named collection for dictionary source.
/// Dictionaries have collection name as name argument of dict configuration and other arguments are overrides.
2023-06-06 12:46:34 +00:00
MutableNamedCollectionPtr tryGetNamedCollectionWithOverrides(const Poco::Util::AbstractConfiguration & config, const std::string & config_prefix, ContextPtr context);
2022-12-21 23:27:22 +00:00
HTTPHeaderEntries getHeadersFromNamedCollection(const NamedCollection & collection);
2023-02-24 19:38:40 +00:00
struct ExternalDatabaseEqualKeysSet
{
2023-02-27 16:42:04 +00:00
static constexpr std::array<std::pair<std::string_view, std::string_view>, 5> equal_keys{
std::pair{"username", "user"}, std::pair{"database", "db"}, std::pair{"hostname", "host"}, std::pair{"addresses_expr", "host"}, std::pair{"addresses_expr", "hostname"}};
2023-02-24 19:38:40 +00:00
};
struct MongoDBEqualKeysSet
{
static constexpr std::array<std::pair<std::string_view, std::string_view>, 4> equal_keys{
std::pair{"username", "user"}, std::pair{"database", "db"}, std::pair{"hostname", "host"}, std::pair{"table", "collection"}};
};
2023-05-17 02:42:52 +00:00
struct RedisEqualKeysSet
{
static constexpr std::array<std::pair<std::string_view, std::string_view>, 4> equal_keys{std::pair{"hostname", "host"}};
};
2023-02-24 19:38:40 +00:00
2023-02-27 20:43:45 +00:00
template <typename EqualKeys> struct NamedCollectionValidateKey
2023-02-24 19:38:40 +00:00
{
2023-02-27 20:43:45 +00:00
NamedCollectionValidateKey() = default;
NamedCollectionValidateKey(const char * value_) : value(value_) {}
NamedCollectionValidateKey(std::string_view value_) : value(value_) {}
NamedCollectionValidateKey(const String & value_) : value(value_) {}
std::string_view value;
bool operator==(const auto & other) const
2023-02-24 19:38:40 +00:00
{
2023-02-27 20:43:45 +00:00
if (value == other.value)
2023-02-24 19:38:40 +00:00
return true;
for (const auto & equal : EqualKeys::equal_keys)
{
2023-02-27 20:43:45 +00:00
if (((equal.first == value) && (equal.second == other.value)) || ((equal.first == other.value) && (equal.second == value)))
{
2023-02-24 19:38:40 +00:00
return true;
2023-02-27 20:43:45 +00:00
}
2023-02-24 19:38:40 +00:00
}
return false;
}
2023-02-27 20:43:45 +00:00
bool operator<(const auto & other) const
{
2023-03-02 18:04:33 +00:00
std::string_view canonical_self = value;
std::string_view canonical_other = other.value;
for (const auto & equal : EqualKeys::equal_keys)
{
if ((equal.first == value) || (equal.second == value))
2023-03-03 15:32:23 +00:00
canonical_self = std::max(canonical_self, std::max(equal.first, equal.second));
2023-03-02 18:04:33 +00:00
if ((equal.first == other.value) || (equal.second == other.value))
2023-03-03 15:32:23 +00:00
canonical_other = std::max(canonical_other, std::max(equal.first, equal.second));
2023-03-02 18:04:33 +00:00
}
return canonical_self < canonical_other;
2023-02-27 20:43:45 +00:00
}
2023-02-24 19:38:40 +00:00
};
2023-03-02 18:04:33 +00:00
template <typename T>
std::ostream & operator << (std::ostream & ostr, const NamedCollectionValidateKey<T> & key)
{
ostr << key.value;
return ostr;
}
2023-02-24 19:38:40 +00:00
2023-03-02 18:04:33 +00:00
template <class keys_cmp> using ValidateKeysMultiset = std::multiset<NamedCollectionValidateKey<keys_cmp>, std::less<NamedCollectionValidateKey<keys_cmp>>>;
using ValidateKeysSet = std::multiset<std::string_view>;
2023-02-24 19:38:40 +00:00
template <typename Keys = ValidateKeysSet>
void validateNamedCollection(
const NamedCollection & collection,
2023-02-24 19:38:40 +00:00
const Keys & required_keys,
const Keys & optional_keys,
2022-12-21 23:27:22 +00:00
const std::vector<std::regex> & optional_regex_keys = {})
{
NamedCollection::Keys keys = collection.getKeys();
2022-12-21 23:27:22 +00:00
auto required_keys_copy = required_keys;
2022-12-21 23:27:22 +00:00
for (const auto & key : keys)
{
if (required_keys_copy.contains(key))
{
required_keys_copy.erase(key);
continue;
}
if (optional_keys.contains(key))
2023-03-02 18:04:33 +00:00
{
2022-12-21 23:27:22 +00:00
continue;
2023-03-02 18:04:33 +00:00
}
2022-12-21 23:27:22 +00:00
2023-03-05 11:50:29 +00:00
if (required_keys.contains(key))
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Duplicate key {} in named collection", key);
2022-12-21 23:27:22 +00:00
auto match = std::find_if(
optional_regex_keys.begin(), optional_regex_keys.end(),
[&](const std::regex & regex) { return std::regex_search(key, regex); })
!= optional_regex_keys.end();
if (!match)
{
2023-02-27 20:43:45 +00:00
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Unexpected key {} in named collection. Required keys: {}, optional keys: {}",
backQuoteIfNeed(key), fmt::join(required_keys, ", "), fmt::join(optional_keys, ", "));
2022-12-21 23:27:22 +00:00
}
}
if (!required_keys_copy.empty())
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Required keys ({}) are not specified. All required keys: {}, optional keys: {}",
fmt::join(required_keys_copy, ", "), fmt::join(required_keys, ", "), fmt::join(optional_keys, ", "));
}
}
}
2023-02-27 20:43:45 +00:00
template <typename T>
struct fmt::formatter<DB::NamedCollectionValidateKey<T>>
{
constexpr static auto parse(format_parse_context & context)
{
return context.begin();
}
template <typename FormatContext>
auto format(const DB::NamedCollectionValidateKey<T> & elem, FormatContext & context)
{
return fmt::format_to(context.out(), "{}", elem.value);
}
};