Split SettingsCollection.h into 3 files: SettingsFields.h, SettingsEnums.h, SettingsCollection.h

This commit is contained in:
Vitaly Baranov 2020-07-17 01:01:08 +03:00
parent 90602b869a
commit 18e3f1f60d
15 changed files with 940 additions and 894 deletions

View File

@ -20,7 +20,6 @@
#include <Common/ThreadStatus.h>
#include <Common/config_version.h>
#include <Common/quoteString.h>
#include <Common/SettingsChanges.h>
#include <IO/ReadBufferFromString.h>
#include <IO/WriteBufferFromFileDescriptor.h>
#include <IO/UseSSL.h>

View File

@ -1,7 +1,7 @@
#pragma once
#include <Access/MultipleAccessStorage.h>
#include <Poco/AutoPtr.h>
#include <Common/SettingsChanges.h>
#include <boost/container/flat_set.hpp>
#include <memory>

View File

@ -4,7 +4,7 @@
#include <Common/ProfileEvents.h>
#include <Common/MemoryTracker.h>
#include <Core/SettingsCollection.h>
#include <Core/SettingsEnums.h>
#include <IO/Progress.h>

View File

@ -1,6 +1,7 @@
#pragma once
#include <Core/SettingsCollection.h>
#include <Core/SettingsEnums.h>
#include <Core/Defines.h>

View File

@ -2,7 +2,6 @@
#include <Core/SettingsCollectionImpl.h>
#include <Core/Field.h>
#include <Common/getNumberOfPhysicalCPUCores.h>
#include <Common/FieldVisitors.h>
#include <common/logger_useful.h>
#include <IO/ReadHelpers.h>
@ -14,555 +13,10 @@ namespace DB
{
namespace ErrorCodes
{
extern const int UNKNOWN_LOAD_BALANCING;
extern const int UNKNOWN_OVERFLOW_MODE;
extern const int UNKNOWN_TOTALS_MODE;
extern const int UNKNOWN_DISTRIBUTED_PRODUCT_MODE;
extern const int UNKNOWN_JOIN;
extern const int SIZE_OF_FIXED_STRING_DOESNT_MATCH;
extern const int BAD_ARGUMENTS;
extern const int UNKNOWN_SETTING;
extern const int CANNOT_PARSE_BOOL;
}
template <typename Type>
String SettingFieldNumber<Type>::toString() const
{
return DB::toString(value);
}
template <typename Type>
Field SettingFieldNumber<Type>::toField() const
{
return value;
}
template <typename Type>
void SettingFieldNumber<Type>::set(Type x)
{
value = x;
changed = true;
}
template <typename Type>
void SettingFieldNumber<Type>::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<Type>(), x));
}
template <typename Type>
void SettingFieldNumber<Type>::set(const String & x)
{
set(parseWithSizeSuffix<Type>(x));
}
template <>
void SettingFieldNumber<bool>::set(const String & x)
{
if (x.size() == 1)
{
if (x[0] == '0')
set(false);
else if (x[0] == '1')
set(true);
else
throw Exception("Cannot parse bool from string '" + x + "'", ErrorCodes::CANNOT_PARSE_BOOL);
}
else
{
ReadBufferFromString buf(x);
if (checkStringCaseInsensitive("true", buf))
set(true);
else if (checkStringCaseInsensitive("false", buf))
set(false);
else
throw Exception("Cannot parse bool from string '" + x + "'", ErrorCodes::CANNOT_PARSE_BOOL);
}
}
template <typename Type>
void SettingFieldNumber<Type>::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const
{
if (format >= SettingsBinaryFormat::STRINGS)
{
writeStringBinary(toString(), buf);
return;
}
if constexpr (is_integral_v<Type> && is_unsigned_v<Type>)
writeVarUInt(static_cast<UInt64>(value), buf);
else if constexpr (is_integral_v<Type> && is_signed_v<Type>)
writeVarInt(static_cast<Int64>(value), buf);
else
{
static_assert(std::is_floating_point_v<Type>);
writeStringBinary(toString(), buf);
}
}
template <typename Type>
void SettingFieldNumber<Type>::deserialize(ReadBuffer & buf, SettingsBinaryFormat format)
{
if (format >= SettingsBinaryFormat::STRINGS)
{
String x;
readStringBinary(x, buf);
set(x);
return;
}
if constexpr (is_integral_v<Type> && is_unsigned_v<Type>)
{
UInt64 x;
readVarUInt(x, buf);
set(static_cast<Type>(x));
}
else if constexpr (is_integral_v<Type> && is_signed_v<Type>)
{
Int64 x;
readVarInt(x, buf);
set(static_cast<Type>(x));
}
else
{
static_assert(std::is_floating_point_v<Type>);
String x;
readStringBinary(x, buf);
set(x);
}
}
template struct SettingFieldNumber<UInt64>;
template struct SettingFieldNumber<Int64>;
template struct SettingFieldNumber<float>;
template struct SettingFieldNumber<bool>;
String SettingFieldMaxThreads::toString() const
{
/// Instead of the `auto` value, we output the actual value to make it easier to see.
return is_auto ? ("auto(" + DB::toString(value) + ")") : DB::toString(value);
}
Field SettingFieldMaxThreads::toField() const
{
return is_auto ? 0 : value;
}
void SettingFieldMaxThreads::set(UInt64 x)
{
value = x ? x : getAutoValue();
is_auto = x == 0;
changed = true;
}
void SettingFieldMaxThreads::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<UInt64>(), x));
}
void SettingFieldMaxThreads::set(const String & x)
{
if (startsWith(x, "auto"))
setAuto();
else
set(parse<UInt64>(x));
}
void SettingFieldMaxThreads::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const
{
if (format >= SettingsBinaryFormat::STRINGS)
{
writeStringBinary(is_auto ? "auto" : DB::toString(value), buf);
return;
}
writeVarUInt(is_auto ? 0 : value, buf);
}
void SettingFieldMaxThreads::deserialize(ReadBuffer & buf, SettingsBinaryFormat format)
{
if (format >= SettingsBinaryFormat::STRINGS)
{
String x;
readStringBinary(x, buf);
set(x);
return;
}
UInt64 x = 0;
readVarUInt(x, buf);
set(x);
}
void SettingFieldMaxThreads::setAuto()
{
value = getAutoValue();
is_auto = true;
}
UInt64 SettingFieldMaxThreads::getAutoValue()
{
return getNumberOfPhysicalCPUCores();
}
template <SettingFieldTimespanIO io_unit>
String SettingFieldTimespan<io_unit>::toString() const
{
return DB::toString(value.totalMicroseconds() / microseconds_per_io_unit);
}
template <SettingFieldTimespanIO io_unit>
Field SettingFieldTimespan<io_unit>::toField() const
{
return value.totalMicroseconds() / microseconds_per_io_unit;
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::set(const Poco::Timespan & x)
{
value = x;
changed = true;
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::set(UInt64 x)
{
set(Poco::Timespan(x * microseconds_per_io_unit));
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<UInt64>(), x));
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::set(const String & x)
{
set(parse<UInt64>(x));
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const
{
if (format >= SettingsBinaryFormat::STRINGS)
{
writeStringBinary(toString(), buf);
return;
}
writeVarUInt(value.totalMicroseconds() / microseconds_per_io_unit, buf);
}
template <SettingFieldTimespanIO io_unit>
void SettingFieldTimespan<io_unit>::deserialize(ReadBuffer & buf, SettingsBinaryFormat format)
{
if (format >= SettingsBinaryFormat::STRINGS)
{
String x;
readStringBinary(x, buf);
set(x);
return;
}
UInt64 x = 0;
readVarUInt(x, buf);
set(x);
}
template struct SettingFieldTimespan<SettingFieldTimespanIO::SECOND>;
template struct SettingFieldTimespan<SettingFieldTimespanIO::MILLISECOND>;
String SettingFieldString::toString() const
{
return value;
}
Field SettingFieldString::toField() const
{
return value;
}
void SettingFieldString::set(const String & x)
{
value = x;
changed = true;
}
void SettingFieldString::set(const Field & x)
{
set(safeGet<const String &>(x));
}
void SettingFieldString::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
{
writeStringBinary(value, buf);
}
void SettingFieldString::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
{
String s;
readStringBinary(s, buf);
set(s);
}
String SettingFieldChar::toString() const
{
return String(1, value);
}
Field SettingFieldChar::toField() const
{
return toString();
}
void SettingFieldChar::set(char x)
{
value = x;
changed = true;
}
void SettingFieldChar::set(const String & x)
{
if (x.size() > 1)
throw Exception("A setting's value string has to be an exactly one character long", ErrorCodes::SIZE_OF_FIXED_STRING_DOESNT_MATCH);
char c = (x.size() == 1) ? x[0] : '\0';
set(c);
}
void SettingFieldChar::set(const Field & x)
{
const String & s = safeGet<const String &>(x);
set(s);
}
void SettingFieldChar::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
{
writeStringBinary(toString(), buf);
}
void SettingFieldChar::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
{
String s;
readStringBinary(s, buf);
set(s);
}
template <typename EnumType, typename Tag>
void SettingFieldEnum<EnumType, Tag>::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
{
writeStringBinary(toString(), buf);
}
template <typename EnumType, typename Tag>
void SettingFieldEnum<EnumType, Tag>::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
{
String s;
readStringBinary(s, buf);
set(s);
}
template <typename EnumType, typename Tag>
Field SettingFieldEnum<EnumType, Tag>::toField() const
{
return toString();
}
template <typename EnumType, typename Tag>
void SettingFieldEnum<EnumType, Tag>::set(const Field & x)
{
set(safeGet<const String &>(x));
}
String SettingFieldURI::toString() const
{
return value.toString();
}
Field SettingFieldURI::toField() const
{
return value.toString();
}
void SettingFieldURI::set(const Poco::URI & x)
{
value = x;
changed = true;
}
void SettingFieldURI::set(const Field & x)
{
const String & s = safeGet<const String &>(x);
set(s);
}
void SettingFieldURI::set(const String & x)
{
set(Poco::URI(x));
}
void SettingFieldURI::serialize(WriteBuffer & buf, SettingsBinaryFormat) const
{
writeStringBinary(toString(), buf);
}
void SettingFieldURI::deserialize(ReadBuffer & buf, SettingsBinaryFormat)
{
String s;
readStringBinary(s, buf);
set(s);
}
#define IMPLEMENT_SETTING_ENUM(ENUM_NAME, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME) \
IMPLEMENT_SETTING_ENUM_WITH_TAG(ENUM_NAME, void, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME)
#define IMPLEMENT_SETTING_ENUM_WITH_TAG(ENUM_NAME, TAG, LIST_OF_NAMES_MACRO, ERROR_CODE_FOR_UNEXPECTED_NAME) \
template <> \
String SettingFieldEnum<ENUM_NAME, TAG>::toString() const \
{ \
using EnumType = ENUM_NAME; \
using UnderlyingType = std::underlying_type<EnumType>::type; \
switch (static_cast<UnderlyingType>(value)) \
{ \
LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_TO_STRING_HELPER_) \
} \
throw Exception("Unknown " #ENUM_NAME, ERROR_CODE_FOR_UNEXPECTED_NAME); \
} \
\
template <> \
void SettingFieldEnum<ENUM_NAME, TAG>::set(const String & s) \
{ \
using EnumType = ENUM_NAME; \
LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_FROM_STRING_HELPER_) \
\
String all_io_names; \
LIST_OF_NAMES_MACRO(IMPLEMENT_SETTING_ENUM_CONCAT_NAMES_HELPER_) \
throw Exception("Unknown " #ENUM_NAME " : '" + s + "', must be one of " + all_io_names, \
ERROR_CODE_FOR_UNEXPECTED_NAME); \
} \
\
template struct SettingFieldEnum<ENUM_NAME, TAG>;
#define IMPLEMENT_SETTING_ENUM_TO_STRING_HELPER_(NAME, IO_NAME) \
case static_cast<UnderlyingType>(EnumType::NAME): return IO_NAME;
#define IMPLEMENT_SETTING_ENUM_FROM_STRING_HELPER_(NAME, IO_NAME) \
if (s == (IO_NAME)) \
{ \
set(EnumType::NAME); \
return; \
}
#define IMPLEMENT_SETTING_ENUM_CONCAT_NAMES_HELPER_(NAME, IO_NAME) \
if (!all_io_names.empty()) \
all_io_names += ", "; \
all_io_names += String("'") + (IO_NAME) + "'";
#define LOAD_BALANCING_LIST_OF_NAMES(M) \
M(RANDOM, "random") \
M(NEAREST_HOSTNAME, "nearest_hostname") \
M(IN_ORDER, "in_order") \
M(FIRST_OR_RANDOM, "first_or_random") \
M(ROUND_ROBIN, "round_robin")
IMPLEMENT_SETTING_ENUM(LoadBalancing, LOAD_BALANCING_LIST_OF_NAMES, ErrorCodes::UNKNOWN_LOAD_BALANCING)
#define SPECIAL_SORT_ALGORITHM_NAMES(M) \
M(NOT_SPECIFIED, "not_specified") \
M(OPENCL_BITONIC, "opencl_bitonic")
IMPLEMENT_SETTING_ENUM(SpecialSort, SPECIAL_SORT_ALGORITHM_NAMES, ErrorCodes::UNKNOWN_JOIN)
#define JOIN_STRICTNESS_LIST_OF_NAMES(M) \
M(Unspecified, "") \
M(ALL, "ALL") \
M(ANY, "ANY")
IMPLEMENT_SETTING_ENUM(JoinStrictness, JOIN_STRICTNESS_LIST_OF_NAMES, ErrorCodes::UNKNOWN_JOIN) // NOLINT
#define JOIN_ALGORITHM_NAMES(M) \
M(AUTO, "auto") \
M(HASH, "hash") \
M(PARTIAL_MERGE, "partial_merge") \
M(PREFER_PARTIAL_MERGE, "prefer_partial_merge")
IMPLEMENT_SETTING_ENUM(JoinAlgorithm, JOIN_ALGORITHM_NAMES, ErrorCodes::UNKNOWN_JOIN)
#define TOTALS_MODE_LIST_OF_NAMES(M) \
M(BEFORE_HAVING, "before_having") \
M(AFTER_HAVING_EXCLUSIVE, "after_having_exclusive") \
M(AFTER_HAVING_INCLUSIVE, "after_having_inclusive") \
M(AFTER_HAVING_AUTO, "after_having_auto")
IMPLEMENT_SETTING_ENUM(TotalsMode, TOTALS_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_TOTALS_MODE)
#define OVERFLOW_MODE_LIST_OF_NAMES(M) \
M(THROW, "throw") \
M(BREAK, "break")
IMPLEMENT_SETTING_ENUM(OverflowMode, OVERFLOW_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_OVERFLOW_MODE)
#define OVERFLOW_MODE_LIST_OF_NAMES_WITH_ANY(M) \
M(THROW, "throw") \
M(BREAK, "break") \
M(ANY, "any")
IMPLEMENT_SETTING_ENUM_WITH_TAG(OverflowMode, SettingFieldOverflowModeGroupByTag, OVERFLOW_MODE_LIST_OF_NAMES_WITH_ANY, ErrorCodes::UNKNOWN_OVERFLOW_MODE)
#define DISTRIBUTED_PRODUCT_MODE_LIST_OF_NAMES(M) \
M(DENY, "deny") \
M(LOCAL, "local") \
M(GLOBAL, "global") \
M(ALLOW, "allow")
IMPLEMENT_SETTING_ENUM(DistributedProductMode, DISTRIBUTED_PRODUCT_MODE_LIST_OF_NAMES, ErrorCodes::UNKNOWN_DISTRIBUTED_PRODUCT_MODE)
#define DATE_TIME_INPUT_FORMAT_LIST_OF_NAMES(M) \
M(Basic, "basic") \
M(BestEffort, "best_effort")
IMPLEMENT_SETTING_ENUM(FormatSettings::DateTimeInputFormat, DATE_TIME_INPUT_FORMAT_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS)
#define LOGS_LEVEL_LIST_OF_NAMES(M) \
M(none, "none") \
M(fatal, "fatal") \
M(error, "error") \
M(warning, "warning") \
M(information, "information") \
M(debug, "debug") \
M(trace, "trace")
IMPLEMENT_SETTING_ENUM(LogsLevel, LOGS_LEVEL_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS)
#define LOG_QUERIES_TYPE_LIST_OF_NAMES(M) \
M(QUERY_START, "QUERY_START") \
M(QUERY_FINISH, "QUERY_FINISH") \
M(EXCEPTION_BEFORE_START, "EXCEPTION_BEFORE_START") \
M(EXCEPTION_WHILE_PROCESSING, "EXCEPTION_WHILE_PROCESSING")
IMPLEMENT_SETTING_ENUM(QueryLogElementType, LOG_QUERIES_TYPE_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS)
#define DEFAULT_DATABASE_ENGINE_LIST_OF_NAMES(M) \
M(Ordinary, "Ordinary") \
M(Atomic, "Atomic")
IMPLEMENT_SETTING_ENUM(DefaultDatabaseEngine , DEFAULT_DATABASE_ENGINE_LIST_OF_NAMES, ErrorCodes::BAD_ARGUMENTS)
namespace details
{
void SettingsCollectionUtils::serializeName(const StringRef & name, WriteBuffer & buf)

View File

@ -1,11 +1,7 @@
#pragma once
#include <Poco/Timespan.h>
#include <Poco/URI.h>
#include <DataStreams/SizeLimits.h>
#include <Formats/FormatSettings.h>
#include <common/StringRef.h>
#include <Core/Types.h>
#include <Core/SettingsFields.h>
#include <unordered_map>
@ -17,326 +13,6 @@ struct SettingChange;
class SettingsChanges;
class ReadBuffer;
class WriteBuffer;
enum class SettingsBinaryFormat;
/** One setting for any type.
* Stores a value within itself, as well as a flag - whether the value was changed.
* This is done so that you can send to the remote servers only changed settings (or explicitly specified in the config) values.
* That is, if the configuration was not specified in the config and was not dynamically changed, it is not sent to the remote server,
* and the remote server will use its default value.
*/
template <typename Type>
struct SettingFieldNumber
{
Type value;
bool changed = false;
SettingFieldNumber(Type x = 0) : value(x) {}
operator Type() const { return value; }
SettingFieldNumber & operator= (Type x) { set(x); return *this; }
/// Serialize to a test string.
String toString() const;
/// Converts to a field.
Field toField() const;
void set(Type x);
/// Read from SQL literal.
void set(const Field & x);
/// Read from text string.
void set(const String & x);
/// Serialize to binary stream suitable for transfer over network.
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
/// Read from binary stream.
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
};
using SettingFieldUInt64 = SettingFieldNumber<UInt64>;
using SettingFieldInt64 = SettingFieldNumber<Int64>;
using SettingFieldFloat = SettingFieldNumber<float>;
using SettingFieldBool = SettingFieldNumber<bool>;
/** Unlike SettingUInt64, supports the value of 'auto' - the number of processor cores without taking into account SMT.
* A value of 0 is also treated as auto.
* When serializing, `auto` is written in the same way as 0.
*/
struct SettingFieldMaxThreads
{
UInt64 value;
bool is_auto;
bool changed = false;
SettingFieldMaxThreads(UInt64 x = 0) : value(x ? x : getAutoValue()), is_auto(x == 0) {}
operator UInt64() const { return value; }
SettingFieldMaxThreads & operator= (UInt64 x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(UInt64 x);
void set(const Field & x);
void set(const String & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
void setAuto();
static UInt64 getAutoValue();
};
enum class SettingFieldTimespanIO { MILLISECOND, SECOND };
template <SettingFieldTimespanIO io_unit>
struct SettingFieldTimespan
{
Poco::Timespan value;
bool changed = false;
SettingFieldTimespan(UInt64 x = 0) : value(x * microseconds_per_io_unit) {}
operator Poco::Timespan() const { return value; }
SettingFieldTimespan & operator=(const Poco::Timespan & x) { set(x); return *this; }
template <class Rep, class Period = std::ratio<1>>
operator std::chrono::duration<Rep, Period>() const { return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(std::chrono::microseconds(value.totalMicroseconds())); }
template <class Rep, class Period = std::ratio<1>>
SettingFieldTimespan & operator=(const std::chrono::duration<Rep, Period> & x) { set(x); return *this; }
Poco::Timespan::TimeDiff totalSeconds() const { return value.totalSeconds(); }
Poco::Timespan::TimeDiff totalMilliseconds() const { return value.totalMilliseconds(); }
String toString() const;
Field toField() const;
void set(const Poco::Timespan & x);
template <class Rep, class Period = std::ratio<1>>
void set(const std::chrono::duration<Rep, Period> & duration) { set(static_cast<UInt64>(std::chrono::duration_cast<std::chrono::microseconds>(duration).count())); }
void set(UInt64 x);
void set(const Field & x);
void set(const String & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
static constexpr UInt64 microseconds_per_io_unit = (io_unit == SettingFieldTimespanIO::MILLISECOND) ? 1000 : 1000000;
};
using SettingFieldSeconds = SettingFieldTimespan<SettingFieldTimespanIO::SECOND>;
using SettingFieldMilliseconds = SettingFieldTimespan<SettingFieldTimespanIO::MILLISECOND>;
struct SettingFieldString
{
String value;
bool changed = false;
SettingFieldString(const String & x = String{}) : value(x) {}
operator String() const { return value; }
SettingFieldString & operator= (const String & x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(const String & x);
void set(const Field & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
};
struct SettingFieldChar
{
public:
char value;
bool changed = false;
SettingFieldChar(char x = '\0') : value(x) {}
operator char() const { return value; }
SettingFieldChar & operator= (char x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(char x);
void set(const String & x);
void set(const Field & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
};
/// Template class to define enum-based settings.
template <typename EnumType, typename Tag = void>
struct SettingFieldEnum
{
EnumType value;
bool changed = false;
SettingFieldEnum(EnumType x) : value(x) {}
operator EnumType() const { return value; }
SettingFieldEnum & operator= (EnumType x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(EnumType x) { value = x; changed = true; }
void set(const Field & x);
void set(const String & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
};
struct SettingFieldURI
{
Poco::URI value;
bool changed = false;
SettingFieldURI(const Poco::URI & x = Poco::URI{}) : value(x) {}
operator Poco::URI() const { return value; }
SettingFieldURI & operator= (const Poco::URI & x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(const Poco::URI & x);
void set(const Field & x);
void set(const String & x);
void serialize(WriteBuffer & buf, SettingsBinaryFormat format) const;
void deserialize(ReadBuffer & buf, SettingsBinaryFormat format);
};
enum class LoadBalancing
{
/// among replicas with a minimum number of errors selected randomly
RANDOM = 0,
/// a replica is selected among the replicas with the minimum number of errors
/// with the minimum number of distinguished characters in the replica name and local hostname
NEAREST_HOSTNAME,
// replicas with the same number of errors are accessed in the same order
// as they are specified in the configuration.
IN_ORDER,
/// if first replica one has higher number of errors,
/// pick a random one from replicas with minimum number of errors
FIRST_OR_RANDOM,
// round robin across replicas with the same number of errors.
ROUND_ROBIN,
};
using SettingFieldLoadBalancing = SettingFieldEnum<LoadBalancing>;
enum class JoinStrictness
{
Unspecified = 0, /// Query JOIN without strictness will throw Exception.
ALL, /// Query JOIN without strictness -> ALL JOIN ...
ANY, /// Query JOIN without strictness -> ANY JOIN ...
};
using SettingFieldJoinStrictness = SettingFieldEnum<JoinStrictness>;
enum class JoinAlgorithm
{
AUTO = 0,
HASH,
PARTIAL_MERGE,
PREFER_PARTIAL_MERGE,
};
using SettingFieldJoinAlgorithm = SettingFieldEnum<JoinAlgorithm>;
enum class SpecialSort
{
NOT_SPECIFIED = 0,
OPENCL_BITONIC,
};
using SettingFieldSpecialSort = SettingFieldEnum<SpecialSort>;
/// Which rows should be included in TOTALS.
enum class TotalsMode
{
BEFORE_HAVING = 0, /// Count HAVING for all read rows;
/// including those not in max_rows_to_group_by
/// and have not passed HAVING after grouping.
AFTER_HAVING_INCLUSIVE = 1, /// Count on all rows except those that have not passed HAVING;
/// that is, to include in TOTALS all the rows that did not pass max_rows_to_group_by.
AFTER_HAVING_EXCLUSIVE = 2, /// Include only the rows that passed and max_rows_to_group_by, and HAVING.
AFTER_HAVING_AUTO = 3, /// Automatically select between INCLUSIVE and EXCLUSIVE,
};
using SettingFieldTotalsMode = SettingFieldEnum<TotalsMode>;
/// The settings keeps OverflowMode which cannot be OverflowMode::ANY.
using SettingFieldOverflowMode = SettingFieldEnum<OverflowMode>;
struct SettingFieldOverflowModeGroupByTag;
/// The settings keeps OverflowMode which can be OverflowMode::ANY.
using SettingFieldOverflowModeGroupBy = SettingFieldEnum<OverflowMode, SettingFieldOverflowModeGroupByTag>;
/// The setting for executing distributed subqueries inside IN or JOIN sections.
enum class DistributedProductMode
{
DENY = 0, /// Disable
LOCAL, /// Convert to local query
GLOBAL, /// Convert to global query
ALLOW /// Enable
};
using SettingFieldDistributedProductMode = SettingFieldEnum<DistributedProductMode>;
using SettingFieldDateTimeInputFormat = SettingFieldEnum<FormatSettings::DateTimeInputFormat>;
enum class LogsLevel
{
none = 0, /// Disable
fatal,
error,
warning,
information,
debug,
trace,
};
using SettingFieldLogsLevel = SettingFieldEnum<LogsLevel>;
enum class DefaultDatabaseEngine
{
Ordinary,
Atomic,
};
using SettingFieldDefaultDatabaseEngine = SettingFieldEnum<DefaultDatabaseEngine>;
// Make it signed for compatibility with DataTypeEnum8
enum QueryLogElementType : int8_t
{
QUERY_START = 1,
QUERY_FINISH = 2,
EXCEPTION_BEFORE_START = 3,
EXCEPTION_WHILE_PROCESSING = 4,
};
using SettingFieldLogQueriesType = SettingFieldEnum<QueryLogElementType>;
enum class SettingsBinaryFormat
{
@ -377,8 +53,8 @@ private:
using GetFieldFunction = Field (*)(const Derived &);
using SetStringFunction = void (*)(Derived &, const String &);
using SetFieldFunction = void (*)(Derived &, const Field &);
using SerializeFunction = void (*)(const Derived &, WriteBuffer & buf, SettingsBinaryFormat);
using DeserializeFunction = void (*)(Derived &, ReadBuffer & buf, SettingsBinaryFormat);
using WriteBinaryFunction = void (*)(const Derived &, WriteBuffer & buf);
using ReadBinaryFunction = void (*)(Derived &, ReadBuffer & buf);
using ValueToStringFunction = String (*)(const Field &);
using ValueToCorrespondingTypeFunction = Field (*)(const Field &);
@ -391,8 +67,8 @@ private:
GetFieldFunction get_field;
SetStringFunction set_string;
SetFieldFunction set_field;
SerializeFunction serialize;
DeserializeFunction deserialize;
WriteBinaryFunction write_binary;
ReadBinaryFunction read_binary;
ValueToStringFunction value_to_string;
ValueToCorrespondingTypeFunction value_to_corresponding_type;
};

View File

@ -278,8 +278,12 @@ void SettingsCollection<Derived>::serialize(WriteBuffer & buf, SettingsBinaryFor
{
details::SettingsCollectionUtils::serializeName(member.name, buf);
if (format >= SettingsBinaryFormat::STRINGS)
{
details::SettingsCollectionUtils::serializeFlag(member.is_important, buf);
member.serialize(castToDerived(), buf, format);
details::SettingsCollectionUtils::serializeName(member.get_string(castToDerived()), buf);
}
else
member.write_binary(castToDerived(), buf);
}
}
details::SettingsCollectionUtils::serializeName(StringRef{} /* empty string is a marker of the end of settings */, buf);
@ -296,20 +300,30 @@ void SettingsCollection<Derived>::deserialize(ReadBuffer & buf, SettingsBinaryFo
if (name.empty() /* empty string is a marker of the end of settings */)
break;
auto * member = the_members.find(name);
bool is_important = (format >= SettingsBinaryFormat::STRINGS) ? details::SettingsCollectionUtils::deserializeFlag(buf) : true;
if (member)
bool is_important = true;
if (format >= SettingsBinaryFormat::STRINGS)
is_important = details::SettingsCollectionUtils::deserializeFlag(buf);
if (!member)
{
member->deserialize(castToDerived(), buf, format);
if (is_important)
{
details::SettingsCollectionUtils::throwNameNotFound(name);
}
else
{
details::SettingsCollectionUtils::warningNameNotFound(name);
details::SettingsCollectionUtils::skipValue(buf);
continue;
}
}
else if (is_important)
if (format >= SettingsBinaryFormat::STRINGS)
{
details::SettingsCollectionUtils::throwNameNotFound(name);
String value = details::SettingsCollectionUtils::deserializeName(buf);
member->set_string(castToDerived(), value);
}
else
{
details::SettingsCollectionUtils::warningNameNotFound(name);
details::SettingsCollectionUtils::skipValue(buf);
}
member->read_binary(castToDerived(), buf);
}
}
@ -340,8 +354,8 @@ void SettingsCollection<Derived>::deserialize(ReadBuffer & buf, SettingsBinaryFo
static Field NAME##_getField(const Derived & collection) { return collection.NAME.toField(); } \
static void NAME##_setString(Derived & collection, const String & value) { collection.NAME.set(value); } \
static void NAME##_setField(Derived & collection, const Field & value) { collection.NAME.set(value); } \
static void NAME##_serialize(const Derived & collection, WriteBuffer & buf, SettingsBinaryFormat format) { collection.NAME.serialize(buf, format); } \
static void NAME##_deserialize(Derived & collection, ReadBuffer & buf, SettingsBinaryFormat format) { collection.NAME.deserialize(buf, format); } \
static void NAME##_writeBinary(const Derived & collection, WriteBuffer & buf) { collection.NAME.writeBinary(buf); } \
static void NAME##_readBinary(Derived & collection, ReadBuffer & buf) { collection.NAME.readBinary(buf); } \
static String NAME##_valueToString(const Field & value) { SettingField##TYPE temp{DEFAULT}; temp.set(value); return temp.toString(); } \
static Field NAME##_valueToCorrespondingType(const Field & value) { SettingField##TYPE temp{DEFAULT}; temp.set(value); return temp.toField(); } \
@ -354,6 +368,6 @@ void SettingsCollection<Derived>::deserialize(ReadBuffer & buf, SettingsBinaryFo
[](const Derived & d) { return d.NAME.changed; }, \
&Functions::NAME##_getString, &Functions::NAME##_getField, \
&Functions::NAME##_setString, &Functions::NAME##_setField, \
&Functions::NAME##_serialize, &Functions::NAME##_deserialize, \
&Functions::NAME##_writeBinary, &Functions::NAME##_readBinary, \
&Functions::NAME##_valueToString, &Functions::NAME##_valueToCorrespondingType});
}

View File

@ -0,0 +1,94 @@
#include <Core/SettingsEnums.h>
namespace DB
{
namespace ErrorCodes
{
extern const int UNKNOWN_LOAD_BALANCING;
extern const int UNKNOWN_OVERFLOW_MODE;
extern const int UNKNOWN_TOTALS_MODE;
extern const int UNKNOWN_DISTRIBUTED_PRODUCT_MODE;
extern const int UNKNOWN_JOIN;
extern const int BAD_ARGUMENTS;
}
IMPLEMENT_SETTING_ENUM(LoadBalancing, ErrorCodes::UNKNOWN_LOAD_BALANCING,
{{"random", LoadBalancing::RANDOM},
{"nearest_hostname", LoadBalancing::NEAREST_HOSTNAME},
{"in_order", LoadBalancing::IN_ORDER},
{"first_or_random", LoadBalancing::FIRST_OR_RANDOM},
{"round_robin", LoadBalancing::ROUND_ROBIN}})
IMPLEMENT_SETTING_ENUM(SpecialSort, ErrorCodes::UNKNOWN_JOIN,
{{"not_specified", SpecialSort::NOT_SPECIFIED},
{"opencl_bitonic", SpecialSort::OPENCL_BITONIC}})
IMPLEMENT_SETTING_ENUM(JoinStrictness, ErrorCodes::UNKNOWN_JOIN,
{{"", JoinStrictness::Unspecified},
{"ALL", JoinStrictness::ALL},
{"ANY", JoinStrictness::ANY}})
IMPLEMENT_SETTING_ENUM(JoinAlgorithm, ErrorCodes::UNKNOWN_JOIN,
{{"auto", JoinAlgorithm::AUTO},
{"hash", JoinAlgorithm::HASH},
{"partial_merge", JoinAlgorithm::PARTIAL_MERGE},
{"prefer_partial_merge", JoinAlgorithm::PREFER_PARTIAL_MERGE}})
IMPLEMENT_SETTING_ENUM(TotalsMode, ErrorCodes::UNKNOWN_TOTALS_MODE,
{{"before_having", TotalsMode::BEFORE_HAVING},
{"after_having_exclusive", TotalsMode::AFTER_HAVING_EXCLUSIVE},
{"after_having_inclusive", TotalsMode::AFTER_HAVING_INCLUSIVE},
{"after_having_auto", TotalsMode::AFTER_HAVING_AUTO}})
IMPLEMENT_SETTING_ENUM(OverflowMode, ErrorCodes::UNKNOWN_OVERFLOW_MODE,
{{"throw", OverflowMode::THROW},
{"break", OverflowMode::BREAK}})
IMPLEMENT_SETTING_ENUM_WITH_RENAME(OverflowModeGroupBy, ErrorCodes::UNKNOWN_OVERFLOW_MODE,
{{"throw", OverflowMode::THROW},
{"break", OverflowMode::BREAK},
{"any", OverflowMode::ANY}})
IMPLEMENT_SETTING_ENUM(DistributedProductMode, ErrorCodes::UNKNOWN_DISTRIBUTED_PRODUCT_MODE,
{{"deny", DistributedProductMode::DENY},
{"local", DistributedProductMode::LOCAL},
{"global", DistributedProductMode::GLOBAL},
{"allow", DistributedProductMode::ALLOW}})
IMPLEMENT_SETTING_ENUM_WITH_RENAME(DateTimeInputFormat, ErrorCodes::BAD_ARGUMENTS,
{{"basic", FormatSettings::DateTimeInputFormat::Basic},
{"best_effort", FormatSettings::DateTimeInputFormat::BestEffort}})
IMPLEMENT_SETTING_ENUM(LogsLevel, ErrorCodes::BAD_ARGUMENTS,
{{"none", LogsLevel::none},
{"fatal", LogsLevel::fatal},
{"error", LogsLevel::error},
{"warning", LogsLevel::warning},
{"information", LogsLevel::information},
{"debug", LogsLevel::debug},
{"trace", LogsLevel::trace}})
IMPLEMENT_SETTING_ENUM_WITH_RENAME(LogQueriesType, ErrorCodes::BAD_ARGUMENTS,
{{"QUERY_START", QUERY_START},
{"QUERY_FINISH", QUERY_FINISH},
{"EXCEPTION_BEFORE_START", EXCEPTION_BEFORE_START},
{"EXCEPTION_WHILE_PROCESSING", EXCEPTION_WHILE_PROCESSING}})
IMPLEMENT_SETTING_ENUM_WITH_RENAME(DefaultDatabaseEngine, ErrorCodes::BAD_ARGUMENTS,
{{"Ordinary", DefaultDatabaseEngine::Ordinary},
{"Atomic", DefaultDatabaseEngine::Atomic}})
}

129
src/Core/SettingsEnums.h Normal file
View File

@ -0,0 +1,129 @@
#pragma once
#include <Core/SettingsFields.h>
#include <DataStreams/SizeLimits.h>
#include <Formats/FormatSettings.h>
namespace DB
{
enum class LoadBalancing
{
/// among replicas with a minimum number of errors selected randomly
RANDOM = 0,
/// a replica is selected among the replicas with the minimum number of errors
/// with the minimum number of distinguished characters in the replica name and local hostname
NEAREST_HOSTNAME,
// replicas with the same number of errors are accessed in the same order
// as they are specified in the configuration.
IN_ORDER,
/// if first replica one has higher number of errors,
/// pick a random one from replicas with minimum number of errors
FIRST_OR_RANDOM,
// round robin across replicas with the same number of errors.
ROUND_ROBIN,
};
DECLARE_SETTING_ENUM(LoadBalancing)
enum class JoinStrictness
{
Unspecified = 0, /// Query JOIN without strictness will throw Exception.
ALL, /// Query JOIN without strictness -> ALL JOIN ...
ANY, /// Query JOIN without strictness -> ANY JOIN ...
};
DECLARE_SETTING_ENUM(JoinStrictness)
enum class JoinAlgorithm
{
AUTO = 0,
HASH,
PARTIAL_MERGE,
PREFER_PARTIAL_MERGE,
};
DECLARE_SETTING_ENUM(JoinAlgorithm)
enum class SpecialSort
{
NOT_SPECIFIED = 0,
OPENCL_BITONIC,
};
DECLARE_SETTING_ENUM(SpecialSort)
/// Which rows should be included in TOTALS.
enum class TotalsMode
{
BEFORE_HAVING = 0, /// Count HAVING for all read rows;
/// including those not in max_rows_to_group_by
/// and have not passed HAVING after grouping.
AFTER_HAVING_INCLUSIVE = 1, /// Count on all rows except those that have not passed HAVING;
/// that is, to include in TOTALS all the rows that did not pass max_rows_to_group_by.
AFTER_HAVING_EXCLUSIVE = 2, /// Include only the rows that passed and max_rows_to_group_by, and HAVING.
AFTER_HAVING_AUTO = 3, /// Automatically select between INCLUSIVE and EXCLUSIVE,
};
DECLARE_SETTING_ENUM(TotalsMode)
/// The settings keeps OverflowMode which cannot be OverflowMode::ANY.
DECLARE_SETTING_ENUM(OverflowMode)
/// The settings keeps OverflowMode which can be OverflowMode::ANY.
DECLARE_SETTING_ENUM_WITH_RENAME(OverflowModeGroupBy, OverflowMode)
/// The setting for executing distributed subqueries inside IN or JOIN sections.
enum class DistributedProductMode
{
DENY = 0, /// Disable
LOCAL, /// Convert to local query
GLOBAL, /// Convert to global query
ALLOW /// Enable
};
DECLARE_SETTING_ENUM(DistributedProductMode)
DECLARE_SETTING_ENUM_WITH_RENAME(DateTimeInputFormat, FormatSettings::DateTimeInputFormat)
enum class LogsLevel
{
none = 0, /// Disable
fatal,
error,
warning,
information,
debug,
trace,
};
DECLARE_SETTING_ENUM(LogsLevel)
// Make it signed for compatibility with DataTypeEnum8
enum QueryLogElementType : int8_t
{
QUERY_START = 1,
QUERY_FINISH = 2,
EXCEPTION_BEFORE_START = 3,
EXCEPTION_WHILE_PROCESSING = 4,
};
DECLARE_SETTING_ENUM_WITH_RENAME(LogQueriesType, QueryLogElementType)
enum class DefaultDatabaseEngine
{
Ordinary,
Atomic,
};
DECLARE_SETTING_ENUM(DefaultDatabaseEngine)
}

365
src/Core/SettingsFields.cpp Normal file
View File

@ -0,0 +1,365 @@
#include <Core/SettingsFields.h>
#include <Core/Field.h>
#include <Common/getNumberOfPhysicalCPUCores.h>
#include <Common/FieldVisitors.h>
#include <common/logger_useful.h>
#include <IO/ReadHelpers.h>
#include <IO/ReadBufferFromString.h>
#include <IO/WriteHelpers.h>
namespace DB
{
namespace ErrorCodes
{
extern const int SIZE_OF_FIXED_STRING_DOESNT_MATCH;
extern const int CANNOT_PARSE_BOOL;
}
template <typename Type>
String SettingFieldNumber<Type>::toString() const
{
return DB::toString(value);
}
template <typename Type>
Field SettingFieldNumber<Type>::toField() const
{
return value;
}
template <typename Type>
void SettingFieldNumber<Type>::set(Type x)
{
value = x;
changed = true;
}
template <typename Type>
void SettingFieldNumber<Type>::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<Type>(), x));
}
template <typename Type>
void SettingFieldNumber<Type>::set(const String & x)
{
set(parseWithSizeSuffix<Type>(x));
}
template <>
void SettingFieldNumber<bool>::set(const String & x)
{
if (x.size() == 1)
{
if (x[0] == '0')
set(false);
else if (x[0] == '1')
set(true);
else
throw Exception("Cannot parse bool from string '" + x + "'", ErrorCodes::CANNOT_PARSE_BOOL);
}
else
{
ReadBufferFromString buf(x);
if (checkStringCaseInsensitive("true", buf))
set(true);
else if (checkStringCaseInsensitive("false", buf))
set(false);
else
throw Exception("Cannot parse bool from string '" + x + "'", ErrorCodes::CANNOT_PARSE_BOOL);
}
}
template <typename Type>
void SettingFieldNumber<Type>::writeBinary(WriteBuffer & out) const
{
if constexpr (is_integral_v<Type> && is_unsigned_v<Type>)
writeVarUInt(static_cast<UInt64>(value), out);
else if constexpr (is_integral_v<Type> && is_signed_v<Type>)
writeVarInt(static_cast<Int64>(value), out);
else
{
static_assert(std::is_floating_point_v<Type>);
writeStringBinary(toString(), out);
}
}
template <typename Type>
void SettingFieldNumber<Type>::readBinary(ReadBuffer & in)
{
if constexpr (is_integral_v<Type> && is_unsigned_v<Type>)
{
UInt64 x;
readVarUInt(x, in);
set(static_cast<Type>(x));
}
else if constexpr (is_integral_v<Type> && is_signed_v<Type>)
{
Int64 x;
readVarInt(x, in);
set(static_cast<Type>(x));
}
else
{
static_assert(std::is_floating_point_v<Type>);
String x;
readStringBinary(x, in);
set(x);
}
}
template struct SettingFieldNumber<UInt64>;
template struct SettingFieldNumber<Int64>;
template struct SettingFieldNumber<float>;
template struct SettingFieldNumber<bool>;
String SettingFieldMaxThreads::toString() const
{
/// Instead of the `auto` value, we output the actual value to make it easier to see.
return is_auto ? ("auto(" + DB::toString(value) + ")") : DB::toString(value);
}
Field SettingFieldMaxThreads::toField() const
{
return is_auto ? 0 : value;
}
void SettingFieldMaxThreads::set(UInt64 x)
{
value = x ? x : getAutoValue();
is_auto = x == 0;
changed = true;
}
void SettingFieldMaxThreads::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<UInt64>(), x));
}
void SettingFieldMaxThreads::set(const String & x)
{
if (startsWith(x, "auto"))
setAuto();
else
set(parse<UInt64>(x));
}
void SettingFieldMaxThreads::setAuto()
{
value = getAutoValue();
is_auto = true;
}
UInt64 SettingFieldMaxThreads::getAutoValue()
{
static auto res = getNumberOfPhysicalCPUCores();
return res;
}
void SettingFieldMaxThreads::writeBinary(WriteBuffer & out) const
{
writeVarUInt(is_auto ? 0 : value, out);
}
void SettingFieldMaxThreads::readBinary(ReadBuffer & in)
{
UInt64 x = 0;
readVarUInt(x, in);
set(x);
}
template <SettingFieldTimespanUnit unit>
String SettingFieldTimespan<unit>::toString() const
{
return DB::toString(value.totalMicroseconds() / microseconds_per_unit);
}
template <SettingFieldTimespanUnit unit>
Field SettingFieldTimespan<unit>::toField() const
{
return value.totalMicroseconds() / microseconds_per_unit;
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::set(const Poco::Timespan & x)
{
value = x;
changed = true;
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::set(UInt64 x)
{
set(Poco::Timespan(x * microseconds_per_unit));
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::set(const Field & x)
{
if (x.getType() == Field::Types::String)
set(get<const String &>(x));
else
set(applyVisitor(FieldVisitorConvertToNumber<UInt64>(), x));
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::set(const String & x)
{
set(parse<UInt64>(x));
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::writeBinary(WriteBuffer & out) const
{
writeVarUInt(value.totalMicroseconds() / microseconds_per_unit, out);
}
template <SettingFieldTimespanUnit unit>
void SettingFieldTimespan<unit>::readBinary(ReadBuffer & in)
{
UInt64 x = 0;
readVarUInt(x, in);
set(x);
}
template struct SettingFieldTimespan<SettingFieldTimespanUnit::SECOND>;
template struct SettingFieldTimespan<SettingFieldTimespanUnit::MILLISECOND>;
Field SettingFieldString::toField() const
{
return value;
}
void SettingFieldString::set(const String & x)
{
value = x;
changed = true;
}
void SettingFieldString::set(const Field & x)
{
set(safeGet<const String &>(x));
}
void SettingFieldString::writeBinary(WriteBuffer & out) const
{
writeStringBinary(value, out);
}
void SettingFieldString::readBinary(ReadBuffer & in)
{
String s;
readStringBinary(s, in);
set(s);
}
String SettingFieldChar::toString() const
{
return String(1, value);
}
Field SettingFieldChar::toField() const
{
return toString();
}
void SettingFieldChar::set(char x)
{
value = x;
changed = true;
}
void SettingFieldChar::set(const String & x)
{
if (x.size() > 1)
throw Exception("A setting's value string has to be an exactly one character long", ErrorCodes::SIZE_OF_FIXED_STRING_DOESNT_MATCH);
char c = (x.size() == 1) ? x[0] : '\0';
set(c);
}
void SettingFieldChar::set(const Field & x)
{
const String & s = safeGet<const String &>(x);
set(s);
}
void SettingFieldChar::writeBinary(WriteBuffer & out) const
{
writeStringBinary(toString(), out);
}
void SettingFieldChar::readBinary(ReadBuffer & in)
{
String s;
readStringBinary(s, in);
set(s);
}
String SettingFieldURI::toString() const
{
return value.toString();
}
Field SettingFieldURI::toField() const
{
return value.toString();
}
void SettingFieldURI::set(const Poco::URI & x)
{
value = x;
changed = true;
}
void SettingFieldURI::set(const Field & x)
{
const String & s = safeGet<const String &>(x);
set(s);
}
void SettingFieldURI::set(const String & x)
{
set(Poco::URI(x));
}
void SettingFieldURI::writeBinary(WriteBuffer & buf) const
{
writeStringBinary(toString(), buf);
}
void SettingFieldURI::readBinary(ReadBuffer & buf)
{
String s;
readStringBinary(s, buf);
set(s);
}
void SettingFieldEnumHelpers::writeBinary(const std::string_view & str, WriteBuffer & out)
{
writeStringBinary(str, out);
}
String SettingFieldEnumHelpers::readBinary(ReadBuffer & in)
{
String str;
readStringBinary(str, in);
return str;
}
}

313
src/Core/SettingsFields.h Normal file
View File

@ -0,0 +1,313 @@
#pragma once
#include <Poco/Timespan.h>
#include <Poco/URI.h>
#include <Core/Types.h>
#include <Core/Field.h>
#include <boost/range/adaptor/map.hpp>
#include <chrono>
#include <unordered_map>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
class ReadBuffer;
class WriteBuffer;
/** One setting for any type.
* Stores a value within itself, as well as a flag - whether the value was changed.
* This is done so that you can send to the remote servers only changed settings (or explicitly specified in the config) values.
* That is, if the configuration was not specified in the config and was not dynamically changed, it is not sent to the remote server,
* and the remote server will use its default value.
*/
template <typename Type>
struct SettingFieldNumber
{
Type value;
bool changed = false;
SettingFieldNumber(Type x = 0) : value(x) {}
operator Type() const { return value; }
SettingFieldNumber & operator=(Type x) { set(x); return *this; }
/// Serialize to a test string.
String toString() const;
/// Converts to a field.
Field toField() const;
void set(Type x);
/// Read from SQL literal.
void set(const Field & x);
/// Read from text string.
void set(const String & x);
/// Serialize to binary stream.
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
using SettingFieldUInt64 = SettingFieldNumber<UInt64>;
using SettingFieldInt64 = SettingFieldNumber<Int64>;
using SettingFieldFloat = SettingFieldNumber<float>;
using SettingFieldBool = SettingFieldNumber<bool>;
/** Unlike SettingFieldUInt64, supports the value of 'auto' - the number of processor cores without taking into account SMT.
* A value of 0 is also treated as auto.
* When serializing, `auto` is written in the same way as 0.
*/
struct SettingFieldMaxThreads
{
UInt64 value;
bool is_auto;
bool changed = false;
SettingFieldMaxThreads(UInt64 x = 0) : value(x ? x : getAutoValue()), is_auto(x == 0) {}
operator UInt64() const { return value; }
SettingFieldMaxThreads & operator=(UInt64 x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(UInt64 x);
void set(const Field & x);
void set(const String & x);
void setAuto();
static UInt64 getAutoValue();
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
enum class SettingFieldTimespanUnit { MILLISECOND, SECOND };
template <SettingFieldTimespanUnit unit>
struct SettingFieldTimespan
{
static constexpr UInt64 microseconds_per_unit = (unit == SettingFieldTimespanUnit::MILLISECOND) ? 1000 : 1000000;
Poco::Timespan value;
bool changed = false;
SettingFieldTimespan(UInt64 x = 0) : value(x * microseconds_per_unit) {}
operator Poco::Timespan() const { return value; }
SettingFieldTimespan & operator=(const Poco::Timespan & x) { set(x); return *this; }
template <class Rep, class Period = std::ratio<1>>
operator std::chrono::duration<Rep, Period>() const { return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(std::chrono::microseconds(value.totalMicroseconds())); }
template <class Rep, class Period = std::ratio<1>>
SettingFieldTimespan & operator=(const std::chrono::duration<Rep, Period> & x) { set(x); return *this; }
Poco::Timespan::TimeDiff totalSeconds() const { return value.totalSeconds(); }
Poco::Timespan::TimeDiff totalMilliseconds() const { return value.totalMilliseconds(); }
String toString() const;
Field toField() const;
void set(const Poco::Timespan & x);
template <class Rep, class Period = std::ratio<1>>
void set(const std::chrono::duration<Rep, Period> & duration) { set(static_cast<UInt64>(std::chrono::duration_cast<std::chrono::microseconds>(duration).count())); }
void set(UInt64 x);
void set(const Field & x);
void set(const String & x);
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
using SettingFieldSeconds = SettingFieldTimespan<SettingFieldTimespanUnit::SECOND>;
using SettingFieldMilliseconds = SettingFieldTimespan<SettingFieldTimespanUnit::MILLISECOND>;
struct SettingFieldString
{
String value;
bool changed = false;
SettingFieldString(const String & x = String{}) : value(x) {}
operator String() const { return value; }
SettingFieldString & operator=(const String & x) { set(x); return *this; }
const String & toString() const { return value; }
Field toField() const;
void set(const String & x);
void set(const Field & x);
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
struct SettingFieldChar
{
public:
char value;
bool changed = false;
SettingFieldChar(char x = '\0') : value(x) {}
operator char() const { return value; }
SettingFieldChar & operator=(char x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(char x);
void set(const String & x);
void set(const Field & x);
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
struct SettingFieldURI
{
Poco::URI value;
bool changed = false;
SettingFieldURI(const Poco::URI & x = Poco::URI{}) : value(x) {}
operator Poco::URI() const { return value; }
SettingFieldURI & operator=(const Poco::URI & x) { set(x); return *this; }
String toString() const;
Field toField() const;
void set(const Poco::URI & x);
void set(const Field & x);
void set(const String & x);
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
/** Template class to define enum-based settings.
* Example of usage:
*
* mysettings.h:
* enum Gender { Male, Female };
* DECLARE_SETTING_ENUM(SettingFieldGender, Gender)
*
* mysettings.cpp:
* IMPLEMENT_SETTING_ENUM(SettingFieldGender, ErrorCodes::BAD_ARGUMENTS,
* {{"Male", Gender::Male}, {"Female", Gender::Female}})
*/
template <typename EnumType, typename NameValueConverter>
struct SettingFieldEnum
{
EnumType value;
bool changed = false;
SettingFieldEnum(EnumType x) : value(x) {}
operator EnumType() const { return value; }
SettingFieldEnum & operator=(EnumType x) { set(x); return *this; }
const String & toString() const { return NameValueConverter::toString(value); }
Field toField() const { return toString(); }
void set(EnumType x) { value = x; changed = true; }
void set(const Field & x) { set(safeGet<const String &>(x)); }
void set(const String & x) { set(NameValueConverter::fromString(x)); }
void writeBinary(WriteBuffer & out) const;
void readBinary(ReadBuffer & in);
};
struct SettingFieldEnumHelpers
{
static void writeBinary(const std::string_view & str, WriteBuffer & out);
static String readBinary(ReadBuffer & in);
};
template <typename EnumType, typename NameValueConverter>
inline void SettingFieldEnum<EnumType, NameValueConverter>::writeBinary(WriteBuffer & out) const
{
SettingFieldEnumHelpers::writeBinary(toString(), out);
}
template <typename EnumType, typename NameValueConverter>
inline void SettingFieldEnum<EnumType, NameValueConverter>::readBinary(ReadBuffer & in)
{
set(SettingFieldEnumHelpers::readBinary(in));
}
#define DECLARE_SETTING_ENUM(ENUM_TYPE) \
DECLARE_SETTING_ENUM_WITH_RENAME(ENUM_TYPE, ENUM_TYPE)
#define IMPLEMENT_SETTING_ENUM(ENUM_TYPE, ERROR_CODE_FOR_UNEXPECTED_NAME, ...) \
IMPLEMENT_SETTING_ENUM_WITH_RENAME(ENUM_TYPE, ERROR_CODE_FOR_UNEXPECTED_NAME, __VA_ARGS__)
#define DECLARE_SETTING_ENUM_WITH_RENAME(NEW_NAME, ENUM_TYPE) \
struct SettingField##NEW_NAME##NameValueConverter \
{ \
using EnumType = ENUM_TYPE; \
static const String & toString(EnumType value); \
static EnumType fromString(const std::string_view & str); \
}; \
\
using SettingField##NEW_NAME = SettingFieldEnum<ENUM_TYPE, SettingField##NEW_NAME##NameValueConverter>;
#define IMPLEMENT_SETTING_ENUM_WITH_RENAME(NEW_NAME, ERROR_CODE_FOR_UNEXPECTED_NAME, ...) \
const String & SettingField##NEW_NAME##NameValueConverter::toString(typename SettingField##NEW_NAME##NameValueConverter::EnumType value) \
{ \
static const std::unordered_map<EnumType, String> map = [] { \
std::unordered_map<EnumType, String> res; \
constexpr std::pair<const char *, EnumType> pairs[] = __VA_ARGS__; \
for (const auto & [name, val] : pairs) \
res.emplace(val, name); \
return res; \
}(); \
auto it = map.find(value); \
if (it != map.end()) \
return it->second; \
throw Exception( \
"Unexpected value of " #NEW_NAME ":" + std::to_string(std::underlying_type<EnumType>::type(value)), \
ERROR_CODE_FOR_UNEXPECTED_NAME); \
} \
\
typename SettingField##NEW_NAME##NameValueConverter::EnumType SettingField##NEW_NAME##NameValueConverter::fromString(const std::string_view & str) \
{ \
static const std::unordered_map<std::string_view, EnumType> map = [] { \
std::unordered_map<std::string_view, EnumType> res; \
constexpr std::pair<const char *, EnumType> pairs[] = __VA_ARGS__; \
for (const auto & [name, val] : pairs) \
res.emplace(name, val); \
return res; \
}(); \
auto it = map.find(str); \
if (it != map.end()) \
return it->second; \
String msg = "Unexpected value of " #NEW_NAME ": '" + String{str} + "'. Must be one of ["; \
bool need_comma = false; \
for (auto & name : map | boost::adaptors::map_keys) \
{ \
if (std::exchange(need_comma, true)) \
msg += ", "; \
msg += "'" + String{name} + "'"; \
} \
msg += "]"; \
throw Exception(msg, ERROR_CODE_FOR_UNEXPECTED_NAME); \
}
}

View File

@ -5,7 +5,7 @@
#include <cstddef>
#include <string>
#include <Core/Field.h>
#include <Core/SettingsCollection.h>
#include <Core/SettingsEnums.h>
class Collator;

View File

@ -20,6 +20,8 @@ SRCS(
NamesAndTypes.cpp
Settings.cpp
SettingsCollection.cpp
SettingsEnums.cpp
SettingsFields.cpp
SortDescription.cpp
)

View File

@ -2,7 +2,6 @@
#include <Interpreters/SystemLog.h>
#include <Interpreters/ClientInfo.h>
#include <Core/SettingsCollection.h>
namespace ProfileEvents

View File

@ -2,7 +2,7 @@
#include <Core/Names.h>
#include <Core/NamesAndTypes.h>
#include <Core/SettingsCollection.h>
#include <Core/SettingsEnums.h>
#include <Parsers/ASTTablesInSelectQuery.h>
#include <Interpreters/IJoin.h>
#include <Interpreters/asof.h>