mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Merge zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.1-comeng-unification
into zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.1-recentcommmerge BitKeeper/deleted/.del-ha_berkeley.cc: Auto merged BitKeeper/deleted/.del-mysqld.vcproj~6aa7b3f9c3e28fcb: Auto merged BitKeeper/triggers/post-commit: Auto merged client/mysqlcheck.c: Auto merged include/config-win.h: Auto merged include/my_dbug.h: Auto merged libmysqld/Makefile.am: Auto merged mysql-test/r/func_in.result: Auto merged mysql-test/r/information_schema.result: Auto merged mysql-test/r/information_schema_db.result: Auto merged mysql-test/t/func_in.test: Auto merged mysql-test/t/information_schema.test: Auto merged sql/Makefile.am: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_func.cc: Auto merged sql/lock.cc: Auto merged sql/log_event.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.h: Auto merged sql/sp_head.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_view.cc: Auto merged sql/structs.h: Auto merged sql/table.h: Auto merged storage/archive/ha_archive.cc: Auto merged storage/myisam/ha_myisam.cc: Auto merged storage/myisam/mi_open.c: Auto merged storage/myisammrg/ha_myisammrg.cc: Auto merged storage/ndb/src/common/util/File.cpp: Auto merged configure.in: Manual merge. sql/CMakeLists.txt: Manual merge. sql/mysql_priv.h: Manual merge. sql/mysqld.cc: Manual merge. sql/set_var.cc: Manual merge. sql/slave.cc: Manual merge. sql/sql_cache.cc: Manual merge. sql/sql_class.cc: Manual merge. sql/sql_lex.h: Manual merge. sql/sql_parse.cc: Manual merge. sql/sql_select.cc: Manual merge. sql/sql_show.cc: Manual merge. sql/sql_table.cc: Manual merge. sql/sql_update.cc: Manual merge. sql/sql_yacc.yy: Manual merge.
This commit is contained in:
@@ -112,7 +112,6 @@ public:
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
@class Prepared_statement
|
||||
@brief Prepared_statement: a statement that can contain placeholders
|
||||
*/
|
||||
|
||||
@@ -229,7 +228,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
|
||||
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
|
||||
{
|
||||
NET *net= &stmt->thd->net;
|
||||
char buff[12];
|
||||
uchar buff[12];
|
||||
uint tmp;
|
||||
DBUG_ENTER("send_prep_stmt");
|
||||
|
||||
@@ -572,6 +571,8 @@ void set_param_date(Item_param *param, uchar **pos, ulong len)
|
||||
static void set_param_str(Item_param *param, uchar **pos, ulong len)
|
||||
{
|
||||
ulong length= get_param_length(pos, len);
|
||||
if (length > len)
|
||||
length= len;
|
||||
param->set_str((const char *)*pos, length);
|
||||
*pos+= length;
|
||||
}
|
||||
@@ -742,6 +743,8 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
|
||||
if (read_pos >= data_end)
|
||||
DBUG_RETURN(1);
|
||||
param->set_param_func(param, &read_pos, data_end - read_pos);
|
||||
if (param->state == Item_param::NO_VALUE)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
res= param->query_val_str(&str);
|
||||
@@ -778,6 +781,8 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
|
||||
if (read_pos >= data_end)
|
||||
DBUG_RETURN(1);
|
||||
param->set_param_func(param, &read_pos, data_end - read_pos);
|
||||
if (param->state == Item_param::NO_VALUE)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if (param->convert_str_value(stmt->thd))
|
||||
@@ -860,6 +865,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
|
||||
client_param->length ?
|
||||
*client_param->length :
|
||||
client_param->buffer_length);
|
||||
if (param->state == Item_param::NO_VALUE)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if (param->convert_str_value(thd))
|
||||
@@ -902,6 +909,8 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt,
|
||||
client_param->length ?
|
||||
*client_param->length :
|
||||
client_param->buffer_length);
|
||||
if (param->state == Item_param::NO_VALUE)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
res= param->query_val_str(&str);
|
||||
@@ -946,7 +955,7 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
|
||||
Item_param *param= *it;
|
||||
varname= var_it++;
|
||||
entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
|
||||
(byte*) varname->str,
|
||||
(uchar*) varname->str,
|
||||
varname->length);
|
||||
if (param->set_from_user_var(stmt->thd, entry) ||
|
||||
param->convert_str_value(stmt->thd))
|
||||
@@ -981,6 +990,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||
String buf;
|
||||
const String *val;
|
||||
uint32 length= 0;
|
||||
THD *thd= stmt->thd;
|
||||
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
@@ -991,34 +1001,20 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||
{
|
||||
Item_param *param= *it;
|
||||
varname= var_it++;
|
||||
if (get_var_with_binlog(stmt->thd, stmt->lex->sql_command,
|
||||
*varname, &entry))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (param->set_from_user_var(stmt->thd, entry))
|
||||
entry= (user_var_entry *) hash_search(&thd->user_vars, (uchar*) varname->str,
|
||||
varname->length);
|
||||
/*
|
||||
We have to call the setup_one_conversion_function() here to set
|
||||
the parameter's members that might be needed further
|
||||
(e.g. value.cs_info.character_set_client is used in the query_val_str()).
|
||||
*/
|
||||
setup_one_conversion_function(thd, param, param->param_type);
|
||||
if (param->set_from_user_var(thd, entry))
|
||||
DBUG_RETURN(1);
|
||||
/* Insert @'escaped-varname' instead of parameter in the query */
|
||||
if (entry)
|
||||
{
|
||||
char *start, *ptr;
|
||||
buf.length(0);
|
||||
if (buf.reserve(entry->name.length*2+3))
|
||||
DBUG_RETURN(1);
|
||||
val= param->query_val_str(&buf);
|
||||
|
||||
start= ptr= buf.c_ptr_quick();
|
||||
*ptr++= '@';
|
||||
*ptr++= '\'';
|
||||
ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci,
|
||||
ptr, 0, entry->name.str,
|
||||
entry->name.length);
|
||||
*ptr++= '\'';
|
||||
buf.length(ptr - start);
|
||||
val= &buf;
|
||||
}
|
||||
else
|
||||
val= &my_null_string;
|
||||
|
||||
if (param->convert_str_value(stmt->thd))
|
||||
if (param->convert_str_value(thd))
|
||||
DBUG_RETURN(1); /* out of memory */
|
||||
|
||||
if (query->replace(param->pos_in_query+length, 1, *val))
|
||||
@@ -1077,7 +1073,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
|
||||
if (table_list->table)
|
||||
{
|
||||
// don't allocate insert_values
|
||||
table_list->table->insert_values=(byte *)1;
|
||||
table_list->table->insert_values=(uchar *)1;
|
||||
}
|
||||
|
||||
if (mysql_prepare_insert(thd, table_list, table_list->table,
|
||||
@@ -1164,8 +1160,9 @@ static int mysql_test_update(Prepared_statement *stmt,
|
||||
goto error;
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/* TABLE_LIST contain right privilages request */
|
||||
want_privilege= table_list->grant.want_privilege;
|
||||
/* Force privilege re-checking for views after they have been opened. */
|
||||
want_privilege= (table_list->view ? UPDATE_ACL :
|
||||
table_list->grant.want_privilege);
|
||||
#endif
|
||||
|
||||
if (mysql_prepare_update(thd, table_list, &select->where,
|
||||
@@ -1492,8 +1489,21 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
|
||||
|
||||
if (select_lex->item_list.elements)
|
||||
{
|
||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
lex->link_first_table_back(create_table, link_to_local);
|
||||
create_table->create= TRUE;
|
||||
}
|
||||
|
||||
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||
create_table= lex->unlink_first_table(&link_to_local);
|
||||
|
||||
select_lex->context.resolve_in_select_list= TRUE;
|
||||
res= select_like_stmt_test_with_open(stmt, tables, 0, 0);
|
||||
|
||||
res= select_like_stmt_test(stmt, 0, 0);
|
||||
}
|
||||
|
||||
/* put tables back for PS rexecuting */
|
||||
@@ -1590,7 +1600,7 @@ static bool mysql_insert_select_prepare_tester(THD *thd)
|
||||
next_local;
|
||||
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
first_select->table_list.first= (byte *) second_table;
|
||||
first_select->table_list.first= (uchar *) second_table;
|
||||
thd->lex->select_lex.context.table_list=
|
||||
thd->lex->select_lex.context.first_name_resolution_table= second_table;
|
||||
|
||||
@@ -1621,7 +1631,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
|
||||
if (tables->table)
|
||||
{
|
||||
// don't allocate insert_values
|
||||
tables->table->insert_values=(byte *)1;
|
||||
tables->table->insert_values=(uchar *)1;
|
||||
}
|
||||
|
||||
if (insert_precheck(stmt->thd, tables))
|
||||
@@ -1636,7 +1646,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
|
||||
&mysql_insert_select_prepare_tester,
|
||||
OPTION_SETUP_TABLES_DONE);
|
||||
/* revert changes made by mysql_insert_select_prepare_tester */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table;
|
||||
lex->select_lex.table_list.first= (uchar*) first_local_table;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1715,6 +1725,13 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
||||
res= mysql_test_create_table(stmt);
|
||||
break;
|
||||
|
||||
case SQLCOM_CREATE_VIEW:
|
||||
if (lex->create_view_mode == VIEW_ALTER)
|
||||
{
|
||||
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case SQLCOM_DO:
|
||||
res= mysql_test_do_fields(stmt, tables, lex->insert_list);
|
||||
break;
|
||||
@@ -1751,6 +1768,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
||||
case SQLCOM_SHOW_CREATE_PROC:
|
||||
case SQLCOM_SHOW_CREATE_FUNC:
|
||||
case SQLCOM_SHOW_CREATE_EVENT:
|
||||
case SQLCOM_SHOW_CREATE_TRIGGER:
|
||||
case SQLCOM_SHOW_CREATE:
|
||||
case SQLCOM_SHOW_PROC_CODE:
|
||||
case SQLCOM_SHOW_FUNC_CODE:
|
||||
@@ -1768,7 +1786,6 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
||||
case SQLCOM_ROLLBACK:
|
||||
case SQLCOM_TRUNCATE:
|
||||
case SQLCOM_CALL:
|
||||
case SQLCOM_CREATE_VIEW:
|
||||
case SQLCOM_DROP_VIEW:
|
||||
case SQLCOM_REPAIR:
|
||||
case SQLCOM_ANALYZE:
|
||||
@@ -1794,6 +1811,9 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
||||
case SQLCOM_KILL:
|
||||
break;
|
||||
|
||||
case SQLCOM_PREPARE:
|
||||
case SQLCOM_EXECUTE:
|
||||
case SQLCOM_DEALLOCATE_PREPARE:
|
||||
default:
|
||||
/*
|
||||
Trivial check of all status commands. This is easier than having
|
||||
@@ -1920,13 +1940,6 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
|
||||
/* Statement map deletes statement on erase */
|
||||
thd->stmt_map.erase(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *format= "[%lu] %.*b";
|
||||
general_log_print(thd, COM_STMT_PREPARE, format, stmt->id,
|
||||
stmt->query_length, stmt->query);
|
||||
|
||||
}
|
||||
/* check_prepared_statemnt sends the metadata packet in case of success */
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -1970,7 +1983,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
|
||||
*/
|
||||
if ((entry=
|
||||
(user_var_entry*)hash_search(&thd->user_vars,
|
||||
(byte*)lex->prepared_stmt_code.str,
|
||||
(uchar*)lex->prepared_stmt_code.str,
|
||||
lex->prepared_stmt_code.length))
|
||||
&& entry->value)
|
||||
{
|
||||
@@ -1999,7 +2012,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
|
||||
|
||||
len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
|
||||
var_value->length());
|
||||
if (!(query_str= alloc_root(thd->mem_root, len+1)))
|
||||
if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
|
||||
goto end;
|
||||
|
||||
if (needs_conversion)
|
||||
@@ -2312,12 +2325,6 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
||||
test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
if (error == 0)
|
||||
{
|
||||
const char *format= "[%lu] %.*b";
|
||||
general_log_print(thd, COM_STMT_EXECUTE, format, stmt->id,
|
||||
thd->query_length, thd->query);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
@@ -2355,7 +2362,7 @@ void mysql_sql_stmt_execute(THD *thd)
|
||||
/* Query text for binary, general or slow log, if any of them is open */
|
||||
String expanded_query;
|
||||
DBUG_ENTER("mysql_sql_stmt_execute");
|
||||
DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str));
|
||||
DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
|
||||
|
||||
if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
|
||||
{
|
||||
@@ -2416,7 +2423,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
|
||||
|
||||
/* First of all clear possible warnings from the previous command */
|
||||
mysql_reset_thd_for_next_command(thd);
|
||||
statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
|
||||
status_var_increment(thd->status_var.com_stmt_fetch);
|
||||
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
@@ -2480,7 +2487,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
|
||||
/* First of all clear possible warnings from the previous command */
|
||||
mysql_reset_thd_for_next_command(thd);
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
|
||||
status_var_increment(thd->status_var.com_stmt_reset);
|
||||
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
@@ -2543,7 +2550,8 @@ void mysql_sql_stmt_close(THD *thd)
|
||||
{
|
||||
Prepared_statement* stmt;
|
||||
LEX_STRING *name= &thd->lex->prepared_stmt_name;
|
||||
DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name->length, name->str));
|
||||
DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
|
||||
name->str));
|
||||
|
||||
if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
|
||||
{
|
||||
@@ -2584,7 +2592,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
|
||||
#endif
|
||||
DBUG_ENTER("mysql_stmt_get_longdata");
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
|
||||
status_var_increment(thd->status_var.com_stmt_send_long_data);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
/* Minimal size of long data packet is 6 bytes */
|
||||
if (packet_length <= MYSQL_LONG_DATA_HEADER)
|
||||
@@ -2788,7 +2796,7 @@ void Prepared_statement::cleanup_stmt()
|
||||
bool Prepared_statement::set_name(LEX_STRING *name_arg)
|
||||
{
|
||||
name.length= name_arg->length;
|
||||
name.str= memdup_root(mem_root, (char*) name_arg->str, name_arg->length);
|
||||
name.str= (char*) memdup_root(mem_root, name_arg->str, name_arg->length);
|
||||
return name.str == 0;
|
||||
}
|
||||
|
||||
@@ -2835,7 +2843,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
However, it seems handy if com_stmt_prepare is increased always,
|
||||
no matter what kind of prepare is processed.
|
||||
*/
|
||||
statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status);
|
||||
status_var_increment(thd->status_var.com_stmt_prepare);
|
||||
|
||||
/*
|
||||
alloc_query() uses thd->memroot && thd->query, so we should call
|
||||
@@ -2853,11 +2861,28 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
|
||||
old_stmt_arena= thd->stmt_arena;
|
||||
thd->stmt_arena= this;
|
||||
lex_start(thd, thd->query, thd->query_length);
|
||||
lex->stmt_prepare_mode= TRUE;
|
||||
|
||||
error= MYSQLparse((void *)thd) || thd->is_fatal_error ||
|
||||
thd->net.report_error || init_param_array(this);
|
||||
Lex_input_stream lip(thd, thd->query, thd->query_length);
|
||||
lip.stmt_prepare_mode= TRUE;
|
||||
lex_start(thd);
|
||||
|
||||
error= parse_sql(thd, &lip, NULL) ||
|
||||
thd->net.report_error ||
|
||||
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)
|
||||
@@ -2901,24 +2926,35 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
||||
thd->restore_backup_statement(this, &stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
||||
if ((protocol->type() == Protocol::PROTOCOL_TEXT) && (param_count > 0))
|
||||
{
|
||||
/*
|
||||
This is a mysql_sql_stmt_prepare(); query expansion will insert user
|
||||
variable references, and user variables are uncacheable, thus we have to
|
||||
mark this statement as uncacheable.
|
||||
This has to be done before setup_set_params(), as it may make expansion
|
||||
unneeded.
|
||||
*/
|
||||
lex->safe_to_cache_query= FALSE;
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
setup_set_params();
|
||||
init_stmt_after_parse(lex);
|
||||
state= Query_arena::PREPARED;
|
||||
flags&= ~ (uint) IS_IN_USE;
|
||||
|
||||
/*
|
||||
Log COM_EXECUTE to the general log. Note, that in case of SQL
|
||||
prepared statements this causes two records to be output:
|
||||
|
||||
Query PREPARE stmt from @user_variable
|
||||
Prepare <statement SQL text>
|
||||
|
||||
This is considered user-friendly, since in the
|
||||
second log entry we output the actual statement text.
|
||||
|
||||
Do not print anything if this is an SQL prepared statement and
|
||||
we're inside a stored procedure (also called Dynamic SQL) --
|
||||
sub-statements inside stored procedures are not logged into
|
||||
the general log.
|
||||
*/
|
||||
if (thd->spcont == NULL)
|
||||
{
|
||||
const char *format= "[%lu] %.*b";
|
||||
general_log_print(thd, COM_STMT_PREPARE, format, id,
|
||||
query_length, query);
|
||||
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@@ -2954,7 +2990,14 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
||||
Query_arena *old_stmt_arena;
|
||||
bool error= TRUE;
|
||||
|
||||
statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
|
||||
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 */
|
||||
if (state == Query_arena::ERROR)
|
||||
@@ -3002,6 +3045,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))
|
||||
@@ -3030,6 +3088,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);
|
||||
@@ -3048,6 +3108,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 */
|
||||
@@ -3065,6 +3136,28 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
||||
if (state == Query_arena::PREPARED)
|
||||
state= Query_arena::EXECUTED;
|
||||
|
||||
/*
|
||||
Log COM_EXECUTE to the general log. Note, that in case of SQL
|
||||
prepared statements this causes two records to be output:
|
||||
|
||||
Query EXECUTE <statement name>
|
||||
Execute <statement SQL text>
|
||||
|
||||
This is considered user-friendly, since in the
|
||||
second log entry we output values of parameter markers.
|
||||
|
||||
Do not print anything if this is an SQL prepared statement and
|
||||
we're inside a stored procedure (also called Dynamic SQL) --
|
||||
sub-statements inside stored procedures are not logged into
|
||||
the general log.
|
||||
*/
|
||||
if (error == 0 && thd->spcont == NULL)
|
||||
{
|
||||
const char *format= "[%lu] %.*b";
|
||||
general_log_print(thd, COM_STMT_EXECUTE, format, id,
|
||||
thd->query_length, thd->query);
|
||||
}
|
||||
|
||||
error:
|
||||
flags&= ~ (uint) IS_IN_USE;
|
||||
return error;
|
||||
@@ -3076,7 +3169,7 @@ error:
|
||||
bool Prepared_statement::deallocate()
|
||||
{
|
||||
/* We account deallocate in the same manner as mysql_stmt_close */
|
||||
statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
|
||||
status_var_increment(thd->status_var.com_stmt_close);
|
||||
if (flags & (uint) IS_IN_USE)
|
||||
{
|
||||
my_error(ER_PS_NO_RECURSION, MYF(0));
|
||||
|
Reference in New Issue
Block a user