1 | #include "ExternalQueryBuilder.h" |
2 | #include <IO/WriteBuffer.h> |
3 | #include <IO/WriteBufferFromString.h> |
4 | #include <IO/WriteHelpers.h> |
5 | #include <boost/range/join.hpp> |
6 | #include <ext/range.h> |
7 | #include "DictionaryStructure.h" |
8 | #include "writeParenthesisedString.h" |
9 | |
10 | |
11 | namespace DB |
12 | { |
13 | namespace ErrorCodes |
14 | { |
15 | extern const int UNSUPPORTED_METHOD; |
16 | extern const int LOGICAL_ERROR; |
17 | } |
18 | |
19 | |
20 | ExternalQueryBuilder::ExternalQueryBuilder( |
21 | const DictionaryStructure & dict_struct_, |
22 | const std::string & db_, |
23 | const std::string & table_, |
24 | const std::string & where_, |
25 | IdentifierQuotingStyle quoting_style_) |
26 | : dict_struct(dict_struct_), db(db_), where(where_), quoting_style(quoting_style_) |
27 | { |
28 | if (auto pos = table_.find('.'); pos != std::string::npos) |
29 | { |
30 | schema = table_.substr(0, pos); |
31 | table = table_.substr(pos + 1); |
32 | } |
33 | else |
34 | { |
35 | schema = "" ; |
36 | table = table_; |
37 | } |
38 | } |
39 | |
40 | |
41 | void ExternalQueryBuilder::writeQuoted(const std::string & s, WriteBuffer & out) const |
42 | { |
43 | switch (quoting_style) |
44 | { |
45 | case IdentifierQuotingStyle::None: |
46 | writeString(s, out); |
47 | break; |
48 | |
49 | case IdentifierQuotingStyle::Backticks: |
50 | writeBackQuotedString(s, out); |
51 | break; |
52 | |
53 | case IdentifierQuotingStyle::DoubleQuotes: |
54 | writeDoubleQuotedString(s, out); |
55 | break; |
56 | |
57 | case IdentifierQuotingStyle::BackticksMySQL: |
58 | writeBackQuotedStringMySQL(s, out); |
59 | break; |
60 | } |
61 | } |
62 | |
63 | |
64 | std::string ExternalQueryBuilder::composeLoadAllQuery() const |
65 | { |
66 | WriteBufferFromOwnString out; |
67 | writeString("SELECT " , out); |
68 | |
69 | if (dict_struct.id) |
70 | { |
71 | if (!dict_struct.id->expression.empty()) |
72 | { |
73 | writeParenthesisedString(dict_struct.id->expression, out); |
74 | writeString(" AS " , out); |
75 | } |
76 | |
77 | writeQuoted(dict_struct.id->name, out); |
78 | |
79 | if (dict_struct.range_min && dict_struct.range_max) |
80 | { |
81 | writeString(", " , out); |
82 | |
83 | if (!dict_struct.range_min->expression.empty()) |
84 | { |
85 | writeParenthesisedString(dict_struct.range_min->expression, out); |
86 | writeString(" AS " , out); |
87 | } |
88 | |
89 | writeQuoted(dict_struct.range_min->name, out); |
90 | |
91 | writeString(", " , out); |
92 | |
93 | if (!dict_struct.range_max->expression.empty()) |
94 | { |
95 | writeParenthesisedString(dict_struct.range_max->expression, out); |
96 | writeString(" AS " , out); |
97 | } |
98 | |
99 | writeQuoted(dict_struct.range_max->name, out); |
100 | } |
101 | } |
102 | else if (dict_struct.key) |
103 | { |
104 | auto first = true; |
105 | for (const auto & key : *dict_struct.key) |
106 | { |
107 | if (!first) |
108 | writeString(", " , out); |
109 | |
110 | first = false; |
111 | |
112 | if (!key.expression.empty()) |
113 | { |
114 | writeParenthesisedString(key.expression, out); |
115 | writeString(" AS " , out); |
116 | } |
117 | |
118 | writeQuoted(key.name, out); |
119 | } |
120 | } |
121 | |
122 | for (const auto & attr : dict_struct.attributes) |
123 | { |
124 | writeString(", " , out); |
125 | |
126 | if (!attr.expression.empty()) |
127 | { |
128 | writeParenthesisedString(attr.expression, out); |
129 | writeString(" AS " , out); |
130 | } |
131 | |
132 | writeQuoted(attr.name, out); |
133 | } |
134 | |
135 | writeString(" FROM " , out); |
136 | if (!db.empty()) |
137 | { |
138 | writeQuoted(db, out); |
139 | writeChar('.', out); |
140 | } |
141 | if (!schema.empty()) |
142 | { |
143 | writeQuoted(schema, out); |
144 | writeChar('.', out); |
145 | } |
146 | writeQuoted(table, out); |
147 | |
148 | if (!where.empty()) |
149 | { |
150 | writeString(" WHERE " , out); |
151 | writeString(where, out); |
152 | } |
153 | |
154 | writeChar(';', out); |
155 | |
156 | return out.str(); |
157 | } |
158 | |
159 | |
160 | std::string ExternalQueryBuilder::composeUpdateQuery(const std::string & update_field, const std::string & time_point) const |
161 | { |
162 | std::string out = composeLoadAllQuery(); |
163 | std::string update_query; |
164 | |
165 | if (!where.empty()) |
166 | update_query = " AND " + update_field + " >= '" + time_point + "'" ; |
167 | else |
168 | update_query = " WHERE " + update_field + " >= '" + time_point + "'" ; |
169 | |
170 | return out.insert(out.size() - 1, update_query); /// This is done to insert "update_query" before "out"'s semicolon |
171 | } |
172 | |
173 | |
174 | std::string ExternalQueryBuilder::composeLoadIdsQuery(const std::vector<UInt64> & ids) |
175 | { |
176 | if (!dict_struct.id) |
177 | throw Exception{"Simple key required for method" , ErrorCodes::UNSUPPORTED_METHOD}; |
178 | |
179 | WriteBufferFromOwnString out; |
180 | writeString("SELECT " , out); |
181 | |
182 | if (!dict_struct.id->expression.empty()) |
183 | { |
184 | writeParenthesisedString(dict_struct.id->expression, out); |
185 | writeString(" AS " , out); |
186 | } |
187 | |
188 | writeQuoted(dict_struct.id->name, out); |
189 | |
190 | for (const auto & attr : dict_struct.attributes) |
191 | { |
192 | writeString(", " , out); |
193 | |
194 | if (!attr.expression.empty()) |
195 | { |
196 | writeParenthesisedString(attr.expression, out); |
197 | writeString(" AS " , out); |
198 | } |
199 | |
200 | writeQuoted(attr.name, out); |
201 | } |
202 | |
203 | writeString(" FROM " , out); |
204 | if (!db.empty()) |
205 | { |
206 | writeQuoted(db, out); |
207 | writeChar('.', out); |
208 | } |
209 | if (!schema.empty()) |
210 | { |
211 | writeQuoted(schema, out); |
212 | writeChar('.', out); |
213 | } |
214 | |
215 | writeQuoted(table, out); |
216 | |
217 | writeString(" WHERE " , out); |
218 | |
219 | if (!where.empty()) |
220 | { |
221 | writeString(where, out); |
222 | writeString(" AND " , out); |
223 | } |
224 | |
225 | writeQuoted(dict_struct.id->name, out); |
226 | writeString(" IN (" , out); |
227 | |
228 | auto first = true; |
229 | for (const auto id : ids) |
230 | { |
231 | if (!first) |
232 | writeString(", " , out); |
233 | |
234 | first = false; |
235 | writeString(DB::toString(id), out); |
236 | } |
237 | |
238 | writeString(");" , out); |
239 | |
240 | return out.str(); |
241 | } |
242 | |
243 | |
244 | std::string |
245 | ExternalQueryBuilder::composeLoadKeysQuery(const Columns & key_columns, const std::vector<size_t> & requested_rows, LoadKeysMethod method) |
246 | { |
247 | if (!dict_struct.key) |
248 | throw Exception{"Composite key required for method" , ErrorCodes::UNSUPPORTED_METHOD}; |
249 | |
250 | WriteBufferFromOwnString out; |
251 | writeString("SELECT " , out); |
252 | |
253 | auto first = true; |
254 | for (const auto & key_or_attribute : boost::join(*dict_struct.key, dict_struct.attributes)) |
255 | { |
256 | if (!first) |
257 | writeString(", " , out); |
258 | |
259 | first = false; |
260 | |
261 | if (!key_or_attribute.expression.empty()) |
262 | { |
263 | writeParenthesisedString(key_or_attribute.expression, out); |
264 | writeString(" AS " , out); |
265 | } |
266 | |
267 | writeQuoted(key_or_attribute.name, out); |
268 | } |
269 | |
270 | writeString(" FROM " , out); |
271 | if (!db.empty()) |
272 | { |
273 | writeQuoted(db, out); |
274 | writeChar('.', out); |
275 | } |
276 | if (!schema.empty()) |
277 | { |
278 | writeQuoted(schema, out); |
279 | writeChar('.', out); |
280 | } |
281 | |
282 | writeQuoted(table, out); |
283 | |
284 | writeString(" WHERE " , out); |
285 | |
286 | if (!where.empty()) |
287 | { |
288 | writeString("(" , out); |
289 | writeString(where, out); |
290 | writeString(") AND (" , out); |
291 | } |
292 | |
293 | if (method == AND_OR_CHAIN) |
294 | { |
295 | first = true; |
296 | for (const auto row : requested_rows) |
297 | { |
298 | if (!first) |
299 | writeString(" OR " , out); |
300 | |
301 | first = false; |
302 | composeKeyCondition(key_columns, row, out); |
303 | } |
304 | } |
305 | else /* if (method == IN_WITH_TUPLES) */ |
306 | { |
307 | writeString(composeKeyTupleDefinition(), out); |
308 | writeString(" IN (" , out); |
309 | |
310 | first = true; |
311 | for (const auto row : requested_rows) |
312 | { |
313 | if (!first) |
314 | writeString(", " , out); |
315 | |
316 | first = false; |
317 | composeKeyTuple(key_columns, row, out); |
318 | } |
319 | |
320 | writeString(")" , out); |
321 | } |
322 | |
323 | if (!where.empty()) |
324 | { |
325 | writeString(")" , out); |
326 | } |
327 | |
328 | writeString(";" , out); |
329 | |
330 | return out.str(); |
331 | } |
332 | |
333 | |
334 | void ExternalQueryBuilder::composeKeyCondition(const Columns & key_columns, const size_t row, WriteBuffer & out) const |
335 | { |
336 | writeString("(" , out); |
337 | |
338 | const auto keys_size = key_columns.size(); |
339 | auto first = true; |
340 | for (const auto i : ext::range(0, keys_size)) |
341 | { |
342 | if (!first) |
343 | writeString(" AND " , out); |
344 | |
345 | first = false; |
346 | |
347 | const auto & key_description = (*dict_struct.key)[i]; |
348 | |
349 | /// key_i=value_i |
350 | writeString(key_description.name, out); |
351 | writeString("=" , out); |
352 | key_description.type->serializeAsTextQuoted(*key_columns[i], row, out, format_settings); |
353 | } |
354 | |
355 | writeString(")" , out); |
356 | } |
357 | |
358 | |
359 | std::string ExternalQueryBuilder::composeKeyTupleDefinition() const |
360 | { |
361 | if (!dict_struct.key) |
362 | throw Exception{"Composite key required for method" , ErrorCodes::UNSUPPORTED_METHOD}; |
363 | |
364 | std::string result{"(" }; |
365 | |
366 | auto first = true; |
367 | for (const auto & key : *dict_struct.key) |
368 | { |
369 | if (!first) |
370 | result += ", " ; |
371 | |
372 | first = false; |
373 | result += key.name; |
374 | } |
375 | |
376 | result += ")" ; |
377 | |
378 | return result; |
379 | } |
380 | |
381 | |
382 | void ExternalQueryBuilder::composeKeyTuple(const Columns & key_columns, const size_t row, WriteBuffer & out) const |
383 | { |
384 | writeString("(" , out); |
385 | |
386 | const auto keys_size = key_columns.size(); |
387 | auto first = true; |
388 | for (const auto i : ext::range(0, keys_size)) |
389 | { |
390 | if (!first) |
391 | writeString(", " , out); |
392 | |
393 | first = false; |
394 | (*dict_struct.key)[i].type->serializeAsTextQuoted(*key_columns[i], row, out, format_settings); |
395 | } |
396 | |
397 | writeString(")" , out); |
398 | } |
399 | |
400 | |
401 | } |
402 | |