summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0ins.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row/row0ins.cc')
-rw-r--r--storage/innobase/row/row0ins.cc108
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;
}