1 | #pragma once |
2 | |
3 | #include <Poco/Timespan.h> |
4 | #include <DataStreams/SizeLimits.h> |
5 | #include <Formats/FormatSettings.h> |
6 | #include <common/StringRef.h> |
7 | #include <Core/Types.h> |
8 | #include <unordered_map> |
9 | |
10 | |
11 | namespace DB |
12 | { |
13 | |
14 | class Field; |
15 | struct SettingChange; |
16 | using SettingsChanges = std::vector<SettingChange>; |
17 | class ReadBuffer; |
18 | class WriteBuffer; |
19 | enum class SettingsBinaryFormat; |
20 | |
21 | |
22 | /** One setting for any type. |
23 | * Stores a value within itself, as well as a flag - whether the value was changed. |
24 | * This is done so that you can send to the remote servers only changed settings (or explicitly specified in the config) values. |
25 | * That is, if the configuration was not specified in the config and was not dynamically changed, it is not sent to the remote server, |
26 | * and the remote server will use its default value. |
27 | */ |
28 | |
29 | template <typename Type> |
30 | struct SettingNumber |
31 | { |
32 | Type value; |
33 | bool changed = false; |
34 | |
35 | SettingNumber(Type x = 0) : value(x) {} |
36 | |
37 | operator Type() const { return value; } |
38 | SettingNumber & operator= (Type x) { set(x); return *this; } |
39 | |
40 | /// Serialize to a test string. |
41 | String toString() const; |
42 | |
43 | /// Converts to a field. |
44 | Field toField() const; |
45 | |
46 | void set(Type x); |
47 | |
48 | /// Read from SQL literal. |
49 | void set(const Field & x); |
50 | |
51 | /// Read from text string. |
52 | void set(const String & x); |
53 | |
54 | /// Serialize to binary stream suitable for transfer over network. |
55 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
56 | |
57 | /// Read from binary stream. |
58 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
59 | }; |
60 | |
61 | using SettingUInt64 = SettingNumber<UInt64>; |
62 | using SettingInt64 = SettingNumber<Int64>; |
63 | using SettingFloat = SettingNumber<float>; |
64 | using SettingBool = SettingNumber<bool>; |
65 | |
66 | |
67 | /** Unlike SettingUInt64, supports the value of 'auto' - the number of processor cores without taking into account SMT. |
68 | * A value of 0 is also treated as auto. |
69 | * When serializing, `auto` is written in the same way as 0. |
70 | */ |
71 | struct SettingMaxThreads |
72 | { |
73 | UInt64 value; |
74 | bool is_auto; |
75 | bool changed = false; |
76 | |
77 | SettingMaxThreads(UInt64 x = 0) : value(x ? x : getAutoValue()), is_auto(x == 0) {} |
78 | |
79 | operator UInt64() const { return value; } |
80 | SettingMaxThreads & operator= (UInt64 x) { set(x); return *this; } |
81 | |
82 | String toString() const; |
83 | Field toField() const; |
84 | |
85 | void set(UInt64 x); |
86 | void set(const Field & x); |
87 | void set(const String & x); |
88 | |
89 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
90 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
91 | |
92 | void setAuto(); |
93 | UInt64 getAutoValue() const; |
94 | }; |
95 | |
96 | |
97 | enum class SettingTimespanIO { MILLISECOND, SECOND }; |
98 | |
99 | template <SettingTimespanIO io_unit> |
100 | struct SettingTimespan |
101 | { |
102 | Poco::Timespan value; |
103 | bool changed = false; |
104 | |
105 | SettingTimespan(UInt64 x = 0) : value(x * microseconds_per_io_unit) {} |
106 | |
107 | operator Poco::Timespan() const { return value; } |
108 | SettingTimespan & operator= (const Poco::Timespan & x) { set(x); return *this; } |
109 | |
110 | Poco::Timespan::TimeDiff totalSeconds() const { return value.totalSeconds(); } |
111 | Poco::Timespan::TimeDiff totalMilliseconds() const { return value.totalMilliseconds(); } |
112 | |
113 | String toString() const; |
114 | Field toField() const; |
115 | |
116 | void set(const Poco::Timespan & x); |
117 | |
118 | void set(UInt64 x); |
119 | void set(const Field & x); |
120 | void set(const String & x); |
121 | |
122 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
123 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
124 | |
125 | static constexpr UInt64 microseconds_per_io_unit = (io_unit == SettingTimespanIO::MILLISECOND) ? 1000 : 1000000; |
126 | }; |
127 | |
128 | using SettingSeconds = SettingTimespan<SettingTimespanIO::SECOND>; |
129 | using SettingMilliseconds = SettingTimespan<SettingTimespanIO::MILLISECOND>; |
130 | |
131 | |
132 | struct SettingString |
133 | { |
134 | String value; |
135 | bool changed = false; |
136 | |
137 | SettingString(const String & x = String{}) : value(x) {} |
138 | |
139 | operator String() const { return value; } |
140 | SettingString & operator= (const String & x) { set(x); return *this; } |
141 | |
142 | String toString() const; |
143 | Field toField() const; |
144 | |
145 | void set(const String & x); |
146 | void set(const Field & x); |
147 | |
148 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
149 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
150 | }; |
151 | |
152 | |
153 | struct SettingChar |
154 | { |
155 | public: |
156 | char value; |
157 | bool changed = false; |
158 | |
159 | SettingChar(char x = '\0') : value(x) {} |
160 | |
161 | operator char() const { return value; } |
162 | SettingChar & operator= (char x) { set(x); return *this; } |
163 | |
164 | String toString() const; |
165 | Field toField() const; |
166 | |
167 | void set(char x); |
168 | void set(const String & x); |
169 | void set(const Field & x); |
170 | |
171 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
172 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
173 | }; |
174 | |
175 | |
176 | /// Template class to define enum-based settings. |
177 | template <typename EnumType, typename Tag = void> |
178 | struct SettingEnum |
179 | { |
180 | EnumType value; |
181 | bool changed = false; |
182 | |
183 | SettingEnum(EnumType x) : value(x) {} |
184 | |
185 | operator EnumType() const { return value; } |
186 | SettingEnum & operator= (EnumType x) { set(x); return *this; } |
187 | |
188 | String toString() const; |
189 | Field toField() const; |
190 | |
191 | void set(EnumType x) { value = x; changed = true; } |
192 | void set(const Field & x); |
193 | void set(const String & x); |
194 | |
195 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const; |
196 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format); |
197 | }; |
198 | |
199 | |
200 | enum class LoadBalancing |
201 | { |
202 | /// among replicas with a minimum number of errors selected randomly |
203 | RANDOM = 0, |
204 | /// a replica is selected among the replicas with the minimum number of errors |
205 | /// with the minimum number of distinguished characters in the replica name and local hostname |
206 | NEAREST_HOSTNAME, |
207 | /// replicas are walked through strictly in order; the number of errors does not matter |
208 | IN_ORDER, |
209 | /// if first replica one has higher number of errors, |
210 | /// pick a random one from replicas with minimum number of errors |
211 | FIRST_OR_RANDOM, |
212 | }; |
213 | using SettingLoadBalancing = SettingEnum<LoadBalancing>; |
214 | |
215 | |
216 | enum class JoinStrictness |
217 | { |
218 | Unspecified = 0, /// Query JOIN without strictness will throw Exception. |
219 | ALL, /// Query JOIN without strictness -> ALL JOIN ... |
220 | ANY, /// Query JOIN without strictness -> ANY JOIN ... |
221 | }; |
222 | using SettingJoinStrictness = SettingEnum<JoinStrictness>; |
223 | |
224 | |
225 | /// Which rows should be included in TOTALS. |
226 | enum class TotalsMode |
227 | { |
228 | BEFORE_HAVING = 0, /// Count HAVING for all read rows; |
229 | /// including those not in max_rows_to_group_by |
230 | /// and have not passed HAVING after grouping. |
231 | AFTER_HAVING_INCLUSIVE = 1, /// Count on all rows except those that have not passed HAVING; |
232 | /// that is, to include in TOTALS all the rows that did not pass max_rows_to_group_by. |
233 | AFTER_HAVING_EXCLUSIVE = 2, /// Include only the rows that passed and max_rows_to_group_by, and HAVING. |
234 | AFTER_HAVING_AUTO = 3, /// Automatically select between INCLUSIVE and EXCLUSIVE, |
235 | }; |
236 | using SettingTotalsMode = SettingEnum<TotalsMode>; |
237 | |
238 | |
239 | /// The settings keeps OverflowMode which cannot be OverflowMode::ANY. |
240 | using SettingOverflowMode = SettingEnum<OverflowMode>; |
241 | struct SettingOverflowModeGroupByTag; |
242 | |
243 | /// The settings keeps OverflowMode which can be OverflowMode::ANY. |
244 | using SettingOverflowModeGroupBy = SettingEnum<OverflowMode, SettingOverflowModeGroupByTag>; |
245 | |
246 | |
247 | /// The setting for executing distributed subqueries inside IN or JOIN sections. |
248 | enum class DistributedProductMode |
249 | { |
250 | DENY = 0, /// Disable |
251 | LOCAL, /// Convert to local query |
252 | GLOBAL, /// Convert to global query |
253 | ALLOW /// Enable |
254 | }; |
255 | using SettingDistributedProductMode = SettingEnum<DistributedProductMode>; |
256 | |
257 | |
258 | using SettingDateTimeInputFormat = SettingEnum<FormatSettings::DateTimeInputFormat>; |
259 | |
260 | |
261 | enum class LogsLevel |
262 | { |
263 | none = 0, /// Disable |
264 | error, |
265 | warning, |
266 | information, |
267 | debug, |
268 | trace, |
269 | }; |
270 | using SettingLogsLevel = SettingEnum<LogsLevel>; |
271 | |
272 | |
273 | enum class SettingsBinaryFormat |
274 | { |
275 | OLD, /// Part of the settings are serialized as strings, and other part as varints. This is the old behaviour. |
276 | STRINGS, /// All settings are serialized as strings. Before each value the flag `is_ignorable` is serialized. |
277 | DEFAULT = STRINGS, |
278 | }; |
279 | |
280 | |
281 | /** Template class to define collections of settings. |
282 | * Example of usage: |
283 | * |
284 | * mysettings.h: |
285 | * struct MySettings : public SettingsCollection<MySettings> |
286 | * { |
287 | * # define APPLY_FOR_MYSETTINGS(M) \ |
288 | * M(SettingUInt64, a, 100, "Description of a", 0) \ |
289 | * M(SettingFloat, f, 3.11, "Description of f", IMPORTANT) // IMPORTANT - means the setting can't be ignored by older versions) \ |
290 | * M(SettingString, s, "default", "Description of s", 0) |
291 | * |
292 | * DECLARE_SETTINGS_COLLECTION(MySettings, APPLY_FOR_MYSETTINGS) |
293 | * }; |
294 | * |
295 | * mysettings.cpp: |
296 | * IMPLEMENT_SETTINGS_COLLECTION(MySettings, APPLY_FOR_MYSETTINGS) |
297 | */ |
298 | template <class Derived> |
299 | class SettingsCollection |
300 | { |
301 | private: |
302 | Derived & castToDerived() { return *static_cast<Derived *>(this); } |
303 | const Derived & castToDerived() const { return *static_cast<const Derived *>(this); } |
304 | |
305 | struct MemberInfo |
306 | { |
307 | using IsChangedFunction = bool (*)(const Derived &); |
308 | using GetStringFunction = String (*)(const Derived &); |
309 | using GetFieldFunction = Field (*)(const Derived &); |
310 | using SetStringFunction = void (*)(Derived &, const String &); |
311 | using SetFieldFunction = void (*)(Derived &, const Field &); |
312 | using SerializeFunction = void (*)(const Derived &, WriteBuffer & buf, SettingsBinaryFormat); |
313 | using DeserializeFunction = void (*)(Derived &, ReadBuffer & buf, SettingsBinaryFormat); |
314 | using ValueToStringFunction = String (*)(const Field &); |
315 | using ValueToCorrespondingTypeFunction = Field (*)(const Field &); |
316 | |
317 | StringRef name; |
318 | StringRef description; |
319 | bool is_important; |
320 | IsChangedFunction is_changed; |
321 | GetStringFunction get_string; |
322 | GetFieldFunction get_field; |
323 | SetStringFunction set_string; |
324 | SetFieldFunction set_field; |
325 | SerializeFunction serialize; |
326 | DeserializeFunction deserialize; |
327 | ValueToStringFunction value_to_string; |
328 | ValueToCorrespondingTypeFunction value_to_corresponding_type; |
329 | }; |
330 | |
331 | class MemberInfos |
332 | { |
333 | public: |
334 | MemberInfos(); |
335 | |
336 | size_t size() const { return infos.size(); } |
337 | const MemberInfo * data() const { return infos.data(); } |
338 | const MemberInfo & operator[](size_t index) const { return infos[index]; } |
339 | |
340 | const MemberInfo * find(const StringRef & name) const; |
341 | const MemberInfo & findStrict(const StringRef & name) const; |
342 | size_t findIndex(const StringRef & name) const; |
343 | size_t findIndexStrict(const StringRef & name) const; |
344 | |
345 | private: |
346 | void add(MemberInfo && member); |
347 | |
348 | std::vector<MemberInfo> infos; |
349 | std::unordered_map<StringRef, size_t> by_name_map; |
350 | }; |
351 | |
352 | static const MemberInfos & members(); |
353 | |
354 | public: |
355 | class const_iterator; |
356 | |
357 | /// Provides read-only access to a setting. |
358 | class const_reference |
359 | { |
360 | public: |
361 | const_reference(const Derived & collection_, const MemberInfo & member_) : collection(&collection_), member(&member_) {} |
362 | const_reference(const const_reference & src) = default; |
363 | const StringRef & getName() const { return member->name; } |
364 | const StringRef & getDescription() const { return member->description; } |
365 | bool isChanged() const { return member->is_changed(*collection); } |
366 | Field getValue() const; |
367 | String getValueAsString() const { return member->get_string(*collection); } |
368 | |
369 | protected: |
370 | friend class SettingsCollection<Derived>::const_iterator; |
371 | const_reference() : collection(nullptr), member(nullptr) {} |
372 | const_reference & operator=(const const_reference &) = default; |
373 | const Derived * collection; |
374 | const MemberInfo * member; |
375 | }; |
376 | |
377 | /// Provides access to a setting. |
378 | class reference : public const_reference |
379 | { |
380 | public: |
381 | reference(Derived & collection_, const MemberInfo & member_) : const_reference(collection_, member_) {} |
382 | reference(const const_reference & src) : const_reference(src) {} |
383 | void setValue(const Field & value) { this->member->set_field(*const_cast<Derived *>(this->collection), value); } |
384 | void setValue(const String & value) { this->member->set_string(*const_cast<Derived *>(this->collection), value); } |
385 | }; |
386 | |
387 | /// Iterator to iterating through all the settings. |
388 | class const_iterator |
389 | { |
390 | public: |
391 | const_iterator(const Derived & collection_, const MemberInfo * member_) : ref(const_cast<Derived &>(collection_), *member_) {} |
392 | const_iterator() = default; |
393 | const_iterator(const const_iterator & src) = default; |
394 | const_iterator & operator =(const const_iterator & src) = default; |
395 | const const_reference & operator *() const { return ref; } |
396 | const const_reference * operator ->() const { return &ref; } |
397 | const_iterator & operator ++() { ++ref.member; return *this; } |
398 | const_iterator operator ++(int) { const_iterator tmp = *this; ++*this; return tmp; } |
399 | bool operator ==(const const_iterator & rhs) const { return ref.member == rhs.ref.member && ref.collection == rhs.ref.collection; } |
400 | bool operator !=(const const_iterator & rhs) const { return !(*this == rhs); } |
401 | protected: |
402 | mutable reference ref; |
403 | }; |
404 | |
405 | class iterator : public const_iterator |
406 | { |
407 | public: |
408 | iterator(Derived & collection_, const MemberInfo * member_) : const_iterator(collection_, member_) {} |
409 | iterator() = default; |
410 | iterator(const const_iterator & src) : const_iterator(src) {} |
411 | iterator & operator =(const const_iterator & src) { const_iterator::operator =(src); return *this; } |
412 | reference & operator *() const { return this->ref; } |
413 | reference * operator ->() const { return &this->ref; } |
414 | iterator & operator ++() { const_iterator::operator ++(); return *this; } |
415 | iterator operator ++(int) { iterator tmp = *this; ++*this; return tmp; } |
416 | }; |
417 | |
418 | /// Returns the number of settings. |
419 | static size_t size() { return members().size(); } |
420 | |
421 | /// Returns name of a setting by its index (0..size()-1). |
422 | static StringRef getName(size_t index) { return members()[index].name; } |
423 | |
424 | /// Returns description of a setting. |
425 | static StringRef getDescription(size_t index) { return members()[index].description; } |
426 | static StringRef getDescription(const String & name) { return members().findStrict(name).description; } |
427 | |
428 | /// Searches a setting by its name; returns `npos` if not found. |
429 | static size_t findIndex(const StringRef & name) { return members().findIndex(name); } |
430 | static constexpr size_t npos = static_cast<size_t>(-1); |
431 | |
432 | /// Searches a setting by its name; throws an exception if not found. |
433 | static size_t findIndexStrict(const StringRef & name) { return members().findIndexStrict(name); } |
434 | |
435 | /// Casts a value to a string according to a specified setting without actual changing this settings. |
436 | static String valueToString(size_t index, const Field & value) { return members()[index].value_to_string(value); } |
437 | static String valueToString(const StringRef & name, const Field & value) { return members().findStrict(name).value_to_string(value); } |
438 | |
439 | /// Casts a value to a type according to a specified setting without actual changing this settings. |
440 | /// E.g. for SettingInt64 it casts Field to Field::Types::Int64. |
441 | static Field valueToCorrespondingType(size_t index, const Field & value); |
442 | static Field valueToCorrespondingType(const StringRef & name, const Field & value); |
443 | |
444 | iterator begin() { return iterator(castToDerived(), members().data()); } |
445 | const_iterator begin() const { return const_iterator(castToDerived(), members().data()); } |
446 | iterator end() { const auto & the_members = members(); return iterator(castToDerived(), the_members.data() + the_members.size()); } |
447 | const_iterator end() const { const auto & the_members = members(); return const_iterator(castToDerived(), the_members.data() + the_members.size()); } |
448 | |
449 | /// Returns a proxy object for accessing to a setting. Throws an exception if there is not setting with such name. |
450 | reference operator[](size_t index) { return reference(castToDerived(), members()[index]); } |
451 | reference operator[](const StringRef & name) { return reference(castToDerived(), members().findStrict(name)); } |
452 | const_reference operator[](size_t index) const { return const_reference(castToDerived(), members()[index]); } |
453 | const_reference operator[](const StringRef & name) const { return const_reference(castToDerived(), members().findStrict(name)); } |
454 | |
455 | /// Searches a setting by its name; returns end() if not found. |
456 | iterator find(const StringRef & name); |
457 | const_iterator find(const StringRef & name) const; |
458 | |
459 | /// Searches a setting by its name; throws an exception if not found. |
460 | iterator findStrict(const StringRef & name); |
461 | const_iterator findStrict(const StringRef & name) const; |
462 | |
463 | /// Sets setting's value. |
464 | void set(size_t index, const Field & value) { (*this)[index].setValue(value); } |
465 | void set(const StringRef & name, const Field & value) { (*this)[name].setValue(value); } |
466 | |
467 | /// Sets setting's value. Read value in text form from string (for example, from configuration file or from URL parameter). |
468 | void set(size_t index, const String & value) { (*this)[index].setValue(value); } |
469 | void set(const StringRef & name, const String & value) { (*this)[name].setValue(value); } |
470 | |
471 | /// Returns value of a setting. |
472 | Field get(size_t index) const; |
473 | Field get(const StringRef & name) const; |
474 | |
475 | /// Returns value of a setting converted to string. |
476 | String getAsString(size_t index) const { return (*this)[index].getValueAsString(); } |
477 | String getAsString(const StringRef & name) const { return (*this)[name].getValueAsString(); } |
478 | |
479 | /// Returns value of a setting; returns false if there is no setting with the specified name. |
480 | bool tryGet(const StringRef & name, Field & value) const; |
481 | |
482 | /// Returns value of a setting converted to string; returns false if there is no setting with the specified name. |
483 | bool tryGet(const StringRef & name, String & value) const; |
484 | |
485 | /// Compares two collections of settings. |
486 | bool operator ==(const Derived & rhs) const; |
487 | bool operator!=(const Derived & rhs) const { return !(*this == rhs); } |
488 | |
489 | /// Gathers all changed values (e.g. for applying them later to another collection of settings). |
490 | SettingsChanges changes() const; |
491 | |
492 | /// Applies change to concrete setting. |
493 | void applyChange(const SettingChange & change); |
494 | |
495 | /// Applies changes to the settings. |
496 | void applyChanges(const SettingsChanges & changes); |
497 | |
498 | void copyChangesFrom(const Derived & src); |
499 | |
500 | void copyChangesTo(Derived & dest) const; |
501 | |
502 | /// Writes the settings to buffer (e.g. to be sent to remote server). |
503 | /// Only changed settings are written. They are written as list of contiguous name-value pairs, |
504 | /// finished with empty name. |
505 | void serialize(WriteBuffer & buf, SettingsBinaryFormat format = SettingsBinaryFormat::DEFAULT) const; |
506 | |
507 | /// Reads the settings from buffer. |
508 | void deserialize(ReadBuffer & buf, SettingsBinaryFormat format = SettingsBinaryFormat::DEFAULT); |
509 | }; |
510 | |
511 | |
512 | #define DECLARE_SETTINGS_COLLECTION(LIST_OF_SETTINGS_MACRO) \ |
513 | LIST_OF_SETTINGS_MACRO(DECLARE_SETTINGS_COLLECTION_DECLARE_VARIABLES_HELPER_) |
514 | |
515 | #define DECLARE_SETTINGS_COLLECTION_DECLARE_VARIABLES_HELPER_(TYPE, NAME, DEFAULT, DESCRIPTION, FLAGS) \ |
516 | TYPE NAME {DEFAULT}; |
517 | } |
518 | |