diff --git a/include/my_sys.h b/include/my_sys.h index 3e34e1a9ac38d51d0930aad26d489e9bcf0659ad..41bd4ba5b2d711892eda8e6802dc26016bfc0577 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 fb93e0ef8abac077da5fcfd3d1bd83106c2117dc..59c030f3db57a1eaa2afbae87b175a2462bb1f4b 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 535c1cb16be75cee1afca9bddaaeb91b9567fc2d..2d22d9c5891c2a5f6f471ff3f9aba6c5368a872b 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 67ae4ed01b41b699d0cb1f0b12102f1024f8f4ff..17c8f0d321d54f0f035d5051a72da79dfb4f7368 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 6fe0521b07ad6d61a6c956d83c80237782d22dd8..95374b691c8a37d02c1cad5e8657ca59a2599b4f 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 d0ad8a4e68111d4b996969e7d036a9ef41ae6099..567135b1378f1b3bb0c132ae808984c7162056b2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -434,15 +434,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 17cccd75697ff04c8f1efca01e34f62fa1e33e05..ba8fe0d879293df4a68c7fb33128bdcdf3f08dc2 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 a09f3d28a0f25c2a25fc3f937cb04faed30ac7a0..99a8a248d244fe183392e0dbefb3f67d323b998b 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 7c2913bc495976d81b690746d4ccb3697fd46886..ac5b7847647c96fe6fc877a457fd50ea004709f5 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> ¶ms= 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> ¶ms= 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> ¶ms= 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> ¶ms= 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> ¶ms= 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 4a098cc6fc04ca0444849b1fc409b8aa40ca657a..7df1973132a2de378eb90663a7340b13b6c94c9a 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 3b9aefc6ec211b33bd0389c2d295c6feb3ec08f2..fa0b65c2928a41c4e1a03ea982622fdfd9258a5f 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 */