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
Support mariadb_stmt_execute_direct also for versions < 10.2
Bundled COM_CLOSE and COM_PREPARE packets
This commit is contained in:
@@ -26,7 +26,8 @@
|
||||
enum enum_multi_status {
|
||||
COM_MULTI_OFF= 0,
|
||||
COM_MULTI_CANCEL,
|
||||
COM_MULTI_PROGRESS,
|
||||
COM_MULTI_ENABLED,
|
||||
COM_MULTI_DISABLED,
|
||||
COM_MULTI_END
|
||||
};
|
||||
|
||||
|
@@ -222,6 +222,7 @@ struct st_mysql_stmt
|
||||
struct st_mysqlnd_stmt_methods *m;
|
||||
unsigned int array_size;
|
||||
size_t row_size;
|
||||
unsigned int prebind_params;
|
||||
};
|
||||
|
||||
typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row);
|
||||
|
@@ -160,12 +160,6 @@ extern unsigned int mariadb_deinitialize_ssl;
|
||||
void *extension;
|
||||
} MYSQL_DATA;
|
||||
|
||||
enum mariadb_com_multi {
|
||||
MARIADB_COM_MULTI_END,
|
||||
MARIADB_COM_MULTI_BEGIN,
|
||||
MARIADB_COM_MULTI_CANCEL
|
||||
};
|
||||
|
||||
enum mysql_option
|
||||
{
|
||||
MYSQL_OPT_CONNECT_TIMEOUT,
|
||||
|
@@ -382,7 +382,7 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
|
||||
if (!arg)
|
||||
arg="";
|
||||
|
||||
if (net->extension->multi_status== COM_MULTI_PROGRESS)
|
||||
if (net->extension->multi_status== COM_MULTI_ENABLED)
|
||||
{
|
||||
return net_add_multi_command(net, command, (const uchar *)arg, length);
|
||||
}
|
||||
@@ -435,12 +435,17 @@ int ma_multi_command(MYSQL *mysql, enum enum_multi_status status)
|
||||
ma_net_clear(net);
|
||||
net->extension->multi_status= status;
|
||||
return 0;
|
||||
case COM_MULTI_PROGRESS:
|
||||
if (net->extension->multi_status > COM_MULTI_OFF)
|
||||
case COM_MULTI_ENABLED:
|
||||
if (net->extension->multi_status > COM_MULTI_DISABLED)
|
||||
return 1;
|
||||
ma_net_clear(net);
|
||||
net->extension->multi_status= status;
|
||||
return 0;
|
||||
case COM_MULTI_DISABLED:
|
||||
/* Opposite to COM_MULTI_OFF we don't clear net buffer,
|
||||
next command or com_nulti_end will flush entire buffer */
|
||||
net->extension->multi_status= status;
|
||||
return 0;
|
||||
case COM_MULTI_END:
|
||||
{
|
||||
size_t len= net->write_pos - net->buff - NET_HEADER_SIZE;
|
||||
|
@@ -835,7 +835,7 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type a
|
||||
*(unsigned long *)value= stmt->prefetch_rows;
|
||||
break;
|
||||
case STMT_ATTR_PREBIND_PARAMS:
|
||||
*(unsigned int *)value= stmt->param_count;
|
||||
*(unsigned int *)value= stmt->prebind_params;
|
||||
break;
|
||||
case STMT_ATTR_ARRAY_SIZE:
|
||||
*(unsigned int *)value= stmt->array_size;
|
||||
@@ -870,7 +870,7 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type a
|
||||
stmt->prefetch_rows= *(long *)value;
|
||||
break;
|
||||
case STMT_ATTR_PREBIND_PARAMS:
|
||||
stmt->param_count= *(unsigned int *)value;
|
||||
stmt->prebind_params= *(unsigned int *)value;
|
||||
break;
|
||||
case STMT_ATTR_ARRAY_SIZE:
|
||||
stmt->array_size= *(unsigned int *)value;
|
||||
@@ -899,17 +899,18 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
|
||||
them, e.g. for mariadb_stmt_execute_direct()
|
||||
*/
|
||||
if ((stmt->state < MYSQL_STMT_PREPARED || stmt->state >= MYSQL_STMT_EXECUTED) &&
|
||||
!(mysql->server_capabilities & CLIENT_MYSQL))
|
||||
stmt->prebind_params > 0)
|
||||
{
|
||||
if (!stmt->params && stmt->param_count)
|
||||
if (!stmt->params && stmt->prebind_params)
|
||||
{
|
||||
if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
|
||||
if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->prebind_params * 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));
|
||||
memset(stmt->params, '\0', stmt->prebind_params * sizeof(MYSQL_BIND));
|
||||
}
|
||||
stmt->param_count= stmt->prebind_params;
|
||||
}
|
||||
else if (stmt->state < MYSQL_STMT_PREPARED) {
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
|
||||
@@ -1350,6 +1351,7 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
|
||||
{
|
||||
MYSQL *mysql= stmt->mysql;
|
||||
int rc= 1;
|
||||
my_bool is_multi= 0;
|
||||
|
||||
if (!stmt->mysql)
|
||||
{
|
||||
@@ -1368,10 +1370,14 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
|
||||
/* check if we have to clear results */
|
||||
if (stmt->state > MYSQL_STMT_INITTED)
|
||||
{
|
||||
char stmt_id[STMT_ID_LENGTH];
|
||||
is_multi= (mysql->net.extension->multi_status > COM_MULTI_OFF);
|
||||
/* We need to semi-close the prepared statement:
|
||||
reset stmt and free all buffers and close the statement
|
||||
on server side. Statment handle will get a new stmt_id */
|
||||
char stmt_id[STMT_ID_LENGTH];
|
||||
|
||||
if (!is_multi)
|
||||
ma_multi_command(mysql, COM_MULTI_ENABLED);
|
||||
|
||||
if (mysql_stmt_internal_reset(stmt, 1))
|
||||
goto fail;
|
||||
@@ -1391,6 +1397,9 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
|
||||
if (mysql->methods->db_command(mysql, COM_STMT_PREPARE, query, length, 1, stmt))
|
||||
goto fail;
|
||||
|
||||
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)
|
||||
return 0;
|
||||
|
||||
@@ -1414,6 +1423,14 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
|
||||
}
|
||||
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);
|
||||
@@ -1421,6 +1438,7 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
|
||||
}
|
||||
memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
|
||||
}
|
||||
}
|
||||
/* allocated bind buffer for result */
|
||||
if (stmt->field_count)
|
||||
{
|
||||
@@ -2087,12 +2105,14 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* avoid sending close + prepare in 2 packets */
|
||||
|
||||
if ((rc= mysql_stmt_prepare(stmt, stmt_str, length)))
|
||||
return rc;
|
||||
return mysql_stmt_execute(stmt);
|
||||
}
|
||||
|
||||
if (ma_multi_command(mysql, COM_MULTI_PROGRESS))
|
||||
if (ma_multi_command(mysql, COM_MULTI_ENABLED))
|
||||
{
|
||||
SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
|
||||
goto fail;
|
||||
|
@@ -19,6 +19,8 @@
|
||||
|
||||
#define TEST_ARRAY_SIZE 1024
|
||||
|
||||
static my_bool bulk_enabled= 0;
|
||||
|
||||
char *rand_str(size_t length) {
|
||||
const char charset[] = "0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
@@ -32,6 +34,14 @@ char *rand_str(size_t length) {
|
||||
return p;
|
||||
}
|
||||
|
||||
static int check_bulk(MYSQL *mysql)
|
||||
{
|
||||
bulk_enabled= (!(mysql->server_capabilities & CLIENT_MYSQL) &&
|
||||
(mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32));
|
||||
diag("bulk %ssupported", bulk_enabled ? "" : "not ");
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int bulk1(MYSQL *mysql)
|
||||
{
|
||||
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
|
||||
@@ -47,6 +57,9 @@ static int bulk1(MYSQL *mysql)
|
||||
MYSQL_ROW row;
|
||||
unsigned int intval;
|
||||
|
||||
if (!bulk_enabled)
|
||||
return SKIP;
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
@@ -133,6 +146,9 @@ static int bulk2(MYSQL *mysql)
|
||||
unsigned int array_size=1024;
|
||||
char indicator[1024];
|
||||
long lval[1024];
|
||||
|
||||
if (!bulk_enabled)
|
||||
return SKIP;
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk2");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
@@ -187,6 +203,8 @@ static int bulk3(MYSQL *mysql)
|
||||
int array_size= 3;
|
||||
ulong length= -1;
|
||||
|
||||
if (!bulk_enabled)
|
||||
return SKIP;
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk3");
|
||||
check_mysql_rc(rc,mysql);
|
||||
rc= mysql_query(mysql, "CREATE TABLE bulk3 (name varchar(20), row int)");
|
||||
@@ -218,6 +236,7 @@ static int bulk3(MYSQL *mysql)
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"check_bulk", check_bulk, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"bulk1", bulk1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"bulk2", bulk2, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"bulk3", bulk3, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
|
@@ -100,7 +100,66 @@ static int execute_direct_example(MYSQL *mysql)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int conc_213(MYSQL *mysql)
|
||||
{
|
||||
MYSQL_BIND bind;
|
||||
unsigned int param_count= 1;
|
||||
long id= 1234;
|
||||
MYSQL_STMT *stmt;
|
||||
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
|
||||
memset(&bind, '\0', sizeof(bind));
|
||||
|
||||
bind.buffer_type = MYSQL_TYPE_LONG;
|
||||
bind.buffer = (void *)&id;
|
||||
bind.buffer_length = sizeof(long);
|
||||
/* bind.is_null = &is_null;
|
||||
bind.length = &length;
|
||||
bind.error = &error; */
|
||||
|
||||
mysql_stmt_attr_set(stmt, STMT_ATTR_PREBIND_PARAMS, ¶m_count);
|
||||
check_stmt_rc(mysql_stmt_bind_param(stmt, &bind), stmt);
|
||||
check_stmt_rc(mariadb_stmt_execute_direct(stmt, "SELECT ?", -1), stmt);
|
||||
check_stmt_rc(mysql_stmt_store_result(stmt), stmt);
|
||||
check_stmt_rc(mysql_stmt_free_result(stmt), stmt);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int conc_212(MYSQL *mysql)
|
||||
{
|
||||
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
|
||||
int rc;
|
||||
|
||||
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1, 2", -1);
|
||||
check_stmt_rc(rc, stmt);
|
||||
mysql_stmt_store_result(stmt);
|
||||
mysql_stmt_free_result(stmt);
|
||||
|
||||
sleep(100);
|
||||
rc= mariadb_stmt_execute_direct(stmt, "SELECT 1, 2", -1);
|
||||
check_stmt_rc(rc, stmt);
|
||||
mysql_stmt_store_result(stmt);
|
||||
mysql_stmt_free_result(stmt);
|
||||
|
||||
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_stmt_close(stmt);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"conc_212", conc_212, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"conc_213", conc_213, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"execute_direct", execute_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"execute_direct_example", execute_direct_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{NULL, NULL, 0, 0, NULL, NULL}
|
||||
|
Reference in New Issue
Block a user