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
/**************************************************//**
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
55
/*********************************************************************//**
56
Creates an insert node struct.
57
@return own: insert node struct */
62
ulint ins_type, /*!< in: INS_VALUES, ... */
63
dict_table_t* table, /*!< in: table where to insert */
64
mem_heap_t* heap) /*!< in: mem heap where created */
68
node = mem_heap_alloc(heap, sizeof(ins_node_t));
70
node->common.type = QUE_NODE_INSERT;
72
node->ins_type = ins_type;
74
node->state = INS_NODE_SET_IX_LOCK;
81
node->trx_id = ut_dulint_zero;
83
node->entry_sys_heap = mem_heap_create(128);
85
node->magic_n = INS_NODE_MAGIC_N;
90
/***********************************************************//**
91
Creates an entry template for each index of a table. */
94
ins_node_create_entry_list(
95
/*=======================*/
96
ins_node_t* node) /*!< in: row insert node */
101
ut_ad(node->entry_sys_heap);
103
UT_LIST_INIT(node->entry_list);
105
index = dict_table_get_first_index(node->table);
107
while (index != NULL) {
108
entry = row_build_index_entry(node->row, NULL, index,
109
node->entry_sys_heap);
110
UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry);
112
index = dict_table_get_next_index(index);
116
/*****************************************************************//**
117
Adds system field buffers to a row. */
120
row_ins_alloc_sys_fields(
121
/*=====================*/
122
ins_node_t* node) /*!< in: insert node */
127
const dict_col_t* col;
133
heap = node->entry_sys_heap;
135
ut_ad(row && table && heap);
136
ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table));
138
/* 1. Allocate buffer for row id */
140
col = dict_table_get_sys_col(table, DATA_ROW_ID);
142
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
144
ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN);
146
dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN);
148
node->row_id_buf = ptr;
150
/* 3. Allocate buffer for trx id */
152
col = dict_table_get_sys_col(table, DATA_TRX_ID);
154
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
155
ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN);
157
dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN);
159
node->trx_id_buf = ptr;
161
/* 4. Allocate buffer for roll ptr */
163
col = dict_table_get_sys_col(table, DATA_ROLL_PTR);
165
dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
166
ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN);
168
dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);
171
/*********************************************************************//**
172
Sets a new row to insert for an INS_DIRECT node. This function is only used
173
if we have constructed the row separately, which is a rare case; this
174
function is quite slow. */
177
ins_node_set_new_row(
178
/*=================*/
179
ins_node_t* node, /*!< in: insert node */
180
dtuple_t* row) /*!< in: new row (or first row) for the node */
182
node->state = INS_NODE_SET_IX_LOCK;
188
mem_heap_empty(node->entry_sys_heap);
190
/* Create templates for index entries */
192
ins_node_create_entry_list(node);
194
/* Allocate from entry_sys_heap buffers for sys fields */
196
row_ins_alloc_sys_fields(node);
198
/* As we allocated a new trx id buf, the trx id should be written
201
node->trx_id = ut_dulint_zero;
204
/*******************************************************************//**
205
Does an insert operation by updating a delete-marked existing record
206
in the index. This situation can occur if the delete-marked record is
207
kept in the index for consistent reads.
208
@return DB_SUCCESS or error code */
211
row_ins_sec_index_entry_by_modify(
212
/*==============================*/
213
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
214
depending on whether mtr holds just a leaf
215
latch or also a tree latch */
216
btr_cur_t* cursor, /*!< in: B-tree cursor */
217
const dtuple_t* entry, /*!< in: index entry to insert */
218
que_thr_t* thr, /*!< in: query thread */
219
mtr_t* mtr) /*!< in: mtr; must be committed before
220
latching any further pages */
222
big_rec_t* dummy_big_rec;
228
rec = btr_cur_get_rec(cursor);
230
ut_ad(!dict_index_is_clust(cursor->index));
231
ut_ad(rec_get_deleted_flag(rec,
232
dict_table_is_comp(cursor->index->table)));
234
/* We know that in the alphabetical ordering, entry and rec are
235
identified. But in their binary form there may be differences if
236
there are char fields in them. Therefore we have to calculate the
239
heap = mem_heap_create(1024);
241
update = row_upd_build_sec_rec_difference_binary(
242
cursor->index, entry, rec, thr_get_trx(thr), heap);
243
if (mode == BTR_MODIFY_LEAF) {
244
/* Try an optimistic updating of the record, keeping changes
247
err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor,
248
update, 0, thr, mtr);
252
case DB_ZIP_OVERFLOW:
256
ut_a(mode == BTR_MODIFY_TREE);
257
if (buf_LRU_buf_pool_running_out()) {
259
err = DB_LOCK_TABLE_FULL;
264
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor,
265
&heap, &dummy_big_rec, update,
267
ut_ad(!dummy_big_rec);
275
/*******************************************************************//**
276
Does an insert operation by delete unmarking and updating a delete marked
277
existing record in the index. This situation can occur if the delete marked
278
record is kept in the index for consistent reads.
279
@return DB_SUCCESS, DB_FAIL, or error code */
282
row_ins_clust_index_entry_by_modify(
283
/*================================*/
284
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
285
depending on whether mtr holds just a leaf
286
latch or also a tree latch */
287
btr_cur_t* cursor, /*!< in: B-tree cursor */
288
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
289
big_rec_t** big_rec,/*!< out: possible big rec vector of fields
290
which have to be stored externally by the
292
const dtuple_t* entry, /*!< in: index entry to insert */
293
que_thr_t* thr, /*!< in: query thread */
294
mtr_t* mtr) /*!< in: mtr; must be committed before
295
latching any further pages */
301
ut_ad(dict_index_is_clust(cursor->index));
305
rec = btr_cur_get_rec(cursor);
307
ut_ad(rec_get_deleted_flag(rec,
308
dict_table_is_comp(cursor->index->table)));
311
*heap = mem_heap_create(1024);
314
/* Build an update vector containing all the fields to be modified;
315
NOTE that this vector may NOT contain system columns trx_id or
318
update = row_upd_build_difference_binary(cursor->index, entry, rec,
319
thr_get_trx(thr), *heap);
320
if (mode == BTR_MODIFY_LEAF) {
321
/* Try optimistic updating of the record, keeping changes
324
err = btr_cur_optimistic_update(0, cursor, update, 0, thr,
329
case DB_ZIP_OVERFLOW:
333
ut_a(mode == BTR_MODIFY_TREE);
334
if (buf_LRU_buf_pool_running_out()) {
336
return(DB_LOCK_TABLE_FULL);
339
err = btr_cur_pessimistic_update(0, cursor,
340
heap, big_rec, update,
347
/*********************************************************************//**
348
Returns TRUE if in a cascaded update/delete an ancestor node of node
349
updates (not DELETE, but UPDATE) table.
350
@return TRUE if an ancestor updates table */
353
row_ins_cascade_ancestor_updates_table(
354
/*===================================*/
355
que_node_t* node, /*!< in: node in a query graph */
356
dict_table_t* table) /*!< in: table */
359
upd_node_t* upd_node;
361
parent = que_node_get_parent(node);
363
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
367
if (upd_node->table == table && upd_node->is_delete == FALSE) {
372
parent = que_node_get_parent(parent);
380
/*********************************************************************//**
381
Returns the number of ancestor UPDATE or DELETE nodes of a
382
cascaded update/delete node.
383
@return number of ancestors */
386
row_ins_cascade_n_ancestors(
387
/*========================*/
388
que_node_t* node) /*!< in: node in a query graph */
391
ulint n_ancestors = 0;
393
parent = que_node_get_parent(node);
395
while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
398
parent = que_node_get_parent(parent);
406
/******************************************************************//**
407
Calculates the update vector node->cascade->update for a child table in
409
@return number of fields in the calculated update vector; the value
410
can also be 0 if no foreign key fields changed; the returned value is
411
ULINT_UNDEFINED if the column type in the child table is too short to
412
fit the new value in the parent table: that means the update fails */
415
row_ins_cascade_calc_update_vec(
416
/*============================*/
417
upd_node_t* node, /*!< in: update node of the parent
419
dict_foreign_t* foreign, /*!< in: foreign key constraint whose
421
mem_heap_t* heap) /*!< in: memory heap to use as
424
upd_node_t* cascade = node->cascade_node;
425
dict_table_t* table = foreign->foreign_table;
426
dict_index_t* index = foreign->foreign_index;
429
dict_table_t* parent_table;
430
dict_index_t* parent_index;
431
upd_t* parent_update;
432
upd_field_t* parent_ufield;
433
ulint n_fields_updated;
434
ulint parent_field_no;
444
/* Calculate the appropriate update vector which will set the fields
445
in the child index record to the same value (possibly padded with
446
spaces if the column is a fixed length CHAR or FIXBINARY column) as
447
the referenced index record will get in the update. */
449
parent_table = node->table;
450
ut_a(parent_table == foreign->referenced_table);
451
parent_index = foreign->referenced_index;
452
parent_update = node->update;
454
update = cascade->update;
456
update->info_bits = 0;
457
update->n_fields = foreign->n_fields;
459
n_fields_updated = 0;
461
for (i = 0; i < foreign->n_fields; i++) {
463
parent_field_no = dict_table_get_nth_col_pos(
465
dict_index_get_nth_col_no(parent_index, i));
467
for (j = 0; j < parent_update->n_fields; j++) {
468
parent_ufield = parent_update->fields + j;
470
if (parent_ufield->field_no == parent_field_no) {
473
const dict_col_t* col;
476
col = dict_index_get_nth_col(index, i);
478
/* A field in the parent index record is
479
updated. Let us make the update vector
480
field for the child table. */
482
ufield = update->fields + n_fields_updated;
485
= dict_table_get_nth_col_pos(
486
table, dict_col_get_no(col));
489
ufield->new_val = parent_ufield->new_val;
490
ufield_len = dfield_get_len(&ufield->new_val);
492
/* Clear the "external storage" flag */
493
dfield_set_len(&ufield->new_val, ufield_len);
495
/* Do not allow a NOT NULL column to be
498
if (dfield_is_null(&ufield->new_val)
499
&& (col->prtype & DATA_NOT_NULL)) {
501
return(ULINT_UNDEFINED);
504
/* If the new value would not fit in the
505
column, do not allow the update */
507
if (!dfield_is_null(&ufield->new_val)
508
&& dtype_get_at_most_n_mbchars(
510
col->mbminlen, col->mbmaxlen,
513
dfield_get_data(&ufield->new_val))
516
return(ULINT_UNDEFINED);
519
/* If the parent column type has a different
520
length than the child column type, we may
521
need to pad with spaces the new value of the
524
min_size = dict_col_get_min_size(col);
526
/* Because UNIV_SQL_NULL (the marker
527
of SQL NULL values) exceeds all possible
528
values of min_size, the test below will
529
not hold for SQL NULL columns. */
531
if (min_size > ufield_len) {
538
pad_start = padded_data + ufield_len;
539
pad_end = padded_data + min_size;
542
dfield_get_data(&ufield
544
dfield_get_len(&ufield
547
switch (UNIV_EXPECT(col->mbminlen,1)) {
550
return(ULINT_UNDEFINED);
553
(dtype_get_charset_coll(
555
== DATA_MYSQL_BINARY_CHARSET_COLL)) {
558
return(ULINT_UNDEFINED);
562
memset(pad_start, 0x20,
563
pad_end - pad_start);
567
ut_a(!(ufield_len % 2));
568
ut_a(!(min_size % 2));
572
} while (pad_start < pad_end);
576
dfield_set_data(&ufield->new_val,
577
padded_data, min_size);
585
update->n_fields = n_fields_updated;
587
return(n_fields_updated);
590
/*********************************************************************//**
591
Set detailed error message associated with foreign key errors for
592
the given transaction. */
595
row_ins_set_detailed(
596
/*=================*/
597
trx_t* trx, /*!< in: transaction */
598
dict_foreign_t* foreign) /*!< in: foreign key constraint */
600
mutex_enter(&srv_misc_tmpfile_mutex);
601
rewind(srv_misc_tmpfile);
603
if (os_file_set_eof(srv_misc_tmpfile)) {
604
ut_print_name(srv_misc_tmpfile, trx, TRUE,
605
foreign->foreign_table_name);
606
dict_print_info_on_foreign_key_in_create_format(
607
srv_misc_tmpfile, trx, foreign, FALSE);
608
trx_set_detailed_error_from_file(trx, srv_misc_tmpfile);
610
trx_set_detailed_error(trx, "temp file operation failed");
613
mutex_exit(&srv_misc_tmpfile_mutex);
616
/*********************************************************************//**
617
Reports a foreign key error associated with an update or a delete of a
618
parent table index entry. */
621
row_ins_foreign_report_err(
622
/*=======================*/
623
const char* errstr, /*!< in: error string from the viewpoint
624
of the parent table */
625
que_thr_t* thr, /*!< in: query thread whose run_node
627
dict_foreign_t* foreign, /*!< in: foreign key constraint */
628
const rec_t* rec, /*!< in: a matching index record in the
630
const dtuple_t* entry) /*!< in: index entry in the parent
633
FILE* ef = dict_foreign_err_file;
634
trx_t* trx = thr_get_trx(thr);
636
row_ins_set_detailed(trx, foreign);
638
mutex_enter(&dict_foreign_err_mutex);
640
ut_print_timestamp(ef);
641
fputs(" Transaction:\n", ef);
642
trx_print(ef, trx, 600);
644
fputs("Foreign key constraint fails for table ", ef);
645
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
647
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
651
fputs(" in parent table, in index ", ef);
652
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
654
fputs(" tuple:\n", ef);
655
dtuple_print(ef, entry);
657
fputs("\nBut in child table ", ef);
658
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
659
fputs(", in index ", ef);
660
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
662
fputs(", there is a record:\n", ef);
663
rec_print(ef, rec, foreign->foreign_index);
665
fputs(", the record is not available\n", ef);
669
mutex_exit(&dict_foreign_err_mutex);
672
/*********************************************************************//**
673
Reports a foreign key error to dict_foreign_err_file when we are trying
674
to add an index entry to a child table. Note that the adding may be the result
675
of an update, too. */
678
row_ins_foreign_report_add_err(
679
/*===========================*/
680
trx_t* trx, /*!< in: transaction */
681
dict_foreign_t* foreign, /*!< in: foreign key constraint */
682
const rec_t* rec, /*!< in: a record in the parent table:
683
it does not match entry because we
685
const dtuple_t* entry) /*!< in: index entry to insert in the
688
FILE* ef = dict_foreign_err_file;
690
row_ins_set_detailed(trx, foreign);
692
mutex_enter(&dict_foreign_err_mutex);
694
ut_print_timestamp(ef);
695
fputs(" Transaction:\n", ef);
696
trx_print(ef, trx, 600);
697
fputs("Foreign key constraint fails for table ", ef);
698
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
700
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
702
fputs("\nTrying to add in child table, in index ", ef);
703
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
705
fputs(" tuple:\n", ef);
706
/* TODO: DB_TRX_ID and DB_ROLL_PTR may be uninitialized.
707
It would be better to only display the user columns. */
708
dtuple_print(ef, entry);
710
fputs("\nBut in parent table ", ef);
711
ut_print_name(ef, trx, TRUE, foreign->referenced_table_name);
712
fputs(", in index ", ef);
713
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
714
fputs(",\nthe closest match we can find is record:\n", ef);
715
if (rec && page_rec_is_supremum(rec)) {
716
/* If the cursor ended on a supremum record, it is better
717
to report the previous record in the error message, so that
718
the user gets a more descriptive error message. */
719
rec = page_rec_get_prev_const(rec);
723
rec_print(ef, rec, foreign->referenced_index);
727
mutex_exit(&dict_foreign_err_mutex);
730
/*********************************************************************//**
731
Invalidate the query cache for the given table. */
734
row_ins_invalidate_query_cache(
735
/*===========================*/
736
que_thr_t* unused, /*!< in: query thread whose run_node
738
const char* name) /*!< in: table name prefixed with
739
database name and a '/' character */
743
ulint len = strlen(name) + 1;
747
buf = mem_strdupl(name, len);
749
ptr = strchr(buf, '/');
756
/*********************************************************************//**
757
Perform referential actions or checks when a parent row is deleted or updated
758
and the constraint had an ON DELETE or ON UPDATE condition which was not
760
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
763
row_ins_foreign_check_on_constraint(
764
/*================================*/
765
que_thr_t* thr, /*!< in: query thread whose run_node
767
dict_foreign_t* foreign, /*!< in: foreign key constraint whose
769
btr_pcur_t* pcur, /*!< in: cursor placed on a matching
770
index record in the child table */
771
dtuple_t* entry, /*!< in: index entry in the parent
773
mtr_t* mtr) /*!< in: mtr holding the latch of pcur
778
dict_table_t* table = foreign->foreign_table;
780
dict_index_t* clust_index;
782
mem_heap_t* upd_vec_heap = NULL;
784
const rec_t* clust_rec;
785
const buf_block_t* clust_block;
791
mem_heap_t* tmp_heap = NULL;
798
trx = thr_get_trx(thr);
800
/* Since we are going to delete or update a row, we have to invalidate
801
the MySQL query cache for table. A deadlock of threads is not possible
802
here because the caller of this function does not hold any latches with
803
the sync0sync.h rank above the kernel mutex. The query cache mutex has
804
a rank just above the kernel mutex. */
806
row_ins_invalidate_query_cache(thr, table->name);
808
node = thr->run_node;
810
if (node->is_delete && 0 == (foreign->type
811
& (DICT_FOREIGN_ON_DELETE_CASCADE
812
| DICT_FOREIGN_ON_DELETE_SET_NULL))) {
814
row_ins_foreign_report_err("Trying to delete",
816
btr_pcur_get_rec(pcur), entry);
818
return(DB_ROW_IS_REFERENCED);
821
if (!node->is_delete && 0 == (foreign->type
822
& (DICT_FOREIGN_ON_UPDATE_CASCADE
823
| DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
825
/* This is an UPDATE */
827
row_ins_foreign_report_err("Trying to update",
829
btr_pcur_get_rec(pcur), entry);
831
return(DB_ROW_IS_REFERENCED);
834
if (node->cascade_node == NULL) {
835
/* Extend our query graph by creating a child to current
836
update node. The child is used in the cascade or set null
839
node->cascade_heap = mem_heap_create(128);
840
node->cascade_node = row_create_update_node_for_mysql(
841
table, node->cascade_heap);
842
que_node_set_parent(node->cascade_node, node);
845
/* Initialize cascade_node to do the operation we want. Note that we
846
use the SAME cascade node to do all foreign key operations of the
847
SQL DELETE: the table of the cascade node may change if there are
848
several child tables to the table where the delete is done! */
850
cascade = node->cascade_node;
852
cascade->table = table;
854
cascade->foreign = foreign;
857
&& (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) {
858
cascade->is_delete = TRUE;
860
cascade->is_delete = FALSE;
862
if (foreign->n_fields > cascade->update_n_fields) {
863
/* We have to make the update vector longer */
865
cascade->update = upd_create(foreign->n_fields,
867
cascade->update_n_fields = foreign->n_fields;
871
/* We do not allow cyclic cascaded updating (DELETE is allowed,
872
but not UPDATE) of the same table, as this can lead to an infinite
873
cycle. Check that we are not updating the same table which is
874
already being modified in this cascade chain. We have to check
875
this also because the modification of the indexes of a 'parent'
876
table may still be incomplete, and we must avoid seeing the indexes
877
of the parent table in an inconsistent state! */
879
if (!cascade->is_delete
880
&& row_ins_cascade_ancestor_updates_table(cascade, table)) {
882
/* We do not know if this would break foreign key
883
constraints, but play safe and return an error */
885
err = DB_ROW_IS_REFERENCED;
887
row_ins_foreign_report_err(
888
"Trying an update, possibly causing a cyclic"
890
"in the child table,", thr, foreign,
891
btr_pcur_get_rec(pcur), entry);
893
goto nonstandard_exit_func;
896
if (row_ins_cascade_n_ancestors(cascade) >= 15) {
897
err = DB_ROW_IS_REFERENCED;
899
row_ins_foreign_report_err(
900
"Trying a too deep cascaded delete or update\n",
901
thr, foreign, btr_pcur_get_rec(pcur), entry);
903
goto nonstandard_exit_func;
906
index = btr_pcur_get_btr_cur(pcur)->index;
908
ut_a(index == foreign->foreign_index);
910
rec = btr_pcur_get_rec(pcur);
912
if (dict_index_is_clust(index)) {
913
/* pcur is already positioned in the clustered index of
918
clust_block = btr_pcur_get_block(pcur);
920
/* We have to look for the record in the clustered index
921
in the child table */
923
clust_index = dict_table_get_first_index(table);
925
tmp_heap = mem_heap_create(256);
927
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
929
btr_pcur_open_with_no_init(clust_index, ref,
930
PAGE_CUR_LE, BTR_SEARCH_LEAF,
931
cascade->pcur, 0, mtr);
933
clust_rec = btr_pcur_get_rec(cascade->pcur);
934
clust_block = btr_pcur_get_block(cascade->pcur);
936
if (!page_rec_is_user_rec(clust_rec)
937
|| btr_pcur_get_low_match(cascade->pcur)
938
< dict_index_get_n_unique(clust_index)) {
940
fputs("InnoDB: error in cascade of a foreign key op\n"
942
dict_index_name_print(stderr, trx, index);
945
"InnoDB: record ", stderr);
946
rec_print(stderr, rec, index);
948
"InnoDB: clustered record ", stderr);
949
rec_print(stderr, clust_rec, clust_index);
951
"InnoDB: Submit a detailed bug report to"
952
" http://bugs.mysql.com\n", stderr);
956
goto nonstandard_exit_func;
960
/* Set an X-lock on the row to delete or update in the child table */
962
err = lock_table(0, table, LOCK_IX, thr);
964
if (err == DB_SUCCESS) {
965
/* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
966
we already have a normal shared lock on the appropriate
967
gap if the search criterion was not unique */
969
err = lock_clust_rec_read_check_and_lock_alt(
970
0, clust_block, clust_rec, clust_index,
971
LOCK_X, LOCK_REC_NOT_GAP, thr);
974
if (err != DB_SUCCESS) {
976
goto nonstandard_exit_func;
979
if (rec_get_deleted_flag(clust_rec, dict_table_is_comp(table))) {
980
/* This can happen if there is a circular reference of
981
rows such that cascading delete comes to delete a row
982
already in the process of being delete marked */
985
goto nonstandard_exit_func;
989
&& (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL))
991
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
993
/* Build the appropriate update vector which sets
994
foreign->n_fields first fields in rec to SQL NULL */
996
update = cascade->update;
998
update->info_bits = 0;
999
update->n_fields = foreign->n_fields;
1001
for (i = 0; i < foreign->n_fields; i++) {
1002
upd_field_t* ufield = &update->fields[i];
1004
ufield->field_no = dict_table_get_nth_col_pos(
1006
dict_index_get_nth_col_no(index, i));
1007
ufield->orig_len = 0;
1009
dfield_set_null(&ufield->new_val);
1013
if (!node->is_delete
1014
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
1016
/* Build the appropriate update vector which sets changing
1017
foreign->n_fields first fields in rec to new values */
1019
upd_vec_heap = mem_heap_create(256);
1021
n_to_update = row_ins_cascade_calc_update_vec(node, foreign,
1023
if (n_to_update == ULINT_UNDEFINED) {
1024
err = DB_ROW_IS_REFERENCED;
1026
row_ins_foreign_report_err(
1027
"Trying a cascaded update where the"
1028
" updated value in the child\n"
1029
"table would not fit in the length"
1030
" of the column, or the value would\n"
1031
"be NULL and the column is"
1032
" declared as not NULL in the child table,",
1033
thr, foreign, btr_pcur_get_rec(pcur), entry);
1035
goto nonstandard_exit_func;
1038
if (cascade->update->n_fields == 0) {
1040
/* The update does not change any columns referred
1041
to in this foreign key constraint: no need to do
1046
goto nonstandard_exit_func;
1050
/* Store pcur position and initialize or store the cascade node
1051
pcur stored position */
1053
btr_pcur_store_position(pcur, mtr);
1055
if (index == clust_index) {
1056
btr_pcur_copy_stored_position(cascade->pcur, pcur);
1058
btr_pcur_store_position(cascade->pcur, mtr);
1063
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
1065
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
1067
err = row_update_cascade_for_mysql(thr, cascade,
1068
foreign->foreign_table);
1070
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
1072
"InnoDB: error: table %s has the counter 0"
1073
" though there is\n"
1074
"InnoDB: a FOREIGN KEY check running on it.\n",
1075
foreign->foreign_table->name);
1078
/* Release the data dictionary latch for a while, so that we do not
1079
starve other threads from doing CREATE TABLE etc. if we have a huge
1080
cascaded operation running. The counter n_foreign_key_checks_running
1081
will prevent other users from dropping or ALTERing the table when we
1082
release the latch. */
1084
row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
1085
row_mysql_freeze_data_dictionary(thr_get_trx(thr));
1089
/* Restore pcur position */
1091
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1094
mem_heap_free(tmp_heap);
1098
mem_heap_free(upd_vec_heap);
1103
nonstandard_exit_func:
1105
mem_heap_free(tmp_heap);
1109
mem_heap_free(upd_vec_heap);
1112
btr_pcur_store_position(pcur, mtr);
1117
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
1122
/*********************************************************************//**
1123
Sets a shared lock on a record. Used in locking possible duplicate key
1124
records and also in checking foreign key constraints.
1125
@return DB_SUCCESS or error code */
1128
row_ins_set_shared_rec_lock(
1129
/*========================*/
1130
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
1131
LOCK_REC_NOT_GAP type lock */
1132
const buf_block_t* block, /*!< in: buffer block of rec */
1133
const rec_t* rec, /*!< in: record */
1134
dict_index_t* index, /*!< in: index */
1135
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
1136
que_thr_t* thr) /*!< in: query thread */
1140
ut_ad(rec_offs_validate(rec, index, offsets));
1142
if (dict_index_is_clust(index)) {
1143
err = lock_clust_rec_read_check_and_lock(
1144
0, block, rec, index, offsets, LOCK_S, type, thr);
1146
err = lock_sec_rec_read_check_and_lock(
1147
0, block, rec, index, offsets, LOCK_S, type, thr);
1153
/*********************************************************************//**
1154
Sets a exclusive lock on a record. Used in locking possible duplicate key
1156
@return DB_SUCCESS or error code */
1159
row_ins_set_exclusive_rec_lock(
1160
/*===========================*/
1161
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
1162
LOCK_REC_NOT_GAP type lock */
1163
const buf_block_t* block, /*!< in: buffer block of rec */
1164
const rec_t* rec, /*!< in: record */
1165
dict_index_t* index, /*!< in: index */
1166
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
1167
que_thr_t* thr) /*!< in: query thread */
1171
ut_ad(rec_offs_validate(rec, index, offsets));
1173
if (dict_index_is_clust(index)) {
1174
err = lock_clust_rec_read_check_and_lock(
1175
0, block, rec, index, offsets, LOCK_X, type, thr);
1177
err = lock_sec_rec_read_check_and_lock(
1178
0, block, rec, index, offsets, LOCK_X, type, thr);
1184
/***************************************************************//**
1185
Checks if foreign key constraint fails for an index entry. Sets shared locks
1186
which lock either the success or the failure of the constraint. NOTE that
1187
the caller must have a shared latch on dict_operation_lock.
1188
@return DB_SUCCESS, DB_NO_REFERENCED_ROW, or DB_ROW_IS_REFERENCED */
1191
row_ins_check_foreign_constraint(
1192
/*=============================*/
1193
ibool check_ref,/*!< in: TRUE if we want to check that
1194
the referenced table is ok, FALSE if we
1195
want to to check the foreign key table */
1196
dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the
1197
tables mentioned in it must be in the
1198
dictionary cache if they exist at all */
1199
dict_table_t* table, /*!< in: if check_ref is TRUE, then the foreign
1200
table, else the referenced table */
1201
dtuple_t* entry, /*!< in: index entry for index */
1202
que_thr_t* thr) /*!< in: query thread */
1204
upd_node_t* upd_node;
1205
dict_table_t* check_table;
1206
dict_index_t* check_index;
1214
trx_t* trx = thr_get_trx(thr);
1215
mem_heap_t* heap = NULL;
1216
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1217
ulint* offsets = offsets_;
1218
rec_offs_init(offsets_);
1221
#ifdef UNIV_SYNC_DEBUG
1222
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
1223
#endif /* UNIV_SYNC_DEBUG */
1227
if (trx->check_foreigns == FALSE) {
1228
/* The user has suppressed foreign key checks currently for
1233
/* If any of the foreign key fields in entry is SQL NULL, we
1234
suppress the foreign key check: this is compatible with Oracle,
1237
for (i = 0; i < foreign->n_fields; i++) {
1238
if (UNIV_SQL_NULL == dfield_get_len(
1239
dtuple_get_nth_field(entry, i))) {
1245
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
1246
upd_node = thr->run_node;
1248
if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
1249
/* If a cascaded update is done as defined by a
1250
foreign key constraint, do not check that
1251
constraint for the child row. In ON UPDATE CASCADE
1252
the update of the parent row is only half done when
1253
we come here: if we would check the constraint here
1254
for the child row it would fail.
1256
A QUESTION remains: if in the child table there are
1257
several constraints which refer to the same parent
1258
table, we should merge all updates to the child as
1259
one update? And the updates can be contradictory!
1260
Currently we just perform the update associated
1261
with each foreign key constraint, one after
1262
another, and the user has problems predicting in
1263
which order they are performed. */
1270
check_table = foreign->referenced_table;
1271
check_index = foreign->referenced_index;
1273
check_table = foreign->foreign_table;
1274
check_index = foreign->foreign_index;
1277
if (check_table == NULL || check_table->ibd_file_missing) {
1279
FILE* ef = dict_foreign_err_file;
1281
row_ins_set_detailed(trx, foreign);
1283
mutex_enter(&dict_foreign_err_mutex);
1285
ut_print_timestamp(ef);
1286
fputs(" Transaction:\n", ef);
1287
trx_print(ef, trx, 600);
1288
fputs("Foreign key constraint fails for table ", ef);
1289
ut_print_name(ef, trx, TRUE,
1290
foreign->foreign_table_name);
1292
dict_print_info_on_foreign_key_in_create_format(
1293
ef, trx, foreign, TRUE);
1294
fputs("\nTrying to add to index ", ef);
1295
ut_print_name(ef, trx, FALSE,
1296
foreign->foreign_index->name);
1297
fputs(" tuple:\n", ef);
1298
dtuple_print(ef, entry);
1299
fputs("\nBut the parent table ", ef);
1300
ut_print_name(ef, trx, TRUE,
1301
foreign->referenced_table_name);
1302
fputs("\nor its .ibd file does"
1303
" not currently exist!\n", ef);
1304
mutex_exit(&dict_foreign_err_mutex);
1306
err = DB_NO_REFERENCED_ROW;
1315
if (check_table != table) {
1316
/* We already have a LOCK_IX on table, but not necessarily
1319
err = lock_table(0, check_table, LOCK_IS, thr);
1321
if (err != DB_SUCCESS) {
1323
goto do_possible_lock_wait;
1329
/* Store old value on n_fields_cmp */
1331
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1333
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
1335
btr_pcur_open(check_index, entry, PAGE_CUR_GE,
1336
BTR_SEARCH_LEAF, &pcur, &mtr);
1338
/* Scan index records and check if there is a matching record */
1341
const rec_t* rec = btr_pcur_get_rec(&pcur);
1342
const buf_block_t* block = btr_pcur_get_block(&pcur);
1344
if (page_rec_is_infimum(rec)) {
1349
offsets = rec_get_offsets(rec, check_index,
1350
offsets, ULINT_UNDEFINED, &heap);
1352
if (page_rec_is_supremum(rec)) {
1354
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
1357
if (err != DB_SUCCESS) {
1365
cmp = cmp_dtuple_rec(entry, rec, offsets);
1368
if (rec_get_deleted_flag(rec,
1369
rec_offs_comp(offsets))) {
1370
err = row_ins_set_shared_rec_lock(
1371
LOCK_ORDINARY, block,
1372
rec, check_index, offsets, thr);
1373
if (err != DB_SUCCESS) {
1378
/* Found a matching record. Lock only
1379
a record because we can allow inserts
1382
err = row_ins_set_shared_rec_lock(
1383
LOCK_REC_NOT_GAP, block,
1384
rec, check_index, offsets, thr);
1386
if (err != DB_SUCCESS) {
1395
} else if (foreign->type != 0) {
1396
/* There is an ON UPDATE or ON DELETE
1397
condition: check them in a separate
1400
err = row_ins_foreign_check_on_constraint(
1401
thr, foreign, &pcur, entry,
1403
if (err != DB_SUCCESS) {
1404
/* Since reporting a plain
1405
"duplicate key" error
1406
message to the user in
1407
cases where a long CASCADE
1408
operation would lead to a
1409
duplicate key in some
1411
confusing, map duplicate
1412
key errors resulting from
1414
separate error code. */
1416
if (err == DB_DUPLICATE_KEY) {
1417
err = DB_FOREIGN_DUPLICATE_KEY;
1423
/* row_ins_foreign_check_on_constraint
1424
may have repositioned pcur on a
1426
block = btr_pcur_get_block(&pcur);
1428
row_ins_foreign_report_err(
1429
"Trying to delete or update",
1430
thr, foreign, rec, entry);
1432
err = DB_ROW_IS_REFERENCED;
1439
err = row_ins_set_shared_rec_lock(
1441
rec, check_index, offsets, thr);
1442
if (err != DB_SUCCESS) {
1448
err = DB_NO_REFERENCED_ROW;
1449
row_ins_foreign_report_add_err(
1450
trx, foreign, rec, entry);
1460
moved = btr_pcur_move_to_next(&pcur, &mtr);
1464
rec = btr_pcur_get_rec(&pcur);
1465
row_ins_foreign_report_add_err(
1466
trx, foreign, rec, entry);
1467
err = DB_NO_REFERENCED_ROW;
1476
btr_pcur_close(&pcur);
1480
/* Restore old value */
1481
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1483
do_possible_lock_wait:
1484
if (err == DB_LOCK_WAIT) {
1485
trx->error_state = err;
1487
que_thr_stop_for_mysql(thr);
1489
srv_suspend_mysql_thread(thr);
1491
if (trx->error_state == DB_SUCCESS) {
1496
err = trx->error_state;
1500
if (UNIV_LIKELY_NULL(heap)) {
1501
mem_heap_free(heap);
1506
/***************************************************************//**
1507
Checks if foreign key constraints fail for an index entry. If index
1508
is not mentioned in any constraint, this function does nothing,
1509
Otherwise does searches to the indexes of referenced tables and
1510
sets shared locks which lock either the success or the failure of
1512
@return DB_SUCCESS or error code */
1515
row_ins_check_foreign_constraints(
1516
/*==============================*/
1517
dict_table_t* table, /*!< in: table */
1518
dict_index_t* index, /*!< in: index */
1519
dtuple_t* entry, /*!< in: index entry for index */
1520
que_thr_t* thr) /*!< in: query thread */
1522
dict_foreign_t* foreign;
1525
ibool got_s_lock = FALSE;
1527
trx = thr_get_trx(thr);
1529
foreign = UT_LIST_GET_FIRST(table->foreign_list);
1532
if (foreign->foreign_index == index) {
1534
if (foreign->referenced_table == NULL) {
1535
dict_table_get(foreign->referenced_table_name,
1539
if (0 == trx->dict_operation_lock_mode) {
1542
row_mysql_freeze_data_dictionary(trx);
1545
if (foreign->referenced_table) {
1546
mutex_enter(&(dict_sys->mutex));
1548
(foreign->referenced_table
1549
->n_foreign_key_checks_running)++;
1551
mutex_exit(&(dict_sys->mutex));
1554
/* NOTE that if the thread ends up waiting for a lock
1555
we will release dict_operation_lock temporarily!
1556
But the counter on the table protects the referenced
1557
table from being dropped while the check is running. */
1559
err = row_ins_check_foreign_constraint(
1560
TRUE, foreign, table, entry, thr);
1562
if (foreign->referenced_table) {
1563
mutex_enter(&(dict_sys->mutex));
1565
ut_a(foreign->referenced_table
1566
->n_foreign_key_checks_running > 0);
1567
(foreign->referenced_table
1568
->n_foreign_key_checks_running)--;
1570
mutex_exit(&(dict_sys->mutex));
1574
row_mysql_unfreeze_data_dictionary(trx);
1577
if (err != DB_SUCCESS) {
1582
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1588
/***************************************************************//**
1589
Checks if a unique key violation to rec would occur at the index entry
1591
@return TRUE if error */
1594
row_ins_dupl_error_with_rec(
1595
/*========================*/
1596
const rec_t* rec, /*!< in: user record; NOTE that we assume
1597
that the caller already has a record lock on
1599
const dtuple_t* entry, /*!< in: entry to insert */
1600
dict_index_t* index, /*!< in: index */
1601
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
1603
ulint matched_fields;
1604
ulint matched_bytes;
1608
ut_ad(rec_offs_validate(rec, index, offsets));
1610
n_unique = dict_index_get_n_unique(index);
1615
cmp_dtuple_rec_with_match(entry, rec, offsets,
1616
&matched_fields, &matched_bytes);
1618
if (matched_fields < n_unique) {
1623
/* In a unique secondary index we allow equal key values if they
1624
contain SQL NULLs */
1626
if (!dict_index_is_clust(index)) {
1628
for (i = 0; i < n_unique; i++) {
1629
if (UNIV_SQL_NULL == dfield_get_len(
1630
dtuple_get_nth_field(entry, i))) {
1637
return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
1640
/***************************************************************//**
1641
Scans a unique non-clustered index at a given index entry to determine
1642
whether a uniqueness violation has occurred for the key value of the entry.
1643
Set shared locks on possible duplicate records.
1644
@return DB_SUCCESS, DB_DUPLICATE_KEY, or DB_LOCK_WAIT */
1647
row_ins_scan_sec_index_for_duplicate(
1648
/*=================================*/
1649
dict_index_t* index, /*!< in: non-clustered unique index */
1650
dtuple_t* entry, /*!< in: index entry */
1651
que_thr_t* thr) /*!< in: query thread */
1658
ulint err = DB_SUCCESS;
1659
unsigned allow_duplicates;
1661
mem_heap_t* heap = NULL;
1662
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1663
ulint* offsets = offsets_;
1664
rec_offs_init(offsets_);
1666
n_unique = dict_index_get_n_unique(index);
1668
/* If the secondary index is unique, but one of the fields in the
1669
n_unique first fields is NULL, a unique key violation cannot occur,
1670
since we define NULL != NULL in this case */
1672
for (i = 0; i < n_unique; i++) {
1673
if (UNIV_SQL_NULL == dfield_get_len(
1674
dtuple_get_nth_field(entry, i))) {
1682
/* Store old value on n_fields_cmp */
1684
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
1686
dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique(index));
1688
btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
1690
allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE;
1692
/* Scan index records and check if there is a duplicate */
1695
const rec_t* rec = btr_pcur_get_rec(&pcur);
1696
const buf_block_t* block = btr_pcur_get_block(&pcur);
1698
if (page_rec_is_infimum(rec)) {
1703
offsets = rec_get_offsets(rec, index, offsets,
1704
ULINT_UNDEFINED, &heap);
1706
if (allow_duplicates) {
1708
/* If the SQL-query will update or replace
1709
duplicate key we will take X-lock for
1710
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1711
INSERT ON DUPLICATE KEY UPDATE). */
1713
err = row_ins_set_exclusive_rec_lock(
1714
LOCK_ORDINARY, block,
1715
rec, index, offsets, thr);
1718
err = row_ins_set_shared_rec_lock(
1719
LOCK_ORDINARY, block,
1720
rec, index, offsets, thr);
1723
if (err != DB_SUCCESS) {
1728
if (page_rec_is_supremum(rec)) {
1733
cmp = cmp_dtuple_rec(entry, rec, offsets);
1736
if (row_ins_dupl_error_with_rec(rec, entry,
1738
err = DB_DUPLICATE_KEY;
1740
thr_get_trx(thr)->error_info = index;
1751
} while (btr_pcur_move_to_next(&pcur, &mtr));
1753
if (UNIV_LIKELY_NULL(heap)) {
1754
mem_heap_free(heap);
1758
/* Restore old value */
1759
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1764
/***************************************************************//**
1765
Checks if a unique key violation error would occur at an index entry
1766
insert. Sets shared locks on possible duplicate records. Works only
1767
for a clustered index!
1768
@return DB_SUCCESS if no error, DB_DUPLICATE_KEY if error,
1769
DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
1773
row_ins_duplicate_error_in_clust(
1774
/*=============================*/
1775
btr_cur_t* cursor, /*!< in: B-tree cursor */
1776
dtuple_t* entry, /*!< in: entry to insert */
1777
que_thr_t* thr, /*!< in: query thread */
1778
mtr_t* mtr) /*!< in: mtr */
1783
trx_t* trx = thr_get_trx(thr);
1784
mem_heap_t*heap = NULL;
1785
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1786
ulint* offsets = offsets_;
1787
rec_offs_init(offsets_);
1791
ut_a(dict_index_is_clust(cursor->index));
1792
ut_ad(dict_index_is_unique(cursor->index));
1794
/* NOTE: For unique non-clustered indexes there may be any number
1795
of delete marked records with the same value for the non-clustered
1796
index key (remember multiversioning), and which differ only in
1797
the row refererence part of the index record, containing the
1798
clustered index key fields. For such a secondary index record,
1799
to avoid race condition, we must FIRST do the insertion and after
1800
that check that the uniqueness condition is not breached! */
1802
/* NOTE: A problem is that in the B-tree node pointers on an
1803
upper level may match more to the entry than the actual existing
1804
user records on the leaf level. So, even if low_match would suggest
1805
that a duplicate key violation may occur, this may not be the case. */
1807
n_unique = dict_index_get_n_unique(cursor->index);
1809
if (cursor->low_match >= n_unique) {
1811
rec = btr_cur_get_rec(cursor);
1813
if (!page_rec_is_infimum(rec)) {
1814
offsets = rec_get_offsets(rec, cursor->index, offsets,
1815
ULINT_UNDEFINED, &heap);
1817
/* We set a lock on the possible duplicate: this
1818
is needed in logical logging of MySQL to make
1819
sure that in roll-forward we get the same duplicate
1820
errors as in original execution */
1822
if (trx->duplicates & TRX_DUP_IGNORE) {
1824
/* If the SQL-query will update or replace
1825
duplicate key we will take X-lock for
1826
duplicates ( REPLACE, LOAD DATAFILE REPLACE,
1827
INSERT ON DUPLICATE KEY UPDATE). */
1829
err = row_ins_set_exclusive_rec_lock(
1831
btr_cur_get_block(cursor),
1832
rec, cursor->index, offsets, thr);
1835
err = row_ins_set_shared_rec_lock(
1837
btr_cur_get_block(cursor), rec,
1838
cursor->index, offsets, thr);
1841
if (err != DB_SUCCESS) {
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);
1881
if (err != DB_SUCCESS) {
1885
if (row_ins_dupl_error_with_rec(
1886
rec, entry, cursor->index, offsets)) {
1887
trx->error_info = cursor->index;
1888
err = DB_DUPLICATE_KEY;
1893
ut_a(!dict_index_is_clust(cursor->index));
1894
/* This should never happen */
1899
if (UNIV_LIKELY_NULL(heap)) {
1900
mem_heap_free(heap);
1905
/***************************************************************//**
1906
Checks if an index entry has long enough common prefix with an existing
1907
record so that the intended insert of the entry must be changed to a modify of
1908
the existing record. In the case of a clustered index, the prefix must be
1909
n_unique fields long, and in the case of a secondary index, all fields must be
1911
@return 0 if no update, ROW_INS_PREV if previous should be updated;
1912
currently we do the search so that only the low_match record can match
1913
enough to the search tuple, not the next record */
1916
row_ins_must_modify(
1917
/*================*/
1918
btr_cur_t* cursor) /*!< in: B-tree cursor */
1923
/* NOTE: (compare to the note in row_ins_duplicate_error) Because node
1924
pointers on upper levels of the B-tree may match more to entry than
1925
to actual user records on the leaf level, we have to check if the
1926
candidate record is actually a user record. In a clustered index
1927
node pointers contain index->n_unique first fields, and in the case
1928
of a secondary index, all fields of the index. */
1930
enough_match = dict_index_get_n_unique_in_tree(cursor->index);
1932
if (cursor->low_match >= enough_match) {
1934
rec = btr_cur_get_rec(cursor);
1936
if (!page_rec_is_infimum(rec)) {
1938
return(ROW_INS_PREV);
1945
/***************************************************************//**
1946
Tries to insert an index entry to an index. If the index is clustered
1947
and a record with the same unique key is found, the other record is
1948
necessarily marked deleted by a committed transaction, or a unique key
1949
violation error occurs. The delete marked record is then updated to an
1950
existing record, and we must write an undo log record on the delete
1951
marked record. If the index is secondary, and a record with exactly the
1952
same fields is found, the other record is necessarily marked deleted.
1953
It is then unmarked. Otherwise, the entry is just inserted to the index.
1954
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL if pessimistic retry needed,
1958
row_ins_index_entry_low(
1959
/*====================*/
1960
ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
1961
depending on whether we wish optimistic or
1962
pessimistic descent down the index tree */
1963
dict_index_t* index, /*!< in: index */
1964
dtuple_t* entry, /*!< in: index entry to insert */
1965
ulint n_ext, /*!< in: number of externally stored columns */
1966
que_thr_t* thr) /*!< in: query thread */
1969
ulint ignore_sec_unique = 0;
1970
ulint modify = 0; /* remove warning */
1975
big_rec_t* big_rec = NULL;
1977
mem_heap_t* heap = NULL;
1985
/* Note that we use PAGE_CUR_LE as the search mode, because then
1986
the function will return in both low_match and up_match of the
1987
cursor sensible values */
1989
if (!(thr_get_trx(thr)->check_unique_secondary)) {
1990
ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE;
1993
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
1994
mode | BTR_INSERT | ignore_sec_unique,
1997
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
1998
/* The insertion was made to the insert buffer already during
1999
the search: we are done */
2008
page_t* page = btr_cur_get_page(&cursor);
2009
rec_t* first_rec = page_rec_get_next(
2010
page_get_infimum_rec(page));
2012
ut_ad(page_rec_is_supremum(first_rec)
2013
|| rec_get_n_fields(first_rec, index)
2014
== dtuple_get_n_fields(entry));
2018
n_unique = dict_index_get_n_unique(index);
2020
if (dict_index_is_unique(index) && (cursor.up_match >= n_unique
2021
|| cursor.low_match >= n_unique)) {
2023
if (dict_index_is_clust(index)) {
2024
/* Note that the following may return also
2027
err = row_ins_duplicate_error_in_clust(
2028
&cursor, entry, thr, &mtr);
2029
if (err != DB_SUCCESS) {
2035
err = row_ins_scan_sec_index_for_duplicate(
2039
if (err != DB_SUCCESS) {
2044
/* We did not find a duplicate and we have now
2045
locked with s-locks the necessary records to
2046
prevent any insertion of a duplicate by another
2047
transaction. Let us now reposition the cursor and
2048
continue the insertion. */
2050
btr_cur_search_to_nth_level(index, 0, entry,
2057
modify = row_ins_must_modify(&cursor);
2060
/* There is already an index entry with a long enough common
2061
prefix, we must convert the insert into a modify of an
2064
if (modify == ROW_INS_NEXT) {
2065
rec = page_rec_get_next(btr_cur_get_rec(&cursor));
2067
btr_cur_position(index, rec,
2068
btr_cur_get_block(&cursor),&cursor);
2071
if (dict_index_is_clust(index)) {
2072
err = row_ins_clust_index_entry_by_modify(
2073
mode, &cursor, &heap, &big_rec, entry,
2077
err = row_ins_sec_index_entry_by_modify(
2078
mode, &cursor, entry, thr, &mtr);
2081
if (mode == BTR_MODIFY_LEAF) {
2082
err = btr_cur_optimistic_insert(
2083
0, &cursor, entry, &insert_rec, &big_rec,
2086
ut_a(mode == BTR_MODIFY_TREE);
2087
if (buf_LRU_buf_pool_running_out()) {
2089
err = DB_LOCK_TABLE_FULL;
2093
err = btr_cur_pessimistic_insert(
2094
0, &cursor, entry, &insert_rec, &big_rec,
2102
if (UNIV_LIKELY_NULL(big_rec)) {
2107
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2108
BTR_MODIFY_TREE, &cursor, 0, &mtr);
2109
rec = btr_cur_get_rec(&cursor);
2110
offsets = rec_get_offsets(rec, index, NULL,
2111
ULINT_UNDEFINED, &heap);
2113
err = btr_store_big_rec_extern_fields(
2114
index, btr_cur_get_block(&cursor),
2115
rec, offsets, big_rec, &mtr);
2118
dtuple_big_rec_free(big_rec);
2120
dtuple_convert_back_big_rec(index, entry, big_rec);
2126
if (UNIV_LIKELY_NULL(heap)) {
2127
mem_heap_free(heap);
2132
/***************************************************************//**
2133
Inserts an index entry to index. Tries first optimistic, then pessimistic
2134
descent down the tree. If the entry matches enough to a delete marked record,
2135
performs the insert by updating or delete unmarking the delete marked
2137
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */
2140
row_ins_index_entry(
2141
/*================*/
2142
dict_index_t* index, /*!< in: index */
2143
dtuple_t* entry, /*!< in: index entry to insert */
2144
ulint n_ext, /*!< in: number of externally stored columns */
2145
ibool foreign,/*!< in: TRUE=check foreign key constraints */
2146
que_thr_t* thr) /*!< in: query thread */
2150
if (foreign && UT_LIST_GET_FIRST(index->table->foreign_list)) {
2151
err = row_ins_check_foreign_constraints(index->table, index,
2153
if (err != DB_SUCCESS) {
2159
/* Try first optimistic descent to the B-tree */
2161
err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
2163
if (err != DB_FAIL) {
2168
/* Try then pessimistic descent to the B-tree */
2170
err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry,
2175
/***********************************************************//**
2176
Sets the values of the dtuple fields in entry from the values of appropriate
2180
row_ins_index_entry_set_vals(
2181
/*=========================*/
2182
dict_index_t* index, /*!< in: index */
2183
dtuple_t* entry, /*!< in: index entry to make */
2184
const dtuple_t* row) /*!< in: row */
2189
ut_ad(entry && row);
2191
n_fields = dtuple_get_n_fields(entry);
2193
for (i = 0; i < n_fields; i++) {
2194
dict_field_t* ind_field;
2196
const dfield_t* row_field;
2199
field = dtuple_get_nth_field(entry, i);
2200
ind_field = dict_index_get_nth_field(index, i);
2201
row_field = dtuple_get_nth_field(row, ind_field->col->ind);
2202
len = dfield_get_len(row_field);
2204
/* Check column prefix indexes */
2205
if (ind_field->prefix_len > 0
2206
&& dfield_get_len(row_field) != UNIV_SQL_NULL) {
2208
const dict_col_t* col
2209
= dict_field_get_col(ind_field);
2211
len = dtype_get_at_most_n_mbchars(
2212
col->prtype, col->mbminlen, col->mbmaxlen,
2213
ind_field->prefix_len,
2214
len, dfield_get_data(row_field));
2216
ut_ad(!dfield_is_ext(row_field));
2219
dfield_set_data(field, dfield_get_data(row_field), len);
2220
if (dfield_is_ext(row_field)) {
2221
ut_ad(dict_index_is_clust(index));
2222
dfield_set_ext(field);
2227
/***********************************************************//**
2228
Inserts a single index entry to the table.
2229
@return DB_SUCCESS if operation successfully completed, else error
2230
code or DB_LOCK_WAIT */
2233
row_ins_index_entry_step(
2234
/*=====================*/
2235
ins_node_t* node, /*!< in: row insert node */
2236
que_thr_t* thr) /*!< in: query thread */
2240
ut_ad(dtuple_check_typed(node->row));
2242
row_ins_index_entry_set_vals(node->index, node->entry, node->row);
2244
ut_ad(dtuple_check_typed(node->entry));
2246
err = row_ins_index_entry(node->index, node->entry, 0, TRUE, thr);
2251
/***********************************************************//**
2252
Allocates a row id for row and inits the node->index field. */
2255
row_ins_alloc_row_id_step(
2256
/*======================*/
2257
ins_node_t* node) /*!< in: row insert node */
2261
ut_ad(node->state == INS_NODE_ALLOC_ROW_ID);
2263
if (dict_index_is_unique(dict_table_get_first_index(node->table))) {
2265
/* No row id is stored if the clustered index is unique */
2270
/* Fill in row id value to row */
2272
row_id = dict_sys_get_new_row_id();
2274
dict_sys_write_row_id(node->row_id_buf, row_id);
2277
/***********************************************************//**
2278
Gets a row to insert from the values list. */
2281
row_ins_get_row_from_values(
2282
/*========================*/
2283
ins_node_t* node) /*!< in: row insert node */
2285
que_node_t* list_node;
2290
/* The field values are copied in the buffers of the select node and
2291
it is safe to use them until we fetch from select again: therefore
2292
we can just copy the pointers */
2297
list_node = node->values_list;
2300
eval_exp(list_node);
2302
dfield = dtuple_get_nth_field(row, i);
2303
dfield_copy_data(dfield, que_node_get_val(list_node));
2306
list_node = que_node_get_next(list_node);
2310
/***********************************************************//**
2311
Gets a row to insert from the select list. */
2314
row_ins_get_row_from_select(
2315
/*========================*/
2316
ins_node_t* node) /*!< in: row insert node */
2318
que_node_t* list_node;
2323
/* The field values are copied in the buffers of the select node and
2324
it is safe to use them until we fetch from select again: therefore
2325
we can just copy the pointers */
2330
list_node = node->select->select_list;
2333
dfield = dtuple_get_nth_field(row, i);
2334
dfield_copy_data(dfield, que_node_get_val(list_node));
2337
list_node = que_node_get_next(list_node);
2341
/***********************************************************//**
2342
Inserts a row to a table.
2343
@return DB_SUCCESS if operation successfully completed, else error
2344
code or DB_LOCK_WAIT */
2349
ins_node_t* node, /*!< in: row insert node */
2350
que_thr_t* thr) /*!< in: query thread */
2356
if (node->state == INS_NODE_ALLOC_ROW_ID) {
2358
row_ins_alloc_row_id_step(node);
2360
node->index = dict_table_get_first_index(node->table);
2361
node->entry = UT_LIST_GET_FIRST(node->entry_list);
2363
if (node->ins_type == INS_SEARCHED) {
2365
row_ins_get_row_from_select(node);
2367
} else if (node->ins_type == INS_VALUES) {
2369
row_ins_get_row_from_values(node);
2372
node->state = INS_NODE_INSERT_ENTRIES;
2375
ut_ad(node->state == INS_NODE_INSERT_ENTRIES);
2377
while (node->index != NULL) {
2378
err = row_ins_index_entry_step(node, thr);
2380
if (err != DB_SUCCESS) {
2385
node->index = dict_table_get_next_index(node->index);
2386
node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
2389
ut_ad(node->entry == NULL);
2391
node->state = INS_NODE_ALLOC_ROW_ID;
2396
/***********************************************************//**
2397
Inserts a row to a table. This is a high-level function used in SQL execution
2399
@return query thread to run next or NULL */
2404
que_thr_t* thr) /*!< in: query thread */
2408
sel_node_t* sel_node;
2414
trx = thr_get_trx(thr);
2416
trx_start_if_not_started(trx);
2418
node = thr->run_node;
2420
ut_ad(que_node_get_type(node) == QUE_NODE_INSERT);
2422
parent = que_node_get_parent(node);
2423
sel_node = node->select;
2425
if (thr->prev_node == parent) {
2426
node->state = INS_NODE_SET_IX_LOCK;
2429
/* If this is the first time this node is executed (or when
2430
execution resumes after wait for the table IX lock), set an
2431
IX lock on the table and reset the possible select node. MySQL's
2432
partitioned table code may also call an insert within the same
2433
SQL statement AFTER it has used this table handle to do a search.
2434
This happens, for example, when a row update moves it to another
2435
partition. In that case, we have already set the IX lock on the
2436
table during the search operation, and there is no need to set
2437
it again here. But we must write trx->id to node->trx_id_buf. */
2439
trx_write_trx_id(node->trx_id_buf, trx->id);
2441
if (node->state == INS_NODE_SET_IX_LOCK) {
2443
/* It may be that the current session has not yet started
2444
its transaction, or it has been committed: */
2446
if (UT_DULINT_EQ(trx->id, node->trx_id)) {
2447
/* No need to do IX-locking */
2452
err = lock_table(0, node->table, LOCK_IX, thr);
2454
if (err != DB_SUCCESS) {
2456
goto error_handling;
2459
node->trx_id = trx->id;
2461
node->state = INS_NODE_ALLOC_ROW_ID;
2463
if (node->ins_type == INS_SEARCHED) {
2464
/* Reset the cursor */
2465
sel_node->state = SEL_NODE_OPEN;
2467
/* Fetch a row to insert */
2469
thr->run_node = sel_node;
2475
if ((node->ins_type == INS_SEARCHED)
2476
&& (sel_node->state != SEL_NODE_FETCH)) {
2478
ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
2480
/* No more rows to insert */
2481
thr->run_node = parent;
2486
/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
2488
err = row_ins(node, thr);
2491
trx->error_state = err;
2493
if (err != DB_SUCCESS) {
2494
/* err == DB_LOCK_WAIT or SQL error detected */
2498
/* DO THE TRIGGER ACTIONS HERE */
2500
if (node->ins_type == INS_SEARCHED) {
2501
/* Fetch a row to insert */
2503
thr->run_node = sel_node;
2505
thr->run_node = que_node_get_parent(node);