summaryrefslogtreecommitdiff
path: root/storage/xtradb/row/row0upd.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/row/row0upd.c')
-rw-r--r--storage/xtradb/row/row0upd.c538
1 files changed, 402 insertions, 136 deletions
diff --git a/storage/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c
index 04c3139fcc7..01fb44f42de 100644
--- a/storage/xtradb/row/row0upd.c
+++ b/storage/xtradb/row/row0upd.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -238,7 +238,7 @@ row_upd_check_references_constraints(
foreign->n_fields))) {
if (foreign->foreign_table == NULL) {
- dict_table_get(foreign->foreign_table_name,
+ dict_table_get(foreign->foreign_table_name_lookup,
FALSE);
}
@@ -371,13 +371,13 @@ UNIV_INTERN
void
row_upd_index_entry_sys_field(
/*==========================*/
- const dtuple_t* entry, /*!< in: index entry, where the memory buffers
- for sys fields are already allocated:
+ dtuple_t* entry, /*!< in/out: index entry, where the memory
+ buffers for sys fields are already allocated:
the function just copies the new values to
them */
dict_index_t* index, /*!< in: clustered index */
ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
- dulint val) /*!< in: value to write */
+ ib_uint64_t val) /*!< in: value to write */
{
dfield_t* dfield;
byte* field;
@@ -439,6 +439,12 @@ row_upd_changes_field_size_or_external(
0);
}
+ if (srv_use_sys_stats_table
+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
+ && upd_field->field_no >= rec_offs_n_fields(offsets)) {
+ return(TRUE);
+ }
+
old_len = rec_offs_nth_size(offsets, upd_field->field_no);
if (rec_offs_comp(offsets)
@@ -466,8 +472,11 @@ row_upd_changes_field_size_or_external(
#endif /* !UNIV_HOTBACKUP */
/***********************************************************//**
-Replaces the new column values stored in the update vector to the record
-given. No field size changes are allowed. */
+Replaces the new column values stored in the update vector to the
+record given. No field size changes are allowed. This function is
+usually invoked on a clustered index. The only use case for a
+secondary index is row_ins_sec_index_entry_by_modify() or its
+counterpart in ibuf_insert_to_index_page(). */
UNIV_INTERN
void
row_upd_rec_in_place(
@@ -495,14 +504,49 @@ row_upd_rec_in_place(
n_fields = upd_get_n_fields(update);
for (i = 0; i < n_fields; i++) {
+#ifdef UNIV_BLOB_DEBUG
+ btr_blob_dbg_t b;
+ const byte* field_ref = NULL;
+#endif /* UNIV_BLOB_DEBUG */
+
upd_field = upd_get_nth_field(update, i);
new_val = &(upd_field->new_val);
ut_ad(!dfield_is_ext(new_val) ==
!rec_offs_nth_extern(offsets, upd_field->field_no));
+#ifdef UNIV_BLOB_DEBUG
+ if (dfield_is_ext(new_val)) {
+ ulint len;
+ field_ref = rec_get_nth_field(rec, offsets, i, &len);
+ ut_a(len != UNIV_SQL_NULL);
+ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
+ field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
+
+ b.ref_page_no = page_get_page_no(page_align(rec));
+ b.ref_heap_no = page_rec_get_heap_no(rec);
+ b.ref_field_no = i;
+ b.blob_page_no = mach_read_from_4(
+ field_ref + BTR_EXTERN_PAGE_NO);
+ ut_a(b.ref_field_no >= index->n_uniq);
+ btr_blob_dbg_rbt_delete(index, &b, "upd_in_place");
+ }
+#endif /* UNIV_BLOB_DEBUG */
rec_set_nth_field(rec, offsets, upd_field->field_no,
dfield_get_data(new_val),
dfield_get_len(new_val));
+
+#ifdef UNIV_BLOB_DEBUG
+ if (dfield_is_ext(new_val)) {
+ b.blob_page_no = mach_read_from_4(
+ field_ref + BTR_EXTERN_PAGE_NO);
+ b.always_owner = b.owner = !(field_ref[BTR_EXTERN_LEN]
+ & BTR_EXTERN_OWNER_FLAG);
+ b.del = rec_get_deleted_flag(
+ rec, rec_offs_comp(offsets));
+
+ btr_blob_dbg_rbt_insert(index, &b, "upd_in_place");
+ }
+#endif /* UNIV_BLOB_DEBUG */
}
if (UNIV_LIKELY_NULL(page_zip)) {
@@ -536,7 +580,7 @@ row_upd_write_sys_vals_to_log(
trx_write_roll_ptr(log_ptr, roll_ptr);
log_ptr += DATA_ROLL_PTR_LEN;
- log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
+ log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
return(log_ptr);
}
@@ -570,7 +614,7 @@ row_upd_parse_sys_vals(
*roll_ptr = trx_read_roll_ptr(ptr);
ptr += DATA_ROLL_PTR_LEN;
- ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
+ ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
return(ptr);
}
@@ -841,6 +885,18 @@ row_upd_build_difference_binary(
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
+ if (srv_use_sys_stats_table
+ && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
+ && i >= rec_offs_n_fields(offsets)) {
+ dfield = dtuple_get_nth_field(entry, i);
+
+ upd_field = upd_get_nth_field(update, n_diff);
+ dfield_copy(&(upd_field->new_val), dfield);
+ upd_field_set_field_no(upd_field, i, index, trx);
+ n_diff++;
+ goto skip_compare;
+ }
+
data = rec_get_nth_field(rec, offsets, i, &len);
dfield = dtuple_get_nth_field(entry, i);
@@ -949,7 +1005,7 @@ row_upd_index_replace_new_col_val(
}
len = dtype_get_at_most_n_mbchars(col->prtype,
- col->mbminlen, col->mbmaxlen,
+ col->mbminmaxlen,
field->prefix_len, len,
(const char*) data);
@@ -1173,8 +1229,8 @@ row_upd_replace(
}
if (n_ext_cols) {
- *ext = row_ext_create(n_ext_cols, ext_cols, row,
- dict_table_zip_size(table), heap);
+ *ext = row_ext_create(n_ext_cols, ext_cols, table->flags, row,
+ heap);
} else {
*ext = NULL;
}
@@ -1189,26 +1245,33 @@ NOTE: we compare the fields as binary strings!
@return TRUE if update vector changes an ordering field in the index record */
UNIV_INTERN
ibool
-row_upd_changes_ord_field_binary(
-/*=============================*/
+row_upd_changes_ord_field_binary_func(
+/*==================================*/
+ dict_index_t* index, /*!< in: index of the record */
+ const upd_t* update, /*!< in: update vector for the row; NOTE: the
+ field numbers in this MUST be clustered index
+ positions! */
+#ifdef UNIV_DEBUG
+ const que_thr_t*thr, /*!< in: query thread */
+#endif /* UNIV_DEBUG */
const dtuple_t* row, /*!< in: old value of row, or NULL if the
row and the data values in update are not
known when this function is called, e.g., at
compile time */
- dict_index_t* index, /*!< in: index of the record */
- const upd_t* update) /*!< in: update vector for the row; NOTE: the
- field numbers in this MUST be clustered index
- positions! */
+ const row_ext_t*ext) /*!< NULL, or prefixes of the externally
+ stored columns in the old row */
{
- ulint n_unique;
- ulint n_upd_fields;
- ulint i, j;
- dict_index_t* clust_index;
+ ulint n_unique;
+ ulint i;
+ const dict_index_t* clust_index;
- ut_ad(update && index);
+ ut_ad(index);
+ ut_ad(update);
+ ut_ad(thr);
+ ut_ad(thr->graph);
+ ut_ad(thr->graph->trx);
n_unique = dict_index_get_n_unique(index);
- n_upd_fields = upd_get_n_fields(update);
clust_index = dict_table_get_first_index(index->table);
@@ -1216,33 +1279,81 @@ row_upd_changes_ord_field_binary(
const dict_field_t* ind_field;
const dict_col_t* col;
- ulint col_pos;
ulint col_no;
+ const upd_field_t* upd_field;
+ const dfield_t* dfield;
+ dfield_t dfield_ext;
+ ulint dfield_len;
+ const byte* buf;
ind_field = dict_index_get_nth_field(index, i);
col = dict_field_get_col(ind_field);
- col_pos = dict_col_get_clust_pos(col, clust_index);
col_no = dict_col_get_no(col);
- for (j = 0; j < n_upd_fields; j++) {
+ upd_field = upd_get_field_by_field_no(
+ update, dict_col_get_clust_pos(col, clust_index));
- const upd_field_t* upd_field
- = upd_get_nth_field(update, j);
+ if (upd_field == NULL) {
+ continue;
+ }
- /* Note that if the index field is a column prefix
- then it may be that row does not contain an externally
- stored part of the column value, and we cannot compare
- the datas */
+ if (row == NULL) {
+ ut_ad(ext == NULL);
+ return(TRUE);
+ }
- if (col_pos == upd_field->field_no
- && (row == NULL
- || ind_field->prefix_len > 0
- || !dfield_datas_are_binary_equal(
- dtuple_get_nth_field(row, col_no),
- &(upd_field->new_val)))) {
+ dfield = dtuple_get_nth_field(row, col_no);
- return(TRUE);
+ /* This treatment of column prefix indexes is loosely
+ based on row_build_index_entry(). */
+
+ if (UNIV_LIKELY(ind_field->prefix_len == 0)
+ || dfield_is_null(dfield)) {
+ /* do nothing special */
+ } else if (UNIV_LIKELY_NULL(ext)) {
+ /* Silence a compiler warning without
+ silencing a Valgrind error. */
+ dfield_len = 0;
+ UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len);
+ /* See if the column is stored externally. */
+ buf = row_ext_lookup(ext, col_no, &dfield_len);
+
+ ut_ad(col->ord_part);
+
+ if (UNIV_LIKELY_NULL(buf)) {
+ if (UNIV_UNLIKELY(buf == field_ref_zero)) {
+ /* The externally stored field
+ was not written yet. This
+ record should only be seen by
+ recv_recovery_rollback_active(),
+ when the server had crashed before
+ storing the field. */
+ ut_ad(thr->graph->trx->is_recovered);
+ ut_ad(trx_is_recv(thr->graph->trx));
+ return(TRUE);
+ }
+
+ goto copy_dfield;
}
+ } else if (dfield_is_ext(dfield)) {
+ dfield_len = dfield_get_len(dfield);
+ ut_a(dfield_len > BTR_EXTERN_FIELD_REF_SIZE);
+ dfield_len -= BTR_EXTERN_FIELD_REF_SIZE;
+ ut_a(dict_index_is_clust(index)
+ || ind_field->prefix_len <= dfield_len);
+ buf = dfield_get_data(dfield);
+copy_dfield:
+ ut_a(dfield_len > 0);
+ dfield_copy(&dfield_ext, dfield);
+ dfield_set_data(&dfield_ext, buf, dfield_len);
+ dfield = &dfield_ext;
+ }
+
+ if (!dfield_datas_are_binary_equal(
+ dfield, &upd_field->new_val,
+ ind_field->prefix_len)) {
+
+ return(TRUE);
}
}
@@ -1326,7 +1437,7 @@ row_upd_changes_first_fields_binary(
if (col_pos == upd_field->field_no
&& !dfield_datas_are_binary_equal(
dtuple_get_nth_field(entry, i),
- &(upd_field->new_val))) {
+ &upd_field->new_val, 0)) {
return(TRUE);
}
@@ -1456,21 +1567,22 @@ row_upd_sec_index_entry(
upd_node_t* node, /*!< in: row update node */
que_thr_t* thr) /*!< in: query thread */
{
- ibool check_ref;
- ibool found;
- dict_index_t* index;
- dtuple_t* entry;
- btr_pcur_t pcur;
- btr_cur_t* btr_cur;
- mem_heap_t* heap;
- rec_t* rec;
- ulint err = DB_SUCCESS;
- mtr_t mtr;
- trx_t* trx = thr_get_trx(thr);
+ mtr_t mtr;
+ const rec_t* rec;
+ btr_pcur_t pcur;
+ mem_heap_t* heap;
+ dtuple_t* entry;
+ dict_index_t* index;
+ btr_cur_t* btr_cur;
+ ibool referenced;
+ ulint err = DB_SUCCESS;
+ trx_t* trx = thr_get_trx(thr);
+ ulint mode = BTR_MODIFY_LEAF;
+ enum row_search_result search_result;
index = node->index;
- check_ref = row_upd_index_is_referenced(index, trx);
+ referenced = row_upd_index_is_referenced(index, trx);
heap = mem_heap_create(1024);
@@ -1480,13 +1592,33 @@ row_upd_sec_index_entry(
mtr_start(&mtr);
- found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
- &mtr);
+ /* Set the query thread, so that ibuf_insert_low() will be
+ able to invoke thd_get_trx(). */
+ btr_pcur_get_btr_cur(&pcur)->thr = thr;
+
+ /* We can only try to use the insert/delete buffer to buffer
+ delete-mark operations if the index we're modifying has no foreign
+ key constraints referring to it. */
+ if (!referenced) {
+ mode |= BTR_DELETE_MARK;
+ }
+
+ search_result = row_search_index_entry(index, entry, mode,
+ &pcur, &mtr);
+
btr_cur = btr_pcur_get_btr_cur(&pcur);
rec = btr_cur_get_rec(btr_cur);
- if (UNIV_UNLIKELY(!found)) {
+ switch (search_result) {
+ case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
+ ut_error;
+ break;
+ case ROW_BUFFERED:
+ /* Entry was delete marked already. */
+ break;
+
+ case ROW_NOT_FOUND:
fputs("InnoDB: error in sec index entry update in\n"
"InnoDB: ", stderr);
dict_index_name_print(stderr, trx, index);
@@ -1503,20 +1635,26 @@ row_upd_sec_index_entry(
fputs("\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
- } else {
+ break;
+ case ROW_FOUND:
/* Delete mark the old index record; it can already be
delete marked if we return after a lock wait in
row_ins_index_entry below */
- if (!rec_get_deleted_flag(rec,
- dict_table_is_comp(index->table))) {
- err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
- thr, &mtr);
- if (err == DB_SUCCESS && check_ref) {
+ if (!rec_get_deleted_flag(
+ rec, dict_table_is_comp(index->table))) {
+
+ err = btr_cur_del_mark_set_sec_rec(
+ 0, btr_cur, TRUE, thr, &mtr);
+
+ if (err == DB_SUCCESS && referenced) {
+
+ ulint* offsets;
+
+ offsets = rec_get_offsets(
+ rec, index, NULL, ULINT_UNDEFINED,
+ &heap);
- ulint* offsets = rec_get_offsets(
- rec, index, NULL,
- ULINT_UNDEFINED, &heap);
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
@@ -1524,6 +1662,7 @@ row_upd_sec_index_entry(
index, offsets, thr, &mtr);
}
}
+ break;
}
btr_pcur_close(&pcur);
@@ -1565,14 +1704,99 @@ row_upd_sec_step(
ut_ad(!dict_index_is_clust(node->index));
if (node->state == UPD_NODE_UPDATE_ALL_SEC
- || row_upd_changes_ord_field_binary(node->row, node->index,
- node->update)) {
+ || row_upd_changes_ord_field_binary(node->index, node->update,
+ thr, node->row, node->ext)) {
return(row_upd_sec_index_entry(node, thr));
}
return(DB_SUCCESS);
}
+#ifdef UNIV_DEBUG
+# define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
+ row_upd_clust_rec_by_insert_inherit_func(rec,offsets,entry,update)
+#else /* UNIV_DEBUG */
+# define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
+ row_upd_clust_rec_by_insert_inherit_func(entry,update)
+#endif /* UNIV_DEBUG */
+/*******************************************************************//**
+Mark non-updated off-page columns inherited when the primary key is
+updated. We must mark them as inherited in entry, so that they are not
+freed in a rollback. A limited version of this function used to be
+called btr_cur_mark_dtuple_inherited_extern().
+@return TRUE if any columns were inherited */
+static __attribute__((warn_unused_result))
+ibool
+row_upd_clust_rec_by_insert_inherit_func(
+/*=====================================*/
+#ifdef UNIV_DEBUG
+ const rec_t* rec, /*!< in: old record, or NULL */
+ const ulint* offsets,/*!< in: rec_get_offsets(rec), or NULL */
+#endif /* UNIV_DEBUG */
+ dtuple_t* entry, /*!< in/out: updated entry to be
+ inserted into the clustered index */
+ const upd_t* update) /*!< in: update vector */
+{
+ ibool inherit = FALSE;
+ ulint i;
+
+ ut_ad(!rec == !offsets);
+ ut_ad(!rec || rec_offs_any_extern(offsets));
+
+ for (i = 0; i < dtuple_get_n_fields(entry); i++) {
+ dfield_t* dfield = dtuple_get_nth_field(entry, i);
+ byte* data;
+ ulint len;
+
+ ut_ad(!offsets
+ || !rec_offs_nth_extern(offsets, i)
+ == !dfield_is_ext(dfield)
+ || upd_get_field_by_field_no(update, i));
+ if (!dfield_is_ext(dfield)
+ || upd_get_field_by_field_no(update, i)) {
+ continue;
+ }
+
+#ifdef UNIV_DEBUG
+ if (UNIV_LIKELY(rec != NULL)) {
+ const byte* rec_data
+ = rec_get_nth_field(rec, offsets, i, &len);
+ ut_ad(len == dfield_get_len(dfield));
+ ut_ad(len != UNIV_SQL_NULL);
+ ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ rec_data += len - BTR_EXTERN_FIELD_REF_SIZE;
+
+ /* The pointer must not be zero. */
+ ut_ad(memcmp(rec_data, field_ref_zero,
+ BTR_EXTERN_FIELD_REF_SIZE));
+ /* The BLOB must be owned. */
+ ut_ad(!(rec_data[BTR_EXTERN_LEN]
+ & BTR_EXTERN_OWNER_FLAG));
+ }
+#endif /* UNIV_DEBUG */
+
+ len = dfield_get_len(dfield);
+ ut_a(len != UNIV_SQL_NULL);
+ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
+ data = dfield_get_data(dfield);
+ data += len - BTR_EXTERN_FIELD_REF_SIZE;
+ /* The pointer must not be zero. */
+ ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
+ /* The BLOB must be owned. */
+ ut_a(!(data[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
+
+ data[BTR_EXTERN_LEN] |= BTR_EXTERN_INHERITED_FLAG;
+ /* The BTR_EXTERN_INHERITED_FLAG only matters in
+ rollback. Purge will always free the extern fields of
+ a delete-marked row. */
+
+ inherit = TRUE;
+ }
+
+ return(inherit);
+}
+
/***********************************************************//**
Marks the clustered index record deleted and inserts the updated version
of the record to the index. This function should be used when the ordering
@@ -1584,21 +1808,23 @@ static
ulint
row_upd_clust_rec_by_insert(
/*========================*/
- upd_node_t* node, /*!< in: row update node */
+ upd_node_t* node, /*!< in/out: row update node */
dict_index_t* index, /*!< in: clustered index of the record */
que_thr_t* thr, /*!< in: query thread */
- ibool check_ref,/*!< in: TRUE if index may be referenced in
+ ibool referenced,/*!< in: TRUE if index may be referenced in
a foreign key constraint */
- mtr_t* mtr) /*!< in: mtr; gets committed here */
+ mtr_t* mtr) /*!< in/out: mtr; gets committed here */
{
- mem_heap_t* heap = NULL;
+ mem_heap_t* heap;
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
trx_t* trx;
dict_table_t* table;
dtuple_t* entry;
ulint err;
- ibool change_ownership = FALSE;
+ ibool change_ownership = FALSE;
+ rec_t* rec;
+ ulint* offsets = NULL;
ut_ad(node);
ut_ad(dict_index_is_clust(index));
@@ -1608,77 +1834,114 @@ row_upd_clust_rec_by_insert(
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
- if (node->state != UPD_NODE_INSERT_CLUSTERED) {
- rec_t* rec;
- dict_index_t* index;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets;
- rec_offs_init(offsets_);
+ heap = mem_heap_create(1000);
+
+ entry = row_build_index_entry(node->upd_row, node->upd_ext,
+ index, heap);
+ ut_a(entry);
+
+ row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
+
+ switch (node->state) {
+ default:
+ ut_error;
+ case UPD_NODE_INSERT_BLOB:
+ /* A lock wait occurred in row_ins_index_entry() in
+ the previous invocation of this function. Mark the
+ off-page columns in the entry inherited. */
+
+ change_ownership = row_upd_clust_rec_by_insert_inherit(
+ NULL, NULL, entry, node->update);
+ ut_a(change_ownership);
+ /* fall through */
+ case UPD_NODE_INSERT_CLUSTERED:
+ /* A lock wait occurred in row_ins_index_entry() in
+ the previous invocation of this function. */
+ break;
+ case UPD_NODE_UPDATE_CLUSTERED:
+ /* This is the first invocation of the function where
+ we update the primary key. Delete-mark the old record
+ in the clustered index and prepare to insert a new entry. */
+ rec = btr_cur_get_rec(btr_cur);
+ offsets = rec_get_offsets(rec, index, NULL,
+ ULINT_UNDEFINED, &heap);
+ ut_ad(page_rec_is_user_rec(rec));
- err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
- btr_cur, TRUE, thr, mtr);
+ err = btr_cur_del_mark_set_clust_rec(
+ BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+ rec, index, offsets, TRUE, thr, mtr);
if (err != DB_SUCCESS) {
+err_exit:
mtr_commit(mtr);
+ mem_heap_free(heap);
return(err);
}
- /* Mark as not-owned the externally stored fields which the new
- row inherits from the delete marked record: purge should not
- free those externally stored fields even if the delete marked
- record is removed from the index tree, or updated. */
+ /* If the the new row inherits externally stored
+ fields (off-page columns a.k.a. BLOBs) from the
+ delete-marked old record, mark them disowned by the
+ old record and owned by the new entry. */
- rec = btr_cur_get_rec(btr_cur);
- index = dict_table_get_first_index(table);
- offsets = rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap);
- change_ownership = btr_cur_mark_extern_inherited_fields(
- btr_cur_get_page_zip(btr_cur), rec, index, offsets,
- node->update, mtr);
- if (check_ref) {
+ if (rec_offs_any_extern(offsets)) {
+ change_ownership = row_upd_clust_rec_by_insert_inherit(
+ rec, offsets, entry, node->update);
+
+ if (change_ownership) {
+ btr_pcur_store_position(pcur, mtr);
+ }
+ }
+
+ if (referenced) {
/* NOTE that the following call loses
the position of pcur ! */
+
err = row_upd_check_references_constraints(
node, pcur, table, index, offsets, thr, mtr);
+
if (err != DB_SUCCESS) {
- mtr_commit(mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(err);
+ goto err_exit;
}
}
}
mtr_commit(mtr);
- if (!heap) {
- heap = mem_heap_create(500);
- }
- node->state = UPD_NODE_INSERT_CLUSTERED;
+ err = row_ins_index_entry(index, entry,
+ node->upd_ext ? node->upd_ext->n_ext : 0,
+ TRUE, thr);
+ node->state = change_ownership
+ ? UPD_NODE_INSERT_BLOB
+ : UPD_NODE_INSERT_CLUSTERED;
- entry = row_build_index_entry(node->upd_row, node->upd_ext,
- index, heap);
- ut_a(entry);
+ if (err == DB_SUCCESS && change_ownership) {
+ /* Mark the non-updated fields disowned by the old record. */
- row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
+ /* NOTE: this transaction has an x-lock on the record
+ and therefore other transactions cannot modify the
+ record when we have no latch on the page. In addition,
+ we assume that other query threads of the same
+ transaction do not modify the record in the meantime.
+ Therefore we can assert that the restoration of the
+ cursor succeeds. */
- if (change_ownership) {
- /* If we return from a lock wait, for example, we may have
- extern fields marked as not-owned in entry (marked in the
- if-branch above). We must unmark them, take the ownership
- back. */
+ mtr_start(mtr);
- btr_cur_unmark_dtuple_extern_fields(entry);
+ if (!btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr)) {
+ ut_error;
+ }
- /* We must mark non-updated extern fields in entry as
- inherited, so that a possible rollback will not free them. */
+ rec = btr_cur_get_rec(btr_cur);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ ut_ad(page_rec_is_user_rec(rec));
+
+ btr_cur_disown_inherited_fields(
+ btr_cur_get_page_zip(btr_cur),
+ rec, index, offsets, node->update, mtr);
- btr_cur_mark_dtuple_inherited_extern(entry, node->update);
+ mtr_commit(mtr);
}
- err = row_ins_index_entry(index, entry,
- node->upd_ext ? node->upd_ext->n_ext : 0,
- TRUE, thr);
mem_heap_free(heap);
return(err);
@@ -1772,7 +2035,7 @@ row_upd_clust_rec(
index, btr_cur_get_block(btr_cur), rec,
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap),
- big_rec, mtr);
+ mtr, TRUE, big_rec);
mtr_commit(mtr);
}
@@ -1799,7 +2062,8 @@ row_upd_del_mark_clust_rec(
ulint* offsets,/*!< in/out: rec_get_offsets() for the
record under the cursor */
que_thr_t* thr, /*!< in: query thread */
- ibool check_ref,/*!< in: TRUE if index may be referenced in
+ ibool referenced,
+ /*!< in: TRUE if index may be referenced in
a foreign key constraint */
mtr_t* mtr) /*!< in: mtr; gets committed here */
{
@@ -1822,15 +2086,14 @@ row_upd_del_mark_clust_rec(
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
- err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
- btr_cur, TRUE, thr, mtr);
- if (err == DB_SUCCESS && check_ref) {
+ err = btr_cur_del_mark_set_clust_rec(
+ BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+ btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
+ if (err == DB_SUCCESS && referenced) {
/* NOTE that the following call loses the position of pcur ! */
- err = row_upd_check_references_constraints(node,
- pcur, index->table,
- index, offsets,
- thr, mtr);
+ err = row_upd_check_references_constraints(
+ node, pcur, index->table, index, offsets, thr, mtr);
}
mtr_commit(mtr);
@@ -1852,7 +2115,6 @@ row_upd_clust_step(
dict_index_t* index;
btr_pcur_t* pcur;
ibool success;
- ibool check_ref;
ulint err;
mtr_t* mtr;
mtr_t mtr_buf;
@@ -1860,11 +2122,12 @@ row_upd_clust_step(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets;
+ ibool referenced;
rec_offs_init(offsets_);
index = dict_table_get_first_index(node->table);
- check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
+ referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
pcur = node->pcur;
@@ -1897,8 +2160,7 @@ row_upd_clust_step(
then we have to free the file segments of the index tree associated
with the index */
- if (node->is_delete
- && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
+ if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
@@ -1934,8 +2196,9 @@ row_upd_clust_step(
/* NOTE: the following function calls will also commit mtr */
if (node->is_delete) {
- err = row_upd_del_mark_clust_rec(node, index, offsets,
- thr, check_ref, mtr);
+ err = row_upd_del_mark_clust_rec(
+ node, index, offsets, thr, referenced, mtr);
+
if (err == DB_SUCCESS) {
node->state = UPD_NODE_UPDATE_ALL_SEC;
node->index = dict_table_get_next_index(index);
@@ -1970,7 +2233,8 @@ exit_func:
row_upd_store_row(node);
- if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
+ if (row_upd_changes_ord_field_binary(index, node->update, thr,
+ node->row, node->ext)) {
/* Update causes an ordering field (ordering fields within
the B-tree) of the clustered index record to change: perform
@@ -1983,8 +2247,9 @@ exit_func:
choosing records to update. MySQL solves now the problem
externally! */
- err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
- mtr);
+ err = row_upd_clust_rec_by_insert(
+ node, index, thr, referenced, mtr);
+
if (err != DB_SUCCESS) {
return(err);
@@ -2039,7 +2304,8 @@ row_upd(
}
if (node->state == UPD_NODE_UPDATE_CLUSTERED
- || node->state == UPD_NODE_INSERT_CLUSTERED) {
+ || node->state == UPD_NODE_INSERT_CLUSTERED
+ || node->state == UPD_NODE_INSERT_BLOB) {
log_free_check();
err = row_upd_clust_step(node, thr);