From 7f595e0bcd96c9a480d5cb72302c2b727944162f Mon Sep 17 00:00:00 2001 From: Facebook Github Bot Date: Mon, 15 Apr 2019 10:30:36 -0700 Subject: [PATCH] [mysql-5.6][PR] FB8-78: Add filesort_max_file_size option Summary: Jira issue: https://jira.percona.com/browse/FB8-78 Reference Patch: https://github.com/facebook/mysql-5.6/commit/11ef068 Add the filesort_max_file_size variable setting which specifies the maximum number of bytes a filesort file can take. If it is exceeded, then the query fails. This is very similar to the tmp_table_max_file_size variable. Pull Request resolved: https://github.com/facebook/mysql-5.6/pull/993 GitHub Author: Manuel Ung Test Plan: main.max_filesort_size Reviewers: Subscribers: butterflybot, vinaybhat, webscalesql-eng@fb.com Differential Revision: https://phabricator.intern.facebook.com/D14652353 Tasks: Tags: Blame Revision: --- mysql-test/r/all_persisted_variables.result | 8 +- mysql-test/r/max_filesort_size.result | 90 +++++++++ mysql-test/r/mysqld--help-notwin.result | 4 + .../r/filesort_max_file_size_basic.result | 118 +++++++++++ .../t/filesort_max_file_size_basic.test | 186 ++++++++++++++++++ mysql-test/t/all_persisted_variables.test | 2 +- mysql-test/t/max_filesort_size.test | 71 +++++++ share/errmsg-utf8.txt | 4 +- sql/filesort.cc | 16 +- sql/sql_sort.h | 4 + sql/sys_vars.cc | 7 + sql/system_variables.h | 1 + 12 files changed, 503 insertions(+), 8 deletions(-) create mode 100644 mysql-test/r/max_filesort_size.result create mode 100644 mysql-test/suite/sys_vars/r/filesort_max_file_size_basic.result create mode 100644 mysql-test/suite/sys_vars/t/filesort_max_file_size_basic.test create mode 100644 mysql-test/t/max_filesort_size.test diff --git a/mysql-test/r/all_persisted_variables.result b/mysql-test/r/all_persisted_variables.result index 446dc41e71d6..afe655d4555e 100644 --- a/mysql-test/r/all_persisted_variables.result +++ b/mysql-test/r/all_persisted_variables.result @@ -44,7 +44,7 @@ include/assert.inc ['Expect 500+ variables in the table. Due to open Bugs, we ar # Test SET PERSIST -include/assert.inc ['Expect 397 persisted variables in the table. Due to open Bugs, we are checking for 391'] +include/assert.inc ['Expect 398 persisted variables in the table. Due to open Bugs, we are checking for 392'] ************************************************************ * 3. Restart server, it must preserve the persisted variable @@ -52,9 +52,9 @@ include/assert.inc ['Expect 397 persisted variables in the table. Due to open Bu ************************************************************ # restart -include/assert.inc ['Expect 391 persisted variables in persisted_variables table.'] -include/assert.inc ['Expect 391 persisted variables shown as PERSISTED in variables_info table.'] -include/assert.inc ['Expect 391 persisted variables with matching peristed and global values.'] +include/assert.inc ['Expect 392 persisted variables in persisted_variables table.'] +include/assert.inc ['Expect 392 persisted variables shown as PERSISTED in variables_info table.'] +include/assert.inc ['Expect 392 persisted variables with matching peristed and global values.'] ************************************************************ * 4. Test RESET PERSIST IF EXISTS. Verify persisted variable diff --git a/mysql-test/r/max_filesort_size.result b/mysql-test/r/max_filesort_size.result new file mode 100644 index 000000000000..135be2b308ff --- /dev/null +++ b/mysql-test/r/max_filesort_size.result @@ -0,0 +1,90 @@ +set @save_filesort_max_file_size = @@global.filesort_max_file_size; +create table t1 (i int, c char(255)); +insert into t1 values (0, lpad('a', 250, 'b')); +insert into t1 select i+1,c from t1; +insert into t1 select i+2,c from t1; +insert into t1 select i+4,c from t1; +insert into t1 select i+8,c from t1; +insert into t1 select i+16,c from t1; +insert into t1 select i+32,c from t1; +insert into t1 select i+64,c from t1; +insert into t1 select i+128,c from t1; +insert into t1 select i+256,c from t1; +insert into t1 select i+512,c from t1; +insert into t1 select i+1024,c from t1; +insert into t1 select i+2048,c from t1; +Query is OK when there is no limit +show variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show session variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show global variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +explain select i, c from t1 order by hex(c) limit 1 offset 4000; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 4096 100.00 Using filesort +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by hex(`test`.`t1`.`c`) limit 4000,1 +select i, c from t1 order by hex(c) limit 1 offset 4000; +i c +2102 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba +select /*+ SET_VAR(filesort_max_file_size = 1000000) */ i, c from t1 order by hex(c) limit 1 offset 4000; +ERROR HY000: Filesort file is too big +Query fails with a limit +set session filesort_max_file_size=1000000; +show variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 1000000 +show session variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 1000000 +show global variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +select i, c from t1 order by hex(c) limit 1 offset 4000; +ERROR HY000: Filesort file is too big +Query is OK when another session has a limit +show variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show session variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show global variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +select i, c from t1 order by hex(c) limit 1 offset 4000; +i c +2102 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba +Query is OK when session limit is reset +set session filesort_max_file_size=0; +show variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show session variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +show global variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 0 +select i, c from t1 order by hex(c) limit 1 offset 4000; +i c +2102 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbba +Query fails when global limit is set +set global filesort_max_file_size=1000000; +show variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 1000000 +show session variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 1000000 +show global variables like "filesort_max_file_size"; +Variable_name Value +filesort_max_file_size 1000000 +select i, c from t1 order by hex(c) limit 1 offset 4000; +ERROR HY000: Filesort file is too big +drop table t1; +set @@global.filesort_max_file_size = @save_filesort_max_file_size; diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 847dc4a2ec41..2c2a8aa89afe 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -326,6 +326,9 @@ The following options may be given as the first argument: With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking. + --filesort-max-file-size=# + The max size of a file to use for filesort. Raise an + error when this is exceeded. 0 means no limit. --flush Flush MyISAM tables to disk between SQL commands --flush-time=# A dedicated thread is created to flush all tables at the given interval @@ -1496,6 +1499,7 @@ event-scheduler ON expire-logs-days 0 explicit-defaults-for-timestamp TRUE external-locking FALSE +filesort-max-file-size 0 flush FALSE flush-time 0 ft-boolean-syntax + -><()~*:""&| diff --git a/mysql-test/suite/sys_vars/r/filesort_max_file_size_basic.result b/mysql-test/suite/sys_vars/r/filesort_max_file_size_basic.result new file mode 100644 index 000000000000..510addb17e5d --- /dev/null +++ b/mysql-test/suite/sys_vars/r/filesort_max_file_size_basic.result @@ -0,0 +1,118 @@ +SET @start_global_value = @@global.filesort_max_file_size; +'#--------------------FN_DYNVARS_005_01-------------------------#' +SET @@global.filesort_max_file_size = 100; +SET @@global.filesort_max_file_size = DEFAULT; +SET @@session.filesort_max_file_size = 200; +SET @@session.filesort_max_file_size = DEFAULT; +'#--------------------FN_DYNVARS_005_02-------------------------#' +SELECT @@global.filesort_max_file_size = 0; +@@global.filesort_max_file_size = 0 +1 +SELECT @@session.filesort_max_file_size = 0; +@@session.filesort_max_file_size = 0 +1 +'#--------------------FN_DYNVARS_005_03-------------------------#' +SET @@global.filesort_max_file_size = 1024; +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +1024 +SET @@global.filesort_max_file_size = 60020; +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +60020 +SET @@global.filesort_max_file_size = 4294967295; +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +4294967295 +'#--------------------FN_DYNVARS_005_04-------------------------#' +SET @@session.filesort_max_file_size = 1024; +SELECT @@session.filesort_max_file_size; +@@session.filesort_max_file_size +1024 +SET @@session.filesort_max_file_size = 4294967295; +SELECT @@session.filesort_max_file_size; +@@session.filesort_max_file_size +4294967295 +SET @@session.filesort_max_file_size = 65535; +SELECT @@session.filesort_max_file_size; +@@session.filesort_max_file_size +65535 +'#------------------FN_DYNVARS_005_05-----------------------#' +SET @@global.filesort_max_file_size = -1024; +Warnings: +Warning 1292 Truncated incorrect filesort_max_file_size value: '-1024' +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +0 +SET @@global.filesort_max_file_size = ON; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@global.filesort_max_file_size = OFF; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@global.filesort_max_file_size = True; +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +1 +SET @@global.filesort_max_file_size = False; +SELECT @@global.filesort_max_file_size; +@@global.filesort_max_file_size +0 +SET @@global.filesort_max_file_size = 65530.34; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@global.filesort_max_file_size ="Test"; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@session.filesort_max_file_size = ON; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@session.filesort_max_file_size = OFF; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@session.filesort_max_file_size = True; +SELECT @@session.filesort_max_file_size; +@@session.filesort_max_file_size +1 +SET @@session.filesort_max_file_size = False; +SELECT @@session.filesort_max_file_size; +@@session.filesort_max_file_size +0 +SET @@session.filesort_max_file_size = "Test"; +ERROR 42000: Incorrect argument type to variable 'filesort_max_file_size' +SET @@session.filesort_max_file_size = 12345678901; +SELECT @@session.filesort_max_file_size IN (12345678901,4294967295); +@@session.filesort_max_file_size IN (12345678901,4294967295) +1 +'#------------------FN_DYNVARS_005_06-----------------------#' +SELECT @@global.filesort_max_file_size = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='filesort_max_file_size'; +@@global.filesort_max_file_size = VARIABLE_VALUE +1 +'#------------------FN_DYNVARS_005_07-----------------------#' +SELECT @@session.filesort_max_file_size = VARIABLE_VALUE +FROM performance_schema.session_variables +WHERE VARIABLE_NAME='filesort_max_file_size'; +@@session.filesort_max_file_size = VARIABLE_VALUE +1 +'#---------------------FN_DYNVARS_001_09----------------------#' +SET @@global.filesort_max_file_size = 1024; +SET @@filesort_max_file_size = 4294967295; +SELECT @@filesort_max_file_size = @@global.filesort_max_file_size; +@@filesort_max_file_size = @@global.filesort_max_file_size +0 +'#---------------------FN_DYNVARS_001_10----------------------#' +SET @@filesort_max_file_size = 100; +SELECT @@filesort_max_file_size = @@local.filesort_max_file_size; +@@filesort_max_file_size = @@local.filesort_max_file_size +1 +SELECT @@local.filesort_max_file_size = @@session.filesort_max_file_size; +@@local.filesort_max_file_size = @@session.filesort_max_file_size +1 +'#---------------------FN_DYNVARS_001_11----------------------#' +SET filesort_max_file_size = 1027; +SELECT @@filesort_max_file_size; +@@filesort_max_file_size +1027 +SELECT local.filesort_max_file_size; +ERROR 42S02: Unknown table 'local' in field list +SELECT global.filesort_max_file_size; +ERROR 42S02: Unknown table 'global' in field list +SELECT filesort_max_file_size = @@session.filesort_max_file_size; +ERROR 42S22: Unknown column 'filesort_max_file_size' in 'field list' +SET @@global.filesort_max_file_size = @start_global_value; diff --git a/mysql-test/suite/sys_vars/t/filesort_max_file_size_basic.test b/mysql-test/suite/sys_vars/t/filesort_max_file_size_basic.test new file mode 100644 index 000000000000..047b3e6ef5a4 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/filesort_max_file_size_basic.test @@ -0,0 +1,186 @@ +####################### filesort_max_file_size_basic.test ##################### +# # +# Variable Name: filesort_max_file_size # +# Scope: GLOBAL | SESSION # +# Access Type: Dynamic # +# Data Type: numeric # +# Default Value: 0 # +# Range: 0-system depended # +# # +# # +# Creation Date: 2016-08-24 # +# Author: mung # +# # +# Description: Test Cases of Dynamic System Variable filesort_max_file_size # +# that checks the behavior of this variable in the following ways # +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +################################################################################ + +--source include/load_sysvars.inc + +############################################################## +# START OF filesort_max_file_size TESTS # +############################################################## + +############################################################# +# Save initial value # +############################################################# + +SET @start_global_value = @@global.filesort_max_file_size; + +--echo '#--------------------FN_DYNVARS_005_01-------------------------#' +############################################################## +# Display the DEFAULT value of filesort_max_file_size # +############################################################## + +SET @@global.filesort_max_file_size = 100; +SET @@global.filesort_max_file_size = DEFAULT; + +SET @@session.filesort_max_file_size = 200; +SET @@session.filesort_max_file_size = DEFAULT; + +--echo '#--------------------FN_DYNVARS_005_02-------------------------#' +######################################################################## +# Check the DEFAULT value of filesort_max_file_size # +######################################################################## +SELECT @@global.filesort_max_file_size = 0; + +SELECT @@session.filesort_max_file_size = 0; + +--echo '#--------------------FN_DYNVARS_005_03-------------------------#' +################################################################################# +# Change the value of filesort_max_file_size to a valid value for GLOBAL Scope # +################################################################################# + +SET @@global.filesort_max_file_size = 1024; +SELECT @@global.filesort_max_file_size; +SET @@global.filesort_max_file_size = 60020; +SELECT @@global.filesort_max_file_size; +SET @@global.filesort_max_file_size = 4294967295; +SELECT @@global.filesort_max_file_size; + +--echo '#--------------------FN_DYNVARS_005_04-------------------------#' +################################################################################## +# Change the value of filesort_max_file_size to a valid value for SESSION Scope # +################################################################################## + +SET @@session.filesort_max_file_size = 1024; +SELECT @@session.filesort_max_file_size; + +SET @@session.filesort_max_file_size = 4294967295; +SELECT @@session.filesort_max_file_size; +SET @@session.filesort_max_file_size = 65535; +SELECT @@session.filesort_max_file_size; + +--echo '#------------------FN_DYNVARS_005_05-----------------------#' +################################################################### +# Change the value of filesort_max_file_size to an invalid value # +################################################################### + +SET @@global.filesort_max_file_size = -1024; +SELECT @@global.filesort_max_file_size; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.filesort_max_file_size = ON; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.filesort_max_file_size = OFF; + +SET @@global.filesort_max_file_size = True; +SELECT @@global.filesort_max_file_size; + +SET @@global.filesort_max_file_size = False; +SELECT @@global.filesort_max_file_size; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.filesort_max_file_size = 65530.34; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.filesort_max_file_size ="Test"; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@session.filesort_max_file_size = ON; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@session.filesort_max_file_size = OFF; + +SET @@session.filesort_max_file_size = True; +SELECT @@session.filesort_max_file_size; + +SET @@session.filesort_max_file_size = False; +SELECT @@session.filesort_max_file_size; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@session.filesort_max_file_size = "Test"; + +SET @@session.filesort_max_file_size = 12345678901; +# With a 64 bit mysqld:12345678901,with a 32 bit mysqld: 4294967295 +SELECT @@session.filesort_max_file_size IN (12345678901,4294967295); + +--echo '#------------------FN_DYNVARS_005_06-----------------------#' +#################################################################### +# Check if the value in GLOBAL Table matches value in variable # +#################################################################### + +SELECT @@global.filesort_max_file_size = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='filesort_max_file_size'; + +--echo '#------------------FN_DYNVARS_005_07-----------------------#' +#################################################################### +# Check if the value in SESSION Table matches value in variable # +#################################################################### + +SELECT @@session.filesort_max_file_size = VARIABLE_VALUE +FROM performance_schema.session_variables +WHERE VARIABLE_NAME='filesort_max_file_size'; + +--echo '#---------------------FN_DYNVARS_001_09----------------------#' +######################################################################## +# Check if global and session variables are independent of each other # +######################################################################## + +SET @@global.filesort_max_file_size = 1024; +SET @@filesort_max_file_size = 4294967295; +SELECT @@filesort_max_file_size = @@global.filesort_max_file_size; + +--echo '#---------------------FN_DYNVARS_001_10----------------------#' +################################################################## +# Check if accessing variable with SESSION,LOCAL and without # +# SCOPE points to same session variable # +################################################################## + +SET @@filesort_max_file_size = 100; +SELECT @@filesort_max_file_size = @@local.filesort_max_file_size; +SELECT @@local.filesort_max_file_size = @@session.filesort_max_file_size; + +--echo '#---------------------FN_DYNVARS_001_11----------------------#' +############################################################################# +# Check if filesort_max_file_size can be accessed with and without @@ sign # +############################################################################# + +SET filesort_max_file_size = 1027; +SELECT @@filesort_max_file_size; + +--Error ER_UNKNOWN_TABLE +SELECT local.filesort_max_file_size; + +--Error ER_UNKNOWN_TABLE +SELECT global.filesort_max_file_size; + +--Error ER_BAD_FIELD_ERROR +SELECT filesort_max_file_size = @@session.filesort_max_file_size; + +#################################### +# Restore initial value # +#################################### + +SET @@global.filesort_max_file_size = @start_global_value; + +################################################### +# END OF filesort_max_file_size TESTS # +################################################### diff --git a/mysql-test/t/all_persisted_variables.test b/mysql-test/t/all_persisted_variables.test index 8235df1346d6..f360dfe89253 100644 --- a/mysql-test/t/all_persisted_variables.test +++ b/mysql-test/t/all_persisted_variables.test @@ -39,7 +39,7 @@ --source include/have_binlog_format_row.inc let $total_global_vars=`SELECT COUNT(*) FROM performance_schema.global_variables where variable_name NOT LIKE 'ndb_%'`; -let $total_persistent_vars=397; +let $total_persistent_vars=398; # Due to open bugs, there are fewer variables --let $total_persistent_vars_sans_bugs=`SELECT $total_persistent_vars - 6;` diff --git a/mysql-test/t/max_filesort_size.test b/mysql-test/t/max_filesort_size.test new file mode 100644 index 000000000000..1254d17fc3ff --- /dev/null +++ b/mysql-test/t/max_filesort_size.test @@ -0,0 +1,71 @@ +--source include/count_sessions.inc + +set @save_filesort_max_file_size = @@global.filesort_max_file_size; + +create table t1 (i int, c char(255)); + +insert into t1 values (0, lpad('a', 250, 'b')); +insert into t1 select i+1,c from t1; +insert into t1 select i+2,c from t1; +insert into t1 select i+4,c from t1; +insert into t1 select i+8,c from t1; +insert into t1 select i+16,c from t1; +insert into t1 select i+32,c from t1; +insert into t1 select i+64,c from t1; +insert into t1 select i+128,c from t1; +insert into t1 select i+256,c from t1; +insert into t1 select i+512,c from t1; +insert into t1 select i+1024,c from t1; +insert into t1 select i+2048,c from t1; + +echo Query is OK when there is no limit; +show variables like "filesort_max_file_size"; +show session variables like "filesort_max_file_size"; +show global variables like "filesort_max_file_size"; +explain select i, c from t1 order by hex(c) limit 1 offset 4000; +select i, c from t1 order by hex(c) limit 1 offset 4000; +--error ER_FILESORT_MAX_FILE_SIZE_EXCEEDED +select /*+ SET_VAR(filesort_max_file_size = 1000000) */ i, c from t1 order by hex(c) limit 1 offset 4000; + +echo Query fails with a limit; +set session filesort_max_file_size=1000000; +show variables like "filesort_max_file_size"; +show session variables like "filesort_max_file_size"; +show global variables like "filesort_max_file_size"; +--error ER_FILESORT_MAX_FILE_SIZE_EXCEEDED +select i, c from t1 order by hex(c) limit 1 offset 4000; + +echo Query is OK when another session has a limit; +connect (root,localhost,root,,test); +show variables like "filesort_max_file_size"; +show session variables like "filesort_max_file_size"; +show global variables like "filesort_max_file_size"; +select i, c from t1 order by hex(c) limit 1 offset 4000; + +connection default; +disconnect root; + +echo Query is OK when session limit is reset; +set session filesort_max_file_size=0; +show variables like "filesort_max_file_size"; +show session variables like "filesort_max_file_size"; +show global variables like "filesort_max_file_size"; +select i, c from t1 order by hex(c) limit 1 offset 4000; + +echo Query fails when global limit is set; +set global filesort_max_file_size=1000000; +connect (root,localhost,root,,test); +show variables like "filesort_max_file_size"; +show session variables like "filesort_max_file_size"; +show global variables like "filesort_max_file_size"; +--error ER_FILESORT_MAX_FILE_SIZE_EXCEEDED +select i, c from t1 order by hex(c) limit 1 offset 4000; + +connection default; +disconnect root; + +drop table t1; + +set @@global.filesort_max_file_size = @save_filesort_max_file_size; + +--source include/wait_until_count_sessions.inc diff --git a/share/errmsg-utf8.txt b/share/errmsg-utf8.txt index a2741abc9b68..5804d5255354 100644 --- a/share/errmsg-utf8.txt +++ b/share/errmsg-utf8.txt @@ -18570,8 +18570,8 @@ ER_PLACEHOLDER_50035 ER_CONNECTION_TIMEOUT eng "Closed connection: idle timeout after %us" -ER_PLACEHOLDER_50037 - eng "Placeholder" +ER_FILESORT_MAX_FILE_SIZE_EXCEEDED + eng "Filesort file is too big" ER_PLACEHOLDER_50038 eng "Placeholder" diff --git a/sql/filesort.cc b/sql/filesort.cc index f696b4980a7b..10b70280f6c9 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -395,6 +395,9 @@ bool filesort(THD *thd, Filesort *filesort, bool sort_positions, sort_positions); table->sort.addon_fields = param.addon_fields; +#ifndef DBUG_OFF + table->sort.file_size_exceeded = false; +#endif /* DBUG_OFF */ /* TODO: Now that we read from RowIterators, the situation is a lot more @@ -589,7 +592,8 @@ bool filesort(THD *thd, Filesort *filesort, bool sort_positions, } } if (error) { - DBUG_ASSERT(thd->is_error() || thd->killed); + DBUG_ASSERT(thd->is_error() || thd->killed || + table->sort.file_size_exceeded); /* Guard against Bug#11745656 -- KILL QUERY should not send "server shutdown" @@ -1119,6 +1123,7 @@ static ha_rows read_all_rows( static int write_keys(Sort_param *param, Filesort_info *fs_info, uint count, IO_CACHE *chunk_file, IO_CACHE *tempfile) { + THD *thd = current_thd; Merge_chunk merge_chunk; DBUG_ENTER("write_keys"); @@ -1151,6 +1156,15 @@ static int write_keys(Sort_param *param, Filesort_info *fs_info, uint count, if (my_b_write(tempfile, record, rec_length)) DBUG_RETURN(1); /* purecov: inspected */ + + if (thd->variables.filesort_max_file_size > 0 && + tempfile->pos_in_file > thd->variables.filesort_max_file_size) { +#ifndef DBUG_OFF + fs_info->file_size_exceeded = true; +#endif /* DBUG_OFF */ + my_error(ER_FILESORT_MAX_FILE_SIZE_EXCEEDED, MYF(0)); + DBUG_RETURN(1); + } } if (my_b_write(chunk_file, &merge_chunk, sizeof(merge_chunk))) diff --git a/sql/sql_sort.h b/sql/sql_sort.h index e814b163ab86..cb6cf4c8be91 100644 --- a/sql/sql_sort.h +++ b/sql/sql_sort.h @@ -170,6 +170,10 @@ class Filesort_info { Filesort_buffer filesort_buffer; public: +#ifndef DBUG_OFF + bool file_size_exceeded; /* If filesort exceeded max file size */ +#endif /* DBUG_OFF */ + Merge_chunk_array merge_chunks; ///< Array of chunk descriptors Addon_fields *addon_fields{nullptr}; ///< Addon field descriptors. diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 592831f1c609..738becce192d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4150,6 +4150,13 @@ static Sys_var_ulong Sys_sort_buffer( VALID_RANGE(MIN_SORT_MEMORY, ULONG_MAX), DEFAULT(DEFAULT_SORT_MEMORY), BLOCK_SIZE(1)); +static Sys_var_ulonglong Sys_filesort_max_file_size( + "filesort_max_file_size", + "The max size of a file to use for filesort. Raise an error " + "when this is exceeded. 0 means no limit.", + HINT_UPDATEABLE SESSION_VAR(filesort_max_file_size), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1)); + /** Check sql modes strict_mode, 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' are used together. If only subset of it diff --git a/sql/system_variables.h b/sql/system_variables.h index 8c7af5dba76d..b9f5caf3692d 100644 --- a/sql/system_variables.h +++ b/sql/system_variables.h @@ -202,6 +202,7 @@ struct System_variables { uint dynamic_variables_size; /* how many bytes are in use */ LIST *dynamic_variables_allocs; /* memory hunks for PLUGIN_VAR_MEMALLOC */ + ulonglong filesort_max_file_size; ulonglong max_heap_table_size; ulonglong tmp_table_size; ulonglong long_query_time;