Skip to content

MDEV-40570 Wrong trigger event flag in ODKU/REPLACE - #5497

Open
MooSayed1 wants to merge 1 commit into
MariaDB:12.3from
MooSayed1:MDEV-40570
Open

MDEV-40570 Wrong trigger event flag in ODKU/REPLACE#5497
MooSayed1 wants to merge 1 commit into
MariaDB:12.3from
MooSayed1:MDEV-40570

Conversation

@MooSayed1

Copy link
Copy Markdown
Contributor

The Jira issue number for this PR is: MDEV-40570

Description

The INSERTING / UPDATING / DELETING clauses in multi-event triggers
(MDEV-10164) reported the wrong statement type:

CREATE TRIGGER trg BEFORE INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW ...
INSERT INTO t1 VALUES (1) ON DUPLICATE KEY UPDATE a = 1;
-- UPDATE triggers fired for the duplicate row saw INSERTING=TRUE,
-- UPDATING=FALSE

These clauses are evaluated by comparing the trigger statement type with
the top of THD's active-statement stack
(Item_trigger_type_of_statement::val_bool() in sql/item.cc).
mysql_insert() pushes INSERTING_STMT for the whole statement, but:

  1. Write_record::insert_on_duplicate_update() fires UPDATE triggers
    without changing the stack — UPDATING was reported as INSERTING.
  2. Write_record::replace_row() fires DELETE triggers for the
    conflicting row without changing the stack — DELETING was reported
    as INSERTING.
  3. INSERT ... SELECT and REPLACE ... SELECT never pushed any type
    at all — all three clauses evaluated to FALSE.

The fix pushes the correct active_dml_stmt via scoped
Running_stmt_guard in the two Write_record paths (matching the
pattern in sql_update.cc / sql_delete.cc), and pushes
INSERTING_STMT for the SQLCOM_INSERT_SELECT /
SQLCOM_REPLACE_SELECT cases in mysql_execute_command().

Release Notes

INSERTING/UPDATING/DELETING clauses in multi-event triggers now report
the correct value for UPDATE triggers fired by INSERT ... ON DUPLICATE
KEY UPDATE, DELETE triggers fired by REPLACE, and triggers fired by
INSERT ... SELECT / REPLACE ... SELECT.

How can this PR be tested?

./mtr main.trigger

New test cases cover: plain INSERT, ODKU (row changed and unchanged),
REPLACE on duplicate key, INSERT ... SELECT ... ON DUPLICATE KEY UPDATE
and REPLACE ... SELECT, verifying the flag seen by both BEFORE and
AFTER multi-event triggers.

Basing the PR against the correct MariaDB version

This is a bug fix. The bug was introduced by MDEV-10164 and the
earliest affected maintained branch is 12.3, so this PR targets
upstream/12.3.

PR quality check

  • I checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am ok with the reviewer making the changes themselves.

…NG/UPDATING/DELETING flag in multi-event triggers

The clauses INSERTING / UPDATING / DELETING available inside
multi-event triggers (MDEV-10164) are evaluated by comparing the
trigger's statement type with the type of DML statement on top of
the THD's active-statement stack (see
Item_trigger_type_of_statement::val_bool()).

mysql_insert() pushes INSERTING_STMT for the whole statement via a
Running_stmt_guard. However, when INSERT ... ON DUPLICATE KEY UPDATE
hits a duplicate key, Write_record::insert_on_duplicate_update()
fires UPDATE triggers without changing the active-statement stack,
so the UPDATING clause evaluated to FALSE and INSERTING to TRUE
inside those triggers. Similarly, when REPLACE deletes a conflicting
row, Write_record::replace_row() fires DELETE triggers while
INSERTING_STMT is still on top of the stack, so the DELETING clause
evaluated to FALSE.

Additionally, INSERT ... SELECT and REPLACE ... SELECT never pushed
any statement type at all, so all of the clauses INSERTING /
UPDATING / DELETING evaluated to FALSE for triggers fired by these
statements.

Fix:
- push UPDATING_STMT in Write_record::insert_on_duplicate_update()
  around the invocation of BEFORE/AFTER UPDATE triggers;
- push DELETING_STMT in Write_record::replace_row() around the
  invocation of BEFORE/AFTER DELETE triggers;
- push INSERTING_STMT for the whole INSERT ... SELECT and
  REPLACE ... SELECT statements in mysql_execute_command(), the
  same way mysql_insert() does.

The pushed value is popped automatically by the Running_stmt_guard
destructor at the end of each scope.
@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Aug 6, 2026

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! This is a preliminary review.

LGTM. Solid work!

Please stand by for the final review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

3 participants