From 6edd87850501ca5fedacfc7c9d36db72334a668d Mon Sep 17 00:00:00 2001 From: Jianhong Shi Date: Sat, 25 Jul 2026 18:11:07 -0500 Subject: [PATCH] flip roots independently in disconnected DAG components --- src/optimizer/robust_optimizer.cpp | 146 ++++++++++++++++++----------- src/optimizer/robust_optimizer.hpp | 6 ++ 2 files changed, 98 insertions(+), 54 deletions(-) diff --git a/src/optimizer/robust_optimizer.cpp b/src/optimizer/robust_optimizer.cpp index 547754b..87f78a4 100644 --- a/src/optimizer/robust_optimizer.cpp +++ b/src/optimizer/robust_optimizer.cpp @@ -797,70 +797,108 @@ vector RobustOptimizerContextState::BuildPhysicalPlanDAG(Logi } void RobustOptimizerContextState::FlipRootsToLeaves(vector &all_nodes) { - // step 1: find all roots - vector roots; + unordered_map visited; + vector components; for (auto *node : all_nodes) { - if (node->parents.empty()) { - roots.push_back(node); + // step 1: find all roots + if (visited.count(node->table_idx)) { + continue; + } + vector comp_nodes; + vector roots; + PhysicalDAGNode *anchor; + vector que; + auto discover = [&](PhysicalDAGNode *candidate) { + if (visited.count(candidate->table_idx)) { + return; + } + if (candidate->parents.empty()) { + roots.push_back(candidate); + } + visited[candidate->table_idx] = true; + que.push_back(candidate); + comp_nodes.push_back(candidate); + }; + discover(node); + while (!que.empty()) { + auto cur = que.back(); + que.pop_back(); + for (auto &child : cur->children) { + discover(child); + } + for (auto &parent : cur->parents) { + discover(parent); + } } - } - if (roots.size() <= 1) { - return; - } - // step 2: find anchor root (largest cardinality) - PhysicalDAGNode *anchor = roots[0]; - for (auto *r : roots) { - if (r->table_op->estimated_cardinality > anchor->table_op->estimated_cardinality) { - anchor = r; + // step 2: find anchor root (largest cardinality) + if (roots.empty()) { + D_PRINTF("ERROR: No root found for this component"); + continue; } + anchor = roots[0]; + for (auto *r : roots) { + if (r->table_op->estimated_cardinality > anchor->table_op->estimated_cardinality) { + anchor = r; + } + } + components.push_back({comp_nodes, roots, anchor}); } + for (auto &comp : components) { + auto &comp_nodes = comp.comp_nodes; + auto &roots = comp.roots; + auto *anchor = comp.anchor; + if (roots.size() <= 1) { + continue; + } - // step 3: repeatedly flip non-anchor roots until only anchor remains - // flipping a root can expose new roots (e.g. flipping name reveals aka_name) - bool flipped = true; - while (flipped) { - flipped = false; - for (auto *node : all_nodes) { - if (!node->parents.empty() || node == anchor) { - continue; - } - // non-anchor root: reverse all edges to its children - auto children_copy = node->children; - for (auto *child : children_copy) { - PhysicalDAGEdge edge; - bool found = false; - for (idx_t i = 0; i < child->parents.size(); i++) { - if (child->parents[i] == node) { - edge = child->edges_to_parents[i]; - child->parents.erase(child->parents.begin() + static_cast(i)); - child->edges_to_parents.erase(child->edges_to_parents.begin() + static_cast(i)); - found = true; - break; - } - } - if (!found) { + // step 3: repeatedly flip non-anchor roots until only anchor remains + // flipping a root can expose new roots (e.g. flipping name reveals aka_name) + bool flipped = true; + while (flipped) { + flipped = false; + for (auto *node : comp_nodes) { + if (!node->parents.empty() || node == anchor) { continue; } - for (idx_t i = 0; i < node->children.size(); i++) { - if (node->children[i] == child) { - node->children.erase(node->children.begin() + static_cast(i)); - break; + // non-anchor root: reverse all edges to its children + auto children_copy = node->children; + for (auto *child : children_copy) { + PhysicalDAGEdge edge; + bool found = false; + for (idx_t i = 0; i < child->parents.size(); i++) { + if (child->parents[i] == node) { + edge = child->edges_to_parents[i]; + child->parents.erase(child->parents.begin() + static_cast(i)); + child->edges_to_parents.erase(child->edges_to_parents.begin() + + static_cast(i)); + found = true; + break; + } + } + if (!found) { + continue; + } + for (idx_t i = 0; i < node->children.size(); i++) { + if (node->children[i] == child) { + node->children.erase(node->children.begin() + static_cast(i)); + break; + } } + child->children.push_back(node); + node->parents.push_back(child); + + PhysicalDAGEdge reversed; + reversed.parent_table = edge.child_table; + reversed.child_table = edge.parent_table; + reversed.parent_cols = edge.child_cols; + reversed.child_cols = edge.parent_cols; + node->edges_to_parents.push_back(reversed); + + // only mark progress on a real reversal; a childless root cannot + // be flipped and must not keep this loop spinning forever + flipped = true; } - child->children.push_back(node); - node->parents.push_back(child); - - PhysicalDAGEdge reversed; - reversed.parent_table = edge.child_table; - reversed.child_table = edge.parent_table; - reversed.parent_cols = edge.child_cols; - reversed.child_cols = edge.parent_cols; - node->edges_to_parents.push_back(reversed); - - // only mark progress on a real reversal; a childless root cannot - // be flipped and must not keep this loop spinning forever - flipped = true; } } } diff --git a/src/optimizer/robust_optimizer.hpp b/src/optimizer/robust_optimizer.hpp index 10bb7be..adc3663 100644 --- a/src/optimizer/robust_optimizer.hpp +++ b/src/optimizer/robust_optimizer.hpp @@ -45,6 +45,12 @@ struct PhysicalDAGNode { } }; +struct Component { + vector comp_nodes; + vector roots; + PhysicalDAGNode *anchor; +}; + // column key for equivalence class union-find using ColKey = std::pair; // (table_idx, column_idx)