1
/*****************************************************************************
3
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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
17
*****************************************************************************/
19
/**************************************************//**
1
/******************************************************
21
2
Undo modify of a row
23
6
Created 2/27/1997 Heikki Tuuri
24
7
*******************************************************/
58
41
some of its fields were changed. Now, it is possible that the delete marked
59
42
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
/***********************************************************//**
44
/***************************************************************
72
45
Checks if also the previous version of the clustered index record was
73
46
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 */
47
that it should be undone in the same rollback. */
78
50
row_undo_mod_undo_also_prev_vers(
79
51
/*=============================*/
80
undo_node_t* node, /*!< in: row undo node */
81
undo_no_t* undo_no)/*!< out: the undo number */
52
/* out: TRUE if also previous modify or
53
insert of this row should be undone */
54
undo_node_t* node, /* in: row undo node */
55
dulint* undo_no)/* out: the undo number */
83
57
trx_undo_rec_t* undo_rec;
88
if (node->new_trx_id != trx->id) {
62
if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) {
64
*undo_no = ut_dulint_zero;
96
70
*undo_no = trx_undo_rec_get_undo_no(undo_rec);
98
return(trx->roll_limit <= *undo_no);
72
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 */
75
/***************************************************************
76
Undoes a modify in a clustered index record. */
106
79
row_undo_mod_clust_low(
107
80
/*===================*/
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
81
/* out: DB_SUCCESS, DB_FAIL, or error code:
82
we may run out of file space */
83
undo_node_t* node, /* in: row undo node */
84
que_thr_t* thr, /* in: query thread */
85
mtr_t* mtr, /* in: mtr; must be committed before
111
86
latching any further pages */
112
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
87
ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
115
90
btr_cur_t* btr_cur;
119
#endif /* UNIV_DEBUG */
121
94
pcur = &(node->pcur);
122
95
btr_cur = btr_pcur_get_btr_cur(pcur);
126
#endif /* UNIV_DEBUG */
127
btr_pcur_restore_position(mode, pcur, mtr);
97
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 */
130
/***************************************************************
131
Removes a clustered index record after undo if possible. */
169
134
row_undo_mod_remove_clust_low(
170
135
/*==========================*/
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 */
136
/* out: DB_SUCCESS, DB_FAIL, or error code:
137
we may run out of file space */
138
undo_node_t* node, /* in: row undo node */
139
que_thr_t* thr __attribute__((unused)), /* in: query thread */
140
mtr_t* mtr, /* in: mtr */
141
ulint mode) /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
176
143
btr_pcur_t* pcur;
177
144
btr_cur_t* btr_cur;
181
ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
182
148
pcur = &(node->pcur);
183
149
btr_cur = btr_pcur_get_btr_cur(pcur);
211
177
ut_ad(mode == BTR_MODIFY_TREE);
213
/* This operation is analogous to purge, we can free also
214
inherited externally stored fields */
179
/* Note that since this operation is analogous to purge,
180
we can free also inherited externally stored fields:
181
hence the RB_NONE in the call below */
216
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
218
? RB_RECOVERY_PURGE_REC
183
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr);
221
185
/* The delete operation may fail if we have little
222
186
file space left: TODO: easiest to crash the database
229
/***********************************************************//**
193
/***************************************************************
230
194
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 */
195
next round of undo. */
235
198
row_undo_mod_clust(
236
199
/*===============*/
237
undo_node_t* node, /*!< in: row undo node */
238
que_thr_t* thr) /*!< in: query thread */
200
/* out: DB_SUCCESS or error code: we may run
202
undo_node_t* node, /* in: row undo node */
203
que_thr_t* thr) /* in: query thread */
240
205
btr_pcur_t* pcur;
245
undo_no_t new_undo_no;
247
212
ut_ad(node && thr);
251
214
/* Check if also the previous version of the clustered index record
252
215
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 */
283
/***************************************************************
284
Delete marks or removes a secondary index entry if found. */
325
287
row_undo_mod_del_mark_or_remove_sec_low(
326
288
/*====================================*/
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
289
/* out: DB_SUCCESS, DB_FAIL, or
290
DB_OUT_OF_FILE_SPACE */
291
undo_node_t* node, /* in: row undo node */
292
que_thr_t* thr, /* in: query thread */
293
dict_index_t* index, /* in: index */
294
dtuple_t* entry, /* in: index entry */
295
ulint mode) /* in: latch mode BTR_MODIFY_LEAF or
332
296
BTR_MODIFY_TREE */
341
enum row_search_result search_result;
343
307
log_free_check();
310
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
346
312
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
/* In crash recovery, the secondary index record may
356
be missing if the UPDATE did not have time to insert
357
the secondary index records before the crash. When we
358
are undoing that UPDATE in crash recovery, the record
361
In normal processing, if an update ends in a deadlock
362
before it has inserted all updated secondary index
363
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. */
317
btr_pcur_close(&pcur);
377
323
/* We should remove the index record if no prior version of the row,
405
351
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
353
/* No need to distinguish RB_RECOVERY here, because we
354
are deleting a secondary index record: the distinction
355
between RB_NORMAL and RB_RECOVERY only matters when
356
deleting a record that contains externally stored
413
358
ut_ad(!dict_index_is_clust(index));
414
359
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
423
368
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
426
369
btr_pcur_close(&pcur);
427
370
mtr_commit(&mtr);
432
/***********************************************************//**
375
/***************************************************************
433
376
Delete marks or removes a secondary index entry if found.
434
377
NOTE that if we updated the fields of a delete-marked secondary index record
435
378
so that alphabetically they stayed the same, e.g., 'abc' -> 'aBc', we cannot
436
379
return to the original values because we do not know them. But this should
437
380
not cause problems because in row0sel.c, in queries we always retrieve the
438
381
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 */
382
record through which we do the search is delete-marked. */
443
385
row_undo_mod_del_mark_or_remove_sec(
444
386
/*================================*/
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 */
387
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
388
undo_node_t* node, /* in: row undo node */
389
que_thr_t* thr, /* in: query thread */
390
dict_index_t* index, /* in: index */
391
dtuple_t* entry) /* in: index entry */
464
/***********************************************************//**
407
/***************************************************************
465
408
Delete unmarks a secondary index entry which must be found. It might not be
466
409
delete-marked at the moment, but it does not harm to unmark it anyway. We also
467
410
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 */
411
fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */
472
414
row_undo_mod_del_unmark_sec_and_undo_update(
473
415
/*========================================*/
474
ulint mode, /*!< in: search mode: BTR_MODIFY_LEAF or
416
/* out: DB_FAIL or DB_SUCCESS or
417
DB_OUT_OF_FILE_SPACE */
418
ulint mode, /* in: search mode: BTR_MODIFY_LEAF or
475
419
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 */
420
que_thr_t* thr, /* in: query thread */
421
dict_index_t* index, /* in: index */
422
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;
427
ulint err = DB_SUCCESS;
428
big_rec_t* dummy_big_rec;
430
trx_t* trx = thr_get_trx(thr);
490
432
/* Ignore indexes that are being created. */
491
433
if (UNIV_UNLIKELY(*index->name == TEMP_INDEX_PREFIX)) {
496
438
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. */
441
if (UNIV_UNLIKELY(!row_search_index_entry(index, entry,
442
mode, &pcur, &mtr))) {
512
443
fputs("InnoDB: error in sec index entry del undo in\n"
513
444
"InnoDB: ", stderr);
514
445
dict_index_name_print(stderr, trx, index);
524
455
"InnoDB: Submit a detailed bug report"
525
456
" to http://bugs.mysql.com\n", stderr);
528
btr_cur = btr_pcur_get_btr_cur(&pcur);
458
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
529
460
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
530
461
btr_cur, FALSE, thr, &mtr);
531
462
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 */
502
/***************************************************************
503
Undoes a modify in secondary indexes when undo record type is UPD_DEL. */
576
506
row_undo_mod_upd_del_sec(
577
507
/*=====================*/
578
undo_node_t* node, /*!< in: row undo node */
579
que_thr_t* thr) /*!< in: query thread */
508
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
509
undo_node_t* node, /* in: row undo node */
510
que_thr_t* thr) /* in: query thread */
581
512
mem_heap_t* heap;
583
514
dict_index_t* index;
584
515
ulint err = DB_SUCCESS;
586
ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
587
517
heap = mem_heap_create(1024);
589
519
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 */
555
/***************************************************************
556
Undoes a modify in secondary indexes when undo record type is DEL_MARK. */
630
559
row_undo_mod_del_mark_sec(
631
560
/*======================*/
632
undo_node_t* node, /*!< in: row undo node */
633
que_thr_t* thr) /*!< in: query thread */
561
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
562
undo_node_t* node, /* in: row undo node */
563
que_thr_t* thr) /* in: query thread */
635
565
mem_heap_t* heap;
667
597
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 */
600
/***************************************************************
601
Undoes a modify in secondary indexes when undo record type is UPD_EXIST. */
675
604
row_undo_mod_upd_exist_sec(
676
605
/*=======================*/
677
undo_node_t* node, /*!< in: row undo node */
678
que_thr_t* thr) /*!< in: query thread */
606
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
607
undo_node_t* node, /* in: row undo node */
608
que_thr_t* thr) /* in: query thread */
680
610
mem_heap_t* heap;
699
629
/* Build the newest version of the index entry */
700
630
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);
633
/* NOTE that if we updated the fields of a
634
delete-marked secondary index record so that
635
alphabetically they stayed the same, e.g.,
636
'abc' -> 'aBc', we cannot return to the original
637
values because we do not know them. But this should
638
not cause problems because in row0sel.c, in queries
639
we always retrieve the clustered index record or an
640
earlier version of it, if the secondary index record
641
through which we do the search is delete-marked. */
643
err = row_undo_mod_del_mark_or_remove_sec(node, thr,
646
if (err != DB_SUCCESS) {
753
652
/* We may have to update the delete mark in the
783
683
return(DB_SUCCESS);
786
/***********************************************************//**
686
/***************************************************************
787
687
Parses the row reference and other info in a modify undo log record. */
790
690
row_undo_mod_parse_undo_rec(
791
691
/*========================*/
792
undo_node_t* node, /*!< in: row undo node */
793
que_thr_t* thr) /*!< in: query thread */
692
undo_node_t* node, /* in: row undo node */
693
que_thr_t* thr) /* in: query thread */
795
695
dict_index_t* clust_index;
843
743
node->cmpl_info = cmpl_info;
846
/***********************************************************//**
847
Undoes a modify operation on a row of a table.
848
@return DB_SUCCESS or error code */
746
/***************************************************************
747
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 */
752
/* out: DB_SUCCESS or error code */
753
undo_node_t* node, /* in: row undo node */
754
que_thr_t* thr) /* in: query thread */