1#include <Interpreters/InterpreterSelectQuery.h>
2#include <Interpreters/InterpreterSelectWithUnionQuery.h>
3#include <Interpreters/PredicateExpressionsOptimizer.h>
4
5#include <Parsers/ASTCreateQuery.h>
6#include <Parsers/ASTSubquery.h>
7#include <Parsers/ASTTablesInSelectQuery.h>
8#include <Parsers/ASTSelectWithUnionQuery.h>
9#include <Parsers/queryToString.h>
10
11#include <Storages/StorageView.h>
12#include <Storages/StorageFactory.h>
13
14#include <DataStreams/MaterializingBlockInputStream.h>
15
16#include <Common/typeid_cast.h>
17
18
19namespace DB
20{
21
22namespace ErrorCodes
23{
24 extern const int INCORRECT_QUERY;
25 extern const int LOGICAL_ERROR;
26}
27
28
29StorageView::StorageView(
30 const String & database_name_,
31 const String & table_name_,
32 const ASTCreateQuery & query,
33 const ColumnsDescription & columns_)
34 : table_name(table_name_), database_name(database_name_)
35{
36 setColumns(columns_);
37
38 if (!query.select)
39 throw Exception("SELECT query is not specified for " + getName(), ErrorCodes::INCORRECT_QUERY);
40
41 inner_query = query.select->ptr();
42}
43
44
45BlockInputStreams StorageView::read(
46 const Names & column_names,
47 const SelectQueryInfo & query_info,
48 const Context & context,
49 QueryProcessingStage::Enum /*processed_stage*/,
50 const size_t /*max_block_size*/,
51 const unsigned /*num_streams*/)
52{
53 BlockInputStreams res;
54
55 ASTPtr current_inner_query = inner_query;
56
57 if (context.getSettings().enable_optimize_predicate_expression)
58 {
59 auto new_inner_query = inner_query->clone();
60 auto new_outer_query = query_info.query->clone();
61 auto * new_outer_select = new_outer_query->as<ASTSelectQuery>();
62
63 replaceTableNameWithSubquery(new_outer_select, new_inner_query);
64
65 if (PredicateExpressionsOptimizer(new_outer_select, context.getSettings(), context).optimize())
66 current_inner_query = new_inner_query;
67 }
68
69 QueryPipeline pipeline;
70 /// FIXME res may implicitly use some objects owned be pipeline, but them will be destructed after return
71 res = InterpreterSelectWithUnionQuery(current_inner_query, context, {}, column_names).executeWithMultipleStreams(pipeline);
72
73 /// It's expected that the columns read from storage are not constant.
74 /// Because method 'getSampleBlockForColumns' is used to obtain a structure of result in InterpreterSelectQuery.
75 for (auto & stream : res)
76 stream = std::make_shared<MaterializingBlockInputStream>(stream);
77
78 return res;
79}
80
81void StorageView::replaceTableNameWithSubquery(ASTSelectQuery * select_query, ASTPtr & subquery)
82{
83 auto * select_element = select_query->tables()->children[0]->as<ASTTablesInSelectQueryElement>();
84
85 if (!select_element->table_expression)
86 throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
87
88 auto * table_expression = select_element->table_expression->as<ASTTableExpression>();
89
90 if (!table_expression->database_and_table_name)
91 throw Exception("Logical error: incorrect table expression", ErrorCodes::LOGICAL_ERROR);
92
93 const auto alias = table_expression->database_and_table_name->tryGetAlias();
94 table_expression->database_and_table_name = {};
95 table_expression->subquery = std::make_shared<ASTSubquery>();
96 table_expression->subquery->children.push_back(subquery);
97 if (!alias.empty())
98 table_expression->subquery->setAlias(alias);
99}
100
101
102void registerStorageView(StorageFactory & factory)
103{
104 factory.registerStorage("View", [](const StorageFactory::Arguments & args)
105 {
106 if (args.query.storage)
107 throw Exception("Specifying ENGINE is not allowed for a View", ErrorCodes::INCORRECT_QUERY);
108
109 return StorageView::create(args.database_name, args.table_name, args.query, args.columns);
110 });
111}
112
113}
114