Skip to content

Commit

Permalink
Fix for CONC-624:
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
9EOR9 committed Jan 15, 2023
1 parent b9e9758 commit bf82b2d
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 31 deletions.
15 changes: 11 additions & 4 deletions include/errmsg.h
Expand Up @@ -31,16 +31,14 @@ extern const char *mariadb_client_errors[]; /* Error messages */
}
#endif



#define CR_MIN_ERROR 2000 /* For easier client code */
#define CR_MAX_ERROR 2999
#define CER_MIN_ERROR 5000
#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 ER_UNKNOWN_ERROR_CODE "Unknown or undefined error code (%d)"

#define CR_UNKNOWN_ERROR 2000
#define CR_SOCKET_CREATE_ERROR 2001
#define CR_CONNECTION_ERROR 2002
Expand Down Expand Up @@ -109,3 +107,12 @@ extern const char *mariadb_client_errors[]; /* Error messages */
value for CR_MARIADB_LAST_ERROR */
#define CR_MARIADB_LAST_ERROR CR_ERR_NET_UNCOMPRESS
#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))

15 changes: 7 additions & 8 deletions include/mariadb_stmt.h
Expand Up @@ -34,14 +34,8 @@
((stmt)->mysql->extension->mariadb_server_capabilities & \
(MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32))))

#define SET_CLIENT_STMT_ERROR(a, b, c, d) \
do { \
(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 SET_CLIENT_STMT_ERROR(a, b, c, d, ...) \
stmt_set_error((a),(b),(c),(d), ##__VA_ARGS__)

#define CLEAR_CLIENT_STMT_ERROR(a) \
do { \
Expand Down Expand Up @@ -262,6 +256,11 @@ void mysql_init_ps_subsystem(void);
unsigned long net_field_length(unsigned char **packet);
int ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *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
*/
Expand Down
18 changes: 10 additions & 8 deletions libmariadb/mariadb_lib.c
Expand Up @@ -1851,7 +1851,7 @@ void ma_invalidate_stmts(MYSQL *mysql, const char *function_name)
{
MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
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;
}
Expand Down Expand Up @@ -2049,18 +2049,20 @@ void my_set_error(MYSQL *mysql,

const char *errmsg;

mysql->net.last_errno= error_nr;
ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);

if (!format)
{
if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR)
if (IS_MYSQL_ERROR(error_nr) || IS_MARIADB_ERROR(error_nr))
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);
else {
snprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE - 1,
ER_UNKNOWN_ERROR_CODE, error_nr);
return;
}
}

mysql->net.last_errno= error_nr;
ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
va_start(ap, format);
vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE - 1,
format ? format : errmsg, ap);
Expand Down
22 changes: 15 additions & 7 deletions libmariadb/mariadb_stmt.c
Expand Up @@ -89,18 +89,26 @@ void stmt_set_error(MYSQL_STMT *stmt,
...)
{
va_list ap;
const char *error= NULL;

if (error_nr >= CR_MIN_ERROR && error_nr <= CR_MYSQL_LAST_ERROR)
error= ER(error_nr);
else if (error_nr >= CER_MIN_ERROR && error_nr <= CR_MARIADB_LAST_ERROR)
error= CER(error_nr);
const char *errmsg;

stmt->last_errno= error_nr;
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);
vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE,
format ? format : error ? error : "", ap);
vsnprintf(stmt->last_error, MYSQL_ERRMSG_SIZE - 1,
format ? format : errmsg, ap);
va_end(ap);
return;
}
Expand Down
41 changes: 41 additions & 0 deletions unittest/libmariadb/basic-t.c
Expand Up @@ -805,7 +805,48 @@ static int test_compressed(MYSQL *unused __attribute__((unused)))
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[] = {
{"test_conc624", test_conc624, 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_conc71", test_conc71, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
Expand Down
13 changes: 9 additions & 4 deletions unittest/libmariadb/charset.c
Expand Up @@ -803,11 +803,16 @@ static int test_conc223(MYSQL *mysql)
res= mysql_store_result(mysql);
while ((row = mysql_fetch_row(res)))
{
int id= atoi(row[0]);
if (!mariadb_get_charset_by_nr(id))
int id;

if (row[0])
{
diag("%04d %s %s", id, row[1], row[2]);
found++;
id= atoi(row[0]);
if (!mariadb_get_charset_by_nr(id))
{
diag("%04d %s %s", id, row[1], row[2]);
found++;
}
}
}
mysql_free_result(res);
Expand Down
1 change: 1 addition & 0 deletions unittest/libmariadb/my_test.h
Expand Up @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <stdlib.h>
#include <ma_server_error.h>
#include <mysql/client_plugin.h>
#include <errmsg.h>

#ifndef WIN32
#include <pthread.h>
Expand Down

0 comments on commit bf82b2d

Please sign in to comment.