~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/trx/trx0rec.c

  • Committer: Monty Taylor
  • Date: 2008-09-15 17:24:04 UTC
  • Revision ID: monty@inaugust.com-20080915172404-ygh6hiyu0q7qpa9x
Removed strndup calls.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include "trx0undo.h"
20
20
#include "dict0dict.h"
21
21
#include "ut0mem.h"
22
 
#include "row0ext.h"
23
22
#include "row0upd.h"
24
23
#include "que0que.h"
25
24
#include "trx0purge.h"
69
68
 
70
69
/***************************************************************
71
70
Parses a redo log record of adding an undo log record. */
72
 
UNIV_INTERN
 
71
 
73
72
byte*
74
73
trx_undo_parse_add_undo_rec(
75
74
/*========================*/
120
119
ulint
121
120
trx_undo_left(
122
121
/*==========*/
123
 
                                /* out: bytes left */
124
 
        const page_t*   page,   /* in: undo log page */
125
 
        const byte*     ptr)    /* in: pointer to page */
 
122
                        /* out: bytes left */
 
123
        page_t* page,   /* in: undo log page */
 
124
        byte*   ptr)    /* in: pointer to page */
126
125
{
127
126
        /* The '- 10' is a safety margin, in case we have some small
128
127
        calculation error below */
131
130
}
132
131
 
133
132
/**************************************************************************
134
 
Set the next and previous pointers in the undo page for the undo record
135
 
that was written to ptr. Update the first free value by the number of bytes
136
 
written for this undo record.*/
137
 
static
138
 
ulint
139
 
trx_undo_page_set_next_prev_and_add(
140
 
/*================================*/
141
 
                                        /* out: offset of the inserted entry
142
 
                                        on the page if succeeded, 0 if fail */
143
 
        page_t*         undo_page,      /* in/out: undo log page */
144
 
        byte*           ptr,            /* in: ptr up to where data has been
145
 
                                        written on this undo page. */
146
 
        mtr_t*          mtr)            /* in: mtr */
147
 
{
148
 
        ulint           first_free;     /* offset within undo_page */
149
 
        ulint           end_of_rec;     /* offset within undo_page */
150
 
        byte*           ptr_to_first_free;
151
 
                                        /* pointer within undo_page
152
 
                                        that points to the next free
153
 
                                        offset value within undo_page.*/
154
 
 
155
 
        ut_ad(ptr > undo_page);
156
 
        ut_ad(ptr < undo_page + UNIV_PAGE_SIZE);
157
 
 
158
 
        if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < 2)) {
159
 
 
160
 
                return(0);
161
 
        }
162
 
 
163
 
        ptr_to_first_free = undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE;
164
 
 
165
 
        first_free = mach_read_from_2(ptr_to_first_free);
166
 
 
167
 
        /* Write offset of the previous undo log record */
168
 
        mach_write_to_2(ptr, first_free);
169
 
        ptr += 2;
170
 
 
171
 
        end_of_rec = ptr - undo_page;
172
 
 
173
 
        /* Write offset of the next undo log record */
174
 
        mach_write_to_2(undo_page + first_free, end_of_rec);
175
 
 
176
 
        /* Update the offset to first free undo record */
177
 
        mach_write_to_2(ptr_to_first_free, end_of_rec);
178
 
 
179
 
        /* Write this log entry to the UNDO log */
180
 
        trx_undof_page_add_undo_rec_log(undo_page, first_free,
181
 
                                        end_of_rec, mtr);
182
 
 
183
 
        return(first_free);
184
 
}
185
 
 
186
 
/**************************************************************************
187
133
Reports in the undo log of an insert of a clustered index record. */
188
134
static
189
135
ulint
194
140
        page_t*         undo_page,      /* in: undo log page */
195
141
        trx_t*          trx,            /* in: transaction */
196
142
        dict_index_t*   index,          /* in: clustered index */
197
 
        const dtuple_t* clust_entry,    /* in: index entry which will be
 
143
        dtuple_t*       clust_entry,    /* in: index entry which will be
198
144
                                        inserted to the clustered index */
199
145
        mtr_t*          mtr)            /* in: mtr */
200
146
{
201
147
        ulint           first_free;
202
148
        byte*           ptr;
 
149
        ulint           len;
 
150
        dfield_t*       field;
 
151
        ulint           flen;
203
152
        ulint           i;
204
153
 
205
 
        ut_ad(dict_index_is_clust(index));
206
154
        ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
207
155
                               + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
208
156
 
212
160
 
213
161
        ut_ad(first_free <= UNIV_PAGE_SIZE);
214
162
 
215
 
        if (trx_undo_left(undo_page, ptr) < 2 + 1 + 11 + 11) {
 
163
        if (trx_undo_left(undo_page, ptr) < 30) {
216
164
 
217
 
                /* Not enough space for writing the general parameters */
 
165
                /* NOTE: the value 30 must be big enough such that the general
 
166
                fields written below fit on the undo log page */
218
167
 
219
168
                return(0);
220
169
        }
223
172
        ptr += 2;
224
173
 
225
174
        /* Store first some general parameters to the undo log */
226
 
        *ptr++ = TRX_UNDO_INSERT_REC;
227
 
        ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
228
 
        ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
 
175
        mach_write_to_1(ptr, TRX_UNDO_INSERT_REC);
 
176
        ptr++;
 
177
 
 
178
        len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
 
179
        ptr += len;
 
180
 
 
181
        len = mach_dulint_write_much_compressed(ptr, (index->table)->id);
 
182
        ptr += len;
229
183
        /*----------------------------------------*/
230
184
        /* Store then the fields required to uniquely determine the record
231
185
        to be inserted in the clustered index */
232
186
 
233
187
        for (i = 0; i < dict_index_get_n_unique(index); i++) {
234
188
 
235
 
                const dfield_t* field   = dtuple_get_nth_field(clust_entry, i);
236
 
                ulint           flen    = dfield_get_len(field);
 
189
                field = dtuple_get_nth_field(clust_entry, i);
 
190
 
 
191
                flen = dfield_get_len(field);
237
192
 
238
193
                if (trx_undo_left(undo_page, ptr) < 5) {
239
194
 
240
195
                        return(0);
241
196
                }
242
197
 
243
 
                ptr += mach_write_compressed(ptr, flen);
 
198
                len = mach_write_compressed(ptr, flen);
 
199
                ptr += len;
244
200
 
245
201
                if (flen != UNIV_SQL_NULL) {
246
202
                        if (trx_undo_left(undo_page, ptr) < flen) {
253
209
                }
254
210
        }
255
211
 
256
 
        return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
 
212
        if (trx_undo_left(undo_page, ptr) < 2) {
 
213
 
 
214
                return(0);
 
215
        }
 
216
 
 
217
        /*----------------------------------------*/
 
218
        /* Write pointers to the previous and the next undo log records */
 
219
 
 
220
        if (trx_undo_left(undo_page, ptr) < 2) {
 
221
 
 
222
                return(0);
 
223
        }
 
224
 
 
225
        mach_write_to_2(ptr, first_free);
 
226
        ptr += 2;
 
227
 
 
228
        mach_write_to_2(undo_page + first_free, ptr - undo_page);
 
229
 
 
230
        mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
 
231
                        ptr - undo_page);
 
232
 
 
233
        /* Write the log entry to the REDO log of this change in the UNDO
 
234
        log */
 
235
        trx_undof_page_add_undo_rec_log(undo_page, first_free,
 
236
                                        ptr - undo_page, mtr);
 
237
        return(first_free);
257
238
}
258
239
 
259
240
/**************************************************************************
260
241
Reads from an undo log record the general parameters. */
261
 
UNIV_INTERN
 
242
 
262
243
byte*
263
244
trx_undo_rec_get_pars(
264
245
/*==================*/
275
256
        dulint*         table_id)       /* out: table id */
276
257
{
277
258
        byte*           ptr;
 
259
        ulint           len;
278
260
        ulint           type_cmpl;
279
261
 
280
262
        ptr = undo_rec + 2;
293
275
        *cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
294
276
 
295
277
        *undo_no = mach_dulint_read_much_compressed(ptr);
296
 
        ptr += mach_dulint_get_much_compressed_size(*undo_no);
 
278
        len = mach_dulint_get_much_compressed_size(*undo_no);
 
279
        ptr += len;
297
280
 
298
281
        *table_id = mach_dulint_read_much_compressed(ptr);
299
 
        ptr += mach_dulint_get_much_compressed_size(*table_id);
 
282
        len = mach_dulint_get_much_compressed_size(*table_id);
 
283
        ptr += len;
300
284
 
301
285
        return(ptr);
302
286
}
311
295
                        reading these values */
312
296
        byte*   ptr,    /* in: pointer to remaining part of undo log record */
313
297
        byte**  field,  /* out: pointer to stored field */
314
 
        ulint*  len,    /* out: length of the field, or UNIV_SQL_NULL */
315
 
        ulint*  orig_len)/* out: original length of the locally
316
 
                        stored part of an externally stored column, or 0 */
 
298
        ulint*  len)    /* out: length of the field, or UNIV_SQL_NULL */
317
299
{
318
300
        *len = mach_read_compressed(ptr);
319
301
        ptr += mach_get_compressed_size(*len);
320
302
 
321
 
        *orig_len = 0;
322
 
 
323
 
        switch (*len) {
324
 
        case UNIV_SQL_NULL:
325
 
                *field = NULL;
326
 
                break;
327
 
        case UNIV_EXTERN_STORAGE_FIELD:
328
 
                *orig_len = mach_read_compressed(ptr);
329
 
                ptr += mach_get_compressed_size(*orig_len);
330
 
                *len = mach_read_compressed(ptr);
331
 
                ptr += mach_get_compressed_size(*len);
332
 
                *field = ptr;
333
 
                ptr += *len;
334
 
 
335
 
                ut_ad(*orig_len >= BTR_EXTERN_FIELD_REF_SIZE);
336
 
                ut_ad(*len > *orig_len);
337
 
                ut_ad(*len >= REC_MAX_INDEX_COL_LEN
338
 
                      + BTR_EXTERN_FIELD_REF_SIZE);
339
 
 
340
 
                *len += UNIV_EXTERN_STORAGE_FIELD;
341
 
                break;
342
 
        default:
343
 
                *field = ptr;
 
303
        *field = ptr;
 
304
 
 
305
        if (*len != UNIV_SQL_NULL) {
344
306
                if (*len >= UNIV_EXTERN_STORAGE_FIELD) {
345
 
                        ptr += *len - UNIV_EXTERN_STORAGE_FIELD;
 
307
                        ptr += (*len - UNIV_EXTERN_STORAGE_FIELD);
346
308
                } else {
347
309
                        ptr += *len;
348
310
                }
353
315
 
354
316
/***********************************************************************
355
317
Builds a row reference from an undo log record. */
356
 
UNIV_INTERN
 
318
 
357
319
byte*
358
320
trx_undo_rec_get_row_ref(
359
321
/*=====================*/
370
332
        mem_heap_t*     heap)   /* in: memory heap from which the memory
371
333
                                needed is allocated */
372
334
{
 
335
        dfield_t*       dfield;
 
336
        byte*           field;
 
337
        ulint           len;
373
338
        ulint           ref_len;
374
339
        ulint           i;
375
340
 
376
341
        ut_ad(index && ptr && ref && heap);
377
 
        ut_a(dict_index_is_clust(index));
 
342
        ut_a(index->type & DICT_CLUSTERED);
378
343
 
379
344
        ref_len = dict_index_get_n_unique(index);
380
345
 
383
348
        dict_index_copy_types(*ref, index, ref_len);
384
349
 
385
350
        for (i = 0; i < ref_len; i++) {
386
 
                dfield_t*       dfield;
387
 
                byte*           field;
388
 
                ulint           len;
389
 
                ulint           orig_len;
390
 
 
391
351
                dfield = dtuple_get_nth_field(*ref, i);
392
352
 
393
 
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
 
353
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
394
354
 
395
355
                dfield_set_data(dfield, field, len);
396
356
        }
400
360
 
401
361
/***********************************************************************
402
362
Skips a row reference from an undo log record. */
403
 
UNIV_INTERN
 
363
 
404
364
byte*
405
365
trx_undo_rec_skip_row_ref(
406
366
/*======================*/
410
370
                                record, at the start of the row reference */
411
371
        dict_index_t*   index)  /* in: clustered index */
412
372
{
 
373
        byte*   field;
 
374
        ulint   len;
413
375
        ulint   ref_len;
414
376
        ulint   i;
415
377
 
416
378
        ut_ad(index && ptr);
417
 
        ut_a(dict_index_is_clust(index));
 
379
        ut_a(index->type & DICT_CLUSTERED);
418
380
 
419
381
        ref_len = dict_index_get_n_unique(index);
420
382
 
421
383
        for (i = 0; i < ref_len; i++) {
422
 
                byte*   field;
423
 
                ulint   len;
424
 
                ulint   orig_len;
425
 
 
426
 
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
427
 
        }
428
 
 
429
 
        return(ptr);
430
 
}
431
 
 
432
 
/**************************************************************************
433
 
Fetch a prefix of an externally stored column, for writing to the undo log
434
 
of an update or delete marking of a clustered index record. */
435
 
static
436
 
byte*
437
 
trx_undo_page_fetch_ext(
438
 
/*====================*/
439
 
                                        /* out: ext_buf */
440
 
        byte*           ext_buf,        /* in: a buffer of
441
 
                                        REC_MAX_INDEX_COL_LEN
442
 
                                        + BTR_EXTERN_FIELD_REF_SIZE */
443
 
        ulint           zip_size,       /* compressed page size in bytes,
444
 
                                        or 0 for uncompressed BLOB  */
445
 
        const byte*     field,          /* in: an externally stored column */
446
 
        ulint*          len)            /* in: length of field;
447
 
                                        out: used length of ext_buf */
448
 
{
449
 
        /* Fetch the BLOB. */
450
 
        ulint   ext_len = btr_copy_externally_stored_field_prefix(
451
 
                ext_buf, REC_MAX_INDEX_COL_LEN, zip_size, field, *len);
452
 
        /* BLOBs should always be nonempty. */
453
 
        ut_a(ext_len);
454
 
        /* Append the BLOB pointer to the prefix. */
455
 
        memcpy(ext_buf + ext_len,
456
 
               field + *len - BTR_EXTERN_FIELD_REF_SIZE,
457
 
               BTR_EXTERN_FIELD_REF_SIZE);
458
 
        *len = ext_len + BTR_EXTERN_FIELD_REF_SIZE;
459
 
        return(ext_buf);
460
 
}
461
 
 
462
 
/**************************************************************************
463
 
Writes to the undo log a prefix of an externally stored column. */
464
 
static
465
 
byte*
466
 
trx_undo_page_report_modify_ext(
467
 
/*============================*/
468
 
                                        /* out: undo log position */
469
 
        byte*           ptr,            /* in: undo log position,
470
 
                                        at least 15 bytes must be available */
471
 
        byte*           ext_buf,        /* in: a buffer of
472
 
                                        REC_MAX_INDEX_COL_LEN
473
 
                                        + BTR_EXTERN_FIELD_REF_SIZE,
474
 
                                        or NULL when should not fetch
475
 
                                        a longer prefix */
476
 
        ulint           zip_size,       /* compressed page size in bytes,
477
 
                                        or 0 for uncompressed BLOB  */
478
 
        const byte**    field,          /* in/out: the locally stored part of
479
 
                                        the externally stored column */
480
 
        ulint*          len)            /* in/out: length of field, in bytes */
481
 
{
482
 
        if (ext_buf) {
483
 
                /* If an ordering column is externally stored, we will
484
 
                have to store a longer prefix of the field.  In this
485
 
                case, write to the log a marker followed by the
486
 
                original length and the real length of the field. */
487
 
                ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD);
488
 
 
489
 
                ptr += mach_write_compressed(ptr, *len);
490
 
 
491
 
                *field = trx_undo_page_fetch_ext(ext_buf, zip_size,
492
 
                                                 *field, len);
493
 
 
494
 
                ptr += mach_write_compressed(ptr, *len);
495
 
        } else {
496
 
                ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD
497
 
                                             + *len);
 
384
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
498
385
        }
499
386
 
500
387
        return(ptr);
514
401
        trx_t*          trx,            /* in: transaction */
515
402
        dict_index_t*   index,          /* in: clustered index where update or
516
403
                                        delete marking is done */
517
 
        const rec_t*    rec,            /* in: clustered index record which
 
404
        rec_t*          rec,            /* in: clustered index record which
518
405
                                        has NOT yet been modified */
519
406
        const ulint*    offsets,        /* in: rec_get_offsets(rec, index) */
520
 
        const upd_t*    update,         /* in: update vector which tells the
 
407
        upd_t*          update,         /* in: update vector which tells the
521
408
                                        columns to be updated; in the case of
522
409
                                        a delete, this should be set to NULL */
523
410
        ulint           cmpl_info,      /* in: compiler info on secondary
525
412
        mtr_t*          mtr)            /* in: mtr */
526
413
{
527
414
        dict_table_t*   table;
 
415
        upd_field_t*    upd_field;
528
416
        ulint           first_free;
529
417
        byte*           ptr;
530
 
        const byte*     field;
 
418
        ulint           len;
 
419
        byte*           field;
531
420
        ulint           flen;
 
421
        ulint           pos;
 
422
        dulint          roll_ptr;
 
423
        dulint          trx_id;
 
424
        ulint           bits;
532
425
        ulint           col_no;
 
426
        byte*           old_ptr;
533
427
        ulint           type_cmpl;
534
428
        byte*           type_cmpl_ptr;
535
429
        ulint           i;
536
 
        byte            ext_buf[REC_MAX_INDEX_COL_LEN
537
 
                                + BTR_EXTERN_FIELD_REF_SIZE];
538
430
 
539
 
        ut_a(dict_index_is_clust(index));
 
431
        ut_a(index->type & DICT_CLUSTERED);
540
432
        ut_ad(rec_offs_validate(rec, index, offsets));
541
433
        ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
542
434
                               + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE);
561
453
 
562
454
        /* Store first some general parameters to the undo log */
563
455
 
564
 
        if (!update) {
 
456
        if (update) {
 
457
                if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
 
458
                        type_cmpl = TRX_UNDO_UPD_DEL_REC;
 
459
                } else {
 
460
                        type_cmpl = TRX_UNDO_UPD_EXIST_REC;
 
461
                }
 
462
        } else {
565
463
                type_cmpl = TRX_UNDO_DEL_MARK_REC;
566
 
        } else if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
567
 
                type_cmpl = TRX_UNDO_UPD_DEL_REC;
568
 
        } else {
569
 
                type_cmpl = TRX_UNDO_UPD_EXIST_REC;
570
464
        }
571
465
 
572
 
        type_cmpl |= cmpl_info * TRX_UNDO_CMPL_INFO_MULT;
 
466
        type_cmpl = type_cmpl | (cmpl_info * TRX_UNDO_CMPL_INFO_MULT);
 
467
 
 
468
        mach_write_to_1(ptr, type_cmpl);
 
469
 
573
470
        type_cmpl_ptr = ptr;
574
471
 
575
 
        *ptr++ = (byte) type_cmpl;
576
 
        ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
 
472
        ptr++;
 
473
        len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
 
474
        ptr += len;
577
475
 
578
 
        ptr += mach_dulint_write_much_compressed(ptr, table->id);
 
476
        len = mach_dulint_write_much_compressed(ptr, table->id);
 
477
        ptr += len;
579
478
 
580
479
        /*----------------------------------------*/
581
480
        /* Store the state of the info bits */
582
481
 
583
 
        *ptr++ = (byte) rec_get_info_bits(rec, dict_table_is_comp(table));
 
482
        bits = rec_get_info_bits(rec, dict_table_is_comp(table));
 
483
        mach_write_to_1(ptr, bits);
 
484
        ptr += 1;
584
485
 
585
486
        /* Store the values of the system columns */
586
487
        field = rec_get_nth_field(rec, offsets,
587
488
                                  dict_index_get_sys_col_pos(
588
 
                                          index, DATA_TRX_ID), &flen);
589
 
        ut_ad(flen == DATA_TRX_ID_LEN);
590
 
 
591
 
        ptr += mach_dulint_write_compressed(ptr, trx_read_trx_id(field));
592
 
 
 
489
                                          index, DATA_TRX_ID), &len);
 
490
        ut_ad(len == DATA_TRX_ID_LEN);
 
491
        trx_id = trx_read_trx_id(field);
593
492
        field = rec_get_nth_field(rec, offsets,
594
493
                                  dict_index_get_sys_col_pos(
595
 
                                          index, DATA_ROLL_PTR), &flen);
596
 
        ut_ad(flen == DATA_ROLL_PTR_LEN);
597
 
 
598
 
        ptr += mach_dulint_write_compressed(ptr, trx_read_roll_ptr(field));
 
494
                                          index, DATA_ROLL_PTR), &len);
 
495
        ut_ad(len == DATA_ROLL_PTR_LEN);
 
496
        roll_ptr = trx_read_roll_ptr(field);
 
497
 
 
498
        len = mach_dulint_write_compressed(ptr, trx_id);
 
499
        ptr += len;
 
500
 
 
501
        len = mach_dulint_write_compressed(ptr, roll_ptr);
 
502
        ptr += len;
599
503
 
600
504
        /*----------------------------------------*/
601
505
        /* Store then the fields required to uniquely determine the
605
509
 
606
510
                field = rec_get_nth_field(rec, offsets, i, &flen);
607
511
 
608
 
                /* The ordering columns must not be stored externally. */
609
 
                ut_ad(!rec_offs_nth_extern(offsets, i));
610
 
                ut_ad(dict_index_get_nth_col(index, i)->ord_part);
611
 
 
612
 
                if (trx_undo_left(undo_page, ptr) < 5) {
 
512
                if (trx_undo_left(undo_page, ptr) < 4) {
613
513
 
614
514
                        return(0);
615
515
                }
616
516
 
617
 
                ptr += mach_write_compressed(ptr, flen);
 
517
                len = mach_write_compressed(ptr, flen);
 
518
                ptr += len;
618
519
 
619
520
                if (flen != UNIV_SQL_NULL) {
620
521
                        if (trx_undo_left(undo_page, ptr) < flen) {
636
537
                        return(0);
637
538
                }
638
539
 
639
 
                ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
 
540
                len = mach_write_compressed(ptr, upd_get_n_fields(update));
 
541
                ptr += len;
640
542
 
641
543
                for (i = 0; i < upd_get_n_fields(update); i++) {
642
544
 
643
 
                        ulint   pos = upd_get_nth_field(update, i)->field_no;
 
545
                        upd_field = upd_get_nth_field(update, i);
 
546
                        pos = upd_field->field_no;
644
547
 
645
548
                        /* Write field number to undo log */
646
549
                        if (trx_undo_left(undo_page, ptr) < 5) {
648
551
                                return(0);
649
552
                        }
650
553
 
651
 
                        ptr += mach_write_compressed(ptr, pos);
 
554
                        len = mach_write_compressed(ptr, pos);
 
555
                        ptr += len;
652
556
 
653
557
                        /* Save the old value of field */
654
558
                        field = rec_get_nth_field(rec, offsets, pos, &flen);
655
559
 
656
 
                        if (trx_undo_left(undo_page, ptr) < 15) {
 
560
                        if (trx_undo_left(undo_page, ptr) < 5) {
657
561
 
658
562
                                return(0);
659
563
                        }
660
564
 
661
565
                        if (rec_offs_nth_extern(offsets, pos)) {
662
 
                                ptr = trx_undo_page_report_modify_ext(
 
566
                                /* If a field has external storage, we add
 
567
                                to flen the flag */
 
568
 
 
569
                                len = mach_write_compressed(
663
570
                                        ptr,
664
 
                                        dict_index_get_nth_col(index, pos)
665
 
                                        ->ord_part
666
 
                                        && flen < REC_MAX_INDEX_COL_LEN
667
 
                                        ? ext_buf : NULL,
668
 
                                        dict_table_zip_size(table),
669
 
                                        &field, &flen);
 
571
                                        UNIV_EXTERN_STORAGE_FIELD + flen);
670
572
 
671
573
                                /* Notify purge that it eventually has to
672
574
                                free the old externally stored field */
673
575
 
674
576
                                trx->update_undo->del_marks = TRUE;
675
577
 
676
 
                                *type_cmpl_ptr |= TRX_UNDO_UPD_EXTERN;
 
578
                                *type_cmpl_ptr = *type_cmpl_ptr
 
579
                                        | TRX_UNDO_UPD_EXTERN;
677
580
                        } else {
678
 
                                ptr += mach_write_compressed(ptr, flen);
 
581
                                len = mach_write_compressed(ptr, flen);
679
582
                        }
680
583
 
 
584
                        ptr += len;
 
585
 
681
586
                        if (flen != UNIV_SQL_NULL) {
682
587
                                if (trx_undo_left(undo_page, ptr) < flen) {
683
588
 
697
602
        in the purge of old versions where we use it to build and search the
698
603
        delete marked index records, to look if we can remove them from the
699
604
        index tree. Note that starting from 4.0.14 also externally stored
700
 
        fields can be ordering in some index. Starting from 5.2, we no longer
701
 
        store REC_MAX_INDEX_COL_LEN first bytes to the undo log record,
702
 
        but we can construct the column prefix fields in the index by
703
 
        fetching the first page of the BLOB that is pointed to by the
704
 
        clustered index. This works also in crash recovery, because all pages
705
 
        (including BLOBs) are recovered before anything is rolled back. */
 
605
        fields can be ordering in some index. But we always store at least
 
606
        384 first bytes locally to the clustered index record, which means
 
607
        we can construct the column prefix fields in the index from the
 
608
        stored data. */
706
609
 
707
610
        if (!update || !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
708
 
                byte*   old_ptr = ptr;
709
611
 
710
612
                trx->update_undo->del_marks = TRUE;
711
613
 
714
616
                        return(0);
715
617
                }
716
618
 
 
619
                old_ptr = ptr;
 
620
 
717
621
                /* Reserve 2 bytes to write the number of bytes the stored
718
622
                fields take in this undo record */
719
623
 
725
629
                        const dict_col_t*       col
726
630
                                = dict_table_get_nth_col(table, col_no);
727
631
 
728
 
                        if (col->ord_part) {
729
 
                                ulint   pos;
730
 
 
731
 
                                /* Write field number to undo log */
732
 
                                if (trx_undo_left(undo_page, ptr) < 5 + 15) {
733
 
 
734
 
                                        return(0);
735
 
                                }
 
632
                        if (col->ord_part > 0) {
736
633
 
737
634
                                pos = dict_index_get_nth_col_pos(index,
738
635
                                                                 col_no);
739
 
                                ptr += mach_write_compressed(ptr, pos);
 
636
 
 
637
                                /* Write field number to undo log */
 
638
                                if (trx_undo_left(undo_page, ptr) < 5) {
 
639
 
 
640
                                        return(0);
 
641
                                }
 
642
 
 
643
                                len = mach_write_compressed(ptr, pos);
 
644
                                ptr += len;
740
645
 
741
646
                                /* Save the old value of field */
742
647
                                field = rec_get_nth_field(rec, offsets, pos,
743
648
                                                          &flen);
744
649
 
745
 
                                if (rec_offs_nth_extern(offsets, pos)) {
746
 
                                        ptr = trx_undo_page_report_modify_ext(
747
 
                                                ptr,
748
 
                                                flen < REC_MAX_INDEX_COL_LEN
749
 
                                                ? ext_buf : NULL,
750
 
                                                dict_table_zip_size(table),
751
 
                                                &field, &flen);
752
 
                                } else {
753
 
                                        ptr += mach_write_compressed(
754
 
                                                ptr, flen);
 
650
                                if (trx_undo_left(undo_page, ptr) < 5) {
 
651
 
 
652
                                        return(0);
755
653
                                }
756
654
 
 
655
                                len = mach_write_compressed(ptr, flen);
 
656
                                ptr += len;
 
657
 
757
658
                                if (flen != UNIV_SQL_NULL) {
758
659
                                        if (trx_undo_left(undo_page, ptr)
759
660
                                            < flen) {
794
695
/**************************************************************************
795
696
Reads from an undo log update record the system field values of the old
796
697
version. */
797
 
UNIV_INTERN
 
698
 
798
699
byte*
799
700
trx_undo_update_rec_get_sys_cols(
800
701
/*=============================*/
807
708
        dulint* roll_ptr,       /* out: roll ptr */
808
709
        ulint*  info_bits)      /* out: info bits state */
809
710
{
 
711
        ulint   len;
 
712
 
810
713
        /* Read the state of the info bits */
811
714
        *info_bits = mach_read_from_1(ptr);
812
715
        ptr += 1;
814
717
        /* Read the values of the system columns */
815
718
 
816
719
        *trx_id = mach_dulint_read_compressed(ptr);
817
 
        ptr += mach_dulint_get_compressed_size(*trx_id);
 
720
        len = mach_dulint_get_compressed_size(*trx_id);
 
721
        ptr += len;
818
722
 
819
723
        *roll_ptr = mach_dulint_read_compressed(ptr);
820
 
        ptr += mach_dulint_get_compressed_size(*roll_ptr);
 
724
        len = mach_dulint_get_compressed_size(*roll_ptr);
 
725
        ptr += len;
821
726
 
822
727
        return(ptr);
823
728
}
858
763
 
859
764
/***********************************************************************
860
765
Builds an update vector based on a remaining part of an undo log record. */
861
 
UNIV_INTERN
 
766
 
862
767
byte*
863
768
trx_undo_update_rec_get_update(
864
769
/*===========================*/
889
794
        upd_t*          update;
890
795
        ulint           n_fields;
891
796
        byte*           buf;
 
797
        byte*           field;
 
798
        ulint           len;
 
799
        ulint           field_no;
892
800
        ulint           i;
893
801
 
894
 
        ut_a(dict_index_is_clust(index));
 
802
        ut_a(index->type & DICT_CLUSTERED);
895
803
 
896
804
        if (type != TRX_UNDO_DEL_MARK_REC) {
897
805
                ptr = trx_undo_update_rec_get_n_upd_fields(ptr, &n_fields);
927
835
 
928
836
        for (i = 0; i < n_fields; i++) {
929
837
 
930
 
                byte*   field;
931
 
                ulint   len;
932
 
                ulint   field_no;
933
 
                ulint   orig_len;
934
 
 
935
838
                ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
936
839
 
937
840
                if (field_no >= dict_index_get_n_fields(index)) {
953
856
                        return(NULL);
954
857
                }
955
858
 
 
859
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
 
860
 
956
861
                upd_field = upd_get_nth_field(update, i);
957
862
 
958
863
                upd_field_set_field_no(upd_field, field_no, index, trx);
959
864
 
960
 
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
961
 
 
962
 
                upd_field->orig_len = orig_len;
963
 
 
964
 
                if (len == UNIV_SQL_NULL) {
965
 
                        dfield_set_null(&upd_field->new_val);
966
 
                } else if (len < UNIV_EXTERN_STORAGE_FIELD) {
967
 
                        dfield_set_data(&upd_field->new_val, field, len);
968
 
                } else {
 
865
                if (len != UNIV_SQL_NULL && len >= UNIV_EXTERN_STORAGE_FIELD) {
 
866
 
 
867
                        upd_field->extern_storage = TRUE;
 
868
 
969
869
                        len -= UNIV_EXTERN_STORAGE_FIELD;
970
 
 
971
 
                        dfield_set_data(&upd_field->new_val, field, len);
972
 
                        dfield_set_ext(&upd_field->new_val);
973
870
                }
 
871
 
 
872
                dfield_set_data(&(upd_field->new_val), field, len);
974
873
        }
975
874
 
976
875
        *upd = update;
981
880
/***********************************************************************
982
881
Builds a partial row from an update undo log record. It contains the
983
882
columns which occur as ordering in any index of the table. */
984
 
UNIV_INTERN
 
883
 
985
884
byte*
986
885
trx_undo_rec_get_partial_row(
987
886
/*=========================*/
999
898
        mem_heap_t*     heap)   /* in: memory heap from which the memory
1000
899
                                needed is allocated */
1001
900
{
1002
 
        const byte*     end_ptr;
 
901
        dfield_t*       dfield;
 
902
        byte*           field;
 
903
        ulint           len;
 
904
        ulint           field_no;
 
905
        ulint           col_no;
1003
906
        ulint           row_len;
 
907
        ulint           total_len;
 
908
        byte*           start_ptr;
 
909
        ulint           i;
1004
910
 
1005
 
        ut_ad(index);
1006
 
        ut_ad(ptr);
1007
 
        ut_ad(row);
1008
 
        ut_ad(heap);
1009
 
        ut_ad(dict_index_is_clust(index));
 
911
        ut_ad(index && ptr && row && heap);
1010
912
 
1011
913
        row_len = dict_table_get_n_cols(index->table);
1012
914
 
1014
916
 
1015
917
        dict_table_copy_types(*row, index->table);
1016
918
 
1017
 
        end_ptr = ptr + mach_read_from_2(ptr);
 
919
        start_ptr = ptr;
 
920
 
 
921
        total_len = mach_read_from_2(ptr);
1018
922
        ptr += 2;
1019
923
 
1020
 
        while (ptr != end_ptr) {
1021
 
                dfield_t*               dfield;
1022
 
                byte*                   field;
1023
 
                ulint                   field_no;
1024
 
                const dict_col_t*       col;
1025
 
                ulint                   col_no;
1026
 
                ulint                   len;
1027
 
                ulint                   orig_len;
 
924
        for (i = 0;; i++) {
 
925
 
 
926
                if (ptr == start_ptr + total_len) {
 
927
 
 
928
                        break;
 
929
                }
1028
930
 
1029
931
                ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
1030
932
 
1031
 
                col = dict_index_get_nth_col(index, field_no);
1032
 
                col_no = dict_col_get_no(col);
 
933
                col_no = dict_index_get_nth_col_no(index, field_no);
1033
934
 
1034
 
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
 
935
                ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
1035
936
 
1036
937
                dfield = dtuple_get_nth_field(*row, col_no);
1037
938
 
1038
939
                dfield_set_data(dfield, field, len);
1039
 
 
1040
 
                if (len != UNIV_SQL_NULL
1041
 
                    && len >= UNIV_EXTERN_STORAGE_FIELD) {
1042
 
                        dfield_set_len(dfield,
1043
 
                                       len - UNIV_EXTERN_STORAGE_FIELD);
1044
 
                        dfield_set_ext(dfield);
1045
 
                        /* If the prefix of this column is indexed,
1046
 
                        ensure that enough prefix is stored in the
1047
 
                        undo log record. */
1048
 
                        ut_a(!col->ord_part
1049
 
                             || dfield_get_len(dfield)
1050
 
                             >= REC_MAX_INDEX_COL_LEN
1051
 
                             + BTR_EXTERN_FIELD_REF_SIZE);
1052
 
                }
1053
940
        }
1054
941
 
1055
942
        return(ptr);
1076
963
 
1077
964
/***************************************************************
1078
965
Parses a redo log record of erasing of an undo page end. */
1079
 
UNIV_INTERN
 
966
 
1080
967
byte*
1081
968
trx_undo_parse_erase_page_end(
1082
969
/*==========================*/
1103
990
of a clustered index record. This information is used in a rollback of the
1104
991
transaction and in consistent reads that must look to the history of this
1105
992
transaction. */
1106
 
UNIV_INTERN
 
993
 
1107
994
ulint
1108
995
trx_undo_report_row_operation(
1109
996
/*==========================*/
1114
1001
                                        TRX_UNDO_MODIFY_OP */
1115
1002
        que_thr_t*      thr,            /* in: query thread */
1116
1003
        dict_index_t*   index,          /* in: clustered index */
1117
 
        const dtuple_t* clust_entry,    /* in: in the case of an insert,
 
1004
        dtuple_t*       clust_entry,    /* in: in the case of an insert,
1118
1005
                                        index entry to insert into the
1119
1006
                                        clustered index, otherwise NULL */
1120
 
        const upd_t*    update,         /* in: in the case of an update,
 
1007
        upd_t*          update,         /* in: in the case of an update,
1121
1008
                                        the update vector, otherwise NULL */
1122
1009
        ulint           cmpl_info,      /* in: compiler info on secondary
1123
1010
                                        index updates */
1124
 
        const rec_t*    rec,            /* in: in case of an update or delete
 
1011
        rec_t*          rec,            /* in: in case of an update or delete
1125
1012
                                        marking, the record in the clustered
1126
1013
                                        index, otherwise NULL */
1127
1014
        dulint*         roll_ptr)       /* out: rollback pointer to the
1131
1018
{
1132
1019
        trx_t*          trx;
1133
1020
        trx_undo_t*     undo;
 
1021
        page_t*         undo_page;
 
1022
        ulint           offset;
1134
1023
        ulint           page_no;
 
1024
        ibool           is_insert;
1135
1025
        trx_rseg_t*     rseg;
1136
1026
        mtr_t           mtr;
1137
1027
        ulint           err             = DB_SUCCESS;
1138
1028
        mem_heap_t*     heap            = NULL;
1139
1029
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1140
1030
        ulint*          offsets         = offsets_;
1141
 
        rec_offs_init(offsets_);
 
1031
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1142
1032
 
1143
 
        ut_a(dict_index_is_clust(index));
 
1033
        ut_a(index->type & DICT_CLUSTERED);
1144
1034
 
1145
1035
        if (flags & BTR_NO_UNDO_LOG_FLAG) {
1146
1036
 
1147
1037
                *roll_ptr = ut_dulint_zero;
1148
1038
 
1149
 
                return(DB_SUCCESS);
 
1039
                return(err);
1150
1040
        }
1151
1041
 
1152
1042
        ut_ad(thr);
1168
1058
                }
1169
1059
 
1170
1060
                undo = trx->insert_undo;
1171
 
 
1172
 
                if (UNIV_UNLIKELY(!undo)) {
1173
 
                        /* Did not succeed */
1174
 
                        mutex_exit(&(trx->undo_mutex));
1175
 
 
1176
 
                        return(err);
1177
 
                }
 
1061
                is_insert = TRUE;
1178
1062
        } else {
1179
1063
                ut_ad(op_type == TRX_UNDO_MODIFY_OP);
1180
1064
 
1185
1069
                }
1186
1070
 
1187
1071
                undo = trx->update_undo;
1188
 
 
1189
 
                if (UNIV_UNLIKELY(!undo)) {
1190
 
                        /* Did not succeed */
1191
 
                        mutex_exit(&(trx->undo_mutex));
1192
 
                        return(err);
1193
 
                }
1194
 
 
1195
 
                offsets = rec_get_offsets(rec, index, offsets,
1196
 
                                          ULINT_UNDEFINED, &heap);
 
1072
                is_insert = FALSE;
 
1073
        }
 
1074
 
 
1075
        if (err != DB_SUCCESS) {
 
1076
                /* Did not succeed: return the error encountered */
 
1077
                mutex_exit(&(trx->undo_mutex));
 
1078
 
 
1079
                return(err);
1197
1080
        }
1198
1081
 
1199
1082
        page_no = undo->last_page_no;
1201
1084
        mtr_start(&mtr);
1202
1085
 
1203
1086
        for (;;) {
1204
 
                buf_block_t*    undo_block;
1205
 
                page_t*         undo_page;
1206
 
                ulint           offset;
 
1087
                undo_page = buf_page_get_gen(undo->space, page_no,
 
1088
                                             RW_X_LATCH, undo->guess_page,
 
1089
                                             BUF_GET,
 
1090
                                             __FILE__, __LINE__,
 
1091
                                             &mtr);
1207
1092
 
1208
 
                undo_block = buf_page_get_gen(undo->space, undo->zip_size,
1209
 
                                              page_no, RW_X_LATCH,
1210
 
                                              undo->guess_block, BUF_GET,
1211
 
                                              __FILE__, __LINE__, &mtr);
1212
1093
#ifdef UNIV_SYNC_DEBUG
1213
 
                buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
 
1094
                buf_page_dbg_add_level(undo_page, SYNC_TRX_UNDO_PAGE);
1214
1095
#endif /* UNIV_SYNC_DEBUG */
1215
 
                undo_page = buf_block_get_frame(undo_block);
1216
1096
 
1217
1097
                if (op_type == TRX_UNDO_INSERT_OP) {
1218
1098
                        offset = trx_undo_page_report_insert(
1219
1099
                                undo_page, trx, index, clust_entry, &mtr);
1220
1100
                } else {
 
1101
                        offsets = rec_get_offsets(rec, index, offsets,
 
1102
                                                  ULINT_UNDEFINED, &heap);
1221
1103
                        offset = trx_undo_page_report_modify(
1222
1104
                                undo_page, trx, index, rec, offsets, update,
1223
1105
                                cmpl_info, &mtr);
1224
1106
                }
1225
1107
 
1226
 
                if (UNIV_UNLIKELY(offset == 0)) {
 
1108
                if (offset == 0) {
1227
1109
                        /* The record did not fit on the page. We erase the
1228
1110
                        end segment of the undo log page and write a log
1229
1111
                        record of it: this is to ensure that in the debug
1231
1113
                        records stays identical to the original page */
1232
1114
 
1233
1115
                        trx_undo_erase_page_end(undo_page, &mtr);
1234
 
                        mtr_commit(&mtr);
1235
 
                } else {
 
1116
                }
 
1117
 
 
1118
                mtr_commit(&mtr);
 
1119
 
 
1120
                if (offset != 0) {
1236
1121
                        /* Success */
1237
1122
 
1238
 
                        mtr_commit(&mtr);
1239
 
 
1240
 
                        undo->empty = FALSE;
1241
 
                        undo->top_page_no = page_no;
1242
 
                        undo->top_offset  = offset;
1243
 
                        undo->top_undo_no = trx->undo_no;
1244
 
                        undo->guess_block = undo_block;
1245
 
 
1246
 
                        UT_DULINT_INC(trx->undo_no);
1247
 
 
1248
 
                        mutex_exit(&trx->undo_mutex);
1249
 
 
1250
 
                        *roll_ptr = trx_undo_build_roll_ptr(
1251
 
                                op_type == TRX_UNDO_INSERT_OP,
1252
 
                                rseg->id, page_no, offset);
1253
 
                        if (UNIV_LIKELY_NULL(heap)) {
1254
 
                                mem_heap_free(heap);
1255
 
                        }
1256
 
                        return(DB_SUCCESS);
 
1123
                        break;
1257
1124
                }
1258
1125
 
1259
1126
                ut_ad(page_no == undo->last_page_no);
1272
1139
 
1273
1140
                mutex_exit(&(rseg->mutex));
1274
1141
 
1275
 
                if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
 
1142
                if (page_no == FIL_NULL) {
1276
1143
                        /* Did not succeed: out of space */
1277
1144
 
1278
1145
                        mutex_exit(&(trx->undo_mutex));
1283
1150
                        return(DB_OUT_OF_FILE_SPACE);
1284
1151
                }
1285
1152
        }
 
1153
 
 
1154
        undo->empty = FALSE;
 
1155
        undo->top_page_no = page_no;
 
1156
        undo->top_offset  = offset;
 
1157
        undo->top_undo_no = trx->undo_no;
 
1158
        undo->guess_page = undo_page;
 
1159
 
 
1160
        UT_DULINT_INC(trx->undo_no);
 
1161
 
 
1162
        mutex_exit(&(trx->undo_mutex));
 
1163
 
 
1164
        *roll_ptr = trx_undo_build_roll_ptr(is_insert, rseg->id, page_no,
 
1165
                                            offset);
 
1166
        if (UNIV_LIKELY_NULL(heap)) {
 
1167
                mem_heap_free(heap);
 
1168
        }
 
1169
        return(err);
1286
1170
}
1287
1171
 
1288
1172
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
1290
1174
/**********************************************************************
1291
1175
Copies an undo record to heap. This function can be called if we know that
1292
1176
the undo log record exists. */
1293
 
UNIV_INTERN
 
1177
 
1294
1178
trx_undo_rec_t*
1295
1179
trx_undo_get_undo_rec_low(
1296
1180
/*======================*/
1313
1197
 
1314
1198
        mtr_start(&mtr);
1315
1199
 
1316
 
        undo_page = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
1317
 
                                                page_no, &mtr);
 
1200
        undo_page = trx_undo_page_get_s_latched(rseg->space, page_no, &mtr);
1318
1201
 
1319
1202
        undo_rec = trx_undo_rec_copy(undo_page + offset, heap);
1320
1203
 
1325
1208
 
1326
1209
/**********************************************************************
1327
1210
Copies an undo record to heap. */
1328
 
UNIV_INTERN
 
1211
 
1329
1212
ulint
1330
1213
trx_undo_get_undo_rec(
1331
1214
/*==================*/
1363
1246
Build a previous version of a clustered index record. This function checks
1364
1247
that the caller has a latch on the index page of the clustered index record
1365
1248
and an s-latch on the purge_view. This guarantees that the stack of versions
1366
 
is locked all the way down to the purge_view. */
1367
 
UNIV_INTERN
 
1249
is locked. */
 
1250
 
1368
1251
ulint
1369
1252
trx_undo_prev_version_build(
1370
1253
/*========================*/
1372
1255
                                the previous version is not >= purge_view,
1373
1256
                                which means that it may have been removed,
1374
1257
                                DB_ERROR if corrupted record */
1375
 
        const rec_t*    index_rec,/* in: clustered index record in the
 
1258
        rec_t*          index_rec,/* in: clustered index record in the
1376
1259
                                index tree */
1377
1260
        mtr_t*          index_mtr __attribute__((unused)),
1378
1261
                                /* in: mtr which contains the latch to
1379
1262
                                index_rec page and purge_view */
1380
 
        const rec_t*    rec,    /* in: version of a clustered index record */
 
1263
        rec_t*          rec,    /* in: version of a clustered index record */
1381
1264
        dict_index_t*   index,  /* in: clustered index */
1382
1265
        ulint*          offsets,/* in: rec_get_offsets(rec, index) */
1383
1266
        mem_heap_t*     heap,   /* in: memory heap from which the memory
1384
1267
                                needed is allocated */
1385
1268
        rec_t**         old_vers)/* out, own: previous version, or NULL if
1386
1269
                                rec is the first inserted version, or if
1387
 
                                history data has been deleted (an error),
1388
 
                                or if the purge COULD have removed the version
1389
 
                                though it has not yet done so */
 
1270
                                history data has been deleted */
1390
1271
{
1391
 
        trx_undo_rec_t* undo_rec        = NULL;
 
1272
        trx_undo_rec_t* undo_rec;
1392
1273
        dtuple_t*       entry;
1393
1274
        dulint          rec_trx_id;
1394
1275
        ulint           type;
1407
1288
#ifdef UNIV_SYNC_DEBUG
1408
1289
        ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
1409
1290
#endif /* UNIV_SYNC_DEBUG */
1410
 
        ut_ad(mtr_memo_contains_page(index_mtr, index_rec, MTR_MEMO_PAGE_S_FIX)
1411
 
              || mtr_memo_contains_page(index_mtr, index_rec,
1412
 
                                        MTR_MEMO_PAGE_X_FIX));
 
1291
        ut_ad(mtr_memo_contains(index_mtr, buf_block_align(index_rec),
 
1292
                                MTR_MEMO_PAGE_S_FIX)
 
1293
              || mtr_memo_contains(index_mtr, buf_block_align(index_rec),
 
1294
                                   MTR_MEMO_PAGE_X_FIX));
1413
1295
        ut_ad(rec_offs_validate(rec, index, offsets));
1414
1296
 
1415
 
        if (!dict_index_is_clust(index)) {
 
1297
        if (!(index->type & DICT_CLUSTERED)) {
1416
1298
                fprintf(stderr, "InnoDB: Error: trying to access"
1417
1299
                        " update undo rec for non-clustered index %s\n"
1418
1300
                        "InnoDB: Submit a detailed bug report to"
1442
1324
 
1443
1325
        err = trx_undo_get_undo_rec(roll_ptr, rec_trx_id, &undo_rec, heap);
1444
1326
 
1445
 
        if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
1446
 
                /* The undo record may already have been purged.
1447
 
                This should never happen in InnoDB. */
 
1327
        if (err != DB_SUCCESS) {
1448
1328
 
1449
1329
                return(err);
1450
1330
        }
1454
1334
 
1455
1335
        ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
1456
1336
                                               &info_bits);
1457
 
 
1458
 
        /* (a) If a clustered index record version is such that the
1459
 
        trx id stamp in it is bigger than purge_sys->view, then the
1460
 
        BLOBs in that version are known to exist (the purge has not
1461
 
        progressed that far);
1462
 
 
1463
 
        (b) if the version is the first version such that trx id in it
1464
 
        is less than purge_sys->view, and it is not delete-marked,
1465
 
        then the BLOBs in that version are known to exist (the purge
1466
 
        cannot have purged the BLOBs referenced by that version
1467
 
        yet).
1468
 
 
1469
 
        This function does not fetch any BLOBs.  The callers might, by
1470
 
        possibly invoking row_ext_create() via row_build().  However,
1471
 
        they should have all needed information in the *old_vers
1472
 
        returned by this function.  This is because *old_vers is based
1473
 
        on the transaction undo log records.  The function
1474
 
        trx_undo_page_fetch_ext() will write BLOB prefixes to the
1475
 
        transaction undo log that are at least as long as the longest
1476
 
        possible column prefix in a secondary index.  Thus, secondary
1477
 
        index entries for *old_vers can be constructed without
1478
 
        dereferencing any BLOB pointers. */
1479
 
 
1480
1337
        ptr = trx_undo_rec_skip_row_ref(ptr, index);
1481
1338
 
1482
1339
        ptr = trx_undo_update_rec_get_update(ptr, index, type, trx_id,
1522
1379
                      "InnoDB: record version ", stderr);
1523
1380
                rec_print_new(stderr, rec, offsets);
1524
1381
                fprintf(stderr, "\n"
1525
 
                        "InnoDB: Record trx id " TRX_ID_FMT
1526
 
                        ", update rec trx id " TRX_ID_FMT "\n"
 
1382
                        "InnoDB: Record trx id %lu %lu, update rec"
 
1383
                        " trx id %lu %lu\n"
1527
1384
                        "InnoDB: Roll ptr in rec %lu %lu, in update rec"
1528
1385
                        " %lu %lu\n",
1529
 
                        TRX_ID_PREP_PRINTF(rec_trx_id),
1530
 
                        TRX_ID_PREP_PRINTF(trx_id),
 
1386
                        (ulong) ut_dulint_get_high(rec_trx_id),
 
1387
                        (ulong) ut_dulint_get_low(rec_trx_id),
 
1388
                        (ulong) ut_dulint_get_high(trx_id),
 
1389
                        (ulong) ut_dulint_get_low(trx_id),
1531
1390
                        (ulong) ut_dulint_get_high(old_roll_ptr),
1532
1391
                        (ulong) ut_dulint_get_low(old_roll_ptr),
1533
1392
                        (ulong) ut_dulint_get_high(roll_ptr),
1538
1397
        }
1539
1398
 
1540
1399
        if (row_upd_changes_field_size_or_external(index, offsets, update)) {
1541
 
                ulint   n_ext;
 
1400
                ulint*  ext_vect;
 
1401
                ulint   n_ext_vect;
1542
1402
 
1543
1403
                /* We have to set the appropriate extern storage bits in the
1544
1404
                old version of the record: the extern bits in rec for those
1545
1405
                fields that update does NOT update, as well as the the bits for
1546
1406
                those fields that update updates to become externally stored
1547
 
                fields. Store the info: */
 
1407
                fields. Store the info to ext_vect: */
1548
1408
 
1549
 
                entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index,
1550
 
                                               offsets, &n_ext, heap);
1551
 
                n_ext += btr_push_update_extern_fields(entry, update, heap);
1552
 
                /* The page containing the clustered index record
1553
 
                corresponding to entry is latched in mtr.  Thus the
1554
 
                following call is safe. */
 
1409
                ext_vect = mem_alloc(sizeof(ulint)
 
1410
                                     * rec_offs_n_fields(offsets));
 
1411
                n_ext_vect = btr_push_update_extern_fields(ext_vect, offsets,
 
1412
                                                           update);
 
1413
                entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec,
 
1414
                                               heap);
1555
1415
                row_upd_index_replace_new_col_vals(entry, index, update, heap);
1556
1416
 
1557
 
                buf = mem_heap_alloc(heap, rec_get_converted_size(index, entry,
1558
 
                                                                  n_ext));
1559
 
 
1560
 
                *old_vers = rec_convert_dtuple_to_rec(buf, index,
1561
 
                                                      entry, n_ext);
 
1417
                buf = mem_heap_alloc(heap,
 
1418
                                     rec_get_converted_size(index, entry));
 
1419
 
 
1420
                *old_vers = rec_convert_dtuple_to_rec(buf, index, entry);
 
1421
 
 
1422
                /* Now set the extern bits in the old version of the record */
 
1423
                rec_set_field_extern_bits(*old_vers, index,
 
1424
                                          ext_vect, n_ext_vect, NULL);
 
1425
                mem_free(ext_vect);
1562
1426
        } else {
1563
1427
                buf = mem_heap_alloc(heap, rec_offs_size(offsets));
1564
1428
                *old_vers = rec_copy(buf, rec, offsets);
1565
1429
                rec_offs_make_valid(*old_vers, index, offsets);
1566
 
                row_upd_rec_in_place(*old_vers, index, offsets, update, NULL);
 
1430
                row_upd_rec_in_place(*old_vers, offsets, update);
1567
1431
        }
1568
1432
 
1569
1433
        return(DB_SUCCESS);