Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Major
-
Resolution: Unresolved
-
11.2.1, 11.4, 11.8, 12.3, 13.0.1
-
None
-
Unexpected results
-
Description
Environment
- Product: MariaDB Server primary/replica replication
- Observed affected topology: MariaDB 12.2.2 primary and MariaDB 12.2.2
replica - Replication: file/position; InnoDB; binlog_format=ROW; full row image
- Observed control: MariaDB 10.6 primary/replica does not diverge in this
schedule (both sides retain the same stale value); the 12.2.2 divergence is
therefore version-specific in the tested matrix.
Replication setup
Use any ordinary, empty MariaDB 12.2.2 primary/replica pair. The primary must
have binary logging and binlog_format=ROW enabled, and the replica must be
running normally before the SQL below is executed. For example, the only
required server options are equivalent to:
primary: --server-id=101 --log-bin=mariadb-bin --binlog-format=ROW
|
replica: --server-id=102 --relay-log=relay-bin
|
On the primary, grant a replication user; obtain SHOW MASTER STATUS; then
on the replica run {{CHANGE MASTER TO MASTER_HOST=..., MASTER_USER=...,
MASTER_PASSWORD=..., MASTER_LOG_FILE=..., MASTER_LOG_POS=...; START SLAVE;}}.
Wait until both Slave_IO_Running and Slave_SQL_Running are Yes.
No data file or attachment is used by this reproduction.
SQL to run on the primary
Run this complete SQL only after the replica has caught up with the primary's
empty mdev_row_generated schema. Then wait for the replica to apply the
transaction and query the parent table on both servers.
DROP DATABASE IF EXISTS mdev_row_generated; |
CREATE DATABASE mdev_row_generated; |
USE mdev_row_generated; |
|
|
CREATE TABLE parent( |
id INT PRIMARY KEY, |
v INT NOT NULL, |
g INT GENERATED ALWAYS AS (v * 2) STORED |
) ENGINE=InnoDB;
|
|
|
CREATE TABLE aux( |
id INT PRIMARY KEY, |
parent_id INT NOT NULL, |
w INT NOT NULL, |
FOREIGN KEY (parent_id) REFERENCES parent(id) |
) ENGINE=InnoDB;
|
|
|
CREATE TABLE audit( |
id INT PRIMARY KEY, |
parent_id INT, |
old_v INT, |
new_v INT, |
new_g INT |
) ENGINE=InnoDB;
|
|
|
INSERT INTO parent(id, v) VALUES (1, 10), (2, 20); |
INSERT INTO aux(id, parent_id, w) VALUES (101, 1, 3), (102, 2, 5); |
|
|
DELIMITER //
|
CREATE TRIGGER parent_bu BEFORE UPDATE ON parent FOR EACH ROW |
BEGIN
|
SET NEW.v = NEW.v + 7; |
END// |
CREATE TRIGGER parent_au AFTER UPDATE ON parent FOR EACH ROW |
BEGIN
|
INSERT INTO audit VALUES (OLD.id, OLD.id, OLD.v, NEW.v, NEW.g); |
END// |
DELIMITER ;
|
|
|
SET SESSION binlog_format = 'ROW'; |
UPDATE parent AS p JOIN aux AS a ON p.id = a.parent_id |
SET p.v = p.v + a.w, |
a.w = a.w + 1;
|
|
|
SELECT id, v, g, v * 2 AS recomputed_g, g = v * 2 AS invariant_holds |
FROM parent |
ORDER BY id; |
Actual result on the 12.2.2 primary and replica
After replication is caught up, the two endpoint queries return different
rows:
primary
|
id v g recomputed_g invariant_holds
|
1 20 26 40 0
|
2 32 50 64 0
|
|
|
replica
|
id v g recomputed_g invariant_holds
|
1 20 40 40 1
|
2 32 64 64 1
|
The primary stores g from the pre-trigger proposals (13 and 25), whereas
the replica stores g recomputed from the row image's v values (20 and
32). The two servers therefore no longer contain identical committed rows
after a forced ROW-logged transaction.
Expected result
For row-based replication, the replica should preserve the primary's committed
row state. It should not silently change g from the source row's stored
value. At minimum, the endpoint snapshots should be identical after the
replica applies the transaction.
Controls and repetition
- Deterministic ROW case above: 3/3 12.2.2 runs diverged after replication
caught up. - No-trigger multi-table UPDATE control: 3/3 runs had matching endpoint rows
and valid generated values. - Single-table UPDATE with a BEFORE-trigger mutation: 3/3 runs had matching
endpoint rows and valid generated values. - The same deterministic multi-table ROW case on MariaDB 10.6: 3/3 runs had
no endpoint divergence.
Nearby reports checked
I checked MDEV-29723, MDEV-21287, MDEV-40227, and MDEV-38465. They concern
transaction-precise timestamps, trigger observation, or other replication /
savepoint mechanisms. None describes MariaDB 12.2 multi-table UPDATE JOIN +
BEFORE-trigger mutation + STORED generated column where a ROW-applied replica
recomputes a value differently from the primary's persisted value.