Commit 6d66e660 authored by Georgi Kodinov's avatar Georgi Kodinov

merge

parents 30a8c53a a0a5152f
[MYSQL]
post_commit_to = "commits@lists.mysql.com"
post_push_to = "commits@lists.mysql.com"
tree_name = "mysql-5.1"
tree_name = "mysql-5.1-bugteam"
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;
CREATE TABLE t1 (c1 BIT, c2 INT);
INSERT INTO `t1` VALUES ( 1, 1 );
UPDATE t1 SET c1=NULL where c2=1;
Comparing tables master:test.t1 and slave:test.t1
DELETE FROM t1 WHERE c2=1 LIMIT 1;
Comparing tables master:test.t1 and slave:test.t1
DROP TABLE t1;
CREATE TABLE t1 (c1 CHAR);
INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
SELECT * FROM t1;
c1
w
# should trigger switch to row due to LIMIT
UPDATE t1 SET c1=NULL WHERE c1='w' LIMIT 2;
Comparing tables master:test.t1 and slave:test.t1
DELETE FROM t1 LIMIT 2;
Comparing tables master:test.t1 and slave:test.t1
DROP TABLE t1;
RESET MASTER;
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 TABLE IF EXISTS `t1`;
### TABLE with field_metadata_size == 290
CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
`c2` varchar(30) NOT NULL,
......@@ -150,7 +156,51 @@ CREATE TABLE `t1` (
PRIMARY KEY (`c1`)
) ENGINE=InnoDB;
LOCK TABLES `t1` WRITE;
INSERT INTO `t1` VALUES ('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1');
DROP TABLE `t1`;
INSERT INTO `t1`(c2) VALUES ('1');
FLUSH LOGS;
### assertion: the slave replicated event successfully and tables match
Comparing tables master:test.t1 and slave:test.t1
DROP TABLE `t1`;
=== Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail.
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;
### action: generating several tables with different metadata
### sizes (resorting to perl)
### testing table with 249 field metadata size.
### testing table with 250 field metadata size.
### testing table with 251 field metadata size.
### testing table with 252 field metadata size.
### testing table with 253 field metadata size.
### testing table with 254 field metadata size.
### testing table with 255 field metadata size.
### testing table with 256 field metadata size.
### testing table with 257 field metadata size.
### testing table with 258 field metadata size.
FLUSH LOGS;
### assertion: the slave replicated event successfully and tables match for t10
Comparing tables master:test.t10 and slave:test.t10
### assertion: the slave replicated event successfully and tables match for t9
Comparing tables master:test.t9 and slave:test.t9
### assertion: the slave replicated event successfully and tables match for t8
Comparing tables master:test.t8 and slave:test.t8
### assertion: the slave replicated event successfully and tables match for t7
Comparing tables master:test.t7 and slave:test.t7
### assertion: the slave replicated event successfully and tables match for t6
Comparing tables master:test.t6 and slave:test.t6
### assertion: the slave replicated event successfully and tables match for t5
Comparing tables master:test.t5 and slave:test.t5
### assertion: the slave replicated event successfully and tables match for t4
Comparing tables master:test.t4 and slave:test.t4
### assertion: the slave replicated event successfully and tables match for t3
Comparing tables master:test.t3 and slave:test.t3
### assertion: the slave replicated event successfully and tables match for t2
Comparing tables master:test.t2 and slave:test.t2
### assertion: the slave replicated event successfully and tables match for t1
Comparing tables master:test.t1 and slave:test.t1
### assertion: check that binlog is not corrupt. Using mysqlbinlog to
### detect failure. Before the patch mysqlbinlog would find
### a corrupted event, thence would fail.
# BUG#49481: RBR: MyISAM and bit fields may cause slave to stop on delete cant find record
# BUG#49482: RBR: Replication may break on deletes when MyISAM tables + char field are used
-- source include/master-slave.inc
-- source include/have_binlog_format_mixed_or_row.inc
-- connection master
CREATE TABLE t1 (c1 BIT, c2 INT);
INSERT INTO `t1` VALUES ( 1, 1 );
UPDATE t1 SET c1=NULL where c2=1;
-- sync_slave_with_master
-- let $diff_table_1=master:test.t1
-- let $diff_table_2=slave:test.t1
-- source include/diff_tables.inc
-- connection master
DELETE FROM t1 WHERE c2=1 LIMIT 1;
-- sync_slave_with_master
-- let $diff_table_1=master:test.t1
-- let $diff_table_2=slave:test.t1
-- source include/diff_tables.inc
-- connection master
DROP TABLE t1;
-- sync_slave_with_master
-- connection master
CREATE TABLE t1 (c1 CHAR);
INSERT INTO t1 ( c1 ) VALUES ( 'w' ) ;
SELECT * FROM t1;
-- echo # should trigger switch to row due to LIMIT
UPDATE t1 SET c1=NULL WHERE c1='w' LIMIT 2;
-- sync_slave_with_master
-- let $diff_table_1=master:test.t1
-- let $diff_table_2=slave:test.t1
-- source include/diff_tables.inc
-- connection master
DELETE FROM t1 LIMIT 2;
-- sync_slave_with_master
-- let $diff_table_1=master:test.t1
-- let $diff_table_2=slave:test.t1
-- source include/diff_tables.inc
-- connection master
DROP TABLE t1;
-- sync_slave_with_master
......@@ -2,38 +2,39 @@
# BUG#42749: infinite loop writing to row based binlog - processlist shows
# "freeing items"
#
#
# WHY
# ===
#
# This bug would make table map event to report data_written one byte less
# than what would actually be written in its body. This would cause one byte shorter
# event end_log_pos. The ultimate impact was that it would make fixing the
# position in MYSQL_BIN_LOG::write_cache bogus or end up in an infinite loop.
#
# This bug would make table map event to report data_written one
# byte less than what would actually be written in its body. This
# would cause one byte shorter event end_log_pos. The ultimate
# impact was that it would make fixing the position in
# MYSQL_BIN_LOG::write_cache bogus or end up in an infinite loop.
#
# HOW
# ===
#
# Checking that the patch fixes the problem is done as follows:
# i) a table with several fields is created;
#
# i) one table with m_field_metadata sized at 290
# ii) an insert is performed;
# iii) the logs are flushed;
# iv) mysqlbinlog is used to check if it succeeds.
#
# In step iv), before the bug was fixed, the test case would fail with
# mysqlbinlog reporting that it was unable to succeed in reading the event.
#
# In step iv), before the bug was fixed, the test case would fail
# with mysqlbinlog reporting that it was unable to succeed in
# reading the event.
-- source include/have_log_bin.inc
-- source include/master-slave.inc
-- source include/have_innodb.inc
-- source include/have_binlog_format_row.inc
-- connection default
RESET MASTER;
-- disable_warnings
DROP TABLE IF EXISTS `t1`;
-- enable_warnings
-- echo ### TABLE with field_metadata_size == 290
CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
`c2` varchar(30) NOT NULL,
......@@ -185,15 +186,155 @@ CREATE TABLE `t1` (
) ENGINE=InnoDB;
LOCK TABLES `t1` WRITE;
INSERT INTO `t1`(c2) VALUES ('1');
FLUSH LOGS;
-- sync_slave_with_master
-- connection master
INSERT INTO `t1` VALUES ('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1');
-- echo ### assertion: the slave replicated event successfully and tables match
-- let $diff_table_1=master:test.t1
-- let $diff_table_2=slave:test.t1
-- source include/diff_tables.inc
DROP TABLE `t1`;
FLUSH LOGS;
-- connection master
-- sync_slave_with_master
-- connection master
-- echo === Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail.
-- let $MYSQLD_DATADIR= `SELECT @@datadir`;
-- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
#############################################################
# BUG#50018: binlog corruption when table has many columns
#
# Same test from BUG#42749, but now we generate some SQL which
# creates and inserts into tables with metadata size from 249
# to 258.
#
# The test works as follows:
# 1. SQL for several CREATE TABLE and INSERTS are generated
# into a file.
# 2. This file is then "sourced"
# 3. The slave is synchronized with the master
# 4. FLUSH LOGS on master
# 5. Compare tables on master and slave.
# 6. run mysqlbinlog on master's binary log
#
# Steps #5 and #6 assert that binary log is not corrupted
# in both cases: when slave is replaying events and when
# mysqlbinlog is used to read the binary log
-- source include/master-slave-reset.inc
-- connection master
# Create several tables with field_metadata_size ranging
# from 249 to 258 (so that we cover 251 and 255 range).
# This should exercise the switch between using 1 or 3
# bytes to pack m_field_metadata_size.
#
# Each varchar field takes up to 2 metadata bytes, see:
#
# Field_varstring::do_save_field_metadata (field.cc)
#
# The float field takes 1 byte, see:
#
# Field_float::do_save_field_metadata (field.cc)
#
-- let $generated_sql= $MYSQLTEST_VARDIR/tmp/b50018.sql
-- let B50018_FILE= $generated_sql
-- echo ### action: generating several tables with different metadata
-- echo ### sizes (resorting to perl)
-- perl
my $file= $ENV{'B50018_FILE'};
open(FILE, ">", "$file") or die "Unable to open bug 50018 generated SQL file: $!" ;
my $tables= "";
my $ntables= 10;
my $base_ncols= 124;
for my $i (1..$ntables)
{
my $ncols= $base_ncols + $i;
my $metadata_size= $ncols_variable * 2 + 1;
print FILE "-- echo ### testing table with " . ($base_ncols*2 + $i) . " field metadata size.\n";
print FILE "CREATE TABLE t$i (\n";
for my $n (1..$base_ncols)
{
print FILE "c$n VARCHAR(30) NOT NULL DEFAULT 'BUG#50018',\n";
}
for my $n (1..$i)
{
print FILE "c" . ($base_ncols+$n) . " FLOAT NOT NULL DEFAULT 0";
if ($n < $i)
{
print FILE ",\n";
}
}
print FILE ") Engine=InnoDB;\n";
$tables.= " t$i WRITE";
if ($i < $ntables)
{
$tables .=",";
}
print FILE "LOCK TABLES t$i WRITE;\n";
print FILE "INSERT INTO t$i(c". ($base_ncols+1) . ") VALUES (50018);\n";
print FILE "UNLOCK TABLES;";
}
close(FILE);
EOF
## we don't need this in the result file
## however, for debugging purposes you
## may want to reactivate query logging
-- disable_query_log
-- source $generated_sql
-- enable_query_log
-- sync_slave_with_master
-- connection master
FLUSH LOGS;
-- let $ntables=10
while($ntables)
{
-- echo ### assertion: the slave replicated event successfully and tables match for t$ntables
-- let $diff_table_1=master:test.t$ntables
-- let $diff_table_2=slave:test.t$ntables
-- source include/diff_tables.inc
-- connection master
-- disable_query_log
-- eval DROP TABLE t$ntables
-- enable_query_log
-- sync_slave_with_master
-- connection master
-- dec $ntables
}
-- echo ### assertion: check that binlog is not corrupt. Using mysqlbinlog to
-- echo ### detect failure. Before the patch mysqlbinlog would find
-- echo ### a corrupted event, thence would fail.
-- let $MYSQLD_DATADIR= `SELECT @@datadir`;
-- exec $MYSQL_BINLOG -v --hex $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog
## clean up
## For debugging purposes you might want not to remove these
-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog
-- remove_file $generated_sql
-- source include/master-slave-end.inc
......@@ -7926,10 +7926,10 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
plus one or three bytes (see pack.c:net_store_length) for number of
elements in the field metadata array.
*/
if (m_field_metadata_size > 255)
m_data_size+= m_field_metadata_size + 3;
else
if (m_field_metadata_size < 251)
m_data_size+= m_field_metadata_size + 1;
else
m_data_size+= m_field_metadata_size + 3;
bzero(m_null_bits, num_null_bytes);
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
......@@ -8724,6 +8724,24 @@ static bool record_compare(TABLE *table)
}
}
/**
Check if we are using MyISAM.
If this is a myisam table, then we cannot do a memcmp
right away because some NULL fields can still contain
an old value in the row - they are not shown to the user
because the null bit is set, however, the contents are
not cleared. As such, plain memory comparison cannot be
assured to work. See: BUG#49482 and BUG#49481.
On top of this, we do not store field contents for null
fields in the binlog, so this is extra important when
comparing records fetched from binlog and from storage
engine.
*/
if (table->file->ht->db_type == DB_TYPE_MYISAM)
goto record_compare_field_by_field;
if (table->s->blob_fields + table->s->varchar_fields == 0)
{
result= cmp_record(table,record[1]);
......@@ -8739,14 +8757,33 @@ static bool record_compare(TABLE *table)
goto record_compare_exit;
}
record_compare_field_by_field:
/* Compare updated fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
Field *f= *ptr;
/* if just one of the fields is null then there is no match */
if ((f->is_null_in_record(table->record[0])) ==
!(f->is_null_in_record(table->record[1])))
{
result= TRUE;
goto record_compare_exit;
}
/* if both fields are not null then we can compare */
if (!(f->is_null_in_record(table->record[0])) &&
!(f->is_null_in_record(table->record[1])))
{
if (f->cmp_binary_offset(table->s->rec_buff_length))
{
result= TRUE;
goto record_compare_exit;
}
}
/* if both fields are null then there is a match. compare next field */
}
record_compare_exit:
......
......@@ -351,6 +351,24 @@ static bool record_compare(TABLE *table)
}
}
/**
Check if we are using MyISAM.
If this is a myisam table, then we cannot do a memcmp
right away because some NULL fields can still contain
an old value in the row - they are not shown to the user
because the null bit is set, however, the contents are
not cleared. As such, plain memory comparison cannot be
assured to work. See: BUG#49482 and BUG#49481.
On top of this, we do not store field contents for null
fields in the binlog, so this is extra important when
comparing records fetched from binlog and from storage
engine.
*/
if (table->file->ht->db_type == DB_TYPE_MYISAM)
goto record_compare_field_by_field;
if (table->s->blob_fields + table->s->varchar_fields == 0)
{
result= cmp_record(table,record[1]);
......@@ -366,14 +384,33 @@ static bool record_compare(TABLE *table)
goto record_compare_exit;
}
record_compare_field_by_field:
/* Compare updated fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
Field *f= *ptr;
/* if just one of the fields is null then there is no match */
if ((f->is_null_in_record(table->record[0])) ==
!(f->is_null_in_record(table->record[1])))
{
result= TRUE;
goto record_compare_exit;
}
/* if both fields are not null then we can compare */
if (!(f->is_null_in_record(table->record[0])) &&
!(f->is_null_in_record(table->record[1])))
{
if (f->cmp_binary_offset(table->s->rec_buff_length))
{
result= TRUE;
goto record_compare_exit;
}
}
/* if both fields are null then there is a match. compare next field */
}
record_compare_exit:
......
......@@ -310,7 +310,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
TABLE *table;
READ_RECORD read_record_info;
my_bool return_val= 1;
my_bool return_val= TRUE;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
int password_length;
......@@ -623,7 +623,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_check_host();
initialized=1;
return_val=0;
return_val= FALSE;
end:
thd->variables.sql_mode= old_sql_mode;
......@@ -674,7 +674,7 @@ my_bool acl_reload(THD *thd)
DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
MEM_ROOT old_mem;
bool old_initialized;
my_bool return_val= 1;
my_bool return_val= TRUE;
DBUG_ENTER("acl_reload");
if (thd->locked_tables)
......@@ -701,8 +701,13 @@ my_bool acl_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
thd->main_da.message());
/*
Execution might have been interrupted; only print the error message
if an error condition has been raised.
*/
if (thd->main_da.is_error())
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
thd->main_da.message());
goto end;
}
......
......@@ -6789,13 +6789,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
thd->store_globals();
lex_start(thd);
}
if (thd)
{
bool reload_acl_failed= acl_reload(thd);
bool reload_grants_failed= grant_reload(thd);
bool reload_servers_failed= servers_reload(thd);
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
{
result= 1;
......@@ -6951,7 +6951,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
return result;
/*
If the query was killed then this function must fail.
*/
return result || thd->killed;
}
......
......@@ -241,8 +241,14 @@ bool servers_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
sql_print_error("Can't open and lock privilege tables: %s",
thd->main_da.message());
/*
Execution might have been interrupted; only print the error message
if an error condition has been raised.
*/
if (thd->main_da.is_error())
sql_print_error("Can't open and lock privilege tables: %s",
thd->main_da.message());
return_val= FALSE;
goto end;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment