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
11namespace DB
12{
13namespace ErrorCodes
14{
15 extern const int UNSUPPORTED_METHOD;
16 extern const int LOGICAL_ERROR;
17}
18
19
20ExternalQueryBuilder::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
41void 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
64std::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
160std::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
174std::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
244std::string
245ExternalQueryBuilder::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
334void 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
359std::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
382void 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