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
IMPORTANT NOTE: Any operation that generates redo MUST check that there
97
is enough space in the redo log before for that operation. This is
98
done by calling log_free_check(). The reason for checking the
99
availability of the redo log space before the start of the operation is
100
that we MUST not hold any synchonization objects when performing the
102
If you make a change in this module make sure that no codepath is
103
introduced where a call to log_free_check() is bypassed. */
105
/*************************************************************************
106
IMPORTANT NOTE: Any operation that generates redo MUST check that there
107
is enough space in the redo log before for that operation. This is
108
done by calling log_free_check(). The reason for checking the
109
availability of the redo log space before the start of the operation is
110
that we MUST not hold any synchonization objects when performing the
112
If you make a change in this module make sure that no codepath is
113
introduced where a call to log_free_check() is bypassed. */
115
/***********************************************************//**
116
Checks if an update vector changes some of the first ordering fields of an
117
index record. This is only used in foreign key checks and we can assume
118
that index does not contain column prefixes.
119
@return TRUE if changes */
122
row_upd_changes_first_fields_binary(
123
/*================================*/
124
dtuple_t* entry, /*!< in: old value of index entry */
125
dict_index_t* index, /*!< in: index of entry */
126
const upd_t* update, /*!< in: update vector for the row */
127
ulint n); /*!< in: how many first fields to check */
130
/*********************************************************************//**
131
Checks if index currently is mentioned as a referenced index in a foreign
134
NOTE that since we do not hold dict_operation_lock when leaving the
135
function, it may be that the referencing table has been dropped when
136
we leave this function: this function is only for heuristic use!
138
@return TRUE if referenced */
141
row_upd_index_is_referenced(
142
/*========================*/
143
dict_index_t* index, /*!< in: index */
144
trx_t* trx) /*!< in: transaction */
146
dict_table_t* table = index->table;
147
dict_foreign_t* foreign;
148
ibool froze_data_dict = FALSE;
149
ibool is_referenced = FALSE;
151
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
156
if (trx->dict_operation_lock_mode == 0) {
157
row_mysql_freeze_data_dictionary(trx);
158
froze_data_dict = TRUE;
161
foreign = UT_LIST_GET_FIRST(table->referenced_list);
164
if (foreign->referenced_index == index) {
166
is_referenced = TRUE;
170
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
174
if (froze_data_dict) {
175
row_mysql_unfreeze_data_dictionary(trx);
178
return(is_referenced);
181
/*********************************************************************//**
182
Checks if possible foreign key constraints hold after a delete of the record
185
NOTE that this function will temporarily commit mtr and lose the
188
@return DB_SUCCESS or an error code */
191
row_upd_check_references_constraints(
192
/*=================================*/
193
upd_node_t* node, /*!< in: row update node */
194
btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the
195
cursor position is lost in this function! */
196
dict_table_t* table, /*!< in: table in question */
197
dict_index_t* index, /*!< in: index of the cursor */
198
ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */
199
que_thr_t* thr, /*!< in: query thread */
200
mtr_t* mtr) /*!< in: mtr */
202
dict_foreign_t* foreign;
209
ibool got_s_lock = FALSE;
211
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
216
trx = thr_get_trx(thr);
218
rec = btr_pcur_get_rec(pcur);
219
ut_ad(rec_offs_validate(rec, index, offsets));
221
heap = mem_heap_create(500);
223
entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
230
if (trx->dict_operation_lock_mode == 0) {
233
row_mysql_freeze_data_dictionary(trx);
236
foreign = UT_LIST_GET_FIRST(table->referenced_list);
239
/* Note that we may have an update which updates the index
240
record, but does NOT update the first fields which are
241
referenced in a foreign key constraint. Then the update does
242
NOT break the constraint. */
244
if (foreign->referenced_index == index
246
|| row_upd_changes_first_fields_binary(
247
entry, index, node->update,
248
foreign->n_fields))) {
250
if (foreign->foreign_table == NULL) {
251
dict_table_get(foreign->foreign_table_name,
255
if (foreign->foreign_table) {
256
mutex_enter(&(dict_sys->mutex));
258
(foreign->foreign_table
259
->n_foreign_key_checks_running)++;
261
mutex_exit(&(dict_sys->mutex));
264
/* NOTE that if the thread ends up waiting for a lock
265
we will release dict_operation_lock temporarily!
266
But the counter on the table protects 'foreign' from
267
being dropped while the check is running. */
269
err = row_ins_check_foreign_constraint(
270
FALSE, foreign, table, entry, thr);
272
if (foreign->foreign_table) {
273
mutex_enter(&(dict_sys->mutex));
275
ut_a(foreign->foreign_table
276
->n_foreign_key_checks_running > 0);
278
(foreign->foreign_table
279
->n_foreign_key_checks_running)--;
281
mutex_exit(&(dict_sys->mutex));
284
if (err != DB_SUCCESS) {
290
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
297
row_mysql_unfreeze_data_dictionary(trx);
305
/*********************************************************************//**
306
Creates an update node for a query graph.
307
@return own: update node */
312
mem_heap_t* heap) /*!< in: mem heap where created */
316
node = static_cast<upd_node_t *>(mem_heap_alloc(heap, sizeof(upd_node_t)));
317
node->common.type = QUE_NODE_UPDATE;
319
node->state = UPD_NODE_UPDATE_CLUSTERED;
320
node->in_mysql_interface = FALSE;
324
node->upd_row = NULL;
325
node->upd_ext = NULL;
329
node->foreign = NULL;
330
node->cascade_heap = NULL;
331
node->cascade_node = NULL;
335
node->heap = mem_heap_create(128);
336
node->magic_n = UPD_NODE_MAGIC_N;
342
#endif /* !UNIV_HOTBACKUP */
344
/*********************************************************************//**
345
Updates the trx id and roll ptr field in a clustered index record in database
349
row_upd_rec_sys_fields_in_recovery(
350
/*===============================*/
351
rec_t* rec, /*!< in/out: record */
352
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
353
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
354
ulint pos, /*!< in: TRX_ID position in rec */
355
trx_id_t trx_id, /*!< in: transaction id */
356
roll_ptr_t roll_ptr)/*!< in: roll ptr of the undo log record */
358
ut_ad(rec_offs_validate(rec, NULL, offsets));
360
if (UNIV_LIKELY_NULL(page_zip)) {
361
page_zip_write_trx_id_and_roll_ptr(
362
page_zip, rec, offsets, pos, trx_id, roll_ptr);
367
field = rec_get_nth_field(rec, offsets, pos, &len);
368
ut_ad(len == DATA_TRX_ID_LEN);
369
#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
370
# error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
372
trx_write_trx_id(field, trx_id);
373
trx_write_roll_ptr(field + DATA_TRX_ID_LEN, roll_ptr);
377
#ifndef UNIV_HOTBACKUP
378
/*********************************************************************//**
379
Sets the trx id or roll ptr field of a clustered index entry. */
382
row_upd_index_entry_sys_field(
383
/*==========================*/
384
dtuple_t* entry, /*!< in/out: index entry, where the memory
385
buffers for sys fields are already allocated:
386
the function just copies the new values to
388
dict_index_t* index, /*!< in: clustered index */
389
ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
390
ib_uint64_t val) /*!< in: value to write */
396
ut_ad(dict_index_is_clust(index));
398
pos = dict_index_get_sys_col_pos(index, type);
400
dfield = dtuple_get_nth_field(entry, pos);
401
field = static_cast<byte *>(dfield_get_data(dfield));
403
if (type == DATA_TRX_ID) {
404
trx_write_trx_id(field, val);
406
ut_ad(type == DATA_ROLL_PTR);
407
trx_write_roll_ptr(field, val);
411
/***********************************************************//**
412
Returns TRUE if row update changes size of some field in index or if some
413
field to be updated is stored externally in rec or update.
414
@return TRUE if the update changes the size of some field in index or
415
the field is external in rec or update */
418
row_upd_changes_field_size_or_external(
419
/*===================================*/
420
dict_index_t* index, /*!< in: index */
421
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
422
const upd_t* update) /*!< in: update vector */
424
const upd_field_t* upd_field;
425
const dfield_t* new_val;
431
ut_ad(rec_offs_validate(NULL, index, offsets));
432
n_fields = upd_get_n_fields(update);
434
for (i = 0; i < n_fields; i++) {
435
upd_field = upd_get_nth_field(update, i);
437
new_val = &(upd_field->new_val);
438
new_len = dfield_get_len(new_val);
440
if (dfield_is_null(new_val) && !rec_offs_comp(offsets)) {
441
/* A bug fixed on Dec 31st, 2004: we looked at the
442
SQL NULL size from the wrong field! We may backport
443
this fix also to 4.0. The merge to 5.0 will be made
444
manually immediately after we commit this to 4.1. */
446
new_len = dict_col_get_sql_null_size(
447
dict_index_get_nth_col(index,
448
upd_field->field_no),
452
old_len = rec_offs_nth_size(offsets, upd_field->field_no);
454
if (rec_offs_comp(offsets)
455
&& rec_offs_nth_sql_null(offsets,
456
upd_field->field_no)) {
457
/* Note that in the compact table format, for a
458
variable length field, an SQL NULL will use zero
459
bytes in the offset array at the start of the physical
460
record, but a zero-length value (empty string) will
461
use one byte! Thus, we cannot use update-in-place
462
if we update an SQL NULL varchar to an empty string! */
464
old_len = UNIV_SQL_NULL;
467
if (dfield_is_ext(new_val) || old_len != new_len
468
|| rec_offs_nth_extern(offsets, upd_field->field_no)) {
476
#endif /* !UNIV_HOTBACKUP */
478
/***********************************************************//**
479
Replaces the new column values stored in the update vector to the
480
record given. No field size changes are allowed. This function is
481
usually invoked on a clustered index. The only use case for a
482
secondary index is row_ins_sec_index_entry_by_modify() or its
483
counterpart in ibuf_insert_to_index_page(). */
486
row_upd_rec_in_place(
487
/*=================*/
488
rec_t* rec, /*!< in/out: record where replaced */
489
dict_index_t* index, /*!< in: the index the record belongs to */
490
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
491
const upd_t* update, /*!< in: update vector */
492
page_zip_des_t* page_zip)/*!< in: compressed page with enough space
493
available, or NULL */
495
const upd_field_t* upd_field;
496
const dfield_t* new_val;
500
ut_ad(rec_offs_validate(rec, index, offsets));
502
if (rec_offs_comp(offsets)) {
503
rec_set_info_bits_new(rec, update->info_bits);
505
rec_set_info_bits_old(rec, update->info_bits);
508
n_fields = upd_get_n_fields(update);
510
for (i = 0; i < n_fields; i++) {
511
upd_field = upd_get_nth_field(update, i);
512
new_val = &(upd_field->new_val);
513
ut_ad(!dfield_is_ext(new_val) ==
514
!rec_offs_nth_extern(offsets, upd_field->field_no));
516
rec_set_nth_field(rec, offsets, upd_field->field_no,
517
dfield_get_data(new_val),
518
dfield_get_len(new_val));
521
if (UNIV_LIKELY_NULL(page_zip)) {
522
page_zip_write_rec(page_zip, rec, index, offsets, 0);
526
#ifndef UNIV_HOTBACKUP
527
/*********************************************************************//**
528
Writes into the redo log the values of trx id and roll ptr and enough info
529
to determine their positions within a clustered index record.
530
@return new pointer to mlog */
533
row_upd_write_sys_vals_to_log(
534
/*==========================*/
535
dict_index_t* index, /*!< in: clustered index */
536
trx_t* trx, /*!< in: transaction */
537
roll_ptr_t roll_ptr,/*!< in: roll ptr of the undo log record */
538
byte* log_ptr,/*!< pointer to a buffer of size > 20 opened
540
mtr_t* /*mtr __attribute__((unused))*/) /*!< in: mtr */
542
ut_ad(dict_index_is_clust(index));
545
log_ptr += mach_write_compressed(log_ptr,
546
dict_index_get_sys_col_pos(
547
index, DATA_TRX_ID));
549
trx_write_roll_ptr(log_ptr, roll_ptr);
550
log_ptr += DATA_ROLL_PTR_LEN;
552
log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
556
#endif /* !UNIV_HOTBACKUP */
558
/*********************************************************************//**
559
Parses the log data of system field values.
560
@return log data end or NULL */
563
row_upd_parse_sys_vals(
564
/*===================*/
565
byte* ptr, /*!< in: buffer */
566
byte* end_ptr,/*!< in: buffer end */
567
ulint* pos, /*!< out: TRX_ID position in record */
568
trx_id_t* trx_id, /*!< out: trx id */
569
roll_ptr_t* roll_ptr)/*!< out: roll ptr */
571
ptr = mach_parse_compressed(ptr, end_ptr, pos);
578
if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
583
*roll_ptr = trx_read_roll_ptr(ptr);
584
ptr += DATA_ROLL_PTR_LEN;
586
ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
591
#ifndef UNIV_HOTBACKUP
592
/***********************************************************//**
593
Writes to the redo log the new values of the fields occurring in the index. */
596
row_upd_index_write_log(
597
/*====================*/
598
const upd_t* update, /*!< in: update vector */
599
byte* log_ptr,/*!< in: pointer to mlog buffer: must
600
contain at least MLOG_BUF_MARGIN bytes
601
of free space; the buffer is closed
602
within this function */
603
mtr_t* mtr) /*!< in: mtr into whose log to write */
605
const upd_field_t* upd_field;
606
const dfield_t* new_val;
612
n_fields = upd_get_n_fields(update);
614
buf_end = log_ptr + MLOG_BUF_MARGIN;
616
mach_write_to_1(log_ptr, update->info_bits);
618
log_ptr += mach_write_compressed(log_ptr, n_fields);
620
for (i = 0; i < n_fields; i++) {
622
#if MLOG_BUF_MARGIN <= 30
623
# error "MLOG_BUF_MARGIN <= 30"
626
if (log_ptr + 30 > buf_end) {
627
mlog_close(mtr, log_ptr);
629
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
630
buf_end = log_ptr + MLOG_BUF_MARGIN;
633
upd_field = upd_get_nth_field(update, i);
635
new_val = &(upd_field->new_val);
637
len = dfield_get_len(new_val);
639
log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
640
log_ptr += mach_write_compressed(log_ptr, len);
642
if (len != UNIV_SQL_NULL) {
643
if (log_ptr + len < buf_end) {
644
memcpy(log_ptr, dfield_get_data(new_val), len);
648
mlog_close(mtr, log_ptr);
650
mlog_catenate_string(mtr,
651
static_cast<byte *>(dfield_get_data(new_val)),
654
log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
655
buf_end = log_ptr + MLOG_BUF_MARGIN;
660
mlog_close(mtr, log_ptr);
662
#endif /* !UNIV_HOTBACKUP */
664
/*********************************************************************//**
665
Parses the log data written by row_upd_index_write_log.
666
@return log data end or NULL */
671
byte* ptr, /*!< in: buffer */
672
byte* end_ptr,/*!< in: buffer end */
673
mem_heap_t* heap, /*!< in: memory heap where update vector is
675
upd_t** update_out)/*!< out: update vector */
678
upd_field_t* upd_field;
685
if (end_ptr < ptr + 1) {
690
info_bits = mach_read_from_1(ptr);
692
ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
699
update = upd_create(n_fields, heap);
700
update->info_bits = info_bits;
702
for (i = 0; i < n_fields; i++) {
704
upd_field = upd_get_nth_field(update, i);
705
new_val = &(upd_field->new_val);
707
ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
714
upd_field->field_no = field_no;
716
ptr = mach_parse_compressed(ptr, end_ptr, &len);
723
if (len != UNIV_SQL_NULL) {
725
if (end_ptr < ptr + len) {
730
dfield_set_data(new_val,
731
mem_heap_dup(heap, ptr, len), len);
734
dfield_set_null(new_val);
738
*update_out = update;
743
#ifndef UNIV_HOTBACKUP
744
/***************************************************************//**
745
Builds an update vector from those fields which in a secondary index entry
746
differ from a record that has the equal ordering fields. NOTE: we compare
747
the fields as binary strings!
748
@return own: update vector of differing fields */
751
row_upd_build_sec_rec_difference_binary(
752
/*====================================*/
753
dict_index_t* index, /*!< in: index */
754
const dtuple_t* entry, /*!< in: entry to insert */
755
const rec_t* rec, /*!< in: secondary index record */
756
trx_t* trx, /*!< in: transaction */
757
mem_heap_t* heap) /*!< in: memory heap from which allocated */
759
upd_field_t* upd_field;
760
const dfield_t* dfield;
766
ulint offsets_[REC_OFFS_SMALL_SIZE];
767
const ulint* offsets;
768
rec_offs_init(offsets_);
770
/* This function is used only for a secondary index */
771
ut_a(!dict_index_is_clust(index));
773
update = upd_create(dtuple_get_n_fields(entry), heap);
776
offsets = rec_get_offsets(rec, index, offsets_,
777
ULINT_UNDEFINED, &heap);
779
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
781
data = rec_get_nth_field(rec, offsets, i, &len);
783
dfield = dtuple_get_nth_field(entry, i);
785
/* NOTE that it may be that len != dfield_get_len(dfield) if we
786
are updating in a character set and collation where strings of
787
different length can be equal in an alphabetical comparison,
788
and also in the case where we have a column prefix index
789
and the last characters in the index field are spaces; the
790
latter case probably caused the assertion failures reported at
791
row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
793
/* NOTE: we compare the fields as binary strings!
796
if (!dfield_data_is_binary_equal(dfield, len, data)) {
798
upd_field = upd_get_nth_field(update, n_diff);
800
dfield_copy(&(upd_field->new_val), dfield);
802
upd_field_set_field_no(upd_field, i, index, trx);
808
update->n_fields = n_diff;
813
/***************************************************************//**
814
Builds an update vector from those fields, excluding the roll ptr and
815
trx id fields, which in an index entry differ from a record that has
816
the equal ordering fields. NOTE: we compare the fields as binary strings!
817
@return own: update vector of differing fields, excluding roll ptr and
821
row_upd_build_difference_binary(
822
/*============================*/
823
dict_index_t* index, /*!< in: clustered index */
824
const dtuple_t* entry, /*!< in: entry to insert */
825
const rec_t* rec, /*!< in: clustered index record */
826
trx_t* trx, /*!< in: transaction */
827
mem_heap_t* heap) /*!< in: memory heap from which allocated */
829
upd_field_t* upd_field;
830
const dfield_t* dfield;
838
ulint offsets_[REC_OFFS_NORMAL_SIZE];
839
const ulint* offsets;
840
rec_offs_init(offsets_);
842
/* This function is used only for a clustered index */
843
ut_a(dict_index_is_clust(index));
845
update = upd_create(dtuple_get_n_fields(entry), heap);
849
roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
850
trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
852
offsets = rec_get_offsets(rec, index, offsets_,
853
ULINT_UNDEFINED, &heap);
855
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
857
data = rec_get_nth_field(rec, offsets, i, &len);
859
dfield = dtuple_get_nth_field(entry, i);
861
/* NOTE: we compare the fields as binary strings!
864
if (i == trx_id_pos || i == roll_ptr_pos) {
869
if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
870
!= !rec_offs_nth_extern(offsets, i))
871
|| !dfield_data_is_binary_equal(dfield, len, data)) {
873
upd_field = upd_get_nth_field(update, n_diff);
875
dfield_copy(&(upd_field->new_val), dfield);
877
upd_field_set_field_no(upd_field, i, index, trx);
885
update->n_fields = n_diff;
890
/***********************************************************//**
891
Fetch a prefix of an externally stored column. This is similar
892
to row_ext_lookup(), but the row_ext_t holds the old values
893
of the column and must not be poisoned with the new values.
894
@return BLOB prefix */
899
const byte* data, /*!< in: 'internally' stored part of the
900
field containing also the reference to
902
ulint local_len, /*!< in: length of data, in bytes */
903
ulint zip_size, /*!< in: nonzero=compressed BLOB
904
page size, zero for uncompressed
906
ulint* len, /*!< in: length of prefix to fetch;
907
out: fetched length of the prefix */
908
mem_heap_t* heap) /*!< in: heap where to allocate */
910
byte* buf = static_cast<byte *>(mem_heap_alloc(heap, *len));
912
*len = btr_copy_externally_stored_field_prefix(buf, *len,
915
/* We should never update records containing a half-deleted BLOB. */
921
/***********************************************************//**
922
Replaces the new column value stored in the update vector in
923
the given index entry field. */
926
row_upd_index_replace_new_col_val(
927
/*==============================*/
928
dfield_t* dfield, /*!< in/out: data field
929
of the index entry */
930
const dict_field_t* field, /*!< in: index field */
931
const dict_col_t* col, /*!< in: field->col */
932
const upd_field_t* uf, /*!< in: update field */
933
mem_heap_t* heap, /*!< in: memory heap for allocating
934
and copying the new value */
935
ulint zip_size)/*!< in: compressed page
936
size of the table, or 0 */
941
dfield_copy_data(dfield, &uf->new_val);
943
if (dfield_is_null(dfield)) {
947
len = dfield_get_len(dfield);
948
data = static_cast<const byte *>(dfield_get_data(dfield));
950
if (field->prefix_len > 0) {
951
ibool fetch_ext = dfield_is_ext(dfield)
952
&& len < (ulint) field->prefix_len
953
+ BTR_EXTERN_FIELD_REF_SIZE;
958
len = field->prefix_len;
960
data = row_upd_ext_fetch(data, l, zip_size,
964
len = dtype_get_at_most_n_mbchars(col->prtype,
966
field->prefix_len, len,
969
dfield_set_data(dfield, data, len);
972
dfield_dup(dfield, heap);
978
switch (uf->orig_len) {
980
case BTR_EXTERN_FIELD_REF_SIZE:
981
/* Restore the original locally stored
982
part of the column. In the undo log,
983
InnoDB writes a longer prefix of externally
984
stored columns, so that column prefixes
985
in secondary indexes can be reconstructed. */
986
dfield_set_data(dfield,
987
data + len - BTR_EXTERN_FIELD_REF_SIZE,
988
BTR_EXTERN_FIELD_REF_SIZE);
989
dfield_set_ext(dfield);
992
dfield_dup(dfield, heap);
995
/* Reconstruct the original locally
996
stored part of the column. The data
997
will have to be copied. */
998
ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
999
buf = static_cast<byte *>(mem_heap_alloc(heap, uf->orig_len));
1000
/* Copy the locally stored prefix. */
1002
uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
1003
/* Copy the BLOB pointer. */
1004
memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
1005
data + len - BTR_EXTERN_FIELD_REF_SIZE,
1006
BTR_EXTERN_FIELD_REF_SIZE);
1008
dfield_set_data(dfield, buf, uf->orig_len);
1009
dfield_set_ext(dfield);
1014
/***********************************************************//**
1015
Replaces the new column values stored in the update vector to the index entry
1019
row_upd_index_replace_new_col_vals_index_pos(
1020
/*=========================================*/
1021
dtuple_t* entry, /*!< in/out: index entry where replaced;
1022
the clustered index record must be
1023
covered by a lock or a page latch to
1024
prevent deletion (rollback or purge) */
1025
dict_index_t* index, /*!< in: index; NOTE that this may also be a
1026
non-clustered index */
1027
const upd_t* update, /*!< in: an update vector built for the index so
1028
that the field number in an upd_field is the
1031
/*!< in: if TRUE, limit the replacement to
1032
ordering fields of index; note that this
1033
does not work for non-clustered indexes. */
1034
mem_heap_t* heap) /*!< in: memory heap for allocating and
1035
copying the new values */
1039
const ulint zip_size = dict_table_zip_size(index->table);
1043
dtuple_set_info_bits(entry, update->info_bits);
1046
n_fields = dict_index_get_n_unique(index);
1048
n_fields = dict_index_get_n_fields(index);
1051
for (i = 0; i < n_fields; i++) {
1052
const dict_field_t* field;
1053
const dict_col_t* col;
1054
const upd_field_t* uf;
1056
field = dict_index_get_nth_field(index, i);
1057
col = dict_field_get_col(field);
1058
uf = upd_get_field_by_field_no(update, i);
1061
row_upd_index_replace_new_col_val(
1062
dtuple_get_nth_field(entry, i),
1063
field, col, uf, heap, zip_size);
1068
/***********************************************************//**
1069
Replaces the new column values stored in the update vector to the index entry
1073
row_upd_index_replace_new_col_vals(
1074
/*===============================*/
1075
dtuple_t* entry, /*!< in/out: index entry where replaced;
1076
the clustered index record must be
1077
covered by a lock or a page latch to
1078
prevent deletion (rollback or purge) */
1079
dict_index_t* index, /*!< in: index; NOTE that this may also be a
1080
non-clustered index */
1081
const upd_t* update, /*!< in: an update vector built for the
1082
CLUSTERED index so that the field number in
1083
an upd_field is the clustered index position */
1084
mem_heap_t* heap) /*!< in: memory heap for allocating and
1085
copying the new values */
1088
const dict_index_t* clust_index
1089
= dict_table_get_first_index(index->table);
1090
const ulint zip_size
1091
= dict_table_zip_size(index->table);
1093
dtuple_set_info_bits(entry, update->info_bits);
1095
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1096
const dict_field_t* field;
1097
const dict_col_t* col;
1098
const upd_field_t* uf;
1100
field = dict_index_get_nth_field(index, i);
1101
col = dict_field_get_col(field);
1102
uf = upd_get_field_by_field_no(
1103
update, dict_col_get_clust_pos(col, clust_index));
1106
row_upd_index_replace_new_col_val(
1107
dtuple_get_nth_field(entry, i),
1108
field, col, uf, heap, zip_size);
1113
/***********************************************************//**
1114
Replaces the new column values stored in the update vector. */
1119
dtuple_t* row, /*!< in/out: row where replaced,
1121
the clustered index record must be
1122
covered by a lock or a page latch to
1123
prevent deletion (rollback or purge) */
1124
row_ext_t** ext, /*!< out, own: NULL, or externally
1125
stored column prefixes */
1126
const dict_index_t* index, /*!< in: clustered index */
1127
const upd_t* update, /*!< in: an update vector built for the
1129
mem_heap_t* heap) /*!< in: memory heap */
1136
const dict_table_t* table;
1141
ut_ad(dict_index_is_clust(index));
1145
n_cols = dtuple_get_n_fields(row);
1146
table = index->table;
1147
ut_ad(n_cols == dict_table_get_n_cols(table));
1149
ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_cols * sizeof *ext_cols));
1152
dtuple_set_info_bits(row, update->info_bits);
1154
for (col_no = 0; col_no < n_cols; col_no++) {
1156
const dict_col_t* col
1157
= dict_table_get_nth_col(table, col_no);
1158
const ulint clust_pos
1159
= dict_col_get_clust_pos(col, index);
1162
if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
1167
dfield = dtuple_get_nth_field(row, col_no);
1169
for (i = 0; i < upd_get_n_fields(update); i++) {
1171
const upd_field_t* upd_field
1172
= upd_get_nth_field(update, i);
1174
if (upd_field->field_no != clust_pos) {
1179
dfield_copy_data(dfield, &upd_field->new_val);
1183
if (dfield_is_ext(dfield) && col->ord_part) {
1184
ext_cols[n_ext_cols++] = col_no;
1189
*ext = row_ext_create(n_ext_cols, ext_cols, row,
1190
dict_table_zip_size(table), heap);
1196
/***********************************************************//**
1197
Checks if an update vector changes an ordering field of an index record.
1199
This function is fast if the update vector is short or the number of ordering
1200
fields in the index is small. Otherwise, this can be quadratic.
1201
NOTE: we compare the fields as binary strings!
1202
@return TRUE if update vector changes an ordering field in the index record */
1205
row_upd_changes_ord_field_binary(
1206
/*=============================*/
1207
const dtuple_t* row, /*!< in: old value of row, or NULL if the
1208
row and the data values in update are not
1209
known when this function is called, e.g., at
1211
dict_index_t* index, /*!< in: index of the record */
1212
const upd_t* update) /*!< in: update vector for the row; NOTE: the
1213
field numbers in this MUST be clustered index
1219
dict_index_t* clust_index;
1221
ut_ad(update && index);
1223
n_unique = dict_index_get_n_unique(index);
1224
n_upd_fields = upd_get_n_fields(update);
1226
clust_index = dict_table_get_first_index(index->table);
1228
for (i = 0; i < n_unique; i++) {
1230
const dict_field_t* ind_field;
1231
const dict_col_t* col;
1235
ind_field = dict_index_get_nth_field(index, i);
1236
col = dict_field_get_col(ind_field);
1237
col_pos = dict_col_get_clust_pos(col, clust_index);
1238
col_no = dict_col_get_no(col);
1240
for (j = 0; j < n_upd_fields; j++) {
1242
const upd_field_t* upd_field
1243
= upd_get_nth_field(update, j);
1245
/* Note that if the index field is a column prefix
1246
then it may be that row does not contain an externally
1247
stored part of the column value, and we cannot compare
1250
if (col_pos == upd_field->field_no
1252
|| ind_field->prefix_len > 0
1253
|| !dfield_datas_are_binary_equal(
1254
dtuple_get_nth_field(row, col_no),
1255
&(upd_field->new_val)))) {
1265
/***********************************************************//**
1266
Checks if an update vector changes an ordering field of an index record.
1267
NOTE: we compare the fields as binary strings!
1268
@return TRUE if update vector may change an ordering field in an index
1272
row_upd_changes_some_index_ord_field_binary(
1273
/*========================================*/
1274
const dict_table_t* table, /*!< in: table */
1275
const upd_t* update) /*!< in: update vector for the row */
1277
upd_field_t* upd_field;
1278
dict_index_t* index;
1281
index = dict_table_get_first_index(table);
1283
for (i = 0; i < upd_get_n_fields(update); i++) {
1285
upd_field = upd_get_nth_field(update, i);
1287
if (dict_field_get_col(dict_index_get_nth_field(
1288
index, upd_field->field_no))
1298
/***********************************************************//**
1299
Checks if an update vector changes some of the first ordering fields of an
1300
index record. This is only used in foreign key checks and we can assume
1301
that index does not contain column prefixes.
1302
@return TRUE if changes */
1305
row_upd_changes_first_fields_binary(
1306
/*================================*/
1307
dtuple_t* entry, /*!< in: index entry */
1308
dict_index_t* index, /*!< in: index of entry */
1309
const upd_t* update, /*!< in: update vector for the row */
1310
ulint n) /*!< in: how many first fields to check */
1314
dict_index_t* clust_index;
1316
ut_ad(update && index);
1317
ut_ad(n <= dict_index_get_n_fields(index));
1319
n_upd_fields = upd_get_n_fields(update);
1320
clust_index = dict_table_get_first_index(index->table);
1322
for (i = 0; i < n; i++) {
1324
const dict_field_t* ind_field;
1325
const dict_col_t* col;
1328
ind_field = dict_index_get_nth_field(index, i);
1329
col = dict_field_get_col(ind_field);
1330
col_pos = dict_col_get_clust_pos(col, clust_index);
1332
ut_a(ind_field->prefix_len == 0);
1334
for (j = 0; j < n_upd_fields; j++) {
1336
upd_field_t* upd_field
1337
= upd_get_nth_field(update, j);
1339
if (col_pos == upd_field->field_no
1340
&& !dfield_datas_are_binary_equal(
1341
dtuple_get_nth_field(entry, i),
1342
&(upd_field->new_val))) {
1352
/*********************************************************************//**
1353
Copies the column values from a record. */
1356
row_upd_copy_columns(
1357
/*=================*/
1358
rec_t* rec, /*!< in: record in a clustered index */
1359
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
1360
sym_node_t* column) /*!< in: first column in a column list, or
1367
data = rec_get_nth_field(rec, offsets,
1368
column->field_nos[SYM_CLUST_FIELD_NO],
1370
eval_node_copy_and_alloc_val(column, data, len);
1372
column = UT_LIST_GET_NEXT(col_var_list, column);
1376
/*********************************************************************//**
1377
Calculates the new values for fields to update. Note that row_upd_copy_columns
1378
must have been called first. */
1381
row_upd_eval_new_vals(
1382
/*==================*/
1383
upd_t* update) /*!< in/out: update vector */
1386
upd_field_t* upd_field;
1390
n_fields = upd_get_n_fields(update);
1392
for (i = 0; i < n_fields; i++) {
1393
upd_field = upd_get_nth_field(update, i);
1395
exp = upd_field->exp;
1399
dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1403
/***********************************************************//**
1404
Stores to the heap the row on which the node->pcur is positioned. */
1409
upd_node_t* node) /*!< in: row update node */
1411
dict_index_t* clust_index;
1413
mem_heap_t* heap = NULL;
1415
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1416
const ulint* offsets;
1417
rec_offs_init(offsets_);
1419
ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1421
if (node->row != NULL) {
1422
mem_heap_empty(node->heap);
1425
clust_index = dict_table_get_first_index(node->table);
1427
rec = btr_pcur_get_rec(node->pcur);
1429
offsets = rec_get_offsets(rec, clust_index, offsets_,
1430
ULINT_UNDEFINED, &heap);
1432
if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) {
1433
/* In DYNAMIC or COMPRESSED format, there is no prefix
1434
of externally stored columns in the clustered index
1435
record. Build a cache of column prefixes. */
1438
/* REDUNDANT and COMPACT formats store a local
1439
768-byte prefix of each externally stored column.
1440
No cache is needed. */
1445
node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1446
NULL, ext, node->heap);
1447
if (node->is_delete) {
1448
node->upd_row = NULL;
1449
node->upd_ext = NULL;
1451
node->upd_row = dtuple_copy(node->row, node->heap);
1452
row_upd_replace(node->upd_row, &node->upd_ext,
1453
clust_index, node->update, node->heap);
1456
if (UNIV_LIKELY_NULL(heap)) {
1457
mem_heap_free(heap);
1461
/***********************************************************//**
1462
Updates a secondary index entry of a row.
1463
@return DB_SUCCESS if operation successfully completed, else error
1464
code or DB_LOCK_WAIT */
1467
row_upd_sec_index_entry(
1468
/*====================*/
1469
upd_node_t* node, /*!< in: row update node */
1470
que_thr_t* thr) /*!< in: query thread */
1477
dict_index_t* index;
1480
ulint err = DB_SUCCESS;
1481
trx_t* trx = thr_get_trx(thr);
1482
ulint mode = BTR_MODIFY_LEAF;
1483
enum row_search_result search_result;
1485
index = node->index;
1487
referenced = row_upd_index_is_referenced(index, trx);
1489
heap = mem_heap_create(1024);
1491
/* Build old index entry */
1492
entry = row_build_index_entry(node->row, node->ext, index, heap);
1497
/* Set the query thread, so that ibuf_insert_low() will be
1498
able to invoke thd_get_trx(). */
1499
btr_pcur_get_btr_cur(&pcur)->thr = thr;
1501
/* We can only try to use the insert/delete buffer to buffer
1502
delete-mark operations if the index we're modifying has no foreign
1503
key constraints referring to it. */
1505
mode |= BTR_DELETE_MARK;
1508
search_result = row_search_index_entry(index, entry, mode,
1511
btr_cur = btr_pcur_get_btr_cur(&pcur);
1513
rec = btr_cur_get_rec(btr_cur);
1515
switch (search_result) {
1516
case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
1520
/* Entry was delete marked already. */
1524
fputs("InnoDB: error in sec index entry update in\n"
1525
"InnoDB: ", stderr);
1526
dict_index_name_print(stderr, trx, index);
1528
"InnoDB: tuple ", stderr);
1529
dtuple_print(stderr, entry);
1531
"InnoDB: record ", stderr);
1532
rec_print(stderr, rec, index);
1535
trx_print(stderr, trx, 0);
1538
"InnoDB: Submit a detailed bug report"
1539
" to http://bugs.mysql.com\n", stderr);
1542
/* Delete mark the old index record; it can already be
1543
delete marked if we return after a lock wait in
1544
row_ins_index_entry below */
1546
if (!rec_get_deleted_flag(
1547
rec, dict_table_is_comp(index->table))) {
1549
err = btr_cur_del_mark_set_sec_rec(
1550
0, btr_cur, TRUE, thr, &mtr);
1552
if (err == DB_SUCCESS && referenced) {
1556
offsets = rec_get_offsets(
1557
rec, index, NULL, ULINT_UNDEFINED,
1560
/* NOTE that the following call loses
1561
the position of pcur ! */
1562
err = row_upd_check_references_constraints(
1563
node, &pcur, index->table,
1564
index, offsets, thr, &mtr);
1570
btr_pcur_close(&pcur);
1573
if (node->is_delete || err != DB_SUCCESS) {
1578
/* Build a new index entry */
1579
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1583
/* Insert new index entry */
1584
err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1587
mem_heap_free(heap);
1592
/***********************************************************//**
1593
Updates the secondary index record if it is changed in the row update or
1594
deletes it if this is a delete.
1595
@return DB_SUCCESS if operation successfully completed, else error
1596
code or DB_LOCK_WAIT */
1601
upd_node_t* node, /*!< in: row update node */
1602
que_thr_t* thr) /*!< in: query thread */
1604
ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1605
|| (node->state == UPD_NODE_UPDATE_SOME_SEC));
1606
ut_ad(!dict_index_is_clust(node->index));
1608
if (node->state == UPD_NODE_UPDATE_ALL_SEC
1609
|| row_upd_changes_ord_field_binary(node->row, node->index,
1611
return(row_upd_sec_index_entry(node, thr));
1617
/***********************************************************//**
1618
Marks the clustered index record deleted and inserts the updated version
1619
of the record to the index. This function should be used when the ordering
1620
fields of the clustered index record change. This should be quite rare in
1621
database applications.
1622
@return DB_SUCCESS if operation successfully completed, else error
1623
code or DB_LOCK_WAIT */
1626
row_upd_clust_rec_by_insert(
1627
/*========================*/
1628
upd_node_t* node, /*!< in/out: row update node */
1629
dict_index_t* index, /*!< in: clustered index of the record */
1630
que_thr_t* thr, /*!< in: query thread */
1631
ibool referenced,/*!< in: TRUE if index may be referenced in
1632
a foreign key constraint */
1633
mtr_t* mtr) /*!< in/out: mtr; gets committed here */
1635
mem_heap_t* heap = NULL;
1639
dict_table_t* table;
1642
ibool change_ownership = FALSE;
1645
ut_ad(dict_index_is_clust(index));
1647
trx = thr_get_trx(thr);
1648
table = node->table;
1650
btr_cur = btr_pcur_get_btr_cur(pcur);
1652
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1654
dict_index_t* node_index;
1655
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1657
rec_offs_init(offsets_);
1659
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1660
btr_cur, TRUE, thr, mtr);
1661
if (err != DB_SUCCESS) {
1666
/* Mark as not-owned the externally stored fields which the new
1667
row inherits from the delete marked record: purge should not
1668
free those externally stored fields even if the delete marked
1669
record is removed from the index tree, or updated. */
1671
rec = btr_cur_get_rec(btr_cur);
1672
node_index = dict_table_get_first_index(table);
1673
offsets = rec_get_offsets(rec, node_index, offsets_,
1674
ULINT_UNDEFINED, &heap);
1675
change_ownership = btr_cur_mark_extern_inherited_fields(
1676
btr_cur_get_page_zip(btr_cur), rec, node_index, offsets,
1679
/* NOTE that the following call loses
1680
the position of pcur ! */
1682
err = row_upd_check_references_constraints(
1683
node, pcur, table, node_index, offsets, thr, mtr);
1685
if (err != DB_SUCCESS) {
1689
if (UNIV_LIKELY_NULL(heap)) {
1690
mem_heap_free(heap);
1701
heap = mem_heap_create(500);
1703
node->state = UPD_NODE_INSERT_CLUSTERED;
1705
entry = row_build_index_entry(node->upd_row, node->upd_ext,
1709
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1711
if (change_ownership) {
1712
/* If we return from a lock wait, for example, we may have
1713
extern fields marked as not-owned in entry (marked in the
1714
if-branch above). We must unmark them, take the ownership
1717
btr_cur_unmark_dtuple_extern_fields(entry);
1719
/* We must mark non-updated extern fields in entry as
1720
inherited, so that a possible rollback will not free them. */
1722
btr_cur_mark_dtuple_inherited_extern(entry, node->update);
1725
err = row_ins_index_entry(index, entry,
1726
node->upd_ext ? node->upd_ext->n_ext : 0,
1728
mem_heap_free(heap);
1733
/***********************************************************//**
1734
Updates a clustered index record of a row when the ordering fields do
1736
@return DB_SUCCESS if operation successfully completed, else error
1737
code or DB_LOCK_WAIT */
1742
upd_node_t* node, /*!< in: row update node */
1743
dict_index_t* index, /*!< in: clustered index */
1744
que_thr_t* thr, /*!< in: query thread */
1745
mtr_t* mtr) /*!< in: mtr; gets committed here */
1747
mem_heap_t* heap = NULL;
1748
big_rec_t* big_rec = NULL;
1754
ut_ad(dict_index_is_clust(index));
1757
btr_cur = btr_pcur_get_btr_cur(pcur);
1759
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1760
dict_table_is_comp(index->table)));
1762
/* Try optimistic updating of the record, keeping changes within
1763
the page; we do not check locks because we assume the x-lock on the
1766
if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1767
err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1768
btr_cur, node->update,
1769
node->cmpl_info, thr, mtr);
1771
err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1772
btr_cur, node->update,
1773
node->cmpl_info, thr, mtr);
1778
if (UNIV_LIKELY(err == DB_SUCCESS)) {
1783
if (buf_LRU_buf_pool_running_out()) {
1785
return(DB_LOCK_TABLE_FULL);
1787
/* We may have to modify the tree structure: do a pessimistic descent
1788
down the index tree */
1792
/* NOTE: this transaction has an s-lock or x-lock on the record and
1793
therefore other transactions cannot modify the record when we have no
1794
latch on the page. In addition, we assume that other query threads of
1795
the same transaction do not modify the record in the meantime.
1796
Therefore we can assert that the restoration of the cursor succeeds. */
1798
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1800
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1801
dict_table_is_comp(index->table)));
1803
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1804
&heap, &big_rec, node->update,
1805
node->cmpl_info, thr, mtr);
1808
if (err == DB_SUCCESS && big_rec) {
1809
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1811
rec_offs_init(offsets_);
1815
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1816
rec = btr_cur_get_rec(btr_cur);
1817
err = btr_store_big_rec_extern_fields(
1818
index, btr_cur_get_block(btr_cur), rec,
1819
rec_get_offsets(rec, index, offsets_,
1820
ULINT_UNDEFINED, &heap),
1825
if (UNIV_LIKELY_NULL(heap)) {
1826
mem_heap_free(heap);
1830
dtuple_big_rec_free(big_rec);
1836
/***********************************************************//**
1837
Delete marks a clustered index record.
1838
@return DB_SUCCESS if operation successfully completed, else error code */
1841
row_upd_del_mark_clust_rec(
1842
/*=======================*/
1843
upd_node_t* node, /*!< in: row update node */
1844
dict_index_t* index, /*!< in: clustered index */
1845
ulint* offsets,/*!< in/out: rec_get_offsets() for the
1846
record under the cursor */
1847
que_thr_t* thr, /*!< in: query thread */
1849
/*!< in: TRUE if index may be referenced in
1850
a foreign key constraint */
1851
mtr_t* mtr) /*!< in: mtr; gets committed here */
1858
ut_ad(dict_index_is_clust(index));
1859
ut_ad(node->is_delete);
1862
btr_cur = btr_pcur_get_btr_cur(pcur);
1864
/* Store row because we have to build also the secondary index
1867
row_upd_store_row(node);
1869
/* Mark the clustered index record deleted; we do not have to check
1870
locks, because we assume that we have an x-lock on the record */
1872
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1873
btr_cur, TRUE, thr, mtr);
1874
if (err == DB_SUCCESS && referenced) {
1875
/* NOTE that the following call loses the position of pcur ! */
1877
err = row_upd_check_references_constraints(
1878
node, pcur, index->table, index, offsets, thr, mtr);
1886
/***********************************************************//**
1887
Updates the clustered index record.
1888
@return DB_SUCCESS if operation successfully completed, DB_LOCK_WAIT
1889
in case of a lock wait, else error code */
1894
upd_node_t* node, /*!< in: row update node */
1895
que_thr_t* thr) /*!< in: query thread */
1897
dict_index_t* index;
1904
mem_heap_t* heap = NULL;
1905
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1908
rec_offs_init(offsets_);
1910
index = dict_table_get_first_index(node->table);
1912
referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
1916
/* We have to restore the cursor to its position */
1921
/* If the restoration does not succeed, then the same
1922
transaction has deleted the record on which the cursor was,
1923
and that is an SQL error. If the restoration succeeds, it may
1924
still be that the same transaction has successively deleted
1925
and inserted a record with the same ordering fields, but in
1926
that case we know that the transaction has at least an
1927
implicit x-lock on the record. */
1929
ut_a(pcur->rel_pos == BTR_PCUR_ON);
1931
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1934
err = DB_RECORD_NOT_FOUND;
1941
/* If this is a row in SYS_INDEXES table of the data dictionary,
1942
then we have to free the file segments of the index tree associated
1945
if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
1947
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1953
success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
1964
rec = btr_pcur_get_rec(pcur);
1965
offsets = rec_get_offsets(rec, index, offsets_,
1966
ULINT_UNDEFINED, &heap);
1968
if (!node->has_clust_rec_x_lock) {
1969
err = lock_clust_rec_modify_check_and_lock(
1970
0, btr_pcur_get_block(pcur),
1971
rec, index, offsets, thr);
1972
if (err != DB_SUCCESS) {
1978
/* NOTE: the following function calls will also commit mtr */
1980
if (node->is_delete) {
1981
err = row_upd_del_mark_clust_rec(
1982
node, index, offsets, thr, referenced, mtr);
1984
if (err == DB_SUCCESS) {
1985
node->state = UPD_NODE_UPDATE_ALL_SEC;
1986
node->index = dict_table_get_next_index(index);
1989
if (UNIV_LIKELY_NULL(heap)) {
1990
mem_heap_free(heap);
1995
/* If the update is made for MySQL, we already have the update vector
1996
ready, else we have to do some evaluation: */
1998
if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
1999
/* Copy the necessary columns from clust_rec and calculate the
2000
new values to set */
2001
row_upd_copy_columns(rec, offsets,
2002
UT_LIST_GET_FIRST(node->columns));
2003
row_upd_eval_new_vals(node->update);
2006
if (UNIV_LIKELY_NULL(heap)) {
2007
mem_heap_free(heap);
2010
if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
2012
err = row_upd_clust_rec(node, index, thr, mtr);
2016
row_upd_store_row(node);
2018
if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
2020
/* Update causes an ordering field (ordering fields within
2021
the B-tree) of the clustered index record to change: perform
2022
the update by delete marking and inserting.
2024
TODO! What to do to the 'Halloween problem', where an update
2025
moves the record forward in index so that it is again
2026
updated when the cursor arrives there? Solution: the
2027
read operation must check the undo record undo number when
2028
choosing records to update. MySQL solves now the problem
2031
err = row_upd_clust_rec_by_insert(
2032
node, index, thr, referenced, mtr);
2034
if (err != DB_SUCCESS) {
2039
node->state = UPD_NODE_UPDATE_ALL_SEC;
2041
err = row_upd_clust_rec(node, index, thr, mtr);
2043
if (err != DB_SUCCESS) {
2048
node->state = UPD_NODE_UPDATE_SOME_SEC;
2051
node->index = dict_table_get_next_index(index);
2056
/***********************************************************//**
2057
Updates the affected index records of a row. When the control is transferred
2058
to this node, we assume that we have a persistent cursor which was on a
2059
record, and the position of the cursor is stored in the cursor.
2060
@return DB_SUCCESS if operation successfully completed, else error
2061
code or DB_LOCK_WAIT */
2066
upd_node_t* node, /*!< in: row update node */
2067
que_thr_t* thr) /*!< in: query thread */
2069
ulint err = DB_SUCCESS;
2073
if (UNIV_LIKELY(node->in_mysql_interface)) {
2075
/* We do not get the cmpl_info value from the MySQL
2076
interpreter: we must calculate it on the fly: */
2079
|| row_upd_changes_some_index_ord_field_binary(
2080
node->table, node->update)) {
2081
node->cmpl_info = 0;
2083
node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
2087
if (node->state == UPD_NODE_UPDATE_CLUSTERED
2088
|| node->state == UPD_NODE_INSERT_CLUSTERED) {
2091
err = row_upd_clust_step(node, thr);
2093
if (err != DB_SUCCESS) {
2099
if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
2104
while (node->index != NULL) {
2107
err = row_upd_sec_step(node, thr);
2109
if (err != DB_SUCCESS) {
2114
node->index = dict_table_get_next_index(node->index);
2118
if (err == DB_SUCCESS) {
2119
/* Do some cleanup */
2121
if (node->row != NULL) {
2124
node->upd_row = NULL;
2125
node->upd_ext = NULL;
2126
mem_heap_empty(node->heap);
2129
node->state = UPD_NODE_UPDATE_CLUSTERED;
2135
/***********************************************************//**
2136
Updates a row in a table. This is a high-level function used in SQL execution
2138
@return query thread to run next or NULL */
2143
que_thr_t* thr) /*!< in: query thread */
2146
sel_node_t* sel_node;
2148
ulint err = DB_SUCCESS;
2153
trx = thr_get_trx(thr);
2155
trx_start_if_not_started(trx);
2157
node = static_cast<upd_node_t *>(thr->run_node);
2159
sel_node = node->select;
2161
parent = que_node_get_parent(node);
2163
ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2165
if (thr->prev_node == parent) {
2166
node->state = UPD_NODE_SET_IX_LOCK;
2169
if (node->state == UPD_NODE_SET_IX_LOCK) {
2171
if (!node->has_clust_rec_x_lock) {
2172
/* It may be that the current session has not yet
2173
started its transaction, or it has been committed: */
2175
err = lock_table(0, node->table, LOCK_IX, thr);
2177
if (err != DB_SUCCESS) {
2179
goto error_handling;
2183
node->state = UPD_NODE_UPDATE_CLUSTERED;
2185
if (node->searched_update) {
2186
/* Reset the cursor */
2187
sel_node->state = SEL_NODE_OPEN;
2189
/* Fetch a row to update */
2191
thr->run_node = sel_node;
2197
/* sel_node is NULL if we are in the MySQL interface */
2199
if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
2201
if (!node->searched_update) {
2202
/* An explicit cursor should be positioned on a row
2209
goto error_handling;
2212
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2214
/* No more rows to update, or the select node performed the
2215
updates directly in-place */
2217
thr->run_node = parent;
2222
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2224
err = row_upd(node, thr);
2227
trx->error_state = err;
2229
if (err != DB_SUCCESS) {
2233
/* DO THE TRIGGER ACTIONS HERE */
2235
if (node->searched_update) {
2236
/* Fetch next row to update */
2238
thr->run_node = sel_node;
2240
/* It was an explicit cursor update */
2242
thr->run_node = parent;
2245
node->state = UPD_NODE_UPDATE_CLUSTERED;
2249
#endif /* !UNIV_HOTBACKUP */