diff --git a/src/query/service/tests/it/storages/testdata/settings_table.txt b/src/query/service/tests/it/storages/testdata/settings_table.txt index 4ca965c877e7f..0da2b229de652 100644 --- a/src/query/service/tests/it/storages/testdata/settings_table.txt +++ b/src/query/service/tests/it/storages/testdata/settings_table.txt @@ -17,6 +17,7 @@ DB.Table: 'system'.'settings', Table: settings-table_id:1, ver:0, Engine: System | max_block_size | 65536 | 65536 | SESSION | Maximum block size for reading, default value: 65536. | UInt64 | | max_execute_time | 0 | 0 | SESSION | The maximum query execution time. it means no limit if the value is zero. default value: 0. | UInt64 | | max_inlist_to_or | 3 | 3 | SESSION | Max size in inlist expression that will convert to or combinator, default value: 3. | UInt64 | +| max_result_rows | 0 | 0 | SESSION | Auto limit max result rows if user not specify the limit, default is 0 means no limit | UInt64 | | parquet_uncompressed_buffer_size | 2097152 | 2097152 | SESSION | Parquet decompresses buffer size. default: 2MB | UInt64 | | prefer_broadcast_join | 0 | 0 | SESSION | If enable broadcast join, default value: 0 | UInt64 | | quoted_ident_case_sensitive | 1 | 1 | SESSION | Case sensitivity of quoted identifiers, default value: 1 (aka case-sensitive). | UInt64 | diff --git a/src/query/settings/src/lib.rs b/src/query/settings/src/lib.rs index 7a340bf56f721..4534d77d77a2a 100644 --- a/src/query/settings/src/lib.rs +++ b/src/query/settings/src/lib.rs @@ -388,6 +388,13 @@ impl Settings { desc: "the max number of rows each read from parquet to databend processor", possible_values: None, }, + SettingValue { + default_value: UserSettingValue::UInt64(0), + user_setting: UserSetting::create("max_result_rows", UserSettingValue::UInt64(0)), + level: ScopeLevel::Session, + desc: "Auto limit max result rows if user not specify the limit, default is 0 means no limit", + possible_values: None, + }, SettingValue { default_value: UserSettingValue::UInt64(1), user_setting: UserSetting::create( @@ -685,6 +692,12 @@ impl Settings { Ok(v != 0) } + pub fn get_max_result_rows(&self) -> Result { + static KEY: &str = "max_result_rows"; + let v = self.try_get_u64(KEY)?; + Ok(v) + } + pub fn set_enable_distributed_eval_index(&self, val: bool) -> Result<()> { static KEY: &str = "enable_distributed_eval_index"; let v = u64::from(val); diff --git a/src/query/sql/src/planner/binder/select.rs b/src/query/sql/src/planner/binder/select.rs index 1c958c354839a..57531f45605fc 100644 --- a/src/query/sql/src/planner/binder/select.rs +++ b/src/query/sql/src/planner/binder/select.rs @@ -19,6 +19,7 @@ use common_ast::ast::Expr; use common_ast::ast::Join; use common_ast::ast::JoinCondition; use common_ast::ast::JoinOperator; +use common_ast::ast::Literal; use common_ast::ast::OrderByExpr; use common_ast::ast::Query; use common_ast::ast::SelectStmt; @@ -227,6 +228,15 @@ impl<'a> Binder { } }; + let default_limit = if self.ctx.get_settings().get_max_result_rows()? > 0 { + Some(Expr::Literal { + span: &[], + lit: Literal::Integer(self.ctx.get_settings().get_max_result_rows()?), + }) + } else { + None + }; + if !query.limit.is_empty() { if query.limit.len() == 1 { s_expr = self @@ -244,7 +254,11 @@ impl<'a> Binder { } } else if query.offset.is_some() { s_expr = self - .bind_limit(&bind_context, s_expr, None, &query.offset) + .bind_limit(&bind_context, s_expr, default_limit.as_ref(), &query.offset) + .await?; + } else if let Some(l) = default_limit { + s_expr = self + .bind_limit(&bind_context, s_expr, Some(&l), &None) .await?; } diff --git a/tests/sqllogictests/suites/base/20+_others/20_00011_max_result_rows b/tests/sqllogictests/suites/base/20+_others/20_00011_max_result_rows new file mode 100644 index 0000000000000..d6afbb1cc2331 --- /dev/null +++ b/tests/sqllogictests/suites/base/20+_others/20_00011_max_result_rows @@ -0,0 +1,38 @@ +statement ok +DROP DATABASE IF EXISTS db1 + +statement ok +CREATE DATABASE db1 + +statement ok +USE db1 + +statement ok +CREATE TABLE IF NOT EXISTS t1(a INT) Engine = fuse + +statement ok +INSERT INTO t1 (a) values (1), (2), (3) + +query I +SELECT COUNT() FROM (SELECT * FROM t1) +---- +3 + +statement ok +SET max_result_rows=1 + +query I +SELECT COUNT() FROM (SELECT * FROM t1) +---- +1 + +query I +SELECT COUNT() FROM (SELECT * FROM t1 limit 2) +---- +2 + +statement ok +DROP TABLE t1 + +statement ok +DROP DATABASE db1