summaryrefslogtreecommitdiff
path: root/sql-common
diff options
context:
space:
mode:
authorunknown <konstantin@mysql.com>2004-03-16 01:04:04 +0300
committerunknown <konstantin@mysql.com>2004-03-16 01:04:04 +0300
commit321422c86e29199d1d2fb0337640fa819550baa0 (patch)
tree752a7c190fcf0f92940319d09105b114f3e76d52 /sql-common
parent4c0d915652466b8f6c7f1bb5b397f59cb5cea8d3 (diff)
downloadmariadb-git-321422c86e29199d1d2fb0337640fa819550baa0.tar.gz
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 include/errmsg.h: - CR_NOT_ALL_PARAMS_BOUND - this error code wasn't used until now. Apparently it was added in advance, but then interface of mysql_stmt_bind_param changed. Now it's not possible to bind only some parameters - either all or none of parameters are bound. This error code is renamed to CR_PARAMS_NOT_BOUND - CR_FETCH_CANCELLED - error code set on server side when fetch from MYSQL_RES or MYSQL_STMT (in blocking mode) was cancelled because of intercepting call to mysql_stmt_close - CR_NO_DATA - this is proposed error code to return from mysql_stmt_fetch_column if no row was fetched (by any type of fetch). We always can fall back to CR_COMMANDS_OUT_OF_SYNC though. Need reviewer's opinion on this one. include/mysql.h: - added unbuffered_fetch_owner member to MYSQL to point to MYSQL_RES or MYSQL_STMT which is used to fetch result at the moment. This is to be able to set CR_FETCH_CANCELLED error without fantoms. - added unbuffered_fetch_cancelled boolean variable to MYSQL_STMT and MYSQL_RES structures - rename PREP_STMT_STATE -> enum enum_mysql_stmt_state - members of MYSQL_STMT ordered by size. - removed members of MYSQL_STMT: current_row, result_buffered, last_fetched_column, last_fetched_buffer, query - renamed members of MYSQL_STMT: param_buffers -> bind_param_done, res_buffers -> bind_result_done - now mysql_stmt_fetch calls stmt->read_row_func to read row either from buffer or from network. include/sql_common.h: declaration for flush_use_result libmysql/client_settings.h: stmt_close declaration removed libmysql/errmsg.c: Error messages for changed and added error codes. libmysql/libmysql.c: Many changes: - some unused variables removed - cleanups - better error reporting - some function calls commented - alloc_stmt_fields is now called right after execute, to not read mysql->fields of some other statement - new implementation of mysql_stmt_fetch - this is also with cursor fetch in mind (to implement cursor fetch I'll just need to write special read_row function for it, so this change will be local) - implementation of fetch cancellation, including complete rewrite of mysql_stmt_close - now mysql_stmt_free_result doesn't free results of other statements. sql-common/client.c: - implementation of flush_use_result - implementation of fetch cancellation - changed behaviour of mysql_close in regard to mysql_stmt_close - now mysql_close just set stmt->mysql to 0
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/client.c98
1 files changed, 65 insertions, 33 deletions
diff --git a/sql-common/client.c b/sql-common/client.c
index 5d2df4a0ddf..6d0da338543 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -712,6 +712,34 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
net->last_errno= errcode;
strmov(net->last_error, ER(errcode));
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));
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"));
- for (;;)
+ if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
+ mysql->unbuffered_fetch_owner= 0;
+ if (mysql->status == MYSQL_STATUS_USE_RESULT)
{
- ulong pkt_len;
- if ((pkt_len=net_safe_read(result->handle)) == packet_error)
- 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 */
- }
+ flush_use_result(mysql);
+ mysql->status=MYSQL_STATUS_READY;
}
- result->handle->status=MYSQL_STATUS_READY;
}
free_rows(result->data);
if (result->fields)
@@ -2177,12 +2195,13 @@ void STDCALL mysql_close(MYSQL *mysql)
#ifdef MYSQL_CLIENT
if (mysql->stmts)
{
- /* Free any open prepared statements */
- LIST *element, *next_element;
- for (element= mysql->stmts; element; element= next_element)
+ /* Reset connection handle in all prepared statements. */
+ LIST *element;
+ for (element= mysql->stmts; element; element= element->next)
{
- next_element= element->next;
- stmt_close((MYSQL_STMT *)element->data, 1);
+ MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
+ stmt->mysql= 0;
+ /* No need to call list_delete for statement here */
}
mysql->stmts= 0;
}
@@ -2372,9 +2391,10 @@ MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
result->fields= mysql->fields;
result->field_alloc= mysql->field_alloc;
result->field_count= mysql->field_count;
- result->current_field=0;
- result->current_row=0; /* Must do a fetch first */
+ /* The rest of result members is bzeroed in malloc */
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 */
}
@@ -2423,6 +2443,7 @@ static MYSQL_RES * cli_use_result(MYSQL *mysql)
result->current_row= 0;
mysql->fields=0; /* fields is now in result */
mysql->status=MYSQL_STATUS_USE_RESULT;
+ mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
DBUG_RETURN(result); /* Data is read to be fetched */
}
@@ -2439,19 +2460,30 @@ mysql_fetch_row(MYSQL_RES *res)
{ /* Unbufferred fetch */
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)
{
- res->row_count++;
- DBUG_RETURN(res->current_row=res->row);
+ set_mysql_error(mysql,
+ res->unbuffered_fetch_cancelled ?
+ CR_FETCH_CANCELLED : CR_COMMANDS_OUT_OF_SYNC,
+ unknown_sqlstate);
}
- else
+ else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
{
- DBUG_PRINT("info",("end of data"));
- res->eof=1;
- res->handle->status=MYSQL_STATUS_READY;
- /* Don't clear handle in mysql_free_results */
- res->handle=0;
+ res->row_count++;
+ DBUG_RETURN(res->current_row=res->row);
}
+ DBUG_PRINT("info",("end of data"));
+ res->eof=1;
+ mysql->status=MYSQL_STATUS_READY;
+ /*
+ Reset only if owner points to us: there is a chance that somebody
+ started new query after mysql_stmt_close():
+ */
+ 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);
}