You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-07 02:42:49 +03:00
Fix for MDEV-12247:
If a statement with open (read only) cursor is executed there is no buffered result set (result set rows will be fetched directly from server), so we need to skip reading unbuffered result sets if a cursor is open.
This commit is contained in:
@@ -1782,7 +1782,11 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
|||||||
}
|
}
|
||||||
if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
|
if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
|
||||||
{
|
{
|
||||||
mysql->methods->db_stmt_flush_unbuffered(stmt);
|
do {
|
||||||
|
if (!stmt->cursor_exists)
|
||||||
|
mysql->methods->db_stmt_flush_unbuffered(stmt);
|
||||||
|
}
|
||||||
|
while (mysql_stmt_next_result(stmt) == 0);
|
||||||
stmt->state= MYSQL_STMT_PREPARED;
|
stmt->state= MYSQL_STMT_PREPARED;
|
||||||
stmt->mysql->status= MYSQL_STATUS_READY;
|
stmt->mysql->status= MYSQL_STATUS_READY;
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ INCLUDE_DIRECTORIES(${CC_SOURCE_DIR}/include
|
|||||||
${CC_SOURCE_DIR}/unittest/libmariadb)
|
${CC_SOURCE_DIR}/unittest/libmariadb)
|
||||||
ADD_DEFINITIONS(-DLIBMARIADB)
|
ADD_DEFINITIONS(-DLIBMARIADB)
|
||||||
|
|
||||||
SET(API_TESTS "performance" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "features-10_2" "bulk1" )
|
SET(API_TESTS "bulk1" "performance" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs" "sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "features-10_2" "bulk1")
|
||||||
IF(WITH_DYNCOL)
|
IF(WITH_DYNCOL)
|
||||||
SET(API_TESTS ${API_TESTS} "dyncol")
|
SET(API_TESTS ${API_TESTS} "dyncol")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
@@ -402,6 +402,7 @@ static int bulk5(MYSQL *mysql)
|
|||||||
|
|
||||||
res= mysql_store_result(mysql);
|
res= mysql_store_result(mysql);
|
||||||
rows= (unsigned long)mysql_num_rows(res);
|
rows= (unsigned long)mysql_num_rows(res);
|
||||||
|
diag("rows: %d", rows);
|
||||||
mysql_free_result(res);
|
mysql_free_result(res);
|
||||||
|
|
||||||
FAIL_IF(rows != 5, "expected 5 rows");
|
FAIL_IF(rows != 5, "expected 5 rows");
|
||||||
|
@@ -190,8 +190,31 @@ static int conc_218(MYSQL *mysql)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_cursor(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
unsigned int prefetch_rows= 1;
|
||||||
|
unsigned long cursor_type= CURSOR_TYPE_READ_ONLY;
|
||||||
|
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &cursor_type);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, &prefetch_rows);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL", -1);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
rc= mysql_stmt_fetch(stmt);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1 FROM DUAL UNION SELECT 2 FROM DUAL", -1);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_cursor", test_cursor, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"conc_218", conc_218, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"conc_218", conc_218, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"conc_212", conc_212, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"conc_212", conc_212, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"conc_213", conc_213, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"conc_213", conc_213, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
|
@@ -4974,7 +4974,81 @@ static int test_bit2tiny(MYSQL *mysql)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_reexecute(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
MYSQL_BIND ps_params[3]; /* input parameter buffers */
|
||||||
|
int int_data[3]; /* input/output values */
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* set up stored procedure */
|
||||||
|
rc = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
rc = mysql_query(mysql,
|
||||||
|
"CREATE PROCEDURE p1("
|
||||||
|
" IN p_in INT, "
|
||||||
|
" OUT p_out INT, "
|
||||||
|
" INOUT p_inout INT) "
|
||||||
|
"BEGIN "
|
||||||
|
" SELECT p_in, p_out, p_inout; "
|
||||||
|
" SET p_in = 100, p_out = 200, p_inout = 300; "
|
||||||
|
" SELECT p_in, p_out, p_inout; "
|
||||||
|
"END");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/* initialize and prepare CALL statement with parameter placeholders */
|
||||||
|
stmt = mysql_stmt_init(mysql);
|
||||||
|
if (!stmt)
|
||||||
|
{
|
||||||
|
diag("Could not initialize statement");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
rc = mysql_stmt_prepare(stmt, "CALL p1(?, ?, ?)", 16);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
/* initialize parameters: p_in, p_out, p_inout (all INT) */
|
||||||
|
memset(ps_params, 0, sizeof (ps_params));
|
||||||
|
|
||||||
|
ps_params[0].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
ps_params[0].buffer = (char *) &int_data[0];
|
||||||
|
ps_params[0].length = 0;
|
||||||
|
ps_params[0].is_null = 0;
|
||||||
|
|
||||||
|
ps_params[1].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
ps_params[1].buffer = (char *) &int_data[1];
|
||||||
|
ps_params[1].length = 0;
|
||||||
|
ps_params[1].is_null = 0;
|
||||||
|
|
||||||
|
ps_params[2].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
ps_params[2].buffer = (char *) &int_data[2];
|
||||||
|
ps_params[2].length = 0;
|
||||||
|
ps_params[2].is_null = 0;
|
||||||
|
|
||||||
|
/* bind parameters */
|
||||||
|
rc = mysql_stmt_bind_param(stmt, ps_params);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
/* assign values to parameters and execute statement */
|
||||||
|
int_data[0]= 10; /* p_in */
|
||||||
|
int_data[1]= 20; /* p_out */
|
||||||
|
int_data[2]= 30; /* p_inout */
|
||||||
|
|
||||||
|
rc = mysql_stmt_execute(stmt);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
|
rc = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_reexecute", test_reexecute, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_bit2tiny", test_bit2tiny, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_bit2tiny", test_bit2tiny, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_conc97", test_conc97, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
{"test_conc97", test_conc97, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||||
{"test_conc83", test_conc83, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
{"test_conc83", test_conc83, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||||
|
Reference in New Issue
Block a user