You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
CONC-667: Fix statement handling when unbuffered results are pending.
Resetting a statement will result in an error, if another (different) statement has a pending unbuffered result set (CR_COMMANDS_OUT_OF_SYNC). Freeing a statement result set will return an error, if the statement has no result set or was not executed (CR_STMT_NO_RESULT).
This commit is contained in:
@@ -114,10 +114,11 @@ extern const char *mariadb_client_errors[]; /* Error messages */
|
|||||||
#define CR_BINLOG_ERROR 5021
|
#define CR_BINLOG_ERROR 5021
|
||||||
#define CR_BINLOG_INVALID_FILE 5022
|
#define CR_BINLOG_INVALID_FILE 5022
|
||||||
#define CR_BINLOG_SEMI_SYNC_ERROR 5023
|
#define CR_BINLOG_SEMI_SYNC_ERROR 5023
|
||||||
|
#define CR_STMT_NO_RESULT 5024
|
||||||
|
|
||||||
/* Always last, if you add new error codes please update the
|
/* Always last, if you add new error codes please update the
|
||||||
value for CR_MARIADB_LAST_ERROR */
|
value for CR_MARIADB_LAST_ERROR */
|
||||||
#define CR_MARIADB_LAST_ERROR CR_BINLOG_INVALID_FILE
|
#define CR_MARIADB_LAST_ERROR CR_STMT_NO_RESULT
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -118,6 +118,7 @@ const char *mariadb_client_errors[] =
|
|||||||
/* 5021 */ "Binary log error (File: %.*s start_pos=%ld): %s.",
|
/* 5021 */ "Binary log error (File: %.*s start_pos=%ld): %s.",
|
||||||
/* 5022 */ "File '%s' is not a binary log file",
|
/* 5022 */ "File '%s' is not a binary log file",
|
||||||
/* 5023 */ "Semi sync request error: %s",
|
/* 5023 */ "Semi sync request error: %s",
|
||||||
|
/* 5024 */ "Statement has no result set",
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1613,6 +1613,12 @@ unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
|
|||||||
|
|
||||||
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
|
if (stmt->state < MYSQL_STMT_EXECUTED || !stmt->field_count)
|
||||||
|
{
|
||||||
|
stmt_set_error(stmt, CR_STMT_NO_RESULT, SQLSTATE_UNKNOWN, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return madb_reset_stmt(stmt, MADB_RESET_LONGDATA | MADB_RESET_STORED |
|
return madb_reset_stmt(stmt, MADB_RESET_LONGDATA | MADB_RESET_STORED |
|
||||||
MADB_RESET_BUFFER | MADB_RESET_ERROR);
|
MADB_RESET_BUFFER | MADB_RESET_ERROR);
|
||||||
}
|
}
|
||||||
@@ -2198,6 +2204,19 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
|
|||||||
{
|
{
|
||||||
MYSQL *mysql= stmt->mysql;
|
MYSQL *mysql= stmt->mysql;
|
||||||
my_bool ret= 0;
|
my_bool ret= 0;
|
||||||
|
LIST *li_stmt= mysql->stmts;
|
||||||
|
|
||||||
|
/* CONC-667: If an other statement has a pending result set, we
|
||||||
|
need to return an error */
|
||||||
|
for (;li_stmt;li_stmt= li_stmt->next)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *s= (MYSQL_STMT *)li_stmt->data;
|
||||||
|
if (s != stmt && s->state == MYSQL_STMT_WAITING_USE_OR_STORE)
|
||||||
|
{
|
||||||
|
stmt_set_error(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!stmt->mysql)
|
if (!stmt->mysql)
|
||||||
{
|
{
|
||||||
@@ -2297,7 +2316,8 @@ static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close)
|
|||||||
stmt->fetch_row_func == stmt_unbuffered_fetch)
|
stmt->fetch_row_func == stmt_unbuffered_fetch)
|
||||||
flags|= MADB_RESET_BUFFER;
|
flags|= MADB_RESET_BUFFER;
|
||||||
|
|
||||||
ret= madb_reset_stmt(stmt, flags);
|
if (ret= madb_reset_stmt(stmt, flags))
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (stmt->stmt_id)
|
if (stmt->stmt_id)
|
||||||
{
|
{
|
||||||
|
@@ -5741,7 +5741,47 @@ end:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_conc667(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt1, *stmt2;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
stmt1= mysql_stmt_init(mysql);
|
||||||
|
stmt2= mysql_stmt_init(mysql);
|
||||||
|
|
||||||
|
rc= mysql_stmt_prepare(stmt1, "SELECT 1", -1);
|
||||||
|
check_stmt_rc(rc, stmt1);
|
||||||
|
|
||||||
|
rc= mysql_stmt_prepare(stmt2, "SELECT 2", -1);
|
||||||
|
check_stmt_rc(rc, stmt2);
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt1);
|
||||||
|
check_stmt_rc(rc, stmt1);
|
||||||
|
|
||||||
|
rc= mysql_stmt_free_result(stmt2);
|
||||||
|
FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_STMT_NO_RESULT,
|
||||||
|
"Expected CR_STMT_NO_RESULT");
|
||||||
|
diag("Error (expected) %s", mysql_stmt_error(stmt2));
|
||||||
|
|
||||||
|
rc= mysql_stmt_reset(stmt2);
|
||||||
|
FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_COMMANDS_OUT_OF_SYNC,
|
||||||
|
"Expected commands out of sync error");
|
||||||
|
|
||||||
|
rc= mysql_stmt_fetch(stmt1);
|
||||||
|
check_stmt_rc(rc, stmt1);
|
||||||
|
|
||||||
|
mysql_stmt_free_result(stmt1);
|
||||||
|
|
||||||
|
rc= mysql_stmt_close(stmt1);
|
||||||
|
check_stmt_rc(rc, stmt1);
|
||||||
|
rc= mysql_stmt_close(stmt2);
|
||||||
|
check_stmt_rc(rc, stmt2);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_conc667", test_conc667, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
|
Reference in New Issue
Block a user