summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/collapsed2
-rwxr-xr-xBitKeeper/triggers/post-commit14
-rw-r--r--client/mysqlbinlog.cc15
-rw-r--r--configure.in3
-rw-r--r--include/m_ctype.h12
-rw-r--r--mysql-test/Makefile.am2
-rw-r--r--mysql-test/extra/binlog_tests/binlog.test13
-rw-r--r--mysql-test/extra/rpl_tests/rpl_deadlock.test42
-rw-r--r--mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test853
-rw-r--r--mysql-test/extra/rpl_tests/rpl_ndb_ddl.test507
-rw-r--r--mysql-test/include/strict_autoinc.inc4
-rw-r--r--mysql-test/install_test_db.sh17
-rw-r--r--mysql-test/mysql-test-run-shell.sh38
-rwxr-xr-xmysql-test/mysql-test-run.pl34
-rw-r--r--mysql-test/r/binlog_row_binlog.result26
-rw-r--r--mysql-test/r/binlog_stm_binlog.result20
-rw-r--r--mysql-test/r/ctype_recoding.result4
-rw-r--r--mysql-test/r/ctype_ucs.result22
-rw-r--r--mysql-test/r/ctype_utf8.result32
-rw-r--r--mysql-test/r/fulltext.result8
-rw-r--r--mysql-test/r/func_gconcat.result70
-rw-r--r--mysql-test/r/lowercase_table.result24
-rw-r--r--mysql-test/r/rpl_deadlock_innodb.result36
-rw-r--r--mysql-test/r/rpl_do_grant.result2
-rw-r--r--mysql-test/r/rpl_extraCol_innodb.result741
-rw-r--r--mysql-test/r/rpl_extraCol_myisam.result741
-rw-r--r--mysql-test/r/rpl_ignore_table.result16
-rw-r--r--mysql-test/r/rpl_ndb_dd_advance.result16
-rw-r--r--mysql-test/r/rpl_ndb_ddl.result25
-rw-r--r--mysql-test/r/rpl_ndb_extraCol.result742
-rw-r--r--mysql-test/r/rpl_packet.result17
-rw-r--r--mysql-test/r/strict_autoinc_1myisam.result1
-rw-r--r--mysql-test/r/strict_autoinc_2innodb.result1
-rw-r--r--mysql-test/r/strict_autoinc_3heap.result1
-rw-r--r--mysql-test/r/strict_autoinc_4bdb.result1
-rw-r--r--mysql-test/r/strict_autoinc_5ndb.result1
-rw-r--r--mysql-test/r/view.result19
-rw-r--r--mysql-test/r/xml.result73
-rw-r--r--mysql-test/t/ctype_ucs.test17
-rw-r--r--mysql-test/t/ctype_utf8.test24
-rw-r--r--mysql-test/t/func_gconcat.test35
-rw-r--r--mysql-test/t/lowercase_table.test20
-rw-r--r--mysql-test/t/rpl_do_grant.test10
-rw-r--r--mysql-test/t/rpl_extraCol_innodb-master.opt1
-rw-r--r--mysql-test/t/rpl_extraCol_innodb-slave.opt1
-rw-r--r--mysql-test/t/rpl_extraCol_innodb.test13
-rw-r--r--mysql-test/t/rpl_extraCol_myisam.test12
-rw-r--r--mysql-test/t/rpl_ignore_table-slave.opt2
-rw-r--r--mysql-test/t/rpl_ignore_table.test24
-rw-r--r--mysql-test/t/rpl_ndb_dd_advance.test16
-rw-r--r--mysql-test/t/rpl_ndb_ddl.test3
-rw-r--r--mysql-test/t/rpl_ndb_extraCol.test13
-rw-r--r--mysql-test/t/rpl_packet-master.opt1
-rw-r--r--mysql-test/t/rpl_packet-slave.opt1
-rw-r--r--mysql-test/t/rpl_packet.test39
-rw-r--r--mysql-test/t/view.test19
-rw-r--r--mysql-test/t/windows.test1
-rw-r--r--mysql-test/t/xml.test30
-rw-r--r--scripts/make_binary_distribution.sh1
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/field.cc354
-rw-r--r--sql/field.h7
-rw-r--r--sql/ha_ndbcluster.cc179
-rw-r--r--sql/ha_ndbcluster_binlog.cc1
-rw-r--r--sql/handler.cc35
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h12
-rw-r--r--sql/item_sum.cc23
-rw-r--r--sql/item_xmlfunc.cc16
-rw-r--r--sql/log.cc12
-rw-r--r--sql/log_event.cc196
-rw-r--r--sql/log_event.h22
-rw-r--r--sql/mysql_priv.h11
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/parse_file.cc23
-rw-r--r--sql/repl_failsafe.cc2
-rw-r--r--sql/rpl_injector.cc2
-rw-r--r--sql/rpl_mi.cc386
-rw-r--r--sql/rpl_mi.h110
-rw-r--r--sql/rpl_rli.cc1112
-rw-r--r--sql/rpl_rli.h29
-rw-r--r--sql/slave.cc1514
-rw-r--r--sql/slave.h117
-rw-r--r--sql/sql_binlog.cc12
-rw-r--r--sql/sql_class.cc244
-rw-r--r--sql/sql_parse.cc20
-rw-r--r--sql/sql_repl.cc16
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_show.cc3
-rw-r--r--sql/sql_string.cc156
-rw-r--r--sql/sql_string.h8
-rw-r--r--sql/sql_view.cc35
-rw-r--r--storage/federated/ha_federated.cc2
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/myisam/mi_key.c15
-rw-r--r--storage/myisam/mi_open.c2
-rw-r--r--storage/ndb/src/ndbapi/Ndbinit.cpp7
-rw-r--r--storage/ndb/src/ndbapi/TransporterFacade.cpp2
-rw-r--r--strings/ctype-bin.c3
-rw-r--r--strings/ctype-mb.c24
-rw-r--r--strings/ctype-simple.c18
-rw-r--r--strings/ctype-ucs2.c8
-rw-r--r--strings/ctype-utf8.c136
-rw-r--r--support-files/mysql.spec.sh12
-rw-r--r--unittest/README.txt6
-rw-r--r--unittest/mytap/Doxyfile47
-rw-r--r--unittest/mytap/tap.c267
-rw-r--r--unittest/mytap/tap.h28
109 files changed, 7449 insertions, 2282 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed
index 2509fa50a7b..5ff033b2163 100644
--- a/BitKeeper/etc/collapsed
+++ b/BitKeeper/etc/collapsed
@@ -15,6 +15,8 @@
45214442pBGT9KuZEGixBH71jTzbOA
45214a07hVsIGwvwa-WrO-jpeaSwVw
452a92d0-31-8wSzSfZi165fcGcXPA
+452c6c6dAjuNghfc1ObZ_UQ5SCl85g
+4538a7b0EbDHHkWPbIwxO6ZIDdg6Dg
454a7ef8gdvE_ddMlJyghvOAkKPNOQ
454bb488ijVLOUK_GFjcoISE0GxPUA
454bb9a8AwlGRC_wWLS2sNMoRBMRGw
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit
index f7b00625264..86f3db012ee 100755
--- a/BitKeeper/triggers/post-commit
+++ b/BitKeeper/triggers/post-commit
@@ -35,9 +35,17 @@ fi
CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet`
CSETKEY=`bk -R prs -r+ -h -d':KEY:' ChangeSet`
-BUG=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Bb][Uu][Gg] *# *\([0-9][0-9]*\).*$/\1/p'`
-WL=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Ww][Ll] *# *\([0-9][0-9]*\).*$/ WL#\1/p'`
-
+#
+# composing subject lines of commit mails.
+# if a fix targets to a WL and there is a bug referred
+# then X-Bug mail header will contain the first found bug's number
+#
+BUG=`bk -R prs -r+ -h -d':C:' ChangeSet | \
+ sed -ne 's/[Bb][Uu][Gg] *# *\([0-9][0-9]*\).*$/BUG#\1/
+ s/.*BUG#\([0-9][0-9]*\)/\1/p'`
+WL=`bk -R prs -r+ -h -d':C:' ChangeSet | \
+ sed -ne 's/[Ww][Ll] *# *\([0-9][0-9]*\).*$/WL#\1/
+ s/.*\(WL#[0-9][0-9]*\)/ \1/p'`
if [ "$BUG" = "" ]
then
TO=dev-public@mysql.com
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index ab94c415db7..660be6bce50 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -1360,6 +1360,21 @@ static int dump_local_log_entries(const char* logname)
}
else // reading from stdin;
{
+ /*
+ Windows opens stdin in text mode by default. Certain characters
+ such as CTRL-Z are interpeted as events and the read() method
+ will stop. CTRL-Z is the EOF marker in Windows. to get past this
+ you have to open stdin in binary mode. Setmode() is used to set
+ stdin in binary mode. Errors on setting this mode result in
+ halting the function and printing an error message to stderr.
+ */
+#if defined (__WIN__) || (_WIN64)
+ if (_setmode(fileno(stdin), O_BINARY) == -1)
+ {
+ fprintf(stderr, "Could not set binary mode on stdin.\n");
+ return 1;
+ }
+#endif
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
return 1;
diff --git a/configure.in b/configure.in
index 18fe2a6ce87..6388e5836d6 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
-AM_INIT_AUTOMAKE(mysql, 5.1.13-beta)
+AM_INIT_AUTOMAKE(mysql, 5.1.14-beta)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@@ -15,7 +15,6 @@ DOT_FRM_VERSION=6
# See the libtool docs for information on how to do shared lib versions.
SHARED_LIB_MAJOR_VERSION=15
SHARED_LIB_VERSION=$SHARED_LIB_MAJOR_VERSION:0:0
-
# Set all version vars based on $VERSION. How do we do this more elegant ?
# Remember that regexps needs to quote [ and ] since this is run through m4
MYSQL_NO_DASH_VERSION=`echo $VERSION | sed -e "s|[[a-z]]*-.*$||"`
diff --git a/include/m_ctype.h b/include/m_ctype.h
index 5f946a3b443..0d586030735 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -190,8 +190,8 @@ typedef struct my_charset_handler_st
const unsigned char *s, const unsigned char *e);
/* Functions for case and sort conversion */
- void (*caseup_str)(struct charset_info_st *, char *);
- void (*casedn_str)(struct charset_info_st *, char *);
+ uint (*caseup_str)(struct charset_info_st *, char *);
+ uint (*casedn_str)(struct charset_info_st *, char *);
uint (*caseup)(struct charset_info_st *, char *src, uint srclen,
char *dst, uint dstlen);
uint (*casedn)(struct charset_info_st *, char *src, uint srclen,
@@ -324,8 +324,8 @@ extern uint my_instr_simple(struct charset_info_st *,
/* Functions for 8bit */
-extern void my_caseup_str_8bit(CHARSET_INFO *, char *);
-extern void my_casedn_str_8bit(CHARSET_INFO *, char *);
+extern uint my_caseup_str_8bit(CHARSET_INFO *, char *);
+extern uint my_casedn_str_8bit(CHARSET_INFO *, char *);
extern uint my_caseup_8bit(CHARSET_INFO *, char *src, uint srclen,
char *dst, uint dstlen);
extern uint my_casedn_8bit(CHARSET_INFO *, char *src, uint srclen,
@@ -415,8 +415,8 @@ int my_mbcharlen_8bit(CHARSET_INFO *, uint c);
/* Functions for multibyte charsets */
-extern void my_caseup_str_mb(CHARSET_INFO *, char *);
-extern void my_casedn_str_mb(CHARSET_INFO *, char *);
+extern uint my_caseup_str_mb(CHARSET_INFO *, char *);
+extern uint my_casedn_str_mb(CHARSET_INFO *, char *);
extern uint my_caseup_mb(CHARSET_INFO *, char *src, uint srclen,
char *dst, uint dstlen);
extern uint my_casedn_mb(CHARSET_INFO *, char *src, uint srclen,
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index f0bc1e9b20a..e8f00902a33 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -59,6 +59,7 @@ dist-hook:
-$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.opt $(distdir)/extra/binlog_tests
-$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.opt $(distdir)/extra/rpl_tests
$(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include
+ $(INSTALL_DATA) $(srcdir)/include/*.test $(distdir)/include
$(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data
@@ -98,6 +99,7 @@ install-data-local:
-$(INSTALL_DATA) $(srcdir)/extra/binlog_tests/*.opt $(DESTDIR)$(testdir)/extra/binlog_tests
-$(INSTALL_DATA) $(srcdir)/extra/rpl_tests/*.opt $(DESTDIR)$(testdir)/extra/rpl_tests
$(INSTALL_DATA) $(srcdir)/include/*.inc $(DESTDIR)$(testdir)/include
+ $(INSTALL_DATA) $(srcdir)/include/*.test $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.*001 $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data
diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test
index 81c813e78d0..48d9b859c26 100644
--- a/mysql-test/extra/binlog_tests/binlog.test
+++ b/mysql-test/extra/binlog_tests/binlog.test
@@ -59,4 +59,17 @@ insert into t1 values(null);
select * from t1;
drop table t1;
+# bug#22027
+create table t1 (a int);
+create table if not exists t2 select * from t1;
+
+# bug#22762
+create temporary table tt1 (a int);
+create table if not exists t3 like tt1;
+
+--replace_column 2 # 5 #
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
+show binlog events from 102;
+drop table t1,t2,t3,tt1;
+
-- source extra/binlog_tests/binlog_insert_delayed.test
diff --git a/mysql-test/extra/rpl_tests/rpl_deadlock.test b/mysql-test/extra/rpl_tests/rpl_deadlock.test
index adf35a92dc6..236a5f801b0 100644
--- a/mysql-test/extra/rpl_tests/rpl_deadlock.test
+++ b/mysql-test/extra/rpl_tests/rpl_deadlock.test
@@ -15,7 +15,8 @@
connection master;
eval CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=$engine_type;
eval CREATE TABLE t2 (a INT NOT NULL, KEY(a)) ENGINE=$engine_type;
-eval CREATE TABLE t3 (a INT) ENGINE=$engine_type;
+# requiring 'unique' for the timeout part of the test
+eval CREATE TABLE t3 (a INT UNIQUE) ENGINE=$engine_type;
eval CREATE TABLE t4 (a INT) ENGINE=$engine_type;
show variables like 'slave_transaction_retries';
sync_slave_with_master;
@@ -30,7 +31,9 @@ stop slave;
connection master;
begin;
# Let's keep BEGIN and the locked statement in two different relay logs.
-let $1=200;
+insert into t2 values (0); # t2,t1 actors of deadlock in repl-ed ta
+#insert into t3 select * from t2 for update;
+let $1=10;
disable_query_log;
while ($1)
{
@@ -38,16 +41,14 @@ while ($1)
dec $1;
}
enable_query_log;
-insert into t3 select * from t2 for update;
insert into t1 values(1);
commit;
save_master_pos;
connection slave;
begin;
-# Let's make our transaction large so that it's slave who is chosen as
-# victim
-let $1=1000;
+# Let's make our transaction large so that it's repl-ed msta that's victim
+let $1=100;
disable_query_log;
while ($1)
{
@@ -55,14 +56,21 @@ while ($1)
dec $1;
}
enable_query_log;
-select * from t1 for update;
+select * from t1 for update; # t1,t2 on local slave's
start slave;
+
+# bad option, todo: replicate a non-transactional t_sync with the transaction
+# and use wait_until_rows_count macro below
--real_sleep 3 # hope that slave is blocked now
-insert into t2 values(22); # provoke deadlock, slave should be victim
+#let $count=11;
+#let $table=t_sync;
+#--include wait_until_rows_count.inc
+
+select * from t2 for update /* dl */; # provoke deadlock, repl-ed should be victim
commit;
sync_with_master;
-select * from t1; # check that slave succeeded finally
-select * from t2;
+select * from t1; # check that repl-ed succeeded finally
+select * from t2 /* must be 1 */;
# check that no error is reported
--replace_column 1 # 7 # 8 # 9 # 16 # 22 # 23 # 33 #
--replace_result $MASTER_MYPORT MASTER_MYPORT
@@ -73,14 +81,16 @@ show slave status;
# 2) Test lock wait timeout
stop slave;
-change master to master_log_pos=536; # the BEGIN log event
+delete from t3;
+change master to master_log_pos=544; # the BEGIN log event
begin;
select * from t2 for update; # hold lock
start slave;
---real_sleep 10 # slave should have blocked, and be retrying
+--real_sleep 10 # repl-ed should have blocked, and be retrying
+select count(*) from t3 /* must be zero */; # replaying begins after rollback
commit;
sync_with_master;
-select * from t1; # check that slave succeeded finally
+select * from t1; # check that repl-ed succeeded finally
select * from t2;
# check that no error is reported
--replace_column 1 # 7 # 8 # 9 # 11 # 16 # 22 # 23 # 33 #
@@ -96,11 +106,13 @@ set global max_relay_log_size=0;
# This is really copy-paste of 2) of above
stop slave;
-change master to master_log_pos=536;
+delete from t3;
+change master to master_log_pos=544;
begin;
select * from t2 for update;
start slave;
--real_sleep 10
+select count(*) from t3 /* must be zero */; # replaying begins after rollback
commit;
sync_with_master;
select * from t1;
@@ -116,4 +128,4 @@ drop table t1,t2,t3,t4;
sync_slave_with_master;
set global max_relay_log_size= @my_max_relay_log_size;
-# End of 4.1 tests
+--echo End of 5.1 tests
diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test
new file mode 100644
index 00000000000..34e01b7a675
--- /dev/null
+++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test
@@ -0,0 +1,853 @@
+#################################################
+# Author: Jeb
+# Date: 2006-09-07
+# Purpose: To test having extra columns on the slave.
+##################################################
+
+########### Clean up ################
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17;
+--enable_query_log
+--enable_warnings
+
+#################################################
+############ Different Table Def Test ###########
+#################################################
+# Purpose: To have different table def on the #
+# master and slave. Most of these tests#
+# should stop the slave. #
+#################################################
+
+--echo **** Diff Table Def Start ****
+
+##############################################
+### Try to replicate w/ PK on diff columns ###
+### Should Stop Slave ###
+##############################################
+
+--echo *** On Slave ***
+sync_slave_with_master;
+STOP SLAVE;
+RESET SLAVE;
+
+eval CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20),
+ d FLOAT DEFAULT '2.00',
+ e CHAR(4) DEFAULT 'TEST')
+ ENGINE=$engine_type;
+
+--echo *** Create t1 on Master ***
+connection master;
+eval CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(10)
+ ) ENGINE=$engine_type;
+
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+INSERT INTO t1 () VALUES(1,2,'TEXAS'),(2,1,'AUSTIN'),(3,4,'QA');
+SELECT * FROM t1 ORDER BY a;
+
+--echo *** Select from slave ***
+sync_slave_with_master;
+SELECT * FROM t1 ORDER BY a;
+
+--echo *** Drop t1 ***
+connection master;
+DROP TABLE t1;
+sync_slave_with_master;
+
+############################################
+### Try to replicate CHAR(10) to CHAR(5) ###
+### Should Stop Slave or truncate value ###
+############################################
+
+## BUG22086
+#--echo *** Create t2 on slave ***
+#STOP SLAVE;
+#RESET SLAVE;
+#eval CREATE TABLE t2 (a INT, b INT PRIMARY KEY, c CHAR(5),
+# d FLOAT DEFAULT '2.00',
+# e CHAR(5) DEFAULT 'TEST2')
+# ENGINE=$engine_type;
+#
+#--echo *** Create t2 on Master ***
+#connection master;
+#eval CREATE TABLE t2 (a INT PRIMARY KEY, b INT, c CHAR(10)
+# ) ENGINE=$engine_type;
+#RESET MASTER;
+#
+#--echo *** Start Slave ***
+#connection slave;
+#START SLAVE;
+#
+#--echo *** Master Data Insert ***
+#connection master;
+#
+#INSERT INTO t2 () VALUES(1,2,'Kyle, TEX'),(2,1,'JOE AUSTIN'),(3,4,'QA TESTING');
+#SELECT * FROM t2 ORDER BY a;
+
+#--echo *** Select from slave ***
+#sync_slave_with_master;
+#SELECT * FROM t2 ORDER BY a;
+
+#--echo *** Drop t2 ***
+#connection master;
+#DROP TABLE t2;
+#sync_slave_with_master;
+
+####################################
+### Try to replicate BLOB to INT ###
+### Should Stop Slave ###
+####################################
+--echo *** Create t3 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t3 (a INT, b INT PRIMARY KEY, c CHAR(20),
+ d FLOAT DEFAULT '2.00',
+ e CHAR(5) DEFAULT 'TEST2')
+ ENGINE=$engine_type;
+
+--echo *** Create t3 on Master ***
+connection master;
+eval CREATE TABLE t3 (a BLOB, b INT PRIMARY KEY, c CHAR(20)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+
+INSERT INTO t3 () VALUES(@b1,2,'Kyle, TEX'),(@b1,1,'JOE AUSTIN'),(@b1,4,'QA TESTING');
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Drop t3 ***
+connection master;
+DROP TABLE t3;
+sync_slave_with_master;
+
+#####################################################
+# Columns with different types, more columns at end #
+# Expect: proper error message (wrong types) #
+#####################################################
+
+--echo *** Create t4 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t4 (a INT, b INT PRIMARY KEY, c CHAR(20),
+ d FLOAT DEFAULT '2.00',
+ e CHAR(5) DEFAULT 'TEST2')
+ ENGINE=$engine_type;
+
+--echo *** Create t4 on Master ***
+connection master;
+eval CREATE TABLE t4 (a DECIMAL(8,2), b INT PRIMARY KEY, c CHAR(20)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+INSERT INTO t4 () VALUES(100.22,2,'Kyle, TEX'),(200.26,1,'JOE AUSTIN'),
+ (30000.22,4,'QA TESTING');
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Drop t4 ***
+connection master;
+DROP TABLE t4;
+sync_slave_with_master;
+
+#######################################################
+# Columns with different types, same number of colums #
+# Expect: Proper error message #
+#######################################################
+
+--echo *** Create t5 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t5 (a INT PRIMARY KEY, b CHAR(5),
+ c FLOAT, d INT, e DOUBLE,
+ f DECIMAL(8,2))ENGINE=$engine_type;
+
+--echo *** Create t5 on Master ***
+connection master;
+eval CREATE TABLE t5 (a INT PRIMARY KEY, b VARCHAR(6),
+ c DECIMAL(8,2), d BIT, e BLOB,
+ f FLOAT) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
+ (2,'JOE',300.01,0,'b2b2',1.0000009);
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Drop t5 ***
+connection master;
+DROP TABLE t5;
+sync_slave_with_master;
+
+#######################################################
+################## Continued ##########################
+#######################################################
+# Columns with different types, same number of colums #
+# Expect: Proper error message #
+#######################################################
+
+--echo *** Create t6 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t6 (a INT PRIMARY KEY, b CHAR(5),
+ c FLOAT, d INT)ENGINE=$engine_type;
+
+--echo *** Create t6 on Master ***
+connection master;
+eval CREATE TABLE t6 (a INT PRIMARY KEY, b VARCHAR(6),
+ c DECIMAL(8,2), d BIT
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
+ (2,'JOE',300.01,0);
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3;
+#START SLAVE;
+
+--echo *** Drop t6 ***
+connection master;
+DROP TABLE t6;
+connection slave;
+DROP TABLE t6;
+START SLAVE;
+#sync_slave_with_master;
+
+
+--echo **** Diff Table Def End ****
+
+#######################################
+#### Extra Column on Slave Testing ####
+#######################################
+# Purpose: To test extra colums on the#
+# Slave #
+#######################################
+
+--echo **** Extra Colums Start ****
+
+##########################################
+# More columns in slave at end of table, #
+# added columns have default values #
+# Expect: it should work, default values #
+# should be used #
+##########################################
+
+--echo *** Create t7 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t7 (a INT KEY, b BLOB, c CHAR(5),
+ d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+ e CHAR(20) DEFAULT 'Extra Column Testing')
+ ENGINE=$engine_type;
+
+--echo *** Create t7 on Master ***
+connection master;
+eval CREATE TABLE t7 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t7 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t7 ORDER BY a;
+
+--echo *** Select from slave ***
+sync_slave_with_master;
+SELECT * FROM t7 ORDER BY a;
+
+--echo *** Drop t7 ***
+connection master;
+DROP TABLE t7;
+sync_slave_with_master;
+
+###########################################
+# More columns in slave at end of table, #
+# added columns do not have default values#
+# Expect: Proper error message #
+###########################################
+# NOTE: This should fail but currently #
+# works. BUG#22101 #
+###########################################
+--echo *** Create t8 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t8 (a INT KEY, b BLOB, c CHAR(5),
+ d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+ e INT)ENGINE=$engine_type;
+
+--echo *** Create t8 on Master ***
+connection master;
+eval CREATE TABLE t8 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t8 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+
+### Uncomment once bug is fixed
+
+#connection slave;
+#wait_for_slave_to_stop;
+#--replace_result $MASTER_MYPORT MASTER_PORT
+#--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+#--query_vertical SHOW SLAVE STATUS
+#SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+#START SLAVE;
+
+--echo *** Drop t8 ***
+connection master;
+DROP TABLE t8;
+sync_slave_with_master;
+
+###########################################
+############# Continued ###################
+# More columns in slave at end of table, #
+# added columns do not have default values#
+# Expect: Proper error message #
+###########################################
+# Commented out due to Bug #23907 Extra Slave Col is not
+# erroring on extra col with no default values.
+########################################################
+#--echo *** Create t9 on slave ***
+#STOP SLAVE;
+#RESET SLAVE;
+#eval CREATE TABLE t9 (a INT KEY, b BLOB, c CHAR(5),
+# d TIMESTAMP,
+# e INT DEFAULT '1')ENGINE=$engine_type;
+
+#--echo *** Create t9 on Master ***
+#connection master;
+#eval CREATE TABLE t9 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+# ) ENGINE=$engine_type;
+#RESET MASTER;
+
+#--echo *** Start Slave ***
+#connection slave;
+#START SLAVE;
+
+#--echo *** Master Data Insert ***
+#connection master;
+#set @b1 = 'b1b1b1b1';
+#set @b1 = concat(@b1,@b1);
+#INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+
+#--echo *************************************************
+#--echo ** Currently giving wrong error see bug#22234 ***
+#--echo *************************************************
+#sync_slave_with_master;
+#connection slave;
+
+#--echo *** Select from T9 ***
+#wait_for_slave_to_stop;
+#--replace_result $MASTER_MYPORT MASTER_PORT
+#--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+#--query_vertical SHOW SLAVE STATUS
+#SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+#START SLAVE;
+
+#--echo *** Drop t9 ***
+#connection master;
+#DROP TABLE t9;
+#sync_slave_with_master;
+
+############################################
+# More columns in slave at middle of table #
+# Expect: Proper error message #
+############################################
+--echo *** Create t10 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233',
+ c CHAR(5), e INT DEFAULT '1')ENGINE=$engine_type;
+
+--echo *** Create t10 on Master ***
+connection master;
+eval CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Drop t10 ***
+connection master;
+DROP TABLE t10;
+sync_slave_with_master;
+
+############################################
+############## Continued ###################
+############################################
+# More columns in slave at middle of table #
+# Expect: Proper error message #
+############################################
+--echo *** Create t11 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT,
+ c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE=$engine_type;
+
+--echo *** Create t11 on Master ***
+connection master;
+eval CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Drop t11 ***
+connection master;
+DROP TABLE t11;
+sync_slave_with_master;
+
+############################################
+############## Continued ###################
+############################################
+# More columns in slave at middle of table #
+# Expect: This one should pass blob-text #
+############################################
+--echo *** Create t12 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT,
+ c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE=$engine_type;
+
+--echo *** Create t12 on Master ***
+connection master;
+eval CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t12 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t12 ORDER BY a;
+
+--echo *** Select on Slave ***
+sync_slave_with_master;
+SELECT * FROM t12 ORDER BY a;
+
+--echo *** Drop t12 ***
+connection master;
+DROP TABLE t12;
+sync_slave_with_master;
+
+--echo **** Extra Colums End ****
+
+###############################
+# BUG#22177 CURRENT_TIMESTAMP #
+# Sould work with ^ #
+###############################
+--echo *** BUG 22177 Start ***
+--echo *** Create t13 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t13 (a INT KEY, b BLOB, c CHAR(5),
+ d INT DEFAULT '1',
+ e TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+ )ENGINE=$engine_type;
+
+--echo *** Create t13 on Master ***
+connection master;
+eval CREATE TABLE t13 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t13 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t13 ORDER BY a;
+
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 5 CURRENT_TIMESTAMP
+SELECT * FROM t13 ORDER BY a;
+
+--echo *** Drop t13 ***
+connection master;
+DROP TABLE t13;
+sync_slave_with_master;
+
+--echo *** 22117 END ***
+
+##############################
+# ALTER MASTER TABLE TESTING #
+##############################
+
+--echo *** Alter Master Table Testing Start ***
+
+####################################################
+# - Alter Master adding columns at middle of table #
+# Expect: columns added #
+####################################################
+
+--echo *** Create t14 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+ c6 INT DEFAULT '1',
+ c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+ )ENGINE=$engine_type;
+
+--echo *** Create t14 on Master ***
+connection master;
+eval CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1;
+ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+ (2,2.00,'This Test Should work',@b1,'JOE'),
+ (3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t14 ORDER BY c1;
+
+
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 7 CURRENT_TIMESTAMP
+SELECT * FROM t14 ORDER BY c1;
+
+
+####################################################
+# - Alter Master Dropping columns from the middle. #
+# Expect: columns dropped #
+####################################################
+
+--echo *** connect to master and drop columns ***
+connection master;
+ALTER TABLE t14 DROP COLUMN c2;
+ALTER TABLE t14 DROP COLUMN c4;
+--echo *** Select from Master ***
+SELECT * FROM t14 ORDER BY c1;
+
+--echo *** Select from Slave ***
+sync_slave_with_master;
+--replace_column 5 CURRENT_TIMESTAMP
+SELECT * FROM t14 ORDER BY c1;
+
+--echo *** Drop t14 ***
+connection master;
+DROP TABLE t14;
+sync_slave_with_master;
+
+##############################################################
+# - Alter Master adding columns that already exist on slave. #
+# Expect: proper error message #
+##############################################################
+
+--echo *** Create t15 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t15 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+ c4 BLOB, c5 CHAR(5),
+ c6 INT DEFAULT '1',
+ c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+ )ENGINE=$engine_type;
+
+--echo *** Create t15 on Master ***
+connection master;
+eval CREATE TABLE t15 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+ c4 BLOB, c5 CHAR(5)) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t15 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+ (2,2.00,'This Test Should work',@b1,'JOE'),
+ (3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t15 ORDER BY c1;
+
+
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 7 CURRENT_TIMESTAMP
+SELECT * FROM t15 ORDER BY c1;
+
+--echo *** Add column on master that is a Extra on Slave ***
+connection master;
+ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5;
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1060 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo *** Try to insert in master ****
+connection master;
+INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
+SELECT * FROM t15 ORDER BY c1;
+
+--echo *** Try to select from slave ****
+sync_slave_with_master;
+--replace_column 7 CURRENT_TIMESTAMP
+SELECT * FROM t15 ORDER BY c1;
+
+--echo *** DROP TABLE t15 ***
+connection master;
+DROP TABLE t15;
+sync_slave_with_master;
+
+####################################
+# - Alter Master and ADD PARTITION #
+# Expect:? #
+####################################
+
+--echo *** Create t16 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t16 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+ c4 BLOB, c5 CHAR(5),
+ c6 INT DEFAULT '1',
+ c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+ )ENGINE=$engine_type;
+
+--echo *** Create t16 on Master ***
+connection master;
+eval CREATE TABLE t16 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+ c4 BLOB, c5 CHAR(5))ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t16 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+ (2,2.00,'This Test Should work',@b1,'JOE'),
+ (3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t16 ORDER BY c1;
+
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 7 CURRENT_TIMESTAMP
+SELECT * FROM t16 ORDER BY c1;
+
+--echo *** Add Partition on master ***
+connection master;
+ALTER TABLE t16 PARTITION BY KEY(c1) PARTITIONS 4;
+INSERT INTO t16 () VALUES(4,1.00,'Replication Rocks',@b1,'Omer');
+SHOW CREATE TABLE t16;
+
+--echo *** Show table on Slave ****
+sync_slave_with_master;
+SHOW CREATE TABLE t16;
+
+--echo *** DROP TABLE t16 ***
+connection master;
+DROP TABLE t16;
+sync_slave_with_master;
+
+--echo *** Alter Master End ***
+
+############################################
+### Try to replicate BIGINT to SMALLINT ###
+### Should Stop Slave ###
+############################################
+
+--echo *** Create t17 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t17 (a SMALLINT, b INT PRIMARY KEY, c CHAR(5),
+ d FLOAT DEFAULT '2.00',
+ e CHAR(5) DEFAULT 'TEST2')
+ ENGINE=$engine_type;
+
+--echo *** Create t17 on Master ***
+connection master;
+eval CREATE TABLE t17 (a BIGINT PRIMARY KEY, b INT, c CHAR(10)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+
+INSERT INTO t17 () VALUES(9223372036854775807,2,'Kyle, TEX');
+
+--echo ********************************************
+--echo *** Expect slave to fail with Error 1522 ***
+--echo ********************************************
+connection slave;
+wait_for_slave_to_stop;
+--replace_result $MASTER_MYPORT MASTER_PORT
+--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+--query_vertical SHOW SLAVE STATUS
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+
+--echo ** DROP table t17 ***
+connection master;
+DROP TABLE t17;
+sync_slave_with_master;
+
+#### Clean Up ####
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17;
+--enable_query_log
+--enable_warnings
+
+# END 5.1 Test Case
+
+
diff --git a/mysql-test/extra/rpl_tests/rpl_ndb_ddl.test b/mysql-test/extra/rpl_tests/rpl_ndb_ddl.test
new file mode 100644
index 00000000000..26c368589ba
--- /dev/null
+++ b/mysql-test/extra/rpl_tests/rpl_ndb_ddl.test
@@ -0,0 +1,507 @@
+######################## rpl_ddl.test ########################
+# #
+# DDL statements (sometimes with implicit COMMIT) executed #
+# by the master and it's propagation into the slave #
+# #
+##############################################################
+
+#
+# NOTE, PLEASE BE CAREFUL, WHEN MODIFYING THE TESTS !!
+#
+# 1. !All! objects to be dropped, renamed, altered ... must be created
+# in AUTOCOMMIT= 1 mode before AUTOCOMMIT is set to 0 and the test
+# sequences start.
+#
+# 2. Never use a test object, which was direct or indirect affected by a
+# preceeding test sequence again.
+# Except table d1.t1 where ONLY DML is allowed.
+#
+# If one preceeding test sequence hits a (sometimes not good visible,
+# because the sql error code of the statement might be 0) bug
+# and these rules are ignored, a following test sequence might earn ugly
+# effects like failing 'sync_slave_with_master', crashes of the slave or
+# abort of the test case etc..
+#
+# 3. The assignment of the DDL command to be tested to $my_stmt can
+# be a bit difficult. "'" must be avoided, because the test
+# routine "include/rpl_stmt_seq.inc" performs a
+# eval SELECT CONCAT('######## ','$my_stmt',' ########') as "";
+#
+
+###############################################################
+# Some preparations
+###############################################################
+# The sync_slave_with_master is needed to make the xids deterministic.
+sync_slave_with_master;
+connection master;
+
+SET AUTOCOMMIT = 1;
+#
+# 1. DROP all objects, which probably already exist, but must be created here
+#
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+DROP DATABASE IF EXISTS mysqltest3;
+--enable_warnings
+#
+# 2. CREATE all objects needed
+# working database is mysqltest1
+# working (transactional!) is mysqltest1.t1
+#
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+eval CREATE TABLE mysqltest1.t1 (f1 BIGINT) ENGINE=$engine_type;
+INSERT INTO mysqltest1.t1 SET f1= 0;
+eval CREATE TABLE mysqltest1.t2 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t3 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t4 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t5 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t6 (f1 BIGINT) ENGINE=$engine_type;
+CREATE INDEX my_idx6 ON mysqltest1.t6(f1);
+eval CREATE TABLE mysqltest1.t7 (f1 BIGINT) ENGINE=$engine_type;
+INSERT INTO mysqltest1.t7 SET f1= 0;
+eval CREATE TABLE mysqltest1.t8 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t9 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t10 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t11 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t12 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t13 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t14 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t15 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t16 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t17 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t18 (f1 BIGINT) ENGINE=$engine_type;
+eval CREATE TABLE mysqltest1.t19 (f1 BIGINT) ENGINE=$engine_type;
+CREATE TEMPORARY TABLE mysqltest1.t23 (f1 BIGINT);
+
+#
+# 3. master sessions: never do AUTOCOMMIT
+# slave sessions: never do AUTOCOMMIT
+#
+SET AUTOCOMMIT = 0;
+use mysqltest1;
+sync_slave_with_master;
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SET AUTOCOMMIT = 0;
+use mysqltest1;
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+
+# We don't want to abort the whole test if one statement sent
+# to the server gets an error, because the following test
+# sequences are nearly independend of the previous statements.
+--disable_abort_on_error
+
+###############################################################
+# Banal case: (explicit) COMMIT and ROLLBACK
+# Just for checking if the test sequence is usable
+###############################################################
+
+let $my_stmt= COMMIT;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+
+let $my_stmt= ROLLBACK;
+let $my_master_commit= false;
+let $my_slave_commit= false;
+--source include/rpl_stmt_seq.inc
+
+###############################################################
+# Cases with commands very similar to COMMIT
+###############################################################
+
+let $my_stmt= SET AUTOCOMMIT=1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SET AUTOCOMMIT=0;
+
+let $my_stmt= START TRANSACTION;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+
+let $my_stmt= BEGIN;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+
+###############################################################
+# Cases with (BASE) TABLES and (UPDATABLE) VIEWs
+###############################################################
+
+let $my_stmt= DROP TABLE mysqltest1.t2;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW TABLES LIKE 't2';
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW TABLES LIKE 't2';
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+# Note: Since this test is executed with a skip-innodb slave, the
+# slave incorrectly commits the insert. One can *not* have InnoDB on
+# master and MyISAM on slave and expect that a transactional rollback
+# after a CREATE TEMPORARY TABLE should work correctly on the slave.
+# For this to work properly the handler on the slave must be able to
+# handle transactions (e.g. InnoDB or NDB).
+let $my_stmt= DROP TEMPORARY TABLE mysqltest1.t23;
+let $my_master_commit= false;
+let $my_slave_commit= false;
+--source include/rpl_stmt_seq.inc
+SHOW TABLES LIKE 't23';
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW TABLES LIKE 't23';
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+let $my_stmt= RENAME TABLE mysqltest1.t3 to mysqltest1.t20;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW TABLES LIKE 't20';
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW TABLES LIKE 't20';
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+let $my_stmt= ALTER TABLE mysqltest1.t4 ADD column f2 BIGINT;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+describe mysqltest1.t4;
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+describe mysqltest1.t4;
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+let $my_stmt= CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE=;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq2.inc
+
+# Note: Since this test is executed with a skip-innodb slave, the
+# slave incorrectly commits the insert. One can *not* have InnoDB on
+# master and MyISAM on slave and expect that a transactional rollback
+# after a CREATE TEMPORARY TABLE should work correctly on the slave.
+# For this to work properly the handler on the slave must be able to
+# handle transactions (e.g. InnoDB or NDB).
+let $engine='';
+let $eng_type='';
+
+let $my_stmt= CREATE TEMPORARY TABLE mysqltest1.t22 (f1 BIGINT);
+let $my_master_commit= false;
+let $my_slave_commit= false;
+--source include/rpl_stmt_seq.inc
+
+let $my_stmt= TRUNCATE TABLE mysqltest1.t7;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SELECT * FROM mysqltest1.t7;
+--echo -------- switch to slave --------
+sync_slave_with_master;
+SELECT * FROM mysqltest1.t7;
+--echo -------- switch to master -------
+connection master;
+
+###############################################################
+# Cases with LOCK/UNLOCK
+###############################################################
+
+# MySQL insists in locking mysqltest1.t1, because rpl_stmt_seq performs an
+# INSERT into this table.
+let $my_stmt= LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+UNLOCK TABLES;
+
+# No prior locking
+let $my_stmt= UNLOCK TABLES;
+let $my_master_commit= false;
+let $my_slave_commit= false;
+--source include/rpl_stmt_seq.inc
+
+# With prior read locking
+# Note that this test generate an error since the rpl_stmt_seq.inc
+# tries to insert into t1.
+LOCK TABLES mysqltest1.t1 READ;
+let $my_stmt= UNLOCK TABLES;
+let $my_master_commit= false;
+let $my_slave_commit= false;
+--source include/rpl_stmt_seq.inc
+
+# With prior write locking
+LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ;
+let $my_stmt= UNLOCK TABLES;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+
+###############################################################
+# Cases with INDEXES
+###############################################################
+
+let $my_stmt= DROP INDEX my_idx6 ON mysqltest1.t6;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW INDEX FROM mysqltest1.t6;
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW INDEX FROM mysqltest1.t6;
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+let $my_stmt= CREATE INDEX my_idx5 ON mysqltest1.t5(f1);
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW INDEX FROM mysqltest1.t5;
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW INDEX FROM mysqltest1.t5;
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+###############################################################
+# Cases with DATABASE
+###############################################################
+
+let $my_stmt= DROP DATABASE mysqltest2;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW DATABASES LIKE "mysqltest2";
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW DATABASES LIKE "mysqltest2";
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+let $my_stmt= CREATE DATABASE mysqltest3;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW DATABASES LIKE "mysqltest3";
+connection slave;
+--disable_query_log
+SELECT '-------- switch to slave --------' as "";
+--enable_query_log
+SHOW DATABASES LIKE "mysqltest3";
+connection master;
+--disable_query_log
+SELECT '-------- switch to master -------' as "";
+--enable_query_log
+
+# End of 4.1 tests
+
+###############################################################
+# Cases with stored procedures
+###############################################################
+let $my_stmt= CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1";
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+--vertical_results
+--replace_column 5 # 6 #
+SHOW PROCEDURE STATUS LIKE 'p1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+--replace_column 5 # 6 #
+SHOW PROCEDURE STATUS LIKE 'p1';
+connection master;
+--horizontal_results
+
+let $my_stmt= ALTER PROCEDURE p1 COMMENT "I have been altered";
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+--vertical_results
+--replace_column 5 # 6 #
+SHOW PROCEDURE STATUS LIKE 'p1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+--replace_column 5 # 6 #
+SHOW PROCEDURE STATUS LIKE 'p1';
+connection master;
+--horizontal_results
+
+let $my_stmt= DROP PROCEDURE p1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+--vertical_results
+SHOW PROCEDURE STATUS LIKE 'p1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SHOW PROCEDURE STATUS LIKE 'p1';
+connection master;
+--horizontal_results
+
+###############################################################
+# Cases with VIEWs
+###############################################################
+let $my_stmt= CREATE OR REPLACE VIEW v1 as select * from t1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW CREATE VIEW v1;
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SHOW CREATE VIEW v1;
+connection master;
+
+let $my_stmt= ALTER VIEW v1 AS select f1 from t1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW CREATE VIEW v1;
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SHOW CREATE VIEW v1;
+connection master;
+
+let $my_stmt= DROP VIEW IF EXISTS v1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+--error 1146
+SHOW CREATE VIEW v1;
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+--error 1146
+SHOW CREATE VIEW v1;
+connection master;
+
+###############################################################
+# Cases with TRIGGERs
+###############################################################
+let $my_stmt= CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW TRIGGERS;
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SHOW TRIGGERS;
+connection master;
+
+let $my_stmt= DROP TRIGGER trg1;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SHOW TRIGGERS;
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SHOW TRIGGERS;
+connection master;
+
+###############################################################
+# Cases with USERs
+###############################################################
+let $my_stmt= CREATE USER user1@localhost;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SELECT user FROM mysql.user WHERE user = 'user1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SELECT user FROM mysql.user WHERE user = 'user1';
+connection master;
+
+let $my_stmt= RENAME USER user1@localhost TO rename1@localhost;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SELECT user FROM mysql.user WHERE user = 'rename1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SELECT user FROM mysql.user WHERE user = 'rename1';
+connection master;
+
+let $my_stmt= DROP USER rename1@localhost;
+let $my_master_commit= true;
+let $my_slave_commit= true;
+--source include/rpl_stmt_seq.inc
+SELECT user FROM mysql.user WHERE user = 'rename1';
+--disable_query_log
+SELECT '-------- switch to slave -------' as "";
+--enable_query_log
+connection slave;
+SELECT user FROM mysql.user WHERE user = 'rename1';
+connection master;
+
+###############################################################
+# Cleanup
+###############################################################
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+DROP DATABASE IF EXISTS mysqltest3;
+--enable_warnings
+
+-- source include/master-slave-end.inc
+
diff --git a/mysql-test/include/strict_autoinc.inc b/mysql-test/include/strict_autoinc.inc
index 6960440f3a7..823efcc2040 100644
--- a/mysql-test/include/strict_autoinc.inc
+++ b/mysql-test/include/strict_autoinc.inc
@@ -2,6 +2,10 @@
# Test for strict-mode autoincrement
#
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
set @org_mode=@@sql_mode;
eval create table t1
(
diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh
index d7c19438836..87ca7e5a530 100644
--- a/mysql-test/install_test_db.sh
+++ b/mysql-test/install_test_db.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (C) 1997-2002 MySQL AB
+# Copyright (C) 1997-2006 MySQL AB
# For a more info consult the file COPYRIGHT distributed with this file
# This scripts creates the privilege tables db, host, user, tables_priv,
@@ -7,19 +7,26 @@
if [ x$1 = x"--bin" ]; then
shift 1
+ BINARY_DIST=1
+
+ bindir=../bin
+ scriptdir=../bin
+ libexecdir=../libexec
# Check if it's a binary distribution or a 'make install'
if test -x ../libexec/mysqld
then
execdir=../libexec
+ elif test -x ../../sbin/mysqld # RPM installation
+ then
+ execdir=../../sbin
+ bindir=../../bin
+ scriptdir=../../bin
+ libexecdir=../../libexec
else
execdir=../bin
fi
- bindir=../bin
- BINARY_DIST=1
fix_bin=mysql-test
- scriptdir=../bin
- libexecdir=../libexec
else
execdir=../sql
bindir=../client
diff --git a/mysql-test/mysql-test-run-shell.sh b/mysql-test/mysql-test-run-shell.sh
index 99c844b2f78..9c55d879db4 100644
--- a/mysql-test/mysql-test-run-shell.sh
+++ b/mysql-test/mysql-test-run-shell.sh
@@ -180,18 +180,29 @@ fi
# Misc. Definitions
#--
-if [ -d ../sql ] ; then
+# BASEDIR is always above mysql-test directory ...
+MYSQL_TEST_DIR=`pwd`
+cd ..
+
+if [ -d ./sql ] ; then
SOURCE_DIST=1
else
BINARY_DIST=1
fi
-#BASEDIR is always one above mysql-test directory
-CWD=`pwd`
-cd ..
-BASEDIR=`pwd`
-cd $CWD
-MYSQL_TEST_DIR=$BASEDIR/mysql-test
+# ... one level for tar.gz, two levels for a RPM installation
+if [ -d ./bin ] ; then
+ # this is not perfect: we have
+ # /usr/share/mysql/ # mysql-test-run is here, so this is "$MYSQL_TEST_DIR"
+ # /usr/bin/ # with MySQL client programs
+ # so the existence of "/usr/share/bin/" would make this test fail.
+ BASEDIR=`pwd`
+else
+ cd ..
+ BASEDIR=`pwd`
+fi
+
+cd $MYSQL_TEST_DIR
MYSQL_TEST_WINDIR=$MYSQL_TEST_DIR
MYSQLTEST_VARDIR=$MYSQL_TEST_DIR/var
export MYSQL_TEST_DIR MYSQL_TEST_WINDIR MYSQLTEST_VARDIR
@@ -784,8 +795,15 @@ else
if test -x "$BASEDIR/libexec/mysqld"
then
MYSQLD="$VALGRIND $BASEDIR/libexec/mysqld"
- else
+ elif test -x "$BASEDIR/bin/mysqld"
+ then
MYSQLD="$VALGRIND $BASEDIR/bin/mysqld"
+ elif test -x "$BASEDIR/sbin/mysqld"
+ then
+ MYSQLD="$VALGRIND $BASEDIR/sbin/mysqld"
+ else
+ $ECHO "Fatal error: Cannot find program mysqld in $BASEDIR/{libexec,bin,sbin}" 1>&2
+ exit 1
fi
CLIENT_BINDIR="$BASEDIR/bin"
if test -d "$BASEDIR/tests"
@@ -1406,7 +1424,7 @@ start_master()
then
$ECHO "set args $master_args" > $GDB_MASTER_INIT$1
$ECHO "To start gdb for the master , type in another window:"
- $ECHO "cd $CWD ; gdb -x $GDB_MASTER_INIT$1 $MASTER_MYSQLD"
+ $ECHO "cd $MYSQL_TEST_DIR ; gdb -x $GDB_MASTER_INIT$1 $MASTER_MYSQLD"
wait_for_master=1500
else
( $ECHO set args $master_args;
@@ -1563,7 +1581,7 @@ start_slave()
then
$ECHO "set args $slave_args" > $GDB_SLAVE_INIT
echo "To start gdb for the slave, type in another window:"
- echo "cd $CWD ; gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD"
+ echo "cd $MYSQL_TEST_DIR ; gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD"
wait_for_slave=1500
else
( $ECHO set args $slave_args;
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 73bde3b3e57..3c855fb0499 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -225,6 +225,7 @@ our $opt_ndbconnectstring_slave;
our $opt_record;
our $opt_report_features;
our $opt_check_testcases;
+my $opt_report_features;
our $opt_skip;
our $opt_skip_rpl;
@@ -639,7 +640,7 @@ sub command_line_setup () {
$glob_hostname= mtr_short_hostname();
- # 'basedir' is always parent of "mysql-test" directory
+ # Find the absolute path to the test directory
$glob_mysql_test_dir= cwd();
if ( $glob_cygwin_perl )
{
@@ -647,11 +648,27 @@ sub command_line_setup () {
$glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`;
chomp($glob_mysql_test_dir);
}
- $glob_basedir= dirname($glob_mysql_test_dir);
+
+ # In most cases, the base directory we find everything relative to,
+ # is the parent directory of the "mysql-test" directory. For source
+ # distributions, TAR binary distributions and some other packages.
+ $glob_basedir= dirname($glob_mysql_test_dir);
+
+ # In the RPM case, binaries and libraries are installed in the
+ # default system locations, instead of having our own private base
+ # directory. And we install "/usr/share/mysql-test". Moving up one
+ # more directory relative to "mysql-test" gives us a usable base
+ # directory for RPM installs.
+ if ( ! $opt_source_dist and ! -d "$glob_basedir/bin" )
+ {
+ $glob_basedir= dirname($glob_basedir);
+ }
# Expect mysql-bench to be located adjacent to the source tree, by default
$glob_mysql_bench_dir= "$glob_basedir/../mysql-bench"
unless defined $glob_mysql_bench_dir;
+ $glob_mysql_bench_dir= undef
+ unless -d $glob_mysql_bench_dir;
$path_my_basedir=
$opt_source_dist ? $glob_mysql_test_dir : $glob_basedir;
@@ -679,7 +696,8 @@ sub command_line_setup () {
"$path_client_bindir/mysqld-debug",
"$path_client_bindir/mysqld-max",
"$glob_basedir/libexec/mysqld",
- "$glob_basedir/bin/mysqld");
+ "$glob_basedir/bin/mysqld",
+ "$glob_basedir/sbin/mysqld");
# Use the mysqld found above to find out what features are available
collect_mysqld_features();
@@ -796,6 +814,13 @@ sub command_line_setup () {
$opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
}
+ # Ensure a proper error message
+ mkpath("$opt_vardir");
+ unless ( -d $opt_vardir and -w $opt_vardir )
+ {
+ mtr_error("Writable 'var' directory is needed, use the '--vardir' option");
+ }
+
# --------------------------------------------------------------------------
# Set tmpdir
# --------------------------------------------------------------------------
@@ -1308,7 +1333,8 @@ sub executable_setup_im () {
mtr_exe_maybe_exists(
"$glob_basedir/server-tools/instance-manager/mysqlmanager",
"$glob_basedir/libexec/mysqlmanager",
- "$glob_basedir/bin/mysqlmanager");
+ "$glob_basedir/bin/mysqlmanager",
+ "$glob_basedir/sbin/mysqlmanager");
return ($exe_im eq "");
}
diff --git a/mysql-test/r/binlog_row_binlog.result b/mysql-test/r/binlog_row_binlog.result
index 7cbfa525798..aee270bd7f6 100644
--- a/mysql-test/r/binlog_row_binlog.result
+++ b/mysql-test/r/binlog_row_binlog.result
@@ -245,6 +245,24 @@ select * from t1;
id
127
drop table t1;
+create table t1 (a int);
+create table if not exists t2 select * from t1;
+create temporary table tt1 (a int);
+create table if not exists t3 like tt1;
+show binlog events from 102;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `test`; create table t1 (id tinyint auto_increment primary key)
+master-bin.000001 # Table_map 1 # table_id: # (test.t1)
+master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
+master-bin.000001 # Query 1 # use `test`; drop table t1
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS `t2` (
+ `a` int(11) DEFAULT NULL
+)
+master-bin.000001 # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS `t3` (
+ `a` int(11) DEFAULT NULL
+)
+drop table t1,t2,t3,tt1;
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
insert delayed into t1 values (207);
@@ -256,6 +274,14 @@ master-bin.000001 # Query 1 # use `test`; create table t1 (id tinyint auto_incre
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; drop table t1
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS `t2` (
+ `a` int(11) DEFAULT NULL
+)
+master-bin.000001 # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS `t3` (
+ `a` int(11) DEFAULT NULL
+)
+master-bin.000001 # Query 1 # use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query 1 # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
diff --git a/mysql-test/r/binlog_stm_binlog.result b/mysql-test/r/binlog_stm_binlog.result
index eed2df28d1f..a9b3f69ecee 100644
--- a/mysql-test/r/binlog_stm_binlog.result
+++ b/mysql-test/r/binlog_stm_binlog.result
@@ -155,6 +155,21 @@ select * from t1;
id
127
drop table t1;
+create table t1 (a int);
+create table if not exists t2 select * from t1;
+create temporary table tt1 (a int);
+create table if not exists t3 like tt1;
+show binlog events from 102;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `test`; create table t1 (id tinyint auto_increment primary key)
+master-bin.000001 # Intvar 1 # INSERT_ID=127
+master-bin.000001 # Query 1 # use `test`; insert into t1 values(null)
+master-bin.000001 # Query 1 # use `test`; drop table t1
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; create table if not exists t2 select * from t1
+master-bin.000001 # Query 1 # use `test`; create temporary table tt1 (a int)
+master-bin.000001 # Query 1 # use `test`; create table if not exists t3 like tt1
+drop table t1,t2,t3,tt1;
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
insert delayed into t1 values (207);
@@ -166,6 +181,11 @@ master-bin.000001 # Query 1 # use `test`; create table t1 (id tinyint auto_incre
master-bin.000001 # Intvar 1 # INSERT_ID=127
master-bin.000001 # Query 1 # use `test`; insert into t1 values(null)
master-bin.000001 # Query 1 # use `test`; drop table t1
+master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
+master-bin.000001 # Query 1 # use `test`; create table if not exists t2 select * from t1
+master-bin.000001 # Query 1 # use `test`; create temporary table tt1 (a int)
+master-bin.000001 # Query 1 # use `test`; create table if not exists t3 like tt1
+master-bin.000001 # Query 1 # use `test`; drop table t1,t2,t3,tt1
master-bin.000001 # Query 1 # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result
index d0087b03c17..e85d379c932 100644
--- a/mysql-test/r/ctype_recoding.result
+++ b/mysql-test/r/ctype_recoding.result
@@ -171,8 +171,8 @@ create table t1 (a char(10) character set koi8r, b text character set koi8r);
insert into t1 values ('test','test');
insert into t1 values ('ÊÃÕË','ÊÃÕË');
Warnings:
-Warning 1265 Data truncated for column 'a' at row 1
-Warning 1265 Data truncated for column 'b' at row 1
+Warning 1366 Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'a' at row 1
+Warning 1366 Incorrect string value: '\xCA\xC3\xD5\xCB' for column 'b' at row 1
drop table t1;
set names koi8r;
create table t1 (a char(10) character set cp1251);
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 4f08b97492f..a65b19695ec 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -723,6 +723,28 @@ lily
river
drop table t1;
deallocate prepare stmt;
+create table t1 (
+a char(10) unicode not null,
+index a (a)
+) engine=myisam;
+insert into t1 values (repeat(0x201f, 10));
+insert into t1 values (repeat(0x2020, 10));
+insert into t1 values (repeat(0x2021, 10));
+explain select hex(a) from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 20 NULL 3 Using index
+select hex(a) from t1 order by a;
+hex(a)
+201F201F201F201F201F201F201F201F201F201F
+2020202020202020202020202020202020202020
+2021202120212021202120212021202120212021
+alter table t1 drop index a;
+select hex(a) from t1 order by a;
+hex(a)
+201F201F201F201F201F201F201F201F201F201F
+2020202020202020202020202020202020202020
+2021202120212021202120212021202120212021
+drop table t1;
CREATE TABLE t1 (id int, s char(5) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci);
INSERT INTO t1 VALUES (1, 'ZZZZZ'), (1, 'ZZZ'), (2, 'ZZZ'), (2, 'ZZZZZ');
SELECT id, MIN(s) FROM t1 GROUP BY id;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 4ae19fc8f7c..4aa22944b9b 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -197,7 +197,7 @@ drop table t1;
create table t1 (s1 char(10) character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -205,7 +205,7 @@ drop table t1;
create table t1 (s1 varchar(10) character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -213,7 +213,7 @@ drop table t1;
create table t1 (s1 text character set utf8);
insert into t1 values (0x41FF);
Warnings:
-Warning 1265 Data truncated for column 's1' at row 1
+Warning 1366 Incorrect string value: '\xFF' for column 's1' at row 1
select hex(s1) from t1;
hex(s1)
41
@@ -1536,6 +1536,32 @@ set @a:=null;
execute my_stmt using @a;
a b
drop table if exists t1;
+drop table if exists t1;
+drop view if exists v1, v2;
+set names utf8;
+create table t1(col1 varchar(12) character set utf8 collate utf8_unicode_ci);
+insert into t1 values('t1_val');
+create view v1 as select 'v1_val' as col1;
+select coercibility(col1), collation(col1) from v1;
+coercibility(col1) collation(col1)
+4 utf8_general_ci
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1)from v2;
+coercibility(col1) collation(col1)
+2 utf8_unicode_ci
+2 utf8_unicode_ci
+drop view v1, v2;
+create view v1 as select 'v1_val' collate utf8_swedish_ci as col1;
+select coercibility(col1), collation(col1) from v1;
+coercibility(col1) collation(col1)
+0 utf8_swedish_ci
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1) from v2;
+coercibility(col1) collation(col1)
+0 utf8_swedish_ci
+0 utf8_swedish_ci
+drop view v1, v2;
+drop table t1;
CREATE TABLE t1 (
colA int(11) NOT NULL,
colB varchar(255) character set utf8 NOT NULL,
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index 457155b4299..829cf25a896 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -381,10 +381,10 @@ t collation(t) FORMAT(MATCH t AGAINST ('Osnabruck'),6)
aus Osnabrück utf8_general_ci 1.591140
alter table t1 modify t varchar(200) collate latin1_german2_ci not null;
Warnings:
-Warning 1265 Data truncated for column 't' at row 3
-Warning 1265 Data truncated for column 't' at row 4
-Warning 1265 Data truncated for column 't' at row 5
-Warning 1265 Data truncated for column 't' at row 6
+Warning 1366 Incorrect string value: '\xD0\xAD\xD1\x82\xD0\xBE...' for column 't' at row 3
+Warning 1366 Incorrect string value: '\xD0\x9E\xD1\x82\xD0\xBB...' for column 't' at row 4
+Warning 1366 Incorrect string value: '\xD0\x9D\xD0\xB5 \xD0...' for column 't' at row 5
+Warning 1366 Incorrect string value: '\xD0\xB8 \xD0\xB1\xD1...' for column 't' at row 6
SELECT t, collation(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück');
t collation(t)
aus Osnabrück latin1_german2_ci
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index 619c8dafeae..57b0a2aec25 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -664,3 +664,73 @@ GROUP_CONCAT(a) x
2 1,2
1 2,3
DROP TABLE t1;
+set names utf8;
+create table t1
+(
+x text character set utf8 not null,
+y integer not null
+);
+insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
+set group_concat_max_len= 1022 + 10;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1032 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 9;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1031 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 8;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1030 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 7;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1029 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
+set group_concat_max_len= 1022 + 6;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1028 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
+set group_concat_max_len= 1022 + 5;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1027 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
+set group_concat_max_len= 1022 + 4;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1026 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
+set group_concat_max_len= 1022 + 3;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1025 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
+set group_concat_max_len= 1022 + 2;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1024 1023 1023 aaaaaaaaaaa, 61616161612C
+set group_concat_max_len= 1022 + 1;
+select @x:=group_concat(x) from t1 group by y;
+select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
+1023 1023 1023 aaaaaaaaaaa, 61616161612C
+drop table t1;
+set group_concat_max_len=1024;
+set names latin1;
+create table t1 (f1 int unsigned, f2 varchar(255));
+insert into t1 values (1,repeat('a',255)),(2,repeat('b',255));
+select f2,group_concat(f1) from t1 group by f2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t1 t1 f2 f2 253 255 255 Y 0 0 8
+def group_concat(f1) 252 1024 1 Y 128 0 63
+f2 group_concat(f1)
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1
+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 2
+drop table t1;
diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result
index 7705961d08d..464f423fa92 100644
--- a/mysql-test/r/lowercase_table.result
+++ b/mysql-test/r/lowercase_table.result
@@ -84,3 +84,27 @@ create table t2 like T1;
drop table t1, t2;
show tables;
Tables_in_test
+set names utf8;
+drop table if exists Ä°,Ä°Ä°;
+create table Ä° (s1 int);
+show create table Ä°;
+Table Create Table
+Ä° CREATE TABLE `i` (
+ `s1` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show tables;
+Tables_in_test
+i
+drop table Ä°;
+create table Ä°Ä° (s1 int);
+show create table Ä°Ä°;
+Table Create Table
+Ä°Ä° CREATE TABLE `ii` (
+ `s1` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+show tables;
+Tables_in_test
+ii
+drop table Ä°Ä°;
+set names latin1;
+End of 5.0 tests
diff --git a/mysql-test/r/rpl_deadlock_innodb.result b/mysql-test/r/rpl_deadlock_innodb.result
index a384be6eb37..caf040c0997 100644
--- a/mysql-test/r/rpl_deadlock_innodb.result
+++ b/mysql-test/r/rpl_deadlock_innodb.result
@@ -6,7 +6,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=innodb;
CREATE TABLE t2 (a INT NOT NULL, KEY(a)) ENGINE=innodb;
-CREATE TABLE t3 (a INT) ENGINE=innodb;
+CREATE TABLE t3 (a INT UNIQUE) ENGINE=innodb;
CREATE TABLE t4 (a INT) ENGINE=innodb;
show variables like 'slave_transaction_retries';
Variable_name Value
@@ -28,21 +28,22 @@ Variable_name Value
slave_transaction_retries 2
stop slave;
begin;
-insert into t3 select * from t2 for update;
+insert into t2 values (0);
insert into t1 values(1);
commit;
begin;
select * from t1 for update;
a
start slave;
-insert into t2 values(22);
+select * from t2 for update /* dl */;
+a
commit;
select * from t1;
a
1
-select * from t2;
+select * from t2 /* must be 1 */;
a
-22
+0
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -78,12 +79,16 @@ Master_SSL_Cipher
Master_SSL_Key
Seconds_Behind_Master #
stop slave;
-change master to master_log_pos=536;
+delete from t3;
+change master to master_log_pos=544;
begin;
select * from t2 for update;
a
-22
+0
start slave;
+select count(*) from t3 /* must be zero */;
+count(*)
+0
commit;
select * from t1;
a
@@ -91,7 +96,8 @@ a
1
select * from t2;
a
-22
+0
+0
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -129,12 +135,17 @@ Seconds_Behind_Master #
set @my_max_relay_log_size= @@global.max_relay_log_size;
set global max_relay_log_size=0;
stop slave;
-change master to master_log_pos=536;
+delete from t3;
+change master to master_log_pos=544;
begin;
select * from t2 for update;
a
-22
+0
+0
start slave;
+select count(*) from t3 /* must be zero */;
+count(*)
+0
commit;
select * from t1;
a
@@ -143,7 +154,9 @@ a
1
select * from t2;
a
-22
+0
+0
+0
show slave status;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -180,3 +193,4 @@ Master_SSL_Key
Seconds_Behind_Master #
drop table t1,t2,t3,t4;
set global max_relay_log_size= @my_max_relay_log_size;
+End of 5.1 tests
diff --git a/mysql-test/r/rpl_do_grant.result b/mysql-test/r/rpl_do_grant.result
index 8bf8e615448..50d181be0ca 100644
--- a/mysql-test/r/rpl_do_grant.result
+++ b/mysql-test/r/rpl_do_grant.result
@@ -23,6 +23,8 @@ password<>_binary''
delete from mysql.user where user=_binary'rpl_do_grant';
delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges;
+delete from mysql.user where user=_binary'rpl_do_grant';
+delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges;
show grants for rpl_do_grant@localhost;
ERROR 42000: There is no such grant defined for user 'rpl_do_grant' on host 'localhost'
diff --git a/mysql-test/r/rpl_extraCol_innodb.result b/mysql-test/r/rpl_extraCol_innodb.result
new file mode 100644
index 00000000000..7f681aef4be
--- /dev/null
+++ b/mysql-test/r/rpl_extraCol_innodb.result
@@ -0,0 +1,741 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+**** Diff Table Def Start ****
+*** On Slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(4) DEFAULT 'TEST')
+ENGINE='InnoDB';
+*** Create t1 on Master ***
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t1 () VALUES(1,2,'TEXAS'),(2,1,'AUSTIN'),(3,4,'QA');
+SELECT * FROM t1 ORDER BY a;
+a b c
+1 2 TEXAS
+2 1 AUSTIN
+3 4 QA
+*** Select from slave ***
+SELECT * FROM t1 ORDER BY a;
+a b c d e
+1 2 TEXAS 2 TEST
+2 1 AUSTIN 2 TEST
+3 4 QA 2 TEST
+*** Drop t1 ***
+DROP TABLE t1;
+*** Create t3 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t3 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='InnoDB';
+*** Create t3 on Master ***
+CREATE TABLE t3 (a BLOB, b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t3 () VALUES(@b1,2,'Kyle, TEX'),(@b1,1,'JOE AUSTIN'),(@b1,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 252, test.t3 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t3 ***
+DROP TABLE t3;
+*** Create t4 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t4 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='InnoDB';
+*** Create t4 on Master ***
+CREATE TABLE t4 (a DECIMAL(8,2), b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t4 () VALUES(100.22,2,'Kyle, TEX'),(200.26,1,'JOE AUSTIN'),
+(30000.22,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 246, test.t4 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t4 ***
+DROP TABLE t4;
+*** Create t5 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t5 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT, e DOUBLE,
+f DECIMAL(8,2))ENGINE='InnoDB';
+*** Create t5 on Master ***
+CREATE TABLE t5 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT, e BLOB,
+f FLOAT) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
+(2,'JOE',300.01,0,'b2b2',1.0000009);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 5 type mismatch - received type 4, test.t5 has type 246
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t5 ***
+DROP TABLE t5;
+*** Create t6 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t6 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT)ENGINE='InnoDB';
+*** Create t6 on Master ***
+CREATE TABLE t6 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
+(2,'JOE',300.01,0);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 3 type mismatch - received type 16, test.t6 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3;
+*** Drop t6 ***
+DROP TABLE t6;
+DROP TABLE t6;
+START SLAVE;
+**** Diff Table Def End ****
+**** Extra Colums Start ****
+*** Create t7 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t7 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e CHAR(20) DEFAULT 'Extra Column Testing')
+ENGINE='InnoDB';
+*** Create t7 on Master ***
+CREATE TABLE t7 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t7 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t7 ORDER BY a;
+a b c
+1 b1b1 Kyle
+2 b1b1 JOE
+3 b1b1 QA
+*** Select from slave ***
+SELECT * FROM t7 ORDER BY a;
+a b c d e
+1 b1b1 Kyle 0000-00-00 00:00:00 Extra Column Testing
+2 b1b1 JOE 0000-00-00 00:00:00 Extra Column Testing
+3 b1b1 QA 0000-00-00 00:00:00 Extra Column Testing
+*** Drop t7 ***
+DROP TABLE t7;
+*** Create t8 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t8 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e INT)ENGINE='InnoDB';
+*** Create t8 on Master ***
+CREATE TABLE t8 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t8 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+*** Drop t8 ***
+DROP TABLE t8;
+*** Create t10 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233',
+c CHAR(5), e INT DEFAULT '1')ENGINE='InnoDB';
+*** Create t10 on Master ***
+CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 254, test.t10 has type 5
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t10 ***
+DROP TABLE t10;
+*** Create t11 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='InnoDB';
+*** Create t11 on Master ***
+CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 15, test.t11 has type 252
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t11 ***
+DROP TABLE t11;
+*** Create t12 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='InnoDB';
+*** Create t12 on Master ***
+CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t12 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t12 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ***
+SELECT * FROM t12 ORDER BY a;
+a b f c e
+1 b1b1b1b1b1b1b1b1 Kyle test 1
+2 b1b1b1b1b1b1b1b1 JOE test 1
+3 b1b1b1b1b1b1b1b1 QA test 1
+*** Drop t12 ***
+DROP TABLE t12;
+**** Extra Colums End ****
+*** BUG 22177 Start ***
+*** Create t13 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t13 (a INT KEY, b BLOB, c CHAR(5),
+d INT DEFAULT '1',
+e TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='InnoDB';
+*** Create t13 on Master ***
+CREATE TABLE t13 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t13 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t13 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t13 ORDER BY a;
+a b c d e
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Drop t13 ***
+DROP TABLE t13;
+*** 22117 END ***
+*** Alter Master Table Testing Start ***
+*** Create t14 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='InnoDB';
+*** Create t14 on Master ***
+CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1;
+ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** connect to master and drop columns ***
+ALTER TABLE t14 DROP COLUMN c2;
+ALTER TABLE t14 DROP COLUMN c4;
+*** Select from Master ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5
+1 Replication Testing Extra Col Kyle
+2 This Test Should work JOE
+3 If is does not, I will open a bug QA
+*** Select from Slave ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5 c6 c7
+1 Replication Testing Extra Col Kyle 1 CURRENT_TIMESTAMP
+2 This Test Should work JOE 1 CURRENT_TIMESTAMP
+3 If is does not, I will open a bug QA 1 CURRENT_TIMESTAMP
+*** Drop t14 ***
+DROP TABLE t14;
+*** Create t15 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t15 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='InnoDB';
+*** Create t15 on Master ***
+CREATE TABLE t15 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5)) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t15 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add column on master that is a Extra on Slave ***
+ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5;
+********************************************
+*** Expect slave to fail with Error 1060 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1060
+Last_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Try to insert in master ****
+INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2
+*** Try to select from slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** DROP TABLE t15 ***
+DROP TABLE t15;
+*** Create t16 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t16 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='InnoDB';
+*** Create t16 on Master ***
+CREATE TABLE t16 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5))ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t16 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add Partition on master ***
+ALTER TABLE t16 PARTITION BY KEY(c1) PARTITIONS 4;
+INSERT INTO t16 () VALUES(4,1.00,'Replication Rocks',@b1,'Omer');
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** Show table on Slave ****
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ `c6` int(11) DEFAULT '1',
+ `c7` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** DROP TABLE t16 ***
+DROP TABLE t16;
+*** Alter Master End ***
+*** Create t17 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t17 (a SMALLINT, b INT PRIMARY KEY, c CHAR(5),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='InnoDB';
+*** Create t17 on Master ***
+CREATE TABLE t17 (a BIGINT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t17 () VALUES(9223372036854775807,2,'Kyle, TEX');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 8, test.t17 has type 2
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+** DROP table t17 ***
+DROP TABLE t17;
diff --git a/mysql-test/r/rpl_extraCol_myisam.result b/mysql-test/r/rpl_extraCol_myisam.result
new file mode 100644
index 00000000000..3c0d1fae4a8
--- /dev/null
+++ b/mysql-test/r/rpl_extraCol_myisam.result
@@ -0,0 +1,741 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+**** Diff Table Def Start ****
+*** On Slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(4) DEFAULT 'TEST')
+ENGINE='MyISAM';
+*** Create t1 on Master ***
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t1 () VALUES(1,2,'TEXAS'),(2,1,'AUSTIN'),(3,4,'QA');
+SELECT * FROM t1 ORDER BY a;
+a b c
+1 2 TEXAS
+2 1 AUSTIN
+3 4 QA
+*** Select from slave ***
+SELECT * FROM t1 ORDER BY a;
+a b c d e
+1 2 TEXAS 2 TEST
+2 1 AUSTIN 2 TEST
+3 4 QA 2 TEST
+*** Drop t1 ***
+DROP TABLE t1;
+*** Create t3 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t3 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='MyISAM';
+*** Create t3 on Master ***
+CREATE TABLE t3 (a BLOB, b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t3 () VALUES(@b1,2,'Kyle, TEX'),(@b1,1,'JOE AUSTIN'),(@b1,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 252, test.t3 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t3 ***
+DROP TABLE t3;
+*** Create t4 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t4 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='MyISAM';
+*** Create t4 on Master ***
+CREATE TABLE t4 (a DECIMAL(8,2), b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t4 () VALUES(100.22,2,'Kyle, TEX'),(200.26,1,'JOE AUSTIN'),
+(30000.22,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 246, test.t4 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t4 ***
+DROP TABLE t4;
+*** Create t5 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t5 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT, e DOUBLE,
+f DECIMAL(8,2))ENGINE='MyISAM';
+*** Create t5 on Master ***
+CREATE TABLE t5 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT, e BLOB,
+f FLOAT) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
+(2,'JOE',300.01,0,'b2b2',1.0000009);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 5 type mismatch - received type 4, test.t5 has type 246
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t5 ***
+DROP TABLE t5;
+*** Create t6 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t6 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT)ENGINE='MyISAM';
+*** Create t6 on Master ***
+CREATE TABLE t6 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
+(2,'JOE',300.01,0);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 3 type mismatch - received type 16, test.t6 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3;
+*** Drop t6 ***
+DROP TABLE t6;
+DROP TABLE t6;
+START SLAVE;
+**** Diff Table Def End ****
+**** Extra Colums Start ****
+*** Create t7 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t7 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e CHAR(20) DEFAULT 'Extra Column Testing')
+ENGINE='MyISAM';
+*** Create t7 on Master ***
+CREATE TABLE t7 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t7 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t7 ORDER BY a;
+a b c
+1 b1b1 Kyle
+2 b1b1 JOE
+3 b1b1 QA
+*** Select from slave ***
+SELECT * FROM t7 ORDER BY a;
+a b c d e
+1 b1b1 Kyle 0000-00-00 00:00:00 Extra Column Testing
+2 b1b1 JOE 0000-00-00 00:00:00 Extra Column Testing
+3 b1b1 QA 0000-00-00 00:00:00 Extra Column Testing
+*** Drop t7 ***
+DROP TABLE t7;
+*** Create t8 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t8 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e INT)ENGINE='MyISAM';
+*** Create t8 on Master ***
+CREATE TABLE t8 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t8 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+*** Drop t8 ***
+DROP TABLE t8;
+*** Create t10 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233',
+c CHAR(5), e INT DEFAULT '1')ENGINE='MyISAM';
+*** Create t10 on Master ***
+CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 254, test.t10 has type 5
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t10 ***
+DROP TABLE t10;
+*** Create t11 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='MyISAM';
+*** Create t11 on Master ***
+CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 15, test.t11 has type 252
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t11 ***
+DROP TABLE t11;
+*** Create t12 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='MyISAM';
+*** Create t12 on Master ***
+CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t12 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t12 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ***
+SELECT * FROM t12 ORDER BY a;
+a b f c e
+1 b1b1b1b1b1b1b1b1 Kyle test 1
+2 b1b1b1b1b1b1b1b1 JOE test 1
+3 b1b1b1b1b1b1b1b1 QA test 1
+*** Drop t12 ***
+DROP TABLE t12;
+**** Extra Colums End ****
+*** BUG 22177 Start ***
+*** Create t13 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t13 (a INT KEY, b BLOB, c CHAR(5),
+d INT DEFAULT '1',
+e TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='MyISAM';
+*** Create t13 on Master ***
+CREATE TABLE t13 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t13 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t13 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t13 ORDER BY a;
+a b c d e
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Drop t13 ***
+DROP TABLE t13;
+*** 22117 END ***
+*** Alter Master Table Testing Start ***
+*** Create t14 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='MyISAM';
+*** Create t14 on Master ***
+CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1;
+ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** connect to master and drop columns ***
+ALTER TABLE t14 DROP COLUMN c2;
+ALTER TABLE t14 DROP COLUMN c4;
+*** Select from Master ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5
+1 Replication Testing Extra Col Kyle
+2 This Test Should work JOE
+3 If is does not, I will open a bug QA
+*** Select from Slave ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5 c6 c7
+1 Replication Testing Extra Col Kyle 1 CURRENT_TIMESTAMP
+2 This Test Should work JOE 1 CURRENT_TIMESTAMP
+3 If is does not, I will open a bug QA 1 CURRENT_TIMESTAMP
+*** Drop t14 ***
+DROP TABLE t14;
+*** Create t15 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t15 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='MyISAM';
+*** Create t15 on Master ***
+CREATE TABLE t15 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5)) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t15 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add column on master that is a Extra on Slave ***
+ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5;
+********************************************
+*** Expect slave to fail with Error 1060 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1060
+Last_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Try to insert in master ****
+INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2
+*** Try to select from slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** DROP TABLE t15 ***
+DROP TABLE t15;
+*** Create t16 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t16 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='MyISAM';
+*** Create t16 on Master ***
+CREATE TABLE t16 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5))ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t16 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add Partition on master ***
+ALTER TABLE t16 PARTITION BY KEY(c1) PARTITIONS 4;
+INSERT INTO t16 () VALUES(4,1.00,'Replication Rocks',@b1,'Omer');
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** Show table on Slave ****
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ `c6` int(11) DEFAULT '1',
+ `c7` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`c1`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** DROP TABLE t16 ***
+DROP TABLE t16;
+*** Alter Master End ***
+*** Create t17 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t17 (a SMALLINT, b INT PRIMARY KEY, c CHAR(5),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='MyISAM';
+*** Create t17 on Master ***
+CREATE TABLE t17 (a BIGINT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t17 () VALUES(9223372036854775807,2,'Kyle, TEX');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 8, test.t17 has type 2
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+** DROP table t17 ***
+DROP TABLE t17;
diff --git a/mysql-test/r/rpl_ignore_table.result b/mysql-test/r/rpl_ignore_table.result
index 356a9dcb2f8..136cf5cc5eb 100644
--- a/mysql-test/r/rpl_ignore_table.result
+++ b/mysql-test/r/rpl_ignore_table.result
@@ -14,3 +14,19 @@ SELECT * FROM t4;
a
DROP TABLE t1;
DROP TABLE t4;
+DROP TABLE IF EXISTS t5;
+CREATE TABLE t5 (
+word varchar(50) collate utf8_unicode_ci NOT NULL default ''
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SET @@session.character_set_client=33,@@session.collation_connection=192;
+CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY;
+INSERT INTO t5 (word) VALUES ('TEST’');
+SELECT HEX(word) FROM t5;
+HEX(word)
+54455354E28099
+SELECT HEX(word) FROM t5;
+HEX(word)
+54455354E28099
+SELECT * FROM tmptbl504451f4258$1;
+ERROR 42S02: Table 'test.tmptbl504451f4258$1' doesn't exist
+DROP TABLE t5;
diff --git a/mysql-test/r/rpl_ndb_dd_advance.result b/mysql-test/r/rpl_ndb_dd_advance.result
index bbc67a04027..b29d1201a85 100644
--- a/mysql-test/r/rpl_ndb_dd_advance.result
+++ b/mysql-test/r/rpl_ndb_dd_advance.result
@@ -326,12 +326,12 @@ COUNT(*)
**** Must make sure slave is clean *****
STOP SLAVE;
RESET SLAVE;
-DROP PROCEDURE tpcb.load;
-DROP PROCEDURE tpcb.trans;
-DROP TABLE tpcb.account;
-DROP TABLE tpcb.teller;
-DROP TABLE tpcb.branch;
-DROP TABLE tpcb.history;
+DROP PROCEDURE IF EXISTS tpcb.load;
+DROP PROCEDURE IF EXISTS tpcb.trans;
+DROP TABLE IF EXISTS tpcb.account;
+DROP TABLE IF EXISTS tpcb.teller;
+DROP TABLE IF EXISTS tpcb.branch;
+DROP TABLE IF EXISTS tpcb.history;
DROP DATABASE tpcb;
ALTER TABLESPACE ts1
DROP DATAFILE 'datafile.dat'
@@ -392,8 +392,8 @@ COUNT(*)
4050
*** DUMP MASTER & SLAVE FOR COMPARE ********
*************** TEST 2 CLEANUP SECTION ********************
-DROP PROCEDURE tpcb.load;
-DROP PROCEDURE tpcb.trans;
+DROP PROCEDURE IF EXISTS tpcb.load;
+DROP PROCEDURE IF EXISTS tpcb.trans;
DROP TABLE tpcb.account;
DROP TABLE tpcb.teller;
DROP TABLE tpcb.branch;
diff --git a/mysql-test/r/rpl_ndb_ddl.result b/mysql-test/r/rpl_ndb_ddl.result
index de35175bf18..f5d8073be94 100644
--- a/mysql-test/r/rpl_ndb_ddl.result
+++ b/mysql-test/r/rpl_ndb_ddl.result
@@ -359,8 +359,6 @@ MAX(f1)
-------- switch to master -------
ROLLBACK;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
SELECT MAX(f1) FROM t1;
MAX(f1)
5
@@ -370,9 +368,9 @@ TEST-INFO: MASTER: The INSERT is not committed (Succeeded)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
-6
+5
-TEST-INFO: SLAVE: The INSERT is committed (Succeeded)
+TEST-INFO: SLAVE: The INSERT is not committed (Succeeded)
-------- switch to master -------
flush logs;
@@ -401,7 +399,7 @@ MAX(f1)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
-6
+5
-------- switch to master -------
RENAME TABLE mysqltest1.t3 to mysqltest1.t20;
@@ -506,7 +504,7 @@ f2 bigint(20) YES NULL
-------- switch to master -------
-######## CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB" ########
+######## CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "NDB" ########
-------- switch to master -------
INSERT INTO t1 SET f1= 7 + 1;
@@ -520,7 +518,7 @@ MAX(f1)
7
-------- switch to master -------
-CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB";
+CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "NDB";
SELECT MAX(f1) FROM t1;
MAX(f1)
8
@@ -579,8 +577,6 @@ MAX(f1)
-------- switch to master -------
ROLLBACK;
-Warnings:
-Warning 1196 Some non-transactional changed tables couldn't be rolled back
SELECT MAX(f1) FROM t1;
MAX(f1)
8
@@ -590,9 +586,9 @@ TEST-INFO: MASTER: The INSERT is not committed (Succeeded)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
-9
+8
-TEST-INFO: SLAVE: The INSERT is committed (Succeeded)
+TEST-INFO: SLAVE: The INSERT is not committed (Succeeded)
-------- switch to master -------
flush logs;
@@ -613,7 +609,7 @@ MAX(f1)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
-9
+8
-------- switch to master -------
TRUNCATE TABLE mysqltest1.t7;
@@ -650,11 +646,9 @@ flush logs;
-------- switch to master -------
SELECT * FROM mysqltest1.t7;
f1
-
-------- switch to slave --------
SELECT * FROM mysqltest1.t7;
f1
-
-------- switch to master -------
######## LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ ########
@@ -957,7 +951,7 @@ t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE
-------- switch to slave --------
SHOW INDEX FROM mysqltest1.t5;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
-t5 1 my_idx5 1 f1 A NULL NULL NULL YES BTREE
+t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE
-------- switch to master -------
@@ -1691,3 +1685,4 @@ user
DROP DATABASE IF EXISTS mysqltest1;
DROP DATABASE IF EXISTS mysqltest2;
DROP DATABASE IF EXISTS mysqltest3;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
diff --git a/mysql-test/r/rpl_ndb_extraCol.result b/mysql-test/r/rpl_ndb_extraCol.result
new file mode 100644
index 00000000000..e51fae29c54
--- /dev/null
+++ b/mysql-test/r/rpl_ndb_extraCol.result
@@ -0,0 +1,742 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+**** Diff Table Def Start ****
+*** On Slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t1 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(4) DEFAULT 'TEST')
+ENGINE='NDB';
+*** Create t1 on Master ***
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t1 () VALUES(1,2,'TEXAS'),(2,1,'AUSTIN'),(3,4,'QA');
+SELECT * FROM t1 ORDER BY a;
+a b c
+1 2 TEXAS
+2 1 AUSTIN
+3 4 QA
+*** Select from slave ***
+SELECT * FROM t1 ORDER BY a;
+a b c d e
+1 2 TEXAS 2 TEST
+2 1 AUSTIN 2 TEST
+3 4 QA 2 TEST
+*** Drop t1 ***
+DROP TABLE t1;
+*** Create t3 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t3 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='NDB';
+*** Create t3 on Master ***
+CREATE TABLE t3 (a BLOB, b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t3 () VALUES(@b1,2,'Kyle, TEX'),(@b1,1,'JOE AUSTIN'),(@b1,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 252, test.t3 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t3 ***
+DROP TABLE t3;
+*** Create t4 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t4 (a INT, b INT PRIMARY KEY, c CHAR(20),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='NDB';
+*** Create t4 on Master ***
+CREATE TABLE t4 (a DECIMAL(8,2), b INT PRIMARY KEY, c CHAR(20)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t4 () VALUES(100.22,2,'Kyle, TEX'),(200.26,1,'JOE AUSTIN'),
+(30000.22,4,'QA TESTING');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 246, test.t4 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t4 ***
+DROP TABLE t4;
+*** Create t5 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t5 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT, e DOUBLE,
+f DECIMAL(8,2))ENGINE='NDB';
+*** Create t5 on Master ***
+CREATE TABLE t5 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT, e BLOB,
+f FLOAT) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t5 () VALUES(1,'Kyle',200.23,1,'b1b1',23.00098),
+(2,'JOE',300.01,0,'b2b2',1.0000009);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 5 type mismatch - received type 4, test.t5 has type 246
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t5 ***
+DROP TABLE t5;
+*** Create t6 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t6 (a INT PRIMARY KEY, b CHAR(5),
+c FLOAT, d INT)ENGINE='NDB';
+*** Create t6 on Master ***
+CREATE TABLE t6 (a INT PRIMARY KEY, b VARCHAR(6),
+c DECIMAL(8,2), d BIT
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t6 () VALUES(1,'Kyle',200.23,1),
+(2,'JOE',300.01,0);
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 3 type mismatch - received type 16, test.t6 has type 3
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=3;
+*** Drop t6 ***
+DROP TABLE t6;
+DROP TABLE t6;
+START SLAVE;
+**** Diff Table Def End ****
+**** Extra Colums Start ****
+*** Create t7 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t7 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e CHAR(20) DEFAULT 'Extra Column Testing')
+ENGINE='NDB';
+*** Create t7 on Master ***
+CREATE TABLE t7 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t7 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t7 ORDER BY a;
+a b c
+1 b1b1 Kyle
+2 b1b1 JOE
+3 b1b1 QA
+*** Select from slave ***
+SELECT * FROM t7 ORDER BY a;
+a b c d e
+1 b1b1 Kyle 0000-00-00 00:00:00 Extra Column Testing
+2 b1b1 JOE 0000-00-00 00:00:00 Extra Column Testing
+3 b1b1 QA 0000-00-00 00:00:00 Extra Column Testing
+*** Drop t7 ***
+DROP TABLE t7;
+*** Create t8 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t8 (a INT KEY, b BLOB, c CHAR(5),
+d TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
+e INT)ENGINE='NDB';
+*** Create t8 on Master ***
+CREATE TABLE t8 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t8 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+*** Drop t8 ***
+DROP TABLE t8;
+*** Create t10 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t10 (a INT KEY, b BLOB, f DOUBLE DEFAULT '233',
+c CHAR(5), e INT DEFAULT '1')ENGINE='NDB';
+*** Create t10 on Master ***
+CREATE TABLE t10 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t10 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 254, test.t10 has type 5
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t10 ***
+DROP TABLE t10;
+*** Create t11 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t11 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB';
+*** Create t11 on Master ***
+CREATE TABLE t11 (a INT PRIMARY KEY, b BLOB, c VARCHAR(254)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t11 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 2 type mismatch - received type 15, test.t11 has type 252
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Drop t11 ***
+DROP TABLE t11;
+*** Create t12 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t12 (a INT KEY, b BLOB, f TEXT,
+c CHAR(5) DEFAULT 'test', e INT DEFAULT '1')ENGINE='NDB';
+*** Create t12 on Master ***
+CREATE TABLE t12 (a INT PRIMARY KEY, b BLOB, c BLOB
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t12 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t12 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ***
+SELECT * FROM t12 ORDER BY a;
+a b f c e
+1 b1b1b1b1b1b1b1b1 Kyle test 1
+2 b1b1b1b1b1b1b1b1 JOE test 1
+3 b1b1b1b1b1b1b1b1 QA test 1
+*** Drop t12 ***
+DROP TABLE t12;
+**** Extra Colums End ****
+*** BUG 22177 Start ***
+*** Create t13 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t13 (a INT KEY, b BLOB, c CHAR(5),
+d INT DEFAULT '1',
+e TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='NDB';
+*** Create t13 on Master ***
+CREATE TABLE t13 (a INT PRIMARY KEY, b BLOB, c CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t13 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
+SELECT * FROM t13 ORDER BY a;
+a b c
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t13 ORDER BY a;
+a b c d e
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Drop t13 ***
+DROP TABLE t13;
+*** 22117 END ***
+*** Alter Master Table Testing Start ***
+*** Create t14 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14 (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='NDB';
+*** Create t14 on Master ***
+CREATE TABLE t14 (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+ALTER TABLE t14 ADD COLUMN c2 DECIMAL(8,2) AFTER c1;
+ALTER TABLE t14 ADD COLUMN c3 TEXT AFTER c2;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** connect to master and drop columns ***
+ALTER TABLE t14 DROP COLUMN c2;
+ALTER TABLE t14 DROP COLUMN c4;
+*** Select from Master ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5
+1 Replication Testing Extra Col Kyle
+2 This Test Should work JOE
+3 If is does not, I will open a bug QA
+*** Select from Slave ***
+SELECT * FROM t14 ORDER BY c1;
+c1 c3 c5 c6 c7
+1 Replication Testing Extra Col Kyle 1 CURRENT_TIMESTAMP
+2 This Test Should work JOE 1 CURRENT_TIMESTAMP
+3 If is does not, I will open a bug QA 1 CURRENT_TIMESTAMP
+*** Drop t14 ***
+DROP TABLE t14;
+*** Create t15 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t15 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='NDB';
+*** Create t15 on Master ***
+CREATE TABLE t15 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5)) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t15 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add column on master that is a Extra on Slave ***
+ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5;
+********************************************
+*** Expect slave to fail with Error 1060 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1060
+Last_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+*** Try to insert in master ****
+INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2
+*** Try to select from slave ****
+SELECT * FROM t15 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP
+*** DROP TABLE t15 ***
+DROP TABLE t15;
+*** Create t16 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t16 (c1 INT KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='NDB';
+*** Create t16 on Master ***
+CREATE TABLE t16 (c1 INT PRIMARY KEY, c2 DECIMAL(8,2), c3 TEXT,
+c4 BLOB, c5 CHAR(5))ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t16 () VALUES(1,1.00,'Replication Testing Extra Col',@b1,'Kyle'),
+(2,2.00,'This Test Should work',@b1,'JOE'),
+(3,3.00,'If is does not, I will open a bug',@b1,'QA');
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t16 ORDER BY c1;
+c1 c2 c3 c4 c5 c6 c7
+1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Add Partition on master ***
+ALTER TABLE t16 PARTITION BY KEY(c1) PARTITIONS 4;
+INSERT INTO t16 () VALUES(4,1.00,'Replication Rocks',@b1,'Omer');
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** Show table on Slave ****
+SHOW CREATE TABLE t16;
+Table Create Table
+t16 CREATE TABLE `t16` (
+ `c1` int(11) NOT NULL,
+ `c2` decimal(8,2) DEFAULT NULL,
+ `c3` text,
+ `c4` blob,
+ `c5` char(5) DEFAULT NULL,
+ `c6` int(11) DEFAULT '1',
+ `c7` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`c1`)
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1 /*!50100 PARTITION BY KEY (c1) PARTITIONS 4 */
+*** DROP TABLE t16 ***
+DROP TABLE t16;
+*** Alter Master End ***
+*** Create t17 on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t17 (a SMALLINT, b INT PRIMARY KEY, c CHAR(5),
+d FLOAT DEFAULT '2.00',
+e CHAR(5) DEFAULT 'TEST2')
+ENGINE='NDB';
+*** Create t17 on Master ***
+CREATE TABLE t17 (a BIGINT PRIMARY KEY, b INT, c CHAR(10)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+INSERT INTO t17 () VALUES(9223372036854775807,2,'Kyle, TEX');
+********************************************
+*** Expect slave to fail with Error 1522 ***
+********************************************
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1522
+Last_Error Column 0 type mismatch - received type 8, test.t17 has type 2
+Skip_Counter 0
+Exec_Master_Log_Pos #
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+** DROP table t17 ***
+DROP TABLE t17;
diff --git a/mysql-test/r/rpl_packet.result b/mysql-test/r/rpl_packet.result
new file mode 100644
index 00000000000..a5c9b43cabb
--- /dev/null
+++ b/mysql-test/r/rpl_packet.result
@@ -0,0 +1,17 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
+create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
+select @@net_buffer_length, @@max_allowed_packet;
+@@net_buffer_length @@max_allowed_packet
+1024 1024
+create table `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
+INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1023');
+select count(*) from `DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________`.`t1` /* must be 1 */;
+count(*)
+1
+drop database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
diff --git a/mysql-test/r/strict_autoinc_1myisam.result b/mysql-test/r/strict_autoinc_1myisam.result
index dcda74a19cd..afcccb1c40f 100644
--- a/mysql-test/r/strict_autoinc_1myisam.result
+++ b/mysql-test/r/strict_autoinc_1myisam.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_2innodb.result b/mysql-test/r/strict_autoinc_2innodb.result
index 9e90ab886f3..e534286e2a2 100644
--- a/mysql-test/r/strict_autoinc_2innodb.result
+++ b/mysql-test/r/strict_autoinc_2innodb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_3heap.result b/mysql-test/r/strict_autoinc_3heap.result
index d22054eb59d..0a31da04460 100644
--- a/mysql-test/r/strict_autoinc_3heap.result
+++ b/mysql-test/r/strict_autoinc_3heap.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_4bdb.result b/mysql-test/r/strict_autoinc_4bdb.result
index 48ebe196baf..2e8980e435b 100644
--- a/mysql-test/r/strict_autoinc_4bdb.result
+++ b/mysql-test/r/strict_autoinc_4bdb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/strict_autoinc_5ndb.result b/mysql-test/r/strict_autoinc_5ndb.result
index debc7242e15..ea6e5ffc741 100644
--- a/mysql-test/r/strict_autoinc_5ndb.result
+++ b/mysql-test/r/strict_autoinc_5ndb.result
@@ -1,3 +1,4 @@
+drop table if exists t1;
set @org_mode=@@sql_mode;
create table t1
(
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 501d15efa82..4bc122cc97b 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -3015,3 +3015,22 @@ i j
DROP VIEW v1, v2;
DROP TABLE t1;
End of 5.0 tests.
+DROP DATABASE IF EXISTS `d-1`;
+CREATE DATABASE `d-1`;
+USE `d-1`;
+CREATE TABLE `t-1` (c1 INT);
+CREATE VIEW `v-1` AS SELECT c1 FROM `t-1`;
+SHOW TABLES;
+Tables_in_d-1
+t-1
+v-1
+RENAME TABLE `t-1` TO `t-2`;
+RENAME TABLE `v-1` TO `v-2`;
+SHOW TABLES;
+Tables_in_d-1
+t-2
+v-2
+DROP TABLE `t-2`;
+DROP VIEW `v-2`;
+DROP DATABASE `d-1`;
+USE test;
diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result
index efe7d14095d..bb7f84d0287 100644
--- a/mysql-test/r/xml.result
+++ b/mysql-test/r/xml.result
@@ -736,3 +736,76 @@ test
select extractValue('<x.-_:>test</x.-_:>','//*');
extractValue('<x.-_:>test</x.-_:>','//*')
test
+set @xml= "<entry><id>pt10</id><pt>10</pt></entry><entry><id>pt50</id><pt>50</pt></entry>";
+select ExtractValue(@xml, "/entry[(pt=10)]/id");
+ExtractValue(@xml, "/entry[(pt=10)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(pt!=10)]/id");
+ExtractValue(@xml, "/entry[(pt!=10)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(pt<10)]/id");
+ExtractValue(@xml, "/entry[(pt<10)]/id")
+
+select ExtractValue(@xml, "/entry[(pt<=10)]/id");
+ExtractValue(@xml, "/entry[(pt<=10)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(pt>10)]/id");
+ExtractValue(@xml, "/entry[(pt>10)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(pt>=10)]/id");
+ExtractValue(@xml, "/entry[(pt>=10)]/id")
+pt10 pt50
+select ExtractValue(@xml, "/entry[(pt=50)]/id");
+ExtractValue(@xml, "/entry[(pt=50)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(pt!=50)]/id");
+ExtractValue(@xml, "/entry[(pt!=50)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(pt<50)]/id");
+ExtractValue(@xml, "/entry[(pt<50)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(pt<=50)]/id");
+ExtractValue(@xml, "/entry[(pt<=50)]/id")
+pt10 pt50
+select ExtractValue(@xml, "/entry[(pt>50)]/id");
+ExtractValue(@xml, "/entry[(pt>50)]/id")
+
+select ExtractValue(@xml, "/entry[(pt>=50)]/id");
+ExtractValue(@xml, "/entry[(pt>=50)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(10=pt)]/id");
+ExtractValue(@xml, "/entry[(10=pt)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(10!=pt)]/id");
+ExtractValue(@xml, "/entry[(10!=pt)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(10>pt)]/id");
+ExtractValue(@xml, "/entry[(10>pt)]/id")
+
+select ExtractValue(@xml, "/entry[(10>=pt)]/id");
+ExtractValue(@xml, "/entry[(10>=pt)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(10<pt)]/id");
+ExtractValue(@xml, "/entry[(10<pt)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(10<=pt)]/id");
+ExtractValue(@xml, "/entry[(10<=pt)]/id")
+pt10 pt50
+select ExtractValue(@xml, "/entry[(50=pt)]/id");
+ExtractValue(@xml, "/entry[(50=pt)]/id")
+pt50
+select ExtractValue(@xml, "/entry[(50!=pt)]/id");
+ExtractValue(@xml, "/entry[(50!=pt)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(50>pt)]/id");
+ExtractValue(@xml, "/entry[(50>pt)]/id")
+pt10
+select ExtractValue(@xml, "/entry[(50>=pt)]/id");
+ExtractValue(@xml, "/entry[(50>=pt)]/id")
+pt10 pt50
+select ExtractValue(@xml, "/entry[(50<pt)]/id");
+ExtractValue(@xml, "/entry[(50<pt)]/id")
+
+select ExtractValue(@xml, "/entry[(50<=pt)]/id");
+ExtractValue(@xml, "/entry[(50<=pt)]/id")
+pt50
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 6c814368c88..dedba4caf0f 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -455,6 +455,23 @@ drop table t1;
deallocate prepare stmt;
#
+# Bug#22052 Trailing spaces are not removed from UNICODE fields in an index
+#
+create table t1 (
+ a char(10) unicode not null,
+ index a (a)
+) engine=myisam;
+insert into t1 values (repeat(0x201f, 10));
+insert into t1 values (repeat(0x2020, 10));
+insert into t1 values (repeat(0x2021, 10));
+# make sure "index read" is used
+explain select hex(a) from t1 order by a;
+select hex(a) from t1 order by a;
+alter table t1 drop index a;
+select hex(a) from t1 order by a;
+drop table t1;
+
+#
# Bug #20076: server crashes for a query with GROUP BY if MIN/MAX aggregation
# over a 'ucs2' field uses a temporary table
#
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 65ee82fff23..804b17ab6bb 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1229,6 +1229,30 @@ set @a:=null;
execute my_stmt using @a;
drop table if exists t1;
+
+#
+# Bug#21505 Create view - illegal mix of collation for operation 'UNION'
+#
+--disable_warnings
+drop table if exists t1;
+drop view if exists v1, v2;
+--enable_warnings
+set names utf8;
+create table t1(col1 varchar(12) character set utf8 collate utf8_unicode_ci);
+insert into t1 values('t1_val');
+create view v1 as select 'v1_val' as col1;
+select coercibility(col1), collation(col1) from v1;
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1)from v2;
+drop view v1, v2;
+create view v1 as select 'v1_val' collate utf8_swedish_ci as col1;
+select coercibility(col1), collation(col1) from v1;
+create view v2 as select col1 from v1 union select col1 from t1;
+select coercibility(col1), collation(col1) from v2;
+drop view v1, v2;
+drop table t1;
+
+
#
# Bug#19960: Inconsistent results when joining
# InnoDB tables using partial UTF8 indexes
diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test
index db3536c6d36..cde9c1fcea3 100644
--- a/mysql-test/t/func_gconcat.test
+++ b/mysql-test/t/func_gconcat.test
@@ -461,3 +461,38 @@ SELECT GROUP_CONCAT(a), x
GROUP BY x;
DROP TABLE t1;
+#
+# Bug#23451 GROUP_CONCAT truncates a multibyte utf8 character
+#
+set names utf8;
+create table t1
+(
+ x text character set utf8 not null,
+ y integer not null
+);
+insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
+let $1= 10;
+while ($1)
+{
+ eval set group_concat_max_len= 1022 + $1;
+ --disable_result_log
+ select @x:=group_concat(x) from t1 group by y;
+ --enable_result_log
+ select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
+ dec $1;
+}
+drop table t1;
+set group_concat_max_len=1024;
+set names latin1;
+
+#
+# Bug#14169 type of group_concat() result changed to blob if tmp_table was used
+#
+create table t1 (f1 int unsigned, f2 varchar(255));
+insert into t1 values (1,repeat('a',255)),(2,repeat('b',255));
+--enable_metadata
+select f2,group_concat(f1) from t1 group by f2;
+--disable_metadata
+drop table t1;
+
+# End of 4.1 tests
diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test
index 96437bc7636..31513f1bd06 100644
--- a/mysql-test/t/lowercase_table.test
+++ b/mysql-test/t/lowercase_table.test
@@ -85,3 +85,23 @@ drop table t1, t2;
show tables;
# End of 4.1 tests
+
+
+#
+# Bug#20404: SHOW CREATE TABLE fails with Turkish I
+#
+set names utf8;
+--disable_warnings
+drop table if exists Ä°,Ä°Ä°;
+--enable_warnings
+create table Ä° (s1 int);
+show create table Ä°;
+show tables;
+drop table Ä°;
+create table Ä°Ä° (s1 int);
+show create table Ä°Ä°;
+show tables;
+drop table Ä°Ä°;
+set names latin1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/rpl_do_grant.test b/mysql-test/t/rpl_do_grant.test
index 8d6f99e4bf1..4e398114269 100644
--- a/mysql-test/t/rpl_do_grant.test
+++ b/mysql-test/t/rpl_do_grant.test
@@ -39,11 +39,11 @@ connection master;
delete from mysql.user where user=_binary'rpl_do_grant';
delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges;
-save_master_pos;
-connection slave;
-sync_with_master;
-# no need to delete manually, as the DELETEs must have done some real job on
-# master (updated binlog)
+sync_slave_with_master;
+# The mysql database is not replicated, so we have to do the deletes
+# manually on the slave as well.
+delete from mysql.user where user=_binary'rpl_do_grant';
+delete from mysql.db where user=_binary'rpl_do_grant';
flush privileges;
# End of 4.1 tests
diff --git a/mysql-test/t/rpl_extraCol_innodb-master.opt b/mysql-test/t/rpl_extraCol_innodb-master.opt
new file mode 100644
index 00000000000..627becdbfb5
--- /dev/null
+++ b/mysql-test/t/rpl_extraCol_innodb-master.opt
@@ -0,0 +1 @@
+--innodb
diff --git a/mysql-test/t/rpl_extraCol_innodb-slave.opt b/mysql-test/t/rpl_extraCol_innodb-slave.opt
new file mode 100644
index 00000000000..627becdbfb5
--- /dev/null
+++ b/mysql-test/t/rpl_extraCol_innodb-slave.opt
@@ -0,0 +1 @@
+--innodb
diff --git a/mysql-test/t/rpl_extraCol_innodb.test b/mysql-test/t/rpl_extraCol_innodb.test
new file mode 100644
index 00000000000..e9685baf01b
--- /dev/null
+++ b/mysql-test/t/rpl_extraCol_innodb.test
@@ -0,0 +1,13 @@
+###########################################
+# Author: Jeb
+# Date: 2006-09-08
+# Purpose: Wapper for rpl_extraSlave_Col.test
+# Using innodb
+###########################################
+-- source include/have_binlog_format_row.inc
+-- source include/have_innodb.inc
+-- source include/master-slave.inc
+let $engine_type = 'InnoDB';
+-- source extra/rpl_tests/rpl_extraSlave_Col.test
+
+
diff --git a/mysql-test/t/rpl_extraCol_myisam.test b/mysql-test/t/rpl_extraCol_myisam.test
new file mode 100644
index 00000000000..d56df394ccf
--- /dev/null
+++ b/mysql-test/t/rpl_extraCol_myisam.test
@@ -0,0 +1,12 @@
+###########################################
+# Author: Jeb
+# Date: 2006-09-07
+# Purpose: Wapper for rpl_extraSlave_Col.test
+# Using MyISAM
+###########################################
+-- source include/have_binlog_format_row.inc
+-- source include/master-slave.inc
+let $engine_type = 'MyISAM';
+-- source extra/rpl_tests/rpl_extraSlave_Col.test
+
+
diff --git a/mysql-test/t/rpl_ignore_table-slave.opt b/mysql-test/t/rpl_ignore_table-slave.opt
index cb49119bfcb..3aabbb2e0f5 100644
--- a/mysql-test/t/rpl_ignore_table-slave.opt
+++ b/mysql-test/t/rpl_ignore_table-slave.opt
@@ -1 +1 @@
---replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3
+--replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3 --replicate-wild-ignore-table=%.tmptbl%
diff --git a/mysql-test/t/rpl_ignore_table.test b/mysql-test/t/rpl_ignore_table.test
index 84b0a4cde38..10c75db0b70 100644
--- a/mysql-test/t/rpl_ignore_table.test
+++ b/mysql-test/t/rpl_ignore_table.test
@@ -28,3 +28,27 @@ connection master;
DROP TABLE t1;
DROP TABLE t4;
sync_slave_with_master;
+
+#
+# bug#22877 replication character sets get out of sync
+# using replicate-wild-ignore-table
+#
+connection master;
+--disable_warnings
+DROP TABLE IF EXISTS t5;
+--enable_warnings
+CREATE TABLE t5 (
+ word varchar(50) collate utf8_unicode_ci NOT NULL default ''
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SET @@session.character_set_client=33,@@session.collation_connection=192;
+CREATE TEMPORARY TABLE tmptbl504451f4258$1 (id INT NOT NULL) ENGINE=MEMORY;
+INSERT INTO t5 (word) VALUES ('TEST’');
+SELECT HEX(word) FROM t5;
+sync_slave_with_master;
+connection slave;
+SELECT HEX(word) FROM t5;
+--error 1146
+SELECT * FROM tmptbl504451f4258$1;
+connection master;
+DROP TABLE t5;
+sync_slave_with_master;
diff --git a/mysql-test/t/rpl_ndb_dd_advance.test b/mysql-test/t/rpl_ndb_dd_advance.test
index 1fe36ecd8a1..a77521f3a82 100644
--- a/mysql-test/t/rpl_ndb_dd_advance.test
+++ b/mysql-test/t/rpl_ndb_dd_advance.test
@@ -385,12 +385,12 @@ while ($j)
--connection slave
STOP SLAVE;
RESET SLAVE;
-DROP PROCEDURE tpcb.load;
-DROP PROCEDURE tpcb.trans;
-DROP TABLE tpcb.account;
-DROP TABLE tpcb.teller;
-DROP TABLE tpcb.branch;
-DROP TABLE tpcb.history;
+DROP PROCEDURE IF EXISTS tpcb.load;
+DROP PROCEDURE IF EXISTS tpcb.trans;
+DROP TABLE IF EXISTS tpcb.account;
+DROP TABLE IF EXISTS tpcb.teller;
+DROP TABLE IF EXISTS tpcb.branch;
+DROP TABLE IF EXISTS tpcb.history;
DROP DATABASE tpcb;
ALTER TABLESPACE ts1
@@ -534,8 +534,8 @@ SELECT COUNT(*) FROM history;
--echo *************** TEST 2 CLEANUP SECTION ********************
connection master;
-DROP PROCEDURE tpcb.load;
-DROP PROCEDURE tpcb.trans;
+DROP PROCEDURE IF EXISTS tpcb.load;
+DROP PROCEDURE IF EXISTS tpcb.trans;
DROP TABLE tpcb.account;
DROP TABLE tpcb.teller;
DROP TABLE tpcb.branch;
diff --git a/mysql-test/t/rpl_ndb_ddl.test b/mysql-test/t/rpl_ndb_ddl.test
index b3d32232518..0c503e56c9c 100644
--- a/mysql-test/t/rpl_ndb_ddl.test
+++ b/mysql-test/t/rpl_ndb_ddl.test
@@ -31,4 +31,5 @@
--source include/have_ndb.inc
--source include/master-slave.inc
let $engine_type= "NDB";
--- source extra/rpl_tests/rpl_ddl.test
+-- source extra/rpl_tests/rpl_ndb_ddl.test
+
diff --git a/mysql-test/t/rpl_ndb_extraCol.test b/mysql-test/t/rpl_ndb_extraCol.test
new file mode 100644
index 00000000000..cf0501c490a
--- /dev/null
+++ b/mysql-test/t/rpl_ndb_extraCol.test
@@ -0,0 +1,13 @@
+###########################################
+# Author: Jeb
+# Date: 2006-09-08
+# Purpose: Wapper for rpl_extraSlave_Col.test
+# Using NDB
+###########################################
+-- source include/have_binlog_format_row.inc
+--source include/have_ndb.inc
+-- source include/master-slave.inc
+let $engine_type = 'NDB';
+-- source extra/rpl_tests/rpl_extraSlave_Col.test
+
+
diff --git a/mysql-test/t/rpl_packet-master.opt b/mysql-test/t/rpl_packet-master.opt
new file mode 100644
index 00000000000..42d4f94c999
--- /dev/null
+++ b/mysql-test/t/rpl_packet-master.opt
@@ -0,0 +1 @@
+-O max_allowed_packet=1024 -O net_buffer_length=1024
diff --git a/mysql-test/t/rpl_packet-slave.opt b/mysql-test/t/rpl_packet-slave.opt
new file mode 100644
index 00000000000..42d4f94c999
--- /dev/null
+++ b/mysql-test/t/rpl_packet-slave.opt
@@ -0,0 +1 @@
+-O max_allowed_packet=1024 -O net_buffer_length=1024
diff --git a/mysql-test/t/rpl_packet.test b/mysql-test/t/rpl_packet.test
new file mode 100644
index 00000000000..d01979a4731
--- /dev/null
+++ b/mysql-test/t/rpl_packet.test
@@ -0,0 +1,39 @@
+#
+# Check replication protocol packet size handling
+# Bug#19402 SQL close to the size of the max_allowed_packet fails on slave
+#
+
+# max-out size db name
+source include/master-slave.inc;
+
+let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
+disable_warnings;
+eval drop database if exists $db;
+enable_warnings;
+eval create database $db;
+
+connection master;
+select @@net_buffer_length, @@max_allowed_packet;
+disconnect master;
+
+# alas, can't use eval here; if db name changed apply the change here
+connect (master,localhost,root,,DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________);
+
+connection master;
+create table `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
+
+INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1023');
+save_master_pos;
+
+connection slave;
+sync_with_master;
+eval select count(*) from `$db`.`t1` /* must be 1 */;
+
+connection master;
+eval drop database $db;
+save_master_pos;
+
+connection slave;
+sync_with_master;
+
+# End of tests
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index fa3ddd28489..7175db1db4e 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2959,3 +2959,22 @@ DROP TABLE t1;
--echo End of 5.0 tests.
+
+#
+# Bug#21370 View renaming lacks tablename_to_filename encoding
+#
+--disable_warnings
+DROP DATABASE IF EXISTS `d-1`;
+--enable_warnings
+CREATE DATABASE `d-1`;
+USE `d-1`;
+CREATE TABLE `t-1` (c1 INT);
+CREATE VIEW `v-1` AS SELECT c1 FROM `t-1`;
+SHOW TABLES;
+RENAME TABLE `t-1` TO `t-2`;
+RENAME TABLE `v-1` TO `v-2`;
+SHOW TABLES;
+DROP TABLE `t-2`;
+DROP VIEW `v-2`;
+DROP DATABASE `d-1`;
+USE test;
diff --git a/mysql-test/t/windows.test b/mysql-test/t/windows.test
index d979c001454..4dab646df2c 100644
--- a/mysql-test/t/windows.test
+++ b/mysql-test/t/windows.test
@@ -39,3 +39,4 @@ execute abc;
--error ER_UDF_NO_PATHS
execute abc;
deallocate prepare abc;
+
diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test
index 3347573b4b7..ef94c7508c4 100644
--- a/mysql-test/t/xml.test
+++ b/mysql-test/t/xml.test
@@ -376,3 +376,33 @@ select extractValue('<:>test</:>','//*');
select extractValue('<_>test</_>','//*');
# dot, dash, underscore and semicolon are good identifier middle characters
select extractValue('<x.-_:>test</x.-_:>','//*');
+
+#
+# Bug#22823 gt and lt operators appear to be
+# reversed in ExtractValue() command
+#
+set @xml= "<entry><id>pt10</id><pt>10</pt></entry><entry><id>pt50</id><pt>50</pt></entry>";
+select ExtractValue(@xml, "/entry[(pt=10)]/id");
+select ExtractValue(@xml, "/entry[(pt!=10)]/id");
+select ExtractValue(@xml, "/entry[(pt<10)]/id");
+select ExtractValue(@xml, "/entry[(pt<=10)]/id");
+select ExtractValue(@xml, "/entry[(pt>10)]/id");
+select ExtractValue(@xml, "/entry[(pt>=10)]/id");
+select ExtractValue(@xml, "/entry[(pt=50)]/id");
+select ExtractValue(@xml, "/entry[(pt!=50)]/id");
+select ExtractValue(@xml, "/entry[(pt<50)]/id");
+select ExtractValue(@xml, "/entry[(pt<=50)]/id");
+select ExtractValue(@xml, "/entry[(pt>50)]/id");
+select ExtractValue(@xml, "/entry[(pt>=50)]/id");
+select ExtractValue(@xml, "/entry[(10=pt)]/id");
+select ExtractValue(@xml, "/entry[(10!=pt)]/id");
+select ExtractValue(@xml, "/entry[(10>pt)]/id");
+select ExtractValue(@xml, "/entry[(10>=pt)]/id");
+select ExtractValue(@xml, "/entry[(10<pt)]/id");
+select ExtractValue(@xml, "/entry[(10<=pt)]/id");
+select ExtractValue(@xml, "/entry[(50=pt)]/id");
+select ExtractValue(@xml, "/entry[(50!=pt)]/id");
+select ExtractValue(@xml, "/entry[(50>pt)]/id");
+select ExtractValue(@xml, "/entry[(50>=pt)]/id");
+select ExtractValue(@xml, "/entry[(50<pt)]/id");
+select ExtractValue(@xml, "/entry[(50<=pt)]/id");
diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh
index 68798e92725..ddcea343609 100644
--- a/scripts/make_binary_distribution.sh
+++ b/scripts/make_binary_distribution.sh
@@ -243,6 +243,7 @@ $CP mysql-test/lib/*.pl $BASE/mysql-test/lib
$CP mysql-test/lib/*.sql $BASE/mysql-test/lib
$CP mysql-test/t/*.def $BASE/mysql-test/t
$CP mysql-test/include/*.inc $BASE/mysql-test/include
+$CP mysql-test/include/*.test $BASE/mysql-test/include
$CP mysql-test/t/*.def $BASE/mysql-test/t
$CP mysql-test/std_data/*.dat mysql-test/std_data/*.frm \
mysql-test/std_data/*.pem mysql-test/std_data/Moscow_leap \
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 1c2944de530..4cdc4c01c4e 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -54,6 +54,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
+ rpl_rli.cc rpl_mi.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 9a0303a433f..ac2f4836c15 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -54,7 +54,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
ha_ndbcluster.h ha_ndbcluster_binlog.h \
ha_ndbcluster_tables.h \
opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
- log.h sql_show.h rpl_rli.h \
+ log.h sql_show.h rpl_rli.h rpl_mi.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h sql_repl.h slave.h rpl_filter.h \
@@ -94,7 +94,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
- rpl_utility.cc rpl_injector.cc \
+ rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \
sql_union.cc sql_derived.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc \
diff --git a/sql/field.cc b/sql/field.cc
index 122a44305f2..1e42a53e45a 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1427,6 +1427,7 @@ Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
field_charset=charset;
if (charset->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
+ field_derivation= DERIVATION_IMPLICIT;
}
@@ -5921,38 +5922,149 @@ void Field_datetime::sql_type(String &res) const
** A string may be varchar or binary
****************************************************************************/
+/*
+ Report "not well formed" or "cannot convert" error
+ after storing a character string info a field.
+
+ SYNOPSIS
+ check_string_copy_error()
+ field - Field
+ well_formed_error_pos - where not well formed data was first met
+ cannot_convert_error_pos - where a not-convertable character was first met
+ end - end of the string
+
+ NOTES
+ As of version 5.0 both cases return the same error:
+
+ "Invalid string value: 'xxx' for column 't' at row 1"
+
+ Future versions will possibly introduce a new error message:
+
+ "Cannot convert character string: 'xxx' for column 't' at row 1"
+
+ RETURN
+ FALSE - If errors didn't happen
+ TRUE - If an error happened
+*/
+
+static bool
+check_string_copy_error(Field_str *field,
+ const char *well_formed_error_pos,
+ const char *cannot_convert_error_pos,
+ const char *end)
+{
+ const char *pos, *end_orig;
+ char tmp[64], *t;
+
+ if (!(pos= well_formed_error_pos) &&
+ !(pos= cannot_convert_error_pos))
+ return FALSE;
+
+ end_orig= end;
+ set_if_smaller(end, pos + 6);
+
+ for (t= tmp; pos < end; pos++)
+ {
+ if (((unsigned char) *pos) >= 0x20 &&
+ ((unsigned char) *pos) <= 0x7F)
+ {
+ *t++= *pos;
+ }
+ else
+ {
+ *t++= '\\';
+ *t++= 'x';
+ *t++= _dig_vec_upper[((unsigned char) *pos) >> 4];
+ *t++= _dig_vec_upper[((unsigned char) *pos) & 15];
+ }
+ }
+ if (end_orig > end)
+ {
+ *t++= '.';
+ *t++= '.';
+ *t++= '.';
+ }
+ *t= '\0';
+ push_warning_printf(field->table->in_use,
+ field->table->in_use->abort_on_warning ?
+ MYSQL_ERROR::WARN_LEVEL_ERROR :
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "string", tmp, field->field_name,
+ (ulong) field->table->in_use->row_count);
+ return TRUE;
+}
+
+
+
+/*
+ Send a truncation warning or a truncation error
+ after storing a too long character string info a field.
+
+ SYNOPSIS
+ report_data_too_long()
+ field - Field
+
+ RETURN
+ N/A
+*/
+
+inline void
+report_data_too_long(Field_str *field)
+{
+ if (field->table->in_use->abort_on_warning)
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
+ else
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+}
+
+
+/*
+ Test if the given string contains important data:
+ not spaces for character string,
+ or any data for binary string.
+
+ SYNOPSIS
+ test_if_important_data()
+ cs Character set
+ str String to test
+ strend String end
+
+ RETURN
+ FALSE - If string does not have important data
+ TRUE - If string has some important data
+*/
+
+static bool
+test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
+{
+ if (cs != &my_charset_bin)
+ str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+ return (str < strend);
+}
+
+
/* Copy a string and fill with space */
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- int error= 0, well_formed_error;
- uint32 not_used;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
- /* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
-
- /* Make sure we don't break a multibyte sequence or copy malformed data. */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from+length,
- field_length/
- field_charset->mbmaxlen,
- &well_formed_error);
- memmove(ptr, from, copy_length);
+ copy_length= well_formed_copy_nchars(field_charset,
+ ptr, field_length,
+ cs, from, length,
+ field_length / field_charset->mbmaxlen,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
@@ -5960,32 +6072,23 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
field_length-copy_length,
field_charset->pad_char);
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
/*
Check if we lost any important data (anything in a binary string,
or any non-space in others).
*/
- if ((copy_length < length) && table->in_use->count_cuted_fields)
+ if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
- if (binary())
- error= 2;
- else
+ if (test_if_important_data(field_charset, from_end_pos, from + length))
{
- const char *end=from+length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end,
- MY_SEQ_SPACES);
- if (from != end)
- error= 2;
+ report_data_too_long(this);
+ return 2;
}
}
- if (error)
- {
- if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
- else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- }
- return error;
+ return 0;
}
@@ -6343,58 +6446,35 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- uint32 not_used, copy_length;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- int error_code= 0, well_formed_error;
- enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ uint copy_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos;
+
+ copy_length= well_formed_copy_nchars(field_charset,
+ ptr + length_bytes, field_length,
+ cs, from, length,
+ field_length / field_charset->mbmaxlen,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
- /* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used))
- {
- uint conv_errors;
- tmpstr.copy(from, length, cs, field_charset, &conv_errors);
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error_code= WARN_DATA_TRUNCATED;
- }
- /*
- Make sure we don't break a multibyte sequence
- as well as don't copy a malformed data.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from+length,
- field_length/
- field_charset->mbmaxlen,
- &well_formed_error);
- memmove(ptr + length_bytes, from, copy_length);
if (length_bytes == 1)
*ptr= (uchar) copy_length;
else
int2store(ptr, copy_length);
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
// Check if we lost something other than just trailing spaces
- if ((copy_length < length) && table->in_use->count_cuted_fields &&
- !error_code)
- {
- if (!binary())
- {
- const char *end= from + length;
- from+= copy_length;
- from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
- /* If we lost only spaces then produce a NOTE, not a WARNING */
- if (from == end)
- level= MYSQL_ERROR::WARN_LEVEL_NOTE;
- }
- error_code= WARN_DATA_TRUNCATED;
- }
- if (error_code)
+ if ((from_end_pos < from + length) && table->in_use->count_cuted_fields)
{
- if (level == MYSQL_ERROR::WARN_LEVEL_WARN &&
- table->in_use->abort_on_warning)
- error_code= ER_DATA_TOO_LONG;
- set_warning(level, error_code, 1);
+ if (test_if_important_data(field_charset, from_end_pos, from + length))
+ report_data_too_long(this);
+ else /* If we lost only spaces then produce a NOTE, not a WARNING */
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
return 2;
}
return 0;
@@ -7012,68 +7092,70 @@ void Field_blob::put_length(char *pos, uint32 length)
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- int error= 0, well_formed_error;
+ uint copy_length, new_length;
+ const char *well_formed_error_pos;
+ const char *cannot_convert_error_pos;
+ const char *from_end_pos, *tmp;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+
if (!length)
{
bzero(ptr,Field_blob::pack_length());
+ return 0;
}
- else
- {
- bool was_conversion;
- char buff[STRING_BUFFER_USUAL_SIZE];
- String tmpstr(buff,sizeof(buff), &my_charset_bin);
- uint copy_length;
- uint32 not_used;
- /* Convert character set if necessary */
- if ((was_conversion= String::needs_conversion(length, cs, field_charset,
- &not_used)))
- {
- uint conv_errors;
- if (tmpstr.copy(from, length, cs, field_charset, &conv_errors))
- {
- /* Fatal OOM error */
- bzero(ptr,Field_blob::pack_length());
- return -1;
- }
- from= tmpstr.ptr();
- length= tmpstr.length();
- if (conv_errors)
- error= 2;
- }
-
- copy_length= max_data_length();
- /*
- copy_length is OK as last argument to well_formed_len as this is never
- used to limit the length of the data. The cut of long data is done with
- the 'min()' call below.
- */
- copy_length= field_charset->cset->well_formed_len(field_charset,
- from,from +
- min(length, copy_length),
- copy_length,
- &well_formed_error);
- if (copy_length < length)
- error= 2;
- Field_blob::store_length(copy_length);
- if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH)
- { // Must make a copy
- if (from != value.ptr()) // For valgrind
- {
- value.copy(from,copy_length,charset());
- from=value.ptr();
- }
+ if (from == value.ptr())
+ {
+ uint32 dummy_offset;
+ if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
+ {
+ Field_blob::store_length(length);
+ bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ return 0;
}
- bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ if (tmpstr.copy(from, length, cs))
+ goto oom_error;
+ from= tmpstr.ptr();
}
- if (error)
+
+ new_length= min(max_data_length(), field_charset->mbmaxlen * length);
+ if (value.alloc(new_length))
+ goto oom_error;
+
+ /*
+ "length" is OK as "nchars" argument to well_formed_copy_nchars as this
+ is never used to limit the length of the data. The cut of long data
+ is done with the new_length value.
+ */
+ copy_length= well_formed_copy_nchars(field_charset,
+ (char*) value.ptr(), new_length,
+ cs, from, length,
+ length,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
+
+ Field_blob::store_length(copy_length);
+ tmp= value.ptr();
+ bmove(ptr+packlength,(char*) &tmp,sizeof(char*));
+
+ if (check_string_copy_error(this, well_formed_error_pos,
+ cannot_convert_error_pos, from + length))
+ return 2;
+
+ if (copy_length < length)
{
- if (table->in_use->abort_on_warning)
- set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
- else
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ report_data_too_long(this);
+ return 2;
}
+
return 0;
+
+oom_error:
+ /* Fatal OOM error */
+ bzero(ptr,Field_blob::pack_length());
+ return -1;
}
diff --git a/sql/field.h b/sql/field.h
index 9b81931d416..f0cd9cc6f03 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -351,6 +351,9 @@ public:
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { }
+ virtual enum Derivation derivation(void) const
+ { return DERIVATION_IMPLICIT; }
+ virtual void set_derivation(enum Derivation derivation) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
bool check_int(const char *str, int length, const char *int_end,
@@ -446,6 +449,7 @@ public:
class Field_str :public Field {
protected:
CHARSET_INFO *field_charset;
+ enum Derivation field_derivation;
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -459,6 +463,9 @@ public:
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
+ enum Derivation derivation(void) const { return field_derivation; }
+ virtual void set_derivation(enum Derivation derivation_arg)
+ { field_derivation= derivation_arg; }
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_length() { return field_length; }
friend class create_field;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 9df2171d85c..76999896e3c 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -413,7 +413,7 @@ Thd_ndb::get_open_table(THD *thd, const void *key)
thd_ndb_share->stat.no_uncommitted_rows_count= 0;
thd_ndb_share->stat.records= ~(ha_rows)0;
}
- DBUG_PRINT("exit", ("thd_ndb_share: 0x%x key: 0x%x", thd_ndb_share, key));
+ DBUG_PRINT("exit", ("thd_ndb_share: %p key: %p", thd_ndb_share, key));
DBUG_RETURN(thd_ndb_share);
}
@@ -1171,7 +1171,7 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
index= dict->getIndexGlobal(index_name, *m_table);
if (!index)
ERR_RETURN(dict->getNdbError());
- DBUG_PRINT("info", ("index: 0x%x id: %d version: %d.%d status: %d",
+ DBUG_PRINT("info", ("index: %p id: %d version: %d.%d status: %d",
index,
index->getObjectId(),
index->getObjectVersion() & 0xFFFFFF,
@@ -1215,7 +1215,7 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
index= dict->getIndexGlobal(unique_index_name, *m_table);
if (!index)
ERR_RETURN(dict->getNdbError());
- DBUG_PRINT("info", ("index: 0x%x id: %d version: %d.%d status: %d",
+ DBUG_PRINT("info", ("index: %p id: %d version: %d.%d status: %d",
index,
index->getObjectId(),
index->getObjectVersion() & 0xFFFFFF,
@@ -2072,7 +2072,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
all pending update or delete operations should
be sent to NDB
*/
- DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending));
+ DBUG_PRINT("info", ("ops_pending: %llu", m_ops_pending));
if (m_ops_pending)
{
if (m_transaction_on)
@@ -3480,7 +3480,7 @@ int ha_ndbcluster::close_scan()
Take over any pending transactions to the
deleteing/updating transaction before closing the scan
*/
- DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending));
+ DBUG_PRINT("info", ("ops_pending: %llu", m_ops_pending));
if (execute_no_commit(this,trans,false) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
@@ -4286,7 +4286,7 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
while ((share= it++))
{
pthread_mutex_lock(&share->mutex);
- DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %d ",
+ DBUG_PRINT("info", ("Invalidate commit_count for %s, commit_count: %llu ",
share->key, share->commit_count));
share->commit_count= 0;
share->commit_count_lock++;
@@ -4691,7 +4691,7 @@ int ha_ndbcluster::create(const char *name,
DBUG_RETURN(2);
}
- DBUG_PRINT("info", ("setFrm data=%lx len=%d", pack_data, pack_length));
+ DBUG_PRINT("info", ("setFrm data=%p len=%d", pack_data, pack_length));
tab.setFrm(pack_data, pack_length);
my_free((char*)data, MYF(0));
my_free((char*)pack_data, MYF(0));
@@ -5103,8 +5103,8 @@ int ha_ndbcluster::add_index(TABLE *table_arg,
KEY *key_info, uint num_of_keys)
{
DBUG_ENTER("ha_ndbcluster::add_index");
- DBUG_PRINT("info", ("ha_ndbcluster::add_index to table %s",
- table_arg->s->table_name));
+ DBUG_PRINT("info", ("ha_ndbcluster::add_index to table %s",
+ table_arg->s->table_name.str));
int error= 0;
uint idx;
@@ -6103,9 +6103,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path)
#endif
DBUG_VOID_RETURN;
}
-/*
- find all tables in ndb and discover those needed
-*/
+
int ndb_create_table_from_engine(THD *thd, const char *db,
const char *table_name)
{
@@ -6118,6 +6116,9 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
return res;
}
+/*
+ find all tables in ndb and discover those needed
+*/
int ndbcluster_find_all_files(THD *thd)
{
DBUG_ENTER("ndbcluster_find_all_files");
@@ -7162,31 +7163,51 @@ static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
return (byte*) share->key;
}
+
#ifndef DBUG_OFF
-static void dbug_print_open_tables()
+
+static void print_share(const char* where, NDB_SHARE* share)
{
- DBUG_ENTER("dbug_print_open_tables");
- for (uint i= 0; i < ndbcluster_open_tables.records; i++)
- {
- NDB_SHARE *share= (NDB_SHARE*) hash_element(&ndbcluster_open_tables, i);
- DBUG_PRINT("share",
- ("[%d] 0x%lx key: %s key_length: %d",
- i, share, share->key, share->key_length));
- DBUG_PRINT("share",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- share->db, share->table_name,
- share->use_count, share->commit_count));
+ fprintf(DBUG_FILE,
+ "%s %s.%s: use_count: %u, commit_count: %llu\n",
+ where, share->db, share->table_name, share->use_count,
+ share->commit_count);
+ fprintf(DBUG_FILE,
+ " - key: %s, key_length: %d\n",
+ share->key, share->key_length);
+
#ifdef HAVE_NDB_BINLOG
- if (share->table)
- DBUG_PRINT("share",
- ("table->s->db.table_name: %s.%s",
- share->table->s->db.str, share->table->s->table_name.str));
+ if (share->table)
+ fprintf(DBUG_FILE,
+ " - share->table: %p %s.%s\n",
+ share->table, share->table->s->db.str,
+ share->table->s->table_name.str);
#endif
- }
- DBUG_VOID_RETURN;
}
-#else
-#define dbug_print_open_tables()
+
+
+static void print_ndbcluster_open_tables()
+{
+ DBUG_LOCK_FILE;
+ fprintf(DBUG_FILE, ">ndbcluster_open_tables\n");
+ for (uint i= 0; i < ndbcluster_open_tables.records; i++)
+ print_share("",
+ (NDB_SHARE*)hash_element(&ndbcluster_open_tables, i));
+ fprintf(DBUG_FILE, "<ndbcluster_open_tables\n");
+ DBUG_UNLOCK_FILE;
+}
+
+
+#define dbug_print_open_tables() \
+ DBUG_EXECUTE("info", \
+ print_ndbcluster_open_tables(););
+
+#define dbug_print_share(t, s) \
+ DBUG_LOCK_FILE; \
+ DBUG_EXECUTE("info", \
+ print_share((t), (s));); \
+ DBUG_UNLOCK_FILE;
+
#endif
#ifdef HAVE_NDB_BINLOG
@@ -7331,19 +7352,9 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
share->table_name= share->db + strlen(share->db) + 1;
ha_ndbcluster::set_tabname(new_key, share->table_name);
- DBUG_PRINT("rename_share",
- ("0x%lx key: %s key_length: %d",
- share, share->key, share->key_length));
- DBUG_PRINT("rename_share",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- share->db, share->table_name,
- share->use_count, share->commit_count));
+ dbug_print_share("rename_share:", share);
if (share->table)
{
- DBUG_PRINT("rename_share",
- ("table->s->db.table_name: %s.%s",
- share->table->s->db.str, share->table->s->table_name.str));
-
if (share->op == 0)
{
share->table->s->db.str= share->db;
@@ -7371,14 +7382,7 @@ NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share)
share->use_count++;
dbug_print_open_tables();
-
- DBUG_PRINT("get_share",
- ("0x%lx key: %s key_length: %d",
- share, share->key, share->key_length));
- DBUG_PRINT("get_share",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- share->db, share->table_name,
- share->use_count, share->commit_count));
+ dbug_print_share("ndbcluster_get_share:", share);
pthread_mutex_unlock(&ndbcluster_mutex);
return share;
}
@@ -7469,14 +7473,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
share->use_count++;
dbug_print_open_tables();
-
- DBUG_PRINT("info",
- ("0x%lx key: %s key_length: %d key: %s",
- share, share->key, share->key_length, key));
- DBUG_PRINT("info",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- share->db, share->table_name,
- share->use_count, share->commit_count));
+ dbug_print_share("ndbcluster_get_share:", share);
if (!have_lock)
pthread_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(share);
@@ -7486,13 +7483,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
void ndbcluster_real_free_share(NDB_SHARE **share)
{
DBUG_ENTER("ndbcluster_real_free_share");
- DBUG_PRINT("real_free_share",
- ("0x%lx key: %s key_length: %d",
- (*share), (*share)->key, (*share)->key_length));
- DBUG_PRINT("real_free_share",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- (*share)->db, (*share)->table_name,
- (*share)->use_count, (*share)->commit_count));
+ dbug_print_share("ndbcluster_real_free_share:", *share);
hash_delete(&ndbcluster_open_tables, (byte*) *share);
thr_lock_delete(&(*share)->lock);
@@ -7521,12 +7512,7 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
DBUG_VOID_RETURN;
}
-/*
- decrease refcount of share
- calls real_free_share when refcount reaches 0
- have_lock == TRUE, pthread_mutex_lock(&ndbcluster_mutex) already taken
-*/
void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
{
if (!have_lock)
@@ -7540,13 +7526,7 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
else
{
dbug_print_open_tables();
- DBUG_PRINT("free_share",
- ("0x%lx key: %s key_length: %d",
- *share, (*share)->key, (*share)->key_length));
- DBUG_PRINT("free_share",
- ("db.tablename: %s.%s use_count: %d commit_count: %d",
- (*share)->db, (*share)->table_name,
- (*share)->use_count, (*share)->commit_count));
+ dbug_print_share("ndbcluster_free_share:", *share);
}
if (!have_lock)
pthread_mutex_unlock(&ndbcluster_mutex);
@@ -8176,27 +8156,25 @@ ha_ndbcluster::update_table_comment(
pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
{
THD *thd; /* needs to be first for thread_stack */
- Ndb* ndb;
struct timespec abstime;
List<NDB_SHARE> util_open_tables;
+ Thd_ndb *thd_ndb;
my_thread_init();
DBUG_ENTER("ndb_util_thread");
- DBUG_PRINT("enter", ("ndb_cache_check_time: %d", ndb_cache_check_time));
+ DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time));
thd= new THD; /* note that contructor of THD uses DBUG_ */
THD_CHECK_SENTRY(thd);
- ndb= new Ndb(g_ndb_cluster_connection, "");
pthread_detach_this_thread();
ndb_util_thread= pthread_self();
thd->thread_stack= (char*)&thd; /* remember where our stack is */
- if (thd->store_globals() || (ndb->init() != 0))
+ if (thd->store_globals())
{
thd->cleanup();
delete thd;
- delete ndb;
DBUG_RETURN(NULL);
}
thd->init_for_queries();
@@ -8238,16 +8216,14 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
}
pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ /* Get thd_ndb for this thread */
+ if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
{
- Thd_ndb *thd_ndb;
- if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
- {
- sql_print_error("Could not allocate Thd_ndb object");
- goto ndb_util_thread_end;
- }
- set_thd_ndb(thd, thd_ndb);
- thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
+ sql_print_error("Could not allocate Thd_ndb object");
+ goto ndb_util_thread_end;
}
+ set_thd_ndb(thd, thd_ndb);
+ thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
#ifdef HAVE_NDB_BINLOG
if (ndb_extra_logging && ndb_binlog_running)
@@ -8330,26 +8306,26 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
}
#endif /* HAVE_NDB_BINLOG */
DBUG_PRINT("ndb_util_thread",
- ("Fetching commit count for: %s",
- share->key));
+ ("Fetching commit count for: %s", share->key));
- /* Contact NDB to get commit count for table */
- ndb->setDatabaseName(share->db);
struct Ndb_statistics stat;
-
uint lock;
pthread_mutex_lock(&share->mutex);
lock= share->commit_count_lock;
pthread_mutex_unlock(&share->mutex);
{
+ /* Contact NDB to get commit count for table */
+ Ndb* ndb= thd_ndb->ndb;
+ ndb->setDatabaseName(share->db);
Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
if (ndbtab_g.get_table() &&
- ndb_get_table_statistics(NULL, false, ndb, ndbtab_g.get_table(), &stat) == 0)
+ ndb_get_table_statistics(NULL, false, ndb,
+ ndbtab_g.get_table(), &stat) == 0)
{
char buff[22], buff2[22];
DBUG_PRINT("ndb_util_thread",
- ("Table: %s, commit_count: %llu, rows: %llu",
+ ("Table: %s, commit_count: %s, rows: %s",
share->key,
llstr(stat.commit_count, buff),
llstr(stat.row_count, buff2)));
@@ -8401,7 +8377,6 @@ ndb_util_thread_end:
net_end(&thd->net);
thd->cleanup();
delete thd;
- delete ndb;
DBUG_PRINT("exit", ("ndb_util_thread"));
my_thread_end();
pthread_exit(0);
@@ -9191,7 +9166,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
if (context->expecting(Item::INT_ITEM))
{
Item_int *int_item= (Item_int *) item;
- DBUG_PRINT("info", ("value %d", int_item->value));
+ DBUG_PRINT("info", ("value %llu", int_item->value));
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::INT_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
@@ -9214,7 +9189,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->supported= FALSE;
break;
case Item::REAL_ITEM:
- DBUG_PRINT("info", ("REAL_ITEM %s"));
+ DBUG_PRINT("info", ("REAL_ITEM"));
if (context->expecting(Item::REAL_ITEM))
{
Item_float *float_item= (Item_float *) item;
@@ -9262,7 +9237,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->supported= FALSE;
break;
case Item::DECIMAL_ITEM:
- DBUG_PRINT("info", ("DECIMAL_ITEM %s"));
+ DBUG_PRINT("info", ("DECIMAL_ITEM"));
if (context->expecting(Item::DECIMAL_ITEM))
{
Item_decimal *decimal_item= (Item_decimal *) item;
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 3dfca5d1bb2..e0b7502a40a 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -3436,7 +3436,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
global_system_variables.binlog_format == BINLOG_FORMAT_MIXED)
{
ndb_binlog_running= TRUE;
- thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode
}
else
{
diff --git a/sql/handler.cc b/sql/handler.cc
index 451f974a066..f16876f2ffd 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3460,38 +3460,15 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
declared static, but it works by putting it into an anonymous
namespace. */
namespace {
- struct st_table_data {
- char const *db;
- char const *name;
- };
-
- static int table_name_compare(void const *a, void const *b)
- {
- st_table_data const *x = (st_table_data const*) a;
- st_table_data const *y = (st_table_data const*) b;
-
- /* Doing lexical compare in order (db,name) */
- int const res= strcmp(x->db, y->db);
- return res != 0 ? res : strcmp(x->name, y->name);
- }
-
bool check_table_binlog_row_based(THD *thd, TABLE *table)
{
- static st_table_data const ignore[] = {
- { "mysql", "event" },
- { "mysql", "general_log" },
- { "mysql", "slow_log" }
- };
-
- my_size_t const ignore_size = sizeof(ignore)/sizeof(*ignore);
- st_table_data const item = { table->s->db.str, table->s->table_name.str };
-
if (table->s->cached_row_logging_check == -1)
- table->s->cached_row_logging_check=
- (table->s->tmp_table == NO_TMP_TABLE) &&
- binlog_filter->db_ok(table->s->db.str) &&
- bsearch(&item, ignore, ignore_size,
- sizeof(st_table_data), table_name_compare) == NULL;
+ {
+ int const check(table->s->tmp_table == NO_TMP_TABLE &&
+ binlog_filter->db_ok(table->s->db.str) &&
+ strcmp("mysql", table->s->db.str) != 0);
+ table->s->cached_row_logging_check= check;
+ }
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
table->s->cached_row_logging_check == 1);
diff --git a/sql/item.cc b/sql/item.cc
index 8914593e9f0..0662ddefbb4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1655,7 +1655,7 @@ void Item_field::set_field(Field *field_par)
db_name= field_par->table->s->db.str;
alias_name_used= field_par->table->alias_name_used;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
- collation.set(field_par->charset(), DERIVATION_IMPLICIT);
+ collation.set(field_par->charset(), field_par->derivation());
fixed= 1;
}
diff --git a/sql/item.h b/sql/item.h
index 8799fa07eb7..2c26e1c4a07 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -27,19 +27,7 @@ class Item_field;
/*
"Declared Type Collation"
A combination of collation and its derivation.
-*/
-enum Derivation
-{
- DERIVATION_IGNORABLE= 5,
- DERIVATION_COERCIBLE= 4,
- DERIVATION_SYSCONST= 3,
- DERIVATION_IMPLICIT= 2,
- DERIVATION_NONE= 1,
- DERIVATION_EXPLICIT= 0
-};
-
-/*
Flags for collation aggregation modes:
MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b2ff62028c1..1cb943e45c2 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3019,6 +3019,7 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
String tmp2;
String *result= &item->result;
Item **arg= item->args, **arg_end= item->args + item->arg_count_field;
+ uint old_length= result->length();
if (item->no_appended)
item->no_appended= FALSE;
@@ -3053,8 +3054,22 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
/* stop if length of result more than max_length */
if (result->length() > item->max_length)
{
+ int well_formed_error;
+ CHARSET_INFO *cs= item->collation.collation;
+ const char *ptr= result->ptr();
+ uint add_length;
+ /*
+ It's ok to use item->result.length() as the fourth argument
+ as this is never used to limit the length of the data.
+ Cut is done with the third argument.
+ */
+ add_length= cs->cset->well_formed_len(cs,
+ ptr + old_length,
+ ptr + item->max_length,
+ result->length(),
+ &well_formed_error);
+ result->length(old_length + add_length);
item->count_cut_values++;
- result->length(item->max_length);
item->warning_for_row= TRUE;
return 1;
}
@@ -3244,8 +3259,7 @@ bool Item_func_group_concat::add()
we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
instead of doing tree traverse later.
*/
- if (result.length() <= max_length &&
- !warning_for_row &&
+ if (!warning_for_row &&
(!tree || (el->count == 1 && distinct && !arg_count_order)))
dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this);
@@ -3314,7 +3328,8 @@ bool Item_func_group_concat::setup(THD *thd)
DBUG_RETURN(TRUE);
/* We'll convert all blobs to varchar fields in the temporary table */
- tmp_table_param->convert_blob_length= max_length;
+ tmp_table_param->convert_blob_length= max_length *
+ collation.collation->mbmaxlen;
/* Push all not constant fields to the list and create a temp table */
always_null= 0;
for (uint i= 0; i < arg_count_field; i++)
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 44a2b690bac..21239a13735 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -532,7 +532,7 @@ public:
longlong val_int()
{
Item_func *comp= (Item_func*)args[1];
- Item_string *fake= (Item_string*)(comp->arguments()[1]);
+ Item_string *fake= (Item_string*)(comp->arguments()[0]);
String *res= args[0]->val_nodeset(&tmp_nodeset);
MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
@@ -884,7 +884,7 @@ static Item *eq_func(int oper, Item *a, Item *b)
Create a comparator function for scalar arguments,
for the given arguments and reverse operation, e.g.
- A >= B is converted into A < B
+ A > B is converted into B < A
RETURN
The newly created item.
@@ -895,10 +895,10 @@ static Item *eq_func_reverse(int oper, Item *a, Item *b)
{
case '=': return new Item_func_eq(a, b);
case '!': return new Item_func_ne(a, b);
- case MY_XPATH_LEX_GE: return new Item_func_lt(a, b);
- case MY_XPATH_LEX_LE: return new Item_func_gt(a, b);
- case MY_XPATH_LEX_GREATER: return new Item_func_le(a, b);
- case MY_XPATH_LEX_LESS: return new Item_func_ge(a, b);
+ case MY_XPATH_LEX_GE: return new Item_func_le(a, b);
+ case MY_XPATH_LEX_LE: return new Item_func_ge(a, b);
+ case MY_XPATH_LEX_GREATER: return new Item_func_lt(a, b);
+ case MY_XPATH_LEX_LESS: return new Item_func_gt(a, b);
}
return 0;
}
@@ -951,13 +951,13 @@ static Item *create_comparator(MY_XPATH *xpath,
{
nodeset= (Item_nodeset_func*) a;
scalar= b;
- comp= eq_func(oper, scalar, fake);
+ comp= eq_func(oper, fake, scalar);
}
else
{
nodeset= (Item_nodeset_func*) b;
scalar= a;
- comp= eq_func_reverse(oper, scalar, fake);
+ comp= eq_func_reverse(oper, fake, scalar);
}
return new Item_nodeset_to_const_comparator(nodeset, comp, xpath->pxml);
}
diff --git a/sql/log.cc b/sql/log.cc
index 83e190a5c01..620445aecfa 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -424,6 +424,18 @@ bool Log_to_csv_event_handler::
{
TABLE *table= general_log.table;
+ /*
+ "INSERT INTO general_log" can generate warning sometimes.
+ Let's reset warnings from previous queries,
+ otherwise warning list can grow too much,
+ so thd->query gets spoiled as some point in time,
+ and mysql_parse() receives a broken query.
+ QQ: this problem needs to be studied in more details.
+ Probably it's better to suppress warnings in logging INSERTs at all.
+ Comment this line and run "cast.test" to see what's happening:
+ */
+ mysql_reset_errors(table->in_use, 1);
+
/* below should never happen */
if (unlikely(!logger.is_log_tables_initialized))
return FALSE;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d99fb9da8f8..f11822d8ad0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -140,6 +140,21 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len)
}
#endif /* MYSQL_CLIENT */
+#ifdef HAVE_purify
+static void
+valgrind_check_mem(void *ptr, size_t len)
+{
+ static volatile uchar dummy;
+ for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p)
+ {
+ int const c = *p;
+ if (c < 128)
+ dummy= c + 1;
+ else
+ dummy = c - 1;
+ }
+}
+#endif
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
@@ -1398,6 +1413,7 @@ bool Query_log_event::write(IO_CACHE* file)
/* Store length of status variables */
status_vars_len= (uint) (start-start_of_status);
+ DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS);
int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
/*
@@ -5401,7 +5417,13 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
DBUG_ENTER("Rows_log_event::do_add_row_data");
DBUG_PRINT("enter", ("row_data: 0x%lx length: %lu", (ulong) row_data,
length));
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
DBUG_DUMP("row_data", (const char*)row_data, min(length, 32));
+#endif
DBUG_ASSERT(m_rows_buf <= m_rows_cur);
DBUG_ASSERT(!m_rows_buf || m_rows_end && m_rows_buf < m_rows_end);
@@ -5445,14 +5467,13 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
/*
- Unpack a row into a record.
+ Unpack a row into table->record[0].
SYNOPSIS
unpack_row()
rli Relay log info
table Table to unpack into
colcnt Number of columns to read from record
- record Record where the data should be unpacked
row Packed row data
cols Pointer to columns data to fill in
row_end Pointer to variable that will hold the value of the
@@ -5465,6 +5486,11 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
DESCRIPTION
+ The function will always unpack into the table->record[0]
+ record. This is because there are too many dependencies on
+ where the various member functions of Field and subclasses
+ expect to write.
+
The row is assumed to only consist of the fields for which the
bitset represented by 'arr' and 'bits'; the other parts of the
record are left alone.
@@ -5483,13 +5509,15 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
*/
static int
unpack_row(RELAY_LOG_INFO *rli,
- TABLE *table, uint const colcnt, byte *record,
+ TABLE *table, uint const colcnt,
char const *row, MY_BITMAP const *cols,
char const **row_end, ulong *master_reclength,
MY_BITMAP* const rw_set, Log_event_type const event_type)
{
+ byte *const record= table->record[0];
+ DBUG_ENTER("unpack_row");
DBUG_ASSERT(record && row);
- my_ptrdiff_t const offset= record - (byte*) table->record[0];
+ DBUG_PRINT("enter", ("row=0x%lx; table->record[0]=0x%lx", row, record));
my_size_t master_null_bytes= table->s->null_bytes;
if (colcnt != table->s->fields)
@@ -5529,9 +5557,11 @@ unpack_row(RELAY_LOG_INFO *rli,
if (bitmap_is_set(cols, field_ptr - begin_ptr))
{
- f->move_field_offset(offset);
+ DBUG_ASSERT(table->record[0] <= f->ptr);
+ DBUG_ASSERT(f->ptr < table->record[0] + table->s->reclength + (f->pack_length_in_rec() == 0));
+
+ DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name, f->ptr));
ptr= f->unpack(f->ptr, ptr);
- f->move_field_offset(-offset);
/* Field...::unpack() cannot return 0 */
DBUG_ASSERT(ptr != NULL);
}
@@ -5562,13 +5592,10 @@ unpack_row(RELAY_LOG_INFO *rli,
for ( ; *field_ptr ; ++field_ptr)
{
uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
+ Field *const f= *field_ptr;
- DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x",
- (*field_ptr)->flags, mask,
- (*field_ptr)->flags & mask));
-
- if (event_type == WRITE_ROWS_EVENT &&
- ((*field_ptr)->flags & mask) == mask)
+ DBUG_PRINT("info", ("processing column '%s' @ 0x%lx", f->field_name, f->ptr));
+ if (event_type == WRITE_ROWS_EVENT && (f->flags & mask) == mask)
{
slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD,
"Field `%s` of table `%s`.`%s` "
@@ -5578,10 +5605,10 @@ unpack_row(RELAY_LOG_INFO *rli,
error = ER_NO_DEFAULT_FOR_FIELD;
}
else
- (*field_ptr)->set_default();
+ f->set_default();
}
- return error;
+ DBUG_RETURN(error);
}
int Rows_log_event::exec_event(st_relay_log_info *rli)
@@ -5689,12 +5716,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
We also invalidate the query cache for all the tables, since
they will now be changed.
*/
-
TABLE_LIST *ptr;
for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{
rli->m_table_map.set_table(ptr->table_id, ptr->table);
- rli->touching_table(ptr->db, ptr->table_name, ptr->table_id);
}
#ifdef HAVE_QUERY_CACHE
query_cache.invalidate_locked_for_write(rli->tables_to_lock);
@@ -5747,7 +5772,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
if ((error= do_prepare_row(thd, rli, table, row_start, &row_end)))
break; // We should perform the after-row operation even in
// the case of error
-
+
DBUG_ASSERT(row_end != NULL); // cannot happen
DBUG_ASSERT(row_end <= (const char*)m_rows_end);
@@ -5803,9 +5828,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
STMT_END_F.
For now we code, knowing that error is not skippable and so slave SQL
thread is certainly going to stop.
+ rollback at the caller along with sbr.
*/
thd->reset_current_stmt_binlog_row_based();
- rli->cleanup_context(thd, 1);
+ rli->cleanup_context(thd, 0); /* rollback at caller in step with sbr */
thd->query_error= 1;
DBUG_RETURN(error);
}
@@ -6047,7 +6073,13 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
DBUG_PRINT("info",("event_len=%ld, common_header_len=%d, post_header_len=%d",
event_len, common_header_len, post_header_len));
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
DBUG_DUMP("event buffer", buf, event_len);
+#endif
/* Read the post-header */
const char *post_start= buf + common_header_len;
@@ -6230,8 +6262,7 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
/*
We record in the slave's information that the table should be
- locked by linking the table into the list of tables to lock, and
- tell the RLI that we are touching a table.
+ locked by linking the table into the list of tables to lock.
*/
table_list->next_global= table_list->next_local= rli->tables_to_lock;
rli->tables_to_lock= table_list;
@@ -6423,17 +6454,15 @@ int Write_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table,
- char const *row_start,
- char const **row_end)
+ char const *const row_start,
+ char const **const row_end)
{
DBUG_ASSERT(table != NULL);
DBUG_ASSERT(row_start && row_end);
int error;
- error= unpack_row(rli,
- table, m_width, table->record[0],
- row_start, &m_cols, row_end, &m_master_reclength,
- table->write_set, WRITE_ROWS_EVENT);
+ error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end,
+ &m_master_reclength, table->write_set, WRITE_ROWS_EVENT);
bitmap_copy(table->read_set, table->write_set);
return error;
}
@@ -6495,7 +6524,7 @@ copy_extra_record_fields(TABLE *table,
my_ptrdiff_t master_fields)
{
DBUG_PRINT("info", ("Copying to %p "
- "from field %d at offset %u "
+ "from field %ld at offset %u "
"to field %d at offset %u",
table->record[0],
master_fields, master_reclength,
@@ -6595,6 +6624,11 @@ replace_record(THD *thd, TABLE *table,
while ((error= table->file->ha_write_row(table->record[0])))
{
+ if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT)
+ {
+ table->file->print_error(error, MYF(0)); /* to check at exec_relay_log_event */
+ DBUG_RETURN(error);
+ }
if ((keynum= table->file->get_dup_key(error)) < 0)
{
/* We failed to retrieve the duplicate key */
@@ -6649,7 +6683,7 @@ replace_record(THD *thd, TABLE *table,
present on the master from table->record[1], if there are any.
*/
copy_extra_record_fields(table, master_reclength, master_fields);
-
+
/*
REPLACE is defined as either INSERT or DELETE + INSERT. If
possible, we can replace it with an UPDATE, but that will not
@@ -6728,8 +6762,26 @@ static bool record_compare(TABLE *table)
/*
Find the row given by 'key', if the table has keys, or else use a table scan
- to find (and fetch) the row. If the engine allows random access of the
- records, a combination of position() and rnd_pos() will be used.
+ to find (and fetch) the row.
+
+ If the engine allows random access of the records, a combination of
+ position() and rnd_pos() will be used.
+
+ @param table Pointer to table to search
+ @param key Pointer to key to use for search, if table has key
+
+ @pre <code>table->record[0]</code> shall contain the row to locate
+ and <code>key</code> shall contain a key to use for searching, if
+ the engine has a key.
+
+ @post If the return value is zero, <code>table->record[1]</code>
+ will contain the fetched row and the internal "cursor" will refer to
+ the row. If the return value is non-zero,
+ <code>table->record[1]</code> is undefined. In either case,
+ <code>table->record[0]</code> is undefined.
+
+ @return Zero if the row was successfully fetched into
+ <code>table->record[1]</code>, error code otherwise.
*/
static int find_and_fetch_row(TABLE *table, byte *key)
@@ -6749,13 +6801,28 @@ static int find_and_fetch_row(TABLE *table, byte *key)
row reference using the position() member function (it will be
stored in table->file->ref) and the use rnd_pos() to position
the "cursor" (i.e., record[0] in this case) at the correct row.
+
+ TODO: Add a check that the correct record has been fetched by
+ comparing with the original record. Take into account that the
+ record on the master and slave can be of different
+ length. Something along these lines should work:
+
+ ADD>>> store_record(table,record[1]);
+ int error= table->file->rnd_pos(table->record[0], table->file->ref);
+ ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0],
+ table->s->reclength) == 0);
+
*/
table->file->position(table->record[0]);
- DBUG_RETURN(table->file->rnd_pos(table->record[0], table->file->ref));
+ int error= table->file->rnd_pos(table->record[0], table->file->ref);
+ /*
+ rnd_pos() returns the record in table->record[0], so we have to
+ move it to table->record[1].
+ */
+ bmove_align(table->record[1], table->record[0], table->s->reclength);
+ DBUG_RETURN(error);
}
- DBUG_ASSERT(table->record[1]);
-
/* We need to retrieve all fields */
/* TODO: Move this out from this function to main loop */
table->use_all_columns();
@@ -6765,7 +6832,16 @@ static int find_and_fetch_row(TABLE *table, byte *key)
int error;
/* We have a key: search the table using the index */
if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE)))
- return error;
+ DBUG_RETURN(error);
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
+ DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength);
+#endif
/*
We need to set the null bytes to ensure that the filler bit are
@@ -6785,6 +6861,14 @@ static int find_and_fetch_row(TABLE *table, byte *key)
DBUG_RETURN(error);
}
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
+ DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength);
+#endif
/*
Below is a minor "optimization". If the key (i.e., key number
0) has the HA_NOSAME flag set, we know that we have found the
@@ -6969,8 +7053,8 @@ int Delete_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table,
- char const *row_start,
- char const **row_end)
+ char const *const row_start,
+ char const **const row_end)
{
int error;
DBUG_ASSERT(row_start && row_end);
@@ -6980,10 +7064,8 @@ int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
*/
DBUG_ASSERT(table->s->fields >= m_width);
- error= unpack_row(rli,
- table, m_width, table->record[0],
- row_start, &m_cols, row_end, &m_master_reclength,
- table->read_set, DELETE_ROWS_EVENT);
+ error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end,
+ &m_master_reclength, table->read_set, DELETE_ROWS_EVENT);
/*
If we will access rows using the random access method, m_key will
be set to NULL, so we do not need to make a key copy in that case.
@@ -7106,8 +7188,8 @@ int Update_rows_log_event::do_after_row_operations(TABLE *table, int error)
int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
TABLE *table,
- char const *row_start,
- char const **row_end)
+ char const *const row_start,
+ char const **const row_end)
{
int error;
DBUG_ASSERT(row_start && row_end);
@@ -7117,21 +7199,31 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
*/
DBUG_ASSERT(table->s->fields >= m_width);
+ /*
+ We need to perform some juggling below since unpack_row() always
+ unpacks into table->record[0]. For more information, see the
+ comments for unpack_row().
+ */
+
/* record[0] is the before image for the update */
- error= unpack_row(rli,
- table, m_width, table->record[0],
- row_start, &m_cols, row_end, &m_master_reclength,
- table->read_set, UPDATE_ROWS_EVENT);
- row_start = *row_end;
+ error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end,
+ &m_master_reclength, table->read_set, UPDATE_ROWS_EVENT);
+ store_record(table, record[1]);
+ char const *next_start = *row_end;
/* m_after_image is the after image for the update */
- error= unpack_row(rli,
- table, m_width, m_after_image,
- row_start, &m_cols, row_end, &m_master_reclength,
- table->write_set, UPDATE_ROWS_EVENT);
+ error= unpack_row(rli, table, m_width, next_start, &m_cols, row_end,
+ &m_master_reclength, table->write_set, UPDATE_ROWS_EVENT);
+ bmove_align(m_after_image, table->record[0], table->s->reclength);
+ restore_record(table, record[1]);
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
DBUG_DUMP("record[0]", (const char *)table->record[0], table->s->reclength);
DBUG_DUMP("m_after_image", (const char *)m_after_image, table->s->reclength);
-
+#endif
/*
If we will access rows using the random access method, m_key will
diff --git a/sql/log_event.h b/sql/log_event.h
index 81ce2f18b4d..c3f015e723c 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -200,8 +200,26 @@ struct sql_ex_info
#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
-/*
- Event header offsets;
+/*
+ Max number of possible extra bytes in a replication event compared to a
+ packet (i.e. a query) sent from client to master;
+ First, an auxiliary log_event status vars estimation:
+*/
+#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \
+ 8 /* sql mode */ + \
+ 1 + 1 + 255 /* catalog */ + \
+ 4 /* autoinc */ + \
+ 6 /* charset */ + \
+ MAX_TIME_ZONE_NAME_LENGTH)
+#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
+ LOG_EVENT_HEADER_LEN + /* write_header */ \
+ QUERY_HEADER_LEN + /* write_data */ \
+ EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN + /*write_post_header_for_derived */ \
+ MAX_SIZE_LOG_EVENT_STATUS + /* status */ \
+ NAME_LEN + 1)
+
+/*
+ Event header offsets;
these point to places inside the fixed header.
*/
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b0947249439..e30da1f2f0b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -105,6 +105,17 @@ extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
+enum Derivation
+{
+ DERIVATION_IGNORABLE= 5,
+ DERIVATION_COERCIBLE= 4,
+ DERIVATION_SYSCONST= 3,
+ DERIVATION_IMPLICIT= 2,
+ DERIVATION_NONE= 1,
+ DERIVATION_EXPLICIT= 0
+};
+
+
typedef struct my_locale_st
{
const char *name;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 7e57afeafee..16bfbcbc565 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3160,11 +3160,6 @@ with --log-bin instead.");
}
if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC)
{
-#if defined(HAVE_NDB_BINLOG) && defined(HAVE_ROW_BASED_REPLICATION)
- if (opt_bin_log && have_ndbcluster == SHOW_OPTION_YES)
- global_system_variables.binlog_format= BINLOG_FORMAT_ROW;
- else
-#endif
#if defined(HAVE_ROW_BASED_REPLICATION)
global_system_variables.binlog_format= BINLOG_FORMAT_MIXED;
#else
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 0071d59242e..0a2d4012af4 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -368,32 +368,33 @@ my_bool rename_in_schema_file(const char *schema, const char *old_name,
{
char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN];
- strxnmov(old_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/",
- old_name, reg_ext, NullS);
- (void) unpack_filename(old_path, old_path);
-
- strxnmov(new_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/",
- new_name, reg_ext, NullS);
- (void) unpack_filename(new_path, new_path);
+ build_table_filename(old_path, sizeof(old_path) - 1,
+ schema, old_name, reg_ext, 0);
+ build_table_filename(new_path, sizeof(new_path) - 1,
+ schema, new_name, reg_ext, 0);
if (my_rename(old_path, new_path, MYF(MY_WME)))
return 1;
/* check if arc_dir exists */
- strxnmov(arc_path, FN_REFLEN-1, mysql_data_home, "/", schema, "/arc", NullS);
- (void) unpack_filename(arc_path, arc_path);
+ build_table_filename(arc_path, sizeof(arc_path) - 1, schema, "arc", "", 0);
if (revision > 0 && !access(arc_path, F_OK))
{
+ char old_name_buf[FN_REFLEN], new_name_buf[FN_REFLEN];
ulonglong limit= ((revision > num_view_backups) ?
revision - num_view_backups : 0);
+
+ VOID(tablename_to_filename(old_name, old_name_buf, sizeof(old_name_buf)));
+ VOID(tablename_to_filename(new_name, new_name_buf, sizeof(new_name_buf)));
+
for (; revision > limit ; revision--)
{
my_snprintf(old_path, FN_REFLEN, "%s/%s%s-%04lu",
- arc_path, old_name, reg_ext, (ulong)revision);
+ arc_path, old_name_buf, reg_ext, (ulong) revision);
(void) unpack_filename(old_path, old_path);
my_snprintf(new_path, FN_REFLEN, "%s/%s%s-%04lu",
- arc_path, new_name, reg_ext, (ulong)revision);
+ arc_path, new_name_buf, reg_ext, (ulong) revision);
(void) unpack_filename(new_path, new_path);
my_rename(old_path, new_path, MYF(0));
}
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 66e2aa1c31c..2b034d50d6a 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -962,7 +962,7 @@ bool load_master_data(THD* thd)
Cancel the previous START SLAVE UNTIL, as the fact to download
a new copy logically makes UNTIL irrelevant.
*/
- clear_until_condition(&active_mi->rli);
+ active_mi->rli.clear_until_condition();
/*
No need to update rli.event* coordinates, they will be when the slave
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index 5a74fd58755..3a0fca4dfa5 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -39,6 +39,8 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
m_start_pos.m_file_pos= log_info.pos;
begin_trans(m_thd);
+
+ thd->set_current_stmt_binlog_row_based();
}
injector::transaction::~transaction()
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
new file mode 100644
index 00000000000..c89c8aa131e
--- /dev/null
+++ b/sql/rpl_mi.cc
@@ -0,0 +1,386 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h> // For HAVE_REPLICATION
+#include "mysql_priv.h"
+#include <my_dir.h>
+
+#include "rpl_mi.h"
+
+#ifdef HAVE_REPLICATION
+
+
+// Defined in slave.cc
+int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
+int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
+ const char *default_val);
+
+MASTER_INFO::MASTER_INFO()
+ :ssl(0), fd(-1), io_thd(0), inited(0),
+ abort_slave(0),slave_running(0), slave_run_id(0)
+{
+ host[0] = 0; user[0] = 0; password[0] = 0;
+ ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
+ ssl_cipher[0]= 0; ssl_key[0]= 0;
+
+ bzero((char*) &file, sizeof(file));
+ pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&data_cond, NULL);
+ pthread_cond_init(&start_cond, NULL);
+ pthread_cond_init(&stop_cond, NULL);
+}
+
+MASTER_INFO::~MASTER_INFO()
+{
+ pthread_mutex_destroy(&run_lock);
+ pthread_mutex_destroy(&data_lock);
+ pthread_cond_destroy(&data_cond);
+ pthread_cond_destroy(&start_cond);
+ pthread_cond_destroy(&stop_cond);
+}
+
+
+void init_master_info_with_options(MASTER_INFO* mi)
+{
+ DBUG_ENTER("init_master_info_with_options");
+
+ mi->master_log_name[0] = 0;
+ mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
+
+ if (master_host)
+ strmake(mi->host, master_host, sizeof(mi->host) - 1);
+ if (master_user)
+ strmake(mi->user, master_user, sizeof(mi->user) - 1);
+ if (master_password)
+ strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
+ mi->port = master_port;
+ mi->connect_retry = master_connect_retry;
+
+ mi->ssl= master_ssl;
+ if (master_ssl_ca)
+ strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1);
+ if (master_ssl_capath)
+ strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1);
+ if (master_ssl_cert)
+ strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1);
+ if (master_ssl_cipher)
+ strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
+ if (master_ssl_key)
+ strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
+ DBUG_VOID_RETURN;
+}
+
+
+#define LINES_IN_MASTER_INFO_WITH_SSL 14
+
+
+int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname,
+ bool abort_if_no_master_info_file,
+ int thread_mask)
+{
+ int fd,error;
+ char fname[FN_REFLEN+128];
+ DBUG_ENTER("init_master_info");
+
+ if (mi->inited)
+ {
+ /*
+ We have to reset read position of relay-log-bin as we may have
+ already been reading from 'hotlog' when the slave was stopped
+ last time. If this case pos_in_file would be set and we would
+ get a crash when trying to read the signature for the binary
+ relay log.
+
+ We only rewind the read position if we are starting the SQL
+ thread. The handle_slave_sql thread assumes that the read
+ position is at the beginning of the file, and will read the
+ "signature" and then fast-forward to the last position read.
+ */
+ if (thread_mask & SLAVE_SQL)
+ {
+ my_b_seek(mi->rli.cur_log, (my_off_t) 0);
+ }
+ DBUG_RETURN(0);
+ }
+
+ mi->mysql=0;
+ mi->file_id=1;
+ fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
+
+ /*
+ We need a mutex while we are changing master info parameters to
+ keep other threads from reading bogus info
+ */
+
+ pthread_mutex_lock(&mi->data_lock);
+ fd = mi->fd;
+
+ /* does master.info exist ? */
+
+ if (access(fname,F_OK))
+ {
+ if (abort_if_no_master_info_file)
+ {
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(0);
+ }
+ /*
+ if someone removed the file from underneath our feet, just close
+ the old descriptor and re-create the old file
+ */
+ if (fd >= 0)
+ my_close(fd, MYF(MY_WME));
+ if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ {
+ sql_print_error("Failed to create a new master info file (\
+file '%s', errno %d)", fname, my_errno);
+ goto err;
+ }
+ if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
+ MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
+ goto err;
+ }
+
+ mi->fd = fd;
+ init_master_info_with_options(mi);
+
+ }
+ else // file exists
+ {
+ if (fd >= 0)
+ reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
+ else
+ {
+ if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ {
+ sql_print_error("Failed to open the existing master info file (\
+file '%s', errno %d)", fname, my_errno);
+ goto err;
+ }
+ if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
+ 0, MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
+ goto err;
+ }
+ }
+
+ mi->fd = fd;
+ int port, connect_retry, master_log_pos, ssl= 0, lines;
+ char *first_non_digit;
+
+ /*
+ Starting from 4.1.x master.info has new format. Now its
+ first line contains number of lines in file. By reading this
+ number we will be always distinguish to which version our
+ master.info corresponds to. We can't simply count lines in
+ file since versions before 4.1.x could generate files with more
+ lines than needed.
+ If first line doesn't contain a number or contain number less than
+ 14 then such file is treated like file from pre 4.1.1 version.
+ There is no ambiguity when reading an old master.info, as before
+ 4.1.1, the first line contained the binlog's name, which is either
+ empty or has an extension (contains a '.'), so can't be confused
+ with an integer.
+
+ So we're just reading first line and trying to figure which version
+ is this.
+ */
+
+ /*
+ The first row is temporarily stored in mi->master_log_name,
+ if it is line count and not binlog name (new format) it will be
+ overwritten by the second row later.
+ */
+ if (init_strvar_from_file(mi->master_log_name,
+ sizeof(mi->master_log_name), &mi->file,
+ ""))
+ goto errwithmsg;
+
+ lines= strtoul(mi->master_log_name, &first_non_digit, 10);
+
+ if (mi->master_log_name[0]!='\0' &&
+ *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
+ { // Seems to be new format
+ if (init_strvar_from_file(mi->master_log_name,
+ sizeof(mi->master_log_name), &mi->file, ""))
+ goto errwithmsg;
+ }
+ else
+ lines= 7;
+
+ if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
+ init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
+ master_host) ||
+ init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
+ master_user) ||
+ init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
+ &mi->file, master_password) ||
+ init_intvar_from_file(&port, &mi->file, master_port) ||
+ init_intvar_from_file(&connect_retry, &mi->file,
+ master_connect_retry))
+ goto errwithmsg;
+
+ /*
+ If file has ssl part use it even if we have server without
+ SSL support. But these option will be ignored later when
+ slave will try connect to master, so in this case warning
+ is printed.
+ */
+ if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
+ (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
+ init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
+ &mi->file, master_ssl_ca) ||
+ init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
+ &mi->file, master_ssl_capath) ||
+ init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
+ &mi->file, master_ssl_cert) ||
+ init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
+ &mi->file, master_ssl_cipher) ||
+ init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
+ &mi->file, master_ssl_key)))
+ goto errwithmsg;
+#ifndef HAVE_OPENSSL
+ if (ssl)
+ sql_print_warning("SSL information in the master info file "
+ "('%s') are ignored because this MySQL slave was compiled "
+ "without SSL support.", fname);
+#endif /* HAVE_OPENSSL */
+
+ /*
+ This has to be handled here as init_intvar_from_file can't handle
+ my_off_t types
+ */
+ mi->master_log_pos= (my_off_t) master_log_pos;
+ mi->port= (uint) port;
+ mi->connect_retry= (uint) connect_retry;
+ mi->ssl= (my_bool) ssl;
+ }
+ DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
+ mi->master_log_name,
+ (ulong) mi->master_log_pos));
+
+ mi->rli.mi = mi;
+ if (init_relay_log_info(&mi->rli, slave_info_fname))
+ goto err;
+
+ mi->inited = 1;
+ // now change cache READ -> WRITE - must do this before flush_master_info
+ reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
+ if ((error=test(flush_master_info(mi, 1))))
+ sql_print_error("Failed to flush master info file");
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(error);
+
+errwithmsg:
+ sql_print_error("Error reading master configuration");
+
+err:
+ if (fd >= 0)
+ {
+ my_close(fd, MYF(0));
+ end_io_cache(&mi->file);
+ }
+ mi->fd= -1;
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ RETURN
+ 2 - flush relay log failed
+ 1 - flush master info failed
+ 0 - all ok
+*/
+int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
+{
+ IO_CACHE* file = &mi->file;
+ char lbuf[22];
+ DBUG_ENTER("flush_master_info");
+ DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
+
+ /*
+ Flush the relay log to disk. If we don't do it, then the relay log while
+ have some part (its last kilobytes) in memory only, so if the slave server
+ dies now, with, say, from master's position 100 to 150 in memory only (not
+ on disk), and with position 150 in master.info, then when the slave
+ restarts, the I/O thread will fetch binlogs from 150, so in the relay log
+ we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
+ SQL thread will jump from 100 to 150, and replication will silently break.
+
+ When we come to this place in code, relay log may or not be initialized;
+ the caller is responsible for setting 'flush_relay_log_cache' accordingly.
+ */
+ if (flush_relay_log_cache &&
+ flush_io_cache(mi->rli.relay_log.get_log_file()))
+ DBUG_RETURN(2);
+
+ /*
+ We flushed the relay log BEFORE the master.info file, because if we crash
+ now, we will get a duplicate event in the relay log at restart. If we
+ flushed in the other order, we would get a hole in the relay log.
+ And duplicate is better than hole (with a duplicate, in later versions we
+ can add detection and scrap one event; with a hole there's nothing we can
+ do).
+ */
+
+ /*
+ In certain cases this code may create master.info files that seems
+ corrupted, because of extra lines filled with garbage in the end
+ file (this happens if new contents take less space than previous
+ contents of file). But because of number of lines in the first line
+ of file we don't care about this garbage.
+ */
+
+ my_b_seek(file, 0L);
+ my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
+ LINES_IN_MASTER_INFO_WITH_SSL,
+ mi->master_log_name, llstr(mi->master_log_pos, lbuf),
+ mi->host, mi->user,
+ mi->password, mi->port, mi->connect_retry,
+ (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
+ mi->ssl_cipher, mi->ssl_key);
+ DBUG_RETURN(-flush_io_cache(file));
+}
+
+
+void end_master_info(MASTER_INFO* mi)
+{
+ DBUG_ENTER("end_master_info");
+
+ if (!mi->inited)
+ DBUG_VOID_RETURN;
+ end_relay_log_info(&mi->rli);
+ if (mi->fd >= 0)
+ {
+ end_io_cache(&mi->file);
+ (void)my_close(mi->fd, MYF(MY_WME));
+ mi->fd = -1;
+ }
+ mi->inited = 0;
+
+ DBUG_VOID_RETURN;
+}
+
+
+#endif /* HAVE_REPLICATION */
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
new file mode 100644
index 00000000000..f0a7d6681fe
--- /dev/null
+++ b/sql/rpl_mi.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef RPL_MI_H
+#define RPL_MI_H
+
+#ifdef HAVE_REPLICATION
+
+/*****************************************************************************
+
+ Replication IO Thread
+
+ MASTER_INFO contains:
+ - information about how to connect to a master
+ - current master log name
+ - current master log offset
+ - misc control variables
+
+ MASTER_INFO is initialized once from the master.info file if such
+ exists. Otherwise, data members corresponding to master.info fields
+ are initialized with defaults specified by master-* options. The
+ initialization is done through init_master_info() call.
+
+ The format of master.info file:
+
+ log_name
+ log_pos
+ master_host
+ master_user
+ master_pass
+ master_port
+ master_connect_retry
+
+ To write out the contents of master.info file to disk ( needed every
+ time we read and queue data from the master ), a call to
+ flush_master_info() is required.
+
+ To clean up, call end_master_info()
+
+*****************************************************************************/
+
+class MASTER_INFO
+{
+ public:
+ MASTER_INFO();
+ ~MASTER_INFO();
+
+ /* the variables below are needed because we can change masters on the fly */
+ char master_log_name[FN_REFLEN];
+ char host[HOSTNAME_LENGTH+1];
+ char user[USERNAME_LENGTH+1];
+ char password[MAX_PASSWORD_LENGTH+1];
+ my_bool ssl; // enables use of SSL connection if true
+ char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
+ char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
+
+ my_off_t master_log_pos;
+ File fd; // we keep the file open, so we need to remember the file pointer
+ IO_CACHE file;
+
+ pthread_mutex_t data_lock,run_lock;
+ pthread_cond_t data_cond,start_cond,stop_cond;
+ THD *io_thd;
+ MYSQL* mysql;
+ uint32 file_id; /* for 3.23 load data infile */
+ RELAY_LOG_INFO rli;
+ uint port;
+ uint connect_retry;
+#ifndef DBUG_OFF
+ int events_till_disconnect;
+#endif
+ bool inited;
+ volatile bool abort_slave;
+ volatile uint slave_running;
+ volatile ulong slave_run_id;
+ /*
+ The difference in seconds between the clock of the master and the clock of
+ the slave (second - first). It must be signed as it may be <0 or >0.
+ clock_diff_with_master is computed when the I/O thread starts; for this the
+ I/O thread does a SELECT UNIX_TIMESTAMP() on the master.
+ "how late the slave is compared to the master" is computed like this:
+ clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
+
+ */
+ long clock_diff_with_master;
+};
+
+void init_master_info_with_options(MASTER_INFO* mi);
+int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
+ const char* slave_info_fname,
+ bool abort_if_no_master_info_file,
+ int thread_mask);
+void end_master_info(MASTER_INFO* mi);
+int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache);
+
+#endif /* HAVE_REPLICATION */
+#endif /* RPL_MI_H */
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
new file mode 100644
index 00000000000..f01fc5d1c9e
--- /dev/null
+++ b/sql/rpl_rli.cc
@@ -0,0 +1,1112 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+
+#include "rpl_rli.h"
+#include <my_dir.h> // For MY_STAT
+#include "sql_repl.h" // For check_binlog_magic
+
+static int count_relay_log_space(RELAY_LOG_INFO* rli);
+
+// Defined in slave.cc
+int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
+int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
+ const char *default_val);
+
+
+st_relay_log_info::st_relay_log_info()
+ :no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
+ cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
+ ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
+ abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0),
+ inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
+ until_log_pos(0), retried_trans(0),
+ tables_to_lock(0), tables_to_lock_count(0),
+ unsafe_to_stop_at(0)
+{
+ DBUG_ENTER("st_relay_log_info::st_relay_log_info");
+
+ group_relay_log_name[0]= event_relay_log_name[0]=
+ group_master_log_name[0]= 0;
+ last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0;
+ bzero((char*) &info_file, sizeof(info_file));
+ bzero((char*) &cache_buf, sizeof(cache_buf));
+ cached_charset_invalidate();
+ pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&data_cond, NULL);
+ pthread_cond_init(&start_cond, NULL);
+ pthread_cond_init(&stop_cond, NULL);
+ pthread_cond_init(&log_space_cond, NULL);
+ relay_log.init_pthread_objects();
+ DBUG_VOID_RETURN;
+}
+
+
+st_relay_log_info::~st_relay_log_info()
+{
+ DBUG_ENTER("st_relay_log_info::~st_relay_log_info");
+
+ pthread_mutex_destroy(&run_lock);
+ pthread_mutex_destroy(&data_lock);
+ pthread_mutex_destroy(&log_space_lock);
+ pthread_cond_destroy(&data_cond);
+ pthread_cond_destroy(&start_cond);
+ pthread_cond_destroy(&stop_cond);
+ pthread_cond_destroy(&log_space_cond);
+ relay_log.cleanup();
+ DBUG_VOID_RETURN;
+}
+
+
+int init_relay_log_info(RELAY_LOG_INFO* rli,
+ const char* info_fname)
+{
+ char fname[FN_REFLEN+128];
+ int info_fd;
+ const char* msg = 0;
+ int error = 0;
+ DBUG_ENTER("init_relay_log_info");
+ DBUG_ASSERT(!rli->no_storage); // Don't init if there is no storage
+
+ if (rli->inited) // Set if this function called
+ DBUG_RETURN(0);
+ fn_format(fname, info_fname, mysql_data_home, "", 4+32);
+ pthread_mutex_lock(&rli->data_lock);
+ info_fd = rli->info_fd;
+ rli->cur_log_fd = -1;
+ rli->slave_skip_counter=0;
+ rli->abort_pos_wait=0;
+ rli->log_space_limit= relay_log_space_limit;
+ rli->log_space_total= 0;
+ rli->tables_to_lock= 0;
+ rli->tables_to_lock_count= 0;
+
+ /*
+ The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
+ Note that the I/O thread flushes it to disk after writing every
+ event, in flush_master_info(mi, 1).
+ */
+
+ /*
+ For the maximum log size, we choose max_relay_log_size if it is
+ non-zero, max_binlog_size otherwise. If later the user does SET
+ GLOBAL on one of these variables, fix_max_binlog_size and
+ fix_max_relay_log_size will reconsider the choice (for example
+ if the user changes max_relay_log_size to zero, we have to
+ switch to using max_binlog_size for the relay log) and update
+ rli->relay_log.max_size (and mysql_bin_log.max_size).
+ */
+ {
+ char buf[FN_REFLEN];
+ const char *ln;
+ static bool name_warning_sent= 0;
+ ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
+ 1, buf);
+ /* We send the warning only at startup, not after every RESET SLAVE */
+ if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent)
+ {
+ /*
+ User didn't give us info to name the relay log index file.
+ Picking `hostname`-relay-bin.index like we do, causes replication to
+ fail if this slave's hostname is changed later. So, we would like to
+ instead require a name. But as we don't want to break many existing
+ setups, we only give warning, not error.
+ */
+ sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
+ " so replication "
+ "may break when this MySQL server acts as a "
+ "slave and has his hostname changed!! Please "
+ "use '--relay-log=%s' to avoid this problem.", ln);
+ name_warning_sent= 1;
+ }
+ /*
+ note, that if open() fails, we'll still have index file open
+ but a destructor will take care of that
+ */
+ if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) ||
+ rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
+ (max_relay_log_size ? max_relay_log_size :
+ max_binlog_size), 1))
+ {
+ pthread_mutex_unlock(&rli->data_lock);
+ sql_print_error("Failed in open_log() called from init_relay_log_info()");
+ DBUG_RETURN(1);
+ }
+ }
+
+ /* if file does not exist */
+ if (access(fname,F_OK))
+ {
+ /*
+ If someone removed the file from underneath our feet, just close
+ the old descriptor and re-create the old file
+ */
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(MY_WME));
+ if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("Failed to create a new relay log info file (\
+file '%s', errno %d)", fname, my_errno);
+ msg= current_thd->net.last_error;
+ goto err;
+ }
+ if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
+ MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on relay log info file '%s'",
+ fname);
+ msg= current_thd->net.last_error;
+ goto err;
+ }
+
+ /* Init relay log with first entry in the relay index file */
+ if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
+ &msg, 0))
+ {
+ sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
+ goto err;
+ }
+ rli->group_master_log_name[0]= 0;
+ rli->group_master_log_pos= 0;
+ rli->info_fd= info_fd;
+ }
+ else // file exists
+ {
+ if (info_fd >= 0)
+ reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
+ else
+ {
+ int error=0;
+ if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("\
+Failed to open the existing relay log info file '%s' (errno %d)",
+ fname, my_errno);
+ error= 1;
+ }
+ else if (init_io_cache(&rli->info_file, info_fd,
+ IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on relay log info file '%s'",
+ fname);
+ error= 1;
+ }
+ if (error)
+ {
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(0));
+ rli->info_fd= -1;
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(1);
+ }
+ }
+
+ rli->info_fd = info_fd;
+ int relay_log_pos, master_log_pos;
+ if (init_strvar_from_file(rli->group_relay_log_name,
+ sizeof(rli->group_relay_log_name),
+ &rli->info_file, "") ||
+ init_intvar_from_file(&relay_log_pos,
+ &rli->info_file, BIN_LOG_HEADER_SIZE) ||
+ init_strvar_from_file(rli->group_master_log_name,
+ sizeof(rli->group_master_log_name),
+ &rli->info_file, "") ||
+ init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
+ {
+ msg="Error reading slave log configuration";
+ goto err;
+ }
+ strmake(rli->event_relay_log_name,rli->group_relay_log_name,
+ sizeof(rli->event_relay_log_name)-1);
+ rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
+ rli->group_master_log_pos= master_log_pos;
+
+ if (init_relay_log_pos(rli,
+ rli->group_relay_log_name,
+ rli->group_relay_log_pos,
+ 0 /* no data lock*/,
+ &msg, 0))
+ {
+ char llbuf[22];
+ sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)",
+ rli->group_relay_log_name,
+ llstr(rli->group_relay_log_pos, llbuf));
+ goto err;
+ }
+ }
+
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(rli->cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
+ DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
+ DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
+ }
+#endif
+
+ /*
+ Now change the cache from READ to WRITE - must do this
+ before flush_relay_log_info
+ */
+ reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
+ if ((error= flush_relay_log_info(rli)))
+ sql_print_error("Failed to flush relay log info file");
+ if (count_relay_log_space(rli))
+ {
+ msg="Error counting relay log space";
+ goto err;
+ }
+ rli->inited= 1;
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(error);
+
+err:
+ sql_print_error(msg);
+ end_io_cache(&rli->info_file);
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(0));
+ rli->info_fd= -1;
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(1);
+}
+
+
+static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
+{
+ MY_STAT s;
+ DBUG_ENTER("add_relay_log");
+ if (!my_stat(linfo->log_file_name,&s,MYF(0)))
+ {
+ sql_print_error("log %s listed in the index, but failed to stat",
+ linfo->log_file_name);
+ DBUG_RETURN(1);
+ }
+ rli->log_space_total += s.st_size;
+#ifndef DBUG_OFF
+ char buf[22];
+ DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf)));
+#endif
+ DBUG_RETURN(0);
+}
+
+
+static int count_relay_log_space(RELAY_LOG_INFO* rli)
+{
+ LOG_INFO linfo;
+ DBUG_ENTER("count_relay_log_space");
+ rli->log_space_total= 0;
+ if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
+ {
+ sql_print_error("Could not find first log while counting relay log space");
+ DBUG_RETURN(1);
+ }
+ do
+ {
+ if (add_relay_log(rli,&linfo))
+ DBUG_RETURN(1);
+ } while (!rli->relay_log.find_next_log(&linfo, 1));
+ /*
+ As we have counted everything, including what may have written in a
+ preceding write, we must reset bytes_written, or we may count some space
+ twice.
+ */
+ rli->relay_log.reset_bytes_written();
+ DBUG_RETURN(0);
+}
+
+
+void st_relay_log_info::clear_slave_error()
+{
+ DBUG_ENTER("clear_slave_error");
+
+ /* Clear the errors displayed by SHOW SLAVE STATUS */
+ last_slave_error[0]= 0;
+ last_slave_errno= 0;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Reset UNTIL condition for RELAY_LOG_INFO
+
+ SYNOPSYS
+ clear_until_condition()
+ rli - RELAY_LOG_INFO structure where UNTIL condition should be reset
+ */
+
+void st_relay_log_info::clear_until_condition()
+{
+ DBUG_ENTER("clear_until_condition");
+
+ until_condition= RELAY_LOG_INFO::UNTIL_NONE;
+ until_log_name[0]= 0;
+ until_log_pos= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Open the given relay log
+
+ SYNOPSIS
+ init_relay_log_pos()
+ rli Relay information (will be initialized)
+ log Name of relay log file to read from. NULL = First log
+ pos Position in relay log file
+ need_data_lock Set to 1 if this functions should do mutex locks
+ errmsg Store pointer to error message here
+ look_for_description_event
+ 1 if we should look for such an event. We only need
+ this when the SQL thread starts and opens an existing
+ relay log and has to execute it (possibly from an
+ offset >4); then we need to read the first event of
+ the relay log to be able to parse the events we have
+ to execute.
+
+ DESCRIPTION
+ - Close old open relay log files.
+ - If we are using the same relay log as the running IO-thread, then set
+ rli->cur_log to point to the same IO_CACHE entry.
+ - If not, open the 'log' binary file.
+
+ TODO
+ - check proper initialization of group_master_log_name/group_master_log_pos
+
+ RETURN VALUES
+ 0 ok
+ 1 error. errmsg is set to point to the error message
+*/
+
+int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
+ ulonglong pos, bool need_data_lock,
+ const char** errmsg,
+ bool look_for_description_event)
+{
+ DBUG_ENTER("init_relay_log_pos");
+ DBUG_PRINT("info", ("pos=%lu", pos));
+
+ *errmsg=0;
+ pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
+
+ if (need_data_lock)
+ pthread_mutex_lock(&rli->data_lock);
+
+ /*
+ Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER
+ is, too, and init_slave() too; these 2 functions allocate a description
+ event in init_relay_log_pos, which is not freed by the terminating SQL slave
+ thread as that thread is not started by these functions. So we have to free
+ the description_event here, in case, so that there is no memory leak in
+ running, say, CHANGE MASTER.
+ */
+ delete rli->relay_log.description_event_for_exec;
+ /*
+ By default the relay log is in binlog format 3 (4.0).
+ Even if format is 4, this will work enough to read the first event
+ (Format_desc) (remember that format 4 is just lenghtened compared to format
+ 3; format 3 is a prefix of format 4).
+ */
+ rli->relay_log.description_event_for_exec= new
+ Format_description_log_event(3);
+
+ pthread_mutex_lock(log_lock);
+
+ /* Close log file and free buffers if it's already open */
+ if (rli->cur_log_fd >= 0)
+ {
+ end_io_cache(&rli->cache_buf);
+ my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd = -1;
+ }
+
+ rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
+
+ /*
+ Test to see if the previous run was with the skip of purging
+ If yes, we do not purge when we restart
+ */
+ if (rli->relay_log.find_log_pos(&rli->linfo, NullS, 1))
+ {
+ *errmsg="Could not find first log during relay log initialization";
+ goto err;
+ }
+
+ if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
+ {
+ *errmsg="Could not find target log during relay log initialization";
+ goto err;
+ }
+ strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->group_relay_log_name)-1);
+ strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->event_relay_log_name)-1);
+ if (rli->relay_log.is_active(rli->linfo.log_file_name))
+ {
+ /*
+ The IO thread is using this log file.
+ In this case, we will use the same IO_CACHE pointer to
+ read data as the IO thread is using to write data.
+ */
+ my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0);
+ if (check_binlog_magic(rli->cur_log,errmsg))
+ goto err;
+ rli->cur_log_old_open_count=rli->relay_log.get_open_count();
+ }
+ else
+ {
+ /*
+ Open the relay log and set rli->cur_log to point at this one
+ */
+ if ((rli->cur_log_fd=open_binlog(&rli->cache_buf,
+ rli->linfo.log_file_name,errmsg)) < 0)
+ goto err;
+ rli->cur_log = &rli->cache_buf;
+ }
+ /*
+ In all cases, check_binlog_magic() has been called so we're at offset 4 for
+ sure.
+ */
+ if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */
+ {
+ Log_event* ev;
+ while (look_for_description_event)
+ {
+ /*
+ Read the possible Format_description_log_event; if position
+ was 4, no need, it will be read naturally.
+ */
+ DBUG_PRINT("info",("looking for a Format_description_log_event"));
+
+ if (my_b_tell(rli->cur_log) >= pos)
+ break;
+
+ /*
+ Because of we have rli->data_lock and log_lock, we can safely read an
+ event
+ */
+ if (!(ev=Log_event::read_log_event(rli->cur_log,0,
+ rli->relay_log.description_event_for_exec)))
+ {
+ DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
+ rli->cur_log->error));
+ if (rli->cur_log->error) /* not EOF */
+ {
+ *errmsg= "I/O error reading event at position 4";
+ goto err;
+ }
+ break;
+ }
+ else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
+ {
+ DBUG_PRINT("info",("found Format_description_log_event"));
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev;
+ /*
+ As ev was returned by read_log_event, it has passed is_valid(), so
+ my_malloc() in ctor worked, no need to check again.
+ */
+ /*
+ Ok, we found a Format_description event. But it is not sure that this
+ describes the whole relay log; indeed, one can have this sequence
+ (starting from position 4):
+ Format_desc (of slave)
+ Rotate (of master)
+ Format_desc (of master)
+ So the Format_desc which really describes the rest of the relay log
+ is the 3rd event (it can't be further than that, because we rotate
+ the relay log when we queue a Rotate event from the master).
+ But what describes the Rotate is the first Format_desc.
+ So what we do is:
+ go on searching for Format_description events, until you exceed the
+ position (argument 'pos') or until you find another event than Rotate
+ or Format_desc.
+ */
+ }
+ else
+ {
+ DBUG_PRINT("info",("found event of another type=%d",
+ ev->get_type_code()));
+ look_for_description_event= (ev->get_type_code() == ROTATE_EVENT);
+ delete ev;
+ }
+ }
+ my_b_seek(rli->cur_log,(off_t)pos);
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(rli->cur_log),llbuf1),
+ llstr(rli->event_relay_log_pos,llbuf2)));
+ }
+#endif
+
+ }
+
+err:
+ /*
+ If we don't purge, we can't honour relay_log_space_limit ;
+ silently discard it
+ */
+ if (!relay_log_purge)
+ rli->log_space_limit= 0;
+ pthread_cond_broadcast(&rli->data_cond);
+
+ pthread_mutex_unlock(log_lock);
+
+ if (need_data_lock)
+ pthread_mutex_unlock(&rli->data_lock);
+ if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
+ *errmsg= "Invalid Format_description log event; could be out of memory";
+
+ DBUG_RETURN ((*errmsg) ? 1 : 0);
+}
+
+
+/*
+ Waits until the SQL thread reaches (has executed up to) the
+ log/position or timed out.
+
+ SYNOPSIS
+ wait_for_pos()
+ thd client thread that sent SELECT MASTER_POS_WAIT
+ log_name log name to wait for
+ log_pos position to wait for
+ timeout timeout in seconds before giving up waiting
+
+ NOTES
+ timeout is longlong whereas it should be ulong ; but this is
+ to catch if the user submitted a negative timeout.
+
+ RETURN VALUES
+ -2 improper arguments (log_pos<0)
+ or slave not running, or master info changed
+ during the function's execution,
+ or client thread killed. -2 is translated to NULL by caller
+ -1 timed out
+ >=0 number of log events the function had to wait
+ before reaching the desired log/position
+ */
+
+int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
+ longlong log_pos,
+ longlong timeout)
+{
+ int event_count = 0;
+ ulong init_abort_pos_wait;
+ int error=0;
+ struct timespec abstime; // for timeout checking
+ const char *msg;
+ DBUG_ENTER("st_relay_log_info::wait_for_pos");
+
+ if (!inited)
+ DBUG_RETURN(-1);
+
+ DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu",
+ log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
+
+ set_timespec(abstime,timeout);
+ pthread_mutex_lock(&data_lock);
+ msg= thd->enter_cond(&data_cond, &data_lock,
+ "Waiting for the slave SQL thread to "
+ "advance position");
+ /*
+ This function will abort when it notices that some CHANGE MASTER or
+ RESET MASTER has changed the master info.
+ To catch this, these commands modify abort_pos_wait ; We just monitor
+ abort_pos_wait and see if it has changed.
+ Why do we have this mechanism instead of simply monitoring slave_running
+ in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that
+ the SQL thread be stopped?
+ This is becasue if someones does:
+ STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
+ the change may happen very quickly and we may not notice that
+ slave_running briefly switches between 1/0/1.
+ */
+ init_abort_pos_wait= abort_pos_wait;
+
+ /*
+ We'll need to
+ handle all possible log names comparisons (e.g. 999 vs 1000).
+ We use ulong for string->number conversion ; this is no
+ stronger limitation than in find_uniq_filename in sql/log.cc
+ */
+ ulong log_name_extension;
+ char log_name_tmp[FN_REFLEN]; //make a char[] from String
+
+ strmake(log_name_tmp, log_name->ptr(), min(log_name->length(), FN_REFLEN-1));
+
+ char *p= fn_ext(log_name_tmp);
+ char *p_end;
+ if (!*p || log_pos<0)
+ {
+ error= -2; //means improper arguments
+ goto err;
+ }
+ // Convert 0-3 to 4
+ log_pos= max(log_pos, BIN_LOG_HEADER_SIZE);
+ /* p points to '.' */
+ log_name_extension= strtoul(++p, &p_end, 10);
+ /*
+ p_end points to the first invalid character.
+ If it equals to p, no digits were found, error.
+ If it contains '\0' it means conversion went ok.
+ */
+ if (p_end==p || *p_end)
+ {
+ error= -2;
+ goto err;
+ }
+
+ /* The "compare and wait" main loop */
+ while (!thd->killed &&
+ init_abort_pos_wait == abort_pos_wait &&
+ slave_running)
+ {
+ bool pos_reached;
+ int cmp_result= 0;
+
+ DBUG_PRINT("info",
+ ("init_abort_pos_wait: %ld abort_pos_wait: %ld",
+ init_abort_pos_wait, abort_pos_wait));
+ DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu",
+ group_master_log_name, (ulong) group_master_log_pos));
+
+ /*
+ group_master_log_name can be "", if we are just after a fresh
+ replication start or after a CHANGE MASTER TO MASTER_HOST/PORT
+ (before we have executed one Rotate event from the master) or
+ (rare) if the user is doing a weird slave setup (see next
+ paragraph). If group_master_log_name is "", we assume we don't
+ have enough info to do the comparison yet, so we just wait until
+ more data. In this case master_log_pos is always 0 except if
+ somebody (wrongly) sets this slave to be a slave of itself
+ without using --replicate-same-server-id (an unsupported
+ configuration which does nothing), then group_master_log_pos
+ will grow and group_master_log_name will stay "".
+ */
+ if (*group_master_log_name)
+ {
+ char *basename= (group_master_log_name +
+ dirname_length(group_master_log_name));
+ /*
+ First compare the parts before the extension.
+ Find the dot in the master's log basename,
+ and protect against user's input error :
+ if the names do not match up to '.' included, return error
+ */
+ char *q= (char*)(fn_ext(basename)+1);
+ if (strncmp(basename, log_name_tmp, (int)(q-basename)))
+ {
+ error= -2;
+ break;
+ }
+ // Now compare extensions.
+ char *q_end;
+ ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
+ if (group_master_log_name_extension < log_name_extension)
+ cmp_result= -1 ;
+ else
+ cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
+
+ pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
+ cmp_result > 0);
+ if (pos_reached || thd->killed)
+ break;
+ }
+
+ //wait for master update, with optional timeout.
+
+ DBUG_PRINT("info",("Waiting for master update"));
+ /*
+ We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
+ will wake us up.
+ */
+ if (timeout > 0)
+ {
+ /*
+ Note that pthread_cond_timedwait checks for the timeout
+ before for the condition ; i.e. it returns ETIMEDOUT
+ if the system time equals or exceeds the time specified by abstime
+ before the condition variable is signaled or broadcast, _or_ if
+ the absolute time specified by abstime has already passed at the time
+ of the call.
+ For that reason, pthread_cond_timedwait will do the "timeoutting" job
+ even if its condition is always immediately signaled (case of a loaded
+ master).
+ */
+ error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime);
+ }
+ else
+ pthread_cond_wait(&data_cond, &data_lock);
+ DBUG_PRINT("info",("Got signal of master update or timed out"));
+ if (error == ETIMEDOUT || error == ETIME)
+ {
+ error= -1;
+ break;
+ }
+ error=0;
+ event_count++;
+ DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
+ }
+
+err:
+ thd->exit_cond(msg);
+ DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
+improper_arguments: %d timed_out: %d",
+ thd->killed_errno(),
+ (int) (init_abort_pos_wait != abort_pos_wait),
+ (int) slave_running,
+ (int) (error == -2),
+ (int) (error == -1)));
+ if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
+ !slave_running)
+ {
+ error= -2;
+ }
+ DBUG_RETURN( error ? error : event_count );
+}
+
+
+void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
+ bool skip_lock)
+{
+ DBUG_ENTER("st_relay_log_info::inc_group_relay_log_pos");
+
+ if (!skip_lock)
+ pthread_mutex_lock(&data_lock);
+ inc_event_relay_log_pos();
+ group_relay_log_pos= event_relay_log_pos;
+ strmake(group_relay_log_name,event_relay_log_name,
+ sizeof(group_relay_log_name)-1);
+
+ notify_group_relay_log_name_update();
+
+ /*
+ If the slave does not support transactions and replicates a transaction,
+ users should not trust group_master_log_pos (which they can display with
+ SHOW SLAVE STATUS or read from relay-log.info), because to compute
+ group_master_log_pos the slave relies on log_pos stored in the master's
+ binlog, but if we are in a master's transaction these positions are always
+ the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does
+ not advance as it should on the non-transactional slave (it advances by
+ big leaps, whereas it should advance by small leaps).
+ */
+ /*
+ In 4.x we used the event's len to compute the positions here. This is
+ wrong if the event was 3.23/4.0 and has been converted to 5.0, because
+ then the event's len is not what is was in the master's binlog, so this
+ will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
+ replication: Exec_master_log_pos is wrong). Only way to solve this is to
+ have the original offset of the end of the event the relay log. This is
+ what we do in 5.0: log_pos has become "end_log_pos" (because the real use
+ of log_pos in 4.0 was to compute the end_log_pos; so better to store
+ end_log_pos instead of begin_log_pos.
+ If we had not done this fix here, the problem would also have appeared
+ when the slave and master are 5.0 but with different event length (for
+ example the slave is more recent than the master and features the event
+ UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
+ SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
+ value which would lead to badly broken replication.
+ Even the relay_log_pos will be corrupted in this case, because the len is
+ the relay log is not "val".
+ With the end_log_pos solution, we avoid computations involving lengthes.
+ */
+ DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu",
+ (long) log_pos, (long) group_master_log_pos));
+ if (log_pos) // 3.23 binlogs don't have log_posx
+ {
+ group_master_log_pos= log_pos;
+ }
+ pthread_cond_broadcast(&data_cond);
+ if (!skip_lock)
+ pthread_mutex_unlock(&data_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+void st_relay_log_info::close_temporary_tables()
+{
+ TABLE *table,*next;
+ DBUG_ENTER("st_relay_log_info::close_temporary_tables");
+
+ for (table=save_temporary_tables ; table ; table=next)
+ {
+ next=table->next;
+ /*
+ Don't ask for disk deletion. For now, anyway they will be deleted when
+ slave restarts, but it is a better intention to not delete them.
+ */
+ DBUG_PRINT("info", ("table: %p", table));
+ close_temporary(table, 1, 0);
+ }
+ save_temporary_tables= 0;
+ slave_open_temp_tables= 0;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ purge_relay_logs()
+
+ NOTES
+ Assumes to have a run lock on rli and that no slave thread are running.
+*/
+
+int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
+ const char** errmsg)
+{
+ int error=0;
+ DBUG_ENTER("purge_relay_logs");
+
+ /*
+ Even if rli->inited==0, we still try to empty rli->master_log_* variables.
+ Indeed, rli->inited==0 does not imply that they already are empty.
+ It could be that slave's info initialization partly succeeded :
+ for example if relay-log.info existed but *relay-bin*.*
+ have been manually removed, init_relay_log_info reads the old
+ relay-log.info and fills rli->master_log_*, then init_relay_log_info
+ checks for the existence of the relay log, this fails and
+ init_relay_log_info leaves rli->inited to 0.
+ In that pathological case, rli->master_log_pos* will be properly reinited
+ at the next START SLAVE (as RESET SLAVE or CHANGE
+ MASTER, the callers of purge_relay_logs, will delete bogus *.info files
+ or replace them with correct files), however if the user does SHOW SLAVE
+ STATUS before START SLAVE, he will see old, confusing rli->master_log_*.
+ In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS
+ to display fine in any case.
+ */
+
+ rli->group_master_log_name[0]= 0;
+ rli->group_master_log_pos= 0;
+
+ if (!rli->inited)
+ {
+ DBUG_PRINT("info", ("rli->inited == 0"));
+ DBUG_RETURN(0);
+ }
+
+ DBUG_ASSERT(rli->slave_running == 0);
+ DBUG_ASSERT(rli->mi->slave_running == 0);
+
+ rli->slave_skip_counter=0;
+ pthread_mutex_lock(&rli->data_lock);
+
+ /*
+ we close the relay log fd possibly left open by the slave SQL thread,
+ to be able to delete it; the relay log fd possibly left open by the slave
+ I/O thread will be closed naturally in reset_logs() by the
+ close(LOG_CLOSE_TO_BE_OPENED) call
+ */
+ if (rli->cur_log_fd >= 0)
+ {
+ end_io_cache(&rli->cache_buf);
+ my_close(rli->cur_log_fd, MYF(MY_WME));
+ rli->cur_log_fd= -1;
+ }
+
+ if (rli->relay_log.reset_logs(thd))
+ {
+ *errmsg = "Failed during log reset";
+ error=1;
+ goto err;
+ }
+ /* Save name of used relay log file */
+ strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(rli->group_relay_log_name)-1);
+ strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
+ sizeof(rli->event_relay_log_name)-1);
+ rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
+ if (count_relay_log_space(rli))
+ {
+ *errmsg= "Error counting relay log space";
+ goto err;
+ }
+ if (!just_reset)
+ error= init_relay_log_pos(rli, rli->group_relay_log_name,
+ rli->group_relay_log_pos,
+ 0 /* do not need data lock */, errmsg, 0);
+
+err:
+#ifndef DBUG_OFF
+ char buf[22];
+#endif
+ DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf)));
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Check if condition stated in UNTIL clause of START SLAVE is reached.
+ SYNOPSYS
+ st_relay_log_info::is_until_satisfied()
+ DESCRIPTION
+ Checks if UNTIL condition is reached. Uses caching result of last
+ comparison of current log file name and target log file name. So cached
+ value should be invalidated if current log file name changes
+ (see st_relay_log_info::notify_... functions).
+
+ This caching is needed to avoid of expensive string comparisons and
+ strtol() conversions needed for log names comparison. We don't need to
+ compare them each time this function is called, we only need to do this
+ when current log name changes. If we have UNTIL_MASTER_POS condition we
+ need to do this only after Rotate_log_event::exec_event() (which is
+ rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS
+ condition then we should invalidate cached comarison value after
+ inc_group_relay_log_pos() which called for each group of events (so we
+ have some benefit if we have something like queries that use
+ autoincrement or if we have transactions).
+
+ Should be called ONLY if until_condition != UNTIL_NONE !
+ RETURN VALUE
+ true - condition met or error happened (condition seems to have
+ bad log file name)
+ false - condition not met
+*/
+
+bool st_relay_log_info::is_until_satisfied()
+{
+ const char *log_name;
+ ulonglong log_pos;
+ DBUG_ENTER("st_relay_log_info::is_until_satisfied");
+
+ DBUG_ASSERT(until_condition != UNTIL_NONE);
+
+ if (until_condition == UNTIL_MASTER_POS)
+ {
+ log_name= group_master_log_name;
+ log_pos= group_master_log_pos;
+ }
+ else
+ { /* until_condition == UNTIL_RELAY_POS */
+ log_name= group_relay_log_name;
+ log_pos= group_relay_log_pos;
+ }
+
+ if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
+ {
+ /*
+ We have no cached comparison results so we should compare log names
+ and cache result.
+ If we are after RESET SLAVE, and the SQL slave thread has not processed
+ any event yet, it could be that group_master_log_name is "". In that case,
+ just wait for more events (as there is no sensible comparison to do).
+ */
+
+ if (*log_name)
+ {
+ const char *basename= log_name + dirname_length(log_name);
+
+ const char *q= (const char*)(fn_ext(basename)+1);
+ if (strncmp(basename, until_log_name, (int)(q-basename)) == 0)
+ {
+ /* Now compare extensions. */
+ char *q_end;
+ ulong log_name_extension= strtoul(q, &q_end, 10);
+ if (log_name_extension < until_log_name_extension)
+ until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS;
+ else
+ until_log_names_cmp_result=
+ (log_name_extension > until_log_name_extension) ?
+ UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ;
+ }
+ else
+ {
+ /* Probably error so we aborting */
+ sql_print_error("Slave SQL thread is stopped because UNTIL "
+ "condition is bad.");
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ DBUG_RETURN(until_log_pos == 0);
+ }
+
+ DBUG_RETURN(((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL &&
+ log_pos >= until_log_pos) ||
+ until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER));
+}
+
+
+void st_relay_log_info::cached_charset_invalidate()
+{
+ DBUG_ENTER("st_relay_log_info::cached_charset_invalidate");
+
+ /* Full of zeroes means uninitialized. */
+ bzero(cached_charset, sizeof(cached_charset));
+ DBUG_VOID_RETURN;
+}
+
+
+bool st_relay_log_info::cached_charset_compare(char *charset)
+{
+ DBUG_ENTER("st_relay_log_info::cached_charset_compare");
+
+ if (bcmp(cached_charset, charset, sizeof(cached_charset)))
+ {
+ memcpy(cached_charset, charset, sizeof(cached_charset));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+void st_relay_log_info::transaction_end(THD* thd)
+{
+ DBUG_ENTER("st_relay_log_info::transaction_end");
+
+ /*
+ Nothing to do here right now.
+ */
+
+ DBUG_VOID_RETURN;
+}
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+void st_relay_log_info::cleanup_context(THD *thd, bool error)
+{
+ DBUG_ENTER("st_relay_log_info::cleanup_context");
+
+ DBUG_ASSERT(sql_thd == thd);
+ /*
+ 1) Instances of Table_map_log_event, if ::exec_event() was called on them,
+ may have opened tables, which we cannot be sure have been closed (because
+ maybe the Rows_log_event have not been found or will not be, because slave
+ SQL thread is stopping, or relay log has a missing tail etc). So we close
+ all thread's tables. And so the table mappings have to be cancelled.
+ 2) Rows_log_event::exec_event() may even have started statements or
+ transactions on them, which we need to rollback in case of error.
+ 3) If finding a Format_description_log_event after a BEGIN, we also need
+ to rollback before continuing with the next events.
+ 4) so we need this "context cleanup" function.
+ */
+ if (error)
+ {
+ ha_autocommit_or_rollback(thd, 1); // if a "statement transaction"
+ end_trans(thd, ROLLBACK); // if a "real transaction"
+ }
+ m_table_map.clear_tables();
+ close_thread_tables(thd);
+ clear_tables_to_lock();
+ unsafe_to_stop_at= 0;
+ DBUG_VOID_RETURN;
+}
+#endif
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 392f12c2a71..d737055baf2 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -21,6 +21,7 @@
#include "rpl_tblmap.h"
+
/****************************************************************************
Replication SQL Thread
@@ -98,8 +99,8 @@ typedef struct st_relay_log_info
*/
pthread_cond_t start_cond, stop_cond, data_cond;
- /* parent master info structure */
- struct st_master_info *mi;
+ /* parent MASTER_INFO structure */
+ class MASTER_INFO *mi;
/*
Needed to deal properly with cur_log getting closed and re-opened with
@@ -164,6 +165,9 @@ typedef struct st_relay_log_info
time_t last_master_timestamp;
+ void clear_slave_error();
+ void clear_until_condition();
+
/*
Needed for problems when slave stops and we want to restart it
skipping one or more events in the master log that have caused
@@ -289,22 +293,6 @@ typedef struct st_relay_log_info
void cached_charset_invalidate();
bool cached_charset_compare(char *charset);
- /*
- To reload special tables when they are changes, we introduce a set
- of functions that will mark whenever special functions need to be
- called after modifying tables. Right now, the tables are either
- ACL tables or grants tables.
- */
- enum enum_reload_flag
- {
- RELOAD_NONE_F = 0UL,
- RELOAD_GRANT_F = (1UL << 0),
- RELOAD_ACCESS_F = (1UL << 1)
- };
-
- ulong m_reload_flags;
-
- void touching_table(char const* db, char const* table, ulong table_id);
void transaction_end(THD*);
void cleanup_context(THD *, bool);
@@ -322,4 +310,9 @@ typedef struct st_relay_log_info
time_t unsafe_to_stop_at;
} RELAY_LOG_INFO;
+
+// Defined in rpl_rli.cc
+int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname);
+
+
#endif /* RPL_RLI_H */
diff --git a/sql/slave.cc b/sql/slave.cc
index 00d6d168fb8..b497b7c8520 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -31,13 +31,15 @@
#include "rpl_tblmap.h"
+int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
+
+
#define MAX_SLAVE_RETRY_PAUSE 5
bool use_slave_mask = 0;
MY_BITMAP slave_error_mask;
typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
-volatile bool slave_sql_running = 0, slave_io_running = 0;
char* slave_load_tmpdir = 0;
MASTER_INFO *active_mi= 0;
my_bool replicate_same_server_id;
@@ -59,7 +61,6 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev);
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli);
static inline bool io_slave_killed(THD* thd,MASTER_INFO* mi);
static inline bool sql_slave_killed(THD* thd,RELAY_LOG_INFO* rli);
-static int count_relay_log_space(RELAY_LOG_INFO* rli);
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
@@ -202,223 +203,6 @@ err:
/*
- Open the given relay log
-
- SYNOPSIS
- init_relay_log_pos()
- rli Relay information (will be initialized)
- log Name of relay log file to read from. NULL = First log
- pos Position in relay log file
- need_data_lock Set to 1 if this functions should do mutex locks
- errmsg Store pointer to error message here
- look_for_description_event
- 1 if we should look for such an event. We only need
- this when the SQL thread starts and opens an existing
- relay log and has to execute it (possibly from an
- offset >4); then we need to read the first event of
- the relay log to be able to parse the events we have
- to execute.
-
- DESCRIPTION
- - Close old open relay log files.
- - If we are using the same relay log as the running IO-thread, then set
- rli->cur_log to point to the same IO_CACHE entry.
- - If not, open the 'log' binary file.
-
- TODO
- - check proper initialization of group_master_log_name/group_master_log_pos
-
- RETURN VALUES
- 0 ok
- 1 error. errmsg is set to point to the error message
-*/
-
-int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
- ulonglong pos, bool need_data_lock,
- const char** errmsg,
- bool look_for_description_event)
-{
- DBUG_ENTER("init_relay_log_pos");
- DBUG_PRINT("info", ("pos=%lu", pos));
-
- *errmsg=0;
- pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
-
- if (need_data_lock)
- pthread_mutex_lock(&rli->data_lock);
-
- /*
- Slave threads are not the only users of init_relay_log_pos(). CHANGE MASTER
- is, too, and init_slave() too; these 2 functions allocate a description
- event in init_relay_log_pos, which is not freed by the terminating SQL slave
- thread as that thread is not started by these functions. So we have to free
- the description_event here, in case, so that there is no memory leak in
- running, say, CHANGE MASTER.
- */
- delete rli->relay_log.description_event_for_exec;
- /*
- By default the relay log is in binlog format 3 (4.0).
- Even if format is 4, this will work enough to read the first event
- (Format_desc) (remember that format 4 is just lenghtened compared to format
- 3; format 3 is a prefix of format 4).
- */
- rli->relay_log.description_event_for_exec= new
- Format_description_log_event(3);
-
- pthread_mutex_lock(log_lock);
-
- /* Close log file and free buffers if it's already open */
- if (rli->cur_log_fd >= 0)
- {
- end_io_cache(&rli->cache_buf);
- my_close(rli->cur_log_fd, MYF(MY_WME));
- rli->cur_log_fd = -1;
- }
-
- rli->group_relay_log_pos = rli->event_relay_log_pos = pos;
-
- /*
- Test to see if the previous run was with the skip of purging
- If yes, we do not purge when we restart
- */
- if (rli->relay_log.find_log_pos(&rli->linfo, NullS, 1))
- {
- *errmsg="Could not find first log during relay log initialization";
- goto err;
- }
-
- if (log && rli->relay_log.find_log_pos(&rli->linfo, log, 1))
- {
- *errmsg="Could not find target log during relay log initialization";
- goto err;
- }
- strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->group_relay_log_name)-1);
- strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->event_relay_log_name)-1);
- if (rli->relay_log.is_active(rli->linfo.log_file_name))
- {
- /*
- The IO thread is using this log file.
- In this case, we will use the same IO_CACHE pointer to
- read data as the IO thread is using to write data.
- */
- my_b_seek((rli->cur_log=rli->relay_log.get_log_file()), (off_t)0);
- if (check_binlog_magic(rli->cur_log,errmsg))
- goto err;
- rli->cur_log_old_open_count=rli->relay_log.get_open_count();
- }
- else
- {
- /*
- Open the relay log and set rli->cur_log to point at this one
- */
- if ((rli->cur_log_fd=open_binlog(&rli->cache_buf,
- rli->linfo.log_file_name,errmsg)) < 0)
- goto err;
- rli->cur_log = &rli->cache_buf;
- }
- /*
- In all cases, check_binlog_magic() has been called so we're at offset 4 for
- sure.
- */
- if (pos > BIN_LOG_HEADER_SIZE) /* If pos<=4, we stay at 4 */
- {
- Log_event* ev;
- while (look_for_description_event)
- {
- /*
- Read the possible Format_description_log_event; if position
- was 4, no need, it will be read naturally.
- */
- DBUG_PRINT("info",("looking for a Format_description_log_event"));
-
- if (my_b_tell(rli->cur_log) >= pos)
- break;
-
- /*
- Because of we have rli->data_lock and log_lock, we can safely read an
- event
- */
- if (!(ev=Log_event::read_log_event(rli->cur_log,0,
- rli->relay_log.description_event_for_exec)))
- {
- DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
- rli->cur_log->error));
- if (rli->cur_log->error) /* not EOF */
- {
- *errmsg= "I/O error reading event at position 4";
- goto err;
- }
- break;
- }
- else if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
- {
- DBUG_PRINT("info",("found Format_description_log_event"));
- delete rli->relay_log.description_event_for_exec;
- rli->relay_log.description_event_for_exec= (Format_description_log_event*) ev;
- /*
- As ev was returned by read_log_event, it has passed is_valid(), so
- my_malloc() in ctor worked, no need to check again.
- */
- /*
- Ok, we found a Format_description event. But it is not sure that this
- describes the whole relay log; indeed, one can have this sequence
- (starting from position 4):
- Format_desc (of slave)
- Rotate (of master)
- Format_desc (of master)
- So the Format_desc which really describes the rest of the relay log
- is the 3rd event (it can't be further than that, because we rotate
- the relay log when we queue a Rotate event from the master).
- But what describes the Rotate is the first Format_desc.
- So what we do is:
- go on searching for Format_description events, until you exceed the
- position (argument 'pos') or until you find another event than Rotate
- or Format_desc.
- */
- }
- else
- {
- DBUG_PRINT("info",("found event of another type=%d",
- ev->get_type_code()));
- look_for_description_event= (ev->get_type_code() == ROTATE_EVENT);
- delete ev;
- }
- }
- my_b_seek(rli->cur_log,(off_t)pos);
-#ifndef DBUG_OFF
- {
- char llbuf1[22], llbuf2[22];
- DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
- llstr(my_b_tell(rli->cur_log),llbuf1),
- llstr(rli->event_relay_log_pos,llbuf2)));
- }
-#endif
-
- }
-
-err:
- /*
- If we don't purge, we can't honour relay_log_space_limit ;
- silently discard it
- */
- if (!relay_log_purge)
- rli->log_space_limit= 0;
- pthread_cond_broadcast(&rli->data_cond);
-
- pthread_mutex_unlock(log_lock);
-
- if (need_data_lock)
- pthread_mutex_unlock(&rli->data_lock);
- if (!rli->relay_log.description_event_for_exec->is_valid() && !*errmsg)
- *errmsg= "Invalid Format_description log event; could be out of memory";
-
- DBUG_RETURN ((*errmsg) ? 1 : 0);
-}
-
-
-/*
Init function to set up array for errors that should be skipped for slave
SYNOPSIS
@@ -461,174 +245,6 @@ void init_slave_skip_errors(const char* arg)
}
-void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
- bool skip_lock)
-{
- DBUG_ENTER("st_relay_log_info::inc_group_relay_log_pos");
-
- if (!skip_lock)
- pthread_mutex_lock(&data_lock);
- inc_event_relay_log_pos();
- group_relay_log_pos= event_relay_log_pos;
- strmake(group_relay_log_name,event_relay_log_name,
- sizeof(group_relay_log_name)-1);
-
- notify_group_relay_log_name_update();
-
- /*
- If the slave does not support transactions and replicates a transaction,
- users should not trust group_master_log_pos (which they can display with
- SHOW SLAVE STATUS or read from relay-log.info), because to compute
- group_master_log_pos the slave relies on log_pos stored in the master's
- binlog, but if we are in a master's transaction these positions are always
- the BEGIN's one (excepted for the COMMIT), so group_master_log_pos does
- not advance as it should on the non-transactional slave (it advances by
- big leaps, whereas it should advance by small leaps).
- */
- /*
- In 4.x we used the event's len to compute the positions here. This is
- wrong if the event was 3.23/4.0 and has been converted to 5.0, because
- then the event's len is not what is was in the master's binlog, so this
- will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
- replication: Exec_master_log_pos is wrong). Only way to solve this is to
- have the original offset of the end of the event the relay log. This is
- what we do in 5.0: log_pos has become "end_log_pos" (because the real use
- of log_pos in 4.0 was to compute the end_log_pos; so better to store
- end_log_pos instead of begin_log_pos.
- If we had not done this fix here, the problem would also have appeared
- when the slave and master are 5.0 but with different event length (for
- example the slave is more recent than the master and features the event
- UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
- SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
- value which would lead to badly broken replication.
- Even the relay_log_pos will be corrupted in this case, because the len is
- the relay log is not "val".
- With the end_log_pos solution, we avoid computations involving lengthes.
- */
- DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu",
- (long) log_pos, (long) group_master_log_pos));
- if (log_pos) // 3.23 binlogs don't have log_posx
- {
- group_master_log_pos= log_pos;
- }
- pthread_cond_broadcast(&data_cond);
- if (!skip_lock)
- pthread_mutex_unlock(&data_lock);
- DBUG_VOID_RETURN;
-}
-
-
-void st_relay_log_info::close_temporary_tables()
-{
- TABLE *table,*next;
- DBUG_ENTER("st_relay_log_info::close_temporary_tables");
-
- for (table=save_temporary_tables ; table ; table=next)
- {
- next=table->next;
- /*
- Don't ask for disk deletion. For now, anyway they will be deleted when
- slave restarts, but it is a better intention to not delete them.
- */
- DBUG_PRINT("info", ("table: %p", table));
- close_temporary(table, 1, 0);
- }
- save_temporary_tables= 0;
- slave_open_temp_tables= 0;
- DBUG_VOID_RETURN;
-}
-
-/*
- purge_relay_logs()
-
- NOTES
- Assumes to have a run lock on rli and that no slave thread are running.
-*/
-
-int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
- const char** errmsg)
-{
- int error=0;
- DBUG_ENTER("purge_relay_logs");
-
- /*
- Even if rli->inited==0, we still try to empty rli->master_log_* variables.
- Indeed, rli->inited==0 does not imply that they already are empty.
- It could be that slave's info initialization partly succeeded :
- for example if relay-log.info existed but *relay-bin*.*
- have been manually removed, init_relay_log_info reads the old
- relay-log.info and fills rli->master_log_*, then init_relay_log_info
- checks for the existence of the relay log, this fails and
- init_relay_log_info leaves rli->inited to 0.
- In that pathological case, rli->master_log_pos* will be properly reinited
- at the next START SLAVE (as RESET SLAVE or CHANGE
- MASTER, the callers of purge_relay_logs, will delete bogus *.info files
- or replace them with correct files), however if the user does SHOW SLAVE
- STATUS before START SLAVE, he will see old, confusing rli->master_log_*.
- In other words, we reinit rli->master_log_* for SHOW SLAVE STATUS
- to display fine in any case.
- */
-
- rli->group_master_log_name[0]= 0;
- rli->group_master_log_pos= 0;
-
- if (!rli->inited)
- {
- DBUG_PRINT("info", ("rli->inited == 0"));
- DBUG_RETURN(0);
- }
-
- DBUG_ASSERT(rli->slave_running == 0);
- DBUG_ASSERT(rli->mi->slave_running == 0);
-
- rli->slave_skip_counter=0;
- pthread_mutex_lock(&rli->data_lock);
-
- /*
- we close the relay log fd possibly left open by the slave SQL thread,
- to be able to delete it; the relay log fd possibly left open by the slave
- I/O thread will be closed naturally in reset_logs() by the
- close(LOG_CLOSE_TO_BE_OPENED) call
- */
- if (rli->cur_log_fd >= 0)
- {
- end_io_cache(&rli->cache_buf);
- my_close(rli->cur_log_fd, MYF(MY_WME));
- rli->cur_log_fd= -1;
- }
-
- if (rli->relay_log.reset_logs(thd))
- {
- *errmsg = "Failed during log reset";
- error=1;
- goto err;
- }
- /* Save name of used relay log file */
- strmake(rli->group_relay_log_name, rli->relay_log.get_log_fname(),
- sizeof(rli->group_relay_log_name)-1);
- strmake(rli->event_relay_log_name, rli->relay_log.get_log_fname(),
- sizeof(rli->event_relay_log_name)-1);
- rli->group_relay_log_pos= rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
- if (count_relay_log_space(rli))
- {
- *errmsg= "Error counting relay log space";
- goto err;
- }
- if (!just_reset)
- error= init_relay_log_pos(rli, rli->group_relay_log_name,
- rli->group_relay_log_pos,
- 0 /* do not need data lock */, errmsg, 0);
-
-err:
-#ifndef DBUG_OFF
- char buf[22];
-#endif
- DBUG_PRINT("info",("log_space_total: %s",llstr(rli->log_space_total,buf)));
- pthread_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(error);
-}
-
-
int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
{
DBUG_ENTER("terminate_slave_threads");
@@ -1023,7 +639,7 @@ const char *print_slave_db_safe(const char* db)
DBUG_RETURN((db ? db : ""));
}
-static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
+int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
uint length;
@@ -1054,7 +670,7 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
}
-static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
+int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
DBUG_ENTER("init_intvar_from_file");
@@ -1456,261 +1072,6 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
}
-void end_master_info(MASTER_INFO* mi)
-{
- DBUG_ENTER("end_master_info");
-
- if (!mi->inited)
- DBUG_VOID_RETURN;
- end_relay_log_info(&mi->rli);
- if (mi->fd >= 0)
- {
- end_io_cache(&mi->file);
- (void)my_close(mi->fd, MYF(MY_WME));
- mi->fd = -1;
- }
- mi->inited = 0;
-
- DBUG_VOID_RETURN;
-}
-
-
-static int init_relay_log_info(RELAY_LOG_INFO* rli,
- const char* info_fname)
-{
- char fname[FN_REFLEN+128];
- int info_fd;
- const char* msg = 0;
- int error = 0;
- DBUG_ENTER("init_relay_log_info");
- DBUG_ASSERT(!rli->no_storage); // Don't init if there is no storage
-
- if (rli->inited) // Set if this function called
- DBUG_RETURN(0);
- fn_format(fname, info_fname, mysql_data_home, "", 4+32);
- pthread_mutex_lock(&rli->data_lock);
- info_fd = rli->info_fd;
- rli->cur_log_fd = -1;
- rli->slave_skip_counter=0;
- rli->abort_pos_wait=0;
- rli->log_space_limit= relay_log_space_limit;
- rli->log_space_total= 0;
- rli->tables_to_lock= 0;
- rli->tables_to_lock_count= 0;
-
- /*
- The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE.
- Note that the I/O thread flushes it to disk after writing every
- event, in flush_master_info(mi, 1).
- */
-
- /*
- For the maximum log size, we choose max_relay_log_size if it is
- non-zero, max_binlog_size otherwise. If later the user does SET
- GLOBAL on one of these variables, fix_max_binlog_size and
- fix_max_relay_log_size will reconsider the choice (for example
- if the user changes max_relay_log_size to zero, we have to
- switch to using max_binlog_size for the relay log) and update
- rli->relay_log.max_size (and mysql_bin_log.max_size).
- */
- {
- char buf[FN_REFLEN];
- const char *ln;
- static bool name_warning_sent= 0;
- ln= rli->relay_log.generate_name(opt_relay_logname, "-relay-bin",
- 1, buf);
- /* We send the warning only at startup, not after every RESET SLAVE */
- if (!opt_relay_logname && !opt_relaylog_index_name && !name_warning_sent)
- {
- /*
- User didn't give us info to name the relay log index file.
- Picking `hostname`-relay-bin.index like we do, causes replication to
- fail if this slave's hostname is changed later. So, we would like to
- instead require a name. But as we don't want to break many existing
- setups, we only give warning, not error.
- */
- sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
- " so replication "
- "may break when this MySQL server acts as a "
- "slave and has his hostname changed!! Please "
- "use '--relay-log=%s' to avoid this problem.", ln);
- name_warning_sent= 1;
- }
- /*
- note, that if open() fails, we'll still have index file open
- but a destructor will take care of that
- */
- if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) ||
- rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
- (max_relay_log_size ? max_relay_log_size :
- max_binlog_size), 1))
- {
- pthread_mutex_unlock(&rli->data_lock);
- sql_print_error("Failed in open_log() called from init_relay_log_info()");
- DBUG_RETURN(1);
- }
- }
-
- /* if file does not exist */
- if (access(fname,F_OK))
- {
- /*
- If someone removed the file from underneath our feet, just close
- the old descriptor and re-create the old file
- */
- if (info_fd >= 0)
- my_close(info_fd, MYF(MY_WME));
- if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
- {
- sql_print_error("Failed to create a new relay log info file (\
-file '%s', errno %d)", fname, my_errno);
- msg= current_thd->net.last_error;
- goto err;
- }
- if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
- MYF(MY_WME)))
- {
- sql_print_error("Failed to create a cache on relay log info file '%s'",
- fname);
- msg= current_thd->net.last_error;
- goto err;
- }
-
- /* Init relay log with first entry in the relay index file */
- if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
- &msg, 0))
- {
- sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)");
- goto err;
- }
- rli->group_master_log_name[0]= 0;
- rli->group_master_log_pos= 0;
- rli->info_fd= info_fd;
- }
- else // file exists
- {
- if (info_fd >= 0)
- reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
- else
- {
- int error=0;
- if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
- {
- sql_print_error("\
-Failed to open the existing relay log info file '%s' (errno %d)",
- fname, my_errno);
- error= 1;
- }
- else if (init_io_cache(&rli->info_file, info_fd,
- IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
- {
- sql_print_error("Failed to create a cache on relay log info file '%s'",
- fname);
- error= 1;
- }
- if (error)
- {
- if (info_fd >= 0)
- my_close(info_fd, MYF(0));
- rli->info_fd= -1;
- rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
- pthread_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(1);
- }
- }
-
- rli->info_fd = info_fd;
- int relay_log_pos, master_log_pos;
- if (init_strvar_from_file(rli->group_relay_log_name,
- sizeof(rli->group_relay_log_name),
- &rli->info_file, "") ||
- init_intvar_from_file(&relay_log_pos,
- &rli->info_file, BIN_LOG_HEADER_SIZE) ||
- init_strvar_from_file(rli->group_master_log_name,
- sizeof(rli->group_master_log_name),
- &rli->info_file, "") ||
- init_intvar_from_file(&master_log_pos, &rli->info_file, 0))
- {
- msg="Error reading slave log configuration";
- goto err;
- }
- strmake(rli->event_relay_log_name,rli->group_relay_log_name,
- sizeof(rli->event_relay_log_name)-1);
- rli->group_relay_log_pos= rli->event_relay_log_pos= relay_log_pos;
- rli->group_master_log_pos= master_log_pos;
-
- if (init_relay_log_pos(rli,
- rli->group_relay_log_name,
- rli->group_relay_log_pos,
- 0 /* no data lock*/,
- &msg, 0))
- {
- char llbuf[22];
- sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)",
- rli->group_relay_log_name,
- llstr(rli->group_relay_log_pos, llbuf));
- goto err;
- }
- }
-
-#ifndef DBUG_OFF
- {
- char llbuf1[22], llbuf2[22];
- DBUG_PRINT("info", ("my_b_tell(rli->cur_log)=%s rli->event_relay_log_pos=%s",
- llstr(my_b_tell(rli->cur_log),llbuf1),
- llstr(rli->event_relay_log_pos,llbuf2)));
- DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
- }
-#endif
-
- /*
- Now change the cache from READ to WRITE - must do this
- before flush_relay_log_info
- */
- reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
- if ((error= flush_relay_log_info(rli)))
- sql_print_error("Failed to flush relay log info file");
- if (count_relay_log_space(rli))
- {
- msg="Error counting relay log space";
- goto err;
- }
- rli->inited= 1;
- pthread_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(error);
-
-err:
- sql_print_error(msg);
- end_io_cache(&rli->info_file);
- if (info_fd >= 0)
- my_close(info_fd, MYF(0));
- rli->info_fd= -1;
- rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
- pthread_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(1);
-}
-
-
-static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
-{
- MY_STAT s;
- DBUG_ENTER("add_relay_log");
- if (!my_stat(linfo->log_file_name,&s,MYF(0)))
- {
- sql_print_error("log %s listed in the index, but failed to stat",
- linfo->log_file_name);
- DBUG_RETURN(1);
- }
- rli->log_space_total += s.st_size;
-#ifndef DBUG_OFF
- char buf[22];
- DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf)));
-#endif
- DBUG_RETURN(0);
-}
-
-
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
bool slave_killed=0;
@@ -1733,31 +1094,6 @@ Waiting for the slave SQL thread to free enough relay log space");
}
-static int count_relay_log_space(RELAY_LOG_INFO* rli)
-{
- LOG_INFO linfo;
- DBUG_ENTER("count_relay_log_space");
- rli->log_space_total= 0;
- if (rli->relay_log.find_log_pos(&linfo, NullS, 1))
- {
- sql_print_error("Could not find first log while counting relay log space");
- DBUG_RETURN(1);
- }
- do
- {
- if (add_relay_log(rli,&linfo))
- DBUG_RETURN(1);
- } while (!rli->relay_log.find_next_log(&linfo, 1));
- /*
- As we have counted everything, including what may have written in a
- preceding write, we must reset bytes_written, or we may count some space
- twice.
- */
- rli->relay_log.reset_bytes_written();
- DBUG_RETURN(0);
-}
-
-
/*
Builds a Rotate from the ignored events' info and writes it to relay log.
@@ -1811,284 +1147,6 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
}
-void init_master_info_with_options(MASTER_INFO* mi)
-{
- DBUG_ENTER("init_master_info_with_options");
-
- mi->master_log_name[0] = 0;
- mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
-
- if (master_host)
- strmake(mi->host, master_host, sizeof(mi->host) - 1);
- if (master_user)
- strmake(mi->user, master_user, sizeof(mi->user) - 1);
- if (master_password)
- strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
- mi->port = master_port;
- mi->connect_retry = master_connect_retry;
-
- mi->ssl= master_ssl;
- if (master_ssl_ca)
- strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1);
- if (master_ssl_capath)
- strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1);
- if (master_ssl_cert)
- strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1);
- if (master_ssl_cipher)
- strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
- if (master_ssl_key)
- strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
- DBUG_VOID_RETURN;
-}
-
-void clear_slave_error(RELAY_LOG_INFO* rli)
-{
- DBUG_ENTER("clear_slave_error");
-
- /* Clear the errors displayed by SHOW SLAVE STATUS */
- rli->last_slave_error[0]= 0;
- rli->last_slave_errno= 0;
- DBUG_VOID_RETURN;
-}
-
-/*
- Reset UNTIL condition for RELAY_LOG_INFO
- SYNOPSYS
- clear_until_condition()
- rli - RELAY_LOG_INFO structure where UNTIL condition should be reset
- */
-void clear_until_condition(RELAY_LOG_INFO* rli)
-{
- DBUG_ENTER("clear_until_condition");
-
- rli->until_condition= RELAY_LOG_INFO::UNTIL_NONE;
- rli->until_log_name[0]= 0;
- rli->until_log_pos= 0;
- DBUG_VOID_RETURN;
-}
-
-
-#define LINES_IN_MASTER_INFO_WITH_SSL 14
-
-
-int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
- const char* slave_info_fname,
- bool abort_if_no_master_info_file,
- int thread_mask)
-{
- int fd,error;
- char fname[FN_REFLEN+128];
- DBUG_ENTER("init_master_info");
-
- if (mi->inited)
- {
- /*
- We have to reset read position of relay-log-bin as we may have
- already been reading from 'hotlog' when the slave was stopped
- last time. If this case pos_in_file would be set and we would
- get a crash when trying to read the signature for the binary
- relay log.
-
- We only rewind the read position if we are starting the SQL
- thread. The handle_slave_sql thread assumes that the read
- position is at the beginning of the file, and will read the
- "signature" and then fast-forward to the last position read.
- */
- if (thread_mask & SLAVE_SQL)
- {
- my_b_seek(mi->rli.cur_log, (my_off_t) 0);
- }
- DBUG_RETURN(0);
- }
-
- mi->mysql=0;
- mi->file_id=1;
- fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
-
- /*
- We need a mutex while we are changing master info parameters to
- keep other threads from reading bogus info
- */
-
- pthread_mutex_lock(&mi->data_lock);
- fd = mi->fd;
-
- /* does master.info exist ? */
-
- if (access(fname,F_OK))
- {
- if (abort_if_no_master_info_file)
- {
- pthread_mutex_unlock(&mi->data_lock);
- DBUG_RETURN(0);
- }
- /*
- if someone removed the file from underneath our feet, just close
- the old descriptor and re-create the old file
- */
- if (fd >= 0)
- my_close(fd, MYF(MY_WME));
- if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
- {
- sql_print_error("Failed to create a new master info file (\
-file '%s', errno %d)", fname, my_errno);
- goto err;
- }
- if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
- MYF(MY_WME)))
- {
- sql_print_error("Failed to create a cache on master info file (\
-file '%s')", fname);
- goto err;
- }
-
- mi->fd = fd;
- init_master_info_with_options(mi);
-
- }
- else // file exists
- {
- if (fd >= 0)
- reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
- else
- {
- if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
- {
- sql_print_error("Failed to open the existing master info file (\
-file '%s', errno %d)", fname, my_errno);
- goto err;
- }
- if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
- 0, MYF(MY_WME)))
- {
- sql_print_error("Failed to create a cache on master info file (\
-file '%s')", fname);
- goto err;
- }
- }
-
- mi->fd = fd;
- int port, connect_retry, master_log_pos, ssl= 0, lines;
- char *first_non_digit;
-
- /*
- Starting from 4.1.x master.info has new format. Now its
- first line contains number of lines in file. By reading this
- number we will be always distinguish to which version our
- master.info corresponds to. We can't simply count lines in
- file since versions before 4.1.x could generate files with more
- lines than needed.
- If first line doesn't contain a number or contain number less than
- 14 then such file is treated like file from pre 4.1.1 version.
- There is no ambiguity when reading an old master.info, as before
- 4.1.1, the first line contained the binlog's name, which is either
- empty or has an extension (contains a '.'), so can't be confused
- with an integer.
-
- So we're just reading first line and trying to figure which version
- is this.
- */
-
- /*
- The first row is temporarily stored in mi->master_log_name,
- if it is line count and not binlog name (new format) it will be
- overwritten by the second row later.
- */
- if (init_strvar_from_file(mi->master_log_name,
- sizeof(mi->master_log_name), &mi->file,
- ""))
- goto errwithmsg;
-
- lines= strtoul(mi->master_log_name, &first_non_digit, 10);
-
- if (mi->master_log_name[0]!='\0' &&
- *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
- { // Seems to be new format
- if (init_strvar_from_file(mi->master_log_name,
- sizeof(mi->master_log_name), &mi->file, ""))
- goto errwithmsg;
- }
- else
- lines= 7;
-
- if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
- init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
- master_host) ||
- init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
- master_user) ||
- init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
- &mi->file, master_password) ||
- init_intvar_from_file(&port, &mi->file, master_port) ||
- init_intvar_from_file(&connect_retry, &mi->file,
- master_connect_retry))
- goto errwithmsg;
-
- /*
- If file has ssl part use it even if we have server without
- SSL support. But these option will be ignored later when
- slave will try connect to master, so in this case warning
- is printed.
- */
- if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
- (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
- init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
- &mi->file, master_ssl_ca) ||
- init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
- &mi->file, master_ssl_capath) ||
- init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
- &mi->file, master_ssl_cert) ||
- init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
- &mi->file, master_ssl_cipher) ||
- init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
- &mi->file, master_ssl_key)))
- goto errwithmsg;
-#ifndef HAVE_OPENSSL
- if (ssl)
- sql_print_warning("SSL information in the master info file "
- "('%s') are ignored because this MySQL slave was compiled "
- "without SSL support.", fname);
-#endif /* HAVE_OPENSSL */
-
- /*
- This has to be handled here as init_intvar_from_file can't handle
- my_off_t types
- */
- mi->master_log_pos= (my_off_t) master_log_pos;
- mi->port= (uint) port;
- mi->connect_retry= (uint) connect_retry;
- mi->ssl= (my_bool) ssl;
- }
- DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
- mi->master_log_name,
- (ulong) mi->master_log_pos));
-
- mi->rli.mi = mi;
- if (init_relay_log_info(&mi->rli, slave_info_fname))
- goto err;
-
- mi->inited = 1;
- // now change cache READ -> WRITE - must do this before flush_master_info
- reinit_io_cache(&mi->file, WRITE_CACHE, 0L, 0, 1);
- if ((error=test(flush_master_info(mi, 1))))
- sql_print_error("Failed to flush master info file");
- pthread_mutex_unlock(&mi->data_lock);
- DBUG_RETURN(error);
-
-errwithmsg:
- sql_print_error("Error reading master configuration");
-
-err:
- if (fd >= 0)
- {
- my_close(fd, MYF(0));
- end_io_cache(&mi->file);
- }
- mi->fd= -1;
- pthread_mutex_unlock(&mi->data_lock);
- DBUG_RETURN(1);
-}
-
-
int register_slave_on_master(MYSQL* mysql)
{
char buf[1024], *pos= buf;
@@ -2307,313 +1365,6 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(FALSE);
}
-/*
- RETURN
- 2 - flush relay log failed
- 1 - flush master info failed
- 0 - all ok
-*/
-int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
-{
- IO_CACHE* file = &mi->file;
- char lbuf[22];
- DBUG_ENTER("flush_master_info");
- DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
-
- /*
- Flush the relay log to disk. If we don't do it, then the relay log while
- have some part (its last kilobytes) in memory only, so if the slave server
- dies now, with, say, from master's position 100 to 150 in memory only (not
- on disk), and with position 150 in master.info, then when the slave
- restarts, the I/O thread will fetch binlogs from 150, so in the relay log
- we will have "[0, 100] U [150, infinity[" and nobody will notice it, so the
- SQL thread will jump from 100 to 150, and replication will silently break.
-
- When we come to this place in code, relay log may or not be initialized;
- the caller is responsible for setting 'flush_relay_log_cache' accordingly.
- */
- if (flush_relay_log_cache &&
- flush_io_cache(mi->rli.relay_log.get_log_file()))
- DBUG_RETURN(2);
-
- /*
- We flushed the relay log BEFORE the master.info file, because if we crash
- now, we will get a duplicate event in the relay log at restart. If we
- flushed in the other order, we would get a hole in the relay log.
- And duplicate is better than hole (with a duplicate, in later versions we
- can add detection and scrap one event; with a hole there's nothing we can
- do).
- */
-
- /*
- In certain cases this code may create master.info files that seems
- corrupted, because of extra lines filled with garbage in the end
- file (this happens if new contents take less space than previous
- contents of file). But because of number of lines in the first line
- of file we don't care about this garbage.
- */
-
- my_b_seek(file, 0L);
- my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
- LINES_IN_MASTER_INFO_WITH_SSL,
- mi->master_log_name, llstr(mi->master_log_pos, lbuf),
- mi->host, mi->user,
- mi->password, mi->port, mi->connect_retry,
- (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
- mi->ssl_cipher, mi->ssl_key);
- DBUG_RETURN(-flush_io_cache(file));
-}
-
-
-st_relay_log_info::st_relay_log_info()
- :no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
- cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
- ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
- abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0),
- inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
- until_log_pos(0), retried_trans(0),
- tables_to_lock(0), tables_to_lock_count(0),
- m_reload_flags(RELOAD_NONE_F),
- unsafe_to_stop_at(0)
-{
- DBUG_ENTER("st_relay_log_info::st_relay_log_info");
-
- group_relay_log_name[0]= event_relay_log_name[0]=
- group_master_log_name[0]= 0;
- last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0;
- bzero((char*) &info_file, sizeof(info_file));
- bzero((char*) &cache_buf, sizeof(cache_buf));
- cached_charset_invalidate();
- pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&data_cond, NULL);
- pthread_cond_init(&start_cond, NULL);
- pthread_cond_init(&stop_cond, NULL);
- pthread_cond_init(&log_space_cond, NULL);
- relay_log.init_pthread_objects();
- DBUG_VOID_RETURN;
-}
-
-
-st_relay_log_info::~st_relay_log_info()
-{
- DBUG_ENTER("st_relay_log_info::~st_relay_log_info");
-
- pthread_mutex_destroy(&run_lock);
- pthread_mutex_destroy(&data_lock);
- pthread_mutex_destroy(&log_space_lock);
- pthread_cond_destroy(&data_cond);
- pthread_cond_destroy(&start_cond);
- pthread_cond_destroy(&stop_cond);
- pthread_cond_destroy(&log_space_cond);
- relay_log.cleanup();
- DBUG_VOID_RETURN;
-}
-
-/*
- Waits until the SQL thread reaches (has executed up to) the
- log/position or timed out.
-
- SYNOPSIS
- wait_for_pos()
- thd client thread that sent SELECT MASTER_POS_WAIT
- log_name log name to wait for
- log_pos position to wait for
- timeout timeout in seconds before giving up waiting
-
- NOTES
- timeout is longlong whereas it should be ulong ; but this is
- to catch if the user submitted a negative timeout.
-
- RETURN VALUES
- -2 improper arguments (log_pos<0)
- or slave not running, or master info changed
- during the function's execution,
- or client thread killed. -2 is translated to NULL by caller
- -1 timed out
- >=0 number of log events the function had to wait
- before reaching the desired log/position
- */
-
-int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
- longlong log_pos,
- longlong timeout)
-{
- int event_count = 0;
- ulong init_abort_pos_wait;
- int error=0;
- struct timespec abstime; // for timeout checking
- const char *msg;
- DBUG_ENTER("st_relay_log_info::wait_for_pos");
-
- if (!inited)
- DBUG_RETURN(-1);
-
- DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu",
- log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
-
- set_timespec(abstime,timeout);
- pthread_mutex_lock(&data_lock);
- msg= thd->enter_cond(&data_cond, &data_lock,
- "Waiting for the slave SQL thread to "
- "advance position");
- /*
- This function will abort when it notices that some CHANGE MASTER or
- RESET MASTER has changed the master info.
- To catch this, these commands modify abort_pos_wait ; We just monitor
- abort_pos_wait and see if it has changed.
- Why do we have this mechanism instead of simply monitoring slave_running
- in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that
- the SQL thread be stopped?
- This is becasue if someones does:
- STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
- the change may happen very quickly and we may not notice that
- slave_running briefly switches between 1/0/1.
- */
- init_abort_pos_wait= abort_pos_wait;
-
- /*
- We'll need to
- handle all possible log names comparisons (e.g. 999 vs 1000).
- We use ulong for string->number conversion ; this is no
- stronger limitation than in find_uniq_filename in sql/log.cc
- */
- ulong log_name_extension;
- char log_name_tmp[FN_REFLEN]; //make a char[] from String
-
- strmake(log_name_tmp, log_name->ptr(), min(log_name->length(), FN_REFLEN-1));
-
- char *p= fn_ext(log_name_tmp);
- char *p_end;
- if (!*p || log_pos<0)
- {
- error= -2; //means improper arguments
- goto err;
- }
- // Convert 0-3 to 4
- log_pos= max(log_pos, BIN_LOG_HEADER_SIZE);
- /* p points to '.' */
- log_name_extension= strtoul(++p, &p_end, 10);
- /*
- p_end points to the first invalid character.
- If it equals to p, no digits were found, error.
- If it contains '\0' it means conversion went ok.
- */
- if (p_end==p || *p_end)
- {
- error= -2;
- goto err;
- }
-
- /* The "compare and wait" main loop */
- while (!thd->killed &&
- init_abort_pos_wait == abort_pos_wait &&
- slave_running)
- {
- bool pos_reached;
- int cmp_result= 0;
-
- DBUG_PRINT("info",
- ("init_abort_pos_wait: %ld abort_pos_wait: %ld",
- init_abort_pos_wait, abort_pos_wait));
- DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu",
- group_master_log_name, (ulong) group_master_log_pos));
-
- /*
- group_master_log_name can be "", if we are just after a fresh
- replication start or after a CHANGE MASTER TO MASTER_HOST/PORT
- (before we have executed one Rotate event from the master) or
- (rare) if the user is doing a weird slave setup (see next
- paragraph). If group_master_log_name is "", we assume we don't
- have enough info to do the comparison yet, so we just wait until
- more data. In this case master_log_pos is always 0 except if
- somebody (wrongly) sets this slave to be a slave of itself
- without using --replicate-same-server-id (an unsupported
- configuration which does nothing), then group_master_log_pos
- will grow and group_master_log_name will stay "".
- */
- if (*group_master_log_name)
- {
- char *basename= (group_master_log_name +
- dirname_length(group_master_log_name));
- /*
- First compare the parts before the extension.
- Find the dot in the master's log basename,
- and protect against user's input error :
- if the names do not match up to '.' included, return error
- */
- char *q= (char*)(fn_ext(basename)+1);
- if (strncmp(basename, log_name_tmp, (int)(q-basename)))
- {
- error= -2;
- break;
- }
- // Now compare extensions.
- char *q_end;
- ulong group_master_log_name_extension= strtoul(q, &q_end, 10);
- if (group_master_log_name_extension < log_name_extension)
- cmp_result= -1 ;
- else
- cmp_result= (group_master_log_name_extension > log_name_extension) ? 1 : 0 ;
-
- pos_reached= ((!cmp_result && group_master_log_pos >= (ulonglong)log_pos) ||
- cmp_result > 0);
- if (pos_reached || thd->killed)
- break;
- }
-
- //wait for master update, with optional timeout.
-
- DBUG_PRINT("info",("Waiting for master update"));
- /*
- We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
- will wake us up.
- */
- if (timeout > 0)
- {
- /*
- Note that pthread_cond_timedwait checks for the timeout
- before for the condition ; i.e. it returns ETIMEDOUT
- if the system time equals or exceeds the time specified by abstime
- before the condition variable is signaled or broadcast, _or_ if
- the absolute time specified by abstime has already passed at the time
- of the call.
- For that reason, pthread_cond_timedwait will do the "timeoutting" job
- even if its condition is always immediately signaled (case of a loaded
- master).
- */
- error=pthread_cond_timedwait(&data_cond, &data_lock, &abstime);
- }
- else
- pthread_cond_wait(&data_cond, &data_lock);
- DBUG_PRINT("info",("Got signal of master update or timed out"));
- if (error == ETIMEDOUT || error == ETIME)
- {
- error= -1;
- break;
- }
- error=0;
- event_count++;
- DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
- }
-
-err:
- thd->exit_cond(msg);
- DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
-improper_arguments: %d timed_out: %d",
- thd->killed_errno(),
- (int) (init_abort_pos_wait != abort_pos_wait),
- (int) slave_running,
- (int) (error == -2),
- (int) (error == -1)));
- if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
- !slave_running)
- {
- error= -2;
- }
- DBUG_RETURN( error ? error : event_count );
-}
void set_slave_thread_options(THD* thd)
{
@@ -2663,6 +1414,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
thd->security_ctx->skip_grants();
my_net_init(&thd->net, 0);
+/*
+ Adding MAX_LOG_EVENT_HEADER_LEN to the max_allowed_packet on all
+ slave threads, since a replication event can become this much larger
+ than the corresponding packet (query) sent from client to master.
+*/
+ thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
+ + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */
thd->net.read_timeout = slave_net_timeout;
thd->slave_thread = 1;
set_slave_thread_options(thd);
@@ -2872,119 +1630,6 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
}
}
-/*
- Check if condition stated in UNTIL clause of START SLAVE is reached.
- SYNOPSYS
- st_relay_log_info::is_until_satisfied()
- DESCRIPTION
- Checks if UNTIL condition is reached. Uses caching result of last
- comparison of current log file name and target log file name. So cached
- value should be invalidated if current log file name changes
- (see st_relay_log_info::notify_... functions).
-
- This caching is needed to avoid of expensive string comparisons and
- strtol() conversions needed for log names comparison. We don't need to
- compare them each time this function is called, we only need to do this
- when current log name changes. If we have UNTIL_MASTER_POS condition we
- need to do this only after Rotate_log_event::exec_event() (which is
- rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS
- condition then we should invalidate cached comarison value after
- inc_group_relay_log_pos() which called for each group of events (so we
- have some benefit if we have something like queries that use
- autoincrement or if we have transactions).
-
- Should be called ONLY if until_condition != UNTIL_NONE !
- RETURN VALUE
- true - condition met or error happened (condition seems to have
- bad log file name)
- false - condition not met
-*/
-
-bool st_relay_log_info::is_until_satisfied()
-{
- const char *log_name;
- ulonglong log_pos;
- DBUG_ENTER("st_relay_log_info::is_until_satisfied");
-
- DBUG_ASSERT(until_condition != UNTIL_NONE);
-
- if (until_condition == UNTIL_MASTER_POS)
- {
- log_name= group_master_log_name;
- log_pos= group_master_log_pos;
- }
- else
- { /* until_condition == UNTIL_RELAY_POS */
- log_name= group_relay_log_name;
- log_pos= group_relay_log_pos;
- }
-
- if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
- {
- /*
- We have no cached comparison results so we should compare log names
- and cache result.
- If we are after RESET SLAVE, and the SQL slave thread has not processed
- any event yet, it could be that group_master_log_name is "". In that case,
- just wait for more events (as there is no sensible comparison to do).
- */
-
- if (*log_name)
- {
- const char *basename= log_name + dirname_length(log_name);
-
- const char *q= (const char*)(fn_ext(basename)+1);
- if (strncmp(basename, until_log_name, (int)(q-basename)) == 0)
- {
- /* Now compare extensions. */
- char *q_end;
- ulong log_name_extension= strtoul(q, &q_end, 10);
- if (log_name_extension < until_log_name_extension)
- until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS;
- else
- until_log_names_cmp_result=
- (log_name_extension > until_log_name_extension) ?
- UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ;
- }
- else
- {
- /* Probably error so we aborting */
- sql_print_error("Slave SQL thread is stopped because UNTIL "
- "condition is bad.");
- DBUG_RETURN(TRUE);
- }
- }
- else
- DBUG_RETURN(until_log_pos == 0);
- }
-
- DBUG_RETURN(((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL &&
- log_pos >= until_log_pos) ||
- until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER));
-}
-
-
-void st_relay_log_info::cached_charset_invalidate()
-{
- DBUG_ENTER("st_relay_log_info::cached_charset_invalidate");
-
- /* Full of zeroes means uninitialized. */
- bzero(cached_charset, sizeof(cached_charset));
- DBUG_VOID_RETURN;
-}
-
-
-bool st_relay_log_info::cached_charset_compare(char *charset)
-{
- DBUG_ENTER("st_relay_log_info::cached_charset_compare");
-
- if (bcmp(cached_charset, charset, sizeof(cached_charset)))
- {
- memcpy(cached_charset, charset, sizeof(cached_charset));
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-}
/*
Check if the current error is of temporary nature of not.
@@ -3176,6 +1821,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
We were in a transaction which has been rolled back because of a
temporary error;
let's seek back to BEGIN log event and retry it all again.
+ Note, if lock wait timeout (innodb_lock_wait_timeout exceeded)
+ there is no rollback since 5.0.13 (ref: manual).
We have to not only seek but also
a) init_master_info(), to seek back to hot relay log's start for later
(for when we will come back to this hot log after re-processing the
@@ -3303,11 +1950,19 @@ pthread_handler_t handle_slave_io(void *arg)
thd->proc_info = "Connecting to master";
// we can get killed during safe_connect
if (!safe_connect(thd, mysql, mi))
+ {
sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
replication started in log '%s' at position %s", mi->user,
- mi->host, mi->port,
- IO_RPL_LOG_NAME,
- llstr(mi->master_log_pos,llbuff));
+ mi->host, mi->port,
+ IO_RPL_LOG_NAME,
+ llstr(mi->master_log_pos,llbuff));
+ /*
+ Adding MAX_LOG_EVENT_HEADER_LEN to the max_packet_size on the I/O
+ thread, since a replication event can become this much larger than
+ the corresponding packet (query) sent from client to master.
+ */
+ mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER;
+ }
else
{
sql_print_information("Slave I/O thread killed while connecting to master");
@@ -3632,7 +2287,7 @@ pthread_handler_t handle_slave_sql(void *arg)
now.
But the master timestamp is reset by RESET SLAVE & CHANGE MASTER.
*/
- clear_slave_error(rli);
+ rli->clear_slave_error();
//tell the I/O thread to take relay_log_space_limit into account from now on
pthread_mutex_lock(&rli->log_space_lock);
@@ -4455,7 +3110,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
'%s@%s:%d': \
Error: '%s' errno: %d retry-time: %d retries: %lu",
(reconnect ? "reconnecting" : "connecting"),
- mi->user,mi->host,mi->port,
+ mi->user, mi->host, mi->port,
mysql_error(mysql), last_errno,
mi->connect_retry,
master_retry_count);
@@ -4990,121 +3645,6 @@ end:
DBUG_VOID_RETURN;
}
-/*
- Some system tables needed to be re-read by the MySQL server after it has
- updated them; in statement-based replication, the GRANT and other commands
- are sent verbatim to the slave which then reloads; in row-based replication,
- changes to these tables are done through ordinary Rows binlog events, so
- master must add some flag for the slave to know it has to reload the tables.
-*/
-struct st_reload_entry
-{
- char const *table;
- st_relay_log_info::enum_reload_flag flag;
-};
-
-/*
- Sorted array of table names, please keep it sorted since we are
- using bsearch() on it below.
- */
-static st_reload_entry s_mysql_tables[] =
-{
- { "columns_priv", st_relay_log_info::RELOAD_GRANT_F },
- { "db", st_relay_log_info::RELOAD_ACCESS_F },
- { "host", st_relay_log_info::RELOAD_ACCESS_F },
- { "procs_priv", st_relay_log_info::RELOAD_GRANT_F },
- { "tables_priv", st_relay_log_info::RELOAD_GRANT_F },
- { "user", st_relay_log_info::RELOAD_ACCESS_F }
-};
-
-static const my_size_t s_mysql_tables_size =
- sizeof(s_mysql_tables)/sizeof(*s_mysql_tables);
-
-static int reload_entry_compare(const void *lhs, const void *rhs)
-{
- const char *lstr = static_cast<const char *>(lhs);
- const char *rstr = static_cast<const st_reload_entry*>(rhs)->table;
- DBUG_ENTER("reload_entry_compare");
-
- DBUG_RETURN(strcmp(lstr, rstr));
-}
-
-void st_relay_log_info::touching_table(char const* db, char const* table,
- ulong table_id)
-{
- DBUG_ENTER("st_relay_log_info::touching_table");
-
- if (strcmp(db,"mysql") == 0)
- {
-#if defined(HAVE_BSEARCH) && defined(HAVE_SIZE_T)
- void *const ptr= bsearch(table, s_mysql_tables,
- s_mysql_tables_size,
- sizeof(*s_mysql_tables), reload_entry_compare);
- st_reload_entry const *const entry= static_cast<st_reload_entry*>(ptr);
-#else
- /*
- Fall back to full scan, there are few rows anyway and updating the
- "mysql" database is rare.
- */
- st_reload_entry const *entry= s_mysql_tables;
- for ( ; entry < s_mysql_tables + s_mysql_tables_size ; entry++)
- if (reload_entry_compare(table, entry) == 0)
- break;
-#endif
- if (entry)
- m_reload_flags|= entry->flag;
- }
- DBUG_VOID_RETURN;
-}
-
-void st_relay_log_info::transaction_end(THD* thd)
-{
- DBUG_ENTER("st_relay_log_info::transaction_end");
-
- if (m_reload_flags != RELOAD_NONE_F)
- {
- if (m_reload_flags & RELOAD_ACCESS_F)
- acl_reload(thd);
-
- if (m_reload_flags & RELOAD_GRANT_F)
- grant_reload(thd);
-
- m_reload_flags= RELOAD_NONE_F;
- }
- DBUG_VOID_RETURN;
-}
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-void st_relay_log_info::cleanup_context(THD *thd, bool error)
-{
- DBUG_ENTER("st_relay_log_info::cleanup_context");
-
- DBUG_ASSERT(sql_thd == thd);
- /*
- 1) Instances of Table_map_log_event, if ::exec_event() was called on them,
- may have opened tables, which we cannot be sure have been closed (because
- maybe the Rows_log_event have not been found or will not be, because slave
- SQL thread is stopping, or relay log has a missing tail etc). So we close
- all thread's tables. And so the table mappings have to be cancelled.
- 2) Rows_log_event::exec_event() may even have started statements or
- transactions on them, which we need to rollback in case of error.
- 3) If finding a Format_description_log_event after a BEGIN, we also need
- to rollback before continuing with the next events.
- 4) so we need this "context cleanup" function.
- */
- if (error)
- {
- ha_autocommit_or_rollback(thd, 1); // if a "statement transaction"
- end_trans(thd, ROLLBACK); // if a "real transaction"
- }
- m_table_map.clear_tables();
- close_thread_tables(thd);
- clear_tables_to_lock();
- unsafe_to_stop_at= 0;
- DBUG_VOID_RETURN;
-}
-#endif
-
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
diff --git a/sql/slave.h b/sql/slave.h
index e70b2e4b326..24ba09d78d3 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -24,6 +24,7 @@
#include "rpl_filter.h"
#include "rpl_tblmap.h"
#include "rpl_rli.h"
+#include "rpl_mi.h"
#define SLAVE_NET_TIMEOUT 3600
@@ -38,11 +39,11 @@
I/O Thread - One of these threads is started for each master server.
They maintain a connection to their master server, read log
events from the master as they arrive, and queues them into
- a single, shared relay log file. A MASTER_INFO struct
+ a single, shared relay log file. A MASTER_INFO
represents each of these threads.
SQL Thread - One of these threads is started and reads from the relay log
- file, executing each event. A RELAY_LOG_INFO struct
+ file, executing each event. A RELAY_LOG_INFO
represents this thread.
Buffering in the relay log file makes it unnecessary to reread events from
@@ -95,7 +96,6 @@ extern my_string opt_relay_logname, opt_relaylog_index_name;
extern my_bool opt_skip_slave_start, opt_reckless_slave;
extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
-struct st_master_info;
/*
3 possible values for MASTER_INFO::slave_running and
@@ -114,110 +114,6 @@ struct st_master_info;
static Log_event* next_event(RELAY_LOG_INFO* rli);
-/*****************************************************************************
-
- Replication IO Thread
-
- st_master_info contains:
- - information about how to connect to a master
- - current master log name
- - current master log offset
- - misc control variables
-
- st_master_info is initialized once from the master.info file if such
- exists. Otherwise, data members corresponding to master.info fields
- are initialized with defaults specified by master-* options. The
- initialization is done through init_master_info() call.
-
- The format of master.info file:
-
- log_name
- log_pos
- master_host
- master_user
- master_pass
- master_port
- master_connect_retry
-
- To write out the contents of master.info file to disk ( needed every
- time we read and queue data from the master ), a call to
- flush_master_info() is required.
-
- To clean up, call end_master_info()
-
-*****************************************************************************/
-
-typedef struct st_master_info
-{
- /* the variables below are needed because we can change masters on the fly */
- char master_log_name[FN_REFLEN];
- char host[HOSTNAME_LENGTH+1];
- char user[USERNAME_LENGTH+1];
- char password[MAX_PASSWORD_LENGTH+1];
- my_bool ssl; // enables use of SSL connection if true
- char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
- char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
-
- my_off_t master_log_pos;
- File fd; // we keep the file open, so we need to remember the file pointer
- IO_CACHE file;
-
- pthread_mutex_t data_lock,run_lock;
- pthread_cond_t data_cond,start_cond,stop_cond;
- THD *io_thd;
- MYSQL* mysql;
- uint32 file_id; /* for 3.23 load data infile */
- RELAY_LOG_INFO rli;
- uint port;
- uint connect_retry;
-#ifndef DBUG_OFF
- int events_till_disconnect;
-#endif
- bool inited;
- volatile bool abort_slave;
- volatile uint slave_running;
- volatile ulong slave_run_id;
- /*
- The difference in seconds between the clock of the master and the clock of
- the slave (second - first). It must be signed as it may be <0 or >0.
- clock_diff_with_master is computed when the I/O thread starts; for this the
- I/O thread does a SELECT UNIX_TIMESTAMP() on the master.
- "how late the slave is compared to the master" is computed like this:
- clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
-
- */
- long clock_diff_with_master;
-
- st_master_info()
- :ssl(0), fd(-1), io_thd(0), inited(0),
- abort_slave(0),slave_running(0), slave_run_id(0)
- {
- host[0] = 0; user[0] = 0; password[0] = 0;
- ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
- ssl_cipher[0]= 0; ssl_key[0]= 0;
-
- bzero((char*) &file, sizeof(file));
- pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&data_cond, NULL);
- pthread_cond_init(&start_cond, NULL);
- pthread_cond_init(&stop_cond, NULL);
- }
-
- ~st_master_info()
- {
- pthread_mutex_destroy(&run_lock);
- pthread_mutex_destroy(&data_lock);
- pthread_cond_destroy(&data_cond);
- pthread_cond_destroy(&start_cond);
- pthread_cond_destroy(&stop_cond);
- }
-
-} MASTER_INFO;
-
-
-int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
-
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
@@ -231,7 +127,6 @@ int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
int init_slave();
void init_slave_skip_errors(const char* arg);
-int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache);
bool flush_relay_log_info(RELAY_LOG_INFO* rli);
int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
@@ -276,14 +171,8 @@ void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli,
ATTRIBUTE_FORMAT(printf, 4, 5);
void end_slave(); /* clean up */
-void init_master_info_with_options(MASTER_INFO* mi);
void clear_until_condition(RELAY_LOG_INFO* rli);
void clear_slave_error(RELAY_LOG_INFO* rli);
-int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
- const char* slave_info_fname,
- bool abort_if_no_master_info_file,
- int thread_mask);
-void end_master_info(MASTER_INFO* mi);
void end_relay_log_info(RELAY_LOG_INFO* rli);
void lock_slave_threads(MASTER_INFO* mi);
void unlock_slave_threads(MASTER_INFO* mi);
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 23ca5330053..732981b58f3 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -79,9 +79,15 @@ void mysql_client_binlog_statement(THD* thd)
char const *endptr= 0;
int bytes_decoded= base64_decode(strptr, coded_len, buf, &endptr);
+#ifndef HAVE_purify
+ /*
+ This debug printout should not be used for valgrind builds
+ since it will read from unassigned memory.
+ */
DBUG_PRINT("info",
("bytes_decoded=%d; strptr=0x%lu; endptr=0x%lu ('%c':%d)",
bytes_decoded, strptr, endptr, *endptr, *endptr));
+#endif
if (bytes_decoded < 0)
{
@@ -147,8 +153,14 @@ void mysql_client_binlog_statement(THD* thd)
DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code()));
DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET=0x%lx",
bufptr+EVENT_TYPE_OFFSET));
+#ifndef HAVE_purify
+ /*
+ This debug printout should not be used for valgrind builds
+ since it will read from unassigned memory.
+ */
DBUG_PRINT("info", ("bytes_decoded=%d; bufptr=0x%lx; buf[EVENT_LEN_OFFSET]=%u",
bytes_decoded, bufptr, uint4korr(bufptr+EVENT_LEN_OFFSET)));
+#endif
ev->thd= thd;
if (int err= ev->exec_event(thd->rli_fake))
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 776ba4dabea..20acb28bc77 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2552,6 +2552,128 @@ my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data,
}
+namespace {
+ /**
+ Class to handle temporary allocation of memory for row data.
+
+ The responsibilities of the class is to provide memory for
+ packing one or two rows of packed data (depending on what
+ constructor is called).
+
+ In order to make the allocation more efficient for "simple" rows,
+ i.e., rows that do not contain any blobs, a pointer to the
+ allocated memory is of memory is stored in the table structure
+ for simple rows. If memory for a table containing a blob field
+ is requested, only memory for that is allocated, and subsequently
+ released when the object is destroyed.
+
+ */
+ class Row_data_memory {
+ public:
+ /**
+ Build an object to keep track of a block-local piece of memory
+ for storing a row of data.
+
+ @param table
+ Table where the pre-allocated memory is stored.
+
+ @param length
+ Length of data that is needed, if the record contain blobs.
+ */
+ Row_data_memory(TABLE *table, my_size_t const len1)
+ : m_memory(0)
+ {
+#ifndef DBUG_OFF
+ m_alloc_checked= false;
+#endif
+ allocate_memory(table, len1);
+ m_ptr[0]= has_memory() ? m_memory : 0;
+ m_ptr[1]= 0;
+ }
+
+ Row_data_memory(TABLE *table, my_size_t const len1, my_size_t const len2)
+ : m_memory(0)
+ {
+#ifndef DBUG_OFF
+ m_alloc_checked= false;
+#endif
+ allocate_memory(table, len1 + len2);
+ m_ptr[0]= has_memory() ? m_memory : 0;
+ m_ptr[1]= has_memory() ? m_memory + len1 : 0;
+ }
+
+ ~Row_data_memory()
+ {
+ if (m_memory != 0 && m_release_memory_on_destruction)
+ my_free((gptr) m_memory, MYF(MY_WME));
+ }
+
+ /**
+ Is there memory allocated?
+
+ @retval true There is memory allocated
+ @retval false Memory allocation failed
+ */
+ bool has_memory() const {
+#ifndef DBUG_OFF
+ m_alloc_checked= true;
+#endif
+ return m_memory != 0;
+ }
+
+ byte *slot(int const s)
+ {
+ DBUG_ASSERT(0 <= s && s < sizeof(m_ptr)/sizeof(*m_ptr));
+ DBUG_ASSERT(m_ptr[s] != 0);
+ DBUG_ASSERT(m_alloc_checked == true);
+ return m_ptr[s];
+ }
+
+ private:
+ void allocate_memory(TABLE *const table, my_size_t const total_length)
+ {
+ if (table->s->blob_fields == 0)
+ {
+ /*
+ The maximum length of a packed record is less than this
+ length. We use this value instead of the supplied length
+ when allocating memory for records, since we don't know how
+ the memory will be used in future allocations.
+
+ Since table->s->reclength is for unpacked records, we have
+ to add two bytes for each field, which can potentially be
+ added to hold the length of a packed field.
+ */
+ my_size_t const maxlen= table->s->reclength + 2 * table->s->fields;
+
+ /*
+ Allocate memory for two records if memory hasn't been
+ allocated. We allocate memory for two records so that it can
+ be used when processing update rows as well.
+ */
+ if (table->write_row_record == 0)
+ table->write_row_record=
+ (byte *) alloc_root(&table->mem_root, 2 * maxlen);
+ m_memory= table->write_row_record;
+ m_release_memory_on_destruction= false;
+ }
+ else
+ {
+ m_memory= (byte *) my_malloc(total_length, MYF(MY_WME));
+ m_release_memory_on_destruction= true;
+ }
+ }
+
+#ifndef DBUG_OFF
+ mutable bool m_alloc_checked;
+#endif
+ bool m_release_memory_on_destruction;
+ byte *m_memory;
+ byte *m_ptr[2];
+ };
+}
+
+
int THD::binlog_write_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, my_size_t colcnt,
byte const *record)
@@ -2562,40 +2684,25 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- bool error= 0;
- byte *row_data= table->write_row_record;
- my_size_t const max_len= max_row_length(table, record);
- my_size_t len;
- Rows_log_event *ev;
-
- /* Allocate room for a row (if needed) */
- if (!row_data)
- {
- if (!table->s->blob_fields)
- {
- /* multiply max_len by 2 so it can be used for update_row as well */
- table->write_row_record= (byte *) alloc_root(&table->mem_root,
- 2*max_len);
- if (!table->write_row_record)
- return HA_ERR_OUT_OF_MEM;
- row_data= table->write_row_record;
- }
- else if (unlikely(!(row_data= (byte *) my_malloc(max_len, MYF(MY_WME)))))
- return HA_ERR_OUT_OF_MEM;
- }
- len= pack_row(table, cols, row_data, record);
+ int error= 0;
- ev= binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
- len, is_trans,
- static_cast<Write_rows_log_event*>(0));
+ Row_data_memory memory(table, max_row_length(table, record));
+ if (!memory.has_memory())
+ return HA_ERR_OUT_OF_MEM;
- /* add_row_data copies row_data to internal buffer */
- error= likely(ev != 0) ? ev->add_row_data(row_data,len) : HA_ERR_OUT_OF_MEM ;
+ byte *row_data= memory.slot(0);
- if (table->write_row_record == 0)
- my_free((gptr) row_data, MYF(MY_WME));
+ my_size_t const len= pack_row(table, cols, row_data, record);
- return error;
+ Rows_log_event* const ev=
+ binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
+ len, is_trans,
+ static_cast<Write_rows_log_event*>(0));
+
+ if (unlikely(ev == 0))
+ return HA_ERR_OUT_OF_MEM;
+
+ return ev->add_row_data(row_data, len);
}
int THD::binlog_update_row(TABLE* table, bool is_trans,
@@ -2605,53 +2712,44 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
- bool error= 0;
+ int error= 0;
my_size_t const before_maxlen = max_row_length(table, before_record);
my_size_t const after_maxlen = max_row_length(table, after_record);
- byte *row_data= table->write_row_record;
- byte *before_row, *after_row;
- if (row_data != 0)
- {
- before_row= row_data;
- after_row= before_row + before_maxlen;
- }
- else
- {
- if (unlikely(!(row_data= (byte*)my_multi_malloc(MYF(MY_WME),
- &before_row, before_maxlen,
- &after_row, after_maxlen,
- NULL))))
- return HA_ERR_OUT_OF_MEM;
- }
+ Row_data_memory row_data(table, before_maxlen, after_maxlen);
+ if (!row_data.has_memory())
+ return HA_ERR_OUT_OF_MEM;
+
+ byte *before_row= row_data.slot(0);
+ byte *after_row= row_data.slot(1);
my_size_t const before_size= pack_row(table, cols, before_row,
before_record);
my_size_t const after_size= pack_row(table, cols, after_row,
after_record);
-
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_purify
DBUG_DUMP("before_record", (const char *)before_record, table->s->reclength);
DBUG_DUMP("after_record", (const char *)after_record, table->s->reclength);
DBUG_DUMP("before_row", (const char *)before_row, before_size);
DBUG_DUMP("after_row", (const char *)after_row, after_size);
+#endif
Rows_log_event* const ev=
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
before_size + after_size, is_trans,
static_cast<Update_rows_log_event*>(0));
- error=
- unlikely(!ev) ||
+ if (unlikely(ev == 0))
+ return HA_ERR_OUT_OF_MEM;
+
+ return
ev->add_row_data(before_row, before_size) ||
ev->add_row_data(after_row, after_size);
-
- if (!table->write_row_record)
- {
- /* add_row_data copies row_data to internal buffer */
- my_free((gptr)row_data, MYF(MY_WME));
- }
-
- return error;
}
int THD::binlog_delete_row(TABLE* table, bool is_trans,
@@ -2664,11 +2762,14 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- bool error= 0;
- my_size_t const max_len= max_row_length(table, record);
- byte *row_data= table->write_row_record;
- if (!row_data && unlikely(!(row_data= (byte*)my_malloc(max_len, MYF(MY_WME)))))
+ int error= 0;
+
+ Row_data_memory memory(table, max_row_length(table, record));
+ if (unlikely(!memory.has_memory()))
return HA_ERR_OUT_OF_MEM;
+
+ byte *row_data= memory.slot(0);
+
my_size_t const len= pack_row(table, cols, row_data, record);
Rows_log_event* const ev=
@@ -2676,13 +2777,10 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
len, is_trans,
static_cast<Delete_rows_log_event*>(0));
- error= (unlikely(!ev)) || ev->add_row_data(row_data, len);
-
- /* add_row_data copies row_data */
- if (table->write_row_record == 0)
- my_free((gptr)row_data, MYF(MY_WME));
+ if (unlikely(ev == 0))
+ return HA_ERR_OUT_OF_MEM;
- return error;
+ return ev->add_row_data(row_data, len);
}
@@ -2776,6 +2874,12 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
#endif /*HAVE_ROW_BASED_REPLICATION*/
switch (qtype) {
+ case THD::ROW_QUERY_TYPE:
+#ifdef HAVE_ROW_BASED_REPLICATION
+ if (current_stmt_binlog_row_based)
+ DBUG_RETURN(0);
+#endif
+ /* Otherwise, we fall through */
case THD::MYSQL_QUERY_TYPE:
/*
Using this query type is a conveniece hack, since we have been
@@ -2785,12 +2889,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
Make sure to change in check_table_binlog_row_based() according
to how you treat this.
*/
- case THD::ROW_QUERY_TYPE:
-#ifdef HAVE_ROW_BASED_REPLICATION
- if (current_stmt_binlog_row_based)
- DBUG_RETURN(0);
-#endif
- /* Otherwise, we fall through */
case THD::STMT_QUERY_TYPE:
/*
The MYSQL_LOG::write() function will set the STMT_END_F flag and
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2a45520af81..5b61a5fb48a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2550,7 +2550,23 @@ mysql_execute_command(THD *thd)
{
/* we warn the slave SQL thread */
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- reset_one_shot_variables(thd);
+ if (thd->one_shot_set)
+ {
+ /*
+ It's ok to check thd->one_shot_set here:
+
+ The charsets in a MySQL 5.0 slave can change by both a binlogged
+ SET ONE_SHOT statement and the event-internal charset setting,
+ and these two ways to change charsets do not seems to work
+ together.
+
+ At least there seems to be problems in the rli cache for
+ charsets if we are using ONE_SHOT. Note that this is normally no
+ problem because either the >= 5.0 slave reads a 4.1 binlog (with
+ ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
+ */
+ reset_one_shot_variables(thd);
+ }
DBUG_RETURN(0);
}
}
@@ -6317,7 +6333,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->alias= alias_str;
if (lower_case_table_names && table->table.length)
- my_casedn_str(files_charset_info, table->table.str);
+ table->table.length= my_casedn_str(files_charset_info, table->table.str);
ptr->table_name=table->table.str;
ptr->table_name_length=table->table.length;
ptr->lock_type= lock_type;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 52489087b02..7ffbb649cb8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -431,6 +431,12 @@ impossible position";
goto err;
}
packet->set("\0", 1, &my_charset_bin);
+ /*
+ Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become
+ this larger than the corresponding packet (query) sent
+ from client to master.
+ */
+ thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER;
/*
We can set log_lock now, it does not move (it's a member of
@@ -805,7 +811,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
sizeof(mi->rli.until_log_name)-1);
}
else
- clear_until_condition(&mi->rli);
+ mi->rli.clear_until_condition();
if (mi->rli.until_condition != RELAY_LOG_INFO::UNTIL_NONE)
{
@@ -978,8 +984,8 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
Reset errors (the idea is that we forget about the
old master).
*/
- clear_slave_error(&mi->rli);
- clear_until_condition(&mi->rli);
+ mi->rli.clear_slave_error();
+ mi->rli.clear_until_condition();
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
@@ -1244,8 +1250,8 @@ bool change_master(THD* thd, MASTER_INFO* mi)
pthread_mutex_lock(&mi->rli.data_lock);
mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
/* Clear the errors, for a clean start */
- clear_slave_error(&mi->rli);
- clear_until_condition(&mi->rli);
+ mi->rli.clear_slave_error();
+ mi->rli.clear_until_condition();
/*
If we don't write new coordinates to disk now, then old will remain in
relay-log.info until START SLAVE is issued; but if mysqld is shutdown
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index d40d9f16bb5..6758f9d68d0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8723,6 +8723,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
item->collation.collation);
else
new_field= item->make_string_field(table);
+ new_field->set_derivation(item->collation.derivation);
break;
case DECIMAL_RESULT:
new_field= new Field_new_decimal(item->max_length, maybe_null, item->name,
@@ -8908,7 +8909,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
(make_copy_field ? 0 : copy_func),
modify_item, convert_blob_length);
case Item::TYPE_HOLDER:
- return ((Item_type_holder *)item)->make_field_by_type(table);
+ result= ((Item_type_holder *)item)->make_field_by_type(table);
+ result->set_derivation(item->collation.derivation);
+ return result;
default: // Dosen't have to be stored
return 0;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index f6e39fb7913..dc8946df876 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1058,6 +1058,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));
else
packet->append(STRING_WITH_LEN("CREATE TABLE "));
+ if (create_info_arg &&
+ (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))
+ packet->append(STRING_WITH_LEN("IF NOT EXISTS "));
if (table_list->schema_table)
alias= table_list->schema_table->table_name;
else
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 6e4d3f2ed0a..29b53560067 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -844,6 +844,162 @@ outp:
}
+/*
+ copy a string,
+ with optional character set conversion,
+ with optional left padding (for binary -> UCS2 conversion)
+
+ SYNOPSIS
+ well_formed_copy_nhars()
+ to Store result here
+ to_length Maxinum length of "to" string
+ to_cs Character set of "to" string
+ from Copy from here
+ from_length Length of from string
+ from_cs From character set
+ nchars Copy not more that nchars characters
+ well_formed_error_pos Return position when "from" is not well formed
+ or NULL otherwise.
+ cannot_convert_error_pos Return position where a not convertable
+ character met, or NULL otherwise.
+ from_end_pos Return position where scanning of "from"
+ string stopped.
+ NOTES
+
+ RETURN
+ length of bytes copied to 'to'
+*/
+
+
+uint32
+well_formed_copy_nchars(CHARSET_INFO *to_cs,
+ char *to, uint to_length,
+ CHARSET_INFO *from_cs,
+ const char *from, uint from_length,
+ uint nchars,
+ const char **well_formed_error_pos,
+ const char **cannot_convert_error_pos,
+ const char **from_end_pos)
+{
+ uint res;
+
+ if ((to_cs == &my_charset_bin) ||
+ (from_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs))
+ {
+ if (to_length < to_cs->mbminlen || !nchars)
+ {
+ *from_end_pos= from;
+ *cannot_convert_error_pos= NULL;
+ *well_formed_error_pos= NULL;
+ return 0;
+ }
+
+ if (to_cs == &my_charset_bin)
+ {
+ res= min(min(nchars, to_length), from_length);
+ memmove(to, from, res);
+ *from_end_pos= from + res;
+ *well_formed_error_pos= NULL;
+ *cannot_convert_error_pos= NULL;
+ }
+ else
+ {
+ int well_formed_error;
+ uint from_offset;
+
+ if ((from_offset= (from_length % to_cs->mbminlen)) &&
+ (from_cs == &my_charset_bin))
+ {
+ /*
+ Copying from BINARY to UCS2 needs to prepend zeros sometimes:
+ INSERT INTO t1 (ucs2_column) VALUES (0x01);
+ 0x01 -> 0x0001
+ */
+ uint pad_length= to_cs->mbminlen - from_offset;
+ bzero(to, pad_length);
+ memmove(to + pad_length, from, from_offset);
+ nchars--;
+ from+= from_offset;
+ from_length-= from_offset;
+ to+= to_cs->mbminlen;
+ to_length-= to_cs->mbminlen;
+ }
+
+ set_if_smaller(from_length, to_length);
+ res= to_cs->cset->well_formed_len(to_cs, from, from + from_length,
+ nchars, &well_formed_error);
+ memmove(to, from, res);
+ *from_end_pos= from + res;
+ *well_formed_error_pos= well_formed_error ? from + res : NULL;
+ *cannot_convert_error_pos= NULL;
+ if (from_offset)
+ res+= to_cs->mbminlen;
+ }
+ }
+ else
+ {
+ int cnvres;
+ my_wc_t wc;
+ int (*mb_wc)(struct charset_info_st *, my_wc_t *,
+ const uchar *, const uchar *)= from_cs->cset->mb_wc;
+ int (*wc_mb)(struct charset_info_st *, my_wc_t,
+ uchar *s, uchar *e)= to_cs->cset->wc_mb;
+ const uchar *from_end= (const uchar*) from + from_length;
+ uchar *to_end= (uchar*) to + to_length;
+ char *to_start= to;
+ *well_formed_error_pos= NULL;
+ *cannot_convert_error_pos= NULL;
+
+ for ( ; nchars; nchars--)
+ {
+ const char *from_prev= from;
+ if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from, from_end)) > 0)
+ from+= cnvres;
+ else if (cnvres == MY_CS_ILSEQ)
+ {
+ if (!*well_formed_error_pos)
+ *well_formed_error_pos= from;
+ from++;
+ wc= '?';
+ }
+ else if (cnvres > MY_CS_TOOSMALL)
+ {
+ /*
+ A correct multibyte sequence detected
+ But it doesn't have Unicode mapping.
+ */
+ if (!*cannot_convert_error_pos)
+ *cannot_convert_error_pos= from;
+ from+= (-cnvres);
+ wc= '?';
+ }
+ else
+ break; // Not enough characters
+
+outp:
+ if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI && wc != '?')
+ {
+ if (!*cannot_convert_error_pos)
+ *cannot_convert_error_pos= from_prev;
+ wc= '?';
+ goto outp;
+ }
+ else
+ break;
+ }
+ *from_end_pos= from;
+ res= to - to_start;
+ }
+ return (uint32) res;
+}
+
+
+
+
void String::print(String *str)
{
char *st= (char*)Ptr, *end= st+str_length;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index b1d417be2c2..a72b24ae9d0 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -30,6 +30,14 @@ String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
CHARSET_INFO *from_cs, uint *errors);
+uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs,
+ char *to, uint to_length,
+ CHARSET_INFO *from_cs,
+ const char *from, uint from_length,
+ uint nchars,
+ const char **well_formed_error_pos,
+ const char **cannot_convert_error_pos,
+ const char **from_end_pos);
class String
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 5bf67af9271..98226c1651b 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1695,24 +1695,23 @@ mysql_rename_view(THD *thd,
const char *new_name,
TABLE_LIST *view)
{
- LEX_STRING pathstr, file;
+ LEX_STRING pathstr;
File_parser *parser;
- char view_path[FN_REFLEN];
+ char path_buff[FN_REFLEN];
bool error= TRUE;
DBUG_ENTER("mysql_rename_view");
- strxnmov(view_path, FN_REFLEN-1, mysql_data_home, "/", view->db, "/",
- view->table_name, reg_ext, NullS);
- (void) unpack_filename(view_path, view_path);
-
- pathstr.str= (char *)view_path;
- pathstr.length= strlen(view_path);
+ pathstr.str= (char *) path_buff;
+ pathstr.length= build_table_filename(path_buff, sizeof(path_buff) - 1,
+ view->db, view->table_name,
+ reg_ext, 0);
if ((parser= sql_parse_prepare(&pathstr, thd->mem_root, 1)) &&
is_equal(&view_type, parser->type()))
{
TABLE_LIST view_def;
- char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ char dir_buff[FN_REFLEN];
+ LEX_STRING dir, file;
/*
To be PS-friendly we should either to restore state of
@@ -1735,18 +1734,18 @@ mysql_rename_view(THD *thd,
view_def.revision - 1, num_view_backups))
goto err;
- strxnmov(dir_buff, FN_REFLEN-1, mysql_data_home, "/", view->db, "/",
- NullS);
- (void) unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1,
+ view->db, "", "", 0);
- pathstr.str= (char*)dir_buff;
- pathstr.length= strlen(dir_buff);
+ pathstr.str= path_buff;
+ pathstr.length= build_table_filename(path_buff, sizeof(path_buff) - 1,
+ view->db, new_name, reg_ext, 0);
- file.str= file_buff;
- file.length= (strxnmov(file_buff, FN_REFLEN, new_name, reg_ext, NullS)
- - file_buff);
+ file.str= pathstr.str + dir.length;
+ file.length= pathstr.length - dir.length;
- if (sql_create_definition_file(&pathstr, &file, view_file_type,
+ if (sql_create_definition_file(&dir, &file, view_file_type,
(gptr)&view_def, view_parameters,
num_view_backups))
{
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index 51c9f4c192e..53c2ba5a0ee 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -1534,7 +1534,7 @@ int ha_federated::close(void)
0 otherwise
*/
-inline uint field_in_record_is_null(TABLE *table,
+static inline uint field_in_record_is_null(TABLE *table,
Field *field,
char *record)
{
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index ec86b9a2e68..83266a22255 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -2510,7 +2510,7 @@ get_field_offset(
/******************************************************************
Checks if a field in a record is SQL NULL. Uses the record format
information in table to track the null bit in record. */
-inline
+static inline
uint
field_in_record_is_null(
/*====================*/
diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c
index 01bd0c43119..c6f9799bd67 100644
--- a/storage/myisam/mi_key.c
+++ b/storage/myisam/mi_key.c
@@ -52,7 +52,7 @@ static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
const byte *record, my_off_t filepos)
{
- byte *pos,*end;
+ byte *pos;
uchar *start;
reg1 HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
@@ -107,18 +107,17 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
}
if (keyseg->flag & HA_SPACE_PACK)
{
- end= pos + length;
if (type != HA_KEYTYPE_NUM)
{
- while (end > pos && end[-1] == ' ')
- end--;
+ length= cs->cset->lengthsp(cs, pos, length);
}
else
{
+ byte *end= pos + length;
while (pos < end && pos[0] == ' ')
pos++;
+ length=(uint) (end-pos);
}
- length=(uint) (end-pos);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
@@ -403,8 +402,10 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
pos= record+keyseg->start;
if (keyseg->type != (int) HA_KEYTYPE_NUM)
{
- memcpy(pos,key,(size_t) length);
- bfill(pos+length,keyseg->length-length,' ');
+ memcpy(pos,key,(size_t) length);
+ keyseg->charset->cset->fill(keyseg->charset,
+ pos + length, keyseg->length - length,
+ ' ');
}
else
{
diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index 7d1f18d3906..010f7233c32 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/myisam/mi_open.c
@@ -348,6 +348,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
goto err;
}
}
+ else if (pos->type == HA_KEYTYPE_BINARY)
+ pos->charset= &my_charset_bin;
}
if (share->keyinfo[i].flag & HA_SPATIAL)
{
diff --git a/storage/ndb/src/ndbapi/Ndbinit.cpp b/storage/ndb/src/ndbapi/Ndbinit.cpp
index 5c0fb521c36..3d7d1b768f2 100644
--- a/storage/ndb/src/ndbapi/Ndbinit.cpp
+++ b/storage/ndb/src/ndbapi/Ndbinit.cpp
@@ -146,12 +146,13 @@ Ndb::~Ndb()
}
doDisconnect();
- delete theEventBuffer;
-
+ /* Disconnect from transporter to stop signals from coming in */
if (theImpl->m_transporter_facade != NULL && theNdbBlockNumber > 0){
theImpl->m_transporter_facade->close(theNdbBlockNumber, theFirstTransId);
}
-
+
+ delete theEventBuffer;
+
releaseTransactionArrays();
delete []theConnectionArray;
diff --git a/storage/ndb/src/ndbapi/TransporterFacade.cpp b/storage/ndb/src/ndbapi/TransporterFacade.cpp
index 8d0693f17a7..95f614e6699 100644
--- a/storage/ndb/src/ndbapi/TransporterFacade.cpp
+++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp
@@ -762,7 +762,7 @@ TransporterFacade::init(Uint32 nodeId, const ndb_mgm_configuration* props)
void
TransporterFacade::for_each(NdbApiSignal* aSignal, LinearSectionPtr ptr[3])
{
- DBUG_ENTER("TransporterFacade::connected");
+ DBUG_ENTER("TransporterFacade::for_each");
Uint32 sz = m_threads.m_statusNext.size();
TransporterFacade::ThreadData::Object_Execute oe;
for (Uint32 i = 0; i < sz ; i ++)
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 5758960ef6c..289b76c9e6e 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -211,9 +211,10 @@ static int my_strnncollsp_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
/* This function is used for all conversion functions */
-static void my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
+static uint my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
char *str __attribute__((unused)))
{
+ return 0;
}
static uint my_case_bin(CHARSET_INFO *cs __attribute__((unused)),
diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c
index c945164ac9c..c3848c64219 100644
--- a/strings/ctype-mb.c
+++ b/strings/ctype-mb.c
@@ -21,40 +21,44 @@
#ifdef USE_MB
-void my_caseup_str_mb(CHARSET_INFO * cs, char *str)
+uint my_caseup_str_mb(CHARSET_INFO * cs, char *str)
{
register uint32 l;
- register uchar *map=cs->to_upper;
+ register uchar *map= cs->to_upper;
+ char *str_orig= str;
while (*str)
{
/* Pointing after the '\0' is safe here. */
- if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
- str+=l;
+ if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+ str+= l;
else
{
- *str=(char) map[(uchar)*str];
+ *str= (char) map[(uchar)*str];
str++;
}
}
+ return str - str_orig;
}
-void my_casedn_str_mb(CHARSET_INFO * cs, char *str)
+uint my_casedn_str_mb(CHARSET_INFO * cs, char *str)
{
register uint32 l;
- register uchar *map=cs->to_lower;
+ register uchar *map= cs->to_lower;
+ char *str_orig= str;
while (*str)
{
/* Pointing after the '\0' is safe here. */
- if ((l=my_ismbchar(cs, str, str + cs->mbmaxlen)))
- str+=l;
+ if ((l= my_ismbchar(cs, str, str + cs->mbmaxlen)))
+ str+= l;
else
{
- *str=(char) map[(uchar)*str];
+ *str= (char) map[(uchar)*str];
str++;
}
}
+ return str - str_orig;
}
uint my_caseup_mb(CHARSET_INFO * cs, char *src, uint srclen,
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 9b45d5a03b7..9d10ba82114 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -188,20 +188,26 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, uint a_length,
}
-void my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
+uint my_caseup_str_8bit(CHARSET_INFO * cs,char *str)
{
- register uchar *map=cs->to_upper;
- while ((*str = (char) map[(uchar) *str]) != 0)
+ register uchar *map= cs->to_upper;
+ char *str_orig= str;
+ while ((*str= (char) map[(uchar) *str]) != 0)
str++;
+ return str - str_orig;
}
-void my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
+
+uint my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
{
- register uchar *map=cs->to_lower;
- while ((*str = (char) map[(uchar)*str]) != 0)
+ register uchar *map= cs->to_lower;
+ char *str_orig= str;
+ while ((*str= (char) map[(uchar) *str]) != 0)
str++;
+ return str - str_orig;
}
+
uint my_caseup_8bit(CHARSET_INFO * cs, char *src, uint srclen,
char *dst __attribute__((unused)),
uint dstlen __attribute__((unused)))
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index df43eff3d73..5089db6bf48 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -159,13 +159,13 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, uint slen,
}
-static void my_caseup_str_ucs2(CHARSET_INFO * cs __attribute__((unused)),
+static uint my_caseup_str_ucs2(CHARSET_INFO * cs __attribute__((unused)),
char * s __attribute__((unused)))
{
+ return 0;
}
-
static uint my_casedn_ucs2(CHARSET_INFO *cs, char *src, uint srclen,
char *dst __attribute__((unused)),
uint dstlen __attribute__((unused)))
@@ -188,9 +188,11 @@ static uint my_casedn_ucs2(CHARSET_INFO *cs, char *src, uint srclen,
return srclen;
}
-static void my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)),
+
+static uint my_casedn_str_ucs2(CHARSET_INFO *cs __attribute__((unused)),
char * s __attribute__((unused)))
{
+ return 0;
}
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 6c3ceaf868b..8a4ed48bef5 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -2047,6 +2047,52 @@ static int my_utf8_uni(CHARSET_INFO *cs __attribute__((unused)),
return MY_CS_ILSEQ;
}
+
+/*
+ The same as above, but without range check
+ for example, for a null-terminated string
+*/
+static int my_utf8_uni_no_range(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t * pwc, const uchar *s)
+{
+ unsigned char c;
+
+ c= s[0];
+ if (c < 0x80)
+ {
+ *pwc = c;
+ return 1;
+ }
+
+ if (c < 0xc2)
+ return MY_CS_ILSEQ;
+
+ if (c < 0xe0)
+ {
+ if (!((s[1] ^ 0x80) < 0x40))
+ return MY_CS_ILSEQ;
+
+ *pwc = ((my_wc_t) (c & 0x1f) << 6) | (my_wc_t) (s[1] ^ 0x80);
+ return 2;
+ }
+
+ if (c < 0xf0)
+ {
+ if (!((s[1] ^ 0x80) < 0x40 &&
+ (s[2] ^ 0x80) < 0x40 &&
+ (c >= 0xe1 || s[1] >= 0xa0)))
+ return MY_CS_ILSEQ;
+
+ *pwc= ((my_wc_t) (c & 0x0f) << 12) |
+ ((my_wc_t) (s[1] ^ 0x80) << 6) |
+ (my_wc_t) (s[2] ^ 0x80);
+
+ return 3;
+ }
+ return MY_CS_ILSEQ;
+}
+
+
static int my_uni_utf8 (CHARSET_INFO *cs __attribute__((unused)) ,
my_wc_t wc, uchar *r, uchar *e)
{
@@ -2093,6 +2139,34 @@ static int my_uni_utf8 (CHARSET_INFO *cs __attribute__((unused)) ,
}
+/*
+ The same as above, but without range check.
+*/
+static int my_uni_utf8_no_range(CHARSET_INFO *cs __attribute__((unused)),
+ my_wc_t wc, uchar *r)
+{
+ int count;
+
+ if (wc < 0x80)
+ count= 1;
+ else if (wc < 0x800)
+ count= 2;
+ else if (wc < 0x10000)
+ count= 3;
+ else
+ return MY_CS_ILUNI;
+
+ switch (count)
+ {
+ /* Fall through all cases!!! */
+ case 3: r[2]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0x800;
+ case 2: r[1]= (uchar) (0x80 | (wc & 0x3f)); wc= wc >> 6; wc |= 0xc0;
+ case 1: r[0]= (uchar) wc;
+ }
+ return count;
+}
+
+
static uint my_caseup_utf8(CHARSET_INFO *cs, char *src, uint srclen,
char *dst, uint dstlen)
{
@@ -2143,10 +2217,26 @@ static void my_hash_sort_utf8(CHARSET_INFO *cs, const uchar *s, uint slen,
}
-static void my_caseup_str_utf8(CHARSET_INFO * cs, char * s)
+static uint my_caseup_str_utf8(CHARSET_INFO *cs, char *src)
{
- uint len= (uint) strlen(s);
- my_caseup_utf8(cs, s, len, s, len);
+ my_wc_t wc;
+ int srcres, dstres;
+ char *dst= src, *dst0= src;
+ MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+ DBUG_ASSERT(cs->caseup_multiply == 1);
+
+ while (*src &&
+ (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+ {
+ int plane= (wc>>8) & 0xFF;
+ wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].toupper : wc;
+ if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+ break;
+ src+= srcres;
+ dst+= dstres;
+ }
+ *dst= '\0';
+ return (uint) (dst - dst0);
}
@@ -2172,10 +2262,43 @@ static uint my_casedn_utf8(CHARSET_INFO *cs, char *src, uint srclen,
return (uint) (dst - dst0);
}
-static void my_casedn_str_utf8(CHARSET_INFO *cs, char * s)
+
+static uint my_casedn_str_utf8(CHARSET_INFO *cs, char *src)
{
- uint len= (uint) strlen(s);
- my_casedn_utf8(cs, s, len, s, len);
+ my_wc_t wc;
+ int srcres, dstres;
+ char *dst= src, *dst0= src;
+ MY_UNICASE_INFO **uni_plane= cs->caseinfo;
+ DBUG_ASSERT(cs->casedn_multiply == 1);
+
+ while (*src &&
+ (srcres= my_utf8_uni_no_range(cs, &wc, (uchar *) src)) > 0)
+ {
+ int plane= (wc>>8) & 0xFF;
+ wc= uni_plane[plane] ? uni_plane[plane][wc & 0xFF].tolower : wc;
+ if ((dstres= my_uni_utf8_no_range(cs, wc, (uchar*) dst)) <= 0)
+ break;
+ src+= srcres;
+ dst+= dstres;
+ }
+
+ /*
+ In rare cases lower string can be shorter than
+ the original string, for example:
+
+ "U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE"
+ (which is 0xC4B0 in utf8, i.e. two bytes)
+
+ is converted into
+
+ "U+0069 LATIN SMALL LETTER I"
+ (which is 0x69 in utf8, i.e. one byte)
+
+ So, we need to put '\0' terminator after converting.
+ */
+
+ *dst= '\0';
+ return (uint) (dst - dst0);
}
@@ -4051,6 +4174,7 @@ static MY_CHARSET_HANDLER my_charset_filename_handler=
my_strntoull_8bit,
my_strntod_8bit,
my_strtoll10_8bit,
+ my_strntoull10rnd_8bit,
my_scan_8bit
};
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 60548210b7d..d808ade8342 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -318,6 +318,7 @@ BuildMySQL "--enable-shared \
--with-example-storage-engine \
--with-blackhole-storage-engine \
--with-federated-storage-engine \
+ --with-partition \
--with-big-tables \
--with-comment=\"MySQL Community Server - Debug (GPL)\"")
@@ -328,7 +329,7 @@ then
fi
(cd mysql-debug-%{mysql_version}/mysql-test ; \
- ./mysql-test-run.pl --comment=debug --skip-rpl --skip-ndbcluster --force ; \
+ ./mysql-test-run.pl --comment=debug --skip-rpl --skip-ndbcluster --force --report-features ; \
true)
##############################################################################
@@ -348,6 +349,7 @@ BuildMySQL "--enable-shared \
--with-example-storage-engine \
--with-blackhole-storage-engine \
--with-federated-storage-engine \
+ --with-partition \
--with-embedded-server \
--with-big-tables \
--with-comment=\"MySQL Community Server (GPL)\"")
@@ -358,7 +360,7 @@ then
fi
cd mysql-release-%{mysql_version}/mysql-test
-./mysql-test-run.pl --comment=normal --force --skip-ndbcluster --timer || true
+./mysql-test-run.pl --comment=normal --force --skip-ndbcluster --timer --report-features || true
./mysql-test-run.pl --comment=ps --ps-protocol --force --skip-ndbcluster --timer || true
./mysql-test-run.pl --comment=normal+rowrepl --mysqld=--binlog-format=row --force --skip-ndbcluster --timer || true
./mysql-test-run.pl --comment=ps+rowrepl+NDB --ps-protocol --mysqld=--binlog-format=row --force --timer || true
@@ -685,6 +687,12 @@ fi
# itself - note that they must be ordered by date (important when
# merging BK trees)
%changelog
+* Mon Nov 13 2006 Joerg Bruehe <joerg@mysql.com>
+
+- Add "--with-partition" to all server builds.
+
+- Use "--report-features" in one test run per server build.
+
* Tue Aug 15 2006 Joerg Bruehe <joerg@mysql.com>
- The "max" server is removed from packages, effective from 5.1.12-beta.
diff --git a/unittest/README.txt b/unittest/README.txt
index e862a54e443..ea94a50595b 100644
--- a/unittest/README.txt
+++ b/unittest/README.txt
@@ -46,6 +46,8 @@ test won't be executed by 'make test' !
Documentation
-------------
-There is Doxygen-generated documentation available at:
+The generated documentation is temporarily placed at:
- https://intranet.mysql.com/~mkindahl/mytap/html/
+ http://www.kindahl.net/mytap/doc/
+
+I will move it to a better place once I figure out where and how.
diff --git a/unittest/mytap/Doxyfile b/unittest/mytap/Doxyfile
index 8c23703e925..1b1c82b4c98 100644
--- a/unittest/mytap/Doxyfile
+++ b/unittest/mytap/Doxyfile
@@ -432,7 +432,7 @@ FILE_PATTERNS =
# subdirectories should be searched for input files as well. Possible
# values are YES and NO. If left blank NO is used.
-RECURSIVE = YES
+RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that
# should excluded from the INPUT source files. This way you can easily
@@ -457,14 +457,14 @@ EXCLUDE_PATTERNS =
# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH = e
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
-EXAMPLE_PATTERNS =
+EXAMPLE_PATTERNS = *.c
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
@@ -926,7 +926,7 @@ MACRO_EXPANSION = YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
@@ -939,33 +939,34 @@ SEARCH_INCLUDES = YES
INCLUDE_PATH =
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more
+# wildcard patterns (like *.h and *.hpp) to filter out the
+# header-files in the directories. If left blank, the patterns
+# specified with FILE_PATTERNS will be used.
INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
+# The PREDEFINED tag can be used to specify one or more macro names
+# that are defined before the preprocessor is started (similar to the
+# -D option of gcc). The argument of the tag is a list of macros of
+# the form: name or name=definition (no spaces). If the definition and
+# the = are omitted =1 is assumed.
PREDEFINED =
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES
+# then this tag can be used to specify a list of macro names that
+# should be expanded. The macro definition that is found in the
+# sources will be used. Use the PREDEFINED tag if you want to use a
+# different macro definition.
-EXPAND_AS_DEFINED =
+EXPAND_AS_DEFINED = __attribute__
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse the
-# parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are
+# alone on a line, have an all uppercase name, and do not end with a
+# semicolon. Such function macros are typically used for boiler-plate
+# code, and will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = YES
diff --git a/unittest/mytap/tap.c b/unittest/mytap/tap.c
index 54292f3b828..29dc765950f 100644
--- a/unittest/mytap/tap.c
+++ b/unittest/mytap/tap.c
@@ -29,11 +29,17 @@
#include <signal.h>
/**
+ @defgroup MyTAP_Internal MyTAP Internals
+
+ Internal functions and data structures for the MyTAP implementation.
+*/
+
+/**
Test data structure.
Data structure containing all information about the test suite.
- @ingroup MyTAP
+ @ingroup MyTAP_Internal
*/
static TEST_DATA g_test = { 0, 0, 0, "" };
@@ -41,6 +47,8 @@ static TEST_DATA g_test = { 0, 0, 0, "" };
Output stream for test report message.
The macro is just a temporary solution.
+
+ @ingroup MyTAP_Internal
*/
#define tapout stdout
@@ -50,7 +58,7 @@ static TEST_DATA g_test = { 0, 0, 0, "" };
To emit the directive, use the emit_dir() function
- @ingroup MyTAP
+ @ingroup MyTAP_Internal
@see emit_dir
@@ -59,7 +67,7 @@ static TEST_DATA g_test = { 0, 0, 0, "" };
@param ap Vararg list for the description string above.
*/
static void
-emit_tap(int pass, char const *fmt, va_list ap)
+vemit_tap(int pass, char const *fmt, va_list ap)
{
fprintf(tapout, "%sok %d%s",
pass ? "" : "not ",
@@ -80,18 +88,22 @@ emit_tap(int pass, char const *fmt, va_list ap)
not ok 2 # todo some text explaining what remains
@endcode
+ @ingroup MyTAP_Internal
+
@param dir Directive as a string
- @param exp Explanation string
+ @param why Explanation string
*/
static void
-emit_dir(const char *dir, const char *exp)
+emit_dir(const char *dir, const char *why)
{
- fprintf(tapout, " # %s %s", dir, exp);
+ fprintf(tapout, " # %s %s", dir, why);
}
/**
Emit a newline to the TAP output stream.
+
+ @ingroup MyTAP_Internal
*/
static void
emit_endl()
@@ -198,7 +210,7 @@ ok(int const pass, char const *fmt, ...)
if (!pass && *g_test.todo == '\0')
++g_test.failed;
- emit_tap(pass, fmt, ap);
+ vemit_tap(pass, fmt, ap);
va_end(ap);
if (*g_test.todo != '\0')
emit_dir("todo", g_test.todo);
@@ -223,7 +235,7 @@ skip(int how_many, char const *const fmt, ...)
while (how_many-- > 0)
{
va_list ap;
- emit_tap(1, NULL, ap);
+ vemit_tap(1, NULL, ap);
emit_dir("skip", reason);
emit_endl();
}
@@ -316,7 +328,7 @@ int exit_status() {
@section UnitTest Writing unit tests
The purpose of writing unit tests is to use them to drive component
- development towards a solution that the tests. This means that the
+ development towards a solution that passes the tests. This means that the
unit tests has to be as complete as possible, testing at least:
- Normal input
@@ -325,29 +337,240 @@ int exit_status() {
- Error handling
- Bad environment
- We will go over each case and explain it in more detail.
+ @subsection NormalSubSec Normal input
+
+ This is to test that the component have the expected behaviour.
+ This is just plain simple: test that it works. For example, test
+ that you can unpack what you packed, adding gives the sum, pincing
+ the duck makes it quack.
+
+ This is what everybody does when they write tests.
+
+
+ @subsection BorderlineTests Borderline cases
+
+ If you have a size anywhere for your component, does it work for
+ size 1? Size 0? Sizes close to <code>UINT_MAX</code>?
+
+ It might not be sensible to have a size 0, so in this case it is
+ not a borderline case, but rather a faulty input (see @ref
+ FaultyInputTests).
+
+
+ @subsection FaultyInputTests Faulty input
+
+ Does your bitmap handle 0 bits size? Well, it might not be designed
+ for it, but is should <em>not</em> crash the application, but
+ rather produce an error. This is called defensive programming.
- @subsection NormalSSec Normal input
+ Unfortunately, adding checks for values that should just not be
+ entered at all is not always practical: the checks cost cycles and
+ might cost more than it's worth. For example, some functions are
+ designed so that you may not give it a null pointer. In those
+ cases it's not sensible to pass it <code>NULL</code> just to see it
+ crash.
- @subsection BorderlineSSec Borderline cases
+ Since every experienced programmer add an <code>assert()</code> to
+ ensure that you get a proper failure for the debug builds when a
+ null pointer passed (you add asserts too, right?), you will in this
+ case instead have a controlled (early) crash in the debug build.
- @subsection FaultySSec Faulty input
- @subsection ErrorSSec Error handling
+ @subsection ErrorHandlingTests Error handling
- @subsection EnvironmentSSec Environment
+ This is testing that the errors your component is designed to give
+ actually are produced. For example, testing that trying to open a
+ non-existing file produces a sensible error code.
+
+
+ @subsection BadEnvironmentTests Environment
Sometimes, modules has to behave well even when the environment
- fails to work correctly. Typical examples are: out of dynamic
- memory, disk is full,
+ fails to work correctly. Typical examples are when the computer is
+ out of dynamic memory or when the disk is full. You can emulate
+ this by replacing, e.g., <code>malloc()</code> with your own
+ version that will work for a while, but then fail. Some things are
+ worth to keep in mind here:
+
+ - Make sure to make the function fail deterministically, so that
+ you really can repeat the test.
+
+ - Make sure that it doesn't just fail immediately. The unit might
+ have checks for the first case, but might actually fail some time
+ in the near future.
- @section UnitTestSec How to structure a unit test
+
+ @section UnitTest How to structure a unit test
In this section we will give some advice on how to structure the
- unit tests to make the development run smoothly.
+ unit tests to make the development run smoothly. The basic
+ structure of a test is:
+
+ - Plan
+ - Test
+ - Report
+
+
+ @subsection TestPlanning Plan the test
+
+ Planning the test means telling how many tests there are. In the
+ event that one of the tests causes a crash, it is then possible to
+ see that there are fewer tests than expected, and print a proper
+ error message.
+
+ To plan a test, use the @c plan() function in the following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ .
+ .
+ .
+ }
+ @endcode
+
+ If you don't call the @c plan() function, the number of tests
+ executed will be printed at the end. This is intended to be used
+ while developing the unit and you are constantly adding tests. It
+ is not indented to be used after the unit has been released.
+
- @subsection PieceSec Test each piece separately
+ @subsection TestRunning Execute the test
+
+ To report the status of a test, the @c ok() function is used in the
+ following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ ok(ducks == paddling_ducks,
+ "%d ducks did not paddle", ducks - paddling_ducks);
+ .
+ .
+ .
+ }
+ @endcode
+
+ This will print a test result line on the standard output in TAP
+ format, which allows TAP handling frameworks (like Test::Harness)
+ to parse the status of the test.
+
+ @subsection TestReport Report the result of the test
+
+ At the end, a complete test report should be written, with some
+ statistics. If the test returns EXIT_SUCCESS, all tests were
+ successfull, otherwise at least one test failed.
+
+ To get a TAP complient output and exit status, report the exit
+ status in the following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ ok(ducks == paddling_ducks,
+ "%d ducks did not paddle", ducks - paddling_ducks);
+ .
+ .
+ .
+ return exit_status();
+ }
+ @endcode
+
+ @section DontDoThis Ways to not do unit testing
+
+ In this section, we'll go through some quite common ways to write
+ tests that are <em>not</em> a good idea.
+
+ @subsection BreadthFirstTests Doing breadth-first testing
+
+ If you're writing a library with several functions, don't test all
+ functions using size 1, then all functions using size 2, etc. If a
+ test for size 42 fails, you have no easy way of tracking down why
+ it failed.
+
+ It is better to concentrate on getting one function to work at a
+ time, which means that you test each function for all sizes that
+ you think is reasonable. Then you continue with the next function,
+ doing the same. This is usually also the way that a library is
+ developed (one function at a time) so stick to testing that is
+ appropriate for now the unit is developed.
+
+ @subsection JustToBeSafeTest Writing unnecessarily large tests
+
+ Don't write tests that use parameters in the range 1-1024 unless
+ you have a very good reason to belive that the component will
+ succeed for 562 but fail for 564 (the numbers picked are just
+ examples).
+
+ It is very common to write extensive tests "just to be safe."
+ Having a test suite with a lot of values might give you a warm
+ fuzzy feeling, but it doesn't really help you find the bugs. Good
+ tests fail; seriously, if you write a test that you expect to
+ succeed, you don't need to write it. If you think that it
+ <em>might</em> fail, <em>then</em> you should write it.
+
+ Don't take this as an excuse to avoid writing any tests at all
+ "since I make no mistakes" (when it comes to this, there are two
+ kinds of people: those who admit they make mistakes, and those who
+ don't); rather, this means that there is no reason to test that
+ using a buffer with size 100 works when you have a test for buffer
+ size 96.
+
+ The drawback is that the test suite takes longer to run, for little
+ or no benefit. It is acceptable to do a exhaustive test if it
+ doesn't take too long to run and it is quite common to do an
+ exhaustive test of a function for a small set of values.
+ Use your judgment to decide what is excessive: your milage may
+ vary.
+*/
+
+/**
+ @example simple.t.c
+
+ This is an simple example of how to write a test using the
+ library. The output of this program is:
+
+ @code
+ 1..1
+ # Testing basic functions
+ ok 1 - Testing gcs()
+ @endcode
+
+ The basic structure is: plan the number of test points using the
+ plan() function, perform the test and write out the result of each
+ test point using the ok() function, print out a diagnostics message
+ using diag(), and report the result of the test by calling the
+ exit_status() function. Observe that this test does excessive
+ testing (see @ref JustToBeSafeTest), but the test point doesn't
+ take very long time.
+*/
+
+/**
+ @example todo.t.c
+
+ This example demonstrates how to use the <code>todo_start()</code>
+ and <code>todo_end()</code> function to mark a sequence of tests to
+ be done. Observe that the tests are assumed to fail: if any test
+ succeeds, it is considered a "bonus".
+*/
+
+/**
+ @example skip.t.c
+
+ This is an example of how the <code>SKIP_BLOCK_IF</code> can be
+ used to skip a predetermined number of tests. Observe that the
+ macro actually skips the following statement, but it's not sensible
+ to use anything than a block.
+*/
+
+/**
+ @example skip_all.t.c
- Don't test all functions using size 1, then all functions using
- size 2, etc.
+ Sometimes, you skip an entire test because it's testing a feature
+ that doesn't exist on the system that you're testing. To skip an
+ entire test, use the <code>skip_all()</code> function according to
+ this example.
*/
diff --git a/unittest/mytap/tap.h b/unittest/mytap/tap.h
index 51b8c7df04d..a47060fa3cc 100644
--- a/unittest/mytap/tap.h
+++ b/unittest/mytap/tap.h
@@ -33,6 +33,8 @@
/**
Data about test plan.
+ @ingroup MyTAP_Internal
+
@internal We are using the "typedef struct X { ... } X" idiom to
create class/struct X both in C and C++.
*/
@@ -61,6 +63,14 @@ extern "C" {
#endif
/**
+ @defgroup MyTAP_API MyTAP API
+
+ MySQL support for performing unit tests according to TAP.
+
+ @{
+*/
+
+/**
Set number of tests that is planned to execute.
The function also accepts the predefined constant
@@ -101,11 +111,14 @@ void ok(int pass, char const *fmt, ...)
/**
Skip a determined number of tests.
- Function to print that <em>how_many</em> tests have been
- skipped. The reason is printed for each skipped test. Observe
- that this function does not do the actual skipping for you, it just
- prints information that tests have been skipped. It shall be used
- in the following manner:
+ Function to print that <em>how_many</em> tests have been skipped.
+ The reason is printed for each skipped test. Observe that this
+ function does not do the actual skipping for you, it just prints
+ information that tests have been skipped. This function is not
+ usually used, but rather the macro @c SKIP_BLOCK_IF, which does the
+ skipping for you.
+
+ It shall be used in the following manner:
@code
if (ducks == 0) {
@@ -192,8 +205,8 @@ void BAIL_OUT(char const *fmt, ...)
return exit_status();
@endcode
- @returns EXIT_SUCCESS if all tests passed, EXIT_FAILURE if one or
- more tests failed.
+ @returns @c EXIT_SUCCESS if all tests passed, @c EXIT_FAILURE if
+ one or more tests failed.
*/
int exit_status(void);
@@ -242,6 +255,7 @@ void todo_start(char const *message, ...)
void todo_end();
+/** @} */
#ifdef __cplusplus
}