diff options
Diffstat (limited to 'libmysql/libmysql.c')
-rw-r--r-- | libmysql/libmysql.c | 437 |
1 files changed, 274 insertions, 163 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 7135488aade..6ad4e020464 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -84,7 +84,6 @@ my_bool net_flush(NET *net); #define MAX_LONG_DATA_LENGTH 8192 #define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG) -static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data); static void append_wild(char *to,char *end,const char *wild); sig_handler pipe_sig_handler(int sig); @@ -1667,6 +1666,11 @@ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row); static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row); static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); +/* + This function is used in mysql_stmt_store_result if + STMT_ATTR_UPDATE_MAX_LENGTH attribute is set. +*/ +static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data); /* Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME @@ -1674,19 +1678,19 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); */ /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */ -static const unsigned MAX_DATE_REP_LENGTH= 5; +#define MAX_DATE_REP_LENGTH 5 /* 1 (length) + 1 (is negative) + 4 (day count) + 1 (hour) + 1 (minute) + 1 (seconds) + 4 (microseconds) */ -static const unsigned MAX_TIME_REP_LENGTH= 13; +#define MAX_TIME_REP_LENGTH 13 /* 1 (length) + 2 (year) + 1 (month) + 1 (day) + 1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds) */ -static const unsigned MAX_DATETIME_REP_LENGTH= 12; +#define MAX_DATETIME_REP_LENGTH 12 /**************** Misc utility functions ****************************/ @@ -1947,7 +1951,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) mysql_stmt_free_result(stmt); /* - These members must be reset for API to + These members must be reset for API to function in case of error or misuse. */ stmt->bind_param_done= stmt->bind_result_done= FALSE; @@ -1986,14 +1990,14 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) } /* - alloc_root will return valid address even in case param_count + alloc_root will return valid address even in case param_count and field_count are zero. Thus we should never rely on stmt->bind or stmt->params when checking for existence of placeholders or result set. */ if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root, sizeof(MYSQL_BIND)* - (stmt->param_count + + (stmt->param_count + stmt->field_count)))) { set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); @@ -2017,22 +2021,22 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) MYSQL_FIELD *fields, *field, *end; MEM_ROOT *alloc= &stmt->mem_root; MYSQL *mysql= stmt->mysql->last_used_con; - + stmt->field_count= mysql->field_count; - + /* - Get the field information for non-select statements + Get the field information for non-select statements like SHOW and DESCRIBE commands */ - if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, + if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, sizeof(MYSQL_FIELD) * - stmt->field_count)) || - !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, + stmt->field_count)) || + !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, sizeof(MYSQL_BIND) * stmt->field_count))) return 0; - - for (fields= mysql->fields, end= fields+stmt->field_count, + + for (fields= mysql->fields, end= fields+stmt->field_count, field= stmt->fields; field && fields < end; fields++, field++) { @@ -2109,7 +2113,7 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt) { MYSQL_RES *result; DBUG_ENTER("mysql_stmt_result_metadata"); - + /* stmt->fields is only defined if stmt->field_count is not null; stmt->field_count is initialized in prepare. @@ -2132,41 +2136,65 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt) DBUG_RETURN(result); } + /* Returns parameter columns meta information in the form of result set. - XXX: not implemented yet. + + SYNOPSYS + mysql_stmt_param_metadata() + stmt statement handle + + DESCRIPTION + This function can be called after you prepared the statement handle + with mysql_stmt_prepare(). + XXX: not implemented yet. + + RETURN + MYSQL_RES on success, 0 if there is no metadata. + Currently this function always returns 0. */ MYSQL_RES * STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt) { DBUG_ENTER("mysql_stmt_param_metadata"); - + if (!stmt->param_count) DBUG_RETURN(0); /* - TODO: Fix this when server sends the information. - Till then keep a dummy prototype + TODO: Fix this when server sends the information. + Till then keep a dummy prototype. */ DBUG_RETURN(0); } +/* Store type of parameter in network buffer. */ + +static void store_param_type(char **pos, MYSQL_BIND *param) +{ + uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0); + int2store(*pos, typecode); + *pos+= 2; +} + + /* Functions to store parameter data in network packet. - All functions have the following characteristics: - SYNOPSIS store_param_xxx() net MySQL NET connection param MySQL bind param - RETURN VALUES - 0 ok - 1 Error (Can't alloc net->buffer) + DESCRIPTION + These funtions are invoked from mysql_stmt_execute by + MYSQL_BIND::store_param_func pointer. This pointer is set once per many + executions in mysql_stmt_bind_param. The caller must ensure that network + buffer have enough capacity to store parameter (MYSQL_BIND::buffer_length + contains needed number of bytes). */ static void store_param_tinyint(NET *net, MYSQL_BIND *param) @@ -2255,7 +2283,7 @@ static void net_store_datetime(NET *net, MYSQL_TIME *tm) length= 4; else length= 0; - buff[0]= (char) length++; + buff[0]= (char) length++; memcpy((char *)net->write_pos, buff, length); net->write_pos+= length; } @@ -2273,7 +2301,7 @@ static void store_param_datetime(NET *net, MYSQL_BIND *param) MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; net_store_datetime(net, tm); } - + static void store_param_str(NET *net, MYSQL_BIND *param) { /* param->length is always set in mysql_stmt_bind_param */ @@ -2294,7 +2322,8 @@ static void store_param_str(NET *net, MYSQL_BIND *param) DESCRIPTION A data package starts with a string of bits where we set a bit - if a parameter is NULL + if a parameter is NULL. Unlike bit string in result set row, here + we don't have reserved bits for OK/error packet. */ static void store_param_null(NET *net, MYSQL_BIND *param) @@ -2305,8 +2334,9 @@ static void store_param_null(NET *net, MYSQL_BIND *param) /* - Set parameter data by reading from input buffers from the - client application + Store one parameter in network packet: data is read from + client buffer and saved in network packet by means of one + of store_param_xxxx functions. */ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) @@ -2338,14 +2368,15 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) /* - Send the prepared query to server for execution + Auxilary function to send COM_EXECUTE packet to server and read reply. + Used from cli_stmt_execute, which is in turn used by mysql_stmt_execute. */ -static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) +static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length) { MYSQL *mysql= stmt->mysql; NET *net= &mysql->net; - char buff[4 /* size of stmt id */ + + char buff[4 /* size of stmt id */ + 5 /* execution flags */]; DBUG_ENTER("execute"); DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); @@ -2365,14 +2396,6 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) stmt->insert_id= mysql->insert_id; DBUG_RETURN(0); } - - -static void store_param_type(char **pos, MYSQL_BIND *param) -{ - uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0); - int2store(*pos, typecode); - *pos+= 2; -} int cli_stmt_execute(MYSQL_STMT *stmt) @@ -2415,7 +2438,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt) for (param= stmt->params; param < param_end; param++) { - /* check if mysql_long_data() was used */ + /* check if mysql_stmt_send_long_data() was used */ if (param->long_data_used) param->long_data_used= 0; /* Clear for next execute call */ else if (store_param(stmt, param)) @@ -2474,16 +2497,16 @@ static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row) 0 - success; *row contains valid address of a row; row data is stored in network buffer 1 - error; error code is written to - stmt->last_{errno,error}; *row is not changed + stmt->last_{errno,error}; *row is not changed MYSQL_NO_DATA - end of file was read from network; - *row is to NULL + *row is set to NULL */ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row) { int rc= 1; MYSQL *mysql= stmt->mysql; - /* + /* This function won't be called if stmt->field_count is zero or execution wasn't done: this is ensured by mysql_stmt_execute. */ @@ -2557,7 +2580,7 @@ stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)), 0 success !0 wrong attribute type */ - + my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *value) @@ -2566,14 +2589,14 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, case STMT_ATTR_UPDATE_MAX_LENGTH: stmt->update_max_length= value ? *(const my_bool*) value : 0; break; - default: + default: return TRUE; } return FALSE; } -my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, +my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *value) { @@ -2581,7 +2604,7 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, case STMT_ATTR_UPDATE_MAX_LENGTH: *(unsigned long *) value= stmt->update_max_length; break; - default: + default: return TRUE; } return FALSE; @@ -2589,7 +2612,47 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, /* - Execute the prepared query + Send placeholders data to server (if there are placeholders) + and execute prepared statement. + + SYNOPSIS + mysql_stmt_execute() + stmt statement handle. The handle must be created + with mysql_stmt_init() and prepared with + mysql_stmt_prepare(). If there are placeholders + in the statement they must be bound to local + variables with mysql_stmt_bind_param(). + + DESCRIPTION + This function will automatically flush pending result + set (if there is one), send parameters data to the server + and read result of statement execution. + If previous result set was cached with mysql_stmt_store_result() + it will also be freed in the beginning of this call. + The server can return 3 types of responses to this command: + - error, can be retrieved with mysql_stmt_error() + - ok, no result set pending. In this case we just update + stmt->insert_id and stmt->affected_rows. + - the query returns a result set: there could be 0 .. N + rows in it. In this case the server can also send updated + result set metadata. + + Next steps you may want to make: + - find out if there is result set with mysql_stmt_field_count(). + If there is one: + - optionally, cache entire result set on client to unblock + connection with mysql_stmt_store_result() + - bind client variables to result set columns and start read rows + with mysql_stmt_fetch(). + - reset statement with mysql_stmt_reset() or close it with + mysql_stmt_close() + Otherwise: + - find out last insert id and number of affected rows with + mysql_stmt_insert_id(), mysql_stmt_affected_rows() + + RETURN + 0 success + 1 error, message can be retrieved with mysql_stmt_error(). */ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) @@ -2683,7 +2746,19 @@ unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt) } /* - Return last inserted id for auto_increment columns + Return last inserted id for auto_increment columns. + + SYNOPSIS + mysql_stmt_insert_id() + stmt statement handle + + DESCRIPTION + Current implementation of this call has a caveat: stmt->insert_id is + unconditionally updated from mysql->insert_id in the end of each + mysql_stmt_execute(). This works OK if mysql->insert_id contains new + value (sent in reply to mysql_stmt_execute()), otherwise stmt->insert_id + value gets undefined, as it's updated from some arbitrary value saved in + connection structure during some other call. */ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt) @@ -2695,11 +2770,24 @@ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt) static my_bool int_is_null_true= 1; /* Used for MYSQL_TYPE_NULL */ static my_bool int_is_null_false= 0; + /* - Setup the parameter data buffers from application + Setup the input parameter data buffers from application + + SYNOPSIS + mysql_stmt_bind_param() + stmt statement handle + The statement must be prepared with mysql_stmt_prepare(). + bind Array of mysql_stmt_param_count() bind parameters. + + RETURN + 0 success + 1 error, can be retrieved with mysql_stmt_error. + Note, that this function doesn't check that size of MYSQL_BIND + array is >= mysql_stmt_field_count(), */ -my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) +my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind) { uint count=0; MYSQL_BIND *param, *end; @@ -2787,9 +2875,8 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) case MYSQL_TYPE_STRING: param->store_param_func= store_param_str; /* - For variable length types we expect user to set - length or buffer_length. Otherwise mysql_stmt_execute - will just fail. + For variable length types user must set either length or + buffer_length. */ break; default: @@ -2806,7 +2893,7 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) if (!param->length) param->length= ¶m->buffer_length; } - /* We have to send/resendtype information to MySQL */ + /* We have to send/resend type information to MySQL */ stmt->send_types_to_server= TRUE; stmt->bind_param_done= TRUE; DBUG_RETURN(0); @@ -2827,6 +2914,30 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) data Data to send to server length Length of data to send (may be 0) + DESCRIPTION + This call can be used repeatedly to send long data in pieces + for any string/binary placeholder. Data supplied for + a placeholder is saved at server side till execute, and then + used instead of value from MYSQL_BIND object. More precisely, + if long data for a parameter was supplied, MYSQL_BIND object + corresponding to this parameter is not sent to server. In the + end of execution long data states of placeholders are reset, + so next time values of such placeholders will be taken again + from MYSQL_BIND array. + The server does not reply to this call: if there was an error + in data handling (which now only can happen if server run out + of memory) it would be returned in reply to + mysql_stmt_execute(). + You should choose type of long data carefully if you care + about character set conversions performed by server when the + statement is executed. No conversion is performed at all for + MYSQL_TYPE_BLOB and other binary typecodes. For + MYSQL_TYPE_STRING and the rest of text placeholders data is + converted from client character set to character set of + connection. If these character sets are different, this + conversion may require additional memory at server, equal to + total size of supplied pieces. + RETURN VALUES 0 ok 1 error @@ -2841,7 +2952,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, DBUG_ASSERT(stmt != 0); DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld", param_number, data, length)); - + /* We only need to check for stmt->param_count, if it's not null prepare was done. @@ -2866,7 +2977,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, DBUG_RETURN(1); } - /* + /* Send long data packet if there is data or we're sending long data for the first time. */ @@ -2874,8 +2985,8 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, { MYSQL *mysql= stmt->mysql; /* Packet header: stmt id (4 bytes), param no (2 bytes) */ - char buff[MYSQL_LONG_DATA_HEADER]; - + char buff[MYSQL_LONG_DATA_HEADER]; + int4store(buff, stmt->stmt_id); int2store(buff + 4, param_number); param->long_data_used= 1; @@ -2928,7 +3039,7 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos) { uchar *to; uint length; - + /* net_field_length will set pos to the first byte of data */ if (!(length= net_field_length(pos))) { @@ -2985,14 +3096,14 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos) { uchar *to; uint length; - + if (!(length= net_field_length(pos))) { set_zero_time(tm); return 0; } - - to= *pos; + + to= *pos; tm->year = (uint) sint2korr(to); tm->month= (uint) to[2]; tm->day= (uint) to[3]; @@ -3006,7 +3117,7 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos) /* Convert Numeric to buffer types */ static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field, longlong value) -{ +{ char *buffer= param->buffer; uint field_is_unsigned= (field->flags & UNSIGNED_FLAG); @@ -3043,26 +3154,26 @@ static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field, { char tmp[22]; /* Enough for longlong */ uint length= (uint)(longlong10_to_str(value,(char *)tmp, - field_is_unsigned ? 10: -10) - - tmp); + field_is_unsigned ? 10: -10) - + tmp); ulong copy_length= min((ulong)length-param->offset, param->buffer_length); if ((long) copy_length < 0) copy_length=0; else memcpy(buffer, (char *)tmp+param->offset, copy_length); - *param->length= length; - + *param->length= length; + if (copy_length != param->buffer_length) *(buffer+copy_length)= '\0'; } - } + } } /* Convert Double to buffer types */ static void send_data_double(MYSQL_BIND *param, double value) -{ +{ char *buffer= param->buffer; switch(param->buffer_type) { @@ -3101,19 +3212,19 @@ static void send_data_double(MYSQL_BIND *param, double value) copy_length=0; else memcpy(buffer, (char *)tmp+param->offset, copy_length); - *param->length= length; - + *param->length= length; + if (copy_length != param->buffer_length) *(buffer+copy_length)= '\0'; } - } + } } /* Convert string to buffer types */ static void send_data_str(MYSQL_BIND *param, char *value, uint length) -{ +{ char *buffer= param->buffer; int err=0; @@ -3138,7 +3249,7 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length) { int32 data= (int32)my_strntol(&my_charset_latin1,value,length,10,NULL, &err); - int4store(buffer, data); + int4store(buffer, data); break; } case MYSQL_TYPE_LONGLONG: @@ -3181,7 +3292,7 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length) } -static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, +static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, uint length) { switch (param->buffer_type) { @@ -3194,7 +3305,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, case MYSQL_TYPE_TIMESTAMP: { MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; - + tm->year= ltime.year; tm->month= ltime.month; tm->day= ltime.day; @@ -3205,33 +3316,33 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, tm->second_part= ltime.second_part; tm->neg= ltime.neg; - break; + break; } default: { char buff[25]; - + if (!length) ltime.time_type= MYSQL_TIMESTAMP_NONE; switch (ltime.time_type) { case MYSQL_TIMESTAMP_DATE: length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year, - ltime.month,ltime.day)); + ltime.month,ltime.day)); break; case MYSQL_TIMESTAMP_FULL: length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", - ltime.year,ltime.month,ltime.day, - ltime.hour,ltime.minute,ltime.second)); + ltime.year,ltime.month,ltime.day, + ltime.hour,ltime.minute,ltime.second)); break; case MYSQL_TIMESTAMP_TIME: length= my_sprintf(buff, (buff, "%02d:%02d:%02d", - ltime.hour,ltime.minute,ltime.second)); + ltime.hour,ltime.minute,ltime.second)); break; default: length= 0; buff[0]='\0'; } - send_data_str(param, (char *)buff, length); + send_data_str(param, (char *)buff, length); } } } @@ -3263,7 +3374,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) longlong data= ((field_is_unsigned) ? (longlong) (unsigned short) value: (longlong) value); send_data_long(param, field, data); - length= 2; + length= 2; break; } case MYSQL_TYPE_LONG: @@ -3302,7 +3413,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) case MYSQL_TYPE_DATE: { MYSQL_TIME tm; - + length= read_binary_date(&tm, row); tm.time_type= MYSQL_TIMESTAMP_DATE; send_data_time(param, tm, length); @@ -3311,7 +3422,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) case MYSQL_TYPE_TIME: { MYSQL_TIME tm; - + length= read_binary_time(&tm, row); tm.time_type= MYSQL_TIMESTAMP_TIME; send_data_time(param, tm, length); @@ -3321,14 +3432,14 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) case MYSQL_TYPE_TIMESTAMP: { MYSQL_TIME tm; - + length= read_binary_datetime(&tm, row); tm.time_type= MYSQL_TIMESTAMP_FULL; send_data_time(param, tm, length); break; } - default: - length= net_field_length(row); + default: + length= net_field_length(row); send_data_str(param,(char*) *row,length); break; } @@ -3357,7 +3468,7 @@ static void fetch_result_int32(MYSQL_BIND *param, uchar **row) } static void fetch_result_int64(MYSQL_BIND *param, uchar **row) -{ +{ longlong value= (longlong)sint8korr(*row); longlongstore(param->buffer, value); *row+= 8; @@ -3398,11 +3509,11 @@ static void fetch_result_datetime(MYSQL_BIND *param, uchar **row) } static void fetch_result_bin(MYSQL_BIND *param, uchar **row) -{ +{ ulong length= net_field_length(row); ulong copy_length= min(length, param->buffer_length); memcpy(param->buffer, (char *)*row, copy_length); - *param->length= length; + *param->length= length; *row+= length; } @@ -3483,7 +3594,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) We only need to check that stmt->field_count - if it is not null stmt->bind was initialized in mysql_stmt_prepare */ - + memcpy((char*) stmt->bind, (char*) bind, sizeof(MYSQL_BIND) * bind_count); for (param= stmt->bind, end= param + bind_count, field= stmt->fields ; @@ -3645,16 +3756,16 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) /* If output parameters were not bound we should just return success */ return 0; } - - null_ptr= row; + + null_ptr= row; row+= (stmt->field_count+9)/8; /* skip null bits */ bit= 4; /* first 2 bits are reserved */ - + /* Copy complete row to application buffers */ for (bind= stmt->bind, end= bind + stmt->field_count, field= stmt->fields ; bind < end ; bind++, field++) - { + { if (*null_ptr & bit) { /* @@ -3668,12 +3779,12 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) *bind->is_null= 1; } else - { + { *bind->is_null= 0; bind->inter_buffer= row; if (field->type == bind->buffer_type) (*bind->fetch_result)(bind, &row); - else + else fetch_results(bind, field, &row); } if (!((bit<<=1) & 255)) @@ -3733,15 +3844,15 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt) column Column to fetch (first column is 0) ulong offset Offset in result data (to fetch blob in pieces) This is normally 0 - RETURN + RETURN 0 ok 1 error */ -int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, +int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, uint column, ulong offset) { - MYSQL_BIND *param= stmt->bind+column; + MYSQL_BIND *param= stmt->bind+column; DBUG_ENTER("mysql_stmt_fetch_column"); if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE) @@ -3757,7 +3868,7 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, if (param->inter_buffer) { - MYSQL_FIELD *field= stmt->fields+column; + MYSQL_FIELD *field= stmt->fields+column; uchar *row= param->inter_buffer; bind->offset= offset; if (bind->is_null) @@ -3828,6 +3939,49 @@ err: /* + Update meta data for statement + + SYNOPSIS + stmt_update_metadata() + stmt Statement handler + row Binary data + + NOTES + Only updates MYSQL_FIELD->max_length for strings +*/ + +static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data) +{ + MYSQL_BIND *bind, *end; + MYSQL_FIELD *field; + uchar *null_ptr, bit; + uchar *row= (uchar*) data->data; +#ifndef DBUG_OFF + uchar *row_end= row + data->length; +#endif + + null_ptr= row; + row+= (stmt->field_count+9)/8; /* skip null bits */ + bit= 4; /* first 2 bits are reserved */ + + /* Go throw all fields and calculate metadata */ + for (bind= stmt->bind, end= bind + stmt->field_count, field= stmt->fields ; + bind < end ; + bind++, field++) + { + if (!(*null_ptr & bit)) + (*bind->skip_result)(bind, field, &row); + DBUG_ASSERT(row <= row_end); + if (!((bit<<=1) & 255)) + { + bit= 1; /* To next byte */ + null_ptr++; + } + } +} + + +/* Store or buffer the binary results to stmt */ @@ -3882,6 +4036,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); result->data= NULL; result->rows= 0; + mysql->status= MYSQL_STATUS_READY; DBUG_RETURN(1); } @@ -3910,7 +4065,7 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) { MYSQL_ROW_OFFSET offset= stmt->data_cursor; DBUG_ENTER("mysql_stmt_row_seek"); - + stmt->data_cursor= row; DBUG_RETURN(offset); } @@ -3920,11 +4075,11 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) Return the current statement row cursor position */ -MYSQL_ROW_OFFSET STDCALL +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt) { DBUG_ENTER("mysql_stmt_row_tell"); - + DBUG_RETURN(stmt->data_cursor); } @@ -3939,7 +4094,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) MYSQL_ROWS *tmp= stmt->result.data; DBUG_ENTER("mysql_stmt_data_seek"); DBUG_PRINT("enter",("row id to seek: %ld",(long) row)); - + for (; tmp && row; --row, tmp= tmp->next) ; stmt->data_cursor= tmp; @@ -3954,7 +4109,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt) { DBUG_ENTER("mysql_stmt_num_rows"); - + DBUG_RETURN(stmt->result.rows); } @@ -3964,7 +4119,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) DBUG_ENTER("mysql_stmt_free_result"); DBUG_ASSERT(stmt != 0); - + if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { MYSQL *mysql= stmt->mysql; @@ -4032,7 +4187,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) mysql->unbuffered_fetch_owner= 0; if (mysql->status != MYSQL_STATUS_READY) { - /* + /* Flush result set of the connection. If it does not belong to this statement, set a warning. */ @@ -4070,13 +4225,13 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) /* If statement hasnt been prepared there is nothing to reset */ if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) DBUG_RETURN(0); - + mysql= stmt->mysql->last_used_con; int4store(buff, stmt->stmt_id); /* Send stmt id to server */ if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, sizeof(buff), 0, 0, 0)) { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, mysql->net.sqlstate); DBUG_RETURN(1); } @@ -4117,50 +4272,6 @@ const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt) } -/* - Update meta data for statement - - SYNOPSIS - stmt_update_metadata() - stmt Statement handler - row Binary data - - NOTES - Only updates MYSQL_FIELD->max_length for strings - -*/ - -static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data) -{ - MYSQL_BIND *bind, *end; - MYSQL_FIELD *field; - uchar *null_ptr, bit; - uchar *row= (uchar*) data->data; -#ifndef DBUG_OFF - uchar *row_end= row + data->length; -#endif - - null_ptr= row; - row+= (stmt->field_count+9)/8; /* skip null bits */ - bit= 4; /* first 2 bits are reserved */ - - /* Go throw all fields and calculate metadata */ - for (bind= stmt->bind, end= bind + stmt->field_count, field= stmt->fields ; - bind < end ; - bind++, field++) - { - if (!(*null_ptr & bit)) - (*bind->skip_result)(bind, field, &row); - DBUG_ASSERT(row <= row_end); - if (!((bit<<=1) & 255)) - { - bit= 1; /* To next byte */ - null_ptr++; - } - } -} - - /******************************************************************** Transactional APIs *********************************************************************/ @@ -4214,10 +4325,10 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql) { my_bool res; DBUG_ENTER("mysql_more_results"); - - res= ((mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) ? + + res= ((mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS) ? 1: 0); - DBUG_PRINT("exit",("More results exists ? %d", res)); + DBUG_PRINT("exit",("More results exists ? %d", res)); DBUG_RETURN(res); } @@ -4228,7 +4339,7 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql) int STDCALL mysql_next_result(MYSQL *mysql) { DBUG_ENTER("mysql_next_result"); - + if (mysql->status != MYSQL_STATUS_READY) { strmov(mysql->net.sqlstate, unknown_sqlstate); |