#pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { using Poco::SharedPtr; /// имя таблицы -> таблица typedef std::map Tables; /// имя БД -> таблицы typedef std::map Databases; /** Набор известных объектов, которые могут быть использованы в запросе. */ struct Context { String path; /// Путь к директории с данными, со слешем на конце. SharedPtr databases; /// Список БД и таблиц в них. String current_database; /// Текущая БД. SharedPtr functions; /// Обычные функции. AggregateFunctionFactoryPtr aggregate_function_factory; /// Агрегатные функции. DataTypeFactoryPtr data_type_factory; /// Типы данных. StorageFactoryPtr storage_factory; /// Движки таблиц. FormatFactoryPtr format_factory; /// Форматы. NamesAndTypesList columns; /// Столбцы текущей обрабатываемой таблицы. Settings settings; /// Настройки выполнения запроса. Logger * log; /// Логгер. mutable SharedPtr mutex; /// Для доступа и модификации разделяемых объектов. Context() : databases(new Databases), functions(new Functions), log(&Logger::get("Context")), mutex(new Poco::Mutex) {} /** В сервере есть глобальный контекст. * При соединении, он копируется в контекст сессии. * Для каждого запроса, контекст сессии копируется в контекст запроса. * Блокировка нужна, так как запрос может модифицировать глобальный контекст (SET GLOBAL ...). */ Context(const Context & rhs) { Poco::ScopedLock lock(*rhs.mutex); path = rhs.path; databases = rhs.databases; current_database = rhs.current_database; functions = rhs.functions; aggregate_function_factory = rhs.aggregate_function_factory; data_type_factory = rhs.data_type_factory; storage_factory = rhs.storage_factory; columns = rhs.columns; settings = rhs.settings; log = rhs.log; mutex = rhs.mutex; } /// Проверка существования таблицы. database может быть пустой - в этом случае используется текущая БД. bool isTableExist(const String & database_name, const String & table_name) { Poco::ScopedLock lock(*mutex); String db = database_name.empty() ? current_database : database_name; return databases->end() == databases->find(db) || (*databases)[db].end() == (*databases)[db].find(table_name); } void assertTableExists(const String & database_name, const String & table_name) { Poco::ScopedLock lock(*mutex); String db = database_name.empty() ? current_database : database_name; if (databases->end() == databases->find(db)) throw Exception("Database " + db + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE); if ((*databases)[db].end() == (*databases)[db].find(table_name)) throw Exception("Table " + db + "." + table_name + " doesn't exist.", ErrorCodes::UNKNOWN_TABLE); } void assertTableDoesntExist(const String & database_name, const String & table_name) { Poco::ScopedLock lock(*mutex); String db = database_name.empty() ? current_database : database_name; if (databases->end() != databases->find(db) && (*databases)[db].end() != (*databases)[db].find(table_name)) throw Exception("Table " + db + "." + table_name + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS); } void assertDatabaseExists(const String & database_name) { Poco::ScopedLock lock(*mutex); String db = database_name.empty() ? current_database : database_name; if (databases->end() == databases->find(db)) throw Exception("Database " + db + " doesn't exist", ErrorCodes::UNKNOWN_DATABASE); } }; }