summaryrefslogtreecommitdiff
path: root/innobase/row/row0upd.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/row/row0upd.c')
-rw-r--r--innobase/row/row0upd.c88
1 files changed, 81 insertions, 7 deletions
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 1231c94da63..64569bf3f96 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -71,6 +71,20 @@ the x-latch freed? The most efficient way for performing a
searched delete is obviously to keep the x-latch for several
steps of query graph execution. */
+/***************************************************************
+Checks if an update vector changes some of the first fields of an index
+record. */
+static
+ibool
+row_upd_changes_first_fields(
+/*=========================*/
+ /* out: TRUE if changes */
+ dtuple_t* entry, /* in: old value of index entry */
+ dict_index_t* index, /* in: index of entry */
+ upd_t* update, /* in: update vector for the row */
+ ulint n); /* in: how many first fields to check */
+
+
/*************************************************************************
Checks if index currently is mentioned as a referenced index in a foreign
key constraint. */
@@ -132,6 +146,7 @@ ulint
row_upd_check_references_constraints(
/*=================================*/
/* out: DB_SUCCESS or an error code */
+ upd_node_t* node, /* in: row update node */
btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the
cursor position is lost in this function! */
dict_table_t* table, /* in: table in question */
@@ -173,7 +188,16 @@ row_upd_check_references_constraints(
foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign) {
- if (foreign->referenced_index == index) {
+ /* Note that we may have an update which updates the index
+ record, but does NOT update the first fields which are
+ referenced in a foreign key constraint. Then the update does
+ NOT break the constraint. */
+
+ if (foreign->referenced_index == index
+ && (node->is_delete
+ || row_upd_changes_first_fields(entry, index,
+ node->update, foreign->n_fields))) {
+
if (foreign->foreign_table == NULL) {
dict_table_get(foreign->foreign_table_name,
trx);
@@ -189,10 +213,9 @@ row_upd_check_references_constraints(
}
/* 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 'foreign' from being dropped while the check
- is running. */
+ we will release dict_operation_lock temporarily!
+ But the counter on the table protects 'foreign' from
+ being dropped while the check is running. */
err = row_ins_check_foreign_constraint(FALSE, foreign,
table, index, entry, thr);
@@ -255,6 +278,7 @@ upd_node_create(
node->index = NULL;
node->update = NULL;
+ node->foreign = NULL;
node->cascade_heap = NULL;
node->cascade_node = NULL;
@@ -953,6 +977,53 @@ row_upd_changes_some_index_ord_field_binary(
return(FALSE);
}
+/***************************************************************
+Checks if an update vector changes some of the first fields of an index
+record. */
+static
+ibool
+row_upd_changes_first_fields(
+/*=========================*/
+ /* out: TRUE if changes */
+ dtuple_t* entry, /* in: index entry */
+ dict_index_t* index, /* in: index of entry */
+ upd_t* update, /* in: update vector for the row */
+ ulint n) /* in: how many first fields to check */
+{
+ upd_field_t* upd_field;
+ dict_field_t* ind_field;
+ dict_col_t* col;
+ ulint n_upd_fields;
+ ulint col_pos;
+ ulint i, j;
+
+ ut_a(update && index);
+ ut_a(n <= dict_index_get_n_fields(index));
+
+ n_upd_fields = upd_get_n_fields(update);
+
+ for (i = 0; i < n; i++) {
+
+ ind_field = dict_index_get_nth_field(index, i);
+ col = dict_field_get_col(ind_field);
+ col_pos = dict_col_get_clust_pos(col);
+
+ for (j = 0; j < n_upd_fields; j++) {
+
+ upd_field = upd_get_nth_field(update, j);
+
+ if (col_pos == upd_field->field_no
+ && cmp_dfield_dfield(
+ dtuple_get_nth_field(entry, i),
+ &(upd_field->new_val))) {
+ return(TRUE);
+ }
+ }
+ }
+
+ return(FALSE);
+}
+
/*************************************************************************
Copies the column values from a record. */
UNIV_INLINE
@@ -1106,9 +1177,11 @@ row_upd_sec_index_entry(
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
thr, &mtr);
if (err == DB_SUCCESS && check_ref) {
+
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
+ node,
&pcur, index->table,
index, thr, &mtr);
if (err != DB_SUCCESS) {
@@ -1224,7 +1297,7 @@ row_upd_clust_rec_by_insert(
if (check_ref) {
/* NOTE that the following call loses
the position of pcur ! */
- err = row_upd_check_references_constraints(
+ err = row_upd_check_references_constraints(node,
pcur, table,
index, thr, mtr);
if (err != DB_SUCCESS) {
@@ -1392,7 +1465,8 @@ row_upd_del_mark_clust_rec(
if (err == DB_SUCCESS && check_ref) {
/* NOTE that the following call loses the position of pcur ! */
- err = row_upd_check_references_constraints(pcur, index->table,
+ err = row_upd_check_references_constraints(node,
+ pcur, index->table,
index, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);