302
299
/*************************************************************************
303
300
Updates the trx id and roll ptr field in a clustered index record in database
307
304
row_upd_rec_sys_fields_in_recovery(
308
305
/*===============================*/
309
rec_t* rec, /* in/out: record */
310
page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
306
rec_t* rec, /* in: record */
311
307
const ulint* offsets,/* in: array returned by rec_get_offsets() */
312
308
ulint pos, /* in: TRX_ID position in rec */
313
309
dulint trx_id, /* in: transaction id */
314
310
dulint roll_ptr)/* in: roll ptr of the undo log record */
316
ut_ad(rec_offs_validate(rec, NULL, offsets));
318
if (UNIV_LIKELY_NULL(page_zip)) {
319
page_zip_write_trx_id_and_roll_ptr(
320
page_zip, rec, offsets, pos, trx_id, roll_ptr);
325
field = rec_get_nth_field(rec, offsets, pos, &len);
326
ut_ad(len == DATA_TRX_ID_LEN);
327
#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
328
# error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
330
trx_write_trx_id(field, trx_id);
331
trx_write_roll_ptr(field + DATA_TRX_ID_LEN, roll_ptr);
315
field = rec_get_nth_field(rec, offsets, pos, &len);
316
ut_ad(len == DATA_TRX_ID_LEN);
317
trx_write_trx_id(field, trx_id);
319
field = rec_get_nth_field(rec, offsets, pos + 1, &len);
320
ut_ad(len == DATA_ROLL_PTR_LEN);
321
trx_write_roll_ptr(field, roll_ptr);
335
324
/*************************************************************************
336
325
Sets the trx id or roll ptr field of a clustered index entry. */
339
328
row_upd_index_entry_sys_field(
340
329
/*==========================*/
341
const dtuple_t* entry, /* in: index entry, where the memory buffers
330
dtuple_t* entry, /* in: index entry, where the memory buffers
342
331
for sys fields are already allocated:
343
332
the function just copies the new values to
434
432
/***************************************************************
435
433
Replaces the new column values stored in the update vector to the record
436
given. No field size changes are allowed. */
434
given. No field size changes are allowed. This function is used only for
439
438
row_upd_rec_in_place(
440
439
/*=================*/
441
440
rec_t* rec, /* in/out: record where replaced */
442
dict_index_t* index, /* in: the index the record belongs to */
443
441
const ulint* offsets,/* in: array returned by rec_get_offsets() */
444
const upd_t* update, /* in: update vector */
445
page_zip_des_t* page_zip)/* in: compressed page with enough space
446
available, or NULL */
442
upd_t* update) /* in: update vector */
448
const upd_field_t* upd_field;
449
const dfield_t* new_val;
453
ut_ad(rec_offs_validate(rec, index, offsets));
455
if (rec_offs_comp(offsets)) {
456
rec_set_info_bits_new(rec, update->info_bits);
458
rec_set_info_bits_old(rec, update->info_bits);
444
upd_field_t* upd_field;
449
ut_ad(rec_offs_validate(rec, NULL, offsets));
451
rec_set_info_bits(rec, rec_offs_comp(offsets), update->info_bits);
461
453
n_fields = upd_get_n_fields(update);
463
455
for (i = 0; i < n_fields; i++) {
464
456
upd_field = upd_get_nth_field(update, i);
465
457
new_val = &(upd_field->new_val);
466
ut_ad(!dfield_is_ext(new_val) ==
467
!rec_offs_nth_extern(offsets, upd_field->field_no));
469
459
rec_set_nth_field(rec, offsets, upd_field->field_no,
470
460
dfield_get_data(new_val),
471
461
dfield_get_len(new_val));
474
if (UNIV_LIKELY_NULL(page_zip)) {
475
page_zip_write_rec(page_zip, rec, index, offsets, 0);
479
465
/*************************************************************************
480
466
Writes into the redo log the values of trx id and roll ptr and enough info
481
467
to determine their positions within a clustered index record. */
484
470
row_upd_write_sys_vals_to_log(
485
471
/*==========================*/
585
570
new_val = &(upd_field->new_val);
587
len = dfield_get_len(new_val);
589
574
log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
590
575
log_ptr += mach_write_compressed(log_ptr, len);
592
577
if (len != UNIV_SQL_NULL) {
593
578
if (log_ptr + len < buf_end) {
594
memcpy(log_ptr, dfield_get_data(new_val), len);
579
ut_memcpy(log_ptr, new_val->data, len);
598
583
mlog_close(mtr, log_ptr);
600
mlog_catenate_string(mtr,
601
dfield_get_data(new_val),
585
mlog_catenate_string(mtr, new_val->data, len);
604
587
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
605
588
buf_end = log_ptr + MLOG_BUF_MARGIN;
692
676
/*******************************************************************
677
Returns TRUE if ext_vec contains i. */
680
upd_ext_vec_contains(
681
/*=================*/
682
/* out: TRUE if i is in ext_vec */
683
ulint* ext_vec, /* in: array of indexes or NULL */
684
ulint n_ext_vec, /* in: number of numbers in ext_vec */
685
ulint i) /* in: a number */
689
if (ext_vec == NULL) {
694
for (j = 0; j < n_ext_vec; j++) {
695
if (ext_vec[j] == i) {
704
/*******************************************************************
693
705
Builds an update vector from those fields which in a secondary index entry
694
706
differ from a record that has the equal ordering fields. NOTE: we compare
695
707
the fields as binary strings! */
698
710
row_upd_build_sec_rec_difference_binary(
699
711
/*====================================*/
700
712
/* out, own: update vector of differing
702
714
dict_index_t* index, /* in: index */
703
const dtuple_t* entry, /* in: entry to insert */
704
const rec_t* rec, /* in: secondary index record */
715
dtuple_t* entry, /* in: entry to insert */
716
rec_t* rec, /* in: secondary index record */
705
717
trx_t* trx, /* in: transaction */
706
718
mem_heap_t* heap) /* in: memory heap from which allocated */
708
720
upd_field_t* upd_field;
709
const dfield_t* dfield;
715
727
ulint offsets_[REC_OFFS_SMALL_SIZE];
716
728
const ulint* offsets;
717
rec_offs_init(offsets_);
729
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
719
731
/* This function is used only for a secondary index */
720
ut_a(!dict_index_is_clust(index));
732
ut_a(0 == (index->type & DICT_CLUSTERED));
722
734
update = upd_create(dtuple_get_n_fields(entry), heap);
763
777
Builds an update vector from those fields, excluding the roll ptr and
764
778
trx id fields, which in an index entry differ from a record that has
765
779
the equal ordering fields. NOTE: we compare the fields as binary strings! */
768
782
row_upd_build_difference_binary(
769
783
/*============================*/
770
784
/* out, own: update vector of differing
771
785
fields, excluding roll ptr and trx id */
772
786
dict_index_t* index, /* in: clustered index */
773
const dtuple_t* entry, /* in: entry to insert */
774
const rec_t* rec, /* in: clustered index record */
787
dtuple_t* entry, /* in: entry to insert */
788
ulint* ext_vec,/* in: array containing field numbers of
789
externally stored fields in entry, or NULL */
790
ulint n_ext_vec,/* in: number of fields in ext_vec */
791
rec_t* rec, /* in: clustered index record */
775
792
trx_t* trx, /* in: transaction */
776
793
mem_heap_t* heap) /* in: memory heap from which allocated */
778
795
upd_field_t* upd_field;
779
const dfield_t* dfield;
784
801
ulint roll_ptr_pos;
785
802
ulint trx_id_pos;
787
805
ulint offsets_[REC_OFFS_NORMAL_SIZE];
788
806
const ulint* offsets;
789
rec_offs_init(offsets_);
807
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
791
809
/* This function is used only for a clustered index */
792
ut_a(dict_index_is_clust(index));
810
ut_a(index->type & DICT_CLUSTERED);
794
812
update = upd_create(dtuple_get_n_fields(entry), heap);
839
861
/***************************************************************
840
Fetch a prefix of an externally stored column. This is similar
841
to row_ext_lookup(), but the row_ext_t holds the old values
842
of the column and must not be poisoned with the new values. */
847
/* out: BLOB prefix */
848
const byte* data, /* in: 'internally' stored part of the
849
field containing also the reference to
851
ulint local_len, /* in: length of data, in bytes */
852
ulint zip_size, /* in: nonzero=compressed BLOB
853
page size, zero for uncompressed
855
ulint* len, /* in: length of prefix to fetch;
856
out: fetched length of the prefix */
857
mem_heap_t* heap) /* in: heap where to allocate */
859
byte* buf = mem_heap_alloc(heap, *len);
861
*len = btr_copy_externally_stored_field_prefix(buf, *len,
868
/***************************************************************
869
Replaces the new column value stored in the update vector in
870
the given index entry field. */
873
row_upd_index_replace_new_col_val(
874
/*==============================*/
875
dfield_t* dfield, /* in/out: data field
876
of the index entry */
877
const dict_field_t* field, /* in: index field */
878
const dict_col_t* col, /* in: field->col */
879
const upd_field_t* uf, /* in: update field */
880
mem_heap_t* heap, /* in: memory heap for allocating
881
and copying the new value */
882
ulint zip_size)/* in: compressed page
883
size of the table, or 0 */
888
dfield_copy_data(dfield, &uf->new_val);
890
if (dfield_is_null(dfield)) {
894
len = dfield_get_len(dfield);
895
data = dfield_get_data(dfield);
897
if (field->prefix_len > 0) {
898
ibool fetch_ext = dfield_is_ext(dfield)
899
&& len < (ulint) field->prefix_len
900
+ BTR_EXTERN_FIELD_REF_SIZE;
905
len = field->prefix_len;
907
data = row_upd_ext_fetch(data, l, zip_size,
911
len = dtype_get_at_most_n_mbchars(col->prtype,
912
col->mbminlen, col->mbmaxlen,
913
field->prefix_len, len,
916
dfield_set_data(dfield, data, len);
919
dfield_dup(dfield, heap);
925
switch (uf->orig_len) {
927
case BTR_EXTERN_FIELD_REF_SIZE:
928
/* Restore the original locally stored
929
part of the column. In the undo log,
930
InnoDB writes a longer prefix of externally
931
stored columns, so that column prefixes
932
in secondary indexes can be reconstructed. */
933
dfield_set_data(dfield,
934
data + len - BTR_EXTERN_FIELD_REF_SIZE,
935
BTR_EXTERN_FIELD_REF_SIZE);
936
dfield_set_ext(dfield);
939
dfield_dup(dfield, heap);
942
/* Reconstruct the original locally
943
stored part of the column. The data
944
will have to be copied. */
945
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
946
buf = mem_heap_alloc(heap, uf->orig_len);
947
/* Copy the locally stored prefix. */
949
uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
950
/* Copy the BLOB pointer. */
951
memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
952
data + len - BTR_EXTERN_FIELD_REF_SIZE,
953
BTR_EXTERN_FIELD_REF_SIZE);
955
dfield_set_data(dfield, buf, uf->orig_len);
956
dfield_set_ext(dfield);
961
/***************************************************************
962
862
Replaces the new column values stored in the update vector to the index entry
966
866
row_upd_index_replace_new_col_vals_index_pos(
967
867
/*=========================================*/
968
dtuple_t* entry, /* in/out: index entry where replaced;
969
the clustered index record must be
970
covered by a lock or a page latch to
971
prevent deletion (rollback or purge) */
868
dtuple_t* entry, /* in/out: index entry where replaced */
972
869
dict_index_t* index, /* in: index; NOTE that this may also be a
973
870
non-clustered index */
974
const upd_t* update, /* in: an update vector built for the index so
871
upd_t* update, /* in: an update vector built for the index so
975
872
that the field number in an upd_field is the
976
873
index position */
977
874
ibool order_only,
978
875
/* in: if TRUE, limit the replacement to
979
876
ordering fields of index; note that this
980
877
does not work for non-clustered indexes. */
981
mem_heap_t* heap) /* in: memory heap for allocating and
982
copying the new values */
878
mem_heap_t* heap) /* in: memory heap to which we allocate and
879
copy the new values, set this as NULL if you
880
do not want allocation */
883
upd_field_t* upd_field;
986
const ulint zip_size = dict_table_zip_size(index->table);
995
897
n_fields = dict_index_get_n_fields(index);
998
for (i = 0; i < n_fields; i++) {
999
const dict_field_t* field;
1000
const dict_col_t* col;
1001
const upd_field_t* uf;
1003
field = dict_index_get_nth_field(index, i);
1004
col = dict_field_get_col(field);
1005
uf = upd_get_field_by_field_no(update, i);
1008
row_upd_index_replace_new_col_val(
1009
dtuple_get_nth_field(entry, i),
1010
field, col, uf, heap, zip_size);
900
for (j = 0; j < n_fields; j++) {
902
field = dict_index_get_nth_field(index, j);
904
for (i = 0; i < upd_get_n_fields(update); i++) {
906
upd_field = upd_get_nth_field(update, i);
908
if (upd_field->field_no == j) {
910
dfield = dtuple_get_nth_field(entry, j);
912
new_val = &(upd_field->new_val);
914
dfield_set_data(dfield, new_val->data,
916
if (heap && new_val->len != UNIV_SQL_NULL) {
917
dfield->data = mem_heap_alloc(
919
ut_memcpy(dfield->data, new_val->data,
923
if (field->prefix_len > 0
924
&& new_val->len != UNIV_SQL_NULL) {
926
const dict_col_t* col
927
= dict_field_get_col(field);
930
= dtype_get_at_most_n_mbchars(
1015
943
/***************************************************************
1016
944
Replaces the new column values stored in the update vector to the index entry
1020
948
row_upd_index_replace_new_col_vals(
1021
949
/*===============================*/
1022
dtuple_t* entry, /* in/out: index entry where replaced;
1023
the clustered index record must be
1024
covered by a lock or a page latch to
1025
prevent deletion (rollback or purge) */
950
dtuple_t* entry, /* in/out: index entry where replaced */
1026
951
dict_index_t* index, /* in: index; NOTE that this may also be a
1027
952
non-clustered index */
1028
const upd_t* update, /* in: an update vector built for the
953
upd_t* update, /* in: an update vector built for the
1029
954
CLUSTERED index so that the field number in
1030
955
an upd_field is the clustered index position */
1031
mem_heap_t* heap) /* in: memory heap for allocating and
1032
copying the new values */
956
mem_heap_t* heap) /* in: memory heap to which we allocate and
957
copy the new values, set this as NULL if you
958
do not want allocation */
1035
const dict_index_t* clust_index
1036
= dict_table_get_first_index(index->table);
1037
const ulint zip_size
1038
= dict_table_zip_size(index->table);
960
upd_field_t* upd_field;
965
dict_index_t* clust_index;
969
clust_index = dict_table_get_first_index(index->table);
1040
971
dtuple_set_info_bits(entry, update->info_bits);
1042
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1043
const dict_field_t* field;
1044
const dict_col_t* col;
1045
const upd_field_t* uf;
1047
field = dict_index_get_nth_field(index, i);
1048
col = dict_field_get_col(field);
1049
uf = upd_get_field_by_field_no(
1050
update, dict_col_get_clust_pos(col, clust_index));
1053
row_upd_index_replace_new_col_val(
1054
dtuple_get_nth_field(entry, i),
1055
field, col, uf, heap, zip_size);
1060
/***************************************************************
1061
Replaces the new column values stored in the update vector. */
1066
dtuple_t* row, /* in/out: row where replaced,
1068
the clustered index record must be
1069
covered by a lock or a page latch to
1070
prevent deletion (rollback or purge) */
1071
row_ext_t** ext, /* out, own: NULL, or externally
1072
stored column prefixes */
1073
const dict_index_t* index, /* in: clustered index */
1074
const upd_t* update, /* in: an update vector built for the
1076
mem_heap_t* heap) /* in: memory heap */
1083
const dict_table_t* table;
1088
ut_ad(dict_index_is_clust(index));
1092
n_cols = dtuple_get_n_fields(row);
1093
table = index->table;
1094
ut_ad(n_cols == dict_table_get_n_cols(table));
1096
ext_cols = mem_heap_alloc(heap, n_cols * sizeof *ext_cols);
1099
dtuple_set_info_bits(row, update->info_bits);
1101
for (col_no = 0; col_no < n_cols; col_no++) {
1103
const dict_col_t* col
1104
= dict_table_get_nth_col(table, col_no);
1105
const ulint clust_pos
1106
= dict_col_get_clust_pos(col, index);
1109
if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
1114
dfield = dtuple_get_nth_field(row, col_no);
973
for (j = 0; j < dict_index_get_n_fields(index); j++) {
976
dict_field_t* field = dict_index_get_nth_field(index, j);
978
clust_pos = dict_col_get_clust_pos(field->col, clust_index);
1116
980
for (i = 0; i < upd_get_n_fields(update); i++) {
1118
const upd_field_t* upd_field
1119
= upd_get_nth_field(update, i);
1121
if (upd_field->field_no != clust_pos) {
982
upd_field = upd_get_nth_field(update, i);
984
if (upd_field->field_no == clust_pos) {
986
dfield = dtuple_get_nth_field(entry, j);
988
new_val = &(upd_field->new_val);
990
dfield_set_data(dfield, new_val->data,
992
if (heap && new_val->len != UNIV_SQL_NULL) {
993
dfield->data = mem_heap_alloc(
995
ut_memcpy(dfield->data, new_val->data,
999
if (field->prefix_len > 0
1000
&& new_val->len != UNIV_SQL_NULL) {
1002
const dict_col_t* col
1003
= dict_field_get_col(field);
1006
= dtype_get_at_most_n_mbchars(
1126
dfield_copy_data(dfield, &upd_field->new_val);
1130
if (dfield_is_ext(dfield) && col->ord_part) {
1131
ext_cols[n_ext_cols++] = col_no;
1136
*ext = row_ext_create(n_ext_cols, ext_cols, row,
1137
dict_table_zip_size(table), heap);
1467
1341
if (err == DB_SUCCESS && check_ref) {
1469
ulint* offsets = rec_get_offsets(
1471
ULINT_UNDEFINED, &heap);
1472
1343
/* NOTE that the following call loses
1473
1344
the position of pcur ! */
1474
1345
err = row_upd_check_references_constraints(
1475
1346
node, &pcur, index->table,
1476
index, offsets, thr, &mtr);
1348
if (err != DB_SUCCESS) {
1481
1357
btr_pcur_close(&pcur);
1482
1358
mtr_commit(&mtr);
1484
1360
if (node->is_delete || err != DB_SUCCESS) {
1362
mem_heap_free(heap);
1489
1367
/* Build a new index entry */
1490
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1368
row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
1494
1370
/* Insert new index entry */
1495
err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1371
err = row_ins_index_entry(index, entry, NULL, 0, thr);
1498
1373
mem_heap_free(heap);
1578
1454
free those externally stored fields even if the delete marked
1579
1455
record is removed from the index tree, or updated. */
1581
rec = btr_cur_get_rec(btr_cur);
1582
index = dict_table_get_first_index(table);
1583
offsets = rec_get_offsets(rec, index, offsets_,
1584
ULINT_UNDEFINED, &heap);
1585
1457
btr_cur_mark_extern_inherited_fields(
1586
btr_cur_get_page_zip(btr_cur),
1587
rec, index, offsets, node->update, mtr);
1458
btr_cur_get_rec(btr_cur),
1459
rec_get_offsets(btr_cur_get_rec(btr_cur),
1460
dict_table_get_first_index(table),
1461
offsets_, ULINT_UNDEFINED, &heap),
1588
1463
if (check_ref) {
1589
1464
/* NOTE that the following call loses
1590
1465
the position of pcur ! */
1591
1466
err = row_upd_check_references_constraints(
1592
node, pcur, table, index, offsets, thr, mtr);
1467
node, pcur, table, index, thr, mtr);
1593
1468
if (err != DB_SUCCESS) {
1594
1469
mtr_commit(mtr);
1595
1470
if (UNIV_LIKELY_NULL(heap)) {
1608
1484
node->state = UPD_NODE_INSERT_CLUSTERED;
1610
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1486
entry = row_build_index_entry(node->row, index, heap);
1488
row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
1614
1490
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1616
if (node->upd_ext) {
1617
/* If we return from a lock wait, for example, we may have
1618
extern fields marked as not-owned in entry (marked in the
1619
if-branch above). We must unmark them. */
1621
btr_cur_unmark_dtuple_extern_fields(entry);
1623
/* We must mark non-updated extern fields in entry as
1624
inherited, so that a possible rollback will not free them. */
1626
btr_cur_mark_dtuple_inherited_extern(entry, node->update);
1629
err = row_ins_index_entry(index, entry,
1630
node->upd_ext ? node->upd_ext->n_ext : 0,
1492
/* If we return from a lock wait, for example, we may have
1493
extern fields marked as not-owned in entry (marked in the
1494
if-branch above). We must unmark them. */
1496
btr_cur_unmark_dtuple_extern_fields(entry, node->ext_vec,
1498
/* We must mark non-updated extern fields in entry as inherited,
1499
so that a possible rollback will not free them */
1501
btr_cur_mark_dtuple_inherited_extern(entry, node->ext_vec,
1505
err = row_ins_index_entry(index, entry, node->ext_vec,
1506
node->n_ext_vec, thr);
1632
1507
mem_heap_free(heap);
1705
1579
dict_table_is_comp(index->table)));
1707
1581
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1708
&heap, &big_rec, node->update,
1582
&big_rec, node->update,
1709
1583
node->cmpl_info, thr, mtr);
1710
1584
mtr_commit(mtr);
1712
1586
if (err == DB_SUCCESS && big_rec) {
1587
mem_heap_t* heap = NULL;
1713
1588
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1715
rec_offs_init(offsets_);
1590
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
1717
1592
mtr_start(mtr);
1719
1594
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1720
1595
rec = btr_cur_get_rec(btr_cur);
1721
1596
err = btr_store_big_rec_extern_fields(
1722
index, btr_cur_get_block(btr_cur), rec,
1723
1598
rec_get_offsets(rec, index, offsets_,
1724
1599
ULINT_UNDEFINED, &heap),
1601
if (UNIV_LIKELY_NULL(heap)) {
1602
mem_heap_free(heap);
1726
1604
mtr_commit(mtr);
1729
if (UNIV_LIKELY_NULL(heap)) {
1730
mem_heap_free(heap);
1734
1608
dtuple_big_rec_free(big_rec);