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 | |
15 | namespace duckdb { |
16 | class LogicalOperator; |
17 | class PhysicalOperator; |
18 | class Pipeline; |
19 | struct PipelineRenderNode; |
20 | |
21 | struct RenderTreeNode { |
22 | string name; |
23 | string ; |
24 | }; |
25 | |
26 | struct 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 | |
33 | public: |
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 | |
41 | struct 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 = 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 | |
90 | class TreeRenderer { |
91 | public: |
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 | |
114 | private: |
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 (); |
121 | unique_ptr<RenderTreeNode> CreateRenderNode(string name, string ); |
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 | |
127 | private: |
128 | //! The configuration used for rendering |
129 | TreeRendererConfig config; |
130 | |
131 | private: |
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 (const string &, 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 (ExpressionInfo &states); |
148 | }; |
149 | |
150 | } // namespace duckdb |
151 | |