diff --git a/src/query/service/tests/it/sessions/session_setting.rs b/src/query/service/tests/it/sessions/session_setting.rs index 0cf73a9f1b22..9d85ac464cff 100644 --- a/src/query/service/tests/it/sessions/session_setting.rs +++ b/src/query/service/tests/it/sessions/session_setting.rs @@ -54,9 +54,9 @@ async fn test_session_setting_override() -> Result<()> { let overrided = settings.get_max_storage_io_requests()?; let expect = 1000; assert_eq!(overrided, expect); - settings.set_setting("max_storage_io_requests".to_string(), "3000".to_string())?; + settings.set_setting("max_storage_io_requests".to_string(), "300".to_string())?; let actual = settings.get_max_storage_io_requests()?; - let expect = 3000; + let expect = 300; assert_eq!(actual, expect); } diff --git a/src/query/settings/src/settings_default.rs b/src/query/settings/src/settings_default.rs index 474322fb8390..5a152d5a8b3f 100644 --- a/src/query/settings/src/settings_default.rs +++ b/src/query/settings/src/settings_default.rs @@ -13,6 +13,7 @@ // limitations under the License. use std::collections::HashMap; +use std::ops::Range; use std::sync::Arc; use common_config::GlobalConfig; @@ -42,6 +43,7 @@ pub struct DefaultSettingValue { pub(crate) desc: &'static str, pub(crate) possible_values: Option>, pub(crate) mode: SettingMode, + pub(crate) range: Option>, } #[derive(Clone)] @@ -64,24 +66,28 @@ impl DefaultSettings { desc: "Sets the maximum byte size of a single data block that can be read.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("parquet_max_block_size", DefaultSettingValue { value: UserSettingValue::UInt64(8192), desc: "Max block size for parquet reader", possible_values: None, mode: SettingMode::Both, + range: None, }), ("max_threads", DefaultSettingValue { value: UserSettingValue::UInt64(num_cpus), desc: "Sets the maximum number of threads to execute a request.", possible_values: None, mode: SettingMode::Both, + range: Some(1..1024), }), ("max_memory_usage", DefaultSettingValue { value: UserSettingValue::UInt64(max_memory_usage), desc: "Sets the maximum memory usage in bytes for processing a single query.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("retention_period", DefaultSettingValue { // unit of retention_period is hour @@ -89,12 +95,14 @@ impl DefaultSettings { desc: "Sets the retention period in hours.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("max_storage_io_requests", DefaultSettingValue { value: UserSettingValue::UInt64(default_max_storage_io_requests), desc: "Sets the maximum number of concurrent I/O requests.", possible_values: None, mode: SettingMode::Both, + range: Some(1..1024), }), ("storage_io_min_bytes_for_seek", DefaultSettingValue { value: UserSettingValue::UInt64(48), @@ -102,18 +110,21 @@ impl DefaultSettings { when seeking a new location in the data file.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("storage_io_max_page_bytes_for_read", DefaultSettingValue { value: UserSettingValue::UInt64(512 * 1024), desc: "Sets the maximum byte size of data pages that can be read from storage in a single I/O operation.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("flight_client_timeout", DefaultSettingValue { value: UserSettingValue::UInt64(60), desc: "Sets the maximum time in seconds that a flight client request can be processed.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("http_handler_result_timeout_secs", DefaultSettingValue { value: { @@ -124,156 +135,182 @@ impl DefaultSettings { desc: "Set the timeout in seconds that a http query session expires without any polls.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("storage_read_buffer_size", DefaultSettingValue { value: UserSettingValue::UInt64(1024 * 1024), desc: "Sets the byte size of the buffer used for reading data into memory.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("input_read_buffer_size", DefaultSettingValue { value: UserSettingValue::UInt64(4 * 1024 * 1024), desc: "Sets the memory size in bytes allocated to the buffer used by the buffered reader to read data from storage.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("timezone", DefaultSettingValue { value: UserSettingValue::String("UTC".to_owned()), desc: "Sets the timezone.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("group_by_two_level_threshold", DefaultSettingValue { value: UserSettingValue::UInt64(20000), desc: "Sets the number of keys in a GROUP BY operation that will trigger a two-level aggregation.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("max_inlist_to_or", DefaultSettingValue { value: UserSettingValue::UInt64(3), desc: "Sets the maximum number of values that can be included in an IN expression to be converted to an OR operator.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("unquoted_ident_case_sensitive", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Determines whether Databend treats unquoted identifiers as case-sensitive.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("quoted_ident_case_sensitive", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Determines whether Databend treats quoted identifiers as case-sensitive.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("sql_dialect", DefaultSettingValue { value: UserSettingValue::String("PostgreSQL".to_owned()), desc: "Sets the SQL dialect. Available values include \"PostgreSQL\", \"MySQL\", \"Experimental\", and \"Hive\".", possible_values: Some(vec!["PostgreSQL", "MySQL", "Experimental", "Hive"]), mode: SettingMode::Both, + range: None, }), ("enable_dphyp", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables dphyp join order algorithm.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_cbo", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables cost-based optimization.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("disable_join_reorder", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Disable join reorder optimization.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("join_spilling_threshold", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Maximum amount of memory can use for hash join, 0 is unlimited.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_runtime_filter", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enables runtime filter optimization for JOIN.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("max_execute_time_in_seconds", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum query execution time in seconds. Setting it to 0 means no limit.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("collation", DefaultSettingValue { value: UserSettingValue::String("binary".to_owned()), desc: "Sets the character collation. Available values include \"binary\" and \"utf8\".", possible_values: Some(vec!["binary", "utf8"]), mode: SettingMode::Both, + range: None, }), ("max_result_rows", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum number of rows that can be returned in a query result when no specific row count is specified. Setting it to 0 means no limit.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("prefer_broadcast_join", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables broadcast join.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("storage_fetch_part_num", DefaultSettingValue { value: UserSettingValue::UInt64(2), desc: "Sets the number of partitions that are fetched in parallel from storage during query execution.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("load_file_metadata_expire_hours", DefaultSettingValue { value: UserSettingValue::UInt64(24 * 7), desc: "Sets the hours that the metadata of files you load data from with COPY INTO will expire in.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("hide_options_in_show_create_table", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Hides table-relevant information, such as SNAPSHOT_LOCATION and STORAGE_FORMAT, at the end of the result of SHOW TABLE CREATE.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("sandbox_tenant", DefaultSettingValue { value: UserSettingValue::String("".to_string()), desc: "Injects a custom 'sandbox_tenant' into this session. This is only for testing purposes and will take effect only when 'internal_enable_sandbox_tenant' is turned on.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("parquet_uncompressed_buffer_size", DefaultSettingValue { value: UserSettingValue::UInt64(2 * 1024 * 1024), desc: "Sets the byte size of the buffer used for reading Parquet files.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_bushy_join", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enables generating a bushy join plan with the optimizer.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_query_result_cache", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enables caching query results to improve performance for identical queries.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("query_result_cache_max_bytes", DefaultSettingValue { value: UserSettingValue::UInt64(1048576), // 1MB desc: "Sets the maximum byte size of cache for a single query result.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("query_result_cache_ttl_secs", DefaultSettingValue { value: UserSettingValue::UInt64(300), // seconds @@ -281,72 +318,84 @@ impl DefaultSettings { Once the TTL for a cached result has expired, the result is considered stale and will not be used for new queries.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("query_result_cache_allow_inconsistent", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Determines whether Databend will return cached query results that are inconsistent with the underlying data.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_hive_parquet_predict_pushdown", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enable hive parquet predict pushdown by setting this variable to 1, default value: 1", possible_values: None, mode: SettingMode::Both, + range: None, }), ("hive_parquet_chunk_size", DefaultSettingValue { value: UserSettingValue::UInt64(16384), desc: "the max number of rows each read from parquet to databend processor", possible_values: None, mode: SettingMode::Both, + range: None, }), ("aggregate_spilling_bytes_threshold_per_proc", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum amount of memory in bytes that an aggregator can use before spilling data to storage during query execution.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("aggregate_spilling_memory_ratio", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum memory ratio in bytes that an aggregator can use before spilling data to storage during query execution.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("sort_spilling_bytes_threshold_per_proc", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum amount of memory in bytes that a sorter can use before spilling data to storage during query execution.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("sort_spilling_memory_ratio", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Sets the maximum memory ratio in bytes that a sorter can use before spilling data to storage during query execution.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("group_by_shuffle_mode", DefaultSettingValue { value: UserSettingValue::String(String::from("before_merge")), desc: "Group by shuffle mode, 'before_partial' is more balanced, but more data needs to exchange.", possible_values: Some(vec!["before_partial", "before_merge"]), mode: SettingMode::Both, + range: None, }), ("efficiently_memory_group_by", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Memory is used efficiently, but this may cause performance degradation.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("lazy_read_threshold", DefaultSettingValue { value: UserSettingValue::UInt64(1000), desc: "Sets the maximum LIMIT in a query to enable lazy read optimization. Setting it to 0 disables the optimization.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("parquet_fast_read_bytes", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Parquet file with smaller size will be read as a whole file, instead of column by column.", possible_values: None, mode: SettingMode::Both, + range: None, }), // enterprise license related settings @@ -356,198 +405,231 @@ impl DefaultSettings { possible_values: None, // license key should not be reported mode: SettingMode::Write, + range: None, }), ("enable_table_lock", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables table lock if necessary (enabled by default).", possible_values: None, mode: SettingMode::Both, + range: None, }), ("table_lock_expire_secs", DefaultSettingValue { value: UserSettingValue::UInt64(10), desc: "Sets the seconds that the table lock will expire in.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("acquire_lock_timeout", DefaultSettingValue { value: UserSettingValue::UInt64(15), desc: "Sets the maximum timeout in seconds for acquire a lock.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("deduplicate_label", DefaultSettingValue { value: UserSettingValue::String("".to_owned()), desc: "Sql duplicate label for deduplication.", possible_values: None, mode: SettingMode::Write, + range: None, }), ("enable_distributed_copy_into", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enable distributed execution of copy into.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_experimental_merge_into", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enable experimental merge into.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_distributed_merge_into", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enable distributed merge into.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("merge_into_static_filter_partition_threshold", DefaultSettingValue { value: UserSettingValue::UInt64(1500), desc: "Max number of partitions allowed for static filtering of merge into statement", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_distributed_replace_into", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enable distributed execution of replace into.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_distributed_compact", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enable distributed execution of table compaction.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_aggregating_index_scan", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enable scanning aggregating index data while querying.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_recluster_after_write", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables re-clustering after write(copy/replace-into).", possible_values: None, mode: SettingMode::Both, + range: None, }), ("use_parquet2", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Use parquet2 instead of parquet_rs when infer_schema().", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_replace_into_partitioning", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables partitioning for replace-into statement (if table has cluster keys).", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_replace_into_bloom_pruning", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables bloom pruning for replace-into statement.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("replace_into_bloom_pruning_max_column_number", DefaultSettingValue { value: UserSettingValue::UInt64(4), desc: "Max number of columns used by bloom pruning for replace-into statement.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("replace_into_shuffle_strategy", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "0 for Block level shuffle, 1 for segment level shuffle", possible_values: None, mode: SettingMode::Both, + range: None, }), ("recluster_timeout_secs", DefaultSettingValue { value: UserSettingValue::UInt64(12 * 60 * 60), desc: "Sets the seconds that recluster final will be timeout.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_refresh_aggregating_index_after_write", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Refresh aggregating index after new data written", possible_values: None, mode: SettingMode::Both, + range: None, }), ("ddl_column_type_nullable", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "If columns are default nullable when create or alter table", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_query_profiling", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enables recording query profile", possible_values: None, mode: SettingMode::Both, + range: None, }), ("recluster_block_size", DefaultSettingValue { value: UserSettingValue::UInt64(recluster_block_size), desc: "Sets the maximum byte size of blocks for recluster", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_distributed_recluster", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enable distributed execution of table recluster.", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_parquet_page_index", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables parquet page index", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_parquet_rowgroup_pruning", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "Enables parquet rowgroup pruning", possible_values: None, mode: SettingMode::Both, + range: None, }), ("external_server_connect_timeout_secs", DefaultSettingValue { value: UserSettingValue::UInt64(10), desc: "Connection timeout to external server", possible_values: None, mode: SettingMode::Both, + range: None, }), ("external_server_request_timeout_secs", DefaultSettingValue { value: UserSettingValue::UInt64(180), desc: "Request timeout to external server", possible_values: None, mode: SettingMode::Both, + range: None, }), ("enable_parquet_prewhere", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "Enables parquet prewhere", possible_values: None, mode: SettingMode::Both, + range: None, }), ("numeric_cast_option", DefaultSettingValue { value: UserSettingValue::String("rounding".to_string()), desc: "Set numeric cast mode as \"rounding\" or \"truncating\".", possible_values: Some(vec!["rounding", "truncating"]), mode: SettingMode::Both, + range: None, }), ("enable_experimental_rbac_check", DefaultSettingValue { value: UserSettingValue::UInt64(0), desc: "experiment setting disables stage and udf privilege check(disable by default).", possible_values: None, mode: SettingMode::Both, + range: None, }), ("create_query_flight_client_with_current_rt", DefaultSettingValue { value: UserSettingValue::UInt64(1), desc: "create query flight client with current runtime", possible_values: None, mode: SettingMode::Both, + range: None, }), ("query_flight_compression", DefaultSettingValue { value: UserSettingValue::String(String::from("LZ4")), desc: "flight compression method", possible_values: Some(vec!["None", "LZ4", "ZSTD"]), mode: SettingMode::Both, + range: None, }), ]); @@ -659,6 +741,16 @@ impl DefaultSettings { }; let u64_val = val.parse::()?; + + if let Some(range) = &setting_value.range { + if !range.contains(&u64_val) { + return Err(ErrorCode::BadArguments(format!( + "{} value should in range: {:?}", + k, range + ))); + } + } + Ok((k, Some(UserSettingValue::UInt64(u64_val)))) } UserSettingValue::String(_) => Ok((k, Some(UserSettingValue::String(v)))), diff --git a/src/query/settings/src/settings_getter_setter.rs b/src/query/settings/src/settings_getter_setter.rs index 7f49bbc9499c..604f95963b09 100644 --- a/src/query/settings/src/settings_getter_setter.rs +++ b/src/query/settings/src/settings_getter_setter.rs @@ -78,6 +78,15 @@ impl Settings { ))); } + if let Some(range) = &default_val.range { + if !range.contains(&val) { + return Err(ErrorCode::BadArguments(format!( + "{} value should in range: {:?}", + key, range + ))); + } + } + self.changes.insert(key.to_string(), ChangeValue { level: ScopeLevel::Session, value: UserSettingValue::UInt64(val), diff --git a/tests/sqllogictests/suites/base/06_show/06_0003_show_settings.test b/tests/sqllogictests/suites/base/06_show/06_0003_show_settings.test index e1b67cedd932..a600344b51b8 100644 --- a/tests/sqllogictests/suites/base/06_show/06_0003_show_settings.test +++ b/tests/sqllogictests/suites/base/06_show/06_0003_show_settings.test @@ -95,3 +95,15 @@ query TT select value from system.settings where name = 'query_flight_compression' ---- LZ4 + +statement ok +set max_storage_io_requests = 1000 + +statement error +set max_storage_io_requests = 1025 + +statement ok +set max_threads = 1000 + +statement error +set max_threads = 1025