1
/******************************************************
6
Created 12/27/1996 Heikki Tuuri
7
*******************************************************/
15
#include "dict0dict.h"
16
#include "dict0boot.h"
17
#include "dict0crea.h"
18
#include "mach0data.h"
28
#include "lock0lock.h"
31
#include "eval0eval.h"
35
/* What kind of latch and lock can we assume when the control comes to
36
-------------------------------------------------------------------
39
Efficiency of massive updates would require keeping an x-latch on a
40
clustered index page through many updates, and not setting an explicit
41
x-lock on clustered index records, as they anyway will get an implicit
42
x-lock when they are updated. A problem is that the read nodes in the
43
graph should know that they must keep the latch when passing the control
44
up to the update node, and not set any record lock on the record which
45
will be updated. Another problem occurs if the execution is stopped,
46
as the kernel switches to another query thread, or the transaction must
47
wait for a lock. Then we should be able to release the latch and, maybe,
48
acquire an explicit x-lock on the record.
49
Because this seems too complicated, we conclude that the less
50
efficient solution of releasing all the latches when the control is
51
transferred to another node, and acquiring explicit x-locks, is better. */
53
/* How is a delete performed? If there is a delete without an
54
explicit cursor, i.e., a searched delete, there are at least
55
two different situations:
56
the implicit select cursor may run on (1) the clustered index or
57
on (2) a secondary index. The delete is performed by setting
58
the delete bit in the record and substituting the id of the
59
deleting transaction for the original trx id, and substituting a
60
new roll ptr for previous roll ptr. The old trx id and roll ptr
61
are saved in the undo log record. Thus, no physical changes occur
62
in the index tree structure at the time of the delete. Only
63
when the undo log is purged, the index records will be physically
64
deleted from the index trees.
66
The query graph executing a searched delete would consist of
67
a delete node which has as a subtree a select subgraph.
68
The select subgraph should return a (persistent) cursor
69
in the clustered index, placed on page which is x-latched.
70
The delete node should look for all secondary index records for
71
this clustered index entry and mark them as deleted. When is
72
the x-latch freed? The most efficient way for performing a
73
searched delete is obviously to keep the x-latch for several
74
steps of query graph execution. */
76
/***************************************************************
77
Checks if an update vector changes some of the first ordering fields of an
78
index record. This is only used in foreign key checks and we can assume
79
that index does not contain column prefixes. */
82
row_upd_changes_first_fields_binary(
83
/*================================*/
84
/* out: TRUE if changes */
85
dtuple_t* entry, /* in: old value of index entry */
86
dict_index_t* index, /* in: index of entry */
87
const upd_t* update, /* in: update vector for the row */
88
ulint n); /* in: how many first fields to check */
91
/*************************************************************************
92
Checks if index currently is mentioned as a referenced index in a foreign
96
row_upd_index_is_referenced(
97
/*========================*/
98
/* out: TRUE if referenced; NOTE that since
99
we do not hold dict_operation_lock
100
when leaving the function, it may be that
101
the referencing table has been dropped when
102
we leave this function: this function is only
103
for heuristic use! */
104
dict_index_t* index, /* in: index */
105
trx_t* trx) /* in: transaction */
107
dict_table_t* table = index->table;
108
dict_foreign_t* foreign;
109
ibool froze_data_dict = FALSE;
110
ibool is_referenced = FALSE;
112
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
117
if (trx->dict_operation_lock_mode == 0) {
118
row_mysql_freeze_data_dictionary(trx);
119
froze_data_dict = TRUE;
122
foreign = UT_LIST_GET_FIRST(table->referenced_list);
125
if (foreign->referenced_index == index) {
127
is_referenced = TRUE;
131
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
135
if (froze_data_dict) {
136
row_mysql_unfreeze_data_dictionary(trx);
139
return(is_referenced);
142
/*************************************************************************
143
Checks if possible foreign key constraints hold after a delete of the record
144
under pcur. NOTE that this function will temporarily commit mtr and lose the
148
row_upd_check_references_constraints(
149
/*=================================*/
150
/* out: DB_SUCCESS or an error code */
151
upd_node_t* node, /* in: row update node */
152
btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the
153
cursor position is lost in this function! */
154
dict_table_t* table, /* in: table in question */
155
dict_index_t* index, /* in: index of the cursor */
156
ulint* offsets,/* in/out: rec_get_offsets(pcur.rec, index) */
157
que_thr_t* thr, /* in: query thread */
158
mtr_t* mtr) /* in: mtr */
160
dict_foreign_t* foreign;
167
ibool got_s_lock = FALSE;
169
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
174
trx = thr_get_trx(thr);
176
rec = btr_pcur_get_rec(pcur);
177
ut_ad(rec_offs_validate(rec, index, offsets));
179
heap = mem_heap_create(500);
181
entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
188
if (trx->dict_operation_lock_mode == 0) {
191
row_mysql_freeze_data_dictionary(trx);
194
foreign = UT_LIST_GET_FIRST(table->referenced_list);
197
/* Note that we may have an update which updates the index
198
record, but does NOT update the first fields which are
199
referenced in a foreign key constraint. Then the update does
200
NOT break the constraint. */
202
if (foreign->referenced_index == index
204
|| row_upd_changes_first_fields_binary(
205
entry, index, node->update,
206
foreign->n_fields))) {
208
if (foreign->foreign_table == NULL) {
209
dict_table_get(foreign->foreign_table_name,
213
if (foreign->foreign_table) {
214
mutex_enter(&(dict_sys->mutex));
216
(foreign->foreign_table
217
->n_foreign_key_checks_running)++;
219
mutex_exit(&(dict_sys->mutex));
222
/* NOTE that if the thread ends up waiting for a lock
223
we will release dict_operation_lock temporarily!
224
But the counter on the table protects 'foreign' from
225
being dropped while the check is running. */
227
err = row_ins_check_foreign_constraint(
228
FALSE, foreign, table, entry, thr);
230
if (foreign->foreign_table) {
231
mutex_enter(&(dict_sys->mutex));
233
ut_a(foreign->foreign_table
234
->n_foreign_key_checks_running > 0);
236
(foreign->foreign_table
237
->n_foreign_key_checks_running)--;
239
mutex_exit(&(dict_sys->mutex));
242
if (err != DB_SUCCESS) {
248
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
255
row_mysql_unfreeze_data_dictionary(trx);
263
/*************************************************************************
264
Creates an update node for a query graph. */
269
/* out, own: update node */
270
mem_heap_t* heap) /* in: mem heap where created */
274
node = mem_heap_alloc(heap, sizeof(upd_node_t));
275
node->common.type = QUE_NODE_UPDATE;
277
node->state = UPD_NODE_UPDATE_CLUSTERED;
278
node->select_will_do_update = FALSE;
279
node->in_mysql_interface = FALSE;
283
node->upd_row = NULL;
284
node->upd_ext = NULL;
288
node->foreign = NULL;
289
node->cascade_heap = NULL;
290
node->cascade_node = NULL;
294
node->heap = mem_heap_create(128);
295
node->magic_n = UPD_NODE_MAGIC_N;
302
/*************************************************************************
303
Updates the trx id and roll ptr field in a clustered index record in database
307
row_upd_rec_sys_fields_in_recovery(
308
/*===============================*/
309
rec_t* rec, /* in/out: record */
310
page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
311
const ulint* offsets,/* in: array returned by rec_get_offsets() */
312
ulint pos, /* in: TRX_ID position in rec */
313
dulint trx_id, /* in: transaction id */
314
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);
335
/*************************************************************************
336
Sets the trx id or roll ptr field of a clustered index entry. */
339
row_upd_index_entry_sys_field(
340
/*==========================*/
341
const dtuple_t* entry, /* in: index entry, where the memory buffers
342
for sys fields are already allocated:
343
the function just copies the new values to
345
dict_index_t* index, /* in: clustered index */
346
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
347
dulint val) /* in: value to write */
353
ut_ad(dict_index_is_clust(index));
355
pos = dict_index_get_sys_col_pos(index, type);
357
dfield = dtuple_get_nth_field(entry, pos);
358
field = dfield_get_data(dfield);
360
if (type == DATA_TRX_ID) {
361
trx_write_trx_id(field, val);
363
ut_ad(type == DATA_ROLL_PTR);
364
trx_write_roll_ptr(field, val);
368
/***************************************************************
369
Returns TRUE if row update changes size of some field in index or if some
370
field to be updated is stored externally in rec or update. */
373
row_upd_changes_field_size_or_external(
374
/*===================================*/
375
/* out: TRUE if the update changes the size of
376
some field in index or the field is external
378
dict_index_t* index, /* in: index */
379
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
380
const upd_t* update) /* in: update vector */
382
const upd_field_t* upd_field;
383
const dfield_t* new_val;
389
ut_ad(rec_offs_validate(NULL, index, offsets));
390
n_fields = upd_get_n_fields(update);
392
for (i = 0; i < n_fields; i++) {
393
upd_field = upd_get_nth_field(update, i);
395
new_val = &(upd_field->new_val);
396
new_len = dfield_get_len(new_val);
398
if (dfield_is_null(new_val) && !rec_offs_comp(offsets)) {
399
/* A bug fixed on Dec 31st, 2004: we looked at the
400
SQL NULL size from the wrong field! We may backport
401
this fix also to 4.0. The merge to 5.0 will be made
402
manually immediately after we commit this to 4.1. */
404
new_len = dict_col_get_sql_null_size(
405
dict_index_get_nth_col(index,
406
upd_field->field_no));
409
old_len = rec_offs_nth_size(offsets, upd_field->field_no);
411
if (rec_offs_comp(offsets)
412
&& rec_offs_nth_sql_null(offsets,
413
upd_field->field_no)) {
414
/* Note that in the compact table format, for a
415
variable length field, an SQL NULL will use zero
416
bytes in the offset array at the start of the physical
417
record, but a zero-length value (empty string) will
418
use one byte! Thus, we cannot use update-in-place
419
if we update an SQL NULL varchar to an empty string! */
421
old_len = UNIV_SQL_NULL;
424
if (dfield_is_ext(new_val) || old_len != new_len
425
|| rec_offs_nth_extern(offsets, upd_field->field_no)) {
434
/***************************************************************
435
Replaces the new column values stored in the update vector to the record
436
given. No field size changes are allowed. */
439
row_upd_rec_in_place(
440
/*=================*/
441
rec_t* rec, /* in/out: record where replaced */
442
dict_index_t* index, /* in: the index the record belongs to */
443
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 */
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);
461
n_fields = upd_get_n_fields(update);
463
for (i = 0; i < n_fields; i++) {
464
upd_field = upd_get_nth_field(update, i);
465
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
rec_set_nth_field(rec, offsets, upd_field->field_no,
470
dfield_get_data(new_val),
471
dfield_get_len(new_val));
474
if (UNIV_LIKELY_NULL(page_zip)) {
475
page_zip_write_rec(page_zip, rec, index, offsets, 0);
479
/*************************************************************************
480
Writes into the redo log the values of trx id and roll ptr and enough info
481
to determine their positions within a clustered index record. */
484
row_upd_write_sys_vals_to_log(
485
/*==========================*/
486
/* out: new pointer to mlog */
487
dict_index_t* index, /* in: clustered index */
488
trx_t* trx, /* in: transaction */
489
dulint roll_ptr,/* in: roll ptr of the undo log record */
490
byte* log_ptr,/* pointer to a buffer of size > 20 opened
492
mtr_t* mtr __attribute__((unused))) /* in: mtr */
494
ut_ad(dict_index_is_clust(index));
497
log_ptr += mach_write_compressed(log_ptr,
498
dict_index_get_sys_col_pos(
499
index, DATA_TRX_ID));
501
trx_write_roll_ptr(log_ptr, roll_ptr);
502
log_ptr += DATA_ROLL_PTR_LEN;
504
log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
509
/*************************************************************************
510
Parses the log data of system field values. */
513
row_upd_parse_sys_vals(
514
/*===================*/
515
/* out: log data end or NULL */
516
byte* ptr, /* in: buffer */
517
byte* end_ptr,/* in: buffer end */
518
ulint* pos, /* out: TRX_ID position in record */
519
dulint* trx_id, /* out: trx id */
520
dulint* roll_ptr)/* out: roll ptr */
522
ptr = mach_parse_compressed(ptr, end_ptr, pos);
529
if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
534
*roll_ptr = trx_read_roll_ptr(ptr);
535
ptr += DATA_ROLL_PTR_LEN;
537
ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
542
/***************************************************************
543
Writes to the redo log the new values of the fields occurring in the index. */
546
row_upd_index_write_log(
547
/*====================*/
548
const upd_t* update, /* in: update vector */
549
byte* log_ptr,/* in: pointer to mlog buffer: must
550
contain at least MLOG_BUF_MARGIN bytes
551
of free space; the buffer is closed
552
within this function */
553
mtr_t* mtr) /* in: mtr into whose log to write */
555
const upd_field_t* upd_field;
556
const dfield_t* new_val;
562
n_fields = upd_get_n_fields(update);
564
buf_end = log_ptr + MLOG_BUF_MARGIN;
566
mach_write_to_1(log_ptr, update->info_bits);
568
log_ptr += mach_write_compressed(log_ptr, n_fields);
570
for (i = 0; i < n_fields; i++) {
572
#if MLOG_BUF_MARGIN <= 30
573
# error "MLOG_BUF_MARGIN <= 30"
576
if (log_ptr + 30 > buf_end) {
577
mlog_close(mtr, log_ptr);
579
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
580
buf_end = log_ptr + MLOG_BUF_MARGIN;
583
upd_field = upd_get_nth_field(update, i);
585
new_val = &(upd_field->new_val);
587
len = dfield_get_len(new_val);
589
log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
590
log_ptr += mach_write_compressed(log_ptr, len);
592
if (len != UNIV_SQL_NULL) {
593
if (log_ptr + len < buf_end) {
594
memcpy(log_ptr, dfield_get_data(new_val), len);
598
mlog_close(mtr, log_ptr);
600
mlog_catenate_string(mtr,
601
dfield_get_data(new_val),
604
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
605
buf_end = log_ptr + MLOG_BUF_MARGIN;
610
mlog_close(mtr, log_ptr);
613
/*************************************************************************
614
Parses the log data written by row_upd_index_write_log. */
619
/* out: log data end or NULL */
620
byte* ptr, /* in: buffer */
621
byte* end_ptr,/* in: buffer end */
622
mem_heap_t* heap, /* in: memory heap where update vector is
624
upd_t** update_out)/* out: update vector */
627
upd_field_t* upd_field;
634
if (end_ptr < ptr + 1) {
639
info_bits = mach_read_from_1(ptr);
641
ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
648
update = upd_create(n_fields, heap);
649
update->info_bits = info_bits;
651
for (i = 0; i < n_fields; i++) {
653
upd_field = upd_get_nth_field(update, i);
654
new_val = &(upd_field->new_val);
656
ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
663
upd_field->field_no = field_no;
665
ptr = mach_parse_compressed(ptr, end_ptr, &len);
672
if (len != UNIV_SQL_NULL) {
674
if (end_ptr < ptr + len) {
679
dfield_set_data(new_val,
680
mem_heap_dup(heap, ptr, len), len);
683
dfield_set_null(new_val);
687
*update_out = update;
692
/*******************************************************************
693
Builds an update vector from those fields which in a secondary index entry
694
differ from a record that has the equal ordering fields. NOTE: we compare
695
the fields as binary strings! */
698
row_upd_build_sec_rec_difference_binary(
699
/*====================================*/
700
/* out, own: update vector of differing
702
dict_index_t* index, /* in: index */
703
const dtuple_t* entry, /* in: entry to insert */
704
const rec_t* rec, /* in: secondary index record */
705
trx_t* trx, /* in: transaction */
706
mem_heap_t* heap) /* in: memory heap from which allocated */
708
upd_field_t* upd_field;
709
const dfield_t* dfield;
715
ulint offsets_[REC_OFFS_SMALL_SIZE];
716
const ulint* offsets;
717
rec_offs_init(offsets_);
719
/* This function is used only for a secondary index */
720
ut_a(!dict_index_is_clust(index));
722
update = upd_create(dtuple_get_n_fields(entry), heap);
725
offsets = rec_get_offsets(rec, index, offsets_,
726
ULINT_UNDEFINED, &heap);
728
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
730
data = rec_get_nth_field(rec, offsets, i, &len);
732
dfield = dtuple_get_nth_field(entry, i);
734
/* NOTE that it may be that len != dfield_get_len(dfield) if we
735
are updating in a character set and collation where strings of
736
different length can be equal in an alphabetical comparison,
737
and also in the case where we have a column prefix index
738
and the last characters in the index field are spaces; the
739
latter case probably caused the assertion failures reported at
740
row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
742
/* NOTE: we compare the fields as binary strings!
745
if (!dfield_data_is_binary_equal(dfield, len, data)) {
747
upd_field = upd_get_nth_field(update, n_diff);
749
dfield_copy(&(upd_field->new_val), dfield);
751
upd_field_set_field_no(upd_field, i, index, trx);
757
update->n_fields = n_diff;
762
/*******************************************************************
763
Builds an update vector from those fields, excluding the roll ptr and
764
trx id fields, which in an index entry differ from a record that has
765
the equal ordering fields. NOTE: we compare the fields as binary strings! */
768
row_upd_build_difference_binary(
769
/*============================*/
770
/* out, own: update vector of differing
771
fields, excluding roll ptr and trx id */
772
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 */
775
trx_t* trx, /* in: transaction */
776
mem_heap_t* heap) /* in: memory heap from which allocated */
778
upd_field_t* upd_field;
779
const dfield_t* dfield;
787
ulint offsets_[REC_OFFS_NORMAL_SIZE];
788
const ulint* offsets;
789
rec_offs_init(offsets_);
791
/* This function is used only for a clustered index */
792
ut_a(dict_index_is_clust(index));
794
update = upd_create(dtuple_get_n_fields(entry), heap);
798
roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
799
trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
801
offsets = rec_get_offsets(rec, index, offsets_,
802
ULINT_UNDEFINED, &heap);
804
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
806
data = rec_get_nth_field(rec, offsets, i, &len);
808
dfield = dtuple_get_nth_field(entry, i);
810
/* NOTE: we compare the fields as binary strings!
813
if (i == trx_id_pos || i == roll_ptr_pos) {
818
if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
819
!= !rec_offs_nth_extern(offsets, i))
820
|| !dfield_data_is_binary_equal(dfield, len, data)) {
822
upd_field = upd_get_nth_field(update, n_diff);
824
dfield_copy(&(upd_field->new_val), dfield);
826
upd_field_set_field_no(upd_field, i, index, trx);
834
update->n_fields = n_diff;
839
/***************************************************************
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
Replaces the new column values stored in the update vector to the index entry
966
row_upd_index_replace_new_col_vals_index_pos(
967
/*=========================================*/
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) */
972
dict_index_t* index, /* in: index; NOTE that this may also be a
973
non-clustered index */
974
const upd_t* update, /* in: an update vector built for the index so
975
that the field number in an upd_field is the
978
/* in: if TRUE, limit the replacement to
979
ordering fields of index; note that this
980
does not work for non-clustered indexes. */
981
mem_heap_t* heap) /* in: memory heap for allocating and
982
copying the new values */
986
const ulint zip_size = dict_table_zip_size(index->table);
990
dtuple_set_info_bits(entry, update->info_bits);
993
n_fields = dict_index_get_n_unique(index);
995
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);
1015
/***************************************************************
1016
Replaces the new column values stored in the update vector to the index entry
1020
row_upd_index_replace_new_col_vals(
1021
/*===============================*/
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) */
1026
dict_index_t* index, /* in: index; NOTE that this may also be a
1027
non-clustered index */
1028
const upd_t* update, /* in: an update vector built for the
1029
CLUSTERED index so that the field number in
1030
an upd_field is the clustered index position */
1031
mem_heap_t* heap) /* in: memory heap for allocating and
1032
copying the new values */
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);
1040
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);
1116
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) {
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);
1143
/***************************************************************
1144
Checks if an update vector changes an ordering field of an index record.
1145
This function is fast if the update vector is short or the number of ordering
1146
fields in the index is small. Otherwise, this can be quadratic.
1147
NOTE: we compare the fields as binary strings! */
1150
row_upd_changes_ord_field_binary(
1151
/*=============================*/
1152
/* out: TRUE if update vector changes
1153
an ordering field in the index record;
1154
NOTE: the fields are compared as binary
1156
const dtuple_t* row, /* in: old value of row, or NULL if the
1157
row and the data values in update are not
1158
known when this function is called, e.g., at
1160
dict_index_t* index, /* in: index of the record */
1161
const upd_t* update) /* in: update vector for the row; NOTE: the
1162
field numbers in this MUST be clustered index
1168
dict_index_t* clust_index;
1170
ut_ad(update && index);
1172
n_unique = dict_index_get_n_unique(index);
1173
n_upd_fields = upd_get_n_fields(update);
1175
clust_index = dict_table_get_first_index(index->table);
1177
for (i = 0; i < n_unique; i++) {
1179
const dict_field_t* ind_field;
1180
const dict_col_t* col;
1184
ind_field = dict_index_get_nth_field(index, i);
1185
col = dict_field_get_col(ind_field);
1186
col_pos = dict_col_get_clust_pos(col, clust_index);
1187
col_no = dict_col_get_no(col);
1189
for (j = 0; j < n_upd_fields; j++) {
1191
const upd_field_t* upd_field
1192
= upd_get_nth_field(update, j);
1194
/* Note that if the index field is a column prefix
1195
then it may be that row does not contain an externally
1196
stored part of the column value, and we cannot compare
1199
if (col_pos == upd_field->field_no
1201
|| ind_field->prefix_len > 0
1202
|| !dfield_datas_are_binary_equal(
1203
dtuple_get_nth_field(row, col_no),
1204
&(upd_field->new_val)))) {
1214
/***************************************************************
1215
Checks if an update vector changes an ordering field of an index record.
1216
NOTE: we compare the fields as binary strings! */
1219
row_upd_changes_some_index_ord_field_binary(
1220
/*========================================*/
1221
/* out: TRUE if update vector
1222
may change an ordering field
1223
in an index record */
1224
const dict_table_t* table, /* in: table */
1225
const upd_t* update) /* in: update vector for the row */
1227
upd_field_t* upd_field;
1228
dict_index_t* index;
1231
index = dict_table_get_first_index(table);
1233
for (i = 0; i < upd_get_n_fields(update); i++) {
1235
upd_field = upd_get_nth_field(update, i);
1237
if (dict_field_get_col(dict_index_get_nth_field(
1238
index, upd_field->field_no))
1248
/***************************************************************
1249
Checks if an update vector changes some of the first ordering fields of an
1250
index record. This is only used in foreign key checks and we can assume
1251
that index does not contain column prefixes. */
1254
row_upd_changes_first_fields_binary(
1255
/*================================*/
1256
/* out: TRUE if changes */
1257
dtuple_t* entry, /* in: index entry */
1258
dict_index_t* index, /* in: index of entry */
1259
const upd_t* update, /* in: update vector for the row */
1260
ulint n) /* in: how many first fields to check */
1264
dict_index_t* clust_index;
1266
ut_ad(update && index);
1267
ut_ad(n <= dict_index_get_n_fields(index));
1269
n_upd_fields = upd_get_n_fields(update);
1270
clust_index = dict_table_get_first_index(index->table);
1272
for (i = 0; i < n; i++) {
1274
const dict_field_t* ind_field;
1275
const dict_col_t* col;
1278
ind_field = dict_index_get_nth_field(index, i);
1279
col = dict_field_get_col(ind_field);
1280
col_pos = dict_col_get_clust_pos(col, clust_index);
1282
ut_a(ind_field->prefix_len == 0);
1284
for (j = 0; j < n_upd_fields; j++) {
1286
upd_field_t* upd_field
1287
= upd_get_nth_field(update, j);
1289
if (col_pos == upd_field->field_no
1290
&& !dfield_datas_are_binary_equal(
1291
dtuple_get_nth_field(entry, i),
1292
&(upd_field->new_val))) {
1302
/*************************************************************************
1303
Copies the column values from a record. */
1306
row_upd_copy_columns(
1307
/*=================*/
1308
rec_t* rec, /* in: record in a clustered index */
1309
const ulint* offsets,/* in: array returned by rec_get_offsets() */
1310
sym_node_t* column) /* in: first column in a column list, or
1317
data = rec_get_nth_field(rec, offsets,
1318
column->field_nos[SYM_CLUST_FIELD_NO],
1320
if (len == UNIV_SQL_NULL) {
1321
len = UNIV_SQL_NULL;
1323
eval_node_copy_and_alloc_val(column, data, len);
1325
column = UT_LIST_GET_NEXT(col_var_list, column);
1329
/*************************************************************************
1330
Calculates the new values for fields to update. Note that row_upd_copy_columns
1331
must have been called first. */
1334
row_upd_eval_new_vals(
1335
/*==================*/
1336
upd_t* update) /* in/out: update vector */
1339
upd_field_t* upd_field;
1343
n_fields = upd_get_n_fields(update);
1345
for (i = 0; i < n_fields; i++) {
1346
upd_field = upd_get_nth_field(update, i);
1348
exp = upd_field->exp;
1352
dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1356
/***************************************************************
1357
Stores to the heap the row on which the node->pcur is positioned. */
1362
upd_node_t* node) /* in: row update node */
1364
dict_index_t* clust_index;
1366
mem_heap_t* heap = NULL;
1367
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1368
const ulint* offsets;
1369
rec_offs_init(offsets_);
1371
ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1373
if (node->row != NULL) {
1374
mem_heap_empty(node->heap);
1377
clust_index = dict_table_get_first_index(node->table);
1379
rec = btr_pcur_get_rec(node->pcur);
1381
offsets = rec_get_offsets(rec, clust_index, offsets_,
1382
ULINT_UNDEFINED, &heap);
1383
node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1384
NULL, &node->ext, node->heap);
1385
if (node->is_delete) {
1386
node->upd_row = NULL;
1387
node->upd_ext = NULL;
1389
node->upd_row = dtuple_copy(node->row, node->heap);
1390
row_upd_replace(node->upd_row, &node->upd_ext,
1391
clust_index, node->update, node->heap);
1394
if (UNIV_LIKELY_NULL(heap)) {
1395
mem_heap_free(heap);
1399
/***************************************************************
1400
Updates a secondary index entry of a row. */
1403
row_upd_sec_index_entry(
1404
/*====================*/
1405
/* out: DB_SUCCESS if operation successfully
1406
completed, else error code or DB_LOCK_WAIT */
1407
upd_node_t* node, /* in: row update node */
1408
que_thr_t* thr) /* in: query thread */
1412
dict_index_t* index;
1418
ulint err = DB_SUCCESS;
1420
trx_t* trx = thr_get_trx(thr);
1422
index = node->index;
1424
check_ref = row_upd_index_is_referenced(index, trx);
1426
heap = mem_heap_create(1024);
1428
/* Build old index entry */
1429
entry = row_build_index_entry(node->row, node->ext, index, heap);
1435
found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
1437
btr_cur = btr_pcur_get_btr_cur(&pcur);
1439
rec = btr_cur_get_rec(btr_cur);
1441
if (UNIV_UNLIKELY(!found)) {
1442
fputs("InnoDB: error in sec index entry update in\n"
1443
"InnoDB: ", stderr);
1444
dict_index_name_print(stderr, trx, index);
1446
"InnoDB: tuple ", stderr);
1447
dtuple_print(stderr, entry);
1449
"InnoDB: record ", stderr);
1450
rec_print(stderr, rec, index);
1453
trx_print(stderr, trx, 0);
1456
"InnoDB: Submit a detailed bug report"
1457
" to http://bugs.mysql.com\n", stderr);
1459
/* Delete mark the old index record; it can already be
1460
delete marked if we return after a lock wait in
1461
row_ins_index_entry below */
1463
if (!rec_get_deleted_flag(rec,
1464
dict_table_is_comp(index->table))) {
1465
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
1467
if (err == DB_SUCCESS && check_ref) {
1469
ulint* offsets = rec_get_offsets(
1471
ULINT_UNDEFINED, &heap);
1472
/* NOTE that the following call loses
1473
the position of pcur ! */
1474
err = row_upd_check_references_constraints(
1475
node, &pcur, index->table,
1476
index, offsets, thr, &mtr);
1481
btr_pcur_close(&pcur);
1484
if (node->is_delete || err != DB_SUCCESS) {
1489
/* Build a new index entry */
1490
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1494
/* Insert new index entry */
1495
err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1498
mem_heap_free(heap);
1503
/***************************************************************
1504
Updates the secondary index record if it is changed in the row update or
1505
deletes it if this is a delete. */
1510
/* out: DB_SUCCESS if operation successfully
1511
completed, else error code or DB_LOCK_WAIT */
1512
upd_node_t* node, /* in: row update node */
1513
que_thr_t* thr) /* in: query thread */
1515
ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1516
|| (node->state == UPD_NODE_UPDATE_SOME_SEC));
1517
ut_ad(!dict_index_is_clust(node->index));
1519
if (node->state == UPD_NODE_UPDATE_ALL_SEC
1520
|| row_upd_changes_ord_field_binary(node->row, node->index,
1522
return(row_upd_sec_index_entry(node, thr));
1528
/***************************************************************
1529
Marks the clustered index record deleted and inserts the updated version
1530
of the record to the index. This function should be used when the ordering
1531
fields of the clustered index record change. This should be quite rare in
1532
database applications. */
1535
row_upd_clust_rec_by_insert(
1536
/*========================*/
1537
/* out: DB_SUCCESS if operation successfully
1538
completed, else error code or DB_LOCK_WAIT */
1539
upd_node_t* node, /* in: row update node */
1540
dict_index_t* index, /* in: clustered index of the record */
1541
que_thr_t* thr, /* in: query thread */
1542
ibool check_ref,/* in: TRUE if index may be referenced in
1543
a foreign key constraint */
1544
mtr_t* mtr) /* in: mtr; gets committed here */
1546
mem_heap_t* heap = NULL;
1550
dict_table_t* table;
1555
ut_ad(dict_index_is_clust(index));
1557
trx = thr_get_trx(thr);
1558
table = node->table;
1560
btr_cur = btr_pcur_get_btr_cur(pcur);
1562
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1564
dict_index_t* index;
1565
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1567
rec_offs_init(offsets_);
1569
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1570
btr_cur, TRUE, thr, mtr);
1571
if (err != DB_SUCCESS) {
1576
/* Mark as not-owned the externally stored fields which the new
1577
row inherits from the delete marked record: purge should not
1578
free those externally stored fields even if the delete marked
1579
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
btr_cur_mark_extern_inherited_fields(
1586
btr_cur_get_page_zip(btr_cur),
1587
rec, index, offsets, node->update, mtr);
1589
/* NOTE that the following call loses
1590
the position of pcur ! */
1591
err = row_upd_check_references_constraints(
1592
node, pcur, table, index, offsets, thr, mtr);
1593
if (err != DB_SUCCESS) {
1595
if (UNIV_LIKELY_NULL(heap)) {
1596
mem_heap_free(heap);
1606
heap = mem_heap_create(500);
1608
node->state = UPD_NODE_INSERT_CLUSTERED;
1610
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1614
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,
1632
mem_heap_free(heap);
1637
/***************************************************************
1638
Updates a clustered index record of a row when the ordering fields do
1644
/* out: DB_SUCCESS if operation successfully
1645
completed, else error code or DB_LOCK_WAIT */
1646
upd_node_t* node, /* in: row update node */
1647
dict_index_t* index, /* in: clustered index */
1648
que_thr_t* thr, /* in: query thread */
1649
mtr_t* mtr) /* in: mtr; gets committed here */
1651
mem_heap_t* heap = NULL;
1652
big_rec_t* big_rec = NULL;
1658
ut_ad(dict_index_is_clust(index));
1661
btr_cur = btr_pcur_get_btr_cur(pcur);
1663
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1664
dict_table_is_comp(index->table)));
1666
/* Try optimistic updating of the record, keeping changes within
1667
the page; we do not check locks because we assume the x-lock on the
1670
if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1671
err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1672
btr_cur, node->update,
1673
node->cmpl_info, thr, mtr);
1675
err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1676
btr_cur, node->update,
1677
node->cmpl_info, thr, mtr);
1682
if (UNIV_LIKELY(err == DB_SUCCESS)) {
1687
if (buf_LRU_buf_pool_running_out()) {
1689
return(DB_LOCK_TABLE_FULL);
1691
/* We may have to modify the tree structure: do a pessimistic descent
1692
down the index tree */
1696
/* NOTE: this transaction has an s-lock or x-lock on the record and
1697
therefore other transactions cannot modify the record when we have no
1698
latch on the page. In addition, we assume that other query threads of
1699
the same transaction do not modify the record in the meantime.
1700
Therefore we can assert that the restoration of the cursor succeeds. */
1702
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1704
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1705
dict_table_is_comp(index->table)));
1707
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1708
&heap, &big_rec, node->update,
1709
node->cmpl_info, thr, mtr);
1712
if (err == DB_SUCCESS && big_rec) {
1713
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1715
rec_offs_init(offsets_);
1719
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1720
rec = btr_cur_get_rec(btr_cur);
1721
err = btr_store_big_rec_extern_fields(
1722
index, btr_cur_get_block(btr_cur), rec,
1723
rec_get_offsets(rec, index, offsets_,
1724
ULINT_UNDEFINED, &heap),
1729
if (UNIV_LIKELY_NULL(heap)) {
1730
mem_heap_free(heap);
1734
dtuple_big_rec_free(big_rec);
1740
/***************************************************************
1741
Delete marks a clustered index record. */
1744
row_upd_del_mark_clust_rec(
1745
/*=======================*/
1746
/* out: DB_SUCCESS if operation successfully
1747
completed, else error code */
1748
upd_node_t* node, /* in: row update node */
1749
dict_index_t* index, /* in: clustered index */
1750
ulint* offsets,/* in/out: rec_get_offsets() for the
1751
record under the cursor */
1752
que_thr_t* thr, /* in: query thread */
1753
ibool check_ref,/* in: TRUE if index may be referenced in
1754
a foreign key constraint */
1755
mtr_t* mtr) /* in: mtr; gets committed here */
1762
ut_ad(dict_index_is_clust(index));
1763
ut_ad(node->is_delete);
1766
btr_cur = btr_pcur_get_btr_cur(pcur);
1768
/* Store row because we have to build also the secondary index
1771
row_upd_store_row(node);
1773
/* Mark the clustered index record deleted; we do not have to check
1774
locks, because we assume that we have an x-lock on the record */
1776
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1777
btr_cur, TRUE, thr, mtr);
1778
if (err == DB_SUCCESS && check_ref) {
1779
/* NOTE that the following call loses the position of pcur ! */
1781
err = row_upd_check_references_constraints(node,
1792
/***************************************************************
1793
Updates the clustered index record. */
1798
/* out: DB_SUCCESS if operation successfully
1799
completed, DB_LOCK_WAIT in case of a lock wait,
1801
upd_node_t* node, /* in: row update node */
1802
que_thr_t* thr) /* in: query thread */
1804
dict_index_t* index;
1812
mem_heap_t* heap = NULL;
1813
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1815
rec_offs_init(offsets_);
1817
index = dict_table_get_first_index(node->table);
1819
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
1823
/* We have to restore the cursor to its position */
1828
/* If the restoration does not succeed, then the same
1829
transaction has deleted the record on which the cursor was,
1830
and that is an SQL error. If the restoration succeeds, it may
1831
still be that the same transaction has successively deleted
1832
and inserted a record with the same ordering fields, but in
1833
that case we know that the transaction has at least an
1834
implicit x-lock on the record. */
1836
ut_a(pcur->rel_pos == BTR_PCUR_ON);
1838
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1841
err = DB_RECORD_NOT_FOUND;
1848
/* If this is a row in SYS_INDEXES table of the data dictionary,
1849
then we have to free the file segments of the index tree associated
1853
&& ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1855
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1861
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
1872
rec = btr_pcur_get_rec(pcur);
1873
offsets = rec_get_offsets(rec, index, offsets_,
1874
ULINT_UNDEFINED, &heap);
1876
if (!node->has_clust_rec_x_lock) {
1877
err = lock_clust_rec_modify_check_and_lock(
1878
0, btr_pcur_get_block(pcur),
1879
rec, index, offsets, thr);
1880
if (err != DB_SUCCESS) {
1886
/* NOTE: the following function calls will also commit mtr */
1888
if (node->is_delete) {
1889
err = row_upd_del_mark_clust_rec(node, index, offsets,
1890
thr, check_ref, mtr);
1891
if (err == DB_SUCCESS) {
1892
node->state = UPD_NODE_UPDATE_ALL_SEC;
1893
node->index = dict_table_get_next_index(index);
1896
if (UNIV_LIKELY_NULL(heap)) {
1897
mem_heap_free(heap);
1902
/* If the update is made for MySQL, we already have the update vector
1903
ready, else we have to do some evaluation: */
1905
if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
1906
/* Copy the necessary columns from clust_rec and calculate the
1907
new values to set */
1908
row_upd_copy_columns(rec, offsets,
1909
UT_LIST_GET_FIRST(node->columns));
1910
row_upd_eval_new_vals(node->update);
1913
if (UNIV_LIKELY_NULL(heap)) {
1914
mem_heap_free(heap);
1917
if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
1919
err = row_upd_clust_rec(node, index, thr, mtr);
1923
row_upd_store_row(node);
1925
if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
1927
/* Update causes an ordering field (ordering fields within
1928
the B-tree) of the clustered index record to change: perform
1929
the update by delete marking and inserting.
1931
TODO! What to do to the 'Halloween problem', where an update
1932
moves the record forward in index so that it is again
1933
updated when the cursor arrives there? Solution: the
1934
read operation must check the undo record undo number when
1935
choosing records to update. MySQL solves now the problem
1938
err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
1940
if (err != DB_SUCCESS) {
1945
node->state = UPD_NODE_UPDATE_ALL_SEC;
1947
err = row_upd_clust_rec(node, index, thr, mtr);
1949
if (err != DB_SUCCESS) {
1954
node->state = UPD_NODE_UPDATE_SOME_SEC;
1957
node->index = dict_table_get_next_index(index);
1962
/***************************************************************
1963
Updates the affected index records of a row. When the control is transferred
1964
to this node, we assume that we have a persistent cursor which was on a
1965
record, and the position of the cursor is stored in the cursor. */
1970
/* out: DB_SUCCESS if operation successfully
1971
completed, else error code or DB_LOCK_WAIT */
1972
upd_node_t* node, /* in: row update node */
1973
que_thr_t* thr) /* in: query thread */
1975
ulint err = DB_SUCCESS;
1979
if (UNIV_LIKELY(node->in_mysql_interface)) {
1981
/* We do not get the cmpl_info value from the MySQL
1982
interpreter: we must calculate it on the fly: */
1985
|| row_upd_changes_some_index_ord_field_binary(
1986
node->table, node->update)) {
1987
node->cmpl_info = 0;
1989
node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
1993
if (node->state == UPD_NODE_UPDATE_CLUSTERED
1994
|| node->state == UPD_NODE_INSERT_CLUSTERED) {
1996
err = row_upd_clust_step(node, thr);
1998
if (err != DB_SUCCESS) {
2004
if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
2009
while (node->index != NULL) {
2010
err = row_upd_sec_step(node, thr);
2012
if (err != DB_SUCCESS) {
2017
node->index = dict_table_get_next_index(node->index);
2021
if (err == DB_SUCCESS) {
2022
/* Do some cleanup */
2024
if (node->row != NULL) {
2027
node->upd_row = NULL;
2028
node->upd_ext = NULL;
2029
mem_heap_empty(node->heap);
2032
node->state = UPD_NODE_UPDATE_CLUSTERED;
2038
/***************************************************************
2039
Updates a row in a table. This is a high-level function used in SQL execution
2045
/* out: query thread to run next or NULL */
2046
que_thr_t* thr) /* in: query thread */
2049
sel_node_t* sel_node;
2051
ulint err = DB_SUCCESS;
2056
trx = thr_get_trx(thr);
2058
trx_start_if_not_started(trx);
2060
node = thr->run_node;
2062
sel_node = node->select;
2064
parent = que_node_get_parent(node);
2066
ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2068
if (thr->prev_node == parent) {
2069
node->state = UPD_NODE_SET_IX_LOCK;
2072
if (node->state == UPD_NODE_SET_IX_LOCK) {
2074
if (!node->has_clust_rec_x_lock) {
2075
/* It may be that the current session has not yet
2076
started its transaction, or it has been committed: */
2078
err = lock_table(0, node->table, LOCK_IX, thr);
2080
if (err != DB_SUCCESS) {
2082
goto error_handling;
2086
node->state = UPD_NODE_UPDATE_CLUSTERED;
2088
if (node->searched_update) {
2089
/* Reset the cursor */
2090
sel_node->state = SEL_NODE_OPEN;
2092
/* Fetch a row to update */
2094
thr->run_node = sel_node;
2100
/* sel_node is NULL if we are in the MySQL interface */
2102
if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
2104
if (!node->searched_update) {
2105
/* An explicit cursor should be positioned on a row
2112
goto error_handling;
2115
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2117
/* No more rows to update, or the select node performed the
2118
updates directly in-place */
2120
thr->run_node = parent;
2125
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2127
err = row_upd(node, thr);
2130
trx->error_state = err;
2132
if (err != DB_SUCCESS) {
2136
/* DO THE TRIGGER ACTIONS HERE */
2138
if (node->searched_update) {
2139
/* Fetch next row to update */
2141
thr->run_node = sel_node;
2143
/* It was an explicit cursor update */
2145
thr->run_node = parent;
2148
node->state = UPD_NODE_UPDATE_CLUSTERED;
2153
/*************************************************************************
2154
Performs an in-place update for the current clustered index record in
2158
row_upd_in_place_in_select(
2159
/*=======================*/
2160
sel_node_t* sel_node, /* in: select node */
2161
que_thr_t* thr, /* in: query thread */
2162
mtr_t* mtr) /* in: mtr */
2168
mem_heap_t* heap = NULL;
2169
ulint offsets_[REC_OFFS_NORMAL_SIZE];
2170
rec_offs_init(offsets_);
2172
ut_ad(sel_node->select_will_do_update);
2173
ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF);
2174
ut_ad(sel_node->asc);
2176
node = que_node_get_parent(sel_node);
2178
ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2181
btr_cur = btr_pcur_get_btr_cur(pcur);
2183
/* Copy the necessary columns from clust_rec and calculate the new
2186
row_upd_copy_columns(btr_pcur_get_rec(pcur),
2187
rec_get_offsets(btr_pcur_get_rec(pcur),
2188
btr_cur->index, offsets_,
2189
ULINT_UNDEFINED, &heap),
2190
UT_LIST_GET_FIRST(node->columns));
2191
if (UNIV_LIKELY_NULL(heap)) {
2192
mem_heap_free(heap);
2194
row_upd_eval_new_vals(node->update);
2196
ut_ad(!rec_get_deleted_flag(
2197
btr_pcur_get_rec(pcur),
2198
dict_table_is_comp(btr_cur->index->table)));
2200
ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE);
2201
ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
2202
ut_ad(node->select_will_do_update);
2204
err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG, btr_cur,
2205
node->update, node->cmpl_info,
2207
/* TODO: the above can fail with DB_ZIP_OVERFLOW if page_zip != NULL.
2208
However, this function row_upd_in_place_in_select() is only invoked
2209
when executing UPDATE statements of the built-in InnoDB SQL parser.
2210
The built-in SQL is only used for InnoDB system tables, which
2211
always are in the old, uncompressed format (ROW_FORMAT=REDUNDANT,
2212
comp == FALSE, page_zip == NULL). */
2213
ut_ad(err == DB_SUCCESS);