Loading libmysql/libmysql.c +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading sql/sql_prepare.cc +8 −6 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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 { Loading sql/sql_select.h +1 −1 Original line number Diff line number Diff line Loading @@ -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(); }; Loading tests/mysql_client_test.c +68 −0 Original line number Diff line number Diff line Loading @@ -12782,6 +12782,72 @@ static void test_bug8722() } 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 */ Loading Loading @@ -13005,6 +13071,8 @@ static struct my_tests_st my_tests[]= { { "test_bug7990", test_bug7990 }, { "test_bug8378", test_bug8378 }, { "test_bug8722", test_bug8722 }, { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, { 0, 0 } }; Loading Loading
libmysql/libmysql.c +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
sql/sql_prepare.cc +8 −6 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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 { Loading
sql/sql_select.h +1 −1 Original line number Diff line number Diff line Loading @@ -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(); }; Loading
tests/mysql_client_test.c +68 −0 Original line number Diff line number Diff line Loading @@ -12782,6 +12782,72 @@ static void test_bug8722() } 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 */ Loading Loading @@ -13005,6 +13071,8 @@ static struct my_tests_st my_tests[]= { { "test_bug7990", test_bug7990 }, { "test_bug8378", test_bug8378 }, { "test_bug8722", test_bug8722 }, { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, { 0, 0 } }; Loading