diff options
author | dlenev@brandersnatch.localdomain <> | 2005-07-01 13:01:46 +0400 |
---|---|---|
committer | dlenev@brandersnatch.localdomain <> | 2005-07-01 13:01:46 +0400 |
commit | 56ff9f16535d2cb94f6a983b40ed6b6f16e5b370 (patch) | |
tree | f780b41399823750ea4737fc932dfa4c34d0319c | |
parent | f2e358d9dbde3eaf5b62d047b720c078eebbeb41 (diff) | |
download | mariadb-git-56ff9f16535d2cb94f6a983b40ed6b6f16e5b370.tar.gz |
"Fix" for bug #11394 "Recursion in SP crash server" and bug #11600
"Stored procedures: crash with function calling itself".
Disallow recursive stored routines until we either make Item's and LEX
reentrant safe or will use spearate sp_head instances (and thus separate
LEX objects and Item trees) for each routine invocation.
-rw-r--r-- | mysql-test/r/sp-error.result | 40 | ||||
-rw-r--r-- | mysql-test/r/sp.result | 68 | ||||
-rw-r--r-- | mysql-test/t/sp-error.test | 55 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 136 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sp_head.cc | 26 | ||||
-rw-r--r-- | sql/sp_head.h | 3 |
7 files changed, 195 insertions, 135 deletions
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index b6ba737a8ba..814abe4f56d 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -686,3 +686,43 @@ ERROR 0A000: EXECUTE is not allowed in stored procedures create function f() returns int begin execute stmt; ERROR 0A000: EXECUTE is not allowed in stored procedures deallocate prepare stmt; +drop function if exists bug11394| +drop function if exists bug11394_1| +drop function if exists bug11394_2| +drop procedure if exists bug11394| +create function bug11394(i int) returns int +begin +if i <= 0 then +return 0; +else +return (i in (100, 200, bug11394(i-1), 400)); +end if; +end| +select bug11394(2)| +ERROR HY000: Recursive stored routines are not allowed. +drop function bug11394| +create function bug11394_1(i int) returns int +begin +if i <= 0 then +return 0; +else +return (select bug11394_1(i-1)); +end if; +end| +select bug11394_1(2)| +ERROR HY000: Recursive stored routines are not allowed. +drop function bug11394_1| +create function bug11394_2(i int) returns int return i| +select bug11394_2(bug11394_2(10))| +bug11394_2(bug11394_2(10)) +10 +drop function bug11394_2| +create procedure bug11394(i int, j int) +begin +if i > 0 then +call bug11394(i - 1,(select 1)); +end if; +end| +call bug11394(2, 1)| +ERROR HY000: Recursive stored routines are not allowed. +drop procedure bug11394| diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ed858ba27ee..2840e82829c 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1396,60 +1396,6 @@ drop procedure opp| drop procedure ip| show procedure status like '%p%'| Db Name Type Definer Modified Created Security_type Comment -drop table if exists fib| -create table fib ( f bigint unsigned not null )| -drop procedure if exists fib| -create procedure fib(n int unsigned) -begin -if n > 1 then -begin -declare x, y bigint unsigned; -declare c cursor for select f from fib order by f desc limit 2; -open c; -fetch c into y; -fetch c into x; -close c; -insert into fib values (x+y); -call fib(n-1); -end; -end if; -end| -insert into fib values (0), (1)| -call fib(3)| -select * from fib order by f asc| -f -0 -1 -1 -2 -delete from fib| -insert into fib values (0), (1)| -call fib(20)| -select * from fib order by f asc| -f -0 -1 -1 -2 -3 -5 -8 -13 -21 -34 -55 -89 -144 -233 -377 -610 -987 -1597 -2584 -4181 -6765 -drop table fib| -drop procedure fib| drop procedure if exists bar| create procedure bar(x char(16), y int) comment "111111111111" sql security invoker @@ -2506,20 +2452,6 @@ s1 1 drop procedure bug4905| drop table t3| -drop function if exists bug6022| -drop function if exists bug6022| -create function bug6022(x int) returns int -begin -if x < 0 then -return 0; -else -return bug6022(x-1); -end if; -end| -select bug6022(5)| -bug6022(5) -0 -drop function bug6022| drop procedure if exists bug6029| drop procedure if exists bug6029| create procedure bug6029() diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index faf6d8b4de3..ea49aff8bbe 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -986,3 +986,58 @@ create procedure p() execute stmt; create function f() returns int begin execute stmt; deallocate prepare stmt; +# +# Bug #11394 "Recursion in SP crash server" and bug #11600 "Stored +# procedures: crash with function calling itself". +# We have to disable recursion since in many cases LEX and many +# Item's can't be used in reentrant way nowdays. +delimiter |; +--disable_warnings +drop function if exists bug11394| +drop function if exists bug11394_1| +drop function if exists bug11394_2| +drop procedure if exists bug11394| +--enable_warnings +create function bug11394(i int) returns int +begin + if i <= 0 then + return 0; + else + return (i in (100, 200, bug11394(i-1), 400)); + end if; +end| +# If we allow recursive functions without additional modifications +# this will crash server since Item for "IN" is not reenterable. +--error 1423 +select bug11394(2)| +drop function bug11394| +create function bug11394_1(i int) returns int +begin + if i <= 0 then + return 0; + else + return (select bug11394_1(i-1)); + end if; +end| +# The following statement will crash because some LEX members responsible +# for selects cannot be used in reentrant fashion. +--error 1423 +select bug11394_1(2)| +drop function bug11394_1| +# Note that the following should be allowed since it does not contains +# recursion +create function bug11394_2(i int) returns int return i| +select bug11394_2(bug11394_2(10))| +drop function bug11394_2| +create procedure bug11394(i int, j int) +begin + if i > 0 then + call bug11394(i - 1,(select 1)); + end if; +end| +# Again if we allow recursion for stored procedures (without +# additional efforts) the following statement will crash the server. +--error 1423 +call bug11394(2, 1)| +drop procedure bug11394| +delimiter |; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index e7ee4b134ba..4d22f1d4b90 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -1630,54 +1630,56 @@ show procedure status like '%p%'| # Fibonacci, for recursion test. (Yet Another Numerical series :) - ---disable_warnings -drop table if exists fib| ---enable_warnings -create table fib ( f bigint unsigned not null )| - -# We deliberately do it the awkward way, fetching the last two -# values from the table, in order to exercise various statements -# and table accesses at each turn. ---disable_warnings -drop procedure if exists fib| ---enable_warnings -create procedure fib(n int unsigned) -begin - if n > 1 then - begin - declare x, y bigint unsigned; - declare c cursor for select f from fib order by f desc limit 2; - - open c; - fetch c into y; - fetch c into x; - close c; - insert into fib values (x+y); - call fib(n-1); - end; - end if; -end| - -# Minimum test: recursion of 3 levels - -insert into fib values (0), (1)| - -call fib(3)| - -select * from fib order by f asc| - -delete from fib| - -# Original test: 20 levels (may run into memory limits!) - -insert into fib values (0), (1)| - -call fib(20)| - -select * from fib order by f asc| -drop table fib| -drop procedure fib| +# +# This part of test is disabled until we implement support for +# recursive stored procedures. +#--disable_warnings +#drop table if exists fib| +#--enable_warnings +#create table fib ( f bigint unsigned not null )| +# +## We deliberately do it the awkward way, fetching the last two +## values from the table, in order to exercise various statements +## and table accesses at each turn. +#--disable_warnings +#drop procedure if exists fib| +#--enable_warnings +#create procedure fib(n int unsigned) +#begin +# if n > 1 then +# begin +# declare x, y bigint unsigned; +# declare c cursor for select f from fib order by f desc limit 2; +# +# open c; +# fetch c into y; +# fetch c into x; +# close c; +# insert into fib values (x+y); +# call fib(n-1); +# end; +# end if; +#end| +# +## Minimum test: recursion of 3 levels +# +#insert into fib values (0), (1)| +# +#call fib(3)| +# +#select * from fib order by f asc| +# +#delete from fib| +# +## Original test: 20 levels (may run into memory limits!) +# +#insert into fib values (0), (1)| +# +#call fib(20)| +# +#select * from fib order by f asc| +#drop table fib| +#drop procedure fib| # @@ -3011,24 +3013,26 @@ drop table t3| # # BUG#6022: Stored procedure shutdown problem with self-calling function. # ---disable_warnings -drop function if exists bug6022| ---enable_warnings - ---disable_warnings -drop function if exists bug6022| ---enable_warnings -create function bug6022(x int) returns int -begin - if x < 0 then - return 0; - else - return bug6022(x-1); - end if; -end| - -select bug6022(5)| -drop function bug6022| +# This part of test is disabled until we implement support for +# recursive stored functions. +#--disable_warnings +#drop function if exists bug6022| +#--enable_warnings +# +#--disable_warnings +#drop function if exists bug6022| +#--enable_warnings +#create function bug6022(x int) returns int +#begin +# if x < 0 then +# return 0; +# else +# return bug6022(x-1); +# end if; +#end| +# +#select bug6022(5)| +#drop function bug6022| # # BUG#6029: Stored procedure specific handlers should have priority diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7ae5130764f..8230443da48 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5358,3 +5358,5 @@ ER_STMT_HAS_NO_OPEN_CURSOR eng "The statement (%lu) has no open cursor." ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG eng "Explicit or implicit commit is not allowed in stored function or trigger." +ER_SP_NO_RECURSION + eng "Recursive stored routines are not allowed." diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e4dc64c993d..3d5525015c6 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -312,7 +312,8 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), m_returns_cs(NULL), m_has_return(FALSE), - m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE) + m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE), + m_is_invoked(FALSE) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); @@ -587,6 +588,28 @@ sp_head::execute(THD *thd) DBUG_RETURN(-1); } + if (m_is_invoked) + { + /* + We have to disable recursion for stored routines since in + many cases LEX structure and many Item's can't be used in + reentrant way now. + + TODO: We can circumvent this problem by using separate + sp_head instances for each recursive invocation. + + NOTE: Theoretically arguments of procedure can be evaluated + before its invocation so there should be no problem with + recursion. But since we perform cleanup for CALL statement + as for any other statement only after its execution, its LEX + structure is not reusable for recursive calls. Thus we have + to prohibit recursion for stored procedures too. + */ + my_error(ER_SP_NO_RECURSION, MYF(0)); + DBUG_RETURN(-1); + } + m_is_invoked= TRUE; + dbchanged= FALSE; if (m_db.length && (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged))) @@ -704,6 +727,7 @@ sp_head::execute(THD *thd) if (! thd->killed) ret= sp_change_db(thd, olddb, 0); } + m_is_invoked= FALSE; DBUG_RETURN(ret); } diff --git a/sql/sp_head.h b/sql/sp_head.h index aaef5a3d50e..39b0c1394fe 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -259,6 +259,9 @@ private: */ HASH m_sptabs; + /* Used for tracking of routine invocations and preventing recursion. */ + bool m_is_invoked; + int execute(THD *thd); |