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
CONC-533: Support for asynchronous statements (binary protocol)
Added a new option MARIADB_OPT_SKIP_READ_RESPONSE which skips automatic reading of server response after sending a command to the server. Server packets have to be retrieved by calling the corresponding methods, e.g: Send command Read method mysql_real_query/mysql_send_query db_read_query_result mysql_stmt_prepare db_read_prepare_response mysql_stmt_execute, mariadb_stmt_execute_direct db_read_execute_response
This commit is contained in:
@@ -79,6 +79,7 @@ struct st_mysql_options_extension {
|
||||
char *proxy_header;
|
||||
size_t proxy_header_len;
|
||||
int (*io_wait)(my_socket handle, my_bool is_read, int timeout);
|
||||
my_bool skip_read_response;
|
||||
};
|
||||
|
||||
typedef struct st_connection_handler
|
||||
|
@@ -246,7 +246,8 @@ extern const char *SQLSTATE_UNKNOWN;
|
||||
MARIADB_OPT_MULTI_STATEMENTS,
|
||||
MARIADB_OPT_INTERACTIVE,
|
||||
MARIADB_OPT_PROXY_HEADER,
|
||||
MARIADB_OPT_IO_WAIT
|
||||
MARIADB_OPT_IO_WAIT,
|
||||
MARIADB_OPT_SKIP_READ_RESPONSE
|
||||
};
|
||||
|
||||
enum mariadb_value {
|
||||
@@ -872,6 +873,7 @@ struct st_mariadb_methods {
|
||||
void (*set_error)(MYSQL *mysql, unsigned int error_nr, const char *sqlstate, const char *format, ...);
|
||||
void (*invalidate_stmts)(MYSQL *mysql, const char *function_name);
|
||||
struct st_mariadb_api *api;
|
||||
int (*db_read_execute_response)(MYSQL_STMT *stmt);
|
||||
};
|
||||
|
||||
/* synonyms/aliases functions */
|
||||
|
@@ -112,6 +112,7 @@ extern my_bool mthd_supported_buffer_type(enum enum_field_types type);
|
||||
extern my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt);
|
||||
extern my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt);
|
||||
extern my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt);
|
||||
extern int mthd_stmt_read_execute_response(MYSQL_STMT *stmt);
|
||||
extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row);
|
||||
extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
|
||||
extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
|
||||
@@ -2489,7 +2490,7 @@ mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)
|
||||
|
||||
if (ma_simple_command(mysql, COM_QUERY,query,length,1,0))
|
||||
return(-1);
|
||||
if (!skip_result)
|
||||
if (!skip_result && !mysql->options.extension->skip_read_response)
|
||||
return(mysql->methods->db_read_query_result(mysql));
|
||||
return(0);
|
||||
}
|
||||
@@ -3362,6 +3363,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
||||
CHECK_OPT_EXTENSION_SET(&mysql->options);
|
||||
mysql->options.extension->io_wait = (int(*)(my_socket, my_bool, int))arg1;
|
||||
break;
|
||||
case MARIADB_OPT_SKIP_READ_RESPONSE:
|
||||
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, skip_read_response, *(my_bool *)arg1);
|
||||
break;
|
||||
default:
|
||||
va_end(ap);
|
||||
SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
|
||||
@@ -3577,6 +3581,9 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...)
|
||||
case MARIADB_OPT_IO_WAIT:
|
||||
*((int(**)(my_socket, my_bool, int))arg) = mysql->options.extension ? mysql->options.extension->io_wait : NULL;
|
||||
break;
|
||||
case MARIADB_OPT_SKIP_READ_RESPONSE:
|
||||
*((my_bool*)arg)= mysql->options.extension ? mysql->options.extension->skip_read_response : 0;
|
||||
break;
|
||||
default:
|
||||
va_end(ap);
|
||||
SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
|
||||
@@ -4509,5 +4516,7 @@ struct st_mariadb_methods MARIADB_DEFAULT_METHODS = {
|
||||
/* invalidate statements */
|
||||
ma_invalidate_stmts,
|
||||
/* API functions */
|
||||
&MARIADB_API
|
||||
&MARIADB_API,
|
||||
/* read execute response */
|
||||
mthd_stmt_read_execute_response
|
||||
};
|
||||
|
@@ -322,11 +322,14 @@ static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
|
||||
result->data= 0;
|
||||
result->rows= 0;
|
||||
|
||||
if (!stmt->mysql->options.extension->skip_read_response)
|
||||
{
|
||||
if (stmt->mysql->methods->db_stmt_read_all_rows(stmt))
|
||||
return(1);
|
||||
|
||||
return(stmt_buffered_fetch(stmt, row));
|
||||
}
|
||||
}
|
||||
/* no more cursor data available */
|
||||
*row= NULL;
|
||||
return(MYSQL_NO_DATA);
|
||||
@@ -1575,6 +1578,52 @@ my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt)
|
||||
p++;
|
||||
/* for backward compatibility we also update mysql->warning_count */
|
||||
stmt->mysql->warning_count= stmt->upsert_status.warning_count= uint2korr(p);
|
||||
|
||||
/* metadata not supported yet */
|
||||
|
||||
if (stmt->param_count &&
|
||||
stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* allocated bind buffer for parameters */
|
||||
if (stmt->field_count &&
|
||||
stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (stmt->param_count)
|
||||
{
|
||||
if (stmt->prebind_params)
|
||||
{
|
||||
if (stmt->prebind_params != stmt->param_count)
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
return 1;
|
||||
}
|
||||
memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
|
||||
}
|
||||
}
|
||||
/* allocated bind buffer for result */
|
||||
if (stmt->field_count)
|
||||
{
|
||||
MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
|
||||
if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
return 1;
|
||||
}
|
||||
memset(stmt->bind, 0, sizeof(MYSQL_BIND) * stmt->field_count);
|
||||
}
|
||||
stmt->state = MYSQL_STMT_PREPARED;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1663,57 +1712,14 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned lon
|
||||
if (!is_multi && mysql->net.extension->multi_status == COM_MULTI_ENABLED)
|
||||
ma_multi_command(mysql, COM_MULTI_END);
|
||||
|
||||
if (mysql->net.extension->multi_status > COM_MULTI_OFF)
|
||||
if (mysql->net.extension->multi_status > COM_MULTI_OFF ||
|
||||
mysql->options.extension->skip_read_response)
|
||||
return 0;
|
||||
|
||||
if (mysql->methods->db_read_prepare_response &&
|
||||
mysql->methods->db_read_prepare_response(stmt))
|
||||
goto fail;
|
||||
|
||||
/* metadata not supported yet */
|
||||
|
||||
if (stmt->param_count &&
|
||||
stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* allocated bind buffer for parameters */
|
||||
if (stmt->field_count &&
|
||||
stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
if (stmt->param_count)
|
||||
{
|
||||
if (stmt->prebind_params)
|
||||
{
|
||||
if (stmt->prebind_params != stmt->param_count)
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
goto fail;
|
||||
}
|
||||
memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
|
||||
}
|
||||
}
|
||||
/* allocated bind buffer for result */
|
||||
if (stmt->field_count)
|
||||
{
|
||||
MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
|
||||
if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
goto fail;
|
||||
}
|
||||
memset(stmt->bind, 0, sizeof(MYSQL_BIND) * stmt->field_count);
|
||||
}
|
||||
stmt->state = MYSQL_STMT_PREPARED;
|
||||
return(0);
|
||||
|
||||
fail:
|
||||
@@ -1834,7 +1840,7 @@ static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
|
||||
return(0);
|
||||
}
|
||||
|
||||
int stmt_read_execute_response(MYSQL_STMT *stmt)
|
||||
int mthd_stmt_read_execute_response(MYSQL_STMT *stmt)
|
||||
{
|
||||
MYSQL *mysql= stmt->mysql;
|
||||
int ret;
|
||||
@@ -2070,10 +2076,11 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (mysql->net.extension->multi_status > COM_MULTI_OFF)
|
||||
if (mysql->net.extension->multi_status > COM_MULTI_OFF ||
|
||||
mysql->options.extension->skip_read_response)
|
||||
return(0);
|
||||
|
||||
return(stmt_read_execute_response(stmt));
|
||||
return(mthd_stmt_read_execute_response(stmt));
|
||||
}
|
||||
|
||||
static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
|
||||
@@ -2475,6 +2482,8 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
||||
if (ma_multi_command(mysql, COM_MULTI_END))
|
||||
goto fail;
|
||||
|
||||
if (!mysql->options.extension->skip_read_response)
|
||||
{
|
||||
/* read prepare response */
|
||||
if (mysql->methods->db_read_prepare_response &&
|
||||
mysql->methods->db_read_prepare_response(stmt))
|
||||
@@ -2482,36 +2491,9 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
||||
|
||||
clear_result= 0;
|
||||
|
||||
/* metadata not supported yet */
|
||||
|
||||
if (stmt->param_count &&
|
||||
stmt->mysql->methods->db_stmt_get_param_metadata(stmt))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* allocated bind buffer for parameters */
|
||||
if (stmt->field_count &&
|
||||
stmt->mysql->methods->db_stmt_get_result_metadata(stmt))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* allocated bind buffer for result */
|
||||
if (stmt->field_count)
|
||||
{
|
||||
MA_MEM_ROOT *fields_ma_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_ma_alloc_root;
|
||||
if (!(stmt->bind= (MYSQL_BIND *)ma_alloc_root(fields_ma_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
|
||||
goto fail;
|
||||
}
|
||||
memset(stmt->bind, 0, sizeof(MYSQL_BIND) * stmt->field_count);
|
||||
}
|
||||
stmt->state = MYSQL_STMT_PREPARED;
|
||||
|
||||
/* read execute response packet */
|
||||
return stmt_read_execute_response(stmt);
|
||||
return mthd_stmt_read_execute_response(stmt);
|
||||
}
|
||||
fail:
|
||||
/* check if we need to set error message */
|
||||
if (!mysql_stmt_errno(stmt))
|
||||
|
@@ -1019,8 +1019,6 @@ static size_t ma_gnutls_get_protocol_version(const char *tls_version_option,
|
||||
goto end;
|
||||
|
||||
|
||||
if (strstr(tls_version_option, "TLSv1.0"))
|
||||
strcat(tls_versions, ":+VERS-TLS1.0");
|
||||
if (strstr(tls_version_option, "TLSv1.1"))
|
||||
strcat(tls_versions, ":+VERS-TLS1.1");
|
||||
if (strstr(tls_version_option, "TLSv1.2"))
|
||||
@@ -1033,7 +1031,7 @@ end:
|
||||
if (tls_versions[0])
|
||||
snprintf(priority_string, prio_len - 1, "-VERS-TLS-ALL%s:NORMAL", tls_versions);
|
||||
else
|
||||
strncpy(priority_string, "NORMAL:+VERS-ALL", prio_len - 1);
|
||||
strncpy(priority_string, "NORMAL:+VERS-ALL:-VERS-TLSv1.0", prio_len - 1);
|
||||
return strlen(priority_string);
|
||||
}
|
||||
|
||||
|
@@ -103,8 +103,6 @@ static long ma_tls_version_options(const char *version)
|
||||
if (!version)
|
||||
return 0;
|
||||
|
||||
if (strstr(version, "TLSv1.0"))
|
||||
protocol_options&= ~SSL_OP_NO_TLSv1;
|
||||
if (strstr(version, "TLSv1.1"))
|
||||
protocol_options&= ~SSL_OP_NO_TLSv1_1;
|
||||
if (strstr(version, "TLSv1.2"))
|
||||
@@ -445,7 +443,8 @@ void *ma_tls_init(MYSQL *mysql)
|
||||
SSL_CTX *ctx= NULL;
|
||||
long options= SSL_OP_ALL |
|
||||
SSL_OP_NO_SSLv2 |
|
||||
SSL_OP_NO_SSLv3;
|
||||
SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_TLSv1;
|
||||
pthread_mutex_lock(&LOCK_openssl_config);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
|
@@ -1463,7 +1463,65 @@ static int test_conc458(MYSQL *my __attribute__((unused)))
|
||||
}
|
||||
|
||||
|
||||
static int test_conc533(MYSQL *mysql)
|
||||
{
|
||||
my_bool skip= 1;
|
||||
int rc;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[1];
|
||||
char buffer[10];
|
||||
|
||||
rc= mysql_options(mysql, MARIADB_OPT_SKIP_READ_RESPONSE, &skip);
|
||||
|
||||
rc= mysql_real_query(mysql, SL("SELECT 1"));
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql->methods->db_read_query_result(mysql);
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
result= mysql_store_result(mysql);
|
||||
row= mysql_fetch_row(result);
|
||||
|
||||
FAIL_IF(strcmp(row[0], "1"), "Expected value \"1\"");
|
||||
mysql_free_result(result);
|
||||
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
rc= mysql_stmt_prepare(stmt, SL("SELECT 1"));
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
rc= mysql->methods->db_read_prepare_response(stmt);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
FAIL_IF(mysql_stmt_field_count(stmt) != 1, "Expected field_count= 1");
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
rc= mysql->methods->db_read_execute_response(stmt);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
memset(bind, 0, sizeof(MYSQL_BIND));
|
||||
bind[0].buffer= buffer;
|
||||
bind[0].buffer_type= MYSQL_TYPE_STRING;
|
||||
bind[0].buffer_length= 10;
|
||||
|
||||
rc= mysql_stmt_bind_result(stmt, bind);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
rc= mysql_stmt_fetch(stmt);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
FAIL_IF(strcmp(buffer, "1"), "Expected value \"1\"");
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"test_conc533", test_conc533, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{"test_conc458", test_conc458, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||
{"test_conc457", test_conc457, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_conc384", test_conc384, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||
|
Reference in New Issue
Block a user