1 | #include <Core/SettingsCollection.h> |
2 | #include <Core/SettingsCollectionImpl.h> |
3 | |
4 | #include <Core/Field.h> |
5 | #include <Common/getNumberOfPhysicalCPUCores.h> |
6 | #include <Common/FieldVisitors.h> |
7 | #include <common/logger_useful.h> |
8 | #include <IO/ReadHelpers.h> |
9 | #include <IO/ReadBufferFromString.h> |
10 | #include <IO/WriteHelpers.h> |
11 | |
12 | |
13 | namespace DB |
14 | { |
15 | namespace ErrorCodes |
16 | { |
17 | extern const int TYPE_MISMATCH; |
18 | extern const int UNKNOWN_LOAD_BALANCING; |
19 | extern const int UNKNOWN_OVERFLOW_MODE; |
20 | extern const int ILLEGAL_OVERFLOW_MODE; |
21 | extern const int UNKNOWN_TOTALS_MODE; |
22 | extern const int UNKNOWN_COMPRESSION_METHOD; |
23 | extern const int UNKNOWN_DISTRIBUTED_PRODUCT_MODE; |
24 | extern const int UNKNOWN_GLOBAL_SUBQUERIES_METHOD; |
25 | extern const int UNKNOWN_JOIN_STRICTNESS; |
26 | extern const int UNKNOWN_LOG_LEVEL; |
27 | extern const int SIZE_OF_FIXED_STRING_DOESNT_MATCH; |
28 | extern const int BAD_ARGUMENTS; |
29 | extern const int UNKNOWN_SETTING; |
30 | extern const int CANNOT_PARSE_BOOL; |
31 | } |
32 | |
33 | |
34 | template <typename Type> |
35 | String SettingNumber<Type>::toString() const |
36 | { |
37 | return DB::toString(value); |
38 | } |
39 | |
40 | template <typename Type> |
41 | Field SettingNumber<Type>::toField() const |
42 | { |
43 | return value; |
44 | } |
45 | |
46 | template <typename Type> |
47 | void SettingNumber<Type>::set(Type x) |
48 | { |
49 | value = x; |
50 | changed = true; |
51 | } |
52 | |
53 | template <typename Type> |
54 | void SettingNumber<Type>::set(const Field & x) |
55 | { |
56 | if (x.getType() == Field::Types::String) |
57 | set(get<const String &>(x)); |
58 | else |
59 | set(applyVisitor(FieldVisitorConvertToNumber<Type>(), x)); |
60 | } |
61 | |
62 | template <typename Type> |
63 | void SettingNumber<Type>::set(const String & x) |
64 | { |
65 | set(completeParse<Type>(x)); |
66 | } |
67 | |
68 | template <> |
69 | void SettingNumber<bool>::set(const String & x) |
70 | { |
71 | if (x.size() == 1) |
72 | { |
73 | if (x[0] == '0') |
74 | set(false); |
75 | else if (x[0] == '1') |
76 | set(true); |
77 | else |
78 | throw Exception("Cannot parse bool from string '" + x + "'" , ErrorCodes::CANNOT_PARSE_BOOL); |
79 | } |
80 | else |
81 | { |
82 | ReadBufferFromString buf(x); |
83 | if (checkStringCaseInsensitive("true" , buf)) |
84 | set(true); |
85 | else if (checkStringCaseInsensitive("false" , buf)) |
86 | set(false); |
87 | else |
88 | throw Exception("Cannot parse bool from string '" + x + "'" , ErrorCodes::CANNOT_PARSE_BOOL); |
89 | } |
90 | } |
91 | |
92 | template <typename Type> |
93 | void SettingNumber<Type>::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const |
94 | { |
95 | if (format >= SettingsBinaryFormat::STRINGS) |
96 | { |
97 | writeStringBinary(toString(), buf); |
98 | return; |
99 | } |
100 | |
101 | if constexpr (is_integral_v<Type> && is_unsigned_v<Type>) |
102 | writeVarUInt(static_cast<UInt64>(value), buf); |
103 | else if constexpr (is_integral_v<Type> && is_signed_v<Type>) |
104 | writeVarInt(static_cast<Int64>(value), buf); |
105 | else |
106 | { |
107 | static_assert(std::is_floating_point_v<Type>); |
108 | writeStringBinary(toString(), buf); |
109 | } |
110 | } |
111 | |
112 | template <typename Type> |
113 | void SettingNumber<Type>::deserialize(ReadBuffer & buf, SettingsBinaryFormat format) |
114 | { |
115 | if (format >= SettingsBinaryFormat::STRINGS) |
116 | { |
117 | String x; |
118 | readStringBinary(x, buf); |
119 | set(x); |
120 | return; |
121 | } |
122 | |
123 | if constexpr (is_integral_v<Type> && is_unsigned_v<Type>) |
124 | { |
125 | UInt64 x; |
126 | readVarUInt(x, buf); |
127 | set(static_cast<Type>(x)); |
128 | } |
129 | else if constexpr (is_integral_v<Type> && is_signed_v<Type>) |
130 | { |
131 | Int64 x; |
132 | readVarInt(x, buf); |
133 | set(static_cast<Type>(x)); |
134 | } |
135 | else |
136 | { |
137 | static_assert(std::is_floating_point_v<Type>); |
138 | String x; |
139 | readStringBinary(x, buf); |
140 | set(x); |
141 | } |
142 | } |
143 | |
144 | template struct SettingNumber<UInt64>; |
145 | template struct SettingNumber<Int64>; |
146 | template struct SettingNumber<float>; |
147 | template struct SettingNumber<bool>; |
148 | |
149 | |
150 | String SettingMaxThreads::toString() const |
151 | { |
152 | /// Instead of the `auto` value, we output the actual value to make it easier to see. |
153 | return is_auto ? ("auto(" + DB::toString(value) + ")" ) : DB::toString(value); |
154 | } |
155 | |
156 | Field SettingMaxThreads::toField() const |
157 | { |
158 | return is_auto ? 0 : value; |
159 | } |
160 | |
161 | void SettingMaxThreads::set(UInt64 x) |
162 | { |
163 | value = x ? x : getAutoValue(); |
164 | is_auto = x == 0; |
165 | changed = true; |
166 | } |
167 | |
168 | void SettingMaxThreads::set(const Field & x) |
169 | { |
170 | if (x.getType() == Field::Types::String) |
171 | set(get<const String &>(x)); |
172 | else |
173 | set(safeGet<UInt64>(x)); |
174 | } |
175 | |
176 | void SettingMaxThreads::set(const String & x) |
177 | { |
178 | if (startsWith(x, "auto" )) |
179 | setAuto(); |
180 | else |
181 | set(parse<UInt64>(x)); |
182 | } |
183 | |
184 | void SettingMaxThreads::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const |
185 | { |
186 | if (format >= SettingsBinaryFormat::STRINGS) |
187 | { |
188 | writeStringBinary(is_auto ? "auto" : DB::toString(value), buf); |
189 | return; |
190 | } |
191 | |
192 | writeVarUInt(is_auto ? 0 : value, buf); |
193 | } |
194 | |
195 | void SettingMaxThreads::deserialize(ReadBuffer & buf, SettingsBinaryFormat format) |
196 | { |
197 | if (format >= SettingsBinaryFormat::STRINGS) |
198 | { |
199 | String x; |
200 | readStringBinary(x, buf); |
201 | set(x); |
202 | return; |
203 | } |
204 | |
205 | UInt64 x = 0; |
206 | readVarUInt(x, buf); |
207 | set(x); |
208 | } |
209 | |
210 | void SettingMaxThreads::setAuto() |
211 | { |
212 | value = getAutoValue(); |
213 | is_auto = true; |
214 | } |
215 | |
216 | UInt64 SettingMaxThreads::getAutoValue() const |
217 | { |
218 | static auto res = getNumberOfPhysicalCPUCores(); |
219 | return res; |
220 | } |
221 | |
222 | |
223 | template <SettingTimespanIO io_unit> |
224 | String SettingTimespan<io_unit>::toString() const |
225 | { |
226 | return DB::toString(value.totalMicroseconds() / microseconds_per_io_unit); |
227 | } |
228 | |
229 | template <SettingTimespanIO io_unit> |
230 | Field SettingTimespan<io_unit>::toField() const |
231 | { |
232 | return value.totalMicroseconds() / microseconds_per_io_unit; |
233 | } |
234 | |
235 | template <SettingTimespanIO io_unit> |
236 | void SettingTimespan<io_unit>::set(const Poco::Timespan & x) |
237 | { |
238 | value = x; |
239 | changed = true; |
240 | } |
241 | |
242 | template <SettingTimespanIO io_unit> |
243 | void SettingTimespan<io_unit>::set(UInt64 x) |
244 | { |
245 | set(Poco::Timespan(x * microseconds_per_io_unit)); |
246 | } |
247 | |
248 | template <SettingTimespanIO io_unit> |
249 | void SettingTimespan<io_unit>::set(const Field & x) |
250 | { |
251 | if (x.getType() == Field::Types::String) |
252 | set(get<const String &>(x)); |
253 | else |
254 | set(safeGet<UInt64>(x)); |
255 | } |
256 | |
257 | template <SettingTimespanIO io_unit> |
258 | void SettingTimespan<io_unit>::set(const String & x) |
259 | { |
260 | set(parse<UInt64>(x)); |
261 | } |
262 | |
263 | template <SettingTimespanIO io_unit> |
264 | void SettingTimespan<io_unit>::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const |
265 | { |
266 | if (format >= SettingsBinaryFormat::STRINGS) |
267 | { |
268 | writeStringBinary(toString(), buf); |
269 | return; |
270 | } |
271 | |
272 | writeVarUInt(value.totalMicroseconds() / microseconds_per_io_unit, buf); |
273 | } |
274 | |
275 | template <SettingTimespanIO io_unit> |
276 | void SettingTimespan<io_unit>::deserialize(ReadBuffer & buf, SettingsBinaryFormat format) |
277 | { |
278 | if (format >= SettingsBinaryFormat::STRINGS) |
279 | { |
280 | String x; |
281 | readStringBinary(x, buf); |
282 | set(x); |
283 | return; |
284 | } |
285 | |
286 | UInt64 x = 0; |
287 | readVarUInt(x, buf); |
288 | set(x); |
289 | } |
290 | |
291 | template struct SettingTimespan<SettingTimespanIO::SECOND>; |
292 | template struct SettingTimespan<SettingTimespanIO::MILLISECOND>; |
293 | |
294 | |
295 | String SettingString::toString() const |
296 | { |
297 | return value; |
298 | } |
299 | |
300 | Field SettingString::toField() const |
301 | { |
302 | return value; |
303 | } |
304 | |
305 | void SettingString::set(const String & x) |
306 | { |
307 | value = x; |
308 | changed = true; |
309 | } |
310 | |
311 | void SettingString::set(const Field & x) |
312 | { |
313 | set(safeGet<const String &>(x)); |
314 | } |
315 | |
316 | void SettingString::serialize(WriteBuffer & buf, SettingsBinaryFormat) const |
317 | { |
318 | writeStringBinary(value, buf); |
319 | } |
320 | |
321 | void SettingString::deserialize(ReadBuffer & buf, SettingsBinaryFormat) |
322 | { |
323 | String s; |
324 | readStringBinary(s, buf); |
325 | set(s); |
326 | } |
327 | |
328 | |
329 | String SettingChar::toString() const |
330 | { |
331 | return String(1, value); |
332 | } |
333 | |
334 | Field SettingChar::toField() const |
335 | { |
336 | return toString(); |
337 | } |
338 | |
339 | void SettingChar::set(char x) |
340 | { |
341 | value = x; |
342 | changed = true; |
343 | } |
344 | |
345 | void SettingChar::set(const String & x) |
346 | { |
347 | if (x.size() > 1) |
348 | throw Exception("A setting's value string has to be an exactly one character long" , ErrorCodes::SIZE_OF_FIXED_STRING_DOESNT_MATCH); |
349 | char c = (x.size() == 1) ? x[0] : '\0'; |
350 | set(c); |
351 | } |
352 | |
353 | void SettingChar::set(const Field & x) |
354 | { |
355 | const String & s = safeGet<const String &>(x); |
356 | set(s); |
357 | } |
358 | |
359 | void SettingChar::serialize(WriteBuffer & buf, SettingsBinaryFormat) const |
360 | { |
361 | writeStringBinary(toString(), buf); |
362 | } |
363 | |
364 | void SettingChar::deserialize(ReadBuffer & buf, SettingsBinaryFormat) |
365 | { |
366 | String s; |
367 | readStringBinary(s, buf); |
368 | set(s); |
369 | } |
370 | |
371 | |
372 | template <typename EnumType, typename Tag> |
373 | void SettingEnum<EnumType, Tag>::serialize(WriteBuffer & buf, SettingsBinaryFormat) const |
374 | { |
375 | writeStringBinary(toString(), buf); |
376 | } |
377 | |
378 | template <typename EnumType, typename Tag> |
379 | void SettingEnum<EnumType, Tag>::deserialize(ReadBuffer & buf, SettingsBinaryFormat) |
380 | { |
381 | String s; |
382 | readStringBinary(s, buf); |
383 | set(s); |
384 | } |
385 | |
386 | template <typename EnumType, typename Tag> |
387 | Field SettingEnum<EnumType, Tag>::toField() const |
388 | { |
389 | return toString(); |
390 | } |
391 | |
392 | template <typename EnumType, typename Tag> |
393 | void SettingEnum<EnumType, Tag>::set(const Field & x) |
394 | { |
395 | set(safeGet<const String &>(x)); |
396 | } |
397 | |
398 | |
399 | #define IMPLEMENT_SETTING_ENUM(ENUM_NAME, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME) \ |
400 | IMPLEMENT_SETTING_ENUM_WITH_TAG(ENUM_NAME, void, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME) |
401 | |
402 | #define IMPLEMENT_SETTING_ENUM_WITH_TAG(ENUM_NAME, TAG, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME) \ |
403 | template <> \ |
404 | String SettingEnum<ENUM_NAME, TAG>::toString() const \ |
405 | { \ |
406 | using EnumType = ENUM_NAME; \ |
407 | using UnderlyingType = std::underlying_type<EnumType>::type; \ |
408 | switch (static_cast<UnderlyingType>(value)) \ |
409 | { \ |
410 | LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_TO_STRING_HELPER_) \ |
411 | } \ |
412 | throw Exception("Unknown " #ENUM_NAME, ERROR_CODE_FOR_UNEXPECTED_NAME); \ |
413 | } \ |
414 | \ |
415 | template <> \ |
416 | void SettingEnum<ENUM_NAME, TAG>::set(const String & s) \ |
417 | { \ |
418 | using EnumType = ENUM_NAME; \ |
419 | LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_FROM_STRING_HELPER_) \ |
420 | \ |
421 | String all_io_names; \ |
422 | LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_CONCAT_NAMES_HELPER_) \ |
423 | throw Exception("Unknown " #ENUM_NAME " : '" + s + "', must be one of " + all_io_names, \ |
424 | ERROR_CODE_FOR_UNEXPECTED_NAME); \ |
425 | } \ |
426 | \ |
427 | template struct SettingEnum<ENUM_NAME, TAG>; |
428 | |
429 | #define IMPLEMENT_SETTING_ENUM_TO_STRING_HELPER_(NAME, IO_NAME) \ |
430 | case static_cast<UnderlyingType>(EnumType::NAME): return IO_NAME; |
431 | |
432 | #define IMPLEMENT_SETTING_ENUM_FROM_STRING_HELPER_(NAME, IO_NAME) \ |
433 | if (s == IO_NAME) \ |
434 | { \ |
435 | set(EnumType::NAME); \ |
436 | return; \ |
437 | } |
438 | |
439 | #define IMPLEMENT_SETTING_ENUM_CONCAT_NAMES_HELPER_(NAME, IO_NAME) \ |
440 | if (!all_io_names.empty()) \ |
441 | all_io_names += ", "; \ |
442 | all_io_names += String("'") + IO_NAME + "'"; |
443 | |
444 | |
445 | #define LOAD_BALANCING_LIST_OF_NAMES(M) \ |
446 | M(RANDOM, "random") \ |
447 | M(NEAREST_HOSTNAME, "nearest_hostname") \ |
448 | M(IN_ORDER, "in_order") \ |
449 | M(FIRST_OR_RANDOM, "first_or_random") |
450 | IMPLEMENT_SETTING_ENUM(LoadBalancing, LOAD_BALANCING_LIST_OF_NAMES, ErrorCodes::UNKNOWN_LOAD_BALANCING) |
451 | |
452 | |
453 | #define JOIN_STRICTNESS_LIST_OF_NAMES(M) \ |
454 | M(Unspecified, "") \ |
455 | M(ALL, "ALL") \ |
456 | M(ANY, "ANY") |
457 | IMPLEMENT_SETTING_ENUM(JoinStrictness, JOIN_STRICTNESS_LIST_OF_NAMES, ErrorCodes::UNKNOWN_JOIN_STRICTNESS) |
458 | |
459 | |
460 | #define TOTALS_MODE_LIST_OF_NAMES(M) \ |
461 | M(BEFORE_HAVING, "before_having") \ |
462 | M(AFTER_HAVING_EXCLUSIVE, "after_having_exclusive") \ |
463 | M(AFTER_HAVING_INCLUSIVE, "after_having_inclusive") \ |
464 | M(AFTER_HAVING_AUTO, "after_having_auto") |
465 | IMPLEMENT_SETTING_ENUM(TotalsMode, TOTALS_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_TOTALS_MODE) |
466 | |
467 | |
468 | #define OVERFLOW_MODE_LIST_OF_NAMES(M) \ |
469 | M(THROW, "throw") \ |
470 | M(BREAK, "break") |
471 | IMPLEMENT_SETTING_ENUM(OverflowMode, OVERFLOW_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_OVERFLOW_MODE) |
472 | |
473 | |
474 | #define OVERFLOW_MODE_LIST_OF_NAMES_WITH_ANY(M) \ |
475 | M(THROW, "throw") \ |
476 | M(BREAK, "break") \ |
477 | M(ANY, "any") |
478 | IMPLEMENT_SETTING_ENUM_WITH_TAG(OverflowMode, SettingOverflowModeGroupByTag, OVERFLOW_MODE_LIST_OF_NAMES_WITH_ANY, ErrorCodes::UNKNOWN_OVERFLOW_MODE) |
479 | |
480 | |
481 | #define DISTRIBUTED_PRODUCT_MODE_LIST_OF_NAMES(M) \ |
482 | M(DENY, "deny") \ |
483 | M(LOCAL, "local") \ |
484 | M(GLOBAL, "global") \ |
485 | M(ALLOW, "allow") |
486 | IMPLEMENT_SETTING_ENUM(DistributedProductMode, DISTRIBUTED_PRODUCT_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_DISTRIBUTED_PRODUCT_MODE) |
487 | |
488 | |
489 | #define DATE_TIME_INPUT_FORMAT_LIST_OF_NAMES(M) \ |
490 | M(Basic, "basic") \ |
491 | M(BestEffort, "best_effort") |
492 | IMPLEMENT_SETTING_ENUM(FormatSettings::DateTimeInputFormat, DATE_TIME_INPUT_FORMAT_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS) |
493 | |
494 | |
495 | #define LOGS_LEVEL_LIST_OF_NAMES(M) \ |
496 | M(none, "none") \ |
497 | M(error, "error") \ |
498 | M(warning, "warning") \ |
499 | M(information, "information") \ |
500 | M(debug, "debug") \ |
501 | M(trace, "trace") |
502 | IMPLEMENT_SETTING_ENUM(LogsLevel, LOGS_LEVEL_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS) |
503 | |
504 | |
505 | namespace details |
506 | { |
507 | void SettingsCollectionUtils::serializeName(const StringRef & name, WriteBuffer & buf) |
508 | { |
509 | writeStringBinary(name, buf); |
510 | } |
511 | |
512 | String SettingsCollectionUtils::deserializeName(ReadBuffer & buf) |
513 | { |
514 | String name; |
515 | readStringBinary(name, buf); |
516 | return name; |
517 | } |
518 | |
519 | void SettingsCollectionUtils::serializeFlag(bool flag, WriteBuffer & buf) |
520 | { |
521 | buf.write(flag); |
522 | } |
523 | |
524 | bool SettingsCollectionUtils::deserializeFlag(ReadBuffer & buf) |
525 | { |
526 | char c; |
527 | buf.readStrict(c); |
528 | return c; |
529 | } |
530 | |
531 | void SettingsCollectionUtils::skipValue(ReadBuffer & buf) |
532 | { |
533 | /// Ignore a string written by the function writeStringBinary(). |
534 | UInt64 size; |
535 | readVarUInt(size, buf); |
536 | buf.ignore(size); |
537 | } |
538 | |
539 | void SettingsCollectionUtils::warningNameNotFound(const StringRef & name) |
540 | { |
541 | static auto * log = &Logger::get("Settings" ); |
542 | LOG_WARNING(log, "Unknown setting " << name << ", skipping" ); |
543 | } |
544 | |
545 | void SettingsCollectionUtils::throwNameNotFound(const StringRef & name) |
546 | { |
547 | throw Exception("Unknown setting " + name.toString(), ErrorCodes::UNKNOWN_SETTING); |
548 | } |
549 | } |
550 | } |
551 | |