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.*/
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 */
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.*/
155
ut_ad(ptr > undo_page);
156
ut_ad(ptr < undo_page + UNIV_PAGE_SIZE);
158
if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < 2)) {
163
ptr_to_first_free = undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE;
165
first_free = mach_read_from_2(ptr_to_first_free);
167
/* Write offset of the previous undo log record */
168
mach_write_to_2(ptr, first_free);
171
end_of_rec = ptr - undo_page;
173
/* Write offset of the next undo log record */
174
mach_write_to_2(undo_page + first_free, end_of_rec);
176
/* Update the offset to first free undo record */
177
mach_write_to_2(ptr_to_first_free, end_of_rec);
179
/* Write this log entry to the UNDO log */
180
trx_undof_page_add_undo_rec_log(undo_page, first_free,
186
/**************************************************************************
187
133
Reports in the undo log of an insert of a clustered index record. */
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 */
201
147
ulint first_free;
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);
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);
178
len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
181
len = mach_dulint_write_much_compressed(ptr, (index->table)->id);
229
183
/*----------------------------------------*/
230
184
/* Store then the fields required to uniquely determine the record
231
185
to be inserted in the clustered index */
233
187
for (i = 0; i < dict_index_get_n_unique(index); i++) {
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);
191
flen = dfield_get_len(field);
238
193
if (trx_undo_left(undo_page, ptr) < 5) {
243
ptr += mach_write_compressed(ptr, flen);
198
len = mach_write_compressed(ptr, flen);
245
201
if (flen != UNIV_SQL_NULL) {
246
202
if (trx_undo_left(undo_page, ptr) < flen) {
256
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
212
if (trx_undo_left(undo_page, ptr) < 2) {
217
/*----------------------------------------*/
218
/* Write pointers to the previous and the next undo log records */
220
if (trx_undo_left(undo_page, ptr) < 2) {
225
mach_write_to_2(ptr, first_free);
228
mach_write_to_2(undo_page + first_free, ptr - undo_page);
230
mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
233
/* Write the log entry to the REDO log of this change in the UNDO
235
trx_undof_page_add_undo_rec_log(undo_page, first_free,
236
ptr - undo_page, mtr);
259
240
/**************************************************************************
260
241
Reads from an undo log record the general parameters. */
263
244
trx_undo_rec_get_pars(
264
245
/*==================*/
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 */
318
300
*len = mach_read_compressed(ptr);
319
301
ptr += mach_get_compressed_size(*len);
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);
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);
340
*len += UNIV_EXTERN_STORAGE_FIELD;
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);
383
348
dict_index_copy_types(*ref, index, ref_len);
385
350
for (i = 0; i < ref_len; i++) {
391
351
dfield = dtuple_get_nth_field(*ref, i);
393
ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
353
ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
395
355
dfield_set_data(dfield, field, len);
410
370
record, at the start of the row reference */
411
371
dict_index_t* index) /* in: clustered index */
416
378
ut_ad(index && ptr);
417
ut_a(dict_index_is_clust(index));
379
ut_a(index->type & DICT_CLUSTERED);
419
381
ref_len = dict_index_get_n_unique(index);
421
383
for (i = 0; i < ref_len; i++) {
426
ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
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. */
437
trx_undo_page_fetch_ext(
438
/*====================*/
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 */
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. */
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;
462
/**************************************************************************
463
Writes to the undo log a prefix of an externally stored column. */
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
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 */
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);
489
ptr += mach_write_compressed(ptr, *len);
491
*field = trx_undo_page_fetch_ext(ext_buf, zip_size,
494
ptr += mach_write_compressed(ptr, *len);
496
ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD
384
ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
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
562
454
/* Store first some general parameters to the undo log */
457
if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
458
type_cmpl = TRX_UNDO_UPD_DEL_REC;
460
type_cmpl = TRX_UNDO_UPD_EXIST_REC;
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;
569
type_cmpl = TRX_UNDO_UPD_EXIST_REC;
572
type_cmpl |= cmpl_info * TRX_UNDO_CMPL_INFO_MULT;
466
type_cmpl = type_cmpl | (cmpl_info * TRX_UNDO_CMPL_INFO_MULT);
468
mach_write_to_1(ptr, type_cmpl);
573
470
type_cmpl_ptr = ptr;
575
*ptr++ = (byte) type_cmpl;
576
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
473
len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
578
ptr += mach_dulint_write_much_compressed(ptr, table->id);
476
len = mach_dulint_write_much_compressed(ptr, table->id);
580
479
/*----------------------------------------*/
581
480
/* Store the state of the info bits */
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);
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);
591
ptr += mach_dulint_write_compressed(ptr, trx_read_trx_id(field));
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);
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);
498
len = mach_dulint_write_compressed(ptr, trx_id);
501
len = mach_dulint_write_compressed(ptr, roll_ptr);
600
504
/*----------------------------------------*/
601
505
/* Store then the fields required to uniquely determine the
606
510
field = rec_get_nth_field(rec, offsets, i, &flen);
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);
612
if (trx_undo_left(undo_page, ptr) < 5) {
512
if (trx_undo_left(undo_page, ptr) < 4) {
617
ptr += mach_write_compressed(ptr, flen);
517
len = mach_write_compressed(ptr, flen);
619
520
if (flen != UNIV_SQL_NULL) {
620
521
if (trx_undo_left(undo_page, ptr) < flen) {
639
ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
540
len = mach_write_compressed(ptr, upd_get_n_fields(update));
641
543
for (i = 0; i < upd_get_n_fields(update); i++) {
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;
645
548
/* Write field number to undo log */
646
549
if (trx_undo_left(undo_page, ptr) < 5) {
651
ptr += mach_write_compressed(ptr, pos);
554
len = mach_write_compressed(ptr, pos);
653
557
/* Save the old value of field */
654
558
field = rec_get_nth_field(rec, offsets, pos, &flen);
656
if (trx_undo_left(undo_page, ptr) < 15) {
560
if (trx_undo_left(undo_page, ptr) < 5) {
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
569
len = mach_write_compressed(
664
dict_index_get_nth_col(index, pos)
666
&& flen < REC_MAX_INDEX_COL_LEN
668
dict_table_zip_size(table),
571
UNIV_EXTERN_STORAGE_FIELD + flen);
671
573
/* Notify purge that it eventually has to
672
574
free the old externally stored field */
674
576
trx->update_undo->del_marks = TRUE;
676
*type_cmpl_ptr |= TRX_UNDO_UPD_EXTERN;
578
*type_cmpl_ptr = *type_cmpl_ptr
579
| TRX_UNDO_UPD_EXTERN;
678
ptr += mach_write_compressed(ptr, flen);
581
len = mach_write_compressed(ptr, flen);
681
586
if (flen != UNIV_SQL_NULL) {
682
587
if (trx_undo_left(undo_page, ptr) < flen) {
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
707
610
if (!update || !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
710
612
trx->update_undo->del_marks = TRUE;
725
629
const dict_col_t* col
726
630
= dict_table_get_nth_col(table, col_no);
731
/* Write field number to undo log */
732
if (trx_undo_left(undo_page, ptr) < 5 + 15) {
632
if (col->ord_part > 0) {
737
634
pos = dict_index_get_nth_col_pos(index,
739
ptr += mach_write_compressed(ptr, pos);
637
/* Write field number to undo log */
638
if (trx_undo_left(undo_page, ptr) < 5) {
643
len = mach_write_compressed(ptr, pos);
741
646
/* Save the old value of field */
742
647
field = rec_get_nth_field(rec, offsets, pos,
745
if (rec_offs_nth_extern(offsets, pos)) {
746
ptr = trx_undo_page_report_modify_ext(
748
flen < REC_MAX_INDEX_COL_LEN
750
dict_table_zip_size(table),
753
ptr += mach_write_compressed(
650
if (trx_undo_left(undo_page, ptr) < 5) {
655
len = mach_write_compressed(ptr, flen);
757
658
if (flen != UNIV_SQL_NULL) {
758
659
if (trx_undo_left(undo_page, ptr)
859
ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
956
861
upd_field = upd_get_nth_field(update, i);
958
863
upd_field_set_field_no(upd_field, field_no, index, trx);
960
ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
962
upd_field->orig_len = orig_len;
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);
865
if (len != UNIV_SQL_NULL && len >= UNIV_EXTERN_STORAGE_FIELD) {
867
upd_field->extern_storage = TRUE;
969
869
len -= UNIV_EXTERN_STORAGE_FIELD;
971
dfield_set_data(&upd_field->new_val, field, len);
972
dfield_set_ext(&upd_field->new_val);
872
dfield_set_data(&(upd_field->new_val), field, len);
1015
917
dict_table_copy_types(*row, index->table);
1017
end_ptr = ptr + mach_read_from_2(ptr);
921
total_len = mach_read_from_2(ptr);
1020
while (ptr != end_ptr) {
1024
const dict_col_t* col;
926
if (ptr == start_ptr + total_len) {
1029
931
ptr = trx_undo_update_rec_get_field_no(ptr, &field_no);
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);
1034
ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len);
935
ptr = trx_undo_rec_get_col_val(ptr, &field, &len);
1036
937
dfield = dtuple_get_nth_field(*row, col_no);
1038
939
dfield_set_data(dfield, field, len);
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
1049
|| dfield_get_len(dfield)
1050
>= REC_MAX_INDEX_COL_LEN
1051
+ BTR_EXTERN_FIELD_REF_SIZE);
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
1201
1084
mtr_start(&mtr);
1204
buf_block_t* undo_block;
1087
undo_page = buf_page_get_gen(undo->space, page_no,
1088
RW_X_LATCH, undo->guess_page,
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);
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);
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);
1226
if (UNIV_UNLIKELY(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 */
1233
1115
trx_undo_erase_page_end(undo_page, &mtr);
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;
1246
UT_DULINT_INC(trx->undo_no);
1248
mutex_exit(&trx->undo_mutex);
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);
1259
1126
ut_ad(page_no == undo->last_page_no);
1283
1150
return(DB_OUT_OF_FILE_SPACE);
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;
1160
UT_DULINT_INC(trx->undo_no);
1162
mutex_exit(&(trx->undo_mutex));
1164
*roll_ptr = trx_undo_build_roll_ptr(is_insert, rseg->id, page_no,
1166
if (UNIV_LIKELY_NULL(heap)) {
1167
mem_heap_free(heap);
1288
1172
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
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
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 */
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;
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));
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"
1455
1335
ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
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);
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
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. */
1480
1337
ptr = trx_undo_rec_skip_row_ref(ptr, index);
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"
1527
1384
"InnoDB: Roll ptr in rec %lu %lu, in update rec"
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),
1540
1399
if (row_upd_changes_field_size_or_external(index, offsets, update)) {
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: */
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,
1413
entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec,
1555
1415
row_upd_index_replace_new_col_vals(entry, index, update, heap);
1557
buf = mem_heap_alloc(heap, rec_get_converted_size(index, entry,
1560
*old_vers = rec_convert_dtuple_to_rec(buf, index,
1417
buf = mem_heap_alloc(heap,
1418
rec_get_converted_size(index, entry));
1420
*old_vers = rec_convert_dtuple_to_rec(buf, index, entry);
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);
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);
1569
1433
return(DB_SUCCESS);