Commit 1e05e6cb authored by sergefp@mysql.com's avatar sergefp@mysql.com

Post review fixes for "SQL Syntax for Prepared Statements".

parent bec20d1f
...@@ -23,7 +23,7 @@ a b ...@@ -23,7 +23,7 @@ a b
deallocate prepare no_such_statement; deallocate prepare no_such_statement;
ERROR HY000: Unknown prepared statement handler (no_such_statement) given to DEALLOCATE PREPARE ERROR HY000: Unknown prepared statement handler (no_such_statement) given to DEALLOCATE PREPARE
execute stmt1; execute stmt1;
ERROR HY000: Wrong arguments to mysql_execute ERROR HY000: Wrong arguments to EXECUTE
prepare stmt2 from 'prepare nested_stmt from "select 1"'; prepare stmt2 from 'prepare nested_stmt from "select 1"';
ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '"select 1"' at line 1 ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '"select 1"' at line 1
prepare stmt2 from 'execute stmt1'; prepare stmt2 from 'execute stmt1';
......
...@@ -37,8 +37,8 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE]; ...@@ -37,8 +37,8 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
The following subset of printf format is supported: The following subset of printf format is supported:
"%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored. "%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored.
Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but
length value is ignored. the length value is ignored.
*/ */
int my_error(int nr,myf MyFlags, ...) int my_error(int nr,myf MyFlags, ...)
...@@ -49,7 +49,7 @@ int my_error(int nr,myf MyFlags, ...) ...@@ -49,7 +49,7 @@ int my_error(int nr,myf MyFlags, ...)
reg2 char *endpos; reg2 char *endpos;
char * par; char * par;
char ebuff[ERRMSGSIZE+20]; char ebuff[ERRMSGSIZE+20];
int prec_chars; int prec_chars; /* output precision */
my_bool prec_supplied; my_bool prec_supplied;
DBUG_ENTER("my_error"); DBUG_ENTER("my_error");
LINT_INIT(prec_chars); /* protected by prec_supplied */ LINT_INIT(prec_chars); /* protected by prec_supplied */
...@@ -76,10 +76,11 @@ int my_error(int nr,myf MyFlags, ...) ...@@ -76,10 +76,11 @@ int my_error(int nr,myf MyFlags, ...)
} }
else else
{ {
/* /*
Skip size/precision flags to be compatible with printf. Skip size/precision flags to be compatible with printf.
The only size/precision flag supported is "%.*s". The only size/precision flag supported is "%.*s".
"%.*u" and "%.*d" cause If "%.*u" or "%.*d" are encountered, the precision number is read
from the variable argument list but its value is ignored.
*/ */
prec_supplied= 0; prec_supplied= 0;
if (*tpos== '.') if (*tpos== '.')
...@@ -94,52 +95,52 @@ int my_error(int nr,myf MyFlags, ...) ...@@ -94,52 +95,52 @@ int my_error(int nr,myf MyFlags, ...)
prec_supplied= 1; prec_supplied= 1;
} }
} }
if (!prec_supplied) if (!prec_supplied)
{ {
while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' || while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' ||
*tpos == '-') *tpos == '-')
tpos++; tpos++;
if (*tpos == 'l') /* Skipp 'l' argument */ if (*tpos == 'l') /* Skip 'l' argument */
tpos++; tpos++;
} }
if (*tpos == 's') /* String parameter */ if (*tpos == 's') /* String parameter */
{ {
par = va_arg(ap, char *); par= va_arg(ap, char *);
plen = (uint) strlen(par); plen= (uint) strlen(par);
if (prec_supplied && prec_chars > 0) if (prec_supplied && prec_chars > 0)
plen= min((uint)prec_chars, plen); plen= min((uint)prec_chars, plen);
if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */ if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
{ {
memcpy(endpos,par, plen); strmake(endpos, par, plen);
endpos += plen; endpos+= plen;
tpos++; tpos++;
olen+=plen-2; olen+= plen-2;
continue; continue;
} }
} }
else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
{ {
register int iarg; register int iarg;
iarg = va_arg(ap, int); iarg= va_arg(ap, int);
if (*tpos == 'd') if (*tpos == 'd')
plen= (uint) (int10_to_str((long) iarg, endpos, -10) - endpos); plen= (uint) (int10_to_str((long) iarg, endpos, -10) - endpos);
else else
plen= (uint) (int10_to_str((long) (uint) iarg, endpos, 10) - endpos); plen= (uint) (int10_to_str((long) (uint) iarg, endpos, 10) - endpos);
if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */ if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
{ {
endpos+=plen; endpos+= plen;
tpos++; tpos++;
olen+=plen-2; olen+= plen-2;
continue; continue;
} }
} }
} }
*endpos++='%'; /* % used as % or unknown code */ *endpos++= '%'; /* % used as % or unknown code */
} }
*endpos='\0'; /* End of errmessage */ *endpos= '\0'; /* End of errmessage */
va_end(ap); va_end(ap);
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags)); DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
} }
......
...@@ -255,7 +255,7 @@ bool Item::get_time(TIME *ltime) ...@@ -255,7 +255,7 @@ bool Item::get_time(TIME *ltime)
return 0; return 0;
} }
CHARSET_INFO * Item::default_charset() CHARSET_INFO *Item::default_charset()
{ {
return current_thd->variables.collation_connection; return current_thd->variables.collation_connection;
} }
...@@ -735,6 +735,70 @@ bool Item_param::set_longdata(const char *str, ulong length) ...@@ -735,6 +735,70 @@ bool Item_param::set_longdata(const char *str, ulong length)
} }
/*
Set parameter value from user variable value.
SYNOPSIS
set_from_user_var
thd Current thread
entry User variable structure (NULL means use NULL value)
RETURN
0 OK
1 Out of memort
*/
bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
{
DBUG_ENTER("Item_param::set_from_user_var");
if (entry && entry->value)
{
item_result_type= entry->type;
switch (entry->type)
{
case REAL_RESULT:
set_double(*(double*)entry->value);
break;
case INT_RESULT:
set_int(*(longlong*)entry->value, 21);
break;
case STRING_RESULT:
{
CHARSET_INFO *fromcs= entry->collation.collation;
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
make later checks easier.
*/
value.cs_info.final_character_set_of_str_value=
String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
tocs : fromcs;
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
item_type= Item::STRING_ITEM;
item_result_type= STRING_RESULT;
if (set_str((const char *)entry->value, entry->length))
DBUG_RETURN(1);
}
break;
default:
DBUG_ASSERT(0);
set_null();
}
}
else
set_null();
DBUG_RETURN(0);
}
/* /*
Resets parameter after execution. Resets parameter after execution.
...@@ -767,8 +831,6 @@ void Item_param::reset() ...@@ -767,8 +831,6 @@ void Item_param::reset()
int Item_param::save_in_field(Field *field, bool no_conversions) int Item_param::save_in_field(Field *field, bool no_conversions)
{ {
DBUG_ASSERT(current_thd->command == COM_EXECUTE);
field->set_notnull(); field->set_notnull();
switch (state) { switch (state) {
...@@ -1666,7 +1728,7 @@ bool Item::send(Protocol *protocol, String *buffer) ...@@ -1666,7 +1728,7 @@ bool Item::send(Protocol *protocol, String *buffer)
} }
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
{ {
longlong nr; longlong nr;
nr= val_int(); nr= val_int();
if (!null_value) if (!null_value)
result= protocol->store_tiny(nr); result= protocol->store_tiny(nr);
......
...@@ -489,6 +489,7 @@ public: ...@@ -489,6 +489,7 @@ public:
bool set_str(const char *str, ulong length); bool set_str(const char *str, ulong length);
bool set_longdata(const char *str, ulong length); bool set_longdata(const char *str, ulong length);
void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg); void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg);
bool set_from_user_var(THD *thd, const user_var_entry *entry);
void reset(); void reset();
/* /*
Assign placeholder value from bind data. Assign placeholder value from bind data.
......
...@@ -2703,17 +2703,17 @@ void Item_func_get_user_var::fix_length_and_dec() ...@@ -2703,17 +2703,17 @@ void Item_func_get_user_var::fix_length_and_dec()
maybe_null=1; maybe_null=1;
decimals=NOT_FIXED_DEC; decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH; max_length=MAX_BLOB_WIDTH;
error= get_var_with_binlog(thd, name, &var_entry); error= get_var_with_binlog(thd, name, &var_entry);
if (!var_entry) if (var_entry)
null_value= 1;
else
collation.set(var_entry->collation); collation.set(var_entry->collation);
else
null_value= 1;
if (error) if (error)
thd->fatal_error(); thd->fatal_error();
return; return;
} }
......
...@@ -348,6 +348,7 @@ inline THD *_current_thd(void) ...@@ -348,6 +348,7 @@ inline THD *_current_thd(void)
#include "field.h" /* Field definitions */ #include "field.h" /* Field definitions */
#include "protocol.h" #include "protocol.h"
#include "sql_udf.h" #include "sql_udf.h"
class user_var_entry;
#include "item.h" #include "item.h"
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* sql_parse.cc */ /* sql_parse.cc */
......
...@@ -233,7 +233,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0), ...@@ -233,7 +233,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
16); 16);
else else
bzero((char*) &user_var_events, sizeof(user_var_events)); bzero((char*) &user_var_events, sizeof(user_var_events));
/* Protocol */ /* Protocol */
protocol= &protocol_simple; // Default protocol protocol= &protocol_simple; // Default protocol
protocol_simple.init(this); protocol_simple.init(this);
......
...@@ -1976,86 +1976,59 @@ mysql_execute_command(THD *thd) ...@@ -1976,86 +1976,59 @@ mysql_execute_command(THD *thd)
break; break;
} }
case SQLCOM_PREPARE: case SQLCOM_PREPARE:
{ {
char *query_str; char *query_str;
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;
String *pstr;
CHARSET_INFO *to_cs= thd->variables.collation_connection; CHARSET_INFO *to_cs= thd->variables.collation_connection;
CHARSET_INFO *from_cs;
const char *buf;
uint buf_len;
bool need_conversion; bool need_conversion;
LINT_INIT(from_cs); /* protected by need_conversion */
user_var_entry *entry; user_var_entry *entry;
uint32 unused; uint32 unused;
/* /*
Convert @var contents to string in connection character set. Although 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 it is known that int/real/NULL value cannot be a valid query we still
convert it for error messages to uniform. 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,
lex->prepared_stmt_code.length)) lex->prepared_stmt_code.length))
&& entry->value) && entry->value)
{ {
switch (entry->type) String *pstr;
{ my_bool is_var_null;
case REAL_RESULT: pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
str.set(*(double*)entry->value, NOT_FIXED_DEC, to_cs); DBUG_ASSERT(!is_var_null);
buf_len= str.length(); if (!pstr)
buf= str.ptr(); send_error(thd, ER_OUT_OF_RESOURCES);
need_conversion= false; DBUG_ASSERT(pstr == &str);
break;
case INT_RESULT:
str.set(*(longlong*)entry->value, to_cs);
buf_len= str.length();
buf= str.ptr();
need_conversion= false;
break;
case STRING_RESULT:
buf_len= entry->length;
buf= entry->value;
from_cs = entry->collation.collation;
need_conversion= String::needs_conversion(entry->length, from_cs,
to_cs, &unused);
break;
default:
buf= "";
need_conversion= false;
buf_len= 0;
DBUG_ASSERT(0);
}
} }
else else
{ str.set("NULL", 4, &my_charset_latin1);
from_cs= &my_charset_bin; need_conversion=
str.set("NULL", 4, from_cs); String::needs_conversion(str.length(), str.charset(), to_cs, &unused);
buf= str.ptr();
buf_len= str.length(); query_len= need_conversion? (str.length() * to_cs->mbmaxlen) :
need_conversion= String::needs_conversion(str.length(), from_cs, str.length();
to_cs, &unused);
}
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, str.ptr(),
from_cs); str.length(), str.charset());
else else
memcpy(query_str, buf, query_len); memcpy(query_str, str.ptr(), str.length());
query_str[query_len]= 0; query_str[query_len]= 0;
} }
else else
{ {
query_str= lex->prepared_stmt_code.str; query_str= lex->prepared_stmt_code.str;
query_len= lex->prepared_stmt_code.length; 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,
query_len, query_str)); query_len, query_str));
...@@ -2068,7 +2041,7 @@ mysql_execute_command(THD *thd) ...@@ -2068,7 +2041,7 @@ mysql_execute_command(THD *thd)
} }
case SQLCOM_EXECUTE: case SQLCOM_EXECUTE:
{ {
DBUG_PRINT("info", ("EXECUTE: %.*s\n", DBUG_PRINT("info", ("EXECUTE: %.*s\n",
lex->prepared_stmt_name.length, lex->prepared_stmt_name.length,
lex->prepared_stmt_name.str)); lex->prepared_stmt_name.str));
mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name); mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name);
...@@ -3559,7 +3532,6 @@ error: ...@@ -3559,7 +3532,6 @@ error:
*/ */
int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables) int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
{ {
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0)) if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
return 1; return 1;
......
...@@ -777,7 +777,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) ...@@ -777,7 +777,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
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;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -786,7 +786,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) ...@@ -786,7 +786,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
#endif /*!EMBEDDED_LIBRARY*/ #endif /*!EMBEDDED_LIBRARY*/
/* /*
Set prepared statement parameters from user variables. Set prepared statement parameters from user variables.
SYNOPSIS SYNOPSIS
insert_params_from_vars() insert_params_from_vars()
...@@ -796,78 +796,33 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) ...@@ -796,78 +796,33 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
query Ignored 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))) 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;
user_var_entry *entry; user_var_entry *entry;
LEX_STRING *varname; LEX_STRING *varname;
DBUG_ENTER("insert_params_from_vars");
List_iterator<LEX_STRING> var_it(varnames); List_iterator<LEX_STRING> var_it(varnames);
DBUG_ENTER("insert_params_from_vars");
for (Item_param **it= begin; it < end; ++it) for (Item_param **it= begin; it < end; ++it)
{ {
Item_param *param= *it; Item_param *param= *it;
varname= var_it++; varname= var_it++;
if ((entry= (user_var_entry*)hash_search(&stmt->thd->user_vars, entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
(byte*) varname->str, (byte*) varname->str,
varname->length)) varname->length);
&& entry->value) if (param->set_from_user_var(stmt->thd, entry) ||
{ param->convert_str_value(stmt->thd))
param->item_result_type= entry->type; DBUG_RETURN(1);
switch (entry->type)
{
case REAL_RESULT:
param->set_double(*(double*)entry->value);
break;
case INT_RESULT:
param->set_int(*(longlong*)entry->value, 21);
break;
case STRING_RESULT:
{
CHARSET_INFO *fromcs= entry->collation.collation;
CHARSET_INFO *tocs= stmt->thd->variables.collation_connection;
uint32 dummy_offset;
param->value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
make later checks easier.
*/
param->value.cs_info.final_character_set_of_str_value=
String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
tocs : fromcs;
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
if (param->set_str((const char *)entry->value, entry->length))
DBUG_RETURN(1);
}
break;
default:
DBUG_ASSERT(0);
param->set_null();
}
}
else
param->set_null();
if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* /*
Do the same as insert_params_from_vars but also construct query text for Do the same as insert_params_from_vars but also construct query text for
binary log. binary log.
SYNOPSIS SYNOPSIS
...@@ -879,14 +834,14 @@ static bool insert_params_from_vars(Prepared_statement *stmt, ...@@ -879,14 +834,14 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
*/ */
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) 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;
user_var_entry *entry; user_var_entry *entry;
LEX_STRING *varname; LEX_STRING *varname;
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; String str;
...@@ -902,53 +857,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, ...@@ -902,53 +857,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
if (get_var_with_binlog(stmt->thd, *varname, &entry)) if (get_var_with_binlog(stmt->thd, *varname, &entry))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_ASSERT(entry); DBUG_ASSERT(entry);
if (entry->value)
{
param->item_result_type= entry->type;
switch (entry->type)
{
case REAL_RESULT:
param->set_double(*(double*)entry->value);
break;
case INT_RESULT:
param->set_int(*(longlong*)entry->value, 21);
break;
case STRING_RESULT:
{
CHARSET_INFO *fromcs= entry->collation.collation;
CHARSET_INFO *tocs= stmt->thd->variables.collation_connection;
uint32 dummy_offset;
param->value.cs_info.character_set_client= fromcs;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
make later checks easier.
*/
param->value.cs_info.final_character_set_of_str_value=
String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
tocs : fromcs;
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
param->item_type= Item::STRING_ITEM;
param->item_result_type= STRING_RESULT;
if (param->set_str((const char *)entry->value, entry->length))
DBUG_RETURN(1);
}
break;
default:
DBUG_ASSERT(0);
param->set_null();
}
}
else
param->set_null();
/* Insert @'escaped-varname' instead of parameter in the query */ if (param->set_from_user_var(stmt->thd, entry))
DBUG_RETURN(1);
/* Insert @'escaped-varname' instead of parameter in the query */
char *buf, *ptr; char *buf, *ptr;
str.length(0); str.length(0);
if (str.reserve(entry->name.length*2+3)) if (str.reserve(entry->name.length*2+3))
...@@ -958,15 +870,15 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, ...@@ -958,15 +870,15 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
ptr= buf; ptr= buf;
*ptr++= '@'; *ptr++= '@';
*ptr++= '\''; *ptr++= '\'';
ptr+= ptr+=
escape_string_for_mysql(&my_charset_utf8_general_ci, escape_string_for_mysql(&my_charset_utf8_general_ci,
ptr, entry->name.str, entry->name.length); ptr, entry->name.str, entry->name.length);
*ptr++= '\''; *ptr++= '\'';
str.length(ptr - buf); str.length(ptr - buf);
if (param->convert_str_value(stmt->thd)) if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */ DBUG_RETURN(1); /* out of memory */
if (query->replace(param->pos_in_query+length, 1, str)) if (query->replace(param->pos_in_query+length, 1, str))
DBUG_RETURN(1); DBUG_RETURN(1);
length+= str.length()-1; length+= str.length()-1;
...@@ -1837,13 +1749,21 @@ static void reset_stmt_params(Prepared_statement *stmt) ...@@ -1837,13 +1749,21 @@ static void reset_stmt_params(Prepared_statement *stmt)
Executes previously prepared query. Executes previously prepared query.
If there is any parameters, then replace markers with the data supplied If there is any parameters, then replace markers with the data supplied
from client, and then execute the query. from client, and then execute the query.
SYNOPSYS SYNOPSIS
mysql_stmt_execute() mysql_stmt_execute()
thd Current thread
packet Query string
packet_length Query string length, including terminator character.
*/ */
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{ {
ulong stmt_id= uint4korr(packet); ulong stmt_id= uint4korr(packet);
/*
Query text for binary log, or empty string if the query is not put into
binary log.
*/
String expanded_query;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
uchar *packet_end= (uchar *) packet + packet_length - 1; uchar *packet_end= (uchar *) packet + packet_length - 1;
#endif #endif
...@@ -1851,7 +1771,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1851,7 +1771,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_ENTER("mysql_stmt_execute"); DBUG_ENTER("mysql_stmt_execute");
packet+= 9; /* stmt_id + 5 bytes of flags */ packet+= 9; /* stmt_id + 5 bytes of flags */
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute", if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute",
SEND_ERROR))) SEND_ERROR)))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1865,14 +1785,13 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1865,14 +1785,13 @@ 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)) &expanded_query))
goto set_params_data_err; goto set_params_data_err;
} }
#else #else
...@@ -1890,7 +1809,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) ...@@ -1890,7 +1809,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
set_params_data_err: set_params_data_err:
reset_stmt_params(stmt); reset_stmt_params(stmt);
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute"); my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
send_error(thd); send_error(thd);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -1898,16 +1817,20 @@ set_params_data_err: ...@@ -1898,16 +1817,20 @@ set_params_data_err:
/* /*
Execute prepared statement using parameter values from Execute prepared statement using parameter values from
lex->prepared_stmt_params and send result to the client using text protocol. lex->prepared_stmt_params and send result to the client using text protocol.
*/ */
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;
/*
Query text for binary log, or empty string if the query is not put into
binary log.
*/
String expanded_query; 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)))
{ {
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length, my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length,
...@@ -1918,20 +1841,19 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) ...@@ -1918,20 +1841,19 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
if (stmt->param_count != thd->lex->prepared_stmt_params.elements) if (stmt->param_count != thd->lex->prepared_stmt_params.elements)
{ {
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute"); my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
send_error(thd); send_error(thd);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/* Item_param allows setting parameters in COM_EXECUTE only */
thd->command= COM_EXECUTE;
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);
if (stmt->set_params_from_vars(stmt, thd->stmt_backup.lex->prepared_stmt_params, if (stmt->set_params_from_vars(stmt,
thd->stmt_backup.lex->prepared_stmt_params,
&expanded_query)) &expanded_query))
{ {
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute"); my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
send_error(thd); send_error(thd);
} }
execute_stmt(thd, stmt, &expanded_query); execute_stmt(thd, stmt, &expanded_query);
...@@ -1945,7 +1867,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) ...@@ -1945,7 +1867,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
execute_stmt() execute_stmt()
thd Current thread thd Current thread
stmt Statement to execute stmt Statement to execute
expanded_query If binary log is enabled, query string with parameter expanded_query If binary log is enabled, query string with parameter
placeholders replaced with actual values. Otherwise empty placeholders replaced with actual values. Otherwise empty
string. string.
NOTES NOTES
...@@ -1953,7 +1875,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) ...@@ -1953,7 +1875,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
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, bool set_context) String *expanded_query, bool set_context)
{ {
DBUG_ENTER("execute_stmt"); DBUG_ENTER("execute_stmt");
...@@ -1964,9 +1886,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, ...@@ -1964,9 +1886,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
thd->set_statement(stmt); thd->set_statement(stmt);
} }
reset_stmt_for_execute(stmt); reset_stmt_for_execute(stmt);
if (expanded_query->length() && if (expanded_query->length() &&
alloc_query(thd, (char *)expanded_query->ptr(), alloc_query(thd, (char *)expanded_query->ptr(),
expanded_query->length()+1)) expanded_query->length()+1))
{ {
my_error(ER_OUTOFMEMORY, 0, expanded_query->length()); my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
...@@ -1980,14 +1902,11 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, ...@@ -1980,14 +1902,11 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
if (!(specialflag & SPECIAL_NO_PRIOR)) if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR); my_pthread_setprio(pthread_self(), WAIT_PRIOR);
/* /* Free Items that were created during this execution of the PS. */
Free Items that were created during this execution of the PS by query free_items(thd->free_list);
optimizer.
*/
free_items(thd->free_list);
cleanup_items(stmt->free_list); cleanup_items(stmt->free_list);
reset_stmt_params(stmt); reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup); thd->set_statement(&thd->stmt_backup);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2138,24 +2057,6 @@ Prepared_statement::Prepared_statement(THD *thd_arg) ...@@ -2138,24 +2057,6 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
get_longdata_error(0) get_longdata_error(0)
{ {
*last_error= '\0'; *last_error= '\0';
if (mysql_bin_log.is_open()) //psergey-todo: remove this!
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY
set_params= insert_params_withlog;
#else
set_params_data= emb_insert_params_withlog;
#endif
}
else
{
set_params_from_vars= insert_params_from_vars;
#ifndef EMBEDDED_LIBRARY
set_params= insert_params;
#else
set_params_data= emb_insert_params;
#endif
}
} }
void Prepared_statement::setup_set_params() void Prepared_statement::setup_set_params()
......
...@@ -764,12 +764,12 @@ verb_clause: ...@@ -764,12 +764,12 @@ verb_clause:
| checksum | checksum
| commit | commit
| create | create
| deallocate | deallocate
| delete | delete
| describe | describe
| do | do
| drop | drop
| execute | execute
| flush | flush
| grant | grant
| handler | handler
...@@ -781,7 +781,7 @@ verb_clause: ...@@ -781,7 +781,7 @@ verb_clause:
| optimize | optimize
| keycache | keycache
| preload | preload
| prepare | prepare
| purge | purge
| rename | rename
| repair | repair
...@@ -803,7 +803,7 @@ verb_clause: ...@@ -803,7 +803,7 @@ verb_clause:
; ;
deallocate: deallocate:
DEALLOCATE_SYM PREPARE_SYM ident DEALLOCATE_SYM PREPARE_SYM ident
{ {
THD *thd=YYTHD; THD *thd=YYTHD;
LEX *lex= thd->lex; LEX *lex= thd->lex;
...@@ -845,7 +845,7 @@ prepare_src: ...@@ -845,7 +845,7 @@ prepare_src:
lex->prepared_stmt_code= $2; lex->prepared_stmt_code= $2;
lex->prepared_stmt_code_is_varref= true; lex->prepared_stmt_code_is_varref= true;
}; };
execute: execute:
EXECUTE_SYM ident EXECUTE_SYM ident
{ {
......
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