diff options
Diffstat (limited to 'storage/innobase/row/row0ins.cc')
-rw-r--r-- | storage/innobase/row/row0ins.cc | 108 |
1 files changed, 70 insertions, 38 deletions
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index be67d629569..de58e3896b0 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2011,6 +2011,61 @@ row_ins_dupl_error_with_rec( return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); } +/** Determine whether a history row was inserted by this transaction +(row TRX_ID is the same as current TRX_ID). +@param index secondary index +@param rec secondary index record +@param trx transaction +@return error code +@retval DB_SUCCESS on success +@retval DB_FOREIGN_DUPLICATE_KEY if a history row was inserted by trx */ +static dberr_t vers_row_same_trx(dict_index_t* index, const rec_t* rec, + const trx_t& trx) +{ + mtr_t mtr; + dberr_t ret= DB_SUCCESS; + dict_index_t *clust_index= dict_table_get_first_index(index->table); + ut_ad(index != clust_index); + + mtr.start(); + + if (const rec_t *clust_rec= + row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr)) + { + rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; + rec_offs *clust_offs= offsets_; + rec_offs_init(offsets_); + mem_heap_t *heap= NULL; + + clust_offs= + rec_get_offsets(clust_rec, clust_index, clust_offs, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); + if (clust_index->vers_history_row(clust_rec, clust_offs)) + { + ulint trx_id_len; + const byte *trx_id= rec_get_nth_field(clust_rec, clust_offs, + clust_index->n_uniq, &trx_id_len); + ut_ad(trx_id_len == DATA_TRX_ID_LEN); + + if (trx.id == trx_read_trx_id(trx_id)) + ret= DB_FOREIGN_DUPLICATE_KEY; + } + + if (UNIV_LIKELY_NULL(heap)) + mem_heap_free(heap); + } + else + { + ib::error() << "foreign constraints: secondary index " << index->name << + " of table " << index->table->name << " is out of sync"; + ut_ad("secondary index is out of sync" == 0); + ret= DB_TABLE_CORRUPT; + } + + mtr.commit(); + return ret; +} + /***************************************************************//** 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. @@ -2061,8 +2116,8 @@ row_ins_scan_sec_index_for_duplicate( n_fields_cmp = dtuple_get_n_fields_cmp(entry); dtuple_set_n_fields_cmp(entry, n_unique); - const auto allow_duplicates = thr_get_trx(thr)->duplicates; pcur.btr_cur.page_cur.index = index; + trx_t* const trx = thr_get_trx(thr); dberr_t err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, 0, mtr); if (err != DB_SUCCESS) { @@ -2088,7 +2143,7 @@ row_ins_scan_sec_index_for_duplicate( if (flags & BTR_NO_LOCKING_FLAG) { /* Set no locks when applying log in online table rebuild. */ - } else if (allow_duplicates) { + } else if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -2122,9 +2177,18 @@ row_ins_scan_sec_index_for_duplicate( if (cmp == 0) { if (row_ins_dupl_error_with_rec(rec, entry, index, offsets)) { + err = DB_DUPLICATE_KEY; - thr_get_trx(thr)->error_info = index; + trx->error_info = index; + + if (!index->table->versioned()) { + } else if (dberr_t e = + vers_row_same_trx(index, rec, + *trx)) { + err = e; + goto end_scan; + } /* If the duplicate is on hidden FTS_DOC_ID, state so in the error log */ @@ -3559,16 +3623,6 @@ row_ins_get_row_from_select( } } -inline -bool ins_node_t::vers_history_row() const -{ - if (!table->versioned()) - return false; - dfield_t* row_end = dtuple_get_nth_field(row, table->vers_end); - return row_end->vers_history_row(); -} - - /***********************************************************//** Inserts a row to a table. @return DB_SUCCESS if operation successfully completed, else error @@ -3607,34 +3661,12 @@ row_ins( ut_ad(node->state == INS_NODE_INSERT_ENTRIES); while (dict_index_t *index = node->index) { - /* - We do not insert history rows into FTS_DOC_ID_INDEX because - it is unique by FTS_DOC_ID only and we do not want to add - row_end to unique key. Fulltext field works the way new - FTS_DOC_ID is created on every fulltext UPDATE, so holding only - FTS_DOC_ID for history is enough. - */ - const unsigned type = index->type; if (index->type & (DICT_FTS | DICT_CORRUPT) || !index->is_committed()) { - } else if (!(type & DICT_UNIQUE) || index->n_uniq > 1 - || !node->vers_history_row()) { - - dberr_t err = row_ins_index_entry_step(node, thr); - - if (err != DB_SUCCESS) { - DBUG_RETURN(err); - } - } else { - /* Unique indexes with system versioning must contain - the version end column. The only exception is a hidden - FTS_DOC_ID_INDEX that InnoDB may create on a hidden or - user-created FTS_DOC_ID column. */ - ut_ad(!strcmp(index->name, FTS_DOC_ID_INDEX_NAME)); - ut_ad(!strcmp(index->fields[0].name, FTS_DOC_ID_COL_NAME)); + } else if (dberr_t err = row_ins_index_entry_step(node, thr)) { + DBUG_RETURN(err); } - - node->index = dict_table_get_next_index(node->index); + node->index = dict_table_get_next_index(index); ++node->entry; } |