1
/*****************************************************************************
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
23
Created 4/20/1996 Heikki Tuuri
24
*******************************************************/
32
#include "ha_prototypes.h"
33
#include "dict0dict.h"
34
#include "dict0boot.h"
38
#include "mach0data.h"
44
#include "lock0lock.h"
46
#include "eval0eval.h"
47
#include "data0data.h"
51
#define ROW_INS_PREV 1
52
#define ROW_INS_NEXT 2
54
/*************************************************************************
55
IMPORTANT NOTE: Any operation that generates redo MUST check that there
56
is enough space in the redo log before for that operation. This is
57
done by calling log_free_check(). The reason for checking the
58
availability of the redo log space before the start of the operation is
59
that we MUST not hold any synchonization objects when performing the
61
If you make a change in this module make sure that no codepath is
62
introduced where a call to log_free_check() is bypassed. */
64
/*********************************************************************//**
65
Creates an insert node struct.
66
@return own: insert node struct */
71
ulint ins_type, /*!< in: INS_VALUES, ... */
72
dict_table_t* table, /*!< in: table where to insert */
73
mem_heap_t* heap) /*!< in: mem heap where created */
77
node = static_cast<ins_node_t *>(mem_heap_alloc(heap, sizeof(ins_node_t)));
79
node->common.type = QUE_NODE_INSERT;
81
node->ins_type = ins_type;
83
node->state = INS_NODE_SET_IX_LOCK;
92
node->entry_sys_heap = mem_heap_create(128);
94
node->magic_n = INS_NODE_MAGIC_N;
99
/***********************************************************//**
100
Creates an entry template for each index of a table. */
103
ins_node_create_entry_list(
104
/*=======================*/
105
ins_node_t* node) /*!< in: row insert node */
110
ut_ad(node->entry_sys_heap);
112
UT_LIST_INIT(node->entry_list);
114
index = dict_table_get_first_index(node->table);
116
while (index != NULL) {
117
entry = row_build_index_entry(node->row, NULL, index,
118
node->entry_sys_heap);
119
UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry);
121
index = dict_table_get_next_index(index);
125
/*****************************************************************//**
126
Adds system field buffers to a row. */
129
row_ins_alloc_sys_fields(
130
/*=====================*/
131
ins_node_t* node) /*!< in: insert node */
136
const dict_col_t* col;
142
heap = node->entry_sys_heap;
144
ut_ad(row && table && heap);
145
ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table));
147
/* 1. Allocate buffer for row id */
149
col = dict_table_get_sys_col(table, DATA_ROW_ID);
151
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
153
ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_ROW_ID_LEN));
155
dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN);
157
node->row_id_buf = ptr;
159
/* 3. Allocate buffer for trx id */
161
col = dict_table_get_sys_col(table, DATA_TRX_ID);
163
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
164
ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_TRX_ID_LEN));
166
dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN);
168
node->trx_id_buf = ptr;
170
/* 4. Allocate buffer for roll ptr */
172
col = dict_table_get_sys_col(table, DATA_ROLL_PTR);
174
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
175
ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_ROLL_PTR_LEN));
177
dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);
180
/*********************************************************************//**
181
Sets a new row to insert for an INS_DIRECT node. This function is only used
182
if we have constructed the row separately, which is a rare case; this
183
function is quite slow. */
186
ins_node_set_new_row(
187
/*=================*/
188
ins_node_t* node, /*!< in: insert node */
189
dtuple_t* row) /*!< in: new row (or first row) for the node */
191
node->state = INS_NODE_SET_IX_LOCK;
197
mem_heap_empty(node->entry_sys_heap);
199
/* Create templates for index entries */
201
ins_node_create_entry_list(node);
203
/* Allocate from entry_sys_heap buffers for sys fields */
205
row_ins_alloc_sys_fields(node);
207
/* As we allocated a new trx id buf, the trx id should be written
213
/*******************************************************************//**
214
Does an insert operation by updating a delete-marked existing record
215
in the index. This situation can occur if the delete-marked record is
216
kept in the index for consistent reads.
217
@return DB_SUCCESS or error code */
220
row_ins_sec_index_entry_by_modify(
221
/*==============================*/
222
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
223
depending on whether mtr holds just a leaf
224
latch or also a tree latch */
225
btr_cur_t* cursor, /*!< in: B-tree cursor */
226
const dtuple_t* entry, /*!< in: index entry to insert */
227
que_thr_t* thr, /*!< in: query thread */
228
mtr_t* mtr) /*!< in: mtr; must be committed before
229
latching any further pages */
231
big_rec_t* dummy_big_rec;
237
rec = btr_cur_get_rec(cursor);
239
ut_ad(!dict_index_is_clust(cursor->index));
240
ut_ad(rec_get_deleted_flag(rec,
241
dict_table_is_comp(cursor->index->table)));
243
/* We know that in the alphabetical ordering, entry and rec are
244
identified. But in their binary form there may be differences if
245
there are char fields in them. Therefore we have to calculate the
248
heap = mem_heap_create(1024);
250
update = row_upd_build_sec_rec_difference_binary(
251
cursor->index, entry, rec, thr_get_trx(thr), heap);
252
if (mode == BTR_MODIFY_LEAF) {
253
/* Try an optimistic updating of the record, keeping changes
256
err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor,
257
update, 0, thr, mtr);
261
case DB_ZIP_OVERFLOW:
265
ut_a(mode == BTR_MODIFY_TREE);
266
if (buf_LRU_buf_pool_running_out()) {
268
err = DB_LOCK_TABLE_FULL;
273
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
274
&heap, &dummy_big_rec, update,
276
ut_ad(!dummy_big_rec);
284
/*******************************************************************//**
285
Does an insert operation by delete unmarking and updating a delete marked
286
existing record in the index. This situation can occur if the delete marked
287
record is kept in the index for consistent reads.
288
@return DB_SUCCESS, DB_FAIL, or error code */
291
row_ins_clust_index_entry_by_modify(
292
/*================================*/
293
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
294
depending on whether mtr holds just a leaf
295
latch or also a tree latch */
296
btr_cur_t* cursor, /*!< in: B-tree cursor */
297
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
298
big_rec_t** big_rec,/*!< out: possible big rec vector of fields
299
which have to be stored externally by the
301
const dtuple_t* entry, /*!< in: index entry to insert */
302
que_thr_t* thr, /*!< in: query thread */
303
mtr_t* mtr) /*!< in: mtr; must be committed before
304
latching any further pages */
310
ut_ad(dict_index_is_clust(cursor->index));
314
rec = btr_cur_get_rec(cursor);
316
ut_ad(rec_get_deleted_flag(rec,
317
dict_table_is_comp(cursor->index->table)));
320
*heap = mem_heap_create(1024);
323
/* Build an update vector containing all the fields to be modified;
324
NOTE that this vector may NOT contain system columns trx_id or
327
update = row_upd_build_difference_binary(cursor->index, entry, rec,
328
thr_get_trx(thr), *heap);
329
if (mode == BTR_MODIFY_LEAF) {
330
/* Try optimistic updating of the record, keeping changes
333
err = btr_cur_optimistic_update(0, cursor, update, 0, thr,
338
case DB_ZIP_OVERFLOW:
342
ut_a(mode == BTR_MODIFY_TREE);
343
if (buf_LRU_buf_pool_running_out()) {
345
return(DB_LOCK_TABLE_FULL);
348
err = btr_cur_pessimistic_update(0, cursor,
349
heap, big_rec, update,
356
/*********************************************************************//**
357
Returns TRUE if in a cascaded update/delete an ancestor node of node
358
updates (not DELETE, but UPDATE) table.
359
@return TRUE if an ancestor updates table */
362
row_ins_cascade_ancestor_updates_table(
363
/*===================================*/
364
que_node_t* node, /*!< in: node in a query graph */
365
dict_table_t* table) /*!< in: table */
368
upd_node_t* upd_node;
370
parent = que_node_get_parent(node);
372
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
374
upd_node = static_cast<upd_node_t *>(parent);
376
if (upd_node->table == table && upd_node->is_delete == FALSE) {
381
parent = que_node_get_parent(parent);
389
/*********************************************************************//**
390
Returns the number of ancestor UPDATE or DELETE nodes of a
391
cascaded update/delete node.
392
@return number of ancestors */
395
row_ins_cascade_n_ancestors(
396
/*========================*/
397
que_node_t* node) /*!< in: node in a query graph */
400
ulint n_ancestors = 0;
402
parent = que_node_get_parent(node);
404
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
407
parent = que_node_get_parent(parent);
415
/******************************************************************//**
416
Calculates the update vector node->cascade->update for a child table in
418
@return number of fields in the calculated update vector; the value
419
can also be 0 if no foreign key fields changed; the returned value is
420
ULINT_UNDEFINED if the column type in the child table is too short to
421
fit the new value in the parent table: that means the update fails */
424
row_ins_cascade_calc_update_vec(
425
/*============================*/
426
upd_node_t* node, /*!< in: update node of the parent
428
dict_foreign_t* foreign, /*!< in: foreign key constraint whose
430
mem_heap_t* heap) /*!< in: memory heap to use as
433
upd_node_t* cascade = node->cascade_node;
434
dict_table_t* table = foreign->foreign_table;
435
dict_index_t* index = foreign->foreign_index;
438
dict_table_t* parent_table;
439
dict_index_t* parent_index;
440
upd_t* parent_update;
441
upd_field_t* parent_ufield;
442
ulint n_fields_updated;
443
ulint parent_field_no;
453
/* Calculate the appropriate update vector which will set the fields
454
in the child index record to the same value (possibly padded with
455
spaces if the column is a fixed length CHAR or FIXBINARY column) as
456
the referenced index record will get in the update. */
458
parent_table = node->table;
459
ut_a(parent_table == foreign->referenced_table);
460
parent_index = foreign->referenced_index;
461
parent_update = node->update;
463
update = cascade->update;
465
update->info_bits = 0;
466
update->n_fields = foreign->n_fields;
468
n_fields_updated = 0;
470
for (i = 0; i < foreign->n_fields; i++) {
472
parent_field_no = dict_table_get_nth_col_pos(
474
dict_index_get_nth_col_no(parent_index, i));
476
for (j = 0; j < parent_update->n_fields; j++) {
477
parent_ufield = parent_update->fields + j;
479
if (parent_ufield->field_no == parent_field_no) {
482
const dict_col_t* col;
485
col = dict_index_get_nth_col(index, i);
487
/* A field in the parent index record is
488
updated. Let us make the update vector
489
field for the child table. */
491
ufield = update->fields + n_fields_updated;
494
= dict_table_get_nth_col_pos(
495
table, dict_col_get_no(col));
498
ufield->new_val = parent_ufield->new_val;
499
ufield_len = dfield_get_len(&ufield->new_val);
501
/* Clear the "external storage" flag */
502
dfield_set_len(&ufield->new_val, ufield_len);
504
/* Do not allow a NOT NULL column to be
507
if (dfield_is_null(&ufield->new_val)
508
&& (col->prtype & DATA_NOT_NULL)) {
510
return(ULINT_UNDEFINED);
513
/* If the new value would not fit in the
514
column, do not allow the update */
516
if (!dfield_is_null(&ufield->new_val)
517
&& dtype_get_at_most_n_mbchars(
518
col->prtype, col->mbminmaxlen,
521
static_cast<const char *>(dfield_get_data(&ufield->new_val)))
524
return(ULINT_UNDEFINED);
527
/* If the parent column type has a different
528
length than the child column type, we may
529
need to pad with spaces the new value of the
532
min_size = dict_col_get_min_size(col);
534
/* Because UNIV_SQL_NULL (the marker
535
of SQL NULL values) exceeds all possible
536
values of min_size, the test below will
537
not hold for SQL NULL columns. */
539
if (min_size > ufield_len) {
546
padded_data = static_cast<unsigned char *>(mem_heap_alloc(
549
pad = padded_data + ufield_len;
550
pad_len = min_size - ufield_len;
553
dfield_get_data(&ufield
557
mbminlen = dict_col_get_mbminlen(col);
559
ut_ad(!(ufield_len % mbminlen));
560
ut_ad(!(min_size % mbminlen));
563
&& dtype_get_charset_coll(
565
== DATA_MYSQL_BINARY_CHARSET_COLL) {
566
/* Do not pad BINARY columns */
567
return(ULINT_UNDEFINED);
570
row_mysql_pad_col(mbminlen,
572
dfield_set_data(&ufield->new_val,
573
padded_data, min_size);
581
update->n_fields = n_fields_updated;
583
return(n_fields_updated);
586
/*********************************************************************//**
587
Set detailed error message associated with foreign key errors for
588
the given transaction. */
591
row_ins_set_detailed(
592
/*=================*/
593
trx_t* trx, /*!< in: transaction */
594
dict_foreign_t* foreign) /*!< in: foreign key constraint */
596
mutex_enter(&srv_misc_tmpfile_mutex);
597
rewind(srv_misc_tmpfile);
599
if (os_file_set_eof(srv_misc_tmpfile)) {
600
ut_print_name(srv_misc_tmpfile, trx, TRUE,
601
foreign->foreign_table_name);
602
dict_print_info_on_foreign_key_in_create_format(
603
srv_misc_tmpfile, trx, foreign, FALSE);
604
trx_set_detailed_error_from_file(trx, srv_misc_tmpfile);
606
trx_set_detailed_error(trx, "temp file operation failed");
609
mutex_exit(&srv_misc_tmpfile_mutex);
612
/*********************************************************************//**
613
Reports a foreign key error associated with an update or a delete of a
614
parent table index entry. */
617
row_ins_foreign_report_err(
618
/*=======================*/
619
const char* errstr, /*!< in: error string from the viewpoint
620
of the parent table */
621
que_thr_t* thr, /*!< in: query thread whose run_node
623
dict_foreign_t* foreign, /*!< in: foreign key constraint */
624
const rec_t* rec, /*!< in: a matching index record in the
626
const dtuple_t* entry) /*!< in: index entry in the parent
629
FILE* ef = dict_foreign_err_file;
630
trx_t* trx = thr_get_trx(thr);
632
row_ins_set_detailed(trx, foreign);
634
mutex_enter(&dict_foreign_err_mutex);
636
ut_print_timestamp(ef);
637
fputs(" Transaction:\n", ef);
638
trx_print(ef, trx, 600);
640
fputs("Foreign key constraint fails for table ", ef);
641
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
643
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
647
fputs(" in parent table, in index ", ef);
648
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
650
fputs(" tuple:\n", ef);
651
dtuple_print(ef, entry);
653
fputs("\nBut in child table ", ef);
654
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
655
fputs(", in index ", ef);
656
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
658
fputs(", there is a record:\n", ef);
659
rec_print(ef, rec, foreign->foreign_index);
661
fputs(", the record is not available\n", ef);
665
mutex_exit(&dict_foreign_err_mutex);
668
/*********************************************************************//**
669
Reports a foreign key error to dict_foreign_err_file when we are trying
670
to add an index entry to a child table. Note that the adding may be the result
671
of an update, too. */
674
row_ins_foreign_report_add_err(
675
/*===========================*/
676
trx_t* trx, /*!< in: transaction */
677
dict_foreign_t* foreign, /*!< in: foreign key constraint */
678
const rec_t* rec, /*!< in: a record in the parent table:
679
it does not match entry because we
681
const dtuple_t* entry) /*!< in: index entry to insert in the
684
FILE* ef = dict_foreign_err_file;
686
row_ins_set_detailed(trx, foreign);
688
mutex_enter(&dict_foreign_err_mutex);
690
ut_print_timestamp(ef);
691
fputs(" Transaction:\n", ef);
692
trx_print(ef, trx, 600);
693
fputs("Foreign key constraint fails for table ", ef);
694
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
696
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
698
fputs("\nTrying to add in child table, in index ", ef);
699
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
701
fputs(" tuple:\n", ef);
702
/* TODO: DB_TRX_ID and DB_ROLL_PTR may be uninitialized.
703
It would be better to only display the user columns. */
704
dtuple_print(ef, entry);
706
fputs("\nBut in parent table ", ef);
707
ut_print_name(ef, trx, TRUE, foreign->referenced_table_name);
708
fputs(", in index ", ef);
709
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
710
fputs(",\nthe closest match we can find is record:\n", ef);
711
if (rec && page_rec_is_supremum(rec)) {
712
/* If the cursor ended on a supremum record, it is better
713
to report the previous record in the error message, so that
714
the user gets a more descriptive error message. */
715
rec = page_rec_get_prev_const(rec);
719
rec_print(ef, rec, foreign->referenced_index);
723
mutex_exit(&dict_foreign_err_mutex);
726
/*********************************************************************//**
727
Invalidate the query cache for the given table. */
730
row_ins_invalidate_query_cache(
731
/*===========================*/
732
que_thr_t* unused, /*!< in: query thread whose run_node
734
const char* name) /*!< in: table name prefixed with
735
database name and a '/' character */
739
ulint len = strlen(name) + 1;
743
buf = mem_strdupl(name, len);
745
ptr = strchr(buf, '/');
752
/*********************************************************************//**
753
Perform referential actions or checks when a parent row is deleted or updated
754
and the constraint had an ON DELETE or ON UPDATE condition which was not
756
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
759
row_ins_foreign_check_on_constraint(
760
/*================================*/
761
que_thr_t* thr, /*!< in: query thread whose run_node
763
dict_foreign_t* foreign, /*!< in: foreign key constraint whose
765
btr_pcur_t* pcur, /*!< in: cursor placed on a matching
766
index record in the child table */
767
dtuple_t* entry, /*!< in: index entry in the parent
769
mtr_t* mtr) /*!< in: mtr holding the latch of pcur
774
dict_table_t* table = foreign->foreign_table;
776
dict_index_t* clust_index;
778
mem_heap_t* upd_vec_heap = NULL;
780
const rec_t* clust_rec;
781
const buf_block_t* clust_block;
787
mem_heap_t* tmp_heap = NULL;
794
trx = thr_get_trx(thr);
796
/* Since we are going to delete or update a row, we have to invalidate
797
the MySQL query cache for table. A deadlock of threads is not possible
798
here because the caller of this function does not hold any latches with
799
the sync0sync.h rank above the kernel mutex. The query cache mutex has
800
a rank just above the kernel mutex. */
802
row_ins_invalidate_query_cache(thr, table->name);
804
node = static_cast<upd_node_t *>(thr->run_node);
806
if (node->is_delete && 0 == (foreign->type
807
& (DICT_FOREIGN_ON_DELETE_CASCADE
808
| DICT_FOREIGN_ON_DELETE_SET_NULL))) {
810
row_ins_foreign_report_err("Trying to delete",
812
btr_pcur_get_rec(pcur), entry);
814
return(DB_ROW_IS_REFERENCED);
817
if (!node->is_delete && 0 == (foreign->type
818
& (DICT_FOREIGN_ON_UPDATE_CASCADE
819
| DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
821
/* This is an UPDATE */
823
row_ins_foreign_report_err("Trying to update",
825
btr_pcur_get_rec(pcur), entry);
827
return(DB_ROW_IS_REFERENCED);
830
if (node->cascade_node == NULL) {
831
/* Extend our query graph by creating a child to current
832
update node. The child is used in the cascade or set null
835
node->cascade_heap = mem_heap_create(128);
836
node->cascade_node = row_create_update_node_for_mysql(
837
table, node->cascade_heap);
838
que_node_set_parent(node->cascade_node, node);
841
/* Initialize cascade_node to do the operation we want. Note that we
842
use the SAME cascade node to do all foreign key operations of the
843
SQL DELETE: the table of the cascade node may change if there are
844
several child tables to the table where the delete is done! */
846
cascade = node->cascade_node;
848
cascade->table = table;
850
cascade->foreign = foreign;
853
&& (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) {
854
cascade->is_delete = TRUE;
856
cascade->is_delete = FALSE;
858
if (foreign->n_fields > cascade->update_n_fields) {
859
/* We have to make the update vector longer */
861
cascade->update = upd_create(foreign->n_fields,
863
cascade->update_n_fields = foreign->n_fields;
867
/* We do not allow cyclic cascaded updating (DELETE is allowed,
868
but not UPDATE) of the same table, as this can lead to an infinite
869
cycle. Check that we are not updating the same table which is
870
already being modified in this cascade chain. We have to check
871
this also because the modification of the indexes of a 'parent'
872
table may still be incomplete, and we must avoid seeing the indexes
873
of the parent table in an inconsistent state! */
875
if (!cascade->is_delete
876
&& row_ins_cascade_ancestor_updates_table(cascade, table)) {
878
/* We do not know if this would break foreign key
879
constraints, but play safe and return an error */
881
err = DB_ROW_IS_REFERENCED;
883
row_ins_foreign_report_err(
884
"Trying an update, possibly causing a cyclic"
886
"in the child table,", thr, foreign,
887
btr_pcur_get_rec(pcur), entry);
889
goto nonstandard_exit_func;
892
if (row_ins_cascade_n_ancestors(cascade) >= 15) {
893
err = DB_ROW_IS_REFERENCED;
895
row_ins_foreign_report_err(
896
"Trying a too deep cascaded delete or update\n",
897
thr, foreign, btr_pcur_get_rec(pcur), entry);
899
goto nonstandard_exit_func;
902
index = btr_pcur_get_btr_cur(pcur)->index;
904
ut_a(index == foreign->foreign_index);
906
rec = btr_pcur_get_rec(pcur);
908
if (dict_index_is_clust(index)) {
909
/* pcur is already positioned in the clustered index of
914
clust_block = btr_pcur_get_block(pcur);
916
/* We have to look for the record in the clustered index
917
in the child table */
919
clust_index = dict_table_get_first_index(table);
921
tmp_heap = mem_heap_create(256);
923
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
925
btr_pcur_open_with_no_init(clust_index, ref,
926
PAGE_CUR_LE, BTR_SEARCH_LEAF,
927
cascade->pcur, 0, mtr);
929
clust_rec = btr_pcur_get_rec(cascade->pcur);
930
clust_block = btr_pcur_get_block(cascade->pcur);
932
if (!page_rec_is_user_rec(clust_rec)
933
|| btr_pcur_get_low_match(cascade->pcur)
934
< dict_index_get_n_unique(clust_index)) {
936
fputs("InnoDB: error in cascade of a foreign key op\n"
938
dict_index_name_print(stderr, trx, index);
941
"InnoDB: record ", stderr);
942
rec_print(stderr, rec, index);
944
"InnoDB: clustered record ", stderr);
945
rec_print(stderr, clust_rec, clust_index);
947
"InnoDB: Submit a detailed bug report to"
948
" http://bugs.mysql.com\n", stderr);
952
goto nonstandard_exit_func;
956
/* Set an X-lock on the row to delete or update in the child table */
958
err = lock_table(0, table, LOCK_IX, thr);
960
if (err == DB_SUCCESS) {
961
/* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
962
we already have a normal shared lock on the appropriate
963
gap if the search criterion was not unique */
965
err = lock_clust_rec_read_check_and_lock_alt(
966
0, clust_block, clust_rec, clust_index,
967
LOCK_X, LOCK_REC_NOT_GAP, thr);
970
if (err != DB_SUCCESS) {
972
goto nonstandard_exit_func;
975
if (rec_get_deleted_flag(clust_rec, dict_table_is_comp(table))) {
976
/* This can happen if there is a circular reference of
977
rows such that cascading delete comes to delete a row
978
already in the process of being delete marked */
981
goto nonstandard_exit_func;
985
&& (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL))
987
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
989
/* Build the appropriate update vector which sets
990
foreign->n_fields first fields in rec to SQL NULL */
992
update = cascade->update;
994
update->info_bits = 0;
995
update->n_fields = foreign->n_fields;
997
for (i = 0; i < foreign->n_fields; i++) {
998
upd_field_t* ufield = &update->fields[i];
1000
ufield->field_no = dict_table_get_nth_col_pos(
1002
dict_index_get_nth_col_no(index, i));
1003
ufield->orig_len = 0;
1005
dfield_set_null(&ufield->new_val);
1009
if (!node->is_delete
1010
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
1012
/* Build the appropriate update vector which sets changing
1013
foreign->n_fields first fields in rec to new values */
1015
upd_vec_heap = mem_heap_create(256);
1017
n_to_update = row_ins_cascade_calc_update_vec(node, foreign,
1019
if (n_to_update == ULINT_UNDEFINED) {
1020
err = DB_ROW_IS_REFERENCED;
1022
row_ins_foreign_report_err(
1023
"Trying a cascaded update where the"
1024
" updated value in the child\n"
1025
"table would not fit in the length"
1026
" of the column, or the value would\n"
1027
"be NULL and the column is"
1028
" declared as not NULL in the child table,",
1029
thr, foreign, btr_pcur_get_rec(pcur), entry);
1031
goto nonstandard_exit_func;
1034
if (cascade->update->n_fields == 0) {
1036
/* The update does not change any columns referred
1037
to in this foreign key constraint: no need to do
1042
goto nonstandard_exit_func;
1046
/* Store pcur position and initialize or store the cascade node
1047
pcur stored position */
1049
btr_pcur_store_position(pcur, mtr);
1051
if (index == clust_index) {
1052
btr_pcur_copy_stored_position(cascade->pcur, pcur);
1054
btr_pcur_store_position(cascade->pcur, mtr);
1059
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
1061
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
1063
err = row_update_cascade_for_mysql(thr, cascade,
1064
foreign->foreign_table);
1066
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
1068
"InnoDB: error: table %s has the counter 0"
1069
" though there is\n"
1070
"InnoDB: a FOREIGN KEY check running on it.\n",
1071
foreign->foreign_table->name);
1074
/* Release the data dictionary latch for a while, so that we do not
1075
starve other threads from doing CREATE TABLE etc. if we have a huge
1076
cascaded operation running. The counter n_foreign_key_checks_running
1077
will prevent other users from dropping or ALTERing the table when we
1078
release the latch. */
1080
row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
1081
row_mysql_freeze_data_dictionary(thr_get_trx(thr));
1085
/* Restore pcur position */
1087
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1090
mem_heap_free(tmp_heap);
1094
mem_heap_free(upd_vec_heap);
1099
nonstandard_exit_func:
1101
mem_heap_free(tmp_heap);
1105
mem_heap_free(upd_vec_heap);
1108
btr_pcur_store_position(pcur, mtr);
1113
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1118
/*********************************************************************//**
1119
Sets a shared lock on a record. Used in locking possible duplicate key
1120
records and also in checking foreign key constraints.
1121
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
1124
row_ins_set_shared_rec_lock(
1125
/*========================*/
1126
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
1127
LOCK_REC_NOT_GAP type lock */
1128
const buf_block_t* block, /*!< in: buffer block of rec */
1129
const rec_t* rec, /*!< in: record */
1130
dict_index_t* index, /*!< in: index */
1131
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
1132
que_thr_t* thr) /*!< in: query thread */
1136
ut_ad(rec_offs_validate(rec, index, offsets));
1138
if (dict_index_is_clust(index)) {
1139
err = lock_clust_rec_read_check_and_lock(
1140
0, block, rec, index, offsets, LOCK_S, type, thr);
1142
err = lock_sec_rec_read_check_and_lock(
1143
0, block, rec, index, offsets, LOCK_S, type, thr);
1149
/*********************************************************************//**
1150
Sets a exclusive lock on a record. Used in locking possible duplicate key
1152
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
1155
row_ins_set_exclusive_rec_lock(
1156
/*===========================*/
1157
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
1158
LOCK_REC_NOT_GAP type lock */
1159
const buf_block_t* block, /*!< in: buffer block of rec */
1160
const rec_t* rec, /*!< in: record */
1161
dict_index_t* index, /*!< in: index */
1162
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
1163
que_thr_t* thr) /*!< in: query thread */
1167
ut_ad(rec_offs_validate(rec, index, offsets));
1169
if (dict_index_is_clust(index)) {
1170
err = lock_clust_rec_read_check_and_lock(
1171
0, block, rec, index, offsets, LOCK_X, type, thr);
1173
err = lock_sec_rec_read_check_and_lock(
1174
0, block, rec, index, offsets, LOCK_X, type, thr);
1180
/***************************************************************//**
1181
Checks if foreign key constraint fails for an index entry. Sets shared locks
1182
which lock either the success or the failure of the constraint. NOTE that
1183
the caller must have a shared latch on dict_operation_lock.
1184
@return DB_SUCCESS, DB_NO_REFERENCED_ROW, or DB_ROW_IS_REFERENCED */
1187
row_ins_check_foreign_constraint(
1188
/*=============================*/
1189
ibool check_ref,/*!< in: TRUE if we want to check that
1190
the referenced table is ok, FALSE if we
1191
want to check the foreign key table */
1192
dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the
1193
tables mentioned in it must be in the
1194
dictionary cache if they exist at all */
1195
dict_table_t* table, /*!< in: if check_ref is TRUE, then the foreign
1196
table, else the referenced table */
1197
dtuple_t* entry, /*!< in: index entry for index */
1198
que_thr_t* thr) /*!< in: query thread */
1200
upd_node_t* upd_node;
1201
dict_table_t* check_table;
1202
dict_index_t* check_index;
1209
trx_t* trx = thr_get_trx(thr);
1210
mem_heap_t* heap = NULL;
1211
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1212
ulint* offsets = offsets_;
1213
rec_offs_init(offsets_);
1216
#ifdef UNIV_SYNC_DEBUG
1217
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
1218
#endif /* UNIV_SYNC_DEBUG */
1222
if (trx->check_foreigns == FALSE) {
1223
/* The user has suppressed foreign key checks currently for
1228
/* If any of the foreign key fields in entry is SQL NULL, we
1229
suppress the foreign key check: this is compatible with Oracle,
1232
for (i = 0; i < foreign->n_fields; i++) {
1233
if (UNIV_SQL_NULL == dfield_get_len(
1234
dtuple_get_nth_field(entry, i))) {
1240
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
1241
upd_node = static_cast<upd_node_t *>(thr->run_node);
1243
if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
1244
/* If a cascaded update is done as defined by a
1245
foreign key constraint, do not check that
1246
constraint for the child row. In ON UPDATE CASCADE
1247
the update of the parent row is only half done when
1248
we come here: if we would check the constraint here
1249
for the child row it would fail.
1251
A QUESTION remains: if in the child table there are
1252
several constraints which refer to the same parent
1253
table, we should merge all updates to the child as
1254
one update? And the updates can be contradictory!
1255
Currently we just perform the update associated
1256
with each foreign key constraint, one after
1257
another, and the user has problems predicting in
1258
which order they are performed. */
1265
check_table = foreign->referenced_table;
1266
check_index = foreign->referenced_index;
1268
check_table = foreign->foreign_table;
1269
check_index = foreign->foreign_index;
1272
if (check_table == NULL || check_table->ibd_file_missing) {
1274
FILE* ef = dict_foreign_err_file;
1276
row_ins_set_detailed(trx, foreign);
1278
mutex_enter(&dict_foreign_err_mutex);
1280
ut_print_timestamp(ef);
1281
fputs(" Transaction:\n", ef);
1282
trx_print(ef, trx, 600);
1283
fputs("Foreign key constraint fails for table ", ef);
1284
ut_print_name(ef, trx, TRUE,
1285
foreign->foreign_table_name);
1287
dict_print_info_on_foreign_key_in_create_format(
1288
ef, trx, foreign, TRUE);
1289
fputs("\nTrying to add to index ", ef);
1290
ut_print_name(ef, trx, FALSE,
1291
foreign->foreign_index->name);
1292
fputs(" tuple:\n", ef);
1293
dtuple_print(ef, entry);
1294
fputs("\nBut the parent table ", ef);
1295
ut_print_name(ef, trx, TRUE,
1296
foreign->referenced_table_name);
1297
fputs("\nor its .ibd file does"
1298
" not currently exist!\n", ef);
1299
mutex_exit(&dict_foreign_err_mutex);
1301
err = DB_NO_REFERENCED_ROW;
1310
if (check_table != table) {
1311
/* We already have a LOCK_IX on table, but not necessarily
1314
err = lock_table(0, check_table, LOCK_IS, thr);
1316
if (err != DB_SUCCESS) {
1318
goto do_possible_lock_wait;
1324
/* Store old value on n_fields_cmp */
1326
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1328
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
1330
btr_pcur_open(check_index, entry, PAGE_CUR_GE,
1331
BTR_SEARCH_LEAF, &pcur, &mtr);
1333
/* Scan index records and check if there is a matching record */
1336
const rec_t* rec = btr_pcur_get_rec(&pcur);
1337
const buf_block_t* block = btr_pcur_get_block(&pcur);
1339
if (page_rec_is_infimum(rec)) {
1344
offsets = rec_get_offsets(rec, check_index,
1345
offsets, ULINT_UNDEFINED, &heap);
1347
if (page_rec_is_supremum(rec)) {
1349
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
1353
case DB_SUCCESS_LOCKED_REC:
1361
cmp = cmp_dtuple_rec(entry, rec, offsets);
1364
if (rec_get_deleted_flag(rec,
1365
rec_offs_comp(offsets))) {
1366
err = row_ins_set_shared_rec_lock(
1367
LOCK_ORDINARY, block,
1368
rec, check_index, offsets, thr);
1370
case DB_SUCCESS_LOCKED_REC:
1377
/* Found a matching record. Lock only
1378
a record because we can allow inserts
1381
err = row_ins_set_shared_rec_lock(
1382
LOCK_REC_NOT_GAP, block,
1383
rec, check_index, offsets, thr);
1386
case DB_SUCCESS_LOCKED_REC:
1397
} else if (foreign->type != 0) {
1398
/* There is an ON UPDATE or ON DELETE
1399
condition: check them in a separate
1402
err = row_ins_foreign_check_on_constraint(
1403
thr, foreign, &pcur, entry,
1405
if (err != DB_SUCCESS) {
1406
/* Since reporting a plain
1407
"duplicate key" error
1408
message to the user in
1409
cases where a long CASCADE
1410
operation would lead to a
1411
duplicate key in some
1413
confusing, map duplicate
1414
key errors resulting from
1416
separate error code. */
1418
if (err == DB_DUPLICATE_KEY) {
1419
err = DB_FOREIGN_DUPLICATE_KEY;
1425
/* row_ins_foreign_check_on_constraint
1426
may have repositioned pcur on a
1428
block = btr_pcur_get_block(&pcur);
1430
row_ins_foreign_report_err(
1431
"Trying to delete or update",
1432
thr, foreign, rec, entry);
1434
err = DB_ROW_IS_REFERENCED;
1441
err = row_ins_set_shared_rec_lock(
1443
rec, check_index, offsets, thr);
1446
case DB_SUCCESS_LOCKED_REC:
1449
err = DB_NO_REFERENCED_ROW;
1450
row_ins_foreign_report_add_err(
1451
trx, foreign, rec, entry);
1459
} while (btr_pcur_move_to_next(&pcur, &mtr));
1462
row_ins_foreign_report_add_err(
1463
trx, foreign, btr_pcur_get_rec(&pcur), entry);
1464
err = DB_NO_REFERENCED_ROW;
1470
btr_pcur_close(&pcur);
1474
/* Restore old value */
1475
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1477
do_possible_lock_wait:
1478
if (err == DB_LOCK_WAIT) {
1479
trx->error_state = err;
1481
que_thr_stop_for_mysql(thr);
1483
srv_suspend_mysql_thread(thr);
1485
if (trx->error_state == DB_SUCCESS) {
1490
err = trx->error_state;
1494
if (UNIV_LIKELY_NULL(heap)) {
1495
mem_heap_free(heap);
1500
/***************************************************************//**
1501
Checks if foreign key constraints fail for an index entry. If index
1502
is not mentioned in any constraint, this function does nothing,
1503
Otherwise does searches to the indexes of referenced tables and
1504
sets shared locks which lock either the success or the failure of
1506
@return DB_SUCCESS or error code */
1509
row_ins_check_foreign_constraints(
1510
/*==============================*/
1511
dict_table_t* table, /*!< in: table */
1512
dict_index_t* index, /*!< in: index */
1513
dtuple_t* entry, /*!< in: index entry for index */
1514
que_thr_t* thr) /*!< in: query thread */
1516
dict_foreign_t* foreign;
1519
ibool got_s_lock = FALSE;
1521
trx = thr_get_trx(thr);
1523
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1526
if (foreign->foreign_index == index) {
1528
if (foreign->referenced_table == NULL) {
1529
dict_table_get(foreign->referenced_table_name,
1533
if (0 == trx->dict_operation_lock_mode) {
1536
row_mysql_freeze_data_dictionary(trx);
1539
if (foreign->referenced_table) {
1540
mutex_enter(&(dict_sys->mutex));
1542
(foreign->referenced_table
1543
->n_foreign_key_checks_running)++;
1545
mutex_exit(&(dict_sys->mutex));
1548
/* NOTE that if the thread ends up waiting for a lock
1549
we will release dict_operation_lock temporarily!
1550
But the counter on the table protects the referenced
1551
table from being dropped while the check is running. */
1553
err = row_ins_check_foreign_constraint(
1554
TRUE, foreign, table, entry, thr);
1556
if (foreign->referenced_table) {
1557
mutex_enter(&(dict_sys->mutex));
1559
ut_a(foreign->referenced_table
1560
->n_foreign_key_checks_running > 0);
1561
(foreign->referenced_table
1562
->n_foreign_key_checks_running)--;
1564
mutex_exit(&(dict_sys->mutex));
1568
row_mysql_unfreeze_data_dictionary(trx);
1571
if (err != DB_SUCCESS) {
1576
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1582
/***************************************************************//**
1583
Checks if a unique key violation to rec would occur at the index entry
1585
@return TRUE if error */
1588
row_ins_dupl_error_with_rec(
1589
/*========================*/
1590
const rec_t* rec, /*!< in: user record; NOTE that we assume
1591
that the caller already has a record lock on
1593
const dtuple_t* entry, /*!< in: entry to insert */
1594
dict_index_t* index, /*!< in: index */
1595
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
1597
ulint matched_fields;
1598
ulint matched_bytes;
1602
ut_ad(rec_offs_validate(rec, index, offsets));
1604
n_unique = dict_index_get_n_unique(index);
1609
cmp_dtuple_rec_with_match(entry, rec, offsets,
1610
&matched_fields, &matched_bytes);
1612
if (matched_fields < n_unique) {
1617
/* In a unique secondary index we allow equal key values if they
1618
contain SQL NULLs */
1620
if (!dict_index_is_clust(index)) {
1622
for (i = 0; i < n_unique; i++) {
1623
if (UNIV_SQL_NULL == dfield_get_len(
1624
dtuple_get_nth_field(entry, i))) {
1631
return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
1634
/***************************************************************//**
1635
Scans a unique non-clustered index at a given index entry to determine
1636
whether a uniqueness violation has occurred for the key value of the entry.
1637
Set shared locks on possible duplicate records.
1638
@return DB_SUCCESS, DB_DUPLICATE_KEY, or DB_LOCK_WAIT */
1641
row_ins_scan_sec_index_for_duplicate(
1642
/*=================================*/
1643
dict_index_t* index, /*!< in: non-clustered unique index */
1644
dtuple_t* entry, /*!< in: index entry */
1645
que_thr_t* thr) /*!< in: query thread */
1652
ulint err = DB_SUCCESS;
1653
unsigned allow_duplicates;
1655
mem_heap_t* heap = NULL;
1656
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1657
ulint* offsets = offsets_;
1658
rec_offs_init(offsets_);
1660
n_unique = dict_index_get_n_unique(index);
1662
/* If the secondary index is unique, but one of the fields in the
1663
n_unique first fields is NULL, a unique key violation cannot occur,
1664
since we define NULL != NULL in this case */
1666
for (i = 0; i < n_unique; i++) {
1667
if (UNIV_SQL_NULL == dfield_get_len(
1668
dtuple_get_nth_field(entry, i))) {
1676
/* Store old value on n_fields_cmp */
1678
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1680
dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique(index));
1682
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
1684
allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
1686
/* Scan index records and check if there is a duplicate */
1689
const rec_t* rec = btr_pcur_get_rec(&pcur);
1690
const buf_block_t* block = btr_pcur_get_block(&pcur);
1692
if (page_rec_is_infimum(rec)) {
1697
offsets = rec_get_offsets(rec, index, offsets,
1698
ULINT_UNDEFINED, &heap);
1700
if (allow_duplicates) {
1702
/* If the SQL-query will update or replace
1703
duplicate key we will take X-lock for
1704
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1705
INSERT ON DUPLICATE KEY UPDATE). */
1707
err = row_ins_set_exclusive_rec_lock(
1708
LOCK_ORDINARY, block,
1709
rec, index, offsets, thr);
1712
err = row_ins_set_shared_rec_lock(
1713
LOCK_ORDINARY, block,
1714
rec, index, offsets, thr);
1718
case DB_SUCCESS_LOCKED_REC:
1726
if (page_rec_is_supremum(rec)) {
1731
cmp = cmp_dtuple_rec(entry, rec, offsets);
1734
if (row_ins_dupl_error_with_rec(rec, entry,
1736
err = DB_DUPLICATE_KEY;
1738
thr_get_trx(thr)->error_info = index;
1746
} while (btr_pcur_move_to_next(&pcur, &mtr));
1749
if (UNIV_LIKELY_NULL(heap)) {
1750
mem_heap_free(heap);
1754
/* Restore old value */
1755
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1760
/***************************************************************//**
1761
Checks if a unique key violation error would occur at an index entry
1762
insert. Sets shared locks on possible duplicate records. Works only
1763
for a clustered index!
1764
@return DB_SUCCESS if no error, DB_DUPLICATE_KEY if error,
1765
DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
1769
row_ins_duplicate_error_in_clust(
1770
/*=============================*/
1771
btr_cur_t* cursor, /*!< in: B-tree cursor */
1772
const dtuple_t* entry, /*!< in: entry to insert */
1773
que_thr_t* thr, /*!< in: query thread */
1774
mtr_t* mtr) /*!< in: mtr */
1779
trx_t* trx = thr_get_trx(thr);
1780
mem_heap_t*heap = NULL;
1781
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1782
ulint* offsets = offsets_;
1783
rec_offs_init(offsets_);
1787
ut_a(dict_index_is_clust(cursor->index));
1788
ut_ad(dict_index_is_unique(cursor->index));
1790
/* NOTE: For unique non-clustered indexes there may be any number
1791
of delete marked records with the same value for the non-clustered
1792
index key (remember multiversioning), and which differ only in
1793
the row refererence part of the index record, containing the
1794
clustered index key fields. For such a secondary index record,
1795
to avoid race condition, we must FIRST do the insertion and after
1796
that check that the uniqueness condition is not breached! */
1798
/* NOTE: A problem is that in the B-tree node pointers on an
1799
upper level may match more to the entry than the actual existing
1800
user records on the leaf level. So, even if low_match would suggest
1801
that a duplicate key violation may occur, this may not be the case. */
1803
n_unique = dict_index_get_n_unique(cursor->index);
1805
if (cursor->low_match >= n_unique) {
1807
rec = btr_cur_get_rec(cursor);
1809
if (!page_rec_is_infimum(rec)) {
1810
offsets = rec_get_offsets(rec, cursor->index, offsets,
1811
ULINT_UNDEFINED, &heap);
1813
/* We set a lock on the possible duplicate: this
1814
is needed in logical logging of MySQL to make
1815
sure that in roll-forward we get the same duplicate
1816
errors as in original execution */
1818
if (trx->duplicates & TRX_DUP_IGNORE) {
1820
/* If the SQL-query will update or replace
1821
duplicate key we will take X-lock for
1822
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1823
INSERT ON DUPLICATE KEY UPDATE). */
1825
err = row_ins_set_exclusive_rec_lock(
1827
btr_cur_get_block(cursor),
1828
rec, cursor->index, offsets, thr);
1831
err = row_ins_set_shared_rec_lock(
1833
btr_cur_get_block(cursor), rec,
1834
cursor->index, offsets, thr);
1838
case DB_SUCCESS_LOCKED_REC:
1845
if (row_ins_dupl_error_with_rec(
1846
rec, entry, cursor->index, offsets)) {
1847
trx->error_info = cursor->index;
1848
err = DB_DUPLICATE_KEY;
1854
if (cursor->up_match >= n_unique) {
1856
rec = page_rec_get_next(btr_cur_get_rec(cursor));
1858
if (!page_rec_is_supremum(rec)) {
1859
offsets = rec_get_offsets(rec, cursor->index, offsets,
1860
ULINT_UNDEFINED, &heap);
1862
if (trx->duplicates & TRX_DUP_IGNORE) {
1864
/* If the SQL-query will update or replace
1865
duplicate key we will take X-lock for
1866
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1867
INSERT ON DUPLICATE KEY UPDATE). */
1869
err = row_ins_set_exclusive_rec_lock(
1871
btr_cur_get_block(cursor),
1872
rec, cursor->index, offsets, thr);
1875
err = row_ins_set_shared_rec_lock(
1877
btr_cur_get_block(cursor),
1878
rec, cursor->index, offsets, thr);
1882
case DB_SUCCESS_LOCKED_REC:
1889
if (row_ins_dupl_error_with_rec(
1890
rec, entry, cursor->index, offsets)) {
1891
trx->error_info = cursor->index;
1892
err = DB_DUPLICATE_KEY;
1897
ut_a(!dict_index_is_clust(cursor->index));
1898
/* This should never happen */
1903
if (UNIV_LIKELY_NULL(heap)) {
1904
mem_heap_free(heap);
1909
/***************************************************************//**
1910
Checks if an index entry has long enough common prefix with an existing
1911
record so that the intended insert of the entry must be changed to a modify of
1912
the existing record. In the case of a clustered index, the prefix must be
1913
n_unique fields long, and in the case of a secondary index, all fields must be
1915
@return 0 if no update, ROW_INS_PREV if previous should be updated;
1916
currently we do the search so that only the low_match record can match
1917
enough to the search tuple, not the next record */
1920
row_ins_must_modify(
1921
/*================*/
1922
btr_cur_t* cursor) /*!< in: B-tree cursor */
1927
/* NOTE: (compare to the note in row_ins_duplicate_error) Because node
1928
pointers on upper levels of the B-tree may match more to entry than
1929
to actual user records on the leaf level, we have to check if the
1930
candidate record is actually a user record. In a clustered index
1931
node pointers contain index->n_unique first fields, and in the case
1932
of a secondary index, all fields of the index. */
1934
enough_match = dict_index_get_n_unique_in_tree(cursor->index);
1936
if (cursor->low_match >= enough_match) {
1938
rec = btr_cur_get_rec(cursor);
1940
if (!page_rec_is_infimum(rec)) {
1942
return(ROW_INS_PREV);
1949
/***************************************************************//**
1950
Tries to insert an index entry to an index. If the index is clustered
1951
and a record with the same unique key is found, the other record is
1952
necessarily marked deleted by a committed transaction, or a unique key
1953
violation error occurs. The delete marked record is then updated to an
1954
existing record, and we must write an undo log record on the delete
1955
marked record. If the index is secondary, and a record with exactly the
1956
same fields is found, the other record is necessarily marked deleted.
1957
It is then unmarked. Otherwise, the entry is just inserted to the index.
1958
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL if pessimistic retry needed,
1962
row_ins_index_entry_low(
1963
/*====================*/
1964
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
1965
depending on whether we wish optimistic or
1966
pessimistic descent down the index tree */
1967
dict_index_t* index, /*!< in: index */
1968
dtuple_t* entry, /*!< in/out: index entry to insert */
1969
ulint n_ext, /*!< in: number of externally stored columns */
1970
que_thr_t* thr) /*!< in: query thread */
1974
ulint modify = 0; /* remove warning */
1979
big_rec_t* big_rec = NULL;
1981
mem_heap_t* heap = NULL;
1989
/* Note that we use PAGE_CUR_LE as the search mode, because then
1990
the function will return in both low_match and up_match of the
1991
cursor sensible values */
1993
if (dict_index_is_clust(index)) {
1995
} else if (!(thr_get_trx(thr)->check_unique_secondary)) {
1996
search_mode = mode | BTR_INSERT | BTR_IGNORE_SEC_UNIQUE;
1998
search_mode = mode | BTR_INSERT;
2001
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2003
&cursor, 0, __FILE__, __LINE__, &mtr);
2005
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
2006
/* The insertion was made to the insert buffer already during
2007
the search: we are done */
2009
ut_ad(search_mode & BTR_INSERT);
2017
page_t* page = btr_cur_get_page(&cursor);
2018
rec_t* first_rec = page_rec_get_next(
2019
page_get_infimum_rec(page));
2021
ut_ad(page_rec_is_supremum(first_rec)
2022
|| rec_get_n_fields(first_rec, index)
2023
== dtuple_get_n_fields(entry));
2027
n_unique = dict_index_get_n_unique(index);
2029
if (dict_index_is_unique(index) && (cursor.up_match >= n_unique
2030
|| cursor.low_match >= n_unique)) {
2032
if (dict_index_is_clust(index)) {
2033
/* Note that the following may return also
2036
err = row_ins_duplicate_error_in_clust(
2037
&cursor, entry, thr, &mtr);
2038
if (err != DB_SUCCESS) {
2044
err = row_ins_scan_sec_index_for_duplicate(
2048
if (err != DB_SUCCESS) {
2053
/* We did not find a duplicate and we have now
2054
locked with s-locks the necessary records to
2055
prevent any insertion of a duplicate by another
2056
transaction. Let us now reposition the cursor and
2057
continue the insertion. */
2059
btr_cur_search_to_nth_level(index, 0, entry,
2063
__FILE__, __LINE__, &mtr);
2067
modify = row_ins_must_modify(&cursor);
2070
/* There is already an index entry with a long enough common
2071
prefix, we must convert the insert into a modify of an
2074
if (modify == ROW_INS_NEXT) {
2075
rec = page_rec_get_next(btr_cur_get_rec(&cursor));
2077
btr_cur_position(index, rec,
2078
btr_cur_get_block(&cursor),&cursor);
2081
if (dict_index_is_clust(index)) {
2082
err = row_ins_clust_index_entry_by_modify(
2083
mode, &cursor, &heap, &big_rec, entry,
2087
err = row_ins_sec_index_entry_by_modify(
2088
mode, &cursor, entry, thr, &mtr);
2091
if (mode == BTR_MODIFY_LEAF) {
2092
err = btr_cur_optimistic_insert(
2093
0, &cursor, entry, &insert_rec, &big_rec,
2096
ut_a(mode == BTR_MODIFY_TREE);
2097
if (buf_LRU_buf_pool_running_out()) {
2099
err = DB_LOCK_TABLE_FULL;
2103
err = btr_cur_pessimistic_insert(
2104
0, &cursor, entry, &insert_rec, &big_rec,
2112
if (UNIV_LIKELY_NULL(big_rec)) {
2117
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2118
BTR_MODIFY_TREE, &cursor, 0,
2119
__FILE__, __LINE__, &mtr);
2120
exit_rec = btr_cur_get_rec(&cursor);
2121
offsets = rec_get_offsets(exit_rec, index, NULL,
2122
ULINT_UNDEFINED, &heap);
2124
err = btr_store_big_rec_extern_fields(
2125
index, btr_cur_get_block(&cursor),
2126
exit_rec, offsets, big_rec, &mtr);
2129
dtuple_big_rec_free(big_rec);
2131
dtuple_convert_back_big_rec(index, entry, big_rec);
2137
if (UNIV_LIKELY_NULL(heap)) {
2138
mem_heap_free(heap);
2143
/***************************************************************//**
2144
Inserts an index entry to index. Tries first optimistic, then pessimistic
2145
descent down the tree. If the entry matches enough to a delete marked record,
2146
performs the insert by updating or delete unmarking the delete marked
2148
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */
2151
row_ins_index_entry(
2152
/*================*/
2153
dict_index_t* index, /*!< in: index */
2154
dtuple_t* entry, /*!< in/out: index entry to insert */
2155
ulint n_ext, /*!< in: number of externally stored columns */
2156
ibool foreign,/*!< in: TRUE=check foreign key constraints
2157
(foreign=FALSE only during CREATE INDEX) */
2158
que_thr_t* thr) /*!< in: query thread */
2162
if (foreign && UT_LIST_GET_FIRST(index->table->foreign_list)) {
2163
err = static_cast<db_err>(row_ins_check_foreign_constraints(index->table, index,
2165
if (err != DB_SUCCESS) {
2171
/* Try first optimistic descent to the B-tree */
2173
err = static_cast<db_err>(row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
2175
if (err != DB_FAIL) {
2180
/* Try then pessimistic descent to the B-tree */
2182
err = static_cast<db_err>(row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry,
2187
/***********************************************************//**
2188
Sets the values of the dtuple fields in entry from the values of appropriate
2192
row_ins_index_entry_set_vals(
2193
/*=========================*/
2194
dict_index_t* index, /*!< in: index */
2195
dtuple_t* entry, /*!< in: index entry to make */
2196
const dtuple_t* row) /*!< in: row */
2201
ut_ad(entry && row);
2203
n_fields = dtuple_get_n_fields(entry);
2205
for (i = 0; i < n_fields; i++) {
2206
dict_field_t* ind_field;
2208
const dfield_t* row_field;
2211
field = dtuple_get_nth_field(entry, i);
2212
ind_field = dict_index_get_nth_field(index, i);
2213
row_field = dtuple_get_nth_field(row, ind_field->col->ind);
2214
len = dfield_get_len(row_field);
2216
/* Check column prefix indexes */
2217
if (ind_field->prefix_len > 0
2218
&& dfield_get_len(row_field) != UNIV_SQL_NULL) {
2220
const dict_col_t* col
2221
= dict_field_get_col(ind_field);
2223
len = dtype_get_at_most_n_mbchars(
2224
col->prtype, col->mbminmaxlen,
2225
ind_field->prefix_len,
2226
len, static_cast<const char *>(dfield_get_data(row_field)));
2228
ut_ad(!dfield_is_ext(row_field));
2231
dfield_set_data(field, dfield_get_data(row_field), len);
2232
if (dfield_is_ext(row_field)) {
2233
ut_ad(dict_index_is_clust(index));
2234
dfield_set_ext(field);
2239
/***********************************************************//**
2240
Inserts a single index entry to the table.
2241
@return DB_SUCCESS if operation successfully completed, else error
2242
code or DB_LOCK_WAIT */
2245
row_ins_index_entry_step(
2246
/*=====================*/
2247
ins_node_t* node, /*!< in: row insert node */
2248
que_thr_t* thr) /*!< in: query thread */
2252
ut_ad(dtuple_check_typed(node->row));
2254
row_ins_index_entry_set_vals(node->index, node->entry, node->row);
2256
ut_ad(dtuple_check_typed(node->entry));
2258
err = static_cast<db_err>(row_ins_index_entry(node->index, node->entry, 0, TRUE, thr));
2263
/***********************************************************//**
2264
Allocates a row id for row and inits the node->index field. */
2267
row_ins_alloc_row_id_step(
2268
/*======================*/
2269
ins_node_t* node) /*!< in: row insert node */
2273
ut_ad(node->state == INS_NODE_ALLOC_ROW_ID);
2275
if (dict_index_is_unique(dict_table_get_first_index(node->table))) {
2277
/* No row id is stored if the clustered index is unique */
2282
/* Fill in row id value to row */
2284
row_id = dict_sys_get_new_row_id();
2286
dict_sys_write_row_id(node->row_id_buf, row_id);
2289
/***********************************************************//**
2290
Gets a row to insert from the values list. */
2293
row_ins_get_row_from_values(
2294
/*========================*/
2295
ins_node_t* node) /*!< in: row insert node */
2297
que_node_t* list_node;
2302
/* The field values are copied in the buffers of the select node and
2303
it is safe to use them until we fetch from select again: therefore
2304
we can just copy the pointers */
2309
list_node = node->values_list;
2312
eval_exp(list_node);
2314
dfield = dtuple_get_nth_field(row, i);
2315
dfield_copy_data(dfield, que_node_get_val(list_node));
2318
list_node = que_node_get_next(list_node);
2322
/***********************************************************//**
2323
Gets a row to insert from the select list. */
2326
row_ins_get_row_from_select(
2327
/*========================*/
2328
ins_node_t* node) /*!< in: row insert node */
2330
que_node_t* list_node;
2335
/* The field values are copied in the buffers of the select node and
2336
it is safe to use them until we fetch from select again: therefore
2337
we can just copy the pointers */
2342
list_node = node->select->select_list;
2345
dfield = dtuple_get_nth_field(row, i);
2346
dfield_copy_data(dfield, que_node_get_val(list_node));
2349
list_node = que_node_get_next(list_node);
2353
/***********************************************************//**
2354
Inserts a row to a table.
2355
@return DB_SUCCESS if operation successfully completed, else error
2356
code or DB_LOCK_WAIT */
2361
ins_node_t* node, /*!< in: row insert node */
2362
que_thr_t* thr) /*!< in: query thread */
2368
if (node->state == INS_NODE_ALLOC_ROW_ID) {
2370
row_ins_alloc_row_id_step(node);
2372
node->index = dict_table_get_first_index(node->table);
2373
node->entry = UT_LIST_GET_FIRST(node->entry_list);
2375
if (node->ins_type == INS_SEARCHED) {
2377
row_ins_get_row_from_select(node);
2379
} else if (node->ins_type == INS_VALUES) {
2381
row_ins_get_row_from_values(node);
2384
node->state = INS_NODE_INSERT_ENTRIES;
2387
ut_ad(node->state == INS_NODE_INSERT_ENTRIES);
2389
while (node->index != NULL) {
2390
err = row_ins_index_entry_step(node, thr);
2392
if (err != DB_SUCCESS) {
2397
node->index = dict_table_get_next_index(node->index);
2398
node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
2401
ut_ad(node->entry == NULL);
2403
node->state = INS_NODE_ALLOC_ROW_ID;
2408
/***********************************************************//**
2409
Inserts a row to a table. This is a high-level function used in SQL execution
2411
@return query thread to run next or NULL */
2416
que_thr_t* thr) /*!< in: query thread */
2420
sel_node_t* sel_node;
2426
trx = thr_get_trx(thr);
2428
trx_start_if_not_started(trx);
2430
node = static_cast<ins_node_t *>(thr->run_node);
2432
ut_ad(que_node_get_type(node) == QUE_NODE_INSERT);
2434
parent = que_node_get_parent(node);
2435
sel_node = node->select;
2437
if (thr->prev_node == parent) {
2438
node->state = INS_NODE_SET_IX_LOCK;
2441
/* If this is the first time this node is executed (or when
2442
execution resumes after wait for the table IX lock), set an
2443
IX lock on the table and reset the possible select node. MySQL's
2444
partitioned table code may also call an insert within the same
2445
SQL statement AFTER it has used this table handle to do a search.
2446
This happens, for example, when a row update moves it to another
2447
partition. In that case, we have already set the IX lock on the
2448
table during the search operation, and there is no need to set
2449
it again here. But we must write trx->id to node->trx_id_buf. */
2451
trx_write_trx_id(node->trx_id_buf, trx->id);
2453
if (node->state == INS_NODE_SET_IX_LOCK) {
2455
/* It may be that the current session has not yet started
2456
its transaction, or it has been committed: */
2458
if (trx->id == node->trx_id) {
2459
/* No need to do IX-locking */
2464
err = lock_table(0, node->table, LOCK_IX, thr);
2466
if (err != DB_SUCCESS) {
2468
goto error_handling;
2471
node->trx_id = trx->id;
2473
node->state = INS_NODE_ALLOC_ROW_ID;
2475
if (node->ins_type == INS_SEARCHED) {
2476
/* Reset the cursor */
2477
sel_node->state = SEL_NODE_OPEN;
2479
/* Fetch a row to insert */
2481
thr->run_node = sel_node;
2487
if ((node->ins_type == INS_SEARCHED)
2488
&& (sel_node->state != SEL_NODE_FETCH)) {
2490
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2492
/* No more rows to insert */
2493
thr->run_node = parent;
2498
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2500
err = row_ins(node, thr);
2503
trx->error_state = err;
2505
if (err != DB_SUCCESS) {
2506
/* err == DB_LOCK_WAIT or SQL error detected */
2510
/* DO THE TRIGGER ACTIONS HERE */
2512
if (node->ins_type == INS_SEARCHED) {
2513
/* Fetch a row to insert */
2515
thr->run_node = sel_node;
2517
thr->run_node = que_node_get_parent(node);