Intermediate commit of client library (cleanups + fixes of 3 items from
flaws list) TODO: * verify that no sequence of API calls produces SIGSEGV. That is, verify that mysql_stmt_init -> mysql_stmt_fetch is OK, or mysql_stmt_prepare -> mysql_stmt_fetch_column is OK and sets meaningful error. * remove alloc_stmt_fields call * revise stmt->state codes and statement states. * there are other items in prepared statements 'to fix' document. Done: - cleanups and comments - revision of prepared statement error codes. - mysql_stmt_prepare is now can always be called (that is, you can reprepare a statement) - new implementation of mysql_stmt_close and fetch cancellation
This commit is contained in:
parent
e90c78ceb5
commit
420c956d27
@ -67,7 +67,7 @@ extern const char *client_errors[]; /* Error messages */
|
|||||||
/* new 4.1 error codes */
|
/* new 4.1 error codes */
|
||||||
#define CR_NULL_POINTER 2028
|
#define CR_NULL_POINTER 2028
|
||||||
#define CR_NO_PREPARE_STMT 2029
|
#define CR_NO_PREPARE_STMT 2029
|
||||||
#define CR_NOT_ALL_PARAMS_BOUND 2030
|
#define CR_PARAMS_NOT_BOUND 2030
|
||||||
#define CR_DATA_TRUNCATED 2031
|
#define CR_DATA_TRUNCATED 2031
|
||||||
#define CR_NO_PARAMETERS_EXISTS 2032
|
#define CR_NO_PARAMETERS_EXISTS 2032
|
||||||
#define CR_INVALID_PARAMETER_NO 2033
|
#define CR_INVALID_PARAMETER_NO 2033
|
||||||
@ -87,3 +87,5 @@ extern const char *client_errors[]; /* Error messages */
|
|||||||
#define CR_CONN_UNKNOW_PROTOCOL 2046
|
#define CR_CONN_UNKNOW_PROTOCOL 2046
|
||||||
#define CR_INVALID_CONN_HANDLE 2047
|
#define CR_INVALID_CONN_HANDLE 2047
|
||||||
#define CR_SECURE_AUTH 2048
|
#define CR_SECURE_AUTH 2048
|
||||||
|
#define CR_FETCH_CANCELLED 2049
|
||||||
|
#define CR_NO_DATA 2050
|
||||||
|
@ -256,6 +256,11 @@ typedef struct st_mysql
|
|||||||
LIST *stmts; /* list of all statements */
|
LIST *stmts; /* list of all statements */
|
||||||
const struct st_mysql_methods *methods;
|
const struct st_mysql_methods *methods;
|
||||||
void *thd;
|
void *thd;
|
||||||
|
/*
|
||||||
|
Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag
|
||||||
|
from mysql_stmt_close if close had to cancel result set of this object.
|
||||||
|
*/
|
||||||
|
my_bool *unbuffered_fetch_owner;
|
||||||
} MYSQL;
|
} MYSQL;
|
||||||
|
|
||||||
typedef struct st_mysql_res {
|
typedef struct st_mysql_res {
|
||||||
@ -270,6 +275,8 @@ typedef struct st_mysql_res {
|
|||||||
MYSQL_ROW row; /* If unbuffered read */
|
MYSQL_ROW row; /* If unbuffered read */
|
||||||
MYSQL_ROW current_row; /* buffer to current row */
|
MYSQL_ROW current_row; /* buffer to current row */
|
||||||
my_bool eof; /* Used by mysql_fetch_row */
|
my_bool eof; /* Used by mysql_fetch_row */
|
||||||
|
/* mysql_stmt_close() had to cancel this result */
|
||||||
|
my_bool unbuffered_fetch_cancelled;
|
||||||
const struct st_mysql_methods *methods;
|
const struct st_mysql_methods *methods;
|
||||||
} MYSQL_RES;
|
} MYSQL_RES;
|
||||||
|
|
||||||
@ -479,7 +486,11 @@ my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* statement state */
|
/* statement state */
|
||||||
enum PREP_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE };
|
enum enum_mysql_stmt_state
|
||||||
|
{
|
||||||
|
MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE,
|
||||||
|
MYSQL_STMT_FETCH_DONE
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
client TIME structure to handle TIME, DATE and TIMESTAMP directly in
|
client TIME structure to handle TIME, DATE and TIMESTAMP directly in
|
||||||
@ -525,31 +536,34 @@ typedef struct st_mysql_bind
|
|||||||
/* statement handler */
|
/* statement handler */
|
||||||
typedef struct st_mysql_stmt
|
typedef struct st_mysql_stmt
|
||||||
{
|
{
|
||||||
MYSQL *mysql; /* connection handle */
|
MEM_ROOT mem_root; /* root allocations */
|
||||||
MYSQL_BIND *params; /* input parameters */
|
|
||||||
MYSQL_RES *result; /* resultset */
|
|
||||||
MYSQL_BIND *bind; /* row binding */
|
|
||||||
MYSQL_FIELD *fields; /* prepare meta info */
|
|
||||||
LIST list; /* list to keep track of all stmts */
|
LIST list; /* list to keep track of all stmts */
|
||||||
unsigned char *current_row; /* unbuffered row */
|
MYSQL *mysql; /* connection handle */
|
||||||
unsigned char *last_fetched_buffer; /* last fetched column buffer */
|
MYSQL_BIND *params; /* input parameters */
|
||||||
char *query; /* query buffer */
|
MYSQL_BIND *bind; /* output parameters */
|
||||||
MEM_ROOT mem_root; /* root allocations */
|
MYSQL_FIELD *fields; /* result set metadata */
|
||||||
my_ulonglong last_fetched_column; /* last fetched column */
|
MYSQL_RES *result; /* cached result set */
|
||||||
/* copy of mysql->affected_rows after statement execution */
|
/* copy of mysql->affected_rows after statement execution */
|
||||||
my_ulonglong affected_rows;
|
my_ulonglong affected_rows;
|
||||||
|
/*
|
||||||
|
mysql_stmt_fetch() calls this function to fetch one row (it's different
|
||||||
|
for buffered, unbuffered and cursor fetch).
|
||||||
|
*/
|
||||||
|
int (*read_row_func)(struct st_mysql_stmt *stmt,
|
||||||
|
unsigned char **row);
|
||||||
unsigned long stmt_id; /* Id for prepared statement */
|
unsigned long stmt_id; /* Id for prepared statement */
|
||||||
unsigned int last_errno; /* error code */
|
unsigned int last_errno; /* error code */
|
||||||
unsigned int param_count; /* parameters count */
|
unsigned int param_count; /* inpute parameters count */
|
||||||
unsigned int field_count; /* fields count */
|
unsigned int field_count; /* number of columns in result set */
|
||||||
enum PREP_STMT_STATE state; /* statement state */
|
enum enum_mysql_stmt_state state; /* statement state */
|
||||||
char last_error[MYSQL_ERRMSG_SIZE]; /* error message */
|
char last_error[MYSQL_ERRMSG_SIZE]; /* error message */
|
||||||
char sqlstate[SQLSTATE_LENGTH+1];
|
char sqlstate[SQLSTATE_LENGTH+1];
|
||||||
my_bool long_alloced; /* flag to indicate long alloced */
|
/* Types of input parameters should be sent to server */
|
||||||
my_bool send_types_to_server; /* Types sent to server */
|
my_bool send_types_to_server;
|
||||||
my_bool param_buffers; /* param bound buffers */
|
my_bool bind_param_done; /* input buffers were supplied */
|
||||||
my_bool res_buffers; /* output bound buffers */
|
my_bool bind_result_done; /* output buffers were supplied */
|
||||||
my_bool result_buffered; /* Results buffered */
|
/* mysql_stmt_close() had to cancel this result */
|
||||||
|
my_bool unbuffered_fetch_cancelled;
|
||||||
} MYSQL_STMT;
|
} MYSQL_STMT;
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ extern "C" {
|
|||||||
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
|
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
|
||||||
my_bool default_value, uint server_capabilities);
|
my_bool default_value, uint server_capabilities);
|
||||||
void free_rows(MYSQL_DATA *cur);
|
void free_rows(MYSQL_DATA *cur);
|
||||||
|
void flush_use_result(MYSQL *mysql);
|
||||||
my_bool mysql_autenticate(MYSQL *mysql, const char *passwd);
|
my_bool mysql_autenticate(MYSQL *mysql, const char *passwd);
|
||||||
void free_old_query(MYSQL *mysql);
|
void free_old_query(MYSQL *mysql);
|
||||||
void end_server(MYSQL *mysql);
|
void end_server(MYSQL *mysql);
|
||||||
|
@ -22,7 +22,6 @@ extern my_string mysql_unix_port;
|
|||||||
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
|
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
|
||||||
|
|
||||||
sig_handler pipe_sig_handler(int sig __attribute__((unused)));
|
sig_handler pipe_sig_handler(int sig __attribute__((unused)));
|
||||||
my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_free);
|
|
||||||
void read_user_name(char *name);
|
void read_user_name(char *name);
|
||||||
my_bool send_file_to_server(MYSQL *mysql, const char *filename);
|
my_bool send_file_to_server(MYSQL *mysql, const char *filename);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ const char *client_errors[]=
|
|||||||
"Malformed packet",
|
"Malformed packet",
|
||||||
"Invalid use of null pointer",
|
"Invalid use of null pointer",
|
||||||
"Statement not prepared",
|
"Statement not prepared",
|
||||||
"Not all parameters data supplied",
|
"Parameters data was not supplied",
|
||||||
"Data truncated",
|
"Data truncated",
|
||||||
"No parameters exists in the statement",
|
"No parameters exists in the statement",
|
||||||
"Invalid parameter number",
|
"Invalid parameter number",
|
||||||
@ -72,7 +72,9 @@ const char *client_errors[]=
|
|||||||
"Can't open shared memory. Can't send the request event to server (%lu)",
|
"Can't open shared memory. Can't send the request event to server (%lu)",
|
||||||
"Wrong or unknown protocol",
|
"Wrong or unknown protocol",
|
||||||
"Invalid connection handle",
|
"Invalid connection handle",
|
||||||
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
|
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
|
||||||
|
"Row retrieval was cancelled by mysql_stmt_close() call",
|
||||||
|
"Attempt to read column without prior row fetch"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
|
/* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
|
||||||
@ -110,7 +112,7 @@ const char *client_errors[]=
|
|||||||
"Malformed packet",
|
"Malformed packet",
|
||||||
"Invalid use of null pointer",
|
"Invalid use of null pointer",
|
||||||
"Statement not prepared",
|
"Statement not prepared",
|
||||||
"Not all parameters data supplied",
|
"Parameters data was not supplied",
|
||||||
"Data truncated",
|
"Data truncated",
|
||||||
"No parameters exists in the statement",
|
"No parameters exists in the statement",
|
||||||
"Invalid parameter number",
|
"Invalid parameter number",
|
||||||
@ -128,7 +130,9 @@ const char *client_errors[]=
|
|||||||
"Can't open shared memory. Can't send the request event to server (%lu)",
|
"Can't open shared memory. Can't send the request event to server (%lu)",
|
||||||
"Wrong or unknown protocol",
|
"Wrong or unknown protocol",
|
||||||
"Invalid connection handle",
|
"Invalid connection handle",
|
||||||
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
|
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
|
||||||
|
"Row retrieval was cancelled by mysql_stmt_close() call",
|
||||||
|
"Attempt to read column without prior row fetch"
|
||||||
};
|
};
|
||||||
|
|
||||||
#else /* ENGLISH */
|
#else /* ENGLISH */
|
||||||
@ -182,7 +186,9 @@ const char *client_errors[]=
|
|||||||
"Can't open shared memory. Can't send the request event to server (%lu)",
|
"Can't open shared memory. Can't send the request event to server (%lu)",
|
||||||
"Wrong or unknown protocol",
|
"Wrong or unknown protocol",
|
||||||
"Invalid connection handle",
|
"Invalid connection handle",
|
||||||
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)"
|
"Connection using old (pre 4.1.1) authentication protocol refused (client option 'secure_auth' enabled)",
|
||||||
|
"Row retrieval was cancelled by mysql_stmt_close() call",
|
||||||
|
"Attempt to read column without prior row fetch"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -638,6 +638,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
||||||
const char *passwd, const char *db)
|
const char *passwd, const char *db)
|
||||||
{
|
{
|
||||||
@ -866,6 +867,7 @@ STDCALL mysql_set_master(MYSQL* mysql, const char* host,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
|
STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
|
||||||
unsigned int port,
|
unsigned int port,
|
||||||
@ -987,6 +989,7 @@ mysql_list_tables(MYSQL *mysql, const char *wild)
|
|||||||
DBUG_RETURN (mysql_store_result(mysql));
|
DBUG_RETURN (mysql_store_result(mysql));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
|
MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
MYSQL_DATA *query;
|
MYSQL_DATA *query;
|
||||||
@ -1062,6 +1065,7 @@ mysql_list_processes(MYSQL *mysql)
|
|||||||
DBUG_RETURN(mysql_store_result(mysql));
|
DBUG_RETURN(mysql_store_result(mysql));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_OLD_FUNCTIONS
|
#ifdef USE_OLD_FUNCTIONS
|
||||||
int STDCALL
|
int STDCALL
|
||||||
mysql_create_db(MYSQL *mysql, const char *db)
|
mysql_create_db(MYSQL *mysql, const char *db)
|
||||||
@ -1099,6 +1103,7 @@ mysql_refresh(MYSQL *mysql,uint options)
|
|||||||
DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
|
DBUG_RETURN(simple_command(mysql,COM_REFRESH,(char*) bits,1,0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int STDCALL
|
int STDCALL
|
||||||
mysql_kill(MYSQL *mysql,ulong pid)
|
mysql_kill(MYSQL *mysql,ulong pid)
|
||||||
{
|
{
|
||||||
@ -1126,6 +1131,7 @@ mysql_dump_debug_info(MYSQL *mysql)
|
|||||||
DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
|
DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *cli_read_statistics(MYSQL *mysql)
|
const char *cli_read_statistics(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
|
mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
|
||||||
@ -1139,6 +1145,7 @@ const char *cli_read_statistics(MYSQL *mysql)
|
|||||||
return (char*) mysql->net.read_pos;
|
return (char*) mysql->net.read_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char * STDCALL
|
const char * STDCALL
|
||||||
mysql_stat(MYSQL *mysql)
|
mysql_stat(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
@ -1576,6 +1583,10 @@ static my_bool my_realloc_str(NET *net, ulong length)
|
|||||||
Prepare related implementations
|
Prepare related implementations
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read the prepared statement results ..
|
Read the prepared statement results ..
|
||||||
|
|
||||||
@ -1591,13 +1602,12 @@ static my_bool my_realloc_str(NET *net, ulong length)
|
|||||||
my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
|
my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
uchar *pos;
|
uchar *pos;
|
||||||
uint field_count;
|
uint field_count, param_count;
|
||||||
ulong length, param_count;
|
|
||||||
MYSQL_DATA *fields_data;
|
MYSQL_DATA *fields_data;
|
||||||
DBUG_ENTER("read_prepare_result");
|
DBUG_ENTER("read_prepare_result");
|
||||||
|
|
||||||
mysql= mysql->last_used_con;
|
mysql= mysql->last_used_con;
|
||||||
if ((length= net_safe_read(mysql)) == packet_error)
|
if (net_safe_read(mysql) == packet_error)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
pos= (uchar*) mysql->net.read_pos;
|
pos= (uchar*) mysql->net.read_pos;
|
||||||
@ -1634,7 +1644,7 @@ MYSQL_STMT * STDCALL mysql_prepare(MYSQL *mysql, const char *query,
|
|||||||
stmt= mysql_stmt_init(mysql);
|
stmt= mysql_stmt_init(mysql);
|
||||||
if (stmt && mysql_stmt_prepare(stmt, query, query_length))
|
if (stmt && mysql_stmt_prepare(stmt, query, query_length))
|
||||||
{
|
{
|
||||||
stmt_close(stmt, 0);
|
mysql_stmt_close(stmt);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(stmt);
|
DBUG_RETURN(stmt);
|
||||||
@ -1646,6 +1656,7 @@ MYSQL_STMT * STDCALL mysql_prepare(MYSQL *mysql, const char *query,
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
mysql_stmt_init()
|
mysql_stmt_init()
|
||||||
mysql connection handle
|
mysql connection handle
|
||||||
|
|
||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
statement structure upon success and NULL if out of
|
statement structure upon success and NULL if out of
|
||||||
memory
|
memory
|
||||||
@ -1664,20 +1675,35 @@ mysql_stmt_init(MYSQL *mysql)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_alloc_root(&stmt->mem_root,8192,0);
|
init_alloc_root(&stmt->mem_root, 2048, 2048);
|
||||||
mysql->stmts= list_add(mysql->stmts, &stmt->list);
|
mysql->stmts= list_add(mysql->stmts, &stmt->list);
|
||||||
stmt->list.data= stmt;
|
stmt->list.data= stmt;
|
||||||
stmt->state= MY_ST_UNKNOWN;
|
stmt->state= MYSQL_STMT_INIT_DONE;
|
||||||
stmt->mysql= mysql;
|
stmt->mysql= mysql;
|
||||||
|
stmt->read_row_func= stmt_read_row_no_data;
|
||||||
|
/* The rest of statement members was bzeroed inside malloc */
|
||||||
|
|
||||||
DBUG_RETURN(stmt);
|
DBUG_RETURN(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prepare server side statement with query.
|
Prepare server side statement with query:
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_stmt_prepare()
|
||||||
|
query statement to prepare
|
||||||
|
length statement length
|
||||||
|
|
||||||
Also update the total parameter count along with resultset
|
DESCRIPTION
|
||||||
metadata information by reading from server
|
- if this is a re-prepare of the statement, first close previous data
|
||||||
|
structure on the server and free old statement data
|
||||||
|
- send the query to server and get back number of placeholders,
|
||||||
|
number of columns in result set (if any), and result set metadata.
|
||||||
|
At the same time allocate memory for input and output parameters
|
||||||
|
to have less checks in mysql_stmt_bind_{param, result}.
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
0 success
|
||||||
|
!0 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -1687,17 +1713,44 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
MYSQL *mysql= stmt->mysql;
|
MYSQL *mysql= stmt->mysql;
|
||||||
DBUG_ENTER("mysql_stmt_prepare");
|
DBUG_ENTER("mysql_stmt_prepare");
|
||||||
|
|
||||||
DBUG_ASSERT(mysql != 0);
|
if (!mysql)
|
||||||
|
|
||||||
/* In case we reprepare this handle with another statement */
|
|
||||||
free_root(&stmt->mem_root, MYF(0));
|
|
||||||
|
|
||||||
/* stmt->query is never used yet */
|
|
||||||
if (!(stmt->query= strmake_root(&stmt->mem_root, query, length)))
|
|
||||||
{
|
{
|
||||||
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
/* mysql can be reset in mysql_close called from mysql_reconnect */
|
||||||
|
set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
||||||
|
{
|
||||||
|
/* This is second prepare with another statement */
|
||||||
|
char buff[4];
|
||||||
|
|
||||||
|
mysql_stmt_free_result(stmt);
|
||||||
|
/*
|
||||||
|
These members must be reset for API to
|
||||||
|
function in case of error or misuse.
|
||||||
|
*/
|
||||||
|
stmt->bind_param_done= stmt->bind_result_done= FALSE;
|
||||||
|
stmt->param_count= stmt->field_count= 0;
|
||||||
|
stmt->last_errno= 0;
|
||||||
|
stmt->last_error[0]= '\0';
|
||||||
|
free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
|
||||||
|
|
||||||
|
int4store(buff, stmt->stmt_id);
|
||||||
|
/*
|
||||||
|
If there was a 'use' result from another statement, or from
|
||||||
|
mysql_use_result it won't be freed in mysql_stmt_free_result and
|
||||||
|
we should get 'Commands out of sync' here.
|
||||||
|
*/
|
||||||
|
if (simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
|
||||||
|
{
|
||||||
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
|
mysql->net.sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
stmt->state= MYSQL_STMT_INIT_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (simple_command(mysql, COM_PREPARE, query, length, 1))
|
if (simple_command(mysql, COM_PREPARE, query, length, 1))
|
||||||
{
|
{
|
||||||
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
@ -1706,8 +1759,18 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((*mysql->methods->read_prepare_result)(mysql, stmt))
|
if ((*mysql->methods->read_prepare_result)(mysql, stmt))
|
||||||
|
{
|
||||||
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
|
mysql->net.sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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,
|
if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root,
|
||||||
sizeof(MYSQL_BIND)*
|
sizeof(MYSQL_BIND)*
|
||||||
(stmt->param_count +
|
(stmt->param_count +
|
||||||
@ -1717,26 +1780,22 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
stmt->bind= stmt->params + stmt->param_count;
|
stmt->bind= stmt->params + stmt->param_count;
|
||||||
stmt->state= MY_ST_PREPARE;
|
stmt->state= MYSQL_STMT_PREPARE_DONE;
|
||||||
mysql->status= MYSQL_STATUS_READY;
|
|
||||||
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
|
DBUG_PRINT("info", ("Parameter count: %ld", stmt->param_count));
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the execute query meta information for non-select
|
Get the execute query meta information for non-select
|
||||||
statements (on demand).
|
statements.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
|
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;
|
||||||
|
|
||||||
if (stmt->state != MY_ST_EXECUTE || !mysql->field_count)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
stmt->field_count= mysql->field_count;
|
stmt->field_count= mysql->field_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1782,20 +1841,25 @@ 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");
|
||||||
|
|
||||||
if (!stmt->field_count || !stmt->fields)
|
/*
|
||||||
{
|
stmt->fields is only defined if stmt->field_count is not null;
|
||||||
if (!alloc_stmt_fields(stmt))
|
stmt->field_count is initialized in prepare.
|
||||||
DBUG_RETURN(0);
|
*/
|
||||||
}
|
if (!stmt->field_count)
|
||||||
if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
|
DBUG_RETURN(0);
|
||||||
sizeof(ulong)*stmt->field_count,
|
|
||||||
MYF(MY_WME | MY_ZEROFILL))))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
result->methods= stmt->mysql->methods;
|
if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result),
|
||||||
result->eof=1; /* Marker for buffered */
|
MYF(MY_WME | MY_ZEROFILL))))
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result->methods= stmt->mysql->methods;
|
||||||
|
result->eof= 1; /* Marker for buffered */
|
||||||
result->fields= stmt->fields;
|
result->fields= stmt->fields;
|
||||||
result->field_count= stmt->field_count;
|
result->field_count= stmt->field_count;
|
||||||
|
/* The rest of members of 'result' was bzeroed inside malloc */
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1989,11 +2053,9 @@ static void store_param_null(NET *net, MYSQL_BIND *param)
|
|||||||
client application
|
client application
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
|
static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= stmt->mysql;
|
NET *net= &stmt->mysql->net;
|
||||||
NET *net = &mysql->net;
|
|
||||||
DBUG_ENTER("store_param");
|
DBUG_ENTER("store_param");
|
||||||
DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %lu is_null: %d",
|
DBUG_PRINT("enter",("type: %d, buffer:%lx, length: %lu is_null: %d",
|
||||||
param->buffer_type,
|
param->buffer_type,
|
||||||
@ -2059,6 +2121,12 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
uint null_count;
|
uint null_count;
|
||||||
my_bool result;
|
my_bool result;
|
||||||
|
|
||||||
|
if (!stmt->bind_param_done)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
net_clear(net); /* Sets net->write_pos */
|
net_clear(net); /* Sets net->write_pos */
|
||||||
/* Reserve place for null-marker bytes */
|
/* Reserve place for null-marker bytes */
|
||||||
null_count= (stmt->param_count+7) /8;
|
null_count= (stmt->param_count+7) /8;
|
||||||
@ -2093,7 +2161,6 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
net->write_pos= net->buff; /* Reset for net_write() */
|
|
||||||
result= execute(stmt, param_data, length);
|
result= execute(stmt, param_data, length);
|
||||||
stmt->send_types_to_server=0;
|
stmt->send_types_to_server=0;
|
||||||
my_free(param_data, MYF(MY_WME));
|
my_free(param_data, MYF(MY_WME));
|
||||||
@ -2102,22 +2169,146 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
DBUG_RETURN((int) execute(stmt,0,0));
|
DBUG_RETURN((int) execute(stmt,0,0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read one row from buffered result set. Result set is created by prior
|
||||||
|
call to mysql_stmt_store_result().
|
||||||
|
SYNOPSIS
|
||||||
|
stmt_read_row_buffered()
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - success; *row is set to valid row pointer (row data
|
||||||
|
is stored in result set buffer)
|
||||||
|
MYSQL_NO_DATA - end of result set. *row is set to NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row)
|
||||||
|
{
|
||||||
|
MYSQL_RES *result= stmt->result;
|
||||||
|
|
||||||
|
if (result && result->data_cursor)
|
||||||
|
{
|
||||||
|
*row= (uchar *) result->data_cursor->data;
|
||||||
|
result->data_cursor= result->data_cursor->next;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*row= 0;
|
||||||
|
return MYSQL_NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read one row from network: unbuffered non-cursor fetch.
|
||||||
|
If last row was read, or error occured, erase this statement
|
||||||
|
from record pointing to object unbuffered fetch is performed from.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
stmt_read_row_unbuffered()
|
||||||
|
stmt statement handle
|
||||||
|
row pointer to write pointer to row data;
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
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
|
||||||
|
MYSQL_NO_DATA - end of file was read from network;
|
||||||
|
*row is 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.
|
||||||
|
*/
|
||||||
|
if (!mysql)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (mysql->status != MYSQL_STATUS_GET_RESULT)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
|
||||||
|
CR_FETCH_CANCELLED : CR_COMMANDS_OUT_OF_SYNC,
|
||||||
|
unknown_sqlstate);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row))
|
||||||
|
{
|
||||||
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
|
mysql->net.sqlstate);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (!*row)
|
||||||
|
{
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
rc= MYSQL_NO_DATA;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
|
||||||
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Default read row function to not SIGSEGV in client in
|
||||||
|
case of wrong sequence of API calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)),
|
||||||
|
unsigned char **row __attribute__((unused)))
|
||||||
|
{
|
||||||
|
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return MYSQL_NO_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Execute the prepared query
|
Execute the prepared query
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
|
MYSQL *mysql= stmt->mysql;
|
||||||
DBUG_ENTER("mysql_stmt_execute");
|
DBUG_ENTER("mysql_stmt_execute");
|
||||||
|
|
||||||
if ((*stmt->mysql->methods->stmt_execute)(stmt))
|
if (!mysql)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_stmt_free_result(stmt);
|
||||||
|
/*
|
||||||
|
No need to check for stmt->state: if the statement wasn't
|
||||||
|
prepared we'll get 'unknown statemenet handler' error from server.
|
||||||
|
*/
|
||||||
|
if (mysql->methods->stmt_execute(stmt))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
if (!stmt->field_count && mysql->field_count)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
|
||||||
|
prepared statements can't send result set metadata for this queries
|
||||||
|
on prepare stage. Read it now.
|
||||||
|
*/
|
||||||
|
alloc_stmt_fields(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
stmt->state= MY_ST_EXECUTE;
|
stmt->state= MYSQL_STMT_EXECUTE_DONE;
|
||||||
mysql_free_result(stmt->result);
|
if (stmt->field_count)
|
||||||
stmt->result= (MYSQL_RES *)0;
|
{
|
||||||
stmt->result_buffered= 0;
|
stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
|
||||||
stmt->current_row= 0;
|
stmt->unbuffered_fetch_cancelled= FALSE;
|
||||||
|
stmt->read_row_func= stmt_read_row_unbuffered;
|
||||||
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2155,6 +2346,16 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
|
|||||||
MYSQL_BIND *param, *end;
|
MYSQL_BIND *param, *end;
|
||||||
DBUG_ENTER("mysql_stmt_bind_param");
|
DBUG_ENTER("mysql_stmt_bind_param");
|
||||||
|
|
||||||
|
if (!stmt->param_count)
|
||||||
|
{
|
||||||
|
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocated on prepare */
|
/* Allocated on prepare */
|
||||||
memcpy((char*) stmt->params, (char*) bind,
|
memcpy((char*) stmt->params, (char*) bind,
|
||||||
sizeof(MYSQL_BIND) * stmt->param_count);
|
sizeof(MYSQL_BIND) * stmt->param_count);
|
||||||
@ -2166,13 +2367,6 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
|
|||||||
param->param_number= count++;
|
param->param_number= count++;
|
||||||
param->long_data_used= 0;
|
param->long_data_used= 0;
|
||||||
|
|
||||||
/*
|
|
||||||
If param->length is not given, change it to point to buffer_length.
|
|
||||||
This way we can always use *param->length to get the length of data
|
|
||||||
*/
|
|
||||||
if (!param->length)
|
|
||||||
param->length= ¶m->buffer_length;
|
|
||||||
|
|
||||||
/* If param->is_null is not set, then the value can never be NULL */
|
/* If param->is_null is not set, then the value can never be NULL */
|
||||||
if (!param->is_null)
|
if (!param->is_null)
|
||||||
param->is_null= &int_is_null_false;
|
param->is_null= &int_is_null_false;
|
||||||
@ -2239,10 +2433,16 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
|
|||||||
param->buffer_type, count);
|
param->buffer_type, count);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
If param->length is not given, change it to point to buffer_length.
|
||||||
|
This way we can always use *param->length to get the length of data
|
||||||
|
*/
|
||||||
|
if (!param->length)
|
||||||
|
param->length= ¶m->buffer_length;
|
||||||
}
|
}
|
||||||
/* We have to send/resendtype information to MySQL */
|
/* We have to send/resendtype information to MySQL */
|
||||||
stmt->send_types_to_server= 1;
|
stmt->send_types_to_server= TRUE;
|
||||||
stmt->param_buffers= 1;
|
stmt->bind_param_done= TRUE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2276,6 +2476,16 @@ 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
|
||||||
|
prepare was done.
|
||||||
|
*/
|
||||||
|
if (param_number >= stmt->param_count)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
param= stmt->params+param_number;
|
param= stmt->params+param_number;
|
||||||
if (param->buffer_type < MYSQL_TYPE_TINY_BLOB ||
|
if (param->buffer_type < MYSQL_TYPE_TINY_BLOB ||
|
||||||
@ -2846,9 +3056,20 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
|
|||||||
DBUG_ENTER("mysql_stmt_bind_result");
|
DBUG_ENTER("mysql_stmt_bind_result");
|
||||||
DBUG_ASSERT(stmt != 0);
|
DBUG_ASSERT(stmt != 0);
|
||||||
|
|
||||||
if (!(bind_count= stmt->field_count) &&
|
if (!stmt->field_count)
|
||||||
!(bind_count= alloc_stmt_fields(stmt)))
|
{
|
||||||
|
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
|
||||||
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
bind_count= stmt->field_count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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,
|
memcpy((char*) stmt->bind, (char*) bind,
|
||||||
sizeof(MYSQL_BIND)*bind_count);
|
sizeof(MYSQL_BIND)*bind_count);
|
||||||
@ -2929,7 +3150,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stmt->res_buffers= 1;
|
stmt->bind_result_done= TRUE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2943,9 +3164,18 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
|
|||||||
MYSQL_BIND *bind, *end;
|
MYSQL_BIND *bind, *end;
|
||||||
MYSQL_FIELD *field, *field_end;
|
MYSQL_FIELD *field, *field_end;
|
||||||
uchar *null_ptr, bit;
|
uchar *null_ptr, bit;
|
||||||
|
/*
|
||||||
|
Precondition: if stmt->field_count is zero or row is NULL, read_row_*
|
||||||
|
function must return no data.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(stmt->field_count);
|
||||||
|
DBUG_ASSERT(row);
|
||||||
|
|
||||||
if (!row || !stmt->res_buffers)
|
if (!stmt->bind_result_done)
|
||||||
|
{
|
||||||
|
/* 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 */
|
||||||
@ -2994,57 +3224,22 @@ int cli_unbuffered_fetch(MYSQL *mysql, char **row)
|
|||||||
|
|
||||||
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
|
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= stmt->mysql;
|
int rc;
|
||||||
uchar *row;
|
uchar *row;
|
||||||
DBUG_ENTER("mysql_stmt_fetch");
|
DBUG_ENTER("mysql_stmt_fetch");
|
||||||
|
|
||||||
stmt->last_fetched_column= 0; /* reset */
|
if ((rc= (*stmt->read_row_func)(stmt, &row)) ||
|
||||||
if (stmt->result_buffered) /* buffered */
|
(rc= stmt_fetch_row(stmt, row)))
|
||||||
{
|
{
|
||||||
MYSQL_RES *res;
|
stmt->state= MYSQL_STMT_PREPARE_DONE; /* XXX: this is buggy */
|
||||||
|
stmt->read_row_func= stmt_read_row_no_data;
|
||||||
if (!(res= stmt->result))
|
|
||||||
goto no_data;
|
|
||||||
|
|
||||||
if (!res->data_cursor)
|
|
||||||
{
|
|
||||||
stmt->current_row= 0;
|
|
||||||
goto no_data;
|
|
||||||
}
|
|
||||||
row= (uchar *)res->data_cursor->data;
|
|
||||||
res->data_cursor= res->data_cursor->next;
|
|
||||||
}
|
}
|
||||||
else /* un-buffered */
|
else
|
||||||
{
|
{
|
||||||
if (mysql->status != MYSQL_STATUS_GET_RESULT)
|
/* This is to know in mysql_stmt_fetch_column that data was fetched */
|
||||||
{
|
stmt->state= MYSQL_STMT_FETCH_DONE;
|
||||||
if (!stmt->field_count)
|
|
||||||
goto no_data;
|
|
||||||
|
|
||||||
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) &row))
|
|
||||||
{
|
|
||||||
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
|
||||||
mysql->net.sqlstate);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
if (!row)
|
|
||||||
{
|
|
||||||
mysql->status= MYSQL_STATUS_READY;
|
|
||||||
stmt->current_row= 0;
|
|
||||||
goto no_data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
DBUG_RETURN(rc);
|
||||||
stmt->current_row= row;
|
|
||||||
DBUG_RETURN(stmt_fetch_row(stmt, row));
|
|
||||||
|
|
||||||
no_data:
|
|
||||||
DBUG_PRINT("info", ("end of data"));
|
|
||||||
DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3065,13 +3260,22 @@ no_data:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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 (!stmt->current_row)
|
if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
|
||||||
goto no_data;
|
{
|
||||||
|
set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (column >= stmt->field_count)
|
||||||
|
{
|
||||||
|
set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (param->null_field)
|
if (param->null_field)
|
||||||
{
|
{
|
||||||
@ -3092,10 +3296,6 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
|
|||||||
fetch_results(bind, field, &row);
|
fetch_results(bind, field, &row);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
no_data:
|
|
||||||
DBUG_PRINT("info", ("end of data"));
|
|
||||||
DBUG_RETURN(MYSQL_NO_DATA); /* no more data */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3111,7 +3311,7 @@ MYSQL_DATA *cli_read_binary_rows(MYSQL_STMT *stmt)
|
|||||||
MYSQL_DATA *result;
|
MYSQL_DATA *result;
|
||||||
MYSQL_ROWS *cur, **prev_ptr;
|
MYSQL_ROWS *cur, **prev_ptr;
|
||||||
NET *net = &mysql->net;
|
NET *net = &mysql->net;
|
||||||
DBUG_ENTER("read_binary_rows");
|
DBUG_ENTER("cli_read_binary_rows");
|
||||||
|
|
||||||
mysql= mysql->last_used_con;
|
mysql= mysql->last_used_con;
|
||||||
if ((pkt_len= net_safe_read(mysql)) == packet_error)
|
if ((pkt_len= net_safe_read(mysql)) == packet_error)
|
||||||
@ -3181,33 +3381,37 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
|
|||||||
|
|
||||||
if (!stmt->field_count)
|
if (!stmt->field_count)
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
if (mysql->status != MYSQL_STATUS_GET_RESULT)
|
if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE ||
|
||||||
|
mysql->status != MYSQL_STATUS_GET_RESULT)
|
||||||
{
|
{
|
||||||
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
|
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
mysql->status= MYSQL_STATUS_READY; /* server is ready */
|
if (!(result= (MYSQL_RES*) my_malloc(sizeof(MYSQL_RES),
|
||||||
if (!(result= (MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
|
|
||||||
sizeof(ulong) *
|
|
||||||
stmt->field_count),
|
|
||||||
MYF(MY_WME | MY_ZEROFILL))))
|
MYF(MY_WME | MY_ZEROFILL))))
|
||||||
{
|
{
|
||||||
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
result->methods= mysql->methods;
|
result->methods= mysql->methods;
|
||||||
stmt->result_buffered= 1;
|
if ((result->data= (*mysql->methods->read_binary_rows)(stmt)))
|
||||||
if (!(result->data= (*stmt->mysql->methods->read_binary_rows)(stmt)))
|
{
|
||||||
|
result->row_count= result->data->rows;
|
||||||
|
result->data_cursor= result->data->data;
|
||||||
|
}
|
||||||
|
else if (stmt->last_errno)
|
||||||
{
|
{
|
||||||
my_free((gptr) result,MYF(0));
|
my_free((gptr) result,MYF(0));
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
mysql->affected_rows= result->row_count= result->data->rows;
|
mysql->affected_rows= stmt->affected_rows= result->row_count;
|
||||||
stmt->affected_rows= result->row_count;
|
|
||||||
result->data_cursor= result->data->data;
|
|
||||||
result->fields= stmt->fields;
|
result->fields= stmt->fields;
|
||||||
result->field_count= stmt->field_count;
|
result->field_count= stmt->field_count;
|
||||||
|
/* The rest of MYSQL_RES members were bzeroed inside my_malloc */
|
||||||
stmt->result= result;
|
stmt->result= result;
|
||||||
|
stmt->read_row_func= stmt_read_row_buffered;
|
||||||
|
mysql->unbuffered_fetch_owner= 0; /* set in stmt_execute */
|
||||||
|
mysql->status= MYSQL_STATUS_READY; /* server is ready */
|
||||||
DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */
|
DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3292,6 +3496,40 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (stmt->result)
|
||||||
|
{
|
||||||
|
/* Result buffered */
|
||||||
|
mysql_free_result(stmt->result);
|
||||||
|
stmt->result= 0;
|
||||||
|
}
|
||||||
|
else if (mysql && stmt->field_count
|
||||||
|
&& (int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
|
||||||
|
{
|
||||||
|
if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
|
||||||
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
|
if (mysql->status != MYSQL_STATUS_READY)
|
||||||
|
{
|
||||||
|
/* There is a result set and it belongs to this statement */
|
||||||
|
flush_use_result(mysql);
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt->state= MYSQL_STMT_PREPARE_DONE;
|
||||||
|
stmt->read_row_func= stmt_read_row_no_data;
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
statement error handling and close
|
statement error handling and close
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
@ -3300,82 +3538,55 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
|
|||||||
Close the statement handle by freeing all alloced resources
|
Close the statement handle by freeing all alloced resources
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
mysql_stmt_free_result()
|
mysql_stmt_close()
|
||||||
stmt Statement handle
|
stmt Statement handle
|
||||||
skip_list Flag to indicate delete from list or not
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 ok
|
0 ok
|
||||||
1 error
|
1 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
|
||||||
{
|
|
||||||
MYSQL *mysql;
|
|
||||||
DBUG_ENTER("mysql_stmt_free_result");
|
|
||||||
|
|
||||||
DBUG_ASSERT(stmt != 0);
|
|
||||||
|
|
||||||
mysql= stmt->mysql;
|
|
||||||
if (mysql->status != MYSQL_STATUS_READY)
|
|
||||||
{
|
|
||||||
/* Clear the current execution status */
|
|
||||||
DBUG_PRINT("warning",("Not all packets read, clearing them"));
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ulong pkt_len;
|
|
||||||
if ((pkt_len= net_safe_read(mysql)) == packet_error)
|
|
||||||
break;
|
|
||||||
if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mysql->status= MYSQL_STATUS_READY;
|
|
||||||
}
|
|
||||||
mysql_free_result(stmt->result);
|
|
||||||
stmt->result= 0;
|
|
||||||
stmt->result_buffered= 0;
|
|
||||||
stmt->current_row= 0;
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_free)
|
|
||||||
{
|
|
||||||
MYSQL *mysql;
|
|
||||||
DBUG_ENTER("stmt_close");
|
|
||||||
|
|
||||||
DBUG_ASSERT(stmt != 0);
|
|
||||||
|
|
||||||
if (!(mysql= stmt->mysql))
|
|
||||||
{
|
|
||||||
if (!skip_free)
|
|
||||||
my_free((gptr) stmt, MYF(MY_WME));
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
mysql_stmt_free_result(stmt);
|
|
||||||
if (stmt->state == MY_ST_PREPARE || stmt->state == MY_ST_EXECUTE)
|
|
||||||
{
|
|
||||||
char buff[4];
|
|
||||||
int4store(buff, stmt->stmt_id);
|
|
||||||
if (skip_free || simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
|
|
||||||
{
|
|
||||||
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
|
||||||
mysql->net.sqlstate);
|
|
||||||
stmt->mysql= NULL; /* connection isn't valid anymore */
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stmt->field_count= 0;
|
|
||||||
free_root(&stmt->mem_root, MYF(0));
|
|
||||||
mysql->stmts= list_delete(mysql->stmts, &stmt->list);
|
|
||||||
mysql->status= MYSQL_STATUS_READY;
|
|
||||||
my_free((gptr) stmt, MYF(MY_WME));
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
|
my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
return stmt_close(stmt, 0);
|
MYSQL *mysql= stmt->mysql;
|
||||||
|
int rc= 0;
|
||||||
|
DBUG_ENTER("mysql_stmt_close");
|
||||||
|
|
||||||
|
mysql_free_result(stmt->result); /* if result is buffered */
|
||||||
|
free_root(&stmt->mem_root, MYF(0));
|
||||||
|
|
||||||
|
if (mysql)
|
||||||
|
{
|
||||||
|
mysql->stmts= list_delete(mysql->stmts, &stmt->list);
|
||||||
|
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
||||||
|
{
|
||||||
|
char buff[4];
|
||||||
|
|
||||||
|
if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
flush_use_result(mysql);
|
||||||
|
if (mysql->unbuffered_fetch_owner)
|
||||||
|
*mysql->unbuffered_fetch_owner= TRUE;
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
}
|
||||||
|
int4store(buff, stmt->stmt_id);
|
||||||
|
if ((rc= simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1)))
|
||||||
|
{
|
||||||
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
|
mysql->net.sqlstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my_free((gptr) stmt, MYF(MY_WME));
|
||||||
|
|
||||||
|
DBUG_RETURN(test(rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3388,6 +3599,10 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
|
|||||||
MYSQL *mysql;
|
MYSQL *mysql;
|
||||||
DBUG_ENTER("mysql_stmt_reset");
|
DBUG_ENTER("mysql_stmt_reset");
|
||||||
DBUG_ASSERT(stmt != 0);
|
DBUG_ASSERT(stmt != 0);
|
||||||
|
|
||||||
|
/* 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;
|
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 */
|
||||||
|
@ -712,6 +712,34 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
|
|||||||
net->last_errno= errcode;
|
net->last_errno= errcode;
|
||||||
strmov(net->last_error, ER(errcode));
|
strmov(net->last_error, ER(errcode));
|
||||||
strmov(net->sqlstate, sqlstate);
|
strmov(net->sqlstate, sqlstate);
|
||||||
|
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Flush result set sent from server
|
||||||
|
*/
|
||||||
|
|
||||||
|
void flush_use_result(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
/* Clear the current execution status */
|
||||||
|
DBUG_PRINT("warning",("Not all packets read, clearing them"));
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ulong pkt_len;
|
||||||
|
if ((pkt_len=net_safe_read(mysql)) == packet_error)
|
||||||
|
break;
|
||||||
|
if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
|
||||||
|
{
|
||||||
|
if (protocol_41(mysql))
|
||||||
|
{
|
||||||
|
char *pos= (char*) mysql->net.read_pos;
|
||||||
|
mysql->warning_count=uint2korr(pos); pos+=2;
|
||||||
|
mysql->server_status=uint2korr(pos); pos+=2;
|
||||||
|
}
|
||||||
|
break; /* End of data */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -752,26 +780,16 @@ mysql_free_result(MYSQL_RES *result)
|
|||||||
DBUG_PRINT("enter",("mysql_res: %lx",result));
|
DBUG_PRINT("enter",("mysql_res: %lx",result));
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
|
MYSQL *mysql= result->handle;
|
||||||
|
if (mysql)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("warning",("Not all rows in set where read; Ignoring rows"));
|
if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
|
||||||
for (;;)
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
|
if (mysql->status == MYSQL_STATUS_USE_RESULT)
|
||||||
{
|
{
|
||||||
ulong pkt_len;
|
flush_use_result(mysql);
|
||||||
if ((pkt_len=net_safe_read(result->handle)) == packet_error)
|
mysql->status=MYSQL_STATUS_READY;
|
||||||
break;
|
|
||||||
if (pkt_len <= 8 && result->handle->net.read_pos[0] == 254)
|
|
||||||
{
|
|
||||||
if (protocol_41(result->handle))
|
|
||||||
{
|
|
||||||
char *pos= (char*) result->handle->net.read_pos;
|
|
||||||
result->handle->warning_count=uint2korr(pos); pos+=2;
|
|
||||||
result->handle->server_status=uint2korr(pos); pos+=2;
|
|
||||||
}
|
|
||||||
break; /* End of data */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result->handle->status=MYSQL_STATUS_READY;
|
|
||||||
}
|
}
|
||||||
free_rows(result->data);
|
free_rows(result->data);
|
||||||
if (result->fields)
|
if (result->fields)
|
||||||
@ -2177,12 +2195,13 @@ void STDCALL mysql_close(MYSQL *mysql)
|
|||||||
#ifdef MYSQL_CLIENT
|
#ifdef MYSQL_CLIENT
|
||||||
if (mysql->stmts)
|
if (mysql->stmts)
|
||||||
{
|
{
|
||||||
/* Free any open prepared statements */
|
/* Reset connection handle in all prepared statements. */
|
||||||
LIST *element, *next_element;
|
LIST *element;
|
||||||
for (element= mysql->stmts; element; element= next_element)
|
for (element= mysql->stmts; element; element= element->next)
|
||||||
{
|
{
|
||||||
next_element= element->next;
|
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
|
||||||
stmt_close((MYSQL_STMT *)element->data, 1);
|
stmt->mysql= 0;
|
||||||
|
/* No need to call list_delete for statement here */
|
||||||
}
|
}
|
||||||
mysql->stmts= 0;
|
mysql->stmts= 0;
|
||||||
}
|
}
|
||||||
@ -2372,9 +2391,10 @@ MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
|
|||||||
result->fields= mysql->fields;
|
result->fields= mysql->fields;
|
||||||
result->field_alloc= mysql->field_alloc;
|
result->field_alloc= mysql->field_alloc;
|
||||||
result->field_count= mysql->field_count;
|
result->field_count= mysql->field_count;
|
||||||
result->current_field=0;
|
/* The rest of result members is bzeroed in malloc */
|
||||||
result->current_row=0; /* Must do a fetch first */
|
|
||||||
mysql->fields=0; /* fields is now in result */
|
mysql->fields=0; /* fields is now in result */
|
||||||
|
/* just in case this was mistakenly called after mysql_stmt_execute() */
|
||||||
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
DBUG_RETURN(result); /* Data fetched */
|
DBUG_RETURN(result); /* Data fetched */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2423,6 +2443,7 @@ static MYSQL_RES * cli_use_result(MYSQL *mysql)
|
|||||||
result->current_row= 0;
|
result->current_row= 0;
|
||||||
mysql->fields=0; /* fields is now in result */
|
mysql->fields=0; /* fields is now in result */
|
||||||
mysql->status=MYSQL_STATUS_USE_RESULT;
|
mysql->status=MYSQL_STATUS_USE_RESULT;
|
||||||
|
mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
|
||||||
DBUG_RETURN(result); /* Data is read to be fetched */
|
DBUG_RETURN(result); /* Data is read to be fetched */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2439,19 +2460,30 @@ mysql_fetch_row(MYSQL_RES *res)
|
|||||||
{ /* Unbufferred fetch */
|
{ /* Unbufferred fetch */
|
||||||
if (!res->eof)
|
if (!res->eof)
|
||||||
{
|
{
|
||||||
if (!(read_one_row(res->handle,res->field_count,res->row, res->lengths)))
|
MYSQL *mysql= res->handle;
|
||||||
|
if (mysql->status != MYSQL_STATUS_USE_RESULT)
|
||||||
|
{
|
||||||
|
set_mysql_error(mysql,
|
||||||
|
res->unbuffered_fetch_cancelled ?
|
||||||
|
CR_FETCH_CANCELLED : CR_COMMANDS_OUT_OF_SYNC,
|
||||||
|
unknown_sqlstate);
|
||||||
|
}
|
||||||
|
else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
|
||||||
{
|
{
|
||||||
res->row_count++;
|
res->row_count++;
|
||||||
DBUG_RETURN(res->current_row=res->row);
|
DBUG_RETURN(res->current_row=res->row);
|
||||||
}
|
}
|
||||||
else
|
DBUG_PRINT("info",("end of data"));
|
||||||
{
|
res->eof=1;
|
||||||
DBUG_PRINT("info",("end of data"));
|
mysql->status=MYSQL_STATUS_READY;
|
||||||
res->eof=1;
|
/*
|
||||||
res->handle->status=MYSQL_STATUS_READY;
|
Reset only if owner points to us: there is a chance that somebody
|
||||||
/* Don't clear handle in mysql_free_results */
|
started new query after mysql_stmt_close():
|
||||||
res->handle=0;
|
*/
|
||||||
}
|
if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
|
||||||
|
mysql->unbuffered_fetch_owner= 0;
|
||||||
|
/* Don't clear handle in mysql_free_result */
|
||||||
|
res->handle=0;
|
||||||
}
|
}
|
||||||
DBUG_RETURN((MYSQL_ROW) NULL);
|
DBUG_RETURN((MYSQL_ROW) NULL);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user