Commit 7b500f04 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-29078 For old binary logs explicit_defaults_for_timestamp presumed to be...

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.
parent 56c7d142
......@@ -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 *//*!*/;
......
......@@ -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 *//*!*/;
......
#
# 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
--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
......@@ -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.
......
......@@ -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.
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).
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.
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 @@ class Log_event
<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 @@ class Format_description_log_event: public Start_log_event_v3
};
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 @@ class Format_description_log_event: public Start_log_event_v3
}
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)
......
......@@ -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;
......
......@@ -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
......
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