From 5f6133653d5d1ef171b03cf05ea12a9513f0a207 Mon Sep 17 00:00:00 2001 From: Georg Richter Date: Sun, 15 Jan 2023 15:12:38 +0100 Subject: [PATCH] Fix for CONC-623: If callback function returns a non zero return code, execute will now abort with error CR_ERR_STMT_PARAM_CALLBACK. --- include/errmsg.h | 3 ++- libmariadb/ma_errmsg.c | 1 + libmariadb/mariadb_stmt.c | 26 +++++++++++++----- unittest/libmariadb/ps_bugs.c | 51 +++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/include/errmsg.h b/include/errmsg.h index d6b11694..f9da6585 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -106,10 +106,11 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_ERR_NET_READ 5013 #define CR_ERR_NET_WRITE 5014 #define CR_ERR_NET_UNCOMPRESS 5015 +#define CR_ERR_STMT_PARAM_CALLBACK 5016 /* Always last, if you add new error codes please update the value for CR_MARIADB_LAST_ERROR */ -#define CR_MARIADB_LAST_ERROR CR_ERR_NET_UNCOMPRESS +#define CR_MARIADB_LAST_ERROR CR_ERR_STMT_PARAM_CALLBACK #endif diff --git a/libmariadb/ma_errmsg.c b/libmariadb/ma_errmsg.c index 1c9d0932..0b3d6713 100644 --- a/libmariadb/ma_errmsg.c +++ b/libmariadb/ma_errmsg.c @@ -110,6 +110,7 @@ const char *mariadb_client_errors[] = /* 5013 */ "Read error: %s (%d)", /* 5014 */ "Write error: %s (%d)", /* 5015 */ "Error while uncompressing packet", + /* 5016 */ "Error while retrieving parameter from callback function", "" }; diff --git a/libmariadb/mariadb_stmt.c b/libmariadb/mariadb_stmt.c index bb495c57..17b97410 100644 --- a/libmariadb/mariadb_stmt.c +++ b/libmariadb/mariadb_stmt.c @@ -941,7 +941,10 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r /* preallocate length bytes */ if (!(start= p= (uchar *)malloc(length))) - goto mem_error; + { + SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + goto error; + } int4store(p, stmt->stmt_id); p += STMT_ID_LENGTH; @@ -973,7 +976,10 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r size_t offset= p - start; length= offset + stmt->param_count * 2 + 20; if (!(start= (uchar *)realloc(start, length))) - goto mem_error; + { + SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + goto error; + } p= start + offset; } for (i = 0; i < stmt->param_count; i++) @@ -991,7 +997,13 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r /* If callback for parameters was specified, we need to update bind information for new row */ if (stmt->param_callback) - stmt->param_callback(stmt->user_data, stmt->params, j); + { + if (stmt->param_callback(stmt->user_data, stmt->params, j)) + { + SET_CLIENT_STMT_ERROR(stmt, CR_ERR_STMT_PARAM_CALLBACK, SQLSTATE_UNKNOWN, 0); + goto error; + } + } if (mysql_stmt_skip_paramset(stmt, j)) continue; @@ -1059,7 +1071,10 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r size_t offset= p - start; length= MAX(2 * length, offset + size + 20); if (!(start= (uchar *)realloc(start, length))) - goto mem_error; + { + SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + goto error; + } p= start + offset; } @@ -1075,8 +1090,7 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r stmt->send_types_to_server= 0; *request_len = (size_t)(p - start); return start; -mem_error: - SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); +error: free(start); *request_len= 0; return NULL; diff --git a/unittest/libmariadb/ps_bugs.c b/unittest/libmariadb/ps_bugs.c index 72262462..5df5f3ef 100644 --- a/unittest/libmariadb/ps_bugs.c +++ b/unittest/libmariadb/ps_bugs.c @@ -5587,7 +5587,58 @@ static int test_mdev19838(MYSQL *mysql) return OK; } +my_bool conc623_param_callback(void *data __attribute((unused)), + MYSQL_BIND *bind __attribute((unused)), + unsigned int row_nr __attribute((unused))) +{ + return 1; +} + +static int test_conc623(MYSQL *mysql) +{ + int rc; + unsigned int paramcount= 1; + unsigned int array_size= 2; + MYSQL_BIND bind; + + MYSQL_STMT *stmt= mysql_stmt_init(mysql); + + rc= mysql_query(mysql, "CREATE OR REPLACE TEMPORARY TABLE t1 (a int)"); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CB_USER_DATA, mysql); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶mcount); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CB_PARAM, conc623_param_callback); + check_stmt_rc(rc, stmt); + + bind.buffer_type= MYSQL_TYPE_LONG; + rc= mysql_stmt_bind_param(stmt, &bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_prepare(stmt, SL("INSERT INTO t1 VALUES (?)")); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + if (!rc) + { + diag("Error expected from callback function"); + mysql_stmt_close(stmt); + return FAIL; + } + + diag("Error (expected) %s", mysql_stmt_error(stmt)); + mysql_stmt_close(stmt); + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_mdev19838", test_mdev19838, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc525", test_conc525, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc566", test_conc566, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},