diff --git a/include/errmsg.h b/include/errmsg.h index 4afe8e8a..0d8ddcaf 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -114,10 +114,11 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_BINLOG_ERROR 5021 #define CR_BINLOG_INVALID_FILE 5022 #define CR_BINLOG_SEMI_SYNC_ERROR 5023 +#define CR_STMT_NO_RESULT 5024 /* Always last, if you add new error codes please update the 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 diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index 1f3fa408..1fcc6d4a 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -118,6 +118,7 @@ const char *mariadb_client_errors[] = /* 5021 */ "Binary log error (File: %.*s start_pos=%ld): %s.", /* 5022 */ "File '%s' is not a binary log file", /* 5023 */ "Semi sync request error: %s", + /* 5024 */ "Statement has no result set", "" }; diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index 1a20bcca..92f1869c 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -1613,6 +1613,12 @@ unsigned int STDCALL mysql_stmt_field_count(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 | 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; 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) { @@ -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) flags|= MADB_RESET_BUFFER; - ret= madb_reset_stmt(stmt, flags); + if (ret= madb_reset_stmt(stmt, flags)) + return ret; if (stmt->stmt_id) { diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 804ef3e3..562ea3ff 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -5741,7 +5741,47 @@ end: 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[] = { + {"test_conc667", test_conc667, 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_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},