3910 Georgi Kodinov 2012-05-28 [merge]
merge
modified:
libmysqld/examples/CMakeLists.txt
mysql-test/lib/My/Memcache.pm
mysql-test/suite/rpl/r/rpl_semi_sync.result
mysql-test/suite/rpl/t/rpl_semi_sync.test
=== modified file 'client/mysql.cc'
--- a/client/mysql.cc 2012-04-16 09:14:37 +0000
+++ b/client/mysql.cc 2012-05-02 09:30:40 +0000
@@ -1423,6 +1423,9 @@ sig_handler handle_kill_signal(int sig)
}
kill_mysql= mysql_init(kill_mysql);
+ mysql_options(kill_mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(kill_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysql");
if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
"", opt_mysql_port, opt_mysql_unix_port,0))
{
@@ -4508,6 +4511,9 @@ sql_real_connect(char *host,char *databa
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysql");
if (!mysql_real_connect(&mysql, host, user, password,
database, opt_mysql_port, opt_mysql_unix_port,
connect_flag | CLIENT_MULTI_STATEMENTS))
=== modified file 'client/mysqladmin.cc'
--- a/client/mysqladmin.cc 2012-04-16 09:14:37 +0000
+++ b/client/mysqladmin.cc 2012-05-02 09:30:40 +0000
@@ -369,6 +369,9 @@ int main(int argc,char *argv[])
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqladmin");
if (sql_connect(&mysql, option_wait))
{
/*
=== modified file 'client/mysqlbinlog.cc'
--- a/client/mysqlbinlog.cc 2012-05-03 09:41:32 +0000
+++ b/client/mysqlbinlog.cc 2012-05-21 12:00:48 +0000
@@ -1636,6 +1636,9 @@ static Exit_status safe_connect()
mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
+ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlbinlog");
if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0))
{
error("Failed on connect: %s", mysql_error(mysql));
=== modified file 'client/mysqlcheck.c'
--- a/client/mysqlcheck.c 2012-04-16 09:14:37 +0000
+++ b/client/mysqlcheck.c 2012-05-02 09:30:40 +0000
@@ -862,6 +862,9 @@ static int dbConnect(char *host, char *u
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
+ mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlcheck");
if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd,
NULL, opt_mysql_port, opt_mysql_unix_port, 0)))
{
=== modified file 'client/mysqldump.c'
--- a/client/mysqldump.c 2012-05-09 16:53:03 +0000
+++ b/client/mysqldump.c 2012-05-21 12:00:48 +0000
@@ -1511,6 +1511,9 @@ static int connect_to_db(char *host, cha
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqldump");
if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
NULL,opt_mysql_port,opt_mysql_unix_port,
0)))
=== modified file 'client/mysqlimport.c'
--- a/client/mysqlimport.c 2012-04-16 09:14:37 +0000
+++ b/client/mysqlimport.c 2012-05-02 09:30:40 +0000
@@ -453,6 +453,9 @@ static MYSQL *db_connect(char *host, cha
mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
+ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlimport");
if (!(mysql_real_connect(mysql,host,user,passwd,
database,opt_mysql_port,opt_mysql_unix_port,
0)))
=== modified file 'client/mysqlshow.c'
--- a/client/mysqlshow.c 2012-04-16 09:14:37 +0000
+++ b/client/mysqlshow.c 2012-05-02 09:30:40 +0000
@@ -143,6 +143,9 @@ int main(int argc, char **argv)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlshow");
if (!(mysql_real_connect(&mysql,host,user,opt_password,
(first_argument_uses_wildcards) ? "" :
argv[0],opt_mysql_port,opt_mysql_unix_port,
=== modified file 'client/mysqlslap.c'
--- a/client/mysqlslap.c 2012-05-09 16:53:03 +0000
+++ b/client/mysqlslap.c 2012-05-21 12:00:48 +0000
@@ -355,6 +355,9 @@ int main(int argc, char **argv)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqlslap");
if (!opt_only_print)
{
if (!(mysql_real_connect(&mysql, host, user, opt_password,
=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc 2012-04-16 09:14:37 +0000
+++ b/client/mysqltest.cc 2012-05-02 09:30:40 +0000
@@ -5224,6 +5224,10 @@ void safe_connect(MYSQL* mysql, const ch
verbose_msg("Connecting to server %s:%d (socket %s) as '%s'"
", connection '%s', attempt %d ...",
host, port, sock, user, name, failed_attempts);
+
+ mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqltest");
while(!mysql_real_connect(mysql, host,user, pass, db, port, sock,
CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS))
{
@@ -5325,6 +5329,8 @@ int connect_n_handle_errors(struct st_co
dynstr_append_mem(ds, ";\n", 2);
}
+ mysql_options(con, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(con, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysqltest");
while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
CLIENT_MULTI_STATEMENTS))
{
=== modified file 'include/errmsg.h'
--- a/include/errmsg.h 2011-09-07 10:08:09 +0000
+++ b/include/errmsg.h 2012-03-30 16:01:10 +0000
@@ -102,7 +102,8 @@ extern const char *client_errors[]; /* E
#define CR_NEW_STMT_METADATA 2057
#define CR_ALREADY_CONNECTED 2058
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059
-#define CR_ERROR_LAST /*Copy last error nr:*/ 2059
+#define CR_DUPLICATE_CONNECTION_ATTR 2060
+#define CR_ERROR_LAST /*Copy last error nr:*/ 2060
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */
#endif /* ERRMSG_INCLUDED */
=== modified file 'include/mysql.h'
--- a/include/mysql.h 2011-12-09 21:08:37 +0000
+++ b/include/mysql.h 2012-03-30 16:01:10 +0000
@@ -170,7 +170,9 @@ enum mysql_option
MYSQL_OPT_BIND,
MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
- MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH
+ MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
+ MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD,
+ MYSQL_OPT_CONNECT_ATTR_DELETE
};
/**
@@ -460,6 +462,8 @@ MYSQL_RES * STDCALL mysql_list_tables(MY
MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql);
int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
const void *arg);
+int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
+ const void *arg1, const void *arg2);
void STDCALL mysql_free_result(MYSQL_RES *result);
void STDCALL mysql_data_seek(MYSQL_RES *result,
my_ulonglong offset);
=== modified file 'include/mysql.h.pp'
--- a/include/mysql.h.pp 2012-03-06 14:29:42 +0000
+++ b/include/mysql.h.pp 2012-03-30 16:01:10 +0000
@@ -267,7 +267,9 @@ enum mysql_option
MYSQL_OPT_BIND,
MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
- MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH
+ MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
+ MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD,
+ MYSQL_OPT_CONNECT_ATTR_DELETE
};
struct st_mysql_options_extention;
struct st_mysql_options {
@@ -467,6 +469,8 @@ MYSQL_RES * mysql_list_tables(MYSQL *mys
MYSQL_RES * mysql_list_processes(MYSQL *mysql);
int mysql_options(MYSQL *mysql,enum mysql_option option,
const void *arg);
+int mysql_options4(MYSQL *mysql,enum mysql_option option,
+ const void *arg1, const void *arg2);
void mysql_free_result(MYSQL_RES *result);
void mysql_data_seek(MYSQL_RES *result,
my_ulonglong offset);
=== modified file 'include/mysql/psi/psi.h'
--- a/include/mysql/psi/psi.h 2012-05-15 09:39:47 +0000
+++ b/include/mysql/psi/psi.h 2012-05-21 12:00:48 +0000
@@ -1874,6 +1874,19 @@ typedef struct PSI_digest_locker* (*dige
(struct PSI_digest_locker *locker, uint token, struct OPAQUE_LEX_YYSTYPE *yylval);
/**
+ Stores an array of connection attributes
+ @param buffer char array of length encoded connection attributes
+ in network format
+ @param length legnth of the data in buffer
+ @param from_cs charset in which @buffer is encodded
+ @return state
+ @retval non-0 attributes truncated
+ @retval 0 stored the attribute
+*/
+typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
+ const void *from_cs);
+
+/**
Performance Schema Interface, version 1.
@since PSI_VERSION_1
*/
@@ -2068,6 +2081,8 @@ struct PSI_v1
digest_start_v1_t digest_start;
/** @sa digest_add_token_v1_t. */
digest_add_token_v1_t digest_add_token;
+ /** @sa set_thread_connect_attrs_v1_t. */
+ set_thread_connect_attrs_v1_t set_thread_connect_attrs;
};
/** @} (end of group Group_PSI_v1) */
=== modified file 'include/mysql/psi/psi_abi_v1.h.pp'
--- a/include/mysql/psi/psi_abi_v1.h.pp 2012-04-11 11:54:50 +0000
+++ b/include/mysql/psi/psi_abi_v1.h.pp 2012-05-02 11:04:32 +0000
@@ -500,6 +500,8 @@ typedef struct PSI_digest_locker * (*dig
(struct PSI_statement_locker *locker);
typedef struct PSI_digest_locker* (*digest_add_token_v1_t)
(struct PSI_digest_locker *locker, uint token, struct OPAQUE_LEX_YYSTYPE *yylval);
+typedef int (*set_thread_connect_attrs_v1_t)(const char *buffer, uint length,
+ const void *from_cs);
struct PSI_v1
{
register_mutex_v1_t register_mutex;
@@ -597,6 +599,7 @@ struct PSI_v1
set_socket_thread_owner_v1_t set_socket_thread_owner;
digest_start_v1_t digest_start;
digest_add_token_v1_t digest_add_token;
+ set_thread_connect_attrs_v1_t set_thread_connect_attrs;
};
typedef struct PSI_v1 PSI;
typedef struct PSI_mutex_info_v1 PSI_mutex_info;
=== modified file 'include/mysql_com.h'
--- a/include/mysql_com.h 2012-05-08 06:26:36 +0000
+++ b/include/mysql_com.h 2012-05-28 10:46:55 +0000
@@ -173,6 +173,7 @@ enum enum_server_command
#define CLIENT_PS_MULTI_RESULTS (1UL << 18) /* Multi-results in PS-protocol */
#define CLIENT_PLUGIN_AUTH (1UL << 19) /* Client supports plugin authentication */
+#define CLIENT_CONNECT_ATTRS (1UL << 20) /* Client supports connection attributes */
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
#define CLIENT_REMEMBER_OPTIONS (1UL << 31)
@@ -205,7 +206,8 @@ enum enum_server_command
CLIENT_PS_MULTI_RESULTS | \
CLIENT_SSL_VERIFY_SERVER_CERT | \
CLIENT_REMEMBER_OPTIONS | \
- CLIENT_PLUGIN_AUTH)
+ CLIENT_PLUGIN_AUTH | \
+ CLIENT_CONNECT_ATTRS)
/*
Switch off the flags that are optional and depending on build flags
=== modified file 'include/sql_common.h'
--- a/include/sql_common.h 2012-03-06 14:29:42 +0000
+++ b/include/sql_common.h 2012-03-30 16:01:10 +0000
@@ -23,6 +23,7 @@ extern "C" {
#endif
#include <mysql.h>
+#include <hash.h>
extern const char *unknown_sqlstate;
extern const char *cant_connect_sqlstate;
@@ -33,6 +34,8 @@ struct st_mysql_options_extention {
char *default_auth;
char *ssl_crl; /* PEM CRL file */
char *ssl_crlpath; /* PEM directory of CRL-s? */
+ HASH connection_attributes;
+ size_t connection_attributes_length;
};
typedef struct st_mysql_methods
@@ -105,6 +108,7 @@ int mysql_client_plugin_init();
void mysql_client_plugin_deinit();
struct st_mysql_client_plugin;
extern struct st_mysql_client_plugin *mysql_client_builtins[];
+uchar * send_client_connect_attrs(MYSQL *mysql, uchar *buf);
#ifdef __cplusplus
}
=== modified file 'libmysql/client_settings.h'
--- a/libmysql/client_settings.h 2011-09-27 12:11:16 +0000
+++ b/libmysql/client_settings.h 2012-03-30 16:01:10 +0000
@@ -34,7 +34,8 @@ extern char * mysql_unix_port;
CLIENT_SECURE_CONNECTION | \
CLIENT_MULTI_RESULTS | \
CLIENT_PS_MULTI_RESULTS | \
- CLIENT_PLUGIN_AUTH)
+ CLIENT_PLUGIN_AUTH | \
+ CLIENT_CONNECT_ATTRS)
sig_handler my_pipe_sig_handler(int sig);
void read_user_name(char *name);
=== modified file 'libmysqld/lib_sql.cc'
--- a/libmysqld/lib_sql.cc 2012-04-27 11:57:38 +0000
+++ b/libmysqld/lib_sql.cc 2012-05-21 12:00:48 +0000
@@ -735,12 +735,38 @@ err:
}
+static void
+emb_transfer_connect_attrs(MYSQL *mysql)
+{
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ if (mysql->options.extension &&
+ mysql->options.extension->connection_attributes_length)
+ {
+ uchar *buf, *ptr;
+ THD *thd= (THD*)mysql->thd;
+ size_t length= mysql->options.extension->connection_attributes_length;
+
+ /* 9 = max length of the serialized length */
+ ptr= buf= (uchar *) my_alloca(length + 9);
+ send_client_connect_attrs(mysql, buf);
+ net_field_length_ll(&ptr);
+ PSI_THREAD_CALL(set_thread_connect_attrs)((char *) ptr, length, thd->charset());
+ my_afree(buf);
+ }
+#endif
+}
+
+
#ifdef NO_EMBEDDED_ACCESS_CHECKS
int check_embedded_connection(MYSQL *mysql, const char *db)
{
int result;
LEX_STRING db_str = { (char*)db, db ? strlen(db) : 0 };
THD *thd= (THD*)mysql->thd;
+
+ /* the server does the same as the client */
+ mysql->server_capabilities= mysql->client_flag;
+
thd_init_client_charset(thd, mysql->charset->number);
thd->update_charset();
Security_context *sctx= thd->security_ctx;
@@ -750,6 +776,7 @@ int check_embedded_connection(MYSQL *mys
sctx->user= my_strdup(mysql->user, MYF(0));
sctx->proxy_user[0]= 0;
sctx->master_access= GLOBAL_ACLS; // Full rights
+ emb_transfer_connect_attrs(mysql);
/* Change database if necessary */
if (!(result= (db && db[0] && mysql_change_db(thd, &db_str, FALSE))))
my_ok(thd);
@@ -765,11 +792,17 @@ int check_embedded_connection(MYSQL *mys
we emulate a COM_CHANGE_USER user here,
it's easier than to emulate the complete 3-way handshake
*/
- char buf[USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2], *end;
+ char *buf, *end;
NET *net= &mysql->net;
THD *thd= (THD*)mysql->thd;
Security_context *sctx= thd->security_ctx;
+ size_t connect_attrs_len=
+ (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
+ mysql->options.extension) ?
+ mysql->options.extension->connection_attributes_length : 0;
+ buf= my_alloca(USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2 +
+ connect_attrs_len + 2);
if (mysql->options.client_ip)
{
sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
@@ -802,6 +835,13 @@ int check_embedded_connection(MYSQL *mys
int2store(end, (ushort) mysql->charset->number);
end+= 2;
+ end= strmake(end, "mysql_native_password", NAME_LEN) + 1;
+
+ /* the server does the same as the client */
+ mysql->server_capabilities= mysql->client_flag;
+
+ end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
+
/* acl_authenticate() takes the data from thd->net->read_pos */
thd->net.read_pos= (uchar*)buf;
@@ -810,12 +850,14 @@ int check_embedded_connection(MYSQL *mys
x_free(thd->security_ctx->user);
goto err;
}
+ my_afree(buf);
return 0;
err:
strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1);
memcpy(net->sqlstate,
mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
sizeof(net->sqlstate)-1);
+ my_afree(buf);
return 1;
}
#endif
=== modified file 'mysql-test/r/variables.result'
--- a/mysql-test/r/variables.result 2012-05-09 16:47:39 +0000
+++ b/mysql-test/r/variables.result 2012-05-21 12:00:48 +0000
@@ -582,6 +582,7 @@ Warning 1292 Truncated incorrect tmp_tab
set tx_isolation="READ-COMMITTED";
set wait_timeout=100;
set global log_warnings=1;
+set global max_allowed_packet =@my_max_allowed_packet;
select @@session.insert_id;
@@session.insert_id
1
@@ -1054,8 +1055,6 @@ set global max_write_lock_count =de
set global myisam_data_pointer_size =@my_myisam_data_pointer_size;
set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size;
set global net_buffer_length =@my_net_buffer_length;
-Warnings:
-Warning 1708 The value of 'max_allowed_packet' should be no less than the value of 'net_buffer_length'
set global net_write_timeout =@my_net_write_timeout;
set global net_read_timeout =@my_net_read_timeout;
set global query_cache_limit =@my_query_cache_limit;
=== added file 'mysql-test/suite/perfschema/r/connect_attrs.result'
--- a/mysql-test/suite/perfschema/r/connect_attrs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/r/connect_attrs.result 2012-05-02 11:04:32 +0000
@@ -0,0 +1,46 @@
+# must return 0, 6
+SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
+FROM performance_schema.session_connect_attrs
+WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
+'_client_version', '_platform', 'program_name')
+AND PROCESSLIST_ID = CONNECTION_ID();
+SUM(ISNULL(ATTR_VALUE)) COUNT(*)
+0 6
+# must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_connect_attrs;
+COUNT(DISTINCT PROCESSLIST_ID)
+1
+# must return 0, 6
+SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
+FROM performance_schema.session_account_connect_attrs
+WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
+'_client_version', '_platform', 'program_name')
+AND PROCESSLIST_ID = CONNECTION_ID();
+SUM(ISNULL(ATTR_VALUE)) COUNT(*)
+0 6
+# must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_account_connect_attrs;
+COUNT(DISTINCT PROCESSLIST_ID)
+1
+CREATE USER wl5924@localhost;
+# must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_account_connect_attrs;
+COUNT(DISTINCT PROCESSLIST_ID)
+1
+# must return 2
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_connect_attrs;
+COUNT(DISTINCT PROCESSLIST_ID)
+2
+# must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_account_connect_attrs;
+COUNT(DISTINCT PROCESSLIST_ID)
+1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+FROM performance_schema.session_connect_attrs;
+ERROR 42000: SELECT command denied to user 'wl5924'@'localhost' for table 'session_connect_attrs'
+DROP USER wl5924@localhost;
=== added file 'mysql-test/suite/perfschema/r/ddl_session_account_connect_attrs.result'
--- a/mysql-test/suite/perfschema/r/ddl_session_account_connect_attrs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/r/ddl_session_account_connect_attrs.result 2012-03-30 16:01:10 +0000
@@ -0,0 +1,9 @@
+ALTER TABLE performance_schema.session_account_connect_attrs
+ADD COLUMN foo INTEGER;
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
+TRUNCATE TABLE performance_schema.session_account_connect_attrs;
+ERROR HY000: Invalid performance_schema usage.
+ALTER TABLE performance_schema.session_account_connect_attrs ADD INDEX test_index(ATTR_NAME);
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
+CREATE UNIQUE INDEX test_index ON performance_schema.session_account_connect_attrs(ATTR_NAME);
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
=== added file 'mysql-test/suite/perfschema/r/ddl_session_connect_attrs.result'
--- a/mysql-test/suite/perfschema/r/ddl_session_connect_attrs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/r/ddl_session_connect_attrs.result 2012-03-30 16:01:10 +0000
@@ -0,0 +1,9 @@
+ALTER TABLE performance_schema.session_connect_attrs
+ADD COLUMN foo INTEGER;
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
+TRUNCATE TABLE performance_schema.session_connect_attrs;
+ERROR HY000: Invalid performance_schema usage.
+ALTER TABLE performance_schema.session_connect_attrs ADD INDEX test_index(ATTR_NAME);
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
+CREATE UNIQUE INDEX test_index ON performance_schema.session_connect_attrs(ATTR_NAME);
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'performance_schema'
=== modified file 'mysql-test/suite/perfschema/r/dml_handler.result'
--- a/mysql-test/suite/perfschema/r/dml_handler.result 2012-02-28 14:40:36 +0000
+++ b/mysql-test/suite/perfschema/r/dml_handler.result 2012-03-30 16:01:10 +0000
@@ -9,45 +9,51 @@ SELECT COUNT(*) FROM table_list INTO @ta
# For each table in the performance schema, attempt HANDLER...OPEN,
# which should fail with an error 1031, ER_ILLEGAL_HA.
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=50;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=52;
HANDLER performance_schema.users OPEN;
ERROR HY000: Table storage engine for 'users' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=49;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=51;
HANDLER performance_schema.threads OPEN;
ERROR HY000: Table storage engine for 'threads' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=48;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=50;
HANDLER performance_schema.table_lock_waits_summary_by_table OPEN;
ERROR HY000: Table storage engine for 'table_lock_waits_summary_by_table' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=47;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=49;
HANDLER performance_schema.table_io_waits_summary_by_table OPEN;
ERROR HY000: Table storage engine for 'table_io_waits_summary_by_table' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=46;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=48;
HANDLER performance_schema.table_io_waits_summary_by_index_usage OPEN;
ERROR HY000: Table storage engine for 'table_io_waits_summary_by_index_usage' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=45;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=47;
HANDLER performance_schema.socket_summary_by_instance OPEN;
ERROR HY000: Table storage engine for 'socket_summary_by_instance' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=44;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=46;
HANDLER performance_schema.socket_summary_by_event_name OPEN;
ERROR HY000: Table storage engine for 'socket_summary_by_event_name' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=43;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=45;
HANDLER performance_schema.socket_instances OPEN;
ERROR HY000: Table storage engine for 'socket_instances' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=42;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=44;
HANDLER performance_schema.setup_timers OPEN;
ERROR HY000: Table storage engine for 'setup_timers' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=41;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=43;
HANDLER performance_schema.setup_objects OPEN;
ERROR HY000: Table storage engine for 'setup_objects' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=40;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=42;
HANDLER performance_schema.setup_instruments OPEN;
ERROR HY000: Table storage engine for 'setup_instruments' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=39;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=41;
HANDLER performance_schema.setup_consumers OPEN;
ERROR HY000: Table storage engine for 'setup_consumers' doesn't have this option
-SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=38;
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=40;
HANDLER performance_schema.setup_actors OPEN;
ERROR HY000: Table storage engine for 'setup_actors' doesn't have this option
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=39;
+HANDLER performance_schema.session_connect_attrs OPEN;
+ERROR HY000: Table storage engine for 'session_connect_attrs' doesn't have this option
+SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=38;
+HANDLER performance_schema.session_account_connect_attrs OPEN;
+ERROR HY000: Table storage engine for 'session_account_connect_attrs' doesn't have this option
SELECT TABLE_NAME INTO @table_name FROM table_list WHERE id=37;
HANDLER performance_schema.rwlock_instances OPEN;
ERROR HY000: Table storage engine for 'rwlock_instances' doesn't have this option
=== added file 'mysql-test/suite/perfschema/r/dml_session_account_connect_attrs.result'
--- a/mysql-test/suite/perfschema/r/dml_session_account_connect_attrs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/r/dml_session_account_connect_attrs.result 2012-03-30 16:01:10 +0000
@@ -0,0 +1,25 @@
+SELECT * FROM performance_schema.session_account_connect_attrs
+LIMIT 1;
+SELECT * FROM performance_schema.session_account_connect_attrs
+where ATTR_NAME='FOO' OR ATTR_VALUE='BAR';
+INSERT INTO performance_schema.session_account_connect_attrs
+SET ATTR_NAME='FOO', ATTR_VALUE='BAR',
+ORDINAL_POSITION=100, PROCESS_ID=102;
+ERROR 42000: INSERT command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+UPDATE performance_schema.session_account_connect_attrs
+SET ATTR_NAME='FOO';
+ERROR 42000: UPDATE command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+UPDATE performance_schema.session_account_connect_attrs
+SET ATTR_NAME='FOO' WHERE ATTR_VALUE='BAR';
+ERROR 42000: UPDATE command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+DELETE FROM performance_schema.session_account_connect_attrs
+WHERE ATTR_VALUE='BAR';
+ERROR 42000: DELETE command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+DELETE FROM performance_schema.session_account_connect_attrs;
+ERROR 42000: DELETE command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+LOCK TABLES performance_schema.session_account_connect_attrs READ;
+ERROR 42000: SELECT, LOCK TABLES command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+UNLOCK TABLES;
+LOCK TABLES performance_schema.session_account_connect_attrs WRITE;
+ERROR 42000: SELECT, LOCK TABLES command denied to user 'root'@'localhost' for table 'session_account_connect_attrs'
+UNLOCK TABLES;
=== added file 'mysql-test/suite/perfschema/r/dml_session_connect_attrs.result'
--- a/mysql-test/suite/perfschema/r/dml_session_connect_attrs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/r/dml_session_connect_attrs.result 2012-03-30 16:01:10 +0000
@@ -0,0 +1,25 @@
+SELECT * FROM performance_schema.session_connect_attrs
+LIMIT 1;
+SELECT * FROM performance_schema.session_connect_attrs
+where ATTR_NAME='FOO' OR ATTR_VALUE='BAR';
+INSERT INTO performance_schema.session_connect_attrs
+SET ATTR_NAME='FOO', ATTR_VALUE='BAR',
+ORDINAL_POSITION=100, PROCESS_ID=102;
+ERROR 42000: INSERT command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+UPDATE performance_schema.session_connect_attrs
+SET ATTR_NAME='FOO';
+ERROR 42000: UPDATE command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+UPDATE performance_schema.session_connect_attrs
+SET ATTR_NAME='FOO' WHERE ATTR_VALUE='BAR';
+ERROR 42000: UPDATE command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+DELETE FROM performance_schema.session_connect_attrs
+WHERE ATTR_VALUE='BAR';
+ERROR 42000: DELETE command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+DELETE FROM performance_schema.session_connect_attrs;
+ERROR 42000: DELETE command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+LOCK TABLES performance_schema.session_connect_attrs READ;
+ERROR 42000: SELECT, LOCK TABLES command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+UNLOCK TABLES;
+LOCK TABLES performance_schema.session_connect_attrs WRITE;
+ERROR 42000: SELECT, LOCK TABLES command denied to user 'root'@'localhost' for table 'session_connect_attrs'
+UNLOCK TABLES;
=== modified file 'mysql-test/suite/perfschema/r/information_schema.result'
--- a/mysql-test/suite/perfschema/r/information_schema.result 2012-02-28 14:40:36 +0000
+++ b/mysql-test/suite/perfschema/r/information_schema.result 2012-03-30 16:01:10 +0000
@@ -39,6 +39,8 @@ performance_schema mutex_instances def
performance_schema objects_summary_global_by_type def
performance_schema performance_timers def
performance_schema rwlock_instances def
+performance_schema session_account_connect_attrs def
+performance_schema session_connect_attrs def
performance_schema setup_actors def
performance_schema setup_consumers def
performance_schema setup_instruments def
@@ -93,6 +95,8 @@ mutex_instances BASE TABLE PERFORMANCE_S
objects_summary_global_by_type BASE TABLE PERFORMANCE_SCHEMA
performance_timers BASE TABLE PERFORMANCE_SCHEMA
rwlock_instances BASE TABLE PERFORMANCE_SCHEMA
+session_account_connect_attrs BASE TABLE PERFORMANCE_SCHEMA
+session_connect_attrs BASE TABLE PERFORMANCE_SCHEMA
setup_actors BASE TABLE PERFORMANCE_SCHEMA
setup_consumers BASE TABLE PERFORMANCE_SCHEMA
setup_instruments BASE TABLE PERFORMANCE_SCHEMA
@@ -147,6 +151,8 @@ mutex_instances 10 Dynamic
objects_summary_global_by_type 10 Dynamic
performance_timers 10 Fixed
rwlock_instances 10 Dynamic
+session_account_connect_attrs 10 Dynamic
+session_connect_attrs 10 Dynamic
setup_actors 10 Fixed
setup_consumers 10 Dynamic
setup_instruments 10 Dynamic
@@ -201,6 +207,8 @@ mutex_instances 1000 0
objects_summary_global_by_type 1000 0
performance_timers 5 0
rwlock_instances 1000 0
+session_account_connect_attrs 1000 0
+session_connect_attrs 1000 0
setup_actors 1 0
setup_consumers 12 0
setup_instruments 1000 0
@@ -255,6 +263,8 @@ mutex_instances 0 0
objects_summary_global_by_type 0 0
performance_timers 0 0
rwlock_instances 0 0
+session_account_connect_attrs 0 0
+session_connect_attrs 0 0
setup_actors 0 0
setup_consumers 0 0
setup_instruments 0 0
@@ -309,6 +319,8 @@ mutex_instances 0 0 NULL
objects_summary_global_by_type 0 0 NULL
performance_timers 0 0 NULL
rwlock_instances 0 0 NULL
+session_account_connect_attrs 0 0 NULL
+session_connect_attrs 0 0 NULL
setup_actors 0 0 NULL
setup_consumers 0 0 NULL
setup_instruments 0 0 NULL
@@ -363,6 +375,8 @@ mutex_instances NULL NULL NULL
objects_summary_global_by_type NULL NULL NULL
performance_timers NULL NULL NULL
rwlock_instances NULL NULL NULL
+session_account_connect_attrs NULL NULL NULL
+session_connect_attrs NULL NULL NULL
setup_actors NULL NULL NULL
setup_consumers NULL NULL NULL
setup_instruments NULL NULL NULL
@@ -417,6 +431,8 @@ mutex_instances utf8_general_ci NULL
objects_summary_global_by_type utf8_general_ci NULL
performance_timers utf8_general_ci NULL
rwlock_instances utf8_general_ci NULL
+session_account_connect_attrs utf8_bin NULL
+session_connect_attrs utf8_bin NULL
setup_actors utf8_general_ci NULL
setup_consumers utf8_general_ci NULL
setup_instruments utf8_general_ci NULL
@@ -471,6 +487,8 @@ mutex_instances
objects_summary_global_by_type
performance_timers
rwlock_instances
+session_account_connect_attrs
+session_connect_attrs
setup_actors
setup_consumers
setup_instruments
=== modified file 'mysql-test/suite/perfschema/r/pfs_upgrade.result'
--- a/mysql-test/suite/perfschema/r/pfs_upgrade.result 2012-05-10 12:43:57 +0000
+++ b/mysql-test/suite/perfschema/r/pfs_upgrade.result 2012-05-21 12:00:48 +0000
@@ -60,7 +60,9 @@ ERROR 1050 (42S01) at line 1184: Table '
ERROR 1050 (42S01) at line 1193: Table 'users' already exists
ERROR 1050 (42S01) at line 1203: Table 'accounts' already exists
ERROR 1050 (42S01) at line 1237: Table 'events_statements_summary_by_digest' already exists
-ERROR 1644 (HY000) at line 1862: Unexpected content found in the performance_schema database.
+ERROR 1050 (42S01) at line 1247: Table 'session_connect_attrs' already exists
+ERROR 1050 (42S01) at line 1253: Table 'session_account_connect_attrs' already exists
+ERROR 1644 (HY000) at line 1878: Unexpected content found in the performance_schema database.
FATAL ERROR: Upgrade failed
show tables like "user_table";
Tables_in_performance_schema (user_table)
@@ -125,7 +127,9 @@ ERROR 1050 (42S01) at line 1184: Table '
ERROR 1050 (42S01) at line 1193: Table 'users' already exists
ERROR 1050 (42S01) at line 1203: Table 'accounts' already exists
ERROR 1050 (42S01) at line 1237: Table 'events_statements_summary_by_digest' already exists
-ERROR 1644 (HY000) at line 1862: Unexpected content found in the performance_schema database.
+ERROR 1050 (42S01) at line 1247: Table 'session_connect_attrs' already exists
+ERROR 1050 (42S01) at line 1253: Table 'session_account_connect_attrs' already exists
+ERROR 1644 (HY000) at line 1878: Unexpected content found in the performance_schema database.
FATAL ERROR: Upgrade failed
show tables like "user_view";
Tables_in_performance_schema (user_view)
@@ -188,7 +192,9 @@ ERROR 1050 (42S01) at line 1184: Table '
ERROR 1050 (42S01) at line 1193: Table 'users' already exists
ERROR 1050 (42S01) at line 1203: Table 'accounts' already exists
ERROR 1050 (42S01) at line 1237: Table 'events_statements_summary_by_digest' already exists
-ERROR 1644 (HY000) at line 1862: Unexpected content found in the performance_schema database.
+ERROR 1050 (42S01) at line 1247: Table 'session_connect_attrs' already exists
+ERROR 1050 (42S01) at line 1253: Table 'session_account_connect_attrs' already exists
+ERROR 1644 (HY000) at line 1878: Unexpected content found in the performance_schema database.
FATAL ERROR: Upgrade failed
select name from mysql.proc where db='performance_schema';
name
@@ -251,7 +257,9 @@ ERROR 1050 (42S01) at line 1184: Table '
ERROR 1050 (42S01) at line 1193: Table 'users' already exists
ERROR 1050 (42S01) at line 1203: Table 'accounts' already exists
ERROR 1050 (42S01) at line 1237: Table 'events_statements_summary_by_digest' already exists
-ERROR 1644 (HY000) at line 1862: Unexpected content found in the performance_schema database.
+ERROR 1050 (42S01) at line 1247: Table 'session_connect_attrs' already exists
+ERROR 1050 (42S01) at line 1253: Table 'session_account_connect_attrs' already exists
+ERROR 1644 (HY000) at line 1878: Unexpected content found in the performance_schema database.
FATAL ERROR: Upgrade failed
select name from mysql.proc where db='performance_schema';
name
@@ -314,7 +322,9 @@ ERROR 1050 (42S01) at line 1184: Table '
ERROR 1050 (42S01) at line 1193: Table 'users' already exists
ERROR 1050 (42S01) at line 1203: Table 'accounts' already exists
ERROR 1050 (42S01) at line 1237: Table 'events_statements_summary_by_digest' already exists
-ERROR 1644 (HY000) at line 1862: Unexpected content found in the performance_schema database.
+ERROR 1050 (42S01) at line 1247: Table 'session_connect_attrs' already exists
+ERROR 1050 (42S01) at line 1253: Table 'session_account_connect_attrs' already exists
+ERROR 1644 (HY000) at line 1878: Unexpected content found in the performance_schema database.
FATAL ERROR: Upgrade failed
select name from mysql.event where db='performance_schema';
name
=== modified file 'mysql-test/suite/perfschema/r/schema.result'
--- a/mysql-test/suite/perfschema/r/schema.result 2012-04-13 06:44:13 +0000
+++ b/mysql-test/suite/perfschema/r/schema.result 2012-05-02 09:30:40 +0000
@@ -44,6 +44,8 @@ mutex_instances
objects_summary_global_by_type
performance_timers
rwlock_instances
+session_account_connect_attrs
+session_connect_attrs
setup_actors
setup_consumers
setup_instruments
=== modified file 'mysql-test/suite/perfschema/r/table_schema.result'
--- a/mysql-test/suite/perfschema/r/table_schema.result 2012-04-13 06:44:13 +0000
+++ b/mysql-test/suite/perfschema/r/table_schema.result 2012-05-02 11:04:32 +0000
@@ -551,6 +551,14 @@ def performance_schema rwlock_instances
def performance_schema rwlock_instances OBJECT_INSTANCE_BEGIN 2 NULL NO bigint NULL NULL 20 0 NULL NULL NULL bigint(20) unsigned select,insert,update,references
def performance_schema rwlock_instances WRITE_LOCKED_BY_THREAD_ID 3 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references
def performance_schema rwlock_instances READ_LOCKED_BY_COUNT 4 NULL NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references
+def performance_schema session_account_connect_attrs PROCESSLIST_ID 1 NULL NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references
+def performance_schema session_account_connect_attrs ATTR_NAME 2 NULL NO varchar 32 96 NULL NULL NULL utf8 utf8_bin varchar(32) select,insert,update,references
+def performance_schema session_account_connect_attrs ATTR_VALUE 3 NULL YES varchar 1024 3072 NULL NULL NULL utf8 utf8_bin varchar(1024) select,insert,update,references
+def performance_schema session_account_connect_attrs ORDINAL_POSITION 4 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references
+def performance_schema session_connect_attrs PROCESSLIST_ID 1 NULL NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references
+def performance_schema session_connect_attrs ATTR_NAME 2 NULL NO varchar 32 96 NULL NULL NULL utf8 utf8_bin varchar(32) select,insert,update,references
+def performance_schema session_connect_attrs ATTR_VALUE 3 NULL YES varchar 1024 3072 NULL NULL NULL utf8 utf8_bin varchar(1024) select,insert,update,references
+def performance_schema session_connect_attrs ORDINAL_POSITION 4 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references
def performance_schema setup_actors HOST 1 % NO char 60 180 NULL NULL NULL utf8 utf8_bin char(60) select,insert,update,references
def performance_schema setup_actors USER 2 % NO char 16 48 NULL NULL NULL utf8 utf8_bin char(16) select,insert,update,references
def performance_schema setup_actors ROLE 3 % NO char 16 48 NULL NULL NULL utf8 utf8_bin char(16) select,insert,update,references
=== added file 'mysql-test/suite/perfschema/t/connect_attrs.test'
--- a/mysql-test/suite/perfschema/t/connect_attrs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/t/connect_attrs.test 2012-05-02 11:04:32 +0000
@@ -0,0 +1,74 @@
+# Session connect attributes test
+--source include/have_perfschema.inc
+
+# although the connection attributes transfer code works
+# with embedded P_S is not active, so the test won't run.
+# TODO: remove this when P_S works with embedded.
+--source include/not_embedded.inc
+
+# make sure we're alone
+let $count_sessions= 1;
+--source include/wait_until_count_sessions.inc
+
+# basic performance_schema.session_connect_attrs tests
+
+# check the presense of the pre-defined attributes
+--echo # must return 0, 6
+SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
+ FROM performance_schema.session_connect_attrs
+ WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
+ '_client_version', '_platform', 'program_name')
+ AND PROCESSLIST_ID = CONNECTION_ID();
+
+# check the presense of the pre-defined attributes
+--echo # must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_connect_attrs;
+
+
+# basic performance_schema.session_account_connect_attrs tests
+
+# check the presense of the pre-defined attributes
+--echo # must return 0, 6
+SELECT SUM(ISNULL(ATTR_VALUE)), COUNT(*)
+ FROM performance_schema.session_account_connect_attrs
+ WHERE ATTR_NAME IN ('_os', '_client_name', '_pid',
+ '_client_version', '_platform', 'program_name')
+ AND PROCESSLIST_ID = CONNECTION_ID();
+
+# check the presense of the pre-defined attributes
+--echo # must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_account_connect_attrs;
+
+
+
+CREATE USER wl5924@localhost;
+
+connect(non_privileged_user,localhost,wl5924,,test);
+connection default;
+
+--echo # must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_account_connect_attrs;
+
+--echo # must return 2
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_connect_attrs;
+
+connection non_privileged_user;
+--echo # must return 1
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_account_connect_attrs;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT COUNT(DISTINCT PROCESSLIST_ID)
+ FROM performance_schema.session_connect_attrs;
+
+connection default;
+disconnect non_privileged_user;
+
+DROP USER wl5924@localhost;
+
+# Wait till all disconnects are completed
+--source include/wait_until_count_sessions.inc
=== added file 'mysql-test/suite/perfschema/t/ddl_session_account_connect_attrs.test'
--- a/mysql-test/suite/perfschema/t/ddl_session_account_connect_attrs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/t/ddl_session_account_connect_attrs.test 2012-03-30 16:01:10 +0000
@@ -0,0 +1,15 @@
+--source include/not_embedded.inc
+--source include/have_perfschema.inc
+
+-- error ER_DBACCESS_DENIED_ERROR
+ALTER TABLE performance_schema.session_account_connect_attrs
+ ADD COLUMN foo INTEGER;
+
+-- error ER_WRONG_PERFSCHEMA_USAGE
+TRUNCATE TABLE performance_schema.session_account_connect_attrs;
+
+-- error ER_DBACCESS_DENIED_ERROR
+ALTER TABLE performance_schema.session_account_connect_attrs ADD INDEX test_index(ATTR_NAME);
+
+-- error ER_DBACCESS_DENIED_ERROR
+CREATE UNIQUE INDEX test_index ON performance_schema.session_account_connect_attrs(ATTR_NAME);
=== added file 'mysql-test/suite/perfschema/t/ddl_session_connect_attrs.test'
--- a/mysql-test/suite/perfschema/t/ddl_session_connect_attrs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/t/ddl_session_connect_attrs.test 2012-03-30 16:01:10 +0000
@@ -0,0 +1,15 @@
+--source include/not_embedded.inc
+--source include/have_perfschema.inc
+
+-- error ER_DBACCESS_DENIED_ERROR
+ALTER TABLE performance_schema.session_connect_attrs
+ ADD COLUMN foo INTEGER;
+
+-- error ER_WRONG_PERFSCHEMA_USAGE
+TRUNCATE TABLE performance_schema.session_connect_attrs;
+
+-- error ER_DBACCESS_DENIED_ERROR
+ALTER TABLE performance_schema.session_connect_attrs ADD INDEX test_index(ATTR_NAME);
+
+-- error ER_DBACCESS_DENIED_ERROR
+CREATE UNIQUE INDEX test_index ON performance_schema.session_connect_attrs(ATTR_NAME);
=== added file 'mysql-test/suite/perfschema/t/dml_session_account_connect_attrs.test'
--- a/mysql-test/suite/perfschema/t/dml_session_account_connect_attrs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/t/dml_session_account_connect_attrs.test 2012-03-30 16:01:10 +0000
@@ -0,0 +1,38 @@
+--source include/not_embedded.inc
+--source include/have_perfschema.inc
+
+--disable_result_log
+SELECT * FROM performance_schema.session_account_connect_attrs
+ LIMIT 1;
+
+SELECT * FROM performance_schema.session_account_connect_attrs
+ where ATTR_NAME='FOO' OR ATTR_VALUE='BAR';
+--enable_result_log
+
+--error ER_TABLEACCESS_DENIED_ERROR
+INSERT INTO performance_schema.session_account_connect_attrs
+ SET ATTR_NAME='FOO', ATTR_VALUE='BAR',
+ ORDINAL_POSITION=100, PROCESS_ID=102;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+UPDATE performance_schema.session_account_connect_attrs
+ SET ATTR_NAME='FOO';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+UPDATE performance_schema.session_account_connect_attrs
+ SET ATTR_NAME='FOO' WHERE ATTR_VALUE='BAR';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+DELETE FROM performance_schema.session_account_connect_attrs
+ WHERE ATTR_VALUE='BAR';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+DELETE FROM performance_schema.session_account_connect_attrs;
+
+-- error ER_TABLEACCESS_DENIED_ERROR
+LOCK TABLES performance_schema.session_account_connect_attrs READ;
+UNLOCK TABLES;
+
+-- error ER_TABLEACCESS_DENIED_ERROR
+LOCK TABLES performance_schema.session_account_connect_attrs WRITE;
+UNLOCK TABLES;
=== added file 'mysql-test/suite/perfschema/t/dml_session_connect_attrs.test'
--- a/mysql-test/suite/perfschema/t/dml_session_connect_attrs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/perfschema/t/dml_session_connect_attrs.test 2012-03-30 16:01:10 +0000
@@ -0,0 +1,38 @@
+--source include/not_embedded.inc
+--source include/have_perfschema.inc
+
+--disable_result_log
+SELECT * FROM performance_schema.session_connect_attrs
+ LIMIT 1;
+
+SELECT * FROM performance_schema.session_connect_attrs
+ where ATTR_NAME='FOO' OR ATTR_VALUE='BAR';
+--enable_result_log
+
+--error ER_TABLEACCESS_DENIED_ERROR
+INSERT INTO performance_schema.session_connect_attrs
+ SET ATTR_NAME='FOO', ATTR_VALUE='BAR',
+ ORDINAL_POSITION=100, PROCESS_ID=102;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+UPDATE performance_schema.session_connect_attrs
+ SET ATTR_NAME='FOO';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+UPDATE performance_schema.session_connect_attrs
+ SET ATTR_NAME='FOO' WHERE ATTR_VALUE='BAR';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+DELETE FROM performance_schema.session_connect_attrs
+ WHERE ATTR_VALUE='BAR';
+
+--error ER_TABLEACCESS_DENIED_ERROR
+DELETE FROM performance_schema.session_connect_attrs;
+
+-- error ER_TABLEACCESS_DENIED_ERROR
+LOCK TABLES performance_schema.session_connect_attrs READ;
+UNLOCK TABLES;
+
+-- error ER_TABLEACCESS_DENIED_ERROR
+LOCK TABLES performance_schema.session_connect_attrs WRITE;
+UNLOCK TABLES;
=== modified file 'mysql-test/t/variables.test'
--- a/mysql-test/t/variables.test 2011-11-10 06:53:27 +0000
+++ b/mysql-test/t/variables.test 2012-04-03 08:28:58 +0000
@@ -358,6 +358,8 @@ set tx_isolation="READ-COMMITTED";
set wait_timeout=100;
set global log_warnings=1;
+#restore the variable, since it introduces a degree of unpredictability
+set global max_allowed_packet =@my_max_allowed_packet;
#
# Bugs: #20392: INSERT_ID session variable has weird value
#
=== modified file 'mysys/psi_noop.c'
--- a/mysys/psi_noop.c 2012-04-03 21:19:04 +0000
+++ b/mysys/psi_noop.c 2012-05-02 11:04:32 +0000
@@ -622,6 +622,14 @@ digest_add_token_noop(PSI_digest_locker
return NULL;
}
+static int
+set_thread_connect_attrs_noop(const char *buffer __attribute__((unused)),
+ uint length __attribute__((unused)),
+ const void *from_cs __attribute__((unused)))
+{
+ return 0;
+}
+
static PSI PSI_noop=
{
register_mutex_noop,
@@ -717,7 +725,8 @@ static PSI PSI_noop=
set_socket_info_noop,
set_socket_thread_owner_noop,
digest_start_noop,
- digest_add_token_noop
+ digest_add_token_noop,
+ set_thread_connect_attrs_noop
};
/**
=== modified file 'scripts/mysql_system_tables.sql'
--- a/scripts/mysql_system_tables.sql 2012-05-28 09:09:33 +0000
+++ b/scripts/mysql_system_tables.sql 2012-05-28 10:46:55 +0000
@@ -1655,6 +1655,34 @@ PREPARE stmt FROM @str;
EXECUTE stmt;
DROP PREPARE stmt;
+--
+-- TABLE SESSION_CONNECT_ATTRS
+--
+
+SET @cmd="CREATE TABLE performance_schema.session_connect_attrs("
+ "PROCESSLIST_ID INT NOT NULL,"
+ "ATTR_NAME VARCHAR(32) NOT NULL,"
+ "ATTR_VALUE VARCHAR(1024),"
+ "ORDINAL_POSITION INT"
+ ")ENGINE=PERFORMANCE_SCHEMA CHARACTER SET utf8 COLLATE utf8_bin;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+--
+-- TABLE SESSION_ACCOUNT_CONNECT_ATTRS
+--
+
+SET @cmd="CREATE TABLE performance_schema.session_account_connect_attrs "
+ " LIKE performance_schema.session_connect_attrs;";
+
+SET @str = IF(@have_pfs = 1, @cmd, 'SET @dummy = 0');
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
CREATE TABLE IF NOT EXISTS proxies_priv (Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Proxied_host char(60) binary DEFAULT '' NOT NULL, Proxied_user char(16) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Timestamp timestamp, PRIMARY KEY Host (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='User proxy privileges';
-- Remember for later if proxies_priv table already existed
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c 2011-12-09 21:08:37 +0000
+++ b/sql-common/client.c 2012-05-02 14:54:35 +0000
@@ -34,6 +34,7 @@
#include <my_global.h>
#include "mysql.h"
+#include "hash.h"
/* Remove client convenience wrappers */
#undef max_allowed_packet
@@ -1056,14 +1057,22 @@ static int add_init_command(struct st_my
return 0;
}
+#define ALLOCATE_EXTENSIONS(OPTS) \
+ (OPTS)->extension= (struct st_mysql_options_extention *) \
+ my_malloc(sizeof(struct st_mysql_options_extention), \
+ MYF(MY_WME | MY_ZEROFILL)) \
+
+#define ENSURE_EXTENSIONS_PRESENT(OPTS) \
+ if (!(OPTS)->extension) \
+ ALLOCATE_EXTENSIONS(OPTS) \
+
+
#define EXTENSION_SET_STRING(OPTS, X, STR) \
if ((OPTS)->extension) \
my_free((OPTS)->extension->X); \
else \
- (OPTS)->extension= (struct st_mysql_options_extention *) \
- my_malloc(sizeof(struct st_mysql_options_extention), \
- MYF(MY_WME | MY_ZEROFILL)); \
- (OPTS)->extension->X= ((STR) != NULL) ? \
+ ALLOCATE_EXTENSIONS(OPTS); \
+ (OPTS)->extension->X= ((STR) != NULL) ? \
my_strdup((STR), MYF(MY_WME)) : NULL
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
@@ -2258,6 +2267,65 @@ struct st_mysql_client_plugin *mysql_cli
};
+static uchar *
+write_length_encoded_string(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_string(buf, key->str, key->length);
+ buf= write_length_encoded_string(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 {
@@ -2302,8 +2370,13 @@ static int send_change_user_packet(MCPVI
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 + data_len + 1 + NAME_LEN + 2 + NAME_LEN);
+ 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;
@@ -2340,6 +2413,8 @@ static int send_change_user_packet(MCPVI
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);
@@ -2348,6 +2423,9 @@ error:
return res;
}
+
+#define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
+
/**
sends a client authentication packet (second packet in the 3-way handshake)
@@ -2384,10 +2462,17 @@ static int send_client_reply_packet(MCPV
MYSQL *mysql= mpvio->mysql;
NET *net= &mysql->net;
char *buff, *end;
+ 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 */
- buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN);
-
+ buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN +
+ connect_attrs_len + 9 /* for the length of the attrs */);
+
mysql->client_flag|= mysql->options.client_flag;
mysql->client_flag|= CLIENT_CAPABILITIES;
@@ -2541,6 +2626,8 @@ static int send_client_reply_packet(MCPV
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))
{
@@ -2877,6 +2964,55 @@ int run_plugin_auth(MYSQL *mysql, char *
DBUG_RETURN (mysql->net.read_pos[0] != 0);
}
+
+/** 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, "_command_line");
+ 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__
+ rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "_command_line", GetCommandLine());
+
+ 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,
@@ -2909,6 +3045,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
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 */
@@ -3537,6 +3676,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
mysql->db, mysql->port, mysql->unix_socket,
mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
{
+ memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
+ mysql_close(&tmp_mysql);
mysql->net.last_errno= tmp_mysql.net.last_errno;
strmov(mysql->net.last_error, tmp_mysql.net.last_error);
strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
@@ -3633,6 +3774,7 @@ static void mysql_close_free_options(MYS
{
my_free(mysql->options.extension->plugin_dir);
my_free(mysql->options.extension->default_auth);
+ my_hash_free(&mysql->options.extension->connection_attributes);
my_free(mysql->options.extension);
}
memset(&mysql->options, 0, sizeof(mysql->options));
@@ -4129,6 +4271,149 @@ mysql_options(MYSQL *mysql,enum mysql_op
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:
+ 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);
}
=== modified file 'sql/client_settings.h'
--- a/sql/client_settings.h 2011-09-27 12:11:16 +0000
+++ b/sql/client_settings.h 2012-03-30 16:01:10 +0000
@@ -34,7 +34,8 @@
CLIENT_TRANSACTIONS | \
CLIENT_PROTOCOL_41 | \
CLIENT_SECURE_CONNECTION | \
- CLIENT_PLUGIN_AUTH)
+ CLIENT_PLUGIN_AUTH | \
+ CLIENT_CONNECT_ATTRS)
#define read_user_name(A) {}
#undef HAVE_SMEM
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2012-05-28 10:10:17 +0000
+++ b/sql/sql_acl.cc 2012-05-28 10:46:55 +0000
@@ -4675,14 +4675,12 @@ bool check_grant(THD *thd, ulong want_ac
{
case ACL_INTERNAL_ACCESS_GRANTED:
/*
- Currently,
- - the information_schema does not subclass ACL_internal_table_access,
- there are no per table privilege checks for I_S,
- - the performance schema does use per tables checks, but at most
- returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'.
- so this branch is not used.
+ Grant all access to the table to skip column checks.
+ Depend on the controls in the P_S table itself.
*/
- DBUG_ASSERT(0);
+ tl->grant.privilege|= TMP_TABLE_ACLS;
+ tl->grant.want_privilege= 0;
+ continue;
case ACL_INTERNAL_ACCESS_DENIED:
goto err;
case ACL_INTERNAL_ACCESS_CHECK_GRANT:
@@ -8571,6 +8569,44 @@ static bool find_mpvio_user(MPVIO_EXT *m
mpvio->acl_user->plugin.str));
DBUG_RETURN(0);
}
+
+
+static bool
+read_client_connect_attrs(char **ptr, size_t *max_bytes_available,
+ const CHARSET_INFO *from_cs)
+{
+ size_t length, length_length;
+ char *ptr_save;
+ /* not enough bytes to hold the length */
+ if (*max_bytes_available < 1)
+ return true;
+
+ /* read the length */
+ ptr_save= *ptr;
+ length= net_field_length_ll((uchar **) ptr);
+ length_length= *ptr - ptr_save;
+ if (*max_bytes_available < length_length)
+ return true;
+
+ *max_bytes_available-= length_length;
+
+ /* length says there're more data than can fit into the packet */
+ if (length > *max_bytes_available)
+ return true;
+
+ /* impose an artificial length limit of 64k */
+ if (length > 65535)
+ return true;
+
+#ifdef HAVE_PSI_THREAD_INTERFACE
+ if (PSI_THREAD_CALL(set_thread_connect_attrs)(*ptr, length, from_cs) && log_warnings)
+ sql_print_warning("Connection attributes of length %lu were truncated",
+ length);
+#endif
+ return false;
+}
+
+
#endif
/* the packet format is described in send_change_user_packet() */
@@ -8693,6 +8729,13 @@ static bool parse_com_change_user_packet
}
}
+ size_t bytes_remaining_in_packet= end - ptr;
+
+ if ((mpvio->client_capabilities & CLIENT_CONNECT_ATTRS) &&
+ read_client_connect_attrs(&ptr, &bytes_remaining_in_packet,
+ mpvio->charset_adapter->charset()))
+ return packet_error;
+
DBUG_PRINT("info", ("client_plugin=%s, restart", client_plugin));
/*
Remember the data part of the packet, to present it to plugin in
@@ -9078,6 +9121,11 @@ skip_to_ssl:
if (client_plugin == NULL)
client_plugin= &empty_c_string[0];
+ if ((mpvio->client_capabilities & CLIENT_CONNECT_ATTRS) &&
+ read_client_connect_attrs(&end, &bytes_remaining_in_packet,
+ mpvio->charset_adapter->charset()))
+ return packet_error;
+
char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
uint dummy_errors;
=== modified file 'storage/perfschema/CMakeLists.txt'
--- a/storage/perfschema/CMakeLists.txt 2012-02-28 14:40:36 +0000
+++ b/storage/perfschema/CMakeLists.txt 2012-05-04 10:54:36 +0000
@@ -118,6 +118,10 @@ table_tiws_by_index_usage.h
table_tiws_by_table.h
table_tlws_by_table.h
table_users.h
+cursor_by_thread_connect_attr.h
+table_session_connect.h
+table_session_connect_attrs.h
+table_session_account_connect_attrs.h
cursor_by_account.cc
cursor_by_host.cc
cursor_by_thread.cc
@@ -189,6 +193,10 @@ table_tiws_by_index_usage.cc
table_tiws_by_table.cc
table_tlws_by_table.cc
table_users.cc
+cursor_by_thread_connect_attr.cc
+table_session_connect.cc
+table_session_connect_attrs.cc
+table_session_account_connect_attrs.cc
)
MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY)
=== added file 'storage/perfschema/cursor_by_thread_connect_attr.cc'
--- a/storage/perfschema/cursor_by_thread_connect_attr.cc 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_thread_connect_attr.cc 2012-05-04 10:54:36 +0000
@@ -0,0 +1,74 @@
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_global.h"
+#include "cursor_by_thread_connect_attr.h"
+
+cursor_by_thread_connect_attr::cursor_by_thread_connect_attr(
+ const PFS_engine_table_share *share) :
+ PFS_engine_table(share, &m_pos), m_row_exists(false)
+{}
+
+int cursor_by_thread_connect_attr::rnd_next(void)
+{
+ PFS_thread *thread;
+ PFS_thread *current_thread= PFS_thread::get_current_thread();
+
+ for (m_pos.set_at(&m_next_pos);
+ m_pos.has_more_thread();
+ m_pos.next_thread())
+ {
+ thread= &thread_array[m_pos.m_index_1];
+
+ if (thread->m_lock.is_populated() && thread_fits(thread, current_thread))
+ {
+ make_row(thread, m_pos.m_index_2);
+ if (m_row_exists)
+ {
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ }
+ return HA_ERR_END_OF_FILE;
+}
+
+
+int cursor_by_thread_connect_attr::rnd_pos(const void *pos)
+{
+ PFS_thread *thread;
+ PFS_thread *current_thread= PFS_thread::get_current_thread();
+
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index_1 < thread_max);
+
+ thread= &thread_array[m_pos.m_index_1];
+ if (!thread->m_lock.is_populated() ||
+ !thread_fits(thread, current_thread))
+ return HA_ERR_RECORD_DELETED;
+
+ make_row(thread, m_pos.m_index_2);
+ if (m_row_exists)
+ return 0;
+
+ return HA_ERR_RECORD_DELETED;
+}
+
+
+void cursor_by_thread_connect_attr::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
=== added file 'storage/perfschema/cursor_by_thread_connect_attr.h'
--- a/storage/perfschema/cursor_by_thread_connect_attr.h 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/cursor_by_thread_connect_attr.h 2012-05-04 10:54:36 +0000
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef CURSOR_BY_THREAD_CONNECT_ATTR_H
+#define CURSOR_BY_THREAD_CONNECT_ATTR_H
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr.h"
+
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+struct pos_connect_attr_by_thread_by_attr
+: public PFS_double_index
+{
+ pos_connect_attr_by_thread_by_attr()
+ : PFS_double_index(0, 0)
+ {}
+
+ inline bool has_more_thread(void)
+ {
+ return (m_index_1 < thread_max);
+ }
+
+ inline void next_thread(void)
+ {
+ m_index_1++;
+ m_index_2= 0;
+ }
+
+ inline void reset(void)
+ {
+ m_index_1= 0;
+ m_index_2= 0;
+ }
+};
+
+/** Cursor CURSOR_BY_THREAD_CONNECT_ATTR. */
+class cursor_by_thread_connect_attr : public PFS_engine_table
+{
+public:
+ virtual int rnd_next();
+ virtual int rnd_pos(const void *pos);
+ virtual void reset_position(void);
+
+protected:
+ cursor_by_thread_connect_attr(const PFS_engine_table_share *share);
+
+public:
+ ~cursor_by_thread_connect_attr()
+ {}
+
+protected:
+ virtual void make_row(PFS_thread *thread, uint ordinal)= 0;
+ virtual bool thread_fits(PFS_thread *thread, PFS_thread *current_thread)= 0;
+ /** True if row exists */
+ bool m_row_exists;
+
+private:
+ /** Current position. */
+ pos_connect_attr_by_thread_by_attr m_pos;
+ /** Next position. */
+ pos_connect_attr_by_thread_by_attr m_next_pos;
+};
+
+/** @} */
+#endif
=== modified file 'storage/perfschema/pfs.cc'
--- a/storage/perfschema/pfs.cc 2012-05-22 17:44:21 +0000
+++ b/storage/perfschema/pfs.cc 2012-05-28 10:46:55 +0000
@@ -4918,6 +4918,37 @@ static void set_socket_thread_owner_v1(P
pfs_socket->m_thread_owner= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
}
+
+/**
+ Implementation of the thread attribute connection interface
+ @sa PSI_v1::set_thread_connect_attr.
+*/
+static int set_thread_connect_attrs_v1(const char *buffer, uint length,
+ const void *from_cs)
+{
+
+ PFS_thread *thd= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+
+ DBUG_ASSERT(buffer != NULL);
+
+ if (likely(thd != NULL))
+ {
+ /* copy from the input buffer as much as we can fit */
+ uint copy_size= length < (uint) sizeof(thd->m_connect_attrs) ?
+ length : (uint) sizeof(thd->m_connect_attrs);
+
+ thd->m_lock.allocated_to_dirty();
+ memcpy(thd->m_connect_attrs, buffer, copy_size);
+ thd->m_connect_attrs_length= copy_size;
+ thd->m_connect_attrs_cs= (const CHARSET_INFO *) from_cs;
+ thd->m_lock.dirty_to_allocated();
+
+ return (copy_size == length ? 0 : 1);
+ }
+ return 0;
+}
+
+
/**
Implementation of the instrumentation interface.
@sa PSI_v1.
@@ -5017,7 +5048,8 @@ PSI_v1 PFS_v1=
set_socket_info_v1,
set_socket_thread_owner_v1,
pfs_digest_start_v1,
- pfs_digest_add_token_v1
+ pfs_digest_add_token_v1,
+ set_thread_connect_attrs_v1,
};
static void* get_interface(int version)
=== modified file 'storage/perfschema/pfs_engine_table.cc'
--- a/storage/perfschema/pfs_engine_table.cc 2012-05-15 09:39:47 +0000
+++ b/storage/perfschema/pfs_engine_table.cc 2012-05-21 12:00:48 +0000
@@ -69,6 +69,8 @@
#include "table_socket_instances.h"
#include "table_socket_summary_by_instance.h"
#include "table_socket_summary_by_event_name.h"
+#include "table_session_connect_attrs.h"
+#include "table_session_account_connect_attrs.h"
/* For show status */
#include "pfs_column_values.h"
@@ -143,6 +145,8 @@ static PFS_engine_table_share *all_share
&table_socket_instances::m_share,
&table_socket_summary_by_instance::m_share,
&table_socket_summary_by_event_name::m_share,
+ &table_session_connect_attrs::m_share,
+ &table_session_account_connect_attrs::m_share,
NULL
};
=== modified file 'storage/perfschema/pfs_engine_table.h'
--- a/storage/perfschema/pfs_engine_table.h 2012-02-28 14:40:36 +0000
+++ b/storage/perfschema/pfs_engine_table.h 2012-03-30 16:01:10 +0000
@@ -263,7 +263,7 @@ public:
~PFS_readonly_acl()
{}
- ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
+ virtual ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
};
/** Singleton instance of PFS_readonly_acl. */
=== modified file 'storage/perfschema/pfs_instr.h'
--- a/storage/perfschema/pfs_instr.h 2012-05-15 09:39:47 +0000
+++ b/storage/perfschema/pfs_instr.h 2012-05-21 12:00:48 +0000
@@ -328,6 +328,13 @@ extern uint statement_stack_max;
/** The maximun number of passes in @sa PFS_scan. */
#define PFS_MAX_SCAN_PASS 2
+/**
+ @def MAX_CONNECT_ATTRS_BYTE_SIZE
+ The maximum number of bytes that will be reserved in each thread
+ for the connection attributes
+*/
+#define MAX_CONNECT_ATTRS_BYTE_SIZE 8192
+
/**
Helper to scan circular buffers.
Given a buffer of size [0, max_size - 1],
@@ -513,6 +520,13 @@ struct PFS_ALIGNED PFS_thread : PFS_conn
PFS_host *m_host;
PFS_user *m_user;
PFS_account *m_account;
+
+ /** a buffer for the connection attributes */
+ char m_connect_attrs[MAX_CONNECT_ATTRS_BYTE_SIZE];
+ /** length used by @c m_connect_attrs */
+ uint m_connect_attrs_length;
+ /** character set in which @c m_connect_attrs are encoded */
+ const CHARSET_INFO *m_connect_attrs_cs;
};
extern PFS_single_stat *global_instr_class_waits_array;
=== added file 'storage/perfschema/table_session_account_connect_attrs.cc'
--- a/storage/perfschema/table_session_account_connect_attrs.cc 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_account_connect_attrs.cc 2012-05-04 10:54:36 +0000
@@ -0,0 +1,68 @@
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "table_session_account_connect_attrs.h"
+
+THR_LOCK table_session_account_connect_attrs::m_table_lock;
+
+class PFS_readonly_world_acl : public PFS_readonly_acl
+{
+public:
+ PFS_readonly_world_acl()
+ {}
+
+ ~PFS_readonly_world_acl()
+ {}
+ virtual ACL_internal_access_result check(ulong want_access, ulong *save_priv) const
+ {
+ ACL_internal_access_result res= PFS_readonly_acl::check(want_access, save_priv);
+ if (res == ACL_INTERNAL_ACCESS_CHECK_GRANT)
+ res= ACL_INTERNAL_ACCESS_GRANTED;
+ return res;
+ }
+};
+
+PFS_readonly_world_acl pfs_readonly_world_acl;
+
+PFS_engine_table_share
+table_session_account_connect_attrs::m_share=
+{
+ { C_STRING_WITH_LEN("session_account_connect_attrs") },
+ &pfs_readonly_world_acl,
+ &table_session_account_connect_attrs::create,
+ NULL, /* write_row */
+ NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
+ 1000, /* records */
+ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */
+ &m_table_lock,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_session_account_connect_attrs::create()
+{
+ return new table_session_account_connect_attrs();
+}
+
+table_session_account_connect_attrs::table_session_account_connect_attrs()
+ : table_session_connect(&m_share)
+{}
+
+bool
+table_session_account_connect_attrs::thread_fits(PFS_thread *thread,
+ PFS_thread *current_thread){
+ return thread->m_account == current_thread->m_account;
+}
=== added file 'storage/perfschema/table_session_account_connect_attrs.h'
--- a/storage/perfschema/table_session_account_connect_attrs.h 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_account_connect_attrs.h 2012-05-04 10:54:36 +0000
@@ -0,0 +1,50 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_SESSION_ACCOUNT_CONNECT_ATTRS_H
+#define TABLE_SESSION_ACCOUNT_CONNECT_ATTRS_H
+
+#include "table_session_connect.h"
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+/** Table PERFORMANCE_SCHEMA.SESSION_ACCOUNT_CONNECT_ATTRS. */
+class table_session_account_connect_attrs : public table_session_connect
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ /** Table builder */
+ static PFS_engine_table* create();
+
+protected:
+ table_session_account_connect_attrs();
+
+public:
+ ~table_session_account_connect_attrs()
+ {}
+
+protected:
+ bool thread_fits(PFS_thread *thread, PFS_thread *current_thread);
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+};
+
+/** @} */
+#endif
=== added file 'storage/perfschema/table_session_connect.cc'
--- a/storage/perfschema/table_session_connect.cc 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_connect.cc 2012-05-04 10:54:36 +0000
@@ -0,0 +1,264 @@
+/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "table_session_connect.h"
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("PROCESS_ID") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ATTR_NAME") },
+ { C_STRING_WITH_LEN("varchar(32)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ATTR_VALUE") },
+ { C_STRING_WITH_LEN("varchar(1024)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ORDINAL_POSITION") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF table_session_connect::m_field_def=
+{ 4, field_types };
+
+table_session_connect::table_session_connect(const PFS_engine_table_share *share) :
+ cursor_by_thread_connect_attr(share)
+{}
+
+/**
+ Take a length encoded string
+
+ @arg ptr inout the input string array
+ @arg dest where to store the result
+ @arg dest_size max size of @c dest
+ @arg copied_len the actual length of the data copied
+ @arg start_ptr pointer to the start of input
+ @arg input_length the length of the incoming data
+ @arg copy_data copy the data or just skip the input
+ @arg from_cs character set in which @c ptr is encoded
+ @arg nchars_max maximum number of characters to read
+ @return status
+ @retval true parsing failed
+ @retval false parsing succeeded
+*/
+bool parse_length_encoded_string(const char **ptr,
+ char *dest, uint dest_size,
+ uint *copied_len,
+ const char *start_ptr, uint input_length,
+ bool copy_data,
+ const CHARSET_INFO *from_cs,
+ uint nchars_max)
+{
+ ulong copy_length, data_length;
+ const char *well_formed_error_pos= NULL, *cannot_convert_error_pos= NULL,
+ *from_end_pos= NULL;
+
+ copy_length= data_length= net_field_length((uchar **) ptr);
+
+ /* we don't tolerate NULL as a length */
+ if (data_length == NULL_LENGTH)
+ return true;
+
+ if (*ptr - start_ptr + data_length > input_length)
+ return true;
+
+ copy_length= well_formed_copy_nchars(&my_charset_utf8_bin, dest, dest_size,
+ from_cs, *ptr, data_length, nchars_max,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
+ *copied_len= copy_length;
+ (*ptr)+= data_length;
+
+ return false;
+}
+
+/**
+ Take the nth attribute name/value pair
+
+ Parse the attributes blob form the beginning, skipping the attributes
+ whose number is lower than the one we seek.
+ When we reach the attribute at an index we're looking for the values
+ are copied to the output parameters.
+ If parsing fails or no more attributes are found the function stops
+ and returns an error code.
+
+ @arg connect_attrs pointer to the connect attributes blob
+ @arg connect_attrs_length length of @c connect_attrs
+ @arg connect_attrs_cs character set used to encode @c connect_attrs
+ @arg ordinal index of the attribute we need
+ @arg attr_name [out] buffer to receive the attribute name
+ @arg max_attr_name max size of @c attr_name in bytes
+ @arg attr_name_length [out] number of bytes written in @attr_name
+ @arg attr_value [out] buffer to receive the attribute name
+ @arg max_attr_value max size of @c attr_value in bytes
+ @arg attr_value_length [out] number of bytes written in @attr_value
+ @return status
+ @retval true requested attribute pair is found and copied
+ @retval false error. Either because of parsing or too few attributes.
+*/
+bool read_nth_attr(const char *connect_attrs,
+ uint connect_attrs_length,
+ const CHARSET_INFO *connect_attrs_cs,
+ uint ordinal,
+ char *attr_name, uint max_attr_name,
+ uint *attr_name_length,
+ char *attr_value, uint max_attr_value,
+ uint *attr_value_length)
+{
+ uint idx;
+ const char *ptr;
+
+ for (ptr= connect_attrs, idx= 0;
+ (uint)(ptr - connect_attrs) < connect_attrs_length && idx <= ordinal;
+ idx++)
+ {
+ uint copy_length;
+ /* do the copying only if we absolutely have to */
+ bool fill_in_attr_name= idx == ordinal;
+ bool fill_in_attr_value= idx == ordinal;
+
+ /* read the key */
+ if (parse_length_encoded_string(&ptr,
+ attr_name, max_attr_name, ©_length,
+ connect_attrs,
+ connect_attrs_length,
+ fill_in_attr_name,
+ connect_attrs_cs, 32) ||
+ !copy_length
+ )
+ return false;
+
+ if (idx == ordinal)
+ *attr_name_length= copy_length;
+
+ /* read the value */
+ if (parse_length_encoded_string(&ptr,
+ attr_value, max_attr_value, ©_length,
+ connect_attrs,
+ connect_attrs_length,
+ fill_in_attr_value,
+ connect_attrs_cs, 1024))
+ return false;
+
+ if (idx == ordinal)
+ *attr_value_length= copy_length;
+
+ if (idx == ordinal)
+ return true;
+ }
+
+ return false;
+}
+
+void table_session_connect::make_row(PFS_thread *pfs, uint ordinal)
+{
+ pfs_lock lock;
+ PFS_thread_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against thread termination */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+ safe_class= sanitize_thread_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ /* populate the row */
+ if (read_nth_attr(pfs->m_connect_attrs, pfs->m_connect_attrs_length,
+ pfs->m_connect_attrs_cs,
+ ordinal,
+ m_row.m_attr_name, (uint) sizeof(m_row.m_attr_name),
+ &m_row.m_attr_name_length,
+ m_row.m_attr_value, (uint) sizeof(m_row.m_attr_value),
+ &m_row.m_attr_value_length))
+ {
+ /* we don't expect internal threads to have connection attributes */
+ DBUG_ASSERT(pfs->m_thread_id != 0);
+
+ m_row.m_ordinal_position= ordinal;
+ m_row.m_process_id= pfs->m_thread_id;
+ }
+ else
+ return;
+
+ if (pfs->m_lock.end_optimistic_lock(& lock))
+ m_row_exists= true;
+}
+
+int table_session_connect::read_row_values(TABLE *table,
+ unsigned char *buf,
+ Field **fields,
+ bool read_all)
+{
+ Field *f;
+
+ if (unlikely(!m_row_exists))
+ return HA_ERR_RECORD_DELETED;
+
+ /* Set the null bits */
+ DBUG_ASSERT(table->s->null_bytes == 1);
+ buf[0]= 0;
+
+ for (; (f= *fields) ; fields++)
+ {
+ if (read_all || bitmap_is_set(table->read_set, f->field_index))
+ {
+ switch(f->field_index)
+ {
+ case FO_PROCESS_ID:
+ if (m_row.m_process_id != 0)
+ set_field_ulong(f, m_row.m_process_id);
+ else
+ f->set_null();
+ break;
+ case FO_ATTR_NAME:
+ set_field_varchar_utf8(f, m_row.m_attr_name,
+ m_row.m_attr_name_length);
+ break;
+ case FO_ATTR_VALUE:
+ if (m_row.m_attr_value_length)
+ set_field_varchar_utf8(f, m_row.m_attr_value,
+ m_row.m_attr_value_length);
+ else
+ f->set_null();
+ break;
+ case FO_ORDINAL_POSITION:
+ set_field_ulong(f, m_row.m_ordinal_position);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+ return 0;
+}
+
+bool
+table_session_connect::thread_fits(PFS_thread *thread,
+ PFS_thread *current_thread)
+{
+ return true;
+}
+
=== added file 'storage/perfschema/table_session_connect.h'
--- a/storage/perfschema/table_session_connect.h 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_connect.h 2012-05-04 10:54:36 +0000
@@ -0,0 +1,77 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_SESSION_CONNECT_H
+#define TABLE_SESSION_CONNECT_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_thread_connect_attr.h"
+#include "table_helper.h"
+
+#define MAX_ATTR_NAME_CHARS 32
+#define MAX_ATTR_VALUE_CHARS 1024
+#define MAX_UTF8_BYTES 6
+
+/** symbolic names for field offsets, keep in sync with field_types */
+enum field_offsets {
+ FO_PROCESS_ID,
+ FO_ATTR_NAME,
+ FO_ATTR_VALUE,
+ FO_ORDINAL_POSITION
+};
+
+/**
+ A row of PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS and
+ PERFORMANCE_SCHEMA.SESSION_ACCOUNT_CONNECT_ATTRS.
+*/
+struct row_session_connect_attrs
+{
+ /** Column PROCESS_ID. */
+ ulong m_process_id;
+ /** Column ATTR_NAME. In UTF-8 */
+ char m_attr_name[MAX_ATTR_NAME_CHARS * MAX_UTF8_BYTES];
+ /** Length in bytes of @c m_attr_name. */
+ uint m_attr_name_length;
+ /** Column ATTR_VALUE. In UTF-8 */
+ char m_attr_value[MAX_ATTR_VALUE_CHARS * MAX_UTF8_BYTES];
+ /** Length in bytes of @c m_attr_name. */
+ uint m_attr_value_length;
+ /** Column ORDINAL_POSITION. */
+ ulong m_ordinal_position;
+};
+
+class table_session_connect : public cursor_by_thread_connect_attr
+{
+protected:
+ table_session_connect(const PFS_engine_table_share *share);
+
+public:
+ ~table_session_connect()
+ {}
+
+protected:
+ virtual void make_row(PFS_thread *pfs, uint ordinal);
+ virtual bool thread_fits(PFS_thread *thread, PFS_thread *current_thread);
+ virtual int read_row_values(TABLE *table, unsigned char *buf,
+ Field **fields, bool read_all);
+protected:
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+ /** Current row. */
+ row_session_connect_attrs m_row;
+};
+
+/** @} */
+#endif
=== added file 'storage/perfschema/table_session_connect_attrs.cc'
--- a/storage/perfschema/table_session_connect_attrs.cc 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_connect_attrs.cc 2012-05-04 10:54:36 +0000
@@ -0,0 +1,43 @@
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "table_session_connect_attrs.h"
+
+THR_LOCK table_session_connect_attrs::m_table_lock;
+
+PFS_engine_table_share
+table_session_connect_attrs::m_share=
+{
+ { C_STRING_WITH_LEN("session_connect_attrs") },
+ &pfs_readonly_acl,
+ &table_session_connect_attrs::create,
+ NULL, /* write_row */
+ NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
+ 1000, /* records */
+ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */
+ &m_table_lock,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_session_connect_attrs::create()
+{
+ return new table_session_connect_attrs();
+}
+
+table_session_connect_attrs::table_session_connect_attrs()
+ : table_session_connect(&m_share)
+{}
=== added file 'storage/perfschema/table_session_connect_attrs.h'
--- a/storage/perfschema/table_session_connect_attrs.h 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/table_session_connect_attrs.h 2012-05-04 10:54:36 +0000
@@ -0,0 +1,47 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#ifndef TABLE_SESSION_CONNECT_ATTRS_H
+#define TABLE_SESSION_CONNECT_ATTRS_H
+
+#include "table_session_connect.h"
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+/** Table PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS. */
+class table_session_connect_attrs : public table_session_connect
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ /** Table builder */
+ static PFS_engine_table* create();
+
+protected:
+ table_session_connect_attrs();
+
+public:
+ ~table_session_connect_attrs()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+};
+
+/** @} */
+#endif
=== modified file 'storage/perfschema/unittest/CMakeLists.txt'
--- a/storage/perfschema/unittest/CMakeLists.txt 2011-07-29 09:10:56 +0000
+++ b/storage/perfschema/unittest/CMakeLists.txt 2012-04-02 14:48:44 +0000
@@ -43,3 +43,12 @@ SET(tests
FOREACH(testname ${tests})
PFS_ADD_TEST(${testname})
ENDFOREACH()
+
+IF(WIN32)
+ SET(MYSQLD_EXTRA_SOURCES ${CMAKE_SOURCE_DIR}/sql/nt_servc.cc ${CMAKE_SOURCE_DIR}/sql/nt_servc.h)
+ENDIF()
+
+# we need the server libs to test the blob parser
+ADD_EXECUTABLE(pfs_connect_attr-t pfs_connect_attr-t.cc ${MYSQLD_EXTRA_SOURCES})
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t mytap perfschema sql binlog rpl master slave sql mysys ${SSL_LIBRARIES})
+ADD_TEST(pfs_connect_attr pfs_connect_attr-t)
=== added file 'storage/perfschema/unittest/pfs_connect_attr-t.cc'
--- a/storage/perfschema/unittest/pfs_connect_attr-t.cc 1970-01-01 00:00:00 +0000
+++ b/storage/perfschema/unittest/pfs_connect_attr-t.cc 2012-05-24 13:03:41 +0000
@@ -0,0 +1,345 @@
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_server.h>
+#include <pfs_instr_class.h>
+#include <pfs_instr.h>
+#include <pfs_global.h>
+#include <tap.h>
+
+
+#include <string.h>
+#include <memory.h>
+
+/* test helpers, to inspect data */
+bool read_nth_attr(const char *connect_attrs, uint connect_attrs_length,
+ const CHARSET_INFO *connect_attrs_cs,
+ uint ordinal,
+ char *attr_name, uint max_attr_name,
+ uint *attr_name_length,
+ char *attr_value, uint max_attr_value,
+ uint *attr_value_length);
+
+void test_blob_parser()
+{
+ char name[100], value[4096];
+ unsigned char packet[10000], *ptr;
+ uint name_len, value_len, idx, packet_length;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ diag("test_blob_parser");
+
+ result= read_nth_attr("", 0, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "zero length blob");
+
+
+ result= read_nth_attr("\x1", 1, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid key length");
+
+
+ result= read_nth_attr("\x2k1\x1", 4, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid value length");
+
+
+ result= read_nth_attr("\x2k1\x2v1", 6, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "one pair return");
+ ok(name_len == 2, "one pair attr name length");
+ ok(!strncmp(name, "k1", name_len), "one pair attr name");
+ ok(value_len == 2, "one pair value length");
+ ok(!strncmp(value, "v1", value_len), "one pair value");
+
+ result= read_nth_attr("\x2k1\x2v1", 6, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "no second arg");
+
+ result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 12, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "two pairs return");
+ ok(name_len == 2, "two pairs attr name length");
+ ok(!strncmp(name, "k2", name_len), "two pairs attr name");
+ ok(value_len == 2, "two pairs value length");
+ ok(!strncmp(value, "v2", value_len), "two pairs value");
+
+ result= read_nth_attr("\x2k1\xff\x2k2\x2v2", 12, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "two pairs first value bad return");
+
+ result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 10, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "two pairs wrong global length");
+
+ result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1", 37, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "attr name overflow");
+ ok(name_len == 32, "attr name overflow length");
+ ok(!strncmp(name, "z123456789z123456789z123456789z1", name_len),
+ "attr name overflow name");
+ ok(value_len == 2, "attr name overflow value length");
+ ok(!strncmp(value, "v1", value_len), "attr name overflow value");
+
+ packet[0]= 2;
+ packet[1]= 'k';
+ packet[2]= '1';
+ ptr= net_store_length(packet + 3, 1025);
+ for (idx= 0; idx < 1025; idx++)
+ *ptr++= '0' + (idx % 10);
+ packet_length= (uint) (ptr - packet);
+ result= read_nth_attr((char *) packet, packet_length, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "attr value overflow");
+ ok(name_len == 2, "attr value overflow length");
+ ok(!strncmp(name, "k1", name_len), "attr value overflow name");
+ ok(value_len == 1024, "attr value overflow value length");
+ for (idx= 0; idx < 1024; idx++)
+ {
+ if (value[idx] != (char) ('0' + (idx % 10)))
+ break;
+ }
+ ok (idx == 1024, "attr value overflow value");
+
+ result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1\x2k2\x2v2",
+ 43, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "prev attr name overflow");
+ ok(name_len == 2, "prev attr name overflow length");
+ ok(!strncmp(name, "k2", name_len),
+ "prev attr name overflow name");
+ ok(value_len == 2, "prev attr name overflow value length");
+ ok(!strncmp(value, "v2", value_len), "prev attr name overflow value");
+
+
+ packet[1]= 'k';
+ packet[2]= '1';
+ packet[3]= 2;
+ packet[4]= 'v';
+ packet[5]= '1';
+
+ for(idx= 251; idx < 256; idx++)
+ {
+ packet[0]= idx;
+ result= read_nth_attr((char *) packet, 6, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid string length %d", idx);
+ }
+
+ memset(packet, 0, sizeof(packet));
+ for (idx=0; idx < 1660 /* *6 = 9960 */; idx++)
+ memcpy(packet + idx * 6, "\x2k1\x2v1", 6);
+ result= read_nth_attr((char *) packet, 8192, cs, 1364,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "last valid attribute %d", 1364);
+ result= read_nth_attr((char *) packet, 8192, cs, 1365,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "first attribute that's cut %d", 1365);
+}
+
+void test_multibyte_lengths()
+{
+ char name[100], value[4096];
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ unsigned char var_len_packet[] = {
+ 252, 2, 0, 'k', '1',
+ 253, 2, 0, 0, 'v', '1',
+ 254, 2, 0, 0, 0, 0, 0, 0, 0, 'k', '2',
+ 254, 2, 0, 0, 0, 0, 0, 0, 0, 'v', '2'
+ };
+
+ result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "multibyte lengths return");
+ ok(name_len == 2, "multibyte lengths name length");
+ ok(!strncmp(name, "k1", name_len), "multibyte lengths attr name");
+ ok(value_len == 2, "multibyte lengths value length");
+ ok(!strncmp(value, "v1", value_len), "multibyte lengths value");
+
+ result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "multibyte lengths second attr return");
+ ok(name_len == 2, "multibyte lengths second attr name length");
+ ok(!strncmp(name, "k2", name_len), "multibyte lengths second attr attr name");
+ ok(value_len == 2, "multibyte lengths value length");
+ ok(!strncmp(value, "v2", value_len), "multibyte lengths second attr value");
+}
+
+
+void test_utf8_parser()
+{
+ /* utf8 max byte length per character is 6 */
+ char name[33 * 6], value[1024 * 6], packet[1500 * 6], *ptr;
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ /* note : this is encoded in utf-8 */
+ const char *attr1= "���������������";
+ const char *attr2= "��������������";
+ const char *val2= "����������������";
+
+ ptr= packet;
+ *ptr++= strlen(attr1);
+ memcpy(ptr, attr1, strlen(attr1));
+ ptr+= strlen(attr1);
+ *ptr++= strlen(val1);
+ memcpy(ptr, val1, strlen(val1));
+ ptr+= strlen(val1);
+
+ *ptr++= strlen(attr2);
+ memcpy(ptr, attr2, strlen(attr2));
+ ptr+= strlen(attr2);
+ *ptr++= strlen(val2);
+ memcpy(ptr, val2, strlen(val2));
+ ptr+= strlen(val2);
+
+ diag("test_utf8_parser attr pair #1");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ ok(name_len == strlen(attr1), "name length");
+ ok(!strncmp(name, attr1, name_len), "attr name");
+ ok(value_len == strlen(val1), "value length");
+ ok(!strncmp(value, val1, value_len), "value");
+
+ diag("test_utf8_parser attr pair #2");
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 1,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ ok(name_len == strlen(attr2), "name length");
+ ok(!strncmp(name, attr2, name_len), "attr name");
+ ok(value_len == strlen(val2), "value length");
+ ok(!strncmp(value, val2, value_len), "value");
+}
+
+
+void test_utf8_parser_bad_encoding()
+{
+ /* utf8 max byte length per character is 3*/
+ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr;
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ /* note : this is encoded in utf-8 */
+ const char *attr= "������������";
+ const char *val= "�������������ptr, attr, strlen(attr));
+ ptr[0]= 0xFA; // invalid UTF-8 char
+ ptr+= strlen(attr);
+ *ptr++= strlen(val);
+ memcpy(ptr, val, strlen(val));
+ ptr+= strlen(val);
+
+ diag("test_utf8_parser_bad_encoding");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == false, "return");
+}
+
+const CHARSET_INFO *cs_cp1251;
+
+void test_cp1251_parser()
+{
+ /* utf8 max byte length per character is 3*/
+ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr;
+ uint name_len, value_len;
+ bool result;
+
+ /* note : this is ������������ in windows-1251 */
+ const char *attr1= "\xc3\xe5\xee\xf0\xe3\xe8";
+ /* note : this is �������������� in windows-1251 */
+ const char *val1= "\xca\xee\xe4\xe8\xed\xee\xe2";
+ /* note : this is ����������f\xeb\xee\xe2\xe4\xe8\xe2";
+ /* note : this is ��*/
+ const char *val2= "\xc1\xfa\xeb\xe3\xe0\xf0\xe8\xff";
+
+ ptr= packet;
+ *ptr++= strlen(attr1);
+ memcpy(ptr, attr1, strlen(attr1));
+ ptr+= strlen(attr1);
+ *ptr++= strlen(val1);
+ memcpy(ptr, val1, strlen(val1));
+ ptr+= strlen(val1);
+
+ *ptr++= strlen(attr2);
+ memcpy(ptr, attr2, strlen(attr2));
+ ptr+= strlen(attr2);
+ *ptr++= strlen(val2);
+ memcpy(ptr, val2, strlen(val2));
+ ptr+= strlen(val2);
+
+ diag("test_cp1251_parser attr pair #1");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ /* need to compare to the UTF-8 equivalents */
+ ok(name_len == strlen("����������ok(value_len == strlen("��������������"), "value length");
+ ok(!strncmp(value, "�ue");
+
+ diag("test_cp1251_parser attr pair #2");
+ result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 1,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ /* need to compare to the UTF-8 equivalents */
+ ok(name_len == strlen("��������������"), "name length");
+ ok(!strncmp(name, "��������len == strlen("����������������"), "value length");
+ ok(!strncmp(value, "��value");
+}
+
+
+void do_all_tests()
+{
+ test_blob_parser();
+ test_multibyte_lengths();
+ test_utf8_parser();
+ test_utf8_parser_bad_encoding();
+ test_cp1251_parser();
+}
+
+int main(int, char **)
+{
+ MY_INIT("pfs_connect_attr-t");
+
+ cs_cp1251= get_charset_by_csname("cp1251", MY_CS_PRIMARY, MYF(0));
+ if (!cs_cp1251)
+ diag("skipping the cp1251 tests : missing character set");
+ plan(59 + (cs_cp1251 ? 10 : 0));
+ do_all_tests();
+ return 0;
+}
=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c 2012-03-06 14:29:42 +0000
+++ b/tests/mysql_client_test.c 2012-05-02 11:04:32 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) l_mysql, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -116,7 +116,7 @@ if (!opt_silent) \
fprintf(stdout, " \n#####################################\n"); \
}
-static void print_error(const char *msg);
+static void print_error(MYSQL * l_mysql, const char *msg);
static void print_st_error(MYSQL_STMT *stmt, const char *msg);
static void client_disconnect(MYSQL* mysql, my_bool drop_db);
static void get_options(int *argc, char ***argv);
@@ -149,7 +149,8 @@ static void die(const char *file, int li
}
-#define myerror(msg) print_error(msg)
+#define myerror(msg) print_error(mysql,msg)
+#define myerror2(l_mysql, msg) print_error(l_mysql,msg)
#define mysterror(stmt, msg) print_st_error(stmt, msg)
#define myquery(RES) \
@@ -160,6 +161,14 @@ static void die(const char *file, int li
DIE_UNLESS(r == 0); \
}
+#define myquery2(L_MYSQL,RES) \
+{ \
+ int r= (RES); \
+ if (r) \
+ myerror2(L_MYSQL,NULL); \
+ DIE_UNLESS(r == 0); \
+}
+
#define myquery_r(r) \
{ \
if (r) \
@@ -209,17 +218,17 @@ static int cmp_double(double *a, double
/* Print the error message */
-static void print_error(const char *msg)
+static void print_error(MYSQL *l_mysql, const char *msg)
{
if (!opt_silent)
{
- if (mysql && mysql_errno(mysql))
+ if (l_mysql && mysql_errno(l_mysql))
{
if (mysql->server_version)
fprintf(stdout, "\n [MySQL-%s]", mysql->server_version);
else
fprintf(stdout, "\n [MySQL]");
- fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql));
+ fprintf(stdout, "[%d] %s\n", mysql_errno(l_mysql), mysql_error(l_mysql));
}
else if (msg)
fprintf(stderr, " [MySQL] %s\n", msg);
@@ -20165,6 +20174,119 @@ static void test_wl5968()
}
+/*
+ WL#5924: Add connect string processing to mysql
+*/
+static void test_wl5924()
+{
+ int rc;
+ MYSQL *l_mysql;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+
+ myheader("test_wl5924");
+ l_mysql= mysql_client_init(NULL);
+ DIE_UNLESS(l_mysql != NULL);
+
+ /* we want a non-default character set */
+ rc= mysql_set_character_set(l_mysql, "cp1251");
+ DIE_UNLESS(rc == 0);
+
+ /* put in an attr */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key1", "value1");
+ DIE_UNLESS(rc == 0);
+
+ /* put a second attr */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key2", "value2");
+ DIE_UNLESS(rc == 0);
+
+ /* put the second attr again : should fail */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key2", "value2");
+ DIE_UNLESS(rc != 0);
+
+ /* delete the second attr */
+ rc= mysql_options(l_mysql, MYSQL_OPT_CONNECT_ATTR_DELETE,
+ "key2");
+ DIE_UNLESS(rc == 0);
+
+ /* put the second attr again : should pass */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key2", "value2");
+ DIE_UNLESS(rc == 0);
+
+ /* full reset */
+ rc= mysql_options(l_mysql, MYSQL_OPT_CONNECT_ATTR_RESET, NULL);
+ DIE_UNLESS(rc == 0);
+
+ /* put the second attr again : should pass */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key2", "value2");
+ DIE_UNLESS(rc == 0);
+
+ /* full reset */
+ rc= mysql_options(l_mysql, MYSQL_OPT_CONNECT_ATTR_RESET, NULL);
+ DIE_UNLESS(rc == 0);
+
+ /* add a third attr */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key3", "value3");
+ DIE_UNLESS(rc == 0);
+
+ /* add a fourth attr */
+ rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "key4", "value4");
+ DIE_UNLESS(rc == 0);
+
+ /* add a non-ascii attr */
+ /* note : this is ������������, �� rc= mysql_options4(l_mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "\xc3\xe5\xee\xf0\xe3\xe8",
+ "\xca\xee\xe4\xe8\xed\xee\xe2");
+ DIE_UNLESS(rc == 0);
+
+ l_mysql= mysql_real_connect(l_mysql, opt_host, opt_user,
+ opt_password, current_db, opt_port,
+ opt_unix_socket, 0);
+ DIE_UNLESS(l_mysql != 0);
+
+ rc= mysql_query(l_mysql,
+ "SELECT ATTR_NAME, ATTR_VALUE "
+ " FROM performance_schema.session_account_connect_attrs"
+ " WHERE ATTR_NAME IN ('key1','key2','key3','key4',"
+ " '\xc3\xe5\xee\xf0\xe3\xe8') AND"
+ " PROCESSLIST_ID = CONNECTION_ID() ORDER BY ATTR_NAME");
+ myquery2(l_mysql,rc);
+ res= mysql_use_result(l_mysql);
+ DIE_UNLESS(res);
+
+ row= mysql_fetch_row(res);
+ DIE_UNLESS(row);
+ DIE_UNLESS(0 == strcmp(row[0], "key3"));
+ DIE_UNLESS(0 == strcmp(row[1], "value3"));
+
+ row= mysql_fetch_row(res);
+ DIE_UNLESS(row);
+ DIE_UNLESS(0 == strcmp(row[0], "key4"));
+ DIE_UNLESS(0 == strcmp(row[1], "value4"));
+
+ row= mysql_fetch_row(res);
+ DIE_UNLESS(row);
+ DIE_UNLESS(0 == strcmp(row[0], "\xc3\xe5\xee\xf0\xe3\xe8"));
+ DIE_UNLESS(0 == strcmp(row[1], "\xca\xee\xe4\xe8\xed\xee\xe2"));
+
+ mysql_free_result(res);
+
+ l_mysql->reconnect= 1;
+ rc= mysql_reconnect(l_mysql);
+ myquery2(l_mysql,rc);
+
+ mysql_close(l_mysql);
+}
+
+
static struct my_option client_test_long_options[] =
{
{"basedir", 'b', "Basedir for tests.", &opt_basedir,
@@ -20512,6 +20634,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug11754979", test_bug11754979 },
{ "test_bug13001491", test_bug13001491 },
{ "test_wl5968", test_wl5968 },
+ { "test_wl5924", test_wl5924 },
{ 0, 0 }
};
No bundle (reason: useless for push emails).| Thread |
|---|
| • bzr push into mysql-trunk branch (Georgi.Kodinov:3910) | Georgi Kodinov | 28 May |