summaryrefslogtreecommitdiff
path: root/innobase/row/row0ins.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/row/row0ins.c')
-rw-r--r--innobase/row/row0ins.c212
1 files changed, 128 insertions, 84 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 941c9d5759d..4e8b487a0f1 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -321,59 +321,6 @@ row_ins_clust_index_entry_by_modify(
return(err);
}
-/*******************************************************************
-Checks if a unique key violation to rec would occur at the index entry
-insert. */
-static
-ibool
-row_ins_dupl_error_with_rec(
-/*========================*/
- /* out: TRUE if error */
- rec_t* rec, /* in: user record; NOTE that we assume
- that the caller already has a record lock on
- the record! */
- dtuple_t* entry, /* in: entry to insert */
- dict_index_t* index) /* in: index */
-{
- ulint matched_fields;
- ulint matched_bytes;
- ulint n_unique;
- ulint i;
-
- n_unique = dict_index_get_n_unique(index);
-
- matched_fields = 0;
- matched_bytes = 0;
-
- cmp_dtuple_rec_with_match(entry, rec, &matched_fields, &matched_bytes);
-
- if (matched_fields < n_unique) {
-
- return(FALSE);
- }
-
- /* In a unique secondary index we allow equal key values if they
- contain SQL NULLs */
-
- if (!(index->type & DICT_CLUSTERED)) {
-
- for (i = 0; i < n_unique; i++) {
- if (UNIV_SQL_NULL == dfield_get_len(
- dtuple_get_nth_field(entry, i))) {
-
- return(FALSE);
- }
- }
- }
-
- if (!rec_get_deleted_flag(rec)) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
/*************************************************************************
Either deletes or sets the referencing columns SQL NULL in a child row.
Used in ON DELETE ... clause for foreign keys when a parent row is
@@ -533,8 +480,12 @@ row_ins_foreign_delete_or_set_null(
err = lock_table(0, table, LOCK_IX, thr);
if (err == DB_SUCCESS) {
+ /* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
+ we already have a normal shared lock on the appropriate
+ gap if the search criterion was not unique */
+
err = lock_clust_rec_read_check_and_lock(0, clust_rec,
- clust_index, LOCK_X, thr);
+ clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
}
if (err != DB_SUCCESS) {
@@ -630,12 +581,14 @@ nonstandard_exit_func:
/*************************************************************************
Sets a shared lock on a record. Used in locking possible duplicate key
-records. */
+records and also in checking foreign key constraints. */
static
ulint
row_ins_set_shared_rec_lock(
/*========================*/
/* out: DB_SUCCESS or error code */
+ ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
+ LOCK_REC_NOT_GAP type lock */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
que_thr_t* thr) /* in: query thread */
@@ -644,10 +597,10 @@ row_ins_set_shared_rec_lock(
if (index->type & DICT_CLUSTERED) {
err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_S,
- thr);
+ type, thr);
} else {
err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_S,
- thr);
+ type, thr);
}
return(err);
@@ -656,7 +609,7 @@ row_ins_set_shared_rec_lock(
/*******************************************************************
Checks if foreign key constraint fails for an index entry. Sets shared locks
which lock either the success or the failure of the constraint. NOTE that
-the caller must have a shared latch on dict_foreign_key_check_lock. */
+the caller must have a shared latch on dict_operation_lock. */
ulint
row_ins_check_foreign_constraint(
@@ -679,7 +632,7 @@ row_ins_check_foreign_constraint(
dict_table_t* check_table;
dict_index_t* check_index;
ulint n_fields_cmp;
- ibool timeout_expired;
+ ibool unique_search;
rec_t* rec;
btr_pcur_t pcur;
ibool moved;
@@ -689,7 +642,9 @@ row_ins_check_foreign_constraint(
mtr_t mtr;
run_again:
- ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
+ ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
+
+ err = DB_SUCCESS;
if (thr_get_trx(thr)->check_foreigns == FALSE) {
/* The user has suppressed foreign key checks currently for
@@ -748,6 +703,14 @@ run_again:
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
+ if (dict_index_get_n_unique(check_index) <= foreign->n_fields) {
+ /* We can just set a LOCK_REC_NOT_GAP type lock */
+
+ unique_search = TRUE;
+ } else {
+ unique_search = FALSE;
+ }
+
btr_pcur_open(check_index, entry, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
@@ -761,25 +724,45 @@ run_again:
goto next_rec;
}
- /* Try to place a lock on the index record */
-
- err = row_ins_set_shared_rec_lock(rec, check_index, thr);
-
- if (err != DB_SUCCESS) {
-
- break;
- }
-
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
+ err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec,
+ check_index, thr);
+ if (err != DB_SUCCESS) {
+
+ break;
+ }
+
goto next_rec;
}
cmp = cmp_dtuple_rec(entry, rec);
if (cmp == 0) {
- if (!rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec)) {
+ err = row_ins_set_shared_rec_lock(LOCK_ORDINARY,
+ rec, check_index, thr);
+ if (err != DB_SUCCESS) {
+
+ break;
+ }
+ } else {
/* Found a matching record */
+
+ if (unique_search) {
+ err = row_ins_set_shared_rec_lock(
+ LOCK_REC_NOT_GAP,
+ rec, check_index, thr);
+ } else {
+ err = row_ins_set_shared_rec_lock(
+ LOCK_ORDINARY,
+ rec, check_index, thr);
+ }
+
+ if (err != DB_SUCCESS) {
+
+ break;
+ }
/* printf(
"FOREIGN: Found matching record from %s %s\n",
@@ -807,6 +790,13 @@ run_again:
}
if (cmp < 0) {
+ err = row_ins_set_shared_rec_lock(LOCK_GAP,
+ rec, check_index, thr);
+ if (err != DB_SUCCESS) {
+
+ break;
+ }
+
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
} else {
@@ -844,14 +834,14 @@ do_possible_lock_wait:
que_thr_stop_for_mysql(thr);
- timeout_expired = srv_suspend_mysql_thread(thr);
+ srv_suspend_mysql_thread(thr);
- if (!timeout_expired) {
+ if (thr_get_trx(thr)->error_state == DB_SUCCESS) {
goto run_again;
}
- err = DB_LOCK_WAIT_TIMEOUT;
+ err = thr_get_trx(thr)->error_state;
}
return(err);
@@ -890,21 +880,21 @@ row_ins_check_foreign_constraints(
trx);
}
- if (!trx->has_dict_foreign_key_check_lock) {
+ if (!trx->has_dict_operation_lock) {
got_s_lock = TRUE;
- rw_lock_s_lock(&dict_foreign_key_check_lock);
+ rw_lock_s_lock(&dict_operation_lock);
- trx->has_dict_foreign_key_check_lock = TRUE;
+ trx->has_dict_operation_lock = TRUE;
}
err = row_ins_check_foreign_constraint(TRUE, foreign,
table, index, entry, thr);
if (got_s_lock) {
- rw_lock_s_unlock(&dict_foreign_key_check_lock);
+ rw_lock_s_unlock(&dict_operation_lock);
- trx->has_dict_foreign_key_check_lock = FALSE;
+ trx->has_dict_operation_lock = FALSE;
}
if (err != DB_SUCCESS) {
@@ -919,6 +909,59 @@ row_ins_check_foreign_constraints(
}
/*******************************************************************
+Checks if a unique key violation to rec would occur at the index entry
+insert. */
+static
+ibool
+row_ins_dupl_error_with_rec(
+/*========================*/
+ /* out: TRUE if error */
+ rec_t* rec, /* in: user record; NOTE that we assume
+ that the caller already has a record lock on
+ the record! */
+ dtuple_t* entry, /* in: entry to insert */
+ dict_index_t* index) /* in: index */
+{
+ ulint matched_fields;
+ ulint matched_bytes;
+ ulint n_unique;
+ ulint i;
+
+ n_unique = dict_index_get_n_unique(index);
+
+ matched_fields = 0;
+ matched_bytes = 0;
+
+ cmp_dtuple_rec_with_match(entry, rec, &matched_fields, &matched_bytes);
+
+ if (matched_fields < n_unique) {
+
+ return(FALSE);
+ }
+
+ /* In a unique secondary index we allow equal key values if they
+ contain SQL NULLs */
+
+ if (!(index->type & DICT_CLUSTERED)) {
+
+ for (i = 0; i < n_unique; i++) {
+ if (UNIV_SQL_NULL == dfield_get_len(
+ dtuple_get_nth_field(entry, i))) {
+
+ return(FALSE);
+ }
+ }
+ }
+
+ if (!rec_get_deleted_flag(rec)) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*******************************************************************
Scans a unique non-clustered index at a given index entry to determine
whether a uniqueness violation has occurred for the key value of the entry.
Set shared locks on possible duplicate records. */
@@ -976,9 +1019,10 @@ row_ins_scan_sec_index_for_duplicate(
goto next_rec;
}
- /* Try to place a lock on the index record */
+ /* Try to place a lock on the index record */
- err = row_ins_set_shared_rec_lock(rec, index, thr);
+ err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec, index,
+ thr);
if (err != DB_SUCCESS) {
@@ -1082,8 +1126,8 @@ row_ins_duplicate_error_in_clust(
sure that in roll-forward we get the same duplicate
errors as in original execution */
- err = row_ins_set_shared_rec_lock(rec, cursor->index,
- thr);
+ err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP,
+ rec, cursor->index, thr);
if (err != DB_SUCCESS) {
return(err);
@@ -1105,8 +1149,8 @@ row_ins_duplicate_error_in_clust(
if (rec != page_get_supremum_rec(page)) {
- err = row_ins_set_shared_rec_lock(rec, cursor->index,
- thr);
+ err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP,
+ rec, cursor->index, thr);
if (err != DB_SUCCESS) {
return(err);