From 0f95bcac0b962ad86f671aa55a1ac07645633f95 Mon Sep 17 00:00:00 2001 From: Maksim Kita Date: Thu, 18 Mar 2021 14:30:12 +0300 Subject: [PATCH] DDL dictionary use current database name --- src/Functions/FunctionsExternalDictionaries.h | 43 +++++++++++++++++-- ...ionary_use_current_database_name.reference | 8 ++++ ...l_dictionary_use_current_database_name.sql | 26 +++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.reference create mode 100644 tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.sql diff --git a/src/Functions/FunctionsExternalDictionaries.h b/src/Functions/FunctionsExternalDictionaries.h index 4177d686f57..0eeb8d82042 100644 --- a/src/Functions/FunctionsExternalDictionaries.h +++ b/src/Functions/FunctionsExternalDictionaries.h @@ -80,12 +80,31 @@ public: std::shared_ptr getDictionary(const String & dictionary_name) { String resolved_name = DatabaseCatalog::instance().resolveDictionaryName(dictionary_name); - auto dict = external_loader.getDictionary(resolved_name); + + auto dict = external_loader.tryGetDictionary(resolved_name); + + if (!dict) + { + /// If dictionary not found. And database was not implicitly specified + /// we can qualify dictionary name with current database name. + /// It will help if dictionary is created with DDL and is in current database. + if (dictionary_name.find('.') == std::string::npos) + { + String dictionary_name_with_database = context.getCurrentDatabase() + '.' + dictionary_name; + resolved_name = DatabaseCatalog::instance().resolveDictionaryName(dictionary_name_with_database); + dict = external_loader.tryGetDictionary(resolved_name); + } + } + + if (!dict) + throw Exception(ErrorCodes::BAD_ARGUMENTS, "External dictionary ({}) not found", dictionary_name); + if (!access_checked) { context.checkAccess(AccessType::dictGet, dict->getDatabaseOrNoDatabaseTag(), dict->getDictionaryID().getTableName()); access_checked = true; } + return dict; } @@ -118,14 +137,29 @@ public: DictionaryStructure getDictionaryStructure(const String & dictionary_name) const { String resolved_name = DatabaseCatalog::instance().resolveDictionaryName(dictionary_name); + auto load_result = external_loader.getLoadResult(resolved_name); + if (!load_result.config) + { + /// If dictionary not found. And database was not implicitly specified + /// we can qualify dictionary name with current database name. + /// It will help if dictionary is created with DDL and is in current database. + if (dictionary_name.find('.') == std::string::npos) + { + String dictionary_name_with_database = context.getCurrentDatabase() + '.' + dictionary_name; + resolved_name = DatabaseCatalog::instance().resolveDictionaryName(dictionary_name_with_database); + load_result = external_loader.getLoadResult(resolved_name); + } + } + if (!load_result.config) throw Exception("Dictionary " + backQuote(dictionary_name) + " not found", ErrorCodes::BAD_ARGUMENTS); + return ExternalDictionariesLoader::getDictionaryStructure(*load_result.config); } -private: const Context & context; +private: const ExternalDictionariesLoader & external_loader; /// Access cannot be not granted, since in this case checkAccess() will throw and access_checked will not be updated. std::atomic access_checked = false; @@ -296,10 +330,13 @@ public: DataTypes types; + auto current_database_name = helper.context.getCurrentDatabase(); + auto dictionary_structure = helper.getDictionaryStructure(dictionary_name); + for (auto & attribute_name : attribute_names) { /// We're extracting the return type from the dictionary's config, without loading the dictionary. - auto attribute = helper.getDictionaryStructure(dictionary_name).getAttribute(attribute_name); + auto attribute = dictionary_structure.getAttribute(attribute_name); types.emplace_back(attribute.type); } diff --git a/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.reference b/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.reference new file mode 100644 index 00000000000..6594f6baa3d --- /dev/null +++ b/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.reference @@ -0,0 +1,8 @@ +dictGet +0 +1 +0 +dictHas +1 +1 +0 diff --git a/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.sql b/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.sql new file mode 100644 index 00000000000..93cf5a3f009 --- /dev/null +++ b/tests/queries/0_stateless/01760_ddl_dictionary_use_current_database_name.sql @@ -0,0 +1,26 @@ +DROP TABLE IF EXISTS ddl_dictonary_test_source; +CREATE TABLE ddl_dictonary_test_source +( + id UInt64, + value UInt64 +) +ENGINE = TinyLog; + +INSERT INTO ddl_dictonary_test_source VALUES (0, 0); +INSERT INTO ddl_dictonary_test_source VALUES (1, 1); + +DROP DICTIONARY IF EXISTS ddl_dictionary_test; +CREATE DICTIONARY ddl_dictionary_test +( + id UInt64, + value UInt64 DEFAULT 0 +) +PRIMARY KEY id +SOURCE(CLICKHOUSE(HOST 'localhost' PORT tcpPort() USER 'default' TABLE 'ddl_dictonary_test_source')) +LAYOUT(DIRECT()); + +SELECT 'dictGet'; +SELECT dictGet('ddl_dictionary_test', 'value', number) FROM system.numbers LIMIT 3; + +SELECT 'dictHas'; +SELECT dictHas('ddl_dictionary_test', number) FROM system.numbers LIMIT 3;