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
13namespace DB
14{
15namespace 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
34template <typename Type>
35String SettingNumber<Type>::toString() const
36{
37 return DB::toString(value);
38}
39
40template <typename Type>
41Field SettingNumber<Type>::toField() const
42{
43 return value;
44}
45
46template <typename Type>
47void SettingNumber<Type>::set(Type x)
48{
49 value = x;
50 changed = true;
51}
52
53template <typename Type>
54void 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
62template <typename Type>
63void SettingNumber<Type>::set(const String & x)
64{
65 set(completeParse<Type>(x));
66}
67
68template <>
69void 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
92template <typename Type>
93void 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
112template <typename Type>
113void 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
144template struct SettingNumber<UInt64>;
145template struct SettingNumber<Int64>;
146template struct SettingNumber<float>;
147template struct SettingNumber<bool>;
148
149
150String 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
156Field SettingMaxThreads::toField() const
157{
158 return is_auto ? 0 : value;
159}
160
161void SettingMaxThreads::set(UInt64 x)
162{
163 value = x ? x : getAutoValue();
164 is_auto = x == 0;
165 changed = true;
166}
167
168void 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
176void SettingMaxThreads::set(const String & x)
177{
178 if (startsWith(x, "auto"))
179 setAuto();
180 else
181 set(parse<UInt64>(x));
182}
183
184void 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
195void 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
210void SettingMaxThreads::setAuto()
211{
212 value = getAutoValue();
213 is_auto = true;
214}
215
216UInt64 SettingMaxThreads::getAutoValue() const
217{
218 static auto res = getNumberOfPhysicalCPUCores();
219 return res;
220}
221
222
223template <SettingTimespanIO io_unit>
224String SettingTimespan<io_unit>::toString() const
225{
226 return DB::toString(value.totalMicroseconds() / microseconds_per_io_unit);
227}
228
229template <SettingTimespanIO io_unit>
230Field SettingTimespan<io_unit>::toField() const
231{
232 return value.totalMicroseconds() / microseconds_per_io_unit;
233}
234
235template <SettingTimespanIO io_unit>
236void SettingTimespan<io_unit>::set(const Poco::Timespan & x)
237{
238 value = x;
239 changed = true;
240}
241
242template <SettingTimespanIO io_unit>
243void SettingTimespan<io_unit>::set(UInt64 x)
244{
245 set(Poco::Timespan(x * microseconds_per_io_unit));
246}
247
248template <SettingTimespanIO io_unit>
249void 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
257template <SettingTimespanIO io_unit>
258void SettingTimespan<io_unit>::set(const String & x)
259{
260 set(parse<UInt64>(x));
261}
262
263template <SettingTimespanIO io_unit>
264void 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
275template <SettingTimespanIO io_unit>
276void 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
291template struct SettingTimespan<SettingTimespanIO::SECOND>;
292template struct SettingTimespan<SettingTimespanIO::MILLISECOND>;
293
294
295String SettingString::toString() const
296{
297 return value;
298}
299
300Field SettingString::toField() const
301{
302 return value;
303}
304
305void SettingString::set(const String & x)
306{
307 value = x;
308 changed = true;
309}
310
311void SettingString::set(const Field & x)
312{
313 set(safeGet<const String &>(x));
314}
315
316void SettingString::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
317{
318 writeStringBinary(value, buf);
319}
320
321void SettingString::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
322{
323 String s;
324 readStringBinary(s, buf);
325 set(s);
326}
327
328
329String SettingChar::toString() const
330{
331 return String(1, value);
332}
333
334Field SettingChar::toField() const
335{
336 return toString();
337}
338
339void SettingChar::set(char x)
340{
341 value = x;
342 changed = true;
343}
344
345void 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
353void SettingChar::set(const Field & x)
354{
355 const String & s = safeGet<const String &>(x);
356 set(s);
357}
358
359void SettingChar::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
360{
361 writeStringBinary(toString(), buf);
362}
363
364void SettingChar::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
365{
366 String s;
367 readStringBinary(s, buf);
368 set(s);
369}
370
371
372template <typename EnumType, typename Tag>
373void SettingEnum<EnumType, Tag>::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
374{
375 writeStringBinary(toString(), buf);
376}
377
378template <typename EnumType, typename Tag>
379void SettingEnum<EnumType, Tag>::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
380{
381 String s;
382 readStringBinary(s, buf);
383 set(s);
384}
385
386template <typename EnumType, typename Tag>
387Field SettingEnum<EnumType, Tag>::toField() const
388{
389 return toString();
390}
391
392template <typename EnumType, typename Tag>
393void 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")
450IMPLEMENT_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")
457IMPLEMENT_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")
465IMPLEMENT_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")
471IMPLEMENT_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")
478IMPLEMENT_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")
486IMPLEMENT_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")
492IMPLEMENT_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")
502IMPLEMENT_SETTING_ENUM(LogsLevel, LOGS_LEVEL_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS)
503
504
505namespace 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