~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
4
 
 
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.
8
 
 
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.
12
 
 
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
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file row/row0umod.c
 
1
/******************************************************
21
2
Undo modify of a row
22
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
23
6
Created 2/27/1997 Heikki Tuuri
24
7
*******************************************************/
25
8
 
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. */
60
43
 
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
67
 
check.
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. */
70
 
 
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 */
76
 
static
 
47
that it should be undone in the same rollback. */
 
48
UNIV_INLINE
77
49
ibool
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 */
82
56
{
83
57
        trx_undo_rec_t* undo_rec;
84
58
        trx_t*          trx;
85
59
 
86
60
        trx = node->trx;
87
61
 
88
 
        if (node->new_trx_id != trx->id) {
 
62
        if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) {
89
63
 
90
 
                *undo_no = 0;
 
64
                *undo_no = ut_dulint_zero;
91
65
                return(FALSE);
92
66
        }
93
67
 
95
69
 
96
70
        *undo_no = trx_undo_rec_get_undo_no(undo_rec);
97
71
 
98
 
        return(trx->roll_limit <= *undo_no);
 
72
        return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0);
99
73
}
100
74
 
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. */
104
77
static
105
78
ulint
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 */
113
88
{
114
89
        btr_pcur_t*     pcur;
115
90
        btr_cur_t*      btr_cur;
116
91
        ulint           err;
117
 
#ifdef UNIV_DEBUG
118
92
        ibool           success;
119
 
#endif /* UNIV_DEBUG */
120
93
 
121
94
        pcur = &(node->pcur);
122
95
        btr_cur = btr_pcur_get_btr_cur(pcur);
123
96
 
124
 
#ifdef UNIV_DEBUG
125
 
        success =
126
 
#endif /* UNIV_DEBUG */
127
 
        btr_pcur_restore_position(mode, pcur, mtr);
 
97
        success = btr_pcur_restore_position(mode, pcur, mtr);
128
98
 
129
99
        ut_ad(success);
130
100
 
157
127
        return(err);
158
128
}
159
129
 
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. */
167
132
static
168
133
ulint
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 */
175
142
{
176
143
        btr_pcur_t*     pcur;
177
144
        btr_cur_t*      btr_cur;
178
145
        ulint           err;
179
146
        ibool           success;
180
147
 
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);
184
150
 
210
176
        } else {
211
177
                ut_ad(mode == BTR_MODIFY_TREE);
212
178
 
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 */
215
182
 
216
 
                btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
217
 
                                           thr_is_recv(thr)
218
 
                                           ? RB_RECOVERY_PURGE_REC
219
 
                                           : RB_NONE, mtr);
 
183
                btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr);
220
184
 
221
185
                /* The delete operation may fail if we have little
222
186
                file space left: TODO: easiest to crash the database
226
190
        return(err);
227
191
}
228
192
 
229
 
/***********************************************************//**
 
193
/***************************************************************
230
194
Undoes a modify in a clustered index record. Sets also the node state for the
231
 
next round of undo.
232
 
@return DB_SUCCESS or error code: we may run out of file space */
 
195
next round of undo. */
233
196
static
234
197
ulint
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
 
201
                                out of file space */
 
202
        undo_node_t*    node,   /* in: row undo node */
 
203
        que_thr_t*      thr)    /* in: query thread */
239
204
{
240
205
        btr_pcur_t*     pcur;
241
206
        mtr_t           mtr;
242
207
        ulint           err;
243
208
        ibool           success;
244
209
        ibool           more_vers;
245
 
        undo_no_t       new_undo_no;
 
210
        dulint          new_undo_no;
246
211
 
247
212
        ut_ad(node && thr);
248
213
 
249
 
        log_free_check();
250
 
 
251
214
        /* Check if also the previous version of the clustered index record
252
215
        should be undone in this same rollback operation */
253
216
 
317
280
        return(err);
318
281
}
319
282
 
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. */
323
285
static
324
286
ulint
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 */
333
297
{
334
 
        btr_pcur_t              pcur;
335
 
        btr_cur_t*              btr_cur;
336
 
        ibool                   success;
337
 
        ibool                   old_has;
338
 
        ulint                   err;
339
 
        mtr_t                   mtr;
340
 
        mtr_t                   mtr_vers;
341
 
        enum row_search_result  search_result;
 
298
        ibool           found;
 
299
        btr_pcur_t      pcur;
 
300
        btr_cur_t*      btr_cur;
 
301
        ibool           success;
 
302
        ibool           old_has;
 
303
        ulint           err;
 
304
        mtr_t           mtr;
 
305
        mtr_t           mtr_vers;
342
306
 
343
307
        log_free_check();
344
308
        mtr_start(&mtr);
345
309
 
 
310
        found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
 
311
 
346
312
        btr_cur = btr_pcur_get_btr_cur(&pcur);
347
313
 
348
 
        ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
349
 
 
350
 
        search_result = row_search_index_entry(index, entry, mode,
351
 
                                               &pcur, &mtr);
352
 
 
353
 
        switch (UNIV_EXPECT(search_result, ROW_FOUND)) {
354
 
        case ROW_NOT_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
359
 
                may be missing.
360
 
 
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. */
364
 
 
365
 
                err = DB_SUCCESS;
366
 
                goto func_exit;
367
 
        case ROW_FOUND:
368
 
                break;
369
 
        case ROW_BUFFERED:
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. */
374
 
                ut_error;
 
314
        if (!found) {
 
315
                /* Not found */
 
316
 
 
317
                btr_pcur_close(&pcur);
 
318
                mtr_commit(&mtr);
 
319
 
 
320
                return(DB_SUCCESS);
375
321
        }
376
322
 
377
323
        /* We should remove the index record if no prior version of the row,
404
350
                } else {
405
351
                        ut_ad(mode == BTR_MODIFY_TREE);
406
352
 
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
412
357
                        columns. */
413
358
                        ut_ad(!dict_index_is_clust(index));
414
359
                        btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
421
366
        }
422
367
 
423
368
        btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
424
 
 
425
 
func_exit:
426
369
        btr_pcur_close(&pcur);
427
370
        mtr_commit(&mtr);
428
371
 
429
372
        return(err);
430
373
}
431
374
 
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. */
441
383
static
442
384
ulint
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 */
449
392
{
450
393
        ulint   err;
451
394
 
461
404
        return(err);
462
405
}
463
406
 
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'. */
470
412
static
471
413
ulint
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 */
479
423
{
480
 
        mem_heap_t*             heap;
481
 
        btr_pcur_t              pcur;
482
 
        btr_cur_t*              btr_cur;
483
 
        upd_t*                  update;
484
 
        ulint                   err             = DB_SUCCESS;
485
 
        big_rec_t*              dummy_big_rec;
486
 
        mtr_t                   mtr;
487
 
        trx_t*                  trx             = thr_get_trx(thr);
488
 
        enum row_search_result  search_result;
 
424
        mem_heap_t*     heap;
 
425
        btr_pcur_t      pcur;
 
426
        upd_t*          update;
 
427
        ulint           err             = DB_SUCCESS;
 
428
        big_rec_t*      dummy_big_rec;
 
429
        mtr_t           mtr;
 
430
        trx_t*          trx             = thr_get_trx(thr);
489
431
 
490
432
        /* Ignore indexes that are being created. */
491
433
        if (UNIV_UNLIKELY(*index->name == TEMP_INDEX_PREFIX)) {
496
438
        log_free_check();
497
439
        mtr_start(&mtr);
498
440
 
499
 
        ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF);
500
 
 
501
 
        search_result = row_search_index_entry(index, entry, mode,
502
 
                                               &pcur, &mtr);
503
 
 
504
 
        switch (search_result) {
505
 
        case ROW_BUFFERED:
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. */
510
 
                ut_error;
511
 
        case ROW_NOT_FOUND:
 
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);
523
454
                fputs("\n"
524
455
                      "InnoDB: Submit a detailed bug report"
525
456
                      " to http://bugs.mysql.com\n", stderr);
526
 
                break;
527
 
        case ROW_FOUND:
528
 
                btr_cur = btr_pcur_get_btr_cur(&pcur);
 
457
        } else {
 
458
                btr_cur_t*      btr_cur = btr_pcur_get_btr_cur(&pcur);
 
459
 
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);
568
499
        return(err);
569
500
}
570
501
 
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. */
574
504
static
575
505
ulint
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 */
580
511
{
581
512
        mem_heap_t*     heap;
582
513
        dtuple_t*       entry;
583
514
        dict_index_t*   index;
584
515
        ulint           err     = DB_SUCCESS;
585
516
 
586
 
        ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
587
517
        heap = mem_heap_create(1024);
588
518
 
589
519
        while (node->index != NULL) {
601
531
                        does not exist.  However, this situation may
602
532
                        only occur during the rollback of incomplete
603
533
                        transactions. */
604
 
                        ut_a(thr_is_recv(thr));
 
534
                        ut_a(trx_is_recv(thr_get_trx(thr)));
605
535
                } else {
606
536
                        err = row_undo_mod_del_mark_or_remove_sec(
607
537
                                node, thr, index, entry);
622
552
        return(err);
623
553
}
624
554
 
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. */
628
557
static
629
558
ulint
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 */
634
564
{
635
565
        mem_heap_t*     heap;
636
566
        dtuple_t*       entry;
667
597
        return(DB_SUCCESS);
668
598
}
669
599
 
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. */
673
602
static
674
603
ulint
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 */
679
609
{
680
610
        mem_heap_t*     heap;
681
611
        dtuple_t*       entry;
699
629
                        /* Build the newest version of the index entry */
700
630
                        entry = row_build_index_entry(node->row, node->ext,
701
631
                                                      index, heap);
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. */
709
 
 
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);
716
 
 
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);
721
 
 
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. */
729
 
                        } else {
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
740
 
                                delete-marked. */
741
 
 
742
 
                                err = row_undo_mod_del_mark_or_remove_sec(
743
 
                                        node, thr, index, entry);
744
 
                                if (err != DB_SUCCESS) {
745
 
                                        mem_heap_free(heap);
746
 
 
747
 
                                        return(err);
748
 
                                }
749
 
 
750
 
                                mem_heap_empty(heap);
 
632
                        ut_a(entry);
 
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. */
 
642
 
 
643
                        err = row_undo_mod_del_mark_or_remove_sec(node, thr,
 
644
                                                                  index,
 
645
                                                                  entry);
 
646
                        if (err != DB_SUCCESS) {
 
647
                                mem_heap_free(heap);
 
648
 
 
649
                                return(err);
751
650
                        }
752
651
 
753
652
                        /* We may have to update the delete mark in the
756
655
                        the secondary index record if we updated its fields
757
656
                        but alphabetically they stayed the same, e.g.,
758
657
                        'abc' -> 'aBc'. */
 
658
                        mem_heap_empty(heap);
759
659
                        entry = row_build_index_entry(node->undo_row,
760
660
                                                      node->undo_ext,
761
661
                                                      index, heap);
783
683
        return(DB_SUCCESS);
784
684
}
785
685
 
786
 
/***********************************************************//**
 
686
/***************************************************************
787
687
Parses the row reference and other info in a modify undo log record. */
788
688
static
789
689
void
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 */
794
694
{
795
695
        dict_index_t*   clust_index;
796
696
        byte*           ptr;
797
 
        undo_no_t       undo_no;
798
 
        table_id_t      table_id;
799
 
        trx_id_t        trx_id;
800
 
        roll_ptr_t      roll_ptr;
 
697
        dulint          undo_no;
 
698
        dulint          table_id;
 
699
        dulint          trx_id;
 
700
        dulint          roll_ptr;
801
701
        ulint           info_bits;
802
702
        ulint           type;
803
703
        ulint           cmpl_info;
843
743
        node->cmpl_info = cmpl_info;
844
744
}
845
745
 
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. */
849
748
UNIV_INTERN
850
749
ulint
851
750
row_undo_mod(
852
751
/*=========*/
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 */
855
755
{
856
756
        ulint   err;
857
757