Commit 6a594ffd authored by unknown's avatar unknown
Browse files

Fix for BUG#25082: default database change on trigger

execution breaks replication.

When a stored routine is executed, we switch current
database to the database, in which the routine
has been created. When the stored routine finishes,
we switch back to the original database.

The problem was that if the original database does not
exist (anymore) after routine execution, we raised an error.

The fix is to report a warning, and switch to the NULL database.


mysql-test/r/sp.result:
  Updated result file.
mysql-test/t/sp.test:
  Added test case for BUG#25082.
sql/mysql_priv.h:
  1. Change mysql_change_db() prototype;
  2. Polishing.
sql/sp.cc:
  Polishing.
sql/sp_head.cc:
  Polishing.
sql/sql_db.cc:
  1. Polishing.
  2. Fix mysql_change_db().
sql/sql_parse.cc:
  Polishing.
sql/sql_show.cc:
  Polishing.
parent 21af9a55
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -5969,6 +5969,21 @@ SUM(f2) bug25373(f1)
21.300000071526	NULL
DROP FUNCTION bug25373|
DROP TABLE t3|
DROP DATABASE IF EXISTS mysqltest1|
DROP DATABASE IF EXISTS mysqltest2|
CREATE DATABASE mysqltest1|
CREATE DATABASE mysqltest2|
CREATE PROCEDURE mysqltest1.p1()
DROP DATABASE mysqltest2|
use mysqltest2|
CALL mysqltest1.p1()|
Warnings:
Note	1049	Unknown database 'mysqltest2'
SELECT DATABASE()|
DATABASE()
NULL
DROP DATABASE mysqltest1|
use test|
drop table t1,t2;
CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM;
CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb;
+41 −0
Original line number Diff line number Diff line
@@ -6929,6 +6929,47 @@ INSERT INTO t3 VALUES (1, 3.4), (1, 2), (1, 0.9), (2, 8), (2, 7)|
SELECT SUM(f2), bug25373(f1) FROM t3 GROUP BY bug25373(f1) WITH ROLLUP|
DROP FUNCTION bug25373|
DROP TABLE t3|


#
# BUG#25082: Default database change on trigger execution breaks replication.
#
# As it turned out, this bug has actually two bugs. So, here we have two test
# cases -- one in sp.test, the other in sp-security.test.
#

#
# Test case 1: error on dropping the current database.
#

# Prepare.

--disable_warnings
DROP DATABASE IF EXISTS mysqltest1|
DROP DATABASE IF EXISTS mysqltest2|
--enable_warnings

CREATE DATABASE mysqltest1|
CREATE DATABASE mysqltest2|

# Test.

CREATE PROCEDURE mysqltest1.p1()
  DROP DATABASE mysqltest2|

use mysqltest2|

CALL mysqltest1.p1()|

SELECT DATABASE()|

# Cleanup.

DROP DATABASE mysqltest1|

use test|


#
# NOTE: The delimiter is `|`, and not `;`. It is changed to `;`
#       at the end of the file!
+4 −3
Original line number Diff line number Diff line
@@ -693,7 +693,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
                      char *new_table_name, char *new_table_alias,
                      bool skip_error);
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
                     bool force_switch);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
@@ -937,7 +938,7 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,


/* information schema */
extern LEX_STRING information_schema_name;
extern LEX_STRING INFORMATION_SCHEMA_NAME;
LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
                            const char* str, uint length,
                            bool allocate_lex_string);
@@ -955,7 +956,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
bool get_schema_tables_result(JOIN *join,
                              enum enum_schema_table_state executed_place);
#define is_schema_db(X) \
  !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
  !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X))

/* sql_prepare.cc */

+3 −3
Original line number Diff line number Diff line
@@ -441,14 +441,14 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
  {
    sp_head *sp= newlex.sphead;

    if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
    if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
      goto end;
    delete sp;
    ret= SP_PARSE_ERROR;
  }
  else
  {
    if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
    if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
      goto end;
    *sphp= newlex.sphead;
    (*sphp)->set_definer(&definer_user_name, &definer_host_name);
@@ -1896,7 +1896,7 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
    DBUG_RETURN(0);
  }

  ret= mysql_change_db(thd, new_db.str, no_access_check);
  ret= mysql_change_db(thd, &new_db, no_access_check);

  *dbchangedp= ret == 0;
  DBUG_RETURN(ret);
+1 −1
Original line number Diff line number Diff line
@@ -1130,7 +1130,7 @@ sp_head::execute(THD *thd)
      (It would generate an error from mysql_change_db() when old_db=="")
    */
    if (! thd->killed)
      err_status|= mysql_change_db(thd, old_db.str, 1);
      err_status|= mysql_change_db(thd, &old_db, TRUE);
  }
  m_flags&= ~IS_INVOKED;
  DBUG_PRINT("info",
Loading