1
/*****************************************************************************
3
Copyright (c) 1996, 2009, 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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/******************************************************
22
Created 4/20/1996 Heikki Tuuri
23
*******************************************************/
31
#include "dict0dict.h"
32
#include "dict0boot.h"
36
#include "mach0data.h"
42
#include "lock0lock.h"
44
#include "eval0eval.h"
45
#include "data0data.h"
49
#define ROW_INS_PREV 1
50
#define ROW_INS_NEXT 2
53
/*************************************************************************
54
Creates an insert node struct. */
59
/* out, own: insert node struct */
60
ulint ins_type, /* in: INS_VALUES, ... */
61
dict_table_t* table, /* in: table where to insert */
62
mem_heap_t* heap) /* in: mem heap where created */
66
node = mem_heap_alloc(heap, sizeof(ins_node_t));
68
node->common.type = QUE_NODE_INSERT;
70
node->ins_type = ins_type;
72
node->state = INS_NODE_SET_IX_LOCK;
79
node->trx_id = ut_dulint_zero;
81
node->entry_sys_heap = mem_heap_create(128);
83
node->magic_n = INS_NODE_MAGIC_N;
88
/***************************************************************
89
Creates an entry template for each index of a table. */
92
ins_node_create_entry_list(
93
/*=======================*/
94
ins_node_t* node) /* in: row insert node */
99
ut_ad(node->entry_sys_heap);
101
UT_LIST_INIT(node->entry_list);
103
index = dict_table_get_first_index(node->table);
105
while (index != NULL) {
106
entry = row_build_index_entry(node->row, NULL, index,
107
node->entry_sys_heap);
108
UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry);
110
index = dict_table_get_next_index(index);
114
/*********************************************************************
115
Adds system field buffers to a row. */
118
row_ins_alloc_sys_fields(
119
/*=====================*/
120
ins_node_t* node) /* in: insert node */
125
const dict_col_t* col;
131
heap = node->entry_sys_heap;
133
ut_ad(row && table && heap);
134
ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table));
136
/* 1. Allocate buffer for row id */
138
col = dict_table_get_sys_col(table, DATA_ROW_ID);
140
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
142
ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN);
144
dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN);
146
node->row_id_buf = ptr;
148
/* 3. Allocate buffer for trx id */
150
col = dict_table_get_sys_col(table, DATA_TRX_ID);
152
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
153
ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN);
155
dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN);
157
node->trx_id_buf = ptr;
159
/* 4. Allocate buffer for roll ptr */
161
col = dict_table_get_sys_col(table, DATA_ROLL_PTR);
163
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
164
ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN);
166
dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);
169
/*************************************************************************
170
Sets a new row to insert for an INS_DIRECT node. This function is only used
171
if we have constructed the row separately, which is a rare case; this
172
function is quite slow. */
175
ins_node_set_new_row(
176
/*=================*/
177
ins_node_t* node, /* in: insert node */
178
dtuple_t* row) /* in: new row (or first row) for the node */
180
node->state = INS_NODE_SET_IX_LOCK;
186
mem_heap_empty(node->entry_sys_heap);
188
/* Create templates for index entries */
190
ins_node_create_entry_list(node);
192
/* Allocate from entry_sys_heap buffers for sys fields */
194
row_ins_alloc_sys_fields(node);
196
/* As we allocated a new trx id buf, the trx id should be written
199
node->trx_id = ut_dulint_zero;
202
/***********************************************************************
203
Does an insert operation by updating a delete-marked existing record
204
in the index. This situation can occur if the delete-marked record is
205
kept in the index for consistent reads. */
208
row_ins_sec_index_entry_by_modify(
209
/*==============================*/
210
/* out: DB_SUCCESS or error code */
211
ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
212
depending on whether mtr holds just a leaf
213
latch or also a tree latch */
214
btr_cur_t* cursor, /* in: B-tree cursor */
215
const dtuple_t* entry, /* in: index entry to insert */
216
que_thr_t* thr, /* in: query thread */
217
mtr_t* mtr) /* in: mtr; must be committed before
218
latching any further pages */
220
big_rec_t* dummy_big_rec;
226
rec = btr_cur_get_rec(cursor);
228
ut_ad(!dict_index_is_clust(cursor->index));
229
ut_ad(rec_get_deleted_flag(rec,
230
dict_table_is_comp(cursor->index->table)));
232
/* We know that in the alphabetical ordering, entry and rec are
233
identified. But in their binary form there may be differences if
234
there are char fields in them. Therefore we have to calculate the
237
heap = mem_heap_create(1024);
239
update = row_upd_build_sec_rec_difference_binary(
240
cursor->index, entry, rec, thr_get_trx(thr), heap);
241
if (mode == BTR_MODIFY_LEAF) {
242
/* Try an optimistic updating of the record, keeping changes
245
err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor,
246
update, 0, thr, mtr);
250
case DB_ZIP_OVERFLOW:
254
ut_a(mode == BTR_MODIFY_TREE);
255
if (buf_LRU_buf_pool_running_out()) {
257
err = DB_LOCK_TABLE_FULL;
262
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
263
&heap, &dummy_big_rec, update,
265
ut_ad(!dummy_big_rec);
273
/***********************************************************************
274
Does an insert operation by delete unmarking and updating a delete marked
275
existing record in the index. This situation can occur if the delete marked
276
record is kept in the index for consistent reads. */
279
row_ins_clust_index_entry_by_modify(
280
/*================================*/
281
/* out: DB_SUCCESS, DB_FAIL, or error code */
282
ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
283
depending on whether mtr holds just a leaf
284
latch or also a tree latch */
285
btr_cur_t* cursor, /* in: B-tree cursor */
286
mem_heap_t** heap, /* in/out: pointer to memory heap, or NULL */
287
big_rec_t** big_rec,/* out: possible big rec vector of fields
288
which have to be stored externally by the
290
const dtuple_t* entry, /* in: index entry to insert */
291
que_thr_t* thr, /* in: query thread */
292
mtr_t* mtr) /* in: mtr; must be committed before
293
latching any further pages */
299
ut_ad(dict_index_is_clust(cursor->index));
303
rec = btr_cur_get_rec(cursor);
305
ut_ad(rec_get_deleted_flag(rec,
306
dict_table_is_comp(cursor->index->table)));
309
*heap = mem_heap_create(1024);
312
/* Build an update vector containing all the fields to be modified;
313
NOTE that this vector may NOT contain system columns trx_id or
316
update = row_upd_build_difference_binary(cursor->index, entry, rec,
317
thr_get_trx(thr), *heap);
318
if (mode == BTR_MODIFY_LEAF) {
319
/* Try optimistic updating of the record, keeping changes
322
err = btr_cur_optimistic_update(0, cursor, update, 0, thr,
327
case DB_ZIP_OVERFLOW:
331
ut_a(mode == BTR_MODIFY_TREE);
332
if (buf_LRU_buf_pool_running_out()) {
334
return(DB_LOCK_TABLE_FULL);
337
err = btr_cur_pessimistic_update(0, cursor,
338
heap, big_rec, update,
345
/*************************************************************************
346
Returns TRUE if in a cascaded update/delete an ancestor node of node
347
updates (not DELETE, but UPDATE) table. */
350
row_ins_cascade_ancestor_updates_table(
351
/*===================================*/
352
/* out: TRUE if an ancestor updates table */
353
que_node_t* node, /* in: node in a query graph */
354
dict_table_t* table) /* in: table */
357
upd_node_t* upd_node;
359
parent = que_node_get_parent(node);
361
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
365
if (upd_node->table == table && upd_node->is_delete == FALSE) {
370
parent = que_node_get_parent(parent);
378
/*************************************************************************
379
Returns the number of ancestor UPDATE or DELETE nodes of a
380
cascaded update/delete node. */
383
row_ins_cascade_n_ancestors(
384
/*========================*/
385
/* out: number of ancestors */
386
que_node_t* node) /* in: node in a query graph */
389
ulint n_ancestors = 0;
391
parent = que_node_get_parent(node);
393
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
396
parent = que_node_get_parent(parent);
404
/**********************************************************************
405
Calculates the update vector node->cascade->update for a child table in
406
a cascaded update. */
409
row_ins_cascade_calc_update_vec(
410
/*============================*/
411
/* out: number of fields in the
412
calculated update vector; the value
413
can also be 0 if no foreign key
414
fields changed; the returned value
415
is ULINT_UNDEFINED if the column
416
type in the child table is too short
417
to fit the new value in the parent
418
table: that means the update fails */
419
upd_node_t* node, /* in: update node of the parent
421
dict_foreign_t* foreign, /* in: foreign key constraint whose
423
mem_heap_t* heap) /* in: memory heap to use as
426
upd_node_t* cascade = node->cascade_node;
427
dict_table_t* table = foreign->foreign_table;
428
dict_index_t* index = foreign->foreign_index;
431
dict_table_t* parent_table;
432
dict_index_t* parent_index;
433
upd_t* parent_update;
434
upd_field_t* parent_ufield;
435
ulint n_fields_updated;
436
ulint parent_field_no;
446
/* Calculate the appropriate update vector which will set the fields
447
in the child index record to the same value (possibly padded with
448
spaces if the column is a fixed length CHAR or FIXBINARY column) as
449
the referenced index record will get in the update. */
451
parent_table = node->table;
452
ut_a(parent_table == foreign->referenced_table);
453
parent_index = foreign->referenced_index;
454
parent_update = node->update;
456
update = cascade->update;
458
update->info_bits = 0;
459
update->n_fields = foreign->n_fields;
461
n_fields_updated = 0;
463
for (i = 0; i < foreign->n_fields; i++) {
465
parent_field_no = dict_table_get_nth_col_pos(
467
dict_index_get_nth_col_no(parent_index, i));
469
for (j = 0; j < parent_update->n_fields; j++) {
470
parent_ufield = parent_update->fields + j;
472
if (parent_ufield->field_no == parent_field_no) {
475
const dict_col_t* col;
478
col = dict_index_get_nth_col(index, i);
480
/* A field in the parent index record is
481
updated. Let us make the update vector
482
field for the child table. */
484
ufield = update->fields + n_fields_updated;
487
= dict_table_get_nth_col_pos(
488
table, dict_col_get_no(col));
491
ufield->new_val = parent_ufield->new_val;
492
ufield_len = dfield_get_len(&ufield->new_val);
494
/* Clear the "external storage" flag */
495
dfield_set_len(&ufield->new_val, ufield_len);
497
/* Do not allow a NOT NULL column to be
500
if (dfield_is_null(&ufield->new_val)
501
&& (col->prtype & DATA_NOT_NULL)) {
503
return(ULINT_UNDEFINED);
506
/* If the new value would not fit in the
507
column, do not allow the update */
509
if (!dfield_is_null(&ufield->new_val)
510
&& dtype_get_at_most_n_mbchars(
512
col->mbminlen, col->mbmaxlen,
515
dfield_get_data(&ufield->new_val))
518
return(ULINT_UNDEFINED);
521
/* If the parent column type has a different
522
length than the child column type, we may
523
need to pad with spaces the new value of the
526
min_size = dict_col_get_min_size(col);
528
/* Because UNIV_SQL_NULL (the marker
529
of SQL NULL values) exceeds all possible
530
values of min_size, the test below will
531
not hold for SQL NULL columns. */
533
if (min_size > ufield_len) {
540
pad_start = padded_data + ufield_len;
541
pad_end = padded_data + min_size;
544
dfield_get_data(&ufield
546
dfield_get_len(&ufield
549
switch (UNIV_EXPECT(col->mbminlen,1)) {
552
return(ULINT_UNDEFINED);
555
(dtype_get_charset_coll(
557
== DATA_MYSQL_BINARY_CHARSET_COLL)) {
560
return(ULINT_UNDEFINED);
564
memset(pad_start, 0x20,
565
pad_end - pad_start);
569
ut_a(!(ufield_len % 2));
570
ut_a(!(min_size % 2));
574
} while (pad_start < pad_end);
578
dfield_set_data(&ufield->new_val,
579
padded_data, min_size);
587
update->n_fields = n_fields_updated;
589
return(n_fields_updated);
592
/*************************************************************************
593
Set detailed error message associated with foreign key errors for
594
the given transaction. */
597
row_ins_set_detailed(
598
/*=================*/
599
trx_t* trx, /* in: transaction */
600
dict_foreign_t* foreign) /* in: foreign key constraint */
602
mutex_enter(&srv_misc_tmpfile_mutex);
603
rewind(srv_misc_tmpfile);
605
if (os_file_set_eof(srv_misc_tmpfile)) {
606
ut_print_name(srv_misc_tmpfile, trx, TRUE,
607
foreign->foreign_table_name);
608
dict_print_info_on_foreign_key_in_create_format(
609
srv_misc_tmpfile, trx, foreign, FALSE);
610
trx_set_detailed_error_from_file(trx, srv_misc_tmpfile);
612
trx_set_detailed_error(trx, "temp file operation failed");
615
mutex_exit(&srv_misc_tmpfile_mutex);
618
/*************************************************************************
619
Reports a foreign key error associated with an update or a delete of a
620
parent table index entry. */
623
row_ins_foreign_report_err(
624
/*=======================*/
625
const char* errstr, /* in: error string from the viewpoint
626
of the parent table */
627
que_thr_t* thr, /* in: query thread whose run_node
629
dict_foreign_t* foreign, /* in: foreign key constraint */
630
const rec_t* rec, /* in: a matching index record in the
632
const dtuple_t* entry) /* in: index entry in the parent
635
FILE* ef = dict_foreign_err_file;
636
trx_t* trx = thr_get_trx(thr);
638
row_ins_set_detailed(trx, foreign);
640
mutex_enter(&dict_foreign_err_mutex);
642
ut_print_timestamp(ef);
643
fputs(" Transaction:\n", ef);
644
trx_print(ef, trx, 600);
646
fputs("Foreign key constraint fails for table ", ef);
647
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
649
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
653
fputs(" in parent table, in index ", ef);
654
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
656
fputs(" tuple:\n", ef);
657
dtuple_print(ef, entry);
659
fputs("\nBut in child table ", ef);
660
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
661
fputs(", in index ", ef);
662
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
664
fputs(", there is a record:\n", ef);
665
rec_print(ef, rec, foreign->foreign_index);
667
fputs(", the record is not available\n", ef);
671
mutex_exit(&dict_foreign_err_mutex);
674
/*************************************************************************
675
Reports a foreign key error to dict_foreign_err_file when we are trying
676
to add an index entry to a child table. Note that the adding may be the result
677
of an update, too. */
680
row_ins_foreign_report_add_err(
681
/*===========================*/
682
trx_t* trx, /* in: transaction */
683
dict_foreign_t* foreign, /* in: foreign key constraint */
684
const rec_t* rec, /* in: a record in the parent table:
685
it does not match entry because we
687
const dtuple_t* entry) /* in: index entry to insert in the
690
FILE* ef = dict_foreign_err_file;
692
row_ins_set_detailed(trx, foreign);
694
mutex_enter(&dict_foreign_err_mutex);
696
ut_print_timestamp(ef);
697
fputs(" Transaction:\n", ef);
698
trx_print(ef, trx, 600);
699
fputs("Foreign key constraint fails for table ", ef);
700
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
702
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
704
fputs("\nTrying to add in child table, in index ", ef);
705
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
707
fputs(" tuple:\n", ef);
708
/* TODO: DB_TRX_ID and DB_ROLL_PTR may be uninitialized.
709
It would be better to only display the user columns. */
710
dtuple_print(ef, entry);
712
fputs("\nBut in parent table ", ef);
713
ut_print_name(ef, trx, TRUE, foreign->referenced_table_name);
714
fputs(", in index ", ef);
715
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
716
fputs(",\nthe closest match we can find is record:\n", ef);
717
if (rec && page_rec_is_supremum(rec)) {
718
/* If the cursor ended on a supremum record, it is better
719
to report the previous record in the error message, so that
720
the user gets a more descriptive error message. */
721
rec = page_rec_get_prev_const(rec);
725
rec_print(ef, rec, foreign->referenced_index);
729
mutex_exit(&dict_foreign_err_mutex);
732
/*************************************************************************
733
Invalidate the query cache for the given table. */
736
row_ins_invalidate_query_cache(
737
/*===========================*/
738
que_thr_t* unused, /* in: query thread whose run_node
740
const char* name) /* in: table name prefixed with
741
database name and a '/' character */
745
ulint len = strlen(name) + 1;
749
buf = mem_strdupl(name, len);
751
ptr = strchr(buf, '/');
758
/*************************************************************************
759
Perform referential actions or checks when a parent row is deleted or updated
760
and the constraint had an ON DELETE or ON UPDATE condition which was not
764
row_ins_foreign_check_on_constraint(
765
/*================================*/
766
/* out: DB_SUCCESS, DB_LOCK_WAIT,
768
que_thr_t* thr, /* in: query thread whose run_node
770
dict_foreign_t* foreign, /* in: foreign key constraint whose
772
btr_pcur_t* pcur, /* in: cursor placed on a matching
773
index record in the child table */
774
dtuple_t* entry, /* in: index entry in the parent
776
mtr_t* mtr) /* in: mtr holding the latch of pcur
781
dict_table_t* table = foreign->foreign_table;
783
dict_index_t* clust_index;
785
mem_heap_t* upd_vec_heap = NULL;
787
const rec_t* clust_rec;
788
const buf_block_t* clust_block;
794
mem_heap_t* tmp_heap = NULL;
801
trx = thr_get_trx(thr);
803
/* Since we are going to delete or update a row, we have to invalidate
804
the MySQL query cache for table. A deadlock of threads is not possible
805
here because the caller of this function does not hold any latches with
806
the sync0sync.h rank above the kernel mutex. The query cache mutex has
807
a rank just above the kernel mutex. */
809
row_ins_invalidate_query_cache(thr, table->name);
811
node = thr->run_node;
813
if (node->is_delete && 0 == (foreign->type
814
& (DICT_FOREIGN_ON_DELETE_CASCADE
815
| DICT_FOREIGN_ON_DELETE_SET_NULL))) {
817
row_ins_foreign_report_err("Trying to delete",
819
btr_pcur_get_rec(pcur), entry);
821
return(DB_ROW_IS_REFERENCED);
824
if (!node->is_delete && 0 == (foreign->type
825
& (DICT_FOREIGN_ON_UPDATE_CASCADE
826
| DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
828
/* This is an UPDATE */
830
row_ins_foreign_report_err("Trying to update",
832
btr_pcur_get_rec(pcur), entry);
834
return(DB_ROW_IS_REFERENCED);
837
if (node->cascade_node == NULL) {
838
/* Extend our query graph by creating a child to current
839
update node. The child is used in the cascade or set null
842
node->cascade_heap = mem_heap_create(128);
843
node->cascade_node = row_create_update_node_for_mysql(
844
table, node->cascade_heap);
845
que_node_set_parent(node->cascade_node, node);
848
/* Initialize cascade_node to do the operation we want. Note that we
849
use the SAME cascade node to do all foreign key operations of the
850
SQL DELETE: the table of the cascade node may change if there are
851
several child tables to the table where the delete is done! */
853
cascade = node->cascade_node;
855
cascade->table = table;
857
cascade->foreign = foreign;
860
&& (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) {
861
cascade->is_delete = TRUE;
863
cascade->is_delete = FALSE;
865
if (foreign->n_fields > cascade->update_n_fields) {
866
/* We have to make the update vector longer */
868
cascade->update = upd_create(foreign->n_fields,
870
cascade->update_n_fields = foreign->n_fields;
874
/* We do not allow cyclic cascaded updating (DELETE is allowed,
875
but not UPDATE) of the same table, as this can lead to an infinite
876
cycle. Check that we are not updating the same table which is
877
already being modified in this cascade chain. We have to check
878
this also because the modification of the indexes of a 'parent'
879
table may still be incomplete, and we must avoid seeing the indexes
880
of the parent table in an inconsistent state! */
882
if (!cascade->is_delete
883
&& row_ins_cascade_ancestor_updates_table(cascade, table)) {
885
/* We do not know if this would break foreign key
886
constraints, but play safe and return an error */
888
err = DB_ROW_IS_REFERENCED;
890
row_ins_foreign_report_err(
891
"Trying an update, possibly causing a cyclic"
893
"in the child table,", thr, foreign,
894
btr_pcur_get_rec(pcur), entry);
896
goto nonstandard_exit_func;
899
if (row_ins_cascade_n_ancestors(cascade) >= 15) {
900
err = DB_ROW_IS_REFERENCED;
902
row_ins_foreign_report_err(
903
"Trying a too deep cascaded delete or update\n",
904
thr, foreign, btr_pcur_get_rec(pcur), entry);
906
goto nonstandard_exit_func;
909
index = btr_pcur_get_btr_cur(pcur)->index;
911
ut_a(index == foreign->foreign_index);
913
rec = btr_pcur_get_rec(pcur);
915
if (dict_index_is_clust(index)) {
916
/* pcur is already positioned in the clustered index of
921
clust_block = btr_pcur_get_block(pcur);
923
/* We have to look for the record in the clustered index
924
in the child table */
926
clust_index = dict_table_get_first_index(table);
928
tmp_heap = mem_heap_create(256);
930
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
932
btr_pcur_open_with_no_init(clust_index, ref,
933
PAGE_CUR_LE, BTR_SEARCH_LEAF,
934
cascade->pcur, 0, mtr);
936
clust_rec = btr_pcur_get_rec(cascade->pcur);
937
clust_block = btr_pcur_get_block(cascade->pcur);
939
if (!page_rec_is_user_rec(clust_rec)
940
|| btr_pcur_get_low_match(cascade->pcur)
941
< dict_index_get_n_unique(clust_index)) {
943
fputs("InnoDB: error in cascade of a foreign key op\n"
945
dict_index_name_print(stderr, trx, index);
948
"InnoDB: record ", stderr);
949
rec_print(stderr, rec, index);
951
"InnoDB: clustered record ", stderr);
952
rec_print(stderr, clust_rec, clust_index);
954
"InnoDB: Submit a detailed bug report to"
955
" http://bugs.mysql.com\n", stderr);
959
goto nonstandard_exit_func;
963
/* Set an X-lock on the row to delete or update in the child table */
965
err = lock_table(0, table, LOCK_IX, thr);
967
if (err == DB_SUCCESS) {
968
/* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
969
we already have a normal shared lock on the appropriate
970
gap if the search criterion was not unique */
972
err = lock_clust_rec_read_check_and_lock_alt(
973
0, clust_block, clust_rec, clust_index,
974
LOCK_X, LOCK_REC_NOT_GAP, thr);
977
if (err != DB_SUCCESS) {
979
goto nonstandard_exit_func;
982
if (rec_get_deleted_flag(clust_rec, dict_table_is_comp(table))) {
983
/* This can happen if there is a circular reference of
984
rows such that cascading delete comes to delete a row
985
already in the process of being delete marked */
988
goto nonstandard_exit_func;
992
&& (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL))
994
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
996
/* Build the appropriate update vector which sets
997
foreign->n_fields first fields in rec to SQL NULL */
999
update = cascade->update;
1001
update->info_bits = 0;
1002
update->n_fields = foreign->n_fields;
1004
for (i = 0; i < foreign->n_fields; i++) {
1005
upd_field_t* ufield = &update->fields[i];
1007
ufield->field_no = dict_table_get_nth_col_pos(
1009
dict_index_get_nth_col_no(index, i));
1010
ufield->orig_len = 0;
1012
dfield_set_null(&ufield->new_val);
1016
if (!node->is_delete
1017
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
1019
/* Build the appropriate update vector which sets changing
1020
foreign->n_fields first fields in rec to new values */
1022
upd_vec_heap = mem_heap_create(256);
1024
n_to_update = row_ins_cascade_calc_update_vec(node, foreign,
1026
if (n_to_update == ULINT_UNDEFINED) {
1027
err = DB_ROW_IS_REFERENCED;
1029
row_ins_foreign_report_err(
1030
"Trying a cascaded update where the"
1031
" updated value in the child\n"
1032
"table would not fit in the length"
1033
" of the column, or the value would\n"
1034
"be NULL and the column is"
1035
" declared as not NULL in the child table,",
1036
thr, foreign, btr_pcur_get_rec(pcur), entry);
1038
goto nonstandard_exit_func;
1041
if (cascade->update->n_fields == 0) {
1043
/* The update does not change any columns referred
1044
to in this foreign key constraint: no need to do
1049
goto nonstandard_exit_func;
1053
/* Store pcur position and initialize or store the cascade node
1054
pcur stored position */
1056
btr_pcur_store_position(pcur, mtr);
1058
if (index == clust_index) {
1059
btr_pcur_copy_stored_position(cascade->pcur, pcur);
1061
btr_pcur_store_position(cascade->pcur, mtr);
1066
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
1068
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
1070
err = row_update_cascade_for_mysql(thr, cascade,
1071
foreign->foreign_table);
1073
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
1075
"InnoDB: error: table %s has the counter 0"
1076
" though there is\n"
1077
"InnoDB: a FOREIGN KEY check running on it.\n",
1078
foreign->foreign_table->name);
1081
/* Release the data dictionary latch for a while, so that we do not
1082
starve other threads from doing CREATE TABLE etc. if we have a huge
1083
cascaded operation running. The counter n_foreign_key_checks_running
1084
will prevent other users from dropping or ALTERing the table when we
1085
release the latch. */
1087
row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
1088
row_mysql_freeze_data_dictionary(thr_get_trx(thr));
1092
/* Restore pcur position */
1094
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1097
mem_heap_free(tmp_heap);
1101
mem_heap_free(upd_vec_heap);
1106
nonstandard_exit_func:
1108
mem_heap_free(tmp_heap);
1112
mem_heap_free(upd_vec_heap);
1115
btr_pcur_store_position(pcur, mtr);
1120
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1125
/*************************************************************************
1126
Sets a shared lock on a record. Used in locking possible duplicate key
1127
records and also in checking foreign key constraints. */
1130
row_ins_set_shared_rec_lock(
1131
/*========================*/
1132
/* out: DB_SUCCESS or error code */
1133
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
1134
LOCK_REC_NOT_GAP type lock */
1135
const buf_block_t* block, /* in: buffer block of rec */
1136
const rec_t* rec, /* in: record */
1137
dict_index_t* index, /* in: index */
1138
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
1139
que_thr_t* thr) /* in: query thread */
1143
ut_ad(rec_offs_validate(rec, index, offsets));
1145
if (dict_index_is_clust(index)) {
1146
err = lock_clust_rec_read_check_and_lock(
1147
0, block, rec, index, offsets, LOCK_S, type, thr);
1149
err = lock_sec_rec_read_check_and_lock(
1150
0, block, rec, index, offsets, LOCK_S, type, thr);
1156
#ifndef UNIV_HOTBACKUP
1157
/*************************************************************************
1158
Sets a exclusive lock on a record. Used in locking possible duplicate key
1162
row_ins_set_exclusive_rec_lock(
1163
/*===========================*/
1164
/* out: DB_SUCCESS or error code */
1165
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
1166
LOCK_REC_NOT_GAP type lock */
1167
const buf_block_t* block, /* in: buffer block of rec */
1168
const rec_t* rec, /* in: record */
1169
dict_index_t* index, /* in: index */
1170
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
1171
que_thr_t* thr) /* in: query thread */
1175
ut_ad(rec_offs_validate(rec, index, offsets));
1177
if (dict_index_is_clust(index)) {
1178
err = lock_clust_rec_read_check_and_lock(
1179
0, block, rec, index, offsets, LOCK_X, type, thr);
1181
err = lock_sec_rec_read_check_and_lock(
1182
0, block, rec, index, offsets, LOCK_X, type, thr);
1187
#endif /* !UNIV_HOTBACKUP */
1189
/*******************************************************************
1190
Checks if foreign key constraint fails for an index entry. Sets shared locks
1191
which lock either the success or the failure of the constraint. NOTE that
1192
the caller must have a shared latch on dict_operation_lock. */
1195
row_ins_check_foreign_constraint(
1196
/*=============================*/
1198
DB_NO_REFERENCED_ROW,
1199
or DB_ROW_IS_REFERENCED */
1200
ibool check_ref,/* in: TRUE if we want to check that
1201
the referenced table is ok, FALSE if we
1202
want to to check the foreign key table */
1203
dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
1204
tables mentioned in it must be in the
1205
dictionary cache if they exist at all */
1206
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
1207
table, else the referenced table */
1208
dtuple_t* entry, /* in: index entry for index */
1209
que_thr_t* thr) /* in: query thread */
1211
upd_node_t* upd_node;
1212
dict_table_t* check_table;
1213
dict_index_t* check_index;
1221
trx_t* trx = thr_get_trx(thr);
1222
mem_heap_t* heap = NULL;
1223
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1224
ulint* offsets = offsets_;
1225
rec_offs_init(offsets_);
1228
#ifdef UNIV_SYNC_DEBUG
1229
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
1230
#endif /* UNIV_SYNC_DEBUG */
1234
if (trx->check_foreigns == FALSE) {
1235
/* The user has suppressed foreign key checks currently for
1240
/* If any of the foreign key fields in entry is SQL NULL, we
1241
suppress the foreign key check: this is compatible with Oracle,
1244
for (i = 0; i < foreign->n_fields; i++) {
1245
if (UNIV_SQL_NULL == dfield_get_len(
1246
dtuple_get_nth_field(entry, i))) {
1252
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
1253
upd_node = thr->run_node;
1255
if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
1256
/* If a cascaded update is done as defined by a
1257
foreign key constraint, do not check that
1258
constraint for the child row. In ON UPDATE CASCADE
1259
the update of the parent row is only half done when
1260
we come here: if we would check the constraint here
1261
for the child row it would fail.
1263
A QUESTION remains: if in the child table there are
1264
several constraints which refer to the same parent
1265
table, we should merge all updates to the child as
1266
one update? And the updates can be contradictory!
1267
Currently we just perform the update associated
1268
with each foreign key constraint, one after
1269
another, and the user has problems predicting in
1270
which order they are performed. */
1277
check_table = foreign->referenced_table;
1278
check_index = foreign->referenced_index;
1280
check_table = foreign->foreign_table;
1281
check_index = foreign->foreign_index;
1284
if (check_table == NULL || check_table->ibd_file_missing) {
1286
FILE* ef = dict_foreign_err_file;
1288
row_ins_set_detailed(trx, foreign);
1290
mutex_enter(&dict_foreign_err_mutex);
1292
ut_print_timestamp(ef);
1293
fputs(" Transaction:\n", ef);
1294
trx_print(ef, trx, 600);
1295
fputs("Foreign key constraint fails for table ", ef);
1296
ut_print_name(ef, trx, TRUE,
1297
foreign->foreign_table_name);
1299
dict_print_info_on_foreign_key_in_create_format(
1300
ef, trx, foreign, TRUE);
1301
fputs("\nTrying to add to index ", ef);
1302
ut_print_name(ef, trx, FALSE,
1303
foreign->foreign_index->name);
1304
fputs(" tuple:\n", ef);
1305
dtuple_print(ef, entry);
1306
fputs("\nBut the parent table ", ef);
1307
ut_print_name(ef, trx, TRUE,
1308
foreign->referenced_table_name);
1309
fputs("\nor its .ibd file does"
1310
" not currently exist!\n", ef);
1311
mutex_exit(&dict_foreign_err_mutex);
1313
err = DB_NO_REFERENCED_ROW;
1322
if (check_table != table) {
1323
/* We already have a LOCK_IX on table, but not necessarily
1326
err = lock_table(0, check_table, LOCK_IS, thr);
1328
if (err != DB_SUCCESS) {
1330
goto do_possible_lock_wait;
1336
/* Store old value on n_fields_cmp */
1338
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1340
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
1342
btr_pcur_open(check_index, entry, PAGE_CUR_GE,
1343
BTR_SEARCH_LEAF, &pcur, &mtr);
1345
/* Scan index records and check if there is a matching record */
1348
const rec_t* rec = btr_pcur_get_rec(&pcur);
1349
const buf_block_t* block = btr_pcur_get_block(&pcur);
1351
if (page_rec_is_infimum(rec)) {
1356
offsets = rec_get_offsets(rec, check_index,
1357
offsets, ULINT_UNDEFINED, &heap);
1359
if (page_rec_is_supremum(rec)) {
1361
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
1364
if (err != DB_SUCCESS) {
1372
cmp = cmp_dtuple_rec(entry, rec, offsets);
1375
if (rec_get_deleted_flag(rec,
1376
rec_offs_comp(offsets))) {
1377
err = row_ins_set_shared_rec_lock(
1378
LOCK_ORDINARY, block,
1379
rec, check_index, offsets, thr);
1380
if (err != DB_SUCCESS) {
1385
/* Found a matching record. Lock only
1386
a record because we can allow inserts
1389
err = row_ins_set_shared_rec_lock(
1390
LOCK_REC_NOT_GAP, block,
1391
rec, check_index, offsets, thr);
1393
if (err != DB_SUCCESS) {
1402
} else if (foreign->type != 0) {
1403
/* There is an ON UPDATE or ON DELETE
1404
condition: check them in a separate
1407
err = row_ins_foreign_check_on_constraint(
1408
thr, foreign, &pcur, entry,
1410
if (err != DB_SUCCESS) {
1411
/* Since reporting a plain
1412
"duplicate key" error
1413
message to the user in
1414
cases where a long CASCADE
1415
operation would lead to a
1416
duplicate key in some
1418
confusing, map duplicate
1419
key errors resulting from
1421
separate error code. */
1423
if (err == DB_DUPLICATE_KEY) {
1424
err = DB_FOREIGN_DUPLICATE_KEY;
1430
/* row_ins_foreign_check_on_constraint
1431
may have repositioned pcur on a
1433
block = btr_pcur_get_block(&pcur);
1435
row_ins_foreign_report_err(
1436
"Trying to delete or update",
1437
thr, foreign, rec, entry);
1439
err = DB_ROW_IS_REFERENCED;
1446
err = row_ins_set_shared_rec_lock(
1448
rec, check_index, offsets, thr);
1449
if (err != DB_SUCCESS) {
1455
err = DB_NO_REFERENCED_ROW;
1456
row_ins_foreign_report_add_err(
1457
trx, foreign, rec, entry);
1467
moved = btr_pcur_move_to_next(&pcur, &mtr);
1471
rec = btr_pcur_get_rec(&pcur);
1472
row_ins_foreign_report_add_err(
1473
trx, foreign, rec, entry);
1474
err = DB_NO_REFERENCED_ROW;
1483
btr_pcur_close(&pcur);
1487
/* Restore old value */
1488
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1490
do_possible_lock_wait:
1491
if (err == DB_LOCK_WAIT) {
1492
trx->error_state = err;
1494
que_thr_stop_for_mysql(thr);
1496
srv_suspend_mysql_thread(thr);
1498
if (trx->error_state == DB_SUCCESS) {
1503
err = trx->error_state;
1507
if (UNIV_LIKELY_NULL(heap)) {
1508
mem_heap_free(heap);
1513
/*******************************************************************
1514
Checks if foreign key constraints fail for an index entry. If index
1515
is not mentioned in any constraint, this function does nothing,
1516
Otherwise does searches to the indexes of referenced tables and
1517
sets shared locks which lock either the success or the failure of
1521
row_ins_check_foreign_constraints(
1522
/*==============================*/
1523
/* out: DB_SUCCESS or error code */
1524
dict_table_t* table, /* in: table */
1525
dict_index_t* index, /* in: index */
1526
dtuple_t* entry, /* in: index entry for index */
1527
que_thr_t* thr) /* in: query thread */
1529
dict_foreign_t* foreign;
1532
ibool got_s_lock = FALSE;
1534
trx = thr_get_trx(thr);
1536
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1539
if (foreign->foreign_index == index) {
1541
if (foreign->referenced_table == NULL) {
1542
dict_table_get(foreign->referenced_table_name,
1546
if (0 == trx->dict_operation_lock_mode) {
1549
row_mysql_freeze_data_dictionary(trx);
1552
if (foreign->referenced_table) {
1553
mutex_enter(&(dict_sys->mutex));
1555
(foreign->referenced_table
1556
->n_foreign_key_checks_running)++;
1558
mutex_exit(&(dict_sys->mutex));
1561
/* NOTE that if the thread ends up waiting for a lock
1562
we will release dict_operation_lock temporarily!
1563
But the counter on the table protects the referenced
1564
table from being dropped while the check is running. */
1566
err = row_ins_check_foreign_constraint(
1567
TRUE, foreign, table, entry, thr);
1569
if (foreign->referenced_table) {
1570
mutex_enter(&(dict_sys->mutex));
1572
ut_a(foreign->referenced_table
1573
->n_foreign_key_checks_running > 0);
1574
(foreign->referenced_table
1575
->n_foreign_key_checks_running)--;
1577
mutex_exit(&(dict_sys->mutex));
1581
row_mysql_unfreeze_data_dictionary(trx);
1584
if (err != DB_SUCCESS) {
1589
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1595
#ifndef UNIV_HOTBACKUP
1596
/*******************************************************************
1597
Checks if a unique key violation to rec would occur at the index entry
1601
row_ins_dupl_error_with_rec(
1602
/*========================*/
1603
/* out: TRUE if error */
1604
const rec_t* rec, /* in: user record; NOTE that we assume
1605
that the caller already has a record lock on
1607
const dtuple_t* entry, /* in: entry to insert */
1608
dict_index_t* index, /* in: index */
1609
const ulint* offsets)/* in: rec_get_offsets(rec, index) */
1611
ulint matched_fields;
1612
ulint matched_bytes;
1616
ut_ad(rec_offs_validate(rec, index, offsets));
1618
n_unique = dict_index_get_n_unique(index);
1623
cmp_dtuple_rec_with_match(entry, rec, offsets,
1624
&matched_fields, &matched_bytes);
1626
if (matched_fields < n_unique) {
1631
/* In a unique secondary index we allow equal key values if they
1632
contain SQL NULLs */
1634
if (!dict_index_is_clust(index)) {
1636
for (i = 0; i < n_unique; i++) {
1637
if (UNIV_SQL_NULL == dfield_get_len(
1638
dtuple_get_nth_field(entry, i))) {
1645
return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
1647
#endif /* !UNIV_HOTBACKUP */
1649
/*******************************************************************
1650
Scans a unique non-clustered index at a given index entry to determine
1651
whether a uniqueness violation has occurred for the key value of the entry.
1652
Set shared locks on possible duplicate records. */
1655
row_ins_scan_sec_index_for_duplicate(
1656
/*=================================*/
1657
/* out: DB_SUCCESS, DB_DUPLICATE_KEY, or
1659
dict_index_t* index, /* in: non-clustered unique index */
1660
dtuple_t* entry, /* in: index entry */
1661
que_thr_t* thr) /* in: query thread */
1663
#ifndef UNIV_HOTBACKUP
1669
ulint err = DB_SUCCESS;
1670
unsigned allow_duplicates;
1672
mem_heap_t* heap = NULL;
1673
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1674
ulint* offsets = offsets_;
1675
rec_offs_init(offsets_);
1677
n_unique = dict_index_get_n_unique(index);
1679
/* If the secondary index is unique, but one of the fields in the
1680
n_unique first fields is NULL, a unique key violation cannot occur,
1681
since we define NULL != NULL in this case */
1683
for (i = 0; i < n_unique; i++) {
1684
if (UNIV_SQL_NULL == dfield_get_len(
1685
dtuple_get_nth_field(entry, i))) {
1693
/* Store old value on n_fields_cmp */
1695
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1697
dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique(index));
1699
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
1701
allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
1703
/* Scan index records and check if there is a duplicate */
1706
const rec_t* rec = btr_pcur_get_rec(&pcur);
1707
const buf_block_t* block = btr_pcur_get_block(&pcur);
1709
if (page_rec_is_infimum(rec)) {
1714
offsets = rec_get_offsets(rec, index, offsets,
1715
ULINT_UNDEFINED, &heap);
1717
if (allow_duplicates) {
1719
/* If the SQL-query will update or replace
1720
duplicate key we will take X-lock for
1721
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1722
INSERT ON DUPLICATE KEY UPDATE). */
1724
err = row_ins_set_exclusive_rec_lock(
1725
LOCK_ORDINARY, block,
1726
rec, index, offsets, thr);
1729
err = row_ins_set_shared_rec_lock(
1730
LOCK_ORDINARY, block,
1731
rec, index, offsets, thr);
1734
if (err != DB_SUCCESS) {
1739
if (page_rec_is_supremum(rec)) {
1744
cmp = cmp_dtuple_rec(entry, rec, offsets);
1747
if (row_ins_dupl_error_with_rec(rec, entry,
1749
err = DB_DUPLICATE_KEY;
1751
thr_get_trx(thr)->error_info = index;
1762
} while (btr_pcur_move_to_next(&pcur, &mtr));
1764
if (UNIV_LIKELY_NULL(heap)) {
1765
mem_heap_free(heap);
1769
/* Restore old value */
1770
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1773
#else /* UNIV_HOTBACKUP */
1774
/* This function depends on MySQL code that is not included in
1775
InnoDB Hot Backup builds. Besides, this function should never
1776
be called in InnoDB Hot Backup. */
1779
#endif /* UNIV_HOTBACKUP */
1782
/*******************************************************************
1783
Checks if a unique key violation error would occur at an index entry
1784
insert. Sets shared locks on possible duplicate records. Works only
1785
for a clustered index! */
1788
row_ins_duplicate_error_in_clust(
1789
/*=============================*/
1790
/* out: DB_SUCCESS if no error,
1791
DB_DUPLICATE_KEY if error, DB_LOCK_WAIT if we
1792
have to wait for a lock on a possible
1794
btr_cur_t* cursor, /* in: B-tree cursor */
1795
dtuple_t* entry, /* in: entry to insert */
1796
que_thr_t* thr, /* in: query thread */
1797
mtr_t* mtr) /* in: mtr */
1799
#ifndef UNIV_HOTBACKUP
1803
trx_t* trx = thr_get_trx(thr);
1804
mem_heap_t*heap = NULL;
1805
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1806
ulint* offsets = offsets_;
1807
rec_offs_init(offsets_);
1811
ut_a(dict_index_is_clust(cursor->index));
1812
ut_ad(dict_index_is_unique(cursor->index));
1814
/* NOTE: For unique non-clustered indexes there may be any number
1815
of delete marked records with the same value for the non-clustered
1816
index key (remember multiversioning), and which differ only in
1817
the row refererence part of the index record, containing the
1818
clustered index key fields. For such a secondary index record,
1819
to avoid race condition, we must FIRST do the insertion and after
1820
that check that the uniqueness condition is not breached! */
1822
/* NOTE: A problem is that in the B-tree node pointers on an
1823
upper level may match more to the entry than the actual existing
1824
user records on the leaf level. So, even if low_match would suggest
1825
that a duplicate key violation may occur, this may not be the case. */
1827
n_unique = dict_index_get_n_unique(cursor->index);
1829
if (cursor->low_match >= n_unique) {
1831
rec = btr_cur_get_rec(cursor);
1833
if (!page_rec_is_infimum(rec)) {
1834
offsets = rec_get_offsets(rec, cursor->index, offsets,
1835
ULINT_UNDEFINED, &heap);
1837
/* We set a lock on the possible duplicate: this
1838
is needed in logical logging of MySQL to make
1839
sure that in roll-forward we get the same duplicate
1840
errors as in original execution */
1842
if (trx->duplicates & TRX_DUP_IGNORE) {
1844
/* If the SQL-query will update or replace
1845
duplicate key we will take X-lock for
1846
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1847
INSERT ON DUPLICATE KEY UPDATE). */
1849
err = row_ins_set_exclusive_rec_lock(
1851
btr_cur_get_block(cursor),
1852
rec, cursor->index, offsets, thr);
1855
err = row_ins_set_shared_rec_lock(
1857
btr_cur_get_block(cursor), rec,
1858
cursor->index, offsets, thr);
1861
if (err != DB_SUCCESS) {
1865
if (row_ins_dupl_error_with_rec(
1866
rec, entry, cursor->index, offsets)) {
1867
trx->error_info = cursor->index;
1868
err = DB_DUPLICATE_KEY;
1874
if (cursor->up_match >= n_unique) {
1876
rec = page_rec_get_next(btr_cur_get_rec(cursor));
1878
if (!page_rec_is_supremum(rec)) {
1879
offsets = rec_get_offsets(rec, cursor->index, offsets,
1880
ULINT_UNDEFINED, &heap);
1882
if (trx->duplicates & TRX_DUP_IGNORE) {
1884
/* If the SQL-query will update or replace
1885
duplicate key we will take X-lock for
1886
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1887
INSERT ON DUPLICATE KEY UPDATE). */
1889
err = row_ins_set_exclusive_rec_lock(
1891
btr_cur_get_block(cursor),
1892
rec, cursor->index, offsets, thr);
1895
err = row_ins_set_shared_rec_lock(
1897
btr_cur_get_block(cursor),
1898
rec, cursor->index, offsets, thr);
1901
if (err != DB_SUCCESS) {
1905
if (row_ins_dupl_error_with_rec(
1906
rec, entry, cursor->index, offsets)) {
1907
trx->error_info = cursor->index;
1908
err = DB_DUPLICATE_KEY;
1913
ut_a(!dict_index_is_clust(cursor->index));
1914
/* This should never happen */
1919
if (UNIV_LIKELY_NULL(heap)) {
1920
mem_heap_free(heap);
1923
#else /* UNIV_HOTBACKUP */
1924
/* This function depends on MySQL code that is not included in
1925
InnoDB Hot Backup builds. Besides, this function should never
1926
be called in InnoDB Hot Backup. */
1929
#endif /* UNIV_HOTBACKUP */
1932
/*******************************************************************
1933
Checks if an index entry has long enough common prefix with an existing
1934
record so that the intended insert of the entry must be changed to a modify of
1935
the existing record. In the case of a clustered index, the prefix must be
1936
n_unique fields long, and in the case of a secondary index, all fields must be
1940
row_ins_must_modify(
1941
/*================*/
1942
/* out: 0 if no update, ROW_INS_PREV if
1943
previous should be updated; currently we
1944
do the search so that only the low_match
1945
record can match enough to the search tuple,
1946
not the next record */
1947
btr_cur_t* cursor) /* in: B-tree cursor */
1952
/* NOTE: (compare to the note in row_ins_duplicate_error) Because node
1953
pointers on upper levels of the B-tree may match more to entry than
1954
to actual user records on the leaf level, we have to check if the
1955
candidate record is actually a user record. In a clustered index
1956
node pointers contain index->n_unique first fields, and in the case
1957
of a secondary index, all fields of the index. */
1959
enough_match = dict_index_get_n_unique_in_tree(cursor->index);
1961
if (cursor->low_match >= enough_match) {
1963
rec = btr_cur_get_rec(cursor);
1965
if (!page_rec_is_infimum(rec)) {
1967
return(ROW_INS_PREV);
1974
/*******************************************************************
1975
Tries to insert an index entry to an index. If the index is clustered
1976
and a record with the same unique key is found, the other record is
1977
necessarily marked deleted by a committed transaction, or a unique key
1978
violation error occurs. The delete marked record is then updated to an
1979
existing record, and we must write an undo log record on the delete
1980
marked record. If the index is secondary, and a record with exactly the
1981
same fields is found, the other record is necessarily marked deleted.
1982
It is then unmarked. Otherwise, the entry is just inserted to the index. */
1985
row_ins_index_entry_low(
1986
/*====================*/
1987
/* out: DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL
1988
if pessimistic retry needed, or error code */
1989
ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
1990
depending on whether we wish optimistic or
1991
pessimistic descent down the index tree */
1992
dict_index_t* index, /* in: index */
1993
dtuple_t* entry, /* in: index entry to insert */
1994
ulint n_ext, /* in: number of externally stored columns */
1995
que_thr_t* thr) /* in: query thread */
1998
ulint ignore_sec_unique = 0;
1999
ulint modify = 0; /* remove warning */
2004
big_rec_t* big_rec = NULL;
2006
mem_heap_t* heap = NULL;
2014
/* Note that we use PAGE_CUR_LE as the search mode, because then
2015
the function will return in both low_match and up_match of the
2016
cursor sensible values */
2018
if (!(thr_get_trx(thr)->check_unique_secondary)) {
2019
ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE;
2022
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2023
mode | BTR_INSERT | ignore_sec_unique,
2026
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
2027
/* The insertion was made to the insert buffer already during
2028
the search: we are done */
2037
page_t* page = btr_cur_get_page(&cursor);
2038
rec_t* first_rec = page_rec_get_next(
2039
page_get_infimum_rec(page));
2041
ut_ad(page_rec_is_supremum(first_rec)
2042
|| rec_get_n_fields(first_rec, index)
2043
== dtuple_get_n_fields(entry));
2047
n_unique = dict_index_get_n_unique(index);
2049
if (dict_index_is_unique(index) && (cursor.up_match >= n_unique
2050
|| cursor.low_match >= n_unique)) {
2052
if (dict_index_is_clust(index)) {
2053
/* Note that the following may return also
2056
err = row_ins_duplicate_error_in_clust(
2057
&cursor, entry, thr, &mtr);
2058
if (err != DB_SUCCESS) {
2064
err = row_ins_scan_sec_index_for_duplicate(
2068
if (err != DB_SUCCESS) {
2073
/* We did not find a duplicate and we have now
2074
locked with s-locks the necessary records to
2075
prevent any insertion of a duplicate by another
2076
transaction. Let us now reposition the cursor and
2077
continue the insertion. */
2079
btr_cur_search_to_nth_level(index, 0, entry,
2086
modify = row_ins_must_modify(&cursor);
2089
/* There is already an index entry with a long enough common
2090
prefix, we must convert the insert into a modify of an
2093
if (modify == ROW_INS_NEXT) {
2094
rec = page_rec_get_next(btr_cur_get_rec(&cursor));
2096
btr_cur_position(index, rec,
2097
btr_cur_get_block(&cursor),&cursor);
2100
if (dict_index_is_clust(index)) {
2101
err = row_ins_clust_index_entry_by_modify(
2102
mode, &cursor, &heap, &big_rec, entry,
2106
err = row_ins_sec_index_entry_by_modify(
2107
mode, &cursor, entry, thr, &mtr);
2110
if (mode == BTR_MODIFY_LEAF) {
2111
err = btr_cur_optimistic_insert(
2112
0, &cursor, entry, &insert_rec, &big_rec,
2115
ut_a(mode == BTR_MODIFY_TREE);
2116
if (buf_LRU_buf_pool_running_out()) {
2118
err = DB_LOCK_TABLE_FULL;
2122
err = btr_cur_pessimistic_insert(
2123
0, &cursor, entry, &insert_rec, &big_rec,
2131
if (UNIV_LIKELY_NULL(big_rec)) {
2136
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2137
BTR_MODIFY_TREE, &cursor, 0, &mtr);
2138
rec = btr_cur_get_rec(&cursor);
2139
offsets = rec_get_offsets(rec, index, NULL,
2140
ULINT_UNDEFINED, &heap);
2142
err = btr_store_big_rec_extern_fields(
2143
index, btr_cur_get_block(&cursor),
2144
rec, offsets, big_rec, &mtr);
2147
dtuple_big_rec_free(big_rec);
2149
dtuple_convert_back_big_rec(index, entry, big_rec);
2155
if (UNIV_LIKELY_NULL(heap)) {
2156
mem_heap_free(heap);
2161
/*******************************************************************
2162
Inserts an index entry to index. Tries first optimistic, then pessimistic
2163
descent down the tree. If the entry matches enough to a delete marked record,
2164
performs the insert by updating or delete unmarking the delete marked
2168
row_ins_index_entry(
2169
/*================*/
2170
/* out: DB_SUCCESS, DB_LOCK_WAIT,
2171
DB_DUPLICATE_KEY, or some other error code */
2172
dict_index_t* index, /* in: index */
2173
dtuple_t* entry, /* in: index entry to insert */
2174
ulint n_ext, /* in: number of externally stored columns */
2175
ibool foreign,/* in: TRUE=check foreign key constraints */
2176
que_thr_t* thr) /* in: query thread */
2180
if (foreign && UT_LIST_GET_FIRST(index->table->foreign_list)) {
2181
err = row_ins_check_foreign_constraints(index->table, index,
2183
if (err != DB_SUCCESS) {
2189
/* Try first optimistic descent to the B-tree */
2191
err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
2193
if (err != DB_FAIL) {
2198
/* Try then pessimistic descent to the B-tree */
2200
err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry,
2205
/***************************************************************
2206
Sets the values of the dtuple fields in entry from the values of appropriate
2210
row_ins_index_entry_set_vals(
2211
/*=========================*/
2212
dict_index_t* index, /* in: index */
2213
dtuple_t* entry, /* in: index entry to make */
2214
const dtuple_t* row) /* in: row */
2219
ut_ad(entry && row);
2221
n_fields = dtuple_get_n_fields(entry);
2223
for (i = 0; i < n_fields; i++) {
2224
dict_field_t* ind_field;
2226
const dfield_t* row_field;
2229
field = dtuple_get_nth_field(entry, i);
2230
ind_field = dict_index_get_nth_field(index, i);
2231
row_field = dtuple_get_nth_field(row, ind_field->col->ind);
2232
len = dfield_get_len(row_field);
2234
/* Check column prefix indexes */
2235
if (ind_field->prefix_len > 0
2236
&& dfield_get_len(row_field) != UNIV_SQL_NULL) {
2238
const dict_col_t* col
2239
= dict_field_get_col(ind_field);
2241
len = dtype_get_at_most_n_mbchars(
2242
col->prtype, col->mbminlen, col->mbmaxlen,
2243
ind_field->prefix_len,
2244
len, dfield_get_data(row_field));
2246
ut_ad(!dfield_is_ext(row_field));
2249
dfield_set_data(field, dfield_get_data(row_field), len);
2250
if (dfield_is_ext(row_field)) {
2251
ut_ad(dict_index_is_clust(index));
2252
dfield_set_ext(field);
2257
/***************************************************************
2258
Inserts a single index entry to the table. */
2261
row_ins_index_entry_step(
2262
/*=====================*/
2263
/* out: DB_SUCCESS if operation successfully
2264
completed, else error code or DB_LOCK_WAIT */
2265
ins_node_t* node, /* in: row insert node */
2266
que_thr_t* thr) /* in: query thread */
2270
ut_ad(dtuple_check_typed(node->row));
2272
row_ins_index_entry_set_vals(node->index, node->entry, node->row);
2274
ut_ad(dtuple_check_typed(node->entry));
2276
err = row_ins_index_entry(node->index, node->entry, 0, TRUE, thr);
2281
/***************************************************************
2282
Allocates a row id for row and inits the node->index field. */
2285
row_ins_alloc_row_id_step(
2286
/*======================*/
2287
ins_node_t* node) /* in: row insert node */
2291
ut_ad(node->state == INS_NODE_ALLOC_ROW_ID);
2293
if (dict_index_is_unique(dict_table_get_first_index(node->table))) {
2295
/* No row id is stored if the clustered index is unique */
2300
/* Fill in row id value to row */
2302
row_id = dict_sys_get_new_row_id();
2304
dict_sys_write_row_id(node->row_id_buf, row_id);
2307
/***************************************************************
2308
Gets a row to insert from the values list. */
2311
row_ins_get_row_from_values(
2312
/*========================*/
2313
ins_node_t* node) /* in: row insert node */
2315
que_node_t* list_node;
2320
/* The field values are copied in the buffers of the select node and
2321
it is safe to use them until we fetch from select again: therefore
2322
we can just copy the pointers */
2327
list_node = node->values_list;
2330
eval_exp(list_node);
2332
dfield = dtuple_get_nth_field(row, i);
2333
dfield_copy_data(dfield, que_node_get_val(list_node));
2336
list_node = que_node_get_next(list_node);
2340
/***************************************************************
2341
Gets a row to insert from the select list. */
2344
row_ins_get_row_from_select(
2345
/*========================*/
2346
ins_node_t* node) /* in: row insert node */
2348
que_node_t* list_node;
2353
/* The field values are copied in the buffers of the select node and
2354
it is safe to use them until we fetch from select again: therefore
2355
we can just copy the pointers */
2360
list_node = node->select->select_list;
2363
dfield = dtuple_get_nth_field(row, i);
2364
dfield_copy_data(dfield, que_node_get_val(list_node));
2367
list_node = que_node_get_next(list_node);
2371
/***************************************************************
2372
Inserts a row to a table. */
2377
/* out: DB_SUCCESS if operation successfully
2378
completed, else error code or DB_LOCK_WAIT */
2379
ins_node_t* node, /* in: row insert node */
2380
que_thr_t* thr) /* in: query thread */
2386
if (node->state == INS_NODE_ALLOC_ROW_ID) {
2388
row_ins_alloc_row_id_step(node);
2390
node->index = dict_table_get_first_index(node->table);
2391
node->entry = UT_LIST_GET_FIRST(node->entry_list);
2393
if (node->ins_type == INS_SEARCHED) {
2395
row_ins_get_row_from_select(node);
2397
} else if (node->ins_type == INS_VALUES) {
2399
row_ins_get_row_from_values(node);
2402
node->state = INS_NODE_INSERT_ENTRIES;
2405
ut_ad(node->state == INS_NODE_INSERT_ENTRIES);
2407
while (node->index != NULL) {
2408
err = row_ins_index_entry_step(node, thr);
2410
if (err != DB_SUCCESS) {
2415
node->index = dict_table_get_next_index(node->index);
2416
node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
2419
ut_ad(node->entry == NULL);
2421
node->state = INS_NODE_ALLOC_ROW_ID;
2426
/***************************************************************
2427
Inserts a row to a table. This is a high-level function used in SQL execution
2433
/* out: query thread to run next or NULL */
2434
que_thr_t* thr) /* in: query thread */
2438
sel_node_t* sel_node;
2444
trx = thr_get_trx(thr);
2446
trx_start_if_not_started(trx);
2448
node = thr->run_node;
2450
ut_ad(que_node_get_type(node) == QUE_NODE_INSERT);
2452
parent = que_node_get_parent(node);
2453
sel_node = node->select;
2455
if (thr->prev_node == parent) {
2456
node->state = INS_NODE_SET_IX_LOCK;
2459
/* If this is the first time this node is executed (or when
2460
execution resumes after wait for the table IX lock), set an
2461
IX lock on the table and reset the possible select node. MySQL's
2462
partitioned table code may also call an insert within the same
2463
SQL statement AFTER it has used this table handle to do a search.
2464
This happens, for example, when a row update moves it to another
2465
partition. In that case, we have already set the IX lock on the
2466
table during the search operation, and there is no need to set
2467
it again here. But we must write trx->id to node->trx_id_buf. */
2469
trx_write_trx_id(node->trx_id_buf, trx->id);
2471
if (node->state == INS_NODE_SET_IX_LOCK) {
2473
/* It may be that the current session has not yet started
2474
its transaction, or it has been committed: */
2476
if (UT_DULINT_EQ(trx->id, node->trx_id)) {
2477
/* No need to do IX-locking */
2482
err = lock_table(0, node->table, LOCK_IX, thr);
2484
if (err != DB_SUCCESS) {
2486
goto error_handling;
2489
node->trx_id = trx->id;
2491
node->state = INS_NODE_ALLOC_ROW_ID;
2493
if (node->ins_type == INS_SEARCHED) {
2494
/* Reset the cursor */
2495
sel_node->state = SEL_NODE_OPEN;
2497
/* Fetch a row to insert */
2499
thr->run_node = sel_node;
2505
if ((node->ins_type == INS_SEARCHED)
2506
&& (sel_node->state != SEL_NODE_FETCH)) {
2508
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2510
/* No more rows to insert */
2511
thr->run_node = parent;
2516
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2518
err = row_ins(node, thr);
2521
trx->error_state = err;
2523
if (err != DB_SUCCESS) {
2524
/* err == DB_LOCK_WAIT or SQL error detected */
2528
/* DO THE TRIGGER ACTIONS HERE */
2530
if (node->ins_type == INS_SEARCHED) {
2531
/* Fetch a row to insert */
2533
thr->run_node = sel_node;
2535
thr->run_node = que_node_get_parent(node);