1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/optimizer/unnest_rewriter.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/planner/logical_operator.hpp"
12#include "duckdb/common/pair.hpp"
13
14namespace duckdb {
15
16class Optimizer;
17
18struct ReplaceBinding {
19 ReplaceBinding() {};
20 ReplaceBinding(ColumnBinding old_binding, ColumnBinding new_binding)
21 : old_binding(old_binding), new_binding(new_binding) {
22 }
23 ColumnBinding old_binding;
24 ColumnBinding new_binding;
25};
26
27struct LHSBinding {
28 LHSBinding() {};
29 LHSBinding(ColumnBinding binding, LogicalType type) : binding(binding), type(type) {
30 }
31 ColumnBinding binding;
32 LogicalType type;
33 string alias;
34};
35
36//! The UnnestRewriterPlanUpdater updates column bindings after changing the operator plan
37class UnnestRewriterPlanUpdater : LogicalOperatorVisitor {
38public:
39 UnnestRewriterPlanUpdater() {
40 }
41 //! Update each operator of the plan after moving an UNNEST into a projection
42 void VisitOperator(LogicalOperator &op) override;
43 //! Visit an expression and update its column bindings after moving and UNNEST into a projection
44 void VisitExpression(unique_ptr<Expression> *expression) override;
45
46 //! Contains all bindings that need to be updated
47 vector<ReplaceBinding> replace_bindings;
48 //! Stores the table index of the former child of the LOGICAL_UNNEST
49 idx_t overwritten_tbl_idx;
50};
51
52//! The UnnestRewriter optimizer traverses the logical operator tree and rewrites duplicate
53//! eliminated joins that contain UNNESTs by moving the UNNESTs into the projection of
54//! the SELECT
55class UnnestRewriter {
56public:
57 UnnestRewriter() {
58 }
59 //! Rewrite duplicate eliminated joins with UNNESTs
60 unique_ptr<LogicalOperator> Optimize(unique_ptr<LogicalOperator> op);
61
62private:
63 //! Find delim joins that contain an UNNEST
64 void FindCandidates(unique_ptr<LogicalOperator> *op_ptr, vector<unique_ptr<LogicalOperator> *> &candidates);
65 //! Rewrite a delim join that contains an UNNEST
66 bool RewriteCandidate(unique_ptr<LogicalOperator> *candidate);
67 //! Update the bindings of the RHS sequence of LOGICAL_PROJECTION(s)
68 void UpdateRHSBindings(unique_ptr<LogicalOperator> *plan_ptr, unique_ptr<LogicalOperator> *candidate,
69 UnnestRewriterPlanUpdater &updater);
70 //! Update the bindings of the BOUND_UNNEST expression of the LOGICAL_UNNEST
71 void UpdateBoundUnnestBindings(UnnestRewriterPlanUpdater &updater, unique_ptr<LogicalOperator> *candidate);
72
73 //! Store all delim columns of the delim join
74 void GetDelimColumns(LogicalOperator &op);
75 //! Store all LHS expressions of the LOGICAL_PROJECTION
76 void GetLHSExpressions(LogicalOperator &op);
77
78 //! Keep track of the delim columns to find the correct UNNEST column
79 vector<ColumnBinding> delim_columns;
80 //! Store the column bindings of the LHS child of the LOGICAL_DELIM_JOIN
81 vector<LHSBinding> lhs_bindings;
82 //! Stores the table index of the former child of the LOGICAL_UNNEST
83 idx_t overwritten_tbl_idx;
84 //! The number of distinct columns to unnest
85 idx_t distinct_unnest_count;
86};
87
88} // namespace duckdb
89