mirror of
https://github.com/MariaDB/server.git
synced 2025-07-02 14:22:51 +03:00
Automerge
This commit is contained in:
@ -1876,4 +1876,149 @@ id
|
|||||||
TRUNCATE TABLE t2;
|
TRUNCATE TABLE t2;
|
||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# Bug#40127 Multiple table DELETE IGNORE hangs on foreign key constraint violation on 5.0
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t2 (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
aid INT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (aid) REFERENCES t1 (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t3 (
|
||||||
|
bid INT UNSIGNED NOT NULL,
|
||||||
|
FOREIGN KEY (bid) REFERENCES t2 (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t4 (
|
||||||
|
a INT
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t5 (
|
||||||
|
a INT
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 (id) VALUES (1);
|
||||||
|
INSERT INTO t2 (id, aid) VALUES (1, 1),(2,1),(3,1),(4,1);
|
||||||
|
INSERT INTO t3 (bid) VALUES (1);
|
||||||
|
INSERT INTO t4 VALUES (1),(2),(3),(4),(5);
|
||||||
|
INSERT INTO t5 VALUES (1);
|
||||||
|
DELETE t5 FROM t4 LEFT JOIN t5 ON t4.a= t5.a;
|
||||||
|
DELETE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t3`, CONSTRAINT `t3_ibfk_1` FOREIGN KEY (`bid`) REFERENCES `t2` (`id`))
|
||||||
|
DELETE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t3`, CONSTRAINT `t3_ibfk_1` FOREIGN KEY (`bid`) REFERENCES `t2` (`id`))
|
||||||
|
DELETE IGNORE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
DROP TABLE t3;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLES t4,t5;
|
||||||
|
# Bug#40127 Multiple table DELETE IGNORE hangs on foreign key constraint violation on 5.0
|
||||||
|
# Testing for any side effects of IGNORE on AFTER DELETE triggers used with
|
||||||
|
# transactional tables.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t2 (a VARCHAR(100)) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t3 (i INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t4 (i INT NOT NULL PRIMARY KEY, t1i INT,
|
||||||
|
FOREIGN KEY (t1i) REFERENCES t1(i))
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @b:='EXECUTED TRIGGER';
|
||||||
|
INSERT INTO t2 VALUES (@b);
|
||||||
|
SET @a:= error_happens_here;
|
||||||
|
END||
|
||||||
|
SET @b:="";
|
||||||
|
SET @a:="";
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 SELECT * FROM t1;
|
||||||
|
** An error in a trigger causes rollback of the statement.
|
||||||
|
DELETE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
ERROR 42S22: Unknown column 'error_happens_here' in 'field list'
|
||||||
|
SELECT @a,@b;
|
||||||
|
@a @b
|
||||||
|
EXECUTED TRIGGER
|
||||||
|
SELECT * FROM t2;
|
||||||
|
a
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
i i
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
** Same happens with the IGNORE option
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
ERROR 42S22: Unknown column 'error_happens_here' in 'field list'
|
||||||
|
SELECT * FROM t2;
|
||||||
|
a
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
i i
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
**
|
||||||
|
** The following is an attempt to demonstrate
|
||||||
|
** error handling inside a row iteration.
|
||||||
|
**
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
TRUNCATE TABLE t2;
|
||||||
|
TRUNCATE TABLE t3;
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t4 VALUES (3,3),(4,4);
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @b:= CONCAT('EXECUTED TRIGGER FOR ROW ',CAST(OLD.i AS CHAR));
|
||||||
|
INSERT INTO t2 VALUES (@b);
|
||||||
|
END||
|
||||||
|
** DELETE is prevented by foreign key constrains but errors are silenced.
|
||||||
|
** The AFTER trigger isn't fired.
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
** Tables are modified by best effort:
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
i i
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
** The AFTER trigger was only executed on successful rows:
|
||||||
|
SELECT * FROM t2;
|
||||||
|
a
|
||||||
|
EXECUTED TRIGGER FOR ROW 1
|
||||||
|
EXECUTED TRIGGER FOR ROW 2
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
**
|
||||||
|
** Induce an error midway through an AFTER-trigger
|
||||||
|
**
|
||||||
|
TRUNCATE TABLE t4;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
TRUNCATE TABLE t3;
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 VALUES (1),(2),(3),(4);
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @a:= @a+1;
|
||||||
|
IF @a > 2 THEN
|
||||||
|
INSERT INTO t4 VALUES (5,5);
|
||||||
|
END IF;
|
||||||
|
END||
|
||||||
|
SET @a:=0;
|
||||||
|
** Errors in the trigger causes the statement to abort.
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`t1i`) REFERENCES `t1` (`i`))
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
i i
|
||||||
|
1 1
|
||||||
|
2 2
|
||||||
|
3 3
|
||||||
|
4 4
|
||||||
|
SELECT * FROM t4;
|
||||||
|
i t1i
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
DROP TABLE t4;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t3;
|
||||||
End of 5.1 tests
|
End of 5.1 tests
|
||||||
|
@ -185,4 +185,151 @@ TRUNCATE TABLE t2;
|
|||||||
DROP TABLE t2;
|
DROP TABLE t2;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#40127 Multiple table DELETE IGNORE hangs on foreign key constraint violation on 5.0
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
CREATE TABLE t2 (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
aid INT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
FOREIGN KEY (aid) REFERENCES t1 (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
CREATE TABLE t3 (
|
||||||
|
bid INT UNSIGNED NOT NULL,
|
||||||
|
FOREIGN KEY (bid) REFERENCES t2 (id)
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
CREATE TABLE t4 (
|
||||||
|
a INT
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
CREATE TABLE t5 (
|
||||||
|
a INT
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
INSERT INTO t1 (id) VALUES (1);
|
||||||
|
INSERT INTO t2 (id, aid) VALUES (1, 1),(2,1),(3,1),(4,1);
|
||||||
|
INSERT INTO t3 (bid) VALUES (1);
|
||||||
|
|
||||||
|
INSERT INTO t4 VALUES (1),(2),(3),(4),(5);
|
||||||
|
INSERT INTO t5 VALUES (1);
|
||||||
|
|
||||||
|
DELETE t5 FROM t4 LEFT JOIN t5 ON t4.a= t5.a;
|
||||||
|
|
||||||
|
--error ER_ROW_IS_REFERENCED_2
|
||||||
|
DELETE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
--error ER_ROW_IS_REFERENCED_2
|
||||||
|
DELETE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
|
||||||
|
DELETE IGNORE t2, t1 FROM t2 INNER JOIN t1 ON (t2.aid = t1.id) WHERE t2.id = 1;
|
||||||
|
|
||||||
|
DROP TABLE t3;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLES t4,t5;
|
||||||
|
|
||||||
|
--echo # Bug#40127 Multiple table DELETE IGNORE hangs on foreign key constraint violation on 5.0
|
||||||
|
--echo # Testing for any side effects of IGNORE on AFTER DELETE triggers used with
|
||||||
|
--echo # transactional tables.
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t2 (a VARCHAR(100)) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t3 (i INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t4 (i INT NOT NULL PRIMARY KEY, t1i INT,
|
||||||
|
FOREIGN KEY (t1i) REFERENCES t1(i))
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
delimiter ||;
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @b:='EXECUTED TRIGGER';
|
||||||
|
INSERT INTO t2 VALUES (@b);
|
||||||
|
SET @a:= error_happens_here;
|
||||||
|
END||
|
||||||
|
delimiter ;||
|
||||||
|
|
||||||
|
SET @b:="";
|
||||||
|
SET @a:="";
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 SELECT * FROM t1;
|
||||||
|
--echo ** An error in a trigger causes rollback of the statement.
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
DELETE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
SELECT @a,@b;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
|
||||||
|
--echo ** Same happens with the IGNORE option
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
|
||||||
|
--echo **
|
||||||
|
--echo ** The following is an attempt to demonstrate
|
||||||
|
--echo ** error handling inside a row iteration.
|
||||||
|
--echo **
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
TRUNCATE TABLE t2;
|
||||||
|
TRUNCATE TABLE t3;
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t4 VALUES (3,3),(4,4);
|
||||||
|
|
||||||
|
delimiter ||;
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @b:= CONCAT('EXECUTED TRIGGER FOR ROW ',CAST(OLD.i AS CHAR));
|
||||||
|
INSERT INTO t2 VALUES (@b);
|
||||||
|
END||
|
||||||
|
delimiter ;||
|
||||||
|
|
||||||
|
--echo ** DELETE is prevented by foreign key constrains but errors are silenced.
|
||||||
|
--echo ** The AFTER trigger isn't fired.
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
--echo ** Tables are modified by best effort:
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
--echo ** The AFTER trigger was only executed on successful rows:
|
||||||
|
SELECT * FROM t2;
|
||||||
|
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
|
||||||
|
--echo **
|
||||||
|
--echo ** Induce an error midway through an AFTER-trigger
|
||||||
|
--echo **
|
||||||
|
TRUNCATE TABLE t4;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
TRUNCATE TABLE t3;
|
||||||
|
INSERT INTO t1 VALUES (1),(2),(3),(4);
|
||||||
|
INSERT INTO t3 VALUES (1),(2),(3),(4);
|
||||||
|
delimiter ||;
|
||||||
|
CREATE TRIGGER trg AFTER DELETE ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET @a:= @a+1;
|
||||||
|
IF @a > 2 THEN
|
||||||
|
INSERT INTO t4 VALUES (5,5);
|
||||||
|
END IF;
|
||||||
|
END||
|
||||||
|
delimiter ;||
|
||||||
|
|
||||||
|
SET @a:=0;
|
||||||
|
--echo ** Errors in the trigger causes the statement to abort.
|
||||||
|
--error ER_NO_REFERENCED_ROW_2
|
||||||
|
DELETE IGNORE t1 FROM t3 LEFT JOIN t1 ON t1.i=t3.i;
|
||||||
|
SELECT * FROM t1 LEFT JOIN t3 ON t1.i=t3.i;
|
||||||
|
SELECT * FROM t4;
|
||||||
|
|
||||||
|
DROP TRIGGER trg;
|
||||||
|
DROP TABLE t4;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
DROP TABLE t3;
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--echo End of 5.1 tests
|
||||||
|
@ -709,6 +709,8 @@ bool multi_delete::send_data(List<Item> &values)
|
|||||||
TABLE_LIST *del_table;
|
TABLE_LIST *del_table;
|
||||||
DBUG_ENTER("multi_delete::send_data");
|
DBUG_ENTER("multi_delete::send_data");
|
||||||
|
|
||||||
|
bool ignore= thd->lex->current_select->no_error;
|
||||||
|
|
||||||
for (del_table= delete_tables;
|
for (del_table= delete_tables;
|
||||||
del_table;
|
del_table;
|
||||||
del_table= del_table->next_local, secure_counter++)
|
del_table= del_table->next_local, secure_counter++)
|
||||||
@ -741,8 +743,12 @@ bool multi_delete::send_data(List<Item> &values)
|
|||||||
TRG_ACTION_AFTER, FALSE))
|
TRG_ACTION_AFTER, FALSE))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
else
|
else if (!ignore)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
If the IGNORE option is used errors caused by ha_delete_row don't
|
||||||
|
have to stop the iteration.
|
||||||
|
*/
|
||||||
table->file->print_error(error,MYF(0));
|
table->file->print_error(error,MYF(0));
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
@ -834,6 +840,11 @@ int multi_delete::do_deletes()
|
|||||||
{
|
{
|
||||||
int local_error= 0, counter= 0, tmp_error;
|
int local_error= 0, counter= 0, tmp_error;
|
||||||
bool will_batch;
|
bool will_batch;
|
||||||
|
/*
|
||||||
|
If the IGNORE option is used all non fatal errors will be translated
|
||||||
|
to warnings and we should not break the row-by-row iteration
|
||||||
|
*/
|
||||||
|
bool ignore= thd->lex->current_select->no_error;
|
||||||
DBUG_ENTER("do_deletes");
|
DBUG_ENTER("do_deletes");
|
||||||
DBUG_ASSERT(do_delete);
|
DBUG_ASSERT(do_delete);
|
||||||
|
|
||||||
@ -872,11 +883,21 @@ int multi_delete::do_deletes()
|
|||||||
local_error= 1;
|
local_error= 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((local_error=table->file->ha_delete_row(table->record[0])))
|
|
||||||
|
local_error= table->file->ha_delete_row(table->record[0]);
|
||||||
|
if (local_error && !ignore)
|
||||||
{
|
{
|
||||||
table->file->print_error(local_error,MYF(0));
|
table->file->print_error(local_error,MYF(0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Increase the reported number of deleted rows only if no error occurred
|
||||||
|
during ha_delete_row.
|
||||||
|
Also, don't execute the AFTER trigger if the row operation failed.
|
||||||
|
*/
|
||||||
|
if (!local_error)
|
||||||
|
{
|
||||||
deleted++;
|
deleted++;
|
||||||
if (table->triggers &&
|
if (table->triggers &&
|
||||||
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
|
||||||
@ -886,6 +907,7 @@ int multi_delete::do_deletes()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (will_batch && (tmp_error= table->file->end_bulk_delete()))
|
if (will_batch && (tmp_error= table->file->end_bulk_delete()))
|
||||||
{
|
{
|
||||||
if (!local_error)
|
if (!local_error)
|
||||||
|
Reference in New Issue
Block a user