Loading innobase/btr/btr0btr.c +6 −3 Original line number Diff line number Diff line Loading @@ -2401,13 +2401,16 @@ btr_index_rec_validate( 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); Loading innobase/lock/lock0lock.c +28 −7 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } Loading Loading @@ -830,8 +846,12 @@ lock_has_to_wait( 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); Loading Loading @@ -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); } Loading innobase/rem/rem0cmp.c +3 −2 Original line number Diff line number Diff line Loading @@ -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); Loading innobase/row/row0ins.c +107 −12 Original line number Diff line number Diff line Loading @@ -1023,6 +1023,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 which lock either the success or the failure of the constraint. NOTE that Loading Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -1589,8 +1635,26 @@ 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(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); Loading @@ -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, /* 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); Loading Loading @@ -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); Loading @@ -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) { && 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 = ind_field->prefix_len; 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; } Loading innobase/row/row0row.c +27 −6 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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); } } Loading Loading
innobase/btr/btr0btr.c +6 −3 Original line number Diff line number Diff line Loading @@ -2401,13 +2401,16 @@ btr_index_rec_validate( 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); Loading
innobase/lock/lock0lock.c +28 −7 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } Loading Loading @@ -830,8 +846,12 @@ lock_has_to_wait( 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); Loading Loading @@ -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); } Loading
innobase/rem/rem0cmp.c +3 −2 Original line number Diff line number Diff line Loading @@ -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); Loading
innobase/row/row0ins.c +107 −12 Original line number Diff line number Diff line Loading @@ -1023,6 +1023,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 which lock either the success or the failure of the constraint. NOTE that Loading Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -1589,8 +1635,26 @@ 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(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); Loading @@ -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, /* 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); Loading Loading @@ -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); Loading @@ -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) { && 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 = ind_field->prefix_len; 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; } Loading
innobase/row/row0row.c +27 −6 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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); } } Loading