1 /******************************************************
6 Created 12/27/1996 Heikki Tuuri
7 *******************************************************/
9 #include "my_global.h" /* HAVE_* */
10 #include "m_string.h" /* for my_sys.h */
11 #include "my_sys.h" /* DEBUG_SYNC_C */
18 #include "dict0dict.h"
19 #include "dict0boot.h"
20 #include "dict0crea.h"
21 #include "mach0data.h"
30 #include "lock0lock.h"
33 #include "eval0eval.h"
37 /* What kind of latch and lock can we assume when the control comes to
38 -------------------------------------------------------------------
41 Efficiency of massive updates would require keeping an x-latch on a
42 clustered index page through many updates, and not setting an explicit
43 x-lock on clustered index records, as they anyway will get an implicit
44 x-lock when they are updated. A problem is that the read nodes in the
45 graph should know that they must keep the latch when passing the control
46 up to the update node, and not set any record lock on the record which
47 will be updated. Another problem occurs if the execution is stopped,
48 as the kernel switches to another query thread, or the transaction must
49 wait for a lock. Then we should be able to release the latch and, maybe,
50 acquire an explicit x-lock on the record.
51 Because this seems too complicated, we conclude that the less
52 efficient solution of releasing all the latches when the control is
53 transferred to another node, and acquiring explicit x-locks, is better. */
55 /* How is a delete performed? If there is a delete without an
56 explicit cursor, i.e., a searched delete, there are at least
57 two different situations:
58 the implicit select cursor may run on (1) the clustered index or
59 on (2) a secondary index. The delete is performed by setting
60 the delete bit in the record and substituting the id of the
61 deleting transaction for the original trx id, and substituting a
62 new roll ptr for previous roll ptr. The old trx id and roll ptr
63 are saved in the undo log record. Thus, no physical changes occur
64 in the index tree structure at the time of the delete. Only
65 when the undo log is purged, the index records will be physically
66 deleted from the index trees.
68 The query graph executing a searched delete would consist of
69 a delete node which has as a subtree a select subgraph.
70 The select subgraph should return a (persistent) cursor
71 in the clustered index, placed on page which is x-latched.
72 The delete node should look for all secondary index records for
73 this clustered index entry and mark them as deleted. When is
74 the x-latch freed? The most efficient way for performing a
75 searched delete is obviously to keep the x-latch for several
76 steps of query graph execution. */
78 /***************************************************************
79 Checks if an update vector changes some of the first ordering fields of an
80 index record. This is only used in foreign key checks and we can assume
81 that index does not contain column prefixes. */
84 row_upd_changes_first_fields_binary(
85 /*================================*/
86 /* out: TRUE if changes */
87 dtuple_t
* entry
, /* in: old value of index entry */
88 dict_index_t
* index
, /* in: index of entry */
89 upd_t
* update
, /* in: update vector for the row */
90 ulint n
); /* in: how many first fields to check */
93 /*************************************************************************
94 Checks if index currently is mentioned as a referenced index in a foreign
98 row_upd_index_is_referenced(
99 /*========================*/
100 /* out: TRUE if referenced; NOTE that since
101 we do not hold dict_operation_lock
102 when leaving the function, it may be that
103 the referencing table has been dropped when
104 we leave this function: this function is only
105 for heuristic use! */
106 dict_index_t
* index
, /* in: index */
107 trx_t
* trx
) /* in: transaction */
109 dict_table_t
* table
= index
->table
;
110 dict_foreign_t
* foreign
;
111 ibool froze_data_dict
= FALSE
;
113 if (!UT_LIST_GET_FIRST(table
->referenced_list
)) {
118 if (trx
->dict_operation_lock_mode
== 0) {
119 row_mysql_freeze_data_dictionary(trx
);
120 froze_data_dict
= TRUE
;
123 foreign
= UT_LIST_GET_FIRST(table
->referenced_list
);
126 if (foreign
->referenced_index
== index
) {
128 if (froze_data_dict
) {
129 row_mysql_unfreeze_data_dictionary(trx
);
135 foreign
= UT_LIST_GET_NEXT(referenced_list
, foreign
);
138 if (froze_data_dict
) {
139 row_mysql_unfreeze_data_dictionary(trx
);
145 /*************************************************************************
146 Checks if possible foreign key constraints hold after a delete of the record
147 under pcur. NOTE that this function will temporarily commit mtr and lose the
151 row_upd_check_references_constraints(
152 /*=================================*/
153 /* out: DB_SUCCESS or an error code */
154 upd_node_t
* node
, /* in: row update node */
155 btr_pcur_t
* pcur
, /* in: cursor positioned on a record; NOTE: the
156 cursor position is lost in this function! */
157 dict_table_t
* table
, /* in: table in question */
158 dict_index_t
* index
, /* in: index of the cursor */
159 que_thr_t
* thr
, /* in: query thread */
160 mtr_t
* mtr
) /* in: mtr */
162 dict_foreign_t
* foreign
;
168 ibool got_s_lock
= FALSE
;
170 if (UT_LIST_GET_FIRST(table
->referenced_list
) == NULL
) {
175 trx
= thr_get_trx(thr
);
177 rec
= btr_pcur_get_rec(pcur
);
179 heap
= mem_heap_create(500);
181 entry
= row_rec_to_index_entry(ROW_COPY_DATA
, index
, rec
, heap
);
187 if (trx
->dict_operation_lock_mode
== 0) {
190 row_mysql_freeze_data_dictionary(trx
);
193 foreign
= UT_LIST_GET_FIRST(table
->referenced_list
);
196 /* Note that we may have an update which updates the index
197 record, but does NOT update the first fields which are
198 referenced in a foreign key constraint. Then the update does
199 NOT break the constraint. */
201 if (foreign
->referenced_index
== index
203 || row_upd_changes_first_fields_binary(
204 entry
, index
, node
->update
,
205 foreign
->n_fields
))) {
207 if (foreign
->foreign_table
== NULL
) {
208 dict_table_get(foreign
->foreign_table_name
,
212 if (foreign
->foreign_table
) {
213 mutex_enter(&(dict_sys
->mutex
));
215 (foreign
->foreign_table
216 ->n_foreign_key_checks_running
)++;
218 mutex_exit(&(dict_sys
->mutex
));
221 /* NOTE that if the thread ends up waiting for a lock
222 we will release dict_operation_lock temporarily!
223 But the counter on the table protects 'foreign' from
224 being dropped while the check is running. */
226 err
= row_ins_check_foreign_constraint(
227 FALSE
, foreign
, table
, entry
, thr
);
229 if (foreign
->foreign_table
) {
230 mutex_enter(&(dict_sys
->mutex
));
232 ut_a(foreign
->foreign_table
233 ->n_foreign_key_checks_running
> 0);
235 (foreign
->foreign_table
236 ->n_foreign_key_checks_running
)--;
238 mutex_exit(&(dict_sys
->mutex
));
241 if (err
!= DB_SUCCESS
) {
243 row_mysql_unfreeze_data_dictionary(
253 foreign
= UT_LIST_GET_NEXT(referenced_list
, foreign
);
257 row_mysql_unfreeze_data_dictionary(trx
);
265 /*************************************************************************
266 Creates an update node for a query graph. */
271 /* out, own: update node */
272 mem_heap_t
* heap
) /* in: mem heap where created */
276 node
= mem_heap_alloc(heap
, sizeof(upd_node_t
));
277 node
->common
.type
= QUE_NODE_UPDATE
;
279 node
->state
= UPD_NODE_UPDATE_CLUSTERED
;
280 node
->select_will_do_update
= FALSE
;
281 node
->in_mysql_interface
= FALSE
;
284 node
->ext_vec
= NULL
;
288 node
->foreign
= NULL
;
289 node
->cascade_heap
= NULL
;
290 node
->cascade_node
= NULL
;
294 node
->heap
= mem_heap_create(128);
295 node
->magic_n
= UPD_NODE_MAGIC_N
;
302 /*************************************************************************
303 Updates the trx id and roll ptr field in a clustered index record in database
307 row_upd_rec_sys_fields_in_recovery(
308 /*===============================*/
309 rec_t
* rec
, /* in: record */
310 const ulint
* offsets
,/* in: array returned by rec_get_offsets() */
311 ulint pos
, /* in: TRX_ID position in rec */
312 dulint trx_id
, /* in: transaction id */
313 dulint roll_ptr
)/* in: roll ptr of the undo log record */
318 field
= rec_get_nth_field(rec
, offsets
, pos
, &len
);
319 ut_ad(len
== DATA_TRX_ID_LEN
);
320 trx_write_trx_id(field
, trx_id
);
322 field
= rec_get_nth_field(rec
, offsets
, pos
+ 1, &len
);
323 ut_ad(len
== DATA_ROLL_PTR_LEN
);
324 trx_write_roll_ptr(field
, roll_ptr
);
327 /*************************************************************************
328 Sets the trx id or roll ptr field of a clustered index entry. */
331 row_upd_index_entry_sys_field(
332 /*==========================*/
333 dtuple_t
* entry
, /* in: index entry, where the memory buffers
334 for sys fields are already allocated:
335 the function just copies the new values to
337 dict_index_t
* index
, /* in: clustered index */
338 ulint type
, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
339 dulint val
) /* in: value to write */
345 ut_ad(index
->type
& DICT_CLUSTERED
);
347 pos
= dict_index_get_sys_col_pos(index
, type
);
349 dfield
= dtuple_get_nth_field(entry
, pos
);
350 field
= dfield_get_data(dfield
);
352 if (type
== DATA_TRX_ID
) {
353 trx_write_trx_id(field
, val
);
355 ut_ad(type
== DATA_ROLL_PTR
);
356 trx_write_roll_ptr(field
, val
);
360 /***************************************************************
361 Returns TRUE if row update changes size of some field in index or if some
362 field to be updated is stored externally in rec or update. */
365 row_upd_changes_field_size_or_external(
366 /*===================================*/
367 /* out: TRUE if the update changes the size of
368 some field in index or the field is external
370 dict_index_t
* index
, /* in: index */
371 const ulint
* offsets
,/* in: rec_get_offsets(rec, index) */
372 upd_t
* update
) /* in: update vector */
374 upd_field_t
* upd_field
;
381 ut_ad(rec_offs_validate(NULL
, index
, offsets
));
382 n_fields
= upd_get_n_fields(update
);
384 for (i
= 0; i
< n_fields
; i
++) {
385 upd_field
= upd_get_nth_field(update
, i
);
387 new_val
= &(upd_field
->new_val
);
388 new_len
= new_val
->len
;
390 if (new_len
== UNIV_SQL_NULL
&& !rec_offs_comp(offsets
)) {
391 /* A bug fixed on Dec 31st, 2004: we looked at the
392 SQL NULL size from the wrong field! We may backport
393 this fix also to 4.0. The merge to 5.0 will be made
394 manually immediately after we commit this to 4.1. */
396 new_len
= dict_col_get_sql_null_size(
397 dict_index_get_nth_col(index
,
398 upd_field
->field_no
));
401 old_len
= rec_offs_nth_size(offsets
, upd_field
->field_no
);
403 if (rec_offs_comp(offsets
)
404 && rec_offs_nth_sql_null(offsets
,
405 upd_field
->field_no
)) {
406 /* Note that in the compact table format, for a
407 variable length field, an SQL NULL will use zero
408 bytes in the offset array at the start of the physical
409 record, but a zero-length value (empty string) will
410 use one byte! Thus, we cannot use update-in-place
411 if we update an SQL NULL varchar to an empty string! */
413 old_len
= UNIV_SQL_NULL
;
416 if (old_len
!= new_len
) {
421 if (rec_offs_nth_extern(offsets
, upd_field
->field_no
)) {
426 if (upd_field
->extern_storage
) {
435 /***************************************************************
436 Replaces the new column values stored in the update vector to the
437 record given. No field size changes are allowed. This function is
438 usually invoked on a clustered index. The only use case for a
439 secondary index is row_ins_sec_index_entry_by_modify() or its
440 counterpart in ibuf_insert_to_index_page(). */
443 row_upd_rec_in_place(
444 /*=================*/
445 rec_t
* rec
, /* in/out: record where replaced */
446 const ulint
* offsets
,/* in: array returned by rec_get_offsets() */
447 upd_t
* update
) /* in: update vector */
449 upd_field_t
* upd_field
;
454 ut_ad(rec_offs_validate(rec
, NULL
, offsets
));
456 rec_set_info_bits(rec
, rec_offs_comp(offsets
), update
->info_bits
);
458 n_fields
= upd_get_n_fields(update
);
460 for (i
= 0; i
< n_fields
; i
++) {
461 upd_field
= upd_get_nth_field(update
, i
);
462 new_val
= &(upd_field
->new_val
);
464 rec_set_nth_field(rec
, offsets
, upd_field
->field_no
,
465 dfield_get_data(new_val
),
466 dfield_get_len(new_val
));
470 /*************************************************************************
471 Writes into the redo log the values of trx id and roll ptr and enough info
472 to determine their positions within a clustered index record. */
475 row_upd_write_sys_vals_to_log(
476 /*==========================*/
477 /* out: new pointer to mlog */
478 dict_index_t
* index
, /* in: clustered index */
479 trx_t
* trx
, /* in: transaction */
480 dulint roll_ptr
,/* in: roll ptr of the undo log record */
481 byte
* log_ptr
,/* pointer to a buffer of size > 20 opened
483 mtr_t
* mtr
__attribute__((unused
))) /* in: mtr */
485 ut_ad(index
->type
& DICT_CLUSTERED
);
488 log_ptr
+= mach_write_compressed(log_ptr
,
489 dict_index_get_sys_col_pos(
490 index
, DATA_TRX_ID
));
492 trx_write_roll_ptr(log_ptr
, roll_ptr
);
493 log_ptr
+= DATA_ROLL_PTR_LEN
;
495 log_ptr
+= mach_dulint_write_compressed(log_ptr
, trx
->id
);
500 /*************************************************************************
501 Parses the log data of system field values. */
504 row_upd_parse_sys_vals(
505 /*===================*/
506 /* out: log data end or NULL */
507 byte
* ptr
, /* in: buffer */
508 byte
* end_ptr
,/* in: buffer end */
509 ulint
* pos
, /* out: TRX_ID position in record */
510 dulint
* trx_id
, /* out: trx id */
511 dulint
* roll_ptr
)/* out: roll ptr */
513 ptr
= mach_parse_compressed(ptr
, end_ptr
, pos
);
520 if (end_ptr
< ptr
+ DATA_ROLL_PTR_LEN
) {
525 *roll_ptr
= trx_read_roll_ptr(ptr
);
526 ptr
+= DATA_ROLL_PTR_LEN
;
528 ptr
= mach_dulint_parse_compressed(ptr
, end_ptr
, trx_id
);
533 /***************************************************************
534 Writes to the redo log the new values of the fields occurring in the index. */
537 row_upd_index_write_log(
538 /*====================*/
539 upd_t
* update
, /* in: update vector */
540 byte
* log_ptr
,/* in: pointer to mlog buffer: must contain at least
541 MLOG_BUF_MARGIN bytes of free space; the buffer is
542 closed within this function */
543 mtr_t
* mtr
) /* in: mtr into whose log to write */
545 upd_field_t
* upd_field
;
552 n_fields
= upd_get_n_fields(update
);
554 buf_end
= log_ptr
+ MLOG_BUF_MARGIN
;
556 mach_write_to_1(log_ptr
, update
->info_bits
);
558 log_ptr
+= mach_write_compressed(log_ptr
, n_fields
);
560 for (i
= 0; i
< n_fields
; i
++) {
562 #if MLOG_BUF_MARGIN <= 30
563 # error "MLOG_BUF_MARGIN <= 30"
566 if (log_ptr
+ 30 > buf_end
) {
567 mlog_close(mtr
, log_ptr
);
569 log_ptr
= mlog_open(mtr
, MLOG_BUF_MARGIN
);
570 buf_end
= log_ptr
+ MLOG_BUF_MARGIN
;
573 upd_field
= upd_get_nth_field(update
, i
);
575 new_val
= &(upd_field
->new_val
);
579 log_ptr
+= mach_write_compressed(log_ptr
, upd_field
->field_no
);
580 log_ptr
+= mach_write_compressed(log_ptr
, len
);
582 if (len
!= UNIV_SQL_NULL
) {
583 if (log_ptr
+ len
< buf_end
) {
584 ut_memcpy(log_ptr
, new_val
->data
, len
);
588 mlog_close(mtr
, log_ptr
);
590 mlog_catenate_string(mtr
, new_val
->data
, len
);
592 log_ptr
= mlog_open(mtr
, MLOG_BUF_MARGIN
);
593 buf_end
= log_ptr
+ MLOG_BUF_MARGIN
;
598 mlog_close(mtr
, log_ptr
);
601 /*************************************************************************
602 Parses the log data written by row_upd_index_write_log. */
607 /* out: log data end or NULL */
608 byte
* ptr
, /* in: buffer */
609 byte
* end_ptr
,/* in: buffer end */
610 mem_heap_t
* heap
, /* in: memory heap where update vector is
612 upd_t
** update_out
)/* out: update vector */
615 upd_field_t
* upd_field
;
623 if (end_ptr
< ptr
+ 1) {
628 info_bits
= mach_read_from_1(ptr
);
630 ptr
= mach_parse_compressed(ptr
, end_ptr
, &n_fields
);
637 update
= upd_create(n_fields
, heap
);
638 update
->info_bits
= info_bits
;
640 for (i
= 0; i
< n_fields
; i
++) {
641 upd_field
= upd_get_nth_field(update
, i
);
642 new_val
= &(upd_field
->new_val
);
644 ptr
= mach_parse_compressed(ptr
, end_ptr
,
645 &(upd_field
->field_no
));
651 ptr
= mach_parse_compressed(ptr
, end_ptr
, &len
);
660 if (len
!= UNIV_SQL_NULL
) {
662 if (end_ptr
< ptr
+ len
) {
666 buf
= mem_heap_alloc(heap
, len
);
667 ut_memcpy(buf
, ptr
, len
);
676 *update_out
= update
;
681 /*******************************************************************
682 Returns TRUE if ext_vec contains i. */
685 upd_ext_vec_contains(
686 /*=================*/
687 /* out: TRUE if i is in ext_vec */
688 ulint
* ext_vec
, /* in: array of indexes or NULL */
689 ulint n_ext_vec
, /* in: number of numbers in ext_vec */
690 ulint i
) /* in: a number */
694 if (ext_vec
== NULL
) {
699 for (j
= 0; j
< n_ext_vec
; j
++) {
700 if (ext_vec
[j
] == i
) {
709 /*******************************************************************
710 Builds an update vector from those fields which in a secondary index entry
711 differ from a record that has the equal ordering fields. NOTE: we compare
712 the fields as binary strings! */
715 row_upd_build_sec_rec_difference_binary(
716 /*====================================*/
717 /* out, own: update vector of differing
719 dict_index_t
* index
, /* in: index */
720 dtuple_t
* entry
, /* in: entry to insert */
721 rec_t
* rec
, /* in: secondary index record */
722 trx_t
* trx
, /* in: transaction */
723 mem_heap_t
* heap
) /* in: memory heap from which allocated */
725 upd_field_t
* upd_field
;
732 ulint offsets_
[REC_OFFS_SMALL_SIZE
];
733 const ulint
* offsets
;
734 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
736 /* This function is used only for a secondary index */
737 ut_a(0 == (index
->type
& DICT_CLUSTERED
));
739 update
= upd_create(dtuple_get_n_fields(entry
), heap
);
742 offsets
= rec_get_offsets(rec
, index
, offsets_
,
743 ULINT_UNDEFINED
, &heap
);
745 for (i
= 0; i
< dtuple_get_n_fields(entry
); i
++) {
747 data
= rec_get_nth_field(rec
, offsets
, i
, &len
);
749 dfield
= dtuple_get_nth_field(entry
, i
);
751 /* NOTE that it may be that len != dfield_get_len(dfield) if we
752 are updating in a character set and collation where strings of
753 different length can be equal in an alphabetical comparison,
754 and also in the case where we have a column prefix index
755 and the last characters in the index field are spaces; the
756 latter case probably caused the assertion failures reported at
757 row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
759 /* NOTE: we compare the fields as binary strings!
762 if (!dfield_data_is_binary_equal(dfield
, len
, data
)) {
764 upd_field
= upd_get_nth_field(update
, n_diff
);
766 dfield_copy(&(upd_field
->new_val
), dfield
);
768 upd_field_set_field_no(upd_field
, i
, index
, trx
);
770 upd_field
->extern_storage
= FALSE
;
776 update
->n_fields
= n_diff
;
781 /*******************************************************************
782 Builds an update vector from those fields, excluding the roll ptr and
783 trx id fields, which in an index entry differ from a record that has
784 the equal ordering fields. NOTE: we compare the fields as binary strings! */
787 row_upd_build_difference_binary(
788 /*============================*/
789 /* out, own: update vector of differing
790 fields, excluding roll ptr and trx id */
791 dict_index_t
* index
, /* in: clustered index */
792 dtuple_t
* entry
, /* in: entry to insert */
793 ulint
* ext_vec
,/* in: array containing field numbers of
794 externally stored fields in entry, or NULL */
795 ulint n_ext_vec
,/* in: number of fields in ext_vec */
796 rec_t
* rec
, /* in: clustered index record */
797 trx_t
* trx
, /* in: transaction */
798 mem_heap_t
* heap
) /* in: memory heap from which allocated */
800 upd_field_t
* upd_field
;
810 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
811 const ulint
* offsets
;
812 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
814 /* This function is used only for a clustered index */
815 ut_a(index
->type
& DICT_CLUSTERED
);
817 update
= upd_create(dtuple_get_n_fields(entry
), heap
);
821 roll_ptr_pos
= dict_index_get_sys_col_pos(index
, DATA_ROLL_PTR
);
822 trx_id_pos
= dict_index_get_sys_col_pos(index
, DATA_TRX_ID
);
824 offsets
= rec_get_offsets(rec
, index
, offsets_
,
825 ULINT_UNDEFINED
, &heap
);
827 for (i
= 0; i
< dtuple_get_n_fields(entry
); i
++) {
829 data
= rec_get_nth_field(rec
, offsets
, i
, &len
);
831 dfield
= dtuple_get_nth_field(entry
, i
);
833 /* NOTE: we compare the fields as binary strings!
836 if (i
== trx_id_pos
|| i
== roll_ptr_pos
) {
841 extern_bit
= upd_ext_vec_contains(ext_vec
, n_ext_vec
, i
);
843 if (UNIV_UNLIKELY(extern_bit
844 == (ibool
)!rec_offs_nth_extern(offsets
, i
))
845 || !dfield_data_is_binary_equal(dfield
, len
, data
)) {
847 upd_field
= upd_get_nth_field(update
, n_diff
);
849 dfield_copy(&(upd_field
->new_val
), dfield
);
851 upd_field_set_field_no(upd_field
, i
, index
, trx
);
853 upd_field
->extern_storage
= extern_bit
;
861 update
->n_fields
= n_diff
;
866 /***************************************************************
867 Replaces the new column values stored in the update vector to the index entry
871 row_upd_index_replace_new_col_vals_index_pos(
872 /*=========================================*/
873 dtuple_t
* entry
, /* in/out: index entry where replaced */
874 dict_index_t
* index
, /* in: index; NOTE that this may also be a
875 non-clustered index */
876 upd_t
* update
, /* in: an update vector built for the index so
877 that the field number in an upd_field is the
880 /* in: if TRUE, limit the replacement to
881 ordering fields of index; note that this
882 does not work for non-clustered indexes. */
883 mem_heap_t
* heap
) /* in: memory heap to which we allocate and
884 copy the new values, set this as NULL if you
885 do not want allocation */
888 upd_field_t
* upd_field
;
897 dtuple_set_info_bits(entry
, update
->info_bits
);
900 n_fields
= dict_index_get_n_unique(index
);
902 n_fields
= dict_index_get_n_fields(index
);
905 for (j
= 0; j
< n_fields
; j
++) {
907 field
= dict_index_get_nth_field(index
, j
);
909 for (i
= 0; i
< upd_get_n_fields(update
); i
++) {
911 upd_field
= upd_get_nth_field(update
, i
);
913 if (upd_field
->field_no
== j
) {
915 dfield
= dtuple_get_nth_field(entry
, j
);
917 new_val
= &(upd_field
->new_val
);
919 dfield_set_data(dfield
, new_val
->data
,
921 if (heap
&& new_val
->len
!= UNIV_SQL_NULL
) {
922 dfield
->data
= mem_heap_alloc(
924 ut_memcpy(dfield
->data
, new_val
->data
,
928 if (field
->prefix_len
> 0
929 && new_val
->len
!= UNIV_SQL_NULL
) {
931 const dict_col_t
* col
932 = dict_field_get_col(field
);
935 = dtype_get_at_most_n_mbchars(
948 /***************************************************************
949 Replaces the new column values stored in the update vector to the index entry
953 row_upd_index_replace_new_col_vals(
954 /*===============================*/
955 dtuple_t
* entry
, /* in/out: index entry where replaced */
956 dict_index_t
* index
, /* in: index; NOTE that this may also be a
957 non-clustered index */
958 upd_t
* update
, /* in: an update vector built for the
959 CLUSTERED index so that the field number in
960 an upd_field is the clustered index position */
961 mem_heap_t
* heap
) /* in: memory heap to which we allocate and
962 copy the new values, set this as NULL if you
963 do not want allocation */
965 upd_field_t
* upd_field
;
970 dict_index_t
* clust_index
;
974 clust_index
= dict_table_get_first_index(index
->table
);
976 dtuple_set_info_bits(entry
, update
->info_bits
);
978 for (j
= 0; j
< dict_index_get_n_fields(index
); j
++) {
981 dict_field_t
* field
= dict_index_get_nth_field(index
, j
);
983 clust_pos
= dict_col_get_clust_pos(field
->col
, clust_index
);
985 for (i
= 0; i
< upd_get_n_fields(update
); i
++) {
987 upd_field
= upd_get_nth_field(update
, i
);
989 if (upd_field
->field_no
== clust_pos
) {
991 dfield
= dtuple_get_nth_field(entry
, j
);
993 new_val
= &(upd_field
->new_val
);
995 dfield_set_data(dfield
, new_val
->data
,
997 if (heap
&& new_val
->len
!= UNIV_SQL_NULL
) {
998 dfield
->data
= mem_heap_alloc(
1000 ut_memcpy(dfield
->data
, new_val
->data
,
1004 if (field
->prefix_len
> 0
1005 && new_val
->len
!= UNIV_SQL_NULL
) {
1007 const dict_col_t
* col
1008 = dict_field_get_col(field
);
1011 = dtype_get_at_most_n_mbchars(
1024 /***************************************************************
1025 Checks if an update vector changes an ordering field of an index record.
1026 This function is fast if the update vector is short or the number of ordering
1027 fields in the index is small. Otherwise, this can be quadratic.
1028 NOTE: we compare the fields as binary strings! */
1031 row_upd_changes_ord_field_binary(
1032 /*=============================*/
1033 /* out: TRUE if update vector changes
1034 an ordering field in the index record;
1035 NOTE: the fields are compared as binary
1037 dtuple_t
* row
, /* in: old value of row, or NULL if the
1038 row and the data values in update are not
1039 known when this function is called, e.g., at
1041 dict_index_t
* index
, /* in: index of the record */
1042 upd_t
* update
) /* in: update vector for the row; NOTE: the
1043 field numbers in this MUST be clustered index
1049 dict_index_t
* clust_index
;
1051 ut_ad(update
&& index
);
1053 n_unique
= dict_index_get_n_unique(index
);
1054 n_upd_fields
= upd_get_n_fields(update
);
1056 clust_index
= dict_table_get_first_index(index
->table
);
1058 for (i
= 0; i
< n_unique
; i
++) {
1060 const dict_field_t
* ind_field
;
1061 const dict_col_t
* col
;
1065 ind_field
= dict_index_get_nth_field(index
, i
);
1066 col
= dict_field_get_col(ind_field
);
1067 col_pos
= dict_col_get_clust_pos(col
, clust_index
);
1068 col_no
= dict_col_get_no(col
);
1070 for (j
= 0; j
< n_upd_fields
; j
++) {
1072 upd_field_t
* upd_field
1073 = upd_get_nth_field(update
, j
);
1075 /* Note that if the index field is a column prefix
1076 then it may be that row does not contain an externally
1077 stored part of the column value, and we cannot compare
1080 if (col_pos
== upd_field
->field_no
1082 || ind_field
->prefix_len
> 0
1083 || !dfield_datas_are_binary_equal(
1084 dtuple_get_nth_field(row
, col_no
),
1085 &(upd_field
->new_val
)))) {
1095 /***************************************************************
1096 Checks if an update vector changes an ordering field of an index record.
1097 NOTE: we compare the fields as binary strings! */
1100 row_upd_changes_some_index_ord_field_binary(
1101 /*========================================*/
1102 /* out: TRUE if update vector may change
1103 an ordering field in an index record */
1104 dict_table_t
* table
, /* in: table */
1105 upd_t
* update
) /* in: update vector for the row */
1107 upd_field_t
* upd_field
;
1108 dict_index_t
* index
;
1111 index
= dict_table_get_first_index(table
);
1113 for (i
= 0; i
< upd_get_n_fields(update
); i
++) {
1115 upd_field
= upd_get_nth_field(update
, i
);
1117 if (dict_field_get_col(dict_index_get_nth_field(
1118 index
, upd_field
->field_no
))
1128 /***************************************************************
1129 Checks if an update vector changes some of the first ordering fields of an
1130 index record. This is only used in foreign key checks and we can assume
1131 that index does not contain column prefixes. */
1134 row_upd_changes_first_fields_binary(
1135 /*================================*/
1136 /* out: TRUE if changes */
1137 dtuple_t
* entry
, /* in: index entry */
1138 dict_index_t
* index
, /* in: index of entry */
1139 upd_t
* update
, /* in: update vector for the row */
1140 ulint n
) /* in: how many first fields to check */
1144 dict_index_t
* clust_index
;
1146 ut_ad(update
&& index
);
1147 ut_ad(n
<= dict_index_get_n_fields(index
));
1149 n_upd_fields
= upd_get_n_fields(update
);
1150 clust_index
= dict_table_get_first_index(index
->table
);
1152 for (i
= 0; i
< n
; i
++) {
1154 const dict_field_t
* ind_field
;
1155 const dict_col_t
* col
;
1158 ind_field
= dict_index_get_nth_field(index
, i
);
1159 col
= dict_field_get_col(ind_field
);
1160 col_pos
= dict_col_get_clust_pos(col
, clust_index
);
1162 ut_a(ind_field
->prefix_len
== 0);
1164 for (j
= 0; j
< n_upd_fields
; j
++) {
1166 upd_field_t
* upd_field
1167 = upd_get_nth_field(update
, j
);
1169 if (col_pos
== upd_field
->field_no
1170 && !dfield_datas_are_binary_equal(
1171 dtuple_get_nth_field(entry
, i
),
1172 &(upd_field
->new_val
))) {
1182 /*************************************************************************
1183 Copies the column values from a record. */
1186 row_upd_copy_columns(
1187 /*=================*/
1188 rec_t
* rec
, /* in: record in a clustered index */
1189 const ulint
* offsets
,/* in: array returned by rec_get_offsets() */
1190 sym_node_t
* column
) /* in: first column in a column list, or
1197 data
= rec_get_nth_field(rec
, offsets
,
1198 column
->field_nos
[SYM_CLUST_FIELD_NO
],
1200 eval_node_copy_and_alloc_val(column
, data
, len
);
1202 column
= UT_LIST_GET_NEXT(col_var_list
, column
);
1206 /*************************************************************************
1207 Calculates the new values for fields to update. Note that row_upd_copy_columns
1208 must have been called first. */
1211 row_upd_eval_new_vals(
1212 /*==================*/
1213 upd_t
* update
) /* in: update vector */
1216 upd_field_t
* upd_field
;
1220 n_fields
= upd_get_n_fields(update
);
1222 for (i
= 0; i
< n_fields
; i
++) {
1223 upd_field
= upd_get_nth_field(update
, i
);
1225 exp
= upd_field
->exp
;
1229 dfield_copy_data(&(upd_field
->new_val
), que_node_get_val(exp
));
1233 /***************************************************************
1234 Stores to the heap the row on which the node->pcur is positioned. */
1239 upd_node_t
* node
) /* in: row update node */
1241 dict_index_t
* clust_index
;
1244 mem_heap_t
* heap
= NULL
;
1245 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
1246 const ulint
* offsets
;
1247 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
1249 ut_ad(node
->pcur
->latch_mode
!= BTR_NO_LATCHES
);
1251 if (node
->row
!= NULL
) {
1252 mem_heap_empty(node
->heap
);
1256 clust_index
= dict_table_get_first_index(node
->table
);
1258 rec
= btr_pcur_get_rec(node
->pcur
);
1260 offsets
= rec_get_offsets(rec
, clust_index
, offsets_
,
1261 ULINT_UNDEFINED
, &heap
);
1262 node
->row
= row_build(ROW_COPY_DATA
, clust_index
, rec
, offsets
,
1264 node
->ext_vec
= mem_heap_alloc(node
->heap
, sizeof(ulint
)
1265 * rec_offs_n_fields(offsets
));
1266 if (node
->is_delete
) {
1269 update
= node
->update
;
1272 node
->n_ext_vec
= btr_push_update_extern_fields(node
->ext_vec
,
1274 if (UNIV_LIKELY_NULL(heap
)) {
1275 mem_heap_free(heap
);
1279 /***************************************************************
1280 Updates a secondary index entry of a row. */
1283 row_upd_sec_index_entry(
1284 /*====================*/
1285 /* out: DB_SUCCESS if operation successfully
1286 completed, else error code or DB_LOCK_WAIT */
1287 upd_node_t
* node
, /* in: row update node */
1288 que_thr_t
* thr
) /* in: query thread */
1292 dict_index_t
* index
;
1298 ulint err
= DB_SUCCESS
;
1300 trx_t
* trx
= thr_get_trx(thr
);
1302 index
= node
->index
;
1304 check_ref
= row_upd_index_is_referenced(index
, trx
);
1306 heap
= mem_heap_create(1024);
1308 /* Build old index entry */
1309 entry
= row_build_index_entry(node
->row
, index
, heap
);
1314 found
= row_search_index_entry(index
, entry
, BTR_MODIFY_LEAF
, &pcur
,
1316 btr_cur
= btr_pcur_get_btr_cur(&pcur
);
1318 rec
= btr_cur_get_rec(btr_cur
);
1320 if (UNIV_UNLIKELY(!found
)) {
1321 fputs("InnoDB: error in sec index entry update in\n"
1322 "InnoDB: ", stderr
);
1323 dict_index_name_print(stderr
, trx
, index
);
1325 "InnoDB: tuple ", stderr
);
1326 dtuple_print(stderr
, entry
);
1328 "InnoDB: record ", stderr
);
1329 rec_print(stderr
, rec
, index
);
1332 trx_print(stderr
, trx
, 0);
1335 "InnoDB: Submit a detailed bug report"
1336 " to http://bugs.mysql.com\n", stderr
);
1338 /* Delete mark the old index record; it can already be
1339 delete marked if we return after a lock wait in
1340 row_ins_index_entry below */
1342 if (!rec_get_deleted_flag(rec
,
1343 dict_table_is_comp(index
->table
))) {
1344 err
= btr_cur_del_mark_set_sec_rec(0, btr_cur
, TRUE
,
1346 if (err
== DB_SUCCESS
&& check_ref
) {
1348 /* NOTE that the following call loses
1349 the position of pcur ! */
1350 err
= row_upd_check_references_constraints(
1351 node
, &pcur
, index
->table
,
1353 if (err
!= DB_SUCCESS
) {
1362 btr_pcur_close(&pcur
);
1365 if (node
->is_delete
|| err
!= DB_SUCCESS
) {
1367 mem_heap_free(heap
);
1372 /* Build a new index entry */
1373 row_upd_index_replace_new_col_vals(entry
, index
, node
->update
, NULL
);
1375 /* Insert new index entry */
1376 err
= row_ins_index_entry(index
, entry
, NULL
, 0, thr
);
1378 mem_heap_free(heap
);
1383 /***************************************************************
1384 Updates the secondary index record if it is changed in the row update or
1385 deletes it if this is a delete. */
1390 /* out: DB_SUCCESS if operation successfully
1391 completed, else error code or DB_LOCK_WAIT */
1392 upd_node_t
* node
, /* in: row update node */
1393 que_thr_t
* thr
) /* in: query thread */
1397 ut_ad((node
->state
== UPD_NODE_UPDATE_ALL_SEC
)
1398 || (node
->state
== UPD_NODE_UPDATE_SOME_SEC
));
1399 ut_ad(!(node
->index
->type
& DICT_CLUSTERED
));
1401 if (node
->state
== UPD_NODE_UPDATE_ALL_SEC
1402 || row_upd_changes_ord_field_binary(node
->row
, node
->index
,
1404 err
= row_upd_sec_index_entry(node
, thr
);
1412 /***************************************************************
1413 Marks the clustered index record deleted and inserts the updated version
1414 of the record to the index. This function should be used when the ordering
1415 fields of the clustered index record change. This should be quite rare in
1416 database applications. */
1419 row_upd_clust_rec_by_insert(
1420 /*========================*/
1421 /* out: DB_SUCCESS if operation successfully
1422 completed, else error code or DB_LOCK_WAIT */
1423 upd_node_t
* node
, /* in: row update node */
1424 dict_index_t
* index
, /* in: clustered index of the record */
1425 que_thr_t
* thr
, /* in: query thread */
1426 ibool check_ref
,/* in: TRUE if index may be referenced in
1427 a foreign key constraint */
1428 mtr_t
* mtr
) /* in: mtr; gets committed here */
1430 mem_heap_t
* heap
= NULL
;
1434 dict_table_t
* table
;
1439 ut_ad(index
->type
& DICT_CLUSTERED
);
1441 trx
= thr_get_trx(thr
);
1442 table
= node
->table
;
1444 btr_cur
= btr_pcur_get_btr_cur(pcur
);
1446 if (node
->state
!= UPD_NODE_INSERT_CLUSTERED
) {
1447 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
1448 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
1450 err
= btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG
,
1451 btr_cur
, TRUE
, thr
, mtr
);
1452 if (err
!= DB_SUCCESS
) {
1457 /* Mark as not-owned the externally stored fields which the new
1458 row inherits from the delete marked record: purge should not
1459 free those externally stored fields even if the delete marked
1460 record is removed from the index tree, or updated. */
1462 btr_cur_mark_extern_inherited_fields(
1463 btr_cur_get_rec(btr_cur
),
1464 rec_get_offsets(btr_cur_get_rec(btr_cur
),
1465 dict_table_get_first_index(table
),
1466 offsets_
, ULINT_UNDEFINED
, &heap
),
1469 /* NOTE that the following call loses
1470 the position of pcur ! */
1471 err
= row_upd_check_references_constraints(
1472 node
, pcur
, table
, index
, thr
, mtr
);
1473 if (err
!= DB_SUCCESS
) {
1475 if (UNIV_LIKELY_NULL(heap
)) {
1476 mem_heap_free(heap
);
1487 heap
= mem_heap_create(500);
1489 node
->state
= UPD_NODE_INSERT_CLUSTERED
;
1491 entry
= row_build_index_entry(node
->row
, index
, heap
);
1493 row_upd_index_replace_new_col_vals(entry
, index
, node
->update
, NULL
);
1495 row_upd_index_entry_sys_field(entry
, index
, DATA_TRX_ID
, trx
->id
);
1497 /* If we return from a lock wait, for example, we may have
1498 extern fields marked as not-owned in entry (marked in the
1499 if-branch above). We must unmark them. */
1501 btr_cur_unmark_dtuple_extern_fields(entry
, node
->ext_vec
,
1503 /* We must mark non-updated extern fields in entry as inherited,
1504 so that a possible rollback will not free them */
1506 btr_cur_mark_dtuple_inherited_extern(entry
, node
->ext_vec
,
1510 err
= row_ins_index_entry(index
, entry
, node
->ext_vec
,
1511 node
->n_ext_vec
, thr
);
1512 mem_heap_free(heap
);
1517 /***************************************************************
1518 Updates a clustered index record of a row when the ordering fields do
1524 /* out: DB_SUCCESS if operation successfully
1525 completed, else error code or DB_LOCK_WAIT */
1526 upd_node_t
* node
, /* in: row update node */
1527 dict_index_t
* index
, /* in: clustered index */
1528 que_thr_t
* thr
, /* in: query thread */
1529 mtr_t
* mtr
) /* in: mtr; gets committed here */
1531 big_rec_t
* big_rec
= NULL
;
1537 ut_ad(index
->type
& DICT_CLUSTERED
);
1540 btr_cur
= btr_pcur_get_btr_cur(pcur
);
1542 ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur
),
1543 dict_table_is_comp(index
->table
)));
1545 /* Try optimistic updating of the record, keeping changes within
1546 the page; we do not check locks because we assume the x-lock on the
1549 if (node
->cmpl_info
& UPD_NODE_NO_SIZE_CHANGE
) {
1550 err
= btr_cur_update_in_place(BTR_NO_LOCKING_FLAG
,
1551 btr_cur
, node
->update
,
1552 node
->cmpl_info
, thr
, mtr
);
1554 err
= btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG
,
1555 btr_cur
, node
->update
,
1556 node
->cmpl_info
, thr
, mtr
);
1561 if (err
== DB_SUCCESS
) {
1566 if (buf_LRU_buf_pool_running_out()) {
1568 return(DB_LOCK_TABLE_FULL
);
1570 /* We may have to modify the tree structure: do a pessimistic descent
1571 down the index tree */
1575 /* NOTE: this transaction has an s-lock or x-lock on the record and
1576 therefore other transactions cannot modify the record when we have no
1577 latch on the page. In addition, we assume that other query threads of
1578 the same transaction do not modify the record in the meantime.
1579 Therefore we can assert that the restoration of the cursor succeeds. */
1581 ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE
, pcur
, mtr
));
1583 ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur
),
1584 dict_table_is_comp(index
->table
)));
1586 err
= btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG
, btr_cur
,
1587 &big_rec
, node
->update
,
1588 node
->cmpl_info
, thr
, mtr
);
1591 if (err
== DB_SUCCESS
&& big_rec
) {
1592 mem_heap_t
* heap
= NULL
;
1593 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
1595 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
1598 "row_upd_extern_checkpoint",
1599 log_make_checkpoint_at(ut_dulint_max
, TRUE
););
1602 ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE
, pcur
, mtr
));
1603 rec
= btr_cur_get_rec(btr_cur
);
1604 DEBUG_SYNC_C("before_row_upd_extern");
1605 err
= btr_store_big_rec_extern_fields(
1607 rec_get_offsets(rec
, index
, offsets_
,
1608 ULINT_UNDEFINED
, &heap
),
1610 DEBUG_SYNC_C("after_row_upd_extern");
1611 if (UNIV_LIKELY_NULL(heap
)) {
1612 mem_heap_free(heap
);
1618 dtuple_big_rec_free(big_rec
);
1624 /***************************************************************
1625 Delete marks a clustered index record. */
1628 row_upd_del_mark_clust_rec(
1629 /*=======================*/
1630 /* out: DB_SUCCESS if operation successfully
1631 completed, else error code */
1632 upd_node_t
* node
, /* in: row update node */
1633 dict_index_t
* index
, /* in: clustered index */
1634 que_thr_t
* thr
, /* in: query thread */
1635 ibool check_ref
,/* in: TRUE if index may be referenced in
1636 a foreign key constraint */
1637 mtr_t
* mtr
) /* in: mtr; gets committed here */
1644 ut_ad(index
->type
& DICT_CLUSTERED
);
1645 ut_ad(node
->is_delete
);
1648 btr_cur
= btr_pcur_get_btr_cur(pcur
);
1650 /* Store row because we have to build also the secondary index
1653 row_upd_store_row(node
);
1655 /* Mark the clustered index record deleted; we do not have to check
1656 locks, because we assume that we have an x-lock on the record */
1658 err
= btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG
,
1659 btr_cur
, TRUE
, thr
, mtr
);
1660 if (err
== DB_SUCCESS
&& check_ref
) {
1661 /* NOTE that the following call loses the position of pcur ! */
1663 err
= row_upd_check_references_constraints(node
,
1666 if (err
!= DB_SUCCESS
) {
1678 /***************************************************************
1679 Updates the clustered index record. */
1684 /* out: DB_SUCCESS if operation successfully
1685 completed, DB_LOCK_WAIT in case of a lock wait,
1687 upd_node_t
* node
, /* in: row update node */
1688 que_thr_t
* thr
) /* in: query thread */
1690 dict_index_t
* index
;
1698 mem_heap_t
* heap
= NULL
;
1699 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
1700 const ulint
* offsets
;
1701 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
1703 index
= dict_table_get_first_index(node
->table
);
1705 check_ref
= row_upd_index_is_referenced(index
, thr_get_trx(thr
));
1709 /* We have to restore the cursor to its position */
1714 /* If the restoration does not succeed, then the same
1715 transaction has deleted the record on which the cursor was,
1716 and that is an SQL error. If the restoration succeeds, it may
1717 still be that the same transaction has successively deleted
1718 and inserted a record with the same ordering fields, but in
1719 that case we know that the transaction has at least an
1720 implicit x-lock on the record. */
1722 ut_a(pcur
->rel_pos
== BTR_PCUR_ON
);
1724 success
= btr_pcur_restore_position(BTR_MODIFY_LEAF
, pcur
, mtr
);
1727 err
= DB_RECORD_NOT_FOUND
;
1734 /* If this is a row in SYS_INDEXES table of the data dictionary,
1735 then we have to free the file segments of the index tree associated
1739 && ut_dulint_cmp(node
->table
->id
, DICT_INDEXES_ID
) == 0) {
1741 dict_drop_index_tree(btr_pcur_get_rec(pcur
), mtr
);
1747 success
= btr_pcur_restore_position(BTR_MODIFY_LEAF
, pcur
,
1758 rec
= btr_pcur_get_rec(pcur
);
1759 offsets
= rec_get_offsets(rec
, index
, offsets_
,
1760 ULINT_UNDEFINED
, &heap
);
1762 if (!node
->has_clust_rec_x_lock
) {
1763 err
= lock_clust_rec_modify_check_and_lock(
1764 0, rec
, index
, offsets
, thr
);
1765 if (err
!= DB_SUCCESS
) {
1771 /* NOTE: the following function calls will also commit mtr */
1773 if (node
->is_delete
) {
1774 err
= row_upd_del_mark_clust_rec(node
, index
, thr
, check_ref
,
1776 if (err
== DB_SUCCESS
) {
1777 node
->state
= UPD_NODE_UPDATE_ALL_SEC
;
1778 node
->index
= dict_table_get_next_index(index
);
1781 if (UNIV_LIKELY_NULL(heap
)) {
1782 mem_heap_free(heap
);
1787 /* If the update is made for MySQL, we already have the update vector
1788 ready, else we have to do some evaluation: */
1790 if (!node
->in_mysql_interface
) {
1791 /* Copy the necessary columns from clust_rec and calculate the
1792 new values to set */
1793 row_upd_copy_columns(rec
, offsets
,
1794 UT_LIST_GET_FIRST(node
->columns
));
1795 row_upd_eval_new_vals(node
->update
);
1798 if (UNIV_LIKELY_NULL(heap
)) {
1799 mem_heap_free(heap
);
1802 if (node
->cmpl_info
& UPD_NODE_NO_ORD_CHANGE
) {
1804 err
= row_upd_clust_rec(node
, index
, thr
, mtr
);
1808 row_upd_store_row(node
);
1810 if (row_upd_changes_ord_field_binary(node
->row
, index
, node
->update
)) {
1812 /* Update causes an ordering field (ordering fields within
1813 the B-tree) of the clustered index record to change: perform
1814 the update by delete marking and inserting.
1816 TODO! What to do to the 'Halloween problem', where an update
1817 moves the record forward in index so that it is again
1818 updated when the cursor arrives there? Solution: the
1819 read operation must check the undo record undo number when
1820 choosing records to update. MySQL solves now the problem
1823 err
= row_upd_clust_rec_by_insert(node
, index
, thr
, check_ref
,
1825 if (err
!= DB_SUCCESS
) {
1830 node
->state
= UPD_NODE_UPDATE_ALL_SEC
;
1832 err
= row_upd_clust_rec(node
, index
, thr
, mtr
);
1834 if (err
!= DB_SUCCESS
) {
1839 node
->state
= UPD_NODE_UPDATE_SOME_SEC
;
1842 node
->index
= dict_table_get_next_index(index
);
1847 /***************************************************************
1848 Updates the affected index records of a row. When the control is transferred
1849 to this node, we assume that we have a persistent cursor which was on a
1850 record, and the position of the cursor is stored in the cursor. */
1855 /* out: DB_SUCCESS if operation successfully
1856 completed, else error code or DB_LOCK_WAIT */
1857 upd_node_t
* node
, /* in: row update node */
1858 que_thr_t
* thr
) /* in: query thread */
1860 ulint err
= DB_SUCCESS
;
1864 if (UNIV_LIKELY(node
->in_mysql_interface
)) {
1866 /* We do not get the cmpl_info value from the MySQL
1867 interpreter: we must calculate it on the fly: */
1870 || row_upd_changes_some_index_ord_field_binary(
1871 node
->table
, node
->update
)) {
1872 node
->cmpl_info
= 0;
1874 node
->cmpl_info
= UPD_NODE_NO_ORD_CHANGE
;
1878 if (node
->state
== UPD_NODE_UPDATE_CLUSTERED
1879 || node
->state
== UPD_NODE_INSERT_CLUSTERED
) {
1881 err
= row_upd_clust_step(node
, thr
);
1883 if (err
!= DB_SUCCESS
) {
1889 if (!node
->is_delete
&& (node
->cmpl_info
& UPD_NODE_NO_ORD_CHANGE
)) {
1894 while (node
->index
!= NULL
) {
1895 err
= row_upd_sec_step(node
, thr
);
1897 if (err
!= DB_SUCCESS
) {
1902 node
->index
= dict_table_get_next_index(node
->index
);
1906 if (err
== DB_SUCCESS
) {
1907 /* Do some cleanup */
1909 if (node
->row
!= NULL
) {
1911 node
->n_ext_vec
= 0;
1912 mem_heap_empty(node
->heap
);
1915 node
->state
= UPD_NODE_UPDATE_CLUSTERED
;
1921 /***************************************************************
1922 Updates a row in a table. This is a high-level function used in SQL execution
1928 /* out: query thread to run next or NULL */
1929 que_thr_t
* thr
) /* in: query thread */
1932 sel_node_t
* sel_node
;
1934 ulint err
= DB_SUCCESS
;
1939 trx
= thr_get_trx(thr
);
1941 trx_start_if_not_started(trx
);
1943 node
= thr
->run_node
;
1945 sel_node
= node
->select
;
1947 parent
= que_node_get_parent(node
);
1949 ut_ad(que_node_get_type(node
) == QUE_NODE_UPDATE
);
1951 if (thr
->prev_node
== parent
) {
1952 node
->state
= UPD_NODE_SET_IX_LOCK
;
1955 if (node
->state
== UPD_NODE_SET_IX_LOCK
) {
1957 if (!node
->has_clust_rec_x_lock
) {
1958 /* It may be that the current session has not yet
1959 started its transaction, or it has been committed: */
1961 err
= lock_table(0, node
->table
, LOCK_IX
, thr
);
1963 if (err
!= DB_SUCCESS
) {
1965 goto error_handling
;
1969 node
->state
= UPD_NODE_UPDATE_CLUSTERED
;
1971 if (node
->searched_update
) {
1972 /* Reset the cursor */
1973 sel_node
->state
= SEL_NODE_OPEN
;
1975 /* Fetch a row to update */
1977 thr
->run_node
= sel_node
;
1983 /* sel_node is NULL if we are in the MySQL interface */
1985 if (sel_node
&& (sel_node
->state
!= SEL_NODE_FETCH
)) {
1987 if (!node
->searched_update
) {
1988 /* An explicit cursor should be positioned on a row
1995 goto error_handling
;
1998 ut_ad(sel_node
->state
== SEL_NODE_NO_MORE_ROWS
);
2000 /* No more rows to update, or the select node performed the
2001 updates directly in-place */
2003 thr
->run_node
= parent
;
2008 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2010 err
= row_upd(node
, thr
);
2013 trx
->error_state
= err
;
2015 if (err
!= DB_SUCCESS
) {
2019 /* DO THE TRIGGER ACTIONS HERE */
2021 if (node
->searched_update
) {
2022 /* Fetch next row to update */
2024 thr
->run_node
= sel_node
;
2026 /* It was an explicit cursor update */
2028 thr
->run_node
= parent
;
2031 node
->state
= UPD_NODE_UPDATE_CLUSTERED
;
2036 /*************************************************************************
2037 Performs an in-place update for the current clustered index record in
2041 row_upd_in_place_in_select(
2042 /*=======================*/
2043 sel_node_t
* sel_node
, /* in: select node */
2044 que_thr_t
* thr
, /* in: query thread */
2045 mtr_t
* mtr
) /* in: mtr */
2052 #endif /* UNIV_DEBUG */
2053 mem_heap_t
* heap
= NULL
;
2054 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
2055 *offsets_
= (sizeof offsets_
) / sizeof *offsets_
;
2057 ut_ad(sel_node
->select_will_do_update
);
2058 ut_ad(sel_node
->latch_mode
== BTR_MODIFY_LEAF
);
2059 ut_ad(sel_node
->asc
);
2061 node
= que_node_get_parent(sel_node
);
2063 ut_ad(que_node_get_type(node
) == QUE_NODE_UPDATE
);
2066 btr_cur
= btr_pcur_get_btr_cur(pcur
);
2068 /* Copy the necessary columns from clust_rec and calculate the new
2071 row_upd_copy_columns(btr_pcur_get_rec(pcur
),
2072 rec_get_offsets(btr_pcur_get_rec(pcur
),
2073 btr_cur
->index
, offsets_
,
2074 ULINT_UNDEFINED
, &heap
),
2075 UT_LIST_GET_FIRST(node
->columns
));
2076 if (UNIV_LIKELY_NULL(heap
)) {
2077 mem_heap_free(heap
);
2079 row_upd_eval_new_vals(node
->update
);
2081 ut_ad(!rec_get_deleted_flag(
2082 btr_pcur_get_rec(pcur
),
2083 dict_table_is_comp(btr_cur
->index
->table
)));
2085 ut_ad(node
->cmpl_info
& UPD_NODE_NO_SIZE_CHANGE
);
2086 ut_ad(node
->cmpl_info
& UPD_NODE_NO_ORD_CHANGE
);
2087 ut_ad(node
->select_will_do_update
);
2091 #endif /* UNIV_DEBUG */
2092 btr_cur_update_in_place(BTR_NO_LOCKING_FLAG
, btr_cur
,
2093 node
->update
, node
->cmpl_info
,
2095 ut_ad(err
== DB_SUCCESS
);