1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Bug#14013 mysql_stmt_store_result() bombs if a cursor is open

- Add code to 'mysql_stmt_store_result' to allow it to be called on 
   a prepared statement with open server side cursor.
 - Add tests to mysql_client_test that uses 'mysql_stmt_store_result'


client/mysqltest.c:
  Enable cursor protocol(remove the ifdef BUG14013_FIXED)
  When running in cursor mode, the warnings from execute needs 
  to be extracted after mysql_stmt_execute, put them in a dynamic string 
  for later use.
  Untabify some tabs.
libmysql/libmysql.c:
  Allow 'mysql_stmt_store_result' to be called on a statement with an open server side cursor.
  Detect that a server side cursor is open and send a "fetch" to ask for all rows to be sent to the client.
  Read all binary rows as normal store.
  Check that server said last row was sent after all binary rows has been sent.
tests/mysql_client_test.c:
  Update 'fetch_n' function to take parameter indicating if 'mysql_stmt_store_result' should be used on the statement.
  Call fetch_n with parameter set to use 'mysql_stmt_store_result'
This commit is contained in:
unknown
2006-02-10 14:50:29 +01:00
parent db16cfc578
commit 101e618f7f
3 changed files with 73 additions and 22 deletions

View File

@ -3167,7 +3167,7 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", 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(); 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)) if (mysql_stmt_prepare(stmt, query, query_len))
{ {
handle_error(query, command, mysql_stmt_errno(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; goto end;
} }
@ -3648,29 +3648,34 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
parameter markers. parameter markers.
*/ */
#ifdef BUG14013_FIXED
/*
Use cursor when retrieving result
*/
if (cursor_protocol_enabled) if (cursor_protocol_enabled)
{ {
/*
Use cursor when retrieving result
*/
ulong type= CURSOR_TYPE_READ_ONLY; ulong type= CURSOR_TYPE_READ_ONLY;
if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type))
die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", 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 Execute the query
*/ */
if (mysql_stmt_execute(stmt)) if (mysql_stmt_execute(stmt))
{ {
handle_error(query, command, mysql_stmt_errno(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; 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 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 mysql_stmt_store_result(), this is our only way to know how much
@ -3680,7 +3685,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
my_bool one= 1; my_bool one= 1;
if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) 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", 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)) if (mysql_stmt_store_result(stmt))
{ {
handle_error(query, command, mysql_stmt_errno(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; goto end;
} }
@ -3711,10 +3716,10 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command,
uint num_fields= mysql_num_fields(res); uint num_fields= mysql_num_fields(res);
if (display_metadata) if (display_metadata)
append_metadata(ds, fields, num_fields); append_metadata(ds, fields, num_fields);
if (!display_result_vertically) 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); 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 */ /* Append warnings to ds - if there are any */
if (append_warnings(&ds_execute_warnings, mysql) || if (append_warnings(&ds_execute_warnings, mysql) ||
ds_prepare_warnings.length || ds_execute_warnings.length ||
ds_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) if (ds_warnings->length)
dynstr_append_mem(ds, ds_warnings->str, dynstr_append_mem(ds, ds_warnings->str,
ds_warnings->length); ds_warnings->length);

View File

@ -4757,12 +4757,39 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
if (!stmt->field_count) if (!stmt->field_count)
DBUG_RETURN(0); 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); set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1); 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) if (result->data)
{ {
free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
@ -4803,6 +4830,10 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
DBUG_RETURN(1); 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) if (stmt->update_max_length)
{ {
MYSQL_ROWS *cur= result->data; MYSQL_ROWS *cur= result->data;

View File

@ -1049,7 +1049,10 @@ void stmt_fetch_close(Stmt_fetch *fetch)
reading from the rest. 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; unsigned open_statements= query_count;
int rc, error_count= 0; 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]); 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) while (open_statements)
{ {
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) 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)); 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; DBUG_VOID_RETURN;
} }
@ -11880,7 +11893,8 @@ static void test_cursors_with_union()
"SELECT t1.id FROM t1 WHERE t1.id < 5" "SELECT t1.id FROM t1 WHERE t1.id < 5"
}; };
myheader("test_cursors_with_union"); 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);
} }
/* /*