Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
None
-
None
-
None
-
Unexpected results
-
Description
Summary
MariaDB ROW replication can apply a row through a replica-side trigger that
raises SQLSTATE 45000 without stopping the replica SQL thread. The
same trigger raises error 1644 during an ordinary local INSERT on the replica.
Under ROW replication with slave_run_triggers_for_rbr=YES, the source row is
stored on the replica, Last_SQL_Error remains empty, and
Slave_SQL_Running remains Yes.
Environment
- Product: MariaDB Server
- Observed versions:
- MariaDB 12.2.2 primary -> MariaDB 12.2.2 replica
- MariaDB 10.6 primary -> MariaDB 12.2.2 replica
- Replication: asynchronous file/position replication
- Binary logging: binlog_format=ROW
- Replica trigger mode: slave_run_triggers_for_rbr=YES
- Storage engine: InnoDB
Steps to reproduce
Set up a MariaDB primary and replica using file/position ROW replication.
Create the same base table on both endpoints. The base table includes a stored
generated column so the trigger can record the row image it sees:
CREATE TABLE base_t( |
id INT PRIMARY KEY, |
v INT NOT NULL, |
g INT GENERATED ALWAYS AS (v * 2) STORED, |
note VARCHAR(32) NOT NULL |
) ENGINE=InnoDB;
|
On the replica only, create a local audit table and a local AFTER INSERT
trigger. The trigger raises an error for rows whose note value is
'fail':
CREATE TABLE side_audit( |
seq INT AUTO_INCREMENT PRIMARY KEY, |
row_id INT NOT NULL, |
seen_v INT NOT NULL, |
seen_g INT NOT NULL, |
note VARCHAR(32) NOT NULL |
) ENGINE=InnoDB;
|
|
|
CREATE TRIGGER base_t_ai AFTER INSERT ON base_t |
FOR EACH ROW |
BEGIN
|
IF NEW.note = 'fail' THEN |
SIGNAL SQLSTATE '45000' |
SET MESSAGE_TEXT='replica side trigger failure'; |
ELSE |
INSERT INTO side_audit(row_id,seen_v,seen_g,note) |
VALUES(NEW.id,NEW.v,NEW.g,NEW.note); |
END IF; |
END; |
Enable replica-side trigger execution for row events:
SET GLOBAL slave_run_triggers_for_rbr='YES'; |
First verify the local behavior on the replica:
SET sql_log_bin=0; |
INSERT INTO base_t(id,v,note) VALUES(900,900,'fail'); |
The ordinary local INSERT on the replica fails:
ERROR 1644 (45000): replica side trigger failure
|
After cleaning up the local control row if necessary, insert the failing row on
the primary and wait until the replica reaches the primary binary log position:
INSERT INTO base_t(id,v,note) VALUES(1,10,'fail'); |
Then inspect the replica:
SHOW SLAVE STATUS\G
|
SELECT id,v,g,note FROM base_t ORDER BY id; |
SELECT row_id,seen_v,seen_g,note FROM side_audit ORDER BY seq; |
Expected result
Because slave_run_triggers_for_rbr=YES makes the replica run its local
trigger for row events, the trigger's SQLSTATE 45000 error should be
reported as an apply error. A consistent result would be for the replica SQL
thread to stop with the trigger error and not silently advance past the row.
Actual result
The replica SQL thread remains healthy:
Slave_IO_Running: Yes
|
Slave_SQL_Running: Yes
|
Last_SQL_Errno: 0
|
Last_SQL_Error:
|
The row that caused the trigger error under ordinary local execution is present
on the replica:
replica.base_t:
|
(1, 10, 20, 'fail')
|
For the variant where the SQLSTATE error is raised before the audit INSERT, the audit
table remains empty. For the variant where the audit INSERT is executed before
the SQLSTATE error, the audit row is present and the replica still continues without a
SQL-thread error.
Relevant controls
The same trigger was executed by an ordinary local INSERT on the replica, and
the local statement failed with error 1644:
ERROR 1644 (45000): replica side trigger failure
|
Two trigger bodies were tested:
-- Variant 1: SIGNAL before the audit INSERT
|
SIGNAL SQLSTATE '45000' |
SET MESSAGE_TEXT='replica side trigger failure'; |
INSERT INTO side_audit(row_id,seen_v,seen_g,note) |
VALUES(NEW.id,NEW.v,NEW.g,NEW.note); |
|
|
-- Variant 2: audit INSERT before SIGNAL
|
INSERT INTO side_audit(row_id,seen_v,seen_g,note) |
VALUES(NEW.id,NEW.v,NEW.g,NEW.note); |
SIGNAL SQLSTATE '45000' |
SET MESSAGE_TEXT='replica side trigger failure'; |
Both variants show the same error under local execution. Under ROW apply, both
variants allow the replica SQL thread to remain running after the source row is
applied.
Repetition and scope
The behavior reproduced in the following completed executions:
MariaDB 12.2.2 -> 12.2.2: 6/6 executions
|
MariaDB 10.6 -> 12.2.2: 6/6 executions
|
Each execution included the local trigger-error control on the replica. The
replica SQL thread remained running with an empty Last_SQL_Error after ROW
apply in every execution.
Nearby issues checked
This is not a crash-recovery case. The replica is not killed or restarted; the
replica SQL thread stays running during ordinary ROW apply.
This is also different from chained trigger logging behavior. There is only one
replica in this reproduction, and the observation is about propagation of a
trigger error during local row-event trigger execution.