mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
PartialPlanGenerator.cpp
Go to the documentation of this file.
2
4
5
6using namespace m;
7
8
9template<typename PlanTable>
11{
12 if (PT.num_sources() == 0)
13 return;
14
15 if (PT.num_sources() == 1) {
16 const Subproblem root(1UL);
17 partial_plan_type partial_plans{{ root }};
18 callback(partial_plans);
19 return;
20 }
21
22 const auto &final_plan_entry = PT.get_final();
23 const Subproblem root_of_final_plan = final_plan_entry.left | final_plan_entry.right;
24
26 partial_plan_type partial_plans;
28 partial_plan_type candidates;
30 std::vector<bool> decision_stack;
31 partial_plans.reserve(PT.num_sources());
32 candidates.reserve(PT.num_sources());
33 /* Every plan that is *not* a relation, can be rejected. With *n* relations, there are *n-1* such plans. Hence,
34 * the decision stack can have at most *n-1* times NO and *n* times YES. */
35 decision_stack.reserve(2 * PT.num_sources());
36
37 /*----- Initialize -----*/
38 partial_plans.emplace_back(root_of_final_plan);
39 decision_stack.emplace_back(true);
40
41 for (;;) {
42 if (candidates.empty()) {
43 callback(partial_plans);
44
45 /*----- Unwind the decision stack. -----*/
46 for (;;) {
47 if (decision_stack.empty())
48 goto finished;
49
50 const bool was_partial_plan_taken = decision_stack.back();
51 if (not was_partial_plan_taken) {
52 M_insist(candidates.size() >= 2);
53 const Subproblem right = candidates.back();
54 candidates.pop_back();
55 const Subproblem left = candidates.back();
56 candidates.pop_back();
57 decision_stack.pop_back();
58 candidates.emplace_back(left|right); // reconstruct unaccepted partial plan from its children
59 continue;
60 }
61
62 M_insist(not partial_plans.empty());
63 const auto partial_plan = partial_plans.back();
64 partial_plans.pop_back();
65 if (partial_plan.is_singleton()) {
66 decision_stack.pop_back();
67 candidates.push_back(partial_plan); // leaves become candidates again
68 continue;
69 }
70
71 M_insist(was_partial_plan_taken);
72 decision_stack.back() = false; // no more an accepted partial plan in the new trace
73 candidates.push_back(PT[partial_plan].left); // left child
74 candidates.push_back(PT[partial_plan].right); // right child
75 break;
76 }
77 } else {
78 /*----- Take next partial plan candidate. -----*/
79 auto partial_plan = candidates.back();
80 candidates.pop_back();
81 partial_plans.emplace_back(partial_plan);
82 decision_stack.emplace_back(true);
83 }
84 }
85finished:;
86}
87
88template<typename PlanTable>
89void PartialPlanGenerator::write_partial_plans_JSON(std::ostream &out, const QueryGraph &G, const PlanTable &PT,
90 std::function<void(callback_type)> for_each_partial_plan)
91{
92 /*----- Lambda writes a partial plan tree to `out`, given the root if the tree. -----*/
93 auto write_tree = [&](Subproblem root) -> void {
94 auto write_tree_rec = [&](Subproblem root, auto &write_tree_rec) -> void {
95 if (root.is_singleton()) {
96 out << G.sources()[*root.begin()]->name();
97 } else {
98 out << "@ ";
99 write_tree_rec(PT[root].left, write_tree_rec);
100 out << ' ';
101 write_tree_rec(PT[root].right, write_tree_rec);
102 }
103 };
104 write_tree_rec(root, write_tree_rec);
105 };
106
107 /* Given a forest of trees, representing a partial plan of a query, where each tree is uniquely represented by its
108 * root, write a JSON representation of this partial plan to `out`.
109 *
110 * Example:
111 * Graph:
112 * A - B - C
113 *
114 * Input --> Output:
115 * { A, B, C } --> [ "A", "B", "C" ]
116 * { AB, C } --> [ "@ A B", "C" ]
117 * { A, BC } --> [ "A", "@ B C" ]
118 * { A(BC) } --> [ "@ A @ B C" ]
119 * { (AB)C } --> [ "@ @ A B C" ]
120 */
121 auto write_partial_plan = [&](const partial_plan_type &partial_plans) {
122 M_insist(not partial_plans.empty());
123
124 static bool is_first = true;
125 if (is_first)
126 is_first = false;
127 else
128 out << ',';
129 out << "\n ";
130
131 out << "[ ";
132 for (auto it = partial_plans.cbegin(); it != partial_plans.cend(); ++it) {
133 if (it != partial_plans.cbegin()) out << ", ";
134 out << '"';
135 write_tree(*it);
136 out << '"';
137 }
138 out << " ]";
139 };
140
141
142 /*----- Write beginning of JSON. -----*/
143 out << '[';
144
145 /*----- Write partial plans. -----*/
146 for_each_partial_plan(write_partial_plan);
147
148 /*----- Write end of JSON. -----*/
149 out << "\n]\n";
150}
151
152/*----- Explicit tempalte instantiations. ----------------------------------------------------------------------------*/
155template void PartialPlanGenerator::write_partial_plans_JSON(std::ostream&, const QueryGraph&, const PlanTableSmallOrDense&, std::function<void(callback_type)>);
156template void PartialPlanGenerator::write_partial_plans_JSON(std::ostream&, const QueryGraph&, const PlanTableLargeAndSparse&, std::function<void(callback_type)>);
#define M_insist(...)
Definition: macro.hpp:129
‍mutable namespace
Definition: Backend.hpp:10
void for_each_complete_partial_plan(const PlanTable &PT, callback_type callback)
Given a PlanTable with a final plan, enumerate all complete partial plans of this final plan and invo...
void write_partial_plans_JSON(std::ostream &out, const QueryGraph &G, const PlanTable &PT, std::function< void(callback_type)> for_each_partial_plan)
std::vector< Subproblem > partial_plan_type
std::function< void(const partial_plan_type &)> callback_type
This table represents all explored plans with their sub-plans, estimated size, cost,...
Definition: PlanTable.hpp:284
This table represents all explored plans with their sub-plans, estimated size, cost,...
Definition: PlanTable.hpp:180
The query graph represents all data sources and joins in a graph structure.
Definition: QueryGraph.hpp:172
const auto & sources() const
Definition: QueryGraph.hpp:257
Implements a small and efficient set over integers in the range of 0 to 63 (including).
Definition: ADT.hpp:26
bool is_singleton() const
Definition: ADT.hpp:165
auto begin() const
Definition: ADT.hpp:173