Commit e9f2c7d4 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Comments and cleanups in client library.

parent 3ac650c8
...@@ -558,7 +558,7 @@ typedef struct st_mysql_bind ...@@ -558,7 +558,7 @@ typedef struct st_mysql_bind
enum enum_field_types buffer_type; /* buffer type */ enum enum_field_types buffer_type; /* buffer type */
unsigned long buffer_length; /* buffer length, must be set for str/binary */ unsigned long buffer_length; /* buffer length, must be set for str/binary */
/* Following are for internal use. Set by mysql_bind_param */ /* Following are for internal use. Set by mysql_stmt_bind_param */
unsigned char *inter_buffer; /* for the current data position */ unsigned char *inter_buffer; /* for the current data position */
unsigned long offset; /* offset position for char/binary fetch */ unsigned long offset; /* offset position for char/binary fetch */
unsigned long internal_length; /* Used if length is 0 */ unsigned long internal_length; /* Used if length is 0 */
......
...@@ -1945,7 +1945,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) ...@@ -1945,7 +1945,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
mysql_stmt_free_result(stmt); 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. function in case of error or misuse.
*/ */
stmt->bind_param_done= stmt->bind_result_done= FALSE; stmt->bind_param_done= stmt->bind_result_done= FALSE;
...@@ -1984,14 +1984,14 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) ...@@ -1984,14 +1984,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 and field_count are zero. Thus we should never rely on stmt->bind
or stmt->params when checking for existence of placeholders or or stmt->params when checking for existence of placeholders or
result set. result set.
*/ */
if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root, if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root,
sizeof(MYSQL_BIND)* sizeof(MYSQL_BIND)*
(stmt->param_count + (stmt->param_count +
stmt->field_count)))) stmt->field_count))))
{ {
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate); set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
...@@ -2015,22 +2015,22 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) ...@@ -2015,22 +2015,22 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
MYSQL_FIELD *fields, *field, *end; MYSQL_FIELD *fields, *field, *end;
MEM_ROOT *alloc= &stmt->mem_root; MEM_ROOT *alloc= &stmt->mem_root;
MYSQL *mysql= stmt->mysql->last_used_con; MYSQL *mysql= stmt->mysql->last_used_con;
stmt->field_count= mysql->field_count; 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 like SHOW and DESCRIBE commands
*/ */
if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc, if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc,
sizeof(MYSQL_FIELD) * sizeof(MYSQL_FIELD) *
stmt->field_count)) || stmt->field_count)) ||
!(stmt->bind= (MYSQL_BIND *) alloc_root(alloc, !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc,
sizeof(MYSQL_BIND) * sizeof(MYSQL_BIND) *
stmt->field_count))) stmt->field_count)))
return 0; return 0;
for (fields= mysql->fields, end= fields+stmt->field_count, for (fields= mysql->fields, end= fields+stmt->field_count,
field= stmt->fields; field= stmt->fields;
field && fields < end; fields++, field++) field && fields < end; fields++, field++)
{ {
...@@ -2107,7 +2107,7 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt) ...@@ -2107,7 +2107,7 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt)
{ {
MYSQL_RES *result; MYSQL_RES *result;
DBUG_ENTER("mysql_stmt_result_metadata"); DBUG_ENTER("mysql_stmt_result_metadata");
/* /*
stmt->fields is only defined if stmt->field_count is not null; stmt->fields is only defined if stmt->field_count is not null;
stmt->field_count is initialized in prepare. stmt->field_count is initialized in prepare.
...@@ -2130,41 +2130,65 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt) ...@@ -2130,41 +2130,65 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt)
DBUG_RETURN(result); DBUG_RETURN(result);
} }
/* /*
Returns parameter columns meta information in the form of Returns parameter columns meta information in the form of
result set. 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_RES * STDCALL
mysql_stmt_param_metadata(MYSQL_STMT *stmt) mysql_stmt_param_metadata(MYSQL_STMT *stmt)
{ {
DBUG_ENTER("mysql_stmt_param_metadata"); DBUG_ENTER("mysql_stmt_param_metadata");
if (!stmt->param_count) if (!stmt->param_count)
DBUG_RETURN(0); DBUG_RETURN(0);
/* /*
TODO: Fix this when server sends the information. TODO: Fix this when server sends the information.
Till then keep a dummy prototype Till then keep a dummy prototype.
*/ */
DBUG_RETURN(0); 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. Functions to store parameter data in network packet.
All functions have the following characteristics:
SYNOPSIS SYNOPSIS
store_param_xxx() store_param_xxx()
net MySQL NET connection net MySQL NET connection
param MySQL bind param param MySQL bind param
RETURN VALUES DESCRIPTION
0 ok These funtions are invoked from mysql_stmt_execute by
1 Error (Can't alloc net->buffer) 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) static void store_param_tinyint(NET *net, MYSQL_BIND *param)
...@@ -2253,7 +2277,7 @@ static void net_store_datetime(NET *net, MYSQL_TIME *tm) ...@@ -2253,7 +2277,7 @@ static void net_store_datetime(NET *net, MYSQL_TIME *tm)
length= 4; length= 4;
else else
length= 0; length= 0;
buff[0]= (char) length++; buff[0]= (char) length++;
memcpy((char *)net->write_pos, buff, length); memcpy((char *)net->write_pos, buff, length);
net->write_pos+= length; net->write_pos+= length;
} }
...@@ -2271,7 +2295,7 @@ static void store_param_datetime(NET *net, MYSQL_BIND *param) ...@@ -2271,7 +2295,7 @@ static void store_param_datetime(NET *net, MYSQL_BIND *param)
MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
net_store_datetime(net, tm); net_store_datetime(net, tm);
} }
static void store_param_str(NET *net, MYSQL_BIND *param) static void store_param_str(NET *net, MYSQL_BIND *param)
{ {
/* param->length is always set in mysql_stmt_bind_param */ /* param->length is always set in mysql_stmt_bind_param */
...@@ -2292,7 +2316,8 @@ static void store_param_str(NET *net, MYSQL_BIND *param) ...@@ -2292,7 +2316,8 @@ static void store_param_str(NET *net, MYSQL_BIND *param)
DESCRIPTION DESCRIPTION
A data package starts with a string of bits where we set a bit 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) static void store_param_null(NET *net, MYSQL_BIND *param)
...@@ -2303,8 +2328,9 @@ static void store_param_null(NET *net, MYSQL_BIND *param) ...@@ -2303,8 +2328,9 @@ static void store_param_null(NET *net, MYSQL_BIND *param)
/* /*
Set parameter data by reading from input buffers from the Store one parameter in network packet: data is read from
client application 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) static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
...@@ -2339,11 +2365,11 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) ...@@ -2339,11 +2365,11 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
Send the prepared query to server for execution Send the prepared query to server for execution
*/ */
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; MYSQL *mysql= stmt->mysql;
NET *net= &mysql->net; NET *net= &mysql->net;
char buff[4 /* size of stmt id */ + char buff[4 /* size of stmt id */ +
5 /* execution flags */]; 5 /* execution flags */];
DBUG_ENTER("execute"); DBUG_ENTER("execute");
DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length)); DBUG_PRINT("enter",("packet: %s, length :%d",packet ? packet :" ", length));
...@@ -2363,14 +2389,6 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) ...@@ -2363,14 +2389,6 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length)
stmt->insert_id= mysql->insert_id; stmt->insert_id= mysql->insert_id;
DBUG_RETURN(0); 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) int cli_stmt_execute(MYSQL_STMT *stmt)
...@@ -2413,7 +2431,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt) ...@@ -2413,7 +2431,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
for (param= stmt->params; param < param_end; param++) 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) if (param->long_data_used)
param->long_data_used= 0; /* Clear for next execute call */ param->long_data_used= 0; /* Clear for next execute call */
else if (store_param(stmt, param)) else if (store_param(stmt, param))
...@@ -2472,16 +2490,16 @@ static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row) ...@@ -2472,16 +2490,16 @@ static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row)
0 - success; *row contains valid address of a row; 0 - success; *row contains valid address of a row;
row data is stored in network buffer row data is stored in network buffer
1 - error; error code is written to 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; MYSQL_NO_DATA - end of file was read from network;
*row is to NULL *row is to NULL
*/ */
static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row) static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row)
{ {
int rc= 1; int rc= 1;
MYSQL *mysql= stmt->mysql; MYSQL *mysql= stmt->mysql;
/* /*
This function won't be called if stmt->field_count is zero This function won't be called if stmt->field_count is zero
or execution wasn't done: this is ensured by mysql_stmt_execute. or execution wasn't done: this is ensured by mysql_stmt_execute.
*/ */
...@@ -2555,7 +2573,7 @@ stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)), ...@@ -2555,7 +2573,7 @@ stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
0 success 0 success
!0 wrong attribute type !0 wrong attribute type
*/ */
my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
enum enum_stmt_attr_type attr_type, enum enum_stmt_attr_type attr_type,
const void *value) const void *value)
...@@ -2564,14 +2582,14 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, ...@@ -2564,14 +2582,14 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
case STMT_ATTR_UPDATE_MAX_LENGTH: case STMT_ATTR_UPDATE_MAX_LENGTH:
stmt->update_max_length= value ? *(const my_bool*) value : 0; stmt->update_max_length= value ? *(const my_bool*) value : 0;
break; break;
default: default:
return TRUE; return TRUE;
} }
return FALSE; 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, enum enum_stmt_attr_type attr_type,
void *value) void *value)
{ {
...@@ -2579,7 +2597,7 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, ...@@ -2579,7 +2597,7 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt,
case STMT_ATTR_UPDATE_MAX_LENGTH: case STMT_ATTR_UPDATE_MAX_LENGTH:
*(unsigned long *) value= stmt->update_max_length; *(unsigned long *) value= stmt->update_max_length;
break; break;
default: default:
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
...@@ -2587,7 +2605,47 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, ...@@ -2587,7 +2605,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) int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
...@@ -2681,7 +2739,19 @@ unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt) ...@@ -2681,7 +2739,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) my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
...@@ -2693,11 +2763,24 @@ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt) ...@@ -2693,11 +2763,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_true= 1; /* Used for MYSQL_TYPE_NULL */
static my_bool int_is_null_false= 0; 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; uint count=0;
MYSQL_BIND *param, *end; MYSQL_BIND *param, *end;
...@@ -2839,7 +2922,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, ...@@ -2839,7 +2922,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
DBUG_ASSERT(stmt != 0); DBUG_ASSERT(stmt != 0);
DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld", DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld",
param_number, data, length)); param_number, data, length));
/* /*
We only need to check for stmt->param_count, if it's not null We only need to check for stmt->param_count, if it's not null
prepare was done. prepare was done.
...@@ -2864,7 +2947,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, ...@@ -2864,7 +2947,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* /*
Send long data packet if there is data or we're sending long data Send long data packet if there is data or we're sending long data
for the first time. for the first time.
*/ */
...@@ -2872,8 +2955,8 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number, ...@@ -2872,8 +2955,8 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
{ {
MYSQL *mysql= stmt->mysql; MYSQL *mysql= stmt->mysql;
/* Packet header: stmt id (4 bytes), param no (2 bytes) */ /* 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); int4store(buff, stmt->stmt_id);
int2store(buff + 4, param_number); int2store(buff + 4, param_number);
param->long_data_used= 1; param->long_data_used= 1;
...@@ -2926,7 +3009,7 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos) ...@@ -2926,7 +3009,7 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos)
{ {
uchar *to; uchar *to;
uint length; uint length;
/* net_field_length will set pos to the first byte of data */ /* net_field_length will set pos to the first byte of data */
if (!(length= net_field_length(pos))) if (!(length= net_field_length(pos)))
{ {
...@@ -2983,14 +3066,14 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos) ...@@ -2983,14 +3066,14 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos)
{ {
uchar *to; uchar *to;
uint length; uint length;
if (!(length= net_field_length(pos))) if (!(length= net_field_length(pos)))
{ {
set_zero_time(tm); set_zero_time(tm);
return 0; return 0;
} }
to= *pos; to= *pos;
tm->year = (uint) sint2korr(to); tm->year = (uint) sint2korr(to);
tm->month= (uint) to[2]; tm->month= (uint) to[2];
tm->day= (uint) to[3]; tm->day= (uint) to[3];
...@@ -3004,7 +3087,7 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos) ...@@ -3004,7 +3087,7 @@ static uint read_binary_date(MYSQL_TIME *tm, uchar **pos)
/* Convert Numeric to buffer types */ /* Convert Numeric to buffer types */
static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field, static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field,
longlong value) longlong value)
{ {
char *buffer= param->buffer; char *buffer= param->buffer;
uint field_is_unsigned= (field->flags & UNSIGNED_FLAG); uint field_is_unsigned= (field->flags & UNSIGNED_FLAG);
...@@ -3041,26 +3124,26 @@ static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field, ...@@ -3041,26 +3124,26 @@ static void send_data_long(MYSQL_BIND *param, MYSQL_FIELD *field,
{ {
char tmp[22]; /* Enough for longlong */ char tmp[22]; /* Enough for longlong */
uint length= (uint)(longlong10_to_str(value,(char *)tmp, uint length= (uint)(longlong10_to_str(value,(char *)tmp,
field_is_unsigned ? 10: -10) - field_is_unsigned ? 10: -10) -
tmp); tmp);
ulong copy_length= min((ulong)length-param->offset, param->buffer_length); ulong copy_length= min((ulong)length-param->offset, param->buffer_length);
if ((long) copy_length < 0) if ((long) copy_length < 0)
copy_length=0; copy_length=0;
else else
memcpy(buffer, (char *)tmp+param->offset, copy_length); memcpy(buffer, (char *)tmp+param->offset, copy_length);
*param->length= length; *param->length= length;
if (copy_length != param->buffer_length) if (copy_length != param->buffer_length)
*(buffer+copy_length)= '\0'; *(buffer+copy_length)= '\0';
} }
} }
} }
/* Convert Double to buffer types */ /* Convert Double to buffer types */
static void send_data_double(MYSQL_BIND *param, double value) static void send_data_double(MYSQL_BIND *param, double value)
{ {
char *buffer= param->buffer; char *buffer= param->buffer;
switch(param->buffer_type) { switch(param->buffer_type) {
...@@ -3099,19 +3182,19 @@ static void send_data_double(MYSQL_BIND *param, double value) ...@@ -3099,19 +3182,19 @@ static void send_data_double(MYSQL_BIND *param, double value)
copy_length=0; copy_length=0;
else else
memcpy(buffer, (char *)tmp+param->offset, copy_length); memcpy(buffer, (char *)tmp+param->offset, copy_length);
*param->length= length; *param->length= length;
if (copy_length != param->buffer_length) if (copy_length != param->buffer_length)
*(buffer+copy_length)= '\0'; *(buffer+copy_length)= '\0';
} }
} }
} }
/* Convert string to buffer types */ /* Convert string to buffer types */
static void send_data_str(MYSQL_BIND *param, char *value, uint length) static void send_data_str(MYSQL_BIND *param, char *value, uint length)
{ {
char *buffer= param->buffer; char *buffer= param->buffer;
int err=0; int err=0;
...@@ -3136,7 +3219,7 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length) ...@@ -3136,7 +3219,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, int32 data= (int32)my_strntol(&my_charset_latin1,value,length,10,NULL,
&err); &err);
int4store(buffer, data); int4store(buffer, data);
break; break;
} }
case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_LONGLONG:
...@@ -3179,7 +3262,7 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length) ...@@ -3179,7 +3262,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) uint length)
{ {
switch (param->buffer_type) { switch (param->buffer_type) {
...@@ -3192,7 +3275,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, ...@@ -3192,7 +3275,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime,
case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_TIMESTAMP:
{ {
MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
tm->year= ltime.year; tm->year= ltime.year;
tm->month= ltime.month; tm->month= ltime.month;
tm->day= ltime.day; tm->day= ltime.day;
...@@ -3203,33 +3286,33 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, ...@@ -3203,33 +3286,33 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime,
tm->second_part= ltime.second_part; tm->second_part= ltime.second_part;
tm->neg= ltime.neg; tm->neg= ltime.neg;
break; break;
} }
default: default:
{ {
char buff[25]; char buff[25];
if (!length) if (!length)
ltime.time_type= MYSQL_TIMESTAMP_NONE; ltime.time_type= MYSQL_TIMESTAMP_NONE;
switch (ltime.time_type) { switch (ltime.time_type) {
case MYSQL_TIMESTAMP_DATE: case MYSQL_TIMESTAMP_DATE:
length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year, length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year,
ltime.month,ltime.day)); ltime.month,ltime.day));
break; break;
case MYSQL_TIMESTAMP_FULL: case MYSQL_TIMESTAMP_FULL:
length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
ltime.year,ltime.month,ltime.day, ltime.year,ltime.month,ltime.day,
ltime.hour,ltime.minute,ltime.second)); ltime.hour,ltime.minute,ltime.second));
break; break;
case MYSQL_TIMESTAMP_TIME: case MYSQL_TIMESTAMP_TIME:
length= my_sprintf(buff, (buff, "%02d:%02d:%02d", length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
ltime.hour,ltime.minute,ltime.second)); ltime.hour,ltime.minute,ltime.second));
break; break;
default: default:
length= 0; length= 0;
buff[0]='\0'; buff[0]='\0';
} }
send_data_str(param, (char *)buff, length); send_data_str(param, (char *)buff, length);
} }
} }
} }
...@@ -3261,7 +3344,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) ...@@ -3261,7 +3344,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
longlong data= ((field_is_unsigned) ? (longlong) (unsigned short) value: longlong data= ((field_is_unsigned) ? (longlong) (unsigned short) value:
(longlong) value); (longlong) value);
send_data_long(param, field, data); send_data_long(param, field, data);
length= 2; length= 2;
break; break;
} }
case MYSQL_TYPE_LONG: case MYSQL_TYPE_LONG:
...@@ -3300,7 +3383,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) ...@@ -3300,7 +3383,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATE:
{ {
MYSQL_TIME tm; MYSQL_TIME tm;
length= read_binary_date(&tm, row); length= read_binary_date(&tm, row);
tm.time_type= MYSQL_TIMESTAMP_DATE; tm.time_type= MYSQL_TIMESTAMP_DATE;
send_data_time(param, tm, length); send_data_time(param, tm, length);
...@@ -3309,7 +3392,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) ...@@ -3309,7 +3392,7 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIME:
{ {
MYSQL_TIME tm; MYSQL_TIME tm;
length= read_binary_time(&tm, row); length= read_binary_time(&tm, row);
tm.time_type= MYSQL_TIMESTAMP_TIME; tm.time_type= MYSQL_TIMESTAMP_TIME;
send_data_time(param, tm, length); send_data_time(param, tm, length);
...@@ -3319,14 +3402,14 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row) ...@@ -3319,14 +3402,14 @@ static void fetch_results(MYSQL_BIND *param, MYSQL_FIELD *field, uchar **row)
case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_TIMESTAMP:
{ {
MYSQL_TIME tm; MYSQL_TIME tm;
length= read_binary_datetime(&tm, row); length= read_binary_datetime(&tm, row);
tm.time_type= MYSQL_TIMESTAMP_FULL; tm.time_type= MYSQL_TIMESTAMP_FULL;
send_data_time(param, tm, length); send_data_time(param, tm, length);
break; break;
} }
default: default:
length= net_field_length(row); length= net_field_length(row);
send_data_str(param,(char*) *row,length); send_data_str(param,(char*) *row,length);
break; break;
} }
...@@ -3355,7 +3438,7 @@ static void fetch_result_int32(MYSQL_BIND *param, uchar **row) ...@@ -3355,7 +3438,7 @@ static void fetch_result_int32(MYSQL_BIND *param, uchar **row)
} }
static void fetch_result_int64(MYSQL_BIND *param, uchar **row) static void fetch_result_int64(MYSQL_BIND *param, uchar **row)
{ {
longlong value= (longlong)sint8korr(*row); longlong value= (longlong)sint8korr(*row);
longlongstore(param->buffer, value); longlongstore(param->buffer, value);
*row+= 8; *row+= 8;
...@@ -3396,11 +3479,11 @@ static void fetch_result_datetime(MYSQL_BIND *param, uchar **row) ...@@ -3396,11 +3479,11 @@ static void fetch_result_datetime(MYSQL_BIND *param, uchar **row)
} }
static void fetch_result_bin(MYSQL_BIND *param, uchar **row) static void fetch_result_bin(MYSQL_BIND *param, uchar **row)
{ {
ulong length= net_field_length(row); ulong length= net_field_length(row);
ulong copy_length= min(length, param->buffer_length); ulong copy_length= min(length, param->buffer_length);
memcpy(param->buffer, (char *)*row, copy_length); memcpy(param->buffer, (char *)*row, copy_length);
*param->length= length; *param->length= length;
*row+= length; *row+= length;
} }
...@@ -3481,7 +3564,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) ...@@ -3481,7 +3564,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 We only need to check that stmt->field_count - if it is not null
stmt->bind was initialized in mysql_stmt_prepare stmt->bind was initialized in mysql_stmt_prepare
*/ */
memcpy((char*) stmt->bind, (char*) bind, sizeof(MYSQL_BIND) * bind_count); memcpy((char*) stmt->bind, (char*) bind, sizeof(MYSQL_BIND) * bind_count);
for (param= stmt->bind, end= param + bind_count, field= stmt->fields ; for (param= stmt->bind, end= param + bind_count, field= stmt->fields ;
...@@ -3643,16 +3726,16 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) ...@@ -3643,16 +3726,16 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
/* If output parameters were not bound we should just return success */ /* If output parameters were not bound we should just return success */
return 0; return 0;
} }
null_ptr= row; null_ptr= row;
row+= (stmt->field_count+9)/8; /* skip null bits */ row+= (stmt->field_count+9)/8; /* skip null bits */
bit= 4; /* first 2 bits are reserved */ bit= 4; /* first 2 bits are reserved */
/* Copy complete row to application buffers */ /* Copy complete row to application buffers */
for (bind= stmt->bind, end= bind + stmt->field_count, field= stmt->fields ; for (bind= stmt->bind, end= bind + stmt->field_count, field= stmt->fields ;
bind < end ; bind < end ;
bind++, field++) bind++, field++)
{ {
if (*null_ptr & bit) if (*null_ptr & bit)
{ {
/* /*
...@@ -3666,12 +3749,12 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) ...@@ -3666,12 +3749,12 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
*bind->is_null= 1; *bind->is_null= 1;
} }
else else
{ {
*bind->is_null= 0; *bind->is_null= 0;
bind->inter_buffer= row; bind->inter_buffer= row;
if (field->type == bind->buffer_type) if (field->type == bind->buffer_type)
(*bind->fetch_result)(bind, &row); (*bind->fetch_result)(bind, &row);
else else
fetch_results(bind, field, &row); fetch_results(bind, field, &row);
} }
if (!((bit<<=1) & 255)) if (!((bit<<=1) & 255))
...@@ -3731,15 +3814,15 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt) ...@@ -3731,15 +3814,15 @@ int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
column Column to fetch (first column is 0) column Column to fetch (first column is 0)
ulong offset Offset in result data (to fetch blob in pieces) ulong offset Offset in result data (to fetch blob in pieces)
This is normally 0 This is normally 0
RETURN RETURN
0 ok 0 ok
1 error 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) uint column, ulong offset)
{ {
MYSQL_BIND *param= stmt->bind+column; MYSQL_BIND *param= stmt->bind+column;
DBUG_ENTER("mysql_stmt_fetch_column"); DBUG_ENTER("mysql_stmt_fetch_column");
if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE) if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
...@@ -3755,7 +3838,7 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, ...@@ -3755,7 +3838,7 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
if (param->inter_buffer) if (param->inter_buffer)
{ {
MYSQL_FIELD *field= stmt->fields+column; MYSQL_FIELD *field= stmt->fields+column;
uchar *row= param->inter_buffer; uchar *row= param->inter_buffer;
bind->offset= offset; bind->offset= offset;
if (bind->is_null) if (bind->is_null)
...@@ -3825,6 +3908,49 @@ err: ...@@ -3825,6 +3908,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 Store or buffer the binary results to stmt
*/ */
...@@ -3909,7 +4035,7 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) ...@@ -3909,7 +4035,7 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row)
{ {
MYSQL_ROW_OFFSET offset= stmt->data_cursor; MYSQL_ROW_OFFSET offset= stmt->data_cursor;
DBUG_ENTER("mysql_stmt_row_seek"); DBUG_ENTER("mysql_stmt_row_seek");
stmt->data_cursor= row; stmt->data_cursor= row;
DBUG_RETURN(offset); DBUG_RETURN(offset);
} }
...@@ -3919,11 +4045,11 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row) ...@@ -3919,11 +4045,11 @@ mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row)
Return the current statement row cursor position Return the current statement row cursor position
*/ */
MYSQL_ROW_OFFSET STDCALL MYSQL_ROW_OFFSET STDCALL
mysql_stmt_row_tell(MYSQL_STMT *stmt) mysql_stmt_row_tell(MYSQL_STMT *stmt)
{ {
DBUG_ENTER("mysql_stmt_row_tell"); DBUG_ENTER("mysql_stmt_row_tell");
DBUG_RETURN(stmt->data_cursor); DBUG_RETURN(stmt->data_cursor);
} }
...@@ -3938,7 +4064,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) ...@@ -3938,7 +4064,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row)
MYSQL_ROWS *tmp= stmt->result.data; MYSQL_ROWS *tmp= stmt->result.data;
DBUG_ENTER("mysql_stmt_data_seek"); DBUG_ENTER("mysql_stmt_data_seek");
DBUG_PRINT("enter",("row id to seek: %ld",(long) row)); DBUG_PRINT("enter",("row id to seek: %ld",(long) row));
for (; tmp && row; --row, tmp= tmp->next) for (; tmp && row; --row, tmp= tmp->next)
; ;
stmt->data_cursor= tmp; stmt->data_cursor= tmp;
...@@ -3953,7 +4079,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) ...@@ -3953,7 +4079,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row)
my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt) my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
{ {
DBUG_ENTER("mysql_stmt_num_rows"); DBUG_ENTER("mysql_stmt_num_rows");
DBUG_RETURN(stmt->result.rows); DBUG_RETURN(stmt->result.rows);
} }
...@@ -3963,7 +4089,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) ...@@ -3963,7 +4089,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
DBUG_ENTER("mysql_stmt_free_result"); DBUG_ENTER("mysql_stmt_free_result");
DBUG_ASSERT(stmt != 0); DBUG_ASSERT(stmt != 0);
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
{ {
MYSQL *mysql= stmt->mysql; MYSQL *mysql= stmt->mysql;
...@@ -4031,7 +4157,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) ...@@ -4031,7 +4157,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
mysql->unbuffered_fetch_owner= 0; mysql->unbuffered_fetch_owner= 0;
if (mysql->status != MYSQL_STATUS_READY) if (mysql->status != MYSQL_STATUS_READY)
{ {
/* /*
Flush result set of the connection. If it does not belong Flush result set of the connection. If it does not belong
to this statement, set a warning. to this statement, set a warning.
*/ */
...@@ -4069,13 +4195,13 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) ...@@ -4069,13 +4195,13 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
/* If statement hasnt been prepared there is nothing to reset */ /* If statement hasnt been prepared there is nothing to reset */
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
DBUG_RETURN(0); DBUG_RETURN(0);
mysql= stmt->mysql->last_used_con; mysql= stmt->mysql->last_used_con;
int4store(buff, stmt->stmt_id); /* Send stmt id to server */ int4store(buff, stmt->stmt_id); /* Send stmt id to server */
if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff,
sizeof(buff), 0, 0, 0)) 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); mysql->net.sqlstate);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -4116,50 +4242,6 @@ const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt) ...@@ -4116,50 +4242,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 Transactional APIs
*********************************************************************/ *********************************************************************/
...@@ -4213,10 +4295,10 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql) ...@@ -4213,10 +4295,10 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql)
{ {
my_bool res; my_bool res;
DBUG_ENTER("mysql_more_results"); 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); 1: 0);
DBUG_PRINT("exit",("More results exists ? %d", res)); DBUG_PRINT("exit",("More results exists ? %d", res));
DBUG_RETURN(res); DBUG_RETURN(res);
} }
...@@ -4227,7 +4309,7 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql) ...@@ -4227,7 +4309,7 @@ my_bool STDCALL mysql_more_results(MYSQL *mysql)
int STDCALL mysql_next_result(MYSQL *mysql) int STDCALL mysql_next_result(MYSQL *mysql)
{ {
DBUG_ENTER("mysql_next_result"); DBUG_ENTER("mysql_next_result");
if (mysql->status != MYSQL_STATUS_READY) if (mysql->status != MYSQL_STATUS_READY)
{ {
strmov(mysql->net.sqlstate, unknown_sqlstate); strmov(mysql->net.sqlstate, unknown_sqlstate);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment