~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/row/row0ins.c

  • Committer: Monty Taylor
  • Date: 2009-03-02 23:14:32 UTC
  • mto: This revision was merged to the branch mainline in revision 910.
  • Revision ID: mordred@inaugust.com-20090302231432-i35xehp7uzo6hjjw
Updated build system to use new version numbering. Just remember to run ./config/autorun.sh before running make distcheck for release and all should be peachy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file row/row0ins.c
 
1
/******************************************************
21
2
Insert into a table
22
3
 
 
4
(c) 1996 Innobase Oy
 
5
 
23
6
Created 4/20/1996 Heikki Tuuri
24
7
*******************************************************/
25
8
 
29
12
#include "row0ins.ic"
30
13
#endif
31
14
 
32
 
#include "ha_prototypes.h"
33
15
#include "dict0dict.h"
34
16
#include "dict0boot.h"
35
17
#include "trx0undo.h"
51
33
#define ROW_INS_PREV    1
52
34
#define ROW_INS_NEXT    2
53
35
 
 
36
 
 
37
/*********************************************************************
 
38
This prototype is copied from /mysql/sql/ha_innodb.cc.
 
39
Invalidates the MySQL query cache for the table.
 
40
NOTE that the exact prototype of this function has to be in
 
41
/innobase/row/row0ins.c! */
 
42
extern
 
43
void
 
44
innobase_invalidate_query_cache(
 
45
/*============================*/
 
46
        trx_t*  trx,            /* in: transaction which modifies the table */
 
47
        char*   full_name,      /* in: concatenation of database name, null
 
48
                                char '\0', table name, null char'\0';
 
49
                                NOTE that in Windows this is always
 
50
                                in LOWER CASE! */
 
51
        ulint   full_name_len); /* in: full name length where also the null
 
52
                                chars count */
 
53
 
54
54
/*************************************************************************
55
 
IMPORTANT NOTE: Any operation that generates redo MUST check that there
56
 
is enough space in the redo log before for that operation. This is
57
 
done by calling log_free_check(). The reason for checking the
58
 
availability of the redo log space before the start of the operation is
59
 
that we MUST not hold any synchonization objects when performing the
60
 
check.
61
 
If you make a change in this module make sure that no codepath is
62
 
introduced where a call to log_free_check() is bypassed. */
63
 
 
64
 
/*********************************************************************//**
65
 
Creates an insert node struct.
66
 
@return own: insert node struct */
 
55
Creates an insert node struct. */
67
56
UNIV_INTERN
68
57
ins_node_t*
69
58
ins_node_create(
70
59
/*============*/
71
 
        ulint           ins_type,       /*!< in: INS_VALUES, ... */
72
 
        dict_table_t*   table,          /*!< in: table where to insert */
73
 
        mem_heap_t*     heap)           /*!< in: mem heap where created */
 
60
                                        /* out, own: insert node struct */
 
61
        ulint           ins_type,       /* in: INS_VALUES, ... */
 
62
        dict_table_t*   table,          /* in: table where to insert */
 
63
        mem_heap_t*     heap)           /* in: mem heap where created */
74
64
{
75
65
        ins_node_t*     node;
76
66
 
77
 
        node = static_cast<ins_node_t *>(mem_heap_alloc(heap, sizeof(ins_node_t)));
 
67
        node = mem_heap_alloc(heap, sizeof(ins_node_t));
78
68
 
79
69
        node->common.type = QUE_NODE_INSERT;
80
70
 
87
77
 
88
78
        node->select = NULL;
89
79
 
90
 
        node->trx_id = 0;
 
80
        node->trx_id = ut_dulint_zero;
91
81
 
92
82
        node->entry_sys_heap = mem_heap_create(128);
93
83
 
96
86
        return(node);
97
87
}
98
88
 
99
 
/***********************************************************//**
 
89
/***************************************************************
100
90
Creates an entry template for each index of a table. */
101
91
UNIV_INTERN
102
92
void
103
93
ins_node_create_entry_list(
104
94
/*=======================*/
105
 
        ins_node_t*     node)   /*!< in: row insert node */
 
95
        ins_node_t*     node)   /* in: row insert node */
106
96
{
107
97
        dict_index_t*   index;
108
98
        dtuple_t*       entry;
122
112
        }
123
113
}
124
114
 
125
 
/*****************************************************************//**
 
115
/*********************************************************************
126
116
Adds system field buffers to a row. */
127
117
static
128
118
void
129
119
row_ins_alloc_sys_fields(
130
120
/*=====================*/
131
 
        ins_node_t*     node)   /*!< in: insert node */
 
121
        ins_node_t*     node)   /* in: insert node */
132
122
{
133
123
        dtuple_t*               row;
134
124
        dict_table_t*           table;
150
140
 
151
141
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
152
142
 
153
 
        ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_ROW_ID_LEN));
 
143
        ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN);
154
144
 
155
145
        dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN);
156
146
 
161
151
        col = dict_table_get_sys_col(table, DATA_TRX_ID);
162
152
 
163
153
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
164
 
        ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_TRX_ID_LEN));
 
154
        ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN);
165
155
 
166
156
        dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN);
167
157
 
172
162
        col = dict_table_get_sys_col(table, DATA_ROLL_PTR);
173
163
 
174
164
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
175
 
        ptr = static_cast<byte *>(mem_heap_zalloc(heap, DATA_ROLL_PTR_LEN));
 
165
        ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN);
176
166
 
177
167
        dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);
178
168
}
179
169
 
180
 
/*********************************************************************//**
 
170
/*************************************************************************
181
171
Sets a new row to insert for an INS_DIRECT node. This function is only used
182
172
if we have constructed the row separately, which is a rare case; this
183
173
function is quite slow. */
185
175
void
186
176
ins_node_set_new_row(
187
177
/*=================*/
188
 
        ins_node_t*     node,   /*!< in: insert node */
189
 
        dtuple_t*       row)    /*!< in: new row (or first row) for the node */
 
178
        ins_node_t*     node,   /* in: insert node */
 
179
        dtuple_t*       row)    /* in: new row (or first row) for the node */
190
180
{
191
181
        node->state = INS_NODE_SET_IX_LOCK;
192
182
        node->index = NULL;
207
197
        /* As we allocated a new trx id buf, the trx id should be written
208
198
        there again: */
209
199
 
210
 
        node->trx_id = 0;
 
200
        node->trx_id = ut_dulint_zero;
211
201
}
212
202
 
213
 
/*******************************************************************//**
 
203
/***********************************************************************
214
204
Does an insert operation by updating a delete-marked existing record
215
205
in the index. This situation can occur if the delete-marked record is
216
 
kept in the index for consistent reads.
217
 
@return DB_SUCCESS or error code */
 
206
kept in the index for consistent reads. */
218
207
static
219
208
ulint
220
209
row_ins_sec_index_entry_by_modify(
221
210
/*==============================*/
222
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
211
                                /* out: DB_SUCCESS or error code */
 
212
        ulint           mode,   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
223
213
                                depending on whether mtr holds just a leaf
224
214
                                latch or also a tree latch */
225
 
        btr_cur_t*      cursor, /*!< in: B-tree cursor */
226
 
        const dtuple_t* entry,  /*!< in: index entry to insert */
227
 
        que_thr_t*      thr,    /*!< in: query thread */
228
 
        mtr_t*          mtr)    /*!< in: mtr; must be committed before
 
215
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
216
        const dtuple_t* entry,  /* in: index entry to insert */
 
217
        que_thr_t*      thr,    /* in: query thread */
 
218
        mtr_t*          mtr)    /* in: mtr; must be committed before
229
219
                                latching any further pages */
230
220
{
231
221
        big_rec_t*      dummy_big_rec;
281
271
        return(err);
282
272
}
283
273
 
284
 
/*******************************************************************//**
 
274
/***********************************************************************
285
275
Does an insert operation by delete unmarking and updating a delete marked
286
276
existing record in the index. This situation can occur if the delete marked
287
 
record is kept in the index for consistent reads.
288
 
@return DB_SUCCESS, DB_FAIL, or error code */
 
277
record is kept in the index for consistent reads. */
289
278
static
290
279
ulint
291
280
row_ins_clust_index_entry_by_modify(
292
281
/*================================*/
293
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
282
                                /* out: DB_SUCCESS, DB_FAIL, or error code */
 
283
        ulint           mode,   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
294
284
                                depending on whether mtr holds just a leaf
295
285
                                latch or also a tree latch */
296
 
        btr_cur_t*      cursor, /*!< in: B-tree cursor */
297
 
        mem_heap_t**    heap,   /*!< in/out: pointer to memory heap, or NULL */
298
 
        big_rec_t**     big_rec,/*!< out: possible big rec vector of fields
 
286
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
287
        mem_heap_t**    heap,   /* in/out: pointer to memory heap, or NULL */
 
288
        big_rec_t**     big_rec,/* out: possible big rec vector of fields
299
289
                                which have to be stored externally by the
300
290
                                caller */
301
 
        const dtuple_t* entry,  /*!< in: index entry to insert */
302
 
        que_thr_t*      thr,    /*!< in: query thread */
303
 
        mtr_t*          mtr)    /*!< in: mtr; must be committed before
 
291
        const dtuple_t* entry,  /* in: index entry to insert */
 
292
        que_thr_t*      thr,    /* in: query thread */
 
293
        mtr_t*          mtr)    /* in: mtr; must be committed before
304
294
                                latching any further pages */
305
295
{
306
296
        rec_t*          rec;
353
343
        return(err);
354
344
}
355
345
 
356
 
/*********************************************************************//**
 
346
/*************************************************************************
357
347
Returns TRUE if in a cascaded update/delete an ancestor node of node
358
 
updates (not DELETE, but UPDATE) table.
359
 
@return TRUE if an ancestor updates table */
 
348
updates (not DELETE, but UPDATE) table. */
360
349
static
361
350
ibool
362
351
row_ins_cascade_ancestor_updates_table(
363
352
/*===================================*/
364
 
        que_node_t*     node,   /*!< in: node in a query graph */
365
 
        dict_table_t*   table)  /*!< in: table */
 
353
                                /* out: TRUE if an ancestor updates table */
 
354
        que_node_t*     node,   /* in: node in a query graph */
 
355
        dict_table_t*   table)  /* in: table */
366
356
{
367
357
        que_node_t*     parent;
368
358
        upd_node_t*     upd_node;
371
361
 
372
362
        while (que_node_get_type(parent) == QUE_NODE_UPDATE) {
373
363
 
374
 
                upd_node = static_cast<upd_node_t *>(parent);
 
364
                upd_node = parent;
375
365
 
376
366
                if (upd_node->table == table && upd_node->is_delete == FALSE) {
377
367
 
386
376
        return(FALSE);
387
377
}
388
378
 
389
 
/*********************************************************************//**
 
379
/*************************************************************************
390
380
Returns the number of ancestor UPDATE or DELETE nodes of a
391
 
cascaded update/delete node.
392
 
@return number of ancestors */
 
381
cascaded update/delete node. */
393
382
static
394
383
ulint
395
384
row_ins_cascade_n_ancestors(
396
385
/*========================*/
397
 
        que_node_t*     node)   /*!< in: node in a query graph */
 
386
                                /* out: number of ancestors */
 
387
        que_node_t*     node)   /* in: node in a query graph */
398
388
{
399
389
        que_node_t*     parent;
400
390
        ulint           n_ancestors = 0;
412
402
        return(n_ancestors);
413
403
}
414
404
 
415
 
/******************************************************************//**
 
405
/**********************************************************************
416
406
Calculates the update vector node->cascade->update for a child table in
417
 
a cascaded update.
418
 
@return number of fields in the calculated update vector; the value
419
 
can also be 0 if no foreign key fields changed; the returned value is
420
 
ULINT_UNDEFINED if the column type in the child table is too short to
421
 
fit the new value in the parent table: that means the update fails */
 
407
a cascaded update. */
422
408
static
423
409
ulint
424
410
row_ins_cascade_calc_update_vec(
425
411
/*============================*/
426
 
        upd_node_t*     node,           /*!< in: update node of the parent
 
412
                                        /* out: number of fields in the
 
413
                                        calculated update vector; the value
 
414
                                        can also be 0 if no foreign key
 
415
                                        fields changed; the returned value
 
416
                                        is ULINT_UNDEFINED if the column
 
417
                                        type in the child table is too short
 
418
                                        to fit the new value in the parent
 
419
                                        table: that means the update fails */
 
420
        upd_node_t*     node,           /* in: update node of the parent
427
421
                                        table */
428
 
        dict_foreign_t* foreign,        /*!< in: foreign key constraint whose
 
422
        dict_foreign_t* foreign,        /* in: foreign key constraint whose
429
423
                                        type is != 0 */
430
 
        mem_heap_t*     heap)           /*!< in: memory heap to use as
 
424
        mem_heap_t*     heap)           /* in: memory heap to use as
431
425
                                        temporary storage */
432
426
{
433
427
        upd_node_t*     cascade         = node->cascade_node;
515
509
 
516
510
                                if (!dfield_is_null(&ufield->new_val)
517
511
                                    && dtype_get_at_most_n_mbchars(
518
 
                                        col->prtype, col->mbminmaxlen,
 
512
                                        col->prtype,
 
513
                                        col->mbminlen, col->mbmaxlen,
519
514
                                        col->len,
520
515
                                        ufield_len,
521
 
                                        static_cast<const char *>(dfield_get_data(&ufield->new_val)))
 
516
                                        dfield_get_data(&ufield->new_val))
522
517
                                    < ufield_len) {
523
518
 
524
519
                                        return(ULINT_UNDEFINED);
538
533
 
539
534
                                if (min_size > ufield_len) {
540
535
 
541
 
                                        byte*   pad;
542
 
                                        ulint   pad_len;
543
 
                                        byte*   padded_data;
544
 
                                        ulint   mbminlen;
545
 
 
546
 
                                        padded_data = static_cast<unsigned char *>(mem_heap_alloc(
547
 
                                                heap, min_size));
548
 
 
549
 
                                        pad = padded_data + ufield_len;
550
 
                                        pad_len = min_size - ufield_len;
 
536
                                        char*           pad_start;
 
537
                                        const char*     pad_end;
 
538
                                        char*           padded_data
 
539
                                                = mem_heap_alloc(
 
540
                                                        heap, min_size);
 
541
                                        pad_start = padded_data + ufield_len;
 
542
                                        pad_end = padded_data + min_size;
551
543
 
552
544
                                        memcpy(padded_data,
553
545
                                               dfield_get_data(&ufield
554
546
                                                               ->new_val),
555
 
                                               ufield_len);
556
 
 
557
 
                                        mbminlen = dict_col_get_mbminlen(col);
558
 
 
559
 
                                        ut_ad(!(ufield_len % mbminlen));
560
 
                                        ut_ad(!(min_size % mbminlen));
561
 
 
562
 
                                        if (mbminlen == 1
563
 
                                            && dtype_get_charset_coll(
564
 
                                                    col->prtype)
565
 
                                            == DATA_MYSQL_BINARY_CHARSET_COLL) {
566
 
                                                /* Do not pad BINARY columns */
 
547
                                               dfield_get_len(&ufield
 
548
                                                              ->new_val));
 
549
 
 
550
                                        switch (UNIV_EXPECT(col->mbminlen,1)) {
 
551
                                        default:
 
552
                                                ut_error;
567
553
                                                return(ULINT_UNDEFINED);
 
554
                                        case 1:
 
555
                                                if (UNIV_UNLIKELY
 
556
                                                    (dtype_get_charset_coll(
 
557
                                                            col->prtype)
 
558
                                                     == DATA_MYSQL_BINARY_CHARSET_COLL)) {
 
559
                                                        /* Do not pad BINARY
 
560
                                                        columns. */
 
561
                                                        return(ULINT_UNDEFINED);
 
562
                                                }
 
563
 
 
564
                                                /* space=0x20 */
 
565
                                                memset(pad_start, 0x20,
 
566
                                                       pad_end - pad_start);
 
567
                                                break;
 
568
                                        case 2:
 
569
                                                /* space=0x0020 */
 
570
                                                ut_a(!(ufield_len % 2));
 
571
                                                ut_a(!(min_size % 2));
 
572
                                                do {
 
573
                                                        *pad_start++ = 0x00;
 
574
                                                        *pad_start++ = 0x20;
 
575
                                                } while (pad_start < pad_end);
 
576
                                                break;
568
577
                                        }
569
578
 
570
 
                                        row_mysql_pad_col(mbminlen,
571
 
                                                          pad, pad_len);
572
579
                                        dfield_set_data(&ufield->new_val,
573
580
                                                        padded_data, min_size);
574
581
                                }
583
590
        return(n_fields_updated);
584
591
}
585
592
 
586
 
/*********************************************************************//**
 
593
/*************************************************************************
587
594
Set detailed error message associated with foreign key errors for
588
595
the given transaction. */
589
596
static
590
597
void
591
598
row_ins_set_detailed(
592
599
/*=================*/
593
 
        trx_t*          trx,            /*!< in: transaction */
594
 
        dict_foreign_t* foreign)        /*!< in: foreign key constraint */
 
600
        trx_t*          trx,            /* in: transaction */
 
601
        dict_foreign_t* foreign)        /* in: foreign key constraint */
595
602
{
596
603
        mutex_enter(&srv_misc_tmpfile_mutex);
597
604
        rewind(srv_misc_tmpfile);
609
616
        mutex_exit(&srv_misc_tmpfile_mutex);
610
617
}
611
618
 
612
 
/*********************************************************************//**
 
619
/*************************************************************************
613
620
Reports a foreign key error associated with an update or a delete of a
614
621
parent table index entry. */
615
622
static
616
623
void
617
624
row_ins_foreign_report_err(
618
625
/*=======================*/
619
 
        const char*     errstr,         /*!< in: error string from the viewpoint
 
626
        const char*     errstr,         /* in: error string from the viewpoint
620
627
                                        of the parent table */
621
 
        que_thr_t*      thr,            /*!< in: query thread whose run_node
 
628
        que_thr_t*      thr,            /* in: query thread whose run_node
622
629
                                        is an update node */
623
 
        dict_foreign_t* foreign,        /*!< in: foreign key constraint */
624
 
        const rec_t*    rec,            /*!< in: a matching index record in the
 
630
        dict_foreign_t* foreign,        /* in: foreign key constraint */
 
631
        const rec_t*    rec,            /* in: a matching index record in the
625
632
                                        child table */
626
 
        const dtuple_t* entry)          /*!< in: index entry in the parent
 
633
        const dtuple_t* entry)          /* in: index entry in the parent
627
634
                                        table */
628
635
{
629
636
        FILE*   ef      = dict_foreign_err_file;
665
672
        mutex_exit(&dict_foreign_err_mutex);
666
673
}
667
674
 
668
 
/*********************************************************************//**
 
675
/*************************************************************************
669
676
Reports a foreign key error to dict_foreign_err_file when we are trying
670
677
to add an index entry to a child table. Note that the adding may be the result
671
678
of an update, too. */
673
680
void
674
681
row_ins_foreign_report_add_err(
675
682
/*===========================*/
676
 
        trx_t*          trx,            /*!< in: transaction */
677
 
        dict_foreign_t* foreign,        /*!< in: foreign key constraint */
678
 
        const rec_t*    rec,            /*!< in: a record in the parent table:
 
683
        trx_t*          trx,            /* in: transaction */
 
684
        dict_foreign_t* foreign,        /* in: foreign key constraint */
 
685
        const rec_t*    rec,            /* in: a record in the parent table:
679
686
                                        it does not match entry because we
680
687
                                        have an error! */
681
 
        const dtuple_t* entry)          /*!< in: index entry to insert in the
 
688
        const dtuple_t* entry)          /* in: index entry to insert in the
682
689
                                        child table */
683
690
{
684
691
        FILE*   ef      = dict_foreign_err_file;
723
730
        mutex_exit(&dict_foreign_err_mutex);
724
731
}
725
732
 
726
 
/*********************************************************************//**
 
733
/*************************************************************************
727
734
Invalidate the query cache for the given table. */
728
735
static
729
736
void
730
737
row_ins_invalidate_query_cache(
731
738
/*===========================*/
732
 
        que_thr_t*      unused,         /*!< in: query thread whose run_node
 
739
        que_thr_t*      thr,            /* in: query thread whose run_node
733
740
                                        is an update node */
734
 
        const char*     name)           /*!< in: table name prefixed with
 
741
        const char*     name)           /* in: table name prefixed with
735
742
                                        database name and a '/' character */
736
743
{
737
744
        char*   buf;
738
745
        char*   ptr;
739
746
        ulint   len = strlen(name) + 1;
740
747
 
741
 
        (void)unused;
742
 
 
743
748
        buf = mem_strdupl(name, len);
744
749
 
745
750
        ptr = strchr(buf, '/');
746
751
        ut_a(ptr);
747
752
        *ptr = '\0';
748
753
 
 
754
        /* We call a function in ha_innodb.cc */
 
755
#ifndef UNIV_HOTBACKUP
 
756
        innobase_invalidate_query_cache(thr_get_trx(thr), buf, len);
 
757
#endif
749
758
        mem_free(buf);
750
759
}
751
760
 
752
 
/*********************************************************************//**
 
761
/*************************************************************************
753
762
Perform referential actions or checks when a parent row is deleted or updated
754
763
and the constraint had an ON DELETE or ON UPDATE condition which was not
755
 
RESTRICT.
756
 
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
 
764
RESTRICT. */
757
765
static
758
766
ulint
759
767
row_ins_foreign_check_on_constraint(
760
768
/*================================*/
761
 
        que_thr_t*      thr,            /*!< in: query thread whose run_node
 
769
                                        /* out: DB_SUCCESS, DB_LOCK_WAIT,
 
770
                                        or error code */
 
771
        que_thr_t*      thr,            /* in: query thread whose run_node
762
772
                                        is an update node */
763
 
        dict_foreign_t* foreign,        /*!< in: foreign key constraint whose
 
773
        dict_foreign_t* foreign,        /* in: foreign key constraint whose
764
774
                                        type is != 0 */
765
 
        btr_pcur_t*     pcur,           /*!< in: cursor placed on a matching
 
775
        btr_pcur_t*     pcur,           /* in: cursor placed on a matching
766
776
                                        index record in the child table */
767
 
        dtuple_t*       entry,          /*!< in: index entry in the parent
 
777
        dtuple_t*       entry,          /* in: index entry in the parent
768
778
                                        table */
769
 
        mtr_t*          mtr)            /*!< in: mtr holding the latch of pcur
 
779
        mtr_t*          mtr)            /* in: mtr holding the latch of pcur
770
780
                                        page */
771
781
{
772
782
        upd_node_t*     node;
801
811
 
802
812
        row_ins_invalidate_query_cache(thr, table->name);
803
813
 
804
 
        node = static_cast<upd_node_t *>(thr->run_node);
 
814
        node = thr->run_node;
805
815
 
806
816
        if (node->is_delete && 0 == (foreign->type
807
817
                                     & (DICT_FOREIGN_ON_DELETE_CASCADE
1115
1125
        return(err);
1116
1126
}
1117
1127
 
1118
 
/*********************************************************************//**
 
1128
/*************************************************************************
1119
1129
Sets a shared lock on a record. Used in locking possible duplicate key
1120
 
records and also in checking foreign key constraints.
1121
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
 
1130
records and also in checking foreign key constraints. */
1122
1131
static
1123
 
enum db_err
 
1132
ulint
1124
1133
row_ins_set_shared_rec_lock(
1125
1134
/*========================*/
1126
 
        ulint                   type,   /*!< in: LOCK_ORDINARY, LOCK_GAP, or
 
1135
                                        /* out: DB_SUCCESS or error code */
 
1136
        ulint                   type,   /* in: LOCK_ORDINARY, LOCK_GAP, or
1127
1137
                                        LOCK_REC_NOT_GAP type lock */
1128
 
        const buf_block_t*      block,  /*!< in: buffer block of rec */
1129
 
        const rec_t*            rec,    /*!< in: record */
1130
 
        dict_index_t*           index,  /*!< in: index */
1131
 
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
1132
 
        que_thr_t*              thr)    /*!< in: query thread */
 
1138
        const buf_block_t*      block,  /* in: buffer block of rec */
 
1139
        const rec_t*            rec,    /* in: record */
 
1140
        dict_index_t*           index,  /* in: index */
 
1141
        const ulint*            offsets,/* in: rec_get_offsets(rec, index) */
 
1142
        que_thr_t*              thr)    /* in: query thread */
1133
1143
{
1134
 
        enum db_err     err;
 
1144
        ulint   err;
1135
1145
 
1136
1146
        ut_ad(rec_offs_validate(rec, index, offsets));
1137
1147
 
1146
1156
        return(err);
1147
1157
}
1148
1158
 
1149
 
/*********************************************************************//**
 
1159
#ifndef UNIV_HOTBACKUP
 
1160
/*************************************************************************
1150
1161
Sets a exclusive lock on a record. Used in locking possible duplicate key
1151
 
records
1152
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
 
1162
records */
1153
1163
static
1154
 
enum db_err
 
1164
ulint
1155
1165
row_ins_set_exclusive_rec_lock(
1156
1166
/*===========================*/
1157
 
        ulint                   type,   /*!< in: LOCK_ORDINARY, LOCK_GAP, or
 
1167
                                        /* out: DB_SUCCESS or error code */
 
1168
        ulint                   type,   /* in: LOCK_ORDINARY, LOCK_GAP, or
1158
1169
                                        LOCK_REC_NOT_GAP type lock */
1159
 
        const buf_block_t*      block,  /*!< in: buffer block of rec */
1160
 
        const rec_t*            rec,    /*!< in: record */
1161
 
        dict_index_t*           index,  /*!< in: index */
1162
 
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
1163
 
        que_thr_t*              thr)    /*!< in: query thread */
 
1170
        const buf_block_t*      block,  /* in: buffer block of rec */
 
1171
        const rec_t*            rec,    /* in: record */
 
1172
        dict_index_t*           index,  /* in: index */
 
1173
        const ulint*            offsets,/* in: rec_get_offsets(rec, index) */
 
1174
        que_thr_t*              thr)    /* in: query thread */
1164
1175
{
1165
 
        enum db_err     err;
 
1176
        ulint   err;
1166
1177
 
1167
1178
        ut_ad(rec_offs_validate(rec, index, offsets));
1168
1179
 
1176
1187
 
1177
1188
        return(err);
1178
1189
}
 
1190
#endif /* !UNIV_HOTBACKUP */
1179
1191
 
1180
 
/***************************************************************//**
 
1192
/*******************************************************************
1181
1193
Checks if foreign key constraint fails for an index entry. Sets shared locks
1182
1194
which lock either the success or the failure of the constraint. NOTE that
1183
 
the caller must have a shared latch on dict_operation_lock.
1184
 
@return DB_SUCCESS, DB_NO_REFERENCED_ROW, or DB_ROW_IS_REFERENCED */
 
1195
the caller must have a shared latch on dict_operation_lock. */
1185
1196
UNIV_INTERN
1186
1197
ulint
1187
1198
row_ins_check_foreign_constraint(
1188
1199
/*=============================*/
1189
 
        ibool           check_ref,/*!< in: TRUE if we want to check that
 
1200
                                /* out: DB_SUCCESS,
 
1201
                                DB_NO_REFERENCED_ROW,
 
1202
                                or DB_ROW_IS_REFERENCED */
 
1203
        ibool           check_ref,/* in: TRUE if we want to check that
1190
1204
                                the referenced table is ok, FALSE if we
1191
 
                                want to check the foreign key table */
1192
 
        dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the
 
1205
                                want to to check the foreign key table */
 
1206
        dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
1193
1207
                                tables mentioned in it must be in the
1194
1208
                                dictionary cache if they exist at all */
1195
 
        dict_table_t*   table,  /*!< in: if check_ref is TRUE, then the foreign
 
1209
        dict_table_t*   table,  /* in: if check_ref is TRUE, then the foreign
1196
1210
                                table, else the referenced table */
1197
 
        dtuple_t*       entry,  /*!< in: index entry for index */
1198
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1211
        dtuple_t*       entry,  /* in: index entry for index */
 
1212
        que_thr_t*      thr)    /* in: query thread */
1199
1213
{
1200
1214
        upd_node_t*     upd_node;
1201
1215
        dict_table_t*   check_table;
1202
1216
        dict_index_t*   check_index;
1203
1217
        ulint           n_fields_cmp;
1204
1218
        btr_pcur_t      pcur;
 
1219
        ibool           moved;
1205
1220
        int             cmp;
1206
1221
        ulint           err;
1207
1222
        ulint           i;
1238
1253
        }
1239
1254
 
1240
1255
        if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
1241
 
                upd_node = static_cast<upd_node_t *>(thr->run_node);
 
1256
                upd_node = thr->run_node;
1242
1257
 
1243
1258
                if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
1244
1259
                        /* If a cascaded update is done as defined by a
1332
1347
 
1333
1348
        /* Scan index records and check if there is a matching record */
1334
1349
 
1335
 
        do {
 
1350
        for (;;) {
1336
1351
                const rec_t*            rec = btr_pcur_get_rec(&pcur);
1337
1352
                const buf_block_t*      block = btr_pcur_get_block(&pcur);
1338
1353
 
1339
1354
                if (page_rec_is_infimum(rec)) {
1340
1355
 
1341
 
                        continue;
 
1356
                        goto next_rec;
1342
1357
                }
1343
1358
 
1344
1359
                offsets = rec_get_offsets(rec, check_index,
1349
1364
                        err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
1350
1365
                                                          rec, check_index,
1351
1366
                                                          offsets, thr);
1352
 
                        switch (err) {
1353
 
                        case DB_SUCCESS_LOCKED_REC:
1354
 
                        case DB_SUCCESS:
1355
 
                                continue;
1356
 
                        default:
1357
 
                                goto end_scan;
 
1367
                        if (err != DB_SUCCESS) {
 
1368
 
 
1369
                                break;
1358
1370
                        }
 
1371
 
 
1372
                        goto next_rec;
1359
1373
                }
1360
1374
 
1361
1375
                cmp = cmp_dtuple_rec(entry, rec, offsets);
1366
1380
                                err = row_ins_set_shared_rec_lock(
1367
1381
                                        LOCK_ORDINARY, block,
1368
1382
                                        rec, check_index, offsets, thr);
1369
 
                                switch (err) {
1370
 
                                case DB_SUCCESS_LOCKED_REC:
1371
 
                                case DB_SUCCESS:
 
1383
                                if (err != DB_SUCCESS) {
 
1384
 
1372
1385
                                        break;
1373
 
                                default:
1374
 
                                        goto end_scan;
1375
1386
                                }
1376
1387
                        } else {
1377
1388
                                /* Found a matching record. Lock only
1382
1393
                                        LOCK_REC_NOT_GAP, block,
1383
1394
                                        rec, check_index, offsets, thr);
1384
1395
 
1385
 
                                switch (err) {
1386
 
                                case DB_SUCCESS_LOCKED_REC:
1387
 
                                case DB_SUCCESS:
 
1396
                                if (err != DB_SUCCESS) {
 
1397
 
1388
1398
                                        break;
1389
 
                                default:
1390
 
                                        goto end_scan;
1391
1399
                                }
1392
1400
 
1393
1401
                                if (check_ref) {
1394
1402
                                        err = DB_SUCCESS;
1395
1403
 
1396
 
                                        goto end_scan;
 
1404
                                        break;
1397
1405
                                } else if (foreign->type != 0) {
1398
1406
                                        /* There is an ON UPDATE or ON DELETE
1399
1407
                                        condition: check them in a separate
1419
1427
                                                        err = DB_FOREIGN_DUPLICATE_KEY;
1420
1428
                                                }
1421
1429
 
1422
 
                                                goto end_scan;
 
1430
                                                break;
1423
1431
                                        }
1424
1432
 
1425
1433
                                        /* row_ins_foreign_check_on_constraint
1432
1440
                                                thr, foreign, rec, entry);
1433
1441
 
1434
1442
                                        err = DB_ROW_IS_REFERENCED;
1435
 
                                        goto end_scan;
 
1443
                                        break;
1436
1444
                                }
1437
1445
                        }
1438
 
                } else {
1439
 
                        ut_a(cmp < 0);
 
1446
                }
1440
1447
 
 
1448
                if (cmp < 0) {
1441
1449
                        err = row_ins_set_shared_rec_lock(
1442
1450
                                LOCK_GAP, block,
1443
1451
                                rec, check_index, offsets, thr);
1444
 
 
1445
 
                        switch (err) {
1446
 
                        case DB_SUCCESS_LOCKED_REC:
1447
 
                        case DB_SUCCESS:
1448
 
                                if (check_ref) {
1449
 
                                        err = DB_NO_REFERENCED_ROW;
1450
 
                                        row_ins_foreign_report_add_err(
1451
 
                                                trx, foreign, rec, entry);
1452
 
                                } else {
1453
 
                                        err = DB_SUCCESS;
1454
 
                                }
1455
 
                        }
1456
 
 
1457
 
                        goto end_scan;
1458
 
                }
1459
 
        } while (btr_pcur_move_to_next(&pcur, &mtr));
1460
 
 
1461
 
        if (check_ref) {
1462
 
                row_ins_foreign_report_add_err(
1463
 
                        trx, foreign, btr_pcur_get_rec(&pcur), entry);
1464
 
                err = DB_NO_REFERENCED_ROW;
1465
 
        } else {
1466
 
                err = DB_SUCCESS;
 
1452
                        if (err != DB_SUCCESS) {
 
1453
 
 
1454
                                break;
 
1455
                        }
 
1456
 
 
1457
                        if (check_ref) {
 
1458
                                err = DB_NO_REFERENCED_ROW;
 
1459
                                row_ins_foreign_report_add_err(
 
1460
                                        trx, foreign, rec, entry);
 
1461
                        } else {
 
1462
                                err = DB_SUCCESS;
 
1463
                        }
 
1464
 
 
1465
                        break;
 
1466
                }
 
1467
 
 
1468
                ut_a(cmp == 0);
 
1469
next_rec:
 
1470
                moved = btr_pcur_move_to_next(&pcur, &mtr);
 
1471
 
 
1472
                if (!moved) {
 
1473
                        if (check_ref) {
 
1474
                                rec = btr_pcur_get_rec(&pcur);
 
1475
                                row_ins_foreign_report_add_err(
 
1476
                                        trx, foreign, rec, entry);
 
1477
                                err = DB_NO_REFERENCED_ROW;
 
1478
                        } else {
 
1479
                                err = DB_SUCCESS;
 
1480
                        }
 
1481
 
 
1482
                        break;
 
1483
                }
1467
1484
        }
1468
1485
 
1469
 
end_scan:
1470
1486
        btr_pcur_close(&pcur);
1471
1487
 
1472
1488
        mtr_commit(&mtr);
1497
1513
        return(err);
1498
1514
}
1499
1515
 
1500
 
/***************************************************************//**
 
1516
/*******************************************************************
1501
1517
Checks if foreign key constraints fail for an index entry. If index
1502
1518
is not mentioned in any constraint, this function does nothing,
1503
1519
Otherwise does searches to the indexes of referenced tables and
1504
1520
sets shared locks which lock either the success or the failure of
1505
 
a constraint.
1506
 
@return DB_SUCCESS or error code */
 
1521
a constraint. */
1507
1522
static
1508
1523
ulint
1509
1524
row_ins_check_foreign_constraints(
1510
1525
/*==============================*/
1511
 
        dict_table_t*   table,  /*!< in: table */
1512
 
        dict_index_t*   index,  /*!< in: index */
1513
 
        dtuple_t*       entry,  /*!< in: index entry for index */
1514
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1526
                                /* out: DB_SUCCESS or error code */
 
1527
        dict_table_t*   table,  /* in: table */
 
1528
        dict_index_t*   index,  /* in: index */
 
1529
        dtuple_t*       entry,  /* in: index entry for index */
 
1530
        que_thr_t*      thr)    /* in: query thread */
1515
1531
{
1516
1532
        dict_foreign_t* foreign;
1517
1533
        ulint           err;
1579
1595
        return(DB_SUCCESS);
1580
1596
}
1581
1597
 
1582
 
/***************************************************************//**
 
1598
#ifndef UNIV_HOTBACKUP
 
1599
/*******************************************************************
1583
1600
Checks if a unique key violation to rec would occur at the index entry
1584
 
insert.
1585
 
@return TRUE if error */
 
1601
insert. */
1586
1602
static
1587
1603
ibool
1588
1604
row_ins_dupl_error_with_rec(
1589
1605
/*========================*/
1590
 
        const rec_t*    rec,    /*!< in: user record; NOTE that we assume
 
1606
                                /* out: TRUE if error */
 
1607
        const rec_t*    rec,    /* in: user record; NOTE that we assume
1591
1608
                                that the caller already has a record lock on
1592
1609
                                the record! */
1593
 
        const dtuple_t* entry,  /*!< in: entry to insert */
1594
 
        dict_index_t*   index,  /*!< in: index */
1595
 
        const ulint*    offsets)/*!< in: rec_get_offsets(rec, index) */
 
1610
        const dtuple_t* entry,  /* in: entry to insert */
 
1611
        dict_index_t*   index,  /* in: index */
 
1612
        const ulint*    offsets)/* in: rec_get_offsets(rec, index) */
1596
1613
{
1597
1614
        ulint   matched_fields;
1598
1615
        ulint   matched_bytes;
1630
1647
 
1631
1648
        return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
1632
1649
}
 
1650
#endif /* !UNIV_HOTBACKUP */
1633
1651
 
1634
 
/***************************************************************//**
 
1652
/*******************************************************************
1635
1653
Scans a unique non-clustered index at a given index entry to determine
1636
1654
whether a uniqueness violation has occurred for the key value of the entry.
1637
 
Set shared locks on possible duplicate records.
1638
 
@return DB_SUCCESS, DB_DUPLICATE_KEY, or DB_LOCK_WAIT */
 
1655
Set shared locks on possible duplicate records. */
1639
1656
static
1640
1657
ulint
1641
1658
row_ins_scan_sec_index_for_duplicate(
1642
1659
/*=================================*/
1643
 
        dict_index_t*   index,  /*!< in: non-clustered unique index */
1644
 
        dtuple_t*       entry,  /*!< in: index entry */
1645
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1660
                                /* out: DB_SUCCESS, DB_DUPLICATE_KEY, or
 
1661
                                DB_LOCK_WAIT */
 
1662
        dict_index_t*   index,  /* in: non-clustered unique index */
 
1663
        dtuple_t*       entry,  /* in: index entry */
 
1664
        que_thr_t*      thr)    /* in: query thread */
1646
1665
{
 
1666
#ifndef UNIV_HOTBACKUP
1647
1667
        ulint           n_unique;
1648
1668
        ulint           i;
1649
1669
        int             cmp;
1714
1734
                                rec, index, offsets, thr);
1715
1735
                }
1716
1736
 
1717
 
                switch (err) {
1718
 
                case DB_SUCCESS_LOCKED_REC:
1719
 
                        err = DB_SUCCESS;
1720
 
                case DB_SUCCESS:
 
1737
                if (err != DB_SUCCESS) {
 
1738
 
1721
1739
                        break;
1722
 
                default:
1723
 
                        goto end_scan;
1724
1740
                }
1725
1741
 
1726
1742
                if (page_rec_is_supremum(rec)) {
1737
1753
 
1738
1754
                                thr_get_trx(thr)->error_info = index;
1739
1755
 
1740
 
                                goto end_scan;
 
1756
                                break;
1741
1757
                        }
1742
 
                } else {
1743
 
                        ut_a(cmp < 0);
1744
 
                        goto end_scan;
1745
 
                }
 
1758
                }
 
1759
 
 
1760
                if (cmp < 0) {
 
1761
                        break;
 
1762
                }
 
1763
 
 
1764
                ut_a(cmp == 0);
1746
1765
        } while (btr_pcur_move_to_next(&pcur, &mtr));
1747
1766
 
1748
 
end_scan:
1749
1767
        if (UNIV_LIKELY_NULL(heap)) {
1750
1768
                mem_heap_free(heap);
1751
1769
        }
1755
1773
        dtuple_set_n_fields_cmp(entry, n_fields_cmp);
1756
1774
 
1757
1775
        return(err);
 
1776
#else /* UNIV_HOTBACKUP */
 
1777
        /* This function depends on MySQL code that is not included in
 
1778
        InnoDB Hot Backup builds.  Besides, this function should never
 
1779
        be called in InnoDB Hot Backup. */
 
1780
        ut_error;
 
1781
        return(DB_FAIL);
 
1782
#endif /* UNIV_HOTBACKUP */
1758
1783
}
1759
1784
 
1760
 
/***************************************************************//**
 
1785
/*******************************************************************
1761
1786
Checks if a unique key violation error would occur at an index entry
1762
1787
insert. Sets shared locks on possible duplicate records. Works only
1763
 
for a clustered index!
1764
 
@return DB_SUCCESS if no error, DB_DUPLICATE_KEY if error,
1765
 
DB_LOCK_WAIT if we have to wait for a lock on a possible duplicate
1766
 
record */
 
1788
for a clustered index! */
1767
1789
static
1768
1790
ulint
1769
1791
row_ins_duplicate_error_in_clust(
1770
1792
/*=============================*/
1771
 
        btr_cur_t*      cursor, /*!< in: B-tree cursor */
1772
 
        const dtuple_t* entry,  /*!< in: entry to insert */
1773
 
        que_thr_t*      thr,    /*!< in: query thread */
1774
 
        mtr_t*          mtr)    /*!< in: mtr */
 
1793
                                /* out: DB_SUCCESS if no error,
 
1794
                                DB_DUPLICATE_KEY if error, DB_LOCK_WAIT if we
 
1795
                                have to wait for a lock on a possible
 
1796
                                duplicate record */
 
1797
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
1798
        dtuple_t*       entry,  /* in: entry to insert */
 
1799
        que_thr_t*      thr,    /* in: query thread */
 
1800
        mtr_t*          mtr)    /* in: mtr */
1775
1801
{
 
1802
#ifndef UNIV_HOTBACKUP
1776
1803
        ulint   err;
1777
1804
        rec_t*  rec;
1778
1805
        ulint   n_unique;
1834
1861
                                        cursor->index, offsets, thr);
1835
1862
                        }
1836
1863
 
1837
 
                        switch (err) {
1838
 
                        case DB_SUCCESS_LOCKED_REC:
1839
 
                        case DB_SUCCESS:
1840
 
                                break;
1841
 
                        default:
 
1864
                        if (err != DB_SUCCESS) {
1842
1865
                                goto func_exit;
1843
1866
                        }
1844
1867
 
1878
1901
                                        rec, cursor->index, offsets, thr);
1879
1902
                        }
1880
1903
 
1881
 
                        switch (err) {
1882
 
                        case DB_SUCCESS_LOCKED_REC:
1883
 
                        case DB_SUCCESS:
1884
 
                                break;
1885
 
                        default:
 
1904
                        if (err != DB_SUCCESS) {
1886
1905
                                goto func_exit;
1887
1906
                        }
1888
1907
 
1904
1923
                mem_heap_free(heap);
1905
1924
        }
1906
1925
        return(err);
 
1926
#else /* UNIV_HOTBACKUP */
 
1927
        /* This function depends on MySQL code that is not included in
 
1928
        InnoDB Hot Backup builds.  Besides, this function should never
 
1929
        be called in InnoDB Hot Backup. */
 
1930
        ut_error;
 
1931
        return(DB_FAIL);
 
1932
#endif /* UNIV_HOTBACKUP */
1907
1933
}
1908
1934
 
1909
 
/***************************************************************//**
 
1935
/*******************************************************************
1910
1936
Checks if an index entry has long enough common prefix with an existing
1911
1937
record so that the intended insert of the entry must be changed to a modify of
1912
1938
the existing record. In the case of a clustered index, the prefix must be
1913
1939
n_unique fields long, and in the case of a secondary index, all fields must be
1914
 
equal.
1915
 
@return 0 if no update, ROW_INS_PREV if previous should be updated;
1916
 
currently we do the search so that only the low_match record can match
1917
 
enough to the search tuple, not the next record */
 
1940
equal. */
1918
1941
UNIV_INLINE
1919
1942
ulint
1920
1943
row_ins_must_modify(
1921
1944
/*================*/
1922
 
        btr_cur_t*      cursor) /*!< in: B-tree cursor */
 
1945
                                /* out: 0 if no update, ROW_INS_PREV if
 
1946
                                previous should be updated; currently we
 
1947
                                do the search so that only the low_match
 
1948
                                record can match enough to the search tuple,
 
1949
                                not the next record */
 
1950
        btr_cur_t*      cursor) /* in: B-tree cursor */
1923
1951
{
1924
1952
        ulint   enough_match;
1925
1953
        rec_t*  rec;
1946
1974
        return(0);
1947
1975
}
1948
1976
 
1949
 
/***************************************************************//**
 
1977
/*******************************************************************
1950
1978
Tries to insert an index entry to an index. If the index is clustered
1951
1979
and a record with the same unique key is found, the other record is
1952
1980
necessarily marked deleted by a committed transaction, or a unique key
1954
1982
existing record, and we must write an undo log record on the delete
1955
1983
marked record. If the index is secondary, and a record with exactly the
1956
1984
same fields is found, the other record is necessarily marked deleted.
1957
 
It is then unmarked. Otherwise, the entry is just inserted to the index.
1958
 
@return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL if pessimistic retry needed,
1959
 
or error code */
 
1985
It is then unmarked. Otherwise, the entry is just inserted to the index. */
1960
1986
static
1961
1987
ulint
1962
1988
row_ins_index_entry_low(
1963
1989
/*====================*/
1964
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
1990
                                /* out: DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL
 
1991
                                if pessimistic retry needed, or error code */
 
1992
        ulint           mode,   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
1965
1993
                                depending on whether we wish optimistic or
1966
1994
                                pessimistic descent down the index tree */
1967
 
        dict_index_t*   index,  /*!< in: index */
1968
 
        dtuple_t*       entry,  /*!< in/out: index entry to insert */
1969
 
        ulint           n_ext,  /*!< in: number of externally stored columns */
1970
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1995
        dict_index_t*   index,  /* in: index */
 
1996
        dtuple_t*       entry,  /* in: index entry to insert */
 
1997
        ulint           n_ext,  /* in: number of externally stored columns */
 
1998
        que_thr_t*      thr)    /* in: query thread */
1971
1999
{
1972
2000
        btr_cur_t       cursor;
1973
 
        ulint           search_mode;
 
2001
        ulint           ignore_sec_unique       = 0;
1974
2002
        ulint           modify = 0; /* remove warning */
1975
2003
        rec_t*          insert_rec;
1976
2004
        rec_t*          rec;
1990
2018
        the function will return in both low_match and up_match of the
1991
2019
        cursor sensible values */
1992
2020
 
1993
 
        if (dict_index_is_clust(index)) {
1994
 
                search_mode = mode;
1995
 
        } else if (!(thr_get_trx(thr)->check_unique_secondary)) {
1996
 
                search_mode = mode | BTR_INSERT | BTR_IGNORE_SEC_UNIQUE;
1997
 
        } else {
1998
 
                search_mode = mode | BTR_INSERT;
 
2021
        if (!(thr_get_trx(thr)->check_unique_secondary)) {
 
2022
                ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE;
1999
2023
        }
2000
2024
 
2001
2025
        btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2002
 
                                    search_mode,
2003
 
                                    &cursor, 0, __FILE__, __LINE__, &mtr);
 
2026
                                    mode | BTR_INSERT | ignore_sec_unique,
 
2027
                                    &cursor, 0, &mtr);
2004
2028
 
2005
2029
        if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
2006
2030
                /* The insertion was made to the insert buffer already during
2007
2031
                the search: we are done */
2008
2032
 
2009
 
                ut_ad(search_mode & BTR_INSERT);
2010
2033
                err = DB_SUCCESS;
2011
2034
 
2012
2035
                goto function_exit;
2059
2082
                        btr_cur_search_to_nth_level(index, 0, entry,
2060
2083
                                                    PAGE_CUR_LE,
2061
2084
                                                    mode | BTR_INSERT,
2062
 
                                                    &cursor, 0,
2063
 
                                                    __FILE__, __LINE__, &mtr);
 
2085
                                                    &cursor, 0, &mtr);
2064
2086
                }
2065
2087
        }
2066
2088
 
2110
2132
        mtr_commit(&mtr);
2111
2133
 
2112
2134
        if (UNIV_LIKELY_NULL(big_rec)) {
2113
 
                rec_t*  exit_rec;
 
2135
                rec_t*  rec;
2114
2136
                ulint*  offsets;
2115
2137
                mtr_start(&mtr);
2116
2138
 
2117
2139
                btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
2118
 
                                            BTR_MODIFY_TREE, &cursor, 0,
2119
 
                                            __FILE__, __LINE__, &mtr);
2120
 
                exit_rec = btr_cur_get_rec(&cursor);
2121
 
                offsets = rec_get_offsets(exit_rec, index, NULL,
 
2140
                                            BTR_MODIFY_TREE, &cursor, 0, &mtr);
 
2141
                rec = btr_cur_get_rec(&cursor);
 
2142
                offsets = rec_get_offsets(rec, index, NULL,
2122
2143
                                          ULINT_UNDEFINED, &heap);
2123
2144
 
2124
2145
                err = btr_store_big_rec_extern_fields(
2125
2146
                        index, btr_cur_get_block(&cursor),
2126
 
                        exit_rec, offsets, big_rec, &mtr);
 
2147
                        rec, offsets, big_rec, &mtr);
2127
2148
 
2128
2149
                if (modify) {
2129
2150
                        dtuple_big_rec_free(big_rec);
2140
2161
        return(err);
2141
2162
}
2142
2163
 
2143
 
/***************************************************************//**
 
2164
/*******************************************************************
2144
2165
Inserts an index entry to index. Tries first optimistic, then pessimistic
2145
2166
descent down the tree. If the entry matches enough to a delete marked record,
2146
2167
performs the insert by updating or delete unmarking the delete marked
2147
 
record.
2148
 
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DUPLICATE_KEY, or some other error code */
 
2168
record. */
2149
2169
UNIV_INTERN
2150
2170
ulint
2151
2171
row_ins_index_entry(
2152
2172
/*================*/
2153
 
        dict_index_t*   index,  /*!< in: index */
2154
 
        dtuple_t*       entry,  /*!< in/out: index entry to insert */
2155
 
        ulint           n_ext,  /*!< in: number of externally stored columns */
2156
 
        ibool           foreign,/*!< in: TRUE=check foreign key constraints
2157
 
                                (foreign=FALSE only during CREATE INDEX) */
2158
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2173
                                /* out: DB_SUCCESS, DB_LOCK_WAIT,
 
2174
                                DB_DUPLICATE_KEY, or some other error code */
 
2175
        dict_index_t*   index,  /* in: index */
 
2176
        dtuple_t*       entry,  /* in: index entry to insert */
 
2177
        ulint           n_ext,  /* in: number of externally stored columns */
 
2178
        ibool           foreign,/* in: TRUE=check foreign key constraints */
 
2179
        que_thr_t*      thr)    /* in: query thread */
2159
2180
{
2160
 
        enum db_err     err;
 
2181
        ulint   err;
2161
2182
 
2162
2183
        if (foreign && UT_LIST_GET_FIRST(index->table->foreign_list)) {
2163
 
                err = static_cast<db_err>(row_ins_check_foreign_constraints(index->table, index,
2164
 
                                                        entry, thr));
 
2184
                err = row_ins_check_foreign_constraints(index->table, index,
 
2185
                                                        entry, thr);
2165
2186
                if (err != DB_SUCCESS) {
2166
2187
 
2167
2188
                        return(err);
2170
2191
 
2171
2192
        /* Try first optimistic descent to the B-tree */
2172
2193
 
2173
 
        err = static_cast<db_err>(row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
2174
 
                                      n_ext, thr));
 
2194
        err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
 
2195
                                      n_ext, thr);
2175
2196
        if (err != DB_FAIL) {
2176
2197
 
2177
2198
                return(err);
2179
2200
 
2180
2201
        /* Try then pessimistic descent to the B-tree */
2181
2202
 
2182
 
        err = static_cast<db_err>(row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry,
2183
 
                                      n_ext, thr));
 
2203
        err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry,
 
2204
                                      n_ext, thr);
2184
2205
        return(err);
2185
2206
}
2186
2207
 
2187
 
/***********************************************************//**
 
2208
/***************************************************************
2188
2209
Sets the values of the dtuple fields in entry from the values of appropriate
2189
2210
columns in row. */
2190
2211
static
2191
2212
void
2192
2213
row_ins_index_entry_set_vals(
2193
2214
/*=========================*/
2194
 
        dict_index_t*   index,  /*!< in: index */
2195
 
        dtuple_t*       entry,  /*!< in: index entry to make */
2196
 
        const dtuple_t* row)    /*!< in: row */
 
2215
        dict_index_t*   index,  /* in: index */
 
2216
        dtuple_t*       entry,  /* in: index entry to make */
 
2217
        const dtuple_t* row)    /* in: row */
2197
2218
{
2198
2219
        ulint   n_fields;
2199
2220
        ulint   i;
2221
2242
                                = dict_field_get_col(ind_field);
2222
2243
 
2223
2244
                        len = dtype_get_at_most_n_mbchars(
2224
 
                                col->prtype, col->mbminmaxlen,
 
2245
                                col->prtype, col->mbminlen, col->mbmaxlen,
2225
2246
                                ind_field->prefix_len,
2226
 
                                len, static_cast<const char *>(dfield_get_data(row_field)));
 
2247
                                len, dfield_get_data(row_field));
2227
2248
 
2228
2249
                        ut_ad(!dfield_is_ext(row_field));
2229
2250
                }
2236
2257
        }
2237
2258
}
2238
2259
 
2239
 
/***********************************************************//**
2240
 
Inserts a single index entry to the table.
2241
 
@return DB_SUCCESS if operation successfully completed, else error
2242
 
code or DB_LOCK_WAIT */
 
2260
/***************************************************************
 
2261
Inserts a single index entry to the table. */
2243
2262
static
2244
2263
ulint
2245
2264
row_ins_index_entry_step(
2246
2265
/*=====================*/
2247
 
        ins_node_t*     node,   /*!< in: row insert node */
2248
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2266
                                /* out: DB_SUCCESS if operation successfully
 
2267
                                completed, else error code or DB_LOCK_WAIT */
 
2268
        ins_node_t*     node,   /* in: row insert node */
 
2269
        que_thr_t*      thr)    /* in: query thread */
2249
2270
{
2250
 
        enum db_err     err;
 
2271
        ulint   err;
2251
2272
 
2252
2273
        ut_ad(dtuple_check_typed(node->row));
2253
2274
 
2255
2276
 
2256
2277
        ut_ad(dtuple_check_typed(node->entry));
2257
2278
 
2258
 
        err = static_cast<db_err>(row_ins_index_entry(node->index, node->entry, 0, TRUE, thr));
 
2279
        err = row_ins_index_entry(node->index, node->entry, 0, TRUE, thr);
2259
2280
 
2260
2281
        return(err);
2261
2282
}
2262
2283
 
2263
 
/***********************************************************//**
 
2284
/***************************************************************
2264
2285
Allocates a row id for row and inits the node->index field. */
2265
2286
UNIV_INLINE
2266
2287
void
2267
2288
row_ins_alloc_row_id_step(
2268
2289
/*======================*/
2269
 
        ins_node_t*     node)   /*!< in: row insert node */
 
2290
        ins_node_t*     node)   /* in: row insert node */
2270
2291
{
2271
 
        row_id_t        row_id;
 
2292
        dulint  row_id;
2272
2293
 
2273
2294
        ut_ad(node->state == INS_NODE_ALLOC_ROW_ID);
2274
2295
 
2286
2307
        dict_sys_write_row_id(node->row_id_buf, row_id);
2287
2308
}
2288
2309
 
2289
 
/***********************************************************//**
 
2310
/***************************************************************
2290
2311
Gets a row to insert from the values list. */
2291
2312
UNIV_INLINE
2292
2313
void
2293
2314
row_ins_get_row_from_values(
2294
2315
/*========================*/
2295
 
        ins_node_t*     node)   /*!< in: row insert node */
 
2316
        ins_node_t*     node)   /* in: row insert node */
2296
2317
{
2297
2318
        que_node_t*     list_node;
2298
2319
        dfield_t*       dfield;
2319
2340
        }
2320
2341
}
2321
2342
 
2322
 
/***********************************************************//**
 
2343
/***************************************************************
2323
2344
Gets a row to insert from the select list. */
2324
2345
UNIV_INLINE
2325
2346
void
2326
2347
row_ins_get_row_from_select(
2327
2348
/*========================*/
2328
 
        ins_node_t*     node)   /*!< in: row insert node */
 
2349
        ins_node_t*     node)   /* in: row insert node */
2329
2350
{
2330
2351
        que_node_t*     list_node;
2331
2352
        dfield_t*       dfield;
2350
2371
        }
2351
2372
}
2352
2373
 
2353
 
/***********************************************************//**
2354
 
Inserts a row to a table.
2355
 
@return DB_SUCCESS if operation successfully completed, else error
2356
 
code or DB_LOCK_WAIT */
 
2374
/***************************************************************
 
2375
Inserts a row to a table. */
2357
2376
static
2358
2377
ulint
2359
2378
row_ins(
2360
2379
/*====*/
2361
 
        ins_node_t*     node,   /*!< in: row insert node */
2362
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2380
                                /* out: DB_SUCCESS if operation successfully
 
2381
                                completed, else error code or DB_LOCK_WAIT */
 
2382
        ins_node_t*     node,   /* in: row insert node */
 
2383
        que_thr_t*      thr)    /* in: query thread */
2363
2384
{
2364
2385
        ulint   err;
2365
2386
 
2405
2426
        return(DB_SUCCESS);
2406
2427
}
2407
2428
 
2408
 
/***********************************************************//**
 
2429
/***************************************************************
2409
2430
Inserts a row to a table. This is a high-level function used in SQL execution
2410
 
graphs.
2411
 
@return query thread to run next or NULL */
 
2431
graphs. */
2412
2432
UNIV_INTERN
2413
2433
que_thr_t*
2414
2434
row_ins_step(
2415
2435
/*=========*/
2416
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2436
                                /* out: query thread to run next or NULL */
 
2437
        que_thr_t*      thr)    /* in: query thread */
2417
2438
{
2418
2439
        ins_node_t*     node;
2419
2440
        que_node_t*     parent;
2427
2448
 
2428
2449
        trx_start_if_not_started(trx);
2429
2450
 
2430
 
        node = static_cast<ins_node_t *>(thr->run_node);
 
2451
        node = thr->run_node;
2431
2452
 
2432
2453
        ut_ad(que_node_get_type(node) == QUE_NODE_INSERT);
2433
2454
 
2455
2476
                /* It may be that the current session has not yet started
2456
2477
                its transaction, or it has been committed: */
2457
2478
 
2458
 
                if (trx->id == node->trx_id) {
 
2479
                if (UT_DULINT_EQ(trx->id, node->trx_id)) {
2459
2480
                        /* No need to do IX-locking */
2460
2481
 
2461
2482
                        goto same_trx;