1 | #include <Common/typeid_cast.h> |
2 | #include <Parsers/ASTLiteral.h> |
3 | #include <Parsers/ASTFunction.h> |
4 | #include <Parsers/ASTWithAlias.h> |
5 | #include <Parsers/ASTSubquery.h> |
6 | #include <IO/WriteHelpers.h> |
7 | #include <IO/WriteBufferFromString.h> |
8 | |
9 | |
10 | namespace DB |
11 | { |
12 | |
13 | void ASTFunction::appendColumnNameImpl(WriteBuffer & ostr) const |
14 | { |
15 | writeString(name, ostr); |
16 | |
17 | if (parameters) |
18 | { |
19 | writeChar('(', ostr); |
20 | for (auto it = parameters->children.begin(); it != parameters->children.end(); ++it) |
21 | { |
22 | if (it != parameters->children.begin()) |
23 | writeCString(", " , ostr); |
24 | (*it)->appendColumnName(ostr); |
25 | } |
26 | writeChar(')', ostr); |
27 | } |
28 | |
29 | writeChar('(', ostr); |
30 | for (auto it = arguments->children.begin(); it != arguments->children.end(); ++it) |
31 | { |
32 | if (it != arguments->children.begin()) |
33 | writeCString(", " , ostr); |
34 | (*it)->appendColumnName(ostr); |
35 | } |
36 | writeChar(')', ostr); |
37 | } |
38 | |
39 | /** Get the text that identifies this element. */ |
40 | String ASTFunction::getID(char delim) const |
41 | { |
42 | return "Function" + (delim + name); |
43 | } |
44 | |
45 | ASTPtr ASTFunction::clone() const |
46 | { |
47 | auto res = std::make_shared<ASTFunction>(*this); |
48 | res->children.clear(); |
49 | |
50 | if (arguments) { res->arguments = arguments->clone(); res->children.push_back(res->arguments); } |
51 | if (parameters) { res->parameters = parameters->clone(); res->children.push_back(res->parameters); } |
52 | |
53 | return res; |
54 | } |
55 | |
56 | |
57 | /** A special hack. If it's LIKE or NOT LIKE expression and the right hand side is a string literal, |
58 | * we will highlight unescaped metacharacters % and _ in string literal for convenience. |
59 | * Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes. |
60 | * With highlighting we make it clearly obvious. |
61 | * |
62 | * Another case is regexp match. Suppose the user types match(URL, 'www.yandex.ru'). It often means that the user is unaware that . is a metacharacter. |
63 | */ |
64 | static bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, const IAST::FormatSettings & settings, const char * metacharacters) |
65 | { |
66 | if (const auto * literal = node->as<ASTLiteral>()) |
67 | { |
68 | if (literal->value.getType() == Field::Types::String) |
69 | { |
70 | auto string = applyVisitor(FieldVisitorToString(), literal->value); |
71 | |
72 | unsigned escaping = 0; |
73 | for (auto c : string) |
74 | { |
75 | if (c == '\\') |
76 | { |
77 | settings.ostr << c; |
78 | if (escaping == 2) |
79 | escaping = 0; |
80 | ++escaping; |
81 | } |
82 | else if (nullptr != strchr(metacharacters, c)) |
83 | { |
84 | if (escaping == 2) /// Properly escaped metacharacter |
85 | settings.ostr << c; |
86 | else /// Unescaped metacharacter |
87 | settings.ostr << "\033[1;35m" << c << "\033[0m" ; |
88 | escaping = 0; |
89 | } |
90 | else |
91 | { |
92 | settings.ostr << c; |
93 | escaping = 0; |
94 | } |
95 | } |
96 | |
97 | return true; |
98 | } |
99 | } |
100 | |
101 | return false; |
102 | } |
103 | |
104 | |
105 | void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const |
106 | { |
107 | FormatStateStacked nested_need_parens = frame; |
108 | FormatStateStacked nested_dont_need_parens = frame; |
109 | nested_need_parens.need_parens = true; |
110 | nested_dont_need_parens.need_parens = false; |
111 | |
112 | /// Should this function to be written as operator? |
113 | bool written = false; |
114 | if (arguments && !parameters) |
115 | { |
116 | if (arguments->children.size() == 1) |
117 | { |
118 | const char * operators[] = |
119 | { |
120 | "negate" , "-" , |
121 | "not" , "NOT " , |
122 | nullptr |
123 | }; |
124 | |
125 | for (const char ** func = operators; *func; func += 2) |
126 | { |
127 | if (0 == strcmp(name.c_str(), func[0])) |
128 | { |
129 | if (frame.need_parens) |
130 | settings.ostr << '('; |
131 | |
132 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << func[1] << (settings.hilite ? hilite_none : "" ); |
133 | |
134 | /** A particularly stupid case. If we have a unary minus before a literal that is a negative number |
135 | * "-(-1)" or "- -1", this can not be formatted as `--1`, since this will be interpreted as a comment. |
136 | * Instead, add a space. |
137 | * PS. You can not just ask to add parentheses - see formatImpl for ASTLiteral. |
138 | */ |
139 | if (name == "negate" && arguments->children[0]->as<ASTLiteral>()) |
140 | settings.ostr << ' '; |
141 | |
142 | arguments->formatImpl(settings, state, nested_need_parens); |
143 | written = true; |
144 | |
145 | if (frame.need_parens) |
146 | settings.ostr << ')'; |
147 | } |
148 | } |
149 | } |
150 | |
151 | /** need_parens - do we need parentheses around the expression with the operator. |
152 | * They are needed only if this expression is included in another expression with the operator. |
153 | */ |
154 | |
155 | if (!written && arguments->children.size() == 2) |
156 | { |
157 | const char * operators[] = |
158 | { |
159 | "multiply" , " * " , |
160 | "divide" , " / " , |
161 | "modulo" , " % " , |
162 | "plus" , " + " , |
163 | "minus" , " - " , |
164 | "notEquals" , " != " , |
165 | "lessOrEquals" , " <= " , |
166 | "greaterOrEquals" , " >= " , |
167 | "less" , " < " , |
168 | "greater" , " > " , |
169 | "equals" , " = " , |
170 | "like" , " LIKE " , |
171 | "notLike" , " NOT LIKE " , |
172 | "in" , " IN " , |
173 | "notIn" , " NOT IN " , |
174 | "globalIn" , " GLOBAL IN " , |
175 | "globalNotIn" , " GLOBAL NOT IN " , |
176 | nullptr |
177 | }; |
178 | |
179 | for (const char ** func = operators; *func; func += 2) |
180 | { |
181 | if (0 == strcmp(name.c_str(), func[0])) |
182 | { |
183 | if (frame.need_parens) |
184 | settings.ostr << '('; |
185 | arguments->children[0]->formatImpl(settings, state, nested_need_parens); |
186 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << func[1] << (settings.hilite ? hilite_none : "" ); |
187 | |
188 | bool special_hilite = settings.hilite |
189 | && (name == "like" || name == "notLike" ) |
190 | && highlightStringLiteralWithMetacharacters(arguments->children[1], settings, "%_" ); |
191 | |
192 | /// Format x IN 1 as x IN (1): put parens around rhs even if there is a single element in set. |
193 | const auto * second_arg_func = arguments->children[1]->as<ASTFunction>(); |
194 | const auto * second_arg_literal = arguments->children[1]->as<ASTLiteral>(); |
195 | bool = (name == "in" || name == "notIn" || name == "globalIn" || name == "globalNotIn" ) |
196 | && !(second_arg_func && second_arg_func->name == "tuple" ) |
197 | && !(second_arg_literal && second_arg_literal->value.getType() == Field::Types::Tuple) |
198 | && !arguments->children[1]->as<ASTSubquery>(); |
199 | |
200 | if (extra_parents_around_in_rhs) |
201 | { |
202 | settings.ostr << '('; |
203 | arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens); |
204 | settings.ostr << ')'; |
205 | } |
206 | |
207 | if (!special_hilite && !extra_parents_around_in_rhs) |
208 | arguments->children[1]->formatImpl(settings, state, nested_need_parens); |
209 | |
210 | if (frame.need_parens) |
211 | settings.ostr << ')'; |
212 | written = true; |
213 | } |
214 | } |
215 | |
216 | if (!written && 0 == strcmp(name.c_str(), "arrayElement" )) |
217 | { |
218 | if (frame.need_parens) |
219 | settings.ostr << '('; |
220 | |
221 | arguments->children[0]->formatImpl(settings, state, nested_need_parens); |
222 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << '[' << (settings.hilite ? hilite_none : "" ); |
223 | arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens); |
224 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << ']' << (settings.hilite ? hilite_none : "" ); |
225 | written = true; |
226 | |
227 | if (frame.need_parens) |
228 | settings.ostr << ')'; |
229 | } |
230 | |
231 | if (!written && 0 == strcmp(name.c_str(), "tupleElement" )) |
232 | { |
233 | /// It can be printed in a form of 'x.1' only if right hand side is unsigned integer literal. |
234 | if (const auto * lit = arguments->children[1]->as<ASTLiteral>()) |
235 | { |
236 | if (lit->value.getType() == Field::Types::UInt64) |
237 | { |
238 | if (frame.need_parens) |
239 | settings.ostr << '('; |
240 | |
241 | arguments->children[0]->formatImpl(settings, state, nested_need_parens); |
242 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << "." << (settings.hilite ? hilite_none : "" ); |
243 | arguments->children[1]->formatImpl(settings, state, nested_dont_need_parens); |
244 | written = true; |
245 | |
246 | if (frame.need_parens) |
247 | settings.ostr << ')'; |
248 | } |
249 | } |
250 | } |
251 | |
252 | if (!written && 0 == strcmp(name.c_str(), "lambda" )) |
253 | { |
254 | /// Special case: one-element tuple in lhs of lambda is printed as its element. |
255 | |
256 | if (frame.need_parens) |
257 | settings.ostr << '('; |
258 | |
259 | const auto * first_arg_func = arguments->children[0]->as<ASTFunction>(); |
260 | if (first_arg_func |
261 | && first_arg_func->name == "tuple" |
262 | && first_arg_func->arguments |
263 | && first_arg_func->arguments->children.size() == 1) |
264 | { |
265 | first_arg_func->arguments->children[0]->formatImpl(settings, state, nested_need_parens); |
266 | } |
267 | else |
268 | arguments->children[0]->formatImpl(settings, state, nested_need_parens); |
269 | |
270 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << " -> " << (settings.hilite ? hilite_none : "" ); |
271 | arguments->children[1]->formatImpl(settings, state, nested_need_parens); |
272 | if (frame.need_parens) |
273 | settings.ostr << ')'; |
274 | written = true; |
275 | } |
276 | } |
277 | |
278 | if (!written && arguments->children.size() >= 2) |
279 | { |
280 | const char * operators[] = |
281 | { |
282 | "and" , " AND " , |
283 | "or" , " OR " , |
284 | nullptr |
285 | }; |
286 | |
287 | for (const char ** func = operators; *func; func += 2) |
288 | { |
289 | if (0 == strcmp(name.c_str(), func[0])) |
290 | { |
291 | if (frame.need_parens) |
292 | settings.ostr << '('; |
293 | for (size_t i = 0; i < arguments->children.size(); ++i) |
294 | { |
295 | if (i != 0) |
296 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << func[1] << (settings.hilite ? hilite_none : "" ); |
297 | arguments->children[i]->formatImpl(settings, state, nested_need_parens); |
298 | } |
299 | if (frame.need_parens) |
300 | settings.ostr << ')'; |
301 | written = true; |
302 | } |
303 | } |
304 | } |
305 | |
306 | if (!written && 0 == strcmp(name.c_str(), "array" )) |
307 | { |
308 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << '[' << (settings.hilite ? hilite_none : "" ); |
309 | for (size_t i = 0; i < arguments->children.size(); ++i) |
310 | { |
311 | if (i != 0) |
312 | settings.ostr << ", " ; |
313 | arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens); |
314 | } |
315 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << ']' << (settings.hilite ? hilite_none : "" ); |
316 | written = true; |
317 | } |
318 | |
319 | if (!written && arguments->children.size() >= 2 && 0 == strcmp(name.c_str(), "tuple" )) |
320 | { |
321 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << '(' << (settings.hilite ? hilite_none : "" ); |
322 | for (size_t i = 0; i < arguments->children.size(); ++i) |
323 | { |
324 | if (i != 0) |
325 | settings.ostr << ", " ; |
326 | arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens); |
327 | } |
328 | settings.ostr << (settings.hilite ? hilite_operator : "" ) << ')' << (settings.hilite ? hilite_none : "" ); |
329 | written = true; |
330 | } |
331 | } |
332 | |
333 | if (!written) |
334 | { |
335 | settings.ostr << (settings.hilite ? hilite_function : "" ) << name; |
336 | |
337 | if (parameters) |
338 | { |
339 | settings.ostr << '(' << (settings.hilite ? hilite_none : "" ); |
340 | parameters->formatImpl(settings, state, nested_dont_need_parens); |
341 | settings.ostr << (settings.hilite ? hilite_function : "" ) << ')'; |
342 | } |
343 | |
344 | if (arguments) |
345 | { |
346 | settings.ostr << '(' << (settings.hilite ? hilite_none : "" ); |
347 | |
348 | bool special_hilite_regexp = settings.hilite |
349 | && (name == "match" || name == "extract" || name == "extractAll" || name == "replaceRegexpOne" || name == "replaceRegexpAll" ); |
350 | |
351 | for (size_t i = 0, size = arguments->children.size(); i < size; ++i) |
352 | { |
353 | if (i != 0) |
354 | settings.ostr << ", " ; |
355 | |
356 | bool special_hilite = false; |
357 | if (i == 1 && special_hilite_regexp) |
358 | special_hilite = highlightStringLiteralWithMetacharacters(arguments->children[i], settings, "|()^$.[]?*+{:-" ); |
359 | |
360 | if (!special_hilite) |
361 | arguments->children[i]->formatImpl(settings, state, nested_dont_need_parens); |
362 | } |
363 | |
364 | settings.ostr << (settings.hilite ? hilite_function : "" ) << ')'; |
365 | } |
366 | |
367 | settings.ostr << (settings.hilite ? hilite_none : "" ); |
368 | } |
369 | } |
370 | |
371 | } |
372 | |