summaryrefslogtreecommitdiff
path: root/storage/innodb_plugin/row/row0upd.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innodb_plugin/row/row0upd.c')
-rw-r--r--storage/innodb_plugin/row/row0upd.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c
index 13134afd1aa..cb7011105b8 100644
--- a/storage/innodb_plugin/row/row0upd.c
+++ b/storage/innodb_plugin/row/row0upd.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, Oracle and/or its affiliates. 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
@@ -1969,28 +1969,46 @@ row_upd_clust_rec(
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
dict_table_is_comp(index->table)));
- err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
- &heap, &big_rec, node->update,
- node->cmpl_info, thr, mtr);
- mtr_commit(mtr);
-
- if (err == DB_SUCCESS && big_rec) {
+ err = btr_cur_pessimistic_update(
+ BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur,
+ &heap, &big_rec, node->update, node->cmpl_info, thr, mtr);
+ if (big_rec) {
ulint offsets_[REC_OFFS_NORMAL_SIZE];
rec_t* rec;
rec_offs_init(offsets_);
- mtr_start(mtr);
-
- ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
+ ut_a(err == DB_SUCCESS);
+ /* Write out the externally stored columns, but
+ allocate the pages and write the pointers using the
+ mini-transaction of the record update. If any pages
+ were freed in the update, temporarily mark them
+ allocated so that off-page columns will not overwrite
+ them. We must do this, because we write the redo log
+ for the BLOB writes before writing the redo log for
+ the record update. */
+
+ btr_mark_freed_leaves(index, mtr, TRUE);
rec = btr_cur_get_rec(btr_cur);
err = btr_store_big_rec_extern_fields(
index, btr_cur_get_block(btr_cur), rec,
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap),
- mtr, TRUE, big_rec);
- mtr_commit(mtr);
+ big_rec, mtr, TRUE, mtr);
+ /* If writing big_rec fails (for example, because of
+ DB_OUT_OF_FILE_SPACE), the record will be corrupted.
+ Even if we did not update any externally stored
+ columns, our update could cause the record to grow so
+ that a non-updated column was selected for external
+ storage. This non-update would not have been written
+ to the undo log, and thus the record cannot be rolled
+ back. */
+ ut_a(err == DB_SUCCESS);
+ /* Free the pages again in order to avoid a leak. */
+ btr_mark_freed_leaves(index, mtr, FALSE);
}
+ mtr_commit(mtr);
+
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}