MDEV-29078 For old binary logs explicit_defaults_for_timestamp presumed to be OFF, server value ignored

don't assume anymore that OPTIONS_WRITTEN_TO_BIN_LOG is fixed once
and forever. Instead, deduct master's OPTIONS_WRITTEN_TO_BIN_LOG
from the master's version in binlog.
This commit is contained in:
Sergei Golubchik 2022-07-23 16:38:03 +02:00
parent 56c7d14217
commit 7b500f04fb
10 changed files with 190 additions and 39 deletions

View file

@ -724,7 +724,7 @@ ROLLBACK/*!*/;
use `test`/*!*/;
SET TIMESTAMP=1253783037/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -778,7 +778,7 @@ DELIMITER /*!*/;
ROLLBACK/*!*/;
SET TIMESTAMP=1253783037/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -813,7 +813,7 @@ ROLLBACK /* added by mysqlbinlog */;
DELIMITER /*!*/;
SET TIMESTAMP=1266652094/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -855,7 +855,7 @@ ROLLBACK /* added by mysqlbinlog */;
DELIMITER /*!*/;
SET TIMESTAMP=1266652094/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -973,7 +973,7 @@ AAAAAAAAAAAAAAAAAAAgrgJSFzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
# Event: Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1375907364/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -1056,7 +1056,7 @@ AAAAAAAAAAAAAAAAAAA/rQJSGzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
# Event: Query thread_id=1 exec_time=1 error_code=0
SET TIMESTAMP=1375907141/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -1139,7 +1139,7 @@ AAAAAAAAAAAAAAAAAAAnrAJSHzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
# Event: Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1375906879/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
@ -1222,7 +1222,7 @@ AAAAAAAAAAAAAAAAAABbsAJSEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
# Event: Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1375907933/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;

Binary file not shown.

View file

@ -59,7 +59,7 @@ ROLLBACK/*!*/;
<#>
use `test`/*!*/;
SET TIMESTAMP=1196959712/*!*/;
<#>SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=0/*!*/;
<#>SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;

View file

@ -0,0 +1,92 @@
#
# MDEV-29078 For old binary logs explicit_defaults_for_timestamp presumed to be OFF, server value ignored
#
include/master-slave.inc
[connection master]
connection slave;
include/stop_slave.inc
connection master;
flush binary logs;
create table t2 (a timestamp);
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
ROLLBACK/*!*/;
use `test`/*!*/;
SET TIMESTAMP=1658586280/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
SET @@session.sql_mode=1411383296/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table t1 (f1 timestamp, f2 timestamp)
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1658586288/*!*/;
insert t1 values (NULL, NULL)
/*!*/;
SET TIMESTAMP=1658586288/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1658586335/*!*/;
insert t1 () values ()
/*!*/;
SET TIMESTAMP=1658586335/*!*/;
COMMIT
/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
connection slave;
set global explicit_defaults_for_timestamp=1;
reset slave;
include/start_slave.inc
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` timestamp NULL DEFAULT NULL,
`f2` timestamp NULL DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` timestamp NULL DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
set time_zone='+2:00';
select * from t1;
f1 f2
NULL NULL
NULL NULL
drop table t1;
include/stop_slave.inc
set global explicit_defaults_for_timestamp=0;
reset slave;
include/start_slave.inc
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`f2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select * from t1;
f1 f2
2022-07-23 16:24:48 2022-07-23 16:24:48
2022-07-23 16:25:35 0000-00-00 00:00:00
drop table t1;
connection master;
drop table t2;
include/rpl_end.inc

View file

@ -0,0 +1 @@
--version=10.5.99

View file

@ -0,0 +1,49 @@
--echo #
--echo # MDEV-29078 For old binary logs explicit_defaults_for_timestamp presumed to be OFF, server value ignored
--echo #
--source include/have_binlog_format_mixed.inc
--source include/master-slave.inc
--connection slave
--source include/stop_slave.inc
--connection master
--let $datadir= `SELECT @@datadir`
flush binary logs;
create table t2 (a timestamp);
--save_master_pos
--remove_file $datadir/master-bin.000001
--copy_file $MYSQL_TEST_DIR/std_data/mdev29078-mysql-bin.000001 $datadir/master-bin.000001
--exec $MYSQL_BINLOG --short-form $datadir/master-bin.000001
--connection slave
set global explicit_defaults_for_timestamp=1;
reset slave;
--source include/start_slave.inc
--sync_with_master
show create table t1;
show create table t2;
set time_zone='+2:00';
select * from t1;
drop table t1;
--source include/stop_slave.inc
set global explicit_defaults_for_timestamp=0;
reset slave;
--source include/start_slave.inc
--sync_with_master
show create table t1;
show create table t2;
select * from t1;
drop table t1;
--connection master
drop table t2;
--source include/rpl_end.inc

View file

@ -2195,6 +2195,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
break;
}
calc_server_version_split();
deduct_options_written_to_bin_log();
checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
reset_crypto();
}
@ -2255,6 +2256,7 @@ Format_description_log_event(const char* buf,
{
checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
}
deduct_options_written_to_bin_log();
reset_crypto();
DBUG_VOID_RETURN;
@ -2331,6 +2333,27 @@ void Format_description_log_event::calc_server_version_split()
}
void Format_description_log_event::deduct_options_written_to_bin_log()
{
options_written_to_bin_log= OPTION_AUTO_IS_NULL | OPTION_NOT_AUTOCOMMIT |
OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS;
if (!server_version_split.version_is_valid() ||
server_version_split.kind == master_version_split::KIND_MYSQL ||
server_version_split < Version(10,5,2))
return;
options_written_to_bin_log|= OPTION_IF_EXISTS;
if (server_version_split[0] == 10)
{
const static char v[10]={99,99,99,99,99,17,9,5,4,2};
if (server_version_split[1] < 10 &&
server_version_split[2] < v[server_version_split[1]])
return;
}
options_written_to_bin_log|= OPTION_EXPLICIT_DEF_TIMESTAMP;
DBUG_ASSERT(options_written_to_bin_log == OPTIONS_WRITTEN_TO_BIN_LOG);
}
/**
@return TRUE is the event's version is earlier than one that introduced
the replication event checksum. FALSE otherwise.

View file

@ -508,33 +508,16 @@ class String;
be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be
written into the Format_description_log_event, so that if later we
don't want to replicate a variable we did replicate, or the
contrary, it's doable. But it should not be too hard to decide once
for all of what we replicate and what we don't, among the fixed 32
bits of thd->options.
contrary, it's doable. But it should not be too hard to deduct
the value of OPTIONS_WRITTEN_TO_BIN_LOG from the master's version.
I (Guilhem) have read through every option's usage, and it looks
like OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only
ones which alter how the query modifies the table. It's good to
replicate OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the
slave may insert data slower than the master, in InnoDB.
OPTION_BIG_SELECTS is not needed (the slave thread runs with
max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed
either, as the manual says (because a too big in-memory temp table
is automatically written to disk).
This is done in deduct_options_written_to_bin_log().
You *must* update it, when changing the definition below.
*/
#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_EXPLICIT_DEF_TIMESTAMP |\
OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \
OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT | OPTION_IF_EXISTS)
/* Shouldn't be defined before */
#define EXPECTED_OPTIONS \
((1ULL << 14) | (1ULL << 26) | (1ULL << 27) | (1ULL << 19) | (1ULL << 24) | (1ULL << 28))
#if OPTIONS_WRITTEN_TO_BIN_LOG != EXPECTED_OPTIONS
#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values!
#endif
#undef EXPECTED_OPTIONS /* You shouldn't use this one */
#define CHECKSUM_CRC32_SIGNATURE_LEN 4
/**
defined statically while there is just one alg implemented
@ -1832,10 +1815,7 @@ protected:
<td>The flags in @c thd->options, binary AND-ed with @c
OPTIONS_WRITTEN_TO_BIN_LOG. The @c thd->options bitfield contains
options for "SELECT". @c OPTIONS_WRITTEN identifies those options
that need to be written to the binlog (not all do). Specifically,
@c OPTIONS_WRITTEN_TO_BIN_LOG equals (@c OPTION_AUTO_IS_NULL | @c
OPTION_NO_FOREIGN_KEY_CHECKS | @c OPTION_RELAXED_UNIQUE_CHECKS |
@c OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex.
that need to be written to the binlog (not all do).
These flags correspond to the SQL variables SQL_AUTO_IS_NULL,
FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in
@ -2826,6 +2806,7 @@ public:
};
master_version_split server_version_split;
const uint8 *event_type_permutation;
uint32 options_written_to_bin_log;
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
Format_description_log_event(const char* buf, uint event_len,
@ -2873,6 +2854,7 @@ public:
}
void calc_server_version_split();
void deduct_options_written_to_bin_log();
static bool is_version_before_checksum(const master_version_split *version_split);
protected:
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)

View file

@ -1885,6 +1885,7 @@ bool Query_log_event::print_query_header(IO_CACHE* file,
if (unlikely(tmp)) /* some bits have changed */
{
bool need_comma= 0;
ulonglong mask= glob_description_event->options_written_to_bin_log;
if (my_b_write_string(file, "SET ") ||
print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
"@@session.foreign_key_checks", &need_comma)||
@ -1896,10 +1897,11 @@ bool Query_log_event::print_query_header(IO_CACHE* file,
"@@session.autocommit", &need_comma) ||
print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS, ~flags2,
"@@session.check_constraint_checks", &need_comma) ||
print_set_option(file, tmp, OPTION_IF_EXISTS, flags2,
"@@session.sql_if_exists", &need_comma)||
print_set_option(file, tmp, OPTION_EXPLICIT_DEF_TIMESTAMP, flags2,
"@@session.explicit_defaults_for_timestamp", &need_comma)||
print_set_option(file, tmp, mask & OPTION_IF_EXISTS, flags2,
"@@session.sql_if_exists", &need_comma) ||
print_set_option(file, tmp, mask & OPTION_EXPLICIT_DEF_TIMESTAMP, flags2,
"@@session.explicit_defaults_for_timestamp",
&need_comma) ||
my_b_printf(file,"%s\n", print_event_info->delimiter))
goto err;
print_event_info->flags2= flags2;

View file

@ -1718,7 +1718,9 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
OPTIONS_WRITTEN_TO_BIN_LOG must take their value from
flags2.
*/
thd->variables.option_bits= flags2|(thd->variables.option_bits & ~OPTIONS_WRITTEN_TO_BIN_LOG);
ulonglong mask= rli->relay_log.description_event_for_exec->options_written_to_bin_log;
thd->variables.option_bits= (flags2 & mask) |
(thd->variables.option_bits & ~mask);
}
/*
else, we are in a 3.23/4.0 binlog; we previously received a