1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/common/tree_renderer.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/constants.hpp"
12#include "duckdb/common/vector.hpp"
13#include "duckdb/main/query_profiler.hpp"
14
15namespace duckdb {
16class LogicalOperator;
17class PhysicalOperator;
18class Pipeline;
19struct PipelineRenderNode;
20
21struct RenderTreeNode {
22 string name;
23 string extra_text;
24};
25
26struct RenderTree {
27 RenderTree(idx_t width, idx_t height);
28
29 unique_ptr<unique_ptr<RenderTreeNode>[]> nodes;
30 idx_t width;
31 idx_t height;
32
33public:
34 RenderTreeNode *GetNode(idx_t x, idx_t y);
35 void SetNode(idx_t x, idx_t y, unique_ptr<RenderTreeNode> node);
36 bool HasNode(idx_t x, idx_t y);
37
38 idx_t GetPosition(idx_t x, idx_t y);
39};
40
41struct TreeRendererConfig {
42 void enable_detailed() {
43 MAX_EXTRA_LINES = 1000;
44 detailed = true;
45 }
46
47 void enable_standard() {
48 MAX_EXTRA_LINES = 30;
49 detailed = false;
50 }
51
52 idx_t MAXIMUM_RENDER_WIDTH = 240;
53 idx_t NODE_RENDER_WIDTH = 29;
54 idx_t MINIMUM_RENDER_WIDTH = 15;
55 idx_t MAX_EXTRA_LINES = 30;
56 bool detailed = false;
57
58#ifndef DUCKDB_ASCII_TREE_RENDERER
59 const char *LTCORNER = "\342\224\214"; // "┌";
60 const char *RTCORNER = "\342\224\220"; // "┐";
61 const char *LDCORNER = "\342\224\224"; // "└";
62 const char *RDCORNER = "\342\224\230"; // "┘";
63
64 const char *MIDDLE = "\342\224\274"; // "┼";
65 const char *TMIDDLE = "\342\224\254"; // "┬";
66 const char *LMIDDLE = "\342\224\234"; // "├";
67 const char *RMIDDLE = "\342\224\244"; // "┤";
68 const char *DMIDDLE = "\342\224\264"; // "┴";
69
70 const char *VERTICAL = "\342\224\202"; // "│";
71 const char *HORIZONTAL = "\342\224\200"; // "─";
72#else
73 // ASCII version
74 const char *LTCORNER = "<";
75 const char *RTCORNER = ">";
76 const char *LDCORNER = "<";
77 const char *RDCORNER = ">";
78
79 const char *MIDDLE = "+";
80 const char *TMIDDLE = "+";
81 const char *LMIDDLE = "+";
82 const char *RMIDDLE = "+";
83 const char *DMIDDLE = "+";
84
85 const char *VERTICAL = "|";
86 const char *HORIZONTAL = "-";
87#endif
88};
89
90class TreeRenderer {
91public:
92 explicit TreeRenderer(TreeRendererConfig config_p = TreeRendererConfig()) : config(std::move(config_p)) {
93 }
94
95 string ToString(const LogicalOperator &op);
96 string ToString(const PhysicalOperator &op);
97 string ToString(const QueryProfiler::TreeNode &op);
98 string ToString(const Pipeline &op);
99
100 void Render(const LogicalOperator &op, std::ostream &ss);
101 void Render(const PhysicalOperator &op, std::ostream &ss);
102 void Render(const QueryProfiler::TreeNode &op, std::ostream &ss);
103 void Render(const Pipeline &op, std::ostream &ss);
104
105 void ToStream(RenderTree &root, std::ostream &ss);
106
107 void EnableDetailed() {
108 config.enable_detailed();
109 }
110 void EnableStandard() {
111 config.enable_standard();
112 }
113
114private:
115 unique_ptr<RenderTree> CreateTree(const LogicalOperator &op);
116 unique_ptr<RenderTree> CreateTree(const PhysicalOperator &op);
117 unique_ptr<RenderTree> CreateTree(const QueryProfiler::TreeNode &op);
118 unique_ptr<RenderTree> CreateTree(const Pipeline &op);
119
120 string ExtraInfoSeparator();
121 unique_ptr<RenderTreeNode> CreateRenderNode(string name, string extra_info);
122 unique_ptr<RenderTreeNode> CreateNode(const LogicalOperator &op);
123 unique_ptr<RenderTreeNode> CreateNode(const PhysicalOperator &op);
124 unique_ptr<RenderTreeNode> CreateNode(const QueryProfiler::TreeNode &op);
125 unique_ptr<RenderTreeNode> CreateNode(const PipelineRenderNode &op);
126
127private:
128 //! The configuration used for rendering
129 TreeRendererConfig config;
130
131private:
132 void RenderTopLayer(RenderTree &root, std::ostream &ss, idx_t y);
133 void RenderBoxContent(RenderTree &root, std::ostream &ss, idx_t y);
134 void RenderBottomLayer(RenderTree &root, std::ostream &ss, idx_t y);
135
136 bool CanSplitOnThisChar(char l);
137 bool IsPadding(char l);
138 string RemovePadding(string l);
139 void SplitUpExtraInfo(const string &extra_info, vector<string> &result);
140 void SplitStringBuffer(const string &source, vector<string> &result);
141
142 template <class T>
143 idx_t CreateRenderTreeRecursive(RenderTree &result, const T &op, idx_t x, idx_t y);
144
145 template <class T>
146 unique_ptr<RenderTree> CreateRenderTree(const T &op);
147 string ExtractExpressionsRecursive(ExpressionInfo &states);
148};
149
150} // namespace duckdb
151