ClickHouse/dbms/src/Storages/StorageView.cpp

130 lines
4.5 KiB
C++
Raw Normal View History

#include <Interpreters/InterpreterSelectQuery.h>
2018-02-25 06:34:20 +00:00
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
2019-07-21 02:13:42 +00:00
#include <Interpreters/PredicateExpressionsOptimizer.h>
2019-12-18 03:56:03 +00:00
#include <Interpreters/getTableExpressions.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>
2019-07-21 02:13:42 +00:00
#include <Parsers/queryToString.h>
#include <Storages/StorageView.h>
#include <Storages/StorageFactory.h>
2018-02-28 19:47:33 +00:00
#include <DataStreams/MaterializingBlockInputStream.h>
#include <Common/typeid_cast.h>
2019-07-21 02:13:42 +00:00
namespace DB
{
namespace ErrorCodes
{
extern const int INCORRECT_QUERY;
extern const int LOGICAL_ERROR;
2019-12-18 03:56:03 +00:00
extern const int ALIAS_REQUIRED;
}
StorageView::StorageView(
2019-12-04 16:06:55 +00:00
const StorageID & table_id_,
const ASTCreateQuery & query,
const ColumnsDescription & columns_)
2019-12-04 16:06:55 +00:00
: IStorage(table_id_)
{
2019-08-24 21:20:20 +00:00
setColumns(columns_);
if (!query.select)
throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY);
inner_query = query.select->ptr();
}
2014-06-12 23:21:38 +00:00
BlockInputStreams StorageView::read(
const Names & column_names,
const SelectQueryInfo & query_info,
const Context & context,
QueryProcessingStage::Enum /*processed_stage*/,
2017-12-01 21:13:25 +00:00
const size_t /*max_block_size*/,
const unsigned /*num_streams*/)
{
BlockInputStreams res;
ASTPtr current_inner_query = inner_query;
if (context.getSettings().enable_optimize_predicate_expression)
{
auto new_inner_query = inner_query->clone();
auto new_outer_query = query_info.query->clone();
2019-03-11 13:22:51 +00:00
auto * new_outer_select = new_outer_query->as<ASTSelectQuery>();
replaceTableNameWithSubquery(new_outer_select, new_inner_query);
2019-12-18 03:56:03 +00:00
/// TODO: remove getTableExpressions and getTablesWithColumns
{
const auto & table_expressions = getTableExpressions(*new_outer_select);
const auto & tables_with_columns = getDatabaseAndTablesWithColumnNames(table_expressions, context);
auto & settings = context.getSettingsRef();
if (settings.joined_subquery_requires_alias && tables_with_columns.size() > 1)
{
for (auto & pr : tables_with_columns)
if (pr.table.table.empty() && pr.table.alias.empty())
throw Exception("Not unique subquery in FROM requires an alias (or joined_subquery_requires_alias=0 to disable restriction).",
ErrorCodes::ALIAS_REQUIRED);
}
if (PredicateExpressionsOptimizer(context, tables_with_columns, context.getSettings()).optimize(*new_outer_select))
current_inner_query = new_inner_query;
}
}
QueryPipeline pipeline;
/// FIXME res may implicitly use some objects owned be pipeline, but them will be destructed after return
res = InterpreterSelectWithUnionQuery(current_inner_query, context, {}, column_names).executeWithMultipleStreams(pipeline);
2018-02-28 19:47:33 +00:00
/// 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.
for (auto & stream : res)
stream = std::make_shared<MaterializingBlockInputStream>(stream);
return res;
}
void StorageView::replaceTableNameWithSubquery(ASTSelectQuery * select_query, ASTPtr & subquery)
{
auto * select_element = select_query->tables()->children[0]->as<ASTTablesInSelectQueryElement>();
if (!select_element->table_expression)
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
2019-03-11 13:22:51 +00:00
auto * table_expression = select_element->table_expression->as<ASTTableExpression>();
if (!table_expression->database_and_table_name)
throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
const auto alias = table_expression->database_and_table_name->tryGetAlias();
table_expression->database_and_table_name = {};
table_expression->subquery = std::make_shared<ASTSubquery>();
table_expression->subquery->children.push_back(subquery);
if (!alias.empty())
table_expression->subquery->setAlias(alias);
}
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);
2019-12-04 16:06:55 +00:00
return StorageView::create(args.table_id, args.query, args.columns);
});
}
}