ClickHouse/src/Storages/StorageView.cpp

188 lines
7.2 KiB
C++
Raw Normal View History

#include <Interpreters/InterpreterSelectQuery.h>
2018-02-25 06:34:20 +00:00
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
#include <Interpreters/Context.h>
2019-07-21 02:13:42 +00:00
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/ASTSubquery.h>
#include <Parsers/ASTTablesInSelectQuery.h>
2019-03-23 22:45:28 +00:00
#include <Parsers/ASTSelectWithUnionQuery.h>
#include <Storages/StorageView.h>
#include <Storages/StorageFactory.h>
#include <Storages/SelectQueryDescription.h>
#include <Common/typeid_cast.h>
2019-07-21 02:13:42 +00:00
#include <Processors/Pipe.h>
#include <Processors/Transforms/MaterializingTransform.h>
2020-11-17 17:16:55 +00:00
#include <Processors/QueryPlan/ExpressionStep.h>
#include <Processors/QueryPlan/SettingQuotaAndLimitsStep.h>
2021-03-04 17:38:12 +00:00
#include <Processors/QueryPlan/BuildQueryPipelineSettings.h>
#include <Processors/QueryPlan/Optimizations/QueryPlanOptimizationSettings.h>
namespace DB
{
namespace ErrorCodes
{
extern const int INCORRECT_QUERY;
extern const int LOGICAL_ERROR;
}
StorageView::StorageView(
2019-12-04 16:06:55 +00:00
const StorageID & table_id_,
const ASTCreateQuery & query,
2021-05-13 14:21:55 +00:00
const ColumnsDescription & columns_,
const String & comment,
2021-05-13 14:21:55 +00:00
const Settings & settings)
2019-12-04 16:06:55 +00:00
: IStorage(table_id_)
, settings_changes(settings.changes())
{
2020-06-19 15:39:41 +00:00
StorageInMemoryMetadata storage_metadata;
storage_metadata.setColumns(columns_);
2021-04-23 12:18:23 +00:00
storage_metadata.setComment(comment);
2019-08-24 21:20:20 +00:00
if (!query.select)
throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY);
SelectQueryDescription description;
description.inner_query = query.select->ptr();
2020-06-19 15:39:41 +00:00
storage_metadata.setSelectQuery(description);
setInMemoryMetadata(storage_metadata);
}
2014-06-12 23:21:38 +00:00
2020-08-03 13:54:14 +00:00
Pipe StorageView::read(
const Names & column_names,
const StorageMetadataPtr & metadata_snapshot,
SelectQueryInfo & query_info,
ContextPtr context,
QueryProcessingStage::Enum processed_stage,
const size_t max_block_size,
const unsigned num_streams)
{
QueryPlan plan;
read(plan, column_names, metadata_snapshot, query_info, context, processed_stage, max_block_size, num_streams);
2021-03-04 17:38:12 +00:00
return plan.convertToPipe(
QueryPlanOptimizationSettings::fromContext(context),
BuildQueryPipelineSettings::fromContext(context));
}
void StorageView::read(
QueryPlan & query_plan,
const Names & column_names,
const StorageMetadataPtr & metadata_snapshot,
SelectQueryInfo & query_info,
ContextPtr context,
QueryProcessingStage::Enum /*processed_stage*/,
const size_t /*max_block_size*/,
const unsigned /*num_streams*/)
{
ASTPtr current_inner_query = metadata_snapshot->getSelectQuery().inner_query;
if (query_info.view_query)
{
if (!query_info.view_query->as<ASTSelectWithUnionQuery>())
throw Exception("Unexpected optimized VIEW query", ErrorCodes::LOGICAL_ERROR);
current_inner_query = query_info.view_query->clone();
}
2021-05-13 14:21:55 +00:00
auto modified_context = Context::createCopy(context);
modified_context->applySettingsChanges(settings_changes);
InterpreterSelectWithUnionQuery interpreter(current_inner_query, modified_context, {}, column_names);
interpreter.buildQueryPlan(query_plan);
/// It's expected that the columns read from storage are not constant.
/// Because method 'getSampleBlockForColumns' is used to obtain a structure of result in InterpreterSelectQuery.
2021-02-18 11:15:16 +00:00
auto materializing_actions = std::make_shared<ActionsDAG>(query_plan.getCurrentDataStream().header.getColumnsWithTypeAndName());
materializing_actions->addMaterializingOutputActions();
2021-03-04 17:38:12 +00:00
auto materializing = std::make_unique<ExpressionStep>(query_plan.getCurrentDataStream(), std::move(materializing_actions));
materializing->setStepDescription("Materialize constants after VIEW subquery");
query_plan.addStep(std::move(materializing));
/// And also convert to expected structure.
auto header = metadata_snapshot->getSampleBlockForColumns(column_names, getVirtuals(), getStorageID());
2020-11-17 17:16:55 +00:00
auto convert_actions_dag = ActionsDAG::makeConvertingActions(
query_plan.getCurrentDataStream().header.getColumnsWithTypeAndName(),
header.getColumnsWithTypeAndName(),
ActionsDAG::MatchColumnsMode::Name);
2021-03-04 17:38:12 +00:00
auto converting = std::make_unique<ExpressionStep>(query_plan.getCurrentDataStream(), convert_actions_dag);
converting->setStepDescription("Convert VIEW subquery result to VIEW table structure");
query_plan.addStep(std::move(converting));
}
static ASTTableExpression * getFirstTableExpression(ASTSelectQuery & select_query)
2020-03-18 00:57:00 +00:00
{
2021-02-25 14:43:58 +00:00
if (!select_query.tables() || select_query.tables()->children.empty())
throw Exception("Logical error: no table expression in view select AST", ErrorCodes::LOGICAL_ERROR);
auto * select_element = select_query.tables()->children[0]->as<ASTTablesInSelectQueryElement>();
2020-03-18 00:57:00 +00:00
if (!select_element->table_expression)
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
return select_element->table_expression->as<ASTTableExpression>();
}
void StorageView::replaceWithSubquery(ASTSelectQuery & outer_query, ASTPtr view_query, ASTPtr & view_name)
{
ASTTableExpression * table_expression = getFirstTableExpression(outer_query);
2020-03-18 00:57:00 +00:00
if (!table_expression->database_and_table_name)
2020-08-28 14:07:14 +00:00
{
// If it's a view table function, add a fake db.table name.
if (table_expression->table_function && table_expression->table_function->as<ASTFunction>()->name == "view")
table_expression->database_and_table_name = std::make_shared<ASTIdentifier>("__view");
else
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
}
2020-03-18 00:57:00 +00:00
DatabaseAndTableWithAlias db_table(table_expression->database_and_table_name);
String alias = db_table.alias.empty() ? db_table.table : db_table.alias;
view_name = table_expression->database_and_table_name;
2020-03-18 00:57:00 +00:00
table_expression->database_and_table_name = {};
table_expression->subquery = std::make_shared<ASTSubquery>();
table_expression->subquery->children.push_back(view_query);
table_expression->subquery->setAlias(alias);
2020-03-18 00:57:00 +00:00
for (auto & child : table_expression->children)
if (child.get() == view_name.get())
child = view_query;
}
2020-03-18 00:57:00 +00:00
ASTPtr StorageView::restoreViewName(ASTSelectQuery & select_query, const ASTPtr & view_name)
{
ASTTableExpression * table_expression = getFirstTableExpression(select_query);
if (!table_expression->subquery)
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
ASTPtr subquery = table_expression->subquery;
table_expression->subquery = {};
table_expression->database_and_table_name = view_name;
for (auto & child : table_expression->children)
if (child.get() == subquery.get())
child = view_name;
return subquery->children[0];
}
void registerStorageView(StorageFactory & factory)
{
factory.registerStorage("View", [](const StorageFactory::Arguments & args)
{
if (args.query.storage)
throw Exception("Specifying ENGINE is not allowed for a View", ErrorCodes::INCORRECT_QUERY);
return StorageView::create(args.table_id, args.query, args.columns, args.comment, args.getLocalContext()->getSettingsRef());
});
}
}