1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

First implementation of mariadb_stmt_execute_direct

This commit is contained in:
Georg Richter
2016-01-28 16:58:30 +01:00
parent 25e610c965
commit 8845fcb7ce
11 changed files with 392 additions and 125 deletions

View File

@@ -253,3 +253,4 @@ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt);
unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt);
int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt);
my_bool STDCALL mysql_stmt_more_results(MYSQL_STMT *stmt);
int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt, const char *stmt_str, size_t length);

View File

@@ -165,6 +165,12 @@ extern unsigned int mariadb_deinitialize_ssl;
MEM_ROOT alloc;
} 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,
@@ -752,6 +758,7 @@ struct st_mariadb_api {
unsigned int (STDCALL *mysql_stmt_field_count)(MYSQL_STMT *stmt);
int (STDCALL *mysql_stmt_next_result)(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);
};
/* these methods can be overwritten by db plugins */

View File

@@ -129,7 +129,7 @@ enum enum_server_command
#define REFRESH_READ_LOCK 16384 /* Lock tables for read */
#define REFRESH_FAST 32768 /* Intern flag */
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
#define CLIENT_MYSQL 1
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
#define CLIENT_LONG_FLAG 4 /* Get all column flags */
#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */
@@ -157,14 +157,14 @@ enum enum_server_command
/* MariaDB specific capabilities */
#define MARIADB_CLIENT_FLAGS 0xFFFFFFFF00000000ULL
#define MARIADB_CLIENT_COM_MULTI 1
#define MARIADB_CLIENT_PROGRESS (1ULL << 32)
#define MARIADB_CLIENT_EXTENDED_FLAGS (1ULL << 63)
#define MARIADB_CLIENT_COM_MULTI (1ULL << 33)
//#define MARIADB_CLIENT_EXTENDED_FLAGS (1ULL << 63)
#define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\
MARIADB_CLIENT_EXTENDED_FLAGS)
MARIADB_CLIENT_COM_MULTI)
#define CLIENT_SUPPORTED_FLAGS (CLIENT_LONG_PASSWORD |\
#define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\
CLIENT_FOUND_ROWS |\
CLIENT_LONG_FLAG |\
CLIENT_CONNECT_WITH_DB |\
@@ -188,7 +188,7 @@ enum enum_server_command
CLIENT_PLUGIN_AUTH |\
CLIENT_CONNECT_ATTRS)
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | \
#define CLIENT_CAPABILITIES (CLIENT_MYSQL | \
CLIENT_LONG_FLAG |\
CLIENT_TRANSACTIONS |\
CLIENT_SECURE_CONNECTION |\

View File

@@ -35,6 +35,7 @@ SET(EXPORT_SYMBOLS
mariadb_dyncol_val_long
mariadb_dyncol_val_str
mariadb_get_charset_by_name
mariadb_stmt_execute_direct
mariadb_get_charset_by_nr
mariadb_get_info
mariadb_get_infov

View File

@@ -361,16 +361,16 @@ mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
{
NET *net= &mysql->net;
int result= -1;
my_bool is_multi= 0;
enum mariadb_com_multi multi= MARIADB_COM_MULTI_END;
if (OPT_HAS_EXT_VAL(mysql, multi_command))
is_multi= mysql->options.extension->multi_command;
multi= mysql->options.extension->multi_command;
DBUG_ENTER("mthd_my_send_cmd");
DBUG_PRINT("info", ("server_command: %d packet_size: %u", command, length));
if (is_multi)
if (multi == MARIADB_COM_MULTI_BEGIN)
{
/* todo: error handling */
DBUG_RETURN(net_add_multi_command(&mysql->net, command, arg, length));
@@ -1546,7 +1546,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
if (strncmp(end, MA_RPL_VERSION_HACK, sizeof(MA_RPL_VERSION_HACK) - 1) == 0)
{
if (!(mysql->server_version= my_strdup(end + sizeof(MA_RPL_VERSION_HACK), 0)))
if (!(mysql->server_version= my_strdup(end + sizeof(MA_RPL_VERSION_HACK) - 1, 0)))
{
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
goto error;
@@ -1586,11 +1586,11 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
{
mysql->server_language= uint1korr(end + 2);
mysql->server_status= uint2korr(end + 3);
mysql->server_capabilities|= uint2korr(end + 5) << 16;
mysql->server_capabilities|= (unsigned int)(uint2korr(end + 5) << 16);
pkt_scramble_len= uint1korr(end + 7);
/* check if MariaD2B specific capabilities are available */
if (is_maria && !(mysql->server_capabilities & CLIENT_LONG_PASSWORD))
if (is_maria && !(mysql->server_capabilities & CLIENT_MYSQL))
{
mysql->server_capabilities|= (ulonglong) uint4korr(end + 14) << 32;
}
@@ -2630,6 +2630,24 @@ void ma_hash_free(void *p)
my_free(p);
}
int mariadb_flush_multi_command(MYSQL *mysql)
{
int rc;
size_t length= mysql->net.mbuff_pos - mysql->net.mbuff;
rc= simple_command(mysql, COM_MULTI, mysql->net.mbuff,
length, 1, 0);
/* reset multi_buff */
mysql->net.mbuff_pos= mysql->net.mbuff;
if (!rc)
if (mysql->net.mbuff && length > 3 &&
(mysql->net.mbuff[3] == COM_STMT_PREPARE || mysql->net.mbuff[3] == COM_STMT_EXECUTE))
return rc;
else
return mysql->methods->db_read_query_result(mysql);
return rc;
}
int STDCALL
mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
@@ -2975,8 +2993,33 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
break;
case MARIADB_OPT_COM_MULTI:
if (&mysql->net.pvio &&
(mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS))
!(mysql->server_capabilities & CLIENT_MYSQL))
{
enum mariadb_com_multi type= *(enum mariadb_com_multi *)arg1;
switch (type)
{
case MARIADB_COM_MULTI_BEGIN:
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, multi_command, type);
break;
case MARIADB_COM_MULTI_CANCEL:
if (!mysql->options.extension ||
mysql->options.extension->multi_command != MARIADB_COM_MULTI_BEGIN)
DBUG_RETURN(-1);
/* reset multi_buff */
mysql->net.mbuff_pos= mysql->net.mbuff;
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, multi_command, MARIADB_COM_MULTI_END);
break;
case MARIADB_COM_MULTI_END:
if (!mysql->options.extension ||
mysql->options.extension->multi_command != MARIADB_COM_MULTI_BEGIN)
DBUG_RETURN(-1);
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, multi_command, MARIADB_COM_MULTI_END);
if (mariadb_flush_multi_command(mysql))
DBUG_RETURN(-1);
break;
default:
DBUG_RETURN(-1);
}
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, multi_command, *(my_bool *)arg1);
}
else
@@ -3071,6 +3114,15 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...)
case MYSQL_OPT_NONBLOCK:
*((my_bool *)arg)= test(mysql->options.extension && mysql->options.extension->async_context);
break;
case MARIADB_OPT_COM_MULTI:
if (!(mysql->server_capabilities & CLIENT_MYSQL))
{
*((enum mariadb_com_multi *)arg)= mysql->options.extension ?
mysql->options.extension->multi_command : 0;
}
else
DBUG_RETURN(-1);
break;
case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
*((my_bool *)arg)= test(mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT);
break;
@@ -3575,28 +3627,6 @@ static my_socket mariadb_get_socket(MYSQL *mysql)
return sock;
}
int mariadb_flush_multi_command(MYSQL *mysql)
{
int is_multi= 0;
int rc;
/* turn off multi_command option, so simple_command will
* stop to add commands to the queue and send packet
* to the server */
mysql_options(mysql, MARIADB_OPT_COM_MULTI, &is_multi);
rc= simple_command(mysql, COM_MULTI, mysql->net.mbuff,
mysql->net.mbuff_pos - mysql->net.mbuff,
1, 0);
/* reset multi_buff */
mysql->net.mbuff_pos= mysql->net.mbuff;
if (!rc)
rc= mysql->methods->db_read_query_result(mysql);
return rc;
}
my_socket STDCALL
mysql_get_socket(MYSQL *mysql)
{
@@ -3951,7 +3981,8 @@ struct st_mariadb_api MARIADB_API=
mysql_stmt_insert_id,
mysql_stmt_field_count,
mysql_stmt_next_result,
mysql_stmt_more_results
mysql_stmt_more_results,
mariadb_stmt_execute_direct
};
/*

View File

@@ -113,7 +113,7 @@ my_bool mthd_supported_buffer_type(enum enum_field_types type)
}
static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags);
static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close);
static int stmt_unbuffered_eof(MYSQL_STMT *stmt, uchar **row)
{
return MYSQL_NO_DATA;
@@ -281,7 +281,7 @@ static int stmt_cursor_fetch(MYSQL_STMT *stmt, uchar **row)
int4store(buf, stmt->stmt_id);
int4store(buf + STMT_ID_LENGTH, stmt->prefetch_rows);
if (simple_command(stmt->mysql, COM_STMT_FETCH, (char *)buf, sizeof(buf), 1, stmt))
if (stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_FETCH, (char *)buf, sizeof(buf), 1, stmt))
DBUG_RETURN(1);
/* free previously allocated buffer */
@@ -774,9 +774,40 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type a
my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
{
MYSQL *mysql= stmt->mysql;
DBUG_ENTER("mysql_stmt_bind_param");
if (stmt->state < MYSQL_STMT_PREPARED) {
if (!mysql)
{
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
/* for mariadb_stmt_execute_direct we need to bind parameters in advance:
client has to pass a bind array, where last parameter needs to be set
to buffer type MAX_NO_FIELD_TYPES */
if (stmt->state < MYSQL_STMT_PREPARED &&
!(mysql->server_capabilities & CLIENT_MYSQL))
{
if (!stmt->params)
{
int param_count;
for(param_count= 0;
bind[param_count].buffer_type != MAX_NO_FIELD_TYPES;
param_count++);
stmt->param_count= param_count;
if (stmt->param_count)
{
if (!(stmt->params= (MYSQL_BIND *)alloc_root(&stmt->mem_root, stmt->param_count * sizeof(MYSQL_BIND))))
{
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
}
memset(stmt->params, '\0', stmt->param_count * sizeof(MYSQL_BIND));
}
}
else if (stmt->state < MYSQL_STMT_PREPARED) {
SET_CLIENT_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
@@ -947,7 +978,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_RETURN(0);
}
my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
static my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
{
char stmt_id[STMT_ID_LENGTH];
MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
@@ -974,7 +1005,8 @@ my_bool net_stmt_close(MYSQL_STMT *stmt, my_bool remove)
if (stmt->state > MYSQL_STMT_INITTED)
{
int4store(stmt_id, stmt->stmt_id);
if (simple_command(stmt->mysql,COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
if (stmt->mysql->methods->db_command(stmt->mysql,COM_STMT_CLOSE, stmt_id,
sizeof(stmt_id), 1, stmt))
{
SET_CLIENT_STMT_ERROR(stmt, stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate, stmt->mysql->net.last_error);
return 1;
@@ -989,7 +1021,8 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
DBUG_ENTER("mysql_stmt_close");
if (stmt && stmt->mysql && stmt->mysql->net.pvio)
mysql_stmt_reset(stmt);
mysql_stmt_internal_reset(stmt, 1);
net_stmt_close(stmt, 1);
my_free(stmt->extension);
@@ -1142,6 +1175,7 @@ MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql)
/* fill mysql's stmt list */
stmt->list.data= stmt;
stmt->mysql= mysql;
stmt->stmt_id= -1;
mysql->stmts= list_add(mysql->stmts, &stmt->list);
@@ -1226,9 +1260,7 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
MYSQL *mysql= stmt->mysql;
int rc= 1;
DBUG_ENTER("mysql_stmt_prepare");
if (length == -1)
length= strlen(query);
enum mariadb_com_multi multi= MARIADB_COM_MULTI_END;
if (!stmt->mysql)
{
@@ -1236,6 +1268,11 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
DBUG_RETURN(1);
}
if (length == -1)
length= strlen(query);
mysql_get_optionv(mysql, MARIADB_OPT_COM_MULTI, &multi);
/* clear flags */
CLEAR_CLIENT_STMT_ERROR(stmt);
CLEAR_CLIENT_ERROR(stmt->mysql);
@@ -1259,14 +1296,18 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, size_t lengt
stmt->field_count= 0;
int4store(stmt_id, stmt->stmt_id);
if (simple_command(mysql, COM_STMT_CLOSE, stmt_id, sizeof(stmt_id), 1, stmt))
if (mysql->methods->db_command(mysql, COM_STMT_CLOSE, stmt_id,
sizeof(stmt_id), 1, stmt))
goto fail;
}
if (simple_command(mysql, COM_STMT_PREPARE, query, length, 1, stmt))
if (mysql->methods->db_command(mysql, COM_STMT_PREPARE, query, length, 1, stmt))
goto fail;
if (stmt->mysql->methods->db_read_prepare_response &&
stmt->mysql->methods->db_read_prepare_response(stmt))
if (multi == MARIADB_COM_MULTI_BEGIN)
return 0;
if (mysql->methods->db_read_prepare_response &&
mysql->methods->db_read_prepare_response(stmt))
goto fail;
/* metadata not supported yet */
@@ -1346,7 +1387,8 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
int4store(buff, stmt->stmt_id);
int4store(buff + STMT_ID_LENGTH, (int)~0);
if (simple_command(stmt->mysql, COM_STMT_FETCH, buff, sizeof(buff), 1, stmt))
if (stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_FETCH,
buff, sizeof(buff), 1, stmt))
DBUG_RETURN(1);
/* todo: cursor */
}
@@ -1442,63 +1484,17 @@ static int madb_alloc_stmt_fields(MYSQL_STMT *stmt)
DBUG_RETURN(0);
}
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
int stmt_read_execute_response(MYSQL_STMT *stmt)
{
MYSQL *mysql= stmt->mysql;
char *request;
int ret;
size_t request_len= 0;
DBUG_ENTER("stmt_read_execute_response");
DBUG_ENTER("mysql_stmt_execute");
if (!stmt->mysql)
{
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
if (!mysql)
DBUG_RETURN(1);
}
if (stmt->state < MYSQL_STMT_PREPARED)
{
SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
if (stmt->param_count && !stmt->bind_param_done)
{
SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
{
stmt->default_rset_handler = _mysql_stmt_use_result;
stmt->default_rset_handler(stmt);
}
if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
{
mysql->methods->db_stmt_flush_unbuffered(stmt);
stmt->state= MYSQL_STMT_PREPARED;
stmt->mysql->status= MYSQL_STATUS_READY;
}
/* clear data, in case mysql_stmt_store_result was called */
if (stmt->result.data)
{
free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
stmt->result_cursor= stmt->result.data= 0;
stmt->result.rows= 0;
}
request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
DBUG_PRINT("info",("request_len=%ld", request_len));
ret= test(simple_command(mysql, COM_STMT_EXECUTE, request, request_len, 1, stmt) ||
(mysql && mysql->methods->db_read_stmt_result && mysql->methods->db_read_stmt_result(mysql)));
if (request)
my_free(request);
int ret= test((mysql->methods->db_read_stmt_result &&
mysql->methods->db_read_stmt_result(mysql)));
/* if a reconnect occured, our connection handle is invalid */
if (!stmt->mysql)
DBUG_RETURN(1);
@@ -1615,6 +1611,78 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
DBUG_RETURN(0);
}
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
{
MYSQL *mysql= stmt->mysql;
char *request;
int ret;
size_t request_len= 0;
enum mariadb_com_multi multi= MARIADB_COM_MULTI_END;
DBUG_ENTER("mysql_stmt_execute");
if (!stmt->mysql)
{
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
mysql_get_optionv(mysql, MARIADB_OPT_COM_MULTI, &multi);
if (stmt->state < MYSQL_STMT_PREPARED)
{
SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
SET_CLIENT_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
if (stmt->param_count && !stmt->bind_param_done)
{
SET_CLIENT_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, SQLSTATE_UNKNOWN, 0);
DBUG_RETURN(1);
}
if (stmt->state == MYSQL_STMT_WAITING_USE_OR_STORE)
{
stmt->default_rset_handler = _mysql_stmt_use_result;
stmt->default_rset_handler(stmt);
}
if (stmt->state > MYSQL_STMT_WAITING_USE_OR_STORE && stmt->state < MYSQL_STMT_FETCH_DONE && !stmt->result.data)
{
mysql->methods->db_stmt_flush_unbuffered(stmt);
stmt->state= MYSQL_STMT_PREPARED;
stmt->mysql->status= MYSQL_STATUS_READY;
}
/* clear data, in case mysql_stmt_store_result was called */
if (stmt->result.data)
{
free_root(&stmt->result.alloc, MYF(MY_KEEP_PREALLOC));
stmt->result_cursor= stmt->result.data= 0;
stmt->result.rows= 0;
}
request= (char *)mysql_stmt_execute_generate_request(stmt, &request_len);
DBUG_PRINT("info",("request_len=%ld", request_len));
ret= stmt->mysql->methods->db_command(mysql, COM_STMT_EXECUTE, request,
request_len, 1, stmt);
if (request)
my_free(request);
if (ret)
{
SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate,
mysql->net.last_error);
DBUG_RETURN(1);
}
if (multi == MARIADB_COM_MULTI_BEGIN)
DBUG_RETURN(0);
DBUG_RETURN(stmt_read_execute_response(stmt));
}
static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
{
MYSQL *mysql= stmt->mysql;
@@ -1670,11 +1738,13 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
if (flags & MADB_RESET_SERVER)
{
/* reset statement on server side */
if (stmt->mysql && stmt->mysql->status == MYSQL_STATUS_READY)
if (stmt->mysql && stmt->mysql->status == MYSQL_STATUS_READY &&
stmt->mysql->net.pvio)
{
unsigned char cmd_buf[STMT_ID_LENGTH];
int4store(cmd_buf, stmt->stmt_id);
if ((ret= simple_command(mysql,COM_STMT_RESET, (char *)cmd_buf, sizeof(cmd_buf), 0, stmt)))
if ((ret= stmt->mysql->methods->db_command(mysql,COM_STMT_RESET, (char *)cmd_buf,
sizeof(cmd_buf), 0, stmt)))
{
SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate,
mysql->net.last_error);
@@ -1698,13 +1768,13 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags)
DBUG_RETURN(ret);
}
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close)
{
MYSQL *mysql= stmt->mysql;
my_bool ret= 1;
unsigned int flags= MADB_RESET_LONGDATA | MADB_RESET_BUFFER | MADB_RESET_ERROR;
DBUG_ENTER("mysql_stmt_reset");
DBUG_ENTER("mysql_stmt_internal_reset");
if (!mysql)
{
@@ -1739,6 +1809,8 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
stmt->mysql->status= MYSQL_STATUS_READY;
}
}
if (!stmt->execute_count)
if (!is_close)
ret= madb_reset_stmt(stmt, MADB_RESET_SERVER);
}
stmt->state= MYSQL_STMT_PREPARED;
@@ -1770,7 +1842,13 @@ MYSQL_RES * STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt)
res->eof= 1;
res->fields= stmt->fields;
res->field_count= stmt->field_count;
DBUG_RETURN(res);}
DBUG_RETURN(res);
}
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
{
return mysql_stmt_internal_reset(stmt, 0);
}
const char * STDCALL mysql_stmt_sqlstate(MYSQL_STMT *stmt)
{
@@ -1828,7 +1906,8 @@ my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
int2store(cmd_buff + STMT_ID_LENGTH, param_number);
memcpy(cmd_buff + STMT_ID_LENGTH + 2, data, length);
stmt->params[param_number].long_data_used= 1;
ret= simple_command(stmt->mysql, COM_STMT_SEND_LONG_DATA, (char *)cmd_buff, packet_len, 1, stmt);
ret= stmt->mysql->methods->db_command(stmt->mysql, COM_STMT_SEND_LONG_DATA,
(char *)cmd_buff, packet_len, 1, stmt);
my_free(cmd_buff);
DBUG_RETURN(ret);
}
@@ -1915,3 +1994,75 @@ int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
DBUG_RETURN(rc);
}
int STDCALL mariadb_stmt_execute_direct(MYSQL_STMT *stmt,
const char *stmt_str,
size_t length)
{
enum mariadb_com_multi multi= MARIADB_COM_MULTI_BEGIN;
MYSQL *mysql= stmt->mysql;
if (!mysql)
{
SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
goto fail;
}
if (mysql_optionsv(mysql, MARIADB_OPT_COM_MULTI, &multi))
goto fail;
if (length == -1)
length= strlen(stmt_str);
if (mysql_stmt_prepare(stmt, stmt_str, length))
goto fail;
stmt->state= MYSQL_STMT_PREPARED;
if (mysql_stmt_execute(stmt))
goto fail;
multi= MARIADB_COM_MULTI_END;
if (mysql_optionsv(mysql, MARIADB_OPT_COM_MULTI, &multi))
goto fail;
/* read prepare response */
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;
}
/* allocated bind buffer for result */
if (stmt->field_count)
{
MEM_ROOT *fields_alloc_root= &((MADB_STMT_EXTENSION *)stmt->extension)->fields_alloc_root;
if (!(stmt->bind= (MYSQL_BIND *)alloc_root(fields_alloc_root, stmt->field_count * sizeof(MYSQL_BIND))))
{
SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
goto fail;
}
}
stmt->state = MYSQL_STMT_PREPARED;
/* read execute response packet */
return stmt_read_execute_response(stmt);
fail:
stmt->state= MYSQL_STMT_INITTED;
SET_CLIENT_STMT_ERROR(stmt, mysql->net.last_errno, mysql->net.sqlstate,
mysql->net.last_error);
return 1;
}

View File

@@ -169,12 +169,6 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
mysql->client_flag|= CLIENT_MULTI_RESULTS;
/* if server supports extended MariaDB extended protocol, we will unset
CLIENT_LONG_PASSWORD and send extended client capabilities in last
four of 23 unused bytes */
if (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
mysql->client_flag &= ~CLIENT_LONG_PASSWORD;
#if defined(HAVE_SSL) && !defined(EMBEDDED_LIBRARY)
if (mysql->options.ssl_key || mysql->options.ssl_cert ||
mysql->options.ssl_ca || mysql->options.ssl_capath ||
@@ -218,7 +212,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
int4store(buff+4, net->max_packet_size);
buff[8]= (char) mysql->charset->nr;
bzero(buff + 9, 32-9);
if (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
if (!(mysql->server_capabilities & CLIENT_MYSQL))
{
mysql->client_flag |= MARIADB_CLIENT_SUPPORTED_FLAGS;
int4store(buff + 28, mysql->client_flag >> 32);

View File

@@ -22,7 +22,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
ADD_DEFINITIONS(-DLIBMARIADB)
SET(API_TESTS "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
"sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol" "features-10_2")
"sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol" "features-10_2" )
#exclude following tests from ctests, since we need to run them maually with different credentials
SET(MANUAL_TESTS "t_aurora")

View File

@@ -3,26 +3,30 @@
#include "my_test.h"
my_bool have_com_multi= 1;
static int com_multi_1(MYSQL *mysql)
{
int rc;
MYSQL_RES *res;
my_bool is_multi= 1;
enum mariadb_com_multi status;
/* TEST a simple query before COM_MULTI */
rc= mysql_query(mysql, "select 1");
check_mysql_rc(rc, mysql);
FAIL_UNLESS(res, "1 simple query no result");
res= mysql_store_result(mysql);
FAIL_UNLESS(res, "1 simple query no result");
mysql_free_result(res);
/* TEST COM_MULTI */
if (mysql_options(mysql, MARIADB_OPT_COM_MULTI, &is_multi))
status= MARIADB_COM_MULTI_BEGIN;
if (mysql_options(mysql, MARIADB_OPT_COM_MULTI, &status))
{
diag("COM_MULT not supported");
have_com_multi= 0;
return SKIP;
}
@@ -30,7 +34,8 @@ static int com_multi_1(MYSQL *mysql)
rc= mysql_query(mysql, "select 2");
rc= mariadb_flush_multi_command(mysql);
status= MARIADB_COM_MULTI_END;
rc= mysql_options(mysql, MARIADB_OPT_COM_MULTI, &status);
check_mysql_rc(rc, mysql);
/* 1 SELECT result */
res= mysql_store_result(mysql);
@@ -48,10 +53,6 @@ static int com_multi_1(MYSQL *mysql)
strcmp(res->fields[0].name, "2") == 0,
"1 of 2 simple query in batch wrong result");
mysql_free_result(res);
/* WHOLE batch result (OK) */
rc= mysql_next_result(mysql);
res= mysql_store_result(mysql);
FAIL_UNLESS(res == NULL, "rows instead of batch OK");
rc= mysql_next_result(mysql);
FAIL_UNLESS(rc == -1, "more then 2 results");
@@ -69,8 +70,86 @@ static int com_multi_1(MYSQL *mysql)
return OK;
}
static int com_multi_ps1(MYSQL *mysql)
{
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
int rc;
if (!have_com_multi)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b varchar(20))");
rc= mysql_stmt_prepare(stmt, "INSERT INTO t1 values (2, 'execute_direct')", -1);
check_stmt_rc(rc, stmt);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
diag("affected_rows: %d", mysql_stmt_affected_rows(stmt));
diag("stmt_id: %d", stmt->stmt_id);
mysql_stmt_close(stmt);
stmt= mysql_stmt_init(mysql);
rc= mariadb_stmt_execute_direct(stmt, "INSERT INTO t1 values (2, 'execute_direct')", -1);
check_stmt_rc(rc, stmt);
FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "expected affected_rows= 1");
FAIL_IF(stmt->stmt_id < 1, "expected statement id > 0");
rc= mysql_stmt_close(stmt);
check_mysql_rc(rc, mysql);
return OK;
}
static int com_multi_ps2(MYSQL *mysql)
{
MYSQL_STMT *stmt;
MYSQL_BIND bind[3];
int intval= 3, rc;
int i;
char *varval= "com_multi_ps2";
if (!have_com_multi)
return SKIP;
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a int, b varchar(20))");
memset(&bind, 0, sizeof(MYSQL_BIND) * 3);
bind[0].buffer_type= MYSQL_TYPE_SHORT;
bind[0].buffer= &intval;
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= varval;
bind[1].buffer_length= strlen(varval);
bind[2].buffer_type= MAX_NO_FIELD_TYPES;
for (i=0; i < 2; i++)
{
stmt= mysql_stmt_init(mysql);
rc= mysql_stmt_bind_param(stmt, bind);
check_stmt_rc(rc, stmt);
rc= mariadb_stmt_execute_direct(stmt, "INSERT INTO t1 VALUES (1,'foo')", -1);
check_stmt_rc(rc, stmt);
FAIL_IF(mysql_stmt_affected_rows(stmt) != 1, "expected affected_rows= 1");
FAIL_IF(stmt->stmt_id < 1, "expected statement id > 0");
rc= mysql_stmt_close(stmt);
check_mysql_rc(rc, mysql);
}
return OK;
}
struct my_tests_st my_tests[] = {
{"com_multi_1", com_multi_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"com_multi_ps1", com_multi_ps1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{"com_multi_ps2", com_multi_ps2, TEST_CONNECTION_NEW, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};

View File

@@ -189,6 +189,8 @@ int do_verify_prepare_field(MYSQL_RES *result,
FAIL_UNLESS(strcmp(field->table, table) == 0, "field->table differs");
if (org_table)
FAIL_UNLESS(strcmp(field->org_table, org_table) == 0, "field->org_table differs");
if (strcmp(field->db,db))
diag("%s / %s", field->db, db);
FAIL_UNLESS(strcmp(field->db, db) == 0, "field->db differs");
/*
Character set should be taken into account for multibyte encodings, such

View File

@@ -830,6 +830,7 @@ static int test_prepare_alter(MYSQL *mysql)
FAIL_IF(!(mysql_real_connect(mysql_new, hostname, username, password,
schema, port, socketname, 0)), "mysql_real_connect failed");
rc= mysql_query(mysql_new, "ALTER TABLE test_prep_alter change id id_new varchar(20)");
diag("Error: %d %s", mysql_errno(mysql_new), mysql_error(mysql_new));
check_mysql_rc(rc, mysql_new);
mysql_close(mysql_new);