diff options
author | Seppo Jaakola <seppo.jaakola@codership.com> | 2013-12-04 10:32:43 +0200 |
---|---|---|
committer | Seppo Jaakola <seppo.jaakola@codership.com> | 2013-12-04 10:32:43 +0200 |
commit | 496e22cf3bd2a481fd3502d86e5a4e8228bf9823 (patch) | |
tree | 80549f8005fcf3236bfa004a5aea35e4e67b36ca /sql-common | |
parent | 45f484b8381a5923aec9c704e54c7f7bcfa02a40 (diff) | |
parent | 26f56089c734852dc31d98fd73e1d8f1750bd1a8 (diff) | |
download | mariadb-git-496e22cf3bd2a481fd3502d86e5a4e8228bf9823.tar.gz |
merge with MariaDB 5.6 bzr merge lp:maria --rtag:mariadb-10.0.6
and a number of fixes to make this buildable.
Run also few short multi-master high conflict rate tests, with no issues
Diffstat (limited to 'sql-common')
-rw-r--r-- | sql-common/client.c | 310 | ||||
-rw-r--r-- | sql-common/my_user.c | 28 |
2 files changed, 315 insertions, 23 deletions
diff --git a/sql-common/client.c b/sql-common/client.c index 6942822f889..87cbf45a3c6 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -37,6 +37,7 @@ #include <my_global.h> #include <my_default.h> #include "mysql.h" +#include "hash.h" /* Remove client convenience wrappers */ #undef max_allowed_packet @@ -1216,17 +1217,30 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd) return 0; } -#define EXTENSION_SET(OPTS, X, VAL) \ - if (!(OPTS)->extension) \ + +#define ALLOCATE_EXTENSIONS(OPTS) \ (OPTS)->extension= (struct st_mysql_options_extention *) \ my_malloc(sizeof(struct st_mysql_options_extention), \ - MYF(MY_WME | MY_ZEROFILL)); \ - (OPTS)->extension->X= (VAL); + MYF(MY_WME | MY_ZEROFILL)) \ + + +#define ENSURE_EXTENSIONS_PRESENT(OPTS) \ + do { \ + if (!(OPTS)->extension) \ + ALLOCATE_EXTENSIONS(OPTS); \ + } while (0) + #define EXTENSION_SET_STRING(OPTS, X, STR) \ - if ((OPTS)->extension) \ - my_free((OPTS)->extension->X); \ - EXTENSION_SET(OPTS, X, (STR) ? my_strdup((STR), MYF(MY_WME)) : NULL); + do { \ + if ((OPTS)->extension) \ + my_free((OPTS)->extension->X); \ + else \ + ALLOCATE_EXTENSIONS(OPTS); \ + (OPTS)->extension->X= ((STR) != NULL) ? \ + my_strdup((STR), MYF(MY_WME)) : NULL; \ + } while (0) + #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) #define SET_SSL_OPTION(OPTS, opt_var, arg) \ @@ -2376,6 +2390,7 @@ static auth_plugin_t old_password_client_plugin= old_password_auth_client }; + struct st_mysql_client_plugin *mysql_client_builtins[]= { (struct st_mysql_client_plugin *)&native_password_client_plugin, @@ -2383,6 +2398,67 @@ struct st_mysql_client_plugin *mysql_client_builtins[]= 0 }; + +static uchar * +write_length_encoded_string3(uchar *buf, char *string, size_t length) +{ + buf= net_store_length(buf, length); + memcpy(buf, string, length); + buf+= length; + return buf; +} + + +uchar * +send_client_connect_attrs(MYSQL *mysql, uchar *buf) +{ + /* check if the server supports connection attributes */ + if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS) + { + + /* Always store the length if the client supports it */ + buf= net_store_length(buf, + mysql->options.extension ? + mysql->options.extension->connection_attributes_length : + 0); + + /* check if we have connection attributes */ + if (mysql->options.extension && + my_hash_inited(&mysql->options.extension->connection_attributes)) + { + HASH *attrs= &mysql->options.extension->connection_attributes; + ulong idx; + + /* loop over and dump the connection attributes */ + for (idx= 0; idx < attrs->records; idx++) + { + LEX_STRING *attr= (LEX_STRING *) my_hash_element(attrs, idx); + LEX_STRING *key= attr, *value= attr + 1; + + /* we can't have zero length keys */ + DBUG_ASSERT(key->length); + + buf= write_length_encoded_string3(buf, key->str, key->length); + buf= write_length_encoded_string3(buf, value->str, value->length); + } + } + } + return buf; +} + + +static size_t get_length_store_length(size_t length) +{ + /* as defined in net_store_length */ + #define MAX_VARIABLE_STRING_LENGTH 9 + uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr; + + ptr= net_store_length(length_buffer, length); + + return ptr - &length_buffer[0]; +} + + /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */ typedef struct { int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); @@ -2426,8 +2502,13 @@ static int send_change_user_packet(MCPVIO_EXT *mpvio, MYSQL *mysql= mpvio->mysql; char *buff, *end; int res= 1; + size_t connect_attrs_len= + (mysql->server_capabilities & CLIENT_CONNECT_ATTRS && + mysql->options.extension) ? + mysql->options.extension->connection_attributes_length : 0; - buff= my_alloca(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1); + buff= my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN + + connect_attrs_len + 9 /* for the length of the attrs */); end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1; @@ -2464,6 +2545,8 @@ static int send_change_user_packet(MCPVIO_EXT *mpvio, if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1; + end= (char *) send_client_connect_attrs(mysql, (uchar *) end); + res= simple_command(mysql, COM_CHANGE_USER, (uchar*)buff, (ulong)(end-buff), 1); @@ -2472,6 +2555,7 @@ error: return res; } +#define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536 /** sends a client authentication packet (second packet in the 3-way handshake) @@ -2509,10 +2593,21 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, MYSQL *mysql= mpvio->mysql; NET *net= &mysql->net; char *buff, *end; + size_t buff_size; + size_t connect_attrs_len= + (mysql->server_capabilities & CLIENT_CONNECT_ATTRS && + mysql->options.extension) ? + mysql->options.extension->connection_attributes_length : 0; + + DBUG_ASSERT(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH); + + /* + see end= buff+32 below, fixed size of the packet is 32 bytes. + +9 because data is a length encoded binary where meta data size is max 9. + */ + buff_size= 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN + connect_attrs_len + 9; + buff= my_alloca(buff_size); - /* see end= buff+32 below, fixed size of the packet is 32 bytes */ - buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN); - mysql->client_flag|= mysql->options.client_flag; mysql->client_flag|= CLIENT_CAPABILITIES; @@ -2665,6 +2760,8 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1; + end= (char *) send_client_connect_attrs(mysql, (uchar *) end); + /* Write authentication package */ if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net)) { @@ -3024,6 +3121,51 @@ connect_sync_or_async(MYSQL *mysql, NET *net, my_socket fd, return my_connect(fd, name, namelen, mysql->options.connect_timeout); } + +/** set some default attributes */ +static int +set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len) +{ + int rc= 0; + + /* + Clean up any values set by the client code. We want these options as + consistent as possible + */ + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name"); + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os"); + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform"); + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid"); + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread"); + rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version"); + + /* + Now let's set up some values + */ + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, + "_client_name", "libmysql"); + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, + "_client_version", PACKAGE_VERSION); + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, + "_os", SYSTEM_TYPE); + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, + "_platform", MACHINE_TYPE); +#ifdef __WIN__ + snprintf(buff, buf_len, "%lu", (ulong) GetCurrentProcessId()); +#else + snprintf(buff, buf_len, "%lu", (ulong) getpid()); +#endif + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff); + +#ifdef __WIN__ + snprintf(buff, buf_len, "%lu", (ulong) GetCurrentThreadId()); + rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff); +#endif + + return rc > 0 ? 1 : 0; +} + + MYSQL * STDCALL CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, const char *passwd, const char *db, @@ -3057,6 +3199,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, DBUG_RETURN(0); } + if (set_connect_attributes(mysql, buff, sizeof(buff))) + DBUG_RETURN(0); + mysql->methods= &client_methods; net->vio = 0; /* If something goes wrong */ mysql->client_flag=0; /* For handshake */ @@ -3757,6 +3902,7 @@ static void mysql_close_free_options(MYSQL *mysql) struct mysql_async_context *ctxt= mysql->options.extension->async_context; my_free(mysql->options.extension->plugin_dir); my_free(mysql->options.extension->default_auth); + my_hash_free(&mysql->options.extension->connection_attributes); if (ctxt) { my_context_destroy(&ctxt->async_context); @@ -4320,7 +4466,8 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) my_free(ctxt); DBUG_RETURN(1); } - EXTENSION_SET(&(mysql->options), async_context, ctxt) + ENSURE_EXTENSIONS_PRESENT(&(mysql->options)); + mysql->options.extension->async_context= ctxt; if (mysql->net.vio) mysql->net.vio->async_context= ctxt; break; @@ -4345,6 +4492,145 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg) case MYSQL_OPT_SSL_CRLPATH: EXTENSION_SET_SSL_STRING(&mysql->options, ssl_crlpath, arg); break; + case MYSQL_OPT_CONNECT_ATTR_RESET: + ENSURE_EXTENSIONS_PRESENT(&mysql->options); + if (my_hash_inited(&mysql->options.extension->connection_attributes)) + { + my_hash_free(&mysql->options.extension->connection_attributes); + mysql->options.extension->connection_attributes_length= 0; + } + break; + case MYSQL_OPT_CONNECT_ATTR_DELETE: + ENSURE_EXTENSIONS_PRESENT(&mysql->options); + if (my_hash_inited(&mysql->options.extension->connection_attributes)) + { + size_t len; + uchar *elt; + + len= arg ? strlen(arg) : 0; + + if (len) + { + elt= my_hash_search(&mysql->options.extension->connection_attributes, + arg, len); + if (elt) + { + LEX_STRING *attr= (LEX_STRING *) elt; + LEX_STRING *key= attr, *value= attr + 1; + + mysql->options.extension->connection_attributes_length-= + get_length_store_length(key->length) + key->length + + get_length_store_length(value->length) + value->length; + + my_hash_delete(&mysql->options.extension->connection_attributes, + elt); + + } + } + } + break; + default: + break; + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} +/** + A function to return the key from a connection attribute +*/ +uchar * +get_attr_key(LEX_STRING *part, size_t *length, + my_bool not_used __attribute__((unused))) +{ + *length= part[0].length; + return (uchar *) part[0].str; +} + +int STDCALL +mysql_options4(MYSQL *mysql,enum mysql_option option, + const void *arg1, const void *arg2) +{ + DBUG_ENTER("mysql_option"); + DBUG_PRINT("enter",("option: %d",(int) option)); + + switch (option) + { + case MYSQL_OPT_CONNECT_ATTR_ADD: + { + LEX_STRING *elt; + char *key, *value; + size_t key_len= arg1 ? strlen(arg1) : 0, + value_len= arg2 ? strlen(arg2) : 0; + size_t attr_storage_length= key_len + value_len; + + /* we can't have a zero length key */ + if (!key_len) + { + set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate); + DBUG_RETURN(1); + } + + /* calculate the total storage length of the attribute */ + attr_storage_length+= get_length_store_length(key_len); + attr_storage_length+= get_length_store_length(value_len); + + ENSURE_EXTENSIONS_PRESENT(&mysql->options); + + /* + Throw and error if the maximum combined length of the attribute value + will be greater than the maximum that we can safely transmit. + */ + if (attr_storage_length + + mysql->options.extension->connection_attributes_length > + MAX_CONNECTION_ATTR_STORAGE_LENGTH) + { + set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate); + DBUG_RETURN(1); + } + + if (!my_hash_inited(&mysql->options.extension->connection_attributes)) + { + if (my_hash_init(&mysql->options.extension->connection_attributes, + &my_charset_bin, 0, 0, 0, (my_hash_get_key) get_attr_key, + my_free, HASH_UNIQUE)) + { + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); + DBUG_RETURN(1); + } + } + if (!my_multi_malloc(MY_WME, + &elt, 2 * sizeof(LEX_STRING), + &key, key_len + 1, + &value, value_len + 1, + NULL)) + { + set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate); + DBUG_RETURN(1); + } + elt[0].str= key; elt[0].length= key_len; + elt[1].str= value; elt[1].length= value_len; + if (key_len) + memcpy(key, arg1, key_len); + key[key_len]= 0; + if (value_len) + memcpy(value, arg2, value_len); + value[value_len]= 0; + if (my_hash_insert(&mysql->options.extension->connection_attributes, + (uchar *) elt)) + { + /* can't insert the value */ + my_free(elt); + set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR, + unknown_sqlstate); + DBUG_RETURN(1); + } + + mysql->options.extension->connection_attributes_length+= + attr_storage_length; + + break; + } + default: DBUG_RETURN(1); } diff --git a/sql-common/my_user.c b/sql-common/my_user.c index 8d717ea7131..a486f77bc1e 100644 --- a/sql-common/my_user.c +++ b/sql-common/my_user.c @@ -30,34 +30,40 @@ host_name_str [OUT] Buffer to store host name part. Must be not less than HOSTNAME_LENGTH + 1. host_name_len [OUT] A place to store length of the host name part. + + RETURN + 0 - if only a user was set, no '@' was found + 1 - if both user and host were set */ -void parse_user(const char *user_id_str, size_t user_id_len, - char *user_name_str, size_t *user_name_len, - char *host_name_str, size_t *host_name_len) +int parse_user(const char *user_id_str, size_t user_id_len, + char *user_name_str, size_t *user_name_len, + char *host_name_str, size_t *host_name_len) { char *p= strrchr(user_id_str, '@'); if (!p) { - *user_name_len= 0; + *user_name_len= user_id_len; *host_name_len= 0; } else { *user_name_len= (uint) (p - user_id_str); *host_name_len= (uint) (user_id_len - *user_name_len - 1); + } - if (*user_name_len > USERNAME_LENGTH) - *user_name_len= USERNAME_LENGTH; + if (*user_name_len > USERNAME_LENGTH) + *user_name_len= USERNAME_LENGTH; - if (*host_name_len > HOSTNAME_LENGTH) - *host_name_len= HOSTNAME_LENGTH; + if (*host_name_len > HOSTNAME_LENGTH) + *host_name_len= HOSTNAME_LENGTH; - memcpy(user_name_str, user_id_str, *user_name_len); - memcpy(host_name_str, p + 1, *host_name_len); - } + memcpy(user_name_str, user_id_str, *user_name_len); + memcpy(host_name_str, p + 1, *host_name_len); user_name_str[*user_name_len]= 0; host_name_str[*host_name_len]= 0; + + return p != NULL; } |