summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/mysql-test-run.sh2
-rw-r--r--mysql-test/r/init_connect.result24
-rw-r--r--mysql-test/r/rpl_init_slave.result23
-rw-r--r--mysql-test/t/init_connect-master.opt1
-rw-r--r--mysql-test/t/init_connect.test34
-rw-r--r--mysql-test/t/rpl_init_slave-slave.opt1
-rw-r--r--mysql-test/t/rpl_init_slave.test26
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/mysqld.cc30
-rw-r--r--sql/set_var.cc74
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/slave.cc12
-rw-r--r--sql/sql_parse.cc43
-rw-r--r--sql/sql_show.cc15
14 files changed, 278 insertions, 14 deletions
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 29cd7a05f7d..c3bba8d7a70 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -805,7 +805,7 @@ manager_launch()
ident=$1
shift
if [ $USE_MANAGER = 0 ] ; then
- $@ >> $CUR_MYERR 2>&1 &
+ echo $@ | /bin/sh >> $CUR_MYERR 2>&1 &
sleep 2 #hack
return
fi
diff --git a/mysql-test/r/init_connect.result b/mysql-test/r/init_connect.result
new file mode 100644
index 00000000000..3f8e726c775
--- /dev/null
+++ b/mysql-test/r/init_connect.result
@@ -0,0 +1,24 @@
+select hex(@a);
+hex(@a)
+NULL
+select hex(@a);
+hex(@a)
+610063
+set global init_connect="set @a=2;set @b=3";
+select @a, @b;
+@a @b
+2 3
+set GLOBAL init_connect=DEFAULT;
+select @a;
+@a
+NULL
+set global init_connect="create table t1(a char(10));\
+insert into t1 values ('\0');insert into t1 values('abc')";
+select hex(a) from t1;
+hex(a)
+00
+616263
+set GLOBAL init_connect="adsfsdfsdfs";
+select @a;
+ERROR HY000: Lost connection to MySQL server during query
+drop table t1;
diff --git a/mysql-test/r/rpl_init_slave.result b/mysql-test/r/rpl_init_slave.result
new file mode 100644
index 00000000000..a91b2da85cd
--- /dev/null
+++ b/mysql-test/r/rpl_init_slave.result
@@ -0,0 +1,23 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+reset master;
+create table t1(n int);
+insert into t1 values (@a), (@b);
+select * from t1;
+n
+NULL
+NULL
+select * from t1;
+n
+1
+2
+set global init_connect="set @c=1";
+show variables like 'init_connect';
+Variable_name Value
+init_connect set @c=1
+drop table t1;
+stop slave;
diff --git a/mysql-test/t/init_connect-master.opt b/mysql-test/t/init_connect-master.opt
new file mode 100644
index 00000000000..e3316c2def5
--- /dev/null
+++ b/mysql-test/t/init_connect-master.opt
@@ -0,0 +1 @@
+--set-variable=init_connect="set @a='a\0c'"
diff --git a/mysql-test/t/init_connect.test b/mysql-test/t/init_connect.test
new file mode 100644
index 00000000000..563ec6178d0
--- /dev/null
+++ b/mysql-test/t/init_connect.test
@@ -0,0 +1,34 @@
+#
+# Test of init_connect variable
+#
+
+connect (con0,localhost,root,,);
+connection con0;
+select hex(@a);
+connect (con1,localhost,user_1,,);
+connection con1;
+select hex(@a);
+connection con0;
+set global init_connect="set @a=2;set @b=3";
+connect (con2,localhost,user_1,,);
+connection con2;
+select @a, @b;
+connection con0;
+set GLOBAL init_connect=DEFAULT;
+connect (con3,localhost,user_1,,);
+connection con3;
+select @a;
+connection con0;
+set global init_connect="create table t1(a char(10));\
+insert into t1 values ('\0');insert into t1 values('abc')";
+connect (con4,localhost,user_1,,);
+connection con4;
+select hex(a) from t1;
+connection con0;
+set GLOBAL init_connect="adsfsdfsdfs";
+connect (con5,localhost,user_1,,);
+connection con5;
+--error 2013
+select @a;
+connection con0;
+drop table t1;
diff --git a/mysql-test/t/rpl_init_slave-slave.opt b/mysql-test/t/rpl_init_slave-slave.opt
new file mode 100644
index 00000000000..6433dccf4aa
--- /dev/null
+++ b/mysql-test/t/rpl_init_slave-slave.opt
@@ -0,0 +1 @@
+--init-slave="set @a=1;set @b=2"
diff --git a/mysql-test/t/rpl_init_slave.test b/mysql-test/t/rpl_init_slave.test
new file mode 100644
index 00000000000..67d35546225
--- /dev/null
+++ b/mysql-test/t/rpl_init_slave.test
@@ -0,0 +1,26 @@
+source include/master-slave.inc;
+
+#
+# Test of init_slave variable
+#
+
+save_master_pos;
+connection slave;
+sync_with_master;
+reset master;
+connection master;
+create table t1(n int);
+insert into t1 values (@a), (@b);
+select * from t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t1;
+set global init_connect="set @c=1";
+show variables like 'init_connect';
+connection master;
+drop table t1;
+save_master_pos;
+connection slave;
+sync_with_master;
+stop slave;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 62494da45d4..7164a4e496d 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -554,6 +554,8 @@ bool wait_for_tables(THD *thd);
bool table_is_used(TABLE *table, bool wait_for_name_lock);
bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
+void execute_init_command(THD *thd, sys_var_str *init_command_var,
+ rw_lock_t *var_mutex);
extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
TABLE_LIST **where, bool report_error);
@@ -846,7 +848,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager,
LOCK_global_system_variables, LOCK_user_conn;
-extern rw_lock_t LOCK_grant;
+extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_attr_t connection_attrib;
extern I_List<THD> threads;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5a931ffad8e..d861b073b6e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -316,7 +316,8 @@ char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN];
char* log_error_file_ptr= log_error_file;
char mysql_real_data_home[FN_REFLEN],
language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
- max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file;
+ max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file,
+ *opt_init_connect, *opt_init_slave;
const char *opt_date_time_formats[3];
@@ -375,7 +376,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
-rw_lock_t LOCK_grant;
+rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped,
COND_slave_start;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
@@ -923,6 +924,8 @@ void clean_up(bool print_message)
MYF(MY_ALLOW_ZERO_PTR));
if (defaults_argv)
free_defaults(defaults_argv);
+ my_free(sys_init_connect.value, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sys_init_slave.value, MYF(MY_ALLOW_ZERO_PTR));
free_tmpdir(&mysql_tmpdir_list);
#ifdef HAVE_REPLICATION
my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
@@ -994,6 +997,8 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_rpl_status);
#endif
(void) pthread_mutex_destroy(&LOCK_active_mi);
+ (void) rwlock_destroy(&LOCK_sys_init_connect);
+ (void) rwlock_destroy(&LOCK_sys_init_slave);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
@@ -2173,7 +2178,16 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.collation_database= default_charset_info;
global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
- global_system_variables.character_set_client= default_charset_info;
+ global_system_variables.character_set_client= default_charset_info;
+ global_system_variables.collation_connection= default_charset_info;
+
+ sys_init_connect.value_length= 0;
+ if ((sys_init_connect.value= opt_init_connect))
+ sys_init_connect.value_length= strlen(opt_init_connect);
+
+ sys_init_slave.value_length= 0;
+ if ((sys_init_slave.value= opt_init_slave))
+ sys_init_slave.value_length= strlen(opt_init_slave);
if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
@@ -2200,6 +2214,8 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ (void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
+ (void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
(void) my_rwlock_init(&LOCK_grant, NULL);
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
@@ -3640,6 +3656,8 @@ enum options_mysqld
OPT_EXPIRE_LOGS_DAYS,
OPT_GROUP_CONCAT_MAX_LEN,
OPT_DEFAULT_COLLATION,
+ OPT_INIT_CONNECT,
+ OPT_INIT_SLAVE,
OPT_SECURE_AUTH,
OPT_DATE_FORMAT,
OPT_TIME_FORMAT,
@@ -3816,6 +3834,12 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &innobase_file_per_table,
(gptr*) &innobase_file_per_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif /* End HAVE_INNOBASE_DB */
+ {"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection",
+ (gptr*) &opt_init_connect, (gptr*) &opt_init_connect, 0, GET_STR_ALLOC,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed when a slave connects to this master",
+ (gptr*) &opt_init_slave, (gptr*) &opt_init_slave, 0, GET_STR_ALLOC,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"help", '?', "Display this help and exit.",
(gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
diff --git a/sql/set_var.cc b/sql/set_var.cc
index e46fe9729d5..04bd232d0b7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -76,6 +76,10 @@ TYPELIB delay_key_write_typelib=
static bool sys_check_charset(THD *thd, set_var *var);
static bool sys_update_charset(THD *thd, set_var *var);
static void sys_set_default_charset(THD *thd, enum_var_type type);
+static bool sys_update_init_connect(THD*, set_var*);
+static void sys_default_init_connect(THD*, enum_var_type type);
+static bool sys_update_init_slave(THD*, set_var*);
+static void sys_default_init_slave(THD*, enum_var_type type);
static bool set_option_bit(THD *thd, set_var *var);
static bool set_option_autocommit(THD *thd, set_var *var);
static bool set_log_update(THD *thd, set_var *var);
@@ -113,6 +117,12 @@ sys_var_str sys_charset_system("character_set_system",
sys_check_charset,
sys_update_charset,
sys_set_default_charset);
+sys_var_str sys_init_connect("init_connect", 0,
+ sys_update_init_connect,
+ sys_default_init_connect);
+sys_var_str sys_init_slave("init_slave", 0,
+ sys_update_init_slave,
+ sys_default_init_slave);
sys_var_character_set_database sys_character_set_database("character_set_database");
sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection");
@@ -435,6 +445,8 @@ sys_var *sys_variables[]=
&sys_foreign_key_checks,
&sys_group_concat_max_len,
&sys_identity,
+ &sys_init_connect,
+ &sys_init_slave,
&sys_insert_id,
&sys_interactive_timeout,
&sys_join_buffer_size,
@@ -587,6 +599,8 @@ struct show_var_st init_vars[]= {
{"have_openssl", (char*) &have_openssl, SHOW_HAVE},
{"have_query_cache", (char*) &have_query_cache, SHOW_HAVE},
{"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
+ {"init_connect", (char*) &sys_init_connect, SHOW_SYS},
+ {"init_slave", (char*) &sys_init_slave, SHOW_SYS},
#ifdef HAVE_INNOBASE_DB
{"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
{"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG },
@@ -756,6 +770,66 @@ bool sys_var::check(THD *thd, set_var *var)
Functions to check and update variables
*/
+
+/*
+ Update variables 'init_connect, init_slave'.
+
+ In case of 'DEFAULT' value
+ (for example: 'set GLOBAL init_connect=DEFAULT')
+ 'var' parameter is NULL pointer.
+*/
+
+bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex,
+ set_var *var)
+{
+ char *res= 0, *old_value;
+ uint new_length= 0;
+ /* If the string is "", delete old init command */
+ if (var && (new_length= var->value->str_value.length()))
+ {
+ if (!(res= my_strdup_with_length(var->value->str_value.ptr(),
+ new_length,
+ MYF(0))))
+ return 1;
+ }
+ /*
+ Replace the old value in such a way that the any thread using
+ the value will work.
+ */
+ rw_wrlock(var_mutex);
+ old_value= var_str->value;
+ var_str->value= res;
+ var_str->value_length= new_length;
+ rw_unlock(var_mutex);
+ my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
+ return 0;
+}
+
+
+static bool sys_update_init_connect(THD *thd, set_var *var)
+{
+ return update_sys_var_str(&sys_init_connect, &LOCK_sys_init_connect, var);
+}
+
+
+static void sys_default_init_connect(THD* thd, enum_var_type type)
+{
+ update_sys_var_str(&sys_init_connect, &LOCK_sys_init_connect, 0);
+}
+
+
+static bool sys_update_init_slave(THD *thd, set_var *var)
+{
+ return update_sys_var_str(&sys_init_slave, &LOCK_sys_init_slave, var);
+}
+
+
+static void sys_default_init_slave(THD* thd, enum_var_type type)
+{
+ update_sys_var_str(&sys_init_slave, &LOCK_sys_init_slave, 0);
+}
+
+
/*
The following 3 functions need to be changed in 4.1 when we allow
one to change character sets
diff --git a/sql/set_var.h b/sql/set_var.h
index 946341c4559..fc7610ee500 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -132,6 +132,7 @@ class sys_var_str :public sys_var
{
public:
char *value; // Pointer to allocated string
+ uint value_length;
sys_check_func check_func;
sys_update_func update_func;
sys_set_default_func set_default_func;
@@ -803,6 +804,8 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
+extern sys_var_str sys_init_connect;
+extern sys_var_str sys_init_slave;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
NAMED_LIST **found);
diff --git a/sql/slave.cc b/sql/slave.cc
index 5ace523be73..b13ac799c9b 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3159,6 +3159,18 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
llstr(rli->group_relay_log_pos,llbuff1));
+ /* execute init_slave variable */
+ if (sys_init_slave.value)
+ {
+ execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
+ if (thd->query_error)
+ {
+ sql_print_error("\
+Slave SQL thread aborted. Can't execute init_slave query");
+ goto err;
+ }
+ }
+
/* Read queries from the IO/THREAD until this thread is killed */
while (!sql_slave_killed(thd,rli))
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6442bbc1e1d..92a21b5982d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -860,6 +860,37 @@ static int check_connection(THD *thd)
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
}
+
+void execute_init_command(THD *thd, sys_var_str *init_command_var,
+ rw_lock_t *var_mutex)
+{
+ Vio* save_vio;
+ ulong save_client_capabilities;
+
+ thd->proc_info= "Execution of init_command";
+ /*
+ We need to lock init_command_var because
+ during execution of init_command_var query
+ values of init_command_var can't be changed
+ */
+ rw_rdlock(var_mutex);
+ thd->query= init_command_var->value;
+ thd->query_length= init_command_var->value_length;
+ save_client_capabilities= thd->client_capabilities;
+ thd->client_capabilities|= CLIENT_MULTI_QUERIES;
+ /*
+ We don't need return result of execution to client side.
+ To forbid this we should set thd->net.vio to 0.
+ */
+ save_vio= thd->net.vio;
+ thd->net.vio= 0;
+ dispatch_command(COM_QUERY, thd, thd->query, thd->query_length+1);
+ rw_unlock(var_mutex);
+ thd->client_capabilities= save_client_capabilities;
+ thd->net.vio= save_vio;
+}
+
+
pthread_handler_decl(handle_one_connection,arg)
{
THD *thd=(THD*) arg;
@@ -932,9 +963,15 @@ pthread_handler_decl(handle_one_connection,arg)
if (thd->client_capabilities & CLIENT_COMPRESS)
net->compress=1; // Use compression
- thd->proc_info=0; // Remove 'login'
- thd->command=COM_SLEEP;
- thd->version=refresh_version;
+ thd->version= refresh_version;
+ if (sys_init_connect.value && !(thd->master_access & SUPER_ACL))
+ {
+ execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
+ if (thd->query_error)
+ thd->killed= 1;
+ }
+
+ thd->proc_info=0;
thd->set_time();
thd->init_for_queries();
while (!net->error && net->vio != 0 && !thd->killed)
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 4181075cb9f..ac193736be5 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1612,9 +1612,12 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
break;
}
case SHOW_CHAR:
- pos= value;
- end= strend(pos);
+ {
+ if (!(pos= value))
+ pos= "";
+ end= strend(pos);
break;
+ }
case SHOW_STARTTIME:
nr= (long) (thd->query_start() - start_time);
end= int10_to_str(nr, buff, 10);
@@ -1640,10 +1643,10 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
break;
case SHOW_CHAR_PTR:
{
- if (!(pos= *(char**) value))
- pos= "";
- end= strend(pos);
- break;
+ if (!(pos= *(char**) value))
+ pos= "";
+ end= strend(pos);
+ break;
}
#ifdef HAVE_OPENSSL
/* First group - functions relying on CTX */