Commit fd54ee45 authored by konstantin@mysql.com's avatar konstantin@mysql.com

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.
parent 947065dd
......@@ -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 @@ public:
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