1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

Fix for CONC-624:

- ER() macro now checks if the error code is known, if not it will return
  "Unknown or undefined error code" (instead of crashing)
- SET_CLIENT_STMT_ERROR now maps to stmt_set_error and accepts variadic
  arguments
This commit is contained in:
Georg Richter
2023-01-15 14:11:54 +01:00
parent b9e9758e93
commit bf82b2d8cb
7 changed files with 97 additions and 34 deletions

View File

@@ -31,16 +31,14 @@ extern const char *mariadb_client_errors[]; /* Error messages */
} }
#endif #endif
#define CR_MIN_ERROR 2000 /* For easier client code */ #define CR_MIN_ERROR 2000 /* For easier client code */
#define CR_MAX_ERROR 2999 #define CR_MAX_ERROR 2999
#define CER_MIN_ERROR 5000 #define CER_MIN_ERROR 5000
#define CER_MAX_ERROR 5999 #define CER_MAX_ERROR 5999
#define CER(X) mariadb_client_errors[(X)-CER_MIN_ERROR]
#define ER(X) client_errors[(X)-CR_MIN_ERROR]
#define CLIENT_ERRMAP 2 /* Errormap used by ma_error() */ #define CLIENT_ERRMAP 2 /* Errormap used by ma_error() */
#define ER_UNKNOWN_ERROR_CODE "Unknown or undefined error code (%d)"
#define CR_UNKNOWN_ERROR 2000 #define CR_UNKNOWN_ERROR 2000
#define CR_SOCKET_CREATE_ERROR 2001 #define CR_SOCKET_CREATE_ERROR 2001
#define CR_CONNECTION_ERROR 2002 #define CR_CONNECTION_ERROR 2002
@@ -109,3 +107,12 @@ extern const char *mariadb_client_errors[]; /* Error messages */
value for CR_MARIADB_LAST_ERROR */ value for CR_MARIADB_LAST_ERROR */
#define CR_MARIADB_LAST_ERROR CR_ERR_NET_UNCOMPRESS #define CR_MARIADB_LAST_ERROR CR_ERR_NET_UNCOMPRESS
#endif #endif
#define IS_MYSQL_ERROR(code) ((code) > CR_MIN_ERROR && (code) < CR_MYSQL_LAST_ERROR)
#define IS_MARIADB_ERROR(code) ((code) > CER_MIN_ERROR && (code) < CR_MARIADB_LAST_ERROR)
#define ER(code) IS_MYSQL_ERROR((code)) ? client_errors[(code) - CR_MIN_ERROR] : \
IS_MARIADB_ERROR((code)) ? mariadb_client_errors[(code) - CER_MIN_ERROR] : \
"Unknown or undefined error code"
#define CER(code) ER((code))

View File

@@ -34,14 +34,8 @@
((stmt)->mysql->extension->mariadb_server_capabilities & \ ((stmt)->mysql->extension->mariadb_server_capabilities & \
(MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))) (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))))
#define SET_CLIENT_STMT_ERROR(a, b, c, d) \ #define SET_CLIENT_STMT_ERROR(a, b, c, d, ...) \
do { \ stmt_set_error((a),(b),(c),(d), ##__VA_ARGS__)
(a)->last_errno= (b);\
strncpy((a)->sqlstate, (c), SQLSTATE_LENGTH);\
(a)->sqlstate[SQLSTATE_LENGTH]= 0;\
strncpy((a)->last_error, (d) ? (d) : ER((b)), MYSQL_ERRMSG_SIZE);\
(a)->last_error[MYSQL_ERRMSG_SIZE - 1]= 0;\
} while (0)
#define CLEAR_CLIENT_STMT_ERROR(a) \ #define CLEAR_CLIENT_STMT_ERROR(a) \
do { \ do { \
@@ -262,6 +256,11 @@ void mysql_init_ps_subsystem(void);
unsigned long net_field_length(unsigned char **packet); unsigned long net_field_length(unsigned char **packet);
int ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg, int ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
size_t length, my_bool skipp_check, void *opt_arg); size_t length, my_bool skipp_check, void *opt_arg);
void stmt_set_error(MYSQL_STMT *stmt,
unsigned int error_nr,
const char *sqlstate,
const char *format,
...);
/* /*
* function prototypes * function prototypes
*/ */

View File

@@ -1851,7 +1851,7 @@ void ma_invalidate_stmts(MYSQL *mysql, const char *function_name)
{ {
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data; MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
stmt->mysql= NULL; stmt->mysql= NULL;
SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, function_name); SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, 0, function_name);
} }
mysql->stmts= NULL; mysql->stmts= NULL;
} }
@@ -2049,18 +2049,20 @@ void my_set_error(MYSQL *mysql,
const char *errmsg; const char *errmsg;
if (!format)
{
if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR)
errmsg= ER(error_nr);
else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR)
errmsg= CER(error_nr);
else
errmsg= ER(CR_UNKNOWN_ERROR);
}
mysql->net.last_errno= error_nr; mysql->net.last_errno= error_nr;
ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH); ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
if (!format)
{
if (IS_MYSQL_ERROR(error_nr) || IS_MARIADB_ERROR(error_nr))
errmsg= ER(error_nr);
else {
snprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE - 1,
ER_UNKNOWN_ERROR_CODE, error_nr);
return;
}
}
va_start(ap, format); va_start(ap, format);
vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE - 1, vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE - 1,
format ? format : errmsg, ap); format ? format : errmsg, ap);

View File

@@ -89,18 +89,26 @@ void stmt_set_error(MYSQL_STMT *stmt,
...) ...)
{ {
va_list ap; va_list ap;
const char *error= NULL;
if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR) const char *errmsg;
error= ER(error_nr);
else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR)
error= CER(error_nr);
stmt->last_errno= error_nr; stmt->last_errno= error_nr;
ma_strmake(stmt->sqlstate, sqlstate, SQLSTATE_LENGTH); ma_strmake(stmt->sqlstate, sqlstate, SQLSTATE_LENGTH);
if (!format)
{
if (IS_MYSQL_ERROR(error_nr) || IS_MARIADB_ERROR(error_nr))
errmsg= ER(error_nr);
else {
snprintf(stmt->last_error, MYSQL_ERRMSG_SIZE - 1,
ER_UNKNOWN_ERROR_CODE, error_nr);
return;
}
}
va_start(ap, format); va_start(ap, format);
vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE, vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE - 1,
format ? format : error ? error : "", ap); format ? format : errmsg, ap);
va_end(ap); va_end(ap);
return; return;
} }

View File

@@ -805,7 +805,48 @@ static int test_compressed(MYSQL *unused __attribute__((unused)))
return OK; return OK;
} }
static int test_conc624(MYSQL *mysql)
{
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
char errmsg[MYSQL_ERRMSG_SIZE];
SET_CLIENT_STMT_ERROR(stmt, 9000, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 9000);
diag("stmt_error: %s", mysql_stmt_error(stmt));
FAIL_IF(strcmp(mysql_stmt_error(stmt), errmsg), "expected undefined error 9000");
SET_CLIENT_STMT_ERROR(stmt, 0, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 0);
FAIL_IF(strcmp(mysql_stmt_error(stmt), errmsg), "expected undefined error 0");
SET_CLIENT_STMT_ERROR(stmt, 4999, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 4999);
FAIL_IF(strcmp(mysql_stmt_error(stmt), errmsg), "expected undefined error 4999");
my_set_error(mysql, 4999, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 4999);
FAIL_IF(strcmp(mysql_error(mysql), errmsg), "expected undefined error 4999");
my_set_error(mysql, 0, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 0);
FAIL_IF(strcmp(mysql_error(mysql), errmsg), "expected undefined error 0");
my_set_error(mysql, 9000, SQLSTATE_UNKNOWN, 0);
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER_UNKNOWN_ERROR_CODE, 9000);
FAIL_IF(strcmp(mysql_error(mysql), errmsg), "expected undefined error 9000");
/* test if SET_CLIENT_STMT_ERROR works with variadic arguments */
SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, 0, "foobar");
snprintf(errmsg, MYSQL_ERRMSG_SIZE, ER(CR_STMT_CLOSED), "foobar");
FAIL_IF(strcmp(mysql_stmt_error(stmt), errmsg), "error when passing variadic arguments to prepared stmt error function");
mysql_stmt_close(stmt);
return OK;
}
struct my_tests_st my_tests[] = { struct my_tests_st my_tests[] = {
{"test_conc624", test_conc624, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc75", test_conc75, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc75", test_conc75, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc74", test_conc74, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc74", test_conc74, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc71", test_conc71, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc71", test_conc71, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},

View File

@@ -803,13 +803,18 @@ static int test_conc223(MYSQL *mysql)
res= mysql_store_result(mysql); res= mysql_store_result(mysql);
while ((row = mysql_fetch_row(res))) while ((row = mysql_fetch_row(res)))
{ {
int id= atoi(row[0]); int id;
if (row[0])
{
id= atoi(row[0]);
if (!mariadb_get_charset_by_nr(id)) if (!mariadb_get_charset_by_nr(id))
{ {
diag("%04d %s %s", id, row[1], row[2]); diag("%04d %s %s", id, row[1], row[2]);
found++; found++;
} }
} }
}
mysql_free_result(res); mysql_free_result(res);
if (found) if (found)
{ {

View File

@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <stdlib.h> #include <stdlib.h>
#include <ma_server_error.h> #include <ma_server_error.h>
#include <mysql/client_plugin.h> #include <mysql/client_plugin.h>
#include <errmsg.h>
#ifndef WIN32 #ifndef WIN32
#include <pthread.h> #include <pthread.h>