Skip to content

Commit

Permalink
Initial implementation for COM_MULTI
Browse files Browse the repository at this point in the history
  • Loading branch information
9EOR9 committed Dec 17, 2015
1 parent 955bb8d commit c8648cf
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 17 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Expand Up @@ -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 ###
Expand Down
1 change: 1 addition & 0 deletions include/errmsg.h
Expand Up @@ -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"

Expand Down
2 changes: 2 additions & 0 deletions include/ma_common.h
Expand Up @@ -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) \
Expand Down
1 change: 1 addition & 0 deletions include/mysql.h
Expand Up @@ -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
};

Expand Down
7 changes: 5 additions & 2 deletions include/mysql_com.h
Expand Up @@ -87,6 +87,7 @@ enum enum_server_command
COM_SET_OPTION = 27,
COM_STMT_FETCH = 28,
COM_DAEMON,
COM_MULTI = 255,
COM_END
};

Expand Down Expand Up @@ -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 |\
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libmariadb/CMakeLists.txt
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libmariadb/errmsg.c
Expand Up @@ -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'",
""
};

Expand Down
52 changes: 49 additions & 3 deletions libmariadb/libmariadb.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
if (!is_multi)
DBUG_RETURN(mysql->methods->db_read_query_result(mysql));
DBUG_RETURN(0);
}

/**************************************************************************
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
81 changes: 72 additions & 9 deletions libmariadb/net.c
Expand Up @@ -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);


Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -166,16 +171,24 @@ 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))))
{
DBUG_PRINT("info", ("Out of memory"));
net->error=1;
DBUG_RETURN(1);
}
net->buff=net->write_pos=buff;
net->buff_end=buff+(net->max_packet=(unsigned long)pkt_length);
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);
}

Expand All @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
*****************************************************************************/
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions plugins/auth/my_auth.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion unittest/libmariadb/CMakeLists.txt
Expand Up @@ -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
Expand Down

0 comments on commit c8648cf

Please sign in to comment.