1 | #include "duckdb/planner/logical_operator.hpp" |
2 | |
3 | #include "duckdb/common/field_writer.hpp" |
4 | #include "duckdb/common/printer.hpp" |
5 | #include "duckdb/common/serializer/buffered_deserializer.hpp" |
6 | #include "duckdb/common/string_util.hpp" |
7 | #include "duckdb/common/tree_renderer.hpp" |
8 | #include "duckdb/parser/parser.hpp" |
9 | #include "duckdb/planner/operator/list.hpp" |
10 | #include "duckdb/planner/operator/logical_extension_operator.hpp" |
11 | |
12 | namespace duckdb { |
13 | |
14 | const uint64_t PLAN_SERIALIZATION_VERSION = 1; |
15 | |
16 | LogicalOperator::LogicalOperator(LogicalOperatorType type) |
17 | : type(type), estimated_cardinality(0), has_estimated_cardinality(false) { |
18 | } |
19 | |
20 | LogicalOperator::LogicalOperator(LogicalOperatorType type, vector<unique_ptr<Expression>> expressions) |
21 | : type(type), expressions(std::move(expressions)), estimated_cardinality(0), has_estimated_cardinality(false) { |
22 | } |
23 | |
24 | LogicalOperator::~LogicalOperator() { |
25 | } |
26 | |
27 | vector<ColumnBinding> LogicalOperator::GetColumnBindings() { |
28 | return {ColumnBinding(0, 0)}; |
29 | } |
30 | |
31 | string LogicalOperator::GetName() const { |
32 | return LogicalOperatorToString(type); |
33 | } |
34 | |
35 | string LogicalOperator::ParamsToString() const { |
36 | string result; |
37 | for (idx_t i = 0; i < expressions.size(); i++) { |
38 | if (i > 0) { |
39 | result += "\n" ; |
40 | } |
41 | result += expressions[i]->GetName(); |
42 | } |
43 | return result; |
44 | } |
45 | |
46 | void LogicalOperator::ResolveOperatorTypes() { |
47 | |
48 | types.clear(); |
49 | // first resolve child types |
50 | for (auto &child : children) { |
51 | child->ResolveOperatorTypes(); |
52 | } |
53 | // now resolve the types for this operator |
54 | ResolveTypes(); |
55 | D_ASSERT(types.size() == GetColumnBindings().size()); |
56 | } |
57 | |
58 | vector<ColumnBinding> LogicalOperator::GenerateColumnBindings(idx_t table_idx, idx_t column_count) { |
59 | vector<ColumnBinding> result; |
60 | result.reserve(n: column_count); |
61 | for (idx_t i = 0; i < column_count; i++) { |
62 | result.emplace_back(args&: table_idx, args&: i); |
63 | } |
64 | return result; |
65 | } |
66 | |
67 | vector<LogicalType> LogicalOperator::MapTypes(const vector<LogicalType> &types, const vector<idx_t> &projection_map) { |
68 | if (projection_map.empty()) { |
69 | return types; |
70 | } else { |
71 | vector<LogicalType> result_types; |
72 | result_types.reserve(n: projection_map.size()); |
73 | for (auto index : projection_map) { |
74 | result_types.push_back(x: types[index]); |
75 | } |
76 | return result_types; |
77 | } |
78 | } |
79 | |
80 | vector<ColumnBinding> LogicalOperator::MapBindings(const vector<ColumnBinding> &bindings, |
81 | const vector<idx_t> &projection_map) { |
82 | if (projection_map.empty()) { |
83 | return bindings; |
84 | } else { |
85 | vector<ColumnBinding> result_bindings; |
86 | result_bindings.reserve(n: projection_map.size()); |
87 | for (auto index : projection_map) { |
88 | D_ASSERT(index < bindings.size()); |
89 | result_bindings.push_back(x: bindings[index]); |
90 | } |
91 | return result_bindings; |
92 | } |
93 | } |
94 | |
95 | string LogicalOperator::ToString() const { |
96 | TreeRenderer renderer; |
97 | return renderer.ToString(op: *this); |
98 | } |
99 | |
100 | void LogicalOperator::Verify(ClientContext &context) { |
101 | #ifdef DEBUG |
102 | // verify expressions |
103 | for (idx_t expr_idx = 0; expr_idx < expressions.size(); expr_idx++) { |
104 | auto str = expressions[expr_idx]->ToString(); |
105 | // verify that we can (correctly) copy this expression |
106 | auto copy = expressions[expr_idx]->Copy(); |
107 | auto original_hash = expressions[expr_idx]->Hash(); |
108 | auto copy_hash = copy->Hash(); |
109 | // copy should be identical to original |
110 | D_ASSERT(expressions[expr_idx]->ToString() == copy->ToString()); |
111 | D_ASSERT(original_hash == copy_hash); |
112 | D_ASSERT(Expression::Equals(expressions[expr_idx], copy)); |
113 | |
114 | for (idx_t other_idx = 0; other_idx < expr_idx; other_idx++) { |
115 | // comparison with other expressions |
116 | auto other_hash = expressions[other_idx]->Hash(); |
117 | bool expr_equal = Expression::Equals(expressions[expr_idx], expressions[other_idx]); |
118 | if (original_hash != other_hash) { |
119 | // if the hashes are not equal the expressions should not be equal either |
120 | D_ASSERT(!expr_equal); |
121 | } |
122 | } |
123 | D_ASSERT(!str.empty()); |
124 | |
125 | // verify that serialization + deserialization round-trips correctly |
126 | if (expressions[expr_idx]->HasParameter()) { |
127 | continue; |
128 | } |
129 | BufferedSerializer serializer; |
130 | // We are serializing a query plan |
131 | serializer.is_query_plan = true; |
132 | try { |
133 | expressions[expr_idx]->Serialize(serializer); |
134 | } catch (NotImplementedException &ex) { |
135 | // ignore for now (FIXME) |
136 | return; |
137 | } |
138 | |
139 | auto data = serializer.GetData(); |
140 | auto deserializer = BufferedContextDeserializer(context, data.data.get(), data.size); |
141 | |
142 | PlanDeserializationState state(context); |
143 | auto deserialized_expression = Expression::Deserialize(deserializer, state); |
144 | // FIXME: expressions might not be equal yet because of statistics propagation |
145 | continue; |
146 | D_ASSERT(Expression::Equals(expressions[expr_idx], deserialized_expression)); |
147 | D_ASSERT(expressions[expr_idx]->Hash() == deserialized_expression->Hash()); |
148 | } |
149 | D_ASSERT(!ToString().empty()); |
150 | for (auto &child : children) { |
151 | child->Verify(context); |
152 | } |
153 | #endif |
154 | } |
155 | |
156 | void LogicalOperator::AddChild(unique_ptr<LogicalOperator> child) { |
157 | D_ASSERT(child); |
158 | children.push_back(x: std::move(child)); |
159 | } |
160 | |
161 | idx_t LogicalOperator::EstimateCardinality(ClientContext &context) { |
162 | // simple estimator, just take the max of the children |
163 | if (has_estimated_cardinality) { |
164 | return estimated_cardinality; |
165 | } |
166 | idx_t max_cardinality = 0; |
167 | for (auto &child : children) { |
168 | max_cardinality = MaxValue(a: child->EstimateCardinality(context), b: max_cardinality); |
169 | } |
170 | has_estimated_cardinality = true; |
171 | estimated_cardinality = max_cardinality; |
172 | return estimated_cardinality; |
173 | } |
174 | |
175 | void LogicalOperator::Print() { |
176 | Printer::Print(str: ToString()); |
177 | } |
178 | |
179 | void LogicalOperator::Serialize(Serializer &serializer) const { |
180 | FieldWriter writer(serializer); |
181 | writer.WriteField<LogicalOperatorType>(element: type); |
182 | writer.WriteSerializableList(elements: children); |
183 | |
184 | Serialize(writer); |
185 | writer.Finalize(); |
186 | } |
187 | |
188 | unique_ptr<LogicalOperator> LogicalOperator::Deserialize(Deserializer &deserializer, PlanDeserializationState &gstate) { |
189 | unique_ptr<LogicalOperator> result; |
190 | |
191 | FieldReader reader(deserializer); |
192 | auto type = reader.ReadRequired<LogicalOperatorType>(); |
193 | auto children = reader.ReadRequiredSerializableList<LogicalOperator>(args&: gstate); |
194 | |
195 | LogicalDeserializationState state(gstate, type, children); |
196 | switch (type) { |
197 | case LogicalOperatorType::LOGICAL_PROJECTION: |
198 | result = LogicalProjection::Deserialize(state, reader); |
199 | break; |
200 | case LogicalOperatorType::LOGICAL_FILTER: |
201 | result = LogicalFilter::Deserialize(state, reader); |
202 | break; |
203 | case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: |
204 | result = LogicalAggregate::Deserialize(state, reader); |
205 | break; |
206 | case LogicalOperatorType::LOGICAL_WINDOW: |
207 | result = LogicalWindow::Deserialize(state, reader); |
208 | break; |
209 | case LogicalOperatorType::LOGICAL_UNNEST: |
210 | result = LogicalUnnest::Deserialize(state, reader); |
211 | break; |
212 | case LogicalOperatorType::LOGICAL_LIMIT: |
213 | result = LogicalLimit::Deserialize(state, reader); |
214 | break; |
215 | case LogicalOperatorType::LOGICAL_ORDER_BY: |
216 | result = LogicalOrder::Deserialize(state, reader); |
217 | break; |
218 | case LogicalOperatorType::LOGICAL_TOP_N: |
219 | result = LogicalTopN::Deserialize(state, reader); |
220 | break; |
221 | case LogicalOperatorType::LOGICAL_COPY_TO_FILE: |
222 | result = LogicalCopyToFile::Deserialize(state, reader); |
223 | break; |
224 | case LogicalOperatorType::LOGICAL_DISTINCT: |
225 | result = LogicalDistinct::Deserialize(state, reader); |
226 | break; |
227 | case LogicalOperatorType::LOGICAL_SAMPLE: |
228 | result = LogicalSample::Deserialize(state, reader); |
229 | break; |
230 | case LogicalOperatorType::LOGICAL_LIMIT_PERCENT: |
231 | result = LogicalLimitPercent::Deserialize(state, reader); |
232 | break; |
233 | case LogicalOperatorType::LOGICAL_GET: |
234 | result = LogicalGet::Deserialize(state, reader); |
235 | break; |
236 | case LogicalOperatorType::LOGICAL_CHUNK_GET: |
237 | result = LogicalColumnDataGet::Deserialize(state, reader); |
238 | break; |
239 | case LogicalOperatorType::LOGICAL_DELIM_GET: |
240 | result = LogicalDelimGet::Deserialize(state, reader); |
241 | break; |
242 | case LogicalOperatorType::LOGICAL_EXPRESSION_GET: |
243 | result = LogicalExpressionGet::Deserialize(state, reader); |
244 | break; |
245 | case LogicalOperatorType::LOGICAL_DUMMY_SCAN: |
246 | result = LogicalDummyScan::Deserialize(state, reader); |
247 | break; |
248 | case LogicalOperatorType::LOGICAL_EMPTY_RESULT: |
249 | result = LogicalEmptyResult::Deserialize(state, reader); |
250 | break; |
251 | case LogicalOperatorType::LOGICAL_CTE_REF: |
252 | result = LogicalCTERef::Deserialize(state, reader); |
253 | break; |
254 | case LogicalOperatorType::LOGICAL_JOIN: |
255 | throw InternalException("LogicalJoin deserialize not supported" ); |
256 | case LogicalOperatorType::LOGICAL_DELIM_JOIN: |
257 | result = LogicalDelimJoin::Deserialize(state, reader); |
258 | break; |
259 | case LogicalOperatorType::LOGICAL_ASOF_JOIN: |
260 | result = LogicalAsOfJoin::Deserialize(state, reader); |
261 | break; |
262 | case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: |
263 | result = LogicalComparisonJoin::Deserialize(state, reader); |
264 | break; |
265 | case LogicalOperatorType::LOGICAL_ANY_JOIN: |
266 | result = LogicalAnyJoin::Deserialize(state, reader); |
267 | break; |
268 | case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: |
269 | result = LogicalCrossProduct::Deserialize(state, reader); |
270 | break; |
271 | case LogicalOperatorType::LOGICAL_POSITIONAL_JOIN: |
272 | result = LogicalPositionalJoin::Deserialize(state, reader); |
273 | break; |
274 | case LogicalOperatorType::LOGICAL_UNION: |
275 | result = LogicalSetOperation::Deserialize(state, reader); |
276 | break; |
277 | case LogicalOperatorType::LOGICAL_EXCEPT: |
278 | result = LogicalSetOperation::Deserialize(state, reader); |
279 | break; |
280 | case LogicalOperatorType::LOGICAL_INTERSECT: |
281 | result = LogicalSetOperation::Deserialize(state, reader); |
282 | break; |
283 | case LogicalOperatorType::LOGICAL_RECURSIVE_CTE: |
284 | result = LogicalRecursiveCTE::Deserialize(state, reader); |
285 | break; |
286 | case LogicalOperatorType::LOGICAL_INSERT: |
287 | result = LogicalInsert::Deserialize(state, reader); |
288 | break; |
289 | case LogicalOperatorType::LOGICAL_DELETE: |
290 | result = LogicalDelete::Deserialize(state, reader); |
291 | break; |
292 | case LogicalOperatorType::LOGICAL_UPDATE: |
293 | result = LogicalUpdate::Deserialize(state, reader); |
294 | break; |
295 | case LogicalOperatorType::LOGICAL_CREATE_TABLE: |
296 | result = LogicalCreateTable::Deserialize(state, reader); |
297 | break; |
298 | case LogicalOperatorType::LOGICAL_CREATE_INDEX: |
299 | result = LogicalCreateIndex::Deserialize(state, reader); |
300 | break; |
301 | case LogicalOperatorType::LOGICAL_CREATE_SEQUENCE: |
302 | result = LogicalCreate::Deserialize(state, reader); |
303 | break; |
304 | case LogicalOperatorType::LOGICAL_CREATE_VIEW: |
305 | result = LogicalCreate::Deserialize(state, reader); |
306 | break; |
307 | case LogicalOperatorType::LOGICAL_CREATE_SCHEMA: |
308 | result = LogicalCreate::Deserialize(state, reader); |
309 | break; |
310 | case LogicalOperatorType::LOGICAL_CREATE_MACRO: |
311 | result = LogicalCreate::Deserialize(state, reader); |
312 | break; |
313 | case LogicalOperatorType::LOGICAL_PRAGMA: |
314 | result = LogicalPragma::Deserialize(state, reader); |
315 | break; |
316 | case LogicalOperatorType::LOGICAL_CREATE_TYPE: |
317 | result = LogicalCreate::Deserialize(state, reader); |
318 | break; |
319 | case LogicalOperatorType::LOGICAL_EXPLAIN: |
320 | result = LogicalExplain::Deserialize(state, reader); |
321 | break; |
322 | case LogicalOperatorType::LOGICAL_SHOW: |
323 | result = LogicalShow::Deserialize(state, reader); |
324 | break; |
325 | case LogicalOperatorType::LOGICAL_PREPARE: |
326 | result = LogicalPrepare::Deserialize(state, reader); |
327 | break; |
328 | case LogicalOperatorType::LOGICAL_EXECUTE: |
329 | result = LogicalExecute::Deserialize(state, reader); |
330 | break; |
331 | case LogicalOperatorType::LOGICAL_EXPORT: |
332 | result = LogicalExport::Deserialize(state, reader); |
333 | break; |
334 | case LogicalOperatorType::LOGICAL_SET: |
335 | result = LogicalSet::Deserialize(state, reader); |
336 | break; |
337 | case LogicalOperatorType::LOGICAL_RESET: |
338 | result = LogicalReset::Deserialize(state, reader); |
339 | break; |
340 | case LogicalOperatorType::LOGICAL_ALTER: |
341 | case LogicalOperatorType::LOGICAL_VACUUM: |
342 | case LogicalOperatorType::LOGICAL_LOAD: |
343 | case LogicalOperatorType::LOGICAL_ATTACH: |
344 | case LogicalOperatorType::LOGICAL_TRANSACTION: |
345 | case LogicalOperatorType::LOGICAL_DROP: |
346 | case LogicalOperatorType::LOGICAL_DETACH: |
347 | result = LogicalSimple::Deserialize(state, reader); |
348 | break; |
349 | case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: |
350 | result = LogicalExtensionOperator::Deserialize(state, reader); |
351 | break; |
352 | case LogicalOperatorType::LOGICAL_PIVOT: |
353 | result = LogicalPivot::Deserialize(state, reader); |
354 | break; |
355 | case LogicalOperatorType::LOGICAL_INVALID: |
356 | /* no default here to trigger a warning if we forget to implement deserialize for a new operator */ |
357 | throw SerializationException("Invalid type for operator deserialization" ); |
358 | } |
359 | |
360 | reader.Finalize(); |
361 | result->children = std::move(children); |
362 | |
363 | return result; |
364 | } |
365 | |
366 | vector<idx_t> LogicalOperator::GetTableIndex() const { |
367 | return vector<idx_t> {}; |
368 | } |
369 | |
370 | unique_ptr<LogicalOperator> LogicalOperator::Copy(ClientContext &context) const { |
371 | BufferedSerializer logical_op_serializer; |
372 | try { |
373 | this->Serialize(serializer&: logical_op_serializer); |
374 | } catch (NotImplementedException &ex) { |
375 | throw NotImplementedException("Logical Operator Copy requires the logical operator and all of its children to " |
376 | "be serializable: " + |
377 | std::string(ex.what())); |
378 | } |
379 | auto data = logical_op_serializer.GetData(); |
380 | auto logical_op_deserializer = BufferedContextDeserializer(context, data.data.get(), data.size); |
381 | PlanDeserializationState state(context); |
382 | auto op_copy = LogicalOperator::Deserialize(deserializer&: logical_op_deserializer, gstate&: state); |
383 | return op_copy; |
384 | } |
385 | |
386 | } // namespace duckdb |
387 | |