diff options
author | monty@mashka.mysql.fi <> | 2002-10-02 13:33:08 +0300 |
---|---|---|
committer | monty@mashka.mysql.fi <> | 2002-10-02 13:33:08 +0300 |
commit | d69250a969449da43891ef5b2859df77917183a8 (patch) | |
tree | 5a27bda6d3f628af7dcb922ad022e84cf8cb351c /sql/sql_prepare.cc | |
parent | 7134ffec210edde21860a2b2c2654be481de49b4 (diff) | |
download | mariadb-git-d69250a969449da43891ef5b2859df77917183a8.tar.gz |
Fixes and code cleanups after merge with 4.0.3
Warning handling and initial prepared statement handling (last not complete yet)
Changed a lot of functions that returned 0/1 to my_bool type.
GRANT handling now uses read/write locks instead of mutex
Change basic net functions to use THD instead of NET
(needed for 4.1 protocol)
Use my_sprintf instead of sprintf() + strlen()
Added alloc_query() to be able to chare query initialization code with
prepared statements.
Cleanup handling of SHOW COUNT(*) WARNINGS and SELECT LAST_INSERT_ID()
Note that the following test fails (will be fixed ASAP):
sub_select, union, rpl_rotate_logs and rpl_mystery22
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r-- | sql/sql_prepare.cc | 548 |
1 files changed, 337 insertions, 211 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d41aca21fb8..05b3f360caa 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -25,7 +25,7 @@ Prepare: store its information list lex->param_list - Without executing the query, return back to client the total number of parameters along with result-set metadata information - (if any ) + (if any) Prepare-execute: @@ -38,46 +38,132 @@ Prepare-execute: to client Long data handling: - - Server gets the long data in pieces with command type 'COM_LONG_DATA'. - The packet recieved will have the format as: - [type_spec_exists][type][length][data] + [COM_LONG_DATA:1][parameter_number:2][type:2][data] - Checks if the type is specified by client, and if yes reads the type, and stores the data in that format. - - If length == MYSQL_END_OF_DATA, then server sets up the data read ended. + - It's up to the client to check for read data ended. The server doesn't + care. + ***********************************************************************/ #include "mysql_priv.h" #include "sql_acl.h" #include <assert.h> // for DEBUG_ASSERT() -#include <ctype.h> // for isspace() +#include <m_ctype.h> // for isspace() -/**************************************************************************/ extern int yyparse(void); static ulong get_param_length(uchar **packet); static uint get_buffer_type(uchar **packet); static bool param_is_null(uchar **packet); static bool setup_param_fields(THD *thd,List<Item> ¶ms); -static uchar* setup_param_field(Item_param *item_param, uchar *pos, uint buffer_type); +static uchar* setup_param_field(Item_param *item_param, uchar *pos, + uint buffer_type); static void setup_longdata_field(Item_param *item_param, uchar *pos); static bool setup_longdata(THD *thd,List<Item> ¶ms); -static void send_prepare_results(THD *thd); -static void mysql_parse_prepare_query(THD *thd,char *packet,uint length); -static bool mysql_send_insert_fields(THD *thd,TABLE_LIST *table_list, +static bool send_prepare_results(PREP_STMT *stmt); +static bool parse_prepare_query(PREP_STMT *stmt, char *packet, uint length); +static bool mysql_send_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, - List<List_item> &values_list,thr_lock_type lock_type); -static bool mysql_test_insert_fields(THD *thd,TABLE_LIST *table_list, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, - List<List_item> &values_list,thr_lock_type lock_type); -static bool mysql_test_upd_fields(THD *thd,TABLE_LIST *table_list, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, COND *conds,thr_lock_type lock_type); -static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, - List<Item> &fields, List<Item> &values, - COND *conds, ORDER *order, ORDER *group, - Item *having,thr_lock_type lock_type); -extern const char *any_db; -/**************************************************************************/ +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, + List<Item> &fields, List<Item> &values, + COND *conds, ORDER *order, ORDER *group, + Item *having,thr_lock_type lock_type); + + +/* + Find prepared statement in thd + + SYNOPSIS + find_prepared_statement() + thd Thread handler + stmt_id Statement id server specified to the client on prepare + + RETURN VALUES + 0 error. In this case the error is sent with my_error() + ptr Pointer to statement +*/ + +static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id, + const char *when) +{ + PREP_STMT *stmt; + DBUG_ENTER("find_prepared_statement"); + DBUG_PRINT("enter",("stmt_id: %d", stmt_id)); + + if (thd->last_prepared_stmt && thd->last_prepared_stmt->stmt_id == stmt_id) + DBUG_RETURN(thd->last_prepared_stmt); + if ((stmt= (PREP_STMT*) tree_search(&thd->prepared_statements, &stmt_id, + (void*) 0))) + DBUG_RETURN (thd->last_prepared_stmt= stmt); + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, when); + DBUG_RETURN(0); +} + +/* + Compare two prepared statements; Used to find a prepared statement +*/ + +int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used) +{ + return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1; +} + + +/* + Free prepared statement. + + SYNOPSIS + standard tree_element_free function. + + DESCRIPTION + We don't have to free the stmt itself as this was stored in the tree + and will be freed when the node is deleted +*/ + +void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used) +{ + free_root(&stmt->mem_root, MYF(0)); + free_items(stmt->free_list); +} + +/* + Send prepared stmt info to client after prepare +*/ + +bool send_prep_stmt(PREP_STMT *stmt, uint columns) +{ + char buff[8]; + int4store(buff, stmt->stmt_id); + int2store(buff+4, columns); + int2store(buff+6, stmt->param_count); + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + +/* + Send information about all item parameters + + TODO: Not yet ready +*/ + +bool send_item_params(PREP_STMT *stmt) +{ + char buff[1]; + buff[0]=0; + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + + /* Read the buffer type, this happens only first time @@ -90,8 +176,13 @@ static uint get_buffer_type(uchar **packet) return (uint) uint2korr(pos); } + /* Check for NULL param data + + RETURN VALUES + 0 Value was not NULL + 1 Value was NULL */ static bool param_is_null(uchar **packet) @@ -144,8 +235,7 @@ static uchar* setup_param_field(Item_param *item_param, item_param->set_null(); return(pos); } - switch (buffer_type) - { + switch (buffer_type) { case FIELD_TYPE_TINY: item_param->set_int((longlong)(*pos)); pos += 1; @@ -169,7 +259,7 @@ static uchar* setup_param_field(Item_param *item_param, case FIELD_TYPE_FLOAT: float data; float4get(data,pos); - item_param->set_double(data); + item_param->set_double((double) data); pos += 4; break; case FIELD_TYPE_DOUBLE: @@ -193,20 +283,19 @@ static uchar* setup_param_field(Item_param *item_param, from client .. */ -static bool setup_param_fields(THD *thd, List<Item> ¶ms) +static bool setup_param_fields(THD *thd, PREP_STMT *stmt) { - reg2 Item_param *item_param; - List_iterator<Item> it(params); - NET *net = &thd->net; DBUG_ENTER("setup_param_fields"); - +#ifdef READY_TO_BE_USED + Item_param *item_param; ulong param_count=0; - uchar *pos=(uchar*)net->read_pos+1;// skip command type - - if(*pos++) // No types supplied, read only param data + uchar *pos=(uchar*) thd->net.read_pos+1;// skip command type + + + if (*pos++) // No types supplied, read only param data { while ((item_param=(Item_param *)it++) && - (param_count++ < thd->param_count)) + (param_count++ < stmt->param_count)) { if (item_param->long_data_supplied) continue; @@ -224,68 +313,15 @@ static bool setup_param_fields(THD *thd, List<Item> ¶ms) continue; if (!(pos=setup_param_field(item_param,pos, - item_param->buffer_type=(enum_field_types)get_buffer_type(&pos)))) + item_param->buffer_type= + (enum_field_types) get_buffer_type(&pos)))) DBUG_RETURN(1); } } +#endif DBUG_RETURN(0); } -/* - Buffer the long data and update the flags -*/ - -static void setup_longdata_field(Item_param *item_param, uchar *pos) -{ - ulong len; - - if (!*pos++) - item_param->buffer_type=(enum_field_types)get_buffer_type(&pos); - - if (*pos == MYSQL_LONG_DATA_END) - item_param->set_long_end(); - - else - { - len = get_param_length(&pos); - item_param->set_longdata((const char *)pos, len); - } -} - -/* - Store the long data from client in pieces -*/ - -static bool setup_longdata(THD *thd, List<Item> ¶ms) -{ - NET *net=&thd->net; - List_iterator<Item> it(params); - DBUG_ENTER("setup_longdata"); - - uchar *pos=(uchar*)net->read_pos+1;// skip command type at first position - ulong param_number = get_param_length(&pos); - Item_param *item_param = thd->current_param; - - if (thd->current_param_number != param_number) - { - thd->current_param_number = param_number; - while (param_number--) /* TODO: - Change this loop by either having operator '+' - overloaded to point to desired 'item' or - add another memeber in list as 'goto' with - location count as parameter number, but what - is the best way to traverse ? - */ - { - it++; - } - thd->current_param = item_param = (Item_param *)it++; - } - setup_longdata_field(item_param,pos); - DBUG_RETURN(0); -} - - /* Validates insert fields @@ -337,16 +373,15 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields, Validate the following information for INSERT statement: - field existance - fields count - - If there is no column list spec exists, then update the field_list - with all columns from the table, and send fields info back to client */ -static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, +static bool mysql_test_insert_fields(PREP_STMT *stmt, + TABLE_LIST *table_list, List<Item> &fields, List<List_item> &values_list, thr_lock_type lock_type) { + THD *thd= stmt->thd; TABLE *table; List_iterator_fast<List_item> its(values_list); List_item *values; @@ -358,7 +393,7 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, if ((values= its++)) { uint value_count; - ulong counter=0; + ulong counter= 0; if (check_insert_fields(thd,table,fields,*values,1)) DBUG_RETURN(1); @@ -366,35 +401,20 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, value_count= values->elements; its.rewind(); - while ((values = its++)) + while ((values= its++)) { counter++; if (values->elements != value_count) { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0),counter); + MYF(0), counter); DBUG_RETURN(1); } } - if (fields.elements == 0) - { - /* No field listing, so setup all fields */ - List<Item> all_fields; - Field **ptr,*field; - for (ptr=table->field; (field= *ptr) ; ptr++) - { - all_fields.push_back(new Item_field(table->table_cache_key, - table->real_name, - field->field_name)); - } - if ((setup_fields(thd,table_list,all_fields,1,0,0) || - send_fields(thd,all_fields,1))) - DBUG_RETURN(1); - } - else if (send_fields(thd,fields,1)) - DBUG_RETURN(1); } + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) + DBUG_RETURN(1); DBUG_RETURN(0); } @@ -403,15 +423,16 @@ static bool mysql_test_insert_fields(THD *thd, TABLE_LIST *table_list, Validate the following information UPDATE - set and where clause DELETE - where clause - And send update-set cluase column list fields info - back to client. For DELETE, just validate where cluase + 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. */ -static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, List<Item> &fields, List<Item> &values, COND *conds, thr_lock_type lock_type) { + THD *thd= stmt->thd; TABLE *table; DBUG_ENTER("mysql_test_upd_fields"); @@ -426,9 +447,8 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, Currently return only column list info only, and we are not sending any info on where clause. */ - if (fields.elements && send_fields(thd,fields,1)) + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) DBUG_RETURN(1); - DBUG_RETURN(0); } @@ -437,7 +457,7 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, SELECT - column list - where clause - - orderr clause + - order clause - having clause - group by clause - if no column spec i.e. '*', then setup all fields @@ -445,13 +465,14 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, And send column list fields info back to client. */ -static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, List<Item> &fields, List<Item> &values, COND *conds, ORDER *order, ORDER *group, Item *having, thr_lock_type lock_type) { TABLE *table; bool hidden_group_fields; + THD *thd= stmt->thd; List<Item> all_fields(fields); DBUG_ENTER("mysql_test_select_fields"); @@ -482,13 +503,15 @@ static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, Currently return only column list info only, and we are not sending any info on where clause. */ - if (fields.elements && send_fields(thd,fields,1)) + if (send_prep_stmt(stmt, fields.elements) || + send_fields(thd,fields,0) || send_item_params(stmt)) DBUG_RETURN(1); DBUG_RETURN(0); } + /* - Check the access privileges + Check the access privileges */ static bool check_prepare_access(THD *thd, TABLE_LIST *tables, @@ -505,42 +528,47 @@ static bool check_prepare_access(THD *thd, TABLE_LIST *tables, Send the prepare query results back to client */ -static void send_prepare_results(THD *thd) +static bool send_prepare_results(PREP_STMT *stmt) { - DBUG_ENTER("send_prepare_results"); + THD *thd= stmt->thd; + LEX *lex= &thd->lex; enum enum_sql_command sql_command = thd->lex.sql_command; - - DBUG_PRINT("enter",("command :%d, param_count :%ld", - sql_command,thd->param_count)); + DBUG_ENTER("send_prepare_results"); + DBUG_PRINT("enter",("command: %d, param_count: %ld", + sql_command, lex->param_count)); - LEX *lex=&thd->lex; + /* Setup prepared stmt */ + stmt->param_count= lex->param_count; + stmt->free_list= thd->free_list; // Save items used in stmt + thd->free_list= 0; + SELECT_LEX *select_lex = lex->select; TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; - switch(sql_command) { + switch (sql_command) { case SQLCOM_INSERT: - if (mysql_test_insert_fields(thd,tables, lex->field_list, + if (mysql_test_insert_fields(stmt, tables, lex->field_list, lex->many_values, lex->lock_option)) goto abort; break; case SQLCOM_UPDATE: - if (mysql_test_upd_fields(thd,tables, select_lex->item_list, + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, lex->lock_option)) goto abort; break; case SQLCOM_DELETE: - if (mysql_test_upd_fields(thd,tables, select_lex->item_list, + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, lex->lock_option)) goto abort; break; case SQLCOM_SELECT: - if (mysql_test_select_fields(thd,tables, select_lex->item_list, + if (mysql_test_select_fields(stmt, tables, select_lex->item_list, lex->value_list, select_lex->where, (ORDER*) select_lex->order_list.first, (ORDER*) select_lex->group_list.first, @@ -556,42 +584,37 @@ static void send_prepare_results(THD *thd) */ } } - send_ok(&thd->net,thd->param_count,0); - DBUG_VOID_RETURN; + DBUG_RETURN(0); abort: - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); - DBUG_VOID_RETURN; + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); + DBUG_RETURN(1); } /* Parse the prepare query */ -static void mysql_parse_prepare_query(THD *thd, char *packet, uint length) +static bool parse_prepare_query(PREP_STMT *stmt, + char *packet, uint length) { - DBUG_ENTER("mysql_parse_prepare_query"); + bool error= 1; + THD *thd= stmt->thd; + DBUG_ENTER("parse_prepare_query"); mysql_log.write(thd,COM_PREPARE,"%s",packet); mysql_init_query(thd); thd->prepare_command=true; + thd->safe_to_cache_query= 0; - if (query_cache.send_result_to_client(thd, packet, length) <= 0) - { - LEX *lex=lex_start(thd, (uchar*)packet, length); - - if (!yyparse() && !thd->fatal_error) - { - send_prepare_results(thd); - query_cache_end_of_result(&thd->net); - } - else - query_cache_abort(&thd->net); - lex_end(lex); - } - DBUG_VOID_RETURN; + LEX *lex=lex_start(thd, (uchar*) packet, length); + if (!yyparse() && !thd->fatal_error) + error= send_prepare_results(stmt); + lex_end(lex); + DBUG_RETURN(error); } + /* Parse the query and send the total number of parameters and resultset metadata information back to client (if any), @@ -606,52 +629,36 @@ static void mysql_parse_prepare_query(THD *thd, char *packet, uint length) items. */ -void mysql_com_prepare(THD *thd, char *packet, uint packet_length) +bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { MEM_ROOT thd_root = thd->mem_root; - DBUG_ENTER("mysql_com_prepare"); - - packet_length--; - - while (isspace(packet[0]) && packet_length > 0) - { - packet++; - packet_length--; - } - char *pos=packet+packet_length; - while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1]))) - { - pos--; - packet_length--; - } - /* - Have the prepare items to have a connection level scope or - till next prepare statement by doing all allocations using - connection level memory allocator 'con_root' from THD. - */ - free_root(&thd->con_root,MYF(0)); - init_sql_alloc(&thd->con_root,8192,8192); - thd->mem_root = thd->con_root; - - if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), - packet_length, - thd->db_length+2))) - DBUG_VOID_RETURN; - thd->query[packet_length]=0; - thd->packet.shrink(net_buffer_length); - thd->query_length = packet_length; + PREP_STMT stmt; + bool error; + DBUG_ENTER("mysql_stmt_prepare"); - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); - - mysql_parse_prepare_query(thd,thd->query,packet_length); + bzero((char*) &stmt, sizeof(stmt)); + stmt.thd= thd; + stmt.stmt_id= ++thd->current_stmt_id; + init_sql_alloc(&stmt.mem_root, 8192, 8192); + + thd->mem_root= stmt.mem_root; + if (alloc_query(thd, packet, packet_length)) + goto err; + if (parse_prepare_query(&stmt, thd->query, thd->query_length)) + goto err; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); - thd->mem_root = thd_root; // restore main mem_root - DBUG_PRINT("exit",("prepare query ready")); - DBUG_VOID_RETURN; + stmt.mem_root= thd->mem_root; + thd->mem_root= thd_root; // restore main mem_root + DBUG_RETURN(0); + +err: + stmt.mem_root= thd->mem_root; + free_prep_stmt(&stmt, free_free, (void*) 0); + thd->mem_root = thd_root; // restore main mem_root + DBUG_RETURN(1); } @@ -663,47 +670,166 @@ void mysql_com_prepare(THD *thd, char *packet, uint packet_length) execute the query */ -void mysql_com_execute(THD *thd) +void mysql_stmt_execute(THD *thd, char *packet) { - MEM_ROOT thd_root=thd->mem_root; - DBUG_ENTER("mysql_com_execute"); - DBUG_PRINT("enter", ("parameters : %ld", thd->param_count)); + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_execute"); - thd->mem_root = thd->con_root; - if (thd->param_count && setup_param_fields(thd, thd->lex.param_list)) + if (!(stmt=find_prepared_statement(thd, stmt_id, "execute"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + /* Check if we got an error when sending long data */ + if (stmt->error_in_prepare) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + if (stmt->param_count && setup_param_fields(thd, stmt)) DBUG_VOID_RETURN; - + + MEM_ROOT thd_root= thd->mem_root; + thd->mem_root = thd->con_root; if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - /* TODO: + /* + 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 .. */ - mysql_execute_command(); + mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),WAIT_PRIOR); + my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->mem_root = (MEM_ROOT )thd_root; - DBUG_PRINT("exit",("prepare-execute done!")); + thd->mem_root= thd_root; DBUG_VOID_RETURN; } + /* - Long data in pieces from client + Reset a prepared statement + + SYNOPSIS + mysql_stmt_reset() + thd Thread handle + packet Packet with stmt handle + + DESCRIPTION + This function is useful when one gets an error after calling + mysql_stmt_getlongdata() and one wants to reset the handle + so that one can call execute again. */ -void mysql_com_longdata(THD *thd) +void mysql_stmt_reset(THD *thd, char *packet) { - DBUG_ENTER("mysql_com_execute"); + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_reset"); - if(thd->param_count && setup_longdata(thd,thd->lex.param_list)) - DBUG_VOID_RETURN; - - send_ok(&thd->net,0,0);// ok status to client - DBUG_PRINT("exit",("longdata-buffering done!")); + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + stmt->error_in_prepare=0; + Item_param *item= stmt->param, *end= item + stmt->param_count; + + /* Free long data if used */ + if (stmt->long_data_used) + { + stmt->long_data_used= 0; + for (; item < end ; item++) + item->reset(); + } + DBUG_VOID_RETURN; +} + + +/* + Delete a prepared statement from memory +*/ + +void mysql_stmt_close(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_close"); + + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + /* Will call free_prep_stmt() */ + tree_delete(&thd->prepared_statements, (void*) stmt, NULL); + thd->last_prepared_stmt=0; DBUG_VOID_RETURN; } + +/* + Long data in pieces from client + + SYNOPSIS + mysql_stmt_get_longdata() + thd Thread handle + pos String to append + packet_length Length of string + + DESCRIPTION + Get a part of a long data. + To make the protocol efficient, we are not sending any return packages + here. + If something goes wrong, then we will send the error on 'execute' + + We assume that the client takes care of checking that all parts are sent + to the server. (No checking that we get a 'end of column' in the server) +*/ + +void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) +{ + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_get_longdata"); + + /* The following should never happen */ + if (packet_length < 9) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata"); + DBUG_VOID_RETURN; + } + + pos++; // skip command type at first position + ulong stmt_id= uint4korr(pos); + uint param_number= uint2korr(pos+4); + uint param_type= uint2korr(pos+6); + pos+=8; // Point to data + + if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata"))) + { + /* + There is a chance that the client will never see this as + it doesn't expect an answer from this call... + */ + send_error(thd); + DBUG_VOID_RETURN; + } + + if (param_number >= stmt->param_count) + { + stmt->error_in_prepare=1; + stmt->last_errno=ER_WRONG_ARGUMENTS; + sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata"); + DBUG_VOID_RETURN; + } + stmt->param[param_number].set_longdata(pos, packet_length-9); + stmt->long_data_used= 1; + DBUG_VOID_RETURN; +} |