Drizzled Public API Documentation

row0upd.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
4 
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.
8 
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.
12 
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
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "row0upd.h"
27 
28 #ifdef UNIV_NONINL
29 #include "row0upd.ic"
30 #endif
31 
32 #include "dict0dict.h"
33 #include "trx0undo.h"
34 #include "rem0rec.h"
35 #ifndef UNIV_HOTBACKUP
36 #include "dict0boot.h"
37 #include "dict0crea.h"
38 #include "mach0data.h"
39 #include "btr0btr.h"
40 #include "btr0cur.h"
41 #include "que0que.h"
42 #include "row0ext.h"
43 #include "row0ins.h"
44 #include "row0sel.h"
45 #include "row0row.h"
46 #include "rem0cmp.h"
47 #include "lock0lock.h"
48 #include "log0log.h"
49 #include "pars0sym.h"
50 #include "eval0eval.h"
51 #include "buf0lru.h"
52 
53 
54 /* What kind of latch and lock can we assume when the control comes to
55  -------------------------------------------------------------------
56 an update node?
57 --------------
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. */
71 
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.
84 
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. */
94 
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
101 check.
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. */
104 
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
111 check.
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. */
114 
115 /***********************************************************/
120 static
121 ibool
122 row_upd_changes_first_fields_binary(
123 /*================================*/
124  dtuple_t* entry,
125  dict_index_t* index,
126  const upd_t* update,
127  ulint n);
130 /*********************************************************************/
139 static
140 ibool
141 row_upd_index_is_referenced(
142 /*========================*/
143  dict_index_t* index,
144  trx_t* trx)
145 {
146  dict_table_t* table = index->table;
147  dict_foreign_t* foreign;
148  ibool froze_data_dict = FALSE;
149  ibool is_referenced = FALSE;
150 
151  if (!UT_LIST_GET_FIRST(table->referenced_list)) {
152 
153  return(FALSE);
154  }
155 
156  if (trx->dict_operation_lock_mode == 0) {
157  row_mysql_freeze_data_dictionary(trx);
158  froze_data_dict = TRUE;
159  }
160 
161  foreign = UT_LIST_GET_FIRST(table->referenced_list);
162 
163  while (foreign) {
164  if (foreign->referenced_index == index) {
165 
166  is_referenced = TRUE;
167  goto func_exit;
168  }
169 
170  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
171  }
172 
173 func_exit:
174  if (froze_data_dict) {
176  }
177 
178  return(is_referenced);
179 }
180 
181 /*********************************************************************/
189 static
190 ulint
191 row_upd_check_references_constraints(
192 /*=================================*/
193  upd_node_t* node,
194  btr_pcur_t* pcur,
196  dict_table_t* table,
197  dict_index_t* index,
198  ulint* offsets,
199  que_thr_t* thr,
200  mtr_t* mtr)
201 {
202  dict_foreign_t* foreign;
203  mem_heap_t* heap;
204  dtuple_t* entry;
205  trx_t* trx;
206  const rec_t* rec;
207  ulint n_ext;
208  ulint err;
209  ibool got_s_lock = FALSE;
210 
211  if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
212 
213  return(DB_SUCCESS);
214  }
215 
216  trx = thr_get_trx(thr);
217 
218  rec = btr_pcur_get_rec(pcur);
219  ut_ad(rec_offs_validate(rec, index, offsets));
220 
221  heap = mem_heap_create(500);
222 
223  entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
224  &n_ext, heap);
225 
226  mtr_commit(mtr);
227 
228  mtr_start(mtr);
229 
230  if (trx->dict_operation_lock_mode == 0) {
231  got_s_lock = TRUE;
232 
233  row_mysql_freeze_data_dictionary(trx);
234  }
235 
236  foreign = UT_LIST_GET_FIRST(table->referenced_list);
237 
238  while (foreign) {
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. */
243 
244  if (foreign->referenced_index == index
245  && (node->is_delete
246  || row_upd_changes_first_fields_binary(
247  entry, index, node->update,
248  foreign->n_fields))) {
249 
250  if (foreign->foreign_table == NULL) {
251  dict_table_get(foreign->foreign_table_name_lookup,
252  FALSE);
253  }
254 
255  if (foreign->foreign_table) {
256  mutex_enter(&(dict_sys->mutex));
257 
258  (foreign->foreign_table
260 
261  mutex_exit(&(dict_sys->mutex));
262  }
263 
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. */
268 
270  FALSE, foreign, table, entry, thr);
271 
272  if (foreign->foreign_table) {
273  mutex_enter(&(dict_sys->mutex));
274 
275  ut_a(foreign->foreign_table
277 
278  (foreign->foreign_table
280 
281  mutex_exit(&(dict_sys->mutex));
282  }
283 
284  if (err != DB_SUCCESS) {
285 
286  goto func_exit;
287  }
288  }
289 
290  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
291  }
292 
293  err = DB_SUCCESS;
294 
295 func_exit:
296  if (got_s_lock) {
298  }
299 
300  mem_heap_free(heap);
301 
302  return(err);
303 }
304 
305 /*********************************************************************/
308 UNIV_INTERN
309 upd_node_t*
311 /*============*/
312  mem_heap_t* heap)
313 {
314  upd_node_t* node;
315 
316  node = static_cast<upd_node_t *>(mem_heap_alloc(heap, sizeof(upd_node_t)));
317  node->common.type = QUE_NODE_UPDATE;
318 
319  node->state = UPD_NODE_UPDATE_CLUSTERED;
320  node->in_mysql_interface = FALSE;
321 
322  node->row = NULL;
323  node->ext = NULL;
324  node->upd_row = NULL;
325  node->upd_ext = NULL;
326  node->index = NULL;
327  node->update = NULL;
328 
329  node->foreign = NULL;
330  node->cascade_heap = NULL;
331  node->cascade_node = NULL;
332 
333  node->select = NULL;
334 
335  node->heap = mem_heap_create(128);
336  node->magic_n = UPD_NODE_MAGIC_N;
337 
338  node->cmpl_info = 0;
339 
340  return(node);
341 }
342 #endif /* !UNIV_HOTBACKUP */
343 
344 /*********************************************************************/
347 UNIV_INTERN
348 void
350 /*===============================*/
351  rec_t* rec,
352  page_zip_des_t* page_zip,
353  const ulint* offsets,
354  ulint pos,
355  trx_id_t trx_id,
356  roll_ptr_t roll_ptr)
357 {
358  ut_ad(rec_offs_validate(rec, NULL, offsets));
359 
360  if (UNIV_LIKELY_NULL(page_zip)) {
362  page_zip, rec, offsets, pos, trx_id, roll_ptr);
363  } else {
364  byte* field;
365  ulint len;
366 
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"
371 #endif
372  trx_write_trx_id(field, trx_id);
373  trx_write_roll_ptr(field + DATA_TRX_ID_LEN, roll_ptr);
374  }
375 }
376 
377 #ifndef UNIV_HOTBACKUP
378 /*********************************************************************/
380 UNIV_INTERN
381 void
383 /*==========================*/
384  dtuple_t* entry,
388  dict_index_t* index,
389  ulint type,
390  ib_uint64_t val)
391 {
392  dfield_t* dfield;
393  byte* field;
394  ulint pos;
395 
396  ut_ad(dict_index_is_clust(index));
397 
398  pos = dict_index_get_sys_col_pos(index, type);
399 
400  dfield = dtuple_get_nth_field(entry, pos);
401  field = static_cast<byte *>(dfield_get_data(dfield));
402 
403  if (type == DATA_TRX_ID) {
404  trx_write_trx_id(field, val);
405  } else {
406  ut_ad(type == DATA_ROLL_PTR);
407  trx_write_roll_ptr(field, val);
408  }
409 }
410 
411 /***********************************************************/
416 UNIV_INTERN
417 ibool
419 /*===================================*/
420  dict_index_t* index,
421  const ulint* offsets,
422  const upd_t* update)
423 {
424  const upd_field_t* upd_field;
425  const dfield_t* new_val;
426  ulint old_len;
427  ulint new_len;
428  ulint n_fields;
429  ulint i;
430 
431  ut_ad(rec_offs_validate(NULL, index, offsets));
432  n_fields = upd_get_n_fields(update);
433 
434  for (i = 0; i < n_fields; i++) {
435  upd_field = upd_get_nth_field(update, i);
436 
437  new_val = &(upd_field->new_val);
438  new_len = dfield_get_len(new_val);
439 
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. */
445 
446  new_len = dict_col_get_sql_null_size(
448  upd_field->field_no),
449  0);
450  }
451 
452  old_len = rec_offs_nth_size(offsets, upd_field->field_no);
453 
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! */
463 
464  old_len = UNIV_SQL_NULL;
465  }
466 
467  if (dfield_is_ext(new_val) || old_len != new_len
468  || rec_offs_nth_extern(offsets, upd_field->field_no)) {
469 
470  return(TRUE);
471  }
472  }
473 
474  return(FALSE);
475 }
476 #endif /* !UNIV_HOTBACKUP */
477 
478 /***********************************************************/
484 UNIV_INTERN
485 void
487 /*=================*/
488  rec_t* rec,
489  dict_index_t* index,
490  const ulint* offsets,
491  const upd_t* update,
492  page_zip_des_t* page_zip)
494 {
495  const upd_field_t* upd_field;
496  const dfield_t* new_val;
497  ulint n_fields;
498  ulint i;
499 
500  ut_ad(rec_offs_validate(rec, index, offsets));
501 
502  if (rec_offs_comp(offsets)) {
503  rec_set_info_bits_new(rec, update->info_bits);
504  } else {
505  rec_set_info_bits_old(rec, update->info_bits);
506  }
507 
508  n_fields = upd_get_n_fields(update);
509 
510  for (i = 0; i < n_fields; i++) {
511 #ifdef UNIV_BLOB_DEBUG
512  btr_blob_dbg_t b;
513  const byte* field_ref = NULL;
514 #endif /* UNIV_BLOB_DEBUG */
515 
516  upd_field = upd_get_nth_field(update, i);
517  new_val = &(upd_field->new_val);
518  ut_ad(!dfield_is_ext(new_val) ==
519  !rec_offs_nth_extern(offsets, upd_field->field_no));
520 #ifdef UNIV_BLOB_DEBUG
521  if (dfield_is_ext(new_val)) {
522  ulint len;
523  field_ref = rec_get_nth_field(rec, offsets, i, &len);
524  ut_a(len != UNIV_SQL_NULL);
526  field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
527 
528  b.ref_page_no = page_get_page_no(page_align(rec));
529  b.ref_heap_no = page_rec_get_heap_no(rec);
530  b.ref_field_no = i;
531  b.blob_page_no = mach_read_from_4(
532  field_ref + BTR_EXTERN_PAGE_NO);
533  ut_a(b.ref_field_no >= index->n_uniq);
534  btr_blob_dbg_rbt_delete(index, &b, "upd_in_place");
535  }
536 #endif /* UNIV_BLOB_DEBUG */
537 
538  rec_set_nth_field(rec, offsets, upd_field->field_no,
539  dfield_get_data(new_val),
540  dfield_get_len(new_val));
541 
542 #ifdef UNIV_BLOB_DEBUG
543  if (dfield_is_ext(new_val)) {
544  b.blob_page_no = mach_read_from_4(
545  field_ref + BTR_EXTERN_PAGE_NO);
546  b.always_owner = b.owner = !(field_ref[BTR_EXTERN_LEN]
548  b.del = rec_get_deleted_flag(
549  rec, rec_offs_comp(offsets));
550 
551  btr_blob_dbg_rbt_insert(index, &b, "upd_in_place");
552  }
553 #endif /* UNIV_BLOB_DEBUG */
554  }
555 
556  if (UNIV_LIKELY_NULL(page_zip)) {
557  page_zip_write_rec(page_zip, rec, index, offsets, 0);
558  }
559 }
560 
561 #ifndef UNIV_HOTBACKUP
562 /*********************************************************************/
566 UNIV_INTERN
567 byte*
569 /*==========================*/
570  dict_index_t* index,
571  trx_t* trx,
572  roll_ptr_t roll_ptr,
573  byte* log_ptr,
575  mtr_t* /*mtr __attribute__((unused))*/)
576 {
577  ut_ad(dict_index_is_clust(index));
578  ut_ad(mtr);
579 
580  log_ptr += mach_write_compressed(log_ptr,
582  index, DATA_TRX_ID));
583 
584  trx_write_roll_ptr(log_ptr, roll_ptr);
585  log_ptr += DATA_ROLL_PTR_LEN;
586 
587  log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
588 
589  return(log_ptr);
590 }
591 #endif /* !UNIV_HOTBACKUP */
592 
593 /*********************************************************************/
596 UNIV_INTERN
597 byte*
599 /*===================*/
600  byte* ptr,
601  byte* end_ptr,
602  ulint* pos,
603  trx_id_t* trx_id,
604  roll_ptr_t* roll_ptr)
605 {
606  ptr = mach_parse_compressed(ptr, end_ptr, pos);
607 
608  if (ptr == NULL) {
609 
610  return(NULL);
611  }
612 
613  if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
614 
615  return(NULL);
616  }
617 
618  *roll_ptr = trx_read_roll_ptr(ptr);
619  ptr += DATA_ROLL_PTR_LEN;
620 
621  ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
622 
623  return(ptr);
624 }
625 
626 #ifndef UNIV_HOTBACKUP
627 /***********************************************************/
629 UNIV_INTERN
630 void
632 /*====================*/
633  const upd_t* update,
634  byte* log_ptr,
638  mtr_t* mtr)
639 {
640  const upd_field_t* upd_field;
641  const dfield_t* new_val;
642  ulint len;
643  ulint n_fields;
644  byte* buf_end;
645  ulint i;
646 
647  n_fields = upd_get_n_fields(update);
648 
649  buf_end = log_ptr + MLOG_BUF_MARGIN;
650 
651  mach_write_to_1(log_ptr, update->info_bits);
652  log_ptr++;
653  log_ptr += mach_write_compressed(log_ptr, n_fields);
654 
655  for (i = 0; i < n_fields; i++) {
656 
657 #if MLOG_BUF_MARGIN <= 30
658 # error "MLOG_BUF_MARGIN <= 30"
659 #endif
660 
661  if (log_ptr + 30 > buf_end) {
662  mlog_close(mtr, log_ptr);
663 
664  log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
665  buf_end = log_ptr + MLOG_BUF_MARGIN;
666  }
667 
668  upd_field = upd_get_nth_field(update, i);
669 
670  new_val = &(upd_field->new_val);
671 
672  len = dfield_get_len(new_val);
673 
674  log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
675  log_ptr += mach_write_compressed(log_ptr, len);
676 
677  if (len != UNIV_SQL_NULL) {
678  if (log_ptr + len < buf_end) {
679  memcpy(log_ptr, dfield_get_data(new_val), len);
680 
681  log_ptr += len;
682  } else {
683  mlog_close(mtr, log_ptr);
684 
686  static_cast<byte *>(dfield_get_data(new_val)),
687  len);
688 
689  log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
690  buf_end = log_ptr + MLOG_BUF_MARGIN;
691  }
692  }
693  }
694 
695  mlog_close(mtr, log_ptr);
696 }
697 #endif /* !UNIV_HOTBACKUP */
698 
699 /*********************************************************************/
702 UNIV_INTERN
703 byte*
705 /*================*/
706  byte* ptr,
707  byte* end_ptr,
708  mem_heap_t* heap,
710  upd_t** update_out)
711 {
712  upd_t* update;
713  upd_field_t* upd_field;
714  dfield_t* new_val;
715  ulint len;
716  ulint n_fields;
717  ulint info_bits;
718  ulint i;
719 
720  if (end_ptr < ptr + 1) {
721 
722  return(NULL);
723  }
724 
725  info_bits = mach_read_from_1(ptr);
726  ptr++;
727  ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
728 
729  if (ptr == NULL) {
730 
731  return(NULL);
732  }
733 
734  update = upd_create(n_fields, heap);
735  update->info_bits = info_bits;
736 
737  for (i = 0; i < n_fields; i++) {
738  ulint field_no;
739  upd_field = upd_get_nth_field(update, i);
740  new_val = &(upd_field->new_val);
741 
742  ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
743 
744  if (ptr == NULL) {
745 
746  return(NULL);
747  }
748 
749  upd_field->field_no = field_no;
750 
751  ptr = mach_parse_compressed(ptr, end_ptr, &len);
752 
753  if (ptr == NULL) {
754 
755  return(NULL);
756  }
757 
758  if (len != UNIV_SQL_NULL) {
759 
760  if (end_ptr < ptr + len) {
761 
762  return(NULL);
763  }
764 
765  dfield_set_data(new_val,
766  mem_heap_dup(heap, ptr, len), len);
767  ptr += len;
768  } else {
769  dfield_set_null(new_val);
770  }
771  }
772 
773  *update_out = update;
774 
775  return(ptr);
776 }
777 
778 #ifndef UNIV_HOTBACKUP
779 /***************************************************************/
784 UNIV_INTERN
785 upd_t*
787 /*====================================*/
788  dict_index_t* index,
789  const dtuple_t* entry,
790  const rec_t* rec,
791  trx_t* trx,
792  mem_heap_t* heap)
793 {
794  upd_field_t* upd_field;
795  const dfield_t* dfield;
796  const byte* data;
797  ulint len;
798  upd_t* update;
799  ulint n_diff;
800  ulint i;
801  ulint offsets_[REC_OFFS_SMALL_SIZE];
802  const ulint* offsets;
803  rec_offs_init(offsets_);
804 
805  /* This function is used only for a secondary index */
806  ut_a(!dict_index_is_clust(index));
807 
808  update = upd_create(dtuple_get_n_fields(entry), heap);
809 
810  n_diff = 0;
811  offsets = rec_get_offsets(rec, index, offsets_,
812  ULINT_UNDEFINED, &heap);
813 
814  for (i = 0; i < dtuple_get_n_fields(entry); i++) {
815 
816  data = rec_get_nth_field(rec, offsets, i, &len);
817 
818  dfield = dtuple_get_nth_field(entry, i);
819 
820  /* NOTE that it may be that len != dfield_get_len(dfield) if we
821  are updating in a character set and collation where strings of
822  different length can be equal in an alphabetical comparison,
823  and also in the case where we have a column prefix index
824  and the last characters in the index field are spaces; the
825  latter case probably caused the assertion failures reported at
826  row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
827 
828  /* NOTE: we compare the fields as binary strings!
829  (No collation) */
830 
831  if (!dfield_data_is_binary_equal(dfield, len, data)) {
832 
833  upd_field = upd_get_nth_field(update, n_diff);
834 
835  dfield_copy(&(upd_field->new_val), dfield);
836 
837  upd_field_set_field_no(upd_field, i, index, trx);
838 
839  n_diff++;
840  }
841  }
842 
843  update->n_fields = n_diff;
844 
845  return(update);
846 }
847 
848 /***************************************************************/
854 UNIV_INTERN
855 upd_t*
857 /*============================*/
858  dict_index_t* index,
859  const dtuple_t* entry,
860  const rec_t* rec,
861  trx_t* trx,
862  mem_heap_t* heap)
863 {
864  upd_field_t* upd_field;
865  const dfield_t* dfield;
866  const byte* data;
867  ulint len;
868  upd_t* update;
869  ulint n_diff;
870  ulint roll_ptr_pos;
871  ulint trx_id_pos;
872  ulint i;
873  ulint offsets_[REC_OFFS_NORMAL_SIZE];
874  const ulint* offsets;
875  rec_offs_init(offsets_);
876 
877  /* This function is used only for a clustered index */
878  ut_a(dict_index_is_clust(index));
879 
880  update = upd_create(dtuple_get_n_fields(entry), heap);
881 
882  n_diff = 0;
883 
884  roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
885  trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
886 
887  offsets = rec_get_offsets(rec, index, offsets_,
888  ULINT_UNDEFINED, &heap);
889 
890  for (i = 0; i < dtuple_get_n_fields(entry); i++) {
891 
892  data = rec_get_nth_field(rec, offsets, i, &len);
893 
894  dfield = dtuple_get_nth_field(entry, i);
895 
896  /* NOTE: we compare the fields as binary strings!
897  (No collation) */
898 
899  if (i == trx_id_pos || i == roll_ptr_pos) {
900 
901  goto skip_compare;
902  }
903 
904  if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
905  != !rec_offs_nth_extern(offsets, i))
906  || !dfield_data_is_binary_equal(dfield, len, data)) {
907 
908  upd_field = upd_get_nth_field(update, n_diff);
909 
910  dfield_copy(&(upd_field->new_val), dfield);
911 
912  upd_field_set_field_no(upd_field, i, index, trx);
913 
914  n_diff++;
915  }
916 skip_compare:
917  ;
918  }
919 
920  update->n_fields = n_diff;
921 
922  return(update);
923 }
924 
925 /***********************************************************/
930 static
931 byte*
932 row_upd_ext_fetch(
933 /*==============*/
934  const byte* data,
937  ulint local_len,
938  ulint zip_size,
941  ulint* len,
943  mem_heap_t* heap)
944 {
945  byte* buf = static_cast<byte *>(mem_heap_alloc(heap, *len));
946 
947  *len = btr_copy_externally_stored_field_prefix(buf, *len,
948  zip_size,
949  data, local_len);
950  /* We should never update records containing a half-deleted BLOB. */
951  ut_a(*len);
952 
953  return(buf);
954 }
955 
956 /***********************************************************/
959 static
960 void
961 row_upd_index_replace_new_col_val(
962 /*==============================*/
963  dfield_t* dfield,
965  const dict_field_t* field,
966  const dict_col_t* col,
967  const upd_field_t* uf,
968  mem_heap_t* heap,
970  ulint zip_size)
972 {
973  ulint len;
974  const byte* data;
975 
976  dfield_copy_data(dfield, &uf->new_val);
977 
978  if (dfield_is_null(dfield)) {
979  return;
980  }
981 
982  len = dfield_get_len(dfield);
983  data = static_cast<const byte *>(dfield_get_data(dfield));
984 
985  if (field->prefix_len > 0) {
986  ibool fetch_ext = dfield_is_ext(dfield)
987  && len < (ulint) field->prefix_len
989 
990  if (fetch_ext) {
991  ulint l = len;
992 
993  len = field->prefix_len;
994 
995  data = row_upd_ext_fetch(data, l, zip_size,
996  &len, heap);
997  }
998 
999  len = dtype_get_at_most_n_mbchars(col->prtype,
1000  col->mbminmaxlen,
1001  field->prefix_len, len,
1002  (const char*) data);
1003 
1004  dfield_set_data(dfield, data, len);
1005 
1006  if (!fetch_ext) {
1007  dfield_dup(dfield, heap);
1008  }
1009 
1010  return;
1011  }
1012 
1013  switch (uf->orig_len) {
1014  byte* buf;
1016  /* Restore the original locally stored
1017  part of the column. In the undo log,
1018  InnoDB writes a longer prefix of externally
1019  stored columns, so that column prefixes
1020  in secondary indexes can be reconstructed. */
1021  dfield_set_data(dfield,
1022  data + len - BTR_EXTERN_FIELD_REF_SIZE,
1024  dfield_set_ext(dfield);
1025  /* fall through */
1026  case 0:
1027  dfield_dup(dfield, heap);
1028  break;
1029  default:
1030  /* Reconstruct the original locally
1031  stored part of the column. The data
1032  will have to be copied. */
1034  buf = static_cast<byte *>(mem_heap_alloc(heap, uf->orig_len));
1035  /* Copy the locally stored prefix. */
1036  memcpy(buf, data,
1038  /* Copy the BLOB pointer. */
1039  memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
1040  data + len - BTR_EXTERN_FIELD_REF_SIZE,
1042 
1043  dfield_set_data(dfield, buf, uf->orig_len);
1044  dfield_set_ext(dfield);
1045  break;
1046  }
1047 }
1048 
1049 /***********************************************************/
1052 UNIV_INTERN
1053 void
1055 /*=========================================*/
1056  dtuple_t* entry,
1060  dict_index_t* index,
1062  const upd_t* update,
1065  ibool order_only,
1069  mem_heap_t* heap)
1071 {
1072  ulint i;
1073  ulint n_fields;
1074  const ulint zip_size = dict_table_zip_size(index->table);
1075 
1076  ut_ad(index);
1077 
1078  dtuple_set_info_bits(entry, update->info_bits);
1079 
1080  if (order_only) {
1081  n_fields = dict_index_get_n_unique(index);
1082  } else {
1083  n_fields = dict_index_get_n_fields(index);
1084  }
1085 
1086  for (i = 0; i < n_fields; i++) {
1087  const dict_field_t* field;
1088  const dict_col_t* col;
1089  const upd_field_t* uf;
1090 
1091  field = dict_index_get_nth_field(index, i);
1092  col = dict_field_get_col(field);
1093  uf = upd_get_field_by_field_no(update, i);
1094 
1095  if (uf) {
1096  row_upd_index_replace_new_col_val(
1097  dtuple_get_nth_field(entry, i),
1098  field, col, uf, heap, zip_size);
1099  }
1100  }
1101 }
1102 
1103 /***********************************************************/
1106 UNIV_INTERN
1107 void
1109 /*===============================*/
1110  dtuple_t* entry,
1114  dict_index_t* index,
1116  const upd_t* update,
1119  mem_heap_t* heap)
1121 {
1122  ulint i;
1123  const dict_index_t* clust_index
1124  = dict_table_get_first_index(index->table);
1125  const ulint zip_size
1126  = dict_table_zip_size(index->table);
1127 
1128  dtuple_set_info_bits(entry, update->info_bits);
1129 
1130  for (i = 0; i < dict_index_get_n_fields(index); i++) {
1131  const dict_field_t* field;
1132  const dict_col_t* col;
1133  const upd_field_t* uf;
1134 
1135  field = dict_index_get_nth_field(index, i);
1136  col = dict_field_get_col(field);
1138  update, dict_col_get_clust_pos(col, clust_index));
1139 
1140  if (uf) {
1141  row_upd_index_replace_new_col_val(
1142  dtuple_get_nth_field(entry, i),
1143  field, col, uf, heap, zip_size);
1144  }
1145  }
1146 }
1147 
1148 /***********************************************************/
1150 UNIV_INTERN
1151 void
1153 /*============*/
1154  dtuple_t* row,
1159  row_ext_t** ext,
1161  const dict_index_t* index,
1162  const upd_t* update,
1164  mem_heap_t* heap)
1165 {
1166  ulint col_no;
1167  ulint i;
1168  ulint n_cols;
1169  ulint n_ext_cols;
1170  ulint* ext_cols;
1171  const dict_table_t* table;
1172 
1173  ut_ad(row);
1174  ut_ad(ext);
1175  ut_ad(index);
1176  ut_ad(dict_index_is_clust(index));
1177  ut_ad(update);
1178  ut_ad(heap);
1179 
1180  n_cols = dtuple_get_n_fields(row);
1181  table = index->table;
1182  ut_ad(n_cols == dict_table_get_n_cols(table));
1183 
1184  ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_cols * sizeof *ext_cols));
1185  n_ext_cols = 0;
1186 
1187  dtuple_set_info_bits(row, update->info_bits);
1188 
1189  for (col_no = 0; col_no < n_cols; col_no++) {
1190 
1191  const dict_col_t* col
1192  = dict_table_get_nth_col(table, col_no);
1193  const ulint clust_pos
1194  = dict_col_get_clust_pos(col, index);
1195  dfield_t* dfield;
1196 
1197  if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
1198 
1199  continue;
1200  }
1201 
1202  dfield = dtuple_get_nth_field(row, col_no);
1203 
1204  for (i = 0; i < upd_get_n_fields(update); i++) {
1205 
1206  const upd_field_t* upd_field
1207  = upd_get_nth_field(update, i);
1208 
1209  if (upd_field->field_no != clust_pos) {
1210 
1211  continue;
1212  }
1213 
1214  dfield_copy_data(dfield, &upd_field->new_val);
1215  break;
1216  }
1217 
1218  if (dfield_is_ext(dfield) && col->ord_part) {
1219  ext_cols[n_ext_cols++] = col_no;
1220  }
1221  }
1222 
1223  if (n_ext_cols) {
1224  *ext = row_ext_create(n_ext_cols, ext_cols, row,
1225  dict_table_zip_size(table), heap);
1226  } else {
1227  *ext = NULL;
1228  }
1229 }
1230 
1231 /***********************************************************/
1238 UNIV_INTERN
1239 ibool
1241 /*==================================*/
1242  dict_index_t* index,
1243  const upd_t* update,
1246 #ifdef UNIV_DEBUG
1247  const que_thr_t*thr,
1248 #endif /* UNIV_DEBUG */
1249  const dtuple_t* row,
1253  const row_ext_t*ext)
1255 {
1256  ulint n_unique;
1257  ulint i;
1258  const dict_index_t* clust_index;
1259 
1260  ut_ad(index);
1261  ut_ad(update);
1262  ut_ad(thr);
1263  ut_ad(thr->graph);
1264  ut_ad(thr->graph->trx);
1265 
1266  n_unique = dict_index_get_n_unique(index);
1267 
1268  clust_index = dict_table_get_first_index(index->table);
1269 
1270  for (i = 0; i < n_unique; i++) {
1271 
1272  const dict_field_t* ind_field;
1273  const dict_col_t* col;
1274  ulint col_no;
1275  const upd_field_t* upd_field;
1276  const dfield_t* dfield;
1277  dfield_t dfield_ext;
1278  ulint dfield_len;
1279  const byte* buf;
1280 
1281  ind_field = dict_index_get_nth_field(index, i);
1282  col = dict_field_get_col(ind_field);
1283  col_no = dict_col_get_no(col);
1284 
1285  upd_field = upd_get_field_by_field_no(
1286  update, dict_col_get_clust_pos(col, clust_index));
1287 
1288  if (upd_field == NULL) {
1289  continue;
1290  }
1291 
1292  if (row == NULL) {
1293  ut_ad(ext == NULL);
1294  return(TRUE);
1295  }
1296 
1297  dfield = dtuple_get_nth_field(row, col_no);
1298 
1299  /* This treatment of column prefix indexes is loosely
1300  based on row_build_index_entry(). */
1301 
1302  if (UNIV_LIKELY(ind_field->prefix_len == 0)
1303  || dfield_is_null(dfield)) {
1304  /* do nothing special */
1305  } else if (UNIV_LIKELY_NULL(ext)) {
1306  /* Silence a compiler warning without
1307  silencing a Valgrind error. */
1308  dfield_len = 0;
1309  UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len);
1310  /* See if the column is stored externally. */
1311  buf = row_ext_lookup(ext, col_no, &dfield_len);
1312 
1313  ut_ad(col->ord_part);
1314 
1315  if (UNIV_LIKELY_NULL(buf)) {
1316  if (UNIV_UNLIKELY(buf == field_ref_zero)) {
1317  /* The externally stored field
1318  was not written yet. This
1319  record should only be seen by
1320  recv_recovery_rollback_active(),
1321  when the server had crashed before
1322  storing the field. */
1323  ut_ad(thr->graph->trx->is_recovered);
1324  ut_ad(trx_is_recv(thr->graph->trx));
1325  return(TRUE);
1326  }
1327 
1328  goto copy_dfield;
1329  }
1330  } else if (dfield_is_ext(dfield)) {
1331  dfield_len = dfield_get_len(dfield);
1332  ut_a(dfield_len > BTR_EXTERN_FIELD_REF_SIZE);
1333  dfield_len -= BTR_EXTERN_FIELD_REF_SIZE;
1334  ut_a(dict_index_is_clust(index)
1335  || ind_field->prefix_len <= dfield_len);
1336  buf = static_cast<const unsigned char*>(dfield_get_data(dfield));
1337 copy_dfield:
1338  ut_a(dfield_len > 0);
1339  dfield_copy(&dfield_ext, dfield);
1340  dfield_set_data(&dfield_ext, buf, dfield_len);
1341  dfield = &dfield_ext;
1342  }
1343 
1345  dfield, &upd_field->new_val,
1346  ind_field->prefix_len)) {
1347 
1348  return(TRUE);
1349  }
1350  }
1351 
1352  return(FALSE);
1353 }
1354 
1355 /***********************************************************/
1360 UNIV_INTERN
1361 ibool
1363 /*========================================*/
1364  const dict_table_t* table,
1365  const upd_t* update)
1366 {
1367  upd_field_t* upd_field;
1368  dict_index_t* index;
1369  ulint i;
1370 
1371  index = dict_table_get_first_index(table);
1372 
1373  for (i = 0; i < upd_get_n_fields(update); i++) {
1374 
1375  upd_field = upd_get_nth_field(update, i);
1376 
1377  if (dict_field_get_col(dict_index_get_nth_field(
1378  index, upd_field->field_no))
1379  ->ord_part) {
1380 
1381  return(TRUE);
1382  }
1383  }
1384 
1385  return(FALSE);
1386 }
1387 
1388 /***********************************************************/
1393 static
1394 ibool
1395 row_upd_changes_first_fields_binary(
1396 /*================================*/
1397  dtuple_t* entry,
1398  dict_index_t* index,
1399  const upd_t* update,
1400  ulint n)
1401 {
1402  ulint n_upd_fields;
1403  ulint i, j;
1404  dict_index_t* clust_index;
1405 
1406  ut_ad(update && index);
1407  ut_ad(n <= dict_index_get_n_fields(index));
1408 
1409  n_upd_fields = upd_get_n_fields(update);
1410  clust_index = dict_table_get_first_index(index->table);
1411 
1412  for (i = 0; i < n; i++) {
1413 
1414  const dict_field_t* ind_field;
1415  const dict_col_t* col;
1416  ulint col_pos;
1417 
1418  ind_field = dict_index_get_nth_field(index, i);
1419  col = dict_field_get_col(ind_field);
1420  col_pos = dict_col_get_clust_pos(col, clust_index);
1421 
1422  ut_a(ind_field->prefix_len == 0);
1423 
1424  for (j = 0; j < n_upd_fields; j++) {
1425 
1426  upd_field_t* upd_field
1427  = upd_get_nth_field(update, j);
1428 
1429  if (col_pos == upd_field->field_no
1431  dtuple_get_nth_field(entry, i),
1432  &upd_field->new_val, 0)) {
1433 
1434  return(TRUE);
1435  }
1436  }
1437  }
1438 
1439  return(FALSE);
1440 }
1441 
1442 /*********************************************************************/
1444 UNIV_INLINE
1445 void
1446 row_upd_copy_columns(
1447 /*=================*/
1448  rec_t* rec,
1449  const ulint* offsets,
1450  sym_node_t* column)
1452 {
1453  byte* data;
1454  ulint len;
1455 
1456  while (column) {
1457  data = rec_get_nth_field(rec, offsets,
1458  column->field_nos[SYM_CLUST_FIELD_NO],
1459  &len);
1460  eval_node_copy_and_alloc_val(column, data, len);
1461 
1462  column = UT_LIST_GET_NEXT(col_var_list, column);
1463  }
1464 }
1465 
1466 /*********************************************************************/
1469 UNIV_INLINE
1470 void
1471 row_upd_eval_new_vals(
1472 /*==================*/
1473  upd_t* update)
1474 {
1475  que_node_t* exp;
1476  upd_field_t* upd_field;
1477  ulint n_fields;
1478  ulint i;
1479 
1480  n_fields = upd_get_n_fields(update);
1481 
1482  for (i = 0; i < n_fields; i++) {
1483  upd_field = upd_get_nth_field(update, i);
1484 
1485  exp = upd_field->exp;
1486 
1487  eval_exp(exp);
1488 
1489  dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1490  }
1491 }
1492 
1493 /***********************************************************/
1495 static
1496 void
1497 row_upd_store_row(
1498 /*==============*/
1499  upd_node_t* node)
1500 {
1501  dict_index_t* clust_index;
1502  rec_t* rec;
1503  mem_heap_t* heap = NULL;
1504  row_ext_t** ext;
1505  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1506  const ulint* offsets;
1507  rec_offs_init(offsets_);
1508 
1509  ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1510 
1511  if (node->row != NULL) {
1512  mem_heap_empty(node->heap);
1513  }
1514 
1515  clust_index = dict_table_get_first_index(node->table);
1516 
1517  rec = btr_pcur_get_rec(node->pcur);
1518 
1519  offsets = rec_get_offsets(rec, clust_index, offsets_,
1520  ULINT_UNDEFINED, &heap);
1521 
1523  /* In DYNAMIC or COMPRESSED format, there is no prefix
1524  of externally stored columns in the clustered index
1525  record. Build a cache of column prefixes. */
1526  ext = &node->ext;
1527  } else {
1528  /* REDUNDANT and COMPACT formats store a local
1529  768-byte prefix of each externally stored column.
1530  No cache is needed. */
1531  ext = NULL;
1532  node->ext = NULL;
1533  }
1534 
1535  node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1536  NULL, ext, node->heap);
1537  if (node->is_delete) {
1538  node->upd_row = NULL;
1539  node->upd_ext = NULL;
1540  } else {
1541  node->upd_row = dtuple_copy(node->row, node->heap);
1542  row_upd_replace(node->upd_row, &node->upd_ext,
1543  clust_index, node->update, node->heap);
1544  }
1545 
1546  if (UNIV_LIKELY_NULL(heap)) {
1547  mem_heap_free(heap);
1548  }
1549 }
1550 
1551 /***********************************************************/
1555 static
1556 ulint
1557 row_upd_sec_index_entry(
1558 /*====================*/
1559  upd_node_t* node,
1560  que_thr_t* thr)
1561 {
1562  mtr_t mtr;
1563  const rec_t* rec;
1564  btr_pcur_t pcur;
1565  mem_heap_t* heap;
1566  dtuple_t* entry;
1567  dict_index_t* index;
1568  btr_cur_t* btr_cur;
1569  ibool referenced;
1570  ulint err = DB_SUCCESS;
1571  trx_t* trx = thr_get_trx(thr);
1572  ulint mode = BTR_MODIFY_LEAF;
1573  enum row_search_result search_result;
1574 
1575  index = node->index;
1576 
1577  referenced = row_upd_index_is_referenced(index, trx);
1578 
1579  heap = mem_heap_create(1024);
1580 
1581  /* Build old index entry */
1582  entry = row_build_index_entry(node->row, node->ext, index, heap);
1583  ut_a(entry);
1584 
1585  mtr_start(&mtr);
1586 
1587  /* Set the query thread, so that ibuf_insert_low() will be
1588  able to invoke thd_get_trx(). */
1589  btr_pcur_get_btr_cur(&pcur)->thr = thr;
1590 
1591  /* We can only try to use the insert/delete buffer to buffer
1592  delete-mark operations if the index we're modifying has no foreign
1593  key constraints referring to it. */
1594  if (!referenced) {
1595  mode |= BTR_DELETE_MARK;
1596  }
1597 
1598  search_result = row_search_index_entry(index, entry, mode,
1599  &pcur, &mtr);
1600 
1601  btr_cur = btr_pcur_get_btr_cur(&pcur);
1602 
1603  rec = btr_cur_get_rec(btr_cur);
1604 
1605  switch (search_result) {
1606  case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
1607  ut_error;
1608  break;
1609  case ROW_BUFFERED:
1610  /* Entry was delete marked already. */
1611  break;
1612 
1613  case ROW_NOT_FOUND:
1614  fputs("InnoDB: error in sec index entry update in\n"
1615  "InnoDB: ", stderr);
1616  dict_index_name_print(stderr, trx, index);
1617  fputs("\n"
1618  "InnoDB: tuple ", stderr);
1619  dtuple_print(stderr, entry);
1620  fputs("\n"
1621  "InnoDB: record ", stderr);
1622  rec_print(stderr, rec, index);
1623  putc('\n', stderr);
1624 
1625  trx_print(stderr, trx, 0);
1626 
1627  fputs("\n"
1628  "InnoDB: Submit a detailed bug report"
1629  " to http://bugs.mysql.com\n", stderr);
1630  break;
1631  case ROW_FOUND:
1632  /* Delete mark the old index record; it can already be
1633  delete marked if we return after a lock wait in
1634  row_ins_index_entry below */
1635 
1636  if (!rec_get_deleted_flag(
1637  rec, dict_table_is_comp(index->table))) {
1638 
1639  err = btr_cur_del_mark_set_sec_rec(
1640  0, btr_cur, TRUE, thr, &mtr);
1641 
1642  if (err == DB_SUCCESS && referenced) {
1643 
1644  ulint* offsets;
1645 
1646  offsets = rec_get_offsets(
1647  rec, index, NULL, ULINT_UNDEFINED,
1648  &heap);
1649 
1650  /* NOTE that the following call loses
1651  the position of pcur ! */
1652  err = row_upd_check_references_constraints(
1653  node, &pcur, index->table,
1654  index, offsets, thr, &mtr);
1655  }
1656  }
1657  break;
1658  }
1659 
1660  btr_pcur_close(&pcur);
1661  mtr_commit(&mtr);
1662 
1663  if (node->is_delete || err != DB_SUCCESS) {
1664 
1665  goto func_exit;
1666  }
1667 
1668  /* Build a new index entry */
1669  entry = row_build_index_entry(node->upd_row, node->upd_ext,
1670  index, heap);
1671  ut_a(entry);
1672 
1673  /* Insert new index entry */
1674  err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1675 
1676 func_exit:
1677  mem_heap_free(heap);
1678 
1679  return(err);
1680 }
1681 
1682 /***********************************************************/
1687 static
1688 ulint
1689 row_upd_sec_step(
1690 /*=============*/
1691  upd_node_t* node,
1692  que_thr_t* thr)
1693 {
1694  ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1695  || (node->state == UPD_NODE_UPDATE_SOME_SEC));
1696  ut_ad(!dict_index_is_clust(node->index));
1697 
1698  if (node->state == UPD_NODE_UPDATE_ALL_SEC
1699  || row_upd_changes_ord_field_binary(node->index, node->update,
1700  thr, node->row, node->ext)) {
1701  return(row_upd_sec_index_entry(node, thr));
1702  }
1703 
1704  return(DB_SUCCESS);
1705 }
1706 
1707 #ifdef UNIV_DEBUG
1708 # define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
1709  row_upd_clust_rec_by_insert_inherit_func(rec,offsets,entry,update)
1710 #else /* UNIV_DEBUG */
1711 # define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
1712  row_upd_clust_rec_by_insert_inherit_func(entry,update)
1713 #endif /* UNIV_DEBUG */
1714 /*******************************************************************/
1720 static __attribute__((warn_unused_result))
1721 ibool
1722 row_upd_clust_rec_by_insert_inherit_func(
1723 /*=====================================*/
1724 #ifdef UNIV_DEBUG
1725  const rec_t* rec,
1726  const ulint* offsets,
1727 #endif /* UNIV_DEBUG */
1728  dtuple_t* entry,
1730  const upd_t* update)
1731 {
1732  ibool inherit = FALSE;
1733  ulint i;
1734 
1735  ut_ad(!rec == !offsets);
1736  ut_ad(!rec || rec_offs_any_extern(offsets));
1737 
1738  for (i = 0; i < dtuple_get_n_fields(entry); i++) {
1739  dfield_t* dfield = dtuple_get_nth_field(entry, i);
1740  byte* data;
1741  ulint len;
1742 
1743  ut_ad(!offsets
1744  || !rec_offs_nth_extern(offsets, i)
1745  == !dfield_is_ext(dfield)
1746  || upd_get_field_by_field_no(update, i));
1747  if (!dfield_is_ext(dfield)
1748  || upd_get_field_by_field_no(update, i)) {
1749  continue;
1750  }
1751 
1752 #ifdef UNIV_DEBUG
1753  if (UNIV_LIKELY(rec != NULL)) {
1754  const byte* rec_data
1755  = rec_get_nth_field(rec, offsets, i, &len);
1756  ut_ad(len == dfield_get_len(dfield));
1757  ut_ad(len != UNIV_SQL_NULL);
1759 
1760  rec_data += len - BTR_EXTERN_FIELD_REF_SIZE;
1761 
1762  /* The pointer must not be zero. */
1763  ut_ad(memcmp(rec_data, field_ref_zero,
1764  BTR_EXTERN_FIELD_REF_SIZE));
1765  /* The BLOB must be owned. */
1766  ut_ad(!(rec_data[BTR_EXTERN_LEN]
1768  }
1769 #endif /* UNIV_DEBUG */
1770 
1771  len = dfield_get_len(dfield);
1772  ut_a(len != UNIV_SQL_NULL);
1773  ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
1774  data = static_cast<unsigned char*>(dfield_get_data(dfield));
1775  data += len - BTR_EXTERN_FIELD_REF_SIZE;
1776  /* The pointer must not be zero. */
1777  ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
1778  /* The BLOB must be owned. */
1780 
1782  /* The BTR_EXTERN_INHERITED_FLAG only matters in
1783  rollback. Purge will always free the extern fields of
1784  a delete-marked row. */
1785 
1786  inherit = TRUE;
1787  }
1788 
1789  return(inherit);
1790 }
1791 
1792 /***********************************************************/
1799 static
1800 ulint
1801 row_upd_clust_rec_by_insert(
1802 /*========================*/
1803  upd_node_t* node,
1804  dict_index_t* index,
1805  que_thr_t* thr,
1806  ibool referenced,
1808  mtr_t* mtr)
1809 {
1810  mem_heap_t* heap;
1811  btr_pcur_t* pcur;
1812  btr_cur_t* btr_cur;
1813  trx_t* trx;
1814  dict_table_t* table;
1815  dtuple_t* entry;
1816  ulint err;
1817  ibool change_ownership = FALSE;
1818  rec_t* rec;
1819  ulint* offsets = NULL;
1820 
1821  ut_ad(node);
1822  ut_ad(dict_index_is_clust(index));
1823 
1824  trx = thr_get_trx(thr);
1825  table = node->table;
1826  pcur = node->pcur;
1827  btr_cur = btr_pcur_get_btr_cur(pcur);
1828 
1829  heap = mem_heap_create(1000);
1830 
1831 
1832  entry = row_build_index_entry(node->upd_row, node->upd_ext,
1833  index, heap);
1834  ut_a(entry);
1835 
1836  row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1837 
1838  switch (node->state) {
1839  default:
1840  ut_error;
1841  case UPD_NODE_INSERT_BLOB:
1842  /* A lock wait occurred in row_ins_index_entry() in
1843  the previous invocation of this function. Mark the
1844  off-page columns in the entry inherited. */
1845 
1846  change_ownership = row_upd_clust_rec_by_insert_inherit(
1847  NULL, NULL, entry, node->update);
1848  ut_a(change_ownership);
1849  /* fall through */
1850  case UPD_NODE_INSERT_CLUSTERED:
1851  /* A lock wait occurred in row_ins_index_entry() in
1852  the previous invocation of this function. */
1853  break;
1854  case UPD_NODE_UPDATE_CLUSTERED:
1855  /* This is the first invocation of the function where
1856  we update the primary key. Delete-mark the old record
1857  in the clustered index and prepare to insert a new entry. */
1858  rec = btr_cur_get_rec(btr_cur);
1859  offsets = rec_get_offsets(rec, index, NULL,
1860  ULINT_UNDEFINED, &heap);
1862 
1863  err = btr_cur_del_mark_set_clust_rec(
1864  BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
1865  rec, index, offsets, TRUE, thr, mtr);
1866  if (err != DB_SUCCESS) {
1867  err_exit:
1868  mtr_commit(mtr);
1869  mem_heap_free(heap);
1870  return(err);
1871  }
1872 
1873  /* If the the new row inherits externally stored
1874  fields (off-page columns a.k.a. BLOBs) from the
1875  delete-marked old record, mark them disowned by the
1876  old record and owned by the new entry. */
1877 
1878  if (rec_offs_any_extern(offsets)) {
1879  change_ownership = row_upd_clust_rec_by_insert_inherit(
1880  rec, offsets, entry, node->update);
1881 
1882  if (change_ownership) {
1883  btr_pcur_store_position(pcur, mtr);
1884  }
1885  }
1886 
1887  if (referenced) {
1888  /* NOTE that the following call loses
1889  the position of pcur ! */
1890 
1891  err = row_upd_check_references_constraints(
1892  node, pcur, table, index, offsets, thr, mtr);
1893 
1894  if (err != DB_SUCCESS) {
1895  goto err_exit;
1896  }
1897  }
1898  }
1899 
1900  mtr_commit(mtr);
1901 
1902  err = row_ins_index_entry(index, entry,
1903  node->upd_ext ? node->upd_ext->n_ext : 0,
1904  TRUE, thr);
1905  node->state = change_ownership
1906  ? UPD_NODE_INSERT_BLOB
1907  : UPD_NODE_INSERT_CLUSTERED;
1908 
1909  if (err == DB_SUCCESS && change_ownership) {
1910  /* Mark the non-updated fields disowned by the old record. */
1911 
1912  /* NOTE: this transaction has an x-lock on the record
1913  and therefore other transactions cannot modify the
1914  record when we have no latch on the page. In addition,
1915  we assume that other query threads of the same
1916  transaction do not modify the record in the meantime.
1917  Therefore we can assert that the restoration of the
1918  cursor succeeds. */
1919 
1920  mtr_start(mtr);
1921 
1922  if (!btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr)) {
1923  ut_error;
1924  }
1925 
1926  rec = btr_cur_get_rec(btr_cur);
1927  offsets = rec_get_offsets(rec, index, offsets,
1928  ULINT_UNDEFINED, &heap);
1930 
1932  btr_cur_get_page_zip(btr_cur),
1933  rec, index, offsets, node->update, mtr);
1934 
1935  mtr_commit(mtr);
1936  }
1937 
1938  mem_heap_free(heap);
1939 
1940  return(err);
1941 }
1942 
1943 /***********************************************************/
1948 static
1949 ulint
1950 row_upd_clust_rec(
1951 /*==============*/
1952  upd_node_t* node,
1953  dict_index_t* index,
1954  que_thr_t* thr,
1955  mtr_t* mtr)
1956 {
1957  mem_heap_t* heap = NULL;
1958  big_rec_t* big_rec = NULL;
1959  btr_pcur_t* pcur;
1960  btr_cur_t* btr_cur;
1961  ulint err;
1962 
1963  ut_ad(node);
1964  ut_ad(dict_index_is_clust(index));
1965 
1966  pcur = node->pcur;
1967  btr_cur = btr_pcur_get_btr_cur(pcur);
1968 
1969  ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1970  dict_table_is_comp(index->table)));
1971 
1972  /* Try optimistic updating of the record, keeping changes within
1973  the page; we do not check locks because we assume the x-lock on the
1974  record to update */
1975 
1976  if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1977  err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1978  btr_cur, node->update,
1979  node->cmpl_info, thr, mtr);
1980  } else {
1981  err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1982  btr_cur, node->update,
1983  node->cmpl_info, thr, mtr);
1984  }
1985 
1986  mtr_commit(mtr);
1987 
1988  if (UNIV_LIKELY(err == DB_SUCCESS)) {
1989 
1990  return(DB_SUCCESS);
1991  }
1992 
1993  if (buf_LRU_buf_pool_running_out()) {
1994 
1995  return(DB_LOCK_TABLE_FULL);
1996  }
1997  /* We may have to modify the tree structure: do a pessimistic descent
1998  down the index tree */
1999 
2000  mtr_start(mtr);
2001 
2002  /* NOTE: this transaction has an s-lock or x-lock on the record and
2003  therefore other transactions cannot modify the record when we have no
2004  latch on the page. In addition, we assume that other query threads of
2005  the same transaction do not modify the record in the meantime.
2006  Therefore we can assert that the restoration of the cursor succeeds. */
2007 
2008  ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
2009 
2010  ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
2011  dict_table_is_comp(index->table)));
2012 
2013  err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
2014  &heap, &big_rec, node->update,
2015  node->cmpl_info, thr, mtr);
2016  mtr_commit(mtr);
2017 
2018  if (err == DB_SUCCESS && big_rec) {
2019  ulint offsets_[REC_OFFS_NORMAL_SIZE];
2020  rec_t* rec;
2021  rec_offs_init(offsets_);
2022 
2023  mtr_start(mtr);
2024 
2025  ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
2026  rec = btr_cur_get_rec(btr_cur);
2028  index, btr_cur_get_block(btr_cur), rec,
2029  rec_get_offsets(rec, index, offsets_,
2030  ULINT_UNDEFINED, &heap),
2031  mtr, TRUE, big_rec);
2032  mtr_commit(mtr);
2033  }
2034 
2035  if (UNIV_LIKELY_NULL(heap)) {
2036  mem_heap_free(heap);
2037  }
2038 
2039  if (big_rec) {
2040  dtuple_big_rec_free(big_rec);
2041  }
2042 
2043  return(err);
2044 }
2045 
2046 /***********************************************************/
2049 static
2050 ulint
2051 row_upd_del_mark_clust_rec(
2052 /*=======================*/
2053  upd_node_t* node,
2054  dict_index_t* index,
2055  ulint* offsets,
2057  que_thr_t* thr,
2058  ibool referenced,
2061  mtr_t* mtr)
2062 {
2063  btr_pcur_t* pcur;
2064  btr_cur_t* btr_cur;
2065  ulint err;
2066 
2067  ut_ad(node);
2068  ut_ad(dict_index_is_clust(index));
2069  ut_ad(node->is_delete);
2070 
2071  pcur = node->pcur;
2072  btr_cur = btr_pcur_get_btr_cur(pcur);
2073 
2074  /* Store row because we have to build also the secondary index
2075  entries */
2076 
2077  row_upd_store_row(node);
2078 
2079  /* Mark the clustered index record deleted; we do not have to check
2080  locks, because we assume that we have an x-lock on the record */
2081 
2082  err = btr_cur_del_mark_set_clust_rec(
2083  BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
2084  btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
2085  if (err == DB_SUCCESS && referenced) {
2086  /* NOTE that the following call loses the position of pcur ! */
2087 
2088  err = row_upd_check_references_constraints(
2089  node, pcur, index->table, index, offsets, thr, mtr);
2090  }
2091 
2092  mtr_commit(mtr);
2093 
2094  return(err);
2095 }
2096 
2097 /***********************************************************/
2101 static
2102 ulint
2103 row_upd_clust_step(
2104 /*===============*/
2105  upd_node_t* node,
2106  que_thr_t* thr)
2107 {
2108  dict_index_t* index;
2109  btr_pcur_t* pcur;
2110  ibool success;
2111  ulint err;
2112  mtr_t* mtr;
2113  mtr_t mtr_buf;
2114  rec_t* rec;
2115  mem_heap_t* heap = NULL;
2116  ulint offsets_[REC_OFFS_NORMAL_SIZE];
2117  ulint* offsets;
2118  ibool referenced;
2119  rec_offs_init(offsets_);
2120 
2121  index = dict_table_get_first_index(node->table);
2122 
2123  referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
2124 
2125  pcur = node->pcur;
2126 
2127  /* We have to restore the cursor to its position */
2128  mtr = &mtr_buf;
2129 
2130  mtr_start(mtr);
2131 
2132  /* If the restoration does not succeed, then the same
2133  transaction has deleted the record on which the cursor was,
2134  and that is an SQL error. If the restoration succeeds, it may
2135  still be that the same transaction has successively deleted
2136  and inserted a record with the same ordering fields, but in
2137  that case we know that the transaction has at least an
2138  implicit x-lock on the record. */
2139 
2140  ut_a(pcur->rel_pos == BTR_PCUR_ON);
2141 
2142  success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
2143 
2144  if (!success) {
2145  err = DB_RECORD_NOT_FOUND;
2146 
2147  mtr_commit(mtr);
2148 
2149  return(err);
2150  }
2151 
2152  /* If this is a row in SYS_INDEXES table of the data dictionary,
2153  then we have to free the file segments of the index tree associated
2154  with the index */
2155 
2156  if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
2157 
2158  dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
2159 
2160  mtr_commit(mtr);
2161 
2162  mtr_start(mtr);
2163 
2164  success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
2165  mtr);
2166  if (!success) {
2167  err = DB_ERROR;
2168 
2169  mtr_commit(mtr);
2170 
2171  return(err);
2172  }
2173  }
2174 
2175  rec = btr_pcur_get_rec(pcur);
2176  offsets = rec_get_offsets(rec, index, offsets_,
2177  ULINT_UNDEFINED, &heap);
2178 
2179  if (!node->has_clust_rec_x_lock) {
2181  0, btr_pcur_get_block(pcur),
2182  rec, index, offsets, thr);
2183  if (err != DB_SUCCESS) {
2184  mtr_commit(mtr);
2185  goto exit_func;
2186  }
2187  }
2188 
2189  /* NOTE: the following function calls will also commit mtr */
2190 
2191  if (node->is_delete) {
2192  err = row_upd_del_mark_clust_rec(
2193  node, index, offsets, thr, referenced, mtr);
2194 
2195  if (err == DB_SUCCESS) {
2196  node->state = UPD_NODE_UPDATE_ALL_SEC;
2197  node->index = dict_table_get_next_index(index);
2198  }
2199 exit_func:
2200  if (UNIV_LIKELY_NULL(heap)) {
2201  mem_heap_free(heap);
2202  }
2203  return(err);
2204  }
2205 
2206  /* If the update is made for MySQL, we already have the update vector
2207  ready, else we have to do some evaluation: */
2208 
2209  if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
2210  /* Copy the necessary columns from clust_rec and calculate the
2211  new values to set */
2212  row_upd_copy_columns(rec, offsets,
2213  UT_LIST_GET_FIRST(node->columns));
2214  row_upd_eval_new_vals(node->update);
2215  }
2216 
2217  if (UNIV_LIKELY_NULL(heap)) {
2218  mem_heap_free(heap);
2219  }
2220 
2221  if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
2222 
2223  err = row_upd_clust_rec(node, index, thr, mtr);
2224  return(err);
2225  }
2226 
2227  row_upd_store_row(node);
2228 
2229  if (row_upd_changes_ord_field_binary(index, node->update, thr,
2230  node->row, node->ext)) {
2231 
2232  /* Update causes an ordering field (ordering fields within
2233  the B-tree) of the clustered index record to change: perform
2234  the update by delete marking and inserting.
2235 
2236  TODO! What to do to the 'Halloween problem', where an update
2237  moves the record forward in index so that it is again
2238  updated when the cursor arrives there? Solution: the
2239  read operation must check the undo record undo number when
2240  choosing records to update. MySQL solves now the problem
2241  externally! */
2242 
2243  err = row_upd_clust_rec_by_insert(
2244  node, index, thr, referenced, mtr);
2245 
2246  if (err != DB_SUCCESS) {
2247 
2248  return(err);
2249  }
2250 
2251  node->state = UPD_NODE_UPDATE_ALL_SEC;
2252  } else {
2253  err = row_upd_clust_rec(node, index, thr, mtr);
2254 
2255  if (err != DB_SUCCESS) {
2256 
2257  return(err);
2258  }
2259 
2260  node->state = UPD_NODE_UPDATE_SOME_SEC;
2261  }
2262 
2263  node->index = dict_table_get_next_index(index);
2264 
2265  return(err);
2266 }
2267 
2268 /***********************************************************/
2274 static
2275 ulint
2276 row_upd(
2277 /*====*/
2278  upd_node_t* node,
2279  que_thr_t* thr)
2280 {
2281  ulint err = DB_SUCCESS;
2282 
2283  ut_ad(node && thr);
2284 
2285  if (UNIV_LIKELY(node->in_mysql_interface)) {
2286 
2287  /* We do not get the cmpl_info value from the MySQL
2288  interpreter: we must calculate it on the fly: */
2289 
2290  if (node->is_delete
2292  node->table, node->update)) {
2293  node->cmpl_info = 0;
2294  } else {
2295  node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
2296  }
2297  }
2298 
2299  if (node->state == UPD_NODE_UPDATE_CLUSTERED
2300  || node->state == UPD_NODE_INSERT_CLUSTERED
2301  || node->state == UPD_NODE_INSERT_BLOB) {
2302 
2303  log_free_check();
2304  err = row_upd_clust_step(node, thr);
2305 
2306  if (err != DB_SUCCESS) {
2307 
2308  goto function_exit;
2309  }
2310  }
2311 
2312  if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
2313 
2314  goto function_exit;
2315  }
2316 
2317  while (node->index != NULL) {
2318 
2319  log_free_check();
2320  err = row_upd_sec_step(node, thr);
2321 
2322  if (err != DB_SUCCESS) {
2323 
2324  goto function_exit;
2325  }
2326 
2327  node->index = dict_table_get_next_index(node->index);
2328  }
2329 
2330 function_exit:
2331  if (err == DB_SUCCESS) {
2332  /* Do some cleanup */
2333 
2334  if (node->row != NULL) {
2335  node->row = NULL;
2336  node->ext = NULL;
2337  node->upd_row = NULL;
2338  node->upd_ext = NULL;
2339  mem_heap_empty(node->heap);
2340  }
2341 
2342  node->state = UPD_NODE_UPDATE_CLUSTERED;
2343  }
2344 
2345  return(err);
2346 }
2347 
2348 /***********************************************************/
2352 UNIV_INTERN
2353 que_thr_t*
2355 /*=========*/
2356  que_thr_t* thr)
2357 {
2358  upd_node_t* node;
2359  sel_node_t* sel_node;
2360  que_node_t* parent;
2361  ulint err = DB_SUCCESS;
2362  trx_t* trx;
2363 
2364  ut_ad(thr);
2365 
2366  trx = thr_get_trx(thr);
2367 
2369 
2370  node = static_cast<upd_node_t *>(thr->run_node);
2371 
2372  sel_node = node->select;
2373 
2374  parent = que_node_get_parent(node);
2375 
2376  ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2377 
2378  if (thr->prev_node == parent) {
2379  node->state = UPD_NODE_SET_IX_LOCK;
2380  }
2381 
2382  if (node->state == UPD_NODE_SET_IX_LOCK) {
2383 
2384  if (!node->has_clust_rec_x_lock) {
2385  /* It may be that the current session has not yet
2386  started its transaction, or it has been committed: */
2387 
2388  err = lock_table(0, node->table, LOCK_IX, thr);
2389 
2390  if (err != DB_SUCCESS) {
2391 
2392  goto error_handling;
2393  }
2394  }
2395 
2396  node->state = UPD_NODE_UPDATE_CLUSTERED;
2397 
2398  if (node->searched_update) {
2399  /* Reset the cursor */
2400  sel_node->state = SEL_NODE_OPEN;
2401 
2402  /* Fetch a row to update */
2403 
2404  thr->run_node = sel_node;
2405 
2406  return(thr);
2407  }
2408  }
2409 
2410  /* sel_node is NULL if we are in the MySQL interface */
2411 
2412  if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
2413 
2414  if (!node->searched_update) {
2415  /* An explicit cursor should be positioned on a row
2416  to update */
2417 
2418  ut_error;
2419 
2420  err = DB_ERROR;
2421 
2422  goto error_handling;
2423  }
2424 
2425  ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2426 
2427  /* No more rows to update, or the select node performed the
2428  updates directly in-place */
2429 
2430  thr->run_node = parent;
2431 
2432  return(thr);
2433  }
2434 
2435  /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2436 
2437  err = row_upd(node, thr);
2438 
2439 error_handling:
2440  trx->error_state = err;
2441 
2442  if (err != DB_SUCCESS) {
2443  return(NULL);
2444  }
2445 
2446  /* DO THE TRIGGER ACTIONS HERE */
2447 
2448  if (node->searched_update) {
2449  /* Fetch next row to update */
2450 
2451  thr->run_node = sel_node;
2452  } else {
2453  /* It was an explicit cursor update */
2454 
2455  thr->run_node = parent;
2456  }
2457 
2458  node->state = UPD_NODE_UPDATE_CLUSTERED;
2459 
2460  return(thr);
2461 }
2462 #endif /* !UNIV_HOTBACKUP */