diff --git a/src/main/settings.cpp b/src/main/settings.cpp index 3382027db..f104c0a35 100644 --- a/src/main/settings.cpp +++ b/src/main/settings.cpp @@ -1,5 +1,7 @@ #include "main/settings.h" +#include + #include "common/assert.h" #include "common/exception/runtime.h" #include "common/string_utils.h" @@ -34,11 +36,30 @@ void setDefaultHashIndexEnabledOnStorageManagers(ClientContext* context, bool en } } +// The INT64 settings below are stored unsigned; a value that doesn't fit would wrap. +template +T toUnsignedSetting(const char* name, const common::Value& parameter) { + const auto value = parameter.getValue(); + if (value < 0) { + throw common::RuntimeException(std::format("{} must be >= 0, got {}.", name, value)); + } + if constexpr (sizeof(T) < sizeof(int64_t)) { + if (static_cast(value) > std::numeric_limits::max()) { + throw common::RuntimeException(std::format("{} must be <= {}, got {}.", name, + std::numeric_limits::max(), value)); + } + } + return static_cast(value); +} + } // namespace void ThreadsSetting::setContext(ClientContext* context, const common::Value& parameter) { parameter.validateType(inputType); - context->getClientConfigUnsafe()->numThreads = parameter.getValue(); + // 0 means the database's thread count, as in ClientContext::setMaxNumThreadForExec. + const auto numThreads = parameter.getValue(); + context->getClientConfigUnsafe()->numThreads = + numThreads == 0 ? context->getDBConfig()->maxNumThreads : numThreads; } common::Value ThreadsSetting::getSetting(const ClientContext* context) { @@ -76,7 +97,8 @@ common::Value ProgressBarSetting::getSetting(const ClientContext* context) { void VarLengthExtendMaxDepthSetting::setContext(ClientContext* context, const common::Value& parameter) { parameter.validateType(inputType); - context->getClientConfigUnsafe()->varLengthMaxDepth = parameter.getValue(); + context->getClientConfigUnsafe()->varLengthMaxDepth = + toUnsignedSetting(name, parameter); } common::Value VarLengthExtendMaxDepthSetting::getSetting(const ClientContext* context) { @@ -86,7 +108,8 @@ common::Value VarLengthExtendMaxDepthSetting::getSetting(const ClientContext* co void SparseFrontierThresholdSetting::setContext(ClientContext* context, const common::Value& parameter) { parameter.validateType(inputType); - context->getClientConfigUnsafe()->sparseFrontierThreshold = parameter.getValue(); + context->getClientConfigUnsafe()->sparseFrontierThreshold = + toUnsignedSetting(name, parameter); } common::Value SparseFrontierThresholdSetting::getSetting(const ClientContext* context) { @@ -156,7 +179,7 @@ void RecursivePatternFactorSetting::setContext(ClientContext* context, const common::Value& parameter) { parameter.validateType(inputType); context->getClientConfigUnsafe()->recursivePatternCardinalityScaleFactor = - parameter.getValue(); + toUnsignedSetting(name, parameter); } common::Value RecursivePatternFactorSetting::getSetting(const ClientContext* context) { @@ -177,7 +200,8 @@ common::Value EnableMVCCSetting::getSetting(const ClientContext* context) { void CheckpointThresholdSetting::setContext(ClientContext* context, const common::Value& parameter) { parameter.validateType(inputType); - context->getDBConfigUnsafe()->checkpointThreshold = parameter.getValue(); + context->getDBConfigUnsafe()->checkpointThreshold = + toUnsignedSetting(name, parameter); } common::Value CheckpointThresholdSetting::getSetting(const ClientContext* context) { diff --git a/test/test_files/function/call/setting_ranges.test b/test/test_files/function/call/setting_ranges.test new file mode 100644 index 000000000..8c28da1bf --- /dev/null +++ b/test/test_files/function/call/setting_ranges.test @@ -0,0 +1,38 @@ +-DATASET CSV empty + +-- + +-CASE ThreadsZeroUsesDatabaseThreadCount +-LOG threads=0 means the database's thread count, as Connection::setMaxNumThreadForExec(0) does +-STATEMENT CALL threads=0 +---- ok +-STATEMENT UNWIND range(1, 100000) AS x RETURN sum(x) +---- 1 +5000050000 + +-CASE UnsignedSettingsRejectValuesThatWrap +-STATEMENT CALL checkpoint_threshold=-1 +---- error +Runtime exception: checkpoint_threshold must be >= 0, got -1. +-STATEMENT CALL sparse_frontier_threshold=-1 +---- error +Runtime exception: sparse_frontier_threshold must be >= 0, got -1. +-STATEMENT CALL var_length_extend_max_depth=-1 +---- error +Runtime exception: var_length_extend_max_depth must be >= 0, got -1. +-STATEMENT CALL var_length_extend_max_depth=4294967296 +---- error +Runtime exception: var_length_extend_max_depth must be <= 4294967295, got 4294967296. +-STATEMENT CALL recursive_pattern_factor=-5 +---- error +Runtime exception: recursive_pattern_factor must be >= 0, got -5. +-STATEMENT CALL var_length_extend_max_depth=7 +---- ok +-STATEMENT CALL current_setting('var_length_extend_max_depth') RETURN * +---- 1 +7 +-STATEMENT CALL checkpoint_threshold=0 +---- ok +-STATEMENT CALL current_setting('checkpoint_threshold') RETURN * +---- 1 +0