summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.c40
-rw-r--r--libmysql/libmysql.c35
-rw-r--r--tests/mysql_client_test.c20
3 files changed, 73 insertions, 22 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 24be5de8021..3851a922e13 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -3167,7 +3167,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt));
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
free_replace_column();
@@ -3632,7 +3632,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
if (mysql_stmt_prepare(stmt, query, query_len))
{
handle_error(query, command, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
@@ -3648,30 +3648,35 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
parameter markers.
*/
-#ifdef BUG14013_FIXED
- /*
- Use cursor when retrieving result
- */
if (cursor_protocol_enabled)
{
+ /*
+ Use cursor when retrieving result
+ */
ulong type= CURSOR_TYPE_READ_ONLY;
if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type))
die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s",
- mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
}
-#endif
/*
Execute the query
- */
+ */
if (mysql_stmt_execute(stmt))
{
handle_error(query, command, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
/*
+ When running in cursor_protocol get the warnings from execute here
+ and keep them in a separate string for later.
+ */
+ if (cursor_protocol_enabled && !disable_warnings)
+ append_warnings(&ds_execute_warnings, mysql);
+
+ /*
We instruct that we want to update the "max_length" field in
mysql_stmt_store_result(), this is our only way to know how much
buffer to allocate for result data
@@ -3680,7 +3685,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
my_bool one= 1;
if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s",
- mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
}
/*
@@ -3690,7 +3695,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
if (mysql_stmt_store_result(stmt))
{
handle_error(query, command, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
@@ -3711,10 +3716,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
uint num_fields= mysql_num_fields(res);
if (display_metadata)
- append_metadata(ds, fields, num_fields);
+ append_metadata(ds, fields, num_fields);
if (!display_result_vertically)
- append_table_headings(ds, fields, num_fields);
+ append_table_headings(ds, fields, num_fields);
append_stmt_result(ds, stmt, fields, num_fields);
@@ -3736,10 +3741,11 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
/* Append warnings to ds - if there are any */
if (append_warnings(&ds_execute_warnings, mysql) ||
- ds_prepare_warnings.length ||
- ds_warnings->length)
+ ds_execute_warnings.length ||
+ ds_prepare_warnings.length ||
+ ds_warnings->length)
{
- dynstr_append_mem(ds, "Warnings:\n", 10);
+ dynstr_append_mem(ds, "Warnings:\n", 10);
if (ds_warnings->length)
dynstr_append_mem(ds, ds_warnings->str,
ds_warnings->length);
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 11ee7284cbf..30eecf809c5 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -4757,12 +4757,39 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
if (!stmt->field_count)
DBUG_RETURN(0);
- if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE ||
- mysql->status != MYSQL_STATUS_GET_RESULT)
+
+ if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE)
+ {
+ set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+
+ if (mysql->status == MYSQL_STATUS_READY &&
+ stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
+ {
+ /*
+ Server side cursor exist, tell server to start sending the rows
+ */
+ NET *net= &mysql->net;
+ char buff[4 /* statement id */ +
+ 4 /* number of rows to fetch */];
+
+ /* Send row request to the server */
+ int4store(buff, stmt->stmt_id);
+ int4store(buff + 4, (int)~0); /* number of rows to fetch */
+ if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
+ NullS, 0, 1))
+ {
+ set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ DBUG_RETURN(1);
+ }
+ }
+ else if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1);
}
+
if (result->data)
{
free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
@@ -4803,6 +4830,10 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
DBUG_RETURN(1);
}
+ /* Assert that if there was a cursor, all rows have been fetched */
+ DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY ||
+ (mysql->server_status & SERVER_STATUS_LAST_ROW_SENT));
+
if (stmt->update_max_length)
{
MYSQL_ROWS *cur= result->data;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 216961b3a80..25729e9f47c 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -1049,7 +1049,10 @@ void stmt_fetch_close(Stmt_fetch *fetch)
reading from the rest.
*/
-my_bool fetch_n(const char **query_list, unsigned query_count)
+enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
+
+my_bool fetch_n(const char **query_list, unsigned query_count,
+ enum fetch_type fetch_type)
{
unsigned open_statements= query_count;
int rc, error_count= 0;
@@ -1065,6 +1068,15 @@ my_bool fetch_n(const char **query_list, unsigned query_count)
query_list[fetch - fetch_array]);
}
+ if (fetch_type == USE_STORE_RESULT)
+ {
+ for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
+ {
+ rc= mysql_stmt_store_result(fetch->handle);
+ check_execute(fetch->handle, rc);
+ }
+ }
+
while (open_statements)
{
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
@@ -11867,7 +11879,8 @@ static void test_basic_cursors()
fill_tables(basic_tables, sizeof(basic_tables)/sizeof(*basic_tables));
- fetch_n(queries, sizeof(queries)/sizeof(*queries));
+ fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH);
+ fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT);
DBUG_VOID_RETURN;
}
@@ -11880,7 +11893,8 @@ static void test_cursors_with_union()
"SELECT t1.id FROM t1 WHERE t1.id < 5"
};
myheader("test_cursors_with_union");
- fetch_n(queries, sizeof(queries)/sizeof(*queries));
+ fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH);
+ fetch_n(queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT);
}
/*