1 | #pragma once |
2 | |
3 | #include <Core/Types.h> |
4 | #include <Parsers/IAST_fwd.h> |
5 | #include <Parsers/IdentifierQuotingStyle.h> |
6 | #include <Common/Exception.h> |
7 | #include <Common/TypePromotion.h> |
8 | |
9 | #include <algorithm> |
10 | #include <ostream> |
11 | #include <set> |
12 | |
13 | |
14 | class SipHash; |
15 | |
16 | |
17 | namespace DB |
18 | { |
19 | |
20 | namespace ErrorCodes |
21 | { |
22 | extern const int NOT_A_COLUMN; |
23 | extern const int UNKNOWN_TYPE_OF_AST_NODE; |
24 | extern const int UNKNOWN_ELEMENT_IN_AST; |
25 | extern const int LOGICAL_ERROR; |
26 | } |
27 | |
28 | using IdentifierNameSet = std::set<String>; |
29 | |
30 | class WriteBuffer; |
31 | |
32 | |
33 | /** Element of the syntax tree (hereinafter - directed acyclic graph with elements of semantics) |
34 | */ |
35 | class IAST : public std::enable_shared_from_this<IAST>, public TypePromotion<IAST> |
36 | { |
37 | public: |
38 | ASTs children; |
39 | |
40 | virtual ~IAST() = default; |
41 | IAST() = default; |
42 | IAST(const IAST &) = default; |
43 | IAST & operator=(const IAST &) = default; |
44 | |
45 | /** Get the canonical name of the column if the element is a column */ |
46 | String getColumnName() const; |
47 | virtual void appendColumnName(WriteBuffer &) const |
48 | { |
49 | throw Exception("Trying to get name of not a column: " + getID(), ErrorCodes::NOT_A_COLUMN); |
50 | } |
51 | |
52 | /** Get the alias, if any, or the canonical name of the column, if it is not. */ |
53 | virtual String getAliasOrColumnName() const { return getColumnName(); } |
54 | |
55 | /** Get the alias, if any, or an empty string if it does not exist, or if the element does not support aliases. */ |
56 | virtual String tryGetAlias() const { return String(); } |
57 | |
58 | /** Set the alias. */ |
59 | virtual void setAlias(const String & /*to*/) |
60 | { |
61 | throw Exception("Can't set alias of " + getColumnName(), ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE); |
62 | } |
63 | |
64 | /** Get the text that identifies this element. */ |
65 | virtual String getID(char delimiter = '_') const = 0; |
66 | |
67 | ASTPtr ptr() { return shared_from_this(); } |
68 | |
69 | /** Get a deep copy of the tree. Cloned object must have the same range. */ |
70 | virtual ASTPtr clone() const = 0; |
71 | |
72 | /** Get hash code, identifying this element and its subtree. |
73 | */ |
74 | using Hash = std::pair<UInt64, UInt64>; |
75 | Hash getTreeHash() const; |
76 | void updateTreeHash(SipHash & hash_state) const; |
77 | virtual void updateTreeHashImpl(SipHash & hash_state) const; |
78 | |
79 | void dumpTree(std::ostream & ostr, size_t indent = 0) const |
80 | { |
81 | String indent_str(indent, '-'); |
82 | ostr << indent_str << getID() << ", " << this << std::endl; |
83 | for (const auto & child : children) |
84 | child->dumpTree(ostr, indent + 1); |
85 | } |
86 | |
87 | /** Check the depth of the tree. |
88 | * If max_depth is specified and the depth is greater - throw an exception. |
89 | * Returns the depth of the tree. |
90 | */ |
91 | size_t checkDepth(size_t max_depth) const |
92 | { |
93 | return checkDepthImpl(max_depth, 0); |
94 | } |
95 | |
96 | /** Get total number of tree elements |
97 | */ |
98 | size_t size() const; |
99 | |
100 | /** Same for the total number of tree elements. |
101 | */ |
102 | size_t checkSize(size_t max_size) const; |
103 | |
104 | /** Get `set` from the names of the identifiers |
105 | */ |
106 | virtual void collectIdentifierNames(IdentifierNameSet & set) const |
107 | { |
108 | for (const auto & child : children) |
109 | child->collectIdentifierNames(set); |
110 | } |
111 | |
112 | template <typename T> |
113 | void set(T * & field, const ASTPtr & child) |
114 | { |
115 | if (!child) |
116 | return; |
117 | |
118 | T * casted = dynamic_cast<T *>(child.get()); |
119 | if (!casted) |
120 | throw Exception("Could not cast AST subtree" , ErrorCodes::LOGICAL_ERROR); |
121 | |
122 | children.push_back(child); |
123 | field = casted; |
124 | } |
125 | |
126 | template <typename T> |
127 | void replace(T * & field, const ASTPtr & child) |
128 | { |
129 | if (!child) |
130 | throw Exception("Trying to replace AST subtree with nullptr" , ErrorCodes::LOGICAL_ERROR); |
131 | |
132 | T * casted = dynamic_cast<T *>(child.get()); |
133 | if (!casted) |
134 | throw Exception("Could not cast AST subtree" , ErrorCodes::LOGICAL_ERROR); |
135 | |
136 | for (ASTPtr & current_child : children) |
137 | { |
138 | if (current_child.get() == field) |
139 | { |
140 | current_child = child; |
141 | field = casted; |
142 | return; |
143 | } |
144 | } |
145 | |
146 | throw Exception("AST subtree not found in children" , ErrorCodes::LOGICAL_ERROR); |
147 | } |
148 | |
149 | template <typename T> |
150 | void setOrReplace(T * & field, const ASTPtr & child) |
151 | { |
152 | if (field) |
153 | replace(field, child); |
154 | else |
155 | set(field, child); |
156 | } |
157 | |
158 | /// Convert to a string. |
159 | |
160 | /// Format settings. |
161 | struct FormatSettings |
162 | { |
163 | std::ostream & ostr; |
164 | bool hilite = false; |
165 | bool one_line; |
166 | bool always_quote_identifiers = false; |
167 | IdentifierQuotingStyle identifier_quoting_style = IdentifierQuotingStyle::Backticks; |
168 | |
169 | char nl_or_ws; |
170 | |
171 | FormatSettings(std::ostream & ostr_, bool one_line_) |
172 | : ostr(ostr_), one_line(one_line_) |
173 | { |
174 | nl_or_ws = one_line ? ' ' : '\n'; |
175 | } |
176 | |
177 | FormatSettings(std::ostream & ostr_, const FormatSettings & other) |
178 | : ostr(ostr_), hilite(other.hilite), one_line(other.one_line), |
179 | always_quote_identifiers(other.always_quote_identifiers), identifier_quoting_style(other.identifier_quoting_style) |
180 | { |
181 | nl_or_ws = one_line ? ' ' : '\n'; |
182 | } |
183 | |
184 | void writeIdentifier(const String & name) const; |
185 | }; |
186 | |
187 | /// State. For example, a set of nodes can be remembered, which we already walk through. |
188 | struct FormatState |
189 | { |
190 | /** The SELECT query in which the alias was found; identifier of a node with such an alias. |
191 | * It is necessary that when the node has met again, output only the alias. |
192 | */ |
193 | std::set<std::tuple< |
194 | const IAST * /* SELECT query node */, |
195 | std::string /* alias */, |
196 | Hash /* printed content */>> printed_asts_with_alias; |
197 | }; |
198 | |
199 | /// The state that is copied when each node is formatted. For example, nesting level. |
200 | struct FormatStateStacked |
201 | { |
202 | UInt8 indent = 0; |
203 | bool need_parens = false; |
204 | const IAST * current_select = nullptr; |
205 | }; |
206 | |
207 | void format(const FormatSettings & settings) const |
208 | { |
209 | FormatState state; |
210 | formatImpl(settings, state, FormatStateStacked()); |
211 | } |
212 | |
213 | virtual void formatImpl(const FormatSettings & /*settings*/, FormatState & /*state*/, FormatStateStacked /*frame*/) const |
214 | { |
215 | throw Exception("Unknown element in AST: " + getID(), ErrorCodes::UNKNOWN_ELEMENT_IN_AST); |
216 | } |
217 | |
218 | void cloneChildren(); |
219 | |
220 | public: |
221 | /// For syntax highlighting. |
222 | static const char * hilite_keyword; |
223 | static const char * hilite_identifier; |
224 | static const char * hilite_function; |
225 | static const char * hilite_operator; |
226 | static const char * hilite_alias; |
227 | static const char * hilite_substitution; |
228 | static const char * hilite_none; |
229 | |
230 | private: |
231 | size_t checkDepthImpl(size_t max_depth, size_t level) const; |
232 | }; |
233 | |
234 | } |
235 | |