1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

Merge 10.11 into 11.4

This commit is contained in:
Marko Mäkelä
2026-10-13 07:49:28 +03:00
28 changed files with 1232 additions and 24 deletions

View File

@@ -5376,7 +5376,7 @@ void do_sync_with_master(struct st_command *command)
long offset= 0;
char *p= command->first_argument;
const char *offset_start= p;
char *start, *buff= 0;
char *start, *buff= 0, *str;
start= const_cast<char*>("");
if (*offset_start)
@@ -5394,15 +5394,15 @@ void do_sync_with_master(struct st_command *command)
p++;
while (*p && my_isspace(charset_info, *p))
p++;
start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(p)+1,
MYF(MY_WME|MY_FAE));
get_string(&buff, &p, command);
str= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(p)+1,
MYF(MY_WME|MY_FAE));
start= get_string(&str, &p, command);
}
command->last_argument= p;
}
do_sync_with_master2(command, offset, start);
if (buff)
my_free(start);
my_free(buff);
return;
}
@@ -8453,7 +8453,7 @@ void do_get_errcodes(struct st_command *command)
/*
Get a string; Return ptr to end of string
Get a string; Return ptr to start of string
Strings may be surrounded by " or '
If string is a '$variable', return the value of the variable.

View File

@@ -0,0 +1,115 @@
connection node_2;
connection node_1;
#
# Each pair below is two distinct values whose bytes fold to the same
# latin1_swedish_ci weight string (0xC0->0x41, 0x6A->0x4A, 0x6B->0x4B,
# 0xD2->0x4F, 0x7A->0x5A). A UUID is stored as a byte permutation of the
# value shown, which does not affect a byte-wise folding.
#
SELECT WEIGHT_STRING(_latin1 0xC0A8016B9E4D4F7AB3D26A1E8F9C0D1B) =
WEIGHT_STRING(_latin1 0x41A8014B9E4D4F5AB34F4A1E8F9C0D1B) AS uuid_pair_collides,
WEIGHT_STRING(_latin1 0x20010DB80000000000000000C0A8016B) =
WEIGHT_STRING(_latin1 0x20010DB8000000000000000041A8014B) AS inet6_pair_collides,
WEIGHT_STRING(_latin1 0xC0A8016B) =
WEIGHT_STRING(_latin1 0x41A8014B) AS inet4_pair_collides;
uuid_pair_collides inet6_pair_collides inet4_pair_collides
1 1 1
#
# UUID
#
connection node_1;
CREATE TABLE t (id UUID PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b', 0), ('41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b 1
41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;
#
# INET6
#
connection node_1;
CREATE TABLE t (id INET6 PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('2001:db8::c0a8:16b', 0), ('2001:db8::41a8:14b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = '2001:db8::c0a8:16b';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '2001:db8::41a8:14b';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
2001:db8::c0a8:16b 1
2001:db8::41a8:14b 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;
#
# INET4
#
connection node_1;
CREATE TABLE t (id INET4 PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES ('192.168.1.107', 0), ('65.168.1.75', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
UPDATE t SET v = 1 WHERE id = '192.168.1.107';
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE t SET v = 2 WHERE id = '65.168.1.75';
connection node_2;
no_false_dependency
1
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
second_row_applied_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT id, v FROM t ORDER BY v;
id v
192.168.1.107 1
65.168.1.75 2
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE t;

View File

@@ -0,0 +1,104 @@
connection node_2;
connection node_1;
#
# UUID
#
connection node_1;
CREATE TABLE p (id UUID PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id UUID NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;
#
# INET6
#
connection node_1;
CREATE TABLE p (id INET6 PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id INET6 NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('2001:db8::c0a8:16b', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('2001:db8::c0a8:16b');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = '2001:db8::c0a8:16b';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;
#
# INET4
#
connection node_1;
CREATE TABLE p (id INET4 PRIMARY KEY, v INT) ENGINE=InnoDB;
CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id INET4 NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB;
INSERT INTO p VALUES ('192.168.1.107', 0);
connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_1;
INSERT INTO c (p_id) VALUES ('192.168.1.107');
connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
UPDATE p SET v = v + 1 WHERE id = '192.168.1.107';
connection node_2;
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
no_row_modified_in_parallel
1
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
SELECT v FROM p;
v
1
SELECT COUNT(*) FROM c;
COUNT(*)
1
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
connection node_1;
DROP TABLE c, p;

View File

@@ -0,0 +1,67 @@
#
# Body of galera.MDEV-41012-collision, parameterized by the data type.
#
# $fbt_type - data type of the primary key column
# $fbt_value1 - a literal of that type
# $fbt_value2 - a *different* literal whose binary representation folds to
# the same latin1_swedish_ci weight string as $fbt_value1
#
--connection node_1
--eval CREATE TABLE t (id $fbt_type PRIMARY KEY, v INT) ENGINE=InnoDB
--eval INSERT INTO t VALUES ($fbt_value1, 0), ($fbt_value2, 0)
--connection node_2
SET SESSION wsrep_sync_wait = 0;
--let $wait_condition = SELECT COUNT(*) = 2 FROM t
--source include/wait_condition.inc
SET GLOBAL wsrep_slave_threads = 2;
# Park the applier of the first UPDATE on entry to the apply monitor.
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc
--connection node_1
--eval UPDATE t SET v = 1 WHERE id = $fbt_value1
--connection node_2
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc
# Disarm, so the second applier runs into the real dependency check.
--source include/galera_clear_sync_point.inc
--let $apply_waits = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits'`
--connection node_1
--eval UPDATE t SET v = 2 WHERE id = $fbt_value2
--connection node_2
# The two statements modify two *different* rows, so their
# certification keys must differ, there must be no dependency between the two
# writesets, and the second applier must be free to apply its row while the
# first one is still parked.
--let $wait_condition = SELECT (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits') > $apply_waits OR EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0)
--source include/wait_condition.inc
# While the key was collated with latin1_swedish_ci the two keys were equal,
# the second writeset was made to depend on the first, and both of these
# reported 0.
--disable_query_log
--eval SELECT VARIABLE_VALUE = $apply_waits AS no_false_dependency FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits'
--enable_query_log
SELECT COUNT(*) = 1 AS second_row_applied_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc
--let $wait_condition = SELECT SUM(v) = 3 FROM t
--source include/wait_condition.inc
SELECT id, v FROM t ORDER BY v;
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
--connection node_1
DROP TABLE t;

View File

@@ -0,0 +1,64 @@
#
# MDEV-41012: certification key collision between distinct values of a fixed
# binary data type (UUID, INET6, INET4).
#
# Testing key collisions with data types on Field_fbt: UUID, INET6 and INET4,
# where different keys could potentially generate same certification keys.
# i.e. a scenario where two transactions modifying two *different*
# rows certified as a conflict and the later one was aborted with a spurious
# ER_LOCK_DEADLOCK.
#
# A shared key also gives the two writesets a false dependency on each other,
# which serializes applying that should have run in parallel. The test detects
# the collision that way, because it can be driven deterministically. Whether
# the spurious ER_LOCK_DEADLOCK is observed instead depends on whether the
# first writeset has already been applied by the time the second transaction
# replicates, which is a race.
#
# This needs no foreign key: it is the row key path,
# wsrep_store_key_val_for_row(), alone.
#
# This is the second half of MDEV-41012. The other half, a key *mismatch* for
# one and the same row, is covered by galera.MDEV-41012.
#
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/galera_have_debug_sync.inc
--echo #
--echo # Each pair below is two distinct values whose bytes fold to the same
--echo # latin1_swedish_ci weight string (0xC0->0x41, 0x6A->0x4A, 0x6B->0x4B,
--echo # 0xD2->0x4F, 0x7A->0x5A). A UUID is stored as a byte permutation of the
--echo # value shown, which does not affect a byte-wise folding.
--echo #
SELECT WEIGHT_STRING(_latin1 0xC0A8016B9E4D4F7AB3D26A1E8F9C0D1B) =
WEIGHT_STRING(_latin1 0x41A8014B9E4D4F5AB34F4A1E8F9C0D1B) AS uuid_pair_collides,
WEIGHT_STRING(_latin1 0x20010DB80000000000000000C0A8016B) =
WEIGHT_STRING(_latin1 0x20010DB8000000000000000041A8014B) AS inet6_pair_collides,
WEIGHT_STRING(_latin1 0xC0A8016B) =
WEIGHT_STRING(_latin1 0x41A8014B) AS inet4_pair_collides;
--echo #
--echo # UUID
--echo #
--let $fbt_type = UUID
--let $fbt_value1 = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b'
--let $fbt_value2 = '41a8014b-9e4d-4f5a-b34f-4a1e8f9c0d1b'
--source MDEV-41012-collision.inc
--echo #
--echo # INET6
--echo #
--let $fbt_type = INET6
--let $fbt_value1 = '2001:db8::c0a8:16b'
--let $fbt_value2 = '2001:db8::41a8:14b'
--source MDEV-41012-collision.inc
--echo #
--echo # INET4
--echo #
--let $fbt_type = INET4
--let $fbt_value1 = '192.168.1.107'
--let $fbt_value2 = '65.168.1.75'
--source MDEV-41012-collision.inc

View File

@@ -0,0 +1,67 @@
#
# Body of galera.MDEV-41012, parameterized by the data type of the foreign key.
#
# $fbt_type - data type of the parent PK / child FK column
# $fbt_value - a literal of that type whose binary representation contains
# bytes that latin1_swedish_ci folds (0xC0, 0x6A, 0x6B, 0xD2 ...)
#
--connection node_1
--eval CREATE TABLE p (id $fbt_type PRIMARY KEY, v INT) ENGINE=InnoDB
--eval CREATE TABLE c (id INT AUTO_INCREMENT PRIMARY KEY, p_id $fbt_type NOT NULL, KEY k (p_id), FOREIGN KEY (p_id) REFERENCES p (id)) ENGINE=InnoDB
--eval INSERT INTO p VALUES ($fbt_value, 0)
--connection node_2
SET SESSION wsrep_sync_wait = 0;
--let $wait_condition = SELECT COUNT(*) = 1 FROM p
--source include/wait_condition.inc
# Two appliers, so that the two writesets below *can* be applied in parallel
# if certification does not make them depend on each other.
SET GLOBAL wsrep_slave_threads = 2;
# Park the first applier on entry to the apply monitor, i.e. before the child
# INSERT is applied and before its FK check locks the parent row.
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc
--connection node_1
--eval INSERT INTO c (p_id) VALUES ($fbt_value)
--connection node_2
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_wait_sync_point.inc
# clear the sync point. The second applier must run into the real dependency
--source include/galera_clear_sync_point.inc
--let $apply_waits = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits'`
--connection node_1
--eval UPDATE p SET v = v + 1 WHERE id = $fbt_value
--connection node_2
# Wait until the second applier has blocked in the apply monitor because
--let $wait_condition = SELECT (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_apply_waits') > $apply_waits
--source include/wait_condition.inc
# the second applier waited instead of applying it in parallel.
SELECT COUNT(*) = 0 AS no_row_modified_in_parallel FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_rows_modified > 0;
# Release the child INSERT
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc
--let $wait_condition = SELECT COUNT(*) = 1 FROM c
--source include/wait_condition.inc
--let $wait_condition = SELECT v = 1 FROM p
--source include/wait_condition.inc
SELECT v FROM p;
SELECT COUNT(*) FROM c;
SET GLOBAL wsrep_slave_threads = DEFAULT;
SET SESSION wsrep_sync_wait = DEFAULT;
--connection node_1
DROP TABLE c, p;

View File

@@ -0,0 +1,40 @@
#
# MDEV-41012: BF-BF conflict when applying a child INSERT and a parent UPDATE
# in parallel, for a foreign key on a fixed binary data type.
#
# The test sends two write sets having access with the same primary key of fixed
# binary data type, the transactions are:
# * INSERT into the child table havinga reference key for the parent row
# * UPDATE of the parent row having the parent's primary key,
#
# The test orders appliers so that the child INSERT is parked before it
# is applied, the parent UPDATE is replicated after it, and we verify that the
# UPDATE has to wait for the INSERT instead of being applied in parallel.
#
# All three Field_fbt types (UUID, INET4 and INET6) are covered.
#
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/galera_have_debug_sync.inc
--echo #
--echo # UUID
--echo #
--let $fbt_type = UUID
--let $fbt_value = 'c0a8016b-9e4d-4f7a-b3d2-6a1e8f9c0d1b'
--source MDEV-41012.inc
--echo #
--echo # INET6
--echo #
--let $fbt_type = INET6
--let $fbt_value = '2001:db8::c0a8:16b'
--source MDEV-41012.inc
--echo #
--echo # INET4
--echo #
--let $fbt_type = INET4
--let $fbt_value = '192.168.1.107'
--source MDEV-41012.inc

View File

@@ -453,6 +453,9 @@ Executed_log_entries 7
Slave_received_heartbeats 0
Slave_heartbeat_period 60.000
Gtid_Slave_Pos
#
# MDEV-40996: the connection name may be given as a variable
#
stop all slaves;
Warnings:
Note 1938 SLAVE 'slave2' stopped

View File

@@ -77,6 +77,12 @@ reset slave 'slave1' all;
--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 $read_master_log_pos <read_master_log_pos> $relay_log_pos <relay_log_pos> $relay_log_space1 <relay_log_space1> $relay_log_space2 <relay_log_space2>
query_vertical show all slaves status;
--echo #
--echo # MDEV-40996: the connection name may be given as a variable
--echo #
--let $conn_name= slave2
--sync_with_master 0,$conn_name
stop all slaves;
--replace_result $SERVER_MYPORT_1 MYPORT_1 $SERVER_MYPORT_2 MYPORT_2 $read_master_log_pos <read_master_log_pos> $relay_log_pos <relay_log_pos> $relay_log_space1 <relay_log_space1> $relay_log_space2 <relay_log_space2>
query_vertical show all slaves status;

View File

@@ -352,3 +352,149 @@ SELECT * FROM t;
SELECT * FROM tp;
DROP TABLE t, tp, tsp;
--echo #
--echo # MDEV-38757 Exchange partition fails with compound expressions
--echo #
--echo # Test EXCHANGE PARTITION with generated columns containing AND/OR conditions
--echo # This verifies set comparison of generated column conditions during
--echo # partition exchange.
--echo # Test 1: Generated column with OR condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1) VALUES (1, 10), (1, 50), (1, 90);
--echo # This should succeed: EXCHANGE PARTITION with OR condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, vcol1 FROM t1 ORDER BY id;
DROP TABLE t1_working;
DROP TABLE t1;
--echo # Test 2: Generated column with AND condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 20, 50), (1, 5, 200);
--echo # This should succeed: EXCHANGE PARTITION with AND condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol2 FROM t1 ORDER BY id;
DROP TABLE t1_working;
DROP TABLE t1;
--echo # Test 3: Multiple generated columns with different AND/OR combinations
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
vcol3 TINYINT(1) GENERATED ALWAYS AS (col2 > 50 OR col2 < 10) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 15, 75), (1, 90, 5), (1, 50, 200);
--echo # This should succeed: EXCHANGE PARTITION with multiple AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol1, vcol2, vcol3 FROM t1 ORDER BY id;
DROP TABLE t1_working;
DROP TABLE t1;
--echo # Test 4: Nested AND/OR conditions
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS ((col1 > 10 AND col2 < 100) OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2, col3) VALUES (1, 20, 50, 30), (1, 5, 200, 60);
--echo # This should succeed: EXCHANGE PARTITION with nested AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
DROP TABLE t1_working;
DROP TABLE t1;
--echo # Test 5: Reordered condition with a duplicate term
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col3 > 50 OR col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1_working (userId, col1, col2, col3)
VALUES (1, 20, 50, 30), (1, 5, 200, 60);
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
DROP TABLE t1_working;
DROP TABLE t1;
--echo # End of 10.11 tests

View File

@@ -373,3 +373,136 @@ a b
63 Sixty three, new
99 End of values
DROP TABLE t, tp, tsp;
#
# MDEV-38757 Exchange partition fails with compound expressions
#
# Test EXCHANGE PARTITION with generated columns containing AND/OR conditions
# This verifies set comparison of generated column conditions during
# partition exchange.
# Test 1: Generated column with OR condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1) VALUES (1, 10), (1, 50), (1, 90);
# This should succeed: EXCHANGE PARTITION with OR condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, vcol1 FROM t1 ORDER BY id;
id userId col1 vcol1
1 1 10 1
2 1 50 0
3 1 90 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 2: Generated column with AND condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 20, 50), (1, 5, 200);
# This should succeed: EXCHANGE PARTITION with AND condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol2 FROM t1 ORDER BY id;
id userId col1 col2 vcol2
1 1 20 50 1
2 1 5 200 0
DROP TABLE t1_working;
DROP TABLE t1;
# Test 3: Multiple generated columns with different AND/OR combinations
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
vcol3 TINYINT(1) GENERATED ALWAYS AS (col2 > 50 OR col2 < 10) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 15, 75), (1, 90, 5), (1, 50, 200);
# This should succeed: EXCHANGE PARTITION with multiple AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol1, vcol2, vcol3 FROM t1 ORDER BY id;
id userId col1 col2 vcol1 vcol2 vcol3
1 1 15 75 1 1 1
2 1 90 5 1 1 1
3 1 50 200 0 0 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 4: Nested AND/OR conditions
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS ((col1 > 10 AND col2 < 100) OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2, col3) VALUES (1, 20, 50, 30), (1, 5, 200, 60);
# This should succeed: EXCHANGE PARTITION with nested AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 5: Reordered condition with a duplicate term
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col3 > 50 OR col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1_working (userId, col1, col2, col3)
VALUES (1, 20, 50, 30), (1, 5, 200, 60);
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# End of 10.11 tests

View File

@@ -373,3 +373,136 @@ a b
63 Sixty three, new
99 End of values
DROP TABLE t, tp, tsp;
#
# MDEV-38757 Exchange partition fails with compound expressions
#
# Test EXCHANGE PARTITION with generated columns containing AND/OR conditions
# This verifies set comparison of generated column conditions during
# partition exchange.
# Test 1: Generated column with OR condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1) VALUES (1, 10), (1, 50), (1, 90);
# This should succeed: EXCHANGE PARTITION with OR condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, vcol1 FROM t1 ORDER BY id;
id userId col1 vcol1
1 1 10 1
2 1 50 0
3 1 90 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 2: Generated column with AND condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 20, 50), (1, 5, 200);
# This should succeed: EXCHANGE PARTITION with AND condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol2 FROM t1 ORDER BY id;
id userId col1 col2 vcol2
1 1 20 50 1
2 1 5 200 0
DROP TABLE t1_working;
DROP TABLE t1;
# Test 3: Multiple generated columns with different AND/OR combinations
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
vcol3 TINYINT(1) GENERATED ALWAYS AS (col2 > 50 OR col2 < 10) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 15, 75), (1, 90, 5), (1, 50, 200);
# This should succeed: EXCHANGE PARTITION with multiple AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol1, vcol2, vcol3 FROM t1 ORDER BY id;
id userId col1 col2 vcol1 vcol2 vcol3
1 1 15 75 1 1 1
2 1 90 5 1 1 1
3 1 50 200 0 0 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 4: Nested AND/OR conditions
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS ((col1 > 10 AND col2 < 100) OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2, col3) VALUES (1, 20, 50, 30), (1, 5, 200, 60);
# This should succeed: EXCHANGE PARTITION with nested AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 5: Reordered condition with a duplicate term
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col3 > 50 OR col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1_working (userId, col1, col2, col3)
VALUES (1, 20, 50, 30), (1, 5, 200, 60);
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# End of 10.11 tests

View File

@@ -373,3 +373,136 @@ a b
63 Sixty three, new
99 End of values
DROP TABLE t, tp, tsp;
#
# MDEV-38757 Exchange partition fails with compound expressions
#
# Test EXCHANGE PARTITION with generated columns containing AND/OR conditions
# This verifies set comparison of generated column conditions during
# partition exchange.
# Test 1: Generated column with OR condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1) VALUES (1, 10), (1, 50), (1, 90);
# This should succeed: EXCHANGE PARTITION with OR condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, vcol1 FROM t1 ORDER BY id;
id userId col1 vcol1
1 1 10 1
2 1 50 0
3 1 90 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 2: Generated column with AND condition
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 20, 50), (1, 5, 200);
# This should succeed: EXCHANGE PARTITION with AND condition
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol2 FROM t1 ORDER BY id;
id userId col1 col2 vcol2
1 1 20 50 1
2 1 5 200 0
DROP TABLE t1_working;
DROP TABLE t1;
# Test 3: Multiple generated columns with different AND/OR combinations
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
vcol1 TINYINT(1) GENERATED ALWAYS AS (col1 > 80 OR col1 < 20) STORED,
vcol2 TINYINT(1) GENERATED ALWAYS AS (col1 > 10 AND col2 < 100) STORED,
vcol3 TINYINT(1) GENERATED ALWAYS AS (col2 > 50 OR col2 < 10) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1),
PARTITION p2 VALUES IN (2));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2) VALUES (1, 15, 75), (1, 90, 5), (1, 50, 200);
# This should succeed: EXCHANGE PARTITION with multiple AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, vcol1, vcol2, vcol3 FROM t1 ORDER BY id;
id userId col1 col2 vcol1 vcol2 vcol3
1 1 15 75 1 1 1
2 1 90 5 1 1 1
3 1 50 200 0 0 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 4: Nested AND/OR conditions
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS ((col1 > 10 AND col2 < 100) OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working LIKE t1;
ALTER TABLE t1_working REMOVE PARTITIONING;
INSERT INTO t1_working (userId, col1, col2, col3) VALUES (1, 20, 50, 30), (1, 5, 200, 60);
# This should succeed: EXCHANGE PARTITION with nested AND/OR conditions
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# Test 5: Reordered condition with a duplicate term
CREATE TABLE t1 (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST (userId)
(PARTITION p1 VALUES IN (1));
CREATE TABLE t1_working (
id INT NOT NULL AUTO_INCREMENT,
userId INT NOT NULL,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL,
vcol4 TINYINT(1) GENERATED ALWAYS AS
(col3 > 50 OR col1 > 10 AND col2 < 100 OR col3 > 50) STORED,
PRIMARY KEY (id, userId)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO t1_working (userId, col1, col2, col3)
VALUES (1, 20, 50, 30), (1, 5, 200, 60);
ALTER TABLE t1 EXCHANGE PARTITION p1 WITH TABLE t1_working;
SELECT id, userId, col1, col2, col3, vcol4 FROM t1 ORDER BY id;
id userId col1 col2 col3 vcol4
1 1 20 50 30 1
2 1 5 200 60 1
DROP TABLE t1_working;
DROP TABLE t1;
# End of 10.11 tests

View File

@@ -15,3 +15,4 @@ rpl_row_binlog_max_cache_size : MDEV-11092
rpl_row_index_choice : MDEV-11666
rpl_auto_increment_update_failure : disabled for now
rpl_current_user : waits for MDEV-22374 fix
rpl_parallel_multi_domain_xa : (2026-07-24) MDEV-34104: waits for MDEV-32020

View File

@@ -0,0 +1,17 @@
include/master-slave.inc
[connection master]
connection slave;
CHANGE MASTER TO MASTER_DELAY=1 FOR CHANNEL '################################################';
ERROR HY000: Could not initialize master info structure for '################################################'; more error messages can be found in the MariaDB error log
connection master;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
connection slave;
connection slave;
include/diff_tables.inc [master:t1, slave:t1]
CHANGE MASTER 'new_channel' TO MASTER_HOST='127.0.0.1', MASTER_PORT=1, MASTER_USER='root';
RESET SLAVE 'new_channel' ALL;
connection master;
DROP TABLE t1;
connection slave;
include/rpl_end.inc

View File

@@ -0,0 +1,40 @@
#
# CHANGE MASTER ... FOR CHANNEL with a name that overflows the relay
# log file name once escaped should return an error, not crash.
#
# STEPS:
# 1. Issue CHANGE MASTER ... FOR CHANNEL with a channel name that is
# within MAX_CONNECTION_NAME, but expands past the file name
# limit once escaped into the relay log file name.
# 2. Verify the statement fails with a clean error, not a crash.
# 3. Verify the server is still usable: a normal CHANGE MASTER for a
# new, short-named channel succeeds.
#
--source include/master-slave.inc
--connection slave
--let $channel= `SELECT REPEAT('#', 48)`
--error ER_MASTER_INFO
eval CHANGE MASTER TO MASTER_DELAY=1 FOR CHANNEL '$channel';
--connection master
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
--sync_slave_with_master
--connection slave
--let $diff_tables= master:t1, slave:t1
--source include/diff_tables.inc
CHANGE MASTER 'new_channel' TO MASTER_HOST='127.0.0.1', MASTER_PORT=1, MASTER_USER='root';
RESET SLAVE 'new_channel' ALL;
--disable_query_log
call mtr.add_suppression("Failed when trying to open logs");
--enable_query_log
--connection master
DROP TABLE t1;
--sync_slave_with_master
--source include/rpl_end.inc

View File

@@ -655,7 +655,8 @@ public:
bool cleanup_session_expr();
bool fix_and_check_expr(THD *thd, TABLE *table);
bool check_access(THD *thd);
inline bool is_equal(const Virtual_column_info* vcol, bool cmp_names) const;
inline bool is_equal(const Virtual_column_info* vcol, bool cmp_names,
bool unordered_conditions= false) const;
inline void print(String*);
};

View File

@@ -1274,8 +1274,11 @@ public:
{
bool binary_cmp; /**< Make binary comparison */
bool omit_table_names; /**< Skip table and db names comparison */
Eq_config(bool binary_cmp, bool omit_table_names= false)
: binary_cmp(binary_cmp), omit_table_names(omit_table_names) {}
bool unordered_conditions; /**< Ignore AND/OR operand order and duplicates */
Eq_config(bool binary_cmp, bool omit_table_names= false,
bool unordered_conditions= false)
: binary_cmp(binary_cmp), omit_table_names(omit_table_names),
unordered_conditions(unordered_conditions) {}
};
virtual bool eq(const Item *, const Eq_config &config) const;
enum_field_types field_type() const
@@ -8433,11 +8436,13 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
int *escape);
inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol,
bool omit_table_names) const
bool omit_table_names,
bool unordered_conditions) const
{
return type_handler() == vcol->type_handler()
&& is_stored() == vcol->is_stored()
&& expr->eq(vcol->expr, {true, omit_table_names});
&& expr->eq(vcol->expr,
{true, omit_table_names, unordered_conditions});
}
inline void Virtual_column_info::print(String* str)

View File

@@ -5638,6 +5638,80 @@ bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel)
}
/**
Compare two Item_cond expressions for equality.
Distinct AND/OR items are normally not considered equal, preserving their
execution order. Some metadata comparisons can explicitly request a set
comparison because table definitions may be serialized with their
arguments reordered.
@param item The other Item to compare with
@param config Comparison configuration
@return true if expressions are equivalent, false otherwise
*/
bool Item_cond::eq(const Item *item, const Eq_config &config) const
{
if (this == item)
return true;
if (!config.unordered_conditions)
return false;
if (item->type() != COND_ITEM || (used_tables() & RAND_TABLE_BIT))
return false;
const Item_cond *item_cond= (const Item_cond *) item;
if (functype() != item_cond->functype())
return false;
/*
Treat the argument lists as sets. Checking both directions deliberately
ignores duplicate terms: A OR B and A OR B OR A are equivalent here.
*/
List_iterator_fast<Item> li1(const_cast<List<Item>&>(list));
Item *arg1;
while ((arg1= li1++))
{
bool found_match= false;
List_iterator_fast<Item> li2(const_cast<List<Item>&>(item_cond->list));
Item *arg2;
while ((arg2= li2++))
{
if (arg1->eq(arg2, config))
{
found_match= true;
break;
}
}
if (!found_match)
return false;
}
List_iterator_fast<Item> li2(const_cast<List<Item>&>(item_cond->list));
Item *arg2;
while ((arg2= li2++))
{
bool found_match= false;
List_iterator_fast<Item> li1(const_cast<List<Item>&>(list));
Item *arg1;
while ((arg1= li1++))
{
if (arg2->eq(arg1, config))
{
found_match= true;
break;
}
}
if (!found_match)
return false;
}
return true;
}
void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
{
List_iterator<Item> li(list);

View File

@@ -3355,6 +3355,7 @@ public:
Item *deep_copy(THD *thd) const override;
bool excl_dep_on_table(table_map tab_map) override;
bool excl_dep_on_grouping_fields(st_select_lex *sel) override;
bool eq(const Item *item, const Eq_config &config) const override;
private:
void merge_sub_condition(List_iterator<Item>& li);

View File

@@ -3717,15 +3717,15 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
Create an index file that will hold all file names uses for logging.
Add new entries to the end of it.
*/
myf opt= MY_UNPACK_FILENAME;
myf opt= MY_UNPACK_FILENAME | MY_SAFE_PATH;
if (!index_file_name_arg)
{
index_file_name_arg= log_name; // Use same basename for index file
opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_SAFE_PATH;
}
fn_format(index_file_name, index_file_name_arg, mysql_data_home,
".index", opt);
if ((index_file_nr= mysql_file_open(m_key_file_log_index,
if (!fn_format(index_file_name, index_file_name_arg, mysql_data_home,
".index", opt) ||
(index_file_nr= mysql_file_open(m_key_file_log_index,
index_file_name,
O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC,
MYF(MY_WME))) < 0 ||

View File

@@ -1482,7 +1482,8 @@ bool Master_info_index::remove_master_info(Master_info *mi, bool clear_log_files
/* This code is only executed when change_master() failes to create a new master info */
// Delete any temporary relay log files that could have been created by change_master()
mi->rli.relay_log.reset_logs(current_thd, 0, (rpl_gtid*) 0, 0, 0);
if (mi->rli.relay_log.is_open())
mi->rli.relay_log.reset_logs(current_thd, 0, (rpl_gtid*) 0, 0, 0);
/* Delete master-'connection'.info */
create_logfile_name_with_suffix(tmp_name,
sizeof(tmp_name),

View File

@@ -248,7 +248,7 @@ bool compare_table_with_partition(THD *thd, TABLE *table, TABLE *part_table,
the same, so any table using data/index_file_name will fail.
*/
if (mysql_compare_tables(table, &part_alter_info, &part_create_info,
&metadata_equal))
&metadata_equal, true))
{
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
DBUG_RETURN(TRUE);

View File

@@ -7529,13 +7529,17 @@ static void update_altered_table(const Alter_inplace_info &ha_alter_info,
second table.
@param[in] create_info Create options for the second table.
@param[out] metadata_equal Result of comparison.
@param[in] compare_vcol_expr_as_sets
Ignore AND/OR order and duplicate terms in
generated column expressions.
@retval true error
@retval false success
*/
bool mysql_compare_tables(TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info, bool *metadata_equal)
HA_CREATE_INFO *create_info, bool *metadata_equal,
bool compare_vcol_expr_as_sets)
{
DBUG_ENTER("mysql_compare_tables");
@@ -7604,7 +7608,8 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info,
{
if (!tmp_new_field->field->vcol_info)
DBUG_RETURN(false);
if (!field->vcol_info->is_equal(tmp_new_field->field->vcol_info, true))
if (!field->vcol_info->is_equal(tmp_new_field->field->vcol_info,
true, compare_vcol_expr_as_sets))
DBUG_RETURN(false);
}

View File

@@ -165,7 +165,8 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
bool mysql_compare_tables(TABLE *table,
Alter_info *alter_info,
HA_CREATE_INFO *create_info,
bool *metadata_equal);
bool *metadata_equal,
bool compare_vcol_expr_as_sets);
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
class Recreate_info *recreate_info, bool table_copy);
bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,

View File

@@ -228,11 +228,18 @@ void Wsrep_server_service::log_view(
static_cast<Wsrep_high_priority_service*>(high_priority_service);
/* Update global system variables */
mysql_mutex_lock(&LOCK_global_system_variables);
/* The negotiated protocol version gates the writeset format, so it must be
picked up regardless of wsrep_auto_increment_control. Leaving it at this
node's own maximum would make a node in a cluster that settled on an older
version keep emitting the newer format. */
if (view.own_index() >= 0)
{
wsrep_protocol_version= view.protocol_version();
}
if (wsrep_auto_increment_control && view.own_index() >= 0)
{
global_system_variables.auto_increment_offset= view.own_index() + 1;
global_system_variables.auto_increment_increment= view.members().size();
wsrep_protocol_version= view.protocol_version();
}
mysql_mutex_unlock(&LOCK_global_system_variables);

View File

@@ -6931,10 +6931,31 @@ wsrep_store_key_val_for_row(
/* Character set for the field is defined only
to fields whose type is string and real field
type is not enum or set. For these fields check
if character set is multi byte. */
if character set is multi byte.
Fields that InnoDB stores as DATA_BINARY,
DATA_FIXBINARY or DATA_BLOB must not be collated
here: their bytes are opaque. Note that data types
implemented on top of Field_fbt (UUID, INET6, INET4)
report type() == MYSQL_TYPE_STRING and charset() ==
my_charset_numeric (i.e. latin1), while their values
are plain binary and InnoDB maps them to
DATA_FIXBINARY. The binary test below mirrors
get_innobase_type_from_mysql_type().
Skipping the collation changes the key bytes on the
wire, so it is gated on protocol version 5. Below
that version the value is still collated, and
wsrep_rec_get_foreign_key() collates the matching
reference key the same way, so the two agree in a
cluster that has not fully upgraded yet.
See MDEV-41012. */
if (real_type != MYSQL_TYPE_ENUM
&& real_type != MYSQL_TYPE_SET
&& (wsrep_protocol_version < 5
|| (!field->binary()
&& field->key_type()
!= HA_KEYTYPE_BINARY))
&& ( mysql_type == MYSQL_TYPE_VAR_STRING
|| mysql_type == MYSQL_TYPE_STRING)) {

View File

@@ -2667,6 +2667,7 @@ rec_offs_make_nth_extern(
}
#ifdef WITH_WSREP
# include "ha_prototypes.h"
# include <mysql/service_wsrep.h> /* wsrep_protocol_version */
int
wsrep_rec_get_foreign_key(
@@ -2781,9 +2782,31 @@ wsrep_rec_get_foreign_key(
data, len, buf,
*buf_len - key_len, false);
break;
case DATA_FIXBINARY:
if (wsrep_protocol_version < 5
&& !(col_f->prtype
& DATA_BINARY_TYPE)) {
/* A UUID, INET6 or INET4 column is
stored as fixed length binary, but
below protocol version 5
wsrep_store_key_val_for_row() still
collates the row key of the parent
with the character set of the field.
Collate the reference key the same
way, so that the two match in a
cluster that has not fully upgraded
yet. See MDEV-41012. */
len = wsrep_normalize_string(
(int)(col_f->prtype
& DATA_MYSQL_TYPE_MASK),
dtype_get_charset_coll(
col_f->prtype),
data, buf, len, *buf_len);
break;
}
/* fall through */
case DATA_BLOB:
case DATA_BINARY:
case DATA_FIXBINARY:
case DATA_GEOMETRY:
memcpy(buf, data, len);
break;