Commit c0729cbb authored by unknown's avatar unknown

Added support for PREPARE stmt1 FROM @var,

Fixed the problem of previous patch with replication,
More post-review fixes


sql/sql_parse.cc:
  Added support for PREPARE stmt1 FROM @var
sql/sql_prepare.cc:
  Added support for PREPARE stmt1 FROM @var, 
  Fixed the problem of previous patch with replication
  Post-review fixes.
parent fc68be78
...@@ -1978,17 +1978,21 @@ mysql_execute_command(THD *thd) ...@@ -1978,17 +1978,21 @@ mysql_execute_command(THD *thd)
uint query_len; uint query_len;
if (lex->prepared_stmt_code_is_varref) if (lex->prepared_stmt_code_is_varref)
{ {
/* This is PREPARE stmt FROM @var*/ /* This is PREPARE stmt FROM @var. */
String str; String str;
CHARSET_INFO *to_cs= thd->variables.collation_connection; CHARSET_INFO *to_cs= thd->variables.collation_connection;
CHARSET_INFO *from_cs; CHARSET_INFO *from_cs;
const char *buf; const char *buf;
uint buf_len; uint buf_len;
bool need_conversion; bool need_conversion;
//// psergey: find the variable and convert it. LINT_INIT(from_cs); /* protected by need_conversion */
LINT_INIT(from_cs);
user_var_entry *entry; user_var_entry *entry;
uint32 unused; uint32 unused;
/*
Convert @var contents to string in connection character set. Although
it is known that int/real/NULL value cannot be a valid query we still
convert it for error messages to uniform.
*/
if ((entry= if ((entry=
(user_var_entry*)hash_search(&thd->user_vars, (user_var_entry*)hash_search(&thd->user_vars,
(byte*)lex->prepared_stmt_code.str, (byte*)lex->prepared_stmt_code.str,
...@@ -2033,32 +2037,29 @@ mysql_execute_command(THD *thd) ...@@ -2033,32 +2037,29 @@ mysql_execute_command(THD *thd)
to_cs, &unused); to_cs, &unused);
} }
query_len = need_conversion? (buf_len* to_cs->mbmaxlen) : buf_len; query_len = need_conversion? (buf_len * to_cs->mbmaxlen) : buf_len;
if (!(query_str= alloc_root(&thd->mem_root, query_len+1))) if (!(query_str= alloc_root(&thd->mem_root, query_len+1)))
{
send_error(thd, ER_OUT_OF_RESOURCES); send_error(thd, ER_OUT_OF_RESOURCES);
}
if (need_conversion) if (need_conversion)
query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len, query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len,
from_cs); from_cs);
else else
memcpy(query_str, buf, query_len); memcpy(query_str, buf, query_len);
query_str[query_len] = 0; query_str[query_len]= 0;
} }
else else
{ {
query_str= lex->prepared_stmt_code.str;
query_len= lex->prepared_stmt_code.length;
DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n", DBUG_PRINT("info", ("PREPARE: %.*s FROM '%.*s' \n",
lex->prepared_stmt_name.length, lex->prepared_stmt_name.length,
lex->prepared_stmt_name.str, lex->prepared_stmt_name.str,
lex->prepared_stmt_code.length, query_len, query_str));
lex->prepared_stmt_code.str));
query_str= lex->prepared_stmt_code.str;
query_len= lex->prepared_stmt_code.length + 1;
} }
thd->command= COM_PREPARE; thd->command= COM_PREPARE;
if (!mysql_stmt_prepare(thd, query_str, query_len + 1, if (!mysql_stmt_prepare(thd, query_str, query_len + 1,
&lex->prepared_stmt_name)) &lex->prepared_stmt_name))
send_ok(thd, 0L, 0L, "Statement prepared"); send_ok(thd, 0L, 0L, "Statement prepared");
break; break;
} }
......
...@@ -94,19 +94,21 @@ class Prepared_statement: public Statement ...@@ -94,19 +94,21 @@ class Prepared_statement: public Statement
bool log_full_query; bool log_full_query;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end, bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
uchar *read_pos); uchar *read_pos, String *expanded_query);
#else #else
bool (*set_params_data)(Prepared_statement *st); bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
#endif #endif
bool (*set_params_from_vars)(Prepared_statement *stmt, bool (*set_params_from_vars)(Prepared_statement *stmt,
List<LEX_STRING>& varnames); List<LEX_STRING>& varnames,
String *expanded_query);
public: public:
Prepared_statement(THD *thd_arg); Prepared_statement(THD *thd_arg);
virtual ~Prepared_statement(); virtual ~Prepared_statement();
virtual Statement::Type type() const; virtual Statement::Type type() const;
}; };
static void execute_stmt(THD *thd, Prepared_statement *stmt); static void execute_stmt(THD *thd, Prepared_statement *stmt,
String *expanded_query);
/****************************************************************************** /******************************************************************************
Implementation Implementation
...@@ -517,19 +519,20 @@ static void setup_one_conversion_function(Item_param *param, uchar param_type) ...@@ -517,19 +519,20 @@ static void setup_one_conversion_function(Item_param *param, uchar param_type)
*/ */
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
uchar *read_pos, uchar *data_end) uchar *read_pos, uchar *data_end,
String *query)
{ {
THD *thd= stmt->thd; THD *thd= stmt->thd;
Item_param **begin= stmt->param_array; Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count; Item_param **end= begin + stmt->param_count;
uint32 length= 0; uint32 length= 0;
String str, query; String str;
const String *res; const String *res;
DBUG_ENTER("insert_params_withlog"); DBUG_ENTER("insert_params_withlog");
if (query.copy(stmt->query, stmt->query_length, default_charset_info)) if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1); DBUG_RETURN(1);
for (Item_param **it= begin; it < end; ++it) for (Item_param **it= begin; it < end; ++it)
...@@ -552,20 +555,18 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, ...@@ -552,20 +555,18 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
res= param->query_val_str(&str); res= param->query_val_str(&str);
} }
} }
if (query.replace(param->pos_in_query+length, 1, *res)) if (query->replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1); DBUG_RETURN(1);
length+= res->length()-1; length+= res->length()-1;
} }
if (alloc_query(thd, (char *)query.ptr(), query.length()+1))
DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
static bool insert_params(Prepared_statement *stmt, uchar *null_array, static bool insert_params(Prepared_statement *stmt, uchar *null_array,
uchar *read_pos, uchar *data_end) uchar *read_pos, uchar *data_end,
String *expanded_query)
{ {
Item_param **begin= stmt->param_array; Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count; Item_param **end= begin + stmt->param_count;
...@@ -627,7 +628,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt, ...@@ -627,7 +628,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
#else #else
static bool emb_insert_params(Prepared_statement *stmt) static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
{ {
Item_param **it= stmt->param_array; Item_param **it= stmt->param_array;
Item_param **end= it + stmt->param_count; Item_param **end= it + stmt->param_count;
...@@ -658,20 +659,20 @@ static bool emb_insert_params(Prepared_statement *stmt) ...@@ -658,20 +659,20 @@ static bool emb_insert_params(Prepared_statement *stmt)
} }
static bool emb_insert_params_withlog(Prepared_statement *stmt) static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
{ {
THD *thd= stmt->thd; THD *thd= stmt->thd;
Item_param **it= stmt->param_array; Item_param **it= stmt->param_array;
Item_param **end= it + stmt->param_count; Item_param **end= it + stmt->param_count;
MYSQL_BIND *client_param= thd->client_params; MYSQL_BIND *client_param= thd->client_params;
String str, query; String str;
const String *res; const String *res;
uint32 length= 0; uint32 length= 0;
DBUG_ENTER("emb_insert_params_withlog"); DBUG_ENTER("emb_insert_params_withlog");
if (query.copy(stmt->query, stmt->query_length, default_charset_info)) if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1); DBUG_RETURN(1);
for (; it < end; ++it, ++client_param) for (; it < end; ++it, ++client_param)
...@@ -697,14 +698,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt) ...@@ -697,14 +698,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
res= param->query_val_str(&str); res= param->query_val_str(&str);
} }
} }
if (query.replace(param->pos_in_query+length, 1, *res)) if (query->replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1); DBUG_RETURN(1);
length+= res->length()-1; length+= res->length()-1;
} }
if (alloc_query(thd, (char *) query.ptr(), query.length()+1))
DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -718,11 +715,12 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt) ...@@ -718,11 +715,12 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
stmt Statement stmt Statement
varnames List of variables. Caller must ensure that number of variables varnames List of variables. Caller must ensure that number of variables
in the list is equal to number of statement parameters in the list is equal to number of statement parameters
query Ignored
*/ */
static bool insert_params_from_vars(Prepared_statement *stmt, static bool insert_params_from_vars(Prepared_statement *stmt,
List<LEX_STRING>& varnames) List<LEX_STRING>& varnames,
String *query __attribute__((unused)))
{ {
Item_param **begin= stmt->param_array; Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count; Item_param **end= begin + stmt->param_count;
...@@ -763,8 +761,21 @@ static bool insert_params_from_vars(Prepared_statement *stmt, ...@@ -763,8 +761,21 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
Do the same as insert_params_from_vars but also construct query text for
binary log.
SYNOPSIS
insert_params_from_vars()
stmt Statement
varnames List of variables. Caller must ensure that number of variables
in the list is equal to number of statement parameters
query The query with parameter markers replaced with their values
*/
static bool insert_params_from_vars_with_log(Prepared_statement *stmt, static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
List<LEX_STRING>& varnames) List<LEX_STRING>& varnames,
String *query)
{ {
Item_param **begin= stmt->param_array; Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count; Item_param **end= begin + stmt->param_count;
...@@ -773,10 +784,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, ...@@ -773,10 +784,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
DBUG_ENTER("insert_params_from_vars"); DBUG_ENTER("insert_params_from_vars");
List_iterator<LEX_STRING> var_it(varnames); List_iterator<LEX_STRING> var_it(varnames);
String str, query; String str;
const String *res; const String *res;
uint32 length= 0; uint32 length= 0;
if (query.copy(stmt->query, stmt->query_length, default_charset_info)) if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1); DBUG_RETURN(1);
for (Item_param **it= begin; it < end; ++it) for (Item_param **it= begin; it < end; ++it)
...@@ -812,12 +823,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, ...@@ -812,12 +823,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
res= &my_null_string; res= &my_null_string;
} }
if (query.replace(param->pos_in_query+length, 1, *res)) if (query->replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1); DBUG_RETURN(1);
length+= res->length()-1; length+= res->length()-1;
} }
if (alloc_query(stmt->thd, (char *) query.ptr(), query.length()+1))
DBUG_RETURN(1);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1708,13 +1717,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1708,13 +1717,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
String expanded_query;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (stmt->param_count) if (stmt->param_count)
{ {
uchar *null_array= (uchar *) packet; uchar *null_array= (uchar *) packet;
if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) || if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
stmt->set_params(stmt, null_array, (uchar *) packet, packet_end)) stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
&expanded_query))
goto set_params_data_err; goto set_params_data_err;
} }
#else #else
...@@ -1727,7 +1737,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1727,7 +1737,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
goto set_params_data_err; goto set_params_data_err;
#endif #endif
thd->protocol= &thd->protocol_prep; // Switch to binary protocol thd->protocol= &thd->protocol_prep; // Switch to binary protocol
execute_stmt(thd, stmt); execute_stmt(thd, stmt, &expanded_query);
thd->protocol= &thd->protocol_simple; // Use normal protocol thd->protocol= &thd->protocol_simple; // Use normal protocol
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1747,6 +1757,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1747,6 +1757,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
{ {
Prepared_statement *stmt; Prepared_statement *stmt;
String expanded_query;
DBUG_ENTER("mysql_sql_stmt_execute"); DBUG_ENTER("mysql_sql_stmt_execute");
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name))) if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
...@@ -1766,27 +1777,47 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) ...@@ -1766,27 +1777,47 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
/* Item_param allows setting parameters in COM_EXECUTE only */ /* Item_param allows setting parameters in COM_EXECUTE only */
thd->command= COM_EXECUTE; thd->command= COM_EXECUTE;
if (stmt->set_params_from_vars(stmt, thd->lex->prepared_stmt_params)) if (stmt->set_params_from_vars(stmt, thd->lex->prepared_stmt_params,
&expanded_query))
{ {
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute"); my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
send_error(thd); send_error(thd);
} }
execute_stmt(thd, stmt); execute_stmt(thd, stmt, &expanded_query);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/* /*
Execute prepared statement. Execute prepared statement.
SYNOPSIS
execute_stmt()
thd Current thread
stmt Statement to execute
expanded_query If binary log is enabled, query string with parameter
placeholders replaced with actual values. Otherwise empty
string.
NOTES
Caller must set parameter values and thd::protocol. Caller must set parameter values and thd::protocol.
thd->free_list is assumed to be garbage. thd->free_list is assumed to be garbage.
*/ */
static void execute_stmt(THD *thd, Prepared_statement *stmt)
static void execute_stmt(THD *thd, Prepared_statement *stmt,
String *expanded_query)
{ {
DBUG_ENTER("execute_stmt"); DBUG_ENTER("execute_stmt");
thd->free_list= NULL; thd->free_list= NULL;
thd->stmt_backup.set_statement(thd); thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt); thd->set_statement(stmt);
reset_stmt_for_execute(stmt); reset_stmt_for_execute(stmt);
if (expanded_query->length() &&
alloc_query(thd, (char *)expanded_query->ptr(),
expanded_query->length()+1))
{
my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
DBUG_VOID_RETURN;
}
if (!(specialflag & SPECIAL_NO_PRIOR)) if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR); my_pthread_setprio(pthread_self(),QUERY_PRIOR);
...@@ -1808,13 +1839,12 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt) ...@@ -1808,13 +1839,12 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt)
} }
/* /*
Reset a prepared statement in case there was a recoverable error. Reset a prepared statement in case there was a recoverable error.
SYNOPSIS SYNOPSIS
mysql_stmt_reset() mysql_stmt_reset()
thd Thread handle thd Thread handle
packet Packet with stmt id packet Packet with stmt id
DESCRIPTION DESCRIPTION
This function resets statement to the state it was right after prepare. This function resets statement to the state it was right after prepare.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment