Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions mysql-test/main/trigger.result
Original file line number Diff line number Diff line change
Expand Up @@ -3065,3 +3065,116 @@ TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_OBJECT_CATALOG EVENT_OBJECT_SC
DROP VIEW IF EXISTS vt;
DROP TABLE t, t1;
# End of 12.2 tests
#
# MDEV-40570: INSERT ... ON DUPLICATE KEY UPDATE reports the wrong
# INSERTING/UPDATING/DELETING flag in multi-event triggers
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
CREATE TABLE t2 (msg VARCHAR(20));
CREATE TRIGGER t1_b_all BEFORE INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('BEFORE INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('BEFORE UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('BEFORE DELETING');
END IF;
END
$
CREATE TRIGGER t1_a_all AFTER INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('AFTER INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('AFTER UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('AFTER DELETING');
END IF;
END
$
# Ordinary INSERT fires INSERT triggers with the INSERTING flag set
INSERT INTO t1 VALUES (1, 1);
SELECT * FROM t2;
msg
BEFORE INSERTING
AFTER INSERTING
TRUNCATE TABLE t2;
# INSERT ... ON DUPLICATE KEY UPDATE that hits a duplicate key first
# fires INSERT triggers (INSERTING), then performs an update and so
# must fire UPDATE triggers with the UPDATING flag set
INSERT INTO t1 VALUES (1, 2) ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
msg
BEFORE INSERTING
BEFORE UPDATING
AFTER UPDATING
TRUNCATE TABLE t2;
# ON DUPLICATE KEY UPDATE that doesn't change the row still fires
# UPDATE triggers with the UPDATING flag set
INSERT INTO t1 VALUES (1, 2) ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
msg
BEFORE INSERTING
BEFORE UPDATING
AFTER UPDATING
TRUNCATE TABLE t2;
# REPLACE on a duplicate key fires INSERT triggers (INSERTING) and
# DELETE triggers with the DELETING flag set
REPLACE INTO t1 VALUES (1, 3);
SELECT * FROM t2;
msg
BEFORE INSERTING
BEFORE DELETING
AFTER DELETING
AFTER INSERTING
TRUNCATE TABLE t2;
DROP TABLE t1, t2;
#
# Check the same for INSERT ... SELECT ... ON DUPLICATE KEY UPDATE
# and REPLACE ... SELECT
#
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
CREATE TABLE t2 (msg VARCHAR(20));
CREATE TABLE t3 (a INT, b INT);
INSERT INTO t3 VALUES (1, 2);
CREATE TRIGGER t1_b_all BEFORE INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('BEFORE INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('BEFORE UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('BEFORE DELETING');
END IF;
END
$
CREATE TRIGGER t1_a_all AFTER INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('AFTER INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('AFTER UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('AFTER DELETING');
END IF;
END
$
INSERT INTO t1 VALUES (1, 1);
TRUNCATE TABLE t2;
INSERT INTO t1 SELECT * FROM t3 ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
msg
BEFORE INSERTING
BEFORE UPDATING
AFTER UPDATING
TRUNCATE TABLE t2;
REPLACE INTO t1 SELECT a, b + 1 FROM t3;
SELECT * FROM t2;
msg
BEFORE INSERTING
BEFORE DELETING
AFTER DELETING
AFTER INSERTING
DROP TABLE t1, t2, t3;
# End of 12.3 tests
107 changes: 107 additions & 0 deletions mysql-test/main/trigger.test
Original file line number Diff line number Diff line change
Expand Up @@ -3404,3 +3404,110 @@ DROP VIEW IF EXISTS vt;
DROP TABLE t, t1;

--echo # End of 12.2 tests

--echo #
--echo # MDEV-40570: INSERT ... ON DUPLICATE KEY UPDATE reports the wrong
--echo # INSERTING/UPDATING/DELETING flag in multi-event triggers
--echo #

CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
CREATE TABLE t2 (msg VARCHAR(20));

--delimiter $
CREATE TRIGGER t1_b_all BEFORE INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('BEFORE INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('BEFORE UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('BEFORE DELETING');
END IF;
END
$
CREATE TRIGGER t1_a_all AFTER INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('AFTER INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('AFTER UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('AFTER DELETING');
END IF;
END
$
--delimiter ;

--echo # Ordinary INSERT fires INSERT triggers with the INSERTING flag set
INSERT INTO t1 VALUES (1, 1);
SELECT * FROM t2;
TRUNCATE TABLE t2;

--echo # INSERT ... ON DUPLICATE KEY UPDATE that hits a duplicate key first
--echo # fires INSERT triggers (INSERTING), then performs an update and so
--echo # must fire UPDATE triggers with the UPDATING flag set
INSERT INTO t1 VALUES (1, 2) ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
TRUNCATE TABLE t2;

--echo # ON DUPLICATE KEY UPDATE that doesn't change the row still fires
--echo # UPDATE triggers with the UPDATING flag set
INSERT INTO t1 VALUES (1, 2) ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
TRUNCATE TABLE t2;

--echo # REPLACE on a duplicate key fires INSERT triggers (INSERTING) and
--echo # DELETE triggers with the DELETING flag set
REPLACE INTO t1 VALUES (1, 3);
SELECT * FROM t2;
TRUNCATE TABLE t2;

DROP TABLE t1, t2;

--echo #
--echo # Check the same for INSERT ... SELECT ... ON DUPLICATE KEY UPDATE
--echo # and REPLACE ... SELECT
--echo #
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
CREATE TABLE t2 (msg VARCHAR(20));
CREATE TABLE t3 (a INT, b INT);
INSERT INTO t3 VALUES (1, 2);

--delimiter $
CREATE TRIGGER t1_b_all BEFORE INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('BEFORE INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('BEFORE UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('BEFORE DELETING');
END IF;
END
$
CREATE TRIGGER t1_a_all AFTER INSERT OR UPDATE OR DELETE ON t1 FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO t2 VALUES ('AFTER INSERTING');
ELSEIF UPDATING THEN
INSERT INTO t2 VALUES ('AFTER UPDATING');
ELSEIF DELETING THEN
INSERT INTO t2 VALUES ('AFTER DELETING');
END IF;
END
$
--delimiter ;

INSERT INTO t1 VALUES (1, 1);
TRUNCATE TABLE t2;

INSERT INTO t1 SELECT * FROM t3 ON DUPLICATE KEY UPDATE b = 2;
SELECT * FROM t2;
TRUNCATE TABLE t2;

REPLACE INTO t1 SELECT a, b + 1 FROM t3;
SELECT * FROM t2;

DROP TABLE t1, t2, t3;

--echo # End of 12.3 tests
12 changes: 12 additions & 0 deletions sql/sql_insert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2194,6 +2194,12 @@ int Write_record::replace_row(ha_rows *inserted, ha_rows *deleted)
DBUG_PRINT("info", ("Deleting offending row and trying to write"
" new one again"));

/*
Make the DELETE triggers fired below see the DELETING clause
set to true
*/
Running_stmt_guard stmt_guard(thd, active_dml_stmt::DELETING_STMT);

auto *trg = table->triggers;
bool trg_skip_row= false;
if (use_triggers && trg->process_triggers(table->in_use, TRG_EVENT_DELETE,
Expand Down Expand Up @@ -2262,6 +2268,12 @@ int Write_record::insert_on_duplicate_update(ha_rows *inserted,
DBUG_ASSERT(info->update_fields->elements ==
info->update_values->elements);

/*
Make the UPDATE triggers fired below see the UPDATING clause
set to true
*/
Running_stmt_guard stmt_guard(thd, active_dml_stmt::UPDATING_STMT);

bool trg_skip_row= false;
if (fill_record_n_invoke_before_triggers(thd, table,
*info->update_fields,
Expand Down
1 change: 1 addition & 0 deletions sql/sql_parse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4545,6 +4545,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
case SQLCOM_INSERT_SELECT:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
Running_stmt_guard guard(thd, active_dml_stmt::INSERTING_STMT);
select_insert *sel_result;
select_result *result= NULL;
bool explain= MY_TEST(lex->describe);
Expand Down