diff options
Diffstat (limited to 'libmysql')
-rw-r--r-- | libmysql/errmsg.c | 3 | ||||
-rw-r--r-- | libmysql/libmysql.c | 120 |
2 files changed, 74 insertions, 49 deletions
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 90ad3aefaca..48e44327d0f 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -80,6 +80,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement" "" }; @@ -141,6 +142,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement" "" }; @@ -200,6 +202,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement" "" }; #endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index bf797dfd580..3e6b29b7602 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1724,6 +1724,13 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data); static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field); +/* Auxilary function used to reset statement handle. */ + +#define RESET_SERVER_SIDE 1 +#define RESET_LONG_DATA 2 + +static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); + /* Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME values stored in network buffer. @@ -2019,7 +2026,8 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) /* This is second prepare with another statement */ char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - mysql_stmt_free_result(stmt); + if (reset_stmt_handle(stmt, RESET_LONG_DATA)) + DBUG_RETURN(1); /* These members must be reset for API to function in case of error or misuse. @@ -2702,12 +2710,8 @@ 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; + set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate); + return 1; } @@ -2817,7 +2821,8 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) DBUG_RETURN(1); } - mysql_stmt_free_result(stmt); + if (reset_stmt_handle(stmt, 0)) + DBUG_RETURN(1); /* No need to check for stmt->state: if the statement wasn't prepared we'll get 'unknown statement handler' error from server. @@ -4805,16 +4810,21 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt) DBUG_RETURN(stmt->result.rows); } -my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) -{ - MYSQL_DATA *result= &stmt->result; - DBUG_ENTER("mysql_stmt_free_result"); - DBUG_ASSERT(stmt != 0); +/* + Free the client side memory buffers, reset long data state + on client if necessary, and reset the server side statement if + this has been requested. +*/ +static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) +{ + /* If statement hasn't been prepared there is nothing to reset */ if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { MYSQL *mysql= stmt->mysql; + MYSQL_DATA *result= &stmt->result; + my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor; if (result->data) { @@ -4824,23 +4834,58 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) result->rows= 0; stmt->data_cursor= NULL; } - - if (mysql && stmt->field_count && - (int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) + if (flags & RESET_LONG_DATA) { - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (mysql->status != MYSQL_STATUS_READY) + MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count; + /* Clear long_data_used flags */ + for (; param < param_end; param++) + param->long_data_used= 0; + } + stmt->read_row_func= stmt_read_row_no_data; + if (mysql) + { + if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) { - /* There is a result set and it belongs to this statement */ - (*mysql->methods->flush_use_result)(mysql); - mysql->status= MYSQL_STATUS_READY; + if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) + mysql->unbuffered_fetch_owner= 0; + if (stmt->field_count && mysql->status != MYSQL_STATUS_READY) + { + /* There is a result set and it belongs to this statement */ + (*mysql->methods->flush_use_result)(mysql); + if (mysql->unbuffered_fetch_owner) + *mysql->unbuffered_fetch_owner= TRUE; + mysql->status= MYSQL_STATUS_READY; + } + } + if (has_cursor || (flags & RESET_SERVER_SIDE)) + { + /* + Reset the server side statement and close the server side + cursor if it exists. + */ + char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ + int4store(buff, stmt->stmt_id); + if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, + sizeof(buff), 0, 0, 0)) + { + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); + stmt->state= MYSQL_STMT_INIT_DONE; + return 1; + } } } stmt->state= MYSQL_STMT_PREPARE_DONE; - stmt->read_row_func= stmt_read_row_no_data; } - DBUG_RETURN(0); + return 0; +} + +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) +{ + DBUG_ENTER("mysql_stmt_free_result"); + + /* Free the client side and close the server side cursor if there is one */ + DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA)); } /******************************************************************** @@ -4913,33 +4958,10 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) { - char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ - MYSQL *mysql; - MYSQL_BIND *param, *param_end; DBUG_ENTER("mysql_stmt_reset"); 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; - int4store(buff, stmt->stmt_id); /* Send stmt id to server */ - if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, - sizeof(buff), 0, 0, 0)) - { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); - DBUG_RETURN(1); - } - - /* Clear long_data_used for next call (as we do in mysql_stmt_execute() */ - for (param= stmt->params, param_end= param + stmt->param_count; - param < param_end; - param++) - param->long_data_used= 0; - - DBUG_RETURN(0); + /* Reset the client and server sides of the prepared statement */ + DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA)); } /* |