1
0
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:
Georg Richter
2016-11-12 17:51:01 +01:00
parent 64862325a5
commit 03a7ec1b8b
7 changed files with 121 additions and 22 deletions

View File

@@ -26,7 +26,8 @@
enum enum_multi_status { enum enum_multi_status {
COM_MULTI_OFF= 0, COM_MULTI_OFF= 0,
COM_MULTI_CANCEL, COM_MULTI_CANCEL,
COM_MULTI_PROGRESS, COM_MULTI_ENABLED,
COM_MULTI_DISABLED,
COM_MULTI_END COM_MULTI_END
}; };

View File

@@ -222,6 +222,7 @@ struct st_mysql_stmt
struct st_mysqlnd_stmt_methods *m; struct st_mysqlnd_stmt_methods *m;
unsigned int array_size; unsigned int array_size;
size_t row_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); typedef void (*ps_field_fetch_func)(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row);

View File

@@ -160,12 +160,6 @@ extern unsigned int mariadb_deinitialize_ssl;
void *extension; void *extension;
} MYSQL_DATA; } MYSQL_DATA;
enum mariadb_com_multi {
MARIADB_COM_MULTI_END,
MARIADB_COM_MULTI_BEGIN,
MARIADB_COM_MULTI_CANCEL
};
enum mysql_option enum mysql_option
{ {
MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_CONNECT_TIMEOUT,

View File

@@ -382,7 +382,7 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
if (!arg) if (!arg)
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); 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); ma_net_clear(net);
net->extension->multi_status= status; net->extension->multi_status= status;
return 0; return 0;
case COM_MULTI_PROGRESS: case COM_MULTI_ENABLED:
if (net->extension->multi_status > COM_MULTI_OFF) if (net->extension->multi_status > COM_MULTI_DISABLED)
return 1; return 1;
ma_net_clear(net); ma_net_clear(net);
net->extension->multi_status= status; net->extension->multi_status= status;
return 0; 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: case COM_MULTI_END:
{ {
size_t len= net->write_pos - net->buff - NET_HEADER_SIZE; size_t len= net->write_pos - net->buff - NET_HEADER_SIZE;

View File

@@ -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; *(unsigned long *)value= stmt->prefetch_rows;
break; break;
case STMT_ATTR_PREBIND_PARAMS: case STMT_ATTR_PREBIND_PARAMS:
*(unsigned int *)value= stmt->param_count; *(unsigned int *)value= stmt->prebind_params;
break; break;
case STMT_ATTR_ARRAY_SIZE: case STMT_ATTR_ARRAY_SIZE:
*(unsigned int *)value= stmt->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; stmt->prefetch_rows= *(long *)value;
break; break;
case STMT_ATTR_PREBIND_PARAMS: case STMT_ATTR_PREBIND_PARAMS:
stmt->param_count= *(unsigned int *)value; stmt->prebind_params= *(unsigned int *)value;
break; break;
case STMT_ATTR_ARRAY_SIZE: case STMT_ATTR_ARRAY_SIZE:
stmt->array_size= *(unsigned int *)value; 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() them, e.g. for mariadb_stmt_execute_direct()
*/ */
if ((stmt->state < MYSQL_STMT_PREPARED || stmt->state >= MYSQL_STMT_EXECUTED) && 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); SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
return(1); 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) { else if (stmt->state < MYSQL_STMT_PREPARED) {
SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0); 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; MYSQL *mysql= stmt->mysql;
int rc= 1; int rc= 1;
my_bool is_multi= 0;
if (!stmt->mysql) 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 */ /* check if we have to clear results */
if (stmt->state > MYSQL_STMT_INITTED) 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: /* We need to semi-close the prepared statement:
reset stmt and free all buffers and close the statement reset stmt and free all buffers and close the statement
on server side. Statment handle will get a new stmt_id */ 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)) if (mysql_stmt_internal_reset(stmt, 1))
goto fail; 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)) if (mysql->methods->db_command(mysql, COM_STMT_PREPARE, query, length, 1, stmt))
goto fail; 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) if (mysql->net.extension->multi_status > COM_MULTI_OFF)
return 0; return 0;
@@ -1414,12 +1423,21 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
} }
if (stmt->param_count) if (stmt->param_count)
{ {
if (!(stmt->params= (MYSQL_BIND *)ma_alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND)))) if (stmt->prebind_params)
{ {
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); if (stmt->prebind_params != stmt->param_count)
goto fail; {
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));
} }
memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
} }
/* allocated bind buffer for result */ /* allocated bind buffer for result */
if (stmt->field_count) if (stmt->field_count)
@@ -2087,12 +2105,14 @@ int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
{ {
int rc; int rc;
/* avoid sending close + prepare in 2 packets */
if ((rc= mysql_stmt_prepare(stmt, stmt_str, length))) if ((rc= mysql_stmt_prepare(stmt, stmt_str, length)))
return rc; return rc;
return mysql_stmt_execute(stmt); 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); SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
goto fail; goto fail;

View File

@@ -19,6 +19,8 @@
#define TEST_ARRAY_SIZE 1024 #define TEST_ARRAY_SIZE 1024
static my_bool bulk_enabled= 0;
char *rand_str(size_t length) { char *rand_str(size_t length) {
const char charset[] = "0123456789" const char charset[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
@@ -32,6 +34,14 @@ char *rand_str(size_t length) {
return p; 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) static int bulk1(MYSQL *mysql)
{ {
MYSQL_STMT *stmt= mysql_stmt_init(mysql); MYSQL_STMT *stmt= mysql_stmt_init(mysql);
@@ -47,6 +57,9 @@ static int bulk1(MYSQL *mysql)
MYSQL_ROW row; MYSQL_ROW row;
unsigned int intval; unsigned int intval;
if (!bulk_enabled)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk1"); rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk1");
check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
@@ -133,6 +146,9 @@ static int bulk2(MYSQL *mysql)
unsigned int array_size=1024; unsigned int array_size=1024;
char indicator[1024]; char indicator[1024];
long lval[1024]; long lval[1024];
if (!bulk_enabled)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk2"); rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk2");
check_mysql_rc(rc, mysql); check_mysql_rc(rc, mysql);
@@ -187,6 +203,8 @@ static int bulk3(MYSQL *mysql)
int array_size= 3; int array_size= 3;
ulong length= -1; ulong length= -1;
if (!bulk_enabled)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk3"); rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk3");
check_mysql_rc(rc,mysql); check_mysql_rc(rc,mysql);
rc= mysql_query(mysql, "CREATE TABLE bulk3 (name varchar(20), row int)"); 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[] = { struct my_tests_st my_tests[] = {
{"check_bulk", check_bulk, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bulk1", bulk1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk1", bulk1, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bulk2", bulk2, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk2", bulk2, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"bulk3", bulk3, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk3", bulk3, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},

View File

@@ -100,7 +100,66 @@ static int execute_direct_example(MYSQL *mysql)
return OK; 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, &param_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[] = { 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", execute_direct, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"execute_direct_example", execute_direct_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"execute_direct_example", execute_direct_example, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL} {NULL, NULL, 0, 0, NULL, NULL}