You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-07 02:42:49 +03:00
client side implemetation for MDEV-10340:
int STDCALL mysql_reset_connection(MYSQL *mysql)
This commit is contained in:
@@ -90,7 +90,9 @@ enum enum_server_command
|
|||||||
COM_STMT_RESET = 26,
|
COM_STMT_RESET = 26,
|
||||||
COM_SET_OPTION = 27,
|
COM_SET_OPTION = 27,
|
||||||
COM_STMT_FETCH = 28,
|
COM_STMT_FETCH = 28,
|
||||||
COM_DAEMON,
|
COM_DAEMON= 29,
|
||||||
|
COM_UNSUPPORTED= 30,
|
||||||
|
COM_RESET_CONNECTION = 31,
|
||||||
COM_MULTI = 254,
|
COM_MULTI = 254,
|
||||||
COM_END
|
COM_END
|
||||||
};
|
};
|
||||||
|
@@ -673,6 +673,8 @@ int STDCALL mysql_read_query_result_start(my_bool *ret,
|
|||||||
MYSQL *mysql);
|
MYSQL *mysql);
|
||||||
int STDCALL mysql_read_query_result_cont(my_bool *ret,
|
int STDCALL mysql_read_query_result_cont(my_bool *ret,
|
||||||
MYSQL *mysql, int status);
|
MYSQL *mysql, int status);
|
||||||
|
int STDCALL mysql_reset_connection_start(int *ret, MYSQL *mysql);
|
||||||
|
int STDCALL mysql_reset_connection_cont(int *ret, MYSQL *mysql, int status);
|
||||||
int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length);
|
int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length);
|
||||||
int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length);
|
int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type, const char **data, size_t *length);
|
||||||
int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt,const char *query, size_t length);
|
int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt,const char *query, size_t length);
|
||||||
@@ -696,6 +698,7 @@ int STDCALL mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt,
|
|||||||
size_t len);
|
size_t len);
|
||||||
int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt,
|
int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt,
|
||||||
int status);
|
int status);
|
||||||
|
int STDCALL mysql_reset_connection(MYSQL *mysql);
|
||||||
|
|
||||||
/* API function calls (used by dynmic plugins) */
|
/* API function calls (used by dynmic plugins) */
|
||||||
struct st_mariadb_api {
|
struct st_mariadb_api {
|
||||||
@@ -813,6 +816,7 @@ struct st_mariadb_api {
|
|||||||
int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt);
|
int (STDCALL *mysql_stmt_next_result)(MYSQL_STMT *stmt);
|
||||||
my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt);
|
my_bool (STDCALL *mysql_stmt_more_results)(MYSQL_STMT *stmt);
|
||||||
int (STDCALL *mariadb_stmt_execute_direct)(MYSQL_STMT *stmt, const char *stmtstr, size_t length);
|
int (STDCALL *mariadb_stmt_execute_direct)(MYSQL_STMT *stmt, const char *stmtstr, size_t length);
|
||||||
|
int (STDCALL *mysql_reset_connection)(MYSQL *mysql);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* these methods can be overwritten by db plugins */
|
/* these methods can be overwritten by db plugins */
|
||||||
|
@@ -100,6 +100,7 @@ typedef struct st_ma_connection_plugin
|
|||||||
int (*set_connection)(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
int (*set_connection)(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);
|
||||||
my_bool (*reconnect)(MYSQL *mysql);
|
my_bool (*reconnect)(MYSQL *mysql);
|
||||||
|
int (*reset)(MYSQL *mysql);
|
||||||
} MARIADB_CONNECTION_PLUGIN;
|
} MARIADB_CONNECTION_PLUGIN;
|
||||||
|
|
||||||
#define MARIADB_DB_DRIVER(a) ((a)->ext_db)
|
#define MARIADB_DB_DRIVER(a) ((a)->ext_db)
|
||||||
|
@@ -90,6 +90,7 @@ SET(MARIADB_LIB_SYMBOLS
|
|||||||
mysql_real_escape_string
|
mysql_real_escape_string
|
||||||
mysql_real_query
|
mysql_real_query
|
||||||
mysql_refresh
|
mysql_refresh
|
||||||
|
mysql_reset_connection
|
||||||
mysql_rollback
|
mysql_rollback
|
||||||
mysql_row_seek
|
mysql_row_seek
|
||||||
mysql_row_tell
|
mysql_row_tell
|
||||||
@@ -201,6 +202,8 @@ SET(MARIADB_NONBLOCK_SYMBOLS
|
|||||||
mysql_next_result_start
|
mysql_next_result_start
|
||||||
mysql_ping_cont
|
mysql_ping_cont
|
||||||
mysql_ping_start
|
mysql_ping_start
|
||||||
|
mysql_reset_connection_start
|
||||||
|
mysql_reset_connection_cont
|
||||||
mysql_query_cont
|
mysql_query_cont
|
||||||
mysql_query_start
|
mysql_query_start
|
||||||
mysql_read_query_result_cont
|
mysql_read_query_result_cont
|
||||||
|
@@ -2258,6 +2258,10 @@ mysql_fetch_row(MYSQL_RES *res)
|
|||||||
{
|
{
|
||||||
if (!res)
|
if (!res)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (res->handle)
|
||||||
|
if (res->handle->status != MYSQL_STATUS_USE_RESULT &&
|
||||||
|
res->handle->status != MYSQL_STATUS_GET_RESULT)
|
||||||
|
return 0;
|
||||||
if (!res->data)
|
if (!res->data)
|
||||||
{ /* Unbufferred fetch */
|
{ /* Unbufferred fetch */
|
||||||
if (!res->eof)
|
if (!res->eof)
|
||||||
@@ -3873,6 +3877,44 @@ mysql_get_parameters(void)
|
|||||||
return &mariadb_internal_parameters;
|
return &mariadb_internal_parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int STDCALL mysql_reset_connection(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* check if connection handler is active */
|
||||||
|
if (IS_CONNHDLR_ACTIVE(mysql))
|
||||||
|
{
|
||||||
|
if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reset)
|
||||||
|
return(mysql->extension->conn_hdlr->plugin->reset(mysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip result sets */
|
||||||
|
if (mysql->status == MYSQL_STATUS_USE_RESULT ||
|
||||||
|
mysql->status == MYSQL_STATUS_GET_RESULT ||
|
||||||
|
mysql->status & SERVER_MORE_RESULTS_EXIST)
|
||||||
|
{
|
||||||
|
mthd_my_skip_result(mysql);
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc= ma_simple_command(mysql, COM_RESET_CONNECTION, 0, 0, 0, 0);
|
||||||
|
if (rc && mysql->options.reconnect)
|
||||||
|
{
|
||||||
|
/* There is no big sense in resetting but we need reconnect */
|
||||||
|
rc= ma_simple_command(mysql, COM_RESET_CONNECTION,0,0,0,0);
|
||||||
|
}
|
||||||
|
if (rc)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* reset the connection in all active statements */
|
||||||
|
ma_invalidate_stmts(mysql, "mysql_reset_connection()");
|
||||||
|
free_old_query(mysql);
|
||||||
|
mysql->status= MYSQL_STATUS_READY;
|
||||||
|
mysql->affected_rows= ~(my_ulonglong)0;
|
||||||
|
mysql->insert_id= 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#undef STDCALL
|
#undef STDCALL
|
||||||
/* API functions for usage in dynamic plugins */
|
/* API functions for usage in dynamic plugins */
|
||||||
struct st_mariadb_api MARIADB_API=
|
struct st_mariadb_api MARIADB_API=
|
||||||
@@ -3990,7 +4032,8 @@ struct st_mariadb_api MARIADB_API=
|
|||||||
mysql_stmt_field_count,
|
mysql_stmt_field_count,
|
||||||
mysql_stmt_next_result,
|
mysql_stmt_next_result,
|
||||||
mysql_stmt_more_results,
|
mysql_stmt_more_results,
|
||||||
mariadb_stmt_execute_direct
|
mariadb_stmt_execute_direct,
|
||||||
|
mysql_reset_connection
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -76,7 +76,8 @@ MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ =
|
|||||||
aurora_close,
|
aurora_close,
|
||||||
NULL,
|
NULL,
|
||||||
aurora_command,
|
aurora_command,
|
||||||
aurora_reconnect
|
aurora_reconnect,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct st_mariadb_api *mariadb_api= NULL;
|
struct st_mariadb_api *mariadb_api= NULL;
|
||||||
|
@@ -69,7 +69,8 @@ MARIADB_CONNECTION_PLUGIN _mysql_client_plugin_declaration_ =
|
|||||||
repl_close,
|
repl_close,
|
||||||
repl_set_options,
|
repl_set_options,
|
||||||
repl_command,
|
repl_command,
|
||||||
NULL
|
NULL,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct st_conn_repl {
|
typedef struct st_conn_repl {
|
||||||
|
@@ -1006,7 +1006,57 @@ static int test_unix_socket_close(MYSQL *unused __attribute__((unused)))
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_reset(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
MYSQL_RES *res;
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "CREATE TABLE t1 (a int)");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1),(2),(3)");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
FAIL_IF(mysql_affected_rows(mysql) != 3, "Expected 3 rows");
|
||||||
|
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
FAIL_IF(mysql_affected_rows(mysql) != ~(unsigned long)0, "Expected 0 rows");
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "SELECT a FROM t1");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "SELECT 1 FROM DUAL");
|
||||||
|
FAIL_IF(!rc, "Error expected");
|
||||||
|
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
res= mysql_store_result(mysql);
|
||||||
|
FAIL_IF(res, "expected no result");
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "SELECT a FROM t1");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
res= mysql_use_result(mysql);
|
||||||
|
FAIL_IF(!res, "expected result");
|
||||||
|
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
FAIL_IF(mysql_fetch_row(res), "expected error");
|
||||||
|
|
||||||
|
mysql_free_result(res);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_reset", test_reset, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_unix_socket_close", test_unix_socket_close, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
{"test_unix_socket_close", test_unix_socket_close, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||||
{"test_sess_track_db", test_sess_track_db, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_sess_track_db", test_sess_track_db, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_get_options", test_get_options, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_get_options", test_get_options, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
|
@@ -1180,8 +1180,84 @@ static int test_server_status(MYSQL *mysql)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_wl6797(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
int rc;
|
||||||
|
const char *stmt_text;
|
||||||
|
my_ulonglong res;
|
||||||
|
|
||||||
|
if (mysql_get_server_version(mysql) < 50703 ||
|
||||||
|
(mariadb_connection(mysql) && mysql_get_server_version(mysql) < 100203))
|
||||||
|
{
|
||||||
|
diag("Skipping test_wl6797: "
|
||||||
|
"tested feature does not exist in versions before MySQL 5.7.3 and MariaDB 10.2\n");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
/* clean up the session */
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
FAIL_UNLESS(rc == 0, "");
|
||||||
|
|
||||||
|
/* do prepare of a query */
|
||||||
|
mysql_query(mysql, "use test");
|
||||||
|
mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||||
|
mysql_query(mysql, "CREATE TABLE t1 (a int)");
|
||||||
|
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
stmt_text= "INSERT INTO t1 VALUES (1), (2)";
|
||||||
|
|
||||||
|
rc= mysql_stmt_prepare(stmt, stmt_text, (ulong)strlen(stmt_text));
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/* Execute the insert statement */
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
|
||||||
|
/*
|
||||||
|
clean the session this should remove the prepare statement
|
||||||
|
from the cache.
|
||||||
|
*/
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
FAIL_UNLESS(rc == 0, "");
|
||||||
|
|
||||||
|
/* this below stmt should report error */
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
FAIL_IF(rc == 0, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
bug#17653288: MYSQL_RESET_CONNECTION DOES NOT RESET LAST_INSERT_ID
|
||||||
|
*/
|
||||||
|
|
||||||
|
mysql_query(mysql, "DROP TABLE IF EXISTS t2");
|
||||||
|
rc= mysql_query(mysql, "CREATE TABLE t2 (a int NOT NULL PRIMARY KEY"\
|
||||||
|
" auto_increment)");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
rc= mysql_query(mysql, "INSERT INTO t2 VALUES (null)");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
res= mysql_insert_id(mysql);
|
||||||
|
FAIL_UNLESS(res == 1, "");
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
FAIL_UNLESS(rc == 0, "");
|
||||||
|
res= mysql_insert_id(mysql);
|
||||||
|
FAIL_UNLESS(res == 0, "");
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "INSERT INTO t2 VALUES (last_insert_id(100))");
|
||||||
|
check_mysql_rc(rc, mysql);
|
||||||
|
res= mysql_insert_id(mysql);
|
||||||
|
FAIL_UNLESS(res == 100, "");
|
||||||
|
rc= mysql_reset_connection(mysql);
|
||||||
|
FAIL_UNLESS(rc == 0, "");
|
||||||
|
res= mysql_insert_id(mysql);
|
||||||
|
FAIL_UNLESS(res == 0, "");
|
||||||
|
|
||||||
|
mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||||
|
mysql_query(mysql, "DROP TABLE IF EXISTS t2");
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_wl6797", test_wl6797, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_server_status", test_server_status, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_server_status", test_server_status, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_read_timeout", test_read_timeout, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_read_timeout", test_read_timeout, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_zerofill", test_zerofill, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_zerofill", test_zerofill, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
|
@@ -4501,7 +4501,36 @@ static int test_conc217(MYSQL *mysql)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_conc208(MYSQL *mysql)
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
|
||||||
|
int rc;
|
||||||
|
int data;
|
||||||
|
MYSQL_BIND bind;
|
||||||
|
|
||||||
|
rc= mysql_stmt_prepare(stmt, "SELECT \"100\" UNION SELECT \"88\" UNION SELECT \"389789\"", -1);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
memset(&bind, 0, sizeof(MYSQL_BIND));
|
||||||
|
bind.buffer_type= MYSQL_TYPE_LONG;
|
||||||
|
bind.buffer= (void *)&data;
|
||||||
|
|
||||||
|
rc= mysql_stmt_execute(stmt);
|
||||||
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
|
rc= mysql_stmt_bind_result(stmt, &bind);
|
||||||
|
|
||||||
|
while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
|
||||||
|
{
|
||||||
|
diag("data=%d", data);
|
||||||
|
FAIL_IF(data != 100 && data != 88 && data != 389789, "Wrong value");
|
||||||
|
}
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct my_tests_st my_tests[] = {
|
struct my_tests_st my_tests[] = {
|
||||||
|
{"test_conc208", test_conc208, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc217", test_conc217, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc217", test_conc217, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc205", test_conc205, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc205", test_conc205, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
{"test_conc198", test_conc198, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
{"test_conc198", test_conc198, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||||
|
Reference in New Issue
Block a user