ClickHouse/src/Storages/StorageMaterializedView.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

617 lines
24 KiB
C++
Raw Normal View History

#include <Storages/StorageMaterializedView.h>
2023-02-12 19:17:55 +00:00
#include <Storages/MaterializedView/RefreshTask.h>
#include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTCreateQuery.h>
2017-05-23 18:33:48 +00:00
#include <Interpreters/Context.h>
#include <Interpreters/InterpreterCreateQuery.h>
#include <Interpreters/InterpreterDropQuery.h>
#include <Interpreters/InterpreterRenameQuery.h>
2023-02-12 19:17:55 +00:00
#include <Interpreters/InterpreterInsertQuery.h>
#include <Interpreters/getTableExpressions.h>
#include <Interpreters/getHeaderForProcessingStage.h>
#include <Access/Common/AccessFlags.h>
#include <Storages/AlterCommands.h>
#include <Storages/StorageFactory.h>
#include <Storages/ReadInOrderOptimizer.h>
#include <Storages/SelectQueryDescription.h>
2017-07-13 20:58:19 +00:00
#include <Common/typeid_cast.h>
#include <Common/checkStackSize.h>
2022-05-20 19:49:31 +00:00
#include <QueryPipeline/Pipe.h>
2021-09-08 18:29:38 +00:00
#include <Processors/QueryPlan/QueryPlan.h>
#include <Processors/QueryPlan/ExpressionStep.h>
2021-03-04 17:38:12 +00:00
#include <Processors/QueryPlan/BuildQueryPipelineSettings.h>
#include <Processors/QueryPlan/Optimizations/QueryPlanOptimizationSettings.h>
2021-07-23 19:33:59 +00:00
#include <Processors/Sinks/SinkToStorage.h>
#include <Backups/BackupEntriesCollector.h>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
2020-02-25 18:02:41 +00:00
extern const int NOT_IMPLEMENTED;
extern const int INCORRECT_QUERY;
2023-02-12 19:17:55 +00:00
}
2023-02-12 19:17:55 +00:00
namespace ActionLocks
{
extern const StorageActionBlockType ViewRefresh;
}
2020-03-18 17:38:52 +00:00
static inline String generateInnerTableName(const StorageID & view_id)
{
2020-03-18 17:38:52 +00:00
if (view_id.hasUUID())
2020-03-20 00:07:52 +00:00
return ".inner_id." + toString(view_id.uuid);
2020-03-18 17:38:52 +00:00
return ".inner." + view_id.getTableName();
}
/// Remove columns from target_header that does not exists in src_header
static void removeNonCommonColumns(const Block & src_header, Block & target_header)
{
std::set<size_t> target_only_positions;
for (const auto & column : target_header)
{
if (!src_header.has(column.name))
target_only_positions.insert(target_header.getPositionByName(column.name));
}
target_header.erase(target_only_positions);
}
StorageMaterializedView::StorageMaterializedView(
2019-12-04 16:06:55 +00:00
const StorageID & table_id_,
ContextPtr local_context,
const ASTCreateQuery & query,
const ColumnsDescription & columns_,
bool attach_,
const String & comment)
2021-05-31 14:49:02 +00:00
: IStorage(table_id_), WithMutableContext(local_context->getGlobalContext())
{
2020-06-19 15:39:41 +00:00
StorageInMemoryMetadata storage_metadata;
storage_metadata.setColumns(columns_);
2019-08-24 21:20:20 +00:00
if (!query.select)
throw Exception(ErrorCodes::INCORRECT_QUERY, "SELECT query is not specified for {}", getName());
2019-12-10 19:48:16 +00:00
/// If the destination table is not set, use inner table
2019-12-10 19:48:16 +00:00
has_inner_table = query.to_table_id.empty();
2019-12-10 19:48:16 +00:00
if (has_inner_table && !query.storage)
throw Exception(ErrorCodes::INCORRECT_QUERY,
"You must specify where to save results of a MaterializedView query: "
"either ENGINE or an existing table in a TO clause");
2023-11-29 02:32:41 +00:00
auto select = SelectQueryDescription::getSelectQueryFromASTForMatView(query.select->clone(), query.refresh_strategy != nullptr, local_context);
2020-06-19 15:39:41 +00:00
storage_metadata.setSelectQuery(select);
if (!comment.empty())
storage_metadata.setComment(comment);
2023-11-29 02:32:41 +00:00
if (query.refresh_strategy)
storage_metadata.setRefresh(query.refresh_strategy->clone());
2020-06-19 15:39:41 +00:00
setInMemoryMetadata(storage_metadata);
2020-01-31 17:12:18 +00:00
2021-04-13 20:14:05 +00:00
bool point_to_itself_by_uuid = has_inner_table && query.to_inner_uuid != UUIDHelpers::Nil
&& query.to_inner_uuid == table_id_.uuid;
bool point_to_itself_by_name = !has_inner_table && query.to_table_id.database_name == table_id_.database_name
&& query.to_table_id.table_name == table_id_.table_name;
2021-04-13 19:13:26 +00:00
if (point_to_itself_by_uuid || point_to_itself_by_name)
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Materialized view {} cannot point to itself", table_id_.getFullTableName());
2019-12-10 19:48:16 +00:00
if (!has_inner_table)
{
2019-12-10 19:48:16 +00:00
target_table_id = query.to_table_id;
}
2019-12-10 19:48:16 +00:00
else if (attach_)
{
2019-12-10 19:48:16 +00:00
/// If there is an ATTACH request, then the internal table must already be created.
2021-03-08 17:26:38 +00:00
target_table_id = StorageID(getStorageID().database_name, generateInnerTableName(getStorageID()), query.to_inner_uuid);
}
else
{
/// We will create a query to create an internal table.
auto create_context = Context::createCopy(local_context);
auto manual_create_query = std::make_shared<ASTCreateQuery>();
manual_create_query->setDatabase(getStorageID().database_name);
manual_create_query->setTable(generateInnerTableName(getStorageID()));
2021-03-08 17:26:38 +00:00
manual_create_query->uuid = query.to_inner_uuid;
Data Skipping Indices (#4143) * made index parser * added index parsing * some fixes * added index interface and factory * fixed compilation * ptrs * added indexParts * indextypes * index condition * IndexCondition * added indexes in selectexecutor * fix * changed comment * fix * added granularity * comments * fix * fix * added writing indexes * removed indexpart class * fix * added setSkipIndexes * add rw for MergeTreeIndexes * fixes * upd error * fix * fix * reading * test index * fixed nullptr error * fixed * fix * unique names * asts -> exprlist * minmax index * fix * fixed select * fixed merging * fixed mutation * working minmax * removed test index * fixed style * added indexes to checkDataPart * added tests for minmax index * fixed constructor * fix style * fixed includes * fixed setSkipIndexes * added indexes meta to zookeeper * added parsing * removed throw * alter cmds parse * fix * added alter * fix * alters fix * fix alters * fix "after" * fixed alter * alter fix + test * fixes * upd setSkipIndexes * fixed alter bug with drop all indices * fix metadata editing * new test and repl fix * rm test files * fixed repl alter * fix * fix * indices * MTReadStream * upd test for bug * fix * added useful parsers and ast classes * fix * fix comments * replaced columns * fix * fixed parsing * fixed printing * fix err * basic IndicesDescription * go to IndicesDescr * moved indices * go to indicesDescr * fix test minmax_index* * fixed MT alter * fixed bug with replMT indices storing in zk * rename * refactoring * docs ru * docs ru * docs en * refactor * rename tests * fix docs * refactoring * fix * fix * fix * fixed style * unique idx * unique * fix * better minmax calculation * upd * added getBlock * unique_condition * added termForAST * unique * fixed not * uniqueCondition::mayBeTrueOnGranule * fix * fixed bug with double column * is always true * fix * key set * spaces * test * tests * fix * unique * fix * fix * fixed bug with duplicate column * removed unused data * fix * fixes * __bitSwapLastTwo * fix
2019-02-05 14:50:25 +00:00
auto new_columns_list = std::make_shared<ASTColumns>();
new_columns_list->set(new_columns_list->columns, query.columns_list->columns->ptr());
manual_create_query->set(manual_create_query->columns_list, new_columns_list);
manual_create_query->set(manual_create_query->storage, query.storage->ptr());
2021-01-26 17:51:25 +00:00
InterpreterCreateQuery create_interpreter(manual_create_query, create_context);
2019-12-10 19:48:16 +00:00
create_interpreter.setInternal(true);
create_interpreter.execute();
target_table_id = DatabaseCatalog::instance().getTable({manual_create_query->getDatabase(), manual_create_query->getTable()}, getContext())->getStorageID();
}
2023-02-12 19:17:55 +00:00
if (query.refresh_strategy)
refresher = RefreshTask::create(
*this,
getContext(),
*query.refresh_strategy);
}
QueryProcessingStage::Enum StorageMaterializedView::getQueryProcessingStage(
ContextPtr local_context,
QueryProcessingStage::Enum to_stage,
const StorageSnapshotPtr &,
SelectQueryInfo & query_info) const
{
/// TODO: Find a way to support projections for StorageMaterializedView. Why do we use different
/// metadata for materialized view and target table? If they are the same, we can get rid of all
/// converting and use it just like a normal view.
query_info.ignore_projections = true;
const auto & target_metadata = getTargetTable()->getInMemoryMetadataPtr();
return getTargetTable()->getQueryProcessingStage(local_context, to_stage, getTargetTable()->getStorageSnapshot(target_metadata, local_context), query_info);
}
void StorageMaterializedView::read(
QueryPlan & query_plan,
const Names & column_names,
const StorageSnapshotPtr & storage_snapshot,
SelectQueryInfo & query_info,
ContextPtr local_context,
QueryProcessingStage::Enum processed_stage,
const size_t max_block_size,
const size_t num_streams)
{
auto storage = getTargetTable();
auto lock = storage->lockForShare(local_context->getCurrentQueryId(), local_context->getSettingsRef().lock_acquire_timeout);
auto target_metadata_snapshot = storage->getInMemoryMetadataPtr();
auto target_storage_snapshot = storage->getStorageSnapshot(target_metadata_snapshot, local_context);
2020-05-13 13:49:10 +00:00
if (query_info.order_optimizer)
query_info.input_order_info = query_info.order_optimizer->getInputOrder(target_metadata_snapshot, local_context);
storage->read(query_plan, column_names, target_storage_snapshot, query_info, local_context, processed_stage, max_block_size, num_streams);
2020-10-22 12:01:22 +00:00
if (query_plan.isInitialized())
{
auto mv_header = getHeaderForProcessingStage(column_names, storage_snapshot, query_info, local_context, processed_stage);
2021-01-21 12:57:18 +00:00
auto target_header = query_plan.getCurrentDataStream().header;
/// No need to convert columns that does not exists in MV
removeNonCommonColumns(mv_header, target_header);
/// No need to convert columns that does not exists in the result header.
///
/// Distributed storage may process query up to the specific stage, and
/// so the result header may not include all the columns from the
/// materialized view.
removeNonCommonColumns(target_header, mv_header);
if (!blocksHaveEqualStructure(mv_header, target_header))
{
auto converting_actions = ActionsDAG::makeConvertingActions(target_header.getColumnsWithTypeAndName(),
mv_header.getColumnsWithTypeAndName(),
ActionsDAG::MatchColumnsMode::Name);
/* Leave columns outside from materialized view structure as is.
* They may be added in case of distributed query with JOIN.
* In that case underlying table returns joined columns as well.
*/
converting_actions->projectInput(false);
auto converting_step = std::make_unique<ExpressionStep>(query_plan.getCurrentDataStream(), converting_actions);
converting_step->setStepDescription("Convert target table structure to MaterializedView structure");
query_plan.addStep(std::move(converting_step));
}
2022-05-20 19:49:31 +00:00
query_plan.addStorageHolder(storage);
query_plan.addTableLock(std::move(lock));
2020-10-22 12:01:22 +00:00
}
}
SinkToStoragePtr StorageMaterializedView::write(const ASTPtr & query, const StorageMetadataPtr & /*metadata_snapshot*/, ContextPtr local_context, bool async_insert)
{
auto storage = getTargetTable();
auto lock = storage->lockForShare(local_context->getCurrentQueryId(), local_context->getSettingsRef().lock_acquire_timeout);
auto metadata_snapshot = storage->getInMemoryMetadataPtr();
auto sink = storage->write(query, metadata_snapshot, local_context, async_insert);
2021-07-23 19:33:59 +00:00
sink->addTableLock(lock);
return sink;
}
2020-01-22 11:30:11 +00:00
void StorageMaterializedView::drop()
2018-04-21 00:35:20 +00:00
{
2019-12-03 16:25:32 +00:00
auto table_id = getStorageID();
2020-06-17 14:06:22 +00:00
const auto & select_query = getInMemoryMetadataPtr()->getSelectQuery();
if (!select_query.select_table_id.empty())
DatabaseCatalog::instance().removeViewDependency(select_query.select_table_id, table_id);
2018-04-21 00:35:20 +00:00
/// Sync flag and the setting make sense for Atomic databases only.
/// However, with Atomic databases, IStorage::drop() can be called only from a background task in DatabaseCatalog.
/// Running synchronous DROP from that task leads to deadlock.
/// Usually dropInnerTableIfAny is no-op, because the inner table is dropped before enqueueing a drop task for the MV itself.
/// But there's a race condition with SYSTEM RESTART REPLICA: the inner table might be detached due to RESTART.
/// In this case, dropInnerTableIfAny will not find the inner table and will not drop it during executions of DROP query for the MV itself.
/// DDLGuard does not protect from that, because RESTART REPLICA acquires DDLGuard for the inner table name,
/// but DROP acquires DDLGuard for the name of MV. And we cannot acquire second DDLGuard for the inner name in DROP,
/// because it may lead to lock-order-inversion (DDLGuards must be acquired in lexicographical order).
dropInnerTableIfAny(/* sync */ false, getContext());
}
2022-06-23 07:59:13 +00:00
void StorageMaterializedView::dropInnerTableIfAny(bool sync, ContextPtr local_context)
{
/// We will use `sync` argument wneh this function is called from a DROP query
/// and will ignore database_atomic_wait_for_drop_and_detach_synchronously when it's called from drop task.
2023-08-16 22:42:51 +00:00
/// See the comment in StorageMaterializedView::drop.
/// DDL queries with StorageMaterializedView are fundamentally broken.
/// Best-effort to make them work: the inner table name is almost always less than the MV name (so it's safe to lock DDLGuard)
2023-02-12 19:17:55 +00:00
auto inner_table_id = getTargetTableId();
bool may_lock_ddl_guard = getStorageID().getQualifiedName() < inner_table_id.getQualifiedName();
if (has_inner_table && tryGetTargetTable())
2023-02-12 19:17:55 +00:00
InterpreterDropQuery::executeDropQuery(ASTDropQuery::Kind::Drop, getContext(), local_context, inner_table_id,
2023-08-16 22:42:51 +00:00
sync, /* ignore_sync_setting */ true, may_lock_ddl_guard);
2018-06-09 15:48:22 +00:00
}
void StorageMaterializedView::truncate(const ASTPtr &, const StorageMetadataPtr &, ContextPtr local_context, TableExclusiveLockHolder &)
2018-06-09 15:48:22 +00:00
{
if (has_inner_table)
2023-02-12 19:17:55 +00:00
InterpreterDropQuery::executeDropQuery(ASTDropQuery::Kind::Truncate, getContext(), local_context, getTargetTableId(), true);
2018-04-21 00:35:20 +00:00
}
void StorageMaterializedView::checkStatementCanBeForwarded() const
{
if (!has_inner_table)
throw Exception(ErrorCodes::INCORRECT_QUERY, "MATERIALIZED VIEW targets existing table {}. "
2023-02-12 19:17:55 +00:00
"Execute the statement directly on it.", getTargetTableId().getNameForLogs());
}
2020-06-17 13:39:26 +00:00
bool StorageMaterializedView::optimize(
const ASTPtr & query,
const StorageMetadataPtr & /*metadata_snapshot*/,
const ASTPtr & partition,
bool final,
bool deduplicate,
const Names & deduplicate_by_columns,
ContextPtr local_context)
{
checkStatementCanBeForwarded();
2020-06-17 13:39:26 +00:00
auto storage_ptr = getTargetTable();
auto metadata_snapshot = storage_ptr->getInMemoryMetadataPtr();
2023-02-22 03:01:21 +00:00
return storage_ptr->optimize(query, metadata_snapshot, partition, final, deduplicate, deduplicate_by_columns, local_context);
2023-02-12 19:17:55 +00:00
}
2023-12-04 23:23:11 +00:00
std::tuple<ContextMutablePtr, std::shared_ptr<ASTInsertQuery>> StorageMaterializedView::prepareRefresh() const
2023-02-12 19:17:55 +00:00
{
2023-12-04 23:23:11 +00:00
auto refresh_context = Context::createCopy(getContext());
/// Generate a random query id.
refresh_context->setCurrentQueryId("");
CurrentThread::QueryScope query_scope(refresh_context);
2023-02-12 19:17:55 +00:00
auto inner_table_id = getTargetTableId();
auto new_table_name = ".tmp" + generateInnerTableName(getStorageID());
auto db = DatabaseCatalog::instance().getDatabase(inner_table_id.database_name);
auto create_table_query = db->getCreateTableQuery(inner_table_id.table_name, getContext());
auto & create_query = create_table_query->as<ASTCreateQuery &>();
create_query.setTable(new_table_name);
create_query.setDatabase(db->getDatabaseName());
create_query.create_or_replace = true;
create_query.replace_table = true;
create_query.uuid = UUIDHelpers::Nil;
2023-12-04 23:23:11 +00:00
InterpreterCreateQuery create_interpreter(create_table_query, refresh_context);
2023-02-12 19:17:55 +00:00
create_interpreter.setInternal(true);
create_interpreter.execute();
2023-12-04 23:23:11 +00:00
StorageID fresh_table = DatabaseCatalog::instance().getTable({create_query.getDatabase(), create_query.getTable()}, getContext())->getStorageID();
2023-02-15 02:58:26 +00:00
2023-02-12 19:17:55 +00:00
auto insert_query = std::make_shared<ASTInsertQuery>();
insert_query->select = getInMemoryMetadataPtr()->getSelectQuery().select_query;
2023-12-04 23:23:11 +00:00
insert_query->setTable(fresh_table.table_name);
insert_query->setDatabase(fresh_table.database_name);
insert_query->table_id = fresh_table;
return {refresh_context, insert_query};
2023-02-12 19:17:55 +00:00
}
2023-12-04 23:23:11 +00:00
StorageID StorageMaterializedView::exchangeTargetTable(StorageID fresh_table, ContextPtr refresh_context)
2023-02-12 19:17:55 +00:00
{
2023-02-15 02:58:26 +00:00
auto stale_table_id = getTargetTableId();
2023-02-12 19:17:55 +00:00
2023-02-15 02:58:26 +00:00
auto db = DatabaseCatalog::instance().getDatabase(stale_table_id.database_name);
auto target_db = DatabaseCatalog::instance().getDatabase(fresh_table.database_name);
2023-02-12 19:17:55 +00:00
2023-12-04 23:23:11 +00:00
CurrentThread::QueryScope query_scope(refresh_context);
2023-02-12 19:17:55 +00:00
target_db->renameTable(
2023-12-04 23:23:11 +00:00
refresh_context, fresh_table.table_name, *db, stale_table_id.table_name, /*exchange=*/true, /*dictionary=*/false);
2023-02-12 19:17:55 +00:00
2023-02-15 05:04:13 +00:00
std::swap(stale_table_id.database_name, fresh_table.database_name);
std::swap(stale_table_id.table_name, fresh_table.table_name);
setTargetTableId(std::move(fresh_table));
2023-02-15 02:58:26 +00:00
return stale_table_id;
2023-02-12 19:17:55 +00:00
}
void StorageMaterializedView::alter(
const AlterCommands & params,
ContextPtr local_context,
2021-10-25 17:49:49 +00:00
AlterLockHolder &)
{
auto table_id = getStorageID();
2020-06-09 21:22:01 +00:00
StorageInMemoryMetadata new_metadata = getInMemoryMetadata();
2020-06-17 14:06:22 +00:00
StorageInMemoryMetadata old_metadata = getInMemoryMetadata();
params.apply(new_metadata, local_context);
2020-01-31 17:12:18 +00:00
/// start modify query
const auto & new_select = new_metadata.select;
const auto & old_select = old_metadata.getSelectQuery();
2020-01-31 17:12:18 +00:00
DatabaseCatalog::instance().updateViewDependency(old_select.select_table_id, table_id, new_select.select_table_id, table_id);
2020-01-31 17:12:18 +00:00
/// end modify query
DatabaseCatalog::instance().getDatabase(table_id.database_name)->alterTable(local_context, table_id, new_metadata);
setInMemoryMetadata(new_metadata);
2023-11-29 02:32:41 +00:00
if (refresher)
refresher->alterRefreshParams(new_metadata.refresh->as<const ASTRefreshStrategy &>());
}
2023-11-28 13:01:31 +00:00
void StorageMaterializedView::checkAlterIsPossible(const AlterCommands & commands, ContextPtr /*local_context*/) const
{
for (const auto & command : commands)
{
2023-11-29 02:32:41 +00:00
if (command.isCommentAlter())
continue;
if (command.type == AlterCommand::MODIFY_QUERY)
continue;
if (command.type == AlterCommand::MODIFY_REFRESH && refresher)
continue;
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Alter of type '{}' is not supported by storage {}",
command.type, getName());
}
}
void StorageMaterializedView::checkMutationIsPossible(const MutationCommands & commands, const Settings & settings) const
{
checkStatementCanBeForwarded();
getTargetTable()->checkMutationIsPossible(commands, settings);
}
2020-08-03 13:54:14 +00:00
Pipe StorageMaterializedView::alterPartition(
const StorageMetadataPtr & metadata_snapshot, const PartitionCommands & commands, ContextPtr local_context)
{
checkStatementCanBeForwarded();
return getTargetTable()->alterPartition(metadata_snapshot, commands, local_context);
}
2020-07-14 08:19:39 +00:00
void StorageMaterializedView::checkAlterPartitionIsPossible(
2023-10-13 14:22:18 +00:00
const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot,
const Settings & settings, ContextPtr local_context) const
2020-07-14 08:19:39 +00:00
{
checkStatementCanBeForwarded();
2023-10-13 14:22:18 +00:00
getTargetTable()->checkAlterPartitionIsPossible(commands, metadata_snapshot, settings, local_context);
2020-07-14 08:19:39 +00:00
}
2023-01-30 17:38:28 +00:00
void StorageMaterializedView::mutate(const MutationCommands & commands, ContextPtr local_context)
{
checkStatementCanBeForwarded();
2023-01-30 17:38:28 +00:00
getTargetTable()->mutate(commands, local_context);
}
2020-04-07 14:05:51 +00:00
void StorageMaterializedView::renameInMemory(const StorageID & new_table_id)
{
2020-03-18 17:38:52 +00:00
auto old_table_id = getStorageID();
2023-02-12 19:17:55 +00:00
auto inner_table_id = getTargetTableId();
2020-06-17 14:06:22 +00:00
auto metadata_snapshot = getInMemoryMetadataPtr();
2020-04-10 01:35:37 +00:00
bool from_atomic_to_atomic_database = old_table_id.hasUUID() && new_table_id.hasUUID();
2020-04-07 14:05:51 +00:00
2021-05-19 18:53:31 +00:00
if (!from_atomic_to_atomic_database && has_inner_table && tryGetTargetTable())
{
2020-04-08 01:02:00 +00:00
auto new_target_table_name = generateInnerTableName(new_table_id);
2019-12-10 19:48:16 +00:00
auto rename = std::make_shared<ASTRenameQuery>();
2023-02-12 19:17:55 +00:00
assert(inner_table_id.database_name == old_table_id.database_name);
2023-02-14 13:01:06 +00:00
ASTRenameQuery::Element elem
{
ASTRenameQuery::Table
{
2023-02-12 19:17:55 +00:00
inner_table_id.database_name.empty() ? nullptr : std::make_shared<ASTIdentifier>(inner_table_id.database_name),
std::make_shared<ASTIdentifier>(inner_table_id.table_name)
2023-02-14 13:01:06 +00:00
},
ASTRenameQuery::Table
{
2023-02-14 22:17:23 +00:00
new_table_id.database_name.empty() ? nullptr : std::make_shared<ASTIdentifier>(new_table_id.database_name),
2023-02-14 13:01:06 +00:00
std::make_shared<ASTIdentifier>(new_target_table_name)
}
};
rename->elements.emplace_back(std::move(elem));
InterpreterRenameQuery(rename, getContext()).execute();
2023-02-12 19:17:55 +00:00
updateTargetTableId(new_table_id.database_name, new_target_table_name);
}
2020-04-07 14:05:51 +00:00
IStorage::renameInMemory(new_table_id);
2021-05-19 18:53:31 +00:00
if (from_atomic_to_atomic_database && has_inner_table)
{
2023-02-12 19:17:55 +00:00
assert(inner_table_id.database_name == old_table_id.database_name);
updateTargetTableId(new_table_id.database_name, std::nullopt);
2021-05-19 18:53:31 +00:00
}
2020-06-17 14:06:22 +00:00
const auto & select_query = metadata_snapshot->getSelectQuery();
// TODO Actually we don't need to update dependency if MV has UUID, but then db and table name will be outdated
DatabaseCatalog::instance().updateViewDependency(select_query.select_table_id, old_table_id, select_query.select_table_id, getStorageID());
2023-11-29 02:32:41 +00:00
if (refresher)
refresher->rename(new_table_id);
}
void StorageMaterializedView::startup()
{
auto metadata_snapshot = getInMemoryMetadataPtr();
const auto & select_query = metadata_snapshot->getSelectQuery();
if (!select_query.select_table_id.empty())
DatabaseCatalog::instance().addViewDependency(select_query.select_table_id, getStorageID());
2023-02-12 19:17:55 +00:00
if (refresher)
{
2023-11-23 05:08:44 +00:00
refresher->initializeAndStart(std::static_pointer_cast<StorageMaterializedView>(shared_from_this()));
2023-02-12 19:17:55 +00:00
}
}
2023-11-06 14:40:01 +00:00
void StorageMaterializedView::shutdown(bool)
{
2023-02-12 19:17:55 +00:00
if (refresher)
2023-11-24 01:32:45 +00:00
refresher->shutdown();
2023-02-12 19:17:55 +00:00
2020-06-17 14:06:22 +00:00
auto metadata_snapshot = getInMemoryMetadataPtr();
const auto & select_query = metadata_snapshot->getSelectQuery();
/// Make sure the dependency is removed after DETACH TABLE
if (!select_query.select_table_id.empty())
DatabaseCatalog::instance().removeViewDependency(select_query.select_table_id, getStorageID());
}
StoragePtr StorageMaterializedView::getTargetTable() const
{
checkStackSize();
2023-02-12 19:17:55 +00:00
return DatabaseCatalog::instance().getTable(getTargetTableId(), getContext());
}
StoragePtr StorageMaterializedView::tryGetTargetTable() const
{
checkStackSize();
2023-02-12 19:17:55 +00:00
return DatabaseCatalog::instance().tryGetTable(getTargetTableId(), getContext());
}
NamesAndTypesList StorageMaterializedView::getVirtuals() const
{
return getTargetTable()->getVirtuals();
}
2019-04-04 13:13:59 +00:00
Strings StorageMaterializedView::getDataPaths() const
{
if (auto table = tryGetTargetTable())
2019-04-04 13:13:59 +00:00
return table->getDataPaths();
return {};
}
void StorageMaterializedView::backupData(BackupEntriesCollector & backup_entries_collector, const String & data_path_in_backup, const std::optional<ASTs> & partitions)
{
/// We backup the target table's data only if it's inner.
if (hasInnerTable())
2023-11-06 18:05:12 +00:00
{
if (auto table = tryGetTargetTable())
table->backupData(backup_entries_collector, data_path_in_backup, partitions);
else
LOG_WARNING(&Poco::Logger::get("StorageMaterializedView"),
"Inner table does not exist, will not backup any data");
}
}
void StorageMaterializedView::restoreDataFromBackup(RestorerFromBackup & restorer, const String & data_path_in_backup, const std::optional<ASTs> & partitions)
{
if (hasInnerTable())
return getTargetTable()->restoreDataFromBackup(restorer, data_path_in_backup, partitions);
}
bool StorageMaterializedView::supportsBackupPartition() const
{
if (hasInnerTable())
return getTargetTable()->supportsBackupPartition();
return false;
}
std::optional<UInt64> StorageMaterializedView::totalRows(const Settings & settings) const
{
if (hasInnerTable())
{
if (auto table = tryGetTargetTable())
return table->totalRows(settings);
}
return {};
}
std::optional<UInt64> StorageMaterializedView::totalBytes(const Settings & settings) const
{
if (hasInnerTable())
{
if (auto table = tryGetTargetTable())
return table->totalBytes(settings);
}
return {};
}
std::optional<UInt64> StorageMaterializedView::totalBytesUncompressed(const Settings & settings) const
{
if (hasInnerTable())
{
if (auto table = tryGetTargetTable())
return table->totalBytesUncompressed(settings);
}
return {};
}
ActionLock StorageMaterializedView::getActionLock(StorageActionBlockType type)
{
2023-02-12 19:17:55 +00:00
if (type == ActionLocks::ViewRefresh && refresher)
refresher->stop();
2021-05-31 13:38:33 +00:00
if (has_inner_table)
{
if (auto target_table = tryGetTargetTable())
return target_table->getActionLock(type);
}
return ActionLock{};
}
2023-10-16 15:17:55 +00:00
bool StorageMaterializedView::isRemote() const
{
if (auto table = tryGetTargetTable())
return table->isRemote();
return false;
}
2023-02-12 19:17:55 +00:00
void StorageMaterializedView::onActionLockRemove(StorageActionBlockType action_type)
{
if (action_type == ActionLocks::ViewRefresh && refresher)
refresher->start();
}
DB::StorageID StorageMaterializedView::getTargetTableId() const
{
std::lock_guard guard(target_table_id_mutex);
return target_table_id;
}
void StorageMaterializedView::setTargetTableId(DB::StorageID id)
{
std::lock_guard guard(target_table_id_mutex);
target_table_id = std::move(id);
}
void StorageMaterializedView::updateTargetTableId(std::optional<String> database_name, std::optional<String> table_name)
{
std::lock_guard guard(target_table_id_mutex);
if (database_name)
target_table_id.database_name = *std::move(database_name);
if (table_name)
target_table_id.table_name = *std::move(table_name);
}
void registerStorageMaterializedView(StorageFactory & factory)
{
factory.registerStorage("MaterializedView", [](const StorageFactory::Arguments & args)
{
/// Pass local_context here to convey setting for inner table
return std::make_shared<StorageMaterializedView>(
args.table_id, args.getLocalContext(), args.query,
args.columns, args.attach, args.comment);
});
}
}