Commit 3b236b1d authored by unknown's avatar unknown

Fixes and test cases for Bug#8880 "Commands out of sync error with cursors"

 and Bug#9159 "Server crash during mysql_stmt_close".
The patch adds support for single-row result sets in cursors.


libmysql/libmysql.c:
  If we wanted a cursor, and the server wasn't able to create one,
  buffer all rows on client. Currently this is possible only for
  single row result sets and some SHOW commands.
sql/sql_prepare.cc:
  Properly free resources if there was a request to open a cursor which
  wasn't fullfilled.
  Give error on attempt to open a cursor for a statement not returning
  a result set.
sql/sql_select.h:
  Initialize Item_arena of Cursor object. A case when a cursor object
  is created but not used is possible with single-row result sets.
tests/mysql_client_test.c:
  Test cases for Bug#8880 and Bug#9159
parent 648d40ea
......@@ -2862,6 +2862,17 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
mysql->status= MYSQL_STATUS_READY;
stmt->read_row_func= stmt_read_row_from_cursor;
}
else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
{
/*
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
DBUG_RETURN(mysql_stmt_store_result(stmt));
}
else
{
stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
......
......@@ -1970,6 +1970,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) ((uchar) packet[4]);
Cursor *cursor= 0;
/*
Query text for binary log, or empty string if the query is not put into
binary log.
......@@ -2007,15 +2008,17 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
statement: we can't open a cursor for it.
*/
flags= 0;
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
goto err;
}
else
{
DBUG_PRINT("info",("Using READ_ONLY cursor"));
if (!stmt->cursor &&
!(stmt->cursor= new (&stmt->main_mem_root) Cursor()))
!(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
DBUG_VOID_RETURN;
/* If lex->result is set, mysql_execute_command will use it */
stmt->lex->result= &stmt->cursor->result;
stmt->lex->result= &cursor->result;
}
}
#ifndef EMBEDDED_LIBRARY
......@@ -2061,11 +2064,10 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
thd->protocol= &thd->protocol_simple; // Use normal protocol
if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
if (cursor && cursor->is_open())
{
if (stmt->cursor->is_open())
stmt->cursor->init_from_thd(thd);
stmt->cursor->state= stmt->state;
cursor->init_from_thd(thd);
cursor->state= stmt->state;
}
else
{
......
......@@ -370,7 +370,7 @@ class Cursor: public Sql_alloc, public Item_arena
void close();
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
Cursor() :join(0), unit(0) {}
Cursor() :Item_arena(TRUE), join(0), unit(0) {}
~Cursor();
};
......
......@@ -12740,6 +12740,73 @@ static void test_bug8378()
mysql_close(lmysql);
}
MYSQL_STMT *open_cursor(char *query)
{
int rc;
const ulong type= (ulong)CURSOR_TYPE_READ_ONLY;
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(stmt, query, strlen(query));
check_execute(stmt, rc);
mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type);
return stmt;
}
static void test_bug8880()
{
MYSQL_STMT *stmt_list[2], **stmt;
MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2;
int rc;
myheader("test_bug8880");
mysql_query(mysql, "drop table if exists t1");
mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
rc= mysql_query(mysql, "insert into t1 values (1,1)");
myquery(rc); /* one check is enough */
/*
when inserting 2 rows everything works well
mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)");
*/
for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
*stmt= open_cursor("select a from t1");
for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
{
rc= mysql_stmt_execute(*stmt);
check_execute(*stmt, rc);
}
for (stmt= stmt_list; stmt < stmt_list_end; stmt++)
mysql_stmt_close(*stmt);
}
static void test_bug9159()
{
MYSQL_STMT *stmt;
int rc;
const char *stmt_text= "select a, b from t1";
const unsigned long type= CURSOR_TYPE_READ_ONLY;
myheader("test_bug9159");
mysql_query(mysql, "drop table if exists t1");
mysql_query(mysql, "create table t1 (a int not null primary key, b int)");
rc= mysql_query(mysql, "insert into t1 values (1,1)");
myquery(rc);
stmt= mysql_stmt_init(mysql);
mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type);
mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "drop table if exists t1");
myquery(rc);
}
/*
Read and parse arguments and MySQL options from my.cnf
*/
......@@ -12962,6 +13029,8 @@ static struct my_tests_st my_tests[]= {
{ "test_bug8330", test_bug8330 },
{ "test_bug7990", test_bug7990 },
{ "test_bug8378", test_bug8378 },
{ "test_bug8880", test_bug8880 },
{ "test_bug9159", test_bug9159 },
{ 0, 0 }
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment