DDL dictionary use current database name

This commit is contained in:
Maksim Kita 2021-03-18 14:30:12 +03:00
parent f1223e7548
commit 0f95bcac0b
3 changed files with 74 additions and 3 deletions

View File

@ -80,12 +80,31 @@ public:
std::shared_ptr<const IDictionaryBase> 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<bool> 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);
}

View File

@ -0,0 +1,8 @@
dictGet
0
1
0
dictHas
1
1
0

View File

@ -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;