提交 4ff7bf78 编写于 作者: A Alexander Tokmakov

add DatabaseCatalog

上级 b7197ba5
......@@ -12,6 +12,7 @@
#include <Interpreters/ProcessList.h>
#include <Interpreters/executeQuery.h>
#include <Interpreters/loadMetadata.h>
#include <Interpreters/DatabaseCatalog.h>
#include <Common/Exception.h>
#include <Common/Macros.h>
#include <Common/Config/ConfigProcessor.h>
......@@ -200,6 +201,7 @@ try
loadMetadataSystem(*context);
attachSystemTables();
loadMetadata(*context);
context->getDatabaseCatalog().loadDatabases();
LOG_DEBUG(log, "Loaded metadata.");
}
else
......
......@@ -41,6 +41,7 @@
#include <Interpreters/ExternalModelsLoader.h>
#include <Interpreters/ProcessList.h>
#include <Interpreters/loadMetadata.h>
#include <Interpreters/DatabaseCatalog.h>
#include <Interpreters/DNSCacheUpdater.h>
#include <Interpreters/SystemLog.cpp>
#include <Interpreters/ExternalLoaderXMLConfigRepository.h>
......@@ -551,6 +552,7 @@ int Server::main(const std::vector<std::string> & /*args*/)
attachSystemTablesServer(*global_context->getDatabase("system"), has_zookeeper);
/// Then, load remaining databases
loadMetadata(*global_context);
global_context->getDatabaseCatalog().loadDatabases();
}
catch (...)
{
......
......@@ -19,8 +19,7 @@ namespace DB
class DatabaseMemory : public DatabaseWithOwnTablesBase
{
public:
//FIXME default name
DatabaseMemory(const String & name_ = "_temporary_and_external_tables");
DatabaseMemory(const String & name_);
String getEngineName() const override { return "Memory"; }
......
......@@ -59,6 +59,7 @@
#include <Common/RemoteHostFilter.h>
#include <Databases/DatabaseMemory.h>
#include <Interpreters/DatabaseCatalog.h>
namespace ProfileEvents
{
......@@ -103,10 +104,8 @@ namespace ErrorCodes
struct TemporaryTableHolder : boost::noncopyable
{
static constexpr const char * database_name = "_temporary_and_external_tables";
TemporaryTableHolder(const Context & context_,
DatabaseMemory & external_tables_,
IDatabase & external_tables_,
const StoragePtr & table,
const ASTPtr & query = {})
: context(context_), external_tables(external_tables_)
......@@ -136,7 +135,7 @@ struct TemporaryTableHolder : boost::noncopyable
StorageID getGlobalTableID() const
{
return StorageID{database_name, "_data_" + toString(id), id};
return StorageID{DatabaseCatalog::TEMPORARY_DATABASE, "_data_" + toString(id), id};
}
StoragePtr getTable() const
......@@ -148,7 +147,7 @@ struct TemporaryTableHolder : boost::noncopyable
}
const Context & context;
DatabaseMemory & external_tables;
IDatabase & external_tables;
UUID id;
};
......@@ -186,8 +185,7 @@ struct ContextShared
String tmp_path; /// Path to the temporary files that occur when processing the request.
mutable VolumePtr tmp_volume; /// Volume for the the temporary files that occur when processing the request.
Databases databases; /// List of databases and tables in them.
DatabaseMemory temporary_and_external_tables;
std::shared_ptr<DatabaseCatalog> database_catalog; /// Manages databases and tables in them.
mutable std::optional<EmbeddedDictionaries> embedded_dictionaries; /// Metrica's dictionaries. Have lazy initialization.
mutable std::optional<ExternalDictionariesLoader> external_dictionaries_loader;
......@@ -319,28 +317,7 @@ struct ContextShared
if (system_logs)
system_logs->shutdown();
/** At this point, some tables may have threads that block our mutex.
* To shutdown them correctly, we will copy the current list of tables,
* and ask them all to finish their work.
* Then delete all objects with tables.
*/
Databases current_databases;
{
std::lock_guard lock(mutex);
current_databases = databases;
}
/// We still hold "databases" in Context (instead of std::move) for Buffer tables to flush data correctly.
for (auto & database : current_databases)
database.second->shutdown();
{
std::lock_guard lock(mutex);
databases.clear();
}
database_catalog->shutdown();
/// Preemptive destruction is important, because these objects may have a refcount to ContextShared (cyclic reference).
/// TODO: Get rid of this.
......@@ -385,6 +362,7 @@ Context Context::createGlobal()
res.row_policy = std::make_shared<RowPolicyContext>();
res.access_rights = std::make_shared<AccessRightsContext>();
res.shared = std::make_shared<ContextShared>();
res.shared->database_catalog = std::make_shared<DatabaseCatalog>(res);
return res;
}
......@@ -406,19 +384,6 @@ MergeList & Context::getMergeList() { return shared->merge_list; }
const MergeList & Context::getMergeList() const { return shared->merge_list; }
const Databases Context::getDatabases() const
{
auto lock = getLock();
return shared->databases;
}
Databases Context::getDatabases()
{
auto lock = getLock();
return shared->databases;
}
Context::SessionKey Context::getSessionKey(const String & session_id) const
{
auto & user_name = client_info.current_user;
......@@ -526,50 +491,66 @@ std::chrono::steady_clock::duration Context::closeSessions() const
return shared->close_interval;
}
DatabaseCatalog & Context::getDatabaseCatalog() const
{
return *shared->database_catalog;
}
Databases Context::getDatabases() const
{
return shared->database_catalog->getDatabases();
}
static String resolveDatabase(const String & database_name, const String & current_database)
String Context::resolveDatabase(const String & database_name) const
{
String res = database_name.empty() ? getCurrentDatabase() : database_name;
if (res.empty())
throw Exception("Default database is not selected", ErrorCodes::UNKNOWN_DATABASE);
return res;
}
String Context::resolveDatabaseAndCheckAccess(const String & database_name) const
{
auto lock = getLock();
String res = database_name.empty() ? current_database : database_name;
if (res.empty())
throw Exception("Default database is not selected", ErrorCodes::UNKNOWN_DATABASE);
return res;
}
//StorageID Context::resolveDatabase(StorageID table_id) const
//{
// table_id.database_name = resolveDatabase(table_id.database_name);
// return table_id;
//}
const DatabasePtr Context::getDatabase(const String & database_name) const
DatabasePtr Context::getDatabase(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
assertDatabaseExists(db);
return shared->databases[db];
auto db = resolveDatabaseAndCheckAccess(database_name);
return shared->database_catalog->getDatabase(db, *this);
}
DatabasePtr Context::getDatabase(const String & database_name)
DatabasePtr Context::tryGetDatabase(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
assertDatabaseExists(db);
return shared->databases[db];
String db = resolveDatabase(database_name);
return shared->database_catalog->tryGetDatabase(database_name, *this);
}
const DatabasePtr Context::tryGetDatabase(const String & database_name) const
bool Context::isDatabaseExist(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
auto it = shared->databases.find(db);
if (it == shared->databases.end())
return {};
return it->second;
String db = resolveDatabaseAndCheckAccess(database_name);
return shared->database_catalog->isDatabaseExist(database_name);
}
DatabasePtr Context::tryGetDatabase(const String & database_name)
void Context::addDatabase(const String & database_name, const DatabasePtr & database)
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
auto it = shared->databases.find(db);
if (it == shared->databases.end())
return {};
return it->second;
shared->database_catalog->attachDatabase(database_name, database, *this);
}
DatabasePtr Context::detachDatabase(const String & database_name)
{
return shared->database_catalog->detachDatabase(database_name, *this);
}
String Context::getPath() const
......@@ -850,26 +831,17 @@ Dependencies Context::getDependencies(const StorageID & from) const
bool Context::isTableExist(const String & database_name, const String & table_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
Databases::const_iterator it = shared->databases.find(db);
return shared->databases.end() != it
&& it->second->isTableExist(*this, table_name);
//FIXME do we need resolve temporary tables here?
auto table_id = resolveStorageID({database_name, table_name});
return shared->database_catalog->isTableExist(table_id, *this);
}
bool Context::isDictionaryExists(const String & database_name, const String & dictionary_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
Databases::const_iterator it = shared->databases.find(db);
return shared->databases.end() != it && it->second->isDictionaryExist(*this, dictionary_name);
}
bool Context::isDatabaseExist(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
return shared->databases.end() != shared->databases.find(db);
String db = resolveDatabaseAndCheckAccess(database_name);
auto db_ptr = shared->database_catalog->tryGetDatabase(database_name, *this);
return db_ptr && db_ptr->isDictionaryExist(*this, dictionary_name);
}
bool Context::isExternalTableExist(const String & table_name) const
......@@ -880,32 +852,18 @@ bool Context::isExternalTableExist(const String & table_name) const
void Context::assertTableDoesntExist(const String & database_name, const String & table_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
Databases::const_iterator it = shared->databases.find(db);
if (shared->databases.end() != it && it->second->isTableExist(*this, table_name))
throw Exception("Table " + backQuoteIfNeed(db) + "." + backQuoteIfNeed(table_name) + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS);
//FIXME do we need resolve temporary tables here? (and do we need this method?)
auto table_id = resolveStorageID({database_name, table_name});
shared->database_catalog->assertTableDoesntExist(table_id, *this);
}
void Context::assertDatabaseExists(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
if (shared->databases.end() == shared->databases.find(db))
throw Exception("Database " + backQuoteIfNeed(db) + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE);
String db = resolveDatabaseAndCheckAccess(database_name);
shared->database_catalog->assertDatabaseExists(db);
}
void Context::assertDatabaseDoesntExist(const String & database_name) const
{
auto lock = getLock();
String db = resolveDatabase(database_name, current_database);
if (shared->databases.end() != shared->databases.find(db))
throw Exception("Database " + backQuoteIfNeed(db) + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS);
}
const Scalars & Context::getScalars() const
{
return scalars;
......@@ -979,41 +937,8 @@ StoragePtr Context::tryGetTable(const StorageID & table_id) const
StoragePtr Context::getTableImpl(const StorageID & table_id, std::optional<Exception> * exception) const
{
String db;
DatabasePtr database;
{
auto lock = getLock();
if (table_id.database_name.empty())
{
StoragePtr res = tryGetExternalTable(table_id.table_name);
if (res)
return res;
}
db = resolveDatabase(table_id.database_name, current_database);
Databases::const_iterator it = shared->databases.find(db);
if (shared->databases.end() == it)
{
if (exception)
exception->emplace("Database " + backQuoteIfNeed(db) + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE);
return {};
}
database = it->second;
}
auto table = database->tryGetTable(*this, table_id.table_name);
if (!table)
{
if (exception)
exception->emplace("Table " + table_id.getNameForLogs() + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
return {};
}
return table;
auto resolved_id = resolveStorageID(table_id);
return shared->database_catalog->getTable(resolved_id, *this, exception);
}
......@@ -1023,7 +948,8 @@ void Context::addExternalTable(const String & table_name, const StoragePtr & sto
if (external_tables_mapping.end() != external_tables_mapping.find(table_name))
throw Exception("Temporary table " + backQuoteIfNeed(table_name) + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS);
external_tables_mapping.emplace(table_name, std::make_shared<TemporaryTableHolder>(*this, shared->temporary_and_external_tables, storage, ast));
auto holder = std::make_shared<TemporaryTableHolder>(*this, *shared->database_catalog->getDatabaseForTemporaryTables(), storage, ast);
external_tables_mapping.emplace(table_name, std::move(holder));
}
......@@ -1106,33 +1032,13 @@ std::unique_ptr<DDLGuard> Context::getDDLGuard(const String & database, const St
return std::make_unique<DDLGuard>(shared->ddl_guards[database], std::move(lock), table);
}
void Context::addDatabase(const String & database_name, const DatabasePtr & database)
{
auto lock = getLock();
assertDatabaseDoesntExist(database_name);
shared->databases[database_name] = database;
}
DatabasePtr Context::detachDatabase(const String & database_name)
{
auto lock = getLock();
auto res = getDatabase(database_name);
shared->databases.erase(database_name);
return res;
}
ASTPtr Context::getCreateExternalTableQuery(const String & table_name) const
{
auto it = external_tables_mapping.find(table_name);
if (external_tables_mapping.end() == it)
throw Exception("Temporary table " + backQuoteIfNeed(table_name) + " doesn't exist", ErrorCodes::UNKNOWN_TABLE);
return shared->temporary_and_external_tables.getCreateTableQuery(*this, it->second->getGlobalTableID().table_name);
return shared->database_catalog->getDatabaseForTemporaryTables()->getCreateTableQuery(*this, it->second->getGlobalTableID().table_name);
}
Settings Context::getSettings() const
......@@ -1215,6 +1121,7 @@ void Context::checkSettingsConstraints(const SettingsChanges & changes)
String Context::getCurrentDatabase() const
{
auto lock = getLock();
return current_database;
}
......@@ -2211,6 +2118,12 @@ void Context::resetInputCallbacks()
input_blocks_reader = {};
}
StorageID Context::resolveStorageID(StorageID storage_id) const
{
auto lock = getLock();
return resolveStorageIDUnlocked(std::move(storage_id));
}
StorageID Context::resolveStorageIDUnlocked(StorageID storage_id) const
{
if (storage_id.uuid != UUIDHelpers::Nil)
......@@ -2228,7 +2141,6 @@ StorageID Context::resolveStorageIDUnlocked(StorageID storage_id) const
throw Exception("Default database is not selected", ErrorCodes::UNKNOWN_DATABASE);
storage_id.database_name = current_database;
}
checkDatabaseAccessRightsImpl(storage_id.database_name);
return storage_id;
}
......
......@@ -144,6 +144,8 @@ struct SubscriptionForUserChange
};
struct TemporaryTableHolder;
class DatabaseCatalog;
using DatabaseCatalogPtr = std::shared_ptr<DatabaseCatalog>;
/** A set of known objects that can be used in the query.
* Consists of a shared part (always common to all sessions and queries)
......@@ -300,6 +302,8 @@ public:
void addDependencyUnsafe(const StorageID & from, const StorageID & where);
void removeDependencyUnsafe(const StorageID & from, const StorageID & where);
DatabaseCatalog & getDatabaseCatalog() const;
/// Checking the existence of the table/database. Database can be empty - in this case the current database is used.
bool isTableExist(const String & database_name, const String & table_name) const;
bool isDatabaseExist(const String & database_name) const;
......@@ -307,7 +311,12 @@ public:
bool isExternalTableExist(const String & table_name) const;
void assertTableDoesntExist(const String & database_name, const String & table_name) const;
void assertDatabaseExists(const String & database_name) const;
void assertDatabaseDoesntExist(const String & database_name) const;
String resolveDatabase(const String & database_name) const;
String resolveDatabaseAndCheckAccess(const String & database_name) const;
//StorageID resolveDatabase(StorageID table_id) const;
StorageID resolveStorageID(StorageID storage_id) const;
StorageID resolveStorageIDUnlocked(StorageID storage_id) const;
const Scalars & getScalars() const;
const Block & getScalar(const String & name) const;
......@@ -321,7 +330,6 @@ public:
void addScalar(const String & name, const Block & block);
bool hasScalar(const String & name) const;
bool removeExternalTable(const String & table_name);
StorageID resolveStorageIDUnlocked(StorageID storage_id) const;
StoragePtr executeTableFunction(const ASTPtr & table_expression);
......@@ -410,13 +418,10 @@ public:
/// Get query for the CREATE table.
ASTPtr getCreateExternalTableQuery(const String & table_name) const;
const DatabasePtr getDatabase(const String & database_name) const;
DatabasePtr getDatabase(const String & database_name);
const DatabasePtr tryGetDatabase(const String & database_name) const;
DatabasePtr tryGetDatabase(const String & database_name);
DatabasePtr getDatabase(const String & database_name) const;
DatabasePtr tryGetDatabase(const String & database_name) const;
const Databases getDatabases() const;
Databases getDatabases();
Databases getDatabases() const;
std::shared_ptr<Context> acquireSession(const String & session_id, std::chrono::steady_clock::duration timeout, bool session_check) const;
void releaseSession(const String & session_id, std::chrono::steady_clock::duration timeout);
......@@ -617,12 +622,6 @@ private:
void calculateUserSettings();
void calculateAccessRights();
/** Check if the current client has access to the specified database.
* If access is denied, throw an exception.
* NOTE: This method should always be called when the `shared->mutex` mutex is acquired.
*/
void checkDatabaseAccessRightsImpl(const std::string & database_name) const;
template <typename... Args>
void checkAccessImpl(const Args &... args) const;
......
#include <Interpreters/DatabaseCatalog.h>
#include <Interpreters/Context.h>
#include <Interpreters/loadMetadata.h>
#include <IO/WriteHelpers.h>
#include <Storages/StorageID.h>
#include <Databases/IDatabase.h>
#include <Databases/DatabaseMemory.h>
namespace DB
{
namespace ErrorCodes
{
extern const int UNKNOWN_DATABASE;
extern const int UNKNOWN_TABLE;
extern const int TABLE_ALREADY_EXISTS;
extern const int DATABASE_ALREADY_EXISTS;
}
void DatabaseCatalog::loadDatabases()
{
auto db_for_temporary_and_external_tables = std::make_shared<DatabaseMemory>(TEMPORARY_DATABASE);
attachDatabase(TEMPORARY_DATABASE, db_for_temporary_and_external_tables, global_context);
}
void DatabaseCatalog::shutdown()
{
/** At this point, some tables may have threads that block our mutex.
* To shutdown them correctly, we will copy the current list of tables,
* and ask them all to finish their work.
* Then delete all objects with tables.
*/
Databases current_databases;
{
std::lock_guard lock(databases_mutex);
current_databases = databases;
}
/// We still hold "databases" (instead of std::move) for Buffer tables to flush data correctly.
for (auto & database : current_databases)
database.second->shutdown();
std::lock_guard lock(databases_mutex);
databases.clear();
for (auto & elem : uuid_map)
{
std::lock_guard map_lock(elem.mutex);
elem.map.clear();
}
}
DatabaseAndTable DatabaseCatalog::tryGetByUUID(const UUID & uuid) const
{
assert(uuid != UUIDHelpers::Nil && 0 <= getFirstLevelIdx(uuid) && getFirstLevelIdx(uuid) < uuid_map.size());
const UUIDToStorageMapPart & map_part = uuid_map[getFirstLevelIdx(uuid)];
std::lock_guard lock{map_part.mutex};
auto it = map_part.map.find(uuid);
if (it == map_part.map.end())
return {};
return it->second;
}
//String DatabaseCatalog::resolveDatabase(const String & database_name, const String & current_database)
//{
// String res = database_name.empty() ? current_database : database_name;
// if (res.empty())
// throw Exception("Default database is not selected", ErrorCodes::UNKNOWN_DATABASE);
// return res;
//}
StoragePtr DatabaseCatalog::getTable(const StorageID & table_id, const Context & local_context, std::optional<Exception> * exception) const
{
//if (table_id.hasUUID())
//{
// auto db_and_table = tryGetByUUID(table_id.uuid);
// if (!db_and_table.first || !db_and_table.second)
// {
// assert(!db_and_table.first && !db_and_table.second);
// if (exception)
// exception->emplace("Table " + table_id.getNameForLogs() + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
// return {};
//
// }
// return db_and_table.second;
//}
std::lock_guard _lock{databases_mutex};
auto it = databases.find(table_id.getDatabaseName());
if (databases.end() == it)
{
if (exception)
exception->emplace("Database " + backQuoteIfNeed(table_id.getDatabaseName()) + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE);
return {};
}
auto database = it->second;
auto table = database->tryGetTable(local_context, table_id.table_name);
if (!table && exception)
exception->emplace("Table " + table_id.getNameForLogs() + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE);
return table;
}
void DatabaseCatalog::assertDatabaseExists(const String & database_name) const
{
std::lock_guard lock{databases_mutex};
assertDatabaseExistsUnlocked(database_name);
}
void DatabaseCatalog::assertDatabaseDoesntExist(const String & database_name) const
{
std::lock_guard lock{databases_mutex};
assertDatabaseDoesntExistUnlocked(database_name);
}
void DatabaseCatalog::assertDatabaseExistsUnlocked(const String & database_name) const
{
if (databases.end() == databases.find(database_name))
throw Exception("Database " + backQuoteIfNeed(database_name) + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE);
}
void DatabaseCatalog::assertDatabaseDoesntExistUnlocked(const String & database_name) const
{
if (databases.end() != databases.find(database_name))
throw Exception("Database " + backQuoteIfNeed(database_name) + " already exists.", ErrorCodes::DATABASE_ALREADY_EXISTS);
}
void DatabaseCatalog::attachDatabase(const String & database_name, const DatabasePtr & database, const Context & /*local_context*/)
{
//local_context.checkDatabaseAccessRights(database_name);
std::lock_guard lock{databases_mutex};
assertDatabaseDoesntExistUnlocked(database_name);
databases[database_name] = database;
}
DatabasePtr DatabaseCatalog::detachDatabase(const String & database_name, const Context & local_context)
{
//local_context.checkDatabaseAccessRights(database_name);
std::lock_guard lock{databases_mutex};
auto res = getDatabase(database_name, local_context); //FIXME locks order
databases.erase(database_name);
return res;
}
DatabasePtr DatabaseCatalog::getDatabase(const String & database_name, const Context & /*local_context*/) const
{
//String db = local_context.resolveDatabase(database_name);
//local_context.checkDatabaseAccessRights(db); //FIXME non-atomic
std::lock_guard lock{databases_mutex};
assertDatabaseExistsUnlocked(database_name);
return databases.find(database_name)->second;
}
DatabasePtr DatabaseCatalog::tryGetDatabase(const String & database_name, const Context & /*local_context*/) const
{
//String db = local_context.resolveDatabase(database_name);
std::lock_guard lock{databases_mutex};
auto it = databases.find(database_name);
if (it == databases.end())
return {};
return it->second;
}
bool DatabaseCatalog::isDatabaseExist(const String & database_name) const
{
std::lock_guard lock{databases_mutex};
return databases.end() != databases.find(database_name);
}
Databases DatabaseCatalog::getDatabases() const
{
std::lock_guard lock{databases_mutex};
return databases;
}
bool DatabaseCatalog::isTableExist(const DB::StorageID & table_id, const DB::Context & context) const
{
//if (table_id.hasUUID())
// return tryGetByUUID(table_id.uuid).second != nullptr;
//else
//{
std::lock_guard lock{databases_mutex};
auto db = databases.find(table_id.database_name);
return db != databases.end() && db->second->isTableExist(context, table_id.table_name);
//}
}
void DatabaseCatalog::assertTableDoesntExist(const StorageID & table_id, const Context & context) const
{
if (!isTableExist(table_id, context))
throw Exception("Table " + table_id.getNameForLogs() + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS);
}
DatabasePtr DatabaseCatalog::getDatabaseForTemporaryTables() const
{
return getDatabase(TEMPORARY_DATABASE, global_context);
}
void DatabaseCatalog::addUUIDMapping(const UUID & uuid, DatabasePtr database, StoragePtr table)
{
assert(uuid != UUIDHelpers::Nil && 0 <= getFirstLevelIdx(uuid) && getFirstLevelIdx(uuid) < uuid_map.size());
UUIDToStorageMapPart & map_part = uuid_map[getFirstLevelIdx(uuid)];
std::lock_guard lock{map_part.mutex};
auto [_, inserted] = map_part.map.try_emplace(uuid, std::move(database), std::move(table));
if (!inserted)
throw Exception("Mapping for table with UUID=" + toString(uuid) + " already exists", ErrorCodes::LOGICAL_ERROR);
}
void DatabaseCatalog::removeUUIDMapping(const UUID & uuid)
{
assert(uuid != UUIDHelpers::Nil && 0 <= getFirstLevelIdx(uuid) && getFirstLevelIdx(uuid) < uuid_map.size());
UUIDToStorageMapPart & map_part = uuid_map[getFirstLevelIdx(uuid)];
std::lock_guard lock{map_part.mutex};
if (!map_part.map.erase(uuid))
throw Exception("Mapping for table with UUID=" + toString(uuid) + " doesn't exist", ErrorCodes::LOGICAL_ERROR);
}
}
#pragma once
#include <Storages/IStorage_fwd.h>
#include <Core/UUID.h>
#include <boost/noncopyable.hpp>
#include <memory>
#include <map>
#include <unordered_map>
#include <mutex>
#include <array>
namespace DB
{
class Context;
class IDatabase;
struct StorageID;
class Exception;
using DatabasePtr = std::shared_ptr<IDatabase>;
using DatabaseAndTable = std::pair<DatabasePtr, StoragePtr>;
//TODO make singleton?
class DatabaseCatalog : boost::noncopyable
{
public:
using Databases = std::map<String, std::shared_ptr<IDatabase>>;
static constexpr const char * TEMPORARY_DATABASE = "_temporary_and_external_tables";
static constexpr const char * SYSTEM_DATABASE = "system";
DatabaseCatalog(Context & global_context_/*, String default_database_*/)
: global_context(global_context_)/*, default_database(std::move(default_database_))*/ {}
void loadDatabases();
void shutdown();
//static String resolveDatabase(const String & database_name, const String & current_database);
void assertDatabaseExists(const String & database_name) const;
void assertDatabaseDoesntExist(const String & database_name) const;
DatabasePtr getDatabaseForTemporaryTables() const;
void attachDatabase(const String & database_name, const DatabasePtr & database, const Context & local_context); // ca, a
DatabasePtr detachDatabase(const String & database_name, const Context & local_context); // (sr), ca, a
DatabasePtr getDatabase(const String & database_name, const Context & local_context) const; // sr, ca, a
DatabasePtr tryGetDatabase(const String & database_name, const Context & local_context) const; // sr
bool isDatabaseExist(const String & database_name) const; // sr, ca
Databases getDatabases() const;
DatabaseAndTable tryGetByUUID(const UUID & uuid) const;
void assertTableDoesntExist(const StorageID & table_id, const Context & context) const; // sr, ca
bool isTableExist(const StorageID & table_id, const Context & context) const; // sr, ca
void addUUIDMapping(const UUID & uuid, DatabasePtr database, StoragePtr table);
void removeUUIDMapping(const UUID & uuid);
StoragePtr getTable(const StorageID & table_id, const Context & local_context, std::optional<Exception> * exception) const;
private:
void assertDatabaseExistsUnlocked(const String & database_name) const;
void assertDatabaseDoesntExistUnlocked(const String & database_name) const;
struct UUIDToStorageMapPart
{
std::unordered_map<UUID, DatabaseAndTable> map;
mutable std::mutex mutex;
};
static constexpr UInt64 bits_for_first_level = 8;
using UUIDToStorageMap = std::array<UUIDToStorageMapPart, 1ull << bits_for_first_level>;
inline size_t getFirstLevelIdx(const UUID & uuid) const
{
return uuid.toUnderType().low >> (64 - bits_for_first_level);
}
private:
[[maybe_unused]] Context & global_context;
mutable std::mutex databases_mutex;
//const String default_database;
Databases databases;
UUIDToStorageMap uuid_map;
};
}
......@@ -2,6 +2,7 @@
#include <Parsers/ASTShowTablesQuery.h>
#include <Parsers/formatAST.h>
#include <Interpreters/Context.h>
#include <Interpreters/DatabaseCatalog.h>
#include <Interpreters/executeQuery.h>
#include <Interpreters/InterpreterShowTablesQuery.h>
#include <Common/typeid_cast.h>
......@@ -36,7 +37,7 @@ String InterpreterShowTablesQuery::getRewrittenQuery()
throw Exception("The `FROM` and `TEMPORARY` cannot be used together in `SHOW TABLES`", ErrorCodes::SYNTAX_ERROR);
String database = query.from.empty() ? context.getCurrentDatabase() : query.from;
context.assertDatabaseExists(database);
context.getDatabaseCatalog().assertDatabaseExists(database);
std::stringstream rewritten_query;
rewritten_query << "SELECT name FROM system.";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册