~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/row/row0umod.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Undo modify of a row
 
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
 
6
Created 2/27/1997 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "row0umod.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "row0umod.ic"
 
13
#endif
 
14
 
 
15
#include "dict0dict.h"
 
16
#include "dict0boot.h"
 
17
#include "trx0undo.h"
 
18
#include "trx0roll.h"
 
19
#include "btr0btr.h"
 
20
#include "mach0data.h"
 
21
#include "row0undo.h"
 
22
#include "row0vers.h"
 
23
#include "trx0trx.h"
 
24
#include "trx0rec.h"
 
25
#include "row0row.h"
 
26
#include "row0upd.h"
 
27
#include "que0que.h"
 
28
#include "log0log.h"
 
29
 
 
30
/* Considerations on undoing a modify operation.
 
31
(1) Undoing a delete marking: all index records should be found. Some of
 
32
them may have delete mark already FALSE, if the delete mark operation was
 
33
stopped underway, or if the undo operation ended prematurely because of a
 
34
system crash.
 
35
(2) Undoing an update of a delete unmarked record: the newer version of
 
36
an updated secondary index entry should be removed if no prior version
 
37
of the clustered index record requires its existence. Otherwise, it should
 
38
be delete marked.
 
39
(3) Undoing an update of a delete marked record. In this kind of update a
 
40
delete marked clustered index record was delete unmarked and possibly also
 
41
some of its fields were changed. Now, it is possible that the delete marked
 
42
version has become obsolete at the time the undo is started. */
 
43
 
 
44
/***************************************************************
 
45
Checks if also the previous version of the clustered index record was
 
46
modified or inserted by the same transaction, and its undo number is such
 
47
that it should be undone in the same rollback. */
 
48
UNIV_INLINE
 
49
ibool
 
50
row_undo_mod_undo_also_prev_vers(
 
51
/*=============================*/
 
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 */
 
56
{
 
57
        trx_undo_rec_t* undo_rec;
 
58
        trx_t*          trx;
 
59
 
 
60
        trx = node->trx;
 
61
 
 
62
        if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) {
 
63
 
 
64
                *undo_no = ut_dulint_zero;
 
65
                return(FALSE);
 
66
        }
 
67
 
 
68
        undo_rec = trx_undo_get_undo_rec_low(node->new_roll_ptr, node->heap);
 
69
 
 
70
        *undo_no = trx_undo_rec_get_undo_no(undo_rec);
 
71
 
 
72
        return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0);
 
73
}
 
74
 
 
75
/***************************************************************
 
76
Undoes a modify in a clustered index record. */
 
77
static
 
78
ulint
 
79
row_undo_mod_clust_low(
 
80
/*===================*/
 
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 */
 
86
        ulint           mode)   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
 
87
{
 
88
        big_rec_t*      dummy_big_rec;
 
89
        btr_pcur_t*     pcur;
 
90
        btr_cur_t*      btr_cur;
 
91
        ulint           err;
 
92
        ibool           success;
 
93
 
 
94
        pcur = &(node->pcur);
 
95
        btr_cur = btr_pcur_get_btr_cur(pcur);
 
96
 
 
97
        success = btr_pcur_restore_position(mode, pcur, mtr);
 
98
 
 
99
        ut_ad(success);
 
100
 
 
101
        if (mode == BTR_MODIFY_LEAF) {
 
102
 
 
103
                err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG
 
104
                                                | BTR_NO_UNDO_LOG_FLAG
 
105
                                                | BTR_KEEP_SYS_FLAG,
 
106
                                                btr_cur, node->update,
 
107
                                                node->cmpl_info, thr, mtr);
 
108
        } else {
 
109
                ut_ad(mode == BTR_MODIFY_TREE);
 
110
 
 
111
                err = btr_cur_pessimistic_update(
 
112
                        BTR_NO_LOCKING_FLAG
 
113
                        | BTR_NO_UNDO_LOG_FLAG
 
114
                        | BTR_KEEP_SYS_FLAG,
 
115
                        btr_cur, &dummy_big_rec, node->update,
 
116
                        node->cmpl_info, thr, mtr);
 
117
        }
 
118
 
 
119
        return(err);
 
120
}
 
121
 
 
122
/***************************************************************
 
123
Removes a clustered index record after undo if possible. */
 
124
static
 
125
ulint
 
126
row_undo_mod_remove_clust_low(
 
127
/*==========================*/
 
128
                                /* out: DB_SUCCESS, DB_FAIL, or error code:
 
129
                                we may run out of file space */
 
130
        undo_node_t*    node,   /* in: row undo node */
 
131
        que_thr_t*      thr __attribute__((unused)), /* in: query thread */
 
132
        mtr_t*          mtr,    /* in: mtr */
 
133
        ulint           mode)   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
 
134
{
 
135
        btr_pcur_t*     pcur;
 
136
        btr_cur_t*      btr_cur;
 
137
        ulint           err;
 
138
        ibool           success;
 
139
 
 
140
        pcur = &(node->pcur);
 
141
        btr_cur = btr_pcur_get_btr_cur(pcur);
 
142
 
 
143
        success = btr_pcur_restore_position(mode, pcur, mtr);
 
144
 
 
145
        if (!success) {
 
146
 
 
147
                return(DB_SUCCESS);
 
148
        }
 
149
 
 
150
        /* Find out if we can remove the whole clustered index record */
 
151
 
 
152
        if (node->rec_type == TRX_UNDO_UPD_DEL_REC
 
153
            && !row_vers_must_preserve_del_marked(node->new_trx_id, mtr)) {
 
154
 
 
155
                /* Ok, we can remove */
 
156
        } else {
 
157
                return(DB_SUCCESS);
 
158
        }
 
159
 
 
160
        if (mode == BTR_MODIFY_LEAF) {
 
161
                success = btr_cur_optimistic_delete(btr_cur, mtr);
 
162
 
 
163
                if (success) {
 
164
                        err = DB_SUCCESS;
 
165
                } else {
 
166
                        err = DB_FAIL;
 
167
                }
 
168
        } else {
 
169
                ut_ad(mode == BTR_MODIFY_TREE);
 
170
 
 
171
                /* Note that since this operation is analogous to purge,
 
172
                we can free also inherited externally stored fields:
 
173
                hence the last FALSE in the call below */
 
174
 
 
175
                btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, mtr);
 
176
 
 
177
                /* The delete operation may fail if we have little
 
178
                file space left: TODO: easiest to crash the database
 
179
                and restart with more file space */
 
180
        }
 
181
 
 
182
        return(err);
 
183
}
 
184
 
 
185
/***************************************************************
 
186
Undoes a modify in a clustered index record. Sets also the node state for the
 
187
next round of undo. */
 
188
static
 
189
ulint
 
190
row_undo_mod_clust(
 
191
/*===============*/
 
192
                                /* out: DB_SUCCESS or error code: we may run
 
193
                                out of file space */
 
194
        undo_node_t*    node,   /* in: row undo node */
 
195
        que_thr_t*      thr)    /* in: query thread */
 
196
{
 
197
        btr_pcur_t*     pcur;
 
198
        mtr_t           mtr;
 
199
        ulint           err;
 
200
        ibool           success;
 
201
        ibool           more_vers;
 
202
        dulint          new_undo_no;
 
203
 
 
204
        ut_ad(node && thr);
 
205
 
 
206
        /* Check if also the previous version of the clustered index record
 
207
        should be undone in this same rollback operation */
 
208
 
 
209
        more_vers = row_undo_mod_undo_also_prev_vers(node, &new_undo_no);
 
210
 
 
211
        pcur = &(node->pcur);
 
212
 
 
213
        mtr_start(&mtr);
 
214
 
 
215
        /* Try optimistic processing of the record, keeping changes within
 
216
        the index page */
 
217
 
 
218
        err = row_undo_mod_clust_low(node, thr, &mtr, BTR_MODIFY_LEAF);
 
219
 
 
220
        if (err != DB_SUCCESS) {
 
221
                btr_pcur_commit_specify_mtr(pcur, &mtr);
 
222
 
 
223
                /* We may have to modify tree structure: do a pessimistic
 
224
                descent down the index tree */
 
225
 
 
226
                mtr_start(&mtr);
 
227
 
 
228
                err = row_undo_mod_clust_low(node, thr, &mtr, BTR_MODIFY_TREE);
 
229
        }
 
230
 
 
231
        btr_pcur_commit_specify_mtr(pcur, &mtr);
 
232
 
 
233
        if (err == DB_SUCCESS && node->rec_type == TRX_UNDO_UPD_DEL_REC) {
 
234
 
 
235
                mtr_start(&mtr);
 
236
 
 
237
                err = row_undo_mod_remove_clust_low(node, thr, &mtr,
 
238
                                                    BTR_MODIFY_LEAF);
 
239
                if (err != DB_SUCCESS) {
 
240
                        btr_pcur_commit_specify_mtr(pcur, &mtr);
 
241
 
 
242
                        /* We may have to modify tree structure: do a
 
243
                        pessimistic descent down the index tree */
 
244
 
 
245
                        mtr_start(&mtr);
 
246
 
 
247
                        err = row_undo_mod_remove_clust_low(node, thr, &mtr,
 
248
                                                            BTR_MODIFY_TREE);
 
249
                }
 
250
 
 
251
                btr_pcur_commit_specify_mtr(pcur, &mtr);
 
252
        }
 
253
 
 
254
        node->state = UNDO_NODE_FETCH_NEXT;
 
255
 
 
256
        trx_undo_rec_release(node->trx, node->undo_no);
 
257
 
 
258
        if (more_vers && err == DB_SUCCESS) {
 
259
 
 
260
                /* Reserve the undo log record to the prior version after
 
261
                committing &mtr: this is necessary to comply with the latching
 
262
                order, as &mtr may contain the fsp latch which is lower in
 
263
                the latch hierarchy than trx->undo_mutex. */
 
264
 
 
265
                success = trx_undo_rec_reserve(node->trx, new_undo_no);
 
266
 
 
267
                if (success) {
 
268
                        node->state = UNDO_NODE_PREV_VERS;
 
269
                }
 
270
        }
 
271
 
 
272
        return(err);
 
273
}
 
274
 
 
275
/***************************************************************
 
276
Delete marks or removes a secondary index entry if found. */
 
277
static
 
278
ulint
 
279
row_undo_mod_del_mark_or_remove_sec_low(
 
280
/*====================================*/
 
281
                                /* out: DB_SUCCESS, DB_FAIL, or
 
282
                                DB_OUT_OF_FILE_SPACE */
 
283
        undo_node_t*    node,   /* in: row undo node */
 
284
        que_thr_t*      thr,    /* in: query thread */
 
285
        dict_index_t*   index,  /* in: index */
 
286
        dtuple_t*       entry,  /* in: index entry */
 
287
        ulint           mode)   /* in: latch mode BTR_MODIFY_LEAF or
 
288
                                BTR_MODIFY_TREE */
 
289
{
 
290
        ibool           found;
 
291
        btr_pcur_t      pcur;
 
292
        btr_cur_t*      btr_cur;
 
293
        ibool           success;
 
294
        ibool           old_has;
 
295
        ulint           err;
 
296
        mtr_t           mtr;
 
297
        mtr_t           mtr_vers;
 
298
 
 
299
        log_free_check();
 
300
        mtr_start(&mtr);
 
301
 
 
302
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
303
 
 
304
        btr_cur = btr_pcur_get_btr_cur(&pcur);
 
305
 
 
306
        if (!found) {
 
307
                /* Not found */
 
308
 
 
309
                btr_pcur_close(&pcur);
 
310
                mtr_commit(&mtr);
 
311
 
 
312
                return(DB_SUCCESS);
 
313
        }
 
314
 
 
315
        /* We should remove the index record if no prior version of the row,
 
316
        which cannot be purged yet, requires its existence. If some requires,
 
317
        we should delete mark the record. */
 
318
 
 
319
        mtr_start(&mtr_vers);
 
320
 
 
321
        success = btr_pcur_restore_position(BTR_SEARCH_LEAF, &(node->pcur),
 
322
                                            &mtr_vers);
 
323
        ut_a(success);
 
324
 
 
325
        old_has = row_vers_old_has_index_entry(FALSE,
 
326
                                               btr_pcur_get_rec(&(node->pcur)),
 
327
                                               &mtr_vers, index, entry);
 
328
        if (old_has) {
 
329
                err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
 
330
                                                   btr_cur, TRUE, thr, &mtr);
 
331
                ut_ad(err == DB_SUCCESS);
 
332
        } else {
 
333
                /* Remove the index record */
 
334
 
 
335
                if (mode == BTR_MODIFY_LEAF) {
 
336
                        success = btr_cur_optimistic_delete(btr_cur, &mtr);
 
337
                        if (success) {
 
338
                                err = DB_SUCCESS;
 
339
                        } else {
 
340
                                err = DB_FAIL;
 
341
                        }
 
342
                } else {
 
343
                        ut_ad(mode == BTR_MODIFY_TREE);
 
344
 
 
345
                        btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
 
346
                                                   TRUE, &mtr);
 
347
 
 
348
                        /* The delete operation may fail if we have little
 
349
                        file space left: TODO: easiest to crash the database
 
350
                        and restart with more file space */
 
351
                }
 
352
        }
 
353
 
 
354
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
 
355
        btr_pcur_close(&pcur);
 
356
        mtr_commit(&mtr);
 
357
 
 
358
        return(err);
 
359
}
 
360
 
 
361
/***************************************************************
 
362
Delete marks or removes a secondary index entry if found.
 
363
NOTE that if we updated the fields of a delete-marked secondary index record
 
364
so that alphabetically they stayed the same, e.g., 'abc' -> 'aBc', we cannot
 
365
return to the original values because we do not know them. But this should
 
366
not cause problems because in row0sel.c, in queries we always retrieve the
 
367
clustered index record or an earlier version of it, if the secondary index
 
368
record through which we do the search is delete-marked. */
 
369
static
 
370
ulint
 
371
row_undo_mod_del_mark_or_remove_sec(
 
372
/*================================*/
 
373
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
374
        undo_node_t*    node,   /* in: row undo node */
 
375
        que_thr_t*      thr,    /* in: query thread */
 
376
        dict_index_t*   index,  /* in: index */
 
377
        dtuple_t*       entry)  /* in: index entry */
 
378
{
 
379
        ulint   err;
 
380
 
 
381
        err = row_undo_mod_del_mark_or_remove_sec_low(node, thr, index,
 
382
                                                      entry, BTR_MODIFY_LEAF);
 
383
        if (err == DB_SUCCESS) {
 
384
 
 
385
                return(err);
 
386
        }
 
387
 
 
388
        err = row_undo_mod_del_mark_or_remove_sec_low(node, thr, index,
 
389
                                                      entry, BTR_MODIFY_TREE);
 
390
        return(err);
 
391
}
 
392
 
 
393
/***************************************************************
 
394
Delete unmarks a secondary index entry which must be found. It might not be
 
395
delete-marked at the moment, but it does not harm to unmark it anyway. We also
 
396
need to update the fields of the secondary index record if we updated its
 
397
fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */
 
398
static
 
399
ulint
 
400
row_undo_mod_del_unmark_sec_and_undo_update(
 
401
/*========================================*/
 
402
                                /* out: DB_FAIL or DB_SUCCESS or
 
403
                                DB_OUT_OF_FILE_SPACE */
 
404
        ulint           mode,   /* in: search mode: BTR_MODIFY_LEAF or
 
405
                                BTR_MODIFY_TREE */
 
406
        que_thr_t*      thr,    /* in: query thread */
 
407
        dict_index_t*   index,  /* in: index */
 
408
        dtuple_t*       entry)  /* in: index entry */
 
409
{
 
410
        mem_heap_t*     heap;
 
411
        btr_pcur_t      pcur;
 
412
        upd_t*          update;
 
413
        ulint           err             = DB_SUCCESS;
 
414
        ibool           found;
 
415
        big_rec_t*      dummy_big_rec;
 
416
        mtr_t           mtr;
 
417
        trx_t*          trx             = thr_get_trx(thr);
 
418
 
 
419
        log_free_check();
 
420
        mtr_start(&mtr);
 
421
 
 
422
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
423
 
 
424
        if (!found) {
 
425
                fputs("InnoDB: error in sec index entry del undo in\n"
 
426
                      "InnoDB: ", stderr);
 
427
                dict_index_name_print(stderr, trx, index);
 
428
                fputs("\n"
 
429
                      "InnoDB: tuple ", stderr);
 
430
                dtuple_print(stderr, entry);
 
431
                fputs("\n"
 
432
                      "InnoDB: record ", stderr);
 
433
                rec_print(stderr, btr_pcur_get_rec(&pcur), index);
 
434
                putc('\n', stderr);
 
435
                trx_print(stderr, trx, 0);
 
436
                fputs("\n"
 
437
                      "InnoDB: Submit a detailed bug report"
 
438
                      " to http://bugs.mysql.com\n", stderr);
 
439
        } else {
 
440
                btr_cur_t*      btr_cur = btr_pcur_get_btr_cur(&pcur);
 
441
 
 
442
                err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
 
443
                                                   btr_cur, FALSE, thr, &mtr);
 
444
                ut_a(err == DB_SUCCESS);
 
445
                heap = mem_heap_create(100);
 
446
 
 
447
                update = row_upd_build_sec_rec_difference_binary(
 
448
                        index, entry, btr_cur_get_rec(btr_cur), trx, heap);
 
449
                if (upd_get_n_fields(update) == 0) {
 
450
 
 
451
                        /* Do nothing */
 
452
 
 
453
                } else if (mode == BTR_MODIFY_LEAF) {
 
454
                        /* Try an optimistic updating of the record, keeping
 
455
                        changes within the page */
 
456
 
 
457
                        err = btr_cur_optimistic_update(
 
458
                                BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG,
 
459
                                btr_cur, update, 0, thr, &mtr);
 
460
                        if (err == DB_OVERFLOW || err == DB_UNDERFLOW) {
 
461
                                err = DB_FAIL;
 
462
                        }
 
463
                } else {
 
464
                        ut_a(mode == BTR_MODIFY_TREE);
 
465
                        err = btr_cur_pessimistic_update(
 
466
                                BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG,
 
467
                                btr_cur, &dummy_big_rec,
 
468
                                update, 0, thr, &mtr);
 
469
                }
 
470
 
 
471
                mem_heap_free(heap);
 
472
        }
 
473
 
 
474
        btr_pcur_close(&pcur);
 
475
        mtr_commit(&mtr);
 
476
 
 
477
        return(err);
 
478
}
 
479
 
 
480
/***************************************************************
 
481
Undoes a modify in secondary indexes when undo record type is UPD_DEL. */
 
482
static
 
483
ulint
 
484
row_undo_mod_upd_del_sec(
 
485
/*=====================*/
 
486
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
487
        undo_node_t*    node,   /* in: row undo node */
 
488
        que_thr_t*      thr)    /* in: query thread */
 
489
{
 
490
        mem_heap_t*     heap;
 
491
        dtuple_t*       entry;
 
492
        dict_index_t*   index;
 
493
        ulint           err;
 
494
 
 
495
        heap = mem_heap_create(1024);
 
496
 
 
497
        while (node->index != NULL) {
 
498
                index = node->index;
 
499
 
 
500
                entry = row_build_index_entry(node->row, index, heap);
 
501
 
 
502
                err = row_undo_mod_del_mark_or_remove_sec(node, thr, index,
 
503
                                                          entry);
 
504
                if (err != DB_SUCCESS) {
 
505
 
 
506
                        mem_heap_free(heap);
 
507
 
 
508
                        return(err);
 
509
                }
 
510
 
 
511
                node->index = dict_table_get_next_index(node->index);
 
512
        }
 
513
 
 
514
        mem_heap_free(heap);
 
515
 
 
516
        return(DB_SUCCESS);
 
517
}
 
518
 
 
519
/***************************************************************
 
520
Undoes a modify in secondary indexes when undo record type is DEL_MARK. */
 
521
static
 
522
ulint
 
523
row_undo_mod_del_mark_sec(
 
524
/*======================*/
 
525
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
526
        undo_node_t*    node,   /* in: row undo node */
 
527
        que_thr_t*      thr)    /* in: query thread */
 
528
{
 
529
        mem_heap_t*     heap;
 
530
        dtuple_t*       entry;
 
531
        dict_index_t*   index;
 
532
        ulint           err;
 
533
 
 
534
        heap = mem_heap_create(1024);
 
535
 
 
536
        while (node->index != NULL) {
 
537
                index = node->index;
 
538
 
 
539
                entry = row_build_index_entry(node->row, index, heap);
 
540
 
 
541
                err = row_undo_mod_del_unmark_sec_and_undo_update(
 
542
                        BTR_MODIFY_LEAF, thr, index, entry);
 
543
                if (err == DB_FAIL) {
 
544
                        err = row_undo_mod_del_unmark_sec_and_undo_update(
 
545
                                BTR_MODIFY_TREE, thr, index, entry);
 
546
                }
 
547
 
 
548
                if (err != DB_SUCCESS) {
 
549
 
 
550
                        mem_heap_free(heap);
 
551
 
 
552
                        return(err);
 
553
                }
 
554
 
 
555
                node->index = dict_table_get_next_index(node->index);
 
556
        }
 
557
 
 
558
        mem_heap_free(heap);
 
559
 
 
560
        return(DB_SUCCESS);
 
561
}
 
562
 
 
563
/***************************************************************
 
564
Undoes a modify in secondary indexes when undo record type is UPD_EXIST. */
 
565
static
 
566
ulint
 
567
row_undo_mod_upd_exist_sec(
 
568
/*=======================*/
 
569
                                /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
570
        undo_node_t*    node,   /* in: row undo node */
 
571
        que_thr_t*      thr)    /* in: query thread */
 
572
{
 
573
        mem_heap_t*     heap;
 
574
        dtuple_t*       entry;
 
575
        dict_index_t*   index;
 
576
        ulint           err;
 
577
 
 
578
        if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
 
579
                /* No change in secondary indexes */
 
580
 
 
581
                return(DB_SUCCESS);
 
582
        }
 
583
 
 
584
        heap = mem_heap_create(1024);
 
585
 
 
586
        while (node->index != NULL) {
 
587
                index = node->index;
 
588
 
 
589
                if (row_upd_changes_ord_field_binary(node->row, node->index,
 
590
                                                     node->update)) {
 
591
 
 
592
                        /* Build the newest version of the index entry */
 
593
                        entry = row_build_index_entry(node->row, index, heap);
 
594
 
 
595
                        /* NOTE that if we updated the fields of a
 
596
                        delete-marked secondary index record so that
 
597
                        alphabetically they stayed the same, e.g.,
 
598
                        'abc' -> 'aBc', we cannot return to the original
 
599
                        values because we do not know them. But this should
 
600
                        not cause problems because in row0sel.c, in queries
 
601
                        we always retrieve the clustered index record or an
 
602
                        earlier version of it, if the secondary index record
 
603
                        through which we do the search is delete-marked. */
 
604
 
 
605
                        err = row_undo_mod_del_mark_or_remove_sec(node, thr,
 
606
                                                                  index,
 
607
                                                                  entry);
 
608
                        if (err != DB_SUCCESS) {
 
609
                                mem_heap_free(heap);
 
610
 
 
611
                                return(err);
 
612
                        }
 
613
 
 
614
                        /* We may have to update the delete mark in the
 
615
                        secondary index record of the previous version of
 
616
                        the row. We also need to update the fields of
 
617
                        the secondary index record if we updated its fields
 
618
                        but alphabetically they stayed the same, e.g.,
 
619
                        'abc' -> 'aBc'. */
 
620
 
 
621
                        row_upd_index_replace_new_col_vals(entry, index,
 
622
                                                           node->update, NULL);
 
623
                        err = row_undo_mod_del_unmark_sec_and_undo_update(
 
624
                                BTR_MODIFY_LEAF, thr, index, entry);
 
625
                        if (err == DB_FAIL) {
 
626
                                err = row_undo_mod_del_unmark_sec_and_undo_update(
 
627
                                        BTR_MODIFY_TREE, thr, index, entry);
 
628
                        }
 
629
 
 
630
                        if (err != DB_SUCCESS) {
 
631
                                mem_heap_free(heap);
 
632
 
 
633
                                return(err);
 
634
                        }
 
635
                }
 
636
 
 
637
                node->index = dict_table_get_next_index(node->index);
 
638
        }
 
639
 
 
640
        mem_heap_free(heap);
 
641
 
 
642
        return(DB_SUCCESS);
 
643
}
 
644
 
 
645
/***************************************************************
 
646
Parses the row reference and other info in a modify undo log record. */
 
647
static
 
648
void
 
649
row_undo_mod_parse_undo_rec(
 
650
/*========================*/
 
651
        undo_node_t*    node,   /* in: row undo node */
 
652
        que_thr_t*      thr)    /* in: query thread */
 
653
{
 
654
        dict_index_t*   clust_index;
 
655
        byte*           ptr;
 
656
        dulint          undo_no;
 
657
        dulint          table_id;
 
658
        dulint          trx_id;
 
659
        dulint          roll_ptr;
 
660
        ulint           info_bits;
 
661
        ulint           type;
 
662
        ulint           cmpl_info;
 
663
        ibool           dummy_extern;
 
664
        trx_t*          trx;
 
665
 
 
666
        ut_ad(node && thr);
 
667
        trx = thr_get_trx(thr);
 
668
        ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
 
669
                                    &dummy_extern, &undo_no, &table_id);
 
670
        node->rec_type = type;
 
671
 
 
672
        node->table = dict_table_get_on_id(table_id, trx);
 
673
 
 
674
        /* TODO: other fixes associated with DROP TABLE + rollback in the
 
675
        same table by another user */
 
676
 
 
677
        if (node->table == NULL) {
 
678
                /* Table was dropped */
 
679
                return;
 
680
        }
 
681
 
 
682
        if (node->table->ibd_file_missing) {
 
683
                /* We skip undo operations to missing .ibd files */
 
684
                node->table = NULL;
 
685
 
 
686
                return;
 
687
        }
 
688
 
 
689
        clust_index = dict_table_get_first_index(node->table);
 
690
 
 
691
        ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
 
692
                                               &info_bits);
 
693
 
 
694
        ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
 
695
                                       node->heap);
 
696
 
 
697
        trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
 
698
                                       roll_ptr, info_bits, trx,
 
699
                                       node->heap, &(node->update));
 
700
        node->new_roll_ptr = roll_ptr;
 
701
        node->new_trx_id = trx_id;
 
702
        node->cmpl_info = cmpl_info;
 
703
}
 
704
 
 
705
/***************************************************************
 
706
Undoes a modify operation on a row of a table. */
 
707
 
 
708
ulint
 
709
row_undo_mod(
 
710
/*=========*/
 
711
                                /* out: DB_SUCCESS or error code */
 
712
        undo_node_t*    node,   /* in: row undo node */
 
713
        que_thr_t*      thr)    /* in: query thread */
 
714
{
 
715
        ibool   found;
 
716
        ulint   err;
 
717
 
 
718
        ut_ad(node && thr);
 
719
        ut_ad(node->state == UNDO_NODE_MODIFY);
 
720
 
 
721
        row_undo_mod_parse_undo_rec(node, thr);
 
722
 
 
723
        if (node->table == NULL) {
 
724
                found = FALSE;
 
725
        } else {
 
726
                found = row_undo_search_clust_to_pcur(node);
 
727
        }
 
728
 
 
729
        if (!found) {
 
730
                /* It is already undone, or will be undone by another query
 
731
                thread, or table was dropped */
 
732
 
 
733
                trx_undo_rec_release(node->trx, node->undo_no);
 
734
                node->state = UNDO_NODE_FETCH_NEXT;
 
735
 
 
736
                return(DB_SUCCESS);
 
737
        }
 
738
 
 
739
        node->index = dict_table_get_next_index(
 
740
                dict_table_get_first_index(node->table));
 
741
 
 
742
        if (node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
 
743
 
 
744
                err = row_undo_mod_upd_exist_sec(node, thr);
 
745
 
 
746
        } else if (node->rec_type == TRX_UNDO_DEL_MARK_REC) {
 
747
 
 
748
                err = row_undo_mod_del_mark_sec(node, thr);
 
749
        } else {
 
750
                ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
 
751
                err = row_undo_mod_upd_del_sec(node, thr);
 
752
        }
 
753
 
 
754
        if (err != DB_SUCCESS) {
 
755
 
 
756
                return(err);
 
757
        }
 
758
 
 
759
        err = row_undo_mod_clust(node, thr);
 
760
 
 
761
        return(err);
 
762
}