1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
#pragma once
#include <Interpreters/ActionsDAG.h>
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
/** Chain of query actions steps. This class is needed to eliminate unnecessary actions calculations.
* Each step is represented by actions DAG.
*
* Consider such example query:
* SELECT expr(id) FROM test_table WHERE expr(id) > 0.
*
* We want to reuse expr(id) from previous expressions step, and not recalculate it in projection.
* To do this we build a chain of all query action steps.
* For example:
* 1. Before where.
* 2. Before order by.
* 3. Projection.
*
* Initially root of chain is initialized with join tree query plan header.
* Each next chain step, must be initialized with previous step available output columns.
* That way we forward all available output columns (functions, columns, aliases) from first step of the chain to the
* last step. After chain is build we can finalize it.
*
* Each step has input columns (some of them are not necessary) and output columns. Before chain finalize output columns
* contain only necessary actions for step output calculation.
* For each step starting from last (i), we add columns that are necessary for this step to previous step (i - 1),
* and remove unused input columns of previous step(i - 1).
* That way we reuse already calculated expressions from first step to last step.
*/
class ActionsChainStep;
using ActionsChainStepPtr = std::unique_ptr<ActionsChainStep>;
using ActionsChainSteps = std::vector<ActionsChainStepPtr>;
/// Actions chain step represent single step in actions chain.
class ActionsChainStep
{
public:
/** Initialize actions step with actions dag.
* Input column names initialized using actions dag nodes with INPUT type.
* If use_actions_nodes_as_output_columns = true output columns are initialized using actions dag nodes.
* If additional output columns are specified they are added to output columns.
*/
explicit ActionsChainStep(ActionsDAGPtr actions_,
bool use_actions_nodes_as_output_columns = true,
ColumnsWithTypeAndName additional_output_columns_ = {});
/// Get actions
ActionsDAGPtr & getActions()
{
return actions;
}
/// Get actions
const ActionsDAGPtr & getActions() const
{
return actions;
}
/// Get available output columns
const ColumnsWithTypeAndName & getAvailableOutputColumns() const
{
return available_output_columns;
}
/// Get input column names
const NameSet & getInputColumnNames() const
{
return input_columns_names;
}
/** Get child required output columns names.
* Initialized during finalizeOutputColumns method call.
*/
const NameSet & getChildRequiredOutputColumnsNames() const
{
return child_required_output_columns_names;
}
/** Finalize step output columns and remove unnecessary input columns.
* If actions dag node has same name as child input column, it is added to actions output nodes.
*/
void finalizeInputAndOutputColumns(const NameSet & child_input_columns);
/// Dump step into buffer
void dump(WriteBuffer & buffer) const;
/// Dump step
String dump() const;
private:
void initialize();
ActionsDAGPtr actions;
bool use_actions_nodes_as_output_columns = true;
NameSet input_columns_names;
NameSet child_required_output_columns_names;
ColumnsWithTypeAndName available_output_columns;
ColumnsWithTypeAndName additional_output_columns;
};
/// Query actions chain
class ActionsChain
{
public:
/// Add step into actions chain
void addStep(ActionsChainStepPtr step)
{
steps.emplace_back(std::move(step));
}
/// Get steps
const ActionsChainSteps & getSteps() const
{
return steps;
}
/// Get steps size
size_t getStepsSize() const
{
return steps.size();
}
const ActionsChainStepPtr & at(size_t index) const
{
if (index >= steps.size())
throw std::out_of_range("actions chain access is out of range");
return steps[index];
}
ActionsChainStepPtr & at(size_t index)
{
if (index >= steps.size())
throw std::out_of_range("actions chain access is out of range");
return steps[index];
}
ActionsChainStepPtr & operator[](size_t index)
{
return steps[index];
}
const ActionsChainStepPtr & operator[](size_t index) const
{
return steps[index];
}
/// Get last step
ActionsChainStep * getLastStep()
{
return steps.back().get();
}
/// Get last step or throw exception if chain is empty
ActionsChainStep * getLastStepOrThrow()
{
if (steps.empty())
throw Exception(ErrorCodes::LOGICAL_ERROR, "ActionsChain is empty");
return steps.back().get();
}
/// Get last step index
size_t getLastStepIndex()
{
return steps.size() - 1;
}
/// Get last step index or throw exception if chain is empty
size_t getLastStepIndexOrThrow()
{
if (steps.empty())
throw Exception(ErrorCodes::LOGICAL_ERROR, "ActionsChain is empty");
return steps.size() - 1;
}
/// Get last step available output columns
const ColumnsWithTypeAndName & getLastStepAvailableOutputColumns() const
{
return steps.back()->getAvailableOutputColumns();
}
/// Get last step available output columns or throw exception if chain is empty
const ColumnsWithTypeAndName & getLastStepAvailableOutputColumnsOrThrow() const
{
if (steps.empty())
throw Exception(ErrorCodes::LOGICAL_ERROR, "ActionsChain is empty");
return steps.back()->getAvailableOutputColumns();
}
/// Get last step available output columns or null if chain is empty
const ColumnsWithTypeAndName * getLastStepAvailableOutputColumnsOrNull() const
{
if (steps.empty())
return nullptr;
return &steps.back()->getAvailableOutputColumns();
}
/// Finalize chain
void finalize();
/// Dump chain into buffer
void dump(WriteBuffer & buffer) const;
/// Dump chain
String dump() const;
private:
ActionsChainSteps steps;
};
}
|