List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:March 23 2007 2:33pm
Subject:bk commit into 5.0 tree (anozdrin:1.2489) BUG#25082
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-03-23 16:33:31+03:00, anozdrin@stripped +8 -0
  Fix BUG#25082: default database change on trigger execution
  breaks replication.
  
  Basically, the problem was that we could not switch back to
  the database that does not exist anymore.
  
  The fix is to always succeed changing database if we are called
  from stored-routine execution.

  mysql-test/r/sp.result@stripped, 2007-03-23 16:33:27+03:00, anozdrin@stripped +15 -0
    Updated result file.

  mysql-test/t/sp.test@stripped, 2007-03-23 16:33:27+03:00, anozdrin@stripped +41 -0
    Added test case for BUG#25082.

  sql/mysql_priv.h@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +4 -3
    1. Change mysql_change_db() prototype;
    2. Polishing.

  sql/sp.cc@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +3 -3
    Polishing.

  sql/sp_head.cc@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +1 -1
    Polishing.

  sql/sql_db.cc@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +219 -112
    1. Polishing.
    2. Fix mysql_change_db().

  sql/sql_parse.cc@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +15 -9
    Polishing.

  sql/sql_show.cc@stripped, 2007-03-23 16:33:28+03:00, anozdrin@stripped +11 -10
    Polishing.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	anozdrin
# Host:	booka.opbmk
# Root:	/home/alik/Documents/MySQL/devel/5.0-marvel-25082

--- 1.438/sql/mysql_priv.h	2007-03-16 11:47:51 +03:00
+++ 1.439/sql/mysql_priv.h	2007-03-23 16:33:28 +03:00
@@ -695,7 +695,8 @@
 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);
@@ -939,7 +940,7 @@
 
 
 /* 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);
@@ -957,7 +958,7 @@
 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 */
 

--- 1.134/sql/sql_db.cc	2006-12-23 22:04:27 +03:00
+++ 1.135/sql/sql_db.cc	2007-03-23 16:33:28 +03:00
@@ -461,7 +461,7 @@
   DBUG_ENTER("mysql_create_db");
 
   /* do not create 'information_schema' db */
-  if (!my_strcasecmp(system_charset_info, db, information_schema_name.str))
+  if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
   {
     my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
     DBUG_RETURN(-1);
@@ -1126,154 +1126,261 @@
 }
 
 
-/*
-  Change the current database.
+/**
+  @brief Internal implementation: switch current database to a valid one.
 
-  SYNOPSIS
-    mysql_change_db()
-    thd			thread handle
-    name		database name
-    no_access_check	if TRUE, don't do access check. In this
-                        case name may be ""
-
-  DESCRIPTION
-    Check that the database name corresponds to a valid and
-    existent database, check access rights (unless called with
-    no_access_check), and set the current database. This function
-    is called to change the current database upon user request
-    (COM_CHANGE_DB command) or temporarily, to execute a stored
-    routine.
-
-  NOTES
-    This function is not the only way to switch the database that
-    is currently employed. When the replication slave thread
-    switches the database before executing a query, it calls
-    thd->set_db directly. However, if the query, in turn, uses
-    a stored routine, the stored routine will use this function,
-    even if it's run on the slave.
-
-    This function allocates the name of the database on the system
-    heap: this is necessary to be able to uniformly change the
-    database from any module of the server. Up to 5.0 different
-    modules were using different memory to store the name of the
-    database, and this led to memory corruption: a stack pointer
-    set by Stored Procedures was used by replication after the
-    stack address was long gone.
-
-    This function does not send anything, including error
-    messages, to the client. If that should be sent to the client,
-    call net_send_error after this function.
-
-  RETURN VALUES
-    0	OK
-    1	error
+  @param thd            Thread context.
+  @param new_db_name    Name of the database to switch to. The function will
+                        take ownership of the name (the caller must not free
+                        the allocated memory). If the name is NULL, we're
+                        going to switch to NULL db.
+  @param new_db_access  Privileges of the new database.
+  @param new_db_charset Character set of the new database.
+*/
+
+static void mysql_change_db_impl(THD *thd,
+                                 LEX_STRING *new_db_name,
+                                 ulong new_db_access,
+                                 CHARSET_INFO *new_db_charset)
+{
+  /* 1. Change current database in THD. */
+
+  if (new_db_name == NULL)
+  {
+    /*
+      THD::set_db() does all the job -- it frees previous database name and
+      sets the new one.
+    */
+
+    thd->set_db(NULL, 0);
+  }
+  else if (new_db_name == &INFORMATION_SCHEMA_NAME)
+  {
+    /*
+      Here we must use THD::set_db(), because we want to copy
+      INFORMATION_SCHEMA_NAME constant.
+    */
+
+    thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
+  }
+  else
+  {
+    /*
+      Here we already have a copy of database name to be used in THD. So,
+      we just call THD::reset_db(). Since THD::reset_db() does not releases
+      the previous database name, we should do it explicitly.
+    */
+
+    x_free(thd->db);
+
+    thd->reset_db(new_db_name->str, new_db_name->length);
+  }
+
+  /* 2. Update security context. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+  thd->security_ctx->db_access= new_db_access;
+#endif
+
+  /* 3. Update db-charset environment variables. */
+
+  thd->db_charset= new_db_charset;
+  thd->variables.collation_database= new_db_charset;
+
+  /*
+  */
+}
+
+
+/**
+  @brief Change the current database.
+
+  @param thd          thread handle
+  @param name         database name
+  @param force_switch if this flag is set (TRUE), mysql_change_db() will
+                      switch to NULL db if the specified database is not
+                      available anymore. Corresponding warning will be
+                      thrown in this case. This flag is used to change
+                      database in stored-routine-execution code.
+
+  @details Check that the database name corresponds to a valid and existent
+  database, check access rights (unless called with no_access_check), and
+  set the current database. This function is called to change the current
+  database upon user request (COM_CHANGE_DB command) or temporarily, to
+  execute a stored routine.
+
+  This function is not the only way to switch the database that is
+  currently employed. When the replication slave thread switches the
+  database before executing a query, it calls thd->set_db directly.
+  However, if the query, in turn, uses a stored routine, the stored routine
+  will use this function, even if it's run on the slave.
+
+  This function allocates the name of the database on the system heap: this
+  is necessary to be able to uniformly change the database from any module
+  of the server. Up to 5.0 different modules were using different memory to
+  store the name of the database, and this led to memory corruption:
+  a stack pointer set by Stored Procedures was used by replication after
+  the stack address was long gone.
+
+  @return Operation status
+    @retval FALSE Success
+    @retval TRUE  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)
 {
-  int db_length;
-  char *db_name;
-  bool system_db= 0;
+  LEX_STRING new_db_file_name;
+
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-  ulong db_access;
   Security_context *sctx= thd->security_ctx;
-  LINT_INIT(db_access);
+  ulong db_access= sctx->db_access;
 #endif
+
   DBUG_ENTER("mysql_change_db");
-  DBUG_PRINT("enter",("name: '%s'",name));
+  DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
 
-  if (name == NULL || name[0] == '\0' && no_access_check == FALSE)
+  if (new_db_name == NULL ||
+      new_db_name->length == 0 ||
+      new_db_name->str == NULL)
   {
-    my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-    DBUG_RETURN(1);				/* purecov: inspected */
+    if (force_switch)
+    {
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                          ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR));
+
+      /* Change db to NULL. */
+
+      mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+      DBUG_RETURN(FALSE);
+    }
+    else
+    {
+      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+
+      DBUG_RETURN(TRUE);
+    }
   }
-  else if (name[0] == '\0')
+
+  if (my_strcasecmp(system_charset_info, new_db_name->str,
+                    INFORMATION_SCHEMA_NAME.str) == 0)
   {
-    /* Called from SP to restore the original database, which was NULL */
-    DBUG_ASSERT(no_access_check);
-    system_db= 1;
-    db_name= NULL;
-    db_length= 0;
-    goto end;
+    /* Switch database to INFORMATION_SCHEMA. */
+
+    mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
+                         system_charset_info);
+
+    DBUG_RETURN(FALSE);
   }
+
   /*
     Now we need to make a copy because check_db_name requires a
-    non-constant argument. TODO: fix check_db_name.
+    non-constant argument. Actually, it takes database file name.
+
+    TODO: fix check_db_name().
   */
-  if ((db_name= my_strdup(name, MYF(MY_WME))) == NULL)
-    DBUG_RETURN(1);                             /* the error is set */
-  db_length= strlen(db_name);
-  if (check_db_name(db_name))
-  {
-    my_error(ER_WRONG_DB_NAME, MYF(0), db_name);
-    my_free(db_name, MYF(0));
-    DBUG_RETURN(1);
-  }
-  DBUG_PRINT("info",("Use database: %s", db_name));
-  if (!my_strcasecmp(system_charset_info, db_name, information_schema_name.str))
+
+  new_db_file_name.str= my_strdup(new_db_name->str, MYF(MY_WME));
+  new_db_file_name.length= new_db_name->length;
+
+  if (new_db_file_name.str == NULL)
+    DBUG_RETURN(TRUE);                             /* the error is set */
+
+  /*
+    NOTE: if check_db_name() fails, we should throw an error in any case,
+    even if we are called from sp_head::execute().
+
+    It's next to impossible however to get this error when we are called
+    from sp_head::execute(). But let's switch database to NULL in this case
+    to be sure.
+  */
+
+  if (check_db_name(new_db_file_name.str))
   {
-    system_db= 1;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-    db_access= SELECT_ACL;
-#endif
-    goto end;
+    my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
+    my_free(new_db_file_name.str, MYF(0));
+
+    if (force_switch)
+    {
+      /* Change db to NULL. */
+
+      mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+    }
+
+    DBUG_RETURN(TRUE);
   }
 
+  DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
+
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-  if (!no_access_check)
+  if (!force_switch) /* FIXME: this is BUG#27337. */
   {
-    if (test_all_bits(sctx->master_access, DB_ACLS))
-      db_access=DB_ACLS;
-    else
-      db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) |
-                  sctx->master_access);
-    if (!(db_access & DB_ACLS) && (!grant_option ||
-                                   check_grant_db(thd,db_name)))
+    db_access=
+      test_all_bits(sctx->master_access, DB_ACLS) ?
+      DB_ACLS :
+      acl_get(sctx->host,
+              sctx->ip,
+              sctx->priv_user,
+              new_db_file_name.str,
+              FALSE) | sctx->master_access;
+
+    if (!force_switch &&
+        !(db_access & DB_ACLS) &&
+        (!grant_option || check_grant_db(thd, new_db_file_name.str)))
     {
       my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                sctx->priv_user,
                sctx->priv_host,
-               db_name);
+               new_db_file_name.str);
       mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
-                      sctx->priv_user, sctx->priv_host, db_name);
-      my_free(db_name, MYF(0));
-      DBUG_RETURN(1);
+                      sctx->priv_user, sctx->priv_host, new_db_file_name.str);
+      my_free(new_db_file_name.str, MYF(0));
+      DBUG_RETURN(TRUE);
     }
   }
 #endif
 
-  if (check_db_dir_existence(db_name))
+  if (check_db_dir_existence(new_db_file_name.str))
   {
-    my_error(ER_BAD_DB_ERROR, MYF(0), db_name);
-    my_free(db_name, MYF(0));
-    DBUG_RETURN(1);
-  }
+    if (force_switch)
+    {
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                          ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
+                          new_db_file_name.str);
 
-end:
-  x_free(thd->db);
-  DBUG_ASSERT(db_name == NULL || db_name[0] != '\0');
-  thd->reset_db(db_name, db_length);            // THD::~THD will free this
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-  if (!no_access_check)
-    sctx->db_access= db_access;
-#endif
-  if (system_db)
-  {
-    thd->db_charset= system_charset_info;
-    thd->variables.collation_database= system_charset_info;
+      my_free(new_db_file_name.str, MYF(0));
+
+      /* Change db to NULL. */
+
+      mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+      DBUG_RETURN(FALSE);
+    }
+    else
+    {
+      my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
+      my_free(new_db_file_name.str, MYF(0));
+      DBUG_RETURN(TRUE);
+    }
   }
-  else
+
+  /*
+    NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
+    attributes and will be freed in THD::~THD().
+  */
+
   {
-    HA_CREATE_INFO create;
+    HA_CREATE_INFO db_options;
 
-    load_db_opt_by_name(thd, db_name, &create);
+    load_db_opt_by_name(thd, new_db_name->str, &db_options);
 
-    thd->db_charset= create.default_table_charset ?
-      create.default_table_charset :
-      thd->variables.collation_server;
-    thd->variables.collation_database= thd->db_charset;
+    mysql_change_db_impl(thd, &new_db_file_name, db_access,
+                         db_options.default_table_charset ?
+                         db_options.default_table_charset :
+                         thd->variables.collation_server);
   }
-  DBUG_RETURN(0);
+
+  DBUG_RETURN(FALSE);
 }
 
 

--- 1.612/sql/sql_parse.cc	2007-03-16 10:55:14 +03:00
+++ 1.613/sql/sql_parse.cc	2007-03-23 16:33:28 +03:00
@@ -289,7 +289,8 @@
 	       bool check_count)
 {
   DBUG_ENTER("check_user");
-  
+  LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
+
 #ifdef NO_EMBEDDED_ACCESS_CHECKS
   thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
   /* Change database if necessary */
@@ -300,7 +301,7 @@
       function returns 0
     */
     thd->reset_db(NULL, 0);
-    if (mysql_change_db(thd, db, FALSE))
+    if (mysql_change_db(thd, &db_str, FALSE))
     {
       /* Send the error to the client */
       net_send_error(thd);
@@ -442,7 +443,7 @@
       /* Change database if necessary */
       if (db && db[0])
       {
-        if (mysql_change_db(thd, db, FALSE))
+        if (mysql_change_db(thd, &db_str, FALSE))
         {
           /* Send error to the client */
           net_send_error(thd);
@@ -1635,7 +1636,7 @@
 			&LOCK_status);
     thd->convert_string(&tmp, system_charset_info,
 			packet, strlen(packet), thd->charset());
-    if (!mysql_change_db(thd, tmp.str, FALSE))
+    if (!mysql_change_db(thd, &tmp, FALSE))
     {
       mysql_log.write(thd,command,"%s",thd->db);
       send_ok(thd);
@@ -1859,7 +1860,7 @@
     packet= pend+1;
 
     if (!my_strcasecmp(system_charset_info, table_list.db,
-                       information_schema_name.str))
+                       INFORMATION_SCHEMA_NAME.str))
     {
       ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
       if (schema_table)
@@ -3750,9 +3751,14 @@
     }
 #endif
   case SQLCOM_CHANGE_DB:
-    if (!mysql_change_db(thd,select_lex->db,FALSE))
+  {
+    LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };
+
+    if (!mysql_change_db(thd, &db_str, FALSE))
       send_ok(thd);
+
     break;
+  }
 
   case SQLCOM_LOAD:
   {
@@ -5428,7 +5434,7 @@
       if (!no_errors)
         my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                  sctx->priv_user, sctx->priv_host,
-                 information_schema_name.str);
+                 INFORMATION_SCHEMA_NAME.str);
       return TRUE;
     }
     /*
@@ -6248,7 +6254,7 @@
   ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
   ptr->derived=	    table->sel;
   if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
-                                      information_schema_name.str))
+                                      INFORMATION_SCHEMA_NAME.str))
   {
     ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
     if (!schema_table ||
@@ -6256,7 +6262,7 @@
          lex->orig_sql_command == SQLCOM_END))  // not a 'show' command
     {
       my_error(ER_UNKNOWN_TABLE, MYF(0),
-               ptr->table_name, information_schema_name.str);
+               ptr->table_name, INFORMATION_SCHEMA_NAME.str);
       DBUG_RETURN(0);
     }
     ptr->schema_table_name= ptr->table_name;

--- 1.342/sql/sql_show.cc	2007-03-14 12:54:19 +03:00
+++ 1.343/sql/sql_show.cc	2007-03-23 16:33:28 +03:00
@@ -495,9 +495,9 @@
   }
 #endif
   if (!my_strcasecmp(system_charset_info, dbname,
-                     information_schema_name.str))
+                     INFORMATION_SCHEMA_NAME.str))
   {
-    dbname= information_schema_name.str;
+    dbname= INFORMATION_SCHEMA_NAME.str;
     create.default_table_charset= system_charset_info;
   }
   else
@@ -1822,7 +1822,8 @@
 
 
 /* INFORMATION_SCHEMA name */
-LEX_STRING information_schema_name= {(char*)"information_schema", 18};
+LEX_STRING INFORMATION_SCHEMA_NAME=
+  { (char *) STRING_WITH_LEN("information_schema") };
 
 /* This is only used internally, but we need it here as a forward reference */
 extern ST_SCHEMA_TABLE schema_tables[];
@@ -2038,11 +2039,11 @@
     */
     if (!idx_field_vals->db_value ||
         !wild_case_compare(system_charset_info, 
-                           information_schema_name.str,
+                           INFORMATION_SCHEMA_NAME.str,
                            idx_field_vals->db_value))
     {
       *with_i_schema= 1;
-      if (files->push_back(thd->strdup(information_schema_name.str)))
+      if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
         return 1;
     }
     return (find_files(thd, files, NullS, mysql_data_home,
@@ -2057,11 +2058,11 @@
   */
   if (lex->orig_sql_command != SQLCOM_END)
   {
-    if (!my_strcasecmp(system_charset_info, information_schema_name.str,
+    if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str,
                        idx_field_vals->db_value))
     {
       *with_i_schema= 1;
-      return files->push_back(thd->strdup(information_schema_name.str));
+      return files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str));
     }
     return files->push_back(thd->strdup(idx_field_vals->db_value));
   }
@@ -2070,7 +2071,7 @@
     Create list of existing databases. It is used in case
     of select from information schema table
   */
-  if (files->push_back(thd->strdup(information_schema_name.str)))
+  if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
     return 1;
   *with_i_schema= 1;
   return (find_files(thd, files, NullS,
@@ -3926,8 +3927,8 @@
      We have to make non const db_name & table_name
      because of lower_case_table_names
   */
-  make_lex_string(thd, &db, information_schema_name.str,
-                  information_schema_name.length, 0);
+  make_lex_string(thd, &db, INFORMATION_SCHEMA_NAME.str,
+                  INFORMATION_SCHEMA_NAME.length, 0);
   make_lex_string(thd, &table, schema_table->table_name,
                   strlen(schema_table->table_name), 0);
   if (schema_table->old_format(thd, schema_table) ||   /* Handle old syntax */

--- 1.221/mysql-test/r/sp.result	2007-03-08 20:34:05 +03:00
+++ 1.222/mysql-test/r/sp.result	2007-03-23 16:33:27 +03:00
@@ -5778,4 +5778,19 @@
 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;

--- 1.211/mysql-test/t/sp.test	2007-03-08 20:29:57 +03:00
+++ 1.212/mysql-test/t/sp.test	2007-03-23 16:33:27 +03:00
@@ -6753,6 +6753,47 @@
 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!

--- 1.127/sql/sp.cc	2007-01-22 15:10:40 +03:00
+++ 1.128/sql/sp.cc	2007-03-23 16:33:28 +03:00
@@ -441,14 +441,14 @@
   {
     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 @@
     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.237/sql/sp_head.cc	2007-03-15 11:51:33 +03:00
+++ 1.238/sql/sp_head.cc	2007-03-23 16:33:28 +03:00
@@ -1130,7 +1130,7 @@
       (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",
Thread
bk commit into 5.0 tree (anozdrin:1.2489) BUG#25082Alexander Nozdrin23 Mar