1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

A fix and test case for Bug#5985 ""prepare stmt from "select rand(?)"

crashes server." The fix makes Item_func_rand prepared-statements
aware plus it fixes the case when RAND is used in prepared
statements and replication is on (as well as several similar issues).
Until now we did not reset THD before every execution of a prepared
statement, so if some execution had set thd->time_zone_used
or thd->rand_used they would not be reset until next mysql_parse.
Some of post-review fixes done.


mysql-test/r/ps.result:
  A test case for Bug#5985: test results fixed.
mysql-test/t/ps.test:
  A test case for Bug#5985 "prepare stmt from "select rand(?)" crashes
  server."
sql/item_func.cc:
  Actual fix for Bug#5985: Item_func_rand rewritten to be 
  prepared statements aware.
sql/item_func.h:
  Actual fix for Bug#5985: Item_func_rand rewritten to be 
  prepared statements aware.
sql/mysql_priv.h:
  We need a separate call to reset THD state before every execute of
  a prepared statement. Otherwise things like THD->user_var_events
  are never cleaned up and bloat binary log (as the list of events
  grows from execution to execution).
sql/sql_class.cc:
  Statement::end_statement -> THD::end_statement()
  (a leftover from some design change which is not to pushed now, but the
  leftover is to be pushed).
sql/sql_class.h:
  Statement::end_statement -> THD::end_statement()
  (a leftover from some design change which is not to pushed now, but the
  leftover is to be pushed).
sql/sql_lex.cc:
  Move the part responsible for initializing LEX from mysql_init_query
  to lex_start.
sql/sql_lex.h:
  All lex-related initialization is now in lex_start.
  Move thd->select_number to lex->select_number to be able to use it
  easily in lex_start.
sql/sql_parse.cc:
  Split mysql_init_query into two functions: mysql_reset_thd_for_next_query,
  which is used in PS and conventional execution, and lex_start, used only
  when we want to parse something.
  Fix init_connect to use initialized THD.
sql/sql_prepare.cc:
  Deploy mysql_reset_thd_for_next_query to reset THD state before
  execution of a prepared statement.
  Normally this should have been added to just one place, but
  we have to reset thd before assigning placeholders from variables,
  thus we can't do that in execute_stmt (yuck).
This commit is contained in:
unknown
2004-10-14 02:53:59 +04:00
parent d007600b9b
commit 54b00f5453
11 changed files with 159 additions and 54 deletions

View File

@ -1001,16 +1001,15 @@ pthread_handler_decl(handle_one_connection,arg)
net->compress=1; // Use compression
thd->version= refresh_version;
thd->proc_info= 0;
thd->set_time();
thd->init_for_queries();
if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL))
{
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->query_error)
thd->killed= 1;
}
thd->proc_info=0;
thd->set_time();
thd->init_for_queries();
while (!net->error && net->vio != 0 && !thd->killed)
{
if (do_command(thd))
@ -3854,7 +3853,6 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
return 0;
}
/****************************************************************************
Initialize global thd variables needed for query
****************************************************************************/
@ -3863,33 +3861,30 @@ void
mysql_init_query(THD *thd, uchar *buf, uint length)
{
DBUG_ENTER("mysql_init_query");
LEX *lex= thd->lex;
lex->unit.init_query();
lex->unit.init_select();
lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
lex->param_list.empty();
lex->unit.next= lex->unit.master=
lex->unit.link_next= lex->unit.return_to=0;
lex->unit.prev= lex->unit.link_prev= 0;
lex->unit.slave= lex->unit.global_parameters= lex->current_select=
lex->all_selects_list= &lex->select_lex;
lex->select_lex.master= &lex->unit;
lex->select_lex.prev= &lex->unit.slave;
lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
lex->select_lex.options=0;
lex->describe= 0;
lex->derived_tables= FALSE;
lex->lock_option= TL_READ;
lex->found_colon= 0;
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
lex_start(thd, buf, length);
thd->select_number= lex->select_lex.select_number= 1;
thd->free_list= 0;
thd->total_warn_count=0; // Warnings for this query
mysql_reset_thd_for_next_command(thd);
DBUG_VOID_RETURN;
}
/*
Reset THD part responsible for command processing state.
DESCRIPTION
This needs to be called before execution of every statement
(prepared or conventional).
TODO
Make it a method of THD and align its name with the rest of
reset/end/start/init methods.
Call it after we use THD for queries, not before.
*/
void mysql_reset_thd_for_next_command(THD *thd)
{
DBUG_ENTER("mysql_reset_thd_for_next_command");
thd->select_number= 1;
thd->total_warn_count= 0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
thd->sent_row_count= thd->examined_row_count= 0;
thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0;