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
Initial implementation for COM_MULTI
This commit is contained in:
@@ -19,6 +19,13 @@ IF(COMMAND CMAKE_POLICY)
|
||||
CMAKE_POLICY(SET CMP0003 NEW)
|
||||
ENDIF()
|
||||
|
||||
#Allow access to non existing targets
|
||||
IF(CMAKE_VERSION VERSION_GREATER "2.9.9")
|
||||
CMAKE_POLICY(SET CMP0026 OLD)
|
||||
CMAKE_POLICY(SET CMP0042 OLD)
|
||||
CMAKE_POLICY(SET CMP0045 OLD)
|
||||
ENDIF()
|
||||
|
||||
SET(MARIADB_CONNECTOR_C_COPYRIGHT "2013-2015 MariaDB Corporation Ab")
|
||||
|
||||
### Options ###
|
||||
|
@@ -84,6 +84,7 @@ extern const char *mariadb_client_errors[]; /* Error messages */
|
||||
|
||||
#define CR_EVENT_CREATE_FAILED 5000
|
||||
#define CR_BIND_ADDR_FAILED 5001
|
||||
#define CR_FUNCTION_NOT_SUPPORTED 5002
|
||||
|
||||
#define SQLSTATE_UNKNOWN "HY000"
|
||||
|
||||
|
@@ -52,6 +52,8 @@ struct st_mysql_options_extension {
|
||||
char *ssl_fp; /* finger print of server certificate */
|
||||
char *ssl_fp_list; /* white list of finger prints */
|
||||
char *ssl_pw; /* password for encrypted certificates */
|
||||
my_bool multi_command; /* indicates if client wants to send multiple
|
||||
commands in one packet */
|
||||
};
|
||||
|
||||
#define OPT_HAS_EXT_VAL(a,key) \
|
||||
|
@@ -214,6 +214,7 @@ extern unsigned int mariadb_deinitialize_ssl;
|
||||
MARIADB_OPT_SSL_FP, /* single finger print for server certificate verification */
|
||||
MARIADB_OPT_SSL_FP_LIST, /* finger print white list for server certificate verification */
|
||||
MARIADB_OPT_SSL_PASSWORD, /* password for encrypted certificates */
|
||||
MARIADB_OPT_COM_MULTI,
|
||||
MARIADB_OPT_CONNECTION_READ_ONLY
|
||||
};
|
||||
|
||||
|
@@ -87,6 +87,7 @@ enum enum_server_command
|
||||
COM_SET_OPTION = 27,
|
||||
COM_STMT_FETCH = 28,
|
||||
COM_DAEMON,
|
||||
COM_MULTI = 255,
|
||||
COM_END
|
||||
};
|
||||
|
||||
@@ -156,11 +157,12 @@ 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_PROTOCOL (1ULL << 63)
|
||||
#define MARIADB_CLIENT_EXTENDED_FLAGS (1ULL << 63)
|
||||
|
||||
#define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\
|
||||
MARIADB_CLIENT_EXTENDED_PROTOCOL)
|
||||
MARIADB_CLIENT_EXTENDED_FLAGS)
|
||||
|
||||
#define CLIENT_SUPPORTED_FLAGS (CLIENT_LONG_PASSWORD |\
|
||||
CLIENT_FOUND_ROWS |\
|
||||
@@ -245,6 +247,7 @@ typedef struct st_net {
|
||||
MARIADB_PVIO *pvio;
|
||||
unsigned char *buff;
|
||||
unsigned char *buff_end,*write_pos,*read_pos;
|
||||
unsigned char *mbuff, *mbuff_end, *mbuff_pos;
|
||||
my_socket fd; /* For Perl DBI/dbd */
|
||||
unsigned long remain_in_buf,length;
|
||||
unsigned long buf_length, where_b;
|
||||
|
@@ -34,6 +34,7 @@ SET(EXPORT_SYMBOLS
|
||||
mariadb_dyncol_val_double
|
||||
mariadb_dyncol_val_long
|
||||
mariadb_dyncol_val_str
|
||||
mariadb_flush_multi_command
|
||||
myodbc_remove_escape
|
||||
mysql_affected_rows
|
||||
mysql_autocommit
|
||||
|
@@ -149,6 +149,7 @@ const char *mariadb_client_errors[] =
|
||||
{
|
||||
/* 5000 */ "Creating an event failed (Errorcode: %d)",
|
||||
/* 5001 */ "Bind to local interface '-.%64s' failed (Errorcode: %d)",
|
||||
/* 5002 */ "Server doesn't support function '%s'",
|
||||
""
|
||||
};
|
||||
|
||||
|
@@ -88,6 +88,8 @@ extern const CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
|
||||
extern const CHARSET_INFO * mysql_find_charset_name(const char * const name);
|
||||
extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
|
||||
const char *data_plugin, const char *db);
|
||||
extern int net_add_multi_command(NET *net, uchar command, const uchar *packet,
|
||||
size_t length);
|
||||
|
||||
extern LIST *pvio_callback;
|
||||
|
||||
@@ -350,11 +352,21 @@ 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;
|
||||
|
||||
DBUG_ENTER("mthd_my_send_command");
|
||||
if (OPT_HAS_EXT_VAL(mysql, multi_command))
|
||||
is_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)
|
||||
{
|
||||
/* todo: error handling */
|
||||
DBUG_RETURN(net_add_multi_command(&mysql->net, command, arg, length));
|
||||
}
|
||||
|
||||
if (mysql->net.conn_hdlr && mysql->net.conn_hdlr->data)
|
||||
{
|
||||
result= mysql->net.conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg);
|
||||
@@ -661,7 +673,7 @@ enum option_val
|
||||
|
||||
#define OPT_SET_EXTENDED_VALUE_INT(OPTS, KEY, VAL) \
|
||||
CHECK_OPT_EXTENSION_SET(OPTS) \
|
||||
+ (OPTS)->extension->KEY= (VAL)
|
||||
(OPTS)->extension->KEY= (VAL)
|
||||
|
||||
|
||||
static TYPELIB option_types={array_elements(default_options)-1,
|
||||
@@ -2106,15 +2118,22 @@ mysql_read_query_result(MYSQL *mysql)
|
||||
int STDCALL
|
||||
mysql_real_query(MYSQL *mysql, const char *query, size_t length)
|
||||
{
|
||||
my_bool is_multi= 0;
|
||||
|
||||
DBUG_ENTER("mysql_real_query");
|
||||
DBUG_PRINT("enter",("handle: %lx",mysql));
|
||||
DBUG_PRINT("query",("Query = \"%.255s\" length=%u",query, length));
|
||||
|
||||
if (OPT_HAS_EXT_VAL(mysql, multi_command))
|
||||
is_multi= mysql->options.extension->multi_command;
|
||||
|
||||
free_old_query(mysql);
|
||||
|
||||
if (simple_command(mysql, COM_QUERY,query,length,1,0))
|
||||
DBUG_RETURN(-1);
|
||||
if (!is_multi)
|
||||
DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -2891,6 +2910,15 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
|
||||
DBUG_RETURN(mysql->net.conn_hdlr->plugin->options(mysql, MARIADB_OPT_CONNECTION_READ_ONLY, arg1));
|
||||
else
|
||||
return -1;
|
||||
case MARIADB_OPT_COM_MULTI:
|
||||
if (&mysql->net.pvio &&
|
||||
(mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS))
|
||||
{
|
||||
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, multi_command, *(my_bool *)arg1);
|
||||
}
|
||||
else
|
||||
DBUG_RETURN(-1);
|
||||
break;
|
||||
default:
|
||||
va_end(ap);
|
||||
DBUG_RETURN(-1);
|
||||
@@ -3304,6 +3332,24 @@ mysql_get_socket(const MYSQL *mysql)
|
||||
return sock;
|
||||
}
|
||||
|
||||
int STDCALL 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,
|
||||
0, 0);
|
||||
/* reset multi_buff */
|
||||
mysql->net.mbuff_pos= mysql->net.mbuff;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default methods for a connection. These methods are
|
||||
* stored in mysql->methods and can be overwritten by
|
||||
|
@@ -107,7 +107,6 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
|
||||
** can't normally do this the client should have a bigger max-buffer.
|
||||
*/
|
||||
|
||||
#define TEST_BLOCKING 8
|
||||
static int net_write_buff(NET *net,const char *packet, size_t len);
|
||||
|
||||
|
||||
@@ -117,6 +116,10 @@ int my_net_init(NET *net, MARIADB_PVIO* pvio)
|
||||
{
|
||||
if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME | MY_ZEROFILL))))
|
||||
return 1;
|
||||
|
||||
/* We don't allocate memory for multi buffer, since we don't know in advance if the server
|
||||
* supports COM_MULTI comand. It will be allocated on demand in net_add_multi_command */
|
||||
|
||||
max_allowed_packet= net->max_packet_size= MAX(net_buffer_length, max_allowed_packet);
|
||||
net->buff_end=net->buff+(net->max_packet=net_buffer_length);
|
||||
net->pvio = pvio;
|
||||
@@ -141,13 +144,15 @@ int my_net_init(NET *net, MARIADB_PVIO* pvio)
|
||||
|
||||
void net_end(NET *net)
|
||||
{
|
||||
my_free((gptr) net->buff);
|
||||
my_free(net->buff);
|
||||
my_free(net->mbuff);
|
||||
net->buff=0;
|
||||
net->mbuff= 0;
|
||||
}
|
||||
|
||||
/* Realloc the packet buffer */
|
||||
|
||||
static my_bool net_realloc(NET *net, size_t length)
|
||||
static my_bool net_realloc(NET *net, my_bool is_multi, size_t length)
|
||||
{
|
||||
uchar *buff;
|
||||
size_t pkt_length;
|
||||
@@ -166,7 +171,7 @@ static my_bool net_realloc(NET *net, size_t length)
|
||||
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
|
||||
/* reallocate buffer:
|
||||
size= pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE */
|
||||
if (!(buff=(uchar*) my_realloc((char*) net->buff,
|
||||
if (!(buff=(uchar*) my_realloc(is_multi ? net->mbuff : net->buff,
|
||||
pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE,
|
||||
MYF(MY_WME))))
|
||||
{
|
||||
@@ -174,8 +179,16 @@ static my_bool net_realloc(NET *net, size_t length)
|
||||
net->error=1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (!is_multi)
|
||||
{
|
||||
net->buff=net->write_pos=buff;
|
||||
net->buff_end=buff+(net->max_packet=(unsigned long)pkt_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
net->mbuff=net->mbuff_pos=buff;
|
||||
net->mbuff_end=buff+(net->max_packet=(unsigned long)pkt_length);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@@ -186,11 +199,13 @@ void net_clear(NET *net)
|
||||
DBUG_ENTER("net_clear");
|
||||
net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
|
||||
net->write_pos=net->buff;
|
||||
if (net->mbuff)
|
||||
net->mbuff_pos= net->mbuff;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Flush write_buffer if not empty. */
|
||||
/* Flush write_buffer if not empty. */
|
||||
|
||||
int net_flush(NET *net)
|
||||
{
|
||||
@@ -327,6 +342,55 @@ net_write_buff(NET *net,const char *packet, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_add_multi_command(NET *net, uchar command, const uchar *packet,
|
||||
size_t length)
|
||||
{
|
||||
size_t left_length;
|
||||
size_t required_length, current_length;
|
||||
required_length= length + 1 + NET_HEADER_SIZE;
|
||||
|
||||
/* We didn't allocate memory in my_net_init since it was to early to
|
||||
* detect if the server supports COM_MULTI command */
|
||||
if (!net->mbuff)
|
||||
{
|
||||
size_t alloc_size= (required_length + IO_SIZE - 1) & ~(IO_SIZE - 1);
|
||||
if (!(net->mbuff= (char *)my_malloc(alloc_size, MYF(MY_WME))))
|
||||
{
|
||||
net->last_errno=ER_OUT_OF_RESOURCES;
|
||||
net->error=2;
|
||||
net->reading_or_writing=0;
|
||||
return(1);
|
||||
}
|
||||
net->mbuff_pos= net->mbuff;
|
||||
net->mbuff_end= net->mbuff + alloc_size;
|
||||
}
|
||||
|
||||
left_length= net->mbuff_end - net->mbuff_pos;
|
||||
|
||||
/* check if our buffer is large enough */
|
||||
if (left_length < required_length)
|
||||
{
|
||||
current_length= net->mbuff_pos - net->mbuff;
|
||||
if (net_realloc(net, 1, current_length + required_length))
|
||||
goto error;
|
||||
}
|
||||
int3store(net->mbuff_pos, length + 1);
|
||||
net->mbuff_pos+= 3;
|
||||
*net->mbuff_pos= command;
|
||||
net->mbuff_pos++;
|
||||
memcpy(net->mbuff_pos, packet, length);
|
||||
net->mbuff_pos+= length;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (net->mbuff)
|
||||
{
|
||||
my_free(net->mbuff);
|
||||
net->mbuff= net->mbuff_pos= net->mbuff_end= 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read and write using timeouts */
|
||||
|
||||
int
|
||||
@@ -391,7 +455,6 @@ net_real_write(NET *net,const char *packet,size_t len)
|
||||
DBUG_RETURN(((int) (pos != end)));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Read something from server/clinet
|
||||
*****************************************************************************/
|
||||
@@ -460,7 +523,7 @@ my_real_read(NET *net, size_t *complen)
|
||||
/* The necessary size of net->buff */
|
||||
if (helping >= net->max_packet)
|
||||
{
|
||||
if (net_realloc(net,helping))
|
||||
if (net_realloc(net, 0, helping))
|
||||
{
|
||||
len= packet_error; /* Return error */
|
||||
goto end;
|
||||
|
@@ -172,7 +172,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
|
||||
/* 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_PROTOCOL)
|
||||
if (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
|
||||
mysql->client_flag &= ~CLIENT_LONG_PASSWORD;
|
||||
|
||||
#if defined(HAVE_SSL) && !defined(EMBEDDED_LIBRARY)
|
||||
@@ -218,7 +218,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_PROTOCOL)
|
||||
if (mysql->server_capabilities & MARIADB_CLIENT_EXTENDED_FLAGS)
|
||||
{
|
||||
mysql->client_flag |= MARIADB_CLIENT_SUPPORTED_FLAGS;
|
||||
int4store(buff + 28, mysql->client_flag >> 32);
|
||||
|
@@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/unittest/mytap)
|
||||
ADD_DEFINITIONS(-DLIBMARIADB)
|
||||
|
||||
SET(API_TESTS "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
|
||||
SET(API_TESTS "features-10_2" "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
|
||||
"sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol")
|
||||
|
||||
# Get finger print from server certificate
|
||||
|
55
unittest/libmariadb/features-10_2.c
Normal file
55
unittest/libmariadb/features-10_2.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
#include "my_test.h"
|
||||
|
||||
static int com_multi_1(MYSQL *mysql)
|
||||
{
|
||||
int rc;
|
||||
my_bool is_multi= 1;
|
||||
|
||||
if (mysql_options(mysql, MARIADB_OPT_COM_MULTI, &is_multi))
|
||||
{
|
||||
diag("COM_MULT not supported");
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
rc= mysql_query(mysql, "SET @a:=1");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(mysql, "SET @b:=2");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(mysql, "select @a,@b");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mariadb_flush_multi_command(mysql);
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
/* question: how will result sets look like ? */
|
||||
diag("error: %s", mysql_error(mysql));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"com_multi_1", com_multi_1, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{NULL, NULL, 0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
mysql_library_init(0,0,NULL);
|
||||
|
||||
if (argc > 1)
|
||||
get_options(argc, argv);
|
||||
|
||||
get_envvars();
|
||||
|
||||
run_tests(my_tests);
|
||||
|
||||
mysql_server_end();
|
||||
return(exit_status());
|
||||
}
|
Reference in New Issue
Block a user