#include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int INCORRECT_QUERY; } static void extractDependentTable(const ASTSelectQuery & query, String & select_database_name, String & select_table_name) { auto query_table = query.table(); if (!query_table) return; if (auto ast_id = typeid_cast(query_table.get())) { auto query_database = query.database(); if (!query_database) throw Exception("Logical error while creating StorageMaterializedView." " Could not retrieve database name from select query.", DB::ErrorCodes::LOGICAL_ERROR); select_database_name = typeid_cast(*query_database).name; select_table_name = ast_id->name; } else if (auto ast_select = typeid_cast(query_table.get())) { extractDependentTable(*ast_select, select_database_name, select_table_name); } else throw Exception("Logical error while creating StorageMaterializedView." " Could not retrieve table name from select query.", DB::ErrorCodes::LOGICAL_ERROR); } StorageMaterializedView::StorageMaterializedView( const String & table_name_, const String & database_name_, Context & context_, const ASTCreateQuery & query, NamesAndTypesListPtr columns_, const NamesAndTypesList & materialized_columns_, const NamesAndTypesList & alias_columns_, const ColumnDefaults & column_defaults_, bool attach_) : IStorage{materialized_columns_, alias_columns_, column_defaults_}, table_name(table_name_), database_name(database_name_), context(context_), columns(columns_) { if (!query.select) throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY); if (!query.inner_storage) throw Exception("ENGINE of MaterializedView should be specified explicitly", ErrorCodes::INCORRECT_QUERY); extractDependentTable(*query.select, select_database_name, select_table_name); if (!select_table_name.empty()) context.getGlobalContext().addDependency( DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(database_name, table_name)); String inner_table_name = getInnerTableName(); inner_query = query.select->ptr(); /// If there is an ATTACH request, then the internal table must already be connected. if (!attach_) { /// We will create a query to create an internal table. auto manual_create_query = std::make_shared(); manual_create_query->database = database_name; manual_create_query->table = inner_table_name; manual_create_query->set(manual_create_query->columns, query.columns->ptr()); manual_create_query->set(manual_create_query->storage, query.inner_storage->ptr()); /// Execute the query. try { InterpreterCreateQuery create_interpreter(manual_create_query, context); create_interpreter.execute(); } catch (...) { /// In case of any error we should remove dependency to the view. if (!select_table_name.empty()) context.getGlobalContext().removeDependency( DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(database_name, table_name)); throw; } } } NameAndTypePair StorageMaterializedView::getColumn(const String & column_name) const { return getInnerTable()->getColumn(column_name); } bool StorageMaterializedView::hasColumn(const String & column_name) const { return getInnerTable()->hasColumn(column_name); } BlockInputStreams StorageMaterializedView::read( const Names & column_names, const SelectQueryInfo & query_info, const Context & context, QueryProcessingStage::Enum & processed_stage, const size_t max_block_size, const unsigned num_streams) { return getInnerTable()->read(column_names, query_info, context, processed_stage, max_block_size, num_streams); } BlockOutputStreamPtr StorageMaterializedView::write(const ASTPtr & query, const Settings & settings) { return getInnerTable()->write(query, settings); } void StorageMaterializedView::drop() { context.getGlobalContext().removeDependency( DatabaseAndTableName(select_database_name, select_table_name), DatabaseAndTableName(database_name, table_name)); auto inner_table_name = getInnerTableName(); if (context.tryGetTable(database_name, inner_table_name)) { /// We create and execute `drop` query for internal table. auto drop_query = std::make_shared(); drop_query->database = database_name; drop_query->table = inner_table_name; ASTPtr ast_drop_query = drop_query; InterpreterDropQuery drop_interpreter(ast_drop_query, context); drop_interpreter.execute(); } } bool StorageMaterializedView::optimize(const ASTPtr & query, const ASTPtr & partition, bool final, bool deduplicate, const Context & context) { return getInnerTable()->optimize(query, partition, final, deduplicate, context); } StoragePtr StorageMaterializedView::getInnerTable() const { return context.getTable(database_name, getInnerTableName()); } }