summaryrefslogtreecommitdiff
path: root/libmysql
diff options
context:
space:
mode:
Diffstat (limited to 'libmysql')
-rw-r--r--libmysql/errmsg.c3
-rw-r--r--libmysql/libmysql.c120
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));
}
/*