#include "NamedCollectionsHelpers.h" #include #include #include #include #include namespace DB { namespace { NamedCollectionPtr tryGetNamedCollectionFromASTs(ASTs asts) { if (asts.empty()) return nullptr; const auto * identifier = asts[0]->as(); if (!identifier) return nullptr; const auto & collection_name = identifier->name(); return NamedCollectionFactory::instance().tryGet(collection_name); } std::optional> getKeyValueFromAST(ASTPtr ast) { const auto * function = ast->as(); if (!function || function->name != "equals") return std::nullopt; const auto * function_args_expr = assert_cast(function->arguments.get()); const auto & function_args = function_args_expr->children; if (function_args.size() != 2) return std::nullopt; auto literal_key = evaluateConstantExpressionOrIdentifierAsLiteral( function_args[0], Context::getGlobalContextInstance()); auto key = checkAndGetLiteralArgument(literal_key, "key"); auto literal_value = evaluateConstantExpressionOrIdentifierAsLiteral( function_args[1], Context::getGlobalContextInstance()); auto value = literal_value->as()->value; return std::pair{key, value}; } } NamedCollectionPtr tryGetNamedCollectionWithOverrides(ASTs asts) { if (asts.empty()) return nullptr; auto collection = tryGetNamedCollectionFromASTs(asts); if (!collection) return nullptr; if (asts.size() == 1) return collection; auto collection_copy = collection->duplicate(); for (const auto & ast : asts) { auto value_override = getKeyValueFromAST(ast); if (!value_override) continue; const auto & [key, value] = *value_override; collection_copy->set(key, toString(value)); } return collection_copy; } void validateNamedCollection( const NamedCollection & collection, const std::unordered_set & required_keys, const std::unordered_set & optional_keys) { const auto & keys = collection.getKeys(); for (const auto & key : keys) { if (!required_keys.contains(key) && !optional_keys.contains(key)) { throw Exception( ErrorCodes::BAD_ARGUMENTS, "Unexpected key `{}` in named collection. Required keys: {}, optional keys: {}", key, fmt::join(required_keys, ", "), fmt::join(optional_keys, ", ")); } } for (const auto & key : required_keys) { if (!keys.contains(key)) { throw Exception( ErrorCodes::BAD_ARGUMENTS, "Key `{}` is required, but not specified. Required keys: {}, optional keys: {}", key, fmt::join(required_keys, ", "), fmt::join(optional_keys, ", ")); } } } }