2019-05-17 14:34:25 +00:00
|
|
|
#include <Databases/DatabasesCommon.h>
|
2017-05-23 18:33:48 +00:00
|
|
|
|
2019-10-16 17:06:52 +00:00
|
|
|
#include <Interpreters/ExternalDictionariesLoader.h>
|
2017-05-23 18:33:48 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Interpreters/InterpreterCreateQuery.h>
|
2019-05-17 14:34:25 +00:00
|
|
|
#include <Parsers/formatAST.h>
|
2019-10-17 13:05:12 +00:00
|
|
|
#include <Storages/StorageDictionary.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Storages/StorageFactory.h>
|
2019-05-17 14:34:25 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2019-10-25 19:07:47 +00:00
|
|
|
#include <Common/escapeForFileName.h>
|
2019-07-18 18:29:49 +00:00
|
|
|
#include <TableFunctions/TableFunctionFactory.h>
|
2019-05-17 14:34:25 +00:00
|
|
|
|
2016-03-26 03:03:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2017-10-27 21:18:06 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_PASSED;
|
2018-03-23 20:46:43 +00:00
|
|
|
extern const int TABLE_ALREADY_EXISTS;
|
|
|
|
extern const int UNKNOWN_TABLE;
|
|
|
|
extern const int LOGICAL_ERROR;
|
2019-10-14 10:04:10 +00:00
|
|
|
extern const int DICTIONARY_ALREADY_EXISTS;
|
2017-10-27 21:18:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 13:05:12 +00:00
|
|
|
namespace
|
2016-03-26 03:03:50 +00:00
|
|
|
{
|
2017-11-21 14:45:40 +00:00
|
|
|
|
2019-10-17 13:05:12 +00:00
|
|
|
StoragePtr getDictionaryStorage(const Context & context, const String & table_name, const String & db_name)
|
2016-03-26 03:03:50 +00:00
|
|
|
{
|
2019-10-17 13:05:12 +00:00
|
|
|
auto dict_name = db_name + "." + table_name;
|
2019-10-17 17:18:54 +00:00
|
|
|
const auto & external_loader = context.getExternalDictionariesLoader();
|
|
|
|
auto dict_ptr = external_loader.tryGetDictionary(dict_name);
|
2019-10-17 13:05:12 +00:00
|
|
|
if (dict_ptr)
|
2019-07-18 18:29:49 +00:00
|
|
|
{
|
2019-10-17 13:05:12 +00:00
|
|
|
const DictionaryStructure & dictionary_structure = dict_ptr->getStructure();
|
|
|
|
auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure);
|
|
|
|
return StorageDictionary::create(db_name, table_name, ColumnsDescription{columns}, context, true, dict_name);
|
2019-07-18 18:29:49 +00:00
|
|
|
}
|
2019-10-17 13:05:12 +00:00
|
|
|
return nullptr;
|
2016-03-26 03:03:50 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 13:05:12 +00:00
|
|
|
}
|
2018-03-23 20:46:43 +00:00
|
|
|
|
|
|
|
bool DatabaseWithOwnTablesBase::isTableExist(
|
|
|
|
const Context & /*context*/,
|
|
|
|
const String & table_name) const
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2019-10-17 13:05:12 +00:00
|
|
|
return tables.find(table_name) != tables.end() || dictionaries.find(table_name) != dictionaries.end();
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 17:33:01 +00:00
|
|
|
bool DatabaseWithOwnTablesBase::isDictionaryExist(
|
2018-03-23 20:46:43 +00:00
|
|
|
const Context & /*context*/,
|
2019-10-10 17:33:01 +00:00
|
|
|
const String & dictionary_name) const
|
2018-03-23 20:46:43 +00:00
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2019-10-10 17:33:01 +00:00
|
|
|
return dictionaries.find(dictionary_name) != dictionaries.end();
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StoragePtr DatabaseWithOwnTablesBase::tryGetTable(
|
2019-10-17 13:05:12 +00:00
|
|
|
const Context & context,
|
2018-03-23 20:46:43 +00:00
|
|
|
const String & table_name) const
|
|
|
|
{
|
2019-10-17 13:05:12 +00:00
|
|
|
{
|
2019-10-17 17:18:54 +00:00
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
auto it = tables.find(table_name);
|
|
|
|
if (it != tables.end())
|
|
|
|
return it->second;
|
2019-10-17 13:05:12 +00:00
|
|
|
}
|
2019-10-17 17:18:54 +00:00
|
|
|
|
|
|
|
if (isDictionaryExist(context, table_name))
|
|
|
|
/// We don't need lock database here, because database doesn't store dictionary itself
|
|
|
|
/// just metadata
|
|
|
|
return getDictionaryStorage(context, table_name, getDatabaseName());
|
|
|
|
|
|
|
|
return {};
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 17:18:54 +00:00
|
|
|
DatabaseTablesIteratorPtr DatabaseWithOwnTablesBase::getTablesWithDictionaryTablesIterator(const Context & context, const FilterByNameFunction & filter_by_name)
|
2019-10-17 13:05:12 +00:00
|
|
|
{
|
2019-10-17 17:18:54 +00:00
|
|
|
auto tables_it = getTablesIterator(context, filter_by_name);
|
|
|
|
auto dictionaries_it = getDictionariesIterator(context, filter_by_name);
|
|
|
|
|
|
|
|
Tables result;
|
|
|
|
while (tables_it && tables_it->isValid())
|
2019-10-17 13:05:12 +00:00
|
|
|
{
|
2019-10-17 17:18:54 +00:00
|
|
|
result.emplace(tables_it->name(), tables_it->table());
|
|
|
|
tables_it->next();
|
2019-10-17 13:05:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 17:18:54 +00:00
|
|
|
while (dictionaries_it && dictionaries_it->isValid())
|
|
|
|
{
|
|
|
|
auto table_name = dictionaries_it->name();
|
2019-10-17 17:53:08 +00:00
|
|
|
auto table_ptr = getDictionaryStorage(context, table_name, getDatabaseName());
|
|
|
|
if (table_ptr)
|
|
|
|
result.emplace(table_name, table_ptr);
|
2019-10-17 17:18:54 +00:00
|
|
|
dictionaries_it->next();
|
|
|
|
}
|
2019-10-17 13:05:12 +00:00
|
|
|
|
2019-10-17 17:18:54 +00:00
|
|
|
return std::make_unique<DatabaseTablesSnapshotIterator>(result);
|
2019-10-17 13:05:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 17:33:01 +00:00
|
|
|
DatabaseTablesIteratorPtr DatabaseWithOwnTablesBase::getTablesIterator(const Context & /*context*/, const FilterByNameFunction & filter_by_table_name)
|
2018-03-23 20:46:43 +00:00
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2019-06-02 12:11:01 +00:00
|
|
|
if (!filter_by_table_name)
|
2019-10-10 17:33:01 +00:00
|
|
|
return std::make_unique<DatabaseTablesSnapshotIterator>(tables);
|
2019-10-17 13:05:12 +00:00
|
|
|
|
2019-06-02 12:11:01 +00:00
|
|
|
Tables filtered_tables;
|
|
|
|
for (const auto & [table_name, storage] : tables)
|
|
|
|
if (filter_by_table_name(table_name))
|
|
|
|
filtered_tables.emplace(table_name, storage);
|
2019-10-17 13:05:12 +00:00
|
|
|
|
2019-10-10 17:33:01 +00:00
|
|
|
return std::make_unique<DatabaseTablesSnapshotIterator>(std::move(filtered_tables));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DatabaseDictionariesIteratorPtr DatabaseWithOwnTablesBase::getDictionariesIterator(const Context & /*context*/, const FilterByNameFunction & filter_by_dictionary_name)
|
|
|
|
{
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
if (!filter_by_dictionary_name)
|
|
|
|
return std::make_unique<DatabaseDictionariesSnapshotIterator>(dictionaries);
|
|
|
|
|
|
|
|
Dictionaries filtered_dictionaries;
|
2019-10-16 14:59:52 +00:00
|
|
|
for (const auto & dictionary_name : dictionaries)
|
2019-10-10 17:33:01 +00:00
|
|
|
if (filter_by_dictionary_name(dictionary_name))
|
2019-10-16 14:59:52 +00:00
|
|
|
filtered_dictionaries.emplace(dictionary_name);
|
2019-10-10 17:33:01 +00:00
|
|
|
return std::make_unique<DatabaseDictionariesSnapshotIterator>(std::move(filtered_dictionaries));
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DatabaseWithOwnTablesBase::empty(const Context & /*context*/) const
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2019-10-10 17:33:01 +00:00
|
|
|
return tables.empty() && dictionaries.empty();
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StoragePtr DatabaseWithOwnTablesBase::detachTable(const String & table_name)
|
|
|
|
{
|
|
|
|
StoragePtr res;
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2019-10-17 13:05:12 +00:00
|
|
|
if (dictionaries.count(table_name))
|
|
|
|
throw Exception("Cannot detach dictionary " + name + "." + table_name + " as table, use DETACH DICTIONARY query.", ErrorCodes::UNKNOWN_TABLE);
|
|
|
|
|
2018-03-23 20:46:43 +00:00
|
|
|
auto it = tables.find(table_name);
|
|
|
|
if (it == tables.end())
|
|
|
|
throw Exception("Table " + name + "." + table_name + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
|
|
|
|
res = it->second;
|
|
|
|
tables.erase(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:09:41 +00:00
|
|
|
void DatabaseWithOwnTablesBase::detachDictionary(const String & dictionary_name, const Context & context, bool reload)
|
2019-10-10 17:33:01 +00:00
|
|
|
{
|
2019-10-16 17:06:52 +00:00
|
|
|
{
|
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
auto it = dictionaries.find(dictionary_name);
|
|
|
|
if (it == dictionaries.end())
|
|
|
|
throw Exception("Dictionary " + name + "." + dictionary_name + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
|
|
|
|
dictionaries.erase(it);
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:09:41 +00:00
|
|
|
if (reload)
|
2019-10-22 16:26:15 +00:00
|
|
|
context.getExternalDictionariesLoader().reload(getDatabaseName() + "." + dictionary_name);
|
2019-10-10 17:33:01 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-03-23 20:46:43 +00:00
|
|
|
void DatabaseWithOwnTablesBase::attachTable(const String & table_name, const StoragePtr & table)
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2018-03-23 20:46:43 +00:00
|
|
|
if (!tables.emplace(table_name, table).second)
|
|
|
|
throw Exception("Table " + name + "." + table_name + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS);
|
|
|
|
}
|
|
|
|
|
2019-10-10 17:33:01 +00:00
|
|
|
|
2019-10-16 17:06:52 +00:00
|
|
|
void DatabaseWithOwnTablesBase::attachDictionary(const String & dictionary_name, const Context & context, bool load)
|
2019-10-10 17:33:01 +00:00
|
|
|
{
|
2019-10-24 09:25:28 +00:00
|
|
|
const auto & external_loader = context.getExternalDictionariesLoader();
|
|
|
|
|
|
|
|
String full_name = getDatabaseName() + "." + dictionary_name;
|
2019-10-16 17:06:52 +00:00
|
|
|
{
|
|
|
|
std::lock_guard lock(mutex);
|
2019-10-24 09:25:28 +00:00
|
|
|
auto status = external_loader.getCurrentStatus(full_name);
|
|
|
|
if (status != ExternalLoader::Status::NOT_EXIST || !dictionaries.emplace(dictionary_name).second)
|
|
|
|
throw Exception(
|
|
|
|
"Dictionary " + full_name + " already exists.",
|
|
|
|
ErrorCodes::DICTIONARY_ALREADY_EXISTS);
|
2019-10-16 17:06:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (load)
|
2019-10-24 09:25:28 +00:00
|
|
|
external_loader.reload(full_name, true);
|
2019-10-10 17:33:01 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 20:46:43 +00:00
|
|
|
void DatabaseWithOwnTablesBase::shutdown()
|
|
|
|
{
|
|
|
|
/// You can not hold a lock during shutdown.
|
|
|
|
/// Because inside `shutdown` function tables can work with database, and mutex is not recursive.
|
|
|
|
|
|
|
|
Tables tables_snapshot;
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2018-03-23 20:46:43 +00:00
|
|
|
tables_snapshot = tables;
|
|
|
|
}
|
|
|
|
|
2018-06-09 15:48:22 +00:00
|
|
|
for (const auto & kv : tables_snapshot)
|
2018-03-23 20:46:43 +00:00
|
|
|
{
|
|
|
|
kv.second->shutdown();
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2018-03-23 20:46:43 +00:00
|
|
|
tables.clear();
|
2019-10-14 09:52:43 +00:00
|
|
|
dictionaries.clear();
|
2018-03-23 20:46:43 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 20:56:45 +00:00
|
|
|
DatabaseWithOwnTablesBase::~DatabaseWithOwnTablesBase()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
shutdown();
|
|
|
|
}
|
2018-11-23 18:52:00 +00:00
|
|
|
catch (...)
|
2018-03-23 20:56:45 +00:00
|
|
|
{
|
|
|
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-26 03:03:50 +00:00
|
|
|
}
|