1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Fix for BUG#25843: changing default database between PREPARE and EXECUTE

of statement breaks binlog.

There were two problems discovered by this bug:

  1. Default (current) database is not fixed at the creation time.
     That leads to wrong output of DATABASE() function.

  2. Database attributes (@@collation_database) are not fixed at
     the creation time. That leads to wrong resultset.

Binlog breakage and Query Cache wrong output happened because of
the first problem.

The fix is to remember the current database at the PREPARE-time and
set it each time at EXECUTE.
This commit is contained in:
anozdrin/alik@ibm.opbmk
2007-08-31 20:42:14 +04:00
parent f141ba5e26
commit d6f94b062c
13 changed files with 891 additions and 153 deletions

View File

@@ -2868,6 +2868,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
init_param_array(this);
lex->set_trg_event_type_for_tables();
/* Remember the current database. */
if (thd->db && thd->db_length)
{
db= this->strmake(thd->db, thd->db_length);
db_length= thd->db_length;
}
else
{
db= NULL;
db_length= 0;
}
/*
While doing context analysis of the query (in check_prepared_statement)
we allocate a lot of additional memory: for open tables, JOINs, derived
@@ -2974,6 +2987,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Query_arena *old_stmt_arena;
bool error= TRUE;
char saved_cur_db_name_buf[NAME_LEN+1];
LEX_STRING saved_cur_db_name=
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
bool cur_db_changed;
LEX_STRING stmt_db_name= { db, db_length };
status_var_increment(thd->status_var.com_stmt_execute);
/* Check if we got an error when sending long data */
@@ -3022,6 +3042,21 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
*/
thd->set_n_backup_statement(this, &stmt_backup);
/*
Change the current database (if needed).
Force switching, because the database of the prepared statement may be
NULL (prepared statements can be created while no current database
selected).
*/
if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE,
&cur_db_changed))
goto error;
/* Allocate query. */
if (expanded_query->length() &&
alloc_query(thd, (char*) expanded_query->ptr(),
expanded_query->length()+1))
@@ -3050,6 +3085,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
thd->protocol= protocol; /* activate stmt protocol */
/* Go! */
if (open_cursor)
error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
&result, &cursor);
@@ -3068,6 +3105,17 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
}
}
/*
Restore the current database (if changed).
Force switching back to the saved current database (if changed),
because it may be NULL. In this case, mysql_change_db() would generate
an error.
*/
if (cur_db_changed)
mysql_change_db(thd, &saved_cur_db_name, TRUE);
thd->protocol= &thd->protocol_text; /* use normal protocol */
/* Assert that if an error, no cursor is open */