diff --git a/client/mysqltest.c b/client/mysqltest.c index 8e72bc8edb8..ca4d9319707 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -66,7 +66,8 @@ #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif -#define MAX_QUERY 131072 +/* MAX_QUERY is 256K -- there is a test in sp-big that is >128K */ +#define MAX_QUERY (256*1024) #define MAX_VAR_NAME 256 #define MAX_COLUMNS 256 #define PAD_SIZE 128 diff --git a/mysql-test/r/sp-big.result b/mysql-test/r/sp-big.result new file mode 100644 index 00000000000..004ff586aab --- /dev/null +++ b/mysql-test/r/sp-big.result @@ -0,0 +1,15 @@ +drop procedure if exists test.longprocedure; +drop table if exists t1; +create table t1 (a int); +insert into t1 values (1),(2),(3); +length +107520 +select length(routine_definition) from information_schema.routines where routine_schema = 'test' and routine_name = 'longprocedure'; +length(routine_definition) +107530 +call test.longprocedure(@value); +select @value; +@value +3 +drop procedure test.longprocedure; +drop table t1; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 277115733d4..d2872878cb9 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -172,7 +172,7 @@ proc CREATE TABLE `proc` ( `security_type` enum('INVOKER','DEFINER') NOT NULL default 'DEFINER', `param_list` blob NOT NULL, `returns` char(64) NOT NULL default '', - `body` blob NOT NULL, + `body` longblob NOT NULL, `definer` char(77) character set utf8 collate utf8_bin NOT NULL default '', `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `modified` timestamp NOT NULL default '0000-00-00 00:00:00', diff --git a/mysql-test/t/sp-big.test b/mysql-test/t/sp-big.test new file mode 100644 index 00000000000..769d77dbef9 --- /dev/null +++ b/mysql-test/t/sp-big.test @@ -0,0 +1,33 @@ +# +# Bug #11602: SP with very large body not handled well +# + +--disable_warnings +drop procedure if exists test.longprocedure; +drop table if exists t1; +--enable_warnings + +create table t1 (a int); +insert into t1 values (1),(2),(3); + +let $body=`select repeat('select count(*) into out1 from t1;\n', 3072)`; + +delimiter //; +--disable_query_log +eval select length('$body') as length// +eval create procedure test.longprocedure (out out1 int) deterministic +begin + $body +end// +--enable_query_log + +delimiter ;// + +# this is larger than the length above, because it includes the 'begin' and +# 'end' bits and some whitespace +select length(routine_definition) from information_schema.routines where routine_schema = 'test' and routine_name = 'longprocedure'; + +call test.longprocedure(@value); select @value; + +drop procedure test.longprocedure; +drop table t1; diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index a3036b5c10b..383f8b80dc8 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -683,7 +683,7 @@ then c_p="$c_p security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL," c_p="$c_p param_list blob DEFAULT '' NOT NULL," c_p="$c_p returns char(64) DEFAULT '' NOT NULL," - c_p="$c_p body blob DEFAULT '' NOT NULL," + c_p="$c_p body longblob DEFAULT '' NOT NULL," c_p="$c_p definer char(77) collate utf8_bin DEFAULT '' NOT NULL," c_p="$c_p created timestamp," c_p="$c_p modified timestamp," diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index b93e0a47b1b..f67bab44514 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -426,7 +426,7 @@ CREATE TABLE IF NOT EXISTS proc ( security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob DEFAULT '' NOT NULL, returns char(64) DEFAULT '' NOT NULL, - body blob DEFAULT '' NOT NULL, + body longblob DEFAULT '' NOT NULL, definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, @@ -477,6 +477,7 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL, 'READS_SQL_DATA', 'MODIFIES_SQL_DATA' ) DEFAULT 'CONTAINS_SQL' NOT NULL, + MODIFY body longblob DEFAULT '' NOT NULL, MODIFY sql_mode set('REAL_AS_FLOAT', 'PIPES_AS_CONCAT', diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 459560ccac8..5dd5cd9c775 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5386,3 +5386,5 @@ ER_TRG_IN_WRONG_SCHEMA eng "Trigger in wrong schema" ER_STACK_OVERRUN_NEED_MORE eng "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use 'mysqld -O thread_stack=#' to specify a bigger stack." +ER_TOO_LONG_BODY 42000 S1009 + eng "Routine body for '%-.100s' is too long" diff --git a/sql/sp.cc b/sql/sp.cc index dec0eee0095..dfe3493528f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -503,6 +503,11 @@ db_create_routine(THD *thd, int type, sp_head *sp) ret= SP_BAD_IDENTIFIER; goto done; } + if (sp->m_body.length > table->field[MYSQL_PROC_FIELD_BODY]->field_length) + { + ret= SP_BODY_TOO_LONG; + goto done; + } table->field[MYSQL_PROC_FIELD_DB]-> store(sp->m_db.str, sp->m_db.length, system_charset_info); table->field[MYSQL_PROC_FIELD_NAME]-> diff --git a/sql/sp.h b/sql/sp.h index b8af8d3a321..86351f61de9 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -29,6 +29,7 @@ #define SP_INTERNAL_ERROR -7 #define SP_NO_DB_ERROR -8 #define SP_BAD_IDENTIFIER -9 +#define SP_BODY_TOO_LONG -10 /* Drop all routines in database 'db' */ int diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f1950d36b23..bf33f841eb8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4107,6 +4107,12 @@ end_with_restore_list: delete lex->sphead; lex->sphead= 0; goto error; + case SP_BODY_TOO_LONG: + my_error(ER_TOO_LONG_BODY, MYF(0), name); + lex->unit.cleanup(); + delete lex->sphead; + lex->sphead= 0; + goto error; default: my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); lex->unit.cleanup();