summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/innodb/r/foreign_key.result43
-rw-r--r--mysql-test/suite/innodb/r/innodb-index-online-fk.result1
-rw-r--r--mysql-test/suite/innodb/r/innodb.result75
-rw-r--r--mysql-test/suite/innodb/r/update-cascade.result2
-rw-r--r--mysql-test/suite/innodb/t/foreign_key.test40
-rw-r--r--mysql-test/suite/innodb/t/innodb.test72
-rw-r--r--storage/innobase/include/dict0mem.h2
-rw-r--r--storage/innobase/include/row0mysql.h12
-rw-r--r--storage/innobase/include/row0upd.h63
-rw-r--r--storage/innobase/que/que0que.cc9
-rw-r--r--storage/innobase/row/row0ins.cc65
-rw-r--r--storage/innobase/row/row0mysql.cc331
-rw-r--r--storage/innobase/row/row0upd.cc75
13 files changed, 281 insertions, 509 deletions
diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result
index da0e16b86ac..e569fc7dba7 100644
--- a/mysql-test/suite/innodb/r/foreign_key.result
+++ b/mysql-test/suite/innodb/r/foreign_key.result
@@ -263,3 +263,46 @@ SELECT * FROM t2;
id ref_id f
2 2 20
DROP TABLE t2, t1;
+#
+# MDEV-15199 Referential integrity broken in ON DELETE CASCADE
+#
+CREATE TABLE member (id int AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO member VALUES (1);
+CREATE TABLE address (
+id int AUTO_INCREMENT PRIMARY KEY,
+member_id int NOT NULL,
+KEY address_FI_1 (member_id),
+CONSTRAINT address_FK_1 FOREIGN KEY (member_id) REFERENCES member (id)
+ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB;
+INSERT INTO address VALUES (2,1);
+CREATE TABLE payment_method (
+id int AUTO_INCREMENT PRIMARY KEY,
+member_id int NOT NULL,
+cardholder_address_id int DEFAULT NULL,
+KEY payment_method_FI_1 (member_id),
+KEY payment_method_FI_2 (cardholder_address_id),
+CONSTRAINT payment_method_FK_1 FOREIGN KEY (member_id) REFERENCES member (id) ON DELETE CASCADE ON UPDATE CASCADE,
+CONSTRAINT payment_method_FK_2 FOREIGN KEY (cardholder_address_id) REFERENCES address (id) ON DELETE SET NULL ON UPDATE CASCADE
+) ENGINE=InnoDB;
+INSERT INTO payment_method VALUES (3,1,2);
+BEGIN;
+UPDATE member SET id=42;
+SELECT * FROM member;
+id
+42
+SELECT * FROM address;
+id member_id
+2 42
+SELECT * FROM payment_method;
+id member_id cardholder_address_id
+3 42 2
+DELETE FROM member;
+COMMIT;
+SELECT * FROM member;
+id
+SELECT * FROM address;
+id member_id
+SELECT * FROM payment_method;
+id member_id cardholder_address_id
+DROP TABLE payment_method,address,member;
diff --git a/mysql-test/suite/innodb/r/innodb-index-online-fk.result b/mysql-test/suite/innodb/r/innodb-index-online-fk.result
index 359ce4a717c..4bd4b060ab3 100644
--- a/mysql-test/suite/innodb/r/innodb-index-online-fk.result
+++ b/mysql-test/suite/innodb/r/innodb-index-online-fk.result
@@ -86,6 +86,7 @@ child CREATE TABLE `child` (
DELETE FROM parent where a = 1;
SELECT * FROM child;
a1 a2
+1 NULL
2 3
10 20
SET foreign_key_checks = 0;
diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result
index c1bbc2c68d9..ed8720a0df9 100644
--- a/mysql-test/suite/innodb/r/innodb.result
+++ b/mysql-test/suite/innodb/r/innodb.result
@@ -1320,80 +1320,17 @@ INSERT INTO t2 VALUES (10, 'old'), (20, 'other');
UPDATE t1 SET c1 = 'other' WHERE c1 = 'old';
ERROR 23000: Foreign key constraint for table 't1', record 'other-somevalu' would lead to a duplicate entry in table 't2', key 'c1'
DROP TABLE t2,t1;
-call mtr.add_suppression("Cannot delete/update rows with cascading foreign key constraints that exceed max depth of 255. Please drop excessive foreign constraints and try again");
+call mtr.add_suppression("Cannot delete/update rows with cascading foreign key constraints that exceed max depth of 15\\. Please drop excessive foreign constraints and try again");
create table t1(
id int primary key,
pid int,
index(pid),
foreign key(pid) references t1(id) on delete cascade) engine=innodb;
-insert into t1 values
-( 0, 0), ( 1, 0), ( 2, 1), ( 3, 2),
-( 4, 3), ( 5, 4), ( 6, 5), ( 7, 6),
-( 8, 7), ( 9, 8), ( 10, 9), ( 11, 10),
-( 12, 11), ( 13, 12), ( 14, 13), ( 15, 14),
-( 16, 15), ( 17, 16), ( 18, 17), ( 19, 18),
-( 20, 19), ( 21, 20), ( 22, 21), ( 23, 22),
-( 24, 23), ( 25, 24), ( 26, 25), ( 27, 26),
-( 28, 27), ( 29, 28), ( 30, 29), ( 31, 30),
-( 32, 31), ( 33, 32), ( 34, 33), ( 35, 34),
-( 36, 35), ( 37, 36), ( 38, 37), ( 39, 38),
-( 40, 39), ( 41, 40), ( 42, 41), ( 43, 42),
-( 44, 43), ( 45, 44), ( 46, 45), ( 47, 46),
-( 48, 47), ( 49, 48), ( 50, 49), ( 51, 50),
-( 52, 51), ( 53, 52), ( 54, 53), ( 55, 54),
-( 56, 55), ( 57, 56), ( 58, 57), ( 59, 58),
-( 60, 59), ( 61, 60), ( 62, 61), ( 63, 62),
-( 64, 63), ( 65, 64), ( 66, 65), ( 67, 66),
-( 68, 67), ( 69, 68), ( 70, 69), ( 71, 70),
-( 72, 71), ( 73, 72), ( 74, 73), ( 75, 74),
-( 76, 75), ( 77, 76), ( 78, 77), ( 79, 78),
-( 80, 79), ( 81, 80), ( 82, 81), ( 83, 82),
-( 84, 83), ( 85, 84), ( 86, 85), ( 87, 86),
-( 88, 87), ( 89, 88), ( 90, 89), ( 91, 90),
-( 92, 91), ( 93, 92), ( 94, 93), ( 95, 94),
-( 96, 95), ( 97, 96), ( 98, 97), ( 99, 98),
-(100, 99), (101, 100), (102, 101), (103, 102),
-(104, 103), (105, 104), (106, 105), (107, 106),
-(108, 107), (109, 108), (110, 109), (111, 110),
-(112, 111), (113, 112), (114, 113), (115, 114),
-(116, 115), (117, 116), (118, 117), (119, 118),
-(120, 119), (121, 120), (122, 121), (123, 122),
-(124, 123), (125, 124), (126, 125), (127, 126),
-(128, 127), (129, 128), (130, 129), (131, 130),
-(132, 131), (133, 132), (134, 133), (135, 134),
-(136, 135), (137, 136), (138, 137), (139, 138),
-(140, 139), (141, 140), (142, 141), (143, 142),
-(144, 143), (145, 144), (146, 145), (147, 146),
-(148, 147), (149, 148), (150, 149), (151, 150),
-(152, 151), (153, 152), (154, 153), (155, 154),
-(156, 155), (157, 156), (158, 157), (159, 158),
-(160, 159), (161, 160), (162, 161), (163, 162),
-(164, 163), (165, 164), (166, 165), (167, 166),
-(168, 167), (169, 168), (170, 169), (171, 170),
-(172, 171), (173, 172), (174, 173), (175, 174),
-(176, 175), (177, 176), (178, 177), (179, 178),
-(180, 179), (181, 180), (182, 181), (183, 182),
-(184, 183), (185, 184), (186, 185), (187, 186),
-(188, 187), (189, 188), (190, 189), (191, 190),
-(192, 191), (193, 192), (194, 193), (195, 194),
-(196, 195), (197, 196), (198, 197), (199, 198),
-(200, 199), (201, 200), (202, 201), (203, 202),
-(204, 203), (205, 204), (206, 205), (207, 206),
-(208, 207), (209, 208), (210, 209), (211, 210),
-(212, 211), (213, 212), (214, 213), (215, 214),
-(216, 215), (217, 216), (218, 217), (219, 218),
-(220, 219), (221, 220), (222, 221), (223, 222),
-(224, 223), (225, 224), (226, 225), (227, 226),
-(228, 227), (229, 228), (230, 229), (231, 230),
-(232, 231), (233, 232), (234, 233), (235, 234),
-(236, 235), (237, 236), (238, 237), (239, 238),
-(240, 239), (241, 240), (242, 241), (243, 242),
-(244, 243), (245, 244), (246, 245), (247, 246),
-(248, 247), (249, 248), (250, 249), (251, 250),
-(252, 251), (253, 252), (254, 253), (255, 254);
+insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
+(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
delete from t1 where id=0;
Got one of the listed errors
-delete from t1 where id=255;
+delete from t1 where id=15;
delete from t1 where id=0;
drop table t1;
CREATE TABLE t1 (col1 int(1))ENGINE=InnoDB;
@@ -1758,10 +1695,10 @@ variable_value
16384
SELECT variable_value - @innodb_rows_deleted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_deleted';
variable_value - @innodb_rows_deleted_orig
-311
+71
SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted';
variable_value - @innodb_rows_inserted_orig
-1204
+964
SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated';
variable_value - @innodb_rows_updated_orig
866
diff --git a/mysql-test/suite/innodb/r/update-cascade.result b/mysql-test/suite/innodb/r/update-cascade.result
index 6ec7a8cae50..a3c8fed931e 100644
--- a/mysql-test/suite/innodb/r/update-cascade.result
+++ b/mysql-test/suite/innodb/r/update-cascade.result
@@ -176,7 +176,6 @@ set session transaction isolation level read uncommitted;
start transaction;
select f1, right(f2, 20) as p2 from t1;
f1 p2
-10 --------------------
select f1, right(f2, 20) as p2 from t2;
f1 p2
select f1, right(f2, 20) as p2 from t3;
@@ -266,7 +265,6 @@ set session transaction isolation level read uncommitted;
start transaction;
select f1, f2 from t1;
f1 f2
-2 28
select f1, f2 from t2;
f1 f2
select f1, f2 from t3;
diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test
index 3d3466c90f0..862717647b5 100644
--- a/mysql-test/suite/innodb/t/foreign_key.test
+++ b/mysql-test/suite/innodb/t/foreign_key.test
@@ -236,4 +236,44 @@ DELETE FROM t1 WHERE id = 1;
SELECT * FROM t2;
DROP TABLE t2, t1;
+--echo #
+--echo # MDEV-15199 Referential integrity broken in ON DELETE CASCADE
+--echo #
+
+CREATE TABLE member (id int AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO member VALUES (1);
+CREATE TABLE address (
+ id int AUTO_INCREMENT PRIMARY KEY,
+ member_id int NOT NULL,
+ KEY address_FI_1 (member_id),
+ CONSTRAINT address_FK_1 FOREIGN KEY (member_id) REFERENCES member (id)
+ ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
+INSERT INTO address VALUES (2,1);
+CREATE TABLE payment_method (
+ id int AUTO_INCREMENT PRIMARY KEY,
+ member_id int NOT NULL,
+ cardholder_address_id int DEFAULT NULL,
+ KEY payment_method_FI_1 (member_id),
+ KEY payment_method_FI_2 (cardholder_address_id),
+ CONSTRAINT payment_method_FK_1 FOREIGN KEY (member_id) REFERENCES member (id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT payment_method_FK_2 FOREIGN KEY (cardholder_address_id) REFERENCES address (id) ON DELETE SET NULL ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
+INSERT INTO payment_method VALUES (3,1,2);
+
+BEGIN;
+UPDATE member SET id=42;
+SELECT * FROM member;
+SELECT * FROM address;
+SELECT * FROM payment_method;
+DELETE FROM member;
+COMMIT;
+SELECT * FROM member;
+SELECT * FROM address;
+SELECT * FROM payment_method;
+
+DROP TABLE payment_method,address,member;
+
--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test
index 47fb3210807..4ebd4f2fa73 100644
--- a/mysql-test/suite/innodb/t/innodb.test
+++ b/mysql-test/suite/innodb/t/innodb.test
@@ -1058,82 +1058,18 @@ DROP TABLE t2,t1;
#
# test for FK cascade depth limit
#
-call mtr.add_suppression("Cannot delete/update rows with cascading foreign key constraints that exceed max depth of 255. Please drop excessive foreign constraints and try again");
+call mtr.add_suppression("Cannot delete/update rows with cascading foreign key constraints that exceed max depth of 15\\. Please drop excessive foreign constraints and try again");
create table t1(
id int primary key,
pid int,
index(pid),
foreign key(pid) references t1(id) on delete cascade) engine=innodb;
-insert into t1 values
-( 0, 0), ( 1, 0), ( 2, 1), ( 3, 2),
-( 4, 3), ( 5, 4), ( 6, 5), ( 7, 6),
-( 8, 7), ( 9, 8), ( 10, 9), ( 11, 10),
-( 12, 11), ( 13, 12), ( 14, 13), ( 15, 14),
-( 16, 15), ( 17, 16), ( 18, 17), ( 19, 18),
-( 20, 19), ( 21, 20), ( 22, 21), ( 23, 22),
-( 24, 23), ( 25, 24), ( 26, 25), ( 27, 26),
-( 28, 27), ( 29, 28), ( 30, 29), ( 31, 30),
-( 32, 31), ( 33, 32), ( 34, 33), ( 35, 34),
-( 36, 35), ( 37, 36), ( 38, 37), ( 39, 38),
-( 40, 39), ( 41, 40), ( 42, 41), ( 43, 42),
-( 44, 43), ( 45, 44), ( 46, 45), ( 47, 46),
-( 48, 47), ( 49, 48), ( 50, 49), ( 51, 50),
-( 52, 51), ( 53, 52), ( 54, 53), ( 55, 54),
-( 56, 55), ( 57, 56), ( 58, 57), ( 59, 58),
-( 60, 59), ( 61, 60), ( 62, 61), ( 63, 62),
-( 64, 63), ( 65, 64), ( 66, 65), ( 67, 66),
-( 68, 67), ( 69, 68), ( 70, 69), ( 71, 70),
-( 72, 71), ( 73, 72), ( 74, 73), ( 75, 74),
-( 76, 75), ( 77, 76), ( 78, 77), ( 79, 78),
-( 80, 79), ( 81, 80), ( 82, 81), ( 83, 82),
-( 84, 83), ( 85, 84), ( 86, 85), ( 87, 86),
-( 88, 87), ( 89, 88), ( 90, 89), ( 91, 90),
-( 92, 91), ( 93, 92), ( 94, 93), ( 95, 94),
-( 96, 95), ( 97, 96), ( 98, 97), ( 99, 98),
-(100, 99), (101, 100), (102, 101), (103, 102),
-(104, 103), (105, 104), (106, 105), (107, 106),
-(108, 107), (109, 108), (110, 109), (111, 110),
-(112, 111), (113, 112), (114, 113), (115, 114),
-(116, 115), (117, 116), (118, 117), (119, 118),
-(120, 119), (121, 120), (122, 121), (123, 122),
-(124, 123), (125, 124), (126, 125), (127, 126),
-(128, 127), (129, 128), (130, 129), (131, 130),
-(132, 131), (133, 132), (134, 133), (135, 134),
-(136, 135), (137, 136), (138, 137), (139, 138),
-(140, 139), (141, 140), (142, 141), (143, 142),
-(144, 143), (145, 144), (146, 145), (147, 146),
-(148, 147), (149, 148), (150, 149), (151, 150),
-(152, 151), (153, 152), (154, 153), (155, 154),
-(156, 155), (157, 156), (158, 157), (159, 158),
-(160, 159), (161, 160), (162, 161), (163, 162),
-(164, 163), (165, 164), (166, 165), (167, 166),
-(168, 167), (169, 168), (170, 169), (171, 170),
-(172, 171), (173, 172), (174, 173), (175, 174),
-(176, 175), (177, 176), (178, 177), (179, 178),
-(180, 179), (181, 180), (182, 181), (183, 182),
-(184, 183), (185, 184), (186, 185), (187, 186),
-(188, 187), (189, 188), (190, 189), (191, 190),
-(192, 191), (193, 192), (194, 193), (195, 194),
-(196, 195), (197, 196), (198, 197), (199, 198),
-(200, 199), (201, 200), (202, 201), (203, 202),
-(204, 203), (205, 204), (206, 205), (207, 206),
-(208, 207), (209, 208), (210, 209), (211, 210),
-(212, 211), (213, 212), (214, 213), (215, 214),
-(216, 215), (217, 216), (218, 217), (219, 218),
-(220, 219), (221, 220), (222, 221), (223, 222),
-(224, 223), (225, 224), (226, 225), (227, 226),
-(228, 227), (229, 228), (230, 229), (231, 230),
-(232, 231), (233, 232), (234, 233), (235, 234),
-(236, 235), (237, 236), (238, 237), (239, 238),
-(240, 239), (241, 240), (242, 241), (243, 242),
-(244, 243), (245, 244), (246, 245), (247, 246),
-(248, 247), (249, 248), (250, 249), (251, 250),
-(252, 251), (253, 252), (254, 253), (255, 254);
+insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
+(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
--error ER_GET_ERRMSG,ER_ROW_IS_REFERENCED_2
delete from t1 where id=0;
-delete from t1 where id=255;
---error 0,ER_ROW_IS_REFERENCED_2
+delete from t1 where id=15;
delete from t1 where id=0;
drop table t1;
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 4ba1556f3b8..7f90cf0ddbe 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -300,7 +300,7 @@ result in recursive cascading calls. This defines the maximum number of
such cascading deletes/updates allowed. When exceeded, the delete from
parent table will fail, and user has to drop excessive foreign constraint
before proceeds. */
-#define FK_MAX_CASCADE_DEL 255
+#define FK_MAX_CASCADE_DEL 15
/**********************************************************************//**
Creates a table memory object.
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 85f763f07a9..7a34c025dab 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -297,6 +297,18 @@ row_create_update_node_for_mysql(
/*=============================*/
dict_table_t* table, /*!< in: table to update */
mem_heap_t* heap); /*!< in: mem heap from which allocated */
+
+/**********************************************************************//**
+Does a cascaded delete or set null in a foreign key operation.
+@return error code or DB_SUCCESS */
+dberr_t
+row_update_cascade_for_mysql(
+/*=========================*/
+ que_thr_t* thr, /*!< in: query thread */
+ upd_node_t* node, /*!< in: update node used in the cascade
+ or set null operation */
+ dict_table_t* table) /*!< in: table where we do the operation */
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/*********************************************************************//**
Locks the data dictionary exclusively for performing a table create or other
data dictionary modification operation. */
diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h
index ec7995dd096..a174fd03751 100644
--- a/storage/innobase/include/row0upd.h
+++ b/storage/innobase/include/row0upd.h
@@ -32,20 +32,10 @@ Created 12/27/1996 Heikki Tuuri
#include "btr0types.h"
#include "dict0types.h"
#include "trx0types.h"
-#include <stack>
#include "btr0pcur.h"
#include "que0types.h"
#include "pars0types.h"
-/** The std::deque to store cascade update nodes, that uses mem_heap_t
-as allocator. */
-typedef std::deque<upd_node_t*, mem_heap_allocator<upd_node_t*> >
- deque_mem_heap_t;
-
-/** Double-ended queue of update nodes to be processed for cascade
-operations */
-typedef deque_mem_heap_t upd_cascade_t;
-
/*********************************************************************//**
Creates an update vector object.
@return own: update vector object */
@@ -523,38 +513,12 @@ struct upd_node_t{
dict_foreign_t* foreign;/* NULL or pointer to a foreign key
constraint if this update node is used in
doing an ON DELETE or ON UPDATE operation */
-
- bool cascade_top;
- /*!< true if top level in cascade */
-
- upd_cascade_t* cascade_upd_nodes;
- /*!< Queue of update nodes to handle the
- cascade of update and delete operations in an
- iterative manner. Their parent/child
- relations are properly maintained. All update
- nodes point to this same queue. All these
- nodes are allocated in heap pointed to by
- upd_node_t::cascade_heap. */
-
- upd_cascade_t* new_upd_nodes;
- /*!< Intermediate list of update nodes in a
- cascading update/delete operation. After
- processing one update node, this will be
- concatenated to cascade_upd_nodes. This extra
- list is needed so that retry because of
- DB_LOCK_WAIT works corrrectly. */
-
- upd_cascade_t* processed_cascades;
- /*!< List of processed update nodes in a
- cascading update/delete operation. All the
- cascade nodes are stored here, so that memory
- can be freed. */
-
+ upd_node_t* cascade_node;/* NULL or an update node template which
+ is used to implement ON DELETE/UPDATE CASCADE
+ or ... SET NULL for foreign keys */
mem_heap_t* cascade_heap;
- /*!< NULL or a mem heap where cascade_upd_nodes
- are created. This heap is owned by the node
- that has cascade_top=true. */
-
+ /*!< NULL or a mem heap where cascade
+ node is created.*/
sel_node_t* select; /*!< query graph subtree implementing a base
table cursor: the rows returned will be
updated */
@@ -601,25 +565,8 @@ struct upd_node_t{
sym_node_t* table_sym;/* table node in symbol table */
que_node_t* col_assign_list;
/* column assignment list */
-
- doc_id_t fts_doc_id;
- /* The FTS doc id of the row that is now
- pointed to by the pcur. */
-
- doc_id_t fts_next_doc_id;
- /* The new fts doc id that will be used
- in update operation */
-
ulint magic_n;
-#ifndef DBUG_OFF
- /** Print information about this object into the trace log file. */
- void dbug_trace();
-
- /** Ensure that the member cascade_upd_nodes has only one update node
- for each of the tables. This is useful for testing purposes. */
- void check_cascade_only_once();
-#endif /* !DBUG_OFF */
};
#define UPD_NODE_MAGIC_N 1579975
diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc
index 5f9f57dc08a..839f7ca0100 100644
--- a/storage/innobase/que/que0que.cc
+++ b/storage/innobase/que/que0que.cc
@@ -482,20 +482,17 @@ que_graph_free_recursive(
case QUE_NODE_UPDATE:
upd = static_cast<upd_node_t*>(node);
- DBUG_PRINT("que_graph_free_recursive",
- ("QUE_NODE_UPDATE: %p, processed_cascades: %p",
- upd, upd->processed_cascades));
-
if (upd->in_mysql_interface) {
btr_pcur_free_for_mysql(upd->pcur);
upd->in_mysql_interface = FALSE;
}
- if (upd->cascade_top) {
+ que_graph_free_recursive(upd->cascade_node);
+
+ if (upd->cascade_heap) {
mem_heap_free(upd->cascade_heap);
upd->cascade_heap = NULL;
- upd->cascade_top = false;
}
que_graph_free_recursive(upd->select);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 75ddac440b9..c771d2edb0e 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -475,9 +475,9 @@ row_ins_cascade_calc_update_vec(
type is != 0 */
mem_heap_t* heap, /*!< in: memory heap to use as
temporary storage */
- trx_t* trx, /*!< in: update transaction */
- upd_node_t* cascade) /*!< in: cascade update node */
+ trx_t* trx) /*!< in: update transaction */
{
+ upd_node_t* cascade = node->cascade_node;
dict_table_t* table = foreign->foreign_table;
dict_index_t* index = foreign->foreign_index;
upd_t* update;
@@ -702,13 +702,13 @@ row_ins_cascade_calc_update_vec(
fts_get_next_doc_id(table, next_doc_id);
doc_id = fts_update_doc_id(table, ufield, next_doc_id);
n_fields_updated++;
- cascade->fts_next_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_INSERT, NULL);
} else {
if (doc_id_updated) {
ut_ad(new_doc_id);
- cascade->fts_next_doc_id = new_doc_id;
+ fts_trx_add_op(trx, table, new_doc_id,
+ FTS_INSERT, NULL);
} else {
- cascade->fts_next_doc_id = FTS_NULL_DOC_ID;
ib::error() << "FTS Doc ID must be updated"
" along with FTS indexed column for"
" table " << table->name;
@@ -1121,18 +1121,14 @@ row_ins_foreign_check_on_constraint(
DBUG_RETURN(DB_ROW_IS_REFERENCED);
}
- cascade = row_create_update_node_for_mysql(table, node->cascade_heap);
- que_node_set_parent(cascade, node);
-
- /* For the cascaded operation, all the update nodes are allocated in
- the same heap. All the update nodes will point to the same heap.
- This heap is owned by the first update node. And it must be freed
- only in the first update node */
- cascade->cascade_heap = node->cascade_heap;
- cascade->cascade_upd_nodes = node->cascade_upd_nodes;
- cascade->new_upd_nodes = node->new_upd_nodes;
- cascade->processed_cascades = node->processed_cascades;
+ if (node->cascade_node == NULL) {
+ node->cascade_heap = mem_heap_create(128);
+ node->cascade_node = row_create_update_node_for_mysql(
+ table, node->cascade_heap);
+ que_node_set_parent(node->cascade_node, node);
+ }
+ cascade = node->cascade_node;
cascade->table = table;
cascade->foreign = foreign;
if (!(cascade->is_delete = node->is_delete
@@ -1274,17 +1270,8 @@ row_ins_foreign_check_on_constraint(
if (node->is_delete
? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
: (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) {
-
/* Build the appropriate update vector which sets
foreign->n_fields first fields in rec to SQL NULL */
- if (table->fts) {
-
- /* For the clause ON DELETE SET NULL, the cascade
- operation is actually an update operation with the new
- values being null. For FTS, this means that the old
- values be deleted and no new values to be added.*/
- cascade->fts_next_doc_id = FTS_NULL_DOC_ID;
- }
update = cascade->update;
@@ -1323,7 +1310,7 @@ row_ins_foreign_check_on_constraint(
}
if (affects_fulltext) {
- cascade->fts_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
if (foreign->v_cols != NULL
@@ -1353,7 +1340,7 @@ row_ins_foreign_check_on_constraint(
}
if (affects_fulltext) {
- cascade->fts_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
}
@@ -1364,7 +1351,7 @@ row_ins_foreign_check_on_constraint(
foreign->n_fields first fields in rec to new values */
bool affects_fulltext = row_ins_cascade_calc_update_vec(
- node, foreign, cascade->cascade_heap, trx, cascade);
+ node, foreign, tmp_heap, trx);
if (foreign->v_cols && !foreign->v_cols->empty()) {
row_ins_foreign_fill_virtual(
@@ -1403,7 +1390,7 @@ row_ins_foreign_check_on_constraint(
/* Mark the old Doc ID as deleted */
if (affects_fulltext) {
ut_ad(table->fts);
- cascade->fts_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
}
@@ -1432,11 +1419,8 @@ row_ins_foreign_check_on_constraint(
"WSREP: foreign key append failed: %d\n", err);
} else
#endif /* WITH_WSREP */
- node->new_upd_nodes->push_back(cascade);
-
- my_atomic_addlint(&table->n_foreign_key_checks_running, 1);
-
- ut_ad(foreign->foreign_table->n_foreign_key_checks_running > 0);
+ err = row_update_cascade_for_mysql(thr, cascade,
+ foreign->foreign_table);
/* Release the data dictionary latch for a while, so that we do not
starve other threads from doing CREATE TABLE etc. if we have a huge
@@ -1463,7 +1447,6 @@ row_ins_foreign_check_on_constraint(
DBUG_RETURN(err);
nonstandard_exit_func:
- que_graph_free_recursive(cascade);
if (tmp_heap) {
mem_heap_free(tmp_heap);
@@ -1948,6 +1931,12 @@ row_ins_check_foreign_constraints(
row_mysql_freeze_data_dictionary(trx);
}
+ if (referenced_table) {
+ my_atomic_addlint(
+ &foreign->foreign_table
+ ->n_foreign_key_checks_running, 1);
+ }
+
/* NOTE that if the thread ends up waiting for a lock
we will release dict_operation_lock temporarily!
But the counter on the table protects the referenced
@@ -1956,6 +1945,12 @@ row_ins_check_foreign_constraints(
err = row_ins_check_foreign_constraint(
TRUE, foreign, table, entry, thr);
+ if (referenced_table) {
+ my_atomic_addlint(
+ &foreign->foreign_table
+ ->n_foreign_key_checks_running, -1);
+ }
+
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
}
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index b9f8ec3376a..2f41d322681 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1598,8 +1598,6 @@ row_create_update_node_for_mysql(
node->table_sym = NULL;
node->col_assign_list = NULL;
- node->fts_doc_id = FTS_NULL_DOC_ID;
- node->fts_next_doc_id = UINT64_UNDEFINED;
DBUG_RETURN(node);
}
@@ -1647,9 +1645,9 @@ row_fts_do_update(
doc_id_t old_doc_id, /* in: old document id */
doc_id_t new_doc_id) /* in: new document id */
{
- fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
-
- if (new_doc_id != FTS_NULL_DOC_ID) {
+ if(trx->fts_next_doc_id) {
+ fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
+ if(new_doc_id != FTS_NULL_DOC_ID)
fts_trx_add_op(trx, table, new_doc_id, FTS_INSERT, NULL);
}
}
@@ -1661,24 +1659,30 @@ static
dberr_t
row_fts_update_or_delete(
/*=====================*/
- trx_t* trx,
- upd_node_t* node) /* in: prebuilt struct in MySQL
+ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
handle */
{
- dict_table_t* table = node->table;
- doc_id_t old_doc_id = node->fts_doc_id;
+ trx_t* trx = prebuilt->trx;
+ dict_table_t* table = prebuilt->table;
+ upd_node_t* node = prebuilt->upd_node;
+ doc_id_t old_doc_id = prebuilt->fts_doc_id;
+
DBUG_ENTER("row_fts_update_or_delete");
- ut_a(dict_table_has_fts_index(node->table));
+ ut_a(dict_table_has_fts_index(prebuilt->table));
/* Deletes are simple; get them out of the way first. */
if (node->is_delete) {
/* A delete affects all FTS indexes, so we pass NULL */
fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
} else {
- doc_id_t new_doc_id = node->fts_next_doc_id;
- ut_ad(new_doc_id != UINT64_UNDEFINED);
+ doc_id_t new_doc_id;
+ new_doc_id = fts_read_doc_id((byte*) &trx->fts_next_doc_id);
+ if (new_doc_id == 0) {
+ ib::error() << "InnoDB FTS: Doc ID cannot be 0";
+ return(DB_FTS_INVALID_DOCID);
+ }
row_fts_do_update(trx, table, old_doc_id, new_doc_id);
}
@@ -1727,19 +1731,6 @@ init_fts_doc_id_for_ref(
}
}
-/* A functor for decrementing counters. */
-class ib_dec_counter {
-public:
- ib_dec_counter() {}
-
- void operator() (upd_node_t* node) {
- ut_ad(node->table->n_foreign_key_checks_running > 0);
- my_atomic_addlint(
- &node->table->n_foreign_key_checks_running, -1);
- }
-};
-
-
/** Does an update or delete of a row for MySQL.
@param[in,out] prebuilt prebuilt struct in MySQL handle
@return error code or DB_SUCCESS */
@@ -1749,15 +1740,11 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
trx_savept_t savept;
dberr_t err;
que_thr_t* thr;
- ibool was_lock_wait;
dict_index_t* clust_index;
upd_node_t* node;
dict_table_t* table = prebuilt->table;
trx_t* trx = prebuilt->trx;
ulint fk_depth = 0;
- upd_cascade_t* cascade_upd_nodes;
- upd_cascade_t* new_upd_nodes;
- upd_cascade_t* processed_cascades;
bool got_s_lock = false;
DBUG_ENTER("row_update_for_mysql");
@@ -1802,26 +1789,6 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
const bool is_delete = node->is_delete;
ut_ad(node->table == table);
- if (node->cascade_heap) {
- mem_heap_empty(node->cascade_heap);
- } else {
- node->cascade_heap = mem_heap_create(128);
- }
-
- mem_heap_allocator<upd_node_t*> mem_heap_ator(node->cascade_heap);
-
- cascade_upd_nodes = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
- new_upd_nodes = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
- processed_cascades = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
clust_index = dict_table_get_first_index(table);
if (prebuilt->pcur->btr_cur.index == clust_index) {
@@ -1846,121 +1813,52 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
node->state = UPD_NODE_UPDATE_CLUSTERED;
- node->cascade_top = true;
- node->cascade_upd_nodes = cascade_upd_nodes;
- node->new_upd_nodes = new_upd_nodes;
- node->processed_cascades = processed_cascades;
- node->fts_doc_id = prebuilt->fts_doc_id;
-
- if (trx->fts_next_doc_id != UINT64_UNDEFINED) {
- node->fts_next_doc_id = fts_read_doc_id(
- (byte*) &trx->fts_next_doc_id);
- } else {
- node->fts_next_doc_id = UINT64_UNDEFINED;
- }
-
ut_ad(!prebuilt->sql_stat_start);
que_thr_move_to_run_state_for_mysql(thr, trx);
- thr->fk_cascade_depth = 0;
-
-run_again:
- if (thr->fk_cascade_depth == 1 && trx->dict_operation_lock_mode == 0) {
- got_s_lock = true;
- row_mysql_freeze_data_dictionary(trx);
- }
-
- thr->run_node = node;
- thr->prev_node = node;
-
- row_upd_step(thr);
+ for (;;) {
+ thr->run_node = node;
+ thr->prev_node = node;
+ thr->fk_cascade_depth = 0;
- DBUG_EXECUTE_IF("dml_cascade_only_once", node->check_cascade_only_once(););
+ row_upd_step(thr);
- err = trx->error_state;
+ err = trx->error_state;
- if (err != DB_SUCCESS) {
+ if (err == DB_SUCCESS) {
+ break;
+ }
que_thr_stop_for_mysql(thr);
if (err == DB_RECORD_NOT_FOUND) {
trx->error_state = DB_SUCCESS;
- trx->op_info = "";
-
- if (thr->fk_cascade_depth > 0) {
- que_graph_free_recursive(node);
- }
goto error;
}
- /* Since reporting a plain "duplicate key" error message to
- the user in cases where a long CASCADE operation would lead
- to a duplicate key in some other table is very confusing,
- map duplicate key errors resulting from FK constraints to a
- separate error code. */
- if (err == DB_DUPLICATE_KEY && thr->fk_cascade_depth > 0) {
- err = DB_FOREIGN_DUPLICATE_KEY;
- trx->error_state = err;
- }
-
thr->lock_state= QUE_THR_LOCK_ROW;
DEBUG_SYNC(trx->mysql_thd, "row_update_for_mysql_error");
- was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
- &savept);
+ bool was_lock_wait = row_mysql_handle_errors(
+ &err, trx, thr, &savept);
thr->lock_state= QUE_THR_LOCK_NOLOCK;
- if (was_lock_wait) {
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- ib_dec_counter());
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- que_graph_free_recursive);
- node->new_upd_nodes->clear();
- goto run_again;
- }
-
- trx->op_info = "";
-
- if (thr->fk_cascade_depth > 0) {
- que_graph_free_recursive(node);
+ if (!was_lock_wait) {
+ goto error;
}
- goto error;
- } else {
-
- std::copy(node->new_upd_nodes->begin(),
- node->new_upd_nodes->end(),
- std::back_inserter(*node->cascade_upd_nodes));
-
- node->new_upd_nodes->clear();
- }
-
- if (dict_table_has_fts_index(node->table)
- && node->fts_doc_id != FTS_NULL_DOC_ID
- && node->fts_next_doc_id != UINT64_UNDEFINED) {
- err = row_fts_update_or_delete(trx, node);
- ut_a(err == DB_SUCCESS);
- }
-
- if (thr->fk_cascade_depth > 0) {
- /* Processing cascade operation */
- ut_ad(node->table->n_foreign_key_checks_running > 0);
- my_atomic_addlint(
- &node->table->n_foreign_key_checks_running, -1);
- node->processed_cascades->push_back(node);
}
- if (!cascade_upd_nodes->empty()) {
- DEBUG_SYNC_C("foreign_constraint_update_cascade");
- node = cascade_upd_nodes->front();
- node->cascade_upd_nodes = cascade_upd_nodes;
- cascade_upd_nodes->pop_front();
- thr->fk_cascade_depth++;
+ que_thr_stop_for_mysql_no_error(thr, trx);
- goto run_again;
+ if (dict_table_has_fts_index(table)
+ && trx->fts_next_doc_id != UINT64_UNDEFINED) {
+ err = row_fts_update_or_delete(prebuilt);
+ if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
+ ut_ad(!"unexpected error");
+ goto error;
+ }
}
/* Completed cascading operations (if any) */
@@ -1968,45 +1866,10 @@ run_again:
row_mysql_unfreeze_data_dictionary(trx);
}
- thr->fk_cascade_depth = 0;
-
- /* Update the statistics of each involved table
- only after completing all operations, including
- FOREIGN KEY...ON...CASCADE|SET NULL. */
bool update_statistics;
+ ut_ad(node->is_delete == is_delete);
- for (upd_cascade_t::iterator i = processed_cascades->begin();
- i != processed_cascades->end();
- ++i) {
-
- node = *i;
-
- if (node->is_delete) {
- /* Not protected by dict_table_stats_lock() for
- performance reasons, we would rather get garbage
- in stat_n_rows (which is just an estimate anyway)
- than protecting the following code with a latch. */
- dict_table_n_rows_dec(node->table);
-
- update_statistics = !srv_stats_include_delete_marked;
- srv_stats.n_rows_deleted.inc(size_t(trx->id));
- } else {
- update_statistics
- = !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
- srv_stats.n_rows_updated.inc(size_t(trx->id));
- }
-
- if (update_statistics) {
- dict_stats_update_if_needed(node->table);
- } else {
- /* Always update the table modification counter. */
- node->table->stat_modified_counter++;
- }
-
- que_graph_free_recursive(node);
- }
-
- if (is_delete) {
+ if (/*node->*/is_delete) {
/* Not protected by dict_table_stats_lock() for performance
reasons, we would rather get garbage in stat_n_rows (which is
just an estimate anyway) than protecting the following code
@@ -2040,45 +1903,14 @@ run_again:
trx->op_info = "";
- que_thr_stop_for_mysql_no_error(thr, trx);
-
- DBUG_ASSERT(cascade_upd_nodes->empty());
-
DBUG_RETURN(err);
error:
+ trx->op_info = "";
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
}
- if (thr->fk_cascade_depth > 0) {
- ut_ad(node->table->n_foreign_key_checks_running > 0);
- my_atomic_addlint(
- &node->table->n_foreign_key_checks_running, -1);
- thr->fk_cascade_depth = 0;
- }
-
- /* Reset the table->n_foreign_key_checks_running counter */
- std::for_each(cascade_upd_nodes->begin(),
- cascade_upd_nodes->end(),
- ib_dec_counter());
-
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- ib_dec_counter());
-
- std::for_each(cascade_upd_nodes->begin(),
- cascade_upd_nodes->end(),
- que_graph_free_recursive);
-
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- que_graph_free_recursive);
-
- std::for_each(processed_cascades->begin(),
- processed_cascades->end(),
- que_graph_free_recursive);
-
DBUG_RETURN(err);
}
@@ -2245,6 +2077,89 @@ row_mysql_unfreeze_data_dictionary(
trx->dict_operation_lock_mode = 0;
}
+/**********************************************************************//**
+Does a cascaded delete or set null in a foreign key operation.
+@return error code or DB_SUCCESS */
+dberr_t
+row_update_cascade_for_mysql(
+/*=========================*/
+ que_thr_t* thr, /*!< in: query thread */
+ upd_node_t* node, /*!< in: update node used in the cascade
+ or set null operation */
+ dict_table_t* table) /*!< in: table where we do the operation */
+{
+ /* Increment fk_cascade_depth to record the recursive call depth on
+ a single update/delete that affects multiple tables chained
+ together with foreign key relations. */
+
+ if (++thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
+ return(DB_FOREIGN_EXCEED_MAX_CASCADE);
+ }
+
+ const trx_t* trx = thr_get_trx(thr);
+
+ for (;;) {
+ thr->run_node = node;
+ thr->prev_node = node;
+
+ DEBUG_SYNC_C("foreign_constraint_update_cascade");
+ {
+ TABLE *mysql_table = thr->prebuilt->m_mysql_table;
+ thr->prebuilt->m_mysql_table = NULL;
+ row_upd_step(thr);
+ thr->prebuilt->m_mysql_table = mysql_table;
+ }
+
+ switch (trx->error_state) {
+ case DB_LOCK_WAIT:
+ que_thr_stop_for_mysql(thr);
+ lock_wait_suspend_thread(thr);
+
+ if (trx->error_state == DB_SUCCESS) {
+ continue;
+ }
+
+ /* fall through */
+ default:
+ /* Other errors are handled for the parent node. */
+ thr->fk_cascade_depth = 0;
+ return trx->error_state;
+
+ case DB_SUCCESS:
+ thr->fk_cascade_depth = 0;
+ bool stats;
+
+ if (node->is_delete) {
+ /* Not protected by
+ dict_table_stats_lock() for
+ performance reasons, we would rather
+ get garbage in stat_n_rows (which is
+ just an estimate anyway) than
+ protecting the following code with a
+ latch. */
+ dict_table_n_rows_dec(node->table);
+
+ stats = !srv_stats_include_delete_marked;
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
+ } else {
+ stats = !(node->cmpl_info
+ & UPD_NODE_NO_ORD_CHANGE);
+ srv_stats.n_rows_updated.inc(size_t(trx->id));
+ }
+
+ if (stats) {
+ dict_stats_update_if_needed(node->table);
+ } else {
+ /* Always update the table
+ modification counter. */
+ node->table->stat_modified_counter++;
+ }
+
+ return(DB_SUCCESS);
+ }
+ }
+}
+
/*********************************************************************//**
Locks the data dictionary exclusively for performing a table create or other
data dictionary modification operation. */
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index ed03af11110..5009ac02408 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -319,9 +319,20 @@ row_upd_check_references_constraints(
But the counter on the table protects 'foreign' from
being dropped while the check is running. */
+ if (foreign_table) {
+ my_atomic_addlint(
+ &foreign_table->n_foreign_key_checks_running,
+ 1);
+ }
+
err = row_ins_check_foreign_constraint(
FALSE, foreign, table, entry, thr);
+ if (foreign_table) {
+ my_atomic_addlint(
+ &foreign_table->n_foreign_key_checks_running,
+ -1);
+ }
if (ref_table != NULL) {
dict_table_close(ref_table, FALSE, FALSE);
}
@@ -342,11 +353,6 @@ func_exit:
mem_heap_free(heap);
DEBUG_SYNC_C("foreign_constraint_check_for_update_done");
-
- DBUG_EXECUTE_IF("row_upd_cascade_lock_wait_err",
- err = DB_LOCK_WAIT;
- DBUG_SET("-d,row_upd_cascade_lock_wait_err"););
-
DBUG_RETURN(err);
}
@@ -469,9 +475,8 @@ wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx)
return false;
}
- const upd_node_t* parent = static_cast<const upd_node_t*>(node->common.parent);
-
- return parent->cascade_upd_nodes->empty();
+ return static_cast<upd_node_t*>(node->common.parent)->cascade_node
+ == node;
}
#endif /* WITH_WSREP */
@@ -2151,7 +2156,6 @@ row_upd_store_v_row(
cascade update. And virtual
column can't be affected,
so it is Ok to set it to NULL */
- ut_ad(!node->cascade_top);
dfield_set_null(dfield);
} else {
dfield_t* vfield
@@ -3426,56 +3430,3 @@ error_handling:
DBUG_RETURN(thr);
}
-
-#ifndef DBUG_OFF
-
-/** Ensure that the member cascade_upd_nodes has only one update node
-for each of the tables. This is useful for testing purposes. */
-void upd_node_t::check_cascade_only_once()
-{
- DBUG_ENTER("upd_node_t::check_cascade_only_once");
-
- dbug_trace();
-
- for (upd_cascade_t::const_iterator i = cascade_upd_nodes->begin();
- i != cascade_upd_nodes->end(); ++i) {
-
- const upd_node_t* update_node = *i;
- std::string table_name(update_node->table->name.m_name);
- ulint count = 0;
-
- for (upd_cascade_t::const_iterator j
- = cascade_upd_nodes->begin();
- j != cascade_upd_nodes->end(); ++j) {
-
- const upd_node_t* node = *j;
-
- if (table_name == node->table->name.m_name) {
- DBUG_ASSERT(count++ == 0);
- }
- }
- }
-
- DBUG_VOID_RETURN;
-}
-
-/** Print information about this object into the trace log file. */
-void upd_node_t::dbug_trace()
-{
- DBUG_ENTER("upd_node_t::dbug_trace");
-
- for (upd_cascade_t::const_iterator i = cascade_upd_nodes->begin();
- i != cascade_upd_nodes->end(); ++i) {
- DBUG_LOG("upd_node_t", "cascade_upd_nodes: Cascade to table: "
- << (*i)->table->name);
- }
-
- for (upd_cascade_t::const_iterator j = new_upd_nodes->begin();
- j != new_upd_nodes->end(); ++j) {
- DBUG_LOG("upd_node_t", "new_upd_nodes: Cascade to table: "
- << (*j)->table->name);
- }
-
- DBUG_VOID_RETURN;
-}
-#endif /* !DBUG_OFF */