summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/collapsed5
-rw-r--r--config/ac-macros/ssl.m45
-rw-r--r--include/my_pthread.h3
-rw-r--r--libmysql/libmysql.c16
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--libmysqld/lib_sql.cc16
-rw-r--r--mysql-test/lib/mtr_im.pl4
-rw-r--r--mysql-test/lib/mtr_io.pl1
-rw-r--r--mysql-test/lib/mtr_process.pl6
-rw-r--r--mysql-test/r/func_in.result10
-rw-r--r--mysql-test/r/func_str.result350
-rw-r--r--mysql-test/r/im_daemon_life_cycle.result4
-rw-r--r--mysql-test/r/im_life_cycle.result4
-rw-r--r--mysql-test/r/parser.result13
-rw-r--r--mysql-test/r/ps.result153
-rw-r--r--mysql-test/r/rpl_trigger.result27
-rw-r--r--mysql-test/r/sp.result108
-rw-r--r--mysql-test/r/sp_gis.result30
-rw-r--r--mysql-test/r/trigger.result37
-rw-r--r--mysql-test/r/udf.result16
-rw-r--r--mysql-test/t/events_bugs.test2
-rw-r--r--mysql-test/t/func_in.test30
-rw-r--r--mysql-test/t/func_str.test124
-rw-r--r--mysql-test/t/im_daemon_life_cycle.imtest71
-rw-r--r--mysql-test/t/im_life_cycle.imtest10
-rw-r--r--mysql-test/t/im_options.imtest28
-rw-r--r--mysql-test/t/im_utils.imtest4
-rwxr-xr-xmysql-test/t/kill_n_check.sh82
-rwxr-xr-xmysql-test/t/log.sh24
-rw-r--r--mysql-test/t/parser.test15
-rw-r--r--mysql-test/t/ps.test100
-rw-r--r--mysql-test/t/rpl_trigger.test37
-rw-r--r--mysql-test/t/sp.test120
-rw-r--r--mysql-test/t/sp_gis.test39
-rw-r--r--mysql-test/t/trigger.test48
-rw-r--r--mysql-test/t/udf.test36
-rw-r--r--mysql-test/t/utils.sh55
-rwxr-xr-xmysql-test/t/wait_for_process.sh92
-rwxr-xr-xmysql-test/t/wait_for_socket.sh58
-rw-r--r--server-tools/instance-manager/IMService.cpp24
-rw-r--r--server-tools/instance-manager/IMService.h2
-rw-r--r--server-tools/instance-manager/Makefile.am2
-rw-r--r--server-tools/instance-manager/buffer.cc4
-rw-r--r--server-tools/instance-manager/command.cc6
-rw-r--r--server-tools/instance-manager/command.h6
-rw-r--r--server-tools/instance-manager/commands.cc100
-rw-r--r--server-tools/instance-manager/commands.h82
-rw-r--r--server-tools/instance-manager/guardian.cc134
-rw-r--r--server-tools/instance-manager/guardian.h47
-rw-r--r--server-tools/instance-manager/instance.cc597
-rw-r--r--server-tools/instance-manager/instance.h14
-rw-r--r--server-tools/instance-manager/instance_map.cc51
-rw-r--r--server-tools/instance-manager/instance_map.h13
-rw-r--r--server-tools/instance-manager/instance_options.cc236
-rw-r--r--server-tools/instance-manager/instance_options.h25
-rw-r--r--server-tools/instance-manager/listener.cc178
-rw-r--r--server-tools/instance-manager/listener.h49
-rw-r--r--server-tools/instance-manager/log.cc98
-rw-r--r--server-tools/instance-manager/log.h38
-rw-r--r--server-tools/instance-manager/manager.cc260
-rw-r--r--server-tools/instance-manager/manager.h45
-rw-r--r--server-tools/instance-manager/mysql_connection.cc197
-rw-r--r--server-tools/instance-manager/mysql_connection.h58
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc15
-rw-r--r--server-tools/instance-manager/parse.cc30
-rw-r--r--server-tools/instance-manager/parse.h3
-rw-r--r--server-tools/instance-manager/parse_output.cc2
-rw-r--r--server-tools/instance-manager/priv.cc71
-rw-r--r--server-tools/instance-manager/priv.h15
-rw-r--r--server-tools/instance-manager/thread_registry.cc138
-rw-r--r--server-tools/instance-manager/thread_registry.h61
-rw-r--r--server-tools/instance-manager/user_management_commands.cc10
-rw-r--r--server-tools/instance-manager/user_management_commands.h16
-rw-r--r--server-tools/instance-manager/user_map.cc30
-rw-r--r--server-tools/instance-manager/user_map.h2
-rw-r--r--sql/item_cmpfunc.cc1
-rw-r--r--sql/item_create.cc42
-rw-r--r--sql/item_func.cc27
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_strfunc.cc97
-rw-r--r--sql/item_strfunc.h24
-rw-r--r--sql/item_sum.cc10
-rw-r--r--sql/mysqld.cc12
-rw-r--r--sql/set_var.cc13
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_cache.cc19
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_trigger.cc140
-rw-r--r--sql/sql_yacc.yy69
-rw-r--r--storage/ndb/config/type_kernel.mk.am2
-rw-r--r--storage/ndb/config/type_ndbapi.mk.am2
-rw-r--r--storage/ndb/config/type_ndbapitest.mk.am2
-rw-r--r--storage/ndb/config/type_ndbapitools.mk.am2
-rw-r--r--storage/ndb/config/type_util.mk.am2
-rw-r--r--tests/mysql_client_test.c147
96 files changed, 3436 insertions, 1636 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed
index 10bc7a2182a..f934fa44580 100644
--- a/BitKeeper/etc/collapsed
+++ b/BitKeeper/etc/collapsed
@@ -15,7 +15,8 @@
45214442pBGT9KuZEGixBH71jTzbOA
45214a07hVsIGwvwa-WrO-jpeaSwVw
452a92d0-31-8wSzSfZi165fcGcXPA
-452c6c6dAjuNghfc1ObZ_UQ5SCl85g
-4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg
454a7ef8gdvE_ddMlJyghvOAkKPNOQ
454f8960jsVT_kMKJtZ9OCgXoba0xQ
+4561b2ecZbhuAc0TTDdCdultxUYaMw
+4561bde4qWhz1I8tkItXKex5uniipA
+4562ba016dYH0JzszOqZ8p6psbKfnQ
diff --git a/config/ac-macros/ssl.m4 b/config/ac-macros/ssl.m4
index 0f2f207c36f..4ee58318a62 100644
--- a/config/ac-macros/ssl.m4
+++ b/config/ac-macros/ssl.m4
@@ -28,10 +28,9 @@ AC_DEFUN([MYSQL_USE_BUNDLED_YASSL], [
yassl_dir="yassl"
AC_SUBST([yassl_dir])
- yassl_libs="-L\$(top_srcdir)/extra/yassl/src -lyassl -L\$(top_srcdir)/extra/yassl/taocrypt/src -ltaocrypt"
+ yassl_libs="\$(top_builddir)/extra/yassl/src/libyassl.la \
+ \$(top_builddir)/extra/yassl/taocrypt/src/libtaocrypt.la"
AC_SUBST(yassl_libs)
- yassl_includes="-I\$(top_srcdir)/extra/yassl/include"
- AC_SUBST(yassl_includes)
AC_DEFINE([HAVE_OPENSSL], [1], [Defined by configure. Using yaSSL for SSL.])
AC_DEFINE([HAVE_YASSL], [1], [Defined by configure. Using yaSSL for SSL.])
diff --git a/include/my_pthread.h b/include/my_pthread.h
index 0cb38d29be8..8a0e1fc2b01 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -130,6 +130,9 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
#define pthread_kill(A,B) pthread_dummy(0)
+#define pthread_join(A,B) \
+ ((WaitForSingleObject((A), INFINITE) != WAIT_OBJECT_0) || !CloseHandle(A))
+
/* Dummy defines for easier code */
#define pthread_attr_setdetachstate(A,B) pthread_dummy(0)
#define my_pthread_attr_setprio(A,B) pthread_attr_setprio(A,B)
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index ac4548f7301..898b583a58b 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -2471,6 +2471,8 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
NET *net= &mysql->net;
char buff[4 /* size of stmt id */ +
5 /* execution flags */];
+ my_bool res;
+
DBUG_ENTER("execute");
DBUG_DUMP("packet", packet, length);
@@ -2478,16 +2480,18 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
buff[4]= (char) stmt->flags;
int4store(buff+5, 1); /* iteration count */
- if (cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
- packet, length, 1, NULL) ||
- (*mysql->methods->read_query_result)(mysql))
+
+ res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
+ packet, length, 1, NULL) ||
+ (*mysql->methods->read_query_result)(mysql));
+ stmt->affected_rows= mysql->affected_rows;
+ stmt->server_status= mysql->server_status;
+ stmt->insert_id= mysql->insert_id;
+ if (res)
{
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
DBUG_RETURN(1);
}
- stmt->affected_rows= mysql->affected_rows;
- stmt->server_status= mysql->server_status;
- stmt->insert_id= mysql->insert_id;
DBUG_RETURN(0);
}
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index 7eb160776e0..cf4f90d99c9 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -94,8 +94,8 @@ INC_LIB= $(top_builddir)/regex/libregex.a \
$(yassl_inc_libs)
if HAVE_YASSL
-yassl_inc_libs= $(top_srcdir)/extra/yassl/src/.libs/libyassl.a \
- $(top_srcdir)/extra/yassl/taocrypt/src/.libs/libtaocrypt.a
+yassl_inc_libs= $(top_builddir)/extra/yassl/src/.libs/libyassl.a \
+ $(top_builddir)/extra/yassl/taocrypt/src/.libs/libtaocrypt.a
endif
# Storage engine specific compilation options
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index a3edc310677..9251ddd421a 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -279,24 +279,26 @@ static int emb_stmt_execute(MYSQL_STMT *stmt)
DBUG_ENTER("emb_stmt_execute");
char header[5];
THD *thd;
+ my_bool res;
int4store(header, stmt->stmt_id);
header[4]= stmt->flags;
thd= (THD*)stmt->mysql->thd;
thd->client_param_count= stmt->param_count;
thd->client_params= stmt->params;
- if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
- header, sizeof(header), 1, stmt) ||
- emb_read_query_result(stmt->mysql))
+
+ res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
+ header, sizeof(header), 1, stmt) ||
+ emb_read_query_result(stmt->mysql));
+ stmt->affected_rows= stmt->mysql->affected_rows;
+ stmt->insert_id= stmt->mysql->insert_id;
+ stmt->server_status= stmt->mysql->server_status;
+ if (res)
{
NET *net= &stmt->mysql->net;
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
DBUG_RETURN(1);
}
- stmt->affected_rows= stmt->mysql->affected_rows;
- stmt->insert_id= stmt->mysql->insert_id;
- stmt->server_status= stmt->mysql->server_status;
-
DBUG_RETURN(0);
}
diff --git a/mysql-test/lib/mtr_im.pl b/mysql-test/lib/mtr_im.pl
index ca17516278e..967e92dfcdd 100644
--- a/mysql-test/lib/mtr_im.pl
+++ b/mysql-test/lib/mtr_im.pl
@@ -582,7 +582,7 @@ sub mtr_im_start($$) {
mtr_add_arg($args, $opt);
}
- $im->{'pid'} =
+ $im->{'spawner_pid'} =
mtr_spawn(
$::exe_im, # path to the executable
$args, # cmd-line args
@@ -593,7 +593,7 @@ sub mtr_im_start($$) {
{ append_log_file => 1 } # append log files
);
- unless ( $im->{'pid'} )
+ unless ( $im->{'spawner_pid'} )
{
mtr_error('Could not start Instance Manager.')
}
diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl
index 984d834486c..5be1d2ffddb 100644
--- a/mysql-test/lib/mtr_io.pl
+++ b/mysql-test/lib/mtr_io.pl
@@ -39,6 +39,7 @@ sub mtr_get_pid_from_file ($) {
# Read pid number from file
my $pid= <FILE>;
+ chomp $pid;
close FILE;
return $pid if $pid=~ /^(\d+)/;
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index 9d0c1f601ba..79285de88a7 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -937,6 +937,12 @@ sub check_expected_crash_and_restart($)
}
}
}
+
+ if ($::instance_manager->{'spawner_pid'} eq $ret_pid)
+ {
+ return;
+ }
+
mtr_warning("check_expected_crash_and_restart couldn't find an entry for pid: $ret_pid");
}
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index b88e5a66f96..6578af7cd8b 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -202,6 +202,14 @@ select count(*) from t1 where id not in (1,2);
count(*)
1
drop table t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 SELECT 1 IN (2, NULL);
+SELECT should return NULL.
+SELECT * FROM t1;
+1 IN (2, NULL)
+NULL
+DROP TABLE t1;
+End of 4.1 tests
CREATE TABLE t1 (a int PRIMARY KEY);
INSERT INTO t1 VALUES (44), (45), (46);
SELECT * FROM t1 WHERE a IN (45);
@@ -343,6 +351,7 @@ some_id
1
2
drop table t1;
+End of 5.0 tests
create table t1(f1 char(1));
insert into t1 values ('a'),('b'),('1');
select f1 from t1 where f1 in ('a',1);
@@ -411,3 +420,4 @@ explain select f2 from t2 where f2 in (1,'b');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index
drop table t1, t2;
+End of 5.1 tests
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 733cb5ca5f0..4e63d4d8482 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -813,11 +813,231 @@ drop table t7;
select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2);
substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2) substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2)
1abcd;2abcd 3abcd;4abcd
-explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty");
+explain extended select md5('hello');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
-Note 1003 select md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,cast(_latin1'HE' as char charset binary) AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate latin1_bin),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substring_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")`
+Note 1003 select md5(_latin1'hello') AS `md5('hello')`
+explain extended select sha('abc');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select sha(_latin1'abc') AS `sha('abc')`
+explain extended select sha1('abc');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select sha(_latin1'abc') AS `sha1('abc')`
+explain extended select soundex('');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select soundex(_latin1'') AS `soundex('')`
+explain extended select 'mood' sounds like 'mud';
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select (soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`
+explain extended select aes_decrypt(aes_encrypt('abc','1'),'1');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`
+explain extended select concat('*',space(5),'*');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`
+explain extended select reverse('abc');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select reverse(_latin1'abc') AS `reverse('abc')`
+explain extended select rpad('a',4,'1');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`
+explain extended select lpad('a',4,'1');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`
+explain extended select concat_ws(',','',NULL,'a');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`
+explain extended select make_set(255,_latin2'a', _latin2'b', _latin2'c');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a', _latin2'b', _latin2'c')`
+explain extended select elt(2,1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select elt(2,1) AS `elt(2,1)`
+explain extended select locate("a","b",2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`
+explain extended select format(130,10);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select format(130,10) AS `format(130,10)`
+explain extended select char(0);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select char(0) AS `char(0)`
+explain extended select conv(130,16,10);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select conv(130,16,10) AS `conv(130,16,10)`
+explain extended select hex(130);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select hex(130) AS `hex(130)`
+explain extended select binary 'HE';
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select cast(_latin1'HE' as char charset binary) AS `binary 'HE'`
+explain extended select export_set(255,_latin2'y', _latin2'n', _latin2' ');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y', _latin2'n', _latin2' ')`
+explain extended select FIELD('b' COLLATE latin1_bin,'A','B');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select field((_latin1'b' collate latin1_bin),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`
+explain extended select FIND_IN_SET(_latin1'B', _latin1'a,b,c,d');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B', _latin1'a,b,c,d')`
+explain extended select collation(conv(130,16,10));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select collation(conv(130,16,10)) AS `collation(conv(130,16,10))`
+explain extended select coercibility(conv(130,16,10));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`
+explain extended select length('\n\t\r\b\0\_\%\\');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`
+explain extended select bit_length('\n\t\r\b\0\_\%\\');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
+explain extended select bit_length('\n\t\r\b\0\_\%\\');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`
+explain extended select concat('monty',' was here ','again');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`
+explain extended select length('hello');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select length(_latin1'hello') AS `length('hello')`
+explain extended select char(ascii('h'));
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select char(ascii(_latin1'h')) AS `char(ascii('h'))`
+explain extended select ord('h');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select ord(_latin1'h') AS `ord('h')`
+explain extended select quote(1/0);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select quote((1 / 0)) AS `quote(1/0)`
+explain extended select crc32("123");
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select crc32(_latin1'123') AS `crc32("123")`
+explain extended select replace('aaaa','a','b');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`
+explain extended select insert('txs',2,1,'hi');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`
+explain extended select left(_latin2'a',1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select left(_latin2'a',1) AS `left(_latin2'a',1)`
+explain extended select right(_latin2'a',1);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select right(_latin2'a',1) AS `right(_latin2'a',1)`
+explain extended select lcase(_latin2'a');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select lcase(_latin2'a') AS `lcase(_latin2'a')`
+explain extended select ucase(_latin2'a');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select ucase(_latin2'a') AS `ucase(_latin2'a')`
+explain extended select SUBSTR('abcdefg',3,2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`
+explain extended select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select substring_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`
+explain extended select trim(_latin2' a ');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select trim(_latin2' a ') AS `trim(_latin2' a ')`
+explain extended select ltrim(_latin2' a ');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`
+explain extended select rtrim(_latin2' a ');
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`
+explain extended select decode(encode(repeat("a",100000),"monty"),"monty");
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 select decode(encode(repeat(_latin1'a',100000),_latin1'monty'),_latin1'monty') AS `decode(encode(repeat("a",100000),"monty"),"monty")`
SELECT lpad(12345, 5, "#");
lpad(12345, 5, "#")
12345
@@ -1148,6 +1368,119 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5))
DROP TABLE t1,t2;
+select encode(NULL, NULL);
+encode(NULL, NULL)
+NULL
+select encode("data", NULL);
+encode("data", NULL)
+NULL
+select encode(NULL, "password");
+encode(NULL, "password")
+NULL
+select decode(NULL, NULL);
+decode(NULL, NULL)
+NULL
+select decode("data", NULL);
+decode("data", NULL)
+NULL
+select decode(NULL, "password");
+decode(NULL, "password")
+NULL
+select format(NULL, NULL);
+format(NULL, NULL)
+NULL
+select format(pi(), NULL);
+format(pi(), NULL)
+NULL
+select format(NULL, 2);
+format(NULL, 2)
+NULL
+select benchmark(NULL, NULL);
+benchmark(NULL, NULL)
+NULL
+select benchmark(0, NULL);
+benchmark(0, NULL)
+0
+select benchmark(100, NULL);
+benchmark(100, NULL)
+0
+select benchmark(NULL, 1+1);
+benchmark(NULL, 1+1)
+NULL
+set @password="password";
+set @my_data="clear text to encode";
+select md5(encode(@my_data, "password"));
+md5(encode(@my_data, "password"))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, _utf8 "password"));
+md5(encode(@my_data, _utf8 "password"))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, binary "password"));
+md5(encode(@my_data, binary "password"))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, _latin1 "password"));
+md5(encode(@my_data, _latin1 "password"))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, _koi8r "password"));
+md5(encode(@my_data, _koi8r "password"))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, (select "password" from dual)));
+md5(encode(@my_data, (select "password" from dual)))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, concat("pass", "word")));
+md5(encode(@my_data, concat("pass", "word")))
+44320fd2b4a0ec92faa2da2122def917
+select md5(encode(@my_data, @password));
+md5(encode(@my_data, @password))
+44320fd2b4a0ec92faa2da2122def917
+set @my_data="binary encoded data";
+select md5(decode(@my_data, "password"));
+md5(decode(@my_data, "password"))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, _utf8 "password"));
+md5(decode(@my_data, _utf8 "password"))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, binary "password"));
+md5(decode(@my_data, binary "password"))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, _latin1 "password"));
+md5(decode(@my_data, _latin1 "password"))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, _koi8r "password"));
+md5(decode(@my_data, _koi8r "password"))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, (select "password" from dual)));
+md5(decode(@my_data, (select "password" from dual)))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, concat("pass", "word")));
+md5(decode(@my_data, concat("pass", "word")))
+5bea8c394368dbc03b76684483b7756b
+select md5(decode(@my_data, @password));
+md5(decode(@my_data, @password))
+5bea8c394368dbc03b76684483b7756b
+set @dec=5;
+select format(pi(), (1+1));
+format(pi(), (1+1))
+3.14
+select format(pi(), (select 3 from dual));
+format(pi(), (select 3 from dual))
+3.142
+select format(pi(), @dec);
+format(pi(), @dec)
+3.14159
+set @bench_count=10;
+select benchmark(10, pi());
+benchmark(10, pi())
+0
+select benchmark(5+5, pi());
+benchmark(5+5, pi())
+0
+select benchmark((select 10 from dual), pi());
+benchmark((select 10 from dual), pi())
+0
+select benchmark(@bench_count, pi());
+benchmark(@bench_count, pi())
+0
select locate('he','hello',-2);
locate('he','hello',-2)
0
@@ -1903,4 +2236,17 @@ Warnings:
Error 1292 Truncated incorrect DECIMAL value: ''
Error 1292 Truncated incorrect DECIMAL value: ''
Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated
+SET @orig_sql_mode = @@SQL_MODE;
+SET SQL_MODE=traditional;
+SELECT CHAR(0xff,0x8f USING utf8);
+CHAR(0xff,0x8f USING utf8)
+NULL
+Warnings:
+Error 1300 Invalid utf8 character string: 'FF8F'
+SELECT CHAR(0xff,0x8f USING utf8) IS NULL;
+CHAR(0xff,0x8f USING utf8) IS NULL
+1
+Warnings:
+Error 1300 Invalid utf8 character string: 'FF8F'
+SET SQL_MODE=@orig_sql_mode;
End of 5.0 tests
diff --git a/mysql-test/r/im_daemon_life_cycle.result b/mysql-test/r/im_daemon_life_cycle.result
index 4fe15460ae5..a2baeac5f14 100644
--- a/mysql-test/r/im_daemon_life_cycle.result
+++ b/mysql-test/r/im_daemon_life_cycle.result
@@ -6,7 +6,7 @@ instance_name state
mysqld1 XXXXX
mysqld2 offline
Killing the process...
-Sleeping...
+Waiting...
Success: the process was restarted.
Success: server is ready to accept connection on socket.
@@ -16,7 +16,7 @@ Success: server is ready to accept connection on socket.
START INSTANCE mysqld2;
Success: the process has been started.
Killing the process...
-Sleeping...
+Waiting...
Success: the process was restarted.
Success: server is ready to accept connection on socket.
SHOW INSTANCE STATUS mysqld1;
diff --git a/mysql-test/r/im_life_cycle.result b/mysql-test/r/im_life_cycle.result
index fb25f4a0768..dcabc8cf4f3 100644
--- a/mysql-test/r/im_life_cycle.result
+++ b/mysql-test/r/im_life_cycle.result
@@ -39,7 +39,7 @@ ERROR HY000: Unknown instance name
-- 1.1.6.
--------------------------------------------------------------------
Killing the process...
-Sleeping...
+Waiting...
Success: the process was restarted.
SHOW INSTANCES;
instance_name state
@@ -52,7 +52,7 @@ mysqld2 offline
START INSTANCE mysqld2;
Success: the process has been started.
Killing the process...
-Sleeping...
+Waiting...
Success: the process was killed.
--------------------------------------------------------------------
diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result
index afd78561898..df446e01601 100644
--- a/mysql-test/r/parser.result
+++ b/mysql-test/r/parser.result
@@ -296,11 +296,6 @@ select atan();
ERROR 42000: Incorrect parameter count in the call to native function 'atan'
select atan2(1, 2, 3);
ERROR 42000: Incorrect parameter count in the call to native function 'atan2'
-select benchmark(10, 1+1);
-benchmark(10, 1+1)
-0
-select benchmark(5+5, 2);
-ERROR 42000: Incorrect parameters in the call to native function 'BENCHMARK'
select concat();
ERROR 42000: Incorrect parameter count in the call to native function 'concat'
select concat("foo");
@@ -310,11 +305,6 @@ select concat_ws();
ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws'
select concat_ws("foo");
ERROR 42000: Incorrect parameter count in the call to native function 'concat_ws'
-set @pwd="my password";
-select encode("secret", @pwd);
-ERROR 42000: Incorrect parameters in the call to native function 'ENCODE'
-select decode("encoded-secret", @pwd);
-ERROR 42000: Incorrect parameters in the call to native function 'DECODE'
select encrypt();
ERROR 42000: Incorrect parameter count in the call to native function 'encrypt'
select encrypt(1, 2, 3);
@@ -339,9 +329,6 @@ select field();
ERROR 42000: Incorrect parameter count in the call to native function 'field'
select field("p1");
ERROR 42000: Incorrect parameter count in the call to native function 'field'
-set @dec=2;
-select format(pi(), @dec);
-ERROR 42000: Incorrect parameters in the call to native function 'FORMAT'
select from_unixtime();
ERROR 42000: Incorrect parameter count in the call to native function 'from_unixtime'
select from_unixtime(1, 2, 3);
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 694a934f8b7..e968d3de6e9 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -796,12 +796,12 @@ set @old_max_prepared_stmt_count= @@max_prepared_stmt_count;
show variables like 'max_prepared_stmt_count';
Variable_name Value
max_prepared_stmt_count 16382
-show variables like 'prepared_stmt_count';
+show status like 'prepared_stmt_count';
Variable_name Value
-prepared_stmt_count 0
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
-@@max_prepared_stmt_count @@prepared_stmt_count
-16382 0
+Prepared_stmt_count 0
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
+16382
set global max_prepared_stmt_count=-1;
select @@max_prepared_stmt_count;
@@max_prepared_stmt_count
@@ -820,67 +820,70 @@ set max_prepared_stmt_count=1;
ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL
set local max_prepared_stmt_count=1;
ERROR HY000: Variable 'max_prepared_stmt_count' is a GLOBAL variable and should be set with SET GLOBAL
-set local prepared_stmt_count=0;
-ERROR HY000: Variable 'prepared_stmt_count' is a read only variable
-set @@prepared_stmt_count=0;
-ERROR HY000: Variable 'prepared_stmt_count' is a read only variable
-set global prepared_stmt_count=1;
-ERROR HY000: Variable 'prepared_stmt_count' is a read only variable
set global max_prepared_stmt_count=1;
select @@max_prepared_stmt_count;
@@max_prepared_stmt_count
1
set global max_prepared_stmt_count=0;
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
-@@max_prepared_stmt_count @@prepared_stmt_count
-0 0
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
+0
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
prepare stmt from "select 1";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0)
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-0
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
set global max_prepared_stmt_count=1;
prepare stmt from "select 1";
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-1
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 1
prepare stmt1 from "select 1";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 1)
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-1
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 1
deallocate prepare stmt;
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-0
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
prepare stmt from "select 1";
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-1
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 1
prepare stmt from "select 2";
-select @@prepared_stmt_count;
-@@prepared_stmt_count
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 1
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 1
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
1
-select @@prepared_stmt_count, @@max_prepared_stmt_count;
-@@prepared_stmt_count @@max_prepared_stmt_count
-1 1
set global max_prepared_stmt_count=0;
prepare stmt from "select 1";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0)
execute stmt;
ERROR HY000: Unknown prepared statement handler (stmt) given to EXECUTE
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-0
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
prepare stmt from "select 1";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 0)
-select @@prepared_stmt_count;
-@@prepared_stmt_count
-0
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
set global max_prepared_stmt_count=3;
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
-@@max_prepared_stmt_count @@prepared_stmt_count
-3 0
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
+3
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
prepare stmt from "select 1";
prepare stmt from "select 2";
prepare stmt1 from "select 3";
@@ -888,13 +891,19 @@ prepare stmt2 from "select 4";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 3)
prepare stmt2 from "select 4";
ERROR 42000: Can't create more than max_prepared_stmt_count statements (current value: 3)
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
-@@max_prepared_stmt_count @@prepared_stmt_count
-3 3
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
+3
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 3
deallocate prepare stmt;
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
-@@max_prepared_stmt_count @@prepared_stmt_count
-3 0
+select @@max_prepared_stmt_count;
+@@max_prepared_stmt_count
+3
+show status like 'prepared_stmt_count';
+Variable_name Value
+Prepared_stmt_count 0
set global max_prepared_stmt_count= @old_max_prepared_stmt_count;
drop table if exists t1;
create temporary table if not exists t1 (a1 int);
@@ -2377,3 +2386,49 @@ Level Code Message
Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2'
deallocate prepare abc;
+set @my_password="password";
+set @my_data="clear text to encode";
+prepare stmt1 from 'select decode(encode(?, ?), ?)';
+execute stmt1 using @my_data, @my_password, @my_password;
+decode(encode(?, ?), ?)
+clear text to encode
+set @my_data="more text to encode";
+execute stmt1 using @my_data, @my_password, @my_password;
+decode(encode(?, ?), ?)
+more text to encode
+set @my_password="new password";
+execute stmt1 using @my_data, @my_password, @my_password;
+decode(encode(?, ?), ?)
+more text to encode
+deallocate prepare stmt1;
+set @to_format="123456789.123456789";
+set @dec=0;
+prepare stmt2 from 'select format(?, ?)';
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+123,456,789
+set @dec=4;
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+123,456,789.1235
+set @dec=6;
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+123,456,789.123457
+set @dec=2;
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+123,456,789.12
+set @to_format="100";
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+100.00
+set @to_format="1000000";
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+1,000,000.00
+set @to_format="10000";
+execute stmt2 using @to_format, @dec;
+format(?, ?)
+10,000.00
+deallocate prepare stmt2;
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result
index 50bcd071d23..815a87eede5 100644
--- a/mysql-test/r/rpl_trigger.result
+++ b/mysql-test/r/rpl_trigger.result
@@ -944,3 +944,30 @@ c
---> Cleaning up...
DROP TABLE t1;
DROP TABLE t2;
+drop table if exists t1;
+create table t1(a int, b varchar(50));
+drop trigger not_a_trigger;
+ERROR HY000: Trigger does not exist
+drop trigger if exists not_a_trigger;
+Warnings:
+Note 1360 Trigger does not exist
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+Warnings:
+Note 1360 Trigger does not exist
+insert into t1 values (3, "c");
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+drop table t1;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index aeccfd9c951..60363b06ea0 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -2178,6 +2178,7 @@ set @stamped_time=in_time;
set x=2;
end if;
end|
+set time_zone='+03:00';
call bug3426(1000, @i)|
select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
@i time
@@ -5627,4 +5628,111 @@ Called B
drop procedure proc_21462_a|
drop procedure proc_21462_b|
End of 5.0 tests
+Begin of 5.1 tests
+drop function if exists pi;
+create function pi() returns varchar(50)
+return "pie, my favorite desert.";
+Warnings:
+Note 1578 This function 'pi' has the same name as a native function.
+SET @save_sql_mode=@@sql_mode;
+SET SQL_MODE='IGNORE_SPACE';
+select pi(), pi ();
+pi() pi ()
+3.141593 3.141593
+select test.pi(), test.pi ();
+test.pi() test.pi ()
+pie, my favorite desert. pie, my favorite desert.
+SET SQL_MODE='';
+select pi(), pi ();
+pi() pi ()
+3.141593 3.141593
+select test.pi(), test.pi ();
+test.pi() test.pi ()
+pie, my favorite desert. pie, my favorite desert.
+SET @@sql_mode=@save_sql_mode;
+drop function pi;
+drop function if exists test.database;
+drop function if exists test.current_user;
+drop function if exists test.md5;
+create database nowhere;
+use nowhere;
+drop database nowhere;
+SET @save_sql_mode=@@sql_mode;
+SET SQL_MODE='IGNORE_SPACE';
+select database(), database ();
+database() database ()
+NULL NULL
+select current_user(), current_user ();
+current_user() current_user ()
+root@localhost root@localhost
+select md5("aaa"), md5 ("aaa");
+md5("aaa") md5 ("aaa")
+47bce5c74f589f4867dbd57e9ca9f808 47bce5c74f589f4867dbd57e9ca9f808
+SET SQL_MODE='';
+select database(), database ();
+database() database ()
+NULL NULL
+select current_user(), current_user ();
+current_user() current_user ()
+root@localhost root@localhost
+select md5("aaa"), md5 ("aaa");
+md5("aaa") md5 ("aaa")
+47bce5c74f589f4867dbd57e9ca9f808 47bce5c74f589f4867dbd57e9ca9f808
+use test;
+create function `database`() returns varchar(50)
+return "Stored function database";
+Warnings:
+Note 1578 This function 'database' has the same name as a native function.
+create function `current_user`() returns varchar(50)
+return "Stored function current_user";
+Warnings:
+Note 1578 This function 'current_user' has the same name as a native function.
+create function md5(x varchar(50)) returns varchar(50)
+return "Stored function md5";
+Warnings:
+Note 1578 This function 'md5' has the same name as a native function.
+SET SQL_MODE='IGNORE_SPACE';
+select database(), database ();
+database() database ()
+test test
+select current_user(), current_user ();
+current_user() current_user ()
+root@localhost root@localhost
+select md5("aaa"), md5 ("aaa");
+md5("aaa") md5 ("aaa")
+47bce5c74f589f4867dbd57e9ca9f808 47bce5c74f589f4867dbd57e9ca9f808
+select test.database(), test.database ();
+test.database() test.database ()
+Stored function database Stored function database
+select test.current_user(), test.current_user ();
+test.current_user() test.current_user ()
+Stored function current_user Stored function current_user
+select test.md5("aaa"), test.md5 ("aaa");
+test.md5("aaa") test.md5 ("aaa")
+Stored function md5 Stored function md5
+SET SQL_MODE='';
+select database(), database ();
+database() database ()
+test test
+select current_user(), current_user ();
+current_user() current_user ()
+root@localhost root@localhost
+select md5("aaa"), md5 ("aaa");
+md5("aaa") md5 ("aaa")
+47bce5c74f589f4867dbd57e9ca9f808 47bce5c74f589f4867dbd57e9ca9f808
+select test.database(), test.database ();
+test.database() test.database ()
+Stored function database Stored function database
+select test.current_user(), test.current_user ();
+test.current_user() test.current_user ()
+Stored function current_user Stored function current_user
+select test.md5("aaa"), test.md5 ("aaa");
+test.md5("aaa") test.md5 ("aaa")
+Stored function md5 Stored function md5
+SET @@sql_mode=@save_sql_mode;
+drop function test.database;
+drop function test.current_user;
+drop function md5;
+use test;
+End of 5.1 tests
drop table t1,t2;
diff --git a/mysql-test/r/sp_gis.result b/mysql-test/r/sp_gis.result
new file mode 100644
index 00000000000..ea2cdd0d29d
--- /dev/null
+++ b/mysql-test/r/sp_gis.result
@@ -0,0 +1,30 @@
+use test;
+drop function if exists a;
+drop function if exists x;
+drop function if exists y;
+create function a() returns int
+return 1;
+create function x() returns int
+return 2;
+Warnings:
+Note 1578 This function 'x' has the same name as a native function.
+create function y() returns int
+return 3;
+Warnings:
+Note 1578 This function 'y' has the same name as a native function.
+select a();
+a()
+1
+select x();
+ERROR 42000: Incorrect parameter count in the call to native function 'x'
+select y();
+ERROR 42000: Incorrect parameter count in the call to native function 'y'
+select x(PointFromText("POINT(10 20)")), y(PointFromText("POINT(10 20)"));
+x(PointFromText("POINT(10 20)")) y(PointFromText("POINT(10 20)"))
+10 20
+select test.a(), test.x(), test.y();
+test.a() test.x() test.y()
+1 2 3
+drop function a;
+drop function x;
+drop function y;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 52123885772..e302f5def1b 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1241,4 +1241,41 @@ i j
2 2
13 13
drop table t1;
+drop table if exists t1;
+drop function if exists f1;
+create table t1 (i int);
+create function f1() returns int return 10;
+create trigger t1_bi before insert on t1 for each row set @a:= f1() + 10;
+insert into t1 values ();
+select @a;
+@a
+20
+insert into t1 values ();
+select @a;
+@a
+20
+drop table t1;
+drop function f1;
+drop table if exists t1;
+create table t1(a int, b varchar(50));
+drop trigger not_a_trigger;
+ERROR HY000: Trigger does not exist
+drop trigger if exists not_a_trigger;
+Warnings:
+Note 1360 Trigger does not exist
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+Warnings:
+Note 1360 Trigger does not exist
+insert into t1 values (3, "c");
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+drop table t1;
End of 5.0 tests
diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result
index 16a1c73af80..1308980ca96 100644
--- a/mysql-test/r/udf.result
+++ b/mysql-test/r/udf.result
@@ -185,6 +185,22 @@ DROP VIEW v1;
DROP TABLE t1;
DROP FUNCTION fn;
End of 5.0 tests.
+drop function if exists pi;
+CREATE FUNCTION pi RETURNS STRING SONAME "should_not_parse.so";
+ERROR HY000: This function 'pi' has the same name as a native function.
+DROP FUNCTION IF EXISTS metaphon;
+CREATE FUNCTION metaphon(a int) RETURNS int
+return 0;
+CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
+ERROR HY000: Function 'metaphon' already exists
+DROP FUNCTION metaphon;
+CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
+CREATE FUNCTION metaphon(a int) RETURNS int
+return 0;
+ERROR HY000: Function 'metaphon' already exists
+CREATE FUNCTION test.metaphon(a int) RETURNS int
+return 0;
+ERROR HY000: Function 'metaphon' already exists
DROP FUNCTION metaphon;
DROP FUNCTION myfunc_double;
DROP FUNCTION myfunc_nonexist;
diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test
index 6223395bfd9..81988818809 100644
--- a/mysql-test/t/events_bugs.test
+++ b/mysql-test/t/events_bugs.test
@@ -280,7 +280,7 @@ create event e22830_3 on schedule every 1 hour do alter event e22830_3 on schedu
create event e22830_4 on schedule every 1 hour do alter event e22830_4 on schedule every (select f22830() from dual) hour;
select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name;
set global event_scheduler=on;
---sleep 0.7
+--sleep 2.0
set global event_scheduler=off;
select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name;
drop function f22830;
diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test
index 906747c2f78..ee344d0958b 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -109,7 +109,28 @@ select count(*) from t1 where id not in (1);
select count(*) from t1 where id not in (1,2);
drop table t1;
-# End of 4.1 tests
+
+#
+# BUG#17047: CHAR() and IN() can return NULL without signaling NULL
+# result
+#
+# The problem was in the IN() function that ignored maybe_null flags
+# of all arguments except the first (the one _before_ the IN
+# keyword, '1' in the test case below).
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 SELECT 1 IN (2, NULL);
+--echo SELECT should return NULL.
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+
+--echo End of 4.1 tests
+
#
# Bug #11885: WHERE condition with NOT IN (one element)
@@ -233,6 +254,10 @@ select some_id from t1 where some_id not in(-4,-1,-4);
select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
drop table t1;
+
+--echo End of 5.0 tests
+
+
#
# Bug#18360: Type aggregation for IN and CASE may lead to a wrong result
#
@@ -256,3 +281,6 @@ explain select f2 from t2 where f2 in ('a','b');
select f2 from t2 where f2 in (1,'b');
explain select f2 from t2 where f2 in (1,'b');
drop table t1, t2;
+
+
+--echo End of 5.1 tests
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 94190ff519f..2ec1afc70ee 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -468,7 +468,51 @@ drop table t7;
select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2);
-explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty");
+explain extended select md5('hello');
+explain extended select sha('abc');
+explain extended select sha1('abc');
+explain extended select soundex('');
+explain extended select 'mood' sounds like 'mud';
+explain extended select aes_decrypt(aes_encrypt('abc','1'),'1');
+explain extended select concat('*',space(5),'*');
+explain extended select reverse('abc');
+explain extended select rpad('a',4,'1');
+explain extended select lpad('a',4,'1');
+explain extended select concat_ws(',','',NULL,'a');
+explain extended select make_set(255,_latin2'a', _latin2'b', _latin2'c');
+explain extended select elt(2,1);
+explain extended select locate("a","b",2);
+explain extended select format(130,10);
+explain extended select char(0);
+explain extended select conv(130,16,10);
+explain extended select hex(130);
+explain extended select binary 'HE';
+explain extended select export_set(255,_latin2'y', _latin2'n', _latin2' ');
+explain extended select FIELD('b' COLLATE latin1_bin,'A','B');
+explain extended select FIND_IN_SET(_latin1'B', _latin1'a,b,c,d');
+explain extended select collation(conv(130,16,10));
+explain extended select coercibility(conv(130,16,10));
+explain extended select length('\n\t\r\b\0\_\%\\');
+explain extended select bit_length('\n\t\r\b\0\_\%\\');
+explain extended select bit_length('\n\t\r\b\0\_\%\\');
+explain extended select concat('monty',' was here ','again');
+explain extended select length('hello');
+explain extended select char(ascii('h'));
+explain extended select ord('h');
+explain extended select quote(1/0);
+explain extended select crc32("123");
+explain extended select replace('aaaa','a','b');
+explain extended select insert('txs',2,1,'hi');
+explain extended select left(_latin2'a',1);
+explain extended select right(_latin2'a',1);
+explain extended select lcase(_latin2'a');
+explain extended select ucase(_latin2'a');
+explain extended select SUBSTR('abcdefg',3,2);
+explain extended select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2);
+explain extended select trim(_latin2' a ');
+explain extended select ltrim(_latin2' a ');
+explain extended select rtrim(_latin2' a ');
+explain extended select decode(encode(repeat("a",100000),"monty"),"monty");
#
# lpad returns incorrect result (Bug #2182)
@@ -789,6 +833,70 @@ SELECT * FROM t1 INNER JOIN t2 ON code=id
DROP TABLE t1,t2;
#
+# Bug#22684: The Functions ENCODE, DECODE and FORMAT are not real functions
+#
+
+select encode(NULL, NULL);
+select encode("data", NULL);
+select encode(NULL, "password");
+
+select decode(NULL, NULL);
+select decode("data", NULL);
+select decode(NULL, "password");
+
+select format(NULL, NULL);
+select format(pi(), NULL);
+select format(NULL, 2);
+
+select benchmark(NULL, NULL);
+select benchmark(0, NULL);
+select benchmark(100, NULL);
+select benchmark(NULL, 1+1);
+
+#
+# Please note:
+# 1) The collation of the password is irrelevant, the encryption uses
+# the binary representation of the string without charset/collation.
+# 2) These tests can not print the encoded text directly, because it's binary,
+# and doing this would cause problems with source control.
+# Instead, an md5() checksum is used, to verify the result indirectly.
+# 3) Each md5() result must be identical.
+# 4) The md5() result must never change, and must be stable across releases.
+#
+set @password="password";
+set @my_data="clear text to encode";
+select md5(encode(@my_data, "password"));
+select md5(encode(@my_data, _utf8 "password"));
+select md5(encode(@my_data, binary "password"));
+select md5(encode(@my_data, _latin1 "password"));
+select md5(encode(@my_data, _koi8r "password"));
+select md5(encode(@my_data, (select "password" from dual)));
+select md5(encode(@my_data, concat("pass", "word")));
+select md5(encode(@my_data, @password));
+
+set @my_data="binary encoded data";
+select md5(decode(@my_data, "password"));
+select md5(decode(@my_data, _utf8 "password"));
+select md5(decode(@my_data, binary "password"));
+select md5(decode(@my_data, _latin1 "password"));
+select md5(decode(@my_data, _koi8r "password"));
+select md5(decode(@my_data, (select "password" from dual)));
+select md5(decode(@my_data, concat("pass", "word")));
+select md5(decode(@my_data, @password));
+
+set @dec=5;
+select format(pi(), (1+1));
+select format(pi(), (select 3 from dual));
+select format(pi(), @dec);
+
+set @bench_count=10;
+select benchmark(10, pi());
+select benchmark(5+5, pi());
+select benchmark((select 10 from dual), pi());
+select benchmark(@bench_count, pi());
+
+
+#
# Bug #10963
# 4294967296 18446744073709551616
@@ -977,4 +1085,18 @@ select lpad('hello', 18446744073709551616, '1');
select lpad('hello', -18446744073709551617, '1');
select lpad('hello', 18446744073709551617, '1');
+
+#
+# BUG#17047: CHAR() and IN() can return NULL without signaling NULL
+# result
+#
+SET @orig_sql_mode = @@SQL_MODE;
+SET SQL_MODE=traditional;
+
+SELECT CHAR(0xff,0x8f USING utf8);
+SELECT CHAR(0xff,0x8f USING utf8) IS NULL;
+
+SET SQL_MODE=@orig_sql_mode;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest
index fd19b6f8527..c5b8ee16d9a 100644
--- a/mysql-test/t/im_daemon_life_cycle.imtest
+++ b/mysql-test/t/im_daemon_life_cycle.imtest
@@ -6,59 +6,73 @@
#
###########################################################################
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle im_daemon_life_cycle.imtest started.
+
+###########################################################################
+
--source include/im_check_env.inc
-# Turn on reconnect, not on by default anymore
+# Turn on reconnect, not on by default anymore.
--enable_reconnect
###########################################################################
+#
+# The main daemon-life-cycle test case -- check that IM-angel will restart
+# IM-main if it got killed:
+# - kill IM-main and check that IM-angel will restart it;
+# - wait for IM-main to start accepting connections before continue test
+# case;
+#
+###########################################################################
-# Kill the IM main process and check that the IM Angel will restart the main
-# process.
-
---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Main-test: starting...
-###########################################################################
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Killing IM-main...
+--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30 im_daemon_life_cycle
-# Wait for IM to start accepting connections.
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Waiting for IM-main to start accepting connections...
+--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30 im_daemon_life_cycle
---exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Main-test: done.
###########################################################################
-
#
# BUG#12751: Instance Manager: client hangs
+# - start nonguarded instance (mysqld2);
+# - kill IM-main and get it restarted by IM-angel;
+# - check that guarded instance (mysqld1) is accepting connections.
+# - check that non-guarded instance (mysqld2) were not stopped.
#
+###########################################################################
--echo
--echo --------------------------------------------------------------------
--echo -- Test for BUG#12751
--echo --------------------------------------------------------------------
-# Give some time to begin accepting connections after restart.
-# FIXME: race condition here.
-
---sleep 3
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle BUG12751: starting...
# 1. Start mysqld;
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: starting...
START INSTANCE mysqld2;
-# FIXME: START INSTANCE should be synchronous.
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started
-# 2. Restart IM-main: kill it and IM-angel will restart it; wait for IM to
-# start accepting connections again.
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: waiting to start...
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started im_daemon_life_cycle
---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: started.
---exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30
+# 2. Restart IM-main;
-# 3. Issue some statement -- connection should be re-established.
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Killing IM-main...
+--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted 30 im_daemon_life_cycle
-# Give some time to begin accepting connections after restart.
-# FIXME: race condition here.
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Waiting for IM-main to start accepting connections...
+--exec $MYSQL_TEST_DIR/t/wait_for_socket.sh $EXE_MYSQL $IM_PATH_SOCK $IM_USERNAME $IM_PASSWORD '' 30 im_daemon_life_cycle
+
+# 3. Issue some statement -- connection should be re-established.
---sleep 3
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle Checking that IM-main processing commands...
--replace_column 3 VERSION_NUMBER 4 VERSION
SHOW INSTANCE STATUS mysqld1;
@@ -67,6 +81,13 @@ SHOW INSTANCE STATUS mysqld1;
# So, if it we do not stop it, it will be stopped by mysql-test-run.pl with
# warning.
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: stopping...
STOP INSTANCE mysqld2;
-# FIXME: STOP INSTANCE should be synchronous.
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped
+
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: waiting to stop...
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped im_daemon_life_cycle
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle mysqld2: stopped.
+
+###########################################################################
+
+--exec $MYSQL_TEST_DIR/t/log.sh im_daemon_life_cycle BUG12751: done.
diff --git a/mysql-test/t/im_life_cycle.imtest b/mysql-test/t/im_life_cycle.imtest
index ddfb62d312e..3721b92e2b7 100644
--- a/mysql-test/t/im_life_cycle.imtest
+++ b/mysql-test/t/im_life_cycle.imtest
@@ -25,7 +25,7 @@
START INSTANCE mysqld2;
# FIXME: START INSTANCE should be synchronous.
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started im_life_cycle
# FIXME: Result of SHOW INSTANCES here is not deterministic unless START
# INSTANCE is synchronous. Even waiting for mysqld to start by looking at
@@ -58,7 +58,7 @@ SHOW VARIABLES LIKE 'port';
STOP INSTANCE mysqld2;
# FIXME: STOP INSTANCE should be synchronous.
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped im_life_cycle
# FIXME: Result of SHOW INSTANCES here is not deterministic unless START
# INSTANCE is synchronous. Even waiting for mysqld to start by looking at
@@ -121,7 +121,7 @@ STOP INSTANCE mysqld3;
--echo -- 1.1.6.
--echo --------------------------------------------------------------------
---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted 30
+--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted 30 im_life_cycle
# Give some time to IM to detect that mysqld was restarted. It should be
# longer than monitoring interval.
@@ -143,7 +143,7 @@ SHOW INSTANCES;
START INSTANCE mysqld2;
# FIXME: START INSTANCE should be synchronous.
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started im_life_cycle
# FIXME: Result of SHOW INSTANCES here is not deterministic unless START
# INSTANCE is synchronous. Even waiting for mysqld to start by looking at
@@ -151,7 +151,7 @@ START INSTANCE mysqld2;
# mysqld has started.
# SHOW INSTANCES;
---exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD2_PATH_PID killed 10
+--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD2_PATH_PID killed 10 im_life_cycle
# FIXME: Result of SHOW INSTANCES here is not deterministic unless START
# INSTANCE is synchronous. Even waiting for mysqld to start by looking at
diff --git a/mysql-test/t/im_options.imtest b/mysql-test/t/im_options.imtest
index b3932c446da..8f9bed16473 100644
--- a/mysql-test/t/im_options.imtest
+++ b/mysql-test/t/im_options.imtest
@@ -32,33 +32,7 @@
#
###########################################################################
---source include/im_check_os.inc
-
-###########################################################################
-#
-# Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---echo --------------------------------------------------------------------
---exec grep '^server_id[^a-zA-Z0-9_-]' $MYSQLTEST_VARDIR/im.cnf ;
---echo --------------------------------------------------------------------
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-
-SHOW INSTANCES;
+--source include/im_check_env.inc
###########################################################################
#
diff --git a/mysql-test/t/im_utils.imtest b/mysql-test/t/im_utils.imtest
index 52878f6c2b5..0866b87204a 100644
--- a/mysql-test/t/im_utils.imtest
+++ b/mysql-test/t/im_utils.imtest
@@ -31,10 +31,10 @@ SHOW INSTANCE OPTIONS mysqld2;
#
START INSTANCE mysqld2;
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 started im_utils
STOP INSTANCE mysqld2;
---exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped
+--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD2_PATH_PID 30 stopped im_utils
#
# Check 'SHOW LOG FILES' command:
diff --git a/mysql-test/t/kill_n_check.sh b/mysql-test/t/kill_n_check.sh
index a54fb6ef8bb..96c402a638c 100755
--- a/mysql-test/t/kill_n_check.sh
+++ b/mysql-test/t/kill_n_check.sh
@@ -2,74 +2,101 @@
###########################################################################
-# NOTE: this script returns 0 (success) even in case of failure. This is
-# because this script is executed under mysql-test-run[.pl] and it's better to
-# examine particular problem in log file, than just having said that the test
-# case has failed.
+# NOTE: this script returns 0 (success) even in case of failure (except for
+# usage-error). This is because this script is executed under
+# mysql-test-run[.pl] and it's better to examine particular problem in log
+# file, than just having said that the test case has failed.
+
+###########################################################################
+
+basename=`basename "$0"`
+dirname=`dirname "$0"`
+
+###########################################################################
+
+. "$dirname/utils.sh"
###########################################################################
check_restart()
{
if [ ! -r "$pid_path" ]; then
+ log_debug "No '$pid_path' found."
user_msg='the process was killed'
return 1
fi
new_pid=`cat "$pid_path" 2>/dev/null`
+ err_code=$?
- if [ $? -eq 0 -a "$original_pid" = "$new_pid" ]; then
+ log_debug "err_code: $err_code; original_pid: $original_pid; new_pid: $new_pid."
+
+ if [ $err_code -eq 0 -a "$original_pid" = "$new_pid" ]; then
+ log_debug "The process was not restarted."
user_msg='the process was not restarted'
return 1
fi
+ log_debug "The process was restarted."
user_msg='the process was restarted'
return 0
}
###########################################################################
-if [ $# -ne 3 ]; then
- echo "Usage: kill_n_check.sh <pid file path> killed|restarted <timeout>"
- exit 0
+if [ $# -ne 4 ]; then
+ echo "Usage: $basename <pid file path> killed|restarted <timeout> <test id>"
+ exit 1
fi
pid_path="$1"
expected_result="$2"
total_timeout="$3"
+test_id="$4"
+log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
+
+log_debug "-- $basename: starting --"
+log_debug "pid_path: '$pid_path'"
+log_debug "expected_result: '$expected_result'"
+log_debug "total_timeout: '$total_timeout'"
+log_debug "test_id: '$test_id'"
+log_debug "log_file: '$log_file'"
+
+###########################################################################
if [ "$expected_result" != 'killed' -a \
"$expected_result" != 'restarted' ]; then
- echo "Error: invalid second argument ('killed' or 'restarted' expected)."
- exit 0
+ log_error "Invalid second argument ($expected_result): 'killed' or 'restarted' expected."
+ quit 0
fi
if [ -z "$pid_path" ]; then
- echo "Error: invalid PID path ($pid_path)."
- exit 0
+ log_error "Invalid PID path ($pid_path)."
+ quit 0
fi
if [ ! -r "$pid_path" ]; then
- echo "Error: PID file ($pid_path) does not exist."
- exit 0
+ log_error "PID file ($pid_path) does not exist."
+ quit 0
fi
if [ -z "$total_timeout" ]; then
- echo "Error: timeout is not specified."
- exit 0
+ log_error "Timeout is not specified."
+ quit 0
fi
###########################################################################
original_pid=`cat "$pid_path"`
+log_debug "original_pid: $original_pid."
-echo "Killing the process..."
+log_info "Killing the process..."
kill -9 $original_pid
###########################################################################
-echo "Sleeping..."
+log_info "Waiting..."
if [ "$expected_result" = "restarted" ]; then
@@ -79,37 +106,42 @@ if [ "$expected_result" = "restarted" ]; then
while true; do
+ log_debug "cur_attempt: $cur_attempt."
+
if check_restart; then
- echo "Success: $user_msg."
- exit 0
+ log_info "Success: $user_msg."
+ quit 0
fi
[ $cur_attempt -ge $total_timeout ] && break
+ log_debug "Sleeping for 1 second..."
sleep 1
cur_attempt=`expr $cur_attempt + 1`
done
- echo "Error: $user_msg."
- exit 0
+ log_error "$user_msg."
+ quit 0
else # $expected_result == killed
# Here we have to sleep for some long time to ensure that the process will
# not be restarted.
+ log_debug "Sleeping for $total_timeout seconds..."
sleep $total_timeout
new_pid=`cat "$pid_path" 2>/dev/null`
+ log_debug "new_pid: $new_pid."
if [ "$new_pid" -a "$new_pid" -ne "$original_pid" ]; then
- echo "Error: the process was restarted."
+ log_error "The process was restarted."
else
- echo "Success: the process was killed."
+ log_info "Success: the process was killed."
fi
- exit 0
+ quit 0
fi
diff --git a/mysql-test/t/log.sh b/mysql-test/t/log.sh
new file mode 100755
index 00000000000..20b265087cc
--- /dev/null
+++ b/mysql-test/t/log.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+###########################################################################
+
+basename=`basename "$0"`
+dirname=`dirname "$0"`
+
+###########################################################################
+
+. "$dirname/utils.sh"
+
+###########################################################################
+
+if [ $# -lt 2 ]; then
+ echo "Usage: $basename <test id> log message ..."
+ exit 1
+fi
+
+test_id="$1"
+log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
+
+shift
+
+log_debug "$*"
diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test
index 11af7c691d8..39c8d8e2bf4 100644
--- a/mysql-test/t/parser.test
+++ b/mysql-test/t/parser.test
@@ -399,11 +399,6 @@ select atan();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select atan2(1, 2, 3);
-select benchmark(10, 1+1);
-
--- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
-select benchmark(5+5, 2);
-
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select concat();
select concat("foo");
@@ -413,12 +408,6 @@ select concat_ws();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select concat_ws("foo");
-set @pwd="my password";
--- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
-select encode("secret", @pwd);
--- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
-select decode("encoded-secret", @pwd);
-
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select encrypt();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
@@ -448,10 +437,6 @@ select field();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select field("p1");
-set @dec=2;
--- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
-select format(pi(), @dec);
-
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
select from_unixtime();
-- error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 827f46664bf..39e4e65c6bf 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -849,6 +849,9 @@ drop table t1;
# Bug#16365 Prepared Statements: DoS with too many open statements
# Check that the limit @@max_prpeared_stmt_count works.
#
+# This is also the test for bug#23159 prepared_stmt_count should be
+# status variable.
+#
# Save the old value
set @old_max_prepared_stmt_count= @@max_prepared_stmt_count;
#
@@ -858,17 +861,17 @@ set @old_max_prepared_stmt_count= @@max_prepared_stmt_count;
#
--disable_ps_protocol
#
-# A. Check that the new variables are present in SHOW VARIABLES list.
+# A. Check that the new variables are present in SHOW VARIABLES and
+# SHOW STATUS lists.
#
show variables like 'max_prepared_stmt_count';
-show variables like 'prepared_stmt_count';
+show status like 'prepared_stmt_count';
#
-# B. Check that the new variables are selectable.
+# B. Check that the new system variable is selectable.
#
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
+select @@max_prepared_stmt_count;
#
-# C. Check that max_prepared_stmt_count is settable (global only),
-# whereas prepared_stmt_count is readonly.
+# C. Check that max_prepared_stmt_count is settable (global only).
#
set global max_prepared_stmt_count=-1;
select @@max_prepared_stmt_count;
@@ -882,12 +885,6 @@ set @@max_prepared_stmt_count=1;
set max_prepared_stmt_count=1;
--error ER_GLOBAL_VARIABLE
set local max_prepared_stmt_count=1;
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-set local prepared_stmt_count=0;
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-set @@prepared_stmt_count=0;
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-set global prepared_stmt_count=1;
# set to a reasonable limit works
set global max_prepared_stmt_count=1;
select @@max_prepared_stmt_count;
@@ -895,47 +892,50 @@ select @@max_prepared_stmt_count;
# D. Check that the variables actually work.
#
set global max_prepared_stmt_count=0;
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
+select @@max_prepared_stmt_count;
+show status like 'prepared_stmt_count';
--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt from "select 1";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
set global max_prepared_stmt_count=1;
prepare stmt from "select 1";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt1 from "select 1";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
deallocate prepare stmt;
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
#
# E. Check that we can prepare a statement with the same name
# successfully, without hitting the limit.
#
prepare stmt from "select 1";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
prepare stmt from "select 2";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
#
# F. We can set the max below the current count. In this case no new
# statements should be allowed to prepare.
#
-select @@prepared_stmt_count, @@max_prepared_stmt_count;
+show status like 'prepared_stmt_count';
+select @@max_prepared_stmt_count;
set global max_prepared_stmt_count=0;
--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt from "select 1";
# Result: the old statement is deallocated, the new is not created.
---error 1243 # ER_UNKNOWN_STMT_HANDLER
+--error ER_UNKNOWN_STMT_HANDLER
execute stmt;
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt from "select 1";
-select @@prepared_stmt_count;
+show status like 'prepared_stmt_count';
#
# G. Show that the variables are up to date even after a connection with all
# statements in it was terminated.
#
set global max_prepared_stmt_count=3;
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
+select @@max_prepared_stmt_count;
+show status like 'prepared_stmt_count';
prepare stmt from "select 1";
connect (con1,localhost,root,,);
connection con1;
@@ -944,26 +944,31 @@ prepare stmt1 from "select 3";
--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt2 from "select 4";
connection default;
---error ER_MAX_PREPARED_STMT_COUNT_REACHED
+--error ER_MAX_PREPARED_STMT_COUNT_REACHED
prepare stmt2 from "select 4";
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
+select @@max_prepared_stmt_count;
+show status like 'prepared_stmt_count';
disconnect con1;
connection default;
# Wait for the connection to die: deal with a possible race
deallocate prepare stmt;
-let $count= `select @@prepared_stmt_count`;
+let $query= select variable_value from information_schema.global_status
+ where variable_name = 'prepared_stmt_count';
+let $count= `$query`;
if ($count)
{
---sleep 2
- let $count= `select @@prepared_stmt_count`;
+--sleep 1
+ let $count= `$query`;
}
-select @@max_prepared_stmt_count, @@prepared_stmt_count;
+select @@max_prepared_stmt_count;
+show status like 'prepared_stmt_count';
#
# Restore the old value.
#
set global max_prepared_stmt_count= @old_max_prepared_stmt_count;
--enable_ps_protocol
+
#
# Bug#19399 "Stored Procedures 'Lost Connection' when dropping/creating
# tables"
@@ -2400,3 +2405,38 @@ execute abc;
drop table if exists t1, t2;
execute abc;
deallocate prepare abc;
+
+#
+# Bug#22684: The Functions ENCODE, DECODE and FORMAT are not real functions
+#
+
+set @my_password="password";
+set @my_data="clear text to encode";
+
+prepare stmt1 from 'select decode(encode(?, ?), ?)';
+execute stmt1 using @my_data, @my_password, @my_password;
+set @my_data="more text to encode";
+execute stmt1 using @my_data, @my_password, @my_password;
+set @my_password="new password";
+execute stmt1 using @my_data, @my_password, @my_password;
+deallocate prepare stmt1;
+
+set @to_format="123456789.123456789";
+set @dec=0;
+
+prepare stmt2 from 'select format(?, ?)';
+execute stmt2 using @to_format, @dec;
+set @dec=4;
+execute stmt2 using @to_format, @dec;
+set @dec=6;
+execute stmt2 using @to_format, @dec;
+set @dec=2;
+execute stmt2 using @to_format, @dec;
+set @to_format="100";
+execute stmt2 using @to_format, @dec;
+set @to_format="1000000";
+execute stmt2 using @to_format, @dec;
+set @to_format="10000";
+execute stmt2 using @to_format, @dec;
+deallocate prepare stmt2;
+
diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test
index 6ec0021635a..9f5f6fc9b4c 100644
--- a/mysql-test/t/rpl_trigger.test
+++ b/mysql-test/t/rpl_trigger.test
@@ -431,6 +431,43 @@ DROP TABLE t2;
--sync_with_master
--connection master
+#
+# BUG#23703: DROP TRIGGER needs an IF EXISTS
+#
+
+connection master;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int, b varchar(50));
+
+-- error ER_TRG_DOES_NOT_EXIST
+drop trigger not_a_trigger;
+
+drop trigger if exists not_a_trigger;
+
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+insert into t1 values (3, "c");
+
+select * from t1;
+
+save_master_pos;
+connection slave;
+sync_with_master;
+
+select * from t1;
+
+connection master;
+
+drop table t1;
#
# End of tests
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index bb18c0e5858..8f4763c636a 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -11,6 +11,7 @@
# Tests that uses 'goto' to into sp-goto.test (currently disabled)
# Tests that destroys system tables (e.g. mysql.proc) for error testing
# go to sp-destruct.
+# Tests that require --with-geometry go into sp_gis.test
use test;
@@ -2584,6 +2585,9 @@ begin
end if;
end|
+# so that from_unixtime() has a deterministic result
+set time_zone='+03:00';
+
call bug3426(1000, @i)|
select @i, from_unixtime(@stamped_time, '%d-%m-%Y %h:%i:%s') as time|
call bug3426(NULL, @i)|
@@ -6585,6 +6589,122 @@ drop procedure proc_21462_b|
--echo End of 5.0 tests
+--echo Begin of 5.1 tests
+
+#
+# BUG#18239: Possible to overload internal functions with stored functions
+#
+
+delimiter ;|
+
+--disable_warnings
+drop function if exists pi;
+--enable_warnings
+
+create function pi() returns varchar(50)
+return "pie, my favorite desert.";
+
+SET @save_sql_mode=@@sql_mode;
+
+SET SQL_MODE='IGNORE_SPACE';
+
+select pi(), pi ();
+
+# Non deterministic warnings from db_load_routine
+--disable_warnings
+select test.pi(), test.pi ();
+--enable_warnings
+
+SET SQL_MODE='';
+
+select pi(), pi ();
+
+# Non deterministic warnings from db_load_routine
+--disable_warnings
+select test.pi(), test.pi ();
+--enable_warnings
+
+SET @@sql_mode=@save_sql_mode;
+
+drop function pi;
+# End of BUG#18239
+
+#
+# BUG#22619: Spaces considered harmful
+#
+
+--disable_warnings
+drop function if exists test.database;
+drop function if exists test.current_user;
+drop function if exists test.md5;
+--enable_warnings
+
+create database nowhere;
+use nowhere;
+drop database nowhere;
+
+SET @save_sql_mode=@@sql_mode;
+
+SET SQL_MODE='IGNORE_SPACE';
+
+select database(), database ();
+select current_user(), current_user ();
+select md5("aaa"), md5 ("aaa");
+
+SET SQL_MODE='';
+
+select database(), database ();
+select current_user(), current_user ();
+select md5("aaa"), md5 ("aaa");
+
+use test;
+
+create function `database`() returns varchar(50)
+return "Stored function database";
+
+create function `current_user`() returns varchar(50)
+return "Stored function current_user";
+
+create function md5(x varchar(50)) returns varchar(50)
+return "Stored function md5";
+
+SET SQL_MODE='IGNORE_SPACE';
+
+select database(), database ();
+select current_user(), current_user ();
+select md5("aaa"), md5 ("aaa");
+
+# Non deterministic warnings from db_load_routine
+--disable_warnings
+select test.database(), test.database ();
+select test.current_user(), test.current_user ();
+select test.md5("aaa"), test.md5 ("aaa");
+--enable_warnings
+
+SET SQL_MODE='';
+
+select database(), database ();
+select current_user(), current_user ();
+select md5("aaa"), md5 ("aaa");
+
+# Non deterministic warnings from db_load_routine
+--disable_warnings
+select test.database(), test.database ();
+select test.current_user(), test.current_user ();
+select test.md5("aaa"), test.md5 ("aaa");
+--enable_warnings
+
+SET @@sql_mode=@save_sql_mode;
+
+drop function test.database;
+drop function test.current_user;
+drop function md5;
+
+use test;
+delimiter |;
+# End of BUG#22619
+
+--echo End of 5.1 tests
#
# BUG#NNNN: New bug synopsis
diff --git a/mysql-test/t/sp_gis.test b/mysql-test/t/sp_gis.test
new file mode 100644
index 00000000000..51ed78b27d5
--- /dev/null
+++ b/mysql-test/t/sp_gis.test
@@ -0,0 +1,39 @@
+-- source include/have_geometry.inc
+
+use test;
+
+#
+# BUG#21025: misleading error message when creating functions named 'x', or 'y'
+#
+
+--disable_warnings
+drop function if exists a;
+drop function if exists x;
+drop function if exists y;
+--enable_warnings
+
+create function a() returns int
+return 1;
+
+create function x() returns int
+return 2;
+
+create function y() returns int
+return 3;
+
+select a();
+--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
+select x();
+--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
+select y();
+select x(PointFromText("POINT(10 20)")), y(PointFromText("POINT(10 20)"));
+
+# Non deterministic warnings from db_load_routine
+--disable_warnings
+select test.a(), test.x(), test.y();
+--enable_warnings
+
+drop function a;
+drop function x;
+drop function y;
+
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 8242c614d0a..12262894e5b 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -1499,4 +1499,52 @@ select * from t1;
drop table t1;
+#
+# Bug #23651 "Server crashes when trigger which uses stored function
+# invoked from different connections".
+#
+--disable_warnings
+drop table if exists t1;
+drop function if exists f1;
+--enable_warnings
+create table t1 (i int);
+create function f1() returns int return 10;
+create trigger t1_bi before insert on t1 for each row set @a:= f1() + 10;
+insert into t1 values ();
+select @a;
+connection addconroot1;
+insert into t1 values ();
+select @a;
+connection default;
+drop table t1;
+drop function f1;
+
+#
+# Bug#23703: DROP TRIGGER needs an IF EXISTS
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int, b varchar(50));
+
+-- error ER_TRG_DOES_NOT_EXIST
+drop trigger not_a_trigger;
+
+drop trigger if exists not_a_trigger;
+
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+insert into t1 values (3, "c");
+
+select * from t1;
+
+drop table t1;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test
index 37358a292be..01aac24ded4 100644
--- a/mysql-test/t/udf.test
+++ b/mysql-test/t/udf.test
@@ -174,6 +174,42 @@ DROP FUNCTION fn;
--echo End of 5.0 tests.
#
+# BUG#18239: Possible to overload internal functions with stored functions
+#
+
+--disable_warnings
+drop function if exists pi;
+--enable_warnings
+
+--error ER_NATIVE_FCT_NAME_COLLISION
+CREATE FUNCTION pi RETURNS STRING SONAME "should_not_parse.so";
+
+# Verify that Stored Functions and UDF are mutually exclusive
+DROP FUNCTION IF EXISTS metaphon;
+
+CREATE FUNCTION metaphon(a int) RETURNS int
+return 0;
+
+--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
+--error ER_UDF_EXISTS
+eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
+
+DROP FUNCTION metaphon;
+
+--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
+eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
+
+--error ER_UDF_EXISTS
+CREATE FUNCTION metaphon(a int) RETURNS int
+return 0;
+
+--error ER_UDF_EXISTS
+CREATE FUNCTION test.metaphon(a int) RETURNS int
+return 0;
+
+# End of Bug#18239
+
+#
# Drop the example functions from udf_example
#
diff --git a/mysql-test/t/utils.sh b/mysql-test/t/utils.sh
new file mode 100644
index 00000000000..b3f4744947d
--- /dev/null
+++ b/mysql-test/t/utils.sh
@@ -0,0 +1,55 @@
+###########################################################################
+#
+# This file provides utility functions and is included by other scripts.
+#
+# The following global variables must be set before calling functions from this
+# file:
+# - basename -- base name of the calling script (main application);
+# - log_file -- where to store log records;
+#
+###########################################################################
+
+log()
+{
+ [ -z "$log_file" ] && return;
+
+ log_level="$1"
+ log_msg="$2"
+ ts=`date`
+
+ echo "[$ts] [$basename] [$log_level] $log_msg" >> "$log_file";
+}
+
+###########################################################################
+
+log_debug()
+{
+ log 'DEBUG' "$1"
+}
+
+###########################################################################
+
+log_info()
+{
+ log 'INFO' "$1"
+ echo "$1"
+}
+
+###########################################################################
+
+log_error()
+{
+ log 'ERROR' "$1"
+ echo "Error: $1"
+}
+
+###########################################################################
+
+quit()
+{
+ exit_status="$1"
+
+ log_debug "-- $basename: finished (exit_status: $exit_status) --"
+
+ exit $exit_status
+}
diff --git a/mysql-test/t/wait_for_process.sh b/mysql-test/t/wait_for_process.sh
index df0f4a17e3a..4c2d89cfea6 100755
--- a/mysql-test/t/wait_for_process.sh
+++ b/mysql-test/t/wait_for_process.sh
@@ -2,34 +2,40 @@
###########################################################################
-pid_path="$1"
-total_attempts="$2"
-event="$3"
+# NOTE: this script returns 0 (success) even in case of failure (except for
+# usage-error). This is because this script is executed under
+# mysql-test-run[.pl] and it's better to examine particular problem in log
+# file, than just having said that the test case has failed.
-case "$3" in
- started)
- check_fn='check_started';
- ;;
+###########################################################################
- stopped)
- check_fn='check_stopped';
- ;;
+basename=`basename "$0"`
+dirname=`dirname "$0"`
- *)
- echo "Error: invalid third argument ('started' or 'stopped' expected)."
- exit 0
-esac
+###########################################################################
+
+. "$dirname/utils.sh"
###########################################################################
check_started()
{
- [ ! -r "$pid_path" ] && return 1
+ if [ ! -r "$pid_path" ]; then
+ log_debug "No PID-file ($pid_path) found -- not started."
+ return 1
+ fi
new_pid=`cat "$pid_path" 2>/dev/null`
+ err_code=$?
+
+ log_debug "err_code: $err_code; new_pid: $new_pid."
- [ $? -eq 0 -a "$original_pid" = "$new_pid" ] && return 1
+ if [ $? -ne 0 -o -z "$new_pid" ]; then
+ log_debug "The process was not started."
+ return 1
+ fi
+ log_debug "The process was started."
return 0
}
@@ -37,30 +43,72 @@ check_started()
check_stopped()
{
- [ -r "$pid_path" ] && return 1
+ if [ -r "$pid_path" ]; then
+ log_debug "PID-file '$pid_path' exists -- not stopped."
+ return 1
+ fi
+ log_debug "No PID-file ($pid_path) found -- stopped."
return 0
}
###########################################################################
+if [ $# -ne 4 ]; then
+ echo "Usage: $basename <pid file path> <total attempts> started|stopped <test id>"
+ exit 1
+fi
+
+pid_path="$1"
+total_attempts="$2"
+event="$3"
+test_id="$4"
+log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
+
+log_debug "-- $basename: starting --"
+log_debug "pid_path: '$pid_path'"
+log_debug "total_attempts: '$total_attempts'"
+log_debug "event: '$event'"
+log_debug "test_id: '$test_id'"
+log_debug "log_file: '$log_file'"
+
+###########################################################################
+
+case "$event" in
+ started)
+ check_fn='check_started';
+ ;;
+
+ stopped)
+ check_fn='check_stopped';
+ ;;
+
+ *)
+ log_error "Invalid third argument ('started' or 'stopped' expected)."
+ quit 0
+esac
+
+###########################################################################
+
cur_attempt=1
while true; do
+ log_debug "cur_attempt: $cur_attempt."
+
if ( eval $check_fn ); then
- echo "Success: the process has been $event."
- exit 0
+ log_info "Success: the process has been $event."
+ quit 0
fi
[ $cur_attempt -ge $total_attempts ] && break
+ log_debug "Sleeping for 1 second..."
sleep 1
cur_attempt=`expr $cur_attempt + 1`
done
-echo "Error: the process has not been $event in $total_attempts secs."
-exit 0
-
+log_error "The process has not been $event in $total_attempts secs."
+quit 0
diff --git a/mysql-test/t/wait_for_socket.sh b/mysql-test/t/wait_for_socket.sh
index b6526b7d19c..1bce74dfd3a 100755
--- a/mysql-test/t/wait_for_socket.sh
+++ b/mysql-test/t/wait_for_socket.sh
@@ -2,9 +2,25 @@
###########################################################################
-if [ $# -ne 6 ]; then
- echo "Usage: wait_for_socket.sh <executable path> <socket path> <username> <password> <db> <timeout>"
- exit 0
+# NOTE: this script returns 0 (success) even in case of failure (except for
+# usage-error). This is because this script is executed under
+# mysql-test-run[.pl] and it's better to examine particular problem in log
+# file, than just having said that the test case has failed.
+
+###########################################################################
+
+basename=`basename "$0"`
+dirname=`dirname "$0"`
+
+###########################################################################
+
+. "$dirname/utils.sh"
+
+###########################################################################
+
+if [ $# -ne 7 ]; then
+ echo "Usage: wait_for_socket.sh <executable path> <socket path> <username> <password> <db> <timeout> <test id>"
+ exit 1
fi
client_exe="$1"
@@ -13,22 +29,34 @@ username="$3"
password="$4"
db="$5"
total_timeout="$6"
+test_id="$7"
+log_file="$MYSQLTEST_VARDIR/log/$test_id.log"
+
+log_debug "-- $basename: starting --"
+log_debug "client_exe: '$client_exe'"
+log_debug "socket_path: '$socket_path'"
+log_debug "username: '$username'"
+log_debug "password: '$password'"
+log_debug "db: '$db'"
+log_debug "total_timeout: '$total_timeout'"
+log_debug "test_id: '$test_id'"
+log_debug "log_file: '$log_file'"
###########################################################################
if [ -z "$client_exe" ]; then
- echo "Error: invalid path to client executable ($client_exe)."
- exit 0;
+ log_error "Invalid path to client executable ($client_exe)."
+ quit 0;
fi
if [ ! -x "$client_exe" ]; then
- echo "Error: client by path '$client_exe' is not available."
- exit 0;
+ log_error "Client by path '$client_exe' is not available."
+ quit 0;
fi
if [ -z "$socket_path" ]; then
- echo "Error: invalid socket patch."
- exit 0
+ log_error "Invalid socket patch ($socket_path)."
+ quit 0
fi
###########################################################################
@@ -39,15 +67,19 @@ client_args="--silent --socket=$socket_path --connect_timeout=1 "
[ -n "$password" ] && client_args="$client_args --password=$password "
[ -n "$db" ] && client_args="$client_args $db"
+log_debug "client_args: '$client_args'"
+
###########################################################################
cur_attempt=1
while true; do
+ log_debug "cur_attempt: $cur_attempt."
+
if ( echo 'quit' | "$client_exe" $client_args >/dev/null 2>&1 ); then
- echo "Success: server is ready to accept connection on socket."
- exit 0
+ log_info "Success: server is ready to accept connection on socket."
+ quit 0
fi
[ $cur_attempt -ge $total_timeout ] && break
@@ -58,5 +90,5 @@ while true; do
done
-echo "Error: server does not accept connections after $total_timeout seconds."
-exit 0
+log_error "Server does not accept connections after $total_timeout seconds."
+quit 0
diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp
index f9ea7ee471d..c8968fe9c16 100644
--- a/server-tools/instance-manager/IMService.cpp
+++ b/server-tools/instance-manager/IMService.cpp
@@ -21,22 +21,22 @@ void IMService::Stop()
{
ReportStatus(SERVICE_STOP_PENDING);
- // stop the IM work
+ /* stop the IM work */
raise(SIGTERM);
}
void IMService::Run(DWORD argc, LPTSTR *argv)
{
- // report to the SCM that we're about to start
+ /* report to the SCM that we're about to start */
ReportStatus((DWORD)SERVICE_START_PENDING);
Options::load(argc, argv);
- // init goes here
+ /* init goes here */
ReportStatus((DWORD)SERVICE_RUNNING);
- // wait for main loop to terminate
- manager();
+ /* wait for main loop to terminate */
+ (void) Manager::main();
Options::cleanup();
}
@@ -54,24 +54,24 @@ int HandleServiceOptions()
if (Options::Service::install_as_service)
{
if (winService.IsInstalled())
- log_info("Service is already installed");
+ log_info("Service is already installed.");
else if (winService.Install())
- log_info("Service installed successfully");
+ log_info("Service installed successfully.");
else
{
- log_info("Service failed to install");
+ log_error("Service failed to install.");
ret_val= 1;
}
}
else if (Options::Service::remove_service)
{
if (! winService.IsInstalled())
- log_info("Service is not installed");
+ log_info("Service is not installed.");
else if (winService.Remove())
- log_info("Service removed successfully");
+ log_info("Service removed successfully.");
else
{
- log_info("Service failed to remove");
+ log_error("Service failed to remove.");
ret_val= 1;
}
}
@@ -81,7 +81,7 @@ int HandleServiceOptions()
if (!winService.Init())
{
- log_info("Service failed to initialize.");
+ log_error("Service failed to initialize.");
fprintf(stderr,
"The service should be started by Windows Service Manager.\n"
"The MySQL Manager should be started with '--standalone'\n"
diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h
index 94d59c2af31..aacc957e195 100644
--- a/server-tools/instance-manager/IMService.h
+++ b/server-tools/instance-manager/IMService.h
@@ -19,7 +19,7 @@
#pragma once
#include "windowsservice.h"
-class IMService : public WindowsService
+class IMService: public WindowsService
{
public:
IMService(void);
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
index 4719828081a..2d2365caa44 100644
--- a/server-tools/instance-manager/Makefile.am
+++ b/server-tools/instance-manager/Makefile.am
@@ -61,6 +61,8 @@ client_settings.h:
libexec_PROGRAMS= mysqlmanager
+mysqlmanager_CXXFLAGS= -Wall -W
+
mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
manager.h manager.cc log.h log.cc \
thread_registry.h thread_registry.cc \
diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc
index 8039ab24481..e1a57a53087 100644
--- a/server-tools/instance-manager/buffer.cc
+++ b/server-tools/instance-manager/buffer.cc
@@ -27,7 +27,7 @@ const uint Buffer::MAX_BUFFER_SIZE= 16777216;
/*
Puts the given string to the buffer.
- SYNOPSYS
+ SYNOPSIS
append()
position start position in the buffer
string string to be put in the buffer
@@ -59,7 +59,7 @@ int Buffer::append(uint position, const char *string, uint len_arg)
Checks whether the current buffer size is ok to put a string of the length
"len_arg" starting from "position" and reallocs it if no.
- SYNOPSYS
+ SYNOPSIS
reserve()
position the number starting byte on the buffer to store a buffer
len_arg the length of the string.
diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc
index f76366d5661..0ada11e8865 100644
--- a/server-tools/instance-manager/command.cc
+++ b/server-tools/instance-manager/command.cc
@@ -19,10 +19,12 @@
#endif
#include "command.h"
+#include "manager.h"
-Command::Command(Instance_map *instance_map_arg)
- :instance_map(instance_map_arg)
+Command::Command()
+ :guardian(Manager::get_guardian()),
+ instance_map(Manager::get_instance_map())
{}
Command::~Command()
diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h
index f31ea404867..e5f7d6e97e6 100644
--- a/server-tools/instance-manager/command.h
+++ b/server-tools/instance-manager/command.h
@@ -24,6 +24,7 @@
/* Class responsible for allocation of IM commands. */
+class Guardian;
class Instance_map;
struct st_net;
@@ -36,13 +37,13 @@ struct st_net;
class Command
{
public:
- Command(Instance_map *instance_map_arg= 0);
+ Command();
virtual ~Command();
/*
This operation incapsulates behaviour of the command.
- SYNOPSYS
+ SYNOPSIS
net The network connection to the client.
connection_id Client connection ID
@@ -53,6 +54,7 @@ public:
virtual int execute(st_net *net, ulong connection_id) = 0;
protected:
+ Guardian *guardian;
Instance_map *instance_map;
};
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
index 66140b8b049..15738f8ebb3 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -29,7 +29,6 @@
#include "guardian.h"
#include "instance_map.h"
#include "log.h"
-#include "manager.h"
#include "messages.h"
#include "mysqld_error.h"
#include "mysql_manager_error.h"
@@ -50,7 +49,7 @@ static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
/*
Add a string to a buffer.
- SYNOPSYS
+ SYNOPSIS
put_to_buff()
buff buffer to add the string
str string to add
@@ -130,7 +129,7 @@ Instance_name::Instance_name(const LEX_STRING *name)
ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Show_instances::execute(st_net *net, ulong connection_id)
+int Show_instances::execute(st_net *net, ulong /* connection_id */)
{
int err_code;
@@ -242,10 +241,8 @@ int Flush_instances::execute(st_net *net, ulong connection_id)
Implementation of Abstract_instance_cmd.
**************************************************************************/
-Abstract_instance_cmd::Abstract_instance_cmd(
- Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
- :Command(instance_map_arg),
- instance_name(instance_name_arg)
+Abstract_instance_cmd::Abstract_instance_cmd(const LEX_STRING *instance_name_arg)
+ :instance_name(instance_name_arg)
{
/*
MT-NOTE: we can not make a search for Instance object here,
@@ -285,9 +282,8 @@ int Abstract_instance_cmd::execute(st_net *net, ulong connection_id)
Implementation of Show_instance_status.
**************************************************************************/
-Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -312,7 +308,8 @@ int Show_instance_status::execute_impl(st_net *net, Instance *instance)
}
-int Show_instance_status::send_ok_response(st_net *net, ulong connection_id)
+int Show_instance_status::send_ok_response(st_net *net,
+ ulong /* connection_id */)
{
if (send_eof(net) || net_flush(net))
return ER_OUT_OF_RESOURCES;
@@ -406,8 +403,8 @@ int Show_instance_status::write_data(st_net *net, Instance *instance)
**************************************************************************/
Show_instance_options::Show_instance_options(
- Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+ const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -432,7 +429,8 @@ int Show_instance_options::execute_impl(st_net *net, Instance *instance)
}
-int Show_instance_options::send_ok_response(st_net *net, ulong connection_id)
+int Show_instance_options::send_ok_response(st_net *net,
+ ulong /* connection_id */)
{
if (send_eof(net) || net_flush(net))
return ER_OUT_OF_RESOURCES;
@@ -501,9 +499,8 @@ int Show_instance_options::write_data(st_net *net, Instance *instance)
Implementation of Start_instance.
**************************************************************************/
-Start_instance::Start_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Start_instance::Start_instance(const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -516,7 +513,7 @@ Start_instance::Start_instance(Instance_map *instance_map_arg,
ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Start_instance::execute_impl(st_net *net, Instance *instance)
+int Start_instance::execute_impl(st_net * /* net */, Instance *instance)
{
int err_code;
@@ -543,9 +540,8 @@ int Start_instance::send_ok_response(st_net *net, ulong connection_id)
Implementation of Stop_instance.
**************************************************************************/
-Stop_instance::Stop_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -558,7 +554,7 @@ Stop_instance::Stop_instance(Instance_map *instance_map_arg,
ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Stop_instance::execute_impl(st_net *net, Instance *instance)
+int Stop_instance::execute_impl(st_net * /* net */, Instance *instance)
{
int err_code;
@@ -585,10 +581,8 @@ int Stop_instance::send_ok_response(st_net *net, ulong connection_id)
Implementation for Create_instance.
**************************************************************************/
-Create_instance::Create_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Command(instance_map_arg),
- instance_name(instance_name_arg)
+Create_instance::Create_instance(const LEX_STRING *instance_name_arg)
+ :instance_name(instance_name_arg)
{
}
@@ -596,7 +590,7 @@ Create_instance::Create_instance(Instance_map *instance_map_arg,
/*
This operation initializes Create_instance object.
- SYNOPSYS
+ SYNOPSIS
text [IN/OUT] a pointer to the text containing instance options.
RETURN
@@ -613,7 +607,7 @@ bool Create_instance::init(const char **text)
/*
This operation parses CREATE INSTANCE options.
- SYNOPSYS
+ SYNOPSIS
text [IN/OUT] a pointer to the text containing instance options.
RETURN
@@ -795,9 +789,8 @@ int Create_instance::execute(st_net *net, ulong connection_id)
Implementation for Drop_instance.
**************************************************************************/
-Drop_instance::Drop_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -811,7 +804,7 @@ Drop_instance::Drop_instance(Instance_map *instance_map_arg,
ER_OUT_OF_RESOURCES Not enough resources to complete the operation
*/
-int Drop_instance::execute_impl(st_net *net, Instance *instance)
+int Drop_instance::execute_impl(st_net * /* net */, Instance *instance)
{
int err_code;
@@ -863,11 +856,10 @@ int Drop_instance::send_ok_response(st_net *net, ulong connection_id)
Implementation for Show_instance_log.
**************************************************************************/
-Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg,
+Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg,
Log_type log_type_arg,
uint size_arg, uint offset_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg),
+ :Abstract_instance_cmd(instance_name_arg),
log_type(log_type_arg),
size(size_arg),
offset(offset_arg)
@@ -908,7 +900,8 @@ int Show_instance_log::execute_impl(st_net *net, Instance *instance)
}
-int Show_instance_log::send_ok_response(st_net *net, ulong connection_id)
+int Show_instance_log::send_ok_response(st_net *net,
+ ulong /* connection_id */)
{
if (send_eof(net) || net_flush(net))
return ER_OUT_OF_RESOURCES;
@@ -1013,9 +1006,8 @@ int Show_instance_log::write_data(st_net *net, Instance *instance)
**************************************************************************/
Show_instance_log_files::Show_instance_log_files
- (Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg)
- :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+ (const LEX_STRING *instance_name_arg)
+ :Abstract_instance_cmd(instance_name_arg)
{
}
@@ -1040,7 +1032,8 @@ int Show_instance_log_files::execute_impl(st_net *net, Instance *instance)
}
-int Show_instance_log_files::send_ok_response(st_net *net, ulong connection_id)
+int Show_instance_log_files::send_ok_response(st_net *net,
+ ulong /* connection_id */)
{
if (send_eof(net) || net_flush(net))
return ER_OUT_OF_RESOURCES;
@@ -1214,9 +1207,8 @@ C_MODE_END
/**************************************************************************/
-Abstract_option_cmd::Abstract_option_cmd(Instance_map *instance_map_arg)
- :Command(instance_map_arg),
- initialized(FALSE)
+Abstract_option_cmd::Abstract_option_cmd()
+ :initialized(FALSE)
{
}
@@ -1263,7 +1255,7 @@ bool Abstract_option_cmd::init(const char **text)
Correct the option file. The "skip" option is used to remove the found
option.
- SYNOPSYS
+ SYNOPSIS
Abstract_option_cmd::correct_file()
skip Skip the option, being searched while writing the result file.
That is, to delete it.
@@ -1400,16 +1392,10 @@ int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id)
Implementation of Set_option.
**************************************************************************/
-Set_option::Set_option(Instance_map *instance_map_arg)
- :Abstract_option_cmd(instance_map_arg)
-{
-}
-
-
/*
This operation parses SET options.
- SYNOPSYS
+ SYNOPSIS
text [IN/OUT] a pointer to the text containing options.
RETURN
@@ -1553,7 +1539,7 @@ int Set_option::process_option(Instance *instance, Named_value *option)
if (instance->is_mysqld_compatible() &&
Instance_options::is_option_im_specific(option->get_name()))
{
- log_error("Error: IM-option (%s) can not be used "
+ log_error("IM-option (%s) can not be used "
"in the configuration of mysqld-compatible instance (%s).",
(const char *) option->get_name(),
(const char *) instance->get_name()->str);
@@ -1580,16 +1566,10 @@ int Set_option::process_option(Instance *instance, Named_value *option)
Implementation of Unset_option.
**************************************************************************/
-Unset_option::Unset_option(Instance_map *instance_map_arg)
- :Abstract_option_cmd(instance_map_arg)
-{
-}
-
-
/*
This operation parses UNSET options.
- SYNOPSYS
+ SYNOPSIS
text [IN/OUT] a pointer to the text containing options.
RETURN
@@ -1712,7 +1692,7 @@ int Unset_option::process_option(Instance *instance, Named_value *option)
Implementation of Syntax_error.
**************************************************************************/
-int Syntax_error::execute(st_net *net, ulong connection_id)
+int Syntax_error::execute(st_net * /* net */, ulong /* connection_id */)
{
return ER_SYNTAX_ERROR;
}
diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h
index 9a9911f2358..8768aaab121 100644
--- a/server-tools/instance-manager/commands.h
+++ b/server-tools/instance-manager/commands.h
@@ -32,15 +32,16 @@
/*
Print all instances of this instance manager.
- Grammar: SHOW ISTANCES
+ Grammar: SHOW INSTANCES
*/
-class Show_instances : public Command
+class Show_instances: public Command
{
public:
- Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
- {}
+ Show_instances()
+ { }
+public:
int execute(st_net *net, ulong connection_id);
private:
@@ -54,12 +55,13 @@ private:
Grammar: FLUSH INSTANCES
*/
-class Flush_instances : public Command
+class Flush_instances: public Command
{
public:
- Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
- {}
+ Flush_instances()
+ { }
+public:
int execute(st_net *net, ulong connection_id);
};
@@ -68,11 +70,10 @@ public:
Abstract class for Instance-specific commands.
*/
-class Abstract_instance_cmd : public Command
+class Abstract_instance_cmd: public Command
{
public:
- Abstract_instance_cmd(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Abstract_instance_cmd(const LEX_STRING *instance_name_arg);
public:
virtual int execute(st_net *net, ulong connection_id);
@@ -102,14 +103,13 @@ private:
/*
Print status of an instance.
- Grammar: SHOW ISTANCE STATUS <instance_name>
+ Grammar: SHOW INSTANCE STATUS <instance_name>
*/
-class Show_instance_status : public Abstract_instance_cmd
+class Show_instance_status: public Abstract_instance_cmd
{
public:
- Show_instance_status(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Show_instance_status(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -126,11 +126,10 @@ private:
Grammar: SHOW INSTANCE OPTIONS <instance_name>
*/
-class Show_instance_options : public Abstract_instance_cmd
+class Show_instance_options: public Abstract_instance_cmd
{
public:
- Show_instance_options(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Show_instance_options(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -147,11 +146,10 @@ private:
Grammar: START INSTANCE <instance_name>
*/
-class Start_instance : public Abstract_instance_cmd
+class Start_instance: public Abstract_instance_cmd
{
public:
- Start_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Start_instance(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -164,11 +162,10 @@ protected:
Grammar: STOP INSTANCE <instance_name>
*/
-class Stop_instance : public Abstract_instance_cmd
+class Stop_instance: public Abstract_instance_cmd
{
public:
- Stop_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Stop_instance(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -181,11 +178,10 @@ protected:
Grammar: CREATE INSTANCE <instance_name> [<options>]
*/
-class Create_instance : public Command
+class Create_instance: public Command
{
public:
- Create_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Create_instance(const LEX_STRING *instance_name_arg);
public:
bool init(const char **text);
@@ -217,11 +213,10 @@ private:
is removed from the instance map.
*/
-class Drop_instance : public Abstract_instance_cmd
+class Drop_instance: public Abstract_instance_cmd
{
public:
- Drop_instance(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Drop_instance(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -235,11 +230,10 @@ protected:
SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[, offset_from_end]
*/
-class Show_instance_log : public Abstract_instance_cmd
+class Show_instance_log: public Abstract_instance_cmd
{
public:
- Show_instance_log(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg,
+ Show_instance_log(const LEX_STRING *instance_name_arg,
Log_type log_type_arg, uint size_arg, uint offset_arg);
protected:
@@ -263,11 +257,10 @@ private:
Grammar: SHOW <instance_name> LOG FILES
*/
-class Show_instance_log_files : public Abstract_instance_cmd
+class Show_instance_log_files: public Abstract_instance_cmd
{
public:
- Show_instance_log_files(Instance_map *instance_map_arg,
- const LEX_STRING *instance_name_arg);
+ Show_instance_log_files(const LEX_STRING *instance_name_arg);
protected:
virtual int execute_impl(st_net *net, Instance *instance);
@@ -285,7 +278,7 @@ private:
class Instance_options_list;
-class Abstract_option_cmd : public Command
+class Abstract_option_cmd: public Command
{
public:
~Abstract_option_cmd();
@@ -299,7 +292,7 @@ public:
virtual int execute(st_net *net, ulong connection_id);
protected:
- Abstract_option_cmd(Instance_map *instance_map_arg);
+ Abstract_option_cmd();
int correct_file(Instance *instance, Named_value *option, bool skip);
@@ -324,10 +317,11 @@ private:
Grammar: SET instance_name.option[=option_value][, ...]
*/
-class Set_option : public Abstract_option_cmd
+class Set_option: public Abstract_option_cmd
{
public:
- Set_option(Instance_map *instance_map_arg);
+ Set_option()
+ { }
protected:
virtual bool parse_args(const char **text);
@@ -343,7 +337,8 @@ protected:
class Unset_option: public Abstract_option_cmd
{
public:
- Unset_option(Instance_map *instance_map_arg);
+ Unset_option()
+ { }
protected:
virtual bool parse_args(const char **text);
@@ -360,12 +355,11 @@ protected:
just returns NULL.
*/
-class Syntax_error : public Command
+class Syntax_error: public Command
{
public:
- /* This is just to avoid compiler warning. */
- Syntax_error() :Command(NULL)
- {}
+ Syntax_error()
+ { }
public:
int execute(st_net *net, ulong connection_id);
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
index 03bfadd8571..e601ce0111c 100644
--- a/server-tools/instance-manager/guardian.cc
+++ b/server-tools/instance-manager/guardian.cc
@@ -20,7 +20,6 @@
#endif
#include "guardian.h"
-
#include <string.h>
#include <sys/types.h>
#include <signal.h>
@@ -30,17 +29,8 @@
#include "log.h"
#include "mysql_manager_error.h"
-
-pthread_handler_t guardian(void *arg)
-{
- Guardian_thread *guardian_thread= (Guardian_thread *) arg;
- guardian_thread->run();
- return 0;
-}
-
-
const char *
-Guardian_thread::get_instance_state_name(enum_instance_state state)
+Guardian::get_instance_state_name(enum_instance_state state)
{
switch (state) {
case NOT_STARTED:
@@ -68,23 +58,24 @@ Guardian_thread::get_instance_state_name(enum_instance_state state)
return NULL; /* just to ignore compiler warning. */
}
+/* {{{ Constructor & destructor. */
-Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
- Instance_map *instance_map_arg,
- uint monitoring_interval_arg) :
- Guardian_thread_args(thread_registry_arg, instance_map_arg,
- monitoring_interval_arg),
- thread_info(pthread_self(), TRUE), guarded_instances(0)
+Guardian::Guardian(Thread_registry *thread_registry_arg,
+ Instance_map *instance_map_arg,
+ uint monitoring_interval_arg)
+ :stopped(FALSE),
+ monitoring_interval(monitoring_interval_arg),
+ thread_registry(thread_registry_arg),
+ instance_map(instance_map_arg),
+ shutdown_requested(FALSE)
{
pthread_mutex_init(&LOCK_guardian, 0);
pthread_cond_init(&COND_guardian, 0);
- shutdown_requested= FALSE;
- stopped= FALSE;
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
}
-Guardian_thread::~Guardian_thread()
+Guardian::~Guardian()
{
/* delay guardian destruction to the moment when no one needs it */
pthread_mutex_lock(&LOCK_guardian);
@@ -94,21 +85,23 @@ Guardian_thread::~Guardian_thread()
pthread_cond_destroy(&COND_guardian);
}
+/* }}} */
-void Guardian_thread::request_shutdown()
+
+void Guardian::request_shutdown()
{
pthread_mutex_lock(&LOCK_guardian);
- /* stop instances or just clean up Guardian repository */
+ /* STOP Instances or just clean up Guardian repository */
stop_instances();
shutdown_requested= TRUE;
pthread_mutex_unlock(&LOCK_guardian);
}
-void Guardian_thread::process_instance(Instance *instance,
- GUARD_NODE *current_node,
- LIST **guarded_instances,
- LIST *node)
+void Guardian::process_instance(Instance *instance,
+ GUARD_NODE *current_node,
+ LIST **guarded_instances,
+ LIST *node)
{
uint waitchild= (uint) Instance::DEFAULT_SHUTDOWN_DELAY;
/* The amount of times, Guardian attempts to restart an instance */
@@ -117,23 +110,14 @@ void Guardian_thread::process_instance(Instance *instance,
if (current_node->state == STOPPING)
{
- /* this brach is executed during shutdown */
- if (instance->options.shutdown_delay)
- {
- /*
- NOTE: it is important to check shutdown_delay here, but use
- shutdown_delay_val. The idea is that if the option is unset,
- shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
- */
- waitchild= instance->options.shutdown_delay_val;
- }
+ waitchild= instance->options.get_shutdown_delay();
/* this returns TRUE if and only if an instance was stopped for sure */
if (instance->is_crashed())
*guarded_instances= list_delete(*guarded_instances, node);
else if ( (uint) (current_time - current_node->last_checked) > waitchild)
{
- instance->kill_instance(SIGKILL);
+ instance->kill_mysqld(SIGKILL);
/*
Later we do node= node->next. This is ok, as we are only removing
the node from the list. The pointer to the next one is still valid.
@@ -144,20 +128,20 @@ void Guardian_thread::process_instance(Instance *instance,
return;
}
- if (instance->is_running())
+ if (instance->is_mysqld_running())
{
/* The instance can be contacted on it's port */
/* If STARTING also check that pidfile has been created */
if (current_node->state == STARTING &&
- current_node->instance->options.get_pid() == 0)
+ current_node->instance->options.load_pid() == 0)
{
/* Pid file not created yet, don't go to STARTED state yet */
}
else if (current_node->state != STARTED)
{
/* clear status fields */
- log_info("guardian: instance '%s' is running, set state to STARTED.",
+ log_info("Guardian: '%s' is running, set state to STARTED.",
(const char *) instance->options.instance_name.str);
current_node->restart_counter= 0;
current_node->crash_moment= 0;
@@ -168,7 +152,7 @@ void Guardian_thread::process_instance(Instance *instance,
{
switch (current_node->state) {
case NOT_STARTED:
- log_info("guardian: starting instance '%s'...",
+ log_info("Guardian: starting '%s'...",
(const char *) instance->options.instance_name.str);
/* NOTE, set state to STARTING _before_ start() is called */
@@ -193,7 +177,7 @@ void Guardian_thread::process_instance(Instance *instance,
if (instance->is_crashed())
{
instance->start();
- log_info("guardian: starting instance '%s'...",
+ log_info("Guardian: starting '%s'...",
(const char *) instance->options.instance_name.str);
}
}
@@ -211,14 +195,15 @@ void Guardian_thread::process_instance(Instance *instance,
instance->start();
current_node->last_checked= current_time;
current_node->restart_counter++;
- log_info("guardian: restarting instance '%s'...",
+ log_info("Guardian: restarting '%s'...",
(const char *) instance->options.instance_name.str);
}
}
else
{
- log_info("guardian: cannot start instance %s. Abandoning attempts "
- "to (re)start it", instance->options.instance_name.str);
+ log_info("Guardian: can not start '%s'. "
+ "Abandoning attempts to (re)start it",
+ (const char *) instance->options.instance_name.str);
current_node->state= CRASHED_AND_ABANDONED;
}
}
@@ -233,18 +218,17 @@ void Guardian_thread::process_instance(Instance *instance,
/*
- Run guardian thread
+ Main function of Guardian thread.
- SYNOPSYS
+ SYNOPSIS
run()
DESCRIPTION
-
Check for all guarded instances and restart them if needed. If everything
is fine go and sleep for some time.
*/
-void Guardian_thread::run()
+void Guardian::run()
{
Instance *instance;
LIST *node;
@@ -252,9 +236,8 @@ void Guardian_thread::run()
log_info("Guardian: started.");
- thread_registry.register_thread(&thread_info);
+ thread_registry->register_thread(&thread_info);
- my_thread_init();
pthread_mutex_lock(&LOCK_guardian);
/* loop, until all instances were shut down at the end */
@@ -275,8 +258,8 @@ void Guardian_thread::run()
/* check the loop predicate before sleeping */
if (!(shutdown_requested && (!(guarded_instances))))
- thread_registry.cond_timedwait(&thread_info, &COND_guardian,
- &LOCK_guardian, &timeout);
+ thread_registry->cond_timedwait(&thread_info, &COND_guardian,
+ &LOCK_guardian, &timeout);
}
log_info("Guardian: stopped.");
@@ -284,15 +267,14 @@ void Guardian_thread::run()
stopped= TRUE;
pthread_mutex_unlock(&LOCK_guardian);
/* now, when the Guardian is stopped we can stop the IM */
- thread_registry.unregister_thread(&thread_info);
- thread_registry.request_shutdown();
- my_thread_end();
+ thread_registry->unregister_thread(&thread_info);
+ thread_registry->request_shutdown();
log_info("Guardian: finished.");
}
-int Guardian_thread::is_stopped()
+int Guardian::is_stopped()
{
int var;
pthread_mutex_lock(&LOCK_guardian);
@@ -306,19 +288,19 @@ int Guardian_thread::is_stopped()
Initialize the list of guarded instances: loop through the Instance_map and
add all of the instances, which don't have 'nonguarded' option specified.
- SYNOPSYS
- Guardian_thread::init()
+ SYNOPSIS
+ Guardian::init()
NOTE: The operation should be invoked with the following locks acquired:
- - Guardian_thread;
+ - Guardian;
- Instance_map;
RETURN
0 - ok
- 1 - error occured
+ 1 - error occurred
*/
-int Guardian_thread::init()
+int Guardian::init()
{
Instance *instance;
Instance_map::Iterator iterator(instance_map);
@@ -344,7 +326,7 @@ int Guardian_thread::init()
/*
Add instance to the Guardian list
- SYNOPSYS
+ SYNOPSIS
guard()
instance the instance to be guarded
nolock whether we prefer do not lock Guardian here,
@@ -357,10 +339,10 @@ int Guardian_thread::init()
RETURN
0 - ok
- 1 - error occured
+ 1 - error occurred
*/
-int Guardian_thread::guard(Instance *instance, bool nolock)
+int Guardian::guard(Instance *instance, bool nolock)
{
LIST *node;
GUARD_NODE *content;
@@ -397,7 +379,7 @@ int Guardian_thread::guard(Instance *instance, bool nolock)
a piece of the MEM_ROOT).
*/
-int Guardian_thread::stop_guard(Instance *instance)
+int Guardian::stop_guard(Instance *instance)
{
LIST *node;
@@ -418,7 +400,7 @@ int Guardian_thread::stop_guard(Instance *instance)
An internal method which is called at shutdown to unregister instances and
attempt to stop them if requested.
- SYNOPSYS
+ SYNOPSIS
stop_instances()
DESCRIPTION
@@ -431,10 +413,10 @@ int Guardian_thread::stop_guard(Instance *instance)
RETURN
0 - ok
- 1 - error occured
+ 1 - error occurred
*/
-int Guardian_thread::stop_instances()
+int Guardian::stop_instances()
{
LIST *node;
node= guarded_instances;
@@ -445,7 +427,7 @@ int Guardian_thread::stop_instances()
If instance is running or was running (and now probably hanging),
request stop.
*/
- if (current_node->instance->is_running() ||
+ if (current_node->instance->is_mysqld_running() ||
(current_node->state == STARTED))
{
current_node->state= STOPPING;
@@ -455,26 +437,26 @@ int Guardian_thread::stop_instances()
/* otherwise remove it from the list */
guarded_instances= list_delete(guarded_instances, node);
/* But try to kill it anyway. Just in case */
- current_node->instance->kill_instance(SIGTERM);
+ current_node->instance->kill_mysqld(SIGTERM);
node= node->next;
}
return 0;
}
-void Guardian_thread::lock()
+void Guardian::lock()
{
pthread_mutex_lock(&LOCK_guardian);
}
-void Guardian_thread::unlock()
+void Guardian::unlock()
{
pthread_mutex_unlock(&LOCK_guardian);
}
-LIST *Guardian_thread::find_instance_node(Instance *instance)
+LIST *Guardian::find_instance_node(Instance *instance)
{
LIST *node= guarded_instances;
@@ -494,7 +476,7 @@ LIST *Guardian_thread::find_instance_node(Instance *instance)
}
-bool Guardian_thread::is_active(Instance *instance)
+bool Guardian::is_active(Instance *instance)
{
bool guarded;
@@ -508,5 +490,5 @@ bool Guardian_thread::is_active(Instance *instance)
if (guarded)
return true;
- return instance->is_running();
+ return instance->is_mysqld_running();
}
diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h
index 27ca155fd67..0eee1dc631d 100644
--- a/server-tools/instance-manager/guardian.h
+++ b/server-tools/instance-manager/guardian.h
@@ -16,11 +16,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <my_global.h>
-#include <my_sys.h>
-#include <my_list.h>
#include "thread_registry.h"
+#include <my_sys.h>
+#include <my_list.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
@@ -31,30 +30,12 @@ class Instance_map;
class Thread_registry;
struct GUARD_NODE;
-pthread_handler_t guardian(void *arg);
-
-struct Guardian_thread_args
-{
- Thread_registry &thread_registry;
- Instance_map *instance_map;
- int monitoring_interval;
-
- Guardian_thread_args(Thread_registry &thread_registry_arg,
- Instance_map *instance_map_arg,
- uint monitoring_interval_arg) :
- thread_registry(thread_registry_arg),
- instance_map(instance_map_arg),
- monitoring_interval(monitoring_interval_arg)
- {}
-};
-
-
-/*
+/**
The guardian thread is responsible for monitoring and restarting of guarded
instances.
*/
-class Guardian_thread: public Guardian_thread_args
+class Guardian: public Thread
{
public:
/* states of an instance */
@@ -82,12 +63,10 @@ public:
/* Return client state name. */
static const char *get_instance_state_name(enum_instance_state state);
- Guardian_thread(Thread_registry &thread_registry_arg,
- Instance_map *instance_map_arg,
- uint monitoring_interval_arg);
- ~Guardian_thread();
- /* Main funtion of the thread */
- void run();
+ Guardian(Thread_registry *thread_registry_arg,
+ Instance_map *instance_map_arg,
+ uint monitoring_interval_arg);
+ virtual ~Guardian();
/* Initialize or refresh the list of guarded instances */
int init();
/* Request guardian shutdown. Stop instances if needed */
@@ -117,6 +96,9 @@ public:
a valid list node.
*/
inline enum_instance_state get_instance_state(LIST *instance_node);
+protected:
+ /* Main funtion of the thread */
+ virtual void run();
public:
pthread_cond_t COND_guardian;
@@ -133,6 +115,9 @@ private:
private:
pthread_mutex_t LOCK_guardian;
Thread_info thread_info;
+ int monitoring_interval;
+ Thread_registry *thread_registry;
+ Instance_map *instance_map;
LIST *guarded_instances;
MEM_ROOT alloc;
/* this variable is set to TRUE when we want to stop Guardian thread */
@@ -140,8 +125,8 @@ private:
};
-inline Guardian_thread::enum_instance_state
-Guardian_thread::get_instance_state(LIST *instance_node)
+inline Guardian::enum_instance_state
+Guardian::get_instance_state(LIST *instance_node)
{
return ((GUARD_NODE *) instance_node->data)->state;
}
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 3927363a3e5..6b4289c5b29 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -20,7 +20,6 @@
#include "instance.h"
-#include <my_global.h>
#include <mysql.h>
#include <signal.h>
@@ -29,24 +28,15 @@
#endif
#include "guardian.h"
-#include "instance_map.h"
+#include "manager.h"
#include "log.h"
#include "mysql_manager_error.h"
#include "portability.h"
#include "priv.h"
#include "thread_registry.h"
+#include "instance_map.h"
-
-const LEX_STRING
-Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") };
-
-static const char * const INSTANCE_NAME_PREFIX= Instance::DFLT_INSTANCE_NAME.str;
-static const int INSTANCE_NAME_PREFIX_LEN= Instance::DFLT_INSTANCE_NAME.length;
-
-
-static void start_and_monitor_instance(Instance_options *old_instance_options,
- Instance_map *instance_map,
- Thread_registry *thread_registry);
+/* {{{ Platform-specific functions. */
#ifndef __WIN__
typedef pid_t My_process_info;
@@ -61,19 +51,31 @@ typedef PROCESS_INFORMATION My_process_info;
to do it in a portable way.
*/
-pthread_handler_t proxy(void *arg)
+class Instance_monitor: public Thread
+{
+public:
+ Instance_monitor(Instance *instance_arg) :instance(instance_arg) {}
+protected:
+ virtual void run();
+ void start_and_monitor_instance(Instance_options *old_instance_options,
+ Instance_map *instance_map,
+ Thread_registry *thread_registry);
+private:
+ Instance *instance;
+};
+
+void Instance_monitor::run()
{
- Instance *instance= (Instance *) arg;
start_and_monitor_instance(&instance->options,
- instance->get_map(),
- &instance->thread_registry);
- return 0;
+ Manager::get_instance_map(),
+ Manager::get_thread_registry());
+ delete this;
}
/*
Wait for an instance
- SYNOPSYS
+ SYNOPSIS
wait_process()
pi Pointer to the process information structure
(platform-dependent).
@@ -103,7 +105,7 @@ static int wait_process(My_process_info *pi)
couldn't use wait(), because it could return in any wait() in the program.
*/
- if (linuxthreads)
+ if (Manager::is_linux_threads())
wait(NULL); /* LinuxThreads were detected */
else
waitpid(*pi, NULL, 0);
@@ -131,11 +133,10 @@ static int wait_process(My_process_info *pi)
}
#endif
-
/*
Launch an instance
- SYNOPSYS
+ SYNOPSIS
start_process()
instance_options Pointer to the options of the instance to be
launched.
@@ -143,13 +144,13 @@ static int wait_process(My_process_info *pi)
(platform-dependent).
RETURN
- 0 - Success
- 1 - Cannot create an instance
+ FALSE - Success
+ TRUE - Cannot create an instance
*/
#ifndef __WIN__
-static int start_process(Instance_options *instance_options,
- My_process_info *pi)
+static bool start_process(Instance_options *instance_options,
+ My_process_info *pi)
{
#ifndef __QNX__
*pi= fork();
@@ -169,15 +170,16 @@ static int start_process(Instance_options *instance_options,
/* exec never returns */
exit(1);
case -1:
- log_info("cannot create a new process to start instance '%s'.",
- (const char *) instance_options->instance_name.str);
- return 1;
+ log_error("Instance '%s': can not start mysqld: fork() failed.",
+ (const char *) instance_options->instance_name.str);
+ return TRUE;
}
- return 0;
+
+ return FALSE;
}
#else
-static int start_process(Instance_options *instance_options,
- My_process_info *pi)
+static bool start_process(Instance_options *instance_options,
+ My_process_info *pi)
{
STARTUPINFO si;
@@ -192,7 +194,7 @@ static int start_process(Instance_options *instance_options,
char *cmdline= new char[cmdlen];
if (cmdline == NULL)
- return 1;
+ return TRUE;
cmdline[0]= 0;
for (int i= 0; instance_options->argv[i] != 0; i++)
@@ -216,14 +218,87 @@ static int start_process(Instance_options *instance_options,
pi); /* Pointer to PROCESS_INFORMATION structure */
delete cmdline;
- return (!result);
+ return !result;
}
#endif
+#ifdef __WIN__
+
+BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
+{
+ DWORD dwTID, dwCode, dwErr= 0;
+ HANDLE hProcessDup= INVALID_HANDLE_VALUE;
+ HANDLE hRT= NULL;
+ HINSTANCE hKernel= GetModuleHandle("Kernel32");
+ BOOL bSuccess= FALSE;
+
+ BOOL bDup= DuplicateHandle(GetCurrentProcess(),
+ hProcess, GetCurrentProcess(), &hProcessDup,
+ PROCESS_ALL_ACCESS, FALSE, 0);
+
+ // Detect the special case where the process is
+ // already dead...
+ if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
+ (dwCode == STILL_ACTIVE))
+ {
+ FARPROC pfnExitProc;
+
+ pfnExitProc= GetProcAddress(hKernel, "ExitProcess");
+
+ hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0,
+ (LPTHREAD_START_ROUTINE)pfnExitProc,
+ (PVOID)uExitCode, 0, &dwTID);
+
+ if (hRT == NULL)
+ dwErr= GetLastError();
+ }
+ else
+ dwErr= ERROR_PROCESS_ABORTED;
+
+ if (hRT)
+ {
+ // Must wait process to terminate to
+ // guarantee that it has exited...
+ WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
+
+ CloseHandle(hRT);
+ bSuccess= TRUE;
+ }
+
+ if (bDup)
+ CloseHandle(hProcessDup);
+
+ if (!bSuccess)
+ SetLastError(dwErr);
+
+ return bSuccess;
+}
+
+int kill(pid_t pid, int signum)
+{
+ HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+ if (signum == SIGTERM)
+ ::SafeTerminateProcess(processhandle, 0);
+ else
+ ::TerminateProcess(processhandle, -1);
+ return 0;
+}
+#endif
+
+/* }}} */
+
+/* {{{ Static constants. */
+
+const LEX_STRING
+Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") };
+
+/* }}} */
+
+
/*
Fork child, exec an instance and monitor it.
- SYNOPSYS
+ SYNOPSIS
start_and_monitor_instance()
old_instance_options Pointer to the options of the instance to be
launched. This info is likely to become obsolete
@@ -238,32 +313,39 @@ static int start_process(Instance_options *instance_options,
set appropriate flags and wake all threads waiting for instance
to stop.
+ NOTE
+ A separate thread for starting/monitoring instance is a simple way
+ to avoid all pitfalls of the threads implementation in the OS (e.g.
+ LinuxThreads). For one, with such a thread we don't have to process
+ SIGCHLD, which is a tricky business if we want to do it in a
+ portable way.
+
RETURN
Function returns no value
*/
-static void start_and_monitor_instance(Instance_options *old_instance_options,
- Instance_map *instance_map,
- Thread_registry *thread_registry)
+void
+Instance_monitor::
+start_and_monitor_instance(Instance_options *old_instance_options,
+ Instance_map *instance_map,
+ Thread_registry *thread_registry)
{
Instance_name instance_name(&old_instance_options->instance_name);
Instance *current_instance;
My_process_info process_info;
- Thread_info thread_info(pthread_self(), FALSE);
+ Thread_info thread_info;
- log_info("Monitoring thread (instance: '%s'): started.",
- (const char *) instance_name.get_c_str());
+ log_info("Instance '%s': Monitor: started.",
+ (const char *) instance->get_name()->str);
if (!old_instance_options->nonguarded)
{
/*
Register thread in Thread_registry to wait for it to stop on shutdown
- only if instance is nuarded. If instance is guarded, the thread will not
+ only if instance is guarded. If instance is guarded, the thread will not
finish, because nonguarded instances are not stopped on shutdown.
*/
-
- thread_registry->register_thread(&thread_info);
- my_thread_init();
+ thread_registry->register_thread(&thread_info, FALSE);
}
/*
@@ -277,8 +359,8 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
are using is destroyed. (E.g. by "FLUSH INSTANCES")
*/
- log_info("starting instance %s...",
- (const char *) instance_name.get_c_str());
+ log_info("Instance '%s': Monitor: starting mysqld...",
+ (const char *) instance->get_name()->str);
if (start_process(old_instance_options, &process_info))
{
@@ -289,8 +371,10 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
/* allow users to delete instances */
instance_map->unlock();
- /* don't check for return value */
- wait_process(&process_info);
+ log_info("Instance '%s': Monitor: waiting for mysqld to stop...",
+ (const char *) instance->get_name()->str);
+
+ wait_process(&process_info); /* Don't check for return value. */
instance_map->lock();
@@ -302,21 +386,19 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
instance_map->unlock();
if (!old_instance_options->nonguarded)
- {
thread_registry->unregister_thread(&thread_info);
- my_thread_end();
- }
- log_info("Monitoring thread (instance: '%s'): finished.",
- (const char *) instance_name.get_c_str());
+ log_info("Instance '%s': Monitor: finished.",
+ (const char *) instance->get_name()->str);
}
bool Instance::is_name_valid(const LEX_STRING *name)
{
- const char *name_suffix= name->str + INSTANCE_NAME_PREFIX_LEN;
+ const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length;
- if (strncmp(name->str, INSTANCE_NAME_PREFIX, INSTANCE_NAME_PREFIX_LEN) != 0)
+ if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str,
+ Instance::DFLT_INSTANCE_NAME.length) != 0)
return FALSE;
return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
@@ -325,31 +407,139 @@ bool Instance::is_name_valid(const LEX_STRING *name)
bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
{
- return strcmp(name->str, INSTANCE_NAME_PREFIX) == 0;
+ return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0;
}
-Instance_map *Instance::get_map()
+
+/* {{{ Constructor & destructor */
+
+Instance::Instance()
+ :crashed(FALSE),
+ configured(FALSE)
{
- return instance_map;
+ pthread_mutex_init(&LOCK_instance, 0);
+ pthread_cond_init(&COND_instance_stopped, 0);
}
-void Instance::remove_pid()
+Instance::~Instance()
+{
+ log_info("Instance '%s': destroying...", (const char *) get_name()->str);
+
+ pthread_cond_destroy(&COND_instance_stopped);
+ pthread_mutex_destroy(&LOCK_instance);
+}
+
+/* }}} */
+
+/*
+ Initialize instance options.
+
+ SYNOPSIS
+ init()
+ name_arg name of the instance
+
+ RETURN:
+ FALSE - ok
+ TRUE - error
+*/
+
+bool Instance::init(const LEX_STRING *name_arg)
{
- int pid;
- if ((pid= options.get_pid()) != 0) /* check the pidfile */
- if (options.unlink_pidfile()) /* remove stalled pidfile */
- log_error("cannot remove pidfile for instance '%s', this might be "
- "since IM lacks permmissions or hasn't found the pidifle",
- (const char *) options.instance_name.str);
+ mysqld_compatible= is_mysqld_compatible_name(name_arg);
+
+ return options.init(name_arg);
}
/*
+ Complete instance options initialization.
+
+ SYNOPSIS
+ complete_initialization()
+
+ RETURN
+ FALSE - ok
+ TRUE - error
+*/
+
+bool Instance::complete_initialization()
+{
+ configured= ! options.complete_initialization();
+ return FALSE;
+ /*
+ TODO: return actual status (from
+ Instance_options::complete_initialization()) here.
+ */
+}
+
+/*
+ Determine if mysqld is accepting connections.
+
+ SYNOPSIS
+ is_mysqld_running()
+
+ DESCRIPTION
+ Try to connect to mysqld with fake login/password to check whether it is
+ accepting connections or not.
+
+ MT-NOTE: this operation must be called under acquired LOCK_instance.
+
+ RETURN
+ TRUE - mysqld is alive and accept connections
+ FALSE - otherwise.
+*/
+
+bool Instance::is_mysqld_running()
+{
+ MYSQL mysql;
+ uint port= options.get_mysqld_port(); /* 0 if not specified. */
+ const char *socket= NULL;
+ static const char *password= "check_connection";
+ static const char *username= "MySQL_Instance_Manager";
+ static const char *access_denied_message= "Access denied for user";
+ bool return_val;
+
+ if (options.mysqld_socket)
+ socket= options.mysqld_socket;
+
+ /* no port was specified => instance falled back to default value */
+ if (!port && !options.mysqld_socket)
+ port= SERVER_DEFAULT_PORT;
+
+ pthread_mutex_lock(&LOCK_instance);
+
+ mysql_init(&mysql);
+ /* try to connect to a server with a fake username/password pair */
+ if (mysql_real_connect(&mysql, LOCAL_HOST, username,
+ password,
+ NullS, port,
+ socket, 0))
+ {
+ /*
+ We have successfully connected to the server using fake
+ username/password. Write a warning to the logfile.
+ */
+ log_error("Instance '%s': was able to log into mysqld.",
+ (const char *) get_name()->str);
+ pthread_mutex_unlock(&LOCK_instance);
+ return_val= TRUE; /* server is alive */
+ }
+ else
+ return_val= test(!strncmp(access_denied_message, mysql_error(&mysql),
+ sizeof(access_denied_message) - 1));
+
+ mysql_close(&mysql);
+ pthread_mutex_unlock(&LOCK_instance);
+
+ return return_val;
+}
+
+/*
The method starts an instance.
- SYNOPSYS
+ SYNOPSIS
start()
RETURN
@@ -367,24 +557,21 @@ int Instance::start()
pthread_mutex_unlock(&LOCK_instance);
- if (configured && !is_running())
+ if (configured && !is_mysqld_running())
{
+ Instance_monitor *instance_monitor;
remove_pid();
- pthread_t proxy_thd_id;
- pthread_attr_t proxy_thd_attr;
- int rc;
+ instance_monitor= new Instance_monitor(this);
- pthread_attr_init(&proxy_thd_attr);
- pthread_attr_setdetachstate(&proxy_thd_attr, PTHREAD_CREATE_DETACHED);
- rc= pthread_create(&proxy_thd_id, &proxy_thd_attr, proxy,
- this);
- pthread_attr_destroy(&proxy_thd_attr);
- if (rc)
+ if (instance_monitor == NULL || instance_monitor->start(Thread::DETACHED))
{
- log_error("Instance::start(): pthread_create(proxy) failed");
+ delete instance_monitor;
+ log_error("Instance::start(): failed to create the monitoring thread"
+ " to start an instance");
return ER_CANNOT_START_INSTANCE;
}
+ /* The monitoring thread will delete itself when it's finished. */
return 0;
}
@@ -397,7 +584,7 @@ int Instance::start()
The method sets the crash flag and wakes all waiters on
COND_instance_stopped and COND_guardian
- SYNOPSYS
+ SYNOPSIS
set_crash_flag_n_wake_all()
DESCRIPTION
@@ -423,97 +610,14 @@ void Instance::set_crash_flag_n_wake_all()
*/
pthread_cond_signal(&COND_instance_stopped);
/* wake guardian */
- pthread_cond_signal(&instance_map->guardian->COND_guardian);
-}
-
-
-
-Instance::Instance(Thread_registry &thread_registry_arg):
- crashed(FALSE), configured(FALSE), thread_registry(thread_registry_arg)
-{
- pthread_mutex_init(&LOCK_instance, 0);
- pthread_cond_init(&COND_instance_stopped, 0);
-}
-
-
-Instance::~Instance()
-{
- pthread_cond_destroy(&COND_instance_stopped);
- pthread_mutex_destroy(&LOCK_instance);
-}
-
-
-bool Instance::is_crashed()
-{
- bool val;
- pthread_mutex_lock(&LOCK_instance);
- val= crashed;
- pthread_mutex_unlock(&LOCK_instance);
- return val;
-}
-
-
-bool Instance::is_running()
-{
- MYSQL mysql;
- uint port= 0;
- const char *socket= NULL;
- static const char *password= "check_connection";
- static const char *username= "MySQL_Instance_Manager";
- static const char *access_denied_message= "Access denied for user";
- bool return_val;
-
- if (options.mysqld_port)
- {
- /*
- NOTE: it is important to check mysqld_port here, but use
- mysqld_port_val. The idea is that if the option is unset, mysqld_port
- will be NULL, but mysqld_port_val will not be reset.
- */
- port= options.mysqld_port_val;
- }
-
- if (options.mysqld_socket)
- socket= options.mysqld_socket;
-
- /* no port was specified => instance falled back to default value */
- if (!options.mysqld_port && !options.mysqld_socket)
- port= SERVER_DEFAULT_PORT;
-
- pthread_mutex_lock(&LOCK_instance);
-
- mysql_init(&mysql);
- /* try to connect to a server with a fake username/password pair */
- if (mysql_real_connect(&mysql, LOCAL_HOST, username,
- password,
- NullS, port,
- socket, 0))
- {
- /*
- We have successfully connected to the server using fake
- username/password. Write a warning to the logfile.
- */
- log_info("The Instance Manager was able to log into you server "
- "with faked compiled-in password while checking server status. "
- "Looks like something is wrong.");
- pthread_mutex_unlock(&LOCK_instance);
- return_val= TRUE; /* server is alive */
- }
- else
- return_val= test(!strncmp(access_denied_message, mysql_error(&mysql),
- sizeof(access_denied_message) - 1));
-
- mysql_close(&mysql);
- pthread_mutex_unlock(&LOCK_instance);
-
- return return_val;
+ pthread_cond_signal(&Manager::get_guardian()->COND_guardian);
}
/*
Stop an instance.
- SYNOPSYS
+ SYNOPSIS
stop()
RETURN:
@@ -527,19 +631,11 @@ int Instance::stop()
struct timespec timeout;
uint waitchild= (uint) DEFAULT_SHUTDOWN_DELAY;
- if (is_running())
+ if (is_mysqld_running())
{
- if (options.shutdown_delay)
- {
- /*
- NOTE: it is important to check shutdown_delay here, but use
- shutdown_delay_val. The idea is that if the option is unset,
- shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
- */
- waitchild= options.shutdown_delay_val;
- }
+ waitchild= options.get_shutdown_delay();
- kill_instance(SIGTERM);
+ kill_mysqld(SIGTERM);
/* sleep on condition to wait for SIGCHLD */
timeout.tv_sec= time(NULL) + waitchild;
@@ -547,7 +643,7 @@ int Instance::stop()
if (pthread_mutex_lock(&LOCK_instance))
return ER_STOP_INSTANCE;
- while (options.get_pid() != 0) /* while server isn't stopped */
+ while (options.load_pid() != 0) /* while server isn't stopped */
{
int status;
@@ -560,7 +656,7 @@ int Instance::stop()
pthread_mutex_unlock(&LOCK_instance);
- kill_instance(SIGKILL);
+ kill_mysqld(SIGKILL);
return 0;
}
@@ -568,120 +664,83 @@ int Instance::stop()
return ER_INSTANCE_IS_NOT_STARTED;
}
-#ifdef __WIN__
-BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
-{
- DWORD dwTID, dwCode, dwErr= 0;
- HANDLE hProcessDup= INVALID_HANDLE_VALUE;
- HANDLE hRT= NULL;
- HINSTANCE hKernel= GetModuleHandle("Kernel32");
- BOOL bSuccess= FALSE;
+/*
+ Send signal to mysqld.
- BOOL bDup= DuplicateHandle(GetCurrentProcess(),
- hProcess, GetCurrentProcess(), &hProcessDup,
- PROCESS_ALL_ACCESS, FALSE, 0);
+ SYNOPSIS
+ kill_mysqld()
+*/
- // Detect the special case where the process is
- // already dead...
- if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
- (dwCode == STILL_ACTIVE))
+void Instance::kill_mysqld(int signum)
+{
+ pid_t mysqld_pid= options.load_pid();
+
+ if (mysqld_pid == 0)
{
- FARPROC pfnExitProc;
+ log_info("Instance '%s': no pid file to send a signal (%d).",
+ (const char *) get_name()->str,
+ (int) signum);
+ return;
+ }
- pfnExitProc= GetProcAddress(hKernel, "ExitProcess");
+ log_info("Instance '%s': sending %d to %d...",
+ (const char *) get_name()->str,
+ (int) signum,
+ (int) mysqld_pid);
- hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0,
- (LPTHREAD_START_ROUTINE)pfnExitProc,
- (PVOID)uExitCode, 0, &dwTID);
-
- if (hRT == NULL)
- dwErr= GetLastError();
+ if (kill(mysqld_pid, signum))
+ {
+ log_info("Instance '%s': kill() failed.",
+ (const char *) get_name()->str);
+ return;
}
- else
- dwErr= ERROR_PROCESS_ABORTED;
- if (hRT)
+ /* Kill suceeded */
+ if (signum == SIGKILL) /* really killed instance with SIGKILL */
{
- // Must wait process to terminate to
- // guarantee that it has exited...
- WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
+ log_error("Instance '%s': killed.",
+ (const char *) options.instance_name.str);
- CloseHandle(hRT);
- bSuccess= TRUE;
+ /* After sucessful hard kill the pidfile need to be removed */
+ options.unlink_pidfile();
}
+}
- if (bDup)
- CloseHandle(hProcessDup);
-
- if (!bSuccess)
- SetLastError(dwErr);
+/*
+ Return crashed flag.
- return bSuccess;
-}
+ SYNOPSIS
+ is_crashed()
-int kill(pid_t pid, int signum)
-{
- HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (signum == SIGTERM)
- ::SafeTerminateProcess(processhandle, 0);
- else
- ::TerminateProcess(processhandle, -1);
- return 0;
-}
-#endif
+ RETURN
+ TRUE - mysqld crashed
+ FALSE - mysqld hasn't crashed yet
+*/
-void Instance::kill_instance(int signum)
+bool Instance::is_crashed()
{
- pid_t pid;
- /* if there are no pid, everything seems to be fine */
- if ((pid= options.get_pid()) != 0) /* get pid from pidfile */
- {
- if (kill(pid, signum) == 0)
- {
- /* Kill suceeded */
- if (signum == SIGKILL) /* really killed instance with SIGKILL */
- {
- log_error("The instance '%s' is being stopped forcibly. Normally"
- "it should not happen. Probably the instance has been"
- "hanging. You should also check your IM setup",
- (const char *) options.instance_name.str);
- /* After sucessful hard kill the pidfile need to be removed */
- options.unlink_pidfile();
- }
- }
- }
- return;
+ bool val;
+ pthread_mutex_lock(&LOCK_instance);
+ val= crashed;
+ pthread_mutex_unlock(&LOCK_instance);
+ return val;
}
/*
- Initialize instance parameters.
-
- SYNOPSYS
- Instance::init()
- name_arg name of the instance
-
- RETURN:
- 0 ok
- !0 error
+ Remove pid file.
*/
-int Instance::init(const LEX_STRING *name_arg)
+void Instance::remove_pid()
{
- mysqld_compatible= is_mysqld_compatible_name(name_arg);
-
- return options.init(name_arg);
-}
+ int mysqld_pid= options.load_pid();
+ if (mysqld_pid == 0)
+ return;
-int Instance::complete_initialization(Instance_map *instance_map_arg,
- const char *mysqld_path)
-{
- instance_map= instance_map_arg;
- configured= !options.complete_initialization(mysqld_path);
- return 0;
- /*
- TODO: return actual status (from
- Instance_options::complete_initialization()) here.
- */
+ if (options.unlink_pidfile())
+ {
+ log_error("Instance '%s': can not unlink pid file.",
+ (const char *) options.instance_name.str);
+ }
}
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index 329eaa68b1a..412d01acc46 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -88,21 +88,19 @@ public:
static bool is_mysqld_compatible_name(const LEX_STRING *name);
public:
- Instance(Thread_registry &thread_registry_arg);
+ Instance();
~Instance();
- int init(const LEX_STRING *name_arg);
- int complete_initialization(Instance_map *instance_map_arg,
- const char *mysqld_path);
+ bool init(const LEX_STRING *name_arg);
+ bool complete_initialization();
- bool is_running();
+ bool is_mysqld_running();
int start();
int stop();
/* send a signal to the instance */
- void kill_instance(int signo);
+ void kill_mysqld(int signo);
bool is_crashed();
void set_crash_flag_n_wake_all();
- Instance_map *get_map();
/*
The operation is intended to check if the instance is mysqld-compatible
@@ -121,7 +119,6 @@ public:
public:
enum { DEFAULT_SHUTDOWN_DELAY= 35 };
Instance_options options;
- Thread_registry &thread_registry;
private:
/* This attributes is a flag, specifies if the instance has been crashed. */
@@ -155,7 +152,6 @@ private:
stop in Instance::stop()
*/
pthread_cond_t COND_instance_stopped;
- Instance_map *instance_map;
void remove_pid();
};
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc
index 2f830e616c4..a356e308e44 100644
--- a/server-tools/instance-manager/instance_map.cc
+++ b/server-tools/instance-manager/instance_map.cc
@@ -63,7 +63,7 @@ static void delete_instance(void *u)
/*
The option handler to pass to the process_default_option_files finction.
- SYNOPSYS
+ SYNOPSIS
process_option()
ctx Handler context. Here it is an instance_map structure.
group_name The name of the group the option belongs to.
@@ -169,7 +169,7 @@ int Instance_map::process_one_option(const LEX_STRING *group,
if (!(instance= (Instance *) hash_search(&hash, (byte *) group->str,
group->length)))
{
- if (!(instance= new Instance(thread_registry)))
+ if (!(instance= new Instance()))
return 1;
if (instance->init(group) || add_instance(instance))
@@ -213,16 +213,13 @@ int Instance_map::process_one_option(const LEX_STRING *group,
}
-Instance_map::Instance_map(const char *default_mysqld_path_arg,
- Thread_registry &thread_registry_arg):
- mysqld_path(default_mysqld_path_arg),
- thread_registry(thread_registry_arg)
+Instance_map::Instance_map()
{
pthread_mutex_init(&LOCK_instance_map, 0);
}
-int Instance_map::init()
+bool Instance_map::init()
{
return hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_instance_key, delete_instance, 0);
@@ -276,7 +273,7 @@ void Instance_map::unlock()
FLUSH INSTANCES without prior stop of all running instances.
NOTE: The operation should be invoked with the following locks acquired:
- - Guardian_thread;
+ - Guardian;
- Instance_map;
*/
@@ -310,7 +307,7 @@ bool Instance_map::is_there_active_instance()
while ((instance= iterator.next()))
{
if (guardian->find_instance_node(instance) != NULL ||
- instance->is_running())
+ instance->is_mysqld_running())
{
return TRUE;
}
@@ -335,18 +332,18 @@ int Instance_map::remove_instance(Instance *instance)
int Instance_map::create_instance(const LEX_STRING *instance_name,
const Named_value_arr *options)
{
- Instance *instance= new Instance(thread_registry);
+ Instance *instance= new Instance();
if (!instance)
{
- log_error("Error: can not initialize (name: '%s').",
+ log_error("Can not allocate instance (name: '%s').",
(const char *) instance_name->str);
return ER_OUT_OF_RESOURCES;
}
if (instance->init(instance_name))
{
- log_error("Error: can not initialize (name: '%s').",
+ log_error("Can not initialize instance (name: '%s').",
(const char *) instance_name->str);
delete instance;
return ER_OUT_OF_RESOURCES;
@@ -359,7 +356,7 @@ int Instance_map::create_instance(const LEX_STRING *instance_name,
if (instance->is_mysqld_compatible() &&
Instance_options::is_option_im_specific(option.get_name()))
{
- log_error("Error: IM-option (%s) can not be used "
+ log_error("IM-option (%s) can not be used "
"in configuration of mysqld-compatible instance (%s).",
(const char *) option.get_name(),
(const char *) instance_name->str);
@@ -374,9 +371,9 @@ int Instance_map::create_instance(const LEX_STRING *instance_name,
log_info("Warning: instance name '%s' is mysqld-compatible.",
(const char *) instance_name->str);
- if (instance->complete_initialization(this, mysqld_path))
+ if (instance->complete_initialization())
{
- log_error("Error: can not complete initialization of instance (name: '%s').",
+ log_error("Can not complete initialization of instance (name: '%s').",
(const char *) instance_name->str);
delete instance;
return ER_OUT_OF_RESOURCES;
@@ -385,7 +382,7 @@ int Instance_map::create_instance(const LEX_STRING *instance_name,
if (add_instance(instance))
{
- log_error("Error: can not register instance (name: '%s').",
+ log_error("Can not register instance (name: '%s').",
(const char *) instance_name->str);
delete instance;
return ER_OUT_OF_RESOURCES;
@@ -411,7 +408,7 @@ bool Instance_map::complete_initialization()
{
Instance *instance= (Instance *) hash_element(&hash, i);
- if (instance->complete_initialization(this, mysqld_path))
+ if (instance->complete_initialization())
return TRUE;
}
@@ -429,7 +426,7 @@ bool Instance_map::complete_initialization()
if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL))
{
- log_error("Error: could not create default instance.");
+ log_error("Can not create default instance.");
return TRUE;
}
@@ -444,7 +441,7 @@ bool Instance_map::complete_initialization()
break;
default:
- log_error("Error: could not add default instance to the config file.");
+ log_error("Can not add default instance to the config file.");
Instance *instance= find(&Instance::DFLT_INSTANCE_NAME);
@@ -502,7 +499,7 @@ int Instance_map::load()
if (my_search_option_files(Options::Main::config_file, &argc,
(char ***) &argv, &args_used,
process_option, (void*) this))
- log_info("Falling back to compiled-in defaults");
+ log_info("Falling back to compiled-in defaults.");
return complete_initialization();
}
@@ -537,20 +534,20 @@ const char *Instance_map::get_instance_state_name(Instance *instance)
{
/* The instance is managed by Guardian: we can report precise state. */
- return Guardian_thread::get_instance_state_name(
+ return Guardian::get_instance_state_name(
guardian->get_instance_state(instance_node));
}
/* The instance is not managed by Guardian: we can report status only. */
- return instance->is_running() ? "online" : "offline";
+ return instance->is_mysqld_running() ? "online" : "offline";
}
/*
Create a new configuration section for mysqld-instance in the config file.
- SYNOPSYS
+ SYNOPSIS
create_instance_in_file()
instance_name mysqld-instance name
options options for the new mysqld-instance
@@ -569,7 +566,7 @@ int create_instance_in_file(const LEX_STRING *instance_name,
if (my_access(Options::Main::config_file, W_OK))
{
- log_error("Error: configuration file (%s) does not exist.",
+ log_error("Configuration file (%s) does not exist.",
(const char *) Options::Main::config_file);
return ER_CONF_FILE_DOES_NOT_EXIST;
}
@@ -578,7 +575,7 @@ int create_instance_in_file(const LEX_STRING *instance_name,
if (cnf_file <= 0)
{
- log_error("Error: can not open configuration file (%s): %s.",
+ log_error("Can not open configuration file (%s): %s.",
(const char *) Options::Main::config_file,
(const char *) strerror(errno));
return ER_ACCESS_OPTION_FILE;
@@ -591,7 +588,7 @@ int create_instance_in_file(const LEX_STRING *instance_name,
my_write(cnf_file, (byte*)"]", 1, MYF(MY_NABP)) ||
my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
{
- log_error("Error: can not write to configuration file (%s): %s.",
+ log_error("Can not write to configuration file (%s): %s.",
(const char *) Options::Main::config_file,
(const char *) strerror(errno));
my_close(cnf_file, MYF(0));
@@ -615,7 +612,7 @@ int create_instance_in_file(const LEX_STRING *instance_name,
if (my_write(cnf_file, (byte*)option_str, option_str_len, MYF(MY_NABP)) ||
my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
{
- log_error("Error: can not write to configuration file (%s): %s.",
+ log_error("Can not write to configuration file (%s): %s.",
(const char *) Options::Main::config_file,
(const char *) strerror(errno));
my_close(cnf_file, MYF(0));
diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h
index 9de40e35e0f..69d225c89f7 100644
--- a/server-tools/instance-manager/instance_map.h
+++ b/server-tools/instance-manager/instance_map.h
@@ -25,7 +25,7 @@
#pragma interface
#endif
-class Guardian_thread;
+class Guardian;
class Instance;
class Named_value_arr;
class Thread_registry;
@@ -75,7 +75,7 @@ public:
void lock();
void unlock();
- int init();
+ bool init();
/*
Process a given option and assign it to appropricate instance. This is
@@ -105,8 +105,7 @@ public:
int create_instance(const LEX_STRING *instance_name,
const Named_value_arr *options);
- Instance_map(const char *default_mysqld_path_arg,
- Thread_registry &thread_registry_arg);
+ Instance_map();
~Instance_map();
/*
@@ -115,13 +114,13 @@ public:
MT-NOTE: the options must be called under acquired locks of the following
objects:
- Instance_map;
- - Guardian_thread;
+ - Guardian;
*/
const char *get_instance_state_name(Instance *instance);
public:
const char *mysqld_path;
- Guardian_thread *guardian;
+ Guardian *guardian;
private:
/* loads options from config files */
@@ -132,8 +131,6 @@ private:
enum { START_HASH_SIZE = 16 };
pthread_mutex_t LOCK_instance_map;
HASH hash;
-
- Thread_registry &thread_registry;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
index 00da6660703..58e7b630fe9 100644
--- a/server-tools/instance-manager/instance_options.cc
+++ b/server-tools/instance-manager/instance_options.cc
@@ -29,13 +29,14 @@
#include "buffer.h"
#include "instance.h"
#include "log.h"
+#include "options.h"
#include "parse_output.h"
#include "priv.h"
/* Create "mysqld ..." command in the buffer */
-static inline int create_mysqld_command(Buffer *buf,
+static inline bool create_mysqld_command(Buffer *buf,
const LEX_STRING *mysqld_path,
const LEX_STRING *option)
{
@@ -54,12 +55,35 @@ static inline int create_mysqld_command(Buffer *buf,
/* here the '\0' character is copied from the option string */
buf->append(position, option->str, option->length + 1);
- return buf->is_error();
+ return buf->is_error() ? TRUE : FALSE;
}
- return 1;
+ return TRUE;
+}
+
+static inline bool is_path_separator(char ch)
+{
+#if defined(__WIN__) || defined(__NETWARE__)
+ /* On windows and netware more delimiters are possible */
+ return ch == FN_LIBCHAR || ch == FN_DEVCHAR || ch == '/';
+#else
+ return ch == FN_LIBCHAR; /* Unixes */
+#endif
}
+static char *find_last_path_separator(char *path, uint length)
+{
+ while (length)
+ {
+ if (is_path_separator(path[length]))
+ return path + length;
+ length--;
+ }
+ return NULL; /* No path separator found */
+}
+
+
+
bool Instance_options::is_option_im_specific(const char *option_name)
{
static const char *IM_SPECIFIC_OPTIONS[] =
@@ -82,8 +106,12 @@ bool Instance_options::is_option_im_specific(const char *option_name)
Instance_options::Instance_options()
:mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL),
- mysqld_pid_file(NULL), mysqld_port(NULL), mysqld_port_val(0),
- nonguarded(NULL), shutdown_delay(NULL), shutdown_delay_val(0),
+ mysqld_pid_file(NULL),
+ nonguarded(NULL),
+ mysqld_port(NULL),
+ mysqld_port_val(0),
+ shutdown_delay(NULL),
+ shutdown_delay_val(0),
filled_default_options(0)
{
mysqld_path.str= NULL;
@@ -99,7 +127,7 @@ Instance_options::Instance_options()
/*
Get compiled-in value of default_option
- SYNOPSYS
+ SYNOPSIS
get_default_option()
result buffer to put found value
result_len buffer size
@@ -139,7 +167,7 @@ err:
/*
Fill mysqld_version option (used at initialization stage)
- SYNOPSYS
+ SYNOPSIS
fill_instance_version()
DESCRIPTION
@@ -147,27 +175,36 @@ err:
Get mysqld version string from "mysqld --version" output.
RETURN
- 0 - ok
- 1 - error occured
+ FALSE - ok
+ TRUE - error occured
*/
-int Instance_options::fill_instance_version()
+bool Instance_options::fill_instance_version()
{
char result[MAX_VERSION_LENGTH];
LEX_STRING version_option=
{ C_STRING_WITH_LEN(" --no-defaults --version") };
- int rc= 1;
Buffer cmd(mysqld_path.length + version_option.length + 1);
if (create_mysqld_command(&cmd, &mysqld_path, &version_option))
- goto err;
+ {
+ log_error("Failed to get version of '%s': out of memory.",
+ (const char *) mysqld_path.str);
+ return TRUE;
+ }
bzero(result, MAX_VERSION_LENGTH);
- rc= parse_output_and_get_value(cmd.buffer, "Ver", result,
- MAX_VERSION_LENGTH, GET_LINE);
+ if (parse_output_and_get_value(cmd.buffer, "Ver", result,
+ MAX_VERSION_LENGTH, GET_LINE))
+ {
+ log_error("Failed to get version of '%s': unexpected output.",
+ (const char *) mysqld_path.str);
+ return TRUE;
+ }
+
+ DBUG_ASSERT(*result != '\0');
- if (*result != '\0')
{
char *start;
/* chop the newline from the end of the version string */
@@ -179,18 +216,15 @@ int Instance_options::fill_instance_version()
mysqld_version= strdup_root(&alloc, start);
}
-err:
- if (rc)
- log_error("fill_instance_version: Failed to get version of '%s'",
- mysqld_path.str);
- return rc;
+
+ return FALSE;
}
/*
Fill mysqld_real_path
- SYNOPSYS
+ SYNOPSIS
fill_mysqld_real_path()
DESCRIPTION
@@ -202,28 +236,37 @@ err:
script(for example libtool) or a symlink.
RETURN
- 0 - ok
- 1 - error occured
+ FALSE - ok
+ TRUE - error occured
*/
-int Instance_options::fill_mysqld_real_path()
+bool Instance_options::fill_mysqld_real_path()
{
char result[FN_REFLEN];
LEX_STRING help_option=
{ C_STRING_WITH_LEN(" --no-defaults --help") };
- int rc= 1;
Buffer cmd(mysqld_path.length + help_option.length);
if (create_mysqld_command(&cmd, &mysqld_path, &help_option))
- goto err;
+ {
+ log_error("Failed to get real path of '%s': out of memory.",
+ (const char *) mysqld_path.str);
+ return TRUE;
+ }
bzero(result, FN_REFLEN);
- rc= parse_output_and_get_value(cmd.buffer, "Usage: ",
+ if (parse_output_and_get_value(cmd.buffer, "Usage: ",
result, FN_REFLEN,
- GET_LINE);
+ GET_LINE))
+ {
+ log_error("Failed to get real path of '%s': unexpected output.",
+ (const char *) mysqld_path.str);
+ return TRUE;
+ }
+
+ DBUG_ASSERT(*result != '\0');
- if (*result != '\0')
{
char* options_str;
/* chop the path of at [OPTIONS] */
@@ -232,17 +275,15 @@ int Instance_options::fill_mysqld_real_path()
mysqld_real_path.str= strdup_root(&alloc, result);
mysqld_real_path.length= strlen(mysqld_real_path.str);
}
-err:
- if (rc)
- log_error("fill_mysqld_real_path: Failed to get real path of mysqld");
- return rc;
+
+ return FALSE;
}
/*
Fill various log options
- SYNOPSYS
+ SYNOPSIS
fill_log_options()
DESCRIPTION
@@ -252,11 +293,11 @@ err:
file name and placement.
RETURN
- 0 - ok
- 1 - error occured
+ FALSE - ok
+ TRUE - error occured
*/
-int Instance_options::fill_log_options()
+bool Instance_options::fill_log_options()
{
Buffer buff;
enum { MAX_LOG_OPTION_LENGTH= 256 };
@@ -282,7 +323,7 @@ int Instance_options::fill_log_options()
if (mysqld_datadir == NULL)
{
if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir"))
- goto err;
+ return TRUE;
}
else
{
@@ -320,7 +361,7 @@ int Instance_options::fill_log_options()
if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) <=
strlen(log_files->default_suffix))
- goto err;
+ return TRUE;
strmov(full_name + strlen(full_name), log_files->default_suffix);
@@ -340,22 +381,20 @@ int Instance_options::fill_log_options()
datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH);
if (!(*(log_files->value)= strdup_root(&alloc, full_name)))
- goto err;
+ return TRUE;
}
}
}
}
- return 0;
-err:
- return 1;
+ return FALSE;
}
/*
Get the full pid file name with path
- SYNOPSYS
+ SYNOPSIS
get_pid_filaname()
result buffer to sotre the pidfile value
@@ -396,7 +435,7 @@ int Instance_options::unlink_pidfile()
}
-pid_t Instance_options::get_pid()
+pid_t Instance_options::load_pid()
{
FILE *pid_file_stream;
@@ -415,26 +454,56 @@ pid_t Instance_options::get_pid()
}
-int Instance_options::complete_initialization(const char *default_path)
+bool Instance_options::complete_initialization()
{
int arg_idx;
const char *tmp;
char *end;
+ char bin_name_firstchar;
if (!mysqld_path.str)
{
- // Need one extra byte, as convert_dirname() adds a slash at the end.
- if (!(mysqld_path.str= alloc_root(&alloc, strlen(default_path) + 2)))
- goto err;
- strcpy(mysqld_path.str, default_path);
- }
+ /*
+ Need to copy the path to allocated memory, as convert_dirname() might
+ need to change it
+ */
+ mysqld_path.str=
+ alloc_root(&alloc, strlen(Options::Main::default_mysqld_path) + 1);
+
+ if (!mysqld_path.str)
+ return TRUE;
- // it's safe to cast this to char* since this is a buffer we are allocating
- end= convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS);
- end[-1]= 0;
+ strcpy(mysqld_path.str, Options::Main::default_mysqld_path);
+ }
mysqld_path.length= strlen(mysqld_path.str);
+ /*
+ If we found path with no slashes (end == NULL), we should not call
+ convert_dirname() at all. As we have got relative path to the binary.
+ That is, user supposes that mysqld resides in the same dir as
+ mysqlmanager.
+ */
+ if ((end= find_last_path_separator(mysqld_path.str, mysqld_path.length)))
+ {
+ bin_name_firstchar= end[1];
+
+ /*
+ Below we will conver the path to mysqld in the case, it was given
+ in a format of another OS (e.g. uses '/' instead of '\' etc).
+ Here we strip the path to get rid of the binary name ("mysqld"),
+ we do it by removing first letter of the binary name (e.g. 'm'
+ in "mysqld"). Later we put it back.
+ */
+ end[1]= 0;
+
+ /* convert dirname to the format of current OS */
+ convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS);
+
+ /* put back the first character of the binary name*/
+ end[1]= bin_name_firstchar;
+ }
+
if (mysqld_port)
mysqld_port_val= atoi(mysqld_port);
@@ -442,7 +511,7 @@ int Instance_options::complete_initialization(const char *default_path)
shutdown_delay_val= atoi(shutdown_delay);
if (!(tmp= strdup_root(&alloc, "--no-defaults")))
- goto err;
+ return TRUE;
if (!mysqld_pid_file)
{
@@ -477,21 +546,21 @@ int Instance_options::complete_initialization(const char *default_path)
}
if (get_pid_filename(pid_file_with_path))
- goto err;
+ return TRUE;
/* we need to reserve space for the final zero + possible default options */
if (!(argv= (char**)
alloc_root(&alloc, (get_num_options() + 1
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
- goto err;
+ return TRUE;
filled_default_options= 0;
/* the path must be first in the argv */
if (add_to_argv(mysqld_path.str))
- goto err;
+ return TRUE;
if (add_to_argv(tmp))
- goto err;
+ return TRUE;
arg_idx= filled_default_options;
for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx)
@@ -514,12 +583,9 @@ int Instance_options::complete_initialization(const char *default_path)
argv[arg_idx]= 0;
if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version())
- goto err;
-
- return 0;
+ return TRUE;
-err:
- return 1;
+ return FALSE;
}
@@ -636,26 +702,26 @@ void Instance_options::print_argv()
/*
We execute this function to initialize some options.
- Return value: 0 - ok. 1 - unable to allocate memory.
+
+ RETURN
+ FALSE - ok
+ TRUE - memory allocation error
*/
-int Instance_options::init(const LEX_STRING *instance_name_arg)
+bool Instance_options::init(const LEX_STRING *instance_name_arg)
{
instance_name.length= instance_name_arg->length;
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
if (options.init())
- goto err;
+ return TRUE;
if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str,
instance_name_arg->length)))
- goto err;
-
- return 0;
+ return TRUE;
-err:
- return 1;
+ return FALSE;
}
@@ -663,3 +729,29 @@ Instance_options::~Instance_options()
{
free_root(&alloc, MYF(0));
}
+
+
+uint Instance_options::get_shutdown_delay() const
+{
+ static const uint DEFAULT_SHUTDOWN_DELAY= 35;
+
+ /*
+ NOTE: it is important to check shutdown_delay here, but use
+ shutdown_delay_val. The idea is that if the option is unset,
+ shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+ */
+
+ return shutdown_delay ? shutdown_delay_val : DEFAULT_SHUTDOWN_DELAY;
+}
+
+int Instance_options::get_mysqld_port() const
+{
+ /*
+ NOTE: it is important to check mysqld_port here, but use mysqld_port_val.
+ The idea is that if the option is unset, mysqld_port will be NULL, but
+ mysqld_port_val will not be reset.
+ */
+
+ return mysqld_port ? mysqld_port_val : 0;
+}
+
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
index c3b0a16a40d..7c1e1a8dcf3 100644
--- a/server-tools/instance-manager/instance_options.h
+++ b/server-tools/instance-manager/instance_options.h
@@ -45,8 +45,9 @@ public:
public:
Instance_options();
~Instance_options();
+
/* fills in argv */
- int complete_initialization(const char *default_path);
+ bool complete_initialization();
bool set_option(Named_value *option);
void unset_option(const char *option_name);
@@ -55,12 +56,15 @@ public:
inline Named_value get_option(int idx) const;
public:
- int init(const LEX_STRING *instance_name_arg);
- pid_t get_pid();
+ bool init(const LEX_STRING *instance_name_arg);
+ pid_t load_pid();
int get_pid_filename(char *result);
int unlink_pidfile();
void print_argv();
+ uint get_shutdown_delay() const;
+ int get_mysqld_port() const;
+
public:
/*
We need this value to be greater or equal then FN_REFLEN found in
@@ -79,21 +83,17 @@ public:
const char *mysqld_socket;
const char *mysqld_datadir;
const char *mysqld_pid_file;
- const char *mysqld_port;
- uint mysqld_port_val;
LEX_STRING instance_name;
LEX_STRING mysqld_path;
LEX_STRING mysqld_real_path;
const char *nonguarded;
- const char *shutdown_delay;
- uint shutdown_delay_val;
/* log enums are defined in parse.h */
char *logs[3];
private:
- int fill_log_options();
- int fill_instance_version();
- int fill_mysqld_real_path();
+ bool fill_log_options();
+ bool fill_instance_version();
+ bool fill_mysqld_real_path();
int add_to_argv(const char *option);
int get_default_option(char *result, size_t result_len,
const char *option_name);
@@ -102,6 +102,11 @@ private:
int find_option(const char *option_name);
private:
+ const char *mysqld_port;
+ uint mysqld_port_val;
+ const char *shutdown_delay;
+ uint shutdown_delay_val;
+
uint filled_default_options;
MEM_ROOT alloc;
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 62962c00957..f18a594985c 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -29,7 +29,6 @@
#include <sys/un.h>
#endif
-#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
#include "options.h"
@@ -59,47 +58,18 @@ static void set_no_inherit(int socket)
}
-/*
- Listener_thread - incapsulates listening functionality
-*/
-
-class Listener_thread: public Listener_thread_args
-{
-public:
- Listener_thread(const Listener_thread_args &args);
- ~Listener_thread();
- void run();
-private:
- static const int LISTEN_BACK_LOG_SIZE= 5; /* standard backlog size */
- ulong total_connection_count;
- Thread_info thread_info;
-
- int sockets[2];
- int num_sockets;
- fd_set read_fds;
-private:
- void handle_new_mysql_connection(Vio *vio);
- int create_tcp_socket();
- int create_unix_socket(struct sockaddr_un &unix_socket_address);
-};
-
-
-Listener_thread::Listener_thread(const Listener_thread_args &args) :
- Listener_thread_args(args.thread_registry, args.user_map, args.instance_map)
- ,total_connection_count(0)
- ,thread_info(pthread_self(), TRUE)
- ,num_sockets(0)
-{
-}
-
-
-Listener_thread::~Listener_thread()
+Listener::Listener(Thread_registry *thread_registry_arg,
+ User_map *user_map_arg)
+ :thread_registry(thread_registry_arg),
+ user_map(user_map_arg),
+ total_connection_count(0),
+ num_sockets(0)
{
}
/*
- Listener_thread::run() - listen all supported sockets and spawn a thread
+ Listener::run() - listen all supported sockets and spawn a thread
to handle incoming connection.
Using 'die' in case of syscall failure is OK now - we don't hold any
resources and 'die' kills the signal thread automatically. To be rewritten
@@ -108,26 +78,17 @@ Listener_thread::~Listener_thread()
architecture.
*/
-void Listener_thread::run()
+void Listener::run()
{
int i, n= 0;
- log_info("Listener_thread: started.");
-
#ifndef __WIN__
- /* we use this var to check whether we are running on LinuxThreads */
- pid_t thread_pid;
-
- thread_pid= getpid();
-
struct sockaddr_un unix_socket_address;
- /* set global variable */
- linuxthreads= (thread_pid != manager_pid);
#endif
- thread_registry.register_thread(&thread_info);
+ log_info("Listener: started.");
- my_thread_init();
+ thread_registry->register_thread(&thread_info);
FD_ZERO(&read_fds);
@@ -146,7 +107,7 @@ void Listener_thread::run()
n++;
timeval tv;
- while (!thread_registry.is_shutdown())
+ while (!thread_registry->is_shutdown())
{
fd_set read_fds_arg= read_fds;
/*
@@ -166,8 +127,8 @@ void Listener_thread::run()
if (rc == 0 || rc == -1)
{
if (rc == -1 && errno != EINTR)
- log_error("Listener_thread: select() failed, %s",
- strerror(errno));
+ log_error("Listener: select() failed: %s.",
+ (const char *) strerror(errno));
continue;
}
@@ -183,10 +144,12 @@ void Listener_thread::run()
{
set_no_inherit(client_fd);
- Vio *vio= vio_new(client_fd, socket_index == 0 ?
- VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
- socket_index == 0 ? 1 : 0);
- if (vio != 0)
+ struct st_vio *vio=
+ vio_new(client_fd,
+ socket_index == 0 ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
+ socket_index == 0 ? 1 : 0);
+
+ if (vio != NULL)
handle_new_mysql_connection(vio);
else
{
@@ -200,7 +163,7 @@ void Listener_thread::run()
/* III. Release all resources and exit */
- log_info("Listener_thread: shutdown requested, exiting...");
+ log_info("Listener: shutdown requested, exiting...");
for (i= 0; i < num_sockets; i++)
close(sockets[i]);
@@ -209,10 +172,9 @@ void Listener_thread::run()
unlink(unix_socket_address.sun_path);
#endif
- thread_registry.unregister_thread(&thread_info);
- my_thread_end();
+ thread_registry->unregister_thread(&thread_info);
- log_info("Listener_thread: finished.");
+ log_info("Listener: finished.");
return;
err:
@@ -220,13 +182,12 @@ err:
for (i= 0; i < num_sockets; i++)
close(sockets[i]);
- thread_registry.unregister_thread(&thread_info);
- thread_registry.request_shutdown();
- my_thread_end();
+ thread_registry->unregister_thread(&thread_info);
+ thread_registry->request_shutdown();
return;
}
-int Listener_thread::create_tcp_socket()
+int Listener::create_tcp_socket()
{
/* value to be set by setsockopt */
int arg= 1;
@@ -234,8 +195,8 @@ int Listener_thread::create_tcp_socket()
int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
if (ip_socket == INVALID_SOCKET)
{
- log_error("Listener_thead: socket(AF_INET) failed, %s",
- strerror(errno));
+ log_error("Listener: socket(AF_INET) failed: %s.",
+ (const char *) strerror(errno));
return -1;
}
@@ -247,7 +208,7 @@ int Listener_thread::create_tcp_socket()
{
im_bind_addr= (ulong) inet_addr(Options::Main::bind_address);
- if (im_bind_addr == INADDR_NONE)
+ if (im_bind_addr == (ulong) INADDR_NONE)
im_bind_addr= htonl(INADDR_ANY);
}
else
@@ -265,16 +226,16 @@ int Listener_thread::create_tcp_socket()
if (bind(ip_socket, (struct sockaddr *) &ip_socket_address,
sizeof(ip_socket_address)))
{
- log_error("Listener_thread: bind(ip socket) failed, '%s'",
- strerror(errno));
+ log_error("Listener: bind(ip socket) failed: %s.",
+ (const char *) strerror(errno));
close(ip_socket);
return -1;
}
if (listen(ip_socket, LISTEN_BACK_LOG_SIZE))
{
- log_error("Listener_thread: listen(ip socket) failed, %s",
- strerror(errno));
+ log_error("Listener: listen(ip socket) failed: %s.",
+ (const char *) strerror(errno));
close(ip_socket);
return -1;
}
@@ -287,19 +248,20 @@ int Listener_thread::create_tcp_socket()
FD_SET(ip_socket, &read_fds);
sockets[num_sockets++]= ip_socket;
- log_info("accepting connections on ip socket (port: %d)", (int) im_port);
+ log_info("Listener: accepting connections on ip socket (port: %d)...",
+ (int) im_port);
return 0;
}
#ifndef __WIN__
-int Listener_thread::
+int Listener::
create_unix_socket(struct sockaddr_un &unix_socket_address)
{
int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0);
if (unix_socket == INVALID_SOCKET)
{
- log_error("Listener_thead: socket(AF_UNIX) failed, %s",
- strerror(errno));
+ log_error("Listener: socket(AF_UNIX) failed: %s.",
+ (const char *) strerror(errno));
return -1;
}
@@ -318,9 +280,9 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
if (bind(unix_socket, (struct sockaddr *) &unix_socket_address,
sizeof(unix_socket_address)))
{
- log_error("Listener_thread: bind(unix socket) failed, "
- "socket file name is '%s', error '%s'",
- unix_socket_address.sun_path, strerror(errno));
+ log_error("Listener: bind(unix socket) failed for '%s': %s.",
+ (const char *) unix_socket_address.sun_path,
+ (const char *) strerror(errno));
close(unix_socket);
return -1;
}
@@ -329,8 +291,8 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
{
- log_error("Listener_thread: listen(unix socket) failed, %s",
- strerror(errno));
+ log_error("Listener: listen(unix socket) failed: %s.",
+ (const char *) strerror(errno));
close(unix_socket);
return -1;
}
@@ -341,8 +303,8 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
/* make sure that instances won't be listening our sockets */
set_no_inherit(unix_socket);
- log_info("accepting connections on unix socket '%s'",
- unix_socket_address.sun_path);
+ log_info("Listener: accepting connections on unix socket '%s'...",
+ (const char *) unix_socket_address.sun_path);
sockets[num_sockets++]= unix_socket;
FD_SET(unix_socket, &read_fds);
return 0;
@@ -352,51 +314,21 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
/*
Create new mysql connection. Created thread is responsible for deletion of
- the Mysql_connection_thread_args and Vio instances passed to it.
- SYNOPSYS
+ the Mysql_connection and Vio instances passed to it.
+ SYNOPSIS
handle_new_mysql_connection()
*/
-void Listener_thread::handle_new_mysql_connection(Vio *vio)
+void Listener::handle_new_mysql_connection(struct st_vio *vio)
{
- if (Mysql_connection_thread_args *mysql_thread_args=
- new Mysql_connection_thread_args(vio, thread_registry, user_map,
- ++total_connection_count,
- instance_map)
- )
+ Mysql_connection *mysql_connection=
+ new Mysql_connection(thread_registry, user_map,
+ vio, ++total_connection_count);
+ if (mysql_connection == NULL || mysql_connection->start(Thread::DETACHED))
{
- /*
- Initialize thread attributes to create detached thread; it seems
- easier to do it ad-hoc than have a global variable for attributes.
- */
- pthread_t mysql_thd_id;
- pthread_attr_t mysql_thd_attr;
- pthread_attr_init(&mysql_thd_attr);
- pthread_attr_setdetachstate(&mysql_thd_attr, PTHREAD_CREATE_DETACHED);
- if (set_stacksize_n_create_thread(&mysql_thd_id, &mysql_thd_attr,
- mysql_connection, mysql_thread_args))
- {
- delete mysql_thread_args;
- vio_delete(vio);
- log_error("handle_one_mysql_connection():"
- "set_stacksize_n_create_thread(mysql) failed");
- }
- pthread_attr_destroy(&mysql_thd_attr);
- }
- else
+ log_error("Listener: can not start connection handler.");
+ delete mysql_connection;
vio_delete(vio);
+ }
+ /* The connection will delete itself when the thread is finished */
}
-
-
-pthread_handler_t listener(void *arg)
-{
- Listener_thread_args *args= (Listener_thread_args *) arg;
- Listener_thread listener(*args);
- listener.run();
- /*
- args is a stack variable because listener thread lives as long as the
- manager process itself
- */
- return 0;
-}
-
diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h
index c28ab0649d7..811744f8ea6 100644
--- a/server-tools/instance-manager/listener.h
+++ b/server-tools/instance-manager/listener.h
@@ -16,33 +16,46 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <my_global.h>
-#include <my_pthread.h>
+#include "thread_registry.h"
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
-
-pthread_handler_t listener(void *arg);
-
class Thread_registry;
class User_map;
-class Instance_map;
-struct Listener_thread_args
+/**
+ Listener - a thread listening on sockets and spawning
+ connection threads.
+*/
+
+class Listener: public Thread
{
- Thread_registry &thread_registry;
- const User_map &user_map;
- Instance_map &instance_map;
-
- Listener_thread_args(Thread_registry &thread_registry_arg,
- const User_map &user_map_arg,
- Instance_map &instance_map_arg) :
- thread_registry(thread_registry_arg)
- ,user_map(user_map_arg)
- ,instance_map(instance_map_arg)
- {}
+public:
+ Listener(Thread_registry *thread_registry_arg, User_map *user_map_arg);
+
+protected:
+ virtual void run();
+
+private:
+ static const int LISTEN_BACK_LOG_SIZE= 5; /* standard backlog size */
+
+private:
+ Thread_info thread_info;
+ Thread_registry *thread_registry;
+ User_map *user_map;
+
+ ulong total_connection_count;
+
+ int sockets[2];
+ int num_sockets;
+ fd_set read_fds;
+
+private:
+ void handle_new_mysql_connection(struct st_vio *vio);
+ int create_tcp_socket();
+ int create_unix_socket(struct sockaddr_un &unix_socket_address);
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc
index 7214cde7193..7ff45a15432 100644
--- a/server-tools/instance-manager/log.cc
+++ b/server-tools/instance-manager/log.cc
@@ -33,11 +33,12 @@
/*
Format log entry and write it to the given stream.
- SYNOPSYS
+ SYNOPSIS
log()
*/
-static inline void log(FILE *file, const char *format, va_list args)
+static void log(FILE *file,const char *level_tag, const char *format,
+ va_list args)
{
/*
log() should be thread-safe; it implies that we either call fprintf()
@@ -53,15 +54,16 @@ static inline void log(FILE *file, const char *format, va_list args)
localtime_r(&now, &bd_time);
char buff_date[128];
- sprintf(buff_date, "[%d/%lu] [%02d/%02d/%02d %02d:%02d:%02d] ",
+ sprintf(buff_date, "[%d/%lu] [%02d/%02d/%02d %02d:%02d:%02d] [%s] ",
(int) getpid(),
(unsigned long) pthread_self(),
- bd_time.tm_year % 100,
- bd_time.tm_mon + 1,
- bd_time.tm_mday,
- bd_time.tm_hour,
- bd_time.tm_min,
- bd_time.tm_sec);
+ (int) bd_time.tm_year % 100,
+ (int) bd_time.tm_mon + 1,
+ (int) bd_time.tm_mday,
+ (int) bd_time.tm_hour,
+ (int) bd_time.tm_min,
+ (int) bd_time.tm_sec,
+ (const char *) level_tag);
/* Format the message */
char buff_stack[256];
@@ -109,57 +111,73 @@ static inline void log(FILE *file, const char *format, va_list args)
/* don't fflush() the file: buffering strategy is set in log_init() */
}
+/**************************************************************************
+ Logging: implementation of public interface.
+**************************************************************************/
-void log_error(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- log(stderr, format, args);
- va_end(args);
-}
+/*
+ The function initializes logging sub-system.
+ SYNOPSIS
+ log_init()
+*/
-void log_info(const char *format, ...)
+void log_init()
{
- va_list args;
- va_start(args, format);
- log(stdout, format, args);
- va_end(args);
+ /*
+ stderr is unbuffered by default; there is no good of line buffering,
+ as all logging is performed linewise - so remove buffering from stdout
+ also
+ */
+ setbuf(stdout, 0);
}
-/* TODO: rewrite with buffering print */
-void print_info(const char *format, ...)
+
+/*
+ The function is intended to log error messages. It precedes a message
+ with date, time and [ERROR] tag and print it to the stderr.
+
+ SYNOPSIS
+ log_error()
+ format [IN] format string
+ ... [IN] arguments to format
+*/
+
+void log_error(const char *format, ...)
{
va_list args;
va_start(args, format);
- vfprintf(stdout, format, args);
+ log(stderr, "ERROR", format, args);
va_end(args);
}
-void print_error(const char *format, ...)
+
+/*
+ The function is intended to log information messages. It precedes
+ a message with date, time and [INFO] tag and print it to the stdout.
+
+ SYNOPSIS
+ log_error()
+ format [IN] format string
+ ... [IN] arguments to format
+*/
+
+void log_info(const char *format, ...)
{
va_list args;
va_start(args, format);
- vfprintf(stderr, format, args);
+ log(stdout, "INFO", format, args);
va_end(args);
}
/*
- log_init()
- RETURN VALUE
- 0 ok
- !0 error
-*/
+ The function prints information to the error log and eixt(1).
-void log_init()
-{
- /*
- stderr is unbuffered by default; there is no good of line buffering,
- as all logging is performed linewise - so remove buffering from stdout
- also
- */
- setbuf(stdout, 0);
-}
+ SYNOPSIS
+ die()
+ format [IN] format string
+ ... [IN] arguments to format
+*/
void die(const char *format, ...)
{
diff --git a/server-tools/instance-manager/log.h b/server-tools/instance-manager/log.h
index 825d7515513..9c47dbe04f5 100644
--- a/server-tools/instance-manager/log.h
+++ b/server-tools/instance-manager/log.h
@@ -19,20 +19,23 @@
/*
Logging facilities.
- Two logging streams are supported: error log and info log. Additionally
- libdbug may be used for debug information output.
+ Two logging streams are supported: error log and info log.
+ Additionally libdbug may be used for debug information output.
+
ANSI C buffered I/O is used to perform logging.
+
Logging is performed via stdout/stder, so one can reopen them to point to
- ordinary files. To initialize loggin environment log_init() must be called.
+ ordinary files. To initialize logging environment log_init() must be called.
Rationale:
- no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
- no constructors/desctructors to make logging available all the time
- Function names are subject to change.
*/
-/* Precede error message with date and time and print it to the stdout */
+void log_init();
+
+
void log_info(const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format(printf, 1, 2)))
@@ -40,7 +43,6 @@ void log_info(const char *format, ...)
;
-/* Precede error message with date and time and print it to the stderr */
void log_error(const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
@@ -48,30 +50,6 @@ void log_error(const char *format, ...)
;
-/*
- Now this is simple catchouts for printf (no date/time is logged), to be
- able to replace underlying streams in future.
-*/
-
-void print_info(const char *format, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
- ;
-
-
-void print_error(const char *format, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
- ;
-
-/* initialize logs */
-void log_init();
-
-
-/* print information to the error log and eixt(1) */
-
void die(const char *format, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
index 4bd298eedec..a002902bd56 100644
--- a/server-tools/instance-manager/manager.cc
+++ b/server-tools/instance-manager/manager.cc
@@ -37,33 +37,6 @@
#include "user_map.h"
-int create_pid_file(const char *pid_file_name, int pid)
-{
- FILE *pid_file;
-
- if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
- MYF(0))))
- {
- log_error("Error: can not create pid file '%s': %s (errno: %d)",
- (const char *) pid_file_name,
- (const char *) strerror(errno),
- (int) errno);
- return 1;
- }
-
- if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
- {
- log_error("Error: can not write to pid file '%s': %s (errno: %d)",
- (const char *) pid_file_name,
- (const char *) strerror(errno),
- (int) errno);
- return 1;
- }
-
- my_fclose(pid_file, MYF(0));
-
- return 0;
-}
#ifndef __WIN__
void set_signals(sigset_t *mask)
@@ -120,19 +93,79 @@ int my_sigwait(const sigset_t *set, int *sig)
#endif
-void stop_all(Guardian_thread *guardian, Thread_registry *registry)
+/**********************************************************************
+ Implementation of checking the actual thread model.
+***********************************************************************/
+
+namespace { /* no-indent */
+
+class ThreadModelChecker: public Thread
+{
+public:
+ ThreadModelChecker()
+ :main_pid(getpid())
+ { }
+
+public:
+ inline bool is_linux_threads() const
+ {
+ return linux_threads;
+ }
+
+protected:
+ virtual void run()
+ {
+ linux_threads= main_pid != getpid();
+ }
+
+private:
+ pid_t main_pid;
+ bool linux_threads;
+};
+
+bool check_if_linux_threads(bool *linux_threads)
+{
+ ThreadModelChecker checker;
+
+ if (checker.start() || checker.join())
+ return TRUE;
+
+ *linux_threads= checker.is_linux_threads();
+
+ return FALSE;
+}
+
+}
+
+
+/**********************************************************************
+ Manager implementation
+***********************************************************************/
+
+Guardian *Manager::p_guardian;
+Instance_map *Manager::p_instance_map;
+Thread_registry *Manager::p_thread_registry;
+User_map *Manager::p_user_map;
+
+#ifndef __WIN__
+bool Manager::linux_threads;
+#endif // __WIN__
+
+
+void Manager::stop_all_threads()
{
/*
Let guardian thread know that it should break it's processing cycle,
once it wakes up.
*/
- guardian->request_shutdown();
+ p_guardian->request_shutdown();
/* wake guardian */
- pthread_cond_signal(&guardian->COND_guardian);
+ pthread_cond_signal(&p_guardian->COND_guardian);
/* stop all threads */
- registry->deliver_shutdown();
+ p_thread_registry->deliver_shutdown();
}
+
/*
manager - entry point to the main instance manager process: start
listener thread, write pid file and enter into signal handling.
@@ -142,11 +175,24 @@ void stop_all(Guardian_thread *guardian, Thread_registry *registry)
TODO: how about returning error status.
*/
-void manager()
+int Manager::main()
{
int err_code;
+ int rc= 1;
const char *err_msg;
bool shutdown_complete= FALSE;
+ pid_t manager_pid= getpid();
+
+#ifndef __WIN__
+ if (check_if_linux_threads(&linux_threads))
+ {
+ log_error("Can not determine thread model.");
+ return 1;
+ }
+
+ log_info("Detected threads model: %s.",
+ (const char *) (linux_threads ? "LINUX threads" : "POSIX threads"));
+#endif // __WIN__
Thread_registry thread_registry;
/*
@@ -156,31 +202,31 @@ void manager()
*/
User_map user_map;
- Instance_map instance_map(Options::Main::default_mysqld_path,
- thread_registry);
- Guardian_thread guardian_thread(thread_registry,
- &instance_map,
- Options::Main::monitoring_interval);
+ Instance_map instance_map;
+ Guardian guardian(&thread_registry, &instance_map,
+ Options::Main::monitoring_interval);
- Listener_thread_args listener_args(thread_registry, user_map, instance_map);
+ Listener listener(&thread_registry, &user_map);
- manager_pid= getpid();
- instance_map.guardian= &guardian_thread;
+ p_instance_map= &instance_map;
+ p_guardian= instance_map.guardian= &guardian;
+ p_thread_registry= &thread_registry;
+ p_user_map= &user_map;
/* Initialize instance map. */
if (instance_map.init())
{
- log_error("Error: can not initialize instance list: out of memory.");
- return;
+ log_error("Can not initialize instance list: out of memory.");
+ return 1;
}
/* Initialize user map and load password file. */
if (user_map.init())
{
- log_error("Error: can not initialize user list: out of memory.");
- return;
+ log_error("Can not initialize user list: out of memory.");
+ return 1;
}
if ((err_code= user_map.load(Options::Main::password_file_name, &err_msg)))
@@ -193,13 +239,13 @@ void manager()
mysqld_safe-compatible mode. Continue, but complain in log.
*/
- log_error("Warning: password file does not exist, "
- "nobody will be able to connect to Instance Manager.");
+ log_info("Warning: password file does not exist, "
+ "nobody will be able to connect to Instance Manager.");
}
else
{
- log_error("Error: %s.", (const char *) err_msg);
- return;
+ log_error("%s.", (const char *) err_msg);
+ return 1;
}
}
@@ -210,7 +256,7 @@ void manager()
(int) manager_pid);
if (create_pid_file(Options::Main::pid_file_name, manager_pid))
- return; /* necessary logging has been already done. */
+ return 1; /* necessary logging has been already done. */
/*
Initialize signals and alarm-infrastructure.
@@ -218,49 +264,36 @@ void manager()
NOTE: To work nicely with LinuxThreads, the signal thread is the first
thread in the process.
- NOTE:
- After init_thr_alarm() call it's possible to call thr_alarm() (from
- different threads), that results in sending ALARM signal to the alarm
- thread (which can be the main thread). That signal can interrupt
- blocking calls.
-
- In other words, a blocking call can be interrupted in the main thread
- after init_thr_alarm().
+ NOTE: After init_thr_alarm() call it's possible to call thr_alarm()
+ (from different threads), that results in sending ALARM signal to the
+ alarm thread (which can be the main thread). That signal can interrupt
+ blocking calls. In other words, a blocking call can be interrupted in
+ the main thread after init_thr_alarm().
*/
sigset_t mask;
set_signals(&mask);
- /* create guardian thread */
+ /*
+ Create the guardian thread. The newly started thread will block until
+ we actually load instances.
+
+ NOTE: Guardian should be shutdown first. Only then all other threads
+ can be stopped. This should be done in this order because the guardian
+ is responsible for shutting down all the guarded instances, and this
+ is a long operation.
+
+ NOTE: Guardian uses thr_alarm() when detects the current state of an
+ instance (is_running()), but this does not interfere with
+ flush_instances() call later in the code, because until
+ flush_instances() completes in the main thread, Guardian thread is not
+ permitted to process instances. And before flush_instances() has
+ completed, there are no instances to guard.
+ */
+ if (guardian.start(Thread::DETACHED))
{
- pthread_t guardian_thd_id;
- pthread_attr_t guardian_thd_attr;
- int rc;
-
- /*
- NOTE: Guardian should be shutdown first. Only then all other threads
- need to be stopped. This should be done, as guardian is responsible
- for shutting down the instances, and this is a long operation.
-
- NOTE: Guardian uses thr_alarm() when detects current state of
- instances (is_running()), but it is not interfere with
- flush_instances() later in the code, because until flush_instances()
- complete in the main thread, Guardian thread is not permitted to
- process instances. And before flush_instances() there is no instances
- to proceed.
- */
-
- pthread_attr_init(&guardian_thd_attr);
- pthread_attr_setdetachstate(&guardian_thd_attr, PTHREAD_CREATE_DETACHED);
- rc= set_stacksize_n_create_thread(&guardian_thd_id, &guardian_thd_attr,
- guardian, &guardian_thread);
- pthread_attr_destroy(&guardian_thd_attr);
- if (rc)
- {
- log_error("manager(): set_stacksize_n_create_thread(guardian) failed");
- goto err;
- }
-
+ log_error("Can not start Guardian thread.");
+ goto err;
}
/* Load instances. */
@@ -276,40 +309,30 @@ void manager()
if (flush_instances_status)
{
- log_error("Cannot init instances repository. This might be caused by "
- "the wrong config file options. For instance, missing mysqld "
- "binary. Aborting.");
- stop_all(&guardian_thread, &thread_registry);
+ log_error("Can not init instances repository.");
+ stop_all_threads();
goto err;
}
}
- /* create the listener */
+ /* Initialize the Listener. */
+
+ if (listener.start(Thread::DETACHED))
{
- pthread_t listener_thd_id;
- pthread_attr_t listener_thd_attr;
- int rc;
-
- pthread_attr_init(&listener_thd_attr);
- pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
- rc= set_stacksize_n_create_thread(&listener_thd_id, &listener_thd_attr,
- listener, &listener_args);
- pthread_attr_destroy(&listener_thd_attr);
- if (rc)
- {
- log_error("manager(): set_stacksize_n_create_thread(listener) failed");
- stop_all(&guardian_thread, &thread_registry);
- goto err;
- }
+ log_error("Can not start Listener thread.");
+ stop_all_threads();
+ goto err;
}
/*
After the list of guarded instances have been initialized,
Guardian should start them.
*/
- pthread_cond_signal(&guardian_thread.COND_guardian);
+ pthread_cond_signal(&guardian.COND_guardian);
- log_info("Main loop: started.");
+ /* Main loop. */
+
+ log_info("Manager: started.");
while (!shutdown_complete)
{
@@ -319,7 +342,7 @@ void manager()
if ((status= my_sigwait(&mask, &signo)) != 0)
{
log_error("sigwait() failed");
- stop_all(&guardian_thread, &thread_registry);
+ stop_all_threads();
goto err;
}
@@ -328,8 +351,8 @@ void manager()
- we are waiting for SIGINT, SIGTERM -- signals that mean we should
shutdown;
- as shutdown signal is caught, we stop Guardian thread (by calling
- Guardian_thread::request_shutdown());
- - as Guardian_thread is stopped, it sends SIGTERM to this thread
+ Guardian::request_shutdown());
+ - as Guardian is stopped, it sends SIGTERM to this thread
(by calling Thread_registry::request_shutdown()), so that the
my_sigwait() above returns;
- as we catch the second SIGTERM, we send signals to all threads
@@ -345,7 +368,7 @@ void manager()
Bug #14164 IM tests fail on MacOS X (powermacg5)
*/
#ifdef IGNORE_SIGHUP_SIGQUIT
- if ( SIGHUP == signo )
+ if (SIGHUP == signo)
continue;
#endif
if (THR_SERVER_ALARM == signo)
@@ -353,12 +376,12 @@ void manager()
else
#endif
{
- log_info("Main loop: got shutdown signal.");
+ log_info("Manager: got shutdown signal.");
- if (!guardian_thread.is_stopped())
+ if (!guardian.is_stopped())
{
- guardian_thread.request_shutdown();
- pthread_cond_signal(&guardian_thread.COND_guardian);
+ guardian.request_shutdown();
+ pthread_cond_signal(&guardian.COND_guardian);
}
else
{
@@ -368,7 +391,9 @@ void manager()
}
}
- log_info("Main loop: finished.");
+ log_info("Manager: finished.");
+
+ rc= 0;
err:
/* delete the pid file */
@@ -379,4 +404,5 @@ err:
end_thr_alarm(1);
/* don't pthread_exit to kill all threads who did not shut down in time */
#endif
+ return rc;
}
diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h
index 7aa4b3e1a96..a77809cca6d 100644
--- a/server-tools/instance-manager/manager.h
+++ b/server-tools/instance-manager/manager.h
@@ -16,8 +16,49 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-void manager();
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
+#include <my_global.h>
-int create_pid_file(const char *pid_file_name, int pid);
+class Guardian;
+class Instance_map;
+class Thread_registry;
+class User_map;
+
+class Manager
+{
+public:
+ static int main();
+ /**
+ These methods return a non-zero value only for the duration
+ of main().
+ */
+ static Instance_map *get_instance_map() { return p_instance_map; }
+ static Guardian *get_guardian() { return p_guardian; }
+ static Thread_registry *get_thread_registry() { return p_thread_registry; }
+ static User_map *get_user_map() { return p_user_map; }
+
+#ifndef __WIN__
+ static bool is_linux_threads() { return linux_threads; }
+#endif // __WIN__
+
+private:
+ static void stop_all_threads();
+
+private:
+ static Guardian *p_guardian;
+ static Instance_map *p_instance_map;
+ static Thread_registry *p_thread_registry;
+ static User_map *p_user_map;
+
+#ifndef __WIN__
+ /*
+ This flag is set if Instance Manager is running on the system using
+ LinuxThreads.
+ */
+ static bool linux_threads;
+#endif // __WIN__
+};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
index 4ffee83ddc3..952bdcd0e73 100644
--- a/server-tools/instance-manager/mysql_connection.cc
+++ b/server-tools/instance-manager/mysql_connection.cc
@@ -23,7 +23,6 @@
#include <m_string.h>
#include <m_string.h>
#include <my_global.h>
-#include <mysql_com.h>
#include <mysql.h>
#include <my_sys.h>
#include <violite.h>
@@ -40,66 +39,15 @@
#include "user_map.h"
-Mysql_connection_thread_args::Mysql_connection_thread_args(
- struct st_vio *vio_arg,
- Thread_registry &thread_registry_arg,
- const User_map &user_map_arg,
- ulong connection_id_arg,
- Instance_map &instance_map_arg) :
- vio(vio_arg)
- ,thread_registry(thread_registry_arg)
- ,user_map(user_map_arg)
- ,connection_id(connection_id_arg)
- ,instance_map(instance_map_arg)
- {}
-
-/*
- MySQL connection - handle one connection with mysql command line client
- See also comments in mysqlmanager.cc to picture general Instance Manager
- architecture.
- We use conventional technique to work with classes without exceptions:
- class acquires all vital resource in init(); Thus if init() succeed,
- a user must call cleanup(). All other methods are valid only between
- init() and cleanup().
-*/
-
-class Mysql_connection_thread: public Mysql_connection_thread_args
-{
-public:
- Mysql_connection_thread(const Mysql_connection_thread_args &args);
-
- int init();
- void cleanup();
-
- void run();
-
- ~Mysql_connection_thread();
-private:
- Thread_info thread_info;
- NET net;
- struct rand_struct rand_st;
- char scramble[SCRAMBLE_LENGTH + 1];
- uint status;
- ulong client_capabilities;
-private:
- /* Names are conventionally the same as in mysqld */
- int check_connection();
- int do_command();
- int dispatch_command(enum enum_server_command command,
- const char *text, uint len);
-};
-
-
-Mysql_connection_thread::Mysql_connection_thread(
- const Mysql_connection_thread_args &args) :
- Mysql_connection_thread_args(args.vio,
- args.thread_registry,
- args.user_map,
- args.connection_id,
- args.instance_map)
- ,thread_info(pthread_self(), TRUE)
+Mysql_connection::Mysql_connection(Thread_registry *thread_registry_arg,
+ User_map *user_map_arg,
+ struct st_vio *vio_arg, ulong
+ connection_id_arg)
+ :vio(vio_arg),
+ connection_id(connection_id_arg),
+ thread_registry(thread_registry_arg),
+ user_map(user_map_arg)
{
- thread_registry.register_thread(&thread_info);
}
@@ -129,67 +77,73 @@ C_MODE_END
This function is complementary to cleanup().
*/
-int Mysql_connection_thread::init()
+bool Mysql_connection::init()
{
/* Allocate buffers for network I/O */
if (my_net_init(&net, vio))
- return 1;
+ return TRUE;
+
net.return_status= &status;
+
/* Initialize random number generator */
{
ulong seed1= (ulong) &rand_st + rand();
ulong seed2= (ulong) rand() + time(0);
randominit(&rand_st, seed1, seed2);
}
+
/* Fill scramble - server's random message used for handshake */
create_random_string(scramble, SCRAMBLE_LENGTH, &rand_st);
+
/* We don't support transactions, every query is atomic */
status= SERVER_STATUS_AUTOCOMMIT;
- return 0;
+
+ thread_registry->register_thread(&thread_info);
+
+ return FALSE;
}
-void Mysql_connection_thread::cleanup()
+void Mysql_connection::cleanup()
{
net_end(&net);
+ thread_registry->unregister_thread(&thread_info);
}
-Mysql_connection_thread::~Mysql_connection_thread()
+Mysql_connection::~Mysql_connection()
{
/* vio_delete closes the socket if necessary */
vio_delete(vio);
- thread_registry.unregister_thread(&thread_info);
}
-void Mysql_connection_thread::run()
+void Mysql_connection::main()
{
- log_info("accepted mysql connection %lu", connection_id);
-
- my_thread_init();
+ log_info("Connection %lu: accepted.", (unsigned long) connection_id);
if (check_connection())
{
- my_thread_end();
+ log_info("Connection %lu: failed to authorize the user.",
+ (unsigned long) connection_id);
+
return;
}
- log_info("connection %lu is checked successfully", connection_id);
+ log_info("Connection %lu: the user was authorized successfully.",
+ (unsigned long) connection_id);
vio_keepalive(vio, TRUE);
- while (!net.error && net.vio && !thread_registry.is_shutdown())
+ while (!net.error && net.vio && !thread_registry->is_shutdown())
{
if (do_command())
break;
}
-
- my_thread_end();
}
-int Mysql_connection_thread::check_connection()
+int Mysql_connection::check_connection()
{
ulong pkt_len=0; // to hold client reply length
@@ -278,7 +232,7 @@ int Mysql_connection_thread::check_connection()
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
return 1;
}
- if (user_map.authenticate(&user_name, password, scramble))
+ if (user_map->authenticate(&user_name, password, scramble))
{
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
return 1;
@@ -288,7 +242,7 @@ int Mysql_connection_thread::check_connection()
}
-int Mysql_connection_thread::do_command()
+int Mysql_connection::do_command()
{
char *packet;
ulong packet_length;
@@ -301,7 +255,7 @@ int Mysql_connection_thread::do_command()
/* Check if we can continue without closing the connection */
if (net.error != 3) // what is 3 - find out
return 1;
- if (thread_registry.is_shutdown())
+ if (thread_registry->is_shutdown())
return 1;
net_send_error(&net, net.last_errno);
net.error= 0;
@@ -309,76 +263,101 @@ int Mysql_connection_thread::do_command()
}
else
{
- if (thread_registry.is_shutdown())
+ if (thread_registry->is_shutdown())
return 1;
packet= (char*) net.read_pos;
enum enum_server_command command= (enum enum_server_command)
(uchar) *packet;
- log_info("connection: %lu packet_length: %lu command: %d",
- connection_id, packet_length, command);
- return dispatch_command(command, packet + 1, packet_length - 1);
+ log_info("Connection %lu: received packet (length: %lu; command: %d).",
+ (unsigned long) connection_id,
+ (unsigned long) packet_length,
+ (int) command);
+
+ return dispatch_command(command, packet + 1);
}
}
-int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
- const char *packet, uint len)
+int Mysql_connection::dispatch_command(enum enum_server_command command,
+ const char *packet)
{
switch (command) {
case COM_QUIT: // client exit
- log_info("query for connection %lu received quit command", connection_id);
+ log_info("Connection %lu: received QUIT command.",
+ (unsigned long) connection_id);
return 1;
+
case COM_PING:
- log_info("query for connection %lu received ping command", connection_id);
+ log_info("Connection %lu: received PING command.",
+ (unsigned long) connection_id);
net_send_ok(&net, connection_id, NULL);
- break;
+ return 0;
+
case COM_QUERY:
{
- log_info("query for connection %lu : ----\n%s\n-------------------------",
- connection_id,packet);
- if (Command *command= parse_command(&instance_map, packet))
+ log_info("Connection %lu: received QUERY command: '%s'.",
+ (unsigned long) connection_id,
+ (const char *) packet);
+
+ if (Command *command= parse_command(packet))
{
int res= 0;
- log_info("query for connection %lu successefully parsed",connection_id);
+
+ log_info("Connection %lu: query parsed successfully.",
+ (unsigned long) connection_id);
+
res= command->execute(&net, connection_id);
delete command;
+
if (!res)
- log_info("query for connection %lu executed ok",connection_id);
+ {
+ log_info("Connection %lu: query executed successfully",
+ (unsigned long) connection_id);
+ }
else
{
- log_info("query for connection %lu executed err=%d",connection_id,res);
+ log_info("Connection %lu: can not execute query (error: %d).",
+ (unsigned long) connection_id,
+ (int) res);
+
net_send_error(&net, res);
- return 0;
}
}
else
{
+ log_error("Connection %lu: can not parse query: out ot resources.",
+ (unsigned long) connection_id);
+
net_send_error(&net,ER_OUT_OF_RESOURCES);
- return 0;
}
- break;
+
+ return 0;
}
+
default:
- log_info("query for connection %lu received unknown command",connection_id);
+ log_info("Connection %lu: received unsupported command (%d).",
+ (unsigned long) connection_id,
+ (int) command);
+
net_send_error(&net, ER_UNKNOWN_COM_ERROR);
- break;
+ return 0;
}
- return 0;
+
+ return 0; /* Just to make compiler happy. */
}
-pthread_handler_t mysql_connection(void *arg)
+void Mysql_connection::run()
{
- Mysql_connection_thread_args *args= (Mysql_connection_thread_args *) arg;
- Mysql_connection_thread mysql_connection_thread(*args);
- delete args;
- if (mysql_connection_thread.init())
- log_info("mysql_connection(): error initializing thread");
+ if (init())
+ log_error("Connection %lu: can not init handler.",
+ (unsigned long) connection_id);
else
{
- mysql_connection_thread.run();
- mysql_connection_thread.cleanup();
+ main();
+ cleanup();
}
- return 0;
+
+ delete this;
}
/*
diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h
index 3496cc05815..ef58d921637 100644
--- a/server-tools/instance-manager/mysql_connection.h
+++ b/server-tools/instance-manager/mysql_connection.h
@@ -16,33 +16,59 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <my_global.h>
-#include <my_pthread.h>
+#include "thread_registry.h"
+#include <mysql_com.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
#endif
-pthread_handler_t mysql_connection(void *arg);
-
-class Thread_registry;
-class User_map;
-class Instance_map;
struct st_vio;
+class User_map;
-struct Mysql_connection_thread_args
+/*
+ MySQL connection - handle one connection with mysql command line client
+ See also comments in mysqlmanager.cc to picture general Instance Manager
+ architecture.
+ We use conventional technique to work with classes without exceptions:
+ class acquires all vital resource in init(); Thus if init() succeed,
+ a user must call cleanup(). All other methods are valid only between
+ init() and cleanup().
+*/
+
+class Mysql_connection: public Thread
{
+public:
+ Mysql_connection(Thread_registry *thread_registry_arg,
+ User_map *user_map_arg,
+ struct st_vio *vio_arg,
+ ulong connection_id_arg);
+ virtual ~Mysql_connection();
+
+protected:
+ virtual void run();
+
+private:
struct st_vio *vio;
- Thread_registry &thread_registry;
- const User_map &user_map;
ulong connection_id;
- Instance_map &instance_map;
+ Thread_info thread_info;
+ Thread_registry *thread_registry;
+ User_map *user_map;
+ NET net;
+ struct rand_struct rand_st;
+ char scramble[SCRAMBLE_LENGTH + 1];
+ uint status;
+ ulong client_capabilities;
+private:
+ /* The main loop implementation triad */
+ bool init();
+ void main();
+ void cleanup();
- Mysql_connection_thread_args(struct st_vio *vio_arg,
- Thread_registry &thread_registry_arg,
- const User_map &user_map_arg,
- ulong connection_id_arg,
- Instance_map &instance_map_arg);
+ /* Names are conventionally the same as in mysqld */
+ int check_connection();
+ int do_command();
+ int dispatch_command(enum enum_server_command command, const char *text);
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index 177b761b419..8ee8321fffc 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -31,6 +31,7 @@
#include "log.h"
#include "manager.h"
#include "options.h"
+#include "priv.h"
#include "user_management_commands.h"
#ifdef __WIN__
@@ -117,7 +118,7 @@ int main(int argc, char *argv[])
angel();
}
- manager();
+ (void) Manager::main(); /* ignore the return value for now */
#else
@@ -131,7 +132,7 @@ int main(int argc, char *argv[])
}
else
{
- manager();
+ (void) Manager::main(); /* ignore the return value for now */
}
#endif
@@ -190,7 +191,8 @@ static struct passwd *check_user(const char *user)
return user_info;
err:
- log_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n", user);
+ log_error("Can not start under user '%s'.",
+ (const char *) user);
return NULL;
}
@@ -231,7 +233,7 @@ static void init_environment(char *progname)
#ifndef __WIN__
/*
Become a UNIX service
- SYNOPSYS
+ SYNOPSIS
daemonize()
*/
@@ -384,11 +386,10 @@ spawn:
}
/*
mysqlmanager successfully exited, let's silently evaporate
- If we return to main we fall into the manager() function, so let's
- simply exit().
+ If we return to main we will fall into the manager functionality,
+ so let's simply exit().
*/
exit(0);
}
}
-
#endif
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index 048f7983b32..e81320584ea 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -269,12 +269,11 @@ void skip_spaces(const char **text)
}
-Command *parse_command(Instance_map *map, const char *text)
+Command *parse_command(const char *text)
{
uint word_len;
LEX_STRING instance_name;
Command *command= 0;
- const char *saved_text= text;
Token tok1= shift_token(&text, &word_len);
@@ -294,7 +293,7 @@ Command *parse_command(Instance_map *map, const char *text)
if (tok1 == TOK_CREATE)
{
- Create_instance *cmd= new Create_instance(map, &instance_name);
+ Create_instance *cmd= new Create_instance(&instance_name);
if (!cmd)
return NULL; /* Report ER_OUT_OF_RESOURCES. */
@@ -317,16 +316,16 @@ Command *parse_command(Instance_map *map, const char *text)
switch (tok1) {
case TOK_START:
- command= new Start_instance(map, &instance_name);
+ command= new Start_instance(&instance_name);
break;
case TOK_STOP:
- command= new Stop_instance(map, &instance_name);
+ command= new Stop_instance(&instance_name);
break;
case TOK_CREATE:
; /* command already initialized. */
break;
case TOK_DROP:
- command= new Drop_instance(map, &instance_name);
+ command= new Drop_instance(&instance_name);
break;
default: /* this is impossible, but nevertheless... */
DBUG_ASSERT(0);
@@ -340,7 +339,7 @@ Command *parse_command(Instance_map *map, const char *text)
if (word_len)
goto syntax_error;
- command= new Flush_instances(map);
+ command= new Flush_instances();
break;
case TOK_UNSET:
case TOK_SET:
@@ -348,9 +347,9 @@ Command *parse_command(Instance_map *map, const char *text)
Abstract_option_cmd *cmd;
if (tok1 == TOK_SET)
- cmd= new Set_option(map);
+ cmd= new Set_option();
else
- cmd= new Unset_option(map);
+ cmd= new Unset_option();
if (!cmd)
return NULL; /* Report ER_OUT_OF_RESOURCES. */
@@ -371,7 +370,7 @@ Command *parse_command(Instance_map *map, const char *text)
get_word(&text, &word_len, NONSPACE);
if (word_len)
goto syntax_error;
- command= new Show_instances(map);
+ command= new Show_instances();
break;
case TOK_INSTANCE:
switch (Token tok2= shift_token(&text, &word_len)) {
@@ -385,9 +384,9 @@ Command *parse_command(Instance_map *map, const char *text)
if (word_len)
goto syntax_error;
if (tok2 == TOK_STATUS)
- command= new Show_instance_status(map, &instance_name);
+ command= new Show_instance_status(&instance_name);
else
- command= new Show_instance_options(map, &instance_name);
+ command= new Show_instance_options(&instance_name);
break;
default:
goto syntax_error;
@@ -414,7 +413,7 @@ Command *parse_command(Instance_map *map, const char *text)
/* check that this is the end of the command */
if (word_len)
goto syntax_error;
- command= new Show_instance_log_files(map, &instance_name);
+ command= new Show_instance_log_files(&instance_name);
break;
case TOK_ERROR:
case TOK_GENERAL:
@@ -484,7 +483,7 @@ Command *parse_command(Instance_map *map, const char *text)
goto syntax_error;
}
- command= new Show_instance_log(map, &instance_name,
+ command= new Show_instance_log(&instance_name,
log_type, log_size, log_offset);
break;
default:
@@ -504,5 +503,8 @@ Command *parse_command(Instance_map *map, const char *text)
syntax_error:
command= new Syntax_error();
}
+
+ DBUG_ASSERT(command);
+
return command;
}
diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h
index fd970f54d29..7e954b4918f 100644
--- a/server-tools/instance-manager/parse.h
+++ b/server-tools/instance-manager/parse.h
@@ -21,7 +21,6 @@
#include <m_string.h>
class Command;
-class Instance_map;
enum Log_type
{
@@ -30,7 +29,7 @@ enum Log_type
IM_LOG_SLOW
};
-Command *parse_command(Instance_map *map, const char *text);
+Command *parse_command(const char *text);
bool parse_option_value(const char *text, uint *text_len, char **value);
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
index 643a50625a1..9213de82e1d 100644
--- a/server-tools/instance-manager/parse_output.cc
+++ b/server-tools/instance-manager/parse_output.cc
@@ -43,7 +43,7 @@ void trim_space(const char **text, uint *word_len)
/*
Parse output of the given command
- SYNOPSYS
+ SYNOPSIS
parse_output_and_get_value()
command the command to execue with popen.
diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc
index 3dae900d84b..7695b585169 100644
--- a/server-tools/instance-manager/priv.cc
+++ b/server-tools/instance-manager/priv.cc
@@ -18,26 +18,9 @@
#include <my_global.h>
#include <mysql_com.h>
+#include <my_sys.h>
-#if defined(__ia64__) || defined(__ia64)
-/*
- We can live with 32K, but reserve 64K. Just to be safe.
- On ia64 we need to reserve double of the size.
-*/
-#define IM_THREAD_STACK_SIZE (128*1024L)
-#else
-#define IM_THREAD_STACK_SIZE (64*1024)
-#endif
-
-
-/* the pid of the manager process (of the signal thread on the LinuxThreads) */
-pid_t manager_pid;
-
-/*
- This flag is set if mysqlmanager has detected that it is running on the
- system using LinuxThreads
-*/
-bool linuxthreads;
+#include "log.h"
/*
The following string must be less then 80 characters, as
@@ -63,30 +46,32 @@ unsigned long bytes_sent = 0L, bytes_received = 0L;
unsigned long mysqld_net_retry_count = 10L;
unsigned long open_files_limit;
-/*
- Change the stack size and start a thread. Return an error if either
- pthread_attr_setstacksize or pthread_create fails.
- Arguments are the same as for pthread_create().
-*/
-int set_stacksize_n_create_thread(pthread_t *thread, pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
+
+int create_pid_file(const char *pid_file_name, int pid)
{
- int rc= 0;
-
-#ifndef __WIN__
-#ifndef PTHREAD_STACK_MIN
-#define PTHREAD_STACK_MIN 32768
-#endif
- /*
- Set stack size to be safe on the platforms with too small
- default thread stack.
- */
- rc= pthread_attr_setstacksize(attr,
- (size_t) (PTHREAD_STACK_MIN +
- IM_THREAD_STACK_SIZE));
-#endif
- if (!rc)
- rc= pthread_create(thread, attr, start_routine, arg);
- return rc;
+ FILE *pid_file;
+
+ if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
+ MYF(0))))
+ {
+ log_error("Can not create pid file '%s': %s (errno: %d)",
+ (const char *) pid_file_name,
+ (const char *) strerror(errno),
+ (int) errno);
+ return 1;
+ }
+
+ if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
+ {
+ log_error("Can not write to pid file '%s': %s (errno: %d)",
+ (const char *) pid_file_name,
+ (const char *) strerror(errno),
+ (int) errno);
+ return 1;
+ }
+
+ my_fclose(pid_file, MYF(0));
+
+ return 0;
}
diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h
index 0b393c17ac2..4d434213781 100644
--- a/server-tools/instance-manager/priv.h
+++ b/server-tools/instance-manager/priv.h
@@ -50,17 +50,6 @@ const int MAX_VERSION_LENGTH= 160;
const int MAX_INSTANCE_NAME_SIZE= FN_REFLEN;
-/* the pid of the manager process (of the signal thread on the LinuxThreads) */
-extern pid_t manager_pid;
-
-#ifndef __WIN__
-/*
- This flag is set if mysqlmanager has detected that it is running on the
- system using LinuxThreads
-*/
-extern bool linuxthreads;
-#endif
-
extern const LEX_STRING mysqlmanager_version;
/* MySQL client-server protocol version: substituted from configure */
@@ -105,8 +94,6 @@ extern unsigned long bytes_sent, bytes_received;
extern unsigned long mysqld_net_retry_count;
extern unsigned long open_files_limit;
-
-int set_stacksize_n_create_thread(pthread_t *thread, pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg);
+int create_pid_file(const char *pid_file_name, int pid);
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
index 10370e0981e..5cbf1eb044e 100644
--- a/server-tools/instance-manager/thread_registry.cc
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -25,8 +25,6 @@
#include <signal.h>
-#include "log.h"
-
#ifndef __WIN__
/* Kick-off signal handler */
@@ -38,15 +36,13 @@ static void handle_signal(int __attribute__((unused)) sig_no)
}
#endif
-/*
- Thread_info initializer methods
-*/
+/* Thread_info initializer methods */
-Thread_info::Thread_info() {}
-Thread_info::Thread_info(pthread_t thread_id_arg,
- bool send_signal_on_shutdown_arg) :
- thread_id(thread_id_arg),
- send_signal_on_shutdown(send_signal_on_shutdown_arg) {}
+void Thread_info::init(bool send_signal_on_shutdown_arg)
+{
+ thread_id= pthread_self();
+ send_signal_on_shutdown= send_signal_on_shutdown_arg;
+}
/*
TODO: think about moving signal information (now it's shutdown_in_progress)
@@ -86,10 +82,13 @@ Thread_registry::~Thread_registry()
points to the last node.
*/
-void Thread_registry::register_thread(Thread_info *info)
+void Thread_registry::register_thread(Thread_info *info,
+ bool send_signal_on_shutdown)
{
- log_info("Thread_registry: registering thread %d...",
- (int) info->thread_id);
+ info->init(send_signal_on_shutdown);
+
+ DBUG_PRINT("info", ("Thread_registry: registering thread %lu...",
+ (unsigned long) info->thread_id));
#ifndef __WIN__
struct sigaction sa;
@@ -117,8 +116,8 @@ void Thread_registry::register_thread(Thread_info *info)
void Thread_registry::unregister_thread(Thread_info *info)
{
- log_info("Thread_registry: unregistering thread %d...",
- (int) info->thread_id);
+ DBUG_PRINT("info", ("Thread_registry: unregistering thread %lu...",
+ (unsigned long) info->thread_id));
pthread_mutex_lock(&LOCK_thread_registry);
info->prev->next= info->next;
@@ -126,7 +125,7 @@ void Thread_registry::unregister_thread(Thread_info *info)
if (head.next == &head)
{
- log_info("Thread_registry: thread registry is empty!");
+ DBUG_PRINT("info", ("Thread_registry: thread registry is empty!"));
pthread_cond_signal(&COND_thread_registry_is_empty);
}
@@ -230,6 +229,7 @@ void Thread_registry::deliver_shutdown()
wait_for_threads_to_unregister();
+#ifndef DBUG_OFF
/*
Print out threads, that didn't stopped. Thread_registry destructor will
probably abort the program if there is still any alive thread.
@@ -237,15 +237,16 @@ void Thread_registry::deliver_shutdown()
if (head.next != &head)
{
- log_info("Thread_registry: non-stopped threads:");
+ DBUG_PRINT("info", ("Thread_registry: non-stopped threads:"));
for (Thread_info *info= head.next; info != &head; info= info->next)
- log_info(" - %ld", (long int) info->thread_id);
+ DBUG_PRINT("info", (" - %lu", (unsigned long) info->thread_id));
}
else
{
- log_info("Thread_registry: all threads stopped.");
+ DBUG_PRINT("info", ("Thread_registry: all threads stopped."));
}
+#endif // DBUG_OFF
pthread_mutex_unlock(&LOCK_thread_registry);
}
@@ -277,13 +278,13 @@ void Thread_registry::wait_for_threads_to_unregister()
set_timespec(shutdown_time, 1);
- log_info("Thread_registry: joining threads...");
+ DBUG_PRINT("info", ("Thread_registry: joining threads..."));
while (true)
{
if (head.next == &head)
{
- log_info("Thread_registry: emptied.");
+ DBUG_PRINT("info", ("Thread_registry: emptied."));
return;
}
@@ -293,8 +294,101 @@ void Thread_registry::wait_for_threads_to_unregister()
if (error == ETIMEDOUT || error == ETIME)
{
- log_info("Thread_registry: threads shutdown timed out.");
+ DBUG_PRINT("info", ("Thread_registry: threads shutdown timed out."));
return;
}
}
}
+
+
+/*********************************************************************
+ class Thread
+*********************************************************************/
+
+#if defined(__ia64__) || defined(__ia64)
+/*
+ We can live with 32K, but reserve 64K. Just to be safe.
+ On ia64 we need to reserve double of the size.
+*/
+#define IM_THREAD_STACK_SIZE (128*1024L)
+#else
+#define IM_THREAD_STACK_SIZE (64*1024)
+#endif
+
+/*
+ Change the stack size and start a thread. Return an error if either
+ pthread_attr_setstacksize or pthread_create fails.
+ Arguments are the same as for pthread_create().
+*/
+
+static
+int set_stacksize_and_create_thread(pthread_t *thread, pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ int rc= 0;
+
+#ifndef __WIN__
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 32768
+#endif
+ /*
+ Set stack size to be safe on the platforms with too small
+ default thread stack.
+ */
+ rc= pthread_attr_setstacksize(attr,
+ (size_t) (PTHREAD_STACK_MIN +
+ IM_THREAD_STACK_SIZE));
+#endif
+ if (!rc)
+ rc= pthread_create(thread, attr, start_routine, arg);
+ return rc;
+}
+
+
+Thread::~Thread()
+{
+}
+
+
+void *Thread::thread_func(void *arg)
+{
+ Thread *thread= (Thread *) arg;
+ my_thread_init();
+
+ thread->run();
+
+ my_thread_end();
+ return NULL;
+}
+
+
+bool Thread::start(enum_thread_type thread_type)
+{
+ pthread_attr_t attr;
+ int rc;
+
+ pthread_attr_init(&attr);
+
+ if (thread_type == DETACHED)
+ {
+ detached = TRUE;
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ }
+ else
+ {
+ detached = FALSE;
+ }
+
+ rc= set_stacksize_and_create_thread(&id, &attr, Thread::thread_func, this);
+ pthread_attr_destroy(&attr);
+
+ return rc != 0;
+}
+
+
+bool Thread::join()
+{
+ DBUG_ASSERT(!detached);
+
+ return pthread_join(id, NULL) != 0;
+}
diff --git a/server-tools/instance-manager/thread_registry.h b/server-tools/instance-manager/thread_registry.h
index 503d24e5fb0..b9ece271c21 100644
--- a/server-tools/instance-manager/thread_registry.h
+++ b/server-tools/instance-manager/thread_registry.h
@@ -57,7 +57,7 @@
#pragma interface
#endif
-/*
+/**
Thread_info - repository entry for each worker thread
All entries comprise double-linked list like:
0 -- entry -- entry -- entry - 0
@@ -67,12 +67,10 @@
class Thread_info
{
public:
- Thread_info(pthread_t thread_id_arg, bool send_signal_on_shutdown_arg);
+ Thread_info() {}
friend class Thread_registry;
-
private:
- Thread_info();
-
+ void init(bool send_signal_on_shutdown);
private:
pthread_cond_t *current_cond;
Thread_info *prev, *next;
@@ -81,7 +79,51 @@ private:
};
-/*
+/**
+ A base class for a detached thread.
+*/
+
+class Thread
+{
+public:
+ enum enum_thread_type
+ {
+ DETACHED,
+ JOINABLE
+ };
+public:
+ Thread()
+ { }
+
+public:
+ inline bool is_detached() const;
+
+ bool start(enum_thread_type thread_type = JOINABLE);
+ bool join();
+
+protected:
+ virtual void run()= 0;
+ virtual ~Thread();
+
+private:
+ pthread_t id;
+ bool detached;
+
+private:
+ static void *thread_func(void *arg);
+
+private:
+ Thread(const Thread & /* rhs */); /* not implemented */
+ Thread &operator=(const Thread & /* rhs */); /* not implemented */
+};
+
+inline bool Thread::is_detached() const
+{
+ return detached;
+}
+
+
+/**
Thread_registry - contains handles for each worker thread to deliver
signal information to workers.
*/
@@ -92,7 +134,7 @@ public:
Thread_registry();
~Thread_registry();
- void register_thread(Thread_info *info);
+ void register_thread(Thread_info *info, bool send_signal_on_shutdown= TRUE);
void unregister_thread(Thread_info *info);
void deliver_shutdown();
void request_shutdown();
@@ -101,6 +143,7 @@ public:
pthread_mutex_t *mutex);
int cond_timedwait(Thread_info *info, pthread_cond_t *cond,
pthread_mutex_t *mutex, struct timespec *wait_time);
+
private:
void interrupt_threads();
void wait_for_threads_to_unregister();
@@ -111,6 +154,10 @@ private:
pthread_mutex_t LOCK_thread_registry;
pthread_cond_t COND_thread_registry_is_empty;
pthread_t sigwait_thread_pid;
+
+private:
+ Thread_registry(const Thread_registry &);
+ Thread_registry &operator =(const Thread_registry &);
};
diff --git a/server-tools/instance-manager/user_management_commands.cc b/server-tools/instance-manager/user_management_commands.cc
index 20ebeb0d6bf..a32a4e94415 100644
--- a/server-tools/instance-manager/user_management_commands.cc
+++ b/server-tools/instance-manager/user_management_commands.cc
@@ -20,7 +20,7 @@
This function must not be used in user-management command implementations.
Use get_user_name() instead.
- SYNOPSYS
+ SYNOPSIS
get_user_name_impl()
RETURN
@@ -58,7 +58,7 @@ static char *get_user_name_impl()
(not empty, not exceeds USERNAME_LENGTH). Report to stderr if something is
wrong.
- SYNOPSYS
+ SYNOPSIS
get_user_name()
user_name [OUT] on success contains user name
@@ -102,7 +102,7 @@ static bool get_user_name(LEX_STRING *user_name)
The password is retrieved from command-line options (if specified) or from
console.
- SYNOPSYS
+ SYNOPSIS
get_password()
RETURN
@@ -131,7 +131,7 @@ static const char *get_password()
/*
Load password file into user map.
- SYNOPSYS
+ SYNOPSIS
load_password_file()
user_map target user map
@@ -160,7 +160,7 @@ static int load_password_file(User_map *user_map)
/*
Save user map into password file.
- SYNOPSYS
+ SYNOPSIS
save_password_file()
user_map user map
diff --git a/server-tools/instance-manager/user_management_commands.h b/server-tools/instance-manager/user_management_commands.h
index 8d820be5ec7..17c11ccfef0 100644
--- a/server-tools/instance-manager/user_management_commands.h
+++ b/server-tools/instance-manager/user_management_commands.h
@@ -49,7 +49,7 @@ public:
/*
Executes user-management command.
- SYNOPSYS
+ SYNOPSIS
execute()
RETURN
@@ -65,7 +65,7 @@ public:
option.
*************************************************************************/
-class Print_password_line_cmd : public User_management_cmd
+class Print_password_line_cmd: public User_management_cmd
{
public:
Print_password_line_cmd()
@@ -80,7 +80,7 @@ public:
Add_user_cmd: support for --add-user command-line option.
*************************************************************************/
-class Add_user_cmd : public User_management_cmd
+class Add_user_cmd: public User_management_cmd
{
public:
Add_user_cmd()
@@ -95,7 +95,7 @@ public:
Drop_user_cmd: support for --drop-user command-line option.
*************************************************************************/
-class Drop_user_cmd : public User_management_cmd
+class Drop_user_cmd: public User_management_cmd
{
public:
Drop_user_cmd()
@@ -110,7 +110,7 @@ public:
Edit_user_cmd: support for --edit-user command-line option.
*************************************************************************/
-class Edit_user_cmd : public User_management_cmd
+class Edit_user_cmd: public User_management_cmd
{
public:
Edit_user_cmd()
@@ -125,7 +125,7 @@ public:
Clean_db_cmd: support for --clean-db command-line option.
*************************************************************************/
-class Clean_db_cmd : public User_management_cmd
+class Clean_db_cmd: public User_management_cmd
{
public:
Clean_db_cmd()
@@ -140,7 +140,7 @@ public:
Check_db_cmd: support for --check-db command-line option.
*************************************************************************/
-class Check_db_cmd : public User_management_cmd
+class Check_db_cmd: public User_management_cmd
{
public:
Check_db_cmd()
@@ -155,7 +155,7 @@ public:
List_users_cmd: support for --list-users command-line option.
*************************************************************************/
-class List_users_cmd : public User_management_cmd
+class List_users_cmd: public User_management_cmd
{
public:
List_users_cmd()
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index c1439e983d8..f3a6e3cd76c 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -41,8 +41,8 @@ int User::init(const char *line)
name_end= strchr(name_begin, line[0]);
if (name_end == 0 || name_end[1] != ':')
{
- log_info("Error: invalid format (unmatched quote) of user line (%s).",
- (const char *) line);
+ log_error("Invalid format (unmatched quote) of user line (%s).",
+ (const char *) line);
return 1;
}
password= name_end + 2;
@@ -53,8 +53,8 @@ int User::init(const char *line)
name_end= strchr(name_begin, ':');
if (name_end == 0)
{
- log_info("Error: invalid format (no delimiter) of user line (%s).",
- (const char *) line);
+ log_error("Invalid format (no delimiter) of user line (%s).",
+ (const char *) line);
return 1;
}
password= name_end + 1;
@@ -63,18 +63,19 @@ int User::init(const char *line)
user_length= name_end - name_begin;
if (user_length > USERNAME_LENGTH)
{
- log_info("Error: user name is too long (%d). Max length: %d. "
- "User line: '%s'.",
- (int) user_length,
- (int) USERNAME_LENGTH,
- (const char *) line);
+ log_error("User name is too long (%d). Max length: %d. "
+ "User line: '%s'.",
+ (int) user_length,
+ (int) USERNAME_LENGTH,
+ (const char *) line);
return 1;
}
password_length= strlen(password);
if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
{
- log_info("Error: password is too long (%d). Max length: %d. User line: '%s'.",
+ log_error("Password is too long (%d). Max length: %d."
+ "User line: '%s'.",
(int) password_length,
(int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
line);
@@ -89,7 +90,7 @@ int User::init(const char *line)
get_salt_from_password(salt, password);
- log_info("loaded user '%s'.", user);
+ log_info("Loaded user '%s'.", (const char *) user);
return 0;
}
@@ -158,7 +159,7 @@ User_map::~User_map()
/*
Load password database.
- SYNOPSYS
+ SYNOPSIS
load()
password_file_name [IN] password file path
err_msg [OUT] error message
@@ -185,7 +186,6 @@ int User_map::load(const char *password_file_name, const char **err_msg)
2 + /* for newline */
1]; /* for trailing zero */
User *user;
- int rc= 1;
if (my_access(password_file_name, F_OK) != 0)
{
@@ -214,7 +214,7 @@ int User_map::load(const char *password_file_name, const char **err_msg)
return ERR_IO_ERROR;
}
- log_info("loading the password database...");
+ log_info("Loading the password database...");
while (fgets(line, sizeof(line), file))
{
@@ -292,7 +292,7 @@ int User_map::load(const char *password_file_name, const char **err_msg)
}
}
- log_info("the password database loaded successfully.");
+ log_info("The password database loaded successfully.");
my_fclose(file, MYF(0));
diff --git a/server-tools/instance-manager/user_map.h b/server-tools/instance-manager/user_map.h
index de207c11e65..5325af12058 100644
--- a/server-tools/instance-manager/user_map.h
+++ b/server-tools/instance-manager/user_map.h
@@ -60,7 +60,7 @@ public:
{
public:
Iterator(User_map *user_map_arg) :
- cur_idx(0), user_map(user_map_arg)
+ user_map(user_map_arg), cur_idx(0)
{ }
public:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 39c63e9a46a..b1b73a523be 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2551,7 +2551,6 @@ void Item_func_in::fix_length_and_dec()
}
}
}
- maybe_null= args[0]->maybe_null;
max_length= 1;
}
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 7722ce28d4a..da8954910c8 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2612,15 +2612,8 @@ Create_func_benchmark Create_func_benchmark::s_singleton;
Item*
Create_func_benchmark::create(THD *thd, Item *arg1, Item *arg2)
{
- /* TODO: Known limitation, see Bug#22684 */
- if ((arg1->type() != Item::INT_ITEM) || ! arg1->basic_const_item())
- {
- my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "BENCHMARK");
- return NULL;
- }
-
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
- return new (thd->mem_root) Item_func_benchmark(arg1->val_int(), arg2);
+ return new (thd->mem_root) Item_func_benchmark(arg1, arg2);
}
@@ -2887,17 +2880,7 @@ Create_func_decode Create_func_decode::s_singleton;
Item*
Create_func_decode::create(THD *thd, Item *arg1, Item *arg2)
{
- /* TODO: Known limitation, see Bug#22684 */
- if ((arg2->type() != Item::STRING_ITEM) || ! arg2->basic_const_item())
- {
- my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "DECODE");
- return NULL;
- }
-
- String dummy;
- String *val = arg2->val_str(& dummy);
- DBUG_ASSERT(val);
- return new (thd->mem_root) Item_func_decode(arg1, val->c_ptr());
+ return new (thd->mem_root) Item_func_decode(arg1, arg2);
}
@@ -3033,17 +3016,7 @@ Create_func_encode Create_func_encode::s_singleton;
Item*
Create_func_encode::create(THD *thd, Item *arg1, Item *arg2)
{
- /* TODO: Known limitation, see Bug#22684 */
- if ((arg2->type() != Item::STRING_ITEM) || ! arg2->basic_const_item())
- {
- my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "ENCODE");
- return NULL;
- }
-
- String dummy;
- String *val = arg2->val_str(& dummy);
- DBUG_ASSERT(val);
- return new (thd->mem_root) Item_func_encode(arg1, val->c_ptr());
+ return new (thd->mem_root) Item_func_encode(arg1, arg2);
}
@@ -3235,14 +3208,7 @@ Create_func_format Create_func_format::s_singleton;
Item*
Create_func_format::create(THD *thd, Item *arg1, Item *arg2)
{
- /* TODO: Known limitation, see Bug#22684 */
- if ((arg2->type() != Item::INT_ITEM) || ! arg2->basic_const_item())
- {
- my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), "FORMAT");
- return NULL;
- }
-
- return new (thd->mem_root) Item_func_format(arg1, arg2->val_int());
+ return new (thd->mem_root) Item_func_format(arg1, arg2);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0cdf8c5a561..e658a70d7cb 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3424,18 +3424,28 @@ longlong Item_func_benchmark::val_int()
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), &my_charset_bin);
THD *thd=current_thd;
+ ulong loop_count;
+ loop_count= args[0]->val_int();
+
+ if (args[0]->null_value)
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ null_value=0;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
{
- switch (args[0]->result_type()) {
+ switch (args[1]->result_type()) {
case REAL_RESULT:
- (void) args[0]->val_real();
+ (void) args[1]->val_real();
break;
case INT_RESULT:
- (void) args[0]->val_int();
+ (void) args[1]->val_int();
break;
case STRING_RESULT:
- (void) args[0]->val_str(&tmp);
+ (void) args[1]->val_str(&tmp);
break;
case ROW_RESULT:
default:
@@ -3451,13 +3461,9 @@ longlong Item_func_benchmark::val_int()
void Item_func_benchmark::print(String *str)
{
str->append(STRING_WITH_LEN("benchmark("));
- char buffer[20];
- // my_charset_bin is good enough for numbers
- String st(buffer, sizeof(buffer), &my_charset_bin);
- st.set((ulonglong)loop_count, &my_charset_bin);
- str->append(st);
- str->append(',');
args[0]->print(str);
+ str->append(',');
+ args[1]->print(str);
str->append(')');
}
@@ -4873,6 +4879,7 @@ Item_func_sp::cleanup()
result_field= NULL;
}
m_sp= NULL;
+ dummy_table->alias= NULL;
Item_func::cleanup();
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 903179d48f5..5dca1705f9a 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -925,10 +925,9 @@ public:
class Item_func_benchmark :public Item_int_func
{
- ulong loop_count;
public:
- Item_func_benchmark(ulong loop_count_arg,Item *expr)
- :Item_int_func(expr), loop_count(loop_count_arg)
+ Item_func_benchmark(Item *count_expr, Item *expr)
+ :Item_int_func(count_expr, expr)
{}
longlong val_int();
const char *func_name() const { return "benchmark"; }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2a022d4af71..32b283fca57 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -80,6 +80,20 @@ String *Item_str_func::check_well_formed_result(String *str)
}
+bool Item_str_func::fix_fields(THD *thd, Item **ref)
+{
+ bool res= Item_func::fix_fields(thd, ref);
+ /*
+ In Item_str_func::check_well_formed_result() we may set null_value
+ flag on the same condition as in test() below.
+ */
+ maybe_null= (maybe_null ||
+ test(thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)));
+ return res;
+}
+
+
my_decimal *Item_str_func::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -1659,21 +1673,33 @@ String *Item_func_encrypt::val_str(String *str)
void Item_func_encode::fix_length_and_dec()
{
max_length=args[0]->max_length;
- maybe_null=args[0]->maybe_null;
+ maybe_null=args[0]->maybe_null || args[1]->maybe_null;
collation.set(&my_charset_bin);
}
String *Item_func_encode::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
String *res;
+ char pw_buff[80];
+ String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info);
+ String *password;
+ DBUG_ASSERT(fixed == 1);
+
if (!(res=args[0]->val_str(str)))
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
+
+ if (!(password=args[1]->val_str(& tmp_pw_value)))
+ {
+ null_value=1;
+ return 0;
+ }
+
null_value=0;
res=copy_if_not_alloced(str,res,res->length());
+ SQL_CRYPT sql_crypt(password->ptr());
sql_crypt.init();
sql_crypt.encode((char*) res->ptr(),res->length());
res->set_charset(&my_charset_bin);
@@ -1682,15 +1708,27 @@ String *Item_func_encode::val_str(String *str)
String *Item_func_decode::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
String *res;
+ char pw_buff[80];
+ String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info);
+ String *password;
+ DBUG_ASSERT(fixed == 1);
+
if (!(res=args[0]->val_str(str)))
{
null_value=1; /* purecov: inspected */
return 0; /* purecov: inspected */
}
+
+ if (!(password=args[1]->val_str(& tmp_pw_value)))
+ {
+ null_value=1;
+ return 0;
+ }
+
null_value=0;
res=copy_if_not_alloced(str,res,res->length());
+ SQL_CRYPT sql_crypt(password->ptr());
sql_crypt.init();
sql_crypt.decode((char*) res->ptr(),res->length());
return res;
@@ -1860,9 +1898,19 @@ String *Item_func_soundex::val_str(String *str)
** This should be 'internationalized' sometimes.
*/
-Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
+const int FORMAT_MAX_DECIMALS= 30;
+
+Item_func_format::Item_func_format(Item *org, Item *dec)
+: Item_str_func(org, dec)
+{
+}
+
+void Item_func_format::fix_length_and_dec()
{
- decimals=(uint) set_zone(dec,0,30);
+ collation.set(default_charset());
+ uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
+ max_length= ((char_length + (char_length-args[0]->decimals)/3) *
+ collation.collation->mbmaxlen);
}
@@ -1873,10 +1921,25 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
String *Item_func_format::val_str(String *str)
{
- uint32 length, str_length ,dec;
+ uint32 length;
+ uint32 str_length;
+ /* Number of decimal digits */
+ int dec;
+ /* Number of characters used to represent the decimals, including '.' */
+ uint32 dec_length;
int diff;
DBUG_ASSERT(fixed == 1);
- dec= decimals ? decimals+1 : 0;
+
+ dec= args[1]->val_int();
+ if (args[1]->null_value)
+ {
+ null_value=1;
+ return NULL;
+ }
+
+ dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS);
+ dec_length= dec ? dec+1 : 0;
+ null_value=0;
if (args[0]->result_type() == DECIMAL_RESULT ||
args[0]->result_type() == INT_RESULT)
@@ -1885,7 +1948,7 @@ String *Item_func_format::val_str(String *str)
res= args[0]->val_decimal(&dec_val);
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec);
+ my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec);
my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
str_length= str->length();
if (rnd_dec.sign())
@@ -1896,9 +1959,9 @@ String *Item_func_format::val_str(String *str)
double nr= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- nr= my_double_round(nr, decimals, FALSE);
+ nr= my_double_round(nr, dec, FALSE);
/* Here default_charset() is right as this is not an automatic conversion */
- str->set_real(nr,decimals, default_charset());
+ str->set_real(nr, dec, default_charset());
if (isnan(nr))
return str;
str_length=str->length();
@@ -1906,13 +1969,13 @@ String *Item_func_format::val_str(String *str)
str_length--; // Don't count sign
}
/* We need this test to handle 'nan' values */
- if (str_length >= dec+4)
+ if (str_length >= dec_length+4)
{
char *tmp,*pos;
- length= str->length()+(diff=((int)(str_length- dec-1))/3);
+ length= str->length()+(diff=((int)(str_length- dec_length-1))/3);
str= copy_if_not_alloced(&tmp_str,str,length);
str->length(length);
- tmp= (char*) str->ptr()+length - dec-1;
+ tmp= (char*) str->ptr()+length - dec_length-1;
for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--)
pos[0]= pos[-diff];
while (diff)
@@ -1936,12 +1999,8 @@ void Item_func_format::print(String *str)
{
str->append(STRING_WITH_LEN("format("));
args[0]->print(str);
- str->append(',');
- // my_charset_bin is good enough for numbers
- char buffer[20];
- String st(buffer, sizeof(buffer), &my_charset_bin);
- st.set((ulonglong)decimals, &my_charset_bin);
- str->append(st);
+ str->append(',');
+ args[1]->print(str);
str->append(')');
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 2adccd212b3..3b171b5d50f 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -37,6 +37,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
String *check_well_formed_result(String *str);
+ bool fix_fields(THD *thd, Item **ref);
};
class Item_func_md5 :public Item_str_func
@@ -360,11 +361,9 @@ public:
class Item_func_encode :public Item_str_func
{
- protected:
- SQL_CRYPT sql_crypt;
public:
- Item_func_encode(Item *a, char *seed):
- Item_str_func(a),sql_crypt(seed) {}
+ Item_func_encode(Item *a, Item *seed):
+ Item_str_func(a, seed) {}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "encode"; }
@@ -374,7 +373,7 @@ public:
class Item_func_decode :public Item_func_encode
{
public:
- Item_func_decode(Item *a, char *seed): Item_func_encode(a,seed) {}
+ Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {}
String *val_str(String *);
const char *func_name() const { return "decode"; }
};
@@ -507,15 +506,9 @@ class Item_func_format :public Item_str_func
{
String tmp_str;
public:
- Item_func_format(Item *org,int dec);
+ Item_func_format(Item *org, Item *dec);
String *val_str(String *);
- void fix_length_and_dec()
- {
- collation.set(default_charset());
- uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
- max_length= ((char_length + (char_length-args[0]->decimals)/3) *
- collation.collation->mbmaxlen);
- }
+ void fix_length_and_dec();
const char *func_name() const { return "format"; }
void print(String *);
};
@@ -530,9 +523,8 @@ public:
{ collation.set(cs); }
String *val_str(String *);
void fix_length_and_dec()
- {
- maybe_null=0;
- max_length=arg_count * collation.collation->mbmaxlen;
+ {
+ max_length= arg_count * collation.collation->mbmaxlen;
}
const char *func_name() const { return "char"; }
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index ea6a950f07c..cfa4b2ce16c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -322,9 +322,13 @@ void Item_sum::make_field(Send_field *tmp_field)
if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
{
((Item_field*) args[0])->field->make_field(tmp_field);
- tmp_field->db_name=(char*)"";
- tmp_field->org_table_name=tmp_field->table_name=(char*)"";
- tmp_field->org_col_name=tmp_field->col_name=name;
+ /* For expressions only col_name should be non-empty string. */
+ char *empty_string= (char*)"";
+ tmp_field->db_name= empty_string;
+ tmp_field->org_table_name= empty_string;
+ tmp_field->table_name= empty_string;
+ tmp_field->org_col_name= empty_string;
+ tmp_field->col_name= name;
if (maybe_null)
tmp_field->flags&= ~NOT_NULL_FLAG;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index db38753dc74..77679a9795e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -6326,6 +6326,16 @@ static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
+static int show_prepared_stmt_count(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_LONG;
+ var->value= buff;
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ *((long *)buff)= (long)prepared_stmt_count;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ return 0;
+}
+
static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
@@ -6736,6 +6746,7 @@ SHOW_VAR status_vars[]= {
{"Open_table_definitions", (char*) &show_table_definitions, SHOW_FUNC},
{"Open_tables", (char*) &show_open_tables, SHOW_FUNC},
{"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS},
+ {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_FUNC},
#ifdef HAVE_QUERY_CACHE
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_NOFLUSH},
{"Qcache_free_memory", (char*) &query_cache.free_memory, SHOW_LONG_NOFLUSH},
@@ -6915,6 +6926,7 @@ static void mysql_init_variables(void)
binlog_cache_use= binlog_cache_disk_use= 0;
max_used_connections= slow_launch_threads = 0;
mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0;
+ prepared_stmt_count= 0;
errmesg= 0;
mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS;
bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 980e60de502..daca62400e2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -155,7 +155,6 @@ static KEY_CACHE *create_key_cache(const char *name, uint length);
void fix_sql_mode_var(THD *thd, enum_var_type type);
static byte *get_error_count(THD *thd);
static byte *get_warning_count(THD *thd);
-static byte *get_prepared_stmt_count(THD *thd);
static byte *get_tmpdir(THD *thd);
static int sys_check_log_path(THD *thd, set_var *var);
static bool sys_update_general_log_path(THD *thd, set_var * var);
@@ -639,9 +638,6 @@ static sys_var_readonly sys_warning_count("warning_count",
OPT_SESSION,
SHOW_LONG,
get_warning_count);
-static sys_var_readonly sys_prepared_stmt_count("prepared_stmt_count",
- OPT_GLOBAL, SHOW_LONG,
- get_prepared_stmt_count);
/* alias for last_insert_id() to be compatible with Sybase */
#ifdef HAVE_REPLICATION
@@ -943,7 +939,6 @@ SHOW_VAR init_vars[]= {
{"plugin_dir", (char*) opt_plugin_dir, SHOW_CHAR},
{"port", (char*) &mysqld_port, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
- {sys_prepared_stmt_count.name, (char*) &sys_prepared_stmt_count, SHOW_SYS},
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size,
SHOW_SYS},
@@ -3138,14 +3133,6 @@ static byte *get_error_count(THD *thd)
return (byte*) &thd->sys_var_tmp.long_value;
}
-static byte *get_prepared_stmt_count(THD *thd)
-{
- pthread_mutex_lock(&LOCK_prepared_stmt_count);
- thd->sys_var_tmp.ulong_value= prepared_stmt_count;
- pthread_mutex_unlock(&LOCK_prepared_stmt_count);
- return (byte*) &thd->sys_var_tmp.ulong_value;
-}
-
/*
Get the tmpdir that was specified or chosen by default
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 3022967eeeb..5f9b9e6d563 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -6010,4 +6010,6 @@ ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000
eng "Incorrect parameter count in the call to native function '%-.64s'"
ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000
eng "Incorrect parameters in the call to native function '%-.64s'"
+ER_NATIVE_FCT_NAME_COLLISION
+ eng "This function '%-.64s' has the same name as a native function."
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 3362ec76fc2..a6e15c55641 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -737,7 +737,11 @@ void query_cache_end_of_result(THD *thd)
header->query()));
query_cache.wreck(__LINE__, "");
- BLOCK_UNLOCK_WR(query_block);
+ /*
+ We do not need call of BLOCK_UNLOCK_WR(query_block); here because
+ query_cache.wreck() switched query cache off but left content
+ untouched for investigation (it is debugging method).
+ */
goto end;
}
#endif
@@ -3523,7 +3527,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path,
#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK)
-void wreck(uint line, const char *message) {}
+void wreck(uint line, const char *message) { query_cache_size = 0; }
void bins_dump() {}
void cache_dump() {}
void queries_dump() {}
@@ -3535,6 +3539,17 @@ my_bool in_blocks(Query_cache_block * point) { return 0; }
#else
+
+/*
+ Debug method which switch query cache off but left content for
+ investigation.
+
+ SYNOPSIS
+ Query_cache::wreck()
+ line line of the wreck() call
+ message message for logging
+*/
+
void Query_cache::wreck(uint line, const char *message)
{
THD *thd=current_thd;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ca40dc9013a..47704570720 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -244,6 +244,12 @@ bool is_keyword(const char *name, uint len)
return get_hash_symbol(name,len,0)!=0;
}
+bool is_lex_native_function(const LEX_STRING *name)
+{
+ DBUG_ASSERT(name != NULL);
+ return (get_hash_symbol(name->str, name->length, 1) != 0);
+}
+
/* make a copy of token before ptr and set yytoklen */
static LEX_STRING get_token(LEX *lex,uint length)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index dd00018f5f8..3166928420a 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1235,4 +1235,6 @@ extern void lex_end(LEX *lex);
extern int MYSQLlex(void *arg, void *yythd);
extern const uchar *skip_rear_comments(const uchar *ubegin, const uchar *uend);
+extern bool is_lex_native_function(const LEX_STRING *name);
+
#endif /* MYSQL_SERVER */
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 8baf84585b2..e835de4dedd 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -107,7 +107,9 @@ const LEX_STRING trg_event_type_names[]=
};
-static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig);
+static int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST ** table);
class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
{
@@ -156,6 +158,13 @@ private:
*/
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
{
+ /*
+ FIXME: The code below takes too many different paths depending on the
+ 'create' flag, so that the justification for a single function
+ 'mysql_create_or_drop_trigger', compared to two separate functions
+ 'mysql_create_trigger' and 'mysql_drop_trigger' is not apparent.
+ This is a good candidate for a minor refactoring.
+ */
TABLE *table;
bool result= TRUE;
String stmt_query;
@@ -181,10 +190,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- if (!create &&
- !(tables= add_table_for_trigger(thd, thd->lex->spname)))
- DBUG_RETURN(TRUE);
-
/*
We don't allow creating triggers on tables in the 'mysql' schema
*/
@@ -194,30 +199,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- /* We should have only one table in table list. */
- DBUG_ASSERT(tables->next_global == 0);
-
- /*
- Check that the user has TRIGGER privilege on the subject table.
- */
- {
- bool err_status;
- TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
- thd->lex->query_tables_own_last= 0;
-
- err_status= check_table_access(thd, TRIGGER_ACL, tables, 0);
-
- thd->lex->query_tables_own_last= save_query_tables_own_last;
-
- if (err_status)
- DBUG_RETURN(TRUE);
- }
-
/*
There is no DETERMINISTIC clause for triggers, so can't check it.
But a trigger can in theory be used to do nasty things (if it supported
- DROP for example) so we do the check for privileges. Triggers have the
- same nature as functions regarding binlogging: their body is implicitely
+ DROP for example) so we do the check for privileges. For now there is
+ already a stronger test right above; but when this stronger test will
+ be removed, the test below will hold. Because triggers have the same
+ nature as functions regarding binlogging: their body is implicitly
binlogged, so they share the same danger, so trust_function_creators
applies to them too.
*/
@@ -228,24 +216,68 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- /* We do not allow creation of triggers on temporary tables. */
- if (create && find_temporary_table(thd, tables))
- {
- my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
- DBUG_RETURN(TRUE);
- }
-
/*
We don't want perform our operations while global read lock is held
- so we have to wait until its end and then prevent it from occuring
+ so we have to wait until its end and then prevent it from occurring
again until we are done. (Acquiring LOCK_open is not enough because
- global read lock is held without helding LOCK_open).
+ global read lock is held without holding LOCK_open).
*/
if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(TRUE);
VOID(pthread_mutex_lock(&LOCK_open));
+ if (!create)
+ {
+ bool if_exists= thd->lex->drop_if_exists;
+
+ if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
+ goto end;
+
+ if (!tables)
+ {
+ DBUG_ASSERT(if_exists);
+ /*
+ Since the trigger does not exist, there is no associated table,
+ and therefore :
+ - no TRIGGER privileges to check,
+ - no trigger to drop,
+ - no table to lock/modify,
+ so the drop statement is successful.
+ */
+ result= FALSE;
+ /* Still, we need to log the query ... */
+ stmt_query.append(thd->query, thd->query_length);
+ goto end;
+ }
+ }
+
+ /*
+ Check that the user has TRIGGER privilege on the subject table.
+ */
+ {
+ bool err_status;
+ TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
+ thd->lex->query_tables_own_last= 0;
+
+ err_status= check_table_access(thd, TRIGGER_ACL, tables, 0);
+
+ thd->lex->query_tables_own_last= save_query_tables_own_last;
+
+ if (err_status)
+ goto end;
+ }
+
+ /* We should have only one table in table list. */
+ DBUG_ASSERT(tables->next_global == 0);
+
+ /* We do not allow creation of triggers on temporary tables. */
+ if (create && find_temporary_table(thd, tables->db, tables->table_name))
+ {
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ goto end;
+ }
+
if (lock_table_names(thd, tables))
goto end;
@@ -1141,13 +1173,17 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
mysql_table_for_trigger()
thd - current thread context
trig - identifier for trigger
+ if_exists - treat a not existing trigger as a warning if TRUE
+ table - pointer to TABLE_LIST object for the table trigger (output)
RETURN VALUE
- 0 - error
- # - pointer to TABLE_LIST object for the table
+ 0 Success
+ 1 Error
*/
-static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
+static int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST **table)
{
LEX *lex= thd->lex;
char path_buff[FN_REFLEN];
@@ -1158,6 +1194,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
path_buff, &trigname.trigger_table);
DBUG_ENTER("add_table_for_trigger");
+ DBUG_ASSERT(table != NULL);
path.length= build_table_filename(path_buff, FN_REFLEN-1,
trig->m_db.str, trig->m_name.str,
@@ -1166,30 +1203,45 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
if (access(path_buff, F_OK))
{
+ if (if_exists)
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TRG_DOES_NOT_EXIST,
+ ER(ER_TRG_DOES_NOT_EXIST));
+ *table= NULL;
+ DBUG_RETURN(0);
+ }
+
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1)))
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
if (!is_equal(&trigname_file_type, parser->type()))
{
my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext+1,
"TRIGGERNAME");
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
if (parser->parse((gptr)&trigname, thd->mem_root,
trigname_file_parameters, 1,
&trigger_table_hook))
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
- DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
- trigname.trigger_table.str, TL_IGNORE));
+ *table= sp_add_to_query_tables(thd, lex, trig->m_db.str,
+ trigname.trigger_table.str, TL_IGNORE);
+
+ if (! *table)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f5ad6f1e278..ec3094ca721 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -97,6 +97,17 @@ void turn_parser_debug_on()
}
#endif
+static bool is_native_function(THD *thd, const LEX_STRING *name)
+{
+ if (find_native_function_builder(thd, *name))
+ return true;
+
+ if (is_lex_native_function(name))
+ return true;
+
+ return false;
+}
+
%}
%union {
int num;
@@ -1537,6 +1548,7 @@ sp_name:
create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
+ THD *thd= YYTHD;
LEX *lex=Lex;
if (lex->definer != NULL)
{
@@ -1549,6 +1561,12 @@ create_function_tail:
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
YYABORT;
}
+ if (is_native_function(thd, & lex->spname->m_name))
+ {
+ my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
+ lex->spname->m_name.str);
+ YYABORT;
+ }
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
lex->udf.returns=(Item_result) $2;
@@ -1637,6 +1655,7 @@ create_function_tail:
}
sp_proc_stmt
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -1644,15 +1663,50 @@ create_function_tail:
YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
- sp->init_strings(YYTHD, lex);
+ sp->init_strings(thd, lex);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
YYABORT;
}
+ if (is_native_function(thd, & sp->m_name))
+ {
+ /*
+ This warning will be printed when
+ [1] A client query is parsed,
+ [2] A stored function is loaded by db_load_routine.
+ Printing the warning for [2] is intentional, to cover the
+ following scenario:
+ - A user define a SF 'foo' using MySQL 5.N
+ - An application uses select foo(), and works.
+ - MySQL 5.{N+1} defines a new native function 'foo', as
+ part of a new feature.
+ - MySQL 5.{N+1} documentation is updated, and should mention
+ that there is a potential incompatible change in case of
+ existing stored function named 'foo'.
+ - The user deploys 5.{N+1}. At this point, 'select foo()'
+ means something different, and the user code is most likely
+ broken (it's only safe if the code is 'select db.foo()').
+ With a warning printed when the SF is loaded (which has to occur
+ before the call), the warning will provide a hint explaining
+ the root cause of a later failure of 'select foo()'.
+ With no warning printed, the user code will fail with no
+ apparent reason.
+ Printing a warning each time db_load_routine is executed for
+ an ambiguous function is annoying, since that can happen a lot,
+ but in practice should not happen unless there *are* name
+ collisions.
+ If a collision exists, it should not be silenced but fixed.
+ */
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NATIVE_FCT_NAME_COLLISION,
+ ER(ER_NATIVE_FCT_NAME_COLLISION),
+ sp->m_name.str);
+ }
/* Restore flag if it was cleared above */
- YYTHD->client_capabilities |= $<ulong_num>2;
- sp->restore_thd_mem_root(YYTHD);
+ thd->client_capabilities |= $<ulong_num>2;
+ sp->restore_thd_mem_root(thd);
}
;
@@ -7687,11 +7741,12 @@ drop:
Lex->spname= $4;
Lex->sql_command = SQLCOM_DROP_EVENT;
}
- | DROP TRIGGER_SYM sp_name
+ | DROP TRIGGER_SYM if_exists sp_name
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_TRIGGER;
- lex->spname= $3;
+ lex->drop_if_exists= $3;
+ lex->spname= $4;
}
| DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
{
@@ -7702,7 +7757,7 @@ drop:
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
- }
+ }
;
table_list:
@@ -8658,6 +8713,8 @@ load_data_lock:
Ignore this option in SP to avoid problem with query cache
*/
if (Lex->sphead != 0)
+ $$= YYTHD->update_lock_default;
+ else
#endif
$$= TL_WRITE_CONCURRENT_INSERT;
}
diff --git a/storage/ndb/config/type_kernel.mk.am b/storage/ndb/config/type_kernel.mk.am
index 1b9d49d8088..c2a602d4e19 100644
--- a/storage/ndb/config/type_kernel.mk.am
+++ b/storage/ndb/config/type_kernel.mk.am
@@ -2,7 +2,7 @@
INCLUDES += \
-I$(srcdir) \
-I$(top_builddir)/include \
- -I$(top_builddir)/ndb/include \
+ -I$(top_builddir)/storage/ndb/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/storage/ndb/include \
-I$(top_srcdir)/storage/ndb/src/kernel/vm \
diff --git a/storage/ndb/config/type_ndbapi.mk.am b/storage/ndb/config/type_ndbapi.mk.am
index 9e1b83c0cad..258322d6d9a 100644
--- a/storage/ndb/config/type_ndbapi.mk.am
+++ b/storage/ndb/config/type_ndbapi.mk.am
@@ -2,7 +2,7 @@
INCLUDES += \
-I$(srcdir) \
-I$(top_builddir)/include \
- -I$(top_builddir)/ndb/include \
+ -I$(top_builddir)/storage/ndb/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/mysys \
-I$(top_srcdir)/storage/ndb/include \
diff --git a/storage/ndb/config/type_ndbapitest.mk.am b/storage/ndb/config/type_ndbapitest.mk.am
index e385e7bc07e..9a5a7d5a778 100644
--- a/storage/ndb/config/type_ndbapitest.mk.am
+++ b/storage/ndb/config/type_ndbapitest.mk.am
@@ -7,7 +7,7 @@ LDADD += $(top_builddir)/storage/ndb/test/src/libNDBT.a \
INCLUDES += -I$(top_srcdir) \
-I$(top_builddir)/include \
- -I$(top_builddir)/ndb/include \
+ -I$(top_builddir)/storage/ndb/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/storage/ndb/include \
-I$(top_srcdir)/storage/ndb/include/ndbapi \
diff --git a/storage/ndb/config/type_ndbapitools.mk.am b/storage/ndb/config/type_ndbapitools.mk.am
index 1bb8339a390..6003489f46e 100644
--- a/storage/ndb/config/type_ndbapitools.mk.am
+++ b/storage/ndb/config/type_ndbapitools.mk.am
@@ -7,7 +7,7 @@ LDADD += \
INCLUDES += -I$(srcdir) \
-I$(top_builddir)/include \
- -I$(top_builddir)/ndb/include \
+ -I$(top_builddir)/storage/ndb/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/storage/ndb/include \
-I$(top_srcdir)/storage/ndb/include/ndbapi \
diff --git a/storage/ndb/config/type_util.mk.am b/storage/ndb/config/type_util.mk.am
index 02ce2cfc969..2ce75a2ce31 100644
--- a/storage/ndb/config/type_util.mk.am
+++ b/storage/ndb/config/type_util.mk.am
@@ -1,7 +1,7 @@
INCLUDES += -I$(srcdir) \
-I$(top_builddir)/include \
- -I$(top_builddir)/ndb/include \
+ -I$(top_builddir)/storage/ndb/include \
-I$(top_srcdir)/include \
-I$(top_srcdir)/mysys \
-I$(top_srcdir)/storage/ndb/include \
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 56b665b098e..d67ecb4c5e0 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -15541,6 +15541,151 @@ static void test_bug21726()
/*
+ BUG#23383: mysql_affected_rows() returns different values than
+ mysql_stmt_affected_rows()
+
+ Test that both mysql_affected_rows() and mysql_stmt_affected_rows()
+ return -1 on error, 0 when no rows were affected, and (positive) row
+ count when some rows were affected.
+*/
+static void test_bug23383()
+{
+ const char *insert_query= "INSERT INTO t1 VALUES (1), (2)";
+ const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3";
+ MYSQL_STMT *stmt;
+ my_ulonglong row_count;
+ int rc;
+
+ DBUG_ENTER("test_bug23383");
+ myheader("test_bug23383");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)");
+ myquery(rc);
+
+ rc= mysql_query(mysql, insert_query);
+ myquery(rc);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == 2);
+
+ rc= mysql_query(mysql, insert_query);
+ DIE_UNLESS(rc != 0);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == (my_ulonglong)-1);
+
+ rc= mysql_query(mysql, update_query);
+ myquery(rc);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == 0);
+
+ rc= mysql_query(mysql, "DELETE FROM t1");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+ DIE_UNLESS(stmt != 0);
+
+ rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == 2);
+
+ rc= mysql_stmt_execute(stmt);
+ DIE_UNLESS(rc != 0);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == (my_ulonglong)-1);
+
+ rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == 0);
+
+ rc= mysql_stmt_close(stmt);
+ check_execute(stmt, rc);
+
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ BUG#21635: MYSQL_FIELD struct's member strings seem to misbehave for
+ expression cols
+
+ Check that for MIN(), MAX(), COUNT() only MYSQL_FIELD::name is set
+ to either expression or its alias, and db, org_table, table,
+ org_name fields are empty strings.
+*/
+static void test_bug21635()
+{
+ const char *expr[]=
+ {
+ "MIN(i)", "MIN(i)",
+ "MIN(i) AS A1", "A1",
+ "MAX(i)", "MAX(i)",
+ "MAX(i) AS A2", "A2",
+ "COUNT(i)", "COUNT(i)",
+ "COUNT(i) AS A3", "A3",
+ };
+ char query[MAX_TEST_QUERY_LENGTH];
+ char *query_end;
+ MYSQL_RES *result;
+ MYSQL_FIELD *field;
+ unsigned int field_count, i;
+ int rc;
+
+ DBUG_ENTER("test_bug21635");
+ myheader("test_bug21635");
+
+ query_end= strxmov(query, "SELECT ", NullS);
+ for (i= 0; i < sizeof(expr) / sizeof(*expr) / 2; ++i)
+ query_end= strxmov(query_end, expr[i * 2], ", ", NullS);
+ query_end= strxmov(query_end - 2, " FROM t1 GROUP BY i", NullS);
+ DIE_UNLESS(query_end - query < MAX_TEST_QUERY_LENGTH);
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ myquery(rc);
+ rc= mysql_query(mysql, "CREATE TABLE t1 (i INT)");
+ myquery(rc);
+ rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
+ myquery(rc);
+
+ rc= mysql_real_query(mysql, query, query_end - query);
+ myquery(rc);
+
+ result= mysql_use_result(mysql);
+ DIE_UNLESS(result);
+
+ field_count= mysql_field_count(mysql);
+ for (i= 0; i < field_count; ++i)
+ {
+ field= mysql_fetch_field_direct(result, i);
+ printf("%s -> %s ... ", expr[i * 2], field->name);
+ fflush(stdout);
+ DIE_UNLESS(field->db[0] == 0 && field->org_table[0] == 0 &&
+ field->table[0] == 0 && field->org_name[0] == 0);
+ DIE_UNLESS(strcmp(field->name, expr[i * 2 + 1]) == 0);
+ puts("OK");
+ }
+
+ mysql_free_result(result);
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -15818,6 +15963,8 @@ static struct my_tests_st my_tests[]= {
{ "test_bug19671", test_bug19671 },
{ "test_bug21206", test_bug21206 },
{ "test_bug21726", test_bug21726 },
+ { "test_bug23383", test_bug23383 },
+ { "test_bug21635", test_bug21635 },
{ "test_status", test_status},
{ 0, 0 }
};