mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-04 21:42:39 +00:00
443 lines
17 KiB
C++
443 lines
17 KiB
C++
#pragma once
|
|
|
|
#include <Core/UUID.h>
|
|
#include <Databases/LoadingStrictnessLevel.h>
|
|
#include <Interpreters/Context_fwd.h>
|
|
#include <Interpreters/executeQuery.h>
|
|
#include <Parsers/IAST_fwd.h>
|
|
#include <Storages/IStorage_fwd.h>
|
|
#include <base/types.h>
|
|
#include <Common/Exception.h>
|
|
#include <Common/AsyncLoader.h>
|
|
#include <Common/PoolId.h>
|
|
#include <Common/ThreadPool_fwd.h>
|
|
#include <QueryPipeline/BlockIO.h>
|
|
|
|
#include <ctime>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
|
|
namespace DB
|
|
{
|
|
|
|
struct Settings;
|
|
struct ConstraintsDescription;
|
|
struct IndicesDescription;
|
|
struct StorageInMemoryMetadata;
|
|
struct StorageID;
|
|
class ASTCreateQuery;
|
|
class AlterCommands;
|
|
class SettingsChanges;
|
|
using DictionariesWithID = std::vector<std::pair<String, UUID>>;
|
|
struct ParsedTablesMetadata;
|
|
struct QualifiedTableName;
|
|
class IRestoreCoordination;
|
|
|
|
namespace ErrorCodes
|
|
{
|
|
extern const int NOT_IMPLEMENTED;
|
|
extern const int CANNOT_GET_CREATE_TABLE_QUERY;
|
|
extern const int LOGICAL_ERROR;
|
|
}
|
|
|
|
class IDatabaseTablesIterator
|
|
{
|
|
public:
|
|
virtual void next() = 0;
|
|
virtual bool isValid() const = 0;
|
|
|
|
virtual const String & name() const = 0;
|
|
|
|
/// This method can return nullptr if it's Lazy database
|
|
/// (a database with support for lazy tables loading
|
|
/// - it maintains a list of tables but tables are loaded lazily).
|
|
virtual const StoragePtr & table() const = 0;
|
|
|
|
explicit IDatabaseTablesIterator(const String & database_name_) : database_name(database_name_) { }
|
|
explicit IDatabaseTablesIterator(String && database_name_) : database_name(std::move(database_name_)) { }
|
|
|
|
virtual ~IDatabaseTablesIterator() = default;
|
|
|
|
virtual UUID uuid() const { return UUIDHelpers::Nil; }
|
|
|
|
const String & databaseName() const { assert(!database_name.empty()); return database_name; }
|
|
|
|
protected:
|
|
String database_name;
|
|
};
|
|
|
|
/// Copies list of tables and iterates through such snapshot.
|
|
class DatabaseTablesSnapshotIterator : public IDatabaseTablesIterator
|
|
{
|
|
private:
|
|
Tables tables;
|
|
Tables::iterator it;
|
|
|
|
// Tasks to wait before returning a table
|
|
using Tasks = std::unordered_map<String, LoadTaskPtr>;
|
|
Tasks tasks;
|
|
|
|
protected:
|
|
DatabaseTablesSnapshotIterator(DatabaseTablesSnapshotIterator && other) noexcept
|
|
: IDatabaseTablesIterator(std::move(other.database_name))
|
|
{
|
|
size_t idx = std::distance(other.tables.begin(), other.it);
|
|
std::swap(tables, other.tables);
|
|
std::swap(tasks, other.tasks);
|
|
other.it = other.tables.end();
|
|
it = tables.begin();
|
|
std::advance(it, idx);
|
|
}
|
|
|
|
public:
|
|
DatabaseTablesSnapshotIterator(const Tables & tables_, const String & database_name_)
|
|
: IDatabaseTablesIterator(database_name_), tables(tables_), it(tables.begin())
|
|
{
|
|
}
|
|
|
|
DatabaseTablesSnapshotIterator(Tables && tables_, String && database_name_)
|
|
: IDatabaseTablesIterator(std::move(database_name_)), tables(std::move(tables_)), it(tables.begin())
|
|
{
|
|
}
|
|
|
|
void next() override { ++it; }
|
|
|
|
bool isValid() const override { return it != tables.end(); }
|
|
|
|
const String & name() const override { return it->first; }
|
|
|
|
const StoragePtr & table() const override
|
|
{
|
|
if (auto task = tasks.find(it->first); task != tasks.end())
|
|
waitLoad(currentPoolOr(TablesLoaderForegroundPoolId), task->second);
|
|
return it->second;
|
|
}
|
|
|
|
void setLoadTasks(const Tasks & tasks_)
|
|
{
|
|
tasks = tasks_;
|
|
}
|
|
};
|
|
|
|
using DatabaseTablesIteratorPtr = std::unique_ptr<IDatabaseTablesIterator>;
|
|
|
|
|
|
/** Database engine.
|
|
* It is responsible for:
|
|
* - initialization of set of known tables and dictionaries;
|
|
* - checking existence of a table and getting a table object;
|
|
* - retrieving a list of all tables;
|
|
* - creating and dropping tables;
|
|
* - renaming tables and moving between databases with same engine.
|
|
*/
|
|
|
|
class IDatabase : public std::enable_shared_from_this<IDatabase>
|
|
{
|
|
public:
|
|
IDatabase() = delete;
|
|
explicit IDatabase(String database_name_);
|
|
|
|
/// Get name of database engine.
|
|
virtual String getEngineName() const = 0;
|
|
|
|
virtual bool canContainMergeTreeTables() const { return true; }
|
|
|
|
virtual bool canContainDistributedTables() const { return true; }
|
|
|
|
/// Load a set of existing tables.
|
|
/// You can call only once, right after the object is created.
|
|
virtual void loadStoredObjects( /// NOLINT
|
|
ContextMutablePtr /*context*/,
|
|
LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
}
|
|
|
|
virtual bool supportsLoadingInTopologicalOrder() const { return false; }
|
|
|
|
virtual void beforeLoadingMetadata(
|
|
ContextMutablePtr /*context*/, LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
}
|
|
|
|
virtual void loadTablesMetadata(ContextPtr /*local_context*/, ParsedTablesMetadata & /*metadata*/, bool /*is_startup*/)
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Not implemented");
|
|
}
|
|
|
|
virtual void loadTableFromMetadata(
|
|
ContextMutablePtr /*local_context*/,
|
|
const String & /*file_path*/,
|
|
const QualifiedTableName & /*name*/,
|
|
const ASTPtr & /*ast*/,
|
|
LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Not implemented");
|
|
}
|
|
|
|
/// Create a task to load table `name` after specified dependencies `startup_after` using `async_loader`.
|
|
/// `load_after` must contain the tasks returned by `loadTableFromMetadataAsync()` for dependent tables (see TablesLoader).
|
|
/// The returned task is also stored inside the database for cancellation on destruction.
|
|
virtual LoadTaskPtr loadTableFromMetadataAsync(
|
|
AsyncLoader & /*async_loader*/,
|
|
LoadJobSet /*load_after*/,
|
|
ContextMutablePtr /*local_context*/,
|
|
const String & /*file_path*/,
|
|
const QualifiedTableName & /*name*/,
|
|
const ASTPtr & /*ast*/,
|
|
LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Not implemented");
|
|
}
|
|
|
|
/// Create a task to startup table `name` after specified dependencies `startup_after` using `async_loader`.
|
|
/// The returned task is also stored inside the database for cancellation on destruction.
|
|
[[nodiscard]] virtual LoadTaskPtr startupTableAsync(
|
|
AsyncLoader & /*async_loader*/,
|
|
LoadJobSet /*startup_after*/,
|
|
const QualifiedTableName & /*name*/,
|
|
LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Not implemented");
|
|
}
|
|
|
|
/// Create a task to startup database after specified dependencies `startup_after` using `async_loader`.
|
|
/// `startup_after` must contain all the tasks returned by `startupTableAsync()` for every table (see TablesLoader).
|
|
/// The returned task is also stored inside the database for cancellation on destruction.
|
|
[[nodiscard]] virtual LoadTaskPtr startupDatabaseAsync(
|
|
AsyncLoader & /*async_loader*/,
|
|
LoadJobSet /*startup_after*/,
|
|
LoadingStrictnessLevel /*mode*/)
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Not implemented");
|
|
}
|
|
|
|
/// Waits for specific table to be started up, i.e. task returned by `startupTableAsync()` is done
|
|
virtual void waitTableStarted(const String & /*name*/) const {}
|
|
|
|
/// Waits for the database to be started up, i.e. task returned by `startupDatabaseAsync()` is done
|
|
/// NOTE: `no_throw` wait should be used during shutdown to (1) prevent race with startup and (2) avoid exceptions if startup failed
|
|
virtual void waitDatabaseStarted(bool /*no_throw*/) const {}
|
|
|
|
/// Check the existence of the table in memory (attached).
|
|
virtual bool isTableExist(const String & name, ContextPtr context) const = 0;
|
|
|
|
/// Check the existence of the table in any state (in active / detached / detached permanently state).
|
|
/// Throws exception when table exists.
|
|
virtual void checkMetadataFilenameAvailability(const String & /*table_name*/) const {}
|
|
|
|
|
|
/// Get the table for work. Return nullptr if there is no table.
|
|
virtual StoragePtr tryGetTable(const String & name, ContextPtr context) const = 0;
|
|
|
|
virtual StoragePtr getTable(const String & name, ContextPtr context) const;
|
|
|
|
virtual UUID tryGetTableUUID(const String & /*table_name*/) const { return UUIDHelpers::Nil; }
|
|
|
|
using FilterByNameFunction = std::function<bool(const String &)>;
|
|
|
|
/// Get an iterator that allows you to pass through all the tables.
|
|
/// It is possible to have "hidden" tables that are not visible when passing through, but are visible if you get them by name using the functions above.
|
|
virtual DatabaseTablesIteratorPtr getTablesIterator(ContextPtr context, const FilterByNameFunction & filter_by_table_name = {}) const = 0; /// NOLINT
|
|
|
|
/// Is the database empty.
|
|
virtual bool empty() const = 0;
|
|
|
|
virtual bool isReadOnly() const { return false; }
|
|
|
|
/// Add the table to the database. Record its presence in the metadata.
|
|
virtual void createTable(
|
|
ContextPtr /*context*/,
|
|
const String & /*name*/,
|
|
const StoragePtr & /*table*/,
|
|
const ASTPtr & /*query*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "There is no CREATE TABLE query for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Delete the table from the database, drop table and delete the metadata.
|
|
virtual void dropTable( /// NOLINT
|
|
ContextPtr /*context*/,
|
|
const String & /*name*/,
|
|
[[maybe_unused]] bool sync = false)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "There is no DROP TABLE query for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Add a table to the database, but do not add it to the metadata. The database may not support this method.
|
|
///
|
|
/// Note: ATTACH TABLE statement actually uses createTable method.
|
|
virtual void attachTable(ContextPtr /* context */, const String & /*name*/, const StoragePtr & /*table*/, [[maybe_unused]] const String & relative_table_path = {}) /// NOLINT
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "There is no ATTACH TABLE query for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Forget about the table without deleting it, and return it. The database may not support this method.
|
|
virtual StoragePtr detachTable(ContextPtr /* context */, const String & /*name*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "There is no DETACH TABLE query for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Forget about the table without deleting it's data, but rename metadata file to prevent reloading it
|
|
/// with next restart. The database may not support this method.
|
|
virtual void detachTablePermanently(ContextPtr /*context*/, const String & /*name*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "There is no DETACH TABLE PERMANENTLY query for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Returns list of table names that were permanently detached.
|
|
/// This list may not be updated in runtime and may be filled only on server startup
|
|
virtual Strings getNamesOfPermanentlyDetachedTables() const
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Cannot get names of permanently detached tables for Database{}", getEngineName());
|
|
}
|
|
|
|
/// Rename the table and possibly move the table to another database.
|
|
virtual void renameTable(
|
|
ContextPtr /*context*/,
|
|
const String & /*name*/,
|
|
IDatabase & /*to_database*/,
|
|
const String & /*to_name*/,
|
|
bool /*exchange*/,
|
|
bool /*dictionary*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "{}: renameTable() is not supported", getEngineName());
|
|
}
|
|
|
|
using ASTModifier = std::function<void(IAST &)>;
|
|
|
|
/// Change the table structure in metadata.
|
|
/// You must call under the alter_lock of the corresponding table . If engine_modifier is empty, then engine does not change.
|
|
virtual void alterTable(
|
|
ContextPtr /*context*/,
|
|
const StorageID & /*table_id*/,
|
|
const StorageInMemoryMetadata & /*metadata*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "{}: alterTable() is not supported", getEngineName());
|
|
}
|
|
|
|
/// Special method for ReplicatedMergeTree and DatabaseReplicated
|
|
virtual bool canExecuteReplicatedMetadataAlter() const { return true; }
|
|
|
|
/// Returns time of table's metadata change, 0 if there is no corresponding metadata file.
|
|
virtual time_t getObjectMetadataModificationTime(const String & /*name*/) const
|
|
{
|
|
return static_cast<time_t>(0);
|
|
}
|
|
|
|
/// Get the CREATE TABLE query for the table. It can also provide information for detached tables for which there is metadata.
|
|
ASTPtr tryGetCreateTableQuery(const String & name, ContextPtr context) const noexcept
|
|
{
|
|
return getCreateTableQueryImpl(name, context, false);
|
|
}
|
|
|
|
ASTPtr getCreateTableQuery(const String & name, ContextPtr context) const
|
|
{
|
|
return getCreateTableQueryImpl(name, context, true);
|
|
}
|
|
|
|
/// Get the CREATE DATABASE query for current database.
|
|
virtual ASTPtr getCreateDatabaseQuery() const = 0;
|
|
|
|
String getDatabaseComment() const
|
|
{
|
|
std::lock_guard lock{mutex};
|
|
return comment;
|
|
}
|
|
void setDatabaseComment(String new_comment)
|
|
{
|
|
std::lock_guard lock{mutex};
|
|
comment = std::move(new_comment);
|
|
}
|
|
|
|
/// Get name of database.
|
|
String getDatabaseName() const
|
|
{
|
|
std::lock_guard lock{mutex};
|
|
return database_name;
|
|
}
|
|
/// Get UUID of database.
|
|
virtual UUID getUUID() const { return UUIDHelpers::Nil; }
|
|
|
|
virtual void renameDatabase(ContextPtr, const String & /*new_name*/)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "{}: RENAME DATABASE is not supported", getEngineName());
|
|
}
|
|
|
|
/// Returns path for persistent data storage if the database supports it, empty string otherwise
|
|
virtual String getDataPath() const { return {}; }
|
|
|
|
/// Returns path for persistent data storage for table if the database supports it, empty string otherwise. Table must exist
|
|
virtual String getTableDataPath(const String & /*table_name*/) const { return {}; }
|
|
/// Returns path for persistent data storage for CREATE/ATTACH query if the database supports it, empty string otherwise
|
|
virtual String getTableDataPath(const ASTCreateQuery & /*query*/) const { return {}; }
|
|
/// Returns metadata path if the database supports it, empty string otherwise
|
|
virtual String getMetadataPath() const { return {}; }
|
|
/// Returns metadata path of a concrete table if the database supports it, empty string otherwise
|
|
virtual String getObjectMetadataPath(const String & /*table_name*/) const { return {}; }
|
|
|
|
/// All tables and dictionaries should be detached before detaching the database.
|
|
virtual bool shouldBeEmptyOnDetach() const { return true; }
|
|
|
|
virtual void assertCanBeDetached(bool /*cleanup*/) {}
|
|
|
|
virtual void waitDetachedTableNotInUse(const UUID & /*uuid*/) { }
|
|
virtual void checkDetachedTableNotInUse(const UUID & /*uuid*/) { }
|
|
|
|
/// Ask all tables to complete the background threads they are using and delete all table objects.
|
|
virtual void shutdown() = 0;
|
|
|
|
/// Delete data and metadata stored inside the database, if exists.
|
|
virtual void drop(ContextPtr /*context*/) {}
|
|
|
|
virtual void applySettingsChanges(const SettingsChanges &, ContextPtr)
|
|
{
|
|
throw Exception(ErrorCodes::NOT_IMPLEMENTED,
|
|
"Database engine {} either does not support settings, or does not support altering settings",
|
|
getEngineName());
|
|
}
|
|
|
|
virtual bool hasReplicationThread() const { return false; }
|
|
|
|
virtual void stopReplication()
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Database engine {} does not run a replication thread!", getEngineName());
|
|
}
|
|
|
|
virtual bool shouldReplicateQuery(const ContextPtr & /*query_context*/, const ASTPtr & /*query_ptr*/) const { return false; }
|
|
|
|
virtual BlockIO tryEnqueueReplicatedDDL(const ASTPtr & /*query*/, ContextPtr /*query_context*/, [[maybe_unused]] QueryFlags flags = {}) /// NOLINT
|
|
{
|
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "Database engine {} does not have replicated DDL queue", getEngineName());
|
|
}
|
|
|
|
/// Returns CREATE TABLE queries and corresponding tables prepared for writing to a backup.
|
|
virtual std::vector<std::pair<ASTPtr, StoragePtr>> getTablesForBackup(const FilterByNameFunction & filter, const ContextPtr & context) const;
|
|
|
|
/// Creates a table restored from backup.
|
|
virtual void createTableRestoredFromBackup(const ASTPtr & create_table_query, ContextMutablePtr context, std::shared_ptr<IRestoreCoordination> restore_coordination, UInt64 timeout_ms);
|
|
|
|
virtual ~IDatabase();
|
|
|
|
protected:
|
|
virtual ASTPtr getCreateTableQueryImpl(const String & /*name*/, ContextPtr /*context*/, bool throw_on_error) const
|
|
{
|
|
if (throw_on_error)
|
|
throw Exception(ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY, "There is no SHOW CREATE TABLE query for Database{}", getEngineName());
|
|
return nullptr;
|
|
}
|
|
|
|
mutable std::mutex mutex;
|
|
String database_name TSA_GUARDED_BY(mutex);
|
|
String comment TSA_GUARDED_BY(mutex);
|
|
};
|
|
|
|
using DatabasePtr = std::shared_ptr<IDatabase>;
|
|
using ConstDatabasePtr = std::shared_ptr<const IDatabase>;
|
|
using Databases = std::map<String, DatabasePtr>;
|
|
|
|
}
|