1
/*****************************************************************************
3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
23
Created 12/27/1996 Heikki Tuuri
24
*******************************************************/
32
#include "dict0dict.h"
35
#ifndef UNIV_HOTBACKUP
36
#include "dict0boot.h"
37
#include "dict0crea.h"
38
#include "mach0data.h"
47
#include "lock0lock.h"
50
#include "eval0eval.h"
54
/* What kind of latch and lock can we assume when the control comes to
55
-------------------------------------------------------------------
58
Efficiency of massive updates would require keeping an x-latch on a
59
clustered index page through many updates, and not setting an explicit
60
x-lock on clustered index records, as they anyway will get an implicit
61
x-lock when they are updated. A problem is that the read nodes in the
62
graph should know that they must keep the latch when passing the control
63
up to the update node, and not set any record lock on the record which
64
will be updated. Another problem occurs if the execution is stopped,
65
as the kernel switches to another query thread, or the transaction must
66
wait for a lock. Then we should be able to release the latch and, maybe,
67
acquire an explicit x-lock on the record.
68
Because this seems too complicated, we conclude that the less
69
efficient solution of releasing all the latches when the control is
70
transferred to another node, and acquiring explicit x-locks, is better. */
72
/* How is a delete performed? If there is a delete without an
73
explicit cursor, i.e., a searched delete, there are at least
74
two different situations:
75
the implicit select cursor may run on (1) the clustered index or
76
on (2) a secondary index. The delete is performed by setting
77
the delete bit in the record and substituting the id of the
78
deleting transaction for the original trx id, and substituting a
79
new roll ptr for previous roll ptr. The old trx id and roll ptr
80
are saved in the undo log record. Thus, no physical changes occur
81
in the index tree structure at the time of the delete. Only
82
when the undo log is purged, the index records will be physically
83
deleted from the index trees.
85
The query graph executing a searched delete would consist of
86
a delete node which has as a subtree a select subgraph.
87
The select subgraph should return a (persistent) cursor
88
in the clustered index, placed on page which is x-latched.
89
The delete node should look for all secondary index records for
90
this clustered index entry and mark them as deleted. When is
91
the x-latch freed? The most efficient way for performing a
92
searched delete is obviously to keep the x-latch for several
93
steps of query graph execution. */
95
/***********************************************************//**
96
Checks if an update vector changes some of the first ordering fields of an
97
index record. This is only used in foreign key checks and we can assume
98
that index does not contain column prefixes.
99
@return TRUE if changes */
102
row_upd_changes_first_fields_binary(
103
/*================================*/
104
dtuple_t* entry, /*!< in: old value of index entry */
105
dict_index_t* index, /*!< in: index of entry */
106
const upd_t* update, /*!< in: update vector for the row */
107
ulint n); /*!< in: how many first fields to check */
110
/*********************************************************************//**
111
Checks if index currently is mentioned as a referenced index in a foreign
114
NOTE that since we do not hold dict_operation_lock when leaving the
115
function, it may be that the referencing table has been dropped when
116
we leave this function: this function is only for heuristic use!
118
@return TRUE if referenced */
121
row_upd_index_is_referenced(
122
/*========================*/
123
dict_index_t* index, /*!< in: index */
124
trx_t* trx) /*!< in: transaction */
126
dict_table_t* table = index->table;
127
dict_foreign_t* foreign;
128
ibool froze_data_dict = FALSE;
129
ibool is_referenced = FALSE;
131
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
136
if (trx->dict_operation_lock_mode == 0) {
137
row_mysql_freeze_data_dictionary(trx);
138
froze_data_dict = TRUE;
141
foreign = UT_LIST_GET_FIRST(table->referenced_list);
144
if (foreign->referenced_index == index) {
146
is_referenced = TRUE;
150
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
154
if (froze_data_dict) {
155
row_mysql_unfreeze_data_dictionary(trx);
158
return(is_referenced);
161
/*********************************************************************//**
162
Checks if possible foreign key constraints hold after a delete of the record
165
NOTE that this function will temporarily commit mtr and lose the
168
@return DB_SUCCESS or an error code */
171
row_upd_check_references_constraints(
172
/*=================================*/
173
upd_node_t* node, /*!< in: row update node */
174
btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the
175
cursor position is lost in this function! */
176
dict_table_t* table, /*!< in: table in question */
177
dict_index_t* index, /*!< in: index of the cursor */
178
ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */
179
que_thr_t* thr, /*!< in: query thread */
180
mtr_t* mtr) /*!< in: mtr */
182
dict_foreign_t* foreign;
189
ibool got_s_lock = FALSE;
191
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
196
trx = thr_get_trx(thr);
198
rec = btr_pcur_get_rec(pcur);
199
ut_ad(rec_offs_validate(rec, index, offsets));
201
heap = mem_heap_create(500);
203
entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
210
if (trx->dict_operation_lock_mode == 0) {
213
row_mysql_freeze_data_dictionary(trx);
216
foreign = UT_LIST_GET_FIRST(table->referenced_list);
219
/* Note that we may have an update which updates the index
220
record, but does NOT update the first fields which are
221
referenced in a foreign key constraint. Then the update does
222
NOT break the constraint. */
224
if (foreign->referenced_index == index
226
|| row_upd_changes_first_fields_binary(
227
entry, index, node->update,
228
foreign->n_fields))) {
230
if (foreign->foreign_table == NULL) {
231
dict_table_get(foreign->foreign_table_name,
235
if (foreign->foreign_table) {
236
mutex_enter(&(dict_sys->mutex));
238
(foreign->foreign_table
239
->n_foreign_key_checks_running)++;
241
mutex_exit(&(dict_sys->mutex));
244
/* NOTE that if the thread ends up waiting for a lock
245
we will release dict_operation_lock temporarily!
246
But the counter on the table protects 'foreign' from
247
being dropped while the check is running. */
249
err = row_ins_check_foreign_constraint(
250
FALSE, foreign, table, entry, thr);
252
if (foreign->foreign_table) {
253
mutex_enter(&(dict_sys->mutex));
255
ut_a(foreign->foreign_table
256
->n_foreign_key_checks_running > 0);
258
(foreign->foreign_table
259
->n_foreign_key_checks_running)--;
261
mutex_exit(&(dict_sys->mutex));
264
if (err != DB_SUCCESS) {
270
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
277
row_mysql_unfreeze_data_dictionary(trx);
285
/*********************************************************************//**
286
Creates an update node for a query graph.
287
@return own: update node */
292
mem_heap_t* heap) /*!< in: mem heap where created */
296
node = mem_heap_alloc(heap, sizeof(upd_node_t));
297
node->common.type = QUE_NODE_UPDATE;
299
node->state = UPD_NODE_UPDATE_CLUSTERED;
300
node->in_mysql_interface = FALSE;
304
node->upd_row = NULL;
305
node->upd_ext = NULL;
309
node->foreign = NULL;
310
node->cascade_heap = NULL;
311
node->cascade_node = NULL;
315
node->heap = mem_heap_create(128);
316
node->magic_n = UPD_NODE_MAGIC_N;
322
#endif /* !UNIV_HOTBACKUP */
324
/*********************************************************************//**
325
Updates the trx id and roll ptr field in a clustered index record in database
329
row_upd_rec_sys_fields_in_recovery(
330
/*===============================*/
331
rec_t* rec, /*!< in/out: record */
332
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
333
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
334
ulint pos, /*!< in: TRX_ID position in rec */
335
trx_id_t trx_id, /*!< in: transaction id */
336
roll_ptr_t roll_ptr)/*!< in: roll ptr of the undo log record */
338
ut_ad(rec_offs_validate(rec, NULL, offsets));
340
if (UNIV_LIKELY_NULL(page_zip)) {
341
page_zip_write_trx_id_and_roll_ptr(
342
page_zip, rec, offsets, pos, trx_id, roll_ptr);
347
field = rec_get_nth_field(rec, offsets, pos, &len);
348
ut_ad(len == DATA_TRX_ID_LEN);
349
#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
350
# error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
352
trx_write_trx_id(field, trx_id);
353
trx_write_roll_ptr(field + DATA_TRX_ID_LEN, roll_ptr);
357
#ifndef UNIV_HOTBACKUP
358
/*********************************************************************//**
359
Sets the trx id or roll ptr field of a clustered index entry. */
362
row_upd_index_entry_sys_field(
363
/*==========================*/
364
const dtuple_t* entry, /*!< in: index entry, where the memory buffers
365
for sys fields are already allocated:
366
the function just copies the new values to
368
dict_index_t* index, /*!< in: clustered index */
369
ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
370
dulint val) /*!< in: value to write */
376
ut_ad(dict_index_is_clust(index));
378
pos = dict_index_get_sys_col_pos(index, type);
380
dfield = dtuple_get_nth_field(entry, pos);
381
field = dfield_get_data(dfield);
383
if (type == DATA_TRX_ID) {
384
trx_write_trx_id(field, val);
386
ut_ad(type == DATA_ROLL_PTR);
387
trx_write_roll_ptr(field, val);
391
/***********************************************************//**
392
Returns TRUE if row update changes size of some field in index or if some
393
field to be updated is stored externally in rec or update.
394
@return TRUE if the update changes the size of some field in index or
395
the field is external in rec or update */
398
row_upd_changes_field_size_or_external(
399
/*===================================*/
400
dict_index_t* index, /*!< in: index */
401
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
402
const upd_t* update) /*!< in: update vector */
404
const upd_field_t* upd_field;
405
const dfield_t* new_val;
411
ut_ad(rec_offs_validate(NULL, index, offsets));
412
n_fields = upd_get_n_fields(update);
414
for (i = 0; i < n_fields; i++) {
415
upd_field = upd_get_nth_field(update, i);
417
new_val = &(upd_field->new_val);
418
new_len = dfield_get_len(new_val);
420
if (dfield_is_null(new_val) && !rec_offs_comp(offsets)) {
421
/* A bug fixed on Dec 31st, 2004: we looked at the
422
SQL NULL size from the wrong field! We may backport
423
this fix also to 4.0. The merge to 5.0 will be made
424
manually immediately after we commit this to 4.1. */
426
new_len = dict_col_get_sql_null_size(
427
dict_index_get_nth_col(index,
428
upd_field->field_no),
432
old_len = rec_offs_nth_size(offsets, upd_field->field_no);
434
if (rec_offs_comp(offsets)
435
&& rec_offs_nth_sql_null(offsets,
436
upd_field->field_no)) {
437
/* Note that in the compact table format, for a
438
variable length field, an SQL NULL will use zero
439
bytes in the offset array at the start of the physical
440
record, but a zero-length value (empty string) will
441
use one byte! Thus, we cannot use update-in-place
442
if we update an SQL NULL varchar to an empty string! */
444
old_len = UNIV_SQL_NULL;
447
if (dfield_is_ext(new_val) || old_len != new_len
448
|| rec_offs_nth_extern(offsets, upd_field->field_no)) {
456
#endif /* !UNIV_HOTBACKUP */
458
/***********************************************************//**
459
Replaces the new column values stored in the update vector to the record
460
given. No field size changes are allowed. */
463
row_upd_rec_in_place(
464
/*=================*/
465
rec_t* rec, /*!< in/out: record where replaced */
466
dict_index_t* index, /*!< in: the index the record belongs to */
467
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
468
const upd_t* update, /*!< in: update vector */
469
page_zip_des_t* page_zip)/*!< in: compressed page with enough space
470
available, or NULL */
472
const upd_field_t* upd_field;
473
const dfield_t* new_val;
477
ut_ad(rec_offs_validate(rec, index, offsets));
479
if (rec_offs_comp(offsets)) {
480
rec_set_info_bits_new(rec, update->info_bits);
482
rec_set_info_bits_old(rec, update->info_bits);
485
n_fields = upd_get_n_fields(update);
487
for (i = 0; i < n_fields; i++) {
488
upd_field = upd_get_nth_field(update, i);
489
new_val = &(upd_field->new_val);
490
ut_ad(!dfield_is_ext(new_val) ==
491
!rec_offs_nth_extern(offsets, upd_field->field_no));
493
rec_set_nth_field(rec, offsets, upd_field->field_no,
494
dfield_get_data(new_val),
495
dfield_get_len(new_val));
498
if (UNIV_LIKELY_NULL(page_zip)) {
499
page_zip_write_rec(page_zip, rec, index, offsets, 0);
503
#ifndef UNIV_HOTBACKUP
504
/*********************************************************************//**
505
Writes into the redo log the values of trx id and roll ptr and enough info
506
to determine their positions within a clustered index record.
507
@return new pointer to mlog */
510
row_upd_write_sys_vals_to_log(
511
/*==========================*/
512
dict_index_t* index, /*!< in: clustered index */
513
trx_t* trx, /*!< in: transaction */
514
roll_ptr_t roll_ptr,/*!< in: roll ptr of the undo log record */
515
byte* log_ptr,/*!< pointer to a buffer of size > 20 opened
517
mtr_t* mtr __attribute__((unused))) /*!< in: mtr */
519
ut_ad(dict_index_is_clust(index));
522
log_ptr += mach_write_compressed(log_ptr,
523
dict_index_get_sys_col_pos(
524
index, DATA_TRX_ID));
526
trx_write_roll_ptr(log_ptr, roll_ptr);
527
log_ptr += DATA_ROLL_PTR_LEN;
529
log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
533
#endif /* !UNIV_HOTBACKUP */
535
/*********************************************************************//**
536
Parses the log data of system field values.
537
@return log data end or NULL */
540
row_upd_parse_sys_vals(
541
/*===================*/
542
byte* ptr, /*!< in: buffer */
543
byte* end_ptr,/*!< in: buffer end */
544
ulint* pos, /*!< out: TRX_ID position in record */
545
trx_id_t* trx_id, /*!< out: trx id */
546
roll_ptr_t* roll_ptr)/*!< out: roll ptr */
548
ptr = mach_parse_compressed(ptr, end_ptr, pos);
555
if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
560
*roll_ptr = trx_read_roll_ptr(ptr);
561
ptr += DATA_ROLL_PTR_LEN;
563
ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
568
#ifndef UNIV_HOTBACKUP
569
/***********************************************************//**
570
Writes to the redo log the new values of the fields occurring in the index. */
573
row_upd_index_write_log(
574
/*====================*/
575
const upd_t* update, /*!< in: update vector */
576
byte* log_ptr,/*!< in: pointer to mlog buffer: must
577
contain at least MLOG_BUF_MARGIN bytes
578
of free space; the buffer is closed
579
within this function */
580
mtr_t* mtr) /*!< in: mtr into whose log to write */
582
const upd_field_t* upd_field;
583
const dfield_t* new_val;
589
n_fields = upd_get_n_fields(update);
591
buf_end = log_ptr + MLOG_BUF_MARGIN;
593
mach_write_to_1(log_ptr, update->info_bits);
595
log_ptr += mach_write_compressed(log_ptr, n_fields);
597
for (i = 0; i < n_fields; i++) {
599
#if MLOG_BUF_MARGIN <= 30
600
# error "MLOG_BUF_MARGIN <= 30"
603
if (log_ptr + 30 > buf_end) {
604
mlog_close(mtr, log_ptr);
606
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
607
buf_end = log_ptr + MLOG_BUF_MARGIN;
610
upd_field = upd_get_nth_field(update, i);
612
new_val = &(upd_field->new_val);
614
len = dfield_get_len(new_val);
616
log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
617
log_ptr += mach_write_compressed(log_ptr, len);
619
if (len != UNIV_SQL_NULL) {
620
if (log_ptr + len < buf_end) {
621
memcpy(log_ptr, dfield_get_data(new_val), len);
625
mlog_close(mtr, log_ptr);
627
mlog_catenate_string(mtr,
628
dfield_get_data(new_val),
631
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
632
buf_end = log_ptr + MLOG_BUF_MARGIN;
637
mlog_close(mtr, log_ptr);
639
#endif /* !UNIV_HOTBACKUP */
641
/*********************************************************************//**
642
Parses the log data written by row_upd_index_write_log.
643
@return log data end or NULL */
648
byte* ptr, /*!< in: buffer */
649
byte* end_ptr,/*!< in: buffer end */
650
mem_heap_t* heap, /*!< in: memory heap where update vector is
652
upd_t** update_out)/*!< out: update vector */
655
upd_field_t* upd_field;
662
if (end_ptr < ptr + 1) {
667
info_bits = mach_read_from_1(ptr);
669
ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
676
update = upd_create(n_fields, heap);
677
update->info_bits = info_bits;
679
for (i = 0; i < n_fields; i++) {
681
upd_field = upd_get_nth_field(update, i);
682
new_val = &(upd_field->new_val);
684
ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
691
upd_field->field_no = field_no;
693
ptr = mach_parse_compressed(ptr, end_ptr, &len);
700
if (len != UNIV_SQL_NULL) {
702
if (end_ptr < ptr + len) {
707
dfield_set_data(new_val,
708
mem_heap_dup(heap, ptr, len), len);
711
dfield_set_null(new_val);
715
*update_out = update;
720
#ifndef UNIV_HOTBACKUP
721
/***************************************************************//**
722
Builds an update vector from those fields which in a secondary index entry
723
differ from a record that has the equal ordering fields. NOTE: we compare
724
the fields as binary strings!
725
@return own: update vector of differing fields */
728
row_upd_build_sec_rec_difference_binary(
729
/*====================================*/
730
dict_index_t* index, /*!< in: index */
731
const dtuple_t* entry, /*!< in: entry to insert */
732
const rec_t* rec, /*!< in: secondary index record */
733
trx_t* trx, /*!< in: transaction */
734
mem_heap_t* heap) /*!< in: memory heap from which allocated */
736
upd_field_t* upd_field;
737
const dfield_t* dfield;
743
ulint offsets_[REC_OFFS_SMALL_SIZE];
744
const ulint* offsets;
745
rec_offs_init(offsets_);
747
/* This function is used only for a secondary index */
748
ut_a(!dict_index_is_clust(index));
750
update = upd_create(dtuple_get_n_fields(entry), heap);
753
offsets = rec_get_offsets(rec, index, offsets_,
754
ULINT_UNDEFINED, &heap);
756
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
758
data = rec_get_nth_field(rec, offsets, i, &len);
760
dfield = dtuple_get_nth_field(entry, i);
762
/* NOTE that it may be that len != dfield_get_len(dfield) if we
763
are updating in a character set and collation where strings of
764
different length can be equal in an alphabetical comparison,
765
and also in the case where we have a column prefix index
766
and the last characters in the index field are spaces; the
767
latter case probably caused the assertion failures reported at
768
row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
770
/* NOTE: we compare the fields as binary strings!
773
if (!dfield_data_is_binary_equal(dfield, len, data)) {
775
upd_field = upd_get_nth_field(update, n_diff);
777
dfield_copy(&(upd_field->new_val), dfield);
779
upd_field_set_field_no(upd_field, i, index, trx);
785
update->n_fields = n_diff;
790
/***************************************************************//**
791
Builds an update vector from those fields, excluding the roll ptr and
792
trx id fields, which in an index entry differ from a record that has
793
the equal ordering fields. NOTE: we compare the fields as binary strings!
794
@return own: update vector of differing fields, excluding roll ptr and
798
row_upd_build_difference_binary(
799
/*============================*/
800
dict_index_t* index, /*!< in: clustered index */
801
const dtuple_t* entry, /*!< in: entry to insert */
802
const rec_t* rec, /*!< in: clustered index record */
803
trx_t* trx, /*!< in: transaction */
804
mem_heap_t* heap) /*!< in: memory heap from which allocated */
806
upd_field_t* upd_field;
807
const dfield_t* dfield;
815
ulint offsets_[REC_OFFS_NORMAL_SIZE];
816
const ulint* offsets;
817
rec_offs_init(offsets_);
819
/* This function is used only for a clustered index */
820
ut_a(dict_index_is_clust(index));
822
update = upd_create(dtuple_get_n_fields(entry), heap);
826
roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
827
trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
829
offsets = rec_get_offsets(rec, index, offsets_,
830
ULINT_UNDEFINED, &heap);
832
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
834
data = rec_get_nth_field(rec, offsets, i, &len);
836
dfield = dtuple_get_nth_field(entry, i);
838
/* NOTE: we compare the fields as binary strings!
841
if (i == trx_id_pos || i == roll_ptr_pos) {
846
if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
847
!= !rec_offs_nth_extern(offsets, i))
848
|| !dfield_data_is_binary_equal(dfield, len, data)) {
850
upd_field = upd_get_nth_field(update, n_diff);
852
dfield_copy(&(upd_field->new_val), dfield);
854
upd_field_set_field_no(upd_field, i, index, trx);
862
update->n_fields = n_diff;
867
/***********************************************************//**
868
Fetch a prefix of an externally stored column. This is similar
869
to row_ext_lookup(), but the row_ext_t holds the old values
870
of the column and must not be poisoned with the new values.
871
@return BLOB prefix */
876
const byte* data, /*!< in: 'internally' stored part of the
877
field containing also the reference to
879
ulint local_len, /*!< in: length of data, in bytes */
880
ulint zip_size, /*!< in: nonzero=compressed BLOB
881
page size, zero for uncompressed
883
ulint* len, /*!< in: length of prefix to fetch;
884
out: fetched length of the prefix */
885
mem_heap_t* heap) /*!< in: heap where to allocate */
887
byte* buf = mem_heap_alloc(heap, *len);
889
*len = btr_copy_externally_stored_field_prefix(buf, *len,
892
/* We should never update records containing a half-deleted BLOB. */
898
/***********************************************************//**
899
Replaces the new column value stored in the update vector in
900
the given index entry field. */
903
row_upd_index_replace_new_col_val(
904
/*==============================*/
905
dfield_t* dfield, /*!< in/out: data field
906
of the index entry */
907
const dict_field_t* field, /*!< in: index field */
908
const dict_col_t* col, /*!< in: field->col */
909
const upd_field_t* uf, /*!< in: update field */
910
mem_heap_t* heap, /*!< in: memory heap for allocating
911
and copying the new value */
912
ulint zip_size)/*!< in: compressed page
913
size of the table, or 0 */
918
dfield_copy_data(dfield, &uf->new_val);
920
if (dfield_is_null(dfield)) {
924
len = dfield_get_len(dfield);
925
data = dfield_get_data(dfield);
927
if (field->prefix_len > 0) {
928
ibool fetch_ext = dfield_is_ext(dfield)
929
&& len < (ulint) field->prefix_len
930
+ BTR_EXTERN_FIELD_REF_SIZE;
935
len = field->prefix_len;
937
data = row_upd_ext_fetch(data, l, zip_size,
941
len = dtype_get_at_most_n_mbchars(col->prtype,
942
col->mbminlen, col->mbmaxlen,
943
field->prefix_len, len,
946
dfield_set_data(dfield, data, len);
949
dfield_dup(dfield, heap);
955
switch (uf->orig_len) {
957
case BTR_EXTERN_FIELD_REF_SIZE:
958
/* Restore the original locally stored
959
part of the column. In the undo log,
960
InnoDB writes a longer prefix of externally
961
stored columns, so that column prefixes
962
in secondary indexes can be reconstructed. */
963
dfield_set_data(dfield,
964
data + len - BTR_EXTERN_FIELD_REF_SIZE,
965
BTR_EXTERN_FIELD_REF_SIZE);
966
dfield_set_ext(dfield);
969
dfield_dup(dfield, heap);
972
/* Reconstruct the original locally
973
stored part of the column. The data
974
will have to be copied. */
975
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
976
buf = mem_heap_alloc(heap, uf->orig_len);
977
/* Copy the locally stored prefix. */
979
uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
980
/* Copy the BLOB pointer. */
981
memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
982
data + len - BTR_EXTERN_FIELD_REF_SIZE,
983
BTR_EXTERN_FIELD_REF_SIZE);
985
dfield_set_data(dfield, buf, uf->orig_len);
986
dfield_set_ext(dfield);
991
/***********************************************************//**
992
Replaces the new column values stored in the update vector to the index entry
996
row_upd_index_replace_new_col_vals_index_pos(
997
/*=========================================*/
998
dtuple_t* entry, /*!< in/out: index entry where replaced;
999
the clustered index record must be
1000
covered by a lock or a page latch to
1001
prevent deletion (rollback or purge) */
1002
dict_index_t* index, /*!< in: index; NOTE that this may also be a
1003
non-clustered index */
1004
const upd_t* update, /*!< in: an update vector built for the index so
1005
that the field number in an upd_field is the
1008
/*!< in: if TRUE, limit the replacement to
1009
ordering fields of index; note that this
1010
does not work for non-clustered indexes. */
1011
mem_heap_t* heap) /*!< in: memory heap for allocating and
1012
copying the new values */
1016
const ulint zip_size = dict_table_zip_size(index->table);
1020
dtuple_set_info_bits(entry, update->info_bits);
1023
n_fields = dict_index_get_n_unique(index);
1025
n_fields = dict_index_get_n_fields(index);
1028
for (i = 0; i < n_fields; i++) {
1029
const dict_field_t* field;
1030
const dict_col_t* col;
1031
const upd_field_t* uf;
1033
field = dict_index_get_nth_field(index, i);
1034
col = dict_field_get_col(field);
1035
uf = upd_get_field_by_field_no(update, i);
1038
row_upd_index_replace_new_col_val(
1039
dtuple_get_nth_field(entry, i),
1040
field, col, uf, heap, zip_size);
1045
/***********************************************************//**
1046
Replaces the new column values stored in the update vector to the index entry
1050
row_upd_index_replace_new_col_vals(
1051
/*===============================*/
1052
dtuple_t* entry, /*!< in/out: index entry where replaced;
1053
the clustered index record must be
1054
covered by a lock or a page latch to
1055
prevent deletion (rollback or purge) */
1056
dict_index_t* index, /*!< in: index; NOTE that this may also be a
1057
non-clustered index */
1058
const upd_t* update, /*!< in: an update vector built for the
1059
CLUSTERED index so that the field number in
1060
an upd_field is the clustered index position */
1061
mem_heap_t* heap) /*!< in: memory heap for allocating and
1062
copying the new values */
1065
const dict_index_t* clust_index
1066
= dict_table_get_first_index(index->table);
1067
const ulint zip_size
1068
= dict_table_zip_size(index->table);
1070
dtuple_set_info_bits(entry, update->info_bits);
1072
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1073
const dict_field_t* field;
1074
const dict_col_t* col;
1075
const upd_field_t* uf;
1077
field = dict_index_get_nth_field(index, i);
1078
col = dict_field_get_col(field);
1079
uf = upd_get_field_by_field_no(
1080
update, dict_col_get_clust_pos(col, clust_index));
1083
row_upd_index_replace_new_col_val(
1084
dtuple_get_nth_field(entry, i),
1085
field, col, uf, heap, zip_size);
1090
/***********************************************************//**
1091
Replaces the new column values stored in the update vector. */
1096
dtuple_t* row, /*!< in/out: row where replaced,
1098
the clustered index record must be
1099
covered by a lock or a page latch to
1100
prevent deletion (rollback or purge) */
1101
row_ext_t** ext, /*!< out, own: NULL, or externally
1102
stored column prefixes */
1103
const dict_index_t* index, /*!< in: clustered index */
1104
const upd_t* update, /*!< in: an update vector built for the
1106
mem_heap_t* heap) /*!< in: memory heap */
1113
const dict_table_t* table;
1118
ut_ad(dict_index_is_clust(index));
1122
n_cols = dtuple_get_n_fields(row);
1123
table = index->table;
1124
ut_ad(n_cols == dict_table_get_n_cols(table));
1126
ext_cols = mem_heap_alloc(heap, n_cols * sizeof *ext_cols);
1129
dtuple_set_info_bits(row, update->info_bits);
1131
for (col_no = 0; col_no < n_cols; col_no++) {
1133
const dict_col_t* col
1134
= dict_table_get_nth_col(table, col_no);
1135
const ulint clust_pos
1136
= dict_col_get_clust_pos(col, index);
1139
if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
1144
dfield = dtuple_get_nth_field(row, col_no);
1146
for (i = 0; i < upd_get_n_fields(update); i++) {
1148
const upd_field_t* upd_field
1149
= upd_get_nth_field(update, i);
1151
if (upd_field->field_no != clust_pos) {
1156
dfield_copy_data(dfield, &upd_field->new_val);
1160
if (dfield_is_ext(dfield) && col->ord_part) {
1161
ext_cols[n_ext_cols++] = col_no;
1166
*ext = row_ext_create(n_ext_cols, ext_cols, row,
1167
dict_table_zip_size(table), heap);
1173
/***********************************************************//**
1174
Checks if an update vector changes an ordering field of an index record.
1176
This function is fast if the update vector is short or the number of ordering
1177
fields in the index is small. Otherwise, this can be quadratic.
1178
NOTE: we compare the fields as binary strings!
1179
@return TRUE if update vector changes an ordering field in the index record */
1182
row_upd_changes_ord_field_binary(
1183
/*=============================*/
1184
const dtuple_t* row, /*!< in: old value of row, or NULL if the
1185
row and the data values in update are not
1186
known when this function is called, e.g., at
1188
dict_index_t* index, /*!< in: index of the record */
1189
const upd_t* update) /*!< in: update vector for the row; NOTE: the
1190
field numbers in this MUST be clustered index
1196
dict_index_t* clust_index;
1198
ut_ad(update && index);
1200
n_unique = dict_index_get_n_unique(index);
1201
n_upd_fields = upd_get_n_fields(update);
1203
clust_index = dict_table_get_first_index(index->table);
1205
for (i = 0; i < n_unique; i++) {
1207
const dict_field_t* ind_field;
1208
const dict_col_t* col;
1212
ind_field = dict_index_get_nth_field(index, i);
1213
col = dict_field_get_col(ind_field);
1214
col_pos = dict_col_get_clust_pos(col, clust_index);
1215
col_no = dict_col_get_no(col);
1217
for (j = 0; j < n_upd_fields; j++) {
1219
const upd_field_t* upd_field
1220
= upd_get_nth_field(update, j);
1222
/* Note that if the index field is a column prefix
1223
then it may be that row does not contain an externally
1224
stored part of the column value, and we cannot compare
1227
if (col_pos == upd_field->field_no
1229
|| ind_field->prefix_len > 0
1230
|| !dfield_datas_are_binary_equal(
1231
dtuple_get_nth_field(row, col_no),
1232
&(upd_field->new_val)))) {
1242
/***********************************************************//**
1243
Checks if an update vector changes an ordering field of an index record.
1244
NOTE: we compare the fields as binary strings!
1245
@return TRUE if update vector may change an ordering field in an index
1249
row_upd_changes_some_index_ord_field_binary(
1250
/*========================================*/
1251
const dict_table_t* table, /*!< in: table */
1252
const upd_t* update) /*!< in: update vector for the row */
1254
upd_field_t* upd_field;
1255
dict_index_t* index;
1258
index = dict_table_get_first_index(table);
1260
for (i = 0; i < upd_get_n_fields(update); i++) {
1262
upd_field = upd_get_nth_field(update, i);
1264
if (dict_field_get_col(dict_index_get_nth_field(
1265
index, upd_field->field_no))
1275
/***********************************************************//**
1276
Checks if an update vector changes some of the first ordering fields of an
1277
index record. This is only used in foreign key checks and we can assume
1278
that index does not contain column prefixes.
1279
@return TRUE if changes */
1282
row_upd_changes_first_fields_binary(
1283
/*================================*/
1284
dtuple_t* entry, /*!< in: index entry */
1285
dict_index_t* index, /*!< in: index of entry */
1286
const upd_t* update, /*!< in: update vector for the row */
1287
ulint n) /*!< in: how many first fields to check */
1291
dict_index_t* clust_index;
1293
ut_ad(update && index);
1294
ut_ad(n <= dict_index_get_n_fields(index));
1296
n_upd_fields = upd_get_n_fields(update);
1297
clust_index = dict_table_get_first_index(index->table);
1299
for (i = 0; i < n; i++) {
1301
const dict_field_t* ind_field;
1302
const dict_col_t* col;
1305
ind_field = dict_index_get_nth_field(index, i);
1306
col = dict_field_get_col(ind_field);
1307
col_pos = dict_col_get_clust_pos(col, clust_index);
1309
ut_a(ind_field->prefix_len == 0);
1311
for (j = 0; j < n_upd_fields; j++) {
1313
upd_field_t* upd_field
1314
= upd_get_nth_field(update, j);
1316
if (col_pos == upd_field->field_no
1317
&& !dfield_datas_are_binary_equal(
1318
dtuple_get_nth_field(entry, i),
1319
&(upd_field->new_val))) {
1329
/*********************************************************************//**
1330
Copies the column values from a record. */
1333
row_upd_copy_columns(
1334
/*=================*/
1335
rec_t* rec, /*!< in: record in a clustered index */
1336
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1337
sym_node_t* column) /*!< in: first column in a column list, or
1344
data = rec_get_nth_field(rec, offsets,
1345
column->field_nos[SYM_CLUST_FIELD_NO],
1347
eval_node_copy_and_alloc_val(column, data, len);
1349
column = UT_LIST_GET_NEXT(col_var_list, column);
1353
/*********************************************************************//**
1354
Calculates the new values for fields to update. Note that row_upd_copy_columns
1355
must have been called first. */
1358
row_upd_eval_new_vals(
1359
/*==================*/
1360
upd_t* update) /*!< in/out: update vector */
1363
upd_field_t* upd_field;
1367
n_fields = upd_get_n_fields(update);
1369
for (i = 0; i < n_fields; i++) {
1370
upd_field = upd_get_nth_field(update, i);
1372
exp = upd_field->exp;
1376
dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1380
/***********************************************************//**
1381
Stores to the heap the row on which the node->pcur is positioned. */
1386
upd_node_t* node) /*!< in: row update node */
1388
dict_index_t* clust_index;
1390
mem_heap_t* heap = NULL;
1391
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1392
const ulint* offsets;
1393
rec_offs_init(offsets_);
1395
ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1397
if (node->row != NULL) {
1398
mem_heap_empty(node->heap);
1401
clust_index = dict_table_get_first_index(node->table);
1403
rec = btr_pcur_get_rec(node->pcur);
1405
offsets = rec_get_offsets(rec, clust_index, offsets_,
1406
ULINT_UNDEFINED, &heap);
1407
node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1408
NULL, &node->ext, node->heap);
1409
if (node->is_delete) {
1410
node->upd_row = NULL;
1411
node->upd_ext = NULL;
1413
node->upd_row = dtuple_copy(node->row, node->heap);
1414
row_upd_replace(node->upd_row, &node->upd_ext,
1415
clust_index, node->update, node->heap);
1418
if (UNIV_LIKELY_NULL(heap)) {
1419
mem_heap_free(heap);
1423
/***********************************************************//**
1424
Updates a secondary index entry of a row.
1425
@return DB_SUCCESS if operation successfully completed, else error
1426
code or DB_LOCK_WAIT */
1429
row_upd_sec_index_entry(
1430
/*====================*/
1431
upd_node_t* node, /*!< in: row update node */
1432
que_thr_t* thr) /*!< in: query thread */
1439
dict_index_t* index;
1442
ulint err = DB_SUCCESS;
1443
trx_t* trx = thr_get_trx(thr);
1444
ulint mode = BTR_MODIFY_LEAF;
1445
enum row_search_result search_result;
1447
index = node->index;
1449
referenced = row_upd_index_is_referenced(index, trx);
1451
heap = mem_heap_create(1024);
1453
/* Build old index entry */
1454
entry = row_build_index_entry(node->row, node->ext, index, heap);
1460
/* Set the query thread, so that ibuf_insert_low() will be
1461
able to invoke thd_get_trx(). */
1462
btr_pcur_get_btr_cur(&pcur)->thr = thr;
1464
/* We can only try to use the insert/delete buffer to buffer
1465
delete-mark operations if the index we're modifying has no foreign
1466
key constraints referring to it. */
1468
mode |= BTR_DELETE_MARK;
1471
search_result = row_search_index_entry(index, entry, mode,
1474
btr_cur = btr_pcur_get_btr_cur(&pcur);
1476
rec = btr_cur_get_rec(btr_cur);
1478
switch (search_result) {
1479
case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
1483
/* Entry was delete marked already. */
1487
fputs("InnoDB: error in sec index entry update in\n"
1488
"InnoDB: ", stderr);
1489
dict_index_name_print(stderr, trx, index);
1491
"InnoDB: tuple ", stderr);
1492
dtuple_print(stderr, entry);
1494
"InnoDB: record ", stderr);
1495
rec_print(stderr, rec, index);
1498
trx_print(stderr, trx, 0);
1501
"InnoDB: Submit a detailed bug report"
1502
" to http://bugs.mysql.com\n", stderr);
1505
/* Delete mark the old index record; it can already be
1506
delete marked if we return after a lock wait in
1507
row_ins_index_entry below */
1509
if (!rec_get_deleted_flag(
1510
rec, dict_table_is_comp(index->table))) {
1512
err = btr_cur_del_mark_set_sec_rec(
1513
0, btr_cur, TRUE, thr, &mtr);
1515
if (err == DB_SUCCESS && referenced) {
1519
offsets = rec_get_offsets(
1520
rec, index, NULL, ULINT_UNDEFINED,
1523
/* NOTE that the following call loses
1524
the position of pcur ! */
1525
err = row_upd_check_references_constraints(
1526
node, &pcur, index->table,
1527
index, offsets, thr, &mtr);
1533
btr_pcur_close(&pcur);
1536
if (node->is_delete || err != DB_SUCCESS) {
1541
/* Build a new index entry */
1542
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1546
/* Insert new index entry */
1547
err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1550
mem_heap_free(heap);
1555
/***********************************************************//**
1556
Updates the secondary index record if it is changed in the row update or
1557
deletes it if this is a delete.
1558
@return DB_SUCCESS if operation successfully completed, else error
1559
code or DB_LOCK_WAIT */
1564
upd_node_t* node, /*!< in: row update node */
1565
que_thr_t* thr) /*!< in: query thread */
1567
ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1568
|| (node->state == UPD_NODE_UPDATE_SOME_SEC));
1569
ut_ad(!dict_index_is_clust(node->index));
1571
if (node->state == UPD_NODE_UPDATE_ALL_SEC
1572
|| row_upd_changes_ord_field_binary(node->row, node->index,
1574
return(row_upd_sec_index_entry(node, thr));
1580
/***********************************************************//**
1581
Marks the clustered index record deleted and inserts the updated version
1582
of the record to the index. This function should be used when the ordering
1583
fields of the clustered index record change. This should be quite rare in
1584
database applications.
1585
@return DB_SUCCESS if operation successfully completed, else error
1586
code or DB_LOCK_WAIT */
1589
row_upd_clust_rec_by_insert(
1590
/*========================*/
1591
upd_node_t* node, /*!< in: row update node */
1592
dict_index_t* index, /*!< in: clustered index of the record */
1593
que_thr_t* thr, /*!< in: query thread */
1594
ibool referenced,/*!< in: TRUE if index may be referenced in
1595
a foreign key constraint */
1596
mtr_t* mtr) /*!< in: mtr; gets committed here */
1598
mem_heap_t* heap = NULL;
1602
dict_table_t* table;
1607
ut_ad(dict_index_is_clust(index));
1609
trx = thr_get_trx(thr);
1610
table = node->table;
1612
btr_cur = btr_pcur_get_btr_cur(pcur);
1614
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1616
dict_index_t* index;
1617
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1619
rec_offs_init(offsets_);
1621
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1622
btr_cur, TRUE, thr, mtr);
1623
if (err != DB_SUCCESS) {
1628
/* Mark as not-owned the externally stored fields which the new
1629
row inherits from the delete marked record: purge should not
1630
free those externally stored fields even if the delete marked
1631
record is removed from the index tree, or updated. */
1633
rec = btr_cur_get_rec(btr_cur);
1634
index = dict_table_get_first_index(table);
1635
offsets = rec_get_offsets(rec, index, offsets_,
1636
ULINT_UNDEFINED, &heap);
1637
btr_cur_mark_extern_inherited_fields(
1638
btr_cur_get_page_zip(btr_cur),
1639
rec, index, offsets, node->update, mtr);
1641
/* NOTE that the following call loses
1642
the position of pcur ! */
1644
err = row_upd_check_references_constraints(
1645
node, pcur, table, index, offsets, thr, mtr);
1647
if (err != DB_SUCCESS) {
1651
if (UNIV_LIKELY_NULL(heap)) {
1652
mem_heap_free(heap);
1663
heap = mem_heap_create(500);
1665
node->state = UPD_NODE_INSERT_CLUSTERED;
1667
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1671
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1673
if (node->upd_ext) {
1674
/* If we return from a lock wait, for example, we may have
1675
extern fields marked as not-owned in entry (marked in the
1676
if-branch above). We must unmark them. */
1678
btr_cur_unmark_dtuple_extern_fields(entry);
1680
/* We must mark non-updated extern fields in entry as
1681
inherited, so that a possible rollback will not free them. */
1683
btr_cur_mark_dtuple_inherited_extern(entry, node->update);
1686
err = row_ins_index_entry(index, entry,
1687
node->upd_ext ? node->upd_ext->n_ext : 0,
1689
mem_heap_free(heap);
1694
/***********************************************************//**
1695
Updates a clustered index record of a row when the ordering fields do
1697
@return DB_SUCCESS if operation successfully completed, else error
1698
code or DB_LOCK_WAIT */
1703
upd_node_t* node, /*!< in: row update node */
1704
dict_index_t* index, /*!< in: clustered index */
1705
que_thr_t* thr, /*!< in: query thread */
1706
mtr_t* mtr) /*!< in: mtr; gets committed here */
1708
mem_heap_t* heap = NULL;
1709
big_rec_t* big_rec = NULL;
1715
ut_ad(dict_index_is_clust(index));
1718
btr_cur = btr_pcur_get_btr_cur(pcur);
1720
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1721
dict_table_is_comp(index->table)));
1723
/* Try optimistic updating of the record, keeping changes within
1724
the page; we do not check locks because we assume the x-lock on the
1727
if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1728
err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1729
btr_cur, node->update,
1730
node->cmpl_info, thr, mtr);
1732
err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1733
btr_cur, node->update,
1734
node->cmpl_info, thr, mtr);
1739
if (UNIV_LIKELY(err == DB_SUCCESS)) {
1744
if (buf_LRU_buf_pool_running_out()) {
1746
return(DB_LOCK_TABLE_FULL);
1748
/* We may have to modify the tree structure: do a pessimistic descent
1749
down the index tree */
1753
/* NOTE: this transaction has an s-lock or x-lock on the record and
1754
therefore other transactions cannot modify the record when we have no
1755
latch on the page. In addition, we assume that other query threads of
1756
the same transaction do not modify the record in the meantime.
1757
Therefore we can assert that the restoration of the cursor succeeds. */
1759
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1761
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1762
dict_table_is_comp(index->table)));
1764
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1765
&heap, &big_rec, node->update,
1766
node->cmpl_info, thr, mtr);
1769
if (err == DB_SUCCESS && big_rec) {
1770
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1772
rec_offs_init(offsets_);
1776
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1777
rec = btr_cur_get_rec(btr_cur);
1778
err = btr_store_big_rec_extern_fields(
1779
index, btr_cur_get_block(btr_cur), rec,
1780
rec_get_offsets(rec, index, offsets_,
1781
ULINT_UNDEFINED, &heap),
1786
if (UNIV_LIKELY_NULL(heap)) {
1787
mem_heap_free(heap);
1791
dtuple_big_rec_free(big_rec);
1797
/***********************************************************//**
1798
Delete marks a clustered index record.
1799
@return DB_SUCCESS if operation successfully completed, else error code */
1802
row_upd_del_mark_clust_rec(
1803
/*=======================*/
1804
upd_node_t* node, /*!< in: row update node */
1805
dict_index_t* index, /*!< in: clustered index */
1806
ulint* offsets,/*!< in/out: rec_get_offsets() for the
1807
record under the cursor */
1808
que_thr_t* thr, /*!< in: query thread */
1810
/*!< in: TRUE if index may be referenced in
1811
a foreign key constraint */
1812
mtr_t* mtr) /*!< in: mtr; gets committed here */
1819
ut_ad(dict_index_is_clust(index));
1820
ut_ad(node->is_delete);
1823
btr_cur = btr_pcur_get_btr_cur(pcur);
1825
/* Store row because we have to build also the secondary index
1828
row_upd_store_row(node);
1830
/* Mark the clustered index record deleted; we do not have to check
1831
locks, because we assume that we have an x-lock on the record */
1833
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1834
btr_cur, TRUE, thr, mtr);
1835
if (err == DB_SUCCESS && referenced) {
1836
/* NOTE that the following call loses the position of pcur ! */
1838
err = row_upd_check_references_constraints(
1839
node, pcur, index->table, index, offsets, thr, mtr);
1847
/***********************************************************//**
1848
Updates the clustered index record.
1849
@return DB_SUCCESS if operation successfully completed, DB_LOCK_WAIT
1850
in case of a lock wait, else error code */
1855
upd_node_t* node, /*!< in: row update node */
1856
que_thr_t* thr) /*!< in: query thread */
1858
dict_index_t* index;
1865
mem_heap_t* heap = NULL;
1866
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1869
rec_offs_init(offsets_);
1871
index = dict_table_get_first_index(node->table);
1873
referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
1877
/* We have to restore the cursor to its position */
1882
/* If the restoration does not succeed, then the same
1883
transaction has deleted the record on which the cursor was,
1884
and that is an SQL error. If the restoration succeeds, it may
1885
still be that the same transaction has successively deleted
1886
and inserted a record with the same ordering fields, but in
1887
that case we know that the transaction has at least an
1888
implicit x-lock on the record. */
1890
ut_a(pcur->rel_pos == BTR_PCUR_ON);
1892
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1895
err = DB_RECORD_NOT_FOUND;
1902
/* If this is a row in SYS_INDEXES table of the data dictionary,
1903
then we have to free the file segments of the index tree associated
1907
&& ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1909
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1915
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
1926
rec = btr_pcur_get_rec(pcur);
1927
offsets = rec_get_offsets(rec, index, offsets_,
1928
ULINT_UNDEFINED, &heap);
1930
if (!node->has_clust_rec_x_lock) {
1931
err = lock_clust_rec_modify_check_and_lock(
1932
0, btr_pcur_get_block(pcur),
1933
rec, index, offsets, thr);
1934
if (err != DB_SUCCESS) {
1940
/* NOTE: the following function calls will also commit mtr */
1942
if (node->is_delete) {
1943
err = row_upd_del_mark_clust_rec(
1944
node, index, offsets, thr, referenced, mtr);
1946
if (err == DB_SUCCESS) {
1947
node->state = UPD_NODE_UPDATE_ALL_SEC;
1948
node->index = dict_table_get_next_index(index);
1951
if (UNIV_LIKELY_NULL(heap)) {
1952
mem_heap_free(heap);
1957
/* If the update is made for MySQL, we already have the update vector
1958
ready, else we have to do some evaluation: */
1960
if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
1961
/* Copy the necessary columns from clust_rec and calculate the
1962
new values to set */
1963
row_upd_copy_columns(rec, offsets,
1964
UT_LIST_GET_FIRST(node->columns));
1965
row_upd_eval_new_vals(node->update);
1968
if (UNIV_LIKELY_NULL(heap)) {
1969
mem_heap_free(heap);
1972
if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
1974
err = row_upd_clust_rec(node, index, thr, mtr);
1978
row_upd_store_row(node);
1980
if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
1982
/* Update causes an ordering field (ordering fields within
1983
the B-tree) of the clustered index record to change: perform
1984
the update by delete marking and inserting.
1986
TODO! What to do to the 'Halloween problem', where an update
1987
moves the record forward in index so that it is again
1988
updated when the cursor arrives there? Solution: the
1989
read operation must check the undo record undo number when
1990
choosing records to update. MySQL solves now the problem
1993
err = row_upd_clust_rec_by_insert(
1994
node, index, thr, referenced, mtr);
1996
if (err != DB_SUCCESS) {
2001
node->state = UPD_NODE_UPDATE_ALL_SEC;
2003
err = row_upd_clust_rec(node, index, thr, mtr);
2005
if (err != DB_SUCCESS) {
2010
node->state = UPD_NODE_UPDATE_SOME_SEC;
2013
node->index = dict_table_get_next_index(index);
2018
/***********************************************************//**
2019
Updates the affected index records of a row. When the control is transferred
2020
to this node, we assume that we have a persistent cursor which was on a
2021
record, and the position of the cursor is stored in the cursor.
2022
@return DB_SUCCESS if operation successfully completed, else error
2023
code or DB_LOCK_WAIT */
2028
upd_node_t* node, /*!< in: row update node */
2029
que_thr_t* thr) /*!< in: query thread */
2031
ulint err = DB_SUCCESS;
2035
if (UNIV_LIKELY(node->in_mysql_interface)) {
2037
/* We do not get the cmpl_info value from the MySQL
2038
interpreter: we must calculate it on the fly: */
2041
|| row_upd_changes_some_index_ord_field_binary(
2042
node->table, node->update)) {
2043
node->cmpl_info = 0;
2045
node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
2049
if (node->state == UPD_NODE_UPDATE_CLUSTERED
2050
|| node->state == UPD_NODE_INSERT_CLUSTERED) {
2052
err = row_upd_clust_step(node, thr);
2054
if (err != DB_SUCCESS) {
2060
if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
2065
while (node->index != NULL) {
2066
err = row_upd_sec_step(node, thr);
2068
if (err != DB_SUCCESS) {
2073
node->index = dict_table_get_next_index(node->index);
2077
if (err == DB_SUCCESS) {
2078
/* Do some cleanup */
2080
if (node->row != NULL) {
2083
node->upd_row = NULL;
2084
node->upd_ext = NULL;
2085
mem_heap_empty(node->heap);
2088
node->state = UPD_NODE_UPDATE_CLUSTERED;
2094
/***********************************************************//**
2095
Updates a row in a table. This is a high-level function used in SQL execution
2097
@return query thread to run next or NULL */
2102
que_thr_t* thr) /*!< in: query thread */
2105
sel_node_t* sel_node;
2107
ulint err = DB_SUCCESS;
2112
trx = thr_get_trx(thr);
2114
trx_start_if_not_started(trx);
2116
node = thr->run_node;
2118
sel_node = node->select;
2120
parent = que_node_get_parent(node);
2122
ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2124
if (thr->prev_node == parent) {
2125
node->state = UPD_NODE_SET_IX_LOCK;
2128
if (node->state == UPD_NODE_SET_IX_LOCK) {
2130
if (!node->has_clust_rec_x_lock) {
2131
/* It may be that the current session has not yet
2132
started its transaction, or it has been committed: */
2134
err = lock_table(0, node->table, LOCK_IX, thr);
2136
if (err != DB_SUCCESS) {
2138
goto error_handling;
2142
node->state = UPD_NODE_UPDATE_CLUSTERED;
2144
if (node->searched_update) {
2145
/* Reset the cursor */
2146
sel_node->state = SEL_NODE_OPEN;
2148
/* Fetch a row to update */
2150
thr->run_node = sel_node;
2156
/* sel_node is NULL if we are in the MySQL interface */
2158
if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
2160
if (!node->searched_update) {
2161
/* An explicit cursor should be positioned on a row
2168
goto error_handling;
2171
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2173
/* No more rows to update, or the select node performed the
2174
updates directly in-place */
2176
thr->run_node = parent;
2181
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2183
err = row_upd(node, thr);
2186
trx->error_state = err;
2188
if (err != DB_SUCCESS) {
2192
/* DO THE TRIGGER ACTIONS HERE */
2194
if (node->searched_update) {
2195
/* Fetch next row to update */
2197
thr->run_node = sel_node;
2199
/* It was an explicit cursor update */
2201
thr->run_node = parent;
2204
node->state = UPD_NODE_UPDATE_CLUSTERED;
2208
#endif /* !UNIV_HOTBACKUP */