2022-12-16 22:57:09 +00:00
|
|
|
#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>
|
2022-12-16 22:57:09 +00:00
|
|
|
#include <unordered_set>
|
|
|
|
#include <string_view>
|
2022-12-21 23:27:22 +00:00
|
|
|
#include <fmt/format.h>
|
2022-12-16 22:57:09 +00:00
|
|
|
#include <regex>
|
|
|
|
|
2022-12-21 23:27:22 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int BAD_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
2022-12-16 22:57:09 +00:00
|
|
|
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-16 22:57:09 +00:00
|
|
|
|
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>
|
2022-12-16 22:57:09 +00:00
|
|
|
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 = {})
|
|
|
|
{
|
2023-01-03 10:37:55 +00:00
|
|
|
NamedCollection::Keys keys = collection.getKeys();
|
2022-12-21 23:27:22 +00:00
|
|
|
auto required_keys_copy = required_keys;
|
2022-12-16 22:57:09 +00:00
|
|
|
|
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, ", "));
|
|
|
|
}
|
|
|
|
}
|
2022-12-16 22:57:09 +00:00
|
|
|
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
};
|