~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Reverted 1103

Show diffs side-by-side

added added

removed removed

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