diff options
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/btr/btr0btr.c | 9 | ||||
-rw-r--r-- | innobase/lock/lock0lock.c | 35 | ||||
-rw-r--r-- | innobase/rem/rem0cmp.c | 5 | ||||
-rw-r--r-- | innobase/row/row0ins.c | 119 | ||||
-rw-r--r-- | innobase/row/row0row.c | 33 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 15 | ||||
-rw-r--r-- | innobase/row/row0upd.c | 32 |
7 files changed, 209 insertions, 39 deletions
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c index 27d798f925a..e31aadbbfff 100644 --- a/innobase/btr/btr0btr.c +++ b/innobase/btr/btr0btr.c @@ -2400,14 +2400,17 @@ btr_index_rec_validate( dtype_t* type = dict_index_get_nth_type(index, i); rec_get_nth_field(rec, i, &len); - + + /* Note that prefix indexes are not fixed size even when + their type is CHAR. */ + if ((dict_index_get_nth_field(index, i)->prefix_len == 0 && len != UNIV_SQL_NULL && dtype_is_fixed_size(type) && len != dtype_get_fixed_size(type)) || (dict_index_get_nth_field(index, i)->prefix_len > 0 - && len != UNIV_SQL_NULL && dtype_is_fixed_size(type) - && len != + && len != UNIV_SQL_NULL + && len > dict_index_get_nth_field(index, i)->prefix_len)) { btr_index_rec_validate_report(page, rec, index); diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index c9c0cd109a9..5705c8b0b3e 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -756,9 +756,13 @@ lock_rec_has_to_wait( ulint type_mode,/* in: precise mode of the new lock to set: LOCK_S or LOCK_X, possibly ORed to LOCK_GAP or LOCK_REC_NOT_GAP, LOCK_INSERT_INTENTION */ - lock_t* lock2) /* in: another record lock; NOTE that it is assumed + lock_t* lock2, /* in: another record lock; NOTE that it is assumed that this has a lock bit set on the same record as in the new lock we are setting */ + ibool lock_is_on_supremum) /* in: TRUE if we are setting the lock + on the 'supremum' record of an index + page: we know then that the lock request + is really for a 'gap' type lock */ { ut_ad(trx && lock2); ut_ad(lock_get_type(lock2) == LOCK_REC); @@ -770,10 +774,22 @@ lock_rec_has_to_wait( /* We have somewhat complex rules when gap type record locks cause waits */ - if ((type_mode & LOCK_REC_NOT_GAP) + if ((lock_is_on_supremum || (type_mode & LOCK_GAP)) + && !(type_mode & LOCK_INSERT_INTENTION)) { + + /* Gap type locks without LOCK_INSERT_INTENTION flag + do not need to wait for anything. This is because + different users can have conflicting lock types + on gaps. */ + + return(FALSE); + } + + if (!(type_mode & LOCK_INSERT_INTENTION) && lock_rec_get_gap(lock2)) { - /* Lock on just the record does not need to wait for - a gap type lock */ + + /* Record lock (LOCK_ORDINARY or LOCK_REC_NOT_GAP + does not need to wait for a gap type lock */ return(FALSE); } @@ -829,9 +845,13 @@ lock_has_to_wait( lock_get_mode(lock2))) { if (lock_get_type(lock1) == LOCK_REC) { ut_ad(lock_get_type(lock2) == LOCK_REC); - + + /* If this lock request is for a supremum record + then the second bit on the lock bitmap is set */ + return(lock_rec_has_to_wait(lock1->trx, - lock1->type_mode, lock2)); + lock1->type_mode, lock2, + lock_rec_get_nth_bit(lock1,1))); } return(TRUE); @@ -1420,7 +1440,8 @@ lock_rec_other_has_conflicting( lock = lock_rec_get_first(rec); while (lock) { - if (lock_rec_has_to_wait(trx, mode, lock)) { + if (lock_rec_has_to_wait(trx, mode, lock, + page_rec_is_supremum(rec))) { return(lock); } diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c index 6e8f3d82ef3..041fb7914e2 100644 --- a/innobase/rem/rem0cmp.c +++ b/innobase/rem/rem0cmp.c @@ -452,7 +452,7 @@ cmp_dtuple_rec_with_match( ulint cur_bytes; /* number of already matched bytes in current field */ int ret = 3333; /* return value */ - + ut_ad(dtuple && rec && matched_fields && matched_bytes); ut_ad(dtuple_check_typed(dtuple)); @@ -541,7 +541,8 @@ cmp_dtuple_rec_with_match( && dtype_get_charset_coll(cur_type->prtype) != data_mysql_latin1_swedish_charset_coll)) { - ret = cmp_whole_field(cur_type, + ret = cmp_whole_field( + cur_type, dfield_get_data(dtuple_field), dtuple_f_len, rec_b_ptr, rec_f_len); diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 0da749212d2..35641c351a1 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1022,6 +1022,33 @@ row_ins_set_shared_rec_lock( return(err); } + +/************************************************************************* +Sets a exclusive lock on a record. Used in locking possible duplicate key +records */ +static +ulint +row_ins_set_exclusive_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 */ +{ + ulint err; + + if (index->type & DICT_CLUSTERED) { + err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_X, + type, thr); + } else { + err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_X, + type, thr); + } + + return(err); +} /******************************************************************* Checks if foreign key constraint fails for an index entry. Sets shared locks @@ -1451,6 +1478,8 @@ row_ins_scan_sec_index_for_duplicate( ulint err = DB_SUCCESS; ibool moved; mtr_t mtr; + trx_t *trx; + ibool success; n_unique = dict_index_get_n_unique(index); @@ -1488,8 +1517,24 @@ row_ins_scan_sec_index_for_duplicate( /* Try to place a lock on the index record */ - err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec, index, - thr); + trx = thr_get_trx(thr); + ut_ad(trx); + dict_accept(*trx->mysql_query_str, "REPLACE", &success); + + if (success) { + + /* The manual defines the REPLACE semantics that it + is either an INSERT or DELETE(s) for duplicate key + + INSERT. Therefore, we should take X-lock for + duplicates */ + + err = row_ins_set_exclusive_rec_lock( + LOCK_ORDINARY,rec,index,thr); + } else { + + err = row_ins_set_shared_rec_lock( + LOCK_ORDINARY, rec, index,thr); + } if (err != DB_SUCCESS) { @@ -1556,6 +1601,7 @@ row_ins_duplicate_error_in_clust( page_t* page; ulint n_unique; trx_t* trx = thr_get_trx(thr); + ibool success; UT_NOT_USED(mtr); @@ -1588,9 +1634,27 @@ row_ins_duplicate_error_in_clust( is needed in logical logging of MySQL to make sure that in roll-forward we get the same duplicate errors as in original execution */ - - err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP, - rec, cursor->index, thr); + + dict_accept(*trx->mysql_query_str, "REPLACE", + &success); + + if (success) { + + /* The manual defines the REPLACE semantics + that it is either an INSERT or DELETE(s) + for duplicate key + INSERT. Therefore, we + should take X-lock for duplicates */ + + err = row_ins_set_exclusive_rec_lock( + LOCK_REC_NOT_GAP,rec,cursor->index, + thr); + } else { + + err = row_ins_set_shared_rec_lock( + LOCK_REC_NOT_GAP,rec, cursor->index, + thr); + } + if (err != DB_SUCCESS) { return(err); @@ -1611,8 +1675,30 @@ row_ins_duplicate_error_in_clust( if (rec != page_get_supremum_rec(page)) { - err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP, - rec, cursor->index, thr); + + /* The manual defines the REPLACE semantics that it + is either an INSERT or DELETE(s) for duplicate key + + INSERT. Therefore, we should take X-lock for + duplicates. + */ + + /* Is the first word in MySQL query REPLACE ? */ + + dict_accept(*trx->mysql_query_str, "REPLACE", + &success); + + if (success) { + + err = row_ins_set_exclusive_rec_lock( + LOCK_REC_NOT_GAP, + rec,cursor->index,thr); + } else { + + err = row_ins_set_shared_rec_lock( + LOCK_REC_NOT_GAP,rec, + cursor->index, thr); + } + if (err != DB_SUCCESS) { return(err); @@ -1913,6 +1999,7 @@ row_ins_index_entry_set_vals( dfield_t* row_field; ulint n_fields; ulint i; + dtype_t* cur_type; ut_ad(entry && row); @@ -1926,10 +2013,18 @@ row_ins_index_entry_set_vals( /* Check column prefix indexes */ if (ind_field->prefix_len > 0 - && dfield_get_len(row_field) != UNIV_SQL_NULL - && dfield_get_len(row_field) > ind_field->prefix_len) { - - field->len = ind_field->prefix_len; + && dfield_get_len(row_field) != UNIV_SQL_NULL) { + + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(ind_field)); + + field->len = innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + ind_field->prefix_len, + dfield_get_len(row_field),row_field->data); } else { field->len = row_field->len; } @@ -2214,4 +2309,4 @@ error_handling: } return(thr); -} +} diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c index 680539764fd..ed6462b7377 100644 --- a/innobase/row/row0row.c +++ b/innobase/row/row0row.c @@ -113,6 +113,8 @@ row_build_index_entry( dfield_t* dfield2; dict_col_t* col; ulint i; + ulint storage_len; + dtype_t* cur_type; ut_ad(row && index && heap); ut_ad(dtuple_check_typed(row)); @@ -139,10 +141,20 @@ row_build_index_entry( /* If a column prefix index, take only the prefix */ if (ind_field->prefix_len > 0 - && dfield_get_len(dfield2) != UNIV_SQL_NULL - && dfield_get_len(dfield2) > ind_field->prefix_len) { + && dfield_get_len(dfield2) != UNIV_SQL_NULL) { - dfield_set_len(dfield, ind_field->prefix_len); + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(ind_field)); + + storage_len = innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + ind_field->prefix_len, + dfield_get_len(dfield2),dfield2->data); + + dfield_set_len(dfield,storage_len); } } @@ -460,6 +472,7 @@ row_build_row_ref_from_row( dict_col_t* col; ulint ref_len; ulint i; + dtype_t* cur_type; ut_ad(ref && table && row); @@ -481,10 +494,18 @@ row_build_row_ref_from_row( dfield_copy(dfield, dfield2); if (field->prefix_len > 0 - && dfield->len != UNIV_SQL_NULL - && dfield->len > field->prefix_len) { + && dfield->len != UNIV_SQL_NULL) { + + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(field)); - dfield->len = field->prefix_len; + dfield->len = innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + field->prefix_len, + dfield->len,dfield->data); } } diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 2c0092adc6e..d87cc857651 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -76,6 +76,7 @@ row_sel_sec_rec_is_for_clust_rec( ulint clust_len; ulint n; ulint i; + dtype_t* cur_type; UT_NOT_USED(clust_index); @@ -91,10 +92,18 @@ row_sel_sec_rec_is_for_clust_rec( sec_field = rec_get_nth_field(sec_rec, i, &sec_len); if (ifield->prefix_len > 0 - && clust_len != UNIV_SQL_NULL - && clust_len > ifield->prefix_len) { + && clust_len != UNIV_SQL_NULL) { - clust_len = ifield->prefix_len; + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(ifield)); + + clust_len = innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + ifield->prefix_len, + clust_len,clust_field); } if (0 != cmp_data_data(dict_col_get_type(col), diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index d35ae0a3e38..75400e06059 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -842,6 +842,7 @@ row_upd_index_replace_new_col_vals_index_pos( dfield_t* new_val; ulint j; ulint i; + dtype_t* cur_type; ut_ad(index); @@ -871,10 +872,19 @@ row_upd_index_replace_new_col_vals_index_pos( } if (field->prefix_len > 0 - && new_val->len != UNIV_SQL_NULL - && new_val->len > field->prefix_len) { + && new_val->len != UNIV_SQL_NULL) { - dfield->len = field->prefix_len; + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(field)); + + dfield->len = + innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + field->prefix_len, + new_val->len,new_val->data); } } } @@ -904,6 +914,7 @@ row_upd_index_replace_new_col_vals( dfield_t* new_val; ulint j; ulint i; + dtype_t* cur_type; ut_ad(index); @@ -933,10 +944,19 @@ row_upd_index_replace_new_col_vals( } if (field->prefix_len > 0 - && new_val->len != UNIV_SQL_NULL - && new_val->len > field->prefix_len) { + && new_val->len != UNIV_SQL_NULL) { + + /* For prefix keys get the storage length + for the prefix_len characters. */ + + cur_type = dict_col_get_type( + dict_field_get_col(field)); - dfield->len = field->prefix_len; + dfield->len = + innobase_get_at_most_n_mbchars( + dtype_get_charset_coll(cur_type->prtype), + field->prefix_len, + new_val->len,new_val->data); } } } |