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,
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  upd_field = upd_get_nth_field(update, i);
512  new_val = &(upd_field->new_val);
513  ut_ad(!dfield_is_ext(new_val) ==
514  !rec_offs_nth_extern(offsets, upd_field->field_no));
515 
516  rec_set_nth_field(rec, offsets, upd_field->field_no,
517  dfield_get_data(new_val),
518  dfield_get_len(new_val));
519  }
520 
521  if (UNIV_LIKELY_NULL(page_zip)) {
522  page_zip_write_rec(page_zip, rec, index, offsets, 0);
523  }
524 }
525 
526 #ifndef UNIV_HOTBACKUP
527 /*********************************************************************/
531 UNIV_INTERN
532 byte*
534 /*==========================*/
535  dict_index_t* index,
536  trx_t* trx,
537  roll_ptr_t roll_ptr,
538  byte* log_ptr,
540  mtr_t* /*mtr __attribute__((unused))*/)
541 {
542  ut_ad(dict_index_is_clust(index));
543  ut_ad(mtr);
544 
545  log_ptr += mach_write_compressed(log_ptr,
547  index, DATA_TRX_ID));
548 
549  trx_write_roll_ptr(log_ptr, roll_ptr);
550  log_ptr += DATA_ROLL_PTR_LEN;
551 
552  log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
553 
554  return(log_ptr);
555 }
556 #endif /* !UNIV_HOTBACKUP */
557 
558 /*********************************************************************/
561 UNIV_INTERN
562 byte*
564 /*===================*/
565  byte* ptr,
566  byte* end_ptr,
567  ulint* pos,
568  trx_id_t* trx_id,
569  roll_ptr_t* roll_ptr)
570 {
571  ptr = mach_parse_compressed(ptr, end_ptr, pos);
572 
573  if (ptr == NULL) {
574 
575  return(NULL);
576  }
577 
578  if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
579 
580  return(NULL);
581  }
582 
583  *roll_ptr = trx_read_roll_ptr(ptr);
584  ptr += DATA_ROLL_PTR_LEN;
585 
586  ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
587 
588  return(ptr);
589 }
590 
591 #ifndef UNIV_HOTBACKUP
592 /***********************************************************/
594 UNIV_INTERN
595 void
597 /*====================*/
598  const upd_t* update,
599  byte* log_ptr,
603  mtr_t* mtr)
604 {
605  const upd_field_t* upd_field;
606  const dfield_t* new_val;
607  ulint len;
608  ulint n_fields;
609  byte* buf_end;
610  ulint i;
611 
612  n_fields = upd_get_n_fields(update);
613 
614  buf_end = log_ptr + MLOG_BUF_MARGIN;
615 
616  mach_write_to_1(log_ptr, update->info_bits);
617  log_ptr++;
618  log_ptr += mach_write_compressed(log_ptr, n_fields);
619 
620  for (i = 0; i < n_fields; i++) {
621 
622 #if MLOG_BUF_MARGIN <= 30
623 # error "MLOG_BUF_MARGIN <= 30"
624 #endif
625 
626  if (log_ptr + 30 > buf_end) {
627  mlog_close(mtr, log_ptr);
628 
629  log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
630  buf_end = log_ptr + MLOG_BUF_MARGIN;
631  }
632 
633  upd_field = upd_get_nth_field(update, i);
634 
635  new_val = &(upd_field->new_val);
636 
637  len = dfield_get_len(new_val);
638 
639  log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
640  log_ptr += mach_write_compressed(log_ptr, len);
641 
642  if (len != UNIV_SQL_NULL) {
643  if (log_ptr + len < buf_end) {
644  memcpy(log_ptr, dfield_get_data(new_val), len);
645 
646  log_ptr += len;
647  } else {
648  mlog_close(mtr, log_ptr);
649 
651  static_cast<byte *>(dfield_get_data(new_val)),
652  len);
653 
654  log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
655  buf_end = log_ptr + MLOG_BUF_MARGIN;
656  }
657  }
658  }
659 
660  mlog_close(mtr, log_ptr);
661 }
662 #endif /* !UNIV_HOTBACKUP */
663 
664 /*********************************************************************/
667 UNIV_INTERN
668 byte*
670 /*================*/
671  byte* ptr,
672  byte* end_ptr,
673  mem_heap_t* heap,
675  upd_t** update_out)
676 {
677  upd_t* update;
678  upd_field_t* upd_field;
679  dfield_t* new_val;
680  ulint len;
681  ulint n_fields;
682  ulint info_bits;
683  ulint i;
684 
685  if (end_ptr < ptr + 1) {
686 
687  return(NULL);
688  }
689 
690  info_bits = mach_read_from_1(ptr);
691  ptr++;
692  ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
693 
694  if (ptr == NULL) {
695 
696  return(NULL);
697  }
698 
699  update = upd_create(n_fields, heap);
700  update->info_bits = info_bits;
701 
702  for (i = 0; i < n_fields; i++) {
703  ulint field_no;
704  upd_field = upd_get_nth_field(update, i);
705  new_val = &(upd_field->new_val);
706 
707  ptr = mach_parse_compressed(ptr, end_ptr, &field_no);
708 
709  if (ptr == NULL) {
710 
711  return(NULL);
712  }
713 
714  upd_field->field_no = field_no;
715 
716  ptr = mach_parse_compressed(ptr, end_ptr, &len);
717 
718  if (ptr == NULL) {
719 
720  return(NULL);
721  }
722 
723  if (len != UNIV_SQL_NULL) {
724 
725  if (end_ptr < ptr + len) {
726 
727  return(NULL);
728  }
729 
730  dfield_set_data(new_val,
731  mem_heap_dup(heap, ptr, len), len);
732  ptr += len;
733  } else {
734  dfield_set_null(new_val);
735  }
736  }
737 
738  *update_out = update;
739 
740  return(ptr);
741 }
742 
743 #ifndef UNIV_HOTBACKUP
744 /***************************************************************/
749 UNIV_INTERN
750 upd_t*
752 /*====================================*/
753  dict_index_t* index,
754  const dtuple_t* entry,
755  const rec_t* rec,
756  trx_t* trx,
757  mem_heap_t* heap)
758 {
759  upd_field_t* upd_field;
760  const dfield_t* dfield;
761  const byte* data;
762  ulint len;
763  upd_t* update;
764  ulint n_diff;
765  ulint i;
766  ulint offsets_[REC_OFFS_SMALL_SIZE];
767  const ulint* offsets;
768  rec_offs_init(offsets_);
769 
770  /* This function is used only for a secondary index */
771  ut_a(!dict_index_is_clust(index));
772 
773  update = upd_create(dtuple_get_n_fields(entry), heap);
774 
775  n_diff = 0;
776  offsets = rec_get_offsets(rec, index, offsets_,
777  ULINT_UNDEFINED, &heap);
778 
779  for (i = 0; i < dtuple_get_n_fields(entry); i++) {
780 
781  data = rec_get_nth_field(rec, offsets, i, &len);
782 
783  dfield = dtuple_get_nth_field(entry, i);
784 
785  /* NOTE that it may be that len != dfield_get_len(dfield) if we
786  are updating in a character set and collation where strings of
787  different length can be equal in an alphabetical comparison,
788  and also in the case where we have a column prefix index
789  and the last characters in the index field are spaces; the
790  latter case probably caused the assertion failures reported at
791  row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
792 
793  /* NOTE: we compare the fields as binary strings!
794  (No collation) */
795 
796  if (!dfield_data_is_binary_equal(dfield, len, data)) {
797 
798  upd_field = upd_get_nth_field(update, n_diff);
799 
800  dfield_copy(&(upd_field->new_val), dfield);
801 
802  upd_field_set_field_no(upd_field, i, index, trx);
803 
804  n_diff++;
805  }
806  }
807 
808  update->n_fields = n_diff;
809 
810  return(update);
811 }
812 
813 /***************************************************************/
819 UNIV_INTERN
820 upd_t*
822 /*============================*/
823  dict_index_t* index,
824  const dtuple_t* entry,
825  const rec_t* rec,
826  trx_t* trx,
827  mem_heap_t* heap)
828 {
829  upd_field_t* upd_field;
830  const dfield_t* dfield;
831  const byte* data;
832  ulint len;
833  upd_t* update;
834  ulint n_diff;
835  ulint roll_ptr_pos;
836  ulint trx_id_pos;
837  ulint i;
838  ulint offsets_[REC_OFFS_NORMAL_SIZE];
839  const ulint* offsets;
840  rec_offs_init(offsets_);
841 
842  /* This function is used only for a clustered index */
843  ut_a(dict_index_is_clust(index));
844 
845  update = upd_create(dtuple_get_n_fields(entry), heap);
846 
847  n_diff = 0;
848 
849  roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
850  trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
851 
852  offsets = rec_get_offsets(rec, index, offsets_,
853  ULINT_UNDEFINED, &heap);
854 
855  for (i = 0; i < dtuple_get_n_fields(entry); i++) {
856 
857  data = rec_get_nth_field(rec, offsets, i, &len);
858 
859  dfield = dtuple_get_nth_field(entry, i);
860 
861  /* NOTE: we compare the fields as binary strings!
862  (No collation) */
863 
864  if (i == trx_id_pos || i == roll_ptr_pos) {
865 
866  goto skip_compare;
867  }
868 
869  if (UNIV_UNLIKELY(!dfield_is_ext(dfield)
870  != !rec_offs_nth_extern(offsets, i))
871  || !dfield_data_is_binary_equal(dfield, len, data)) {
872 
873  upd_field = upd_get_nth_field(update, n_diff);
874 
875  dfield_copy(&(upd_field->new_val), dfield);
876 
877  upd_field_set_field_no(upd_field, i, index, trx);
878 
879  n_diff++;
880  }
881 skip_compare:
882  ;
883  }
884 
885  update->n_fields = n_diff;
886 
887  return(update);
888 }
889 
890 /***********************************************************/
895 static
896 byte*
897 row_upd_ext_fetch(
898 /*==============*/
899  const byte* data,
902  ulint local_len,
903  ulint zip_size,
906  ulint* len,
908  mem_heap_t* heap)
909 {
910  byte* buf = static_cast<byte *>(mem_heap_alloc(heap, *len));
911 
912  *len = btr_copy_externally_stored_field_prefix(buf, *len,
913  zip_size,
914  data, local_len);
915  /* We should never update records containing a half-deleted BLOB. */
916  ut_a(*len);
917 
918  return(buf);
919 }
920 
921 /***********************************************************/
924 static
925 void
926 row_upd_index_replace_new_col_val(
927 /*==============================*/
928  dfield_t* dfield,
930  const dict_field_t* field,
931  const dict_col_t* col,
932  const upd_field_t* uf,
933  mem_heap_t* heap,
935  ulint zip_size)
937 {
938  ulint len;
939  const byte* data;
940 
941  dfield_copy_data(dfield, &uf->new_val);
942 
943  if (dfield_is_null(dfield)) {
944  return;
945  }
946 
947  len = dfield_get_len(dfield);
948  data = static_cast<const byte *>(dfield_get_data(dfield));
949 
950  if (field->prefix_len > 0) {
951  ibool fetch_ext = dfield_is_ext(dfield)
952  && len < (ulint) field->prefix_len
954 
955  if (fetch_ext) {
956  ulint l = len;
957 
958  len = field->prefix_len;
959 
960  data = row_upd_ext_fetch(data, l, zip_size,
961  &len, heap);
962  }
963 
964  len = dtype_get_at_most_n_mbchars(col->prtype,
965  col->mbminmaxlen,
966  field->prefix_len, len,
967  (const char*) data);
968 
969  dfield_set_data(dfield, data, len);
970 
971  if (!fetch_ext) {
972  dfield_dup(dfield, heap);
973  }
974 
975  return;
976  }
977 
978  switch (uf->orig_len) {
979  byte* buf;
981  /* Restore the original locally stored
982  part of the column. In the undo log,
983  InnoDB writes a longer prefix of externally
984  stored columns, so that column prefixes
985  in secondary indexes can be reconstructed. */
986  dfield_set_data(dfield,
987  data + len - BTR_EXTERN_FIELD_REF_SIZE,
989  dfield_set_ext(dfield);
990  /* fall through */
991  case 0:
992  dfield_dup(dfield, heap);
993  break;
994  default:
995  /* Reconstruct the original locally
996  stored part of the column. The data
997  will have to be copied. */
999  buf = static_cast<byte *>(mem_heap_alloc(heap, uf->orig_len));
1000  /* Copy the locally stored prefix. */
1001  memcpy(buf, data,
1003  /* Copy the BLOB pointer. */
1004  memcpy(buf + uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE,
1005  data + len - BTR_EXTERN_FIELD_REF_SIZE,
1007 
1008  dfield_set_data(dfield, buf, uf->orig_len);
1009  dfield_set_ext(dfield);
1010  break;
1011  }
1012 }
1013 
1014 /***********************************************************/
1017 UNIV_INTERN
1018 void
1020 /*=========================================*/
1021  dtuple_t* entry,
1025  dict_index_t* index,
1027  const upd_t* update,
1030  ibool order_only,
1034  mem_heap_t* heap)
1036 {
1037  ulint i;
1038  ulint n_fields;
1039  const ulint zip_size = dict_table_zip_size(index->table);
1040 
1041  ut_ad(index);
1042 
1043  dtuple_set_info_bits(entry, update->info_bits);
1044 
1045  if (order_only) {
1046  n_fields = dict_index_get_n_unique(index);
1047  } else {
1048  n_fields = dict_index_get_n_fields(index);
1049  }
1050 
1051  for (i = 0; i < n_fields; i++) {
1052  const dict_field_t* field;
1053  const dict_col_t* col;
1054  const upd_field_t* uf;
1055 
1056  field = dict_index_get_nth_field(index, i);
1057  col = dict_field_get_col(field);
1058  uf = upd_get_field_by_field_no(update, i);
1059 
1060  if (uf) {
1061  row_upd_index_replace_new_col_val(
1062  dtuple_get_nth_field(entry, i),
1063  field, col, uf, heap, zip_size);
1064  }
1065  }
1066 }
1067 
1068 /***********************************************************/
1071 UNIV_INTERN
1072 void
1074 /*===============================*/
1075  dtuple_t* entry,
1079  dict_index_t* index,
1081  const upd_t* update,
1084  mem_heap_t* heap)
1086 {
1087  ulint i;
1088  const dict_index_t* clust_index
1089  = dict_table_get_first_index(index->table);
1090  const ulint zip_size
1091  = dict_table_zip_size(index->table);
1092 
1093  dtuple_set_info_bits(entry, update->info_bits);
1094 
1095  for (i = 0; i < dict_index_get_n_fields(index); i++) {
1096  const dict_field_t* field;
1097  const dict_col_t* col;
1098  const upd_field_t* uf;
1099 
1100  field = dict_index_get_nth_field(index, i);
1101  col = dict_field_get_col(field);
1103  update, dict_col_get_clust_pos(col, clust_index));
1104 
1105  if (uf) {
1106  row_upd_index_replace_new_col_val(
1107  dtuple_get_nth_field(entry, i),
1108  field, col, uf, heap, zip_size);
1109  }
1110  }
1111 }
1112 
1113 /***********************************************************/
1115 UNIV_INTERN
1116 void
1118 /*============*/
1119  dtuple_t* row,
1124  row_ext_t** ext,
1126  const dict_index_t* index,
1127  const upd_t* update,
1129  mem_heap_t* heap)
1130 {
1131  ulint col_no;
1132  ulint i;
1133  ulint n_cols;
1134  ulint n_ext_cols;
1135  ulint* ext_cols;
1136  const dict_table_t* table;
1137 
1138  ut_ad(row);
1139  ut_ad(ext);
1140  ut_ad(index);
1141  ut_ad(dict_index_is_clust(index));
1142  ut_ad(update);
1143  ut_ad(heap);
1144 
1145  n_cols = dtuple_get_n_fields(row);
1146  table = index->table;
1147  ut_ad(n_cols == dict_table_get_n_cols(table));
1148 
1149  ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_cols * sizeof *ext_cols));
1150  n_ext_cols = 0;
1151 
1152  dtuple_set_info_bits(row, update->info_bits);
1153 
1154  for (col_no = 0; col_no < n_cols; col_no++) {
1155 
1156  const dict_col_t* col
1157  = dict_table_get_nth_col(table, col_no);
1158  const ulint clust_pos
1159  = dict_col_get_clust_pos(col, index);
1160  dfield_t* dfield;
1161 
1162  if (UNIV_UNLIKELY(clust_pos == ULINT_UNDEFINED)) {
1163 
1164  continue;
1165  }
1166 
1167  dfield = dtuple_get_nth_field(row, col_no);
1168 
1169  for (i = 0; i < upd_get_n_fields(update); i++) {
1170 
1171  const upd_field_t* upd_field
1172  = upd_get_nth_field(update, i);
1173 
1174  if (upd_field->field_no != clust_pos) {
1175 
1176  continue;
1177  }
1178 
1179  dfield_copy_data(dfield, &upd_field->new_val);
1180  break;
1181  }
1182 
1183  if (dfield_is_ext(dfield) && col->ord_part) {
1184  ext_cols[n_ext_cols++] = col_no;
1185  }
1186  }
1187 
1188  if (n_ext_cols) {
1189  *ext = row_ext_create(n_ext_cols, ext_cols, row,
1190  dict_table_zip_size(table), heap);
1191  } else {
1192  *ext = NULL;
1193  }
1194 }
1195 
1196 /***********************************************************/
1203 UNIV_INTERN
1204 ibool
1206 /*=============================*/
1207  const dtuple_t* row,
1211  dict_index_t* index,
1212  const upd_t* update)
1215 {
1216  ulint n_unique;
1217  ulint n_upd_fields;
1218  ulint i, j;
1219  dict_index_t* clust_index;
1220 
1221  ut_ad(update && index);
1222 
1223  n_unique = dict_index_get_n_unique(index);
1224  n_upd_fields = upd_get_n_fields(update);
1225 
1226  clust_index = dict_table_get_first_index(index->table);
1227 
1228  for (i = 0; i < n_unique; i++) {
1229 
1230  const dict_field_t* ind_field;
1231  const dict_col_t* col;
1232  ulint col_pos;
1233  ulint col_no;
1234 
1235  ind_field = dict_index_get_nth_field(index, i);
1236  col = dict_field_get_col(ind_field);
1237  col_pos = dict_col_get_clust_pos(col, clust_index);
1238  col_no = dict_col_get_no(col);
1239 
1240  for (j = 0; j < n_upd_fields; j++) {
1241 
1242  const upd_field_t* upd_field
1243  = upd_get_nth_field(update, j);
1244 
1245  /* Note that if the index field is a column prefix
1246  then it may be that row does not contain an externally
1247  stored part of the column value, and we cannot compare
1248  the datas */
1249 
1250  if (col_pos == upd_field->field_no
1251  && (row == NULL
1252  || ind_field->prefix_len > 0
1254  dtuple_get_nth_field(row, col_no),
1255  &(upd_field->new_val)))) {
1256 
1257  return(TRUE);
1258  }
1259  }
1260  }
1261 
1262  return(FALSE);
1263 }
1264 
1265 /***********************************************************/
1270 UNIV_INTERN
1271 ibool
1273 /*========================================*/
1274  const dict_table_t* table,
1275  const upd_t* update)
1276 {
1277  upd_field_t* upd_field;
1278  dict_index_t* index;
1279  ulint i;
1280 
1281  index = dict_table_get_first_index(table);
1282 
1283  for (i = 0; i < upd_get_n_fields(update); i++) {
1284 
1285  upd_field = upd_get_nth_field(update, i);
1286 
1287  if (dict_field_get_col(dict_index_get_nth_field(
1288  index, upd_field->field_no))
1289  ->ord_part) {
1290 
1291  return(TRUE);
1292  }
1293  }
1294 
1295  return(FALSE);
1296 }
1297 
1298 /***********************************************************/
1303 static
1304 ibool
1305 row_upd_changes_first_fields_binary(
1306 /*================================*/
1307  dtuple_t* entry,
1308  dict_index_t* index,
1309  const upd_t* update,
1310  ulint n)
1311 {
1312  ulint n_upd_fields;
1313  ulint i, j;
1314  dict_index_t* clust_index;
1315 
1316  ut_ad(update && index);
1317  ut_ad(n <= dict_index_get_n_fields(index));
1318 
1319  n_upd_fields = upd_get_n_fields(update);
1320  clust_index = dict_table_get_first_index(index->table);
1321 
1322  for (i = 0; i < n; i++) {
1323 
1324  const dict_field_t* ind_field;
1325  const dict_col_t* col;
1326  ulint col_pos;
1327 
1328  ind_field = dict_index_get_nth_field(index, i);
1329  col = dict_field_get_col(ind_field);
1330  col_pos = dict_col_get_clust_pos(col, clust_index);
1331 
1332  ut_a(ind_field->prefix_len == 0);
1333 
1334  for (j = 0; j < n_upd_fields; j++) {
1335 
1336  upd_field_t* upd_field
1337  = upd_get_nth_field(update, j);
1338 
1339  if (col_pos == upd_field->field_no
1341  dtuple_get_nth_field(entry, i),
1342  &(upd_field->new_val))) {
1343 
1344  return(TRUE);
1345  }
1346  }
1347  }
1348 
1349  return(FALSE);
1350 }
1351 
1352 /*********************************************************************/
1354 UNIV_INLINE
1355 void
1356 row_upd_copy_columns(
1357 /*=================*/
1358  rec_t* rec,
1359  const ulint* offsets,
1360  sym_node_t* column)
1362 {
1363  byte* data;
1364  ulint len;
1365 
1366  while (column) {
1367  data = rec_get_nth_field(rec, offsets,
1368  column->field_nos[SYM_CLUST_FIELD_NO],
1369  &len);
1370  eval_node_copy_and_alloc_val(column, data, len);
1371 
1372  column = UT_LIST_GET_NEXT(col_var_list, column);
1373  }
1374 }
1375 
1376 /*********************************************************************/
1379 UNIV_INLINE
1380 void
1381 row_upd_eval_new_vals(
1382 /*==================*/
1383  upd_t* update)
1384 {
1385  que_node_t* exp;
1386  upd_field_t* upd_field;
1387  ulint n_fields;
1388  ulint i;
1389 
1390  n_fields = upd_get_n_fields(update);
1391 
1392  for (i = 0; i < n_fields; i++) {
1393  upd_field = upd_get_nth_field(update, i);
1394 
1395  exp = upd_field->exp;
1396 
1397  eval_exp(exp);
1398 
1399  dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1400  }
1401 }
1402 
1403 /***********************************************************/
1405 static
1406 void
1407 row_upd_store_row(
1408 /*==============*/
1409  upd_node_t* node)
1410 {
1411  dict_index_t* clust_index;
1412  rec_t* rec;
1413  mem_heap_t* heap = NULL;
1414  row_ext_t** ext;
1415  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1416  const ulint* offsets;
1417  rec_offs_init(offsets_);
1418 
1419  ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1420 
1421  if (node->row != NULL) {
1422  mem_heap_empty(node->heap);
1423  }
1424 
1425  clust_index = dict_table_get_first_index(node->table);
1426 
1427  rec = btr_pcur_get_rec(node->pcur);
1428 
1429  offsets = rec_get_offsets(rec, clust_index, offsets_,
1430  ULINT_UNDEFINED, &heap);
1431 
1433  /* In DYNAMIC or COMPRESSED format, there is no prefix
1434  of externally stored columns in the clustered index
1435  record. Build a cache of column prefixes. */
1436  ext = &node->ext;
1437  } else {
1438  /* REDUNDANT and COMPACT formats store a local
1439  768-byte prefix of each externally stored column.
1440  No cache is needed. */
1441  ext = NULL;
1442  node->ext = NULL;
1443  }
1444 
1445  node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1446  NULL, ext, node->heap);
1447  if (node->is_delete) {
1448  node->upd_row = NULL;
1449  node->upd_ext = NULL;
1450  } else {
1451  node->upd_row = dtuple_copy(node->row, node->heap);
1452  row_upd_replace(node->upd_row, &node->upd_ext,
1453  clust_index, node->update, node->heap);
1454  }
1455 
1456  if (UNIV_LIKELY_NULL(heap)) {
1457  mem_heap_free(heap);
1458  }
1459 }
1460 
1461 /***********************************************************/
1465 static
1466 ulint
1467 row_upd_sec_index_entry(
1468 /*====================*/
1469  upd_node_t* node,
1470  que_thr_t* thr)
1471 {
1472  mtr_t mtr;
1473  const rec_t* rec;
1474  btr_pcur_t pcur;
1475  mem_heap_t* heap;
1476  dtuple_t* entry;
1477  dict_index_t* index;
1478  btr_cur_t* btr_cur;
1479  ibool referenced;
1480  ulint err = DB_SUCCESS;
1481  trx_t* trx = thr_get_trx(thr);
1482  ulint mode = BTR_MODIFY_LEAF;
1483  enum row_search_result search_result;
1484 
1485  index = node->index;
1486 
1487  referenced = row_upd_index_is_referenced(index, trx);
1488 
1489  heap = mem_heap_create(1024);
1490 
1491  /* Build old index entry */
1492  entry = row_build_index_entry(node->row, node->ext, index, heap);
1493  ut_a(entry);
1494 
1495  mtr_start(&mtr);
1496 
1497  /* Set the query thread, so that ibuf_insert_low() will be
1498  able to invoke thd_get_trx(). */
1499  btr_pcur_get_btr_cur(&pcur)->thr = thr;
1500 
1501  /* We can only try to use the insert/delete buffer to buffer
1502  delete-mark operations if the index we're modifying has no foreign
1503  key constraints referring to it. */
1504  if (!referenced) {
1505  mode |= BTR_DELETE_MARK;
1506  }
1507 
1508  search_result = row_search_index_entry(index, entry, mode,
1509  &pcur, &mtr);
1510 
1511  btr_cur = btr_pcur_get_btr_cur(&pcur);
1512 
1513  rec = btr_cur_get_rec(btr_cur);
1514 
1515  switch (search_result) {
1516  case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
1517  ut_error;
1518  break;
1519  case ROW_BUFFERED:
1520  /* Entry was delete marked already. */
1521  break;
1522 
1523  case ROW_NOT_FOUND:
1524  fputs("InnoDB: error in sec index entry update in\n"
1525  "InnoDB: ", stderr);
1526  dict_index_name_print(stderr, trx, index);
1527  fputs("\n"
1528  "InnoDB: tuple ", stderr);
1529  dtuple_print(stderr, entry);
1530  fputs("\n"
1531  "InnoDB: record ", stderr);
1532  rec_print(stderr, rec, index);
1533  putc('\n', stderr);
1534 
1535  trx_print(stderr, trx, 0);
1536 
1537  fputs("\n"
1538  "InnoDB: Submit a detailed bug report"
1539  " to http://bugs.mysql.com\n", stderr);
1540  break;
1541  case ROW_FOUND:
1542  /* Delete mark the old index record; it can already be
1543  delete marked if we return after a lock wait in
1544  row_ins_index_entry below */
1545 
1546  if (!rec_get_deleted_flag(
1547  rec, dict_table_is_comp(index->table))) {
1548 
1549  err = btr_cur_del_mark_set_sec_rec(
1550  0, btr_cur, TRUE, thr, &mtr);
1551 
1552  if (err == DB_SUCCESS && referenced) {
1553 
1554  ulint* offsets;
1555 
1556  offsets = rec_get_offsets(
1557  rec, index, NULL, ULINT_UNDEFINED,
1558  &heap);
1559 
1560  /* NOTE that the following call loses
1561  the position of pcur ! */
1562  err = row_upd_check_references_constraints(
1563  node, &pcur, index->table,
1564  index, offsets, thr, &mtr);
1565  }
1566  }
1567  break;
1568  }
1569 
1570  btr_pcur_close(&pcur);
1571  mtr_commit(&mtr);
1572 
1573  if (node->is_delete || err != DB_SUCCESS) {
1574 
1575  goto func_exit;
1576  }
1577 
1578  /* Build a new index entry */
1579  entry = row_build_index_entry(node->upd_row, node->upd_ext,
1580  index, heap);
1581  ut_a(entry);
1582 
1583  /* Insert new index entry */
1584  err = row_ins_index_entry(index, entry, 0, TRUE, thr);
1585 
1586 func_exit:
1587  mem_heap_free(heap);
1588 
1589  return(err);
1590 }
1591 
1592 /***********************************************************/
1597 static
1598 ulint
1599 row_upd_sec_step(
1600 /*=============*/
1601  upd_node_t* node,
1602  que_thr_t* thr)
1603 {
1604  ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1605  || (node->state == UPD_NODE_UPDATE_SOME_SEC));
1606  ut_ad(!dict_index_is_clust(node->index));
1607 
1608  if (node->state == UPD_NODE_UPDATE_ALL_SEC
1609  || row_upd_changes_ord_field_binary(node->row, node->index,
1610  node->update)) {
1611  return(row_upd_sec_index_entry(node, thr));
1612  }
1613 
1614  return(DB_SUCCESS);
1615 }
1616 
1617 /***********************************************************/
1624 static
1625 ulint
1626 row_upd_clust_rec_by_insert(
1627 /*========================*/
1628  upd_node_t* node,
1629  dict_index_t* index,
1630  que_thr_t* thr,
1631  ibool referenced,
1633  mtr_t* mtr)
1634 {
1635  mem_heap_t* heap = NULL;
1636  btr_pcur_t* pcur;
1637  btr_cur_t* btr_cur;
1638  trx_t* trx;
1639  dict_table_t* table;
1640  dtuple_t* entry;
1641  ulint err;
1642  ibool change_ownership = FALSE;
1643 
1644  ut_ad(node);
1645  ut_ad(dict_index_is_clust(index));
1646 
1647  trx = thr_get_trx(thr);
1648  table = node->table;
1649  pcur = node->pcur;
1650  btr_cur = btr_pcur_get_btr_cur(pcur);
1651 
1652  if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1653  rec_t* rec;
1654  dict_index_t* node_index;
1655  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1656  ulint* offsets;
1657  rec_offs_init(offsets_);
1658 
1659  err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1660  btr_cur, TRUE, thr, mtr);
1661  if (err != DB_SUCCESS) {
1662  mtr_commit(mtr);
1663  return(err);
1664  }
1665 
1666  /* Mark as not-owned the externally stored fields which the new
1667  row inherits from the delete marked record: purge should not
1668  free those externally stored fields even if the delete marked
1669  record is removed from the index tree, or updated. */
1670 
1671  rec = btr_cur_get_rec(btr_cur);
1672  node_index = dict_table_get_first_index(table);
1673  offsets = rec_get_offsets(rec, node_index, offsets_,
1674  ULINT_UNDEFINED, &heap);
1675  change_ownership = btr_cur_mark_extern_inherited_fields(
1676  btr_cur_get_page_zip(btr_cur), rec, node_index, offsets,
1677  node->update, mtr);
1678  if (referenced) {
1679  /* NOTE that the following call loses
1680  the position of pcur ! */
1681 
1682  err = row_upd_check_references_constraints(
1683  node, pcur, table, node_index, offsets, thr, mtr);
1684 
1685  if (err != DB_SUCCESS) {
1686 
1687  mtr_commit(mtr);
1688 
1689  if (UNIV_LIKELY_NULL(heap)) {
1690  mem_heap_free(heap);
1691  }
1692 
1693  return(err);
1694  }
1695  }
1696  }
1697 
1698  mtr_commit(mtr);
1699 
1700  if (!heap) {
1701  heap = mem_heap_create(500);
1702  }
1703  node->state = UPD_NODE_INSERT_CLUSTERED;
1704 
1705  entry = row_build_index_entry(node->upd_row, node->upd_ext,
1706  index, heap);
1707  ut_a(entry);
1708 
1709  row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1710 
1711  if (change_ownership) {
1712  /* If we return from a lock wait, for example, we may have
1713  extern fields marked as not-owned in entry (marked in the
1714  if-branch above). We must unmark them, take the ownership
1715  back. */
1716 
1717  btr_cur_unmark_dtuple_extern_fields(entry);
1718 
1719  /* We must mark non-updated extern fields in entry as
1720  inherited, so that a possible rollback will not free them. */
1721 
1722  btr_cur_mark_dtuple_inherited_extern(entry, node->update);
1723  }
1724 
1725  err = row_ins_index_entry(index, entry,
1726  node->upd_ext ? node->upd_ext->n_ext : 0,
1727  TRUE, thr);
1728  mem_heap_free(heap);
1729 
1730  return(err);
1731 }
1732 
1733 /***********************************************************/
1738 static
1739 ulint
1740 row_upd_clust_rec(
1741 /*==============*/
1742  upd_node_t* node,
1743  dict_index_t* index,
1744  que_thr_t* thr,
1745  mtr_t* mtr)
1746 {
1747  mem_heap_t* heap = NULL;
1748  big_rec_t* big_rec = NULL;
1749  btr_pcur_t* pcur;
1750  btr_cur_t* btr_cur;
1751  ulint err;
1752 
1753  ut_ad(node);
1754  ut_ad(dict_index_is_clust(index));
1755 
1756  pcur = node->pcur;
1757  btr_cur = btr_pcur_get_btr_cur(pcur);
1758 
1760  dict_table_is_comp(index->table)));
1761 
1762  /* Try optimistic updating of the record, keeping changes within
1763  the page; we do not check locks because we assume the x-lock on the
1764  record to update */
1765 
1766  if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1767  err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1768  btr_cur, node->update,
1769  node->cmpl_info, thr, mtr);
1770  } else {
1771  err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1772  btr_cur, node->update,
1773  node->cmpl_info, thr, mtr);
1774  }
1775 
1776  mtr_commit(mtr);
1777 
1778  if (UNIV_LIKELY(err == DB_SUCCESS)) {
1779 
1780  return(DB_SUCCESS);
1781  }
1782 
1783  if (buf_LRU_buf_pool_running_out()) {
1784 
1785  return(DB_LOCK_TABLE_FULL);
1786  }
1787  /* We may have to modify the tree structure: do a pessimistic descent
1788  down the index tree */
1789 
1790  mtr_start(mtr);
1791 
1792  /* NOTE: this transaction has an s-lock or x-lock on the record and
1793  therefore other transactions cannot modify the record when we have no
1794  latch on the page. In addition, we assume that other query threads of
1795  the same transaction do not modify the record in the meantime.
1796  Therefore we can assert that the restoration of the cursor succeeds. */
1797 
1798  ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1799 
1801  dict_table_is_comp(index->table)));
1802 
1803  err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1804  &heap, &big_rec, node->update,
1805  node->cmpl_info, thr, mtr);
1806  mtr_commit(mtr);
1807 
1808  if (err == DB_SUCCESS && big_rec) {
1809  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1810  rec_t* rec;
1811  rec_offs_init(offsets_);
1812 
1813  mtr_start(mtr);
1814 
1815  ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1816  rec = btr_cur_get_rec(btr_cur);
1817  err = btr_store_big_rec_extern_fields(
1818  index, btr_cur_get_block(btr_cur), rec,
1819  rec_get_offsets(rec, index, offsets_,
1820  ULINT_UNDEFINED, &heap),
1821  big_rec, mtr);
1822  mtr_commit(mtr);
1823  }
1824 
1825  if (UNIV_LIKELY_NULL(heap)) {
1826  mem_heap_free(heap);
1827  }
1828 
1829  if (big_rec) {
1830  dtuple_big_rec_free(big_rec);
1831  }
1832 
1833  return(err);
1834 }
1835 
1836 /***********************************************************/
1839 static
1840 ulint
1841 row_upd_del_mark_clust_rec(
1842 /*=======================*/
1843  upd_node_t* node,
1844  dict_index_t* index,
1845  ulint* offsets,
1847  que_thr_t* thr,
1848  ibool referenced,
1851  mtr_t* mtr)
1852 {
1853  btr_pcur_t* pcur;
1854  btr_cur_t* btr_cur;
1855  ulint err;
1856 
1857  ut_ad(node);
1858  ut_ad(dict_index_is_clust(index));
1859  ut_ad(node->is_delete);
1860 
1861  pcur = node->pcur;
1862  btr_cur = btr_pcur_get_btr_cur(pcur);
1863 
1864  /* Store row because we have to build also the secondary index
1865  entries */
1866 
1867  row_upd_store_row(node);
1868 
1869  /* Mark the clustered index record deleted; we do not have to check
1870  locks, because we assume that we have an x-lock on the record */
1871 
1872  err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1873  btr_cur, TRUE, thr, mtr);
1874  if (err == DB_SUCCESS && referenced) {
1875  /* NOTE that the following call loses the position of pcur ! */
1876 
1877  err = row_upd_check_references_constraints(
1878  node, pcur, index->table, index, offsets, thr, mtr);
1879  }
1880 
1881  mtr_commit(mtr);
1882 
1883  return(err);
1884 }
1885 
1886 /***********************************************************/
1890 static
1891 ulint
1892 row_upd_clust_step(
1893 /*===============*/
1894  upd_node_t* node,
1895  que_thr_t* thr)
1896 {
1897  dict_index_t* index;
1898  btr_pcur_t* pcur;
1899  ibool success;
1900  ulint err;
1901  mtr_t* mtr;
1902  mtr_t mtr_buf;
1903  rec_t* rec;
1904  mem_heap_t* heap = NULL;
1905  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1906  ulint* offsets;
1907  ibool referenced;
1908  rec_offs_init(offsets_);
1909 
1910  index = dict_table_get_first_index(node->table);
1911 
1912  referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
1913 
1914  pcur = node->pcur;
1915 
1916  /* We have to restore the cursor to its position */
1917  mtr = &mtr_buf;
1918 
1919  mtr_start(mtr);
1920 
1921  /* If the restoration does not succeed, then the same
1922  transaction has deleted the record on which the cursor was,
1923  and that is an SQL error. If the restoration succeeds, it may
1924  still be that the same transaction has successively deleted
1925  and inserted a record with the same ordering fields, but in
1926  that case we know that the transaction has at least an
1927  implicit x-lock on the record. */
1928 
1929  ut_a(pcur->rel_pos == BTR_PCUR_ON);
1930 
1931  success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1932 
1933  if (!success) {
1934  err = DB_RECORD_NOT_FOUND;
1935 
1936  mtr_commit(mtr);
1937 
1938  return(err);
1939  }
1940 
1941  /* If this is a row in SYS_INDEXES table of the data dictionary,
1942  then we have to free the file segments of the index tree associated
1943  with the index */
1944 
1945  if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
1946 
1947  dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1948 
1949  mtr_commit(mtr);
1950 
1951  mtr_start(mtr);
1952 
1953  success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
1954  mtr);
1955  if (!success) {
1956  err = DB_ERROR;
1957 
1958  mtr_commit(mtr);
1959 
1960  return(err);
1961  }
1962  }
1963 
1964  rec = btr_pcur_get_rec(pcur);
1965  offsets = rec_get_offsets(rec, index, offsets_,
1966  ULINT_UNDEFINED, &heap);
1967 
1968  if (!node->has_clust_rec_x_lock) {
1970  0, btr_pcur_get_block(pcur),
1971  rec, index, offsets, thr);
1972  if (err != DB_SUCCESS) {
1973  mtr_commit(mtr);
1974  goto exit_func;
1975  }
1976  }
1977 
1978  /* NOTE: the following function calls will also commit mtr */
1979 
1980  if (node->is_delete) {
1981  err = row_upd_del_mark_clust_rec(
1982  node, index, offsets, thr, referenced, mtr);
1983 
1984  if (err == DB_SUCCESS) {
1985  node->state = UPD_NODE_UPDATE_ALL_SEC;
1986  node->index = dict_table_get_next_index(index);
1987  }
1988 exit_func:
1989  if (UNIV_LIKELY_NULL(heap)) {
1990  mem_heap_free(heap);
1991  }
1992  return(err);
1993  }
1994 
1995  /* If the update is made for MySQL, we already have the update vector
1996  ready, else we have to do some evaluation: */
1997 
1998  if (UNIV_UNLIKELY(!node->in_mysql_interface)) {
1999  /* Copy the necessary columns from clust_rec and calculate the
2000  new values to set */
2001  row_upd_copy_columns(rec, offsets,
2002  UT_LIST_GET_FIRST(node->columns));
2003  row_upd_eval_new_vals(node->update);
2004  }
2005 
2006  if (UNIV_LIKELY_NULL(heap)) {
2007  mem_heap_free(heap);
2008  }
2009 
2010  if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
2011 
2012  err = row_upd_clust_rec(node, index, thr, mtr);
2013  return(err);
2014  }
2015 
2016  row_upd_store_row(node);
2017 
2018  if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
2019 
2020  /* Update causes an ordering field (ordering fields within
2021  the B-tree) of the clustered index record to change: perform
2022  the update by delete marking and inserting.
2023 
2024  TODO! What to do to the 'Halloween problem', where an update
2025  moves the record forward in index so that it is again
2026  updated when the cursor arrives there? Solution: the
2027  read operation must check the undo record undo number when
2028  choosing records to update. MySQL solves now the problem
2029  externally! */
2030 
2031  err = row_upd_clust_rec_by_insert(
2032  node, index, thr, referenced, mtr);
2033 
2034  if (err != DB_SUCCESS) {
2035 
2036  return(err);
2037  }
2038 
2039  node->state = UPD_NODE_UPDATE_ALL_SEC;
2040  } else {
2041  err = row_upd_clust_rec(node, index, thr, mtr);
2042 
2043  if (err != DB_SUCCESS) {
2044 
2045  return(err);
2046  }
2047 
2048  node->state = UPD_NODE_UPDATE_SOME_SEC;
2049  }
2050 
2051  node->index = dict_table_get_next_index(index);
2052 
2053  return(err);
2054 }
2055 
2056 /***********************************************************/
2062 static
2063 ulint
2064 row_upd(
2065 /*====*/
2066  upd_node_t* node,
2067  que_thr_t* thr)
2068 {
2069  ulint err = DB_SUCCESS;
2070 
2071  ut_ad(node && thr);
2072 
2073  if (UNIV_LIKELY(node->in_mysql_interface)) {
2074 
2075  /* We do not get the cmpl_info value from the MySQL
2076  interpreter: we must calculate it on the fly: */
2077 
2078  if (node->is_delete
2080  node->table, node->update)) {
2081  node->cmpl_info = 0;
2082  } else {
2083  node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
2084  }
2085  }
2086 
2087  if (node->state == UPD_NODE_UPDATE_CLUSTERED
2088  || node->state == UPD_NODE_INSERT_CLUSTERED) {
2089 
2090  log_free_check();
2091  err = row_upd_clust_step(node, thr);
2092 
2093  if (err != DB_SUCCESS) {
2094 
2095  goto function_exit;
2096  }
2097  }
2098 
2099  if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
2100 
2101  goto function_exit;
2102  }
2103 
2104  while (node->index != NULL) {
2105 
2106  log_free_check();
2107  err = row_upd_sec_step(node, thr);
2108 
2109  if (err != DB_SUCCESS) {
2110 
2111  goto function_exit;
2112  }
2113 
2114  node->index = dict_table_get_next_index(node->index);
2115  }
2116 
2117 function_exit:
2118  if (err == DB_SUCCESS) {
2119  /* Do some cleanup */
2120 
2121  if (node->row != NULL) {
2122  node->row = NULL;
2123  node->ext = NULL;
2124  node->upd_row = NULL;
2125  node->upd_ext = NULL;
2126  mem_heap_empty(node->heap);
2127  }
2128 
2129  node->state = UPD_NODE_UPDATE_CLUSTERED;
2130  }
2131 
2132  return(err);
2133 }
2134 
2135 /***********************************************************/
2139 UNIV_INTERN
2140 que_thr_t*
2142 /*=========*/
2143  que_thr_t* thr)
2144 {
2145  upd_node_t* node;
2146  sel_node_t* sel_node;
2147  que_node_t* parent;
2148  ulint err = DB_SUCCESS;
2149  trx_t* trx;
2150 
2151  ut_ad(thr);
2152 
2153  trx = thr_get_trx(thr);
2154 
2156 
2157  node = static_cast<upd_node_t *>(thr->run_node);
2158 
2159  sel_node = node->select;
2160 
2161  parent = que_node_get_parent(node);
2162 
2163  ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2164 
2165  if (thr->prev_node == parent) {
2166  node->state = UPD_NODE_SET_IX_LOCK;
2167  }
2168 
2169  if (node->state == UPD_NODE_SET_IX_LOCK) {
2170 
2171  if (!node->has_clust_rec_x_lock) {
2172  /* It may be that the current session has not yet
2173  started its transaction, or it has been committed: */
2174 
2175  err = lock_table(0, node->table, LOCK_IX, thr);
2176 
2177  if (err != DB_SUCCESS) {
2178 
2179  goto error_handling;
2180  }
2181  }
2182 
2183  node->state = UPD_NODE_UPDATE_CLUSTERED;
2184 
2185  if (node->searched_update) {
2186  /* Reset the cursor */
2187  sel_node->state = SEL_NODE_OPEN;
2188 
2189  /* Fetch a row to update */
2190 
2191  thr->run_node = sel_node;
2192 
2193  return(thr);
2194  }
2195  }
2196 
2197  /* sel_node is NULL if we are in the MySQL interface */
2198 
2199  if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
2200 
2201  if (!node->searched_update) {
2202  /* An explicit cursor should be positioned on a row
2203  to update */
2204 
2205  ut_error;
2206 
2207  err = DB_ERROR;
2208 
2209  goto error_handling;
2210  }
2211 
2212  ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2213 
2214  /* No more rows to update, or the select node performed the
2215  updates directly in-place */
2216 
2217  thr->run_node = parent;
2218 
2219  return(thr);
2220  }
2221 
2222  /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2223 
2224  err = row_upd(node, thr);
2225 
2226 error_handling:
2227  trx->error_state = err;
2228 
2229  if (err != DB_SUCCESS) {
2230  return(NULL);
2231  }
2232 
2233  /* DO THE TRIGGER ACTIONS HERE */
2234 
2235  if (node->searched_update) {
2236  /* Fetch next row to update */
2237 
2238  thr->run_node = sel_node;
2239  } else {
2240  /* It was an explicit cursor update */
2241 
2242  thr->run_node = parent;
2243  }
2244 
2245  node->state = UPD_NODE_UPDATE_CLUSTERED;
2246 
2247  return(thr);
2248 }
2249 #endif /* !UNIV_HOTBACKUP */