diff --git a/Docs/sp-imp-spec.txt b/Docs/sp-imp-spec.txt index 1303ae19c5c..385625464f1 100644 --- a/Docs/sp-imp-spec.txt +++ b/Docs/sp-imp-spec.txt @@ -243,6 +243,23 @@ 5) On success, set the new values of the OUT and INOUT parameters in the caller's frame. + - USE database + + Before executing the instruction we also keeps the current default + database (if any). If this was changed during execution (i.e. a "USE" + statement has been executed), we restore the current database to the + original. + + This is the most useful way to handle USE in procedures. If we didn't, + the caller would find himself in a different database after calling + a function, which can be confusing. + Restoring the database also gives full freedom to the procedure writer: + - It's possible to write "general" procedures that are independent of + the actual database name. + - It's possible to write procedures that work on a particular database + by calling USE, without having to use fully qualified table names + everywhere (which doesn't help if you want to call other, "general", + procedures anyway). - Evaluating Items @@ -340,6 +357,9 @@ Dropping is done by simply getting the procedure with the sp_find() function and calling sp_drop() (both in sp.{cc,h}). + DROP PROCEDURE/FUNCTION also supports the non-standard "IF EXISTS", + analogous to other DROP statements in MySQL. + - Class and function APIs diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index b188a6ed57d..3fe175b10c3 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -18,6 +18,16 @@ id data foo 42 delete from t1; drop procedure foo42; +create procedure u() +use sptmp; +create database sptmp; +use test; +call u(); +select database(); +database() +test +drop database sptmp; +drop procedure u; create procedure bar(x char(16), y int) insert into test.t1 values (x, y); call bar("bar", 666); diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 0d6a84fa63b..3908561b6b0 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -31,6 +31,18 @@ delete from t1; drop procedure foo42; +# USE test: Make sure we remain in the same DB. +create procedure u() + use sptmp; + +create database sptmp; +use test; +call u(); +select database(); +drop database sptmp; +drop procedure u; + + # Single statement, two IN params. create procedure bar(x char(16), y int) insert into test.t1 values (x, y); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0a232ea5b4a..09c680a0b80 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -131,9 +131,14 @@ int sp_head::execute(THD *thd) { DBUG_ENTER("sp_head::execute"); + char *olddbname; + char *olddbptr= thd->db; int ret= 0; uint ip= 0; + if (olddbptr) + olddbname= my_strdup(olddbptr, MYF(MY_WME)); + do { sp_instr *i; @@ -144,6 +149,16 @@ sp_head::execute(THD *thd) DBUG_PRINT("execute", ("Instruction %u", ip)); ret= i->execute(thd, &ip); } while (ret == 0); + + /* If the DB has changed, the pointer has changed too, but the + original thd->db will then have been freed */ + if (olddbptr && olddbptr != thd->db && olddbname) + { + /* QQ Maybe we should issue some special error message or warning here, + if this fails?? */ + ret= mysql_change_db(thd, olddbname); + my_free(olddbname, MYF(0)); + } DBUG_RETURN(ret); }