@@ -59,45 +59,68 @@ void GRAPHVIZTreeRenderer::Render(const Pipeline &op, BaseTreeRenderer &ss) {
5959 ToStream (*tree, ss);
6060}
6161
62- void GRAPHVIZTreeRenderer::ToStreamInternal (RenderTree &root, BaseTreeRenderer &ss) {
63- const string digraph_format = R"(
64- digraph G {
65- node [shape=box, style=rounded, fontname="Courier New", fontsize=10];
66- %s
67- %s
62+ static string GraphvizNodeName (const string &prefix, idx_t x, idx_t y) {
63+ if (prefix.empty ()) {
64+ return StringUtil::Format (" node_%d_%d" , x, y);
65+ }
66+ return StringUtil::Format (" node_%s_%d_%d" , prefix, x, y);
6867}
69- )" ;
70-
71- vector<string> nodes;
72- vector<string> edges;
7368
74- const string node_format = R"( node_%d_%d [label="%s"]; )" ;
75-
76- for (idx_t y = 0 ; y < root .height ; y++) {
77- for (idx_t x = 0 ; x < root .width ; x++) {
78- auto node = root .GetNode (x, y);
69+ static void RenderGraph (RenderTree &tree, const string &prefix, vector<string> &nodes, vector<string> &edges,
70+ idx_t &next_sub_plan) {
71+ for (idx_t y = 0 ; y < tree .height ; y++) {
72+ for (idx_t x = 0 ; x < tree .width ; x++) {
73+ auto node = tree .GetNode (x, y);
7974 if (!node) {
8075 continue ;
8176 }
8277
83- // Create Node
8478 vector<string> body;
8579 body.push_back (node->name );
8680 for (auto &item : node->extra_text ) {
87- auto &key = item.first ;
88- auto &value_raw = item.second ;
89-
90- auto value = QueryProfiler::JSONSanitize (value_raw);
91- body.push_back (StringUtil::Format (" %s:\\ n%s" , key, value));
81+ auto value = QueryProfiler::JSONSanitize (item.second );
82+ body.push_back (StringUtil::Format (" %s:\\ n%s" , item.first , value));
9283 }
93- nodes.push_back (StringUtil::Format (node_format, x, y, StringUtil::Join (body, " \\ n───\\ n" )));
84+ auto node_name = GraphvizNodeName (prefix, x, y);
85+ nodes.push_back (
86+ StringUtil::Format (" %s [label=\" %s\" ];" , node_name, StringUtil::Join (body, " \\ n───\\ n" )));
9487
95- // Create Edge(s)
9688 for (auto &coord : node->child_positions ) {
97- edges.push_back (StringUtil::Format (" node_%d_%d -> node_%d_%d;" , x, y, coord.x , coord.y ));
89+ edges.push_back (
90+ StringUtil::Format (" %s -> %s;" , node_name, GraphvizNodeName (prefix, coord.x , coord.y )));
91+ }
92+ for (auto &sub_plan : node->sub_plans ) {
93+ if (!sub_plan.tree ) {
94+ continue ;
95+ }
96+ auto sub_plan_name = StringUtil::Format (" subplan_%d" , next_sub_plan++);
97+ vector<string> sub_plan_nodes;
98+ vector<string> sub_plan_edges;
99+ RenderGraph (*sub_plan.tree , sub_plan_name, sub_plan_nodes, sub_plan_edges, next_sub_plan);
100+ nodes.push_back (StringUtil::Format (" subgraph cluster_%s {\n label=\" %s\" ;\n %s\n %s\n }" ,
101+ sub_plan_name, QueryProfiler::JSONSanitize (sub_plan.label ),
102+ StringUtil::Join (sub_plan_nodes, " \n " ),
103+ StringUtil::Join (sub_plan_edges, " \n " )));
104+ edges.push_back (StringUtil::Format (" %s -> %s [style=dashed];" , node_name,
105+ GraphvizNodeName (sub_plan_name, 0 , 0 )));
98106 }
99107 }
100108 }
109+ }
110+
111+ void GRAPHVIZTreeRenderer::ToStreamInternal (RenderTree &root, BaseTreeRenderer &ss) {
112+ const string digraph_format = R"(
113+ digraph G {
114+ node [shape=box, style=rounded, fontname="Courier New", fontsize=10];
115+ %s
116+ %s
117+ }
118+ )" ;
119+
120+ vector<string> nodes;
121+ vector<string> edges;
122+ idx_t next_sub_plan = 0 ;
123+ RenderGraph (root, string (), nodes, edges, next_sub_plan);
101124 auto node_lines = StringUtil::Join (nodes, " \n " );
102125 auto edge_lines = StringUtil::Join (edges, " \n " );
103126
0 commit comments