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
14class SipHash;
15
16
17namespace DB
18{
19
20namespace 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
28using IdentifierNameSet = std::set<String>;
29
30class WriteBuffer;
31
32
33/** Element of the syntax tree (hereinafter - directed acyclic graph with elements of semantics)
34 */
35class IAST : public std::enable_shared_from_this<IAST>, public TypePromotion<IAST>
36{
37public:
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
220public:
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
230private:
231 size_t checkDepthImpl(size_t max_depth, size_t level) const;
232};
233
234}
235