11
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
17
*****************************************************************************/
19
/**************************************************//**
19
/******************************************************
21
20
Undo modify of a row
23
22
Created 2/27/1997 Heikki Tuuri
58
57
some of its fields were changed. Now, it is possible that the delete marked
59
58
version has become obsolete at the time the undo is started. */
61
/*************************************************************************
62
IMPORTANT NOTE: Any operation that generates redo MUST check that there
63
is enough space in the redo log before for that operation. This is
64
done by calling log_free_check(). The reason for checking the
65
availability of the redo log space before the start of the operation is
66
that we MUST not hold any synchonization objects when performing the
68
If you make a change in this module make sure that no codepath is
69
introduced where a call to log_free_check() is bypassed. */
71
/***********************************************************//**
60
/***************************************************************
72
61
Checks if also the previous version of the clustered index record was
73
62
modified or inserted by the same transaction, and its undo number is such
74
that it should be undone in the same rollback.
75
@return TRUE if also previous modify or insert of this row should be undone */
63
that it should be undone in the same rollback. */
78
66
row_undo_mod_undo_also_prev_vers(
79
67
/*=============================*/
80
undo_node_t* node, /*!< in: row undo node */
81
undo_no_t* undo_no)/*!< out: the undo number */
68
/* out: TRUE if also previous modify or
69
insert of this row should be undone */
70
undo_node_t* node, /* in: row undo node */
71
dulint* undo_no)/* out: the undo number */
83
73
trx_undo_rec_t* undo_rec;
88
if (node->new_trx_id != trx->id) {
78
if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) {
80
*undo_no = ut_dulint_zero;
96
86
*undo_no = trx_undo_rec_get_undo_no(undo_rec);
98
return(trx->roll_limit <= *undo_no);
88
return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0);
101
/***********************************************************//**
102
Undoes a modify in a clustered index record.
103
@return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */
91
/***************************************************************
92
Undoes a modify in a clustered index record. */
106
95
row_undo_mod_clust_low(
107
96
/*===================*/
108
undo_node_t* node, /*!< in: row undo node */
109
que_thr_t* thr, /*!< in: query thread */
110
mtr_t* mtr, /*!< in: mtr; must be committed before
97
/* out: DB_SUCCESS, DB_FAIL, or error code:
98
we may run out of file space */
99
undo_node_t* node, /* in: row undo node */
100
que_thr_t* thr, /* in: query thread */
101
mtr_t* mtr, /* in: mtr; must be committed before
111
102
latching any further pages */
112
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
103
ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
114
105
btr_pcur_t* pcur;
115
106
btr_cur_t* btr_cur;
119
#endif /* UNIV_DEBUG */
121
110
pcur = &(node->pcur);
122
111
btr_cur = btr_pcur_get_btr_cur(pcur);
126
#endif /* UNIV_DEBUG */
127
btr_pcur_restore_position(mode, pcur, mtr);
113
success = btr_pcur_restore_position(mode, pcur, mtr);
160
/***********************************************************//**
161
Removes a clustered index record after undo if possible.
162
This is attempted when the record was inserted by updating a
163
delete-marked record and there no longer exist transactions
164
that would see the delete-marked record. In other words, we
165
roll back the insert by purging the record.
166
@return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */
146
/***************************************************************
147
Removes a clustered index record after undo if possible. */
169
150
row_undo_mod_remove_clust_low(
170
151
/*==========================*/
171
undo_node_t* node, /*!< in: row undo node */
172
que_thr_t* thr, /*!< in: query thread */
173
mtr_t* mtr, /*!< in: mtr */
174
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
152
/* out: DB_SUCCESS, DB_FAIL, or error code:
153
we may run out of file space */
154
undo_node_t* node, /* in: row undo node */
155
que_thr_t* thr __attribute__((unused)), /* in: query thread */
156
mtr_t* mtr, /* in: mtr */
157
ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
176
159
btr_pcur_t* pcur;
177
160
btr_cur_t* btr_cur;
181
ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
182
164
pcur = &(node->pcur);
183
165
btr_cur = btr_pcur_get_btr_cur(pcur);
211
193
ut_ad(mode == BTR_MODIFY_TREE);
213
/* This operation is analogous to purge, we can free also
214
inherited externally stored fields */
195
/* Note that since this operation is analogous to purge,
196
we can free also inherited externally stored fields:
197
hence the RB_NONE in the call below */
216
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
218
? RB_RECOVERY_PURGE_REC
199
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr);
221
201
/* The delete operation may fail if we have little
222
202
file space left: TODO: easiest to crash the database
229
/***********************************************************//**
209
/***************************************************************
230
210
Undoes a modify in a clustered index record. Sets also the node state for the
232
@return DB_SUCCESS or error code: we may run out of file space */
211
next round of undo. */
235
214
row_undo_mod_clust(
236
215
/*===============*/
237
undo_node_t* node, /*!< in: row undo node */
238
que_thr_t* thr) /*!< in: query thread */
216
/* out: DB_SUCCESS or error code: we may run
218
undo_node_t* node, /* in: row undo node */
219
que_thr_t* thr) /* in: query thread */
240
221
btr_pcur_t* pcur;
245
undo_no_t new_undo_no;
247
228
ut_ad(node && thr);
251
230
/* Check if also the previous version of the clustered index record
252
231
should be undone in this same rollback operation */
320
/***********************************************************//**
321
Delete marks or removes a secondary index entry if found.
322
@return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */
299
/***************************************************************
300
Delete marks or removes a secondary index entry if found. */
325
303
row_undo_mod_del_mark_or_remove_sec_low(
326
304
/*====================================*/
327
undo_node_t* node, /*!< in: row undo node */
328
que_thr_t* thr, /*!< in: query thread */
329
dict_index_t* index, /*!< in: index */
330
dtuple_t* entry, /*!< in: index entry */
331
ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or
305
/* out: DB_SUCCESS, DB_FAIL, or
306
DB_OUT_OF_FILE_SPACE */
307
undo_node_t* node, /* in: row undo node */
308
que_thr_t* thr, /* in: query thread */
309
dict_index_t* index, /* in: index */
310
dtuple_t* entry, /* in: index entry */
311
ulint mode) /* in: latch mode BTR_MODIFY_LEAF or
332
312
BTR_MODIFY_TREE */
341
enum row_search_result search_result;
343
323
log_free_check();
326
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
346
328
btr_cur = btr_pcur_get_btr_cur(&pcur);
348
ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
350
search_result = row_search_index_entry(index, entry, mode,
353
switch (UNIV_EXPECT(search_result, ROW_FOUND)) {
355
331
/* In crash recovery, the secondary index record may
356
332
be missing if the UPDATE did not have time to insert
357
333
the secondary index records before the crash. When we
362
338
before it has inserted all updated secondary index
363
339
records, then the undo will not find those records. */
370
case ROW_NOT_DELETED_REF:
371
/* These are invalid outcomes, because the mode passed
372
to row_search_index_entry() did not include any of the
373
flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
341
btr_pcur_close(&pcur);
377
347
/* We should remove the index record if no prior version of the row,
405
375
ut_ad(mode == BTR_MODIFY_TREE);
407
/* No need to distinguish RB_RECOVERY_PURGE here,
408
because we are deleting a secondary index record:
409
the distinction between RB_NORMAL and
410
RB_RECOVERY_PURGE only matters when deleting a
411
record that contains externally stored
377
/* No need to distinguish RB_RECOVERY here, because we
378
are deleting a secondary index record: the distinction
379
between RB_NORMAL and RB_RECOVERY only matters when
380
deleting a record that contains externally stored
413
382
ut_ad(!dict_index_is_clust(index));
414
383
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
423
392
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
426
393
btr_pcur_close(&pcur);
427
394
mtr_commit(&mtr);
432
/***********************************************************//**
399
/***************************************************************
433
400
Delete marks or removes a secondary index entry if found.
434
401
NOTE that if we updated the fields of a delete-marked secondary index record
435
402
so that alphabetically they stayed the same, e.g., 'abc' -> 'aBc', we cannot
436
403
return to the original values because we do not know them. But this should
437
404
not cause problems because in row0sel.c, in queries we always retrieve the
438
405
clustered index record or an earlier version of it, if the secondary index
439
record through which we do the search is delete-marked.
440
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
406
record through which we do the search is delete-marked. */
443
409
row_undo_mod_del_mark_or_remove_sec(
444
410
/*================================*/
445
undo_node_t* node, /*!< in: row undo node */
446
que_thr_t* thr, /*!< in: query thread */
447
dict_index_t* index, /*!< in: index */
448
dtuple_t* entry) /*!< in: index entry */
411
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
412
undo_node_t* node, /* in: row undo node */
413
que_thr_t* thr, /* in: query thread */
414
dict_index_t* index, /* in: index */
415
dtuple_t* entry) /* in: index entry */
464
/***********************************************************//**
431
/***************************************************************
465
432
Delete unmarks a secondary index entry which must be found. It might not be
466
433
delete-marked at the moment, but it does not harm to unmark it anyway. We also
467
434
need to update the fields of the secondary index record if we updated its
468
fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'.
469
@return DB_FAIL or DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
435
fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */
472
438
row_undo_mod_del_unmark_sec_and_undo_update(
473
439
/*========================================*/
474
ulint mode, /*!< in: search mode: BTR_MODIFY_LEAF or
440
/* out: DB_FAIL or DB_SUCCESS or
441
DB_OUT_OF_FILE_SPACE */
442
ulint mode, /* in: search mode: BTR_MODIFY_LEAF or
475
443
BTR_MODIFY_TREE */
476
que_thr_t* thr, /*!< in: query thread */
477
dict_index_t* index, /*!< in: index */
478
const dtuple_t* entry) /*!< in: index entry */
444
que_thr_t* thr, /* in: query thread */
445
dict_index_t* index, /* in: index */
446
dtuple_t* entry) /* in: index entry */
484
ulint err = DB_SUCCESS;
485
big_rec_t* dummy_big_rec;
487
trx_t* trx = thr_get_trx(thr);
488
enum row_search_result search_result;
451
ulint err = DB_SUCCESS;
452
big_rec_t* dummy_big_rec;
454
trx_t* trx = thr_get_trx(thr);
490
456
/* Ignore indexes that are being created. */
491
457
if (UNIV_UNLIKELY(*index->name == TEMP_INDEX_PREFIX)) {
496
462
log_free_check();
499
ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
501
search_result = row_search_index_entry(index, entry, mode,
504
switch (search_result) {
506
case ROW_NOT_DELETED_REF:
507
/* These are invalid outcomes, because the mode passed
508
to row_search_index_entry() did not include any of the
509
flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
465
if (UNIV_UNLIKELY(!row_search_index_entry(index, entry,
466
mode, &pcur, &mtr))) {
512
467
fputs("InnoDB: error in sec index entry del undo in\n"
513
468
"InnoDB: ", stderr);
514
469
dict_index_name_print(stderr, trx, index);
524
479
"InnoDB: Submit a detailed bug report"
525
480
" to http://bugs.mysql.com\n", stderr);
528
btr_cur = btr_pcur_get_btr_cur(&pcur);
482
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
529
484
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
530
485
btr_cur, FALSE, thr, &mtr);
531
486
ut_a(err == DB_SUCCESS);
571
/***********************************************************//**
572
Undoes a modify in secondary indexes when undo record type is UPD_DEL.
573
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
526
/***************************************************************
527
Undoes a modify in secondary indexes when undo record type is UPD_DEL. */
576
530
row_undo_mod_upd_del_sec(
577
531
/*=====================*/
578
undo_node_t* node, /*!< in: row undo node */
579
que_thr_t* thr) /*!< in: query thread */
532
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
533
undo_node_t* node, /* in: row undo node */
534
que_thr_t* thr) /* in: query thread */
581
536
mem_heap_t* heap;
583
538
dict_index_t* index;
584
539
ulint err = DB_SUCCESS;
586
ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
587
541
heap = mem_heap_create(1024);
589
543
while (node->index != NULL) {
625
/***********************************************************//**
626
Undoes a modify in secondary indexes when undo record type is DEL_MARK.
627
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
579
/***************************************************************
580
Undoes a modify in secondary indexes when undo record type is DEL_MARK. */
630
583
row_undo_mod_del_mark_sec(
631
584
/*======================*/
632
undo_node_t* node, /*!< in: row undo node */
633
que_thr_t* thr) /*!< in: query thread */
585
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
586
undo_node_t* node, /* in: row undo node */
587
que_thr_t* thr) /* in: query thread */
635
589
mem_heap_t* heap;
667
621
return(DB_SUCCESS);
670
/***********************************************************//**
671
Undoes a modify in secondary indexes when undo record type is UPD_EXIST.
672
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
624
/***************************************************************
625
Undoes a modify in secondary indexes when undo record type is UPD_EXIST. */
675
628
row_undo_mod_upd_exist_sec(
676
629
/*=======================*/
677
undo_node_t* node, /*!< in: row undo node */
678
que_thr_t* thr) /*!< in: query thread */
630
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
631
undo_node_t* node, /* in: row undo node */
632
que_thr_t* thr) /* in: query thread */
680
634
mem_heap_t* heap;
699
653
/* Build the newest version of the index entry */
700
654
entry = row_build_index_entry(node->row, node->ext,
702
if (UNIV_UNLIKELY(!entry)) {
703
/* The server must have crashed in
704
row_upd_clust_rec_by_insert(), in
705
row_ins_index_entry_low() before
706
btr_store_big_rec_extern_fields()
707
has written the externally stored columns
708
(BLOBs) of the new clustered index entry. */
710
/* The table must be in DYNAMIC or COMPRESSED
711
format. REDUNDANT and COMPACT formats
712
store a local 768-byte prefix of each
713
externally stored column. */
714
ut_a(dict_table_get_format(index->table)
715
>= DICT_TF_FORMAT_ZIP);
717
/* This is only legitimate when
718
rolling back an incomplete transaction
719
after crash recovery. */
720
ut_a(thr_get_trx(thr)->is_recovered);
722
/* The server must have crashed before
723
completing the insert of the new
724
clustered index entry and before
725
inserting to the secondary indexes.
726
Because node->row was not yet written
727
to this index, we can ignore it. But
728
we must restore node->undo_row. */
730
/* NOTE that if we updated the fields of a
731
delete-marked secondary index record so that
732
alphabetically they stayed the same, e.g.,
733
'abc' -> 'aBc', we cannot return to the
734
original values because we do not know them.
735
But this should not cause problems because
736
in row0sel.c, in queries we always retrieve
737
the clustered index record or an earlier
738
version of it, if the secondary index record
739
through which we do the search is
742
err = row_undo_mod_del_mark_or_remove_sec(
743
node, thr, index, entry);
744
if (err != DB_SUCCESS) {
750
mem_heap_empty(heap);
657
/* NOTE that if we updated the fields of a
658
delete-marked secondary index record so that
659
alphabetically they stayed the same, e.g.,
660
'abc' -> 'aBc', we cannot return to the original
661
values because we do not know them. But this should
662
not cause problems because in row0sel.c, in queries
663
we always retrieve the clustered index record or an
664
earlier version of it, if the secondary index record
665
through which we do the search is delete-marked. */
667
err = row_undo_mod_del_mark_or_remove_sec(node, thr,
670
if (err != DB_SUCCESS) {
753
676
/* We may have to update the delete mark in the
783
707
return(DB_SUCCESS);
786
/***********************************************************//**
710
/***************************************************************
787
711
Parses the row reference and other info in a modify undo log record. */
790
714
row_undo_mod_parse_undo_rec(
791
715
/*========================*/
792
undo_node_t* node, /*!< in: row undo node */
793
que_thr_t* thr) /*!< in: query thread */
716
undo_node_t* node, /* in: row undo node */
717
que_thr_t* thr) /* in: query thread */
795
719
dict_index_t* clust_index;
843
767
node->cmpl_info = cmpl_info;
846
/***********************************************************//**
847
Undoes a modify operation on a row of a table.
848
@return DB_SUCCESS or error code */
770
/***************************************************************
771
Undoes a modify operation on a row of a table. */
853
undo_node_t* node, /*!< in: row undo node */
854
que_thr_t* thr) /*!< in: query thread */
776
/* out: DB_SUCCESS or error code */
777
undo_node_t* node, /* in: row undo node */
778
que_thr_t* thr) /* in: query thread */