Merge branch '10.2' into 10.3

This commit is contained in:
Sergei Golubchik 2022-05-07 11:48:15 +02:00
commit 6f741eb6e4
31 changed files with 649 additions and 113 deletions

View File

@ -11,6 +11,11 @@ MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
# do it himself. No database directories should be removed while the server
# is running!
stop_server() {
# Return immediately if there are no mysql processes running
# as there is no point in trying to shutdown in that case.
# Compatibility with versions that ran 'mariadbd'
if ! pgrep -x --nslist pid --ns $$ "mysqld|mariadbd" > /dev/null; then return; fi
set +e
if [ -x /usr/sbin/invoke-rc.d ]; then
invoke-rc.d mysql stop

View File

@ -22,10 +22,11 @@ mysql_upgradedir=/var/lib/mysql-upgrade
# is running! Another mysqld in e.g. a different chroot is fine for us.
stop_server() {
if [ ! -x /etc/init.d/mysql ]; then return; fi
# Return immediately if there are no mysql processes running
# Return immediately if there are no mysql processes running on a host
# (leave containerized processes with the same name in other namespaces)
# as there is no point in trying to shutdown in that case.
if ! pgrep --ns $$ mysqld > /dev/null; then return; fi
# Compatibility with versions that ran 'mariadbd'
if ! pgrep -x --nslist pid --ns $$ "mysqld|mariadbd" > /dev/null; then return; fi
set +e
if [ -x /usr/sbin/invoke-rc.d ]; then

View File

@ -3406,6 +3406,24 @@ SELECT 1 FROM t1 GROUP BY DEFAULT(pk);
1
1
DROP TABLE t1;
#
# MDEV-28402: ASAN heap-use-after-free in create_tmp_table,
# Assertion `l_offset >= 0 && table->s->rec_buff_length - l_offset > 0'
#
CREATE TABLE t (a INT, KEY (a));
INSERT INTO t VALUES (1),(2);
SELECT DISTINCT DEFAULT(a), CASE a WHEN 0 THEN 1 ELSE 2 END FROM t GROUP BY a WITH ROLLUP;
DEFAULT(a) CASE a WHEN 0 THEN 1 ELSE 2 END
NULL 2
DROP TABLE t;
CREATE TABLE t (a INT, KEY (a));
INSERT INTO t VALUES (1),(2);
CREATE ALGORITHM=TEMPTABLE VIEW v AS SELECT * FROM t;
SELECT DISTINCT DEFAULT(a), CASE a WHEN 0 THEN 1 ELSE 2 END FROM v GROUP BY a WITH ROLLUP;
DEFAULT(a) CASE a WHEN 0 THEN 1 ELSE 2 END
NULL 2
DROP TABLE t;
DROP VIEW v;
# end of 10.2 test
#
# MDEV-22703 DEFAULT() on a BLOB column can overwrite the default

View File

@ -2125,6 +2125,23 @@ CREATE TABLE t1 (pk varchar(36) DEFAULT uuid());
INSERT INTO t1 VALUES (),();
SELECT 1 FROM t1 GROUP BY DEFAULT(pk);
DROP TABLE t1;
--echo #
--echo # MDEV-28402: ASAN heap-use-after-free in create_tmp_table,
--echo # Assertion `l_offset >= 0 && table->s->rec_buff_length - l_offset > 0'
--echo #
CREATE TABLE t (a INT, KEY (a));
INSERT INTO t VALUES (1),(2);
SELECT DISTINCT DEFAULT(a), CASE a WHEN 0 THEN 1 ELSE 2 END FROM t GROUP BY a WITH ROLLUP;
DROP TABLE t;
CREATE TABLE t (a INT, KEY (a));
INSERT INTO t VALUES (1),(2);
CREATE ALGORITHM=TEMPTABLE VIEW v AS SELECT * FROM t;
SELECT DISTINCT DEFAULT(a), CASE a WHEN 0 THEN 1 ELSE 2 END FROM v GROUP BY a WITH ROLLUP;
DROP TABLE t;
DROP VIEW v;
--echo # end of 10.2 test
--echo #

View File

@ -661,3 +661,14 @@ group by (select a),(select 1)
);
1
drop table t1;
#
# MDEV-28437: Assertion `!eliminated' failed in Item_subselect::exec
#
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (b INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (3),(4);
SELECT 1 IN (SELECT a FROM t1 LEFT JOIN t2 ON (a = b AND EXISTS (SELECT * FROM t1)));
1 IN (SELECT a FROM t1 LEFT JOIN t2 ON (a = b AND EXISTS (SELECT * FROM t1)))
1
drop table t1,t2;

View File

@ -655,3 +655,17 @@ select 1 from t1 where not exists
--enable_warnings
drop table t1;
--echo #
--echo # MDEV-28437: Assertion `!eliminated' failed in Item_subselect::exec
--echo #
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (b INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (3),(4);
SELECT 1 IN (SELECT a FROM t1 LEFT JOIN t2 ON (a = b AND EXISTS (SELECT * FROM t1)));
drop table t1,t2;
# End of 10.2 tests

View File

@ -4238,6 +4238,48 @@ SELECT 1 UNION SELECT a FROM t1 ORDER BY (row_number() over ());
ERROR HY000: Expression #1 of ORDER BY contains aggregate function and applies to a UNION
DROP TABLE t1;
#
# MDEV-19398: Assertion `item1->type() == Item::FIELD_ITEM &&
# item2->type() == Item::FIELD_ITEM' failed in compare_order_elements
#
CREATE TABLE t1 ( id varchar(10));
INSERT INTO t1 values (1),(2),(3);
SELECT
dense_rank() over (ORDER BY avg(1)+3),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
dense_rank() over (ORDER BY avg(1)+3) rank() over (ORDER BY avg(1))
1 1
1 1
1 1
SELECT
dense_rank() over (ORDER BY avg(1)),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
dense_rank() over (ORDER BY avg(1)) rank() over (ORDER BY avg(1))
1 1
1 1
1 1
drop table t1;
CREATE TABLE t1 ( a char(25), b text);
INSERT INTO t1 VALUES ('foo','bar');
SELECT
SUM(b) OVER (PARTITION BY a),
ROW_NUMBER() OVER (PARTITION BY b)
FROM t1
GROUP BY
LEFT((SYSDATE()), 'foo')
WITH ROLLUP;
SUM(b) OVER (PARTITION BY a) ROW_NUMBER() OVER (PARTITION BY b)
NULL 1
NULL 1
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'foo'
Warning 1292 Truncated incorrect INTEGER value: 'foo'
drop table t1;
#
#
# End of 10.2 tests
#
#

View File

@ -2740,6 +2740,39 @@ INSERT INTO t1 VALUES (1),(1),(1),(1),(1),(2),(2),(2),(2),(2),(2);
SELECT 1 UNION SELECT a FROM t1 ORDER BY (row_number() over ());
DROP TABLE t1;
--echo #
--echo # MDEV-19398: Assertion `item1->type() == Item::FIELD_ITEM &&
--echo # item2->type() == Item::FIELD_ITEM' failed in compare_order_elements
--echo #
CREATE TABLE t1 ( id varchar(10));
INSERT INTO t1 values (1),(2),(3);
SELECT
dense_rank() over (ORDER BY avg(1)+3),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
SELECT
dense_rank() over (ORDER BY avg(1)),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
drop table t1;
CREATE TABLE t1 ( a char(25), b text);
INSERT INTO t1 VALUES ('foo','bar');
SELECT
SUM(b) OVER (PARTITION BY a),
ROW_NUMBER() OVER (PARTITION BY b)
FROM t1
GROUP BY
LEFT((SYSDATE()), 'foo')
WITH ROLLUP;
drop table t1;
--echo #
--echo #
--echo # End of 10.2 tests
--echo #

View File

@ -4244,6 +4244,48 @@ SELECT 1 UNION SELECT a FROM t1 ORDER BY (row_number() over ());
ERROR HY000: Expression #1 of ORDER BY contains aggregate function and applies to a UNION
DROP TABLE t1;
#
# MDEV-19398: Assertion `item1->type() == Item::FIELD_ITEM &&
# item2->type() == Item::FIELD_ITEM' failed in compare_order_elements
#
CREATE TABLE t1 ( id varchar(10));
INSERT INTO t1 values (1),(2),(3);
SELECT
dense_rank() over (ORDER BY avg(1)+3),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
dense_rank() over (ORDER BY avg(1)+3) rank() over (ORDER BY avg(1))
1 1
1 1
1 1
SELECT
dense_rank() over (ORDER BY avg(1)),
rank() over (ORDER BY avg(1))
FROM t1
GROUP BY nullif(id, 15532);
dense_rank() over (ORDER BY avg(1)) rank() over (ORDER BY avg(1))
1 1
1 1
1 1
drop table t1;
CREATE TABLE t1 ( a char(25), b text);
INSERT INTO t1 VALUES ('foo','bar');
SELECT
SUM(b) OVER (PARTITION BY a),
ROW_NUMBER() OVER (PARTITION BY b)
FROM t1
GROUP BY
LEFT((SYSDATE()), 'foo')
WITH ROLLUP;
SUM(b) OVER (PARTITION BY a) ROW_NUMBER() OVER (PARTITION BY b)
NULL 1
NULL 1
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'foo'
Warning 1292 Truncated incorrect INTEGER value: 'foo'
drop table t1;
#
#
# End of 10.2 tests
#
#

View File

@ -61,10 +61,3 @@ select count(*) from t1 where MBRWithin(t1.c2, @g1);
count(*)
57344
drop table t1;
#
# MDEV-27417 Spatial index tries to update
# change buffer bookkeeping page
#
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL, SPATIAL(c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT PointFromText('POINT(0 0)') FROM seq_1_to_366;
DROP TABLE t1;

View File

@ -0,0 +1,14 @@
#
# MDEV-27417 Spatial index tries to update
# change buffer bookkeeping page
#
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL, SPATIAL(c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT PointFromText('POINT(0 0)') FROM seq_1_to_366;
DROP TABLE t1;
#
# MDEV-28478 Assertion mtr->get_log_mode() == MTR_LOG_NO_REDO
#
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL,SPATIAL (c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT POINT(0,0) FROM seq_1_to_366;
INSERT INTO t1 VALUES (POINT(1e-270,1e-130));
DROP TABLE t1;

View File

@ -72,11 +72,3 @@ select count(*) from t1 where MBRWithin(t1.c2, @g1);
# Clean up.
drop table t1;
--echo #
--echo # MDEV-27417 Spatial index tries to update
--echo # change buffer bookkeeping page
--echo #
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL, SPATIAL(c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT PointFromText('POINT(0 0)') FROM seq_1_to_366;
DROP TABLE t1;

View File

@ -0,0 +1,18 @@
--source include/have_innodb.inc
--source include/have_sequence.inc
--echo #
--echo # MDEV-27417 Spatial index tries to update
--echo # change buffer bookkeeping page
--echo #
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL, SPATIAL(c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT PointFromText('POINT(0 0)') FROM seq_1_to_366;
DROP TABLE t1;
--echo #
--echo # MDEV-28478 Assertion mtr->get_log_mode() == MTR_LOG_NO_REDO
--echo #
CREATE TEMPORARY TABLE t1 (c POINT NOT NULL,SPATIAL (c)) ENGINE=InnoDB;
INSERT INTO t1 SELECT POINT(0,0) FROM seq_1_to_366;
INSERT INTO t1 VALUES (POINT(1e-270,1e-130));
DROP TABLE t1;

View File

@ -0,0 +1,27 @@
--- r/rpl_iodku.result 2022-05-04 18:51:24.956414404 +0300
+++ r/rpl_iodku,stmt.reject 2022-05-04 18:51:49.520106231 +0300
@@ -1,10 +1,15 @@
include/master-slave.inc
[connection master]
+call mtr.add_suppression("Unsafe statement written to the binary log using statement");
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT, c INT,
UNIQUE (a), UNIQUE (b)) ENGINE=innodb;
INSERT INTO t1 (`a`,`c`) VALUES (1,1), (2,1) ON DUPLICATE KEY UPDATE c = 1;
+Warnings:
+Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
# UNSAFE
INSERT INTO t1 (`a`,`c`) VALUES (3, 1),(2,1), (1,1) ON DUPLICATE KEY UPDATE c = a * 10 + VALUES(c);
+Warnings:
+Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
SELECT * from t1;
id a b c
1 1 NULL 11
@@ -17,6 +22,8 @@
INSERT INTO t1 VALUES (1,10,1);
# eligable for the statement format run unsafe warning
INSERT INTO t1 VALUES (2,20,2) ON DUPLICATE KEY UPDATE c = 100;
+Warnings:
+Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
# not eligable: no warning in the statement format run
INSERT INTO t1 (`a`,`c`) VALUES (3, 1) ON DUPLICATE KEY UPDATE c = 99;
SELECT * from t1;

View File

@ -0,0 +1,32 @@
include/master-slave.inc
[connection master]
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT, c INT,
UNIQUE (a), UNIQUE (b)) ENGINE=innodb;
INSERT INTO t1 (`a`,`c`) VALUES (1,1), (2,1) ON DUPLICATE KEY UPDATE c = 1;
# UNSAFE
INSERT INTO t1 (`a`,`c`) VALUES (3, 1),(2,1), (1,1) ON DUPLICATE KEY UPDATE c = a * 10 + VALUES(c);
SELECT * from t1;
id a b c
1 1 NULL 11
2 2 NULL 21
3 3 NULL 1
connection slave;
include/diff_tables.inc [master:t1,slave:t1]
connection master;
CREATE OR REPLACE TABLE t1 (a INT, b INT, c INT, UNIQUE (a), UNIQUE (b)) ENGINE=innodb;
INSERT INTO t1 VALUES (1,10,1);
# eligable for the statement format run unsafe warning
INSERT INTO t1 VALUES (2,20,2) ON DUPLICATE KEY UPDATE c = 100;
# not eligable: no warning in the statement format run
INSERT INTO t1 (`a`,`c`) VALUES (3, 1) ON DUPLICATE KEY UPDATE c = 99;
SELECT * from t1;
a b c
1 10 1
2 20 2
3 NULL 1
connection slave;
include/diff_tables.inc [master:t1,slave:t1]
connection master;
DROP TABLE t1;
connection slave;
include/rpl_end.inc

View File

@ -1,5 +1,6 @@
include/master-slave.inc
[connection master]
# Case 1: UNSAFE
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY , b INT,
UNIQUE(b), c int) engine=innodb;
@ -37,6 +38,7 @@ drop table t1;
connection slave;
start slave;
include/wait_for_slave_to_start.inc
# Case 2: UNSAFE
connection master;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
UNIQUE(b), c int) engine=innodb;
@ -45,8 +47,12 @@ connection master;
INSERT INTO t1 VALUES (default, 1, 1);
BEGIN;
INSERT INTO t1 VALUES (default, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master1;
INSERT INTO t1 VALUES(default, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master;
COMMIT;
SELECT * FROM t1;
@ -62,6 +68,7 @@ a b c
connection master;
drop table t1;
connection slave;
# Case 3A: UNSAFE
connection master;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
@ -93,6 +100,67 @@ a b c d
connection master;
drop table t1;
connection slave;
# Case 3B: UNSAFE - all column specified.
connection master;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
connection slave;
connection master;
INSERT INTO t1 VALUES (1, 1, 1, 1);
BEGIN;
INSERT INTO t1 VALUES (2, NULL, 2, 2) ON DUPLICATE KEY UPDATE c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master1;
INSERT INTO t1 VALUES(3, NULL, 2, 3) ON DUPLICATE KEY UPDATE c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master;
COMMIT;
SELECT * FROM t1;
a b c d
1 1 1 1
2 NULL 2 2
3 NULL 2 3
connection slave;
#same data as master
SELECT * FROM t1;
a b c d
1 1 1 1
2 NULL 2 2
3 NULL 2 3
connection master;
drop table t1;
connection slave;
# Case 3C: SAFE - only one unique key (PK) specified.
connection master;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
connection slave;
connection master;
INSERT INTO t1 VALUES (1, 1, 1, 1);
BEGIN;
INSERT INTO t1 (`a`, `c`, `d`) VALUES (2, 2, 2) ON DUPLICATE KEY UPDATE c=99;
connection master1;
INSERT INTO t1 (`a`, `c`, `d`) VALUES(3, 2, 3) ON DUPLICATE KEY UPDATE c=100;
connection master;
COMMIT;
SELECT * FROM t1;
a b c d
1 1 1 1
2 NULL 2 2
3 NULL 2 3
connection slave;
#same data as master
SELECT * FROM t1;
a b c d
1 1 1 1
2 NULL 2 2
3 NULL 2 3
connection master;
drop table t1;
connection slave;
# Case 4: UNSAFE
connection master;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
UNIQUE(b), c int) engine=innodb;
@ -101,8 +169,12 @@ connection master;
INSERT INTO t1 VALUES (1, 1, 1);
BEGIN;
INSERT INTO t1 VALUES (2, 1, 2) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master1;
INSERT INTO t1 VALUES(2, 2, 3) ON DUPLICATE KEY UPDATE b=VALUES(b), c=VALUES(c);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
connection master;
COMMIT;
SELECT * FROM t1;

View File

@ -1,6 +1,5 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
CREATE TABLE t1(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE t2(id INT AUTO_INCREMENT, i INT, PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TRIGGER trig1 AFTER INSERT ON t1
@ -50,13 +49,9 @@ connection master;
DROP TABLE t1;
CREATE TABLE t1(i INT, j INT, UNIQUE KEY(i), UNIQUE KEY(j)) ENGINE=INNODB;
INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
START TRANSACTION;
LOCK TABLES t1 WRITE;
INSERT INTO t1 (i,j) VALUES (1,2) ON DUPLICATE KEY UPDATE j=j+1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe
UNLOCK TABLES;
COMMIT;
connection slave;

View File

@ -0,0 +1,50 @@
--source include/have_innodb.inc
--source include/master-slave.inc
if (`select @@binlog_format = "statement"`)
{
call mtr.add_suppression("Unsafe statement written to the binary log using statement");
}
## MDEV-28310 loss of binlog event for multi-record IODKU
# Check that the duplicate key error does not cause
# loss of replication event for IODKU that specifies values
# for at least two unique columns per record.
# "Implicit" NULL value of the auto-increment column also counts.
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT, a INT, b INT, c INT,
UNIQUE (a), UNIQUE (b)) ENGINE=innodb;
INSERT INTO t1 (`a`,`c`) VALUES (1,1), (2,1) ON DUPLICATE KEY UPDATE c = 1;
--echo # UNSAFE
# because of two keys involved: a UK and PK even though implicitly via auto-inc
INSERT INTO t1 (`a`,`c`) VALUES (3, 1),(2,1), (1,1) ON DUPLICATE KEY UPDATE c = a * 10 + VALUES(c);
SELECT * from t1;
--sync_slave_with_master
--let $diff_tables = master:t1,slave:t1
--source include/diff_tables.inc
## MDEV-21810 MBR: Unexpected "Unsafe statement" warning for unsafe IODKU
# Unnecessary unsafe statement warning is not error-logged anymore.
--connection master
CREATE OR REPLACE TABLE t1 (a INT, b INT, c INT, UNIQUE (a), UNIQUE (b)) ENGINE=innodb;
INSERT INTO t1 VALUES (1,10,1);
--echo # eligable for the statement format run unsafe warning
INSERT INTO t1 VALUES (2,20,2) ON DUPLICATE KEY UPDATE c = 100;
--echo # not eligable: no warning in the statement format run
INSERT INTO t1 (`a`,`c`) VALUES (3, 1) ON DUPLICATE KEY UPDATE c = 99;
SELECT * from t1;
--sync_slave_with_master
--let $diff_tables = master:t1,slave:t1
--source include/diff_tables.inc
# Cleanup
--connection master
DROP TABLE t1;
--sync_slave_with_master
--source include/rpl_end.inc

View File

@ -2,15 +2,22 @@ source include/have_debug.inc;
source include/have_innodb.inc;
-- source include/have_binlog_format_statement.inc
source include/master-slave.inc;
# MDEV-17614
# INSERT on dup key update is replication unsafe
# There can be three case
# 1. 2 unique key, Replication is unsafe.
# 2. 2 unique key , with one auto increment key, Safe to replicate because Innodb will acquire gap lock
# 3. n no of unique keys (n>1) but insert is only in 1 unique key
# 4. 2 unique key , with one auto increment key(but user gives auto inc value), unsafe to replicate
# MDEV-17614 INSERT on dup key update is replication unsafe
#
# The following cases are tested below:
# 1. 2 unique key, replication is UNSAFE
# 2. 2 unique key, with one auto increment key and implicit value to it.
# It is UNSAFE because autoinc column values of being inserted records
# are revealed dynamically, so unknown at the binlog-format decision time
# and hence this pessimistic expectation
# 3. 2 unique keys
# A. insert is only in 1 unique key, still all colums are specified => UNSAFE
# B. both unique keys are specified => UNSAFE
# C. only one unique key is specified => SAFE (motivated by MDEV-28310)
# 4. 2 unique key, with one auto increment key(but user gives auto inc value) =>
# UNSAFE to replicate
# Case 1
--echo # Case 1: UNSAFE
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY , b INT,
UNIQUE(b), c int) engine=innodb;
@ -42,7 +49,8 @@ drop table t1;
connection slave;
start slave;
--source include/wait_for_slave_to_start.inc
# Case 2
--echo # Case 2: UNSAFE
--connection master
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
UNIQUE(b), c int) engine=innodb;
@ -64,7 +72,7 @@ connection master;
drop table t1;
--sync_slave_with_master
# Case 3
--echo # Case 3A: UNSAFE
--connection master
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
@ -85,7 +93,50 @@ connection master;
drop table t1;
--sync_slave_with_master
# Case 4
--echo # Case 3B: UNSAFE - all column specified.
--connection master
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
sync_slave_with_master;
connection master;
INSERT INTO t1 VALUES (1, 1, 1, 1);
BEGIN;
INSERT INTO t1 VALUES (2, NULL, 2, 2) ON DUPLICATE KEY UPDATE c=VALUES(c);
--connection master1
INSERT INTO t1 VALUES(3, NULL, 2, 3) ON DUPLICATE KEY UPDATE c=VALUES(c);
--connection master
COMMIT;
SELECT * FROM t1;
--sync_slave_with_master
--echo #same data as master
SELECT * FROM t1;
connection master;
drop table t1;
--sync_slave_with_master
--echo # Case 3C: SAFE - only one unique key (PK) specified.
--connection master
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT,
UNIQUE(b), c int, d int ) engine=innodb;
sync_slave_with_master;
connection master;
INSERT INTO t1 VALUES (1, 1, 1, 1);
BEGIN;
INSERT INTO t1 (`a`, `c`, `d`) VALUES (2, 2, 2) ON DUPLICATE KEY UPDATE c=99;
--connection master1
INSERT INTO t1 (`a`, `c`, `d`) VALUES(3, 2, 3) ON DUPLICATE KEY UPDATE c=100;
--connection master
COMMIT;
SELECT * FROM t1;
--sync_slave_with_master
--echo #same data as master
SELECT * FROM t1;
connection master;
drop table t1;
--sync_slave_with_master
--echo # Case 4: UNSAFE
--connection master
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY auto_increment, b INT,
UNIQUE(b), c int) engine=innodb;

View File

@ -24,7 +24,7 @@
--source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc
--source include/master-slave.inc
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
# Case-1: BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS
# Statement is unsafe because it invokes a trigger or a
# stored function that inserts into an AUTO_INCREMENT column.

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2021, MariaDB Corporation.
Copyright (c) 2008, 2022, MariaDB Corporation.
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
@ -6558,47 +6558,84 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_RETURN(0);
}
int THD::decide_logging_format_low(TABLE *table)
/*
Reconsider logging format in case of INSERT...ON DUPLICATE KEY UPDATE
for tables with more than one unique keys in case of MIXED binlog format.
Unsafe means that a master could execute the statement differently than
the slave.
This could can happen in the following cases:
- The unique check are done in different order on master or slave
(different engine or different key order).
- There is a conflict on another key than the first and before the
statement is committed, another connection commits a row that conflicts
on an earlier unique key. Example follows:
Below a and b are unique keys, the table has a row (1,1,0)
connection 1:
INSERT INTO t1 set a=2,b=1,c=0 ON DUPLICATE KEY UPDATE c=1;
connection 2:
INSERT INTO t1 set a=2,b=2,c=0;
If 2 commits after 1 has been executed but before 1 has committed
(and are thus put before the other in the binary log), one will
get different data on the slave:
(1,1,1),(2,2,1) instead of (1,1,1),(2,2,0)
*/
void THD::reconsider_logging_format_for_iodup(TABLE *table)
{
/*
INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
can be unsafe.
*/
if(wsrep_binlog_format() <= BINLOG_FORMAT_STMT &&
!is_current_stmt_binlog_format_row() &&
!lex->is_stmt_unsafe() &&
lex->sql_command == SQLCOM_INSERT &&
lex->duplicates == DUP_UPDATE)
DBUG_ENTER("reconsider_logging_format_for_iodup");
enum_binlog_format bf= (enum_binlog_format) wsrep_binlog_format();
DBUG_ASSERT(lex->duplicates == DUP_UPDATE);
if (bf <= BINLOG_FORMAT_STMT &&
!is_current_stmt_binlog_format_row())
{
KEY *end= table->s->key_info + table->s->keys;
uint unique_keys= 0;
uint keys= table->s->keys, i= 0;
Field *field;
for (KEY* keyinfo= table->s->key_info;
i < keys && unique_keys <= 1; i++, keyinfo++)
if (keyinfo->flags & HA_NOSAME &&
!(keyinfo->key_part->field->flags & AUTO_INCREMENT_FLAG &&
//User given auto inc can be unsafe
!keyinfo->key_part->field->val_int()))
for (KEY *keyinfo= table->s->key_info; keyinfo < end ; keyinfo++)
{
if (keyinfo->flags & HA_NOSAME)
{
/*
We assume that the following cases will guarantee that the
key is unique if a key part is not set:
- The key part is an autoincrement (autogenerated)
- The key part has a default value that is null and it not
a virtual field that will be calculated later.
*/
for (uint j= 0; j < keyinfo->user_defined_key_parts; j++)
{
field= keyinfo->key_part[j].field;
if(!bitmap_is_set(table->write_set,field->field_index))
goto exit;
Field *field= keyinfo->key_part[j].field;
if (!bitmap_is_set(table->write_set, field->field_index))
{
/* Check auto_increment */
if (field == table->next_number_field)
goto exit;
if (field->is_real_null() && !field->default_value)
goto exit;
}
}
unique_keys++;
if (unique_keys++)
break;
exit:;
}
}
if (unique_keys > 1)
{
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
binlog_unsafe_warning_flags|= lex->get_stmt_unsafe_flags();
if (bf == BINLOG_FORMAT_STMT && !lex->is_stmt_unsafe())
{
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
binlog_unsafe_warning_flags|= lex->get_stmt_unsafe_flags();
}
set_current_stmt_binlog_format_row_if_mixed();
return 1;
}
}
return 0;
DBUG_VOID_RETURN;
}
/*

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2009, 2021, MariaDB Corporation.
Copyright (c) 2009, 2022, MariaDB Corporation.
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
@ -4514,18 +4514,18 @@ public:
mdl_context.release_transactional_locks();
}
int decide_logging_format(TABLE_LIST *tables);
/*
In Some cases when decide_logging_format is called it does not have all
information to decide the logging format. So that cases we call decide_logging_format_2
at later stages in execution.
One example would be binlog format for IODKU but column with unique key is not inserted.
We dont have inserted columns info when we call decide_logging_format so on later stage we call
decide_logging_format_low
@returns 0 if no format is changed
1 if there is change in binlog format
/*
In Some cases when decide_logging_format is called it does not have
all information to decide the logging format. So that cases we call
decide_logging_format_2 at later stages in execution.
One example would be binlog format for insert on duplicate key
(IODKU) but column with unique key is not inserted. We do not have
inserted columns info when we call decide_logging_format so on
later stage we call reconsider_logging_format_for_iodup()
*/
int decide_logging_format_low(TABLE *table);
void reconsider_logging_format_for_iodup(TABLE *table);
enum need_invoker { INVOKER_NONE=0, INVOKER_USER, INVOKER_ROLE};
void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; }

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2010, 2019, MariaDB Corporation
Copyright (c) 2010, 2022, MariaDB Corporation
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
@ -945,6 +945,12 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
THD_STAGE_INFO(thd, stage_update);
if (duplic == DUP_UPDATE)
{
restore_record(table,s->default_values); // Get empty record
thd->reconsider_logging_format_for_iodup(table);
}
do
{
DBUG_PRINT("info", ("iteration %llu", iteration));
@ -1057,7 +1063,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
break;
}
thd->decide_logging_format_low(table);
#ifndef EMBEDDED_LIBRARY
if (lock_type == TL_WRITE_DELAYED)
{

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2019, Oracle and/or its affiliates.
Copyright (c) 2009, 2021, MariaDB Corporation.
Copyright (c) 2009, 2022, MariaDB Corporation.
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
@ -4492,17 +4492,21 @@ void SELECT_LEX::update_used_tables()
while ((tl= ti++))
{
TABLE_LIST *embedding= tl;
do
if (!is_eliminated_table(join->eliminated_tables, tl))
{
bool maybe_null;
if ((maybe_null= MY_TEST(embedding->outer_join)))
do
{
tl->table->maybe_null= maybe_null;
break;
bool maybe_null;
if ((maybe_null= MY_TEST(embedding->outer_join)))
{
tl->table->maybe_null= maybe_null;
break;
}
}
while ((embedding= embedding->embedding));
}
while ((embedding= embedding->embedding));
if (tl->on_expr)
if (tl->on_expr && !is_eliminated_table(join->eliminated_tables, tl))
{
tl->on_expr->update_used_tables();
tl->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
@ -4526,8 +4530,11 @@ void SELECT_LEX::update_used_tables()
if (embedding->on_expr &&
embedding->nested_join->join_list.head() == tl)
{
embedding->on_expr->update_used_tables();
embedding->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
if (!is_eliminated_table(join->eliminated_tables, embedding))
{
embedding->on_expr->update_used_tables();
embedding->on_expr->walk(&Item::eval_not_null_tables, 0, NULL);
}
}
tl= embedding;
embedding= tl->embedding;

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
Copyright (c) 2008, 2021, MariaDB
Copyright (c) 2008, 2022, MariaDB
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
@ -8712,6 +8712,7 @@ bool st_select_lex::add_window_def(THD *thd,
fields_in_window_functions+= win_part_list_ptr->elements +
win_order_list_ptr->elements;
}
win_def->win_spec_number= window_specs.elements;
return (win_def == NULL || window_specs.push_back(win_def));
}
@ -8739,6 +8740,7 @@ bool st_select_lex::add_window_spec(THD *thd,
win_order_list_ptr->elements;
}
thd->lex->win_spec= win_spec;
win_spec->win_spec_number= window_specs.elements;
return (win_spec == NULL || window_specs.push_back(win_spec));
}

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2009, 2021, MariaDB Corporation.
Copyright (c) 2009, 2022, MariaDB Corporation.
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
@ -24710,15 +24710,17 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
for (uint i= 0; (item= it++); i++)
{
Field *field;
if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
enum Item::Type item_type= item->type();
if ((item->with_sum_func && item_type != Item::SUM_FUNC_ITEM) ||
item->with_window_func)
item_field= item;
else if (item->type() == Item::FIELD_ITEM)
else if (item_type == Item::FIELD_ITEM ||
item_type == Item::DEFAULT_VALUE_ITEM)
{
if (!(item_field= item->get_tmp_table_item(thd)))
DBUG_RETURN(true);
}
else if (item->type() == Item::FUNC_ITEM &&
else if (item_type == Item::FUNC_ITEM &&
((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
{
field= item->get_tmp_table_field();
@ -26547,7 +26549,7 @@ static void print_table_array(THD *thd,
too)
*/
static bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl)
{
return eliminated_tables &&
((tbl->table && (tbl->table->map & eliminated_tables)) ||

View File

@ -2,7 +2,7 @@
#define SQL_SELECT_INCLUDED
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2008, 2020, MariaDB Corporation.
Copyright (c) 2008, 2022, MariaDB Corporation.
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
@ -2473,4 +2473,6 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort);
JOIN_TAB *first_explain_order_tab(JOIN* join);
JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab);
bool is_eliminated_table(table_map eliminated_tables, TABLE_LIST *tbl);
#endif /* SQL_SELECT_INCLUDED */

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2016, 2017 MariaDB
Copyright (c) 2016, 2022 MariaDB
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
@ -424,16 +424,49 @@ ORDER *st_select_lex::find_common_window_func_partition_fields(THD *thd)
#define CMP_GT 2 // Greater then
static
int compare_order_elements(ORDER *ord1, ORDER *ord2)
int compare_order_elements(ORDER *ord1, int weight1,
ORDER *ord2, int weight2)
{
if (*ord1->item == *ord2->item && ord1->direction == ord2->direction)
return CMP_EQ;
Item *item1= (*ord1->item)->real_item();
Item *item2= (*ord2->item)->real_item();
DBUG_ASSERT(item1->type() == Item::FIELD_ITEM &&
item2->type() == Item::FIELD_ITEM);
int cmp= ((Item_field *) item1)->field->field_index -
((Item_field *) item2)->field->field_index;
bool item1_field= (item1->type() == Item::FIELD_ITEM);
bool item2_field= (item2->type() == Item::FIELD_ITEM);
ptrdiff_t cmp;
if (item1_field && item2_field)
{
DBUG_ASSERT(((Item_field *) item1)->field->table ==
((Item_field *) item2)->field->table);
cmp= ((Item_field *) item1)->field->field_index -
((Item_field *) item2)->field->field_index;
}
else if (item1_field && !item2_field)
return CMP_LT;
else if (!item1_field && item2_field)
return CMP_LT;
else
{
/*
Ok, item1_field==NULL and item2_field==NULL.
We're not able to compare Item expressions. Order them according to
their passed "weight" (which comes from Window_spec::win_spec_number):
*/
if (weight1 != weight2)
cmp= weight1 - weight2;
else
{
/*
The weight is the same. That is, the elements come from the same
window specification... This shouldn't happen.
*/
DBUG_ASSERT(0);
cmp= item1 - item2;
}
}
if (cmp == 0)
{
if (ord1->direction == ord2->direction)
@ -446,7 +479,9 @@ int compare_order_elements(ORDER *ord1, ORDER *ord2)
static
int compare_order_lists(SQL_I_List<ORDER> *part_list1,
SQL_I_List<ORDER> *part_list2)
int spec_number1,
SQL_I_List<ORDER> *part_list2,
int spec_number2)
{
if (part_list1 == part_list2)
return CMP_EQ;
@ -471,7 +506,8 @@ int compare_order_lists(SQL_I_List<ORDER> *part_list1,
if (!elem1 || !elem2)
break;
if ((cmp= compare_order_elements(elem1, elem2)))
if ((cmp= compare_order_elements(elem1, spec_number1,
elem2, spec_number2)))
return cmp;
}
if (elem1)
@ -566,7 +602,9 @@ int compare_window_spec_joined_lists(Window_spec *win_spec1,
win_spec1->join_partition_and_order_lists();
win_spec2->join_partition_and_order_lists();
int cmp= compare_order_lists(win_spec1->partition_list,
win_spec2->partition_list);
win_spec1->win_spec_number,
win_spec2->partition_list,
win_spec2->win_spec_number);
win_spec1->disjoin_partition_and_order_lists();
win_spec2->disjoin_partition_and_order_lists();
return cmp;
@ -584,7 +622,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
if (win_spec1 == win_spec2)
return CMP_EQ;
cmp= compare_order_lists(win_spec1->partition_list,
win_spec2->partition_list);
win_spec1->win_spec_number,
win_spec2->partition_list,
win_spec2->win_spec_number);
if (cmp == CMP_EQ)
{
/*
@ -603,7 +643,9 @@ int compare_window_funcs_by_window_specs(Item_window_func *win_func1,
}
cmp= compare_order_lists(win_spec1->order_list,
win_spec2->order_list);
win_spec1->win_spec_number,
win_spec2->order_list,
win_spec2->win_spec_number);
if (cmp != CMP_EQ)
return cmp;
@ -700,7 +742,9 @@ void order_window_funcs_by_window_specs(List<Item_window_func> *win_func_list)
int cmp;
if (win_spec_prev->partition_list == win_spec_curr->partition_list)
cmp= compare_order_lists(win_spec_prev->order_list,
win_spec_curr->order_list);
win_spec_prev->win_spec_number,
win_spec_curr->order_list,
win_spec_curr->win_spec_number);
else
cmp= compare_window_spec_joined_lists(win_spec_prev, win_spec_curr);
if (!(CMP_LT_C <= cmp && cmp <= CMP_GT_C))

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2016, 2017 MariaDB
Copyright (c) 2016, 2022 MariaDB
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
@ -120,10 +120,15 @@ class Window_spec : public Sql_alloc
Window_spec *referenced_win_spec;
Window_spec(LEX_CSTRING *win_ref,
SQL_I_List<ORDER> *part_list,
SQL_I_List<ORDER> *ord_list,
Window_frame *win_frame)
/*
Window_spec objects are numbered by the number of their appearance in the
query. This is used by compare_order_elements() to provide a predictable
ordering of PARTITION/ORDER BY clauses.
*/
int win_spec_number;
Window_spec(LEX_CSTRING *win_ref, SQL_I_List<ORDER> *part_list,
SQL_I_List<ORDER> *ord_list, Window_frame *win_frame)
: window_names_are_checked(false), window_ref(win_ref),
partition_list(part_list), save_partition_list(NULL),
order_list(ord_list), save_order_list(NULL),

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2021, MariaDB Corporation.
Copyright (c) 2019, 2022, MariaDB Corporation.
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
@ -376,6 +376,7 @@ rtr_update_mbr_field(
if (!rtr_update_mbr_field_in_place(index, rec,
offsets, mbr, mtr)) {
mem_heap_free(heap);
return(false);
}

View File

@ -2966,8 +2966,12 @@ row_ins_sec_index_entry_low(
rtr_init_rtr_info(&rtr_info, false, &cursor,
index, false);
rtr_info_update_btr(&cursor, &rtr_info);
mtr_start(&mtr);
index->set_modified(mtr);
mtr.start();
if (index->table->is_temporary()) {
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
index->set_modified(mtr);
}
search_mode &= ulint(~BTR_MODIFY_LEAF);
search_mode |= BTR_MODIFY_TREE;
err = btr_cur_search_to_nth_level(