summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/my_sys.h1
-rw-r--r--sql/item.h4
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/protocol.h5
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h28
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc24
-rw-r--r--sql/sql_prepare.cc733
-rw-r--r--sql/sql_yacc.yy14
-rw-r--r--tests/client_test.c2
11 files changed, 436 insertions, 394 deletions
diff --git a/include/my_sys.h b/include/my_sys.h
index 6547022601d..6d22301f5d8 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -714,6 +714,7 @@ extern void my_free_lock(byte *ptr,myf flags);
#define my_free_lock(A,B) my_free((A),(B))
#endif
#define alloc_root_inited(A) ((A)->min_malloc != 0)
+#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT))
extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
uint pre_alloc_size);
extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
diff --git a/sql/item.h b/sql/item.h
index fb93e0ef8ab..59c030f3db5 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -375,9 +375,9 @@ public:
bool get_time(TIME *tm);
void reset() {}
#ifndef EMBEDDED_LIBRARY
- void (*setup_param_func)(Item_param *param, uchar **pos);
+ void (*set_param_func)(Item_param *param, uchar **pos);
#else
- void (*setup_param_func)(Item_param *param, uchar **pos, ulong data_len);
+ void (*set_param_func)(Item_param *param, uchar **pos, ulong data_len);
#endif
enum Item_result result_type () const
{ return item_result_type; }
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 535c1cb16be..2d22d9c5891 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -620,14 +620,13 @@ int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
/* sql_prepare.cc */
-bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
+void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
void mysql_stmt_execute(THD *thd, char *packet);
void mysql_stmt_free(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter);
-void setup_param_functions(Item_param *param, uchar param_type);
/* sql_error.cc */
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
diff --git a/sql/protocol.h b/sql/protocol.h
index 67ae4ed01b4..17c8f0d321d 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -178,8 +178,3 @@ char *net_store_data(char *to,const char *from, uint length);
char *net_store_data(char *to,int32 from);
char *net_store_data(char *to,longlong from);
-#ifdef EMBEDDED_LIBRARY
-bool setup_params_data(struct st_prep_stmt *stmt);
-bool setup_params_data_withlog(struct st_prep_stmt *stmt);
-#endif
-
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6fe0521b07a..95374b691c8 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -145,8 +145,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
init();
/* Initialize sub structures */
- bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
- bzero((char*) &warn_root,sizeof(warn_root));
+ clear_alloc_root(&transaction.mem_root);
init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
user_connect=(USER_CONN *)0;
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
@@ -331,7 +330,7 @@ THD::~THD()
dbug_sentry = THD_SENTRY_GONE;
#endif
/* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */
- init_alloc_root(&stmt_backup.mem_root, 0, 0);
+ clear_alloc_root(&stmt_backup.mem_root);
DBUG_VOID_RETURN;
}
@@ -1185,10 +1184,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
Statement::Statement(THD *thd)
:id(++thd->statement_id_counter),
- query_id(thd->query_id),
set_query_id(1),
allow_sum_func(0),
- command(thd->command),
lex(&main_lex),
query(0),
query_length(0),
@@ -1207,10 +1204,8 @@ Statement::Statement(THD *thd)
Statement::Statement()
:id(0),
- query_id(0), /* initialized later */
set_query_id(1),
allow_sum_func(0), /* initialized later */
- command(COM_SLEEP), /* initialized later */
lex(&main_lex),
query(0), /* these two are set */
query_length(0), /* in alloc_query() */
@@ -1229,15 +1224,11 @@ Statement::Type Statement::type() const
void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
- query_id= stmt->query_id;
set_query_id= stmt->set_query_id;
allow_sum_func= stmt->allow_sum_func;
- command= stmt->command;
lex= stmt->lex;
query= stmt->query;
query_length= stmt->query_length;
- free_list= stmt->free_list;
- mem_root= stmt->mem_root;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index d0ad8a4e681..567135b1378 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -435,15 +435,6 @@ public:
ulong id;
/*
- Id of current query. Statement can be reused to execute several queries
- query_id is global in context of the whole MySQL server.
- ID is automatically generated from mutex-protected counter.
- It's used in handler code for various purposes: to check which columns
- from table are necessary for this select, to check if it's necessary to
- update auto-updatable fields (like auto_increment and timestamp).
- */
- ulong query_id;
- /*
- if set_query_id=1, we set field->query_id for all fields. In that case
field list can not contain duplicates.
*/
@@ -461,11 +452,6 @@ public:
See item_sum.cc for details.
*/
bool allow_sum_func;
- /*
- Type of current query: COM_PREPARE, COM_QUERY, etc. Set from
- first byte of the packet in do_command()
- */
- enum enum_server_command command;
LEX *lex; // parse tree descriptor
/*
@@ -676,6 +662,11 @@ public:
uint dbug_sentry; // watch out for memory corruption
#endif
struct st_my_thread_var *mysys_var;
+ /*
+ Type of current query: COM_PREPARE, COM_QUERY, etc. Set from
+ first byte of the packet in do_command()
+ */
+ enum enum_server_command command;
uint32 server_id;
uint32 file_id; // for LOAD DATA INFILE
/*
@@ -751,6 +742,15 @@ public:
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
+ /*
+ Id of current query. Statement can be reused to execute several queries
+ query_id is global in context of the whole MySQL server.
+ ID is automatically generated from mutex-protected counter.
+ It's used in handler code for various purposes: to check which columns
+ from table are necessary for this select, to check if it's necessary to
+ update auto-updatable fields (like auto_increment and timestamp).
+ */
+ ulong query_id;
ulong warn_id, version, options, thread_id, col_access;
/* Statement id is thread-wide. This counter is used to generate ids */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 17cccd75697..ba8fe0d8792 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -552,7 +552,7 @@ typedef struct st_lex
List<Item> *insert_list,field_list,value_list;
List<List_item> many_values;
List<set_var_base> var_list;
- List<Item> param_list;
+ List<Item_param> param_list;
SQL_LIST proc_list, auxilliary_table_list, save_list;
TYPELIB *interval;
create_field *last_field;
@@ -577,7 +577,6 @@ typedef struct st_lex
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
- uint param_count;
uint slave_thd_opt;
uint8 describe;
bool drop_if_exists, drop_temporary, local_file;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a09f3d28a0f..99a8a248d24 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1232,10 +1232,34 @@ bool do_command(THD *thd)
command_name[command]));
}
net->read_timeout=old_timeout; // restore it
+ /*
+ packet_length contains length of data, as it was stored in packet
+ header. In case of malformed header, packet_length can be zero.
+ If packet_length is not zero, my_net_read ensures that this number
+ of bytes was actually read from network. Additionally my_net_read
+ sets packet[packet_length]= 0 (thus if packet_length == 0,
+ command == packet[0] == COM_SLEEP).
+ In dispatch_command packet[packet_length] points beyond the end of packet.
+ */
DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
}
#endif /* EMBEDDED_LIBRARY */
+/*
+ Perform one connection-level (COM_XXXX) command.
+ SYNOPSIS
+ dispatch_command()
+ thd connection handle
+ command type of command to perform
+ packet data for the command, packet is always null-terminated
+ packet_length length of packet + 1 (to show that data is
+ null-terminated) except for COM_SLEEP, where it
+ can be zero.
+ RETURN VALUE
+ 0 ok
+ 1 request of thread shutdown, i. e. if command is
+ COM_QUIT/COM_SHUTDOWN
+*/
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length)
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7c2913bc495..ac5b7847647 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -39,7 +39,7 @@ Prepare-execute:
- Server gets the command 'COM_EXECUTE' to execute the
previously prepared query. If there is any param markers; then client
- will send the data in the following format:
+ will send the data in the following format:
[COM_EXECUTE:1]
[STMT_ID:4]
[NULL_BITS:(param_count+7)/8)]
@@ -86,16 +86,17 @@ class Prepared_statement: public Statement
{
public:
THD *thd;
- Item_param **param; /* array of all placeholders */
+ Item_param **param_array;
uint param_count;
uint last_errno;
char last_error[MYSQL_ERRMSG_SIZE];
- bool error_in_prepare, long_data_used;
+ bool get_longdata_error;
+ bool long_data_used;
bool log_full_query;
#ifndef EMBEDDED_LIBRARY
- bool (*setup_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
+ bool (*set_params)(Prepared_statement *st, uchar *pos, uchar *read_pos);
#else
- bool (*setup_params_data)(Prepared_statement *st);
+ bool (*set_params_data)(Prepared_statement *st);
#endif
public:
Prepared_statement(THD *thd_arg);
@@ -117,13 +118,14 @@ inline bool is_param_null(const uchar *pos, ulong param_no)
enum { STMT_QUERY_LOG_LENGTH= 8192 };
#ifdef EMBEDDED_LIBRARY
-#define SETUP_PARAM_FUNCTION(fn_name) \
+#define SET_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos, ulong data_len)
#else
-#define SETUP_PARAM_FUNCTION(fn_name) \
+#define SET_PARAM_FUNCTION(fn_name) \
static void fn_name(Item_param *param, uchar **pos)
#endif
+enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
/*
Seek prepared statement in statement map by id: returns zero if statement
@@ -131,14 +133,16 @@ static void fn_name(Item_param *param, uchar **pos)
*/
static Prepared_statement *
-find_prepared_statement(THD *thd, ulong id, const char *where)
+find_prepared_statement(THD *thd, ulong id, const char *where,
+ enum enum_send_error se)
{
Statement *stmt= thd->stmt_map.find(id);
if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT)
{
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), id, where);
- send_error(thd);
+ if (se == SEND_ERROR)
+ send_error(thd);
return 0;
}
return (Prepared_statement *) stmt;
@@ -154,11 +158,11 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
{
NET *net= &stmt->thd->net;
char buff[9];
- buff[0]= 0;
+ buff[0]= 0; /* OK packet indicator */
int4store(buff+1, stmt->id);
int2store(buff+5, columns);
int2store(buff+7, stmt->param_count);
- /* This should be fixed to work with prepared statements */
+ /* TODO: send types of placeholders here */
return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
}
#else
@@ -177,8 +181,8 @@ static bool send_prep_stmt(Prepared_statement *stmt,
/*
- Read the length of the parameter data and retun back to
- caller by positing the pointer to param data
+ Read the length of the parameter data and return back to
+ caller by positing the pointer to param data.
*/
#ifndef EMBEDDED_LIBRARY
@@ -208,49 +212,49 @@ static ulong get_param_length(uchar **packet)
#endif /*!EMBEDDED_LIBRARY*/
/*
- Setup param conversion routines
-
- setup_param_xx()
- param Parameter Item
- pos Input data buffer
+ Data conversion routines
+ SYNOPSIS
+ set_param_xx()
+ param parameter item
+ pos input data buffer
+ len length of data in the buffer
- All these functions reads the data from pos and sets up that data
- through 'param' and advances the buffer position to predifined
- length position.
+ All these functions read the data from pos, convert it to requested type
+ and assign to param; pos is advanced to predefined length.
Make a note that the NULL handling is examined at first execution
(i.e. when input types altered) and for all subsequent executions
we don't read any values for this.
- RETURN VALUES
-
+ RETURN VALUE
+ none
*/
-SETUP_PARAM_FUNCTION(setup_param_tiny)
+SET_PARAM_FUNCTION(set_param_tiny)
{
param->set_int((longlong)(**pos));
*pos+= 1;
}
-SETUP_PARAM_FUNCTION(setup_param_short)
+SET_PARAM_FUNCTION(set_param_short)
{
param->set_int((longlong)sint2korr(*pos));
*pos+= 2;
}
-SETUP_PARAM_FUNCTION(setup_param_int32)
+SET_PARAM_FUNCTION(set_param_int32)
{
param->set_int((longlong)sint4korr(*pos));
*pos+= 4;
}
-SETUP_PARAM_FUNCTION(setup_param_int64)
+SET_PARAM_FUNCTION(set_param_int64)
{
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
}
-SETUP_PARAM_FUNCTION(setup_param_float)
+SET_PARAM_FUNCTION(set_param_float)
{
float data;
float4get(data,*pos);
@@ -258,7 +262,7 @@ SETUP_PARAM_FUNCTION(setup_param_float)
*pos+= 4;
}
-SETUP_PARAM_FUNCTION(setup_param_double)
+SET_PARAM_FUNCTION(set_param_double)
{
double data;
float8get(data,*pos);
@@ -266,14 +270,14 @@ SETUP_PARAM_FUNCTION(setup_param_double)
*pos+= 8;
}
-SETUP_PARAM_FUNCTION(setup_param_time)
+SET_PARAM_FUNCTION(set_param_time)
{
ulong length;
if ((length= get_param_length(pos)))
{
uchar *to= *pos;
- TIME tm;
+ TIME tm;
tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
@@ -290,11 +294,11 @@ SETUP_PARAM_FUNCTION(setup_param_time)
*pos+= length;
}
-SETUP_PARAM_FUNCTION(setup_param_datetime)
+SET_PARAM_FUNCTION(set_param_datetime)
{
- uint length= get_param_length(pos);
+ uint length;
- if (length)
+ if ((length= get_param_length(pos)))
{
uchar *to= *pos;
TIME tm;
@@ -320,7 +324,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime)
*pos+= length;
}
-SETUP_PARAM_FUNCTION(setup_param_date)
+SET_PARAM_FUNCTION(set_param_date)
{
ulong length;
@@ -342,55 +346,55 @@ SETUP_PARAM_FUNCTION(setup_param_date)
*pos+= length;
}
-SETUP_PARAM_FUNCTION(setup_param_str)
+SET_PARAM_FUNCTION(set_param_str)
{
ulong len= get_param_length(pos);
param->set_value((const char *)*pos, len);
- *pos+= len;
+ *pos+= len;
}
-void setup_param_functions(Item_param *param, uchar param_type)
+static void setup_one_conversion_function(Item_param *param, uchar param_type)
{
switch (param_type) {
case FIELD_TYPE_TINY:
- param->setup_param_func= setup_param_tiny;
+ param->set_param_func= set_param_tiny;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_SHORT:
- param->setup_param_func= setup_param_short;
+ param->set_param_func= set_param_short;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_LONG:
- param->setup_param_func= setup_param_int32;
+ param->set_param_func= set_param_int32;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_LONGLONG:
- param->setup_param_func= setup_param_int64;
+ param->set_param_func= set_param_int64;
param->item_result_type= INT_RESULT;
break;
case FIELD_TYPE_FLOAT:
- param->setup_param_func= setup_param_float;
+ param->set_param_func= set_param_float;
param->item_result_type= REAL_RESULT;
break;
case FIELD_TYPE_DOUBLE:
- param->setup_param_func= setup_param_double;
+ param->set_param_func= set_param_double;
param->item_result_type= REAL_RESULT;
break;
case FIELD_TYPE_TIME:
- param->setup_param_func= setup_param_time;
+ param->set_param_func= set_param_time;
param->item_result_type= STRING_RESULT;
break;
case FIELD_TYPE_DATE:
- param->setup_param_func= setup_param_date;
+ param->set_param_func= set_param_date;
param->item_result_type= STRING_RESULT;
break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- param->setup_param_func= setup_param_datetime;
+ param->set_param_func= set_param_datetime;
param->item_result_type= STRING_RESULT;
break;
default:
- param->setup_param_func= setup_param_str;
+ param->set_param_func= set_param_str;
param->item_result_type= STRING_RESULT;
}
}
@@ -404,11 +408,11 @@ void setup_param_functions(Item_param *param, uchar param_type)
static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
uchar *read_pos)
{
- THD *thd= stmt->thd;
- List<Item> &params= stmt->lex->param_list;
- List_iterator<Item> param_iterator(params);
- Item_param *param;
-
+ THD *thd= stmt->thd;
+ Item_param **begin= stmt->param_array;
+ Item_param **end= begin + stmt->param_count;
+ uint32 length= 0;
+
String str, query;
const String *res;
@@ -417,16 +421,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
if (query.copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
- ulong param_no= 0;
- uint32 length= 0;
-
- while ((param= (Item_param *)param_iterator++))
+ for (Item_param **it= begin; it < end; ++it)
{
+ Item_param *param= *it;
if (param->long_data_supplied)
- res= param->query_val_str(&str);
+ res= param->query_val_str(&str);
else
{
- if (is_param_null(pos,param_no))
+ if (is_param_null(pos, it - begin))
{
param->maybe_null= param->null_value= 1;
res= &my_null_string;
@@ -434,7 +436,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
else
{
param->maybe_null= param->null_value= 0;
- param->setup_param_func(param,&read_pos);
+ param->set_param_func(param, &read_pos);
res= param->query_val_str(&str);
}
}
@@ -442,7 +444,6 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
DBUG_RETURN(1);
length+= res->length()-1;
- param_no++;
}
if (alloc_query(thd, (char *)query.ptr(), query.length()+1))
DBUG_RETURN(1);
@@ -454,73 +455,68 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos,
static bool insert_params(Prepared_statement *stmt, uchar *pos,
uchar *read_pos)
{
- List<Item> &params= stmt->lex->param_list;
- List_iterator<Item> param_iterator(params);
- Item_param *param;
- ulong param_no= 0;
+ Item_param **begin= stmt->param_array;
+ Item_param **end= begin + stmt->param_count;
DBUG_ENTER("insert_params");
- while ((param= (Item_param *)param_iterator++))
+ for (Item_param **it= begin; it < end; ++it)
{
- if (!param->long_data_supplied)
+ Item_param *param= *it;
+ if (!param->long_data_supplied)
{
- if (is_param_null(pos,param_no))
+ if (is_param_null(pos, it - begin))
param->maybe_null= param->null_value= 1;
else
{
param->maybe_null= param->null_value= 0;
- param->setup_param_func(param,&read_pos);
+ param->set_param_func(param, &read_pos);
}
}
- param_no++;
}
DBUG_RETURN(0);
}
-static bool setup_params_data(Prepared_statement *stmt)
-{
- List<Item> &params= stmt->lex->param_list;
- List_iterator<Item> param_iterator(params);
- Item_param *param;
-
- uchar *pos= (uchar*) stmt->thd->net.read_pos + 1 +
- MYSQL_STMT_HEADER; //skip header
- uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits
+static bool setup_conversion_functions(Prepared_statement *stmt,
+ uchar **data)
+{
+ /* skip null bits */
+ uchar *read_pos= *data + (stmt->param_count+7) / 8;
- DBUG_ENTER("setup_params_data");
+ DBUG_ENTER("setup_conversion_functions");
if (*read_pos++) //types supplied / first execute
- {
+ {
/*
First execute or types altered by the client, setup the
conversion routines for all parameters (one time)
*/
- while ((param= (Item_param *)param_iterator++))
- {
- setup_param_functions(param,*read_pos);
+ Item_param **it= stmt->param_array;
+ Item_param **end= it + stmt->param_count;
+ for (; it < end; ++it)
+ {
+ setup_one_conversion_function(*it, *read_pos);
read_pos+= 2;
}
- param_iterator.rewind();
- }
- stmt->setup_params(stmt,pos,read_pos);
+ }
+ *data= read_pos;
DBUG_RETURN(0);
}
#else
-bool setup_params_data(Prepared_statement *stmt)
-{
- List<Item> &params= stmt->lex->param_list;
- List_iterator<Item> param_iterator(params);
- Item_param *param;
+static bool emb_insert_params(Prepared_statement *stmt)
+{
+ Item_param **it= stmt->param_array;
+ Item_param **end= it + stmt->param_count;
MYSQL_BIND *client_param= stmt->thd->client_params;
- DBUG_ENTER("setup_params_data");
+ DBUG_ENTER("emb_insert_params");
- for (;(param= (Item_param *)param_iterator++); client_param++)
- {
- setup_param_functions(param, client_param->buffer_type);
+ for (; it < end; ++it, ++client_param)
+ {
+ Item_param *param= *it;
+ setup_one_conversion_function(param, client_param->buffer_type);
if (!param->long_data_supplied)
{
if (*client_param->is_null)
@@ -529,39 +525,39 @@ bool setup_params_data(Prepared_statement *stmt)
{
uchar *buff= (uchar*)client_param->buffer;
param->maybe_null= param->null_value= 0;
- param->setup_param_func(param,&buff,
- client_param->length ?
- *client_param->length :
- client_param->buffer_length);
+ param->set_param_func(param, &buff,
+ client_param->length ?
+ *client_param->length :
+ client_param->buffer_length);
}
}
}
DBUG_RETURN(0);
}
-bool setup_params_data_withlog(Prepared_statement *stmt)
-{
+
+static bool emb_insert_params_withlog(Prepared_statement *stmt)
+{
THD *thd= stmt->thd;
- List<Item> &params= stmt->lex->param_list;
- List_iterator<Item> param_iterator(params);
- Item_param *param;
+ Item_param **it= stmt->param_array;
+ Item_param **end= it + stmt->param_count;
MYSQL_BIND *client_param= thd->client_params;
String str, query;
const String *res;
+ uint32 length= 0;
- DBUG_ENTER("setup_params_data_withlog");
+ DBUG_ENTER("emb_insert_params_withlog");
if (query.copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
- uint32 length= 0;
-
- for (;(param= (Item_param *)param_iterator++); client_param++)
- {
- setup_param_functions(param, client_param->buffer_type);
+ for (; it < end; ++it, ++client_param)
+ {
+ Item_param *param= *it;
+ setup_one_conversion_function(param, client_param->buffer_type);
if (param->long_data_supplied)
- res= param->query_val_str(&str);
+ res= param->query_val_str(&str);
else
{
if (*client_param->is_null)
@@ -573,16 +569,15 @@ bool setup_params_data_withlog(Prepared_statement *stmt)
{
uchar *buff= (uchar*)client_param->buffer;
param->maybe_null= param->null_value= 0;
- param->setup_param_func(param,&buff,
- client_param->length ?
- *client_param->length :
- client_param->buffer_length);
+ param->set_param_func(param, &buff,
+ client_param->length ?
+ *client_param->length :
+ client_param->buffer_length);
res= param->query_val_str(&str);
}
}
if (query.replace(param->pos_in_query+length, 1, *res))
DBUG_RETURN(1);
-
length+= res->length()-1;
}
@@ -595,15 +590,21 @@ bool setup_params_data_withlog(Prepared_statement *stmt)
#endif /*!EMBEDDED_LIBRARY*/
/*
- Validate the following information for INSERT statement:
- - field existance
- - fields count
+ Validate the following information for INSERT statement:
+ - field existence
+ - fields count
+ SYNOPSIS
+ mysql_test_insert_fields()
+ RETURN VALUE
+ 0 ok
+ 1 error, sent to the client
+ -1 error, not sent to client
*/
-static bool mysql_test_insert_fields(Prepared_statement *stmt,
- TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list)
+static int mysql_test_insert_fields(Prepared_statement *stmt,
+ TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<List_item> &values_list)
{
THD *thd= stmt->thd;
TABLE *table;
@@ -630,7 +631,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
if (open_and_lock_tables(thd, table_list))
{
thd->free_temporary_memory_pool_for_ps_preparing();
- DBUG_RETURN(1);
+ DBUG_RETURN(-1);
}
table= table_list->table;
@@ -643,7 +644,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
if (check_insert_fields(thd,table,fields,*values,1))
{
thd->free_temporary_memory_pool_for_ps_preparing();
- DBUG_RETURN(1);
+ DBUG_RETURN(-1);
}
thd->free_temporary_memory_pool_for_ps_preparing();
@@ -658,7 +659,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
MYF(0), counter);
- DBUG_RETURN(1);
+ DBUG_RETURN(-1);
}
}
}
@@ -666,25 +667,26 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
{
thd->free_temporary_memory_pool_for_ps_preparing();
}
- if (send_prep_stmt(stmt, 0))
- DBUG_RETURN(1);
DBUG_RETURN(0);
}
/*
- Validate the following information
- UPDATE - set and where clause DELETE - where clause
-
- And send update-set clause column list fields info
- back to client. For DELETE, just validate where clause
- and return no fields information back to client.
+ Validate the following information:
+ UPDATE - set and where clause
+ DELETE - where clause
+ SYNOPSIS
+ mysql_test_upd_fields()
+ RETURN VALUE
+ 0 success
+ 1 error, sent to client
+ -1 error, not sent to client
*/
-static bool mysql_test_upd_fields(Prepared_statement *stmt,
- TABLE_LIST *table_list,
- List<Item> &fields, List<Item> &values,
- COND *conds)
+static int mysql_test_upd_fields(Prepared_statement *stmt,
+ TABLE_LIST *table_list,
+ List<Item> &fields, List<Item> &values,
+ COND *conds)
{
THD *thd= stmt->thd;
@@ -711,44 +713,43 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
thd->free_temporary_memory_pool_for_ps_preparing();
- /*
- Currently return only column list info only, and we are not
- sending any info on where clause.
- */
- if (send_prep_stmt(stmt, 0))
- DBUG_RETURN(1);
+ /* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0);
err:
thd->free_temporary_memory_pool_for_ps_preparing();
- DBUG_RETURN(1);
+ DBUG_RETURN(-1);
}
/*
- Validate the following information:
-
+ Validate the following information:
SELECT - column list
- where clause
- order clause
- having clause
- group by clause
- if no column spec i.e. '*', then setup all fields
-
- And send column list fields info back to client.
+ In case of success, if this query is not EXPLAIN, send column list info
+ back to client.
+ SYNOPSIS
+ mysql_test_select_fields()
+ RETURN VALUE
+ 0 success
+ 1 error, sent to client
+ -1 error, not sent to client
*/
-static bool mysql_test_select_fields(Prepared_statement *stmt,
- TABLE_LIST *tables,
- uint wild_num,
- List<Item> &fields, COND *conds,
- uint og_num, ORDER *order, ORDER *group,
- Item *having, ORDER *proc,
- ulong select_options,
- SELECT_LEX_UNIT *unit,
- SELECT_LEX *select_lex)
+static int mysql_test_select_fields(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ uint wild_num,
+ List<Item> &fields, COND *conds,
+ uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc,
+ ulong select_options,
+ SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- select_result *result= lex->result;
DBUG_ENTER("mysql_test_select_fields");
@@ -772,7 +773,10 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
*/
thd->allocate_temporary_memory_pool_for_ps_preparing();
if (open_and_lock_tables(thd, tables))
+ {
+ send_error(thd);
goto err;
+ }
if (lex->describe)
{
@@ -781,23 +785,27 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
}
else
{
+ select_result *result= lex->result;
if (!result && !(result= new select_send()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
goto err;
}
- thd->used_tables= 0; // Updated by setup_fields
+ thd->used_tables= 0; // Updated by setup_fields
if (unit->prepare(thd, result, 0))
+ {
+ send_error(thd);
goto err_prep;
+ }
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY
- || net_flush(&thd->net)
+ || net_flush(&thd->net)
#endif
- )
+ )
goto err_prep;
unit->cleanup();
@@ -814,97 +822,104 @@ err:
/*
- Send the prepare query results back to client
+ Send the prepare query results back to client
+ SYNOPSIS
+ send_prepare_results()
+ stmt prepared statement
+ RETURN VALUE
+ 0 success
+ 1 error, sent to client
*/
-static bool send_prepare_results(Prepared_statement *stmt)
+static int send_prepare_results(Prepared_statement *stmt)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
enum enum_sql_command sql_command= lex->sql_command;
+ int res;
DBUG_ENTER("send_prepare_results");
DBUG_PRINT("enter",("command: %d, param_count: %ld",
- sql_command, lex->param_count));
-
- /* Setup prepared stmt */
- stmt->param_count= lex->param_count;
-
- SELECT_LEX *select_lex= &lex->select_lex;
- TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
+ sql_command, stmt->param_count));
switch (sql_command) {
case SQLCOM_INSERT:
- if (mysql_test_insert_fields(stmt, tables, lex->field_list,
- lex->many_values))
- goto abort;
+ if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list,
+ lex->many_values)))
+ goto error;
break;
case SQLCOM_UPDATE:
- if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
- lex->value_list, select_lex->where))
- goto abort;
- break;
-
+ /* XXX: fallthrough */
case SQLCOM_DELETE:
- if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
- lex->value_list, select_lex->where))
- goto abort;
+ if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list,
+ lex->value_list, select_lex->where)))
+ goto error;
break;
case SQLCOM_SELECT:
- if (mysql_test_select_fields(stmt, tables, select_lex->with_wild,
- select_lex->item_list,
- select_lex->where,
- select_lex->order_list.elements +
- select_lex->group_list.elements,
- (ORDER*) select_lex->order_list.first,
- (ORDER*) select_lex->group_list.first,
- select_lex->having,
- (ORDER*)lex->proc_list.first,
- select_lex->options | thd->options,
- &(lex->unit), select_lex))
- goto abort;
- break;
+ if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild,
+ select_lex->item_list,
+ select_lex->where,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*)lex->proc_list.first,
+ select_lex->options | thd->options,
+ &(lex->unit), select_lex)))
+ goto error;
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(0);
default:
- {
- /*
- Rest fall through to default category, no parsing
- for non-DML statements
- */
- if (send_prep_stmt(stmt, 0))
- goto abort;
- }
+ /*
+ Rest fall through to default category, no parsing
+ for non-DML statements
+ */
+ break;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(send_prep_stmt(stmt, 0));
-abort:
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+error:
+ if (res < 0)
+ send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
DBUG_RETURN(1);
}
/*
- Initialize parameter items in statement
+ Initialize array of parametes in statement from LEX.
+ (We need to have quick access to items by number in mysql_send_longdata).
+ This is to avoid using malloc/realloc in the parser.
*/
-static bool init_param_items(Prepared_statement *stmt)
+static bool init_param_array(Prepared_statement *stmt)
{
- Item_param **to;
-
- if (!stmt->param_count)
- stmt->param= (Item_param **)0;
- else
- {
- if (!(stmt->param= to= (Item_param **)
- my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
- MYF(MY_WME))))
+ LEX *lex= stmt->lex;
+ if ((stmt->param_count= lex->param_list.elements))
+ {
+ Item_param **to;
+ List_iterator<Item_param> param_iterator(lex->param_list);
+ /* Use thd->mem_root as it points at statement mem_root */
+ stmt->param_array= (Item_param **)
+ alloc_root(&stmt->thd->mem_root,
+ sizeof(Item_param*) * stmt->param_count);
+ if (!stmt->param_array)
+ {
+ send_error(stmt->thd, ER_OUT_OF_RESOURCES);
return 1;
-
- List_iterator<Item> param_iterator(stmt->lex->param_list);
- while ((*(to++)= (Item_param *)param_iterator++));
- }
+ }
+ for (to= stmt->param_array;
+ to < stmt->param_array + stmt->param_count;
+ ++to)
+ {
+ *to= param_iterator++;
+ }
+ }
return 0;
}
@@ -912,137 +927,104 @@ static bool init_param_items(Prepared_statement *stmt)
/*
Parse the query and send the total number of parameters
and resultset metadata information back to client (if any),
- without executing the query i.e. with out any log/disk
+ without executing the query i.e. without any log/disk
writes. This will allow the queries to be re-executed
- without re-parsing during execute.
-
- If parameter markers are found in the query, then store
- the information using Item_param along with maintaining a
- list in lex->param_list, so that a fast and direct
- retrieval can be made without going through all field
- items.
+ without re-parsing during execute.
+
+ If parameter markers are found in the query, then store
+ the information using Item_param along with maintaining a
+ list in lex->param_array, so that a fast and direct
+ retrieval can be made without going through all field
+ items.
*/
-bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
+void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
{
LEX *lex;
Prepared_statement *stmt= new Prepared_statement(thd);
- SELECT_LEX *sl;
+ int error;
DBUG_ENTER("mysql_stmt_prepare");
if (stmt == 0)
- DBUG_RETURN(0);
+ {
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
if (thd->stmt_map.insert(stmt))
- goto insert_stmt_err;
+ {
+ delete stmt;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
thd->stmt_backup.set_statement(thd);
+ thd->stmt_backup.set_item_arena(thd);
thd->set_statement(stmt);
- thd->current_statement= stmt;
+ thd->set_item_arena(stmt);
if (alloc_query(thd, packet, packet_length))
- goto alloc_query_err;
+ {
+ stmt->set_statement(thd);
+ stmt->set_item_arena(thd);
+ thd->set_statement(&thd->stmt_backup);
+ thd->set_item_arena(&thd->stmt_backup);
+ /* Statement map deletes statement on erase */
+ thd->stmt_map.erase(stmt);
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
- mysql_log.write(thd, COM_PREPARE, "%s", packet);
+ mysql_log.write(thd, COM_PREPARE, "%s", packet);
+ thd->current_statement= stmt;
lex= lex_start(thd, (uchar *) thd->query, thd->query_length);
mysql_init_query(thd);
lex->safe_to_cache_query= 0;
- lex->param_count= 0;
- if (yyparse((void *)thd) || thd->is_fatal_error || send_prepare_results(stmt))
- goto yyparse_err;
-
- lex_end(lex);
+ error= yyparse((void *)thd) || thd->is_fatal_error ||
+ init_param_array(stmt) ||
+ send_prepare_results(stmt);
+ /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
-
- // save WHERE clause pointers to avoid damaging they by optimisation
- for (sl= thd->lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
- {
- sl->prep_where= sl->where;
- }
-
- stmt->set_statement(thd);
- thd->set_statement(&thd->stmt_backup);
- thd->current_statement= 0;
-
- if (init_param_items(stmt))
- goto init_param_err;
-
- stmt->command= COM_EXECUTE; // set it only once here
-
- DBUG_RETURN(0);
-
-yyparse_err:
lex_end(lex);
stmt->set_statement(thd);
+ stmt->set_item_arena(thd);
thd->set_statement(&thd->stmt_backup);
-init_param_err:
-alloc_query_err:
- /* Statement map deletes statement on erase */
- thd->stmt_map.erase(stmt);
- thd->current_statement= 0;
- DBUG_RETURN(1);
-insert_stmt_err:
- stmt->set_statement(thd);
- thd->set_statement(&thd->stmt_backup);
- /* Statement map deletes statement on erase */
- thd->stmt_map.erase(stmt);
+ thd->set_item_arena(&thd->stmt_backup);
thd->current_statement= 0;
- delete stmt;
- DBUG_RETURN(1);
-}
-
-
-/*
- Executes previously prepared query
- If there is any parameters (stmt->param_count), then replace
- markers with the data supplied from client, and then
- execute the query
-*/
-
-void mysql_stmt_execute(THD *thd, char *packet)
-{
- ulong stmt_id= uint4korr(packet);
- Prepared_statement *stmt;
-
- DBUG_ENTER("mysql_stmt_execute");
-
- if (!(stmt= find_prepared_statement(thd, stmt_id, "execute")))
- DBUG_VOID_RETURN;
-
- /* Check if we got an error when sending long data */
- if (stmt->error_in_prepare)
+ if (error)
{
- send_error(thd, stmt->last_errno, stmt->last_error);
- DBUG_VOID_RETURN;
+ /* Statement map deletes statement on erase */
+ thd->stmt_map.erase(stmt);
+ /* error is sent inside yyparse/send_prepare_results */
}
+ else
+ {
+ SELECT_LEX *sl= stmt->lex->all_selects_list;
+ /*
+ Save WHERE clause pointers, because they may be changed during query
+ optimisation.
+ */
+ for (; sl; sl= sl->next_select_in_list())
+ {
+ sl->prep_where= sl->where;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
- stmt->query_id= thd->query_id;
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
- thd->free_list= 0;
-
- /*
- To make sure that all runtime data is stored in its own memory root and
- does not interfere with data possibly present in thd->mem_root.
- This root is cleaned up in the end of execution.
- FIXME: to be replaced with more efficient approach, and verified why we
- can not use thd->mem_root safely.
- */
- init_sql_alloc(&thd->mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
+/* Reinit statement before execution */
+static void reset_stmt_for_execute(Prepared_statement *stmt)
+{
+ THD *thd= stmt->thd;
+ SELECT_LEX *sl= stmt->lex->all_selects_list;
- for (SELECT_LEX *sl= stmt->lex->all_selects_list;
- sl;
- sl= sl->next_select_in_list())
+ for (; sl; sl= sl->next_select_in_list())
{
/*
Copy WHERE clause pointers to avoid damaging they by optimisation
@@ -1075,58 +1057,104 @@ void mysql_stmt_execute(THD *thd, char *packet)
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
unit->types.empty();
- // for derived tables & PS (which can't be reset by Item_subquery)
+ /* for derived tables & PS (which can't be reset by Item_subquery) */
unit->reinit_exec_mechanism();
}
}
+}
+
+/*
+ Executes previously prepared query.
+ If there is any parameters, then replace markers with the data supplied
+ from client, and then execute the query.
+ SYNOPSYS
+ mysql_stmt_execute()
+*/
+
+
+void mysql_stmt_execute(THD *thd, char *packet)
+{
+ ulong stmt_id= uint4korr(packet);
+ Prepared_statement *stmt;
+
+ DBUG_ENTER("mysql_stmt_execute");
+
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR)))
+ DBUG_VOID_RETURN;
+
+ /* Check if we got an error when sending long data */
+ if (stmt->get_longdata_error)
+ {
+ send_error(thd, stmt->last_errno, stmt->last_error);
+ DBUG_VOID_RETURN;
+ }
+
+ thd->stmt_backup.set_statement(thd);
+ thd->set_statement(stmt);
+ reset_stmt_for_execute(stmt);
#ifndef EMBEDDED_LIBRARY
- if (stmt->param_count && setup_params_data(stmt))
- goto end;
+ if (stmt->param_count)
+ {
+ packet+= 4;
+ uchar *null_array= (uchar *) packet;
+ if (setup_conversion_functions(stmt, (uchar **) &packet) ||
+ stmt->set_params(stmt, null_array, (uchar *) packet))
+ goto set_params_data_err;
+ }
#else
- if (stmt->param_count && (*stmt->setup_params_data)(stmt))
- goto end;
+ /*
+ In embedded library we re-install conversion routines each time
+ we set params, and also we don't need to parse packet.
+ So we do it in one function.
+ */
+ if (stmt->param_count && stmt->set_params_data(stmt))
+ goto set_params_data_err;
#endif
if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
/*
TODO:
Also, have checks on basic executions such as mysql_insert(),
mysql_delete(), mysql_update() and mysql_select() to not to
have re-check on setup_* and other things ..
- */
- thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ */
+ thd->protocol= &thd->protocol_prep; // Switch to binary protocol
mysql_execute_command(thd);
- thd->protocol= &thd->protocol_simple; // Use normal protocol
+ thd->protocol= &thd->protocol_simple; // Use normal protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- free_items(thd->free_list);
cleanup_items(stmt->free_list);
close_thread_tables(thd); // to close derived tables
- free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup);
-end:
+ DBUG_VOID_RETURN;
+
+set_params_data_err:
+ thd->set_statement(&thd->stmt_backup);
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
+ send_error(thd);
DBUG_VOID_RETURN;
}
/*
- Reset a prepared statement
-
+ Reset a prepared statement, in case there was an error in send_longdata.
+ Note: we don't send any reply to that command.
SYNOPSIS
mysql_stmt_reset()
thd Thread handle
- packet Packet with stmt handle
+ packet Packet with stmt id
DESCRIPTION
This function is useful when one gets an error after calling
- mysql_stmt_getlongdata() and one wants to reset the handle
+ mysql_stmt_getlongdata() and wants to reset the handle
so that one can call execute again.
+ See also bug #1664
*/
void mysql_stmt_reset(THD *thd, char *packet)
@@ -1136,25 +1164,27 @@ void mysql_stmt_reset(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_reset");
- if (!(stmt= find_prepared_statement(thd, stmt_id, "reset")))
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "reset", DONT_SEND_ERROR)))
DBUG_VOID_RETURN;
- stmt->error_in_prepare= 0;
- Item_param *item= *stmt->param, *end= item + stmt->param_count;
+ stmt->get_longdata_error= 0;
/* Free long data if used */
if (stmt->long_data_used)
{
+ Item_param **item= stmt->param_array;
+ Item_param **end= item + stmt->param_count;
stmt->long_data_used= 0;
for (; item < end ; item++)
- item->reset();
+ (**item).reset();
}
DBUG_VOID_RETURN;
}
/*
- Delete a prepared statement from memory
+ Delete a prepared statement from memory.
+ Note: we don't send any reply to that command.
*/
void mysql_stmt_free(THD *thd, char *packet)
@@ -1164,7 +1194,7 @@ void mysql_stmt_free(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_free");
- if (!(stmt= find_prepared_statement(thd, stmt_id, "close")))
+ if (!(stmt= find_prepared_statement(thd, stmt_id, "close", DONT_SEND_ERROR)))
DBUG_VOID_RETURN;
/* Statement map deletes statement on erase */
@@ -1174,7 +1204,7 @@ void mysql_stmt_free(THD *thd, char *packet)
/*
- Long data in pieces from client
+ Long data in pieces from client
SYNOPSIS
mysql_stmt_get_longdata()
@@ -1210,14 +1240,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
ulong stmt_id= uint4korr(pos);
uint param_number= uint2korr(pos+4);
- if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata",
+ DONT_SEND_ERROR)))
DBUG_VOID_RETURN;
#ifndef EMBEDDED_LIBRARY
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
- stmt->error_in_prepare= 1;
+ stmt->get_longdata_error= 1;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
DBUG_VOID_RETURN;
@@ -1225,7 +1256,7 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
pos+= MYSQL_LONG_DATA_HEADER; // Point to data
#endif
- Item_param *param= *(stmt->param+param_number);
+ Item_param *param= stmt->param_array[param_number];
#ifndef EMBEDDED_LIBRARY
param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
#else
@@ -1239,10 +1270,10 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
Prepared_statement::Prepared_statement(THD *thd_arg)
:Statement(thd_arg),
thd(thd_arg),
- param(0),
+ param_array(0),
param_count(0),
last_errno(0),
- error_in_prepare(0),
+ get_longdata_error(0),
long_data_used(0),
log_full_query(0)
{
@@ -1251,23 +1282,22 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
{
log_full_query= 1;
#ifndef EMBEDDED_LIBRARY
- setup_params= insert_params_withlog;
+ set_params= insert_params_withlog;
#else
- setup_params_data= setup_params_data_withlog;
+ set_params_data= emb_insert_params_withlog;
#endif
}
else
#ifndef EMBEDDED_LIBRARY
- setup_params= insert_params; // not fully qualified query
+ set_params= insert_params;
#else
- setup_params_data= ::setup_params_data;
+ set_params_data= emb_insert_params;
#endif
}
Prepared_statement::~Prepared_statement()
{
- my_free((char *) param, MYF(MY_ALLOW_ZERO_PTR));
free_items(free_list);
}
@@ -1277,4 +1307,3 @@ Statement::Type Prepared_statement::type() const
return PREPARED_STATEMENT;
}
-
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 4a098cc6fc0..7df1973132a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4478,11 +4478,17 @@ text_string:
param_marker:
'?'
{
- LEX *lex=Lex;
- if (YYTHD->command == COM_PREPARE)
+ THD *thd=YYTHD;
+ LEX *lex= thd->lex;
+ if (thd->command == COM_PREPARE)
{
- lex->param_list.push_back($$=new Item_param((uint)(lex->tok_start-(uchar *)YYTHD->query)));
- lex->param_count++;
+ Item_param *item= new Item_param((uint) (lex->tok_start -
+ (uchar *) thd->query));
+ if (!($$= item) || lex->param_list.push_back(item))
+ {
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ YYABORT;
+ }
}
else
{
diff --git a/tests/client_test.c b/tests/client_test.c
index 3b9aefc6ec2..fa0b65c2928 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -8470,8 +8470,6 @@ int main(int argc, char **argv)
start_time= time((time_t *)0);
- test_subqueries();
-
client_query(); /* simple client query test */
#if NOT_YET_WORKING
/* Used for internal new development debugging */