@@ -153,6 +153,49 @@ std::string node_detail(const std::string& line) {
153153 return line.substr (bracket + 1 , line.size () - bracket - 2 );
154154}
155155
156+ struct OwnedSubquery {
157+ std::string detail;
158+ const plan::LogicalPlan* plan{nullptr };
159+ };
160+
161+ void collect_scalar_subquery (const plan::BoundScalarExpr& expression,
162+ std::vector<OwnedSubquery>& subqueries) {
163+ if (const auto * subquery = std::get_if<plan::BoundScalarSubquery>(&expression.value );
164+ subquery != nullptr && subquery->plan != nullptr ) {
165+ subqueries.push_back ({" Subquery[" + subquery->name + " ]" , subquery->plan .get ()});
166+ }
167+ }
168+
169+ void collect_predicate_subqueries (const plan::BoundPredicate& predicate,
170+ std::vector<OwnedSubquery>& subqueries) {
171+ if (predicate.kind == sql::PredicateKind::Comparison) {
172+ collect_scalar_subquery (predicate.comparison .left , subqueries);
173+ collect_scalar_subquery (predicate.comparison .right , subqueries);
174+ }
175+ if (predicate.subquery != nullptr ) {
176+ subqueries.push_back ({" Subquery[" + predicate.subquery_name + " ]" , predicate.subquery .get ()});
177+ }
178+ if (predicate.left != nullptr ) collect_predicate_subqueries (*predicate.left , subqueries);
179+ if (predicate.right != nullptr ) collect_predicate_subqueries (*predicate.right , subqueries);
180+ }
181+
182+ std::string tree_json (const plan::LogicalPlan& node, const execution::Catalog& catalog, int indent);
183+
184+ std::string subquery_tree_json (const OwnedSubquery& subquery,
185+ const execution::Catalog& catalog,
186+ int indent) {
187+ const auto estimate = optimizer::estimate_cost (*subquery.plan , catalog);
188+ const std::string pad (static_cast <std::size_t >(indent), ' ' );
189+ std::string out = " {\n " + pad + " \" op\" : \" Subquery\" ," +
190+ " \n " + pad + " \" detail\" : " + quoted (subquery.detail ) +
191+ " ,\n " + pad + " \" rows\" : " + fixed (estimate.rows , 2 ) +
192+ " ,\n " + pad + " \" cost\" : " + fixed (estimate.cost , 2 ) +
193+ " ,\n " + pad + " \" children\" : [\n " + pad + " " +
194+ tree_json (*subquery.plan , catalog, indent + 4 ) +
195+ " \n " + pad + " ]\n " + pad + " }" ;
196+ return out;
197+ }
198+
156199std::string tree_json (const plan::LogicalPlan& node, const execution::Catalog& catalog, int indent) {
157200 const auto estimate = optimizer::estimate_cost (node, catalog);
158201 const auto line = node_line (node);
@@ -166,10 +209,23 @@ std::string tree_json(const plan::LogicalPlan& node, const execution::Catalog& c
166209 if (node.input ) children.push_back (node.input .get ());
167210 if (node.left ) children.push_back (node.left .get ());
168211 if (node.right ) children.push_back (node.right .get ());
169- for (std::size_t i = 0 ; i < children.size (); ++i) {
170- out += (i == 0 ? " \n " : " ,\n " ) + pad + " " + tree_json (*children[i], catalog, indent + 4 );
212+ std::vector<OwnedSubquery> subqueries;
213+ for (const auto & predicate : node.predicates ) {
214+ collect_predicate_subqueries (predicate, subqueries);
215+ }
216+ if (node.null_aware_predicate .has_value ()) {
217+ collect_predicate_subqueries (*node.null_aware_predicate , subqueries);
218+ }
219+ std::size_t child_index = 0 ;
220+ for (const auto * child : children) {
221+ out += (child_index++ == 0 ? " \n " : " ,\n " ) + pad + " " +
222+ tree_json (*child, catalog, indent + 4 );
223+ }
224+ for (const auto & subquery : subqueries) {
225+ out += (child_index++ == 0 ? " \n " : " ,\n " ) + pad + " " +
226+ subquery_tree_json (subquery, catalog, indent + 4 );
171227 }
172- out += children. empty () ? " ]" : " \n " + pad + " ]" ;
228+ out += child_index == 0 ? " ]" : " \n " + pad + " ]" ;
173229 out += " \n " + pad + " }" ;
174230 return out;
175231}
0 commit comments