mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Post review fixes for "SQL Syntax for Prepared Statements".
mysql-test/r/ps.result: Better error message mysys/my_error.c: Comments added sql/item.cc: Moved a chunk of code from sql_prepare.cc to Item_param::set_from_user_var sql/item.h: Moved a chunk of code from sql_prepare.cc to Item_param::set_from_user_var sql/item_func.cc: Code cleanup sql/mysql_priv.h: Code cleanup sql/sql_class.cc: Code cleanup sql/sql_parse.cc: use user_var_entry::val_str in PREPARE stmt FROM @var. sql/sql_prepare.cc: Post-review fixes and code cleanup. sql/sql_yacc.yy: Coding style fixes
This commit is contained in:
@ -23,7 +23,7 @@ a b
|
||||
deallocate prepare no_such_statement;
|
||||
ERROR HY000: Unknown prepared statement handler (no_such_statement) given to DEALLOCATE PREPARE
|
||||
execute stmt1;
|
||||
ERROR HY000: Wrong arguments to mysql_execute
|
||||
ERROR HY000: Wrong arguments to EXECUTE
|
||||
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
|
||||
prepare stmt2 from 'execute stmt1';
|
||||
|
@ -37,8 +37,8 @@ char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
|
||||
The following subset of printf format is supported:
|
||||
"%[0-9.-]*l?[sdu]", where all length flags are parsed but ignored.
|
||||
|
||||
Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but
|
||||
length value is ignored.
|
||||
Additionally "%.*s" is supported and "%.*[ud]" is correctly parsed but
|
||||
the length value is ignored.
|
||||
*/
|
||||
|
||||
int my_error(int nr,myf MyFlags, ...)
|
||||
@ -49,7 +49,7 @@ int my_error(int nr,myf MyFlags, ...)
|
||||
reg2 char *endpos;
|
||||
char * par;
|
||||
char ebuff[ERRMSGSIZE+20];
|
||||
int prec_chars;
|
||||
int prec_chars; /* output precision */
|
||||
my_bool prec_supplied;
|
||||
DBUG_ENTER("my_error");
|
||||
LINT_INIT(prec_chars); /* protected by prec_supplied */
|
||||
@ -76,10 +76,11 @@ int my_error(int nr,myf MyFlags, ...)
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Skip size/precision flags to be compatible with printf.
|
||||
The only size/precision flag supported is "%.*s".
|
||||
"%.*u" and "%.*d" cause
|
||||
/*
|
||||
Skip size/precision flags to be compatible with printf.
|
||||
The only size/precision flag supported is "%.*s".
|
||||
If "%.*u" or "%.*d" are encountered, the precision number is read
|
||||
from the variable argument list but its value is ignored.
|
||||
*/
|
||||
prec_supplied= 0;
|
||||
if (*tpos== '.')
|
||||
@ -94,52 +95,52 @@ int my_error(int nr,myf MyFlags, ...)
|
||||
prec_supplied= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!prec_supplied)
|
||||
{
|
||||
while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' ||
|
||||
while (my_isdigit(&my_charset_latin1, *tpos) || *tpos == '.' ||
|
||||
*tpos == '-')
|
||||
tpos++;
|
||||
|
||||
if (*tpos == 'l') /* Skipp 'l' argument */
|
||||
tpos++;
|
||||
|
||||
if (*tpos == 'l') /* Skip 'l' argument */
|
||||
tpos++;
|
||||
}
|
||||
|
||||
if (*tpos == 's') /* String parameter */
|
||||
{
|
||||
par = va_arg(ap, char *);
|
||||
plen = (uint) strlen(par);
|
||||
par= va_arg(ap, char *);
|
||||
plen= (uint) strlen(par);
|
||||
if (prec_supplied && prec_chars > 0)
|
||||
plen= min((uint)prec_chars, plen);
|
||||
if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
|
||||
{
|
||||
memcpy(endpos,par, plen);
|
||||
endpos += plen;
|
||||
strmake(endpos, par, plen);
|
||||
endpos+= plen;
|
||||
tpos++;
|
||||
olen+=plen-2;
|
||||
olen+= plen-2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
|
||||
{
|
||||
register int iarg;
|
||||
iarg = va_arg(ap, int);
|
||||
iarg= va_arg(ap, int);
|
||||
if (*tpos == 'd')
|
||||
plen= (uint) (int10_to_str((long) iarg, endpos, -10) - endpos);
|
||||
else
|
||||
plen= (uint) (int10_to_str((long) (uint) iarg, endpos, 10) - endpos);
|
||||
if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
|
||||
{
|
||||
endpos+=plen;
|
||||
endpos+= plen;
|
||||
tpos++;
|
||||
olen+=plen-2;
|
||||
olen+= plen-2;
|
||||
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);
|
||||
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
|
||||
}
|
||||
|
70
sql/item.cc
70
sql/item.cc
@ -255,7 +255,7 @@ bool Item::get_time(TIME *ltime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHARSET_INFO * Item::default_charset()
|
||||
CHARSET_INFO *Item::default_charset()
|
||||
{
|
||||
return current_thd->variables.collation_connection;
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -767,8 +831,6 @@ void Item_param::reset()
|
||||
|
||||
int Item_param::save_in_field(Field *field, bool no_conversions)
|
||||
{
|
||||
DBUG_ASSERT(current_thd->command == COM_EXECUTE);
|
||||
|
||||
field->set_notnull();
|
||||
|
||||
switch (state) {
|
||||
@ -1666,7 +1728,7 @@ bool Item::send(Protocol *protocol, String *buffer)
|
||||
}
|
||||
case MYSQL_TYPE_TINY:
|
||||
{
|
||||
longlong nr;
|
||||
longlong nr;
|
||||
nr= val_int();
|
||||
if (!null_value)
|
||||
result= protocol->store_tiny(nr);
|
||||
|
@ -489,6 +489,7 @@ public:
|
||||
bool set_str(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);
|
||||
bool set_from_user_var(THD *thd, const user_var_entry *entry);
|
||||
void reset();
|
||||
/*
|
||||
Assign placeholder value from bind data.
|
||||
|
@ -2703,17 +2703,17 @@ void Item_func_get_user_var::fix_length_and_dec()
|
||||
maybe_null=1;
|
||||
decimals=NOT_FIXED_DEC;
|
||||
max_length=MAX_BLOB_WIDTH;
|
||||
|
||||
|
||||
error= get_var_with_binlog(thd, name, &var_entry);
|
||||
|
||||
if (!var_entry)
|
||||
null_value= 1;
|
||||
else
|
||||
|
||||
if (var_entry)
|
||||
collation.set(var_entry->collation);
|
||||
|
||||
else
|
||||
null_value= 1;
|
||||
|
||||
if (error)
|
||||
thd->fatal_error();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,7 @@ inline THD *_current_thd(void)
|
||||
#include "field.h" /* Field definitions */
|
||||
#include "protocol.h"
|
||||
#include "sql_udf.h"
|
||||
class user_var_entry;
|
||||
#include "item.h"
|
||||
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
|
||||
/* sql_parse.cc */
|
||||
|
@ -233,7 +233,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
|
||||
16);
|
||||
else
|
||||
bzero((char*) &user_var_events, sizeof(user_var_events));
|
||||
|
||||
|
||||
/* Protocol */
|
||||
protocol= &protocol_simple; // Default protocol
|
||||
protocol_simple.init(this);
|
||||
|
@ -1976,86 +1976,59 @@ mysql_execute_command(THD *thd)
|
||||
break;
|
||||
}
|
||||
case SQLCOM_PREPARE:
|
||||
{
|
||||
{
|
||||
char *query_str;
|
||||
uint query_len;
|
||||
if (lex->prepared_stmt_code_is_varref)
|
||||
{
|
||||
/* This is PREPARE stmt FROM @var. */
|
||||
String str;
|
||||
String *pstr;
|
||||
CHARSET_INFO *to_cs= thd->variables.collation_connection;
|
||||
CHARSET_INFO *from_cs;
|
||||
const char *buf;
|
||||
uint buf_len;
|
||||
bool need_conversion;
|
||||
LINT_INIT(from_cs); /* protected by need_conversion */
|
||||
user_var_entry *entry;
|
||||
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.
|
||||
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=
|
||||
(user_var_entry*)hash_search(&thd->user_vars,
|
||||
if ((entry=
|
||||
(user_var_entry*)hash_search(&thd->user_vars,
|
||||
(byte*)lex->prepared_stmt_code.str,
|
||||
lex->prepared_stmt_code.length))
|
||||
&& entry->value)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case REAL_RESULT:
|
||||
str.set(*(double*)entry->value, NOT_FIXED_DEC, to_cs);
|
||||
buf_len= str.length();
|
||||
buf= str.ptr();
|
||||
need_conversion= false;
|
||||
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);
|
||||
}
|
||||
String *pstr;
|
||||
my_bool is_var_null;
|
||||
pstr= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
|
||||
DBUG_ASSERT(!is_var_null);
|
||||
if (!pstr)
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
DBUG_ASSERT(pstr == &str);
|
||||
}
|
||||
else
|
||||
{
|
||||
from_cs= &my_charset_bin;
|
||||
str.set("NULL", 4, from_cs);
|
||||
buf= str.ptr();
|
||||
buf_len= str.length();
|
||||
need_conversion= String::needs_conversion(str.length(), from_cs,
|
||||
to_cs, &unused);
|
||||
}
|
||||
|
||||
query_len = need_conversion? (buf_len * to_cs->mbmaxlen) : buf_len;
|
||||
str.set("NULL", 4, &my_charset_latin1);
|
||||
need_conversion=
|
||||
String::needs_conversion(str.length(), str.charset(), to_cs, &unused);
|
||||
|
||||
query_len= need_conversion? (str.length() * to_cs->mbmaxlen) :
|
||||
str.length();
|
||||
if (!(query_str= alloc_root(&thd->mem_root, query_len+1)))
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
|
||||
|
||||
if (need_conversion)
|
||||
query_len= copy_and_convert(query_str, query_len, to_cs, buf, buf_len,
|
||||
from_cs);
|
||||
query_len= copy_and_convert(query_str, query_len, to_cs, str.ptr(),
|
||||
str.length(), str.charset());
|
||||
else
|
||||
memcpy(query_str, buf, query_len);
|
||||
memcpy(query_str, str.ptr(), str.length());
|
||||
query_str[query_len]= 0;
|
||||
}
|
||||
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.str,
|
||||
query_len, query_str));
|
||||
@ -2068,7 +2041,7 @@ mysql_execute_command(THD *thd)
|
||||
}
|
||||
case SQLCOM_EXECUTE:
|
||||
{
|
||||
DBUG_PRINT("info", ("EXECUTE: %.*s\n",
|
||||
DBUG_PRINT("info", ("EXECUTE: %.*s\n",
|
||||
lex->prepared_stmt_name.length,
|
||||
lex->prepared_stmt_name.str));
|
||||
mysql_sql_stmt_execute(thd, &lex->prepared_stmt_name);
|
||||
@ -3559,7 +3532,6 @@ error:
|
||||
*/
|
||||
|
||||
int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables)
|
||||
|
||||
{
|
||||
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
|
||||
return 1;
|
||||
|
@ -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))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
|
||||
length+= res->length()-1;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
@ -786,7 +786,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
|
||||
#endif /*!EMBEDDED_LIBRARY*/
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Set prepared statement parameters from user variables.
|
||||
SYNOPSIS
|
||||
insert_params_from_vars()
|
||||
@ -796,78 +796,33 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
|
||||
query Ignored
|
||||
*/
|
||||
|
||||
static bool insert_params_from_vars(Prepared_statement *stmt,
|
||||
List<LEX_STRING>& varnames,
|
||||
static bool insert_params_from_vars(Prepared_statement *stmt,
|
||||
List<LEX_STRING>& varnames,
|
||||
String *query __attribute__((unused)))
|
||||
{
|
||||
Item_param **begin= stmt->param_array;
|
||||
Item_param **end= begin + stmt->param_count;
|
||||
user_var_entry *entry;
|
||||
LEX_STRING *varname;
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
List_iterator<LEX_STRING> var_it(varnames);
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
for (Item_param **it= begin; it < end; ++it)
|
||||
{
|
||||
Item_param *param= *it;
|
||||
varname= var_it++;
|
||||
if ((entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
|
||||
(byte*) varname->str,
|
||||
varname->length))
|
||||
&& 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();
|
||||
|
||||
if (param->convert_str_value(stmt->thd))
|
||||
DBUG_RETURN(1); /* out of memory */
|
||||
entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
|
||||
(byte*) varname->str,
|
||||
varname->length);
|
||||
if (param->set_from_user_var(stmt->thd, entry) ||
|
||||
param->convert_str_value(stmt->thd))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
Do the same as insert_params_from_vars but also construct query text for
|
||||
binary log.
|
||||
SYNOPSIS
|
||||
@ -879,14 +834,14 @@ static bool insert_params_from_vars(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 **end= begin + stmt->param_count;
|
||||
user_var_entry *entry;
|
||||
LEX_STRING *varname;
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
DBUG_ENTER("insert_params_from_vars");
|
||||
|
||||
List_iterator<LEX_STRING> var_it(varnames);
|
||||
String str;
|
||||
@ -902,53 +857,10 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||
if (get_var_with_binlog(stmt->thd, *varname, &entry))
|
||||
DBUG_RETURN(1);
|
||||
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;
|
||||
str.length(0);
|
||||
if (str.reserve(entry->name.length*2+3))
|
||||
@ -958,15 +870,15 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
|
||||
ptr= buf;
|
||||
*ptr++= '@';
|
||||
*ptr++= '\'';
|
||||
ptr+=
|
||||
escape_string_for_mysql(&my_charset_utf8_general_ci,
|
||||
ptr+=
|
||||
escape_string_for_mysql(&my_charset_utf8_general_ci,
|
||||
ptr, entry->name.str, entry->name.length);
|
||||
*ptr++= '\'';
|
||||
str.length(ptr - buf);
|
||||
|
||||
if (param->convert_str_value(stmt->thd))
|
||||
DBUG_RETURN(1); /* out of memory */
|
||||
|
||||
|
||||
if (query->replace(param->pos_in_query+length, 1, str))
|
||||
DBUG_RETURN(1);
|
||||
length+= str.length()-1;
|
||||
@ -1837,13 +1749,21 @@ static void reset_stmt_params(Prepared_statement *stmt)
|
||||
Executes previously prepared query.
|
||||
If there is any parameters, then replace markers with the data supplied
|
||||
from client, and then execute the query.
|
||||
SYNOPSYS
|
||||
SYNOPSIS
|
||||
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)
|
||||
{
|
||||
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
|
||||
uchar *packet_end= (uchar *) packet + packet_length - 1;
|
||||
#endif
|
||||
@ -1851,7 +1771,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
||||
DBUG_ENTER("mysql_stmt_execute");
|
||||
|
||||
packet+= 9; /* stmt_id + 5 bytes of flags */
|
||||
|
||||
|
||||
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute",
|
||||
SEND_ERROR)))
|
||||
DBUG_VOID_RETURN;
|
||||
@ -1865,14 +1785,13 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
String expanded_query;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (stmt->param_count)
|
||||
{
|
||||
uchar *null_array= (uchar *) packet;
|
||||
if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
|
||||
stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
|
||||
&expanded_query))
|
||||
&expanded_query))
|
||||
goto set_params_data_err;
|
||||
}
|
||||
#else
|
||||
@ -1890,7 +1809,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
reset_stmt_params(stmt);
|
||||
reset_stmt_params(stmt);
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
|
||||
send_error(thd);
|
||||
DBUG_VOID_RETURN;
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
||||
{
|
||||
Prepared_statement *stmt;
|
||||
/*
|
||||
Query text for binary log, or empty string if the query is not put into
|
||||
binary log.
|
||||
*/
|
||||
String expanded_query;
|
||||
DBUG_ENTER("mysql_sql_stmt_execute");
|
||||
|
||||
|
||||
if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
|
||||
{
|
||||
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)
|
||||
|
||||
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);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
/* Item_param allows setting parameters in COM_EXECUTE only */
|
||||
thd->command= COM_EXECUTE;
|
||||
|
||||
thd->free_list= NULL;
|
||||
thd->stmt_backup.set_statement(thd);
|
||||
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))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
|
||||
send_error(thd);
|
||||
}
|
||||
execute_stmt(thd, stmt, &expanded_query);
|
||||
@ -1945,7 +1867,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
||||
execute_stmt()
|
||||
thd Current thread
|
||||
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
|
||||
string.
|
||||
NOTES
|
||||
@ -1953,7 +1875,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
|
||||
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)
|
||||
{
|
||||
DBUG_ENTER("execute_stmt");
|
||||
@ -1964,9 +1886,9 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
|
||||
thd->set_statement(stmt);
|
||||
}
|
||||
reset_stmt_for_execute(stmt);
|
||||
|
||||
if (expanded_query->length() &&
|
||||
alloc_query(thd, (char *)expanded_query->ptr(),
|
||||
|
||||
if (expanded_query->length() &&
|
||||
alloc_query(thd, (char *)expanded_query->ptr(),
|
||||
expanded_query->length()+1))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
|
||||
@ -1980,14 +1902,11 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
|
||||
/*
|
||||
Free Items that were created during this execution of the PS by query
|
||||
optimizer.
|
||||
*/
|
||||
free_items(thd->free_list);
|
||||
/* Free Items that were created during this execution of the PS. */
|
||||
free_items(thd->free_list);
|
||||
cleanup_items(stmt->free_list);
|
||||
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);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -2138,24 +2057,6 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
|
||||
get_longdata_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()
|
||||
|
@ -764,12 +764,12 @@ verb_clause:
|
||||
| checksum
|
||||
| commit
|
||||
| create
|
||||
| deallocate
|
||||
| deallocate
|
||||
| delete
|
||||
| describe
|
||||
| do
|
||||
| drop
|
||||
| execute
|
||||
| execute
|
||||
| flush
|
||||
| grant
|
||||
| handler
|
||||
@ -781,7 +781,7 @@ verb_clause:
|
||||
| optimize
|
||||
| keycache
|
||||
| preload
|
||||
| prepare
|
||||
| prepare
|
||||
| purge
|
||||
| rename
|
||||
| repair
|
||||
@ -803,7 +803,7 @@ verb_clause:
|
||||
;
|
||||
|
||||
deallocate:
|
||||
DEALLOCATE_SYM PREPARE_SYM ident
|
||||
DEALLOCATE_SYM PREPARE_SYM ident
|
||||
{
|
||||
THD *thd=YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
@ -845,7 +845,7 @@ prepare_src:
|
||||
lex->prepared_stmt_code= $2;
|
||||
lex->prepared_stmt_code_is_varref= true;
|
||||
};
|
||||
|
||||
|
||||
execute:
|
||||
EXECUTE_SYM ident
|
||||
{
|
||||
|
Reference in New Issue
Block a user