Commit f071b762 authored by Yuchen Pei's avatar Yuchen Pei

Merge branch '10.5' into 10.6

parents 6264950c cf1c381b
......@@ -1070,7 +1070,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
case QUERY_COMPRESSED_EVENT:
{
Query_log_event *qe= (Query_log_event*)ev;
if (!qe->is_trans_keyword())
if (!qe->is_trans_keyword(print_event_info->is_xa_trans()))
{
if (shall_skip_database(qe->db))
goto end;
......
......@@ -573,6 +573,22 @@ privilege\&.
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: flashback option
.\" flashback option: mysqlbinlog
\fB\-\-flashback\fR,
\fB\-B\fR
.sp
Support flashback mode\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqlbinlog: force-if-open option
.\" force-if-open option: mysqlbinlog
\fB\-\-force\-if\-open\fR
......
......@@ -894,22 +894,6 @@ instead\&.
.sp -1
.IP \(bu 2.3
.\}
.\" mysqldump: flashback option
.\" flashback option: mysqldump
\fB\-\-flashback\fR,
\fB\-B\fR
.sp
Support flashback mode\&.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqldump: flush-logs option
.\" flush-logs option: mysqldump
\fB\-\-flush\-logs\fR,
......
......@@ -4,4 +4,4 @@
# - r_engine_stats depends on buffer pool state and whether old record versions
# were purged.
--replace_regex /("(r_[a-z_]*_time_ms|r_buffer_size)": )[^, \n]*/\1"REPLACED"/ /("r_engine_stats":) {[^}]*}/\1 REPLACED/
--replace_regex /("(r_[a-z_]*_time_ms|r_buffer_size|r_partial_match_buffer_size)": )[^, \n]*/\1"REPLACED"/ /("r_engine_stats":) {[^}]*}/\1 REPLACED/
if (`select version() like '%valgrind%' || version() like '%asan%'`)
{
skip Does not run with binaries built with valgrind or asan;
}
......@@ -692,21 +692,25 @@ ANALYZE
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"r_loops": 1,
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"materialization": {
"r_strategy": "index_lookup",
"r_loops": 2,
"query_block": {
"select_id": 2,
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"r_engine_stats": REPLACED,
"filtered": 100,
"r_filtered": 100
"r_total_time_ms": "REPLACED",
"table": {
"table_name": "t1",
"access_type": "ALL",
"r_loops": 1,
"rows": 2,
"r_rows": 2,
"r_table_time_ms": "REPLACED",
"r_other_time_ms": "REPLACED",
"r_engine_stats": REPLACED,
"filtered": 100,
"r_filtered": 100
}
}
}
}
......
......@@ -7671,10 +7671,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 2,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -7731,10 +7733,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 2,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -7815,10 +7819,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -7872,10 +7878,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -7924,10 +7932,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -7976,10 +7986,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -8030,10 +8042,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -8082,10 +8096,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -8134,10 +8150,12 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
"materialization": {
"query_block": {
"select_id": 3,
"table": {
"message": "Select tables optimized away"
}
}
}
}
......@@ -8223,10 +8241,12 @@ EXPLAIN
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"message": "Impossible WHERE"
"materialization": {
"query_block": {
"select_id": 2,
"table": {
"message": "Impossible WHERE"
}
}
}
}
......@@ -9294,27 +9314,29 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "<derived3>",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "d_tab.e > 1",
"materialized": {
"query_block": {
"select_id": 3,
"filesort": {
"sort_key": "t2.e",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "t2.e > 1"
"materialization": {
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "<derived3>",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "d_tab.e > 1",
"materialized": {
"query_block": {
"select_id": 3,
"filesort": {
"sort_key": "t2.e",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "t2.e > 1"
}
}
}
}
......@@ -9396,27 +9418,29 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "<derived3>",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "d_tab.max_f > 20",
"materialized": {
"query_block": {
"select_id": 3,
"having_condition": "max_f > 20",
"filesort": {
"sort_key": "t2.e",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 5,
"filtered": 100
"materialization": {
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "<derived3>",
"access_type": "ALL",
"rows": 5,
"filtered": 100,
"attached_condition": "d_tab.max_f > 20",
"materialized": {
"query_block": {
"select_id": 3,
"having_condition": "max_f > 20",
"filesort": {
"sort_key": "t2.e",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 5,
"filtered": 100
}
}
}
}
......@@ -10827,16 +10851,18 @@ EXPLAIN
"attached_condition": "t4.c = `<subquery2>`.`sum(b)`",
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"having_condition": "`f1(a)` > 1 and `sum(b)` > 123",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 3,
"filtered": 100,
"attached_condition": "t1.a + 1 > 10"
"materialization": {
"query_block": {
"select_id": 2,
"having_condition": "`f1(a)` > 1 and `sum(b)` > 123",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 3,
"filtered": 100,
"attached_condition": "t1.a + 1 > 10"
}
}
}
}
......
......@@ -574,14 +574,16 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
"materialization": {
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
......@@ -906,13 +908,15 @@ EXPLAIN
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 2,
"filtered": 100
"materialization": {
"query_block": {
"select_id": 2,
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 2,
"filtered": 100
}
}
}
}
......
......@@ -1134,15 +1134,17 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5 and t2.x > 1"
"materialization": {
"query_block": {
"select_id": 2,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5 and t2.x > 1"
}
}
}
}
......@@ -1183,15 +1185,17 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5 and t2.x > 1"
"materialization": {
"query_block": {
"select_id": 3,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5 and t2.x > 1"
}
}
}
}
......@@ -1257,16 +1261,18 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 2,
"having_condition": "`MAX(t2.y)` < 14",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5"
"materialization": {
"query_block": {
"select_id": 2,
"having_condition": "`MAX(t2.y)` < 14",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5"
}
}
}
}
......@@ -1307,16 +1313,18 @@ EXPLAIN
"filtered": 100,
"materialized": {
"unique": 1,
"query_block": {
"select_id": 3,
"having_condition": "`MAX(t2.y)` < 14",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5"
"materialization": {
"query_block": {
"select_id": 3,
"having_condition": "`MAX(t2.y)` < 14",
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"rows": 4,
"filtered": 100,
"attached_condition": "t2.x < 5"
}
}
}
}
......@@ -5088,4 +5096,91 @@ SELECT * FROM v1
GROUP BY a HAVING a = (a IS NULL OR a IS NULL);
a
DROP VIEW v1;
#
# MDEV-32608: Expression with constant subquery causes a crash
# in pushdown from HAVING
#
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (2, 1), (3, 2);
EXPLAIN FORMAT=JSON SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a + b = 3;
EXPLAIN
{
"query_block": {
"select_id": 1,
"having_condition": "t1.a = (subquery#2)",
"filesort": {
"sort_key": "t1.b",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100,
"attached_condition": "(subquery#2) + t1.b = 3"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100
}
}
}
]
}
}
}
}
SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a + b = 3;
a b
2 1
EXPLAIN FORMAT=JSON SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a > b;
EXPLAIN
{
"query_block": {
"select_id": 1,
"having_condition": "t1.a = (subquery#2)",
"filesort": {
"sort_key": "t1.b",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100,
"attached_condition": "(subquery#2) > t1.b"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100
}
}
}
]
}
}
}
}
SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a > b;
a b
2 1
DROP TABLE t1;
End of 10.5 tests
......@@ -1562,4 +1562,30 @@ SELECT * FROM v1
DROP VIEW v1;
--echo #
--echo # MDEV-32608: Expression with constant subquery causes a crash
--echo # in pushdown from HAVING
--echo #
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (2, 1), (3, 2);
let $q=
SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a + b = 3;
eval EXPLAIN FORMAT=JSON $q;
eval $q;
let $q=
SELECT * FROM t1
GROUP BY b
HAVING (SELECT MAX(b) FROM t1) = a AND a > b;
eval EXPLAIN FORMAT=JSON $q;
eval $q;
DROP TABLE t1;
--echo End of 10.5 tests
--source include/not_msan.inc
--source include/not_valgrind_build.inc
--source include/not_valgrind.inc
--echo # MDEV-20699 do not cache SP in SHOW CREATE
--echo # Warmup round, this might allocate some memory for session variable
......
This diff is collapsed.
set @save_optimizer_switch=@@optimizer_switch;
create table t1 (a int);
create table t2 (b int);
insert into t1 values (null), (1), (2), (3);
insert into t2 values (3), (4);
set @@optimizer_switch = "materialization=on,in_to_exists=off,semijoin=off";
explain format=json select * from t1 where a in (select b from t2);
--echo # "Complete match" execution strategy
--source include/analyze-format.inc
analyze format=json select * from t1 where a in (select b from t2);
--echo # "Partial match" is used due to NOT IN
--echo # Force rowid-merge partial partial matching
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
--source include/analyze-format.inc
analyze format=json select * from t1 where a not in (select b from t2);
--echo # Force table scan partial matching
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=on";
--source include/analyze-format.inc
analyze format=json select * from t1 where a not in (select b from t2);
--echo # Subselect in GROUP BY
--source include/analyze-format.inc
analyze format=json select a from t1 group by a in (select b from t2);
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
--source include/analyze-format.inc
analyze format=json select a from t1 group by a not in (select b from t2);
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=on";
--echo # Subselect in ORDER BY
--source include/analyze-format.inc
analyze format=json select a from t1 order by a in (select b from t2);
--echo # Subselect in HAVING
--source include/analyze-format.inc
analyze format=json select a from t1 having a not in (select b from t2);
--echo # Nested IN
--source include/analyze-format.inc
analyze format=json select a from t1 where a in (select a from t1 where a in (select b from t2));
create table t3 (c int);
insert into t3 (c) values (3), (null), (4);
--echo # Subquery in ON-clause of outer join
--source include/analyze-format.inc
analyze format=json select a from t1 left join t2 on a not in (select c from t3);
--source include/analyze-format.inc
analyze format=json
select (b, b + 1, b + 2) not in
(select count(distinct a), a + 1, a + 2 from t1 group by a + 1, a + 2)
from t2;
drop table t1, t2, t3;
--echo #
--echo # Tables with more than one column
--echo #
create table t1 (a1 char(1), a2 char(1));
insert into t1 values (null, 'b');
create table t2 (b1 char(1), b2 char(2));
insert into t2 values ('a','b'), ('c', 'd'), (null, 'e'), ('f', 'g');
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
explain format=json select * from t1 where (a1, a2) not in (select b1, b2 from t2);
--source include/analyze-format.inc
analyze format=json select * from t1 where (a1, a2) not in (select b1, b2 from t2);
set @@optimizer_switch="partial_match_rowid_merge=off,partial_match_table_scan=on";
--source include/analyze-format.inc
analyze format=json select * from t1 where (a1, a2) not in (select b1, b2 from t2);
--echo # Subquery in SELECT list
explain format=json select t1.*, (a1, a2) in (select * from t2) as in_res from t1;
--source include/analyze-format.inc
analyze format=json select t1.*, (a1, a2) in (select * from t2) as in_res from t1;
--source include/analyze-format.inc
analyze format=json select t1.*, (a1, a2) not in (select * from t2) as in_res from t1;
set @@optimizer_switch="partial_match_rowid_merge=on,partial_match_table_scan=off";
--source include/analyze-format.inc
analyze format=json select t1.*, (a1, a2) in (select * from t2) as in_res from t1;
--source include/analyze-format.inc
analyze format=json select t1.*, (a1, a2) not in (select * from t2) as in_res from t1;
drop table t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
#
# MDEV-34542 Assertion `lock_trx_has_sys_table_locks(trx) == __null'
# failed in void row_mysql_unfreeze_data_dictionary(trx_t*)
#
#
CREATE TABLE t1 (c1 CHAR(1) ,c2 INT) ENGINE=INNODB
PARTITION BY LINEAR HASH ((c2)) PARTITIONS 512;
CREATE TABLE t2 (a INT) ENGINE=INNODB;
set @old_table_open_cache= @@table_open_cache;
XA START 'a';
INSERT INTO mysql.innodb_index_stats SELECT * FROM mysql.innodb_index_stats WHERE table_name='';
SET GLOBAL table_open_cache=10;
INSERT into t2 (a) VALUES (1);
SELECT * FROM t1;
c1 c2
XA END 'a';
XA PREPARE 'a';
SELECT sleep(3);
sleep(3)
0
XA ROLLBACK 'a';
DROP TABLE t1, t2;
SET GLOBAL table_open_cache=@old_table_open_cache;
--source include/have_innodb.inc
--source include/have_partition.inc
--echo #
--echo # MDEV-34542 Assertion `lock_trx_has_sys_table_locks(trx) == __null'
--echo # failed in void row_mysql_unfreeze_data_dictionary(trx_t*)
--echo #
--echo #
CREATE TABLE t1 (c1 CHAR(1) ,c2 INT) ENGINE=INNODB
PARTITION BY LINEAR HASH ((c2)) PARTITIONS 512;
CREATE TABLE t2 (a INT) ENGINE=INNODB;
set @old_table_open_cache= @@table_open_cache;
XA START 'a';
INSERT INTO mysql.innodb_index_stats SELECT * FROM mysql.innodb_index_stats WHERE table_name='';
SET GLOBAL table_open_cache=10;
INSERT into t2 (a) VALUES (1);
SELECT * FROM t1;
XA END 'a';
XA PREPARE 'a';
# Added sleep to make sure that InnoDB main thread is to remove
# the innodb_index_stats from table cache
SELECT sleep(3);
XA ROLLBACK 'a';
DROP TABLE t1, t2;
SET GLOBAL table_open_cache=@old_table_open_cache;
......@@ -1164,6 +1164,84 @@ include/sync_with_master_gtid.inc
connection server_1;
set @@binlog_format = @sav_binlog_format;
set @@global.binlog_format = @sav_binlog_format;
#
# MDEV-33921.1: If a slave's replication of an XA transaction results in
# an empty transaction, e.g. due to replication filters, the slave
# should not binlog any part of the XA transaction.
connection server_1;
create database db1;
create database db2;
create table db1.t1 (a int) engine=innodb;
include/save_master_gtid.inc
connection server_3;
include/sync_with_master_gtid.inc
include/stop_slave.inc
connection server_2;
include/stop_slave.inc
SET @@GLOBAL.replicate_ignore_db= "";
SET @@GLOBAL.replicate_do_db= "db2";
include/start_slave.inc
connection server_1;
use db1;
XA START "x1";
insert into db1.t1 values (1);
XA END "x1";
XA PREPARE "x1";
XA COMMIT "x1";
include/save_master_gtid.inc
connection server_2;
include/sync_with_master_gtid.inc
connection server_2;
include/save_master_gtid.inc
connection server_3;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# 33921.2: If the slave shuts down after "preparing" a filtered-to-empty
# XA transaction (and not completing it), then when the respective
# XA completion (COMMIT in this test) command is replicated, the slave
# should not throw ER_XAER_NOTA. Note that internally, the error is
# thrown, but it is ignored because the target db is filtered.
connection server_3;
include/stop_slave.inc
connection server_1;
use db1;
XA START "x2";
insert into db1.t1 values (2);
XA END "x2";
XA PREPARE "x2";
include/save_master_gtid.inc
connection server_2;
include/sync_with_master_gtid.inc
# Connection named slave is needed for reconnection
connect slave,localhost,root,,;
connect slave1,localhost,root,,;
include/rpl_restart_server.inc [server_number=2]
connection server_2;
include/stop_slave.inc
SET @@GLOBAL.replicate_do_db= "db2";
include/start_slave.inc
connection server_1;
XA COMMIT "x2";
connection server_2;
include/sync_with_master_gtid.inc
include/save_master_gtid.inc
connection server_3;
include/start_slave.inc
include/sync_with_master_gtid.inc
#
# 33921.3: Ensure XA commands are not considered by mysqlbinlog's
# --database filter
connection server_1;
# MYSQL_BINLOG datadir/binlog_file --start-position=pre_xa_pos --database=db2 --result-file=assert_file
include/assert_grep.inc [Mysqlbinlog should output all XA commands from the filtered transaction]
connection server_2;
include/stop_slave.inc
SET @@GLOBAL.replicate_do_db="";
include/start_slave.inc
connection server_1;
drop database db1;
drop database db2;
connection server_1;
include/rpl_end.inc
# End of rpl_xa_empty_transaction.test
......@@ -55,9 +55,7 @@ SET sql_log_bin=1;
# Restart the slave mysqld server, and verify that the GTID position is
# read correctly from the new mysql.gtid_slave_pos_innodb table.
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
--shutdown_server
--source include/wait_until_disconnected.inc
......@@ -94,9 +92,7 @@ DROP TABLE mysql.gtid_slave_pos;
RENAME TABLE mysql.gtid_slave_pos_innodb TO mysql.gtid_slave_pos;
SET sql_log_bin=1;
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
--shutdown_server
--source include/wait_until_disconnected.inc
......@@ -132,9 +128,7 @@ SET sql_log_bin=0;
ALTER TABLE mysql.gtid_slave_pos ENGINE=Aria;
SET sql_log_bin=1;
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
--shutdown_server
--source include/wait_until_disconnected.inc
......@@ -176,9 +170,7 @@ INSERT INTO mysql.gtid_slave_pos SELECT * FROM mysql.gtid_slave_pos_InnoDB;
DROP TABLE mysql.gtid_slave_pos_InnoDB;
SET sql_log_bin=1;
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--write_line "wait" $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
--shutdown_server
--source include/wait_until_disconnected.inc
......@@ -272,9 +264,7 @@ while (!$done)
# MDEV-15373 engine gtid_slave_pos table name disobeys lower-case-table-names
# This snippet verifies that engine gtid_slave_pos table is found,
# its data are up-to-date.
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--write_line wait $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
--connection server_2
--shutdown_server
--source include/wait_until_disconnected.inc
......
......@@ -32,6 +32,10 @@
# MDEV-25616: Binlog event for XA COMMIT is generated without matching
# XA START, replication aborts
#
# MDEV-33921: Replication fails when XA transactions are used where the slave
# has replicate_do_db set and the client has touched a different
# database when running DML such as inserts.
#
--source include/have_log_bin.inc
--let $rpl_server_count= 3
......@@ -167,6 +171,129 @@ set @@global.binlog_format = row;
set @@binlog_format = @sav_binlog_format;
set @@global.binlog_format = @sav_binlog_format;
--echo #
--echo # MDEV-33921.1: If a slave's replication of an XA transaction results in
--echo # an empty transaction, e.g. due to replication filters, the slave
--echo # should not binlog any part of the XA transaction.
#
# Note that the MDEV-33921 report is actually about that XA END is filtered
# out (not executed), and then its corresponding XA PREPARE errors because the
# XA state of the transaction is incorrect. This test case inherently tests
# both bugs.
--connection server_1
create database db1;
create database db2;
create table db1.t1 (a int) engine=innodb;
--source include/save_master_gtid.inc
--connection server_3
--source include/sync_with_master_gtid.inc
--source include/stop_slave.inc
--connection server_2
--source include/stop_slave.inc
SET @@GLOBAL.replicate_ignore_db= "";
SET @@GLOBAL.replicate_do_db= "db2";
--source include/start_slave.inc
--connection server_1
--let $pre_xa_gtid= `SELECT @@global.gtid_binlog_pos`
use db1;
XA START "x1";
insert into db1.t1 values (1);
XA END "x1";
XA PREPARE "x1";
XA COMMIT "x1";
--source include/save_master_gtid.inc
--connection server_2
--source include/sync_with_master_gtid.inc
--let $slave_binlogged_gtid= `SELECT @@global.gtid_binlog_pos`
if (`SELECT strcmp("$slave_binlogged_gtid","$pre_xa_gtid")`)
{
--die Slave binlogged an empty XA transaction yet should not have
}
--connection server_2
--source include/save_master_gtid.inc
--connection server_3
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # 33921.2: If the slave shuts down after "preparing" a filtered-to-empty
--echo # XA transaction (and not completing it), then when the respective
--echo # XA completion (COMMIT in this test) command is replicated, the slave
--echo # should not throw ER_XAER_NOTA. Note that internally, the error is
--echo # thrown, but it is ignored because the target db is filtered.
--connection server_3
--source include/stop_slave.inc
--connection server_1
--let $pre_xa_gtid= `SELECT @@global.gtid_binlog_pos`
# Used by mysqlbinlog in part 3
--let $pre_xa_pos = query_get_value(SHOW MASTER STATUS, Position, 1)
use db1;
XA START "x2";
insert into db1.t1 values (2);
XA END "x2";
XA PREPARE "x2";
--source include/save_master_gtid.inc
--connection server_2
--source include/sync_with_master_gtid.inc
--let $rpl_server_number= 2
--echo # Connection named slave is needed for reconnection
--connect(slave,localhost,root,,)
--connect(slave1,localhost,root,,)
--source include/rpl_restart_server.inc
--connection server_2
--source include/stop_slave.inc
SET @@GLOBAL.replicate_do_db= "db2";
--source include/start_slave.inc
--connection server_1
XA COMMIT "x2";
--connection server_2
--source include/sync_with_master_gtid.inc
--source include/save_master_gtid.inc
--connection server_3
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
--echo #
--echo # 33921.3: Ensure XA commands are not considered by mysqlbinlog's
--echo # --database filter
--connection server_1
--let $datadir= `select @@datadir`
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let assert_file= $MYSQLTEST_VARDIR/tmp/binlog_decoded.out
--echo # MYSQL_BINLOG datadir/binlog_file --start-position=pre_xa_pos --database=db2 --result-file=assert_file
--exec $MYSQL_BINLOG $datadir/$binlog_file --start-position=$pre_xa_pos --database=db2 --result-file=$assert_file
--let assert_text= Mysqlbinlog should output all XA commands from the filtered transaction
--let assert_count= 4
--let assert_select= XA START|XA END|XA PREPARE|XA COMMIT
--source include/assert_grep.inc
--connection server_2
--source include/stop_slave.inc
SET @@GLOBAL.replicate_do_db="";
--source include/start_slave.inc
--connection server_1
drop database db1;
drop database db2;
#
# Cleanup
--connection server_1
......
......@@ -42,7 +42,7 @@ class Item_func_sysconst_test :public Item_func_sysconst
}
const char *fully_qualified_func_name() const override
{ return "sysconst_test()"; }
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_sysconst_test>(thd, this); }
};
......
......@@ -45,7 +45,7 @@ class Item_func_inet_aton : public Item_longlong_func
unsigned_flag= 1;
return FALSE;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_inet_aton>(thd, this); }
};
......@@ -72,7 +72,7 @@ class Item_func_inet_ntoa : public Item_str_func
set_maybe_null();
return FALSE;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_inet_ntoa>(thd, this); }
};
......@@ -118,7 +118,7 @@ class Item_func_inet6_aton : public Item_str_func
set_maybe_null();
return FALSE;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_inet6_aton>(thd, this); }
String *val_str(String *to) override;
......@@ -156,7 +156,7 @@ class Item_func_inet6_ntoa : public Item_str_ascii_func
return FALSE;
}
String *val_str_ascii(String *to) override;
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_inet6_ntoa>(thd, this); }
};
......@@ -178,7 +178,7 @@ class Item_func_is_ipv4 : public Item_func_inet_bool_base
static LEX_CSTRING name= {STRING_WITH_LEN("is_ipv4") };
return name;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_is_ipv4>(thd, this); }
longlong val_int() override;
......@@ -201,7 +201,7 @@ class Item_func_is_ipv6 : public Item_func_inet_bool_base
static LEX_CSTRING name= {STRING_WITH_LEN("is_ipv6") };
return name;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_is_ipv6>(thd, this); }
longlong val_int() override;
......@@ -223,7 +223,7 @@ class Item_func_is_ipv4_compat : public Item_func_inet_bool_base
static LEX_CSTRING name= {STRING_WITH_LEN("is_ipv4_compat") };
return name;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_is_ipv4_compat>(thd, this); }
longlong val_int() override;
};
......@@ -244,7 +244,7 @@ class Item_func_is_ipv4_mapped : public Item_func_inet_bool_base
static LEX_CSTRING name= {STRING_WITH_LEN("is_ipv4_mapped") };
return name;
}
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_is_ipv4_mapped>(thd, this); }
longlong val_int() override;
};
......
......@@ -1523,6 +1523,22 @@ int ha_prepare(THD *thd)
error=1;
}
}
else if (thd->rgi_slave)
{
/*
Slave threads will always process XA COMMITs in the binlog handler (see
MDEV-25616 and MDEV-30423), so if this is a slave thread preparing a
transaction which proved empty during replication (e.g. because of
replication filters) then mark it as XA_ROLLBACK_ONLY so the follow up
XA COMMIT will know to roll it back, rather than try to commit and binlog
a standalone XA COMMIT (without its preceding XA START - XA PREPARE).
If the xid_cache is cleared before the completion event comes, before
issuing ER_XAER_NOTA, first check if the event targets an ignored
database, and ignore the error if so.
*/
thd->transaction->xid_state.set_rollback_only();
}
DBUG_RETURN(error);
}
......
......@@ -1284,6 +1284,25 @@ bool Item::eq(const Item *item, bool binary_cmp) const
}
Item *Item::multiple_equality_transformer(THD *thd, uchar *arg)
{
if (const_item())
{
/*
Mark constant item in the condition with the MARKER_IMMUTABLE flag.
It is needed to prevent cleanup of the sub-items of this item and following
fix_fields() call that can cause a crash on this step of the optimization.
This flag will be removed at the end of the pushdown optimization by
remove_immutable_flag_processor processor.
*/
int new_flag= MARKER_IMMUTABLE;
this->walk(&Item::set_extraction_flag_processor, false,
(void*)&new_flag);
}
return this;
}
Item *Item::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
if (!needs_charset_converter(tocs))
......@@ -2753,7 +2772,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
@retval 0 on a failure
*/
Item* Item_func_or_sum::build_clone(THD *thd)
Item* Item_func_or_sum::do_build_clone(THD *thd) const
{
Item *copy_tmp_args[2]= {0,0};
Item **copy_args= copy_tmp_args;
......@@ -3073,7 +3092,7 @@ Item_sp::init_result_field(THD *thd, uint max_length, uint maybe_null,
0 if an error occurred
*/
Item* Item_ref::build_clone(THD *thd)
Item* Item_ref::do_build_clone(THD *thd) const
{
Item_ref *copy= (Item_ref *) get_copy(thd);
if (unlikely(!copy) ||
......@@ -3886,7 +3905,7 @@ void Item_decimal::set_decimal_value(my_decimal *value_par)
}
Item *Item_decimal::clone_item(THD *thd)
Item *Item_decimal::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_decimal(thd, name.str, &decimal_value, decimals,
max_length);
......@@ -3907,7 +3926,7 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
}
Item *Item_float::clone_item(THD *thd)
Item *Item_float::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_float(thd, name.str, value, decimals,
max_length);
......@@ -4071,7 +4090,7 @@ Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
return this;
}
Item *Item_null::clone_item(THD *thd)
Item *Item_null::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_null(thd, name.str);
}
......@@ -4877,7 +4896,7 @@ bool Item_param::basic_const_item() const
}
Item *Item_param::value_clone_item(THD *thd)
Item *Item_param::value_clone_item(THD *thd) const
{
MEM_ROOT *mem_root= thd->mem_root;
switch (value.type_handler()->cmp_type()) {
......@@ -4891,12 +4910,15 @@ Item *Item_param::value_clone_item(THD *thd)
case DECIMAL_RESULT:
return 0; // Should create Item_decimal. See MDEV-11361.
case STRING_RESULT:
{
String value_copy = value.m_string; // to preserve constness of the func
return new (mem_root) Item_string(thd, name,
Lex_cstring(value.m_string.ptr(),
value.m_string.length()),
value.m_string.charset(),
Lex_cstring(value_copy.ptr(),
value_copy.length()),
value_copy.charset(),
collation.derivation,
collation.repertoire);
}
case TIME_RESULT:
break;
case ROW_RESULT:
......@@ -4910,7 +4932,7 @@ Item *Item_param::value_clone_item(THD *thd)
/* see comments in the header file */
Item *
Item_param::clone_item(THD *thd)
Item_param::do_clone_const_item(THD *thd) const
{
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
......@@ -7000,7 +7022,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
}
Item *Item_string::clone_item(THD *thd)
Item *Item_string::do_clone_const_item(THD *thd) const
{
LEX_CSTRING val;
str_value.get_value(&val);
......@@ -7064,7 +7086,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
}
Item *Item_int::clone_item(THD *thd)
Item *Item_int::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag);
}
......@@ -7093,7 +7115,7 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions)
}
Item *Item_int_with_ref::clone_item(THD *thd)
Item *Item_int_with_ref::do_clone_const_item(THD *thd) const
{
DBUG_ASSERT(ref->const_item());
/*
......@@ -7189,7 +7211,7 @@ Item *Item_uint::neg(THD *thd)
}
Item *Item_uint::clone_item(THD *thd)
Item *Item_uint::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_uint(thd, name.str, value, max_length);
}
......@@ -7429,7 +7451,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type)
}
Item *Item_date_literal::clone_item(THD *thd)
Item *Item_date_literal::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_date_literal(thd, &cached_time);
}
......@@ -7454,7 +7476,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type)
}
Item *Item_datetime_literal::clone_item(THD *thd)
Item *Item_datetime_literal::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals);
}
......@@ -7479,7 +7501,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type)
}
Item *Item_time_literal::clone_item(THD *thd)
Item *Item_time_literal::do_clone_const_item(THD *thd) const
{
return new (thd->mem_root) Item_time_literal(thd, &cached_time, decimals);
}
......@@ -10435,7 +10457,7 @@ void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg)
}
Item *Item_cache_temporal::clone_item(THD *thd)
Item *Item_cache_temporal::do_clone_const_item(THD *thd) const
{
Item_cache *tmp= type_handler()->Item_get_cache(thd, this);
Item_cache_temporal *item= static_cast<Item_cache_temporal*>(tmp);
......
This diff is collapsed.
......@@ -5546,17 +5546,16 @@ void Item_cond::neg_arguments(THD *thd)
0 if an error occurred
*/
Item *Item_cond::build_clone(THD *thd)
Item *Item_cond::do_build_clone(THD *thd) const
{
List_iterator_fast<Item> li(list);
Item *item;
Item_cond *copy= (Item_cond *) get_copy(thd);
if (!copy)
return 0;
copy->list.empty();
while ((item= li++))
for (const Item &item : list)
{
Item *arg_clone= item->build_clone(thd);
Item *arg_clone= item.build_clone(thd);
if (!arg_clone)
return 0;
if (copy->list.push_back(arg_clone, thd->mem_root))
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -180,7 +180,7 @@ void Item_row::bring_value()
}
Item* Item_row::build_clone(THD *thd)
Item* Item_row::do_build_clone(THD *thd) const
{
Item **copy_args= static_cast<Item**>
(alloc_root(thd->mem_root, sizeof(Item*) * arg_count));
......
......@@ -148,9 +148,9 @@ class Item_row: public Item_fixed_hybrid,
}
bool check_vcol_func_processor(void *arg) override {return FALSE; }
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_row>(thd, this); }
Item *build_clone(THD *thd) override;
Item *do_build_clone(THD *thd) const override;
};
#endif /* ITEM_ROW_INCLUDED */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -49,7 +49,7 @@ class Item_func_history: public Item_bool_func
return name;
}
void print(String *str, enum_query_type query_type) override;
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_history>(thd, this); }
};
......@@ -65,7 +65,7 @@ class Item_func_trt_ts: public Item_datetimefunc
return (trt_field == TR_table::FLD_BEGIN_TS) ? begin_name : commit_name;
}
bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override;
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_trt_ts>(thd, this); }
bool fix_length_and_dec() override
{ fix_attributes_datetime(decimals); return FALSE; }
......@@ -110,7 +110,7 @@ class Item_func_trt_id : public Item_longlong_func
}
longlong val_int() override;
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_trt_id>(thd, this); }
};
......@@ -127,7 +127,7 @@ class Item_func_trt_trx_sees : public Item_bool_func
return name;
}
longlong val_int() override;
Item *get_copy(THD *thd) override
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_trt_trx_sees>(thd, this); }
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -56,6 +56,7 @@ class Rpl_filter
bool db_ok_with_wild_table(const char *db);
bool is_on();
bool is_db_empty();
/* Setters - add filtering rules */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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