~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to innobase/row/row0ins.c

  • Committer: monty at mysql
  • Date: 2001-02-17 12:19:19 UTC
  • mto: (554.1.1)
  • mto: This revision was merged to the branch mainline in revision 556.
  • Revision ID: sp1r-monty@donna.mysql.com-20010217121919-07904
Added Innobase to source distribution

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Insert into a table
 
3
 
 
4
(c) 1996 Innobase Oy
 
5
 
 
6
Created 4/20/1996 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "row0ins.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "row0ins.ic"
 
13
#endif
 
14
 
 
15
#include "dict0dict.h"
 
16
#include "dict0boot.h"
 
17
#include "trx0undo.h"
 
18
#include "btr0btr.h"
 
19
#include "btr0cur.h"
 
20
#include "mach0data.h"
 
21
#include "que0que.h"
 
22
#include "row0upd.h"
 
23
#include "row0sel.h"
 
24
#include "row0row.h"
 
25
#include "rem0cmp.h"
 
26
#include "lock0lock.h"
 
27
#include "log0log.h"
 
28
#include "eval0eval.h"
 
29
#include "data0data.h"
 
30
#include "usr0sess.h"
 
31
 
 
32
#define ROW_INS_PREV    1
 
33
#define ROW_INS_NEXT    2
 
34
 
 
35
/*************************************************************************
 
36
Creates an insert node struct. */
 
37
 
 
38
ins_node_t*
 
39
ins_node_create(
 
40
/*============*/
 
41
                                        /* out, own: insert node struct */
 
42
        ulint           ins_type,       /* in: INS_VALUES, ... */
 
43
        dict_table_t*   table,          /* in: table where to insert */
 
44
        mem_heap_t*     heap)           /* in: mem heap where created */
 
45
{
 
46
        ins_node_t*     node;
 
47
 
 
48
        node = mem_heap_alloc(heap, sizeof(ins_node_t));
 
49
 
 
50
        node->common.type = QUE_NODE_INSERT;
 
51
 
 
52
        node->ins_type = ins_type;
 
53
 
 
54
        node->state = INS_NODE_SET_IX_LOCK;
 
55
        node->table = table;
 
56
        node->index = NULL;
 
57
        node->entry = NULL;
 
58
 
 
59
        node->select = NULL;
 
60
        
 
61
        node->trx_id = ut_dulint_zero;
 
62
        
 
63
        node->entry_sys_heap = mem_heap_create(128);
 
64
 
 
65
        node->magic_n = INS_NODE_MAGIC_N;       
 
66
        
 
67
        return(node);
 
68
}
 
69
 
 
70
/***************************************************************
 
71
Creates an entry template for each index of a table. */
 
72
static
 
73
void
 
74
ins_node_create_entry_list(
 
75
/*=======================*/
 
76
        ins_node_t*     node)   /* in: row insert node */
 
77
{
 
78
        dict_index_t*   index;
 
79
        dtuple_t*       entry;
 
80
 
 
81
        ut_ad(node->entry_sys_heap);
 
82
 
 
83
        UT_LIST_INIT(node->entry_list);
 
84
 
 
85
        index = dict_table_get_first_index(node->table);
 
86
        
 
87
        while (index != NULL) {
 
88
                entry = row_build_index_entry(node->row, index,
 
89
                                                        node->entry_sys_heap);
 
90
                UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry);
 
91
 
 
92
                index = dict_table_get_next_index(index);
 
93
        }
 
94
}
 
95
 
 
96
/*********************************************************************
 
97
Adds system field buffers to a row. */
 
98
static
 
99
void
 
100
row_ins_alloc_sys_fields(
 
101
/*=====================*/
 
102
        ins_node_t*     node)   /* in: insert node */
 
103
{
 
104
        dtuple_t*       row;
 
105
        dict_table_t*   table;
 
106
        mem_heap_t*     heap;
 
107
        dict_col_t*     col;
 
108
        dfield_t*       dfield;
 
109
        ulint           len;
 
110
        byte*           ptr;
 
111
 
 
112
        row = node->row;
 
113
        table = node->table;
 
114
        heap = node->entry_sys_heap;
 
115
 
 
116
        ut_ad(row && table && heap);
 
117
        ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table));
 
118
 
 
119
        /* 1. Allocate buffer for row id */
 
120
 
 
121
        col = dict_table_get_sys_col(table, DATA_ROW_ID);
 
122
        
 
123
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
 
124
 
 
125
        ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN);
 
126
                                
 
127
        dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN);
 
128
 
 
129
        node->row_id_buf = ptr;
 
130
 
 
131
        if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
 
132
 
 
133
                /* 2. Fill in the dfield for mix id */
 
134
 
 
135
                col = dict_table_get_sys_col(table, DATA_MIX_ID);
 
136
        
 
137
                dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
 
138
 
 
139
                len = mach_dulint_get_compressed_size(table->mix_id);
 
140
                ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN);
 
141
                                
 
142
                mach_dulint_write_compressed(ptr, table->mix_id);
 
143
                dfield_set_data(dfield, ptr, len);
 
144
        }
 
145
 
 
146
        /* 3. Allocate buffer for trx id */
 
147
 
 
148
        col = dict_table_get_sys_col(table, DATA_TRX_ID);
 
149
        
 
150
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
 
151
        ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN);
 
152
                                
 
153
        dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN);
 
154
 
 
155
        node->trx_id_buf = ptr;
 
156
 
 
157
        /* 4. Allocate buffer for roll ptr */
 
158
 
 
159
        col = dict_table_get_sys_col(table, DATA_ROLL_PTR);
 
160
        
 
161
        dfield = dtuple_get_nth_field(row, dict_col_get_no(col));
 
162
        ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN);
 
163
                                
 
164
        dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN);
 
165
}
 
166
 
 
167
/*************************************************************************
 
168
Sets a new row to insert for an INS_DIRECT node. This function is only used
 
169
if we have constructed the row separately, which is a rare case; this
 
170
function is quite slow. */
 
171
 
 
172
void
 
173
ins_node_set_new_row(
 
174
/*=================*/
 
175
        ins_node_t*     node,   /* in: insert node */
 
176
        dtuple_t*       row)    /* in: new row (or first row) for the node */
 
177
{
 
178
        node->state = INS_NODE_SET_IX_LOCK;
 
179
        node->index = NULL;
 
180
        node->entry = NULL;
 
181
 
 
182
        node->row = row;
 
183
 
 
184
        mem_heap_empty(node->entry_sys_heap);
 
185
 
 
186
        /* Create templates for index entries */
 
187
                        
 
188
        ins_node_create_entry_list(node);
 
189
 
 
190
        /* Allocate from entry_sys_heap buffers for sys fields */
 
191
 
 
192
        row_ins_alloc_sys_fields(node);
 
193
 
 
194
        /* As we allocated a new trx id buf, the trx id should be written
 
195
        there again: */
 
196
 
 
197
        node->trx_id = ut_dulint_zero;
 
198
}
 
199
 
 
200
/***********************************************************************
 
201
Does an insert operation by updating a delete marked existing record
 
202
in the index. This situation can occur if the delete marked record is
 
203
kept in the index for consistent reads. */
 
204
static
 
205
ulint
 
206
row_ins_sec_index_entry_by_modify(
 
207
/*==============================*/
 
208
                                /* out: DB_SUCCESS or error code */
 
209
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
210
        que_thr_t*      thr,    /* in: query thread */
 
211
        mtr_t*          mtr)    /* in: mtr */
 
212
{
 
213
        ulint   err;
 
214
 
 
215
        ut_ad(((cursor->index)->type & DICT_CLUSTERED) == 0);
 
216
        ut_ad(rec_get_deleted_flag(btr_cur_get_rec(cursor)));
 
217
        
 
218
        /* We just remove the delete mark from the secondary index record */
 
219
        err = btr_cur_del_mark_set_sec_rec(0, cursor, FALSE, thr, mtr);
 
220
 
 
221
        return(err);
 
222
}
 
223
 
 
224
/***********************************************************************
 
225
Does an insert operation by delete unmarking and updating a delete marked
 
226
existing record in the index. This situation can occur if the delete marked
 
227
record is kept in the index for consistent reads. */
 
228
static
 
229
ulint
 
230
row_ins_clust_index_entry_by_modify(
 
231
/*================================*/
 
232
                                /* out: DB_SUCCESS, DB_FAIL, or error code */
 
233
        ulint           mode,   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
234
                                depending on whether mtr holds just a leaf
 
235
                                latch or also a tree latch */
 
236
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
237
        dtuple_t*       entry,  /* in: index entry to insert */
 
238
        que_thr_t*      thr,    /* in: query thread */
 
239
        mtr_t*          mtr)    /* in: mtr */
 
240
{
 
241
        mem_heap_t*     heap;
 
242
        rec_t*          rec;
 
243
        upd_t*          update;
 
244
        ulint           err;
 
245
        
 
246
        ut_ad((cursor->index)->type & DICT_CLUSTERED);
 
247
        
 
248
        rec = btr_cur_get_rec(cursor);
 
249
 
 
250
        ut_ad(rec_get_deleted_flag(rec));       
 
251
 
 
252
        heap = mem_heap_create(1024);
 
253
        
 
254
        /* Build an update vector containing all the fields to be modified;
 
255
        NOTE that this vector may contain also system columns! */
 
256
        
 
257
        update = row_upd_build_difference(cursor->index, entry, rec, heap); 
 
258
 
 
259
        if (mode == BTR_MODIFY_LEAF) {
 
260
                /* Try optimistic updating of the record, keeping changes
 
261
                within the page */
 
262
 
 
263
                err = btr_cur_optimistic_update(0, cursor, update, 0, thr,
 
264
                                                                        mtr);
 
265
                if ((err == DB_OVERFLOW) || (err == DB_UNDERFLOW)) {
 
266
                        err = DB_FAIL;
 
267
                }
 
268
        } else  {
 
269
                ut_ad(mode == BTR_MODIFY_TREE);
 
270
                err = btr_cur_pessimistic_update(0, cursor, update, 0, thr,
 
271
                                                                        mtr);
 
272
        }
 
273
        
 
274
        mem_heap_free(heap);
 
275
 
 
276
        return(err);
 
277
}
 
278
 
 
279
/*******************************************************************
 
280
Checks if a unique key violation to rec would occur at the index entry
 
281
insert. */
 
282
static
 
283
ibool
 
284
row_ins_dupl_error_with_rec(
 
285
/*========================*/
 
286
                                /* out: TRUE if error */
 
287
        rec_t*          rec,    /* in: user record */
 
288
        dtuple_t*       entry,  /* in: entry to insert */
 
289
        dict_index_t*   index,  /* in: index */
 
290
        trx_t*          trx)    /* in: inserting transaction */
 
291
{
 
292
        ulint   matched_fields;
 
293
        ulint   matched_bytes;
 
294
        ulint   n_unique;
 
295
        trx_t*  impl_trx;
 
296
        
 
297
        n_unique = dict_index_get_n_unique(index);
 
298
 
 
299
        matched_fields = 0;
 
300
        matched_bytes = 0;
 
301
 
 
302
        cmp_dtuple_rec_with_match(entry, rec, &matched_fields, &matched_bytes);
 
303
 
 
304
        if (matched_fields < n_unique) {
 
305
 
 
306
                        return(FALSE);
 
307
        }
 
308
 
 
309
        if (!rec_get_deleted_flag(rec)) {
 
310
 
 
311
                        return(TRUE);
 
312
        }
 
313
 
 
314
        /* If we get here, the record has its delete mark set. It is still
 
315
        a unique key violation if the transaction which set the delete mark
 
316
        is currently active and is not trx itself. We check if some
 
317
        transaction has an implicit x-lock on the record. */
 
318
 
 
319
        mutex_enter(&kernel_mutex);
 
320
 
 
321
        if (index->type & DICT_CLUSTERED) {
 
322
                impl_trx = lock_clust_rec_some_has_impl(rec, index);
 
323
        } else {
 
324
                impl_trx = lock_sec_rec_some_has_impl_off_kernel(rec, index);
 
325
        }
 
326
 
 
327
        mutex_exit(&kernel_mutex);
 
328
 
 
329
        if (impl_trx && impl_trx != trx) {
 
330
 
 
331
                return(TRUE);
 
332
        }
 
333
 
 
334
        return(FALSE);
 
335
}       
 
336
        
 
337
/*******************************************************************
 
338
Scans a unique non-clustered index at a given index entry to determine
 
339
whether a uniqueness violation has occurred for the key value of the entry. */
 
340
static
 
341
ulint
 
342
row_ins_scan_sec_index_for_duplicate(
 
343
/*=================================*/
 
344
                                /* out: DB_SUCCESS or DB_DUPLICATE_KEY */
 
345
        dict_index_t*   index,  /* in: non-clustered unique index */
 
346
        dtuple_t*       entry,  /* in: index entry */
 
347
        trx_t*          trx)    /* in: inserting transaction */
 
348
{
 
349
        ulint           dupl_count      = 0;
 
350
        int             cmp;
 
351
        ulint           n_fields_cmp;
 
352
        rec_t*          rec;
 
353
        btr_pcur_t      pcur;
 
354
        mtr_t           mtr;
 
355
 
 
356
        mtr_start(&mtr);
 
357
 
 
358
        /* Store old value on n_fields_cmp */
 
359
 
 
360
        n_fields_cmp = dtuple_get_n_fields_cmp(entry);
 
361
 
 
362
        dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique(index));
 
363
        
 
364
        btr_pcur_open_on_user_rec(index, entry, PAGE_CUR_GE,
 
365
                                BTR_SEARCH_LEAF, &pcur, &mtr);
 
366
 
 
367
        /* Scan index records and check that there are no duplicates */
 
368
 
 
369
        for (;;) {
 
370
                if (btr_pcur_is_after_last_in_tree(&pcur, &mtr)) {
 
371
 
 
372
                        break;
 
373
                }
 
374
 
 
375
                rec = btr_pcur_get_rec(&pcur);
 
376
 
 
377
                cmp = cmp_dtuple_rec(entry, rec);
 
378
 
 
379
                if (cmp == 0) {
 
380
                        if (row_ins_dupl_error_with_rec(rec, entry, index,
 
381
                                                                trx)) {
 
382
                                dupl_count++;
 
383
 
 
384
                                if (dupl_count > 1) {
 
385
                                        /* printf(
 
386
                                        "Duplicate key in index %s\n",
 
387
                                                                index->name);
 
388
                                        dtuple_print(entry); */
 
389
                                }
 
390
                        }
 
391
                }
 
392
 
 
393
                if (cmp < 0) {
 
394
                        break;
 
395
                }
 
396
 
 
397
                ut_a(cmp == 0);
 
398
 
 
399
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
400
        }
 
401
 
 
402
        mtr_commit(&mtr);
 
403
 
 
404
        /* Restore old value */
 
405
        dtuple_set_n_fields_cmp(entry, n_fields_cmp);
 
406
 
 
407
        ut_a(dupl_count >= 1);
 
408
 
 
409
        if (dupl_count > 1) {
 
410
 
 
411
                return(DB_DUPLICATE_KEY);
 
412
        }
 
413
 
 
414
        return(DB_SUCCESS);
 
415
}
 
416
 
 
417
/*******************************************************************
 
418
Tries to check if a unique key violation error would occur at an index entry
 
419
insert. */
 
420
static
 
421
ulint
 
422
row_ins_duplicate_error(
 
423
/*====================*/
 
424
                                /* out: DB_SUCCESS if no error
 
425
                                DB_DUPLICATE_KEY if error,
 
426
                                DB_STRONG_FAIL if this is a non-clustered
 
427
                                index record and we cannot determine yet
 
428
                                if there will be an error: in this last
 
429
                                case we must call
 
430
                                row_ins_scan_sec_index_for_duplicate
 
431
                                AFTER the insertion of the record! */
 
432
        btr_cur_t*      cursor, /* in: B-tree cursor */
 
433
        dtuple_t*       entry,  /* in: entry to insert */
 
434
        trx_t*          trx,    /* in: inserting transaction */
 
435
        mtr_t*          mtr,    /* in: mtr */
 
436
        rec_t**         dupl_rec)/* out: record with which duplicate error */
 
437
{
 
438
        rec_t*  rec;
 
439
        page_t* page;
 
440
        ulint   n_unique;
 
441
 
 
442
        ut_ad(cursor->index->type & DICT_UNIQUE);
 
443
 
 
444
        /* NOTE: For unique non-clustered indexes there may be any number
 
445
        of delete marked records with the same value for the non-clustered
 
446
        index key (remember multiversioning), and which differ only in
 
447
        the row refererence part of the index record, containing the
 
448
        clustered index key fields. For such a secondary index record,
 
449
        to avoid race condition, we must FIRST do the insertion and after
 
450
        that check that the uniqueness condition is not breached! */
 
451
        
 
452
        /* NOTE: A problem is that in the B-tree node pointers on an
 
453
        upper level may match more to the entry than the actual existing
 
454
        user records on the leaf level. So, even if low_match would suggest
 
455
        that a duplicate key violation may occur, this may not be the case. */
 
456
 
 
457
        n_unique = dict_index_get_n_unique(cursor->index);
 
458
        
 
459
        if (cursor->low_match >= n_unique) {
 
460
                
 
461
                rec = btr_cur_get_rec(cursor);
 
462
                page = buf_frame_align(rec);
 
463
 
 
464
                if (rec != page_get_infimum_rec(page)) {
 
465
 
 
466
                        if (row_ins_dupl_error_with_rec(rec, entry,
 
467
                                                        cursor->index, trx)) {
 
468
                                *dupl_rec = rec;
 
469
 
 
470
                                return(DB_DUPLICATE_KEY);
 
471
                        }
 
472
                }
 
473
        }
 
474
 
 
475
        if (cursor->up_match >= n_unique) {
 
476
 
 
477
                rec = page_rec_get_next(btr_cur_get_rec(cursor));
 
478
                page = buf_frame_align(rec);
 
479
 
 
480
                if (rec != page_get_supremum_rec(page)) {
 
481
 
 
482
                        if (row_ins_dupl_error_with_rec(rec, entry,
 
483
                                                        cursor->index, trx)) {
 
484
                                *dupl_rec = rec;
 
485
 
 
486
                                return(DB_DUPLICATE_KEY);
 
487
                        }
 
488
                }
 
489
 
 
490
                ut_a(!(cursor->index->type & DICT_CLUSTERED));
 
491
                                                /* This should never happen */
 
492
        }
 
493
 
 
494
        if (cursor->index->type & DICT_CLUSTERED) {
 
495
 
 
496
                return(DB_SUCCESS);
 
497
        }
 
498
 
 
499
        /* It was a non-clustered index: we must scan the index after the
 
500
        insertion to be sure if there will be duplicate key error */
 
501
        
 
502
        return(DB_STRONG_FAIL);
 
503
}
 
504
 
 
505
/*******************************************************************
 
506
Checks if an index entry has long enough common prefix with an existing
 
507
record so that the intended insert of the entry must be changed to a modify of
 
508
the existing record. In the case of a clustered index, the prefix must be
 
509
n_unique fields long, and in the case of a secondary index, all fields must be
 
510
equal. */
 
511
UNIV_INLINE
 
512
ulint
 
513
row_ins_must_modify(
 
514
/*================*/
 
515
                                /* out: 0 if no update, ROW_INS_PREV if
 
516
                                previous should be updated; currently we
 
517
                                do the search so that only the low_match
 
518
                                record can match enough to the search tuple,
 
519
                                not the next record */
 
520
        btr_cur_t*      cursor) /* in: B-tree cursor */
 
521
{
 
522
        ulint   enough_match;
 
523
        rec_t*  rec;
 
524
        page_t* page;
 
525
        
 
526
        /* NOTE: (compare to the note in row_ins_duplicate_error) Because node
 
527
        pointers on upper levels of the B-tree may match more to entry than
 
528
        to actual user records on the leaf level, we have to check if the
 
529
        candidate record is actually a user record. In a clustered index
 
530
        node pointers contain index->n_unique first fields, and in the case
 
531
        of a secondary index, all fields of the index. */
 
532
 
 
533
        enough_match = dict_index_get_n_unique_in_tree(cursor->index);
 
534
        
 
535
        if (cursor->low_match >= enough_match) {
 
536
 
 
537
                rec = btr_cur_get_rec(cursor);
 
538
                page = buf_frame_align(rec);
 
539
 
 
540
                if (rec != page_get_infimum_rec(page)) {
 
541
 
 
542
                        return(ROW_INS_PREV);
 
543
                }
 
544
        }
 
545
 
 
546
        return(0);
 
547
}
 
548
 
 
549
/*******************************************************************
 
550
Tries to insert an index entry to an index. If the index is clustered
 
551
and a record with the same unique key is found, the other record is
 
552
necessarily marked deleted by a committed transaction, or a unique key
 
553
violation error occurs. The delete marked record is then updated to an
 
554
existing record, and we must write an undo log record on the delete
 
555
marked record. If the index is secondary, and a record with exactly the
 
556
same fields is found, the other record is necessarily marked deleted.
 
557
It is then unmarked. Otherwise, the entry is just inserted to the index. */
 
558
 
 
559
ulint
 
560
row_ins_index_entry_low(
 
561
/*====================*/
 
562
                                /* out: DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL
 
563
                                if pessimistic retry needed, or error code */
 
564
        ulint           mode,   /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
 
565
                                depending on whether we wish optimistic or
 
566
                                pessimistic descent down the index tree */
 
567
        dict_index_t*   index,  /* in: index */
 
568
        dtuple_t*       entry,  /* in: index entry to insert */
 
569
        que_thr_t*      thr)    /* in: query thread */
 
570
{
 
571
        btr_cur_t       cursor;         
 
572
        ulint           dupl            = DB_SUCCESS;
 
573
        ulint           modify;
 
574
        rec_t*          dummy_rec;
 
575
        rec_t*          rec;
 
576
        rec_t*          dupl_rec;       /* Note that this may be undefined
 
577
                                        for a non-clustered index even if
 
578
                                        there is a duplicate key */
 
579
        ulint           err;
 
580
        ulint           n_unique;
 
581
        mtr_t           mtr;
 
582
        
 
583
        log_free_check();
 
584
        mtr_start(&mtr);
 
585
 
 
586
        cursor.thr = thr;
 
587
 
 
588
        /* Note that we use PAGE_CUR_LE as the search mode, because then
 
589
        the function will return in both low_match and up_match of the
 
590
        cursor sensible values */
 
591
        
 
592
        btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
 
593
                                        mode | BTR_INSERT, &cursor, 0, &mtr);
 
594
 
 
595
        if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
 
596
                /* The insertion was made to the insert buffer already during
 
597
                the search: we are done */
 
598
 
 
599
                err = DB_SUCCESS;
 
600
 
 
601
                goto function_exit;
 
602
        }       
 
603
                                        
 
604
        n_unique = dict_index_get_n_unique(index);
 
605
 
 
606
        if (index->type & DICT_UNIQUE && (cursor.up_match >= n_unique
 
607
                                         || cursor.low_match >= n_unique)) {
 
608
 
 
609
                dupl = row_ins_duplicate_error(&cursor, entry,
 
610
                                        thr_get_trx(thr), &mtr, &dupl_rec);
 
611
                if (dupl == DB_DUPLICATE_KEY) {
 
612
 
 
613
                        /* printf("Duplicate key in index %s lm %lu\n",
 
614
                                     cursor->index->name, cursor->low_match);
 
615
                        rec_print(rec);
 
616
                        dtuple_print(entry); */
 
617
 
 
618
                        err = dupl;
 
619
 
 
620
                        goto function_exit;                     
 
621
                }
 
622
        }
 
623
 
 
624
        modify = row_ins_must_modify(&cursor);
 
625
 
 
626
        if (modify != 0) {
 
627
                /* There is already an index entry with a long enough common
 
628
                prefix, we must convert the insert into a modify of an
 
629
                existing record */
 
630
 
 
631
                if (modify == ROW_INS_NEXT) {
 
632
                        rec = page_rec_get_next(btr_cur_get_rec(&cursor));
 
633
 
 
634
                        btr_cur_position(index, rec, &cursor);
 
635
                }
 
636
 
 
637
                if (index->type & DICT_CLUSTERED) {
 
638
                        err = row_ins_clust_index_entry_by_modify(mode,
 
639
                                                                &cursor, entry,
 
640
                                                                thr, &mtr);
 
641
                } else {
 
642
                        err = row_ins_sec_index_entry_by_modify(&cursor,
 
643
                                                                thr, &mtr);
 
644
                }
 
645
                
 
646
        } else if (mode == BTR_MODIFY_LEAF) {
 
647
                err = btr_cur_optimistic_insert(0, &cursor, entry,
 
648
                                                        &dummy_rec, thr, &mtr);
 
649
        } else {
 
650
                ut_ad(mode == BTR_MODIFY_TREE);
 
651
                err = btr_cur_pessimistic_insert(0, &cursor, entry,
 
652
                                                        &dummy_rec, thr, &mtr);
 
653
        }
 
654
function_exit:
 
655
        mtr_commit(&mtr);
 
656
 
 
657
        if (err == DB_SUCCESS && dupl == DB_STRONG_FAIL) {
 
658
                /* We were not able to determine before the insertion
 
659
                whether there will be a duplicate key error: do the check
 
660
                now */
 
661
        
 
662
                err = row_ins_scan_sec_index_for_duplicate(index, entry,
 
663
                                                        thr_get_trx(thr));
 
664
        }
 
665
 
 
666
        ut_ad(err != DB_DUPLICATE_KEY || index->type & DICT_CLUSTERED
 
667
                || DB_DUPLICATE_KEY ==
 
668
                row_ins_scan_sec_index_for_duplicate(index, entry,
 
669
                                                        thr_get_trx(thr)));
 
670
        return(err);
 
671
}
 
672
 
 
673
/*******************************************************************
 
674
Inserts an index entry to index. Tries first optimistic, then pessimistic
 
675
descent down the tree. If the entry matches enough to a delete marked record,
 
676
performs the insert by updating or delete unmarking the delete marked
 
677
record. */
 
678
 
 
679
ulint
 
680
row_ins_index_entry(
 
681
/*================*/
 
682
                                /* out: DB_SUCCESS, DB_LOCK_WAIT,
 
683
                                DB_DUPLICATE_KEY, or some other error code */
 
684
        dict_index_t*   index,  /* in: index */
 
685
        dtuple_t*       entry,  /* in: index entry to insert */
 
686
        que_thr_t*      thr)    /* in: query thread */
 
687
{
 
688
        ulint   err;
 
689
 
 
690
        /* Try first optimistic descent to the B-tree */
 
691
 
 
692
        err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry, thr);
 
693
        
 
694
        if (err != DB_FAIL) {
 
695
 
 
696
                return(err);
 
697
        }
 
698
 
 
699
        /* Try then pessimistic descent to the B-tree */
 
700
 
 
701
        err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry, thr);
 
702
 
 
703
        return(err);
 
704
}
 
705
 
 
706
/***************************************************************
 
707
Sets the values of the dtuple fields in entry from the values of appropriate
 
708
columns in row. */
 
709
UNIV_INLINE
 
710
void
 
711
row_ins_index_entry_set_vals(
 
712
/*=========================*/
 
713
        dtuple_t*       entry,  /* in: index entry to make */
 
714
        dtuple_t*       row)    /* in: row */
 
715
{
 
716
        dfield_t*       field;
 
717
        dfield_t*       row_field;
 
718
        ulint           n_fields;
 
719
        ulint           i;
 
720
 
 
721
        ut_ad(entry && row);
 
722
 
 
723
        n_fields = dtuple_get_n_fields(entry);
 
724
 
 
725
        for (i = 0; i < n_fields; i++) {
 
726
                field = dtuple_get_nth_field(entry, i);
 
727
 
 
728
                row_field = dtuple_get_nth_field(row, field->col_no);
 
729
 
 
730
                field->data = row_field->data;
 
731
                field->len = row_field->len;
 
732
        }
 
733
}
 
734
 
 
735
/***************************************************************
 
736
Inserts a single index entry to the table. */
 
737
UNIV_INLINE
 
738
ulint
 
739
row_ins_index_entry_step(
 
740
/*=====================*/
 
741
                                /* out: DB_SUCCESS if operation successfully
 
742
                                completed, else error code or DB_LOCK_WAIT */
 
743
        ins_node_t*     node,   /* in: row insert node */
 
744
        que_thr_t*      thr)    /* in: query thread */
 
745
{
 
746
        ulint   err;
 
747
 
 
748
        ut_ad(dtuple_check_typed(node->row));
 
749
        
 
750
        row_ins_index_entry_set_vals(node->entry, node->row);
 
751
        
 
752
        ut_ad(dtuple_check_typed(node->entry));
 
753
 
 
754
        err = row_ins_index_entry(node->index, node->entry, thr);
 
755
 
 
756
        return(err);
 
757
}
 
758
 
 
759
/***************************************************************
 
760
Allocates a row id for row and inits the node->index field. */
 
761
UNIV_INLINE
 
762
void
 
763
row_ins_alloc_row_id_step(
 
764
/*======================*/
 
765
        ins_node_t*     node)   /* in: row insert node */
 
766
{
 
767
        dulint  row_id;
 
768
        
 
769
        ut_ad(node->state == INS_NODE_ALLOC_ROW_ID);
 
770
        
 
771
        if (dict_table_get_first_index(node->table)->type & DICT_UNIQUE) {
 
772
 
 
773
                /* No row id is stored if the clustered index is unique */
 
774
 
 
775
                return;
 
776
        }
 
777
        
 
778
        /* Fill in row id value to row */
 
779
 
 
780
        row_id = dict_sys_get_new_row_id();
 
781
 
 
782
        dict_sys_write_row_id(node->row_id_buf, row_id);
 
783
}
 
784
 
 
785
/***************************************************************
 
786
Gets a row to insert from the values list. */
 
787
UNIV_INLINE
 
788
void
 
789
row_ins_get_row_from_values(
 
790
/*========================*/
 
791
        ins_node_t*     node)   /* in: row insert node */
 
792
{
 
793
        que_node_t*     list_node;
 
794
        dfield_t*       dfield;
 
795
        dtuple_t*       row;
 
796
        ulint           i;
 
797
        
 
798
        /* The field values are copied in the buffers of the select node and
 
799
        it is safe to use them until we fetch from select again: therefore
 
800
        we can just copy the pointers */
 
801
 
 
802
        row = node->row; 
 
803
 
 
804
        i = 0;
 
805
        list_node = node->values_list;
 
806
 
 
807
        while (list_node) {
 
808
                eval_exp(list_node);
 
809
 
 
810
                dfield = dtuple_get_nth_field(row, i);
 
811
                dfield_copy_data(dfield, que_node_get_val(list_node));
 
812
 
 
813
                i++;
 
814
                list_node = que_node_get_next(list_node);
 
815
        }
 
816
}
 
817
 
 
818
/***************************************************************
 
819
Gets a row to insert from the select list. */
 
820
UNIV_INLINE
 
821
void
 
822
row_ins_get_row_from_select(
 
823
/*========================*/
 
824
        ins_node_t*     node)   /* in: row insert node */
 
825
{
 
826
        que_node_t*     list_node;
 
827
        dfield_t*       dfield;
 
828
        dtuple_t*       row;
 
829
        ulint           i;
 
830
 
 
831
        /* The field values are copied in the buffers of the select node and
 
832
        it is safe to use them until we fetch from select again: therefore
 
833
        we can just copy the pointers */
 
834
 
 
835
        row = node->row; 
 
836
 
 
837
        i = 0;
 
838
        list_node = node->select->select_list;
 
839
 
 
840
        while (list_node) {
 
841
                dfield = dtuple_get_nth_field(row, i);
 
842
                dfield_copy_data(dfield, que_node_get_val(list_node));
 
843
 
 
844
                i++;
 
845
                list_node = que_node_get_next(list_node);
 
846
        }
 
847
}
 
848
        
 
849
/***************************************************************
 
850
Inserts a row to a table. */
 
851
 
 
852
ulint
 
853
row_ins(
 
854
/*====*/
 
855
                                /* out: DB_SUCCESS if operation successfully
 
856
                                completed, else error code or DB_LOCK_WAIT */
 
857
        ins_node_t*     node,   /* in: row insert node */
 
858
        que_thr_t*      thr)    /* in: query thread */
 
859
{
 
860
        ulint   err;
 
861
        
 
862
        ut_ad(node && thr);
 
863
 
 
864
        if (node->state == INS_NODE_ALLOC_ROW_ID) {
 
865
 
 
866
                row_ins_alloc_row_id_step(node);
 
867
        
 
868
                node->index = dict_table_get_first_index(node->table);
 
869
                node->entry = UT_LIST_GET_FIRST(node->entry_list);
 
870
 
 
871
                if (node->ins_type == INS_SEARCHED) {
 
872
 
 
873
                        row_ins_get_row_from_select(node);
 
874
 
 
875
                } else if (node->ins_type == INS_VALUES) {
 
876
 
 
877
                        row_ins_get_row_from_values(node);
 
878
                }
 
879
 
 
880
                node->state = INS_NODE_INSERT_ENTRIES;
 
881
        }
 
882
 
 
883
        ut_ad(node->state == INS_NODE_INSERT_ENTRIES);
 
884
 
 
885
        while (node->index != NULL) {
 
886
                err = row_ins_index_entry_step(node, thr);
 
887
                
 
888
                if (err != DB_SUCCESS) {
 
889
 
 
890
                        return(err);
 
891
                }
 
892
 
 
893
                node->index = dict_table_get_next_index(node->index);
 
894
                node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
 
895
        }
 
896
 
 
897
        ut_ad(node->entry == NULL);
 
898
        
 
899
        node->state = INS_NODE_ALLOC_ROW_ID;
 
900
        
 
901
        return(DB_SUCCESS);
 
902
}
 
903
 
 
904
/***************************************************************
 
905
Inserts a row to a table. This is a high-level function used in SQL execution
 
906
graphs. */
 
907
 
 
908
que_thr_t*
 
909
row_ins_step(
 
910
/*=========*/
 
911
                                /* out: query thread to run next or NULL */
 
912
        que_thr_t*      thr)    /* in: query thread */
 
913
{
 
914
        ins_node_t*     node;
 
915
        que_node_t*     parent;
 
916
        sel_node_t*     sel_node;
 
917
        trx_t*          trx;
 
918
        ulint           err;
 
919
 
 
920
        ut_ad(thr);
 
921
        
 
922
        trx = thr_get_trx(thr);
 
923
 
 
924
        node = thr->run_node;
 
925
 
 
926
        ut_ad(que_node_get_type(node) == QUE_NODE_INSERT);
 
927
 
 
928
        parent = que_node_get_parent(node);
 
929
        sel_node = node->select;
 
930
 
 
931
        if (thr->prev_node == parent) {
 
932
                node->state = INS_NODE_SET_IX_LOCK;
 
933
        }
 
934
 
 
935
        /* If this is the first time this node is executed (or when
 
936
        execution resumes after wait for the table IX lock), set an
 
937
        IX lock on the table and reset the possible select node. */
 
938
 
 
939
        if (node->state == INS_NODE_SET_IX_LOCK) {
 
940
 
 
941
                /* It may be that the current session has not yet started
 
942
                its transaction, or it has been committed: */
 
943
                
 
944
                trx_start_if_not_started(trx);
 
945
 
 
946
                if (UT_DULINT_EQ(trx->id, node->trx_id)) {
 
947
                        /* No need to do IX-locking or write trx id to buf */
 
948
 
 
949
                        goto same_trx;
 
950
                }       
 
951
 
 
952
                trx_write_trx_id(node->trx_id_buf, trx->id);
 
953
 
 
954
                err = lock_table(0, node->table, LOCK_IX, thr);
 
955
 
 
956
                if (err != DB_SUCCESS) {
 
957
 
 
958
                        goto error_handling;
 
959
                }
 
960
 
 
961
                node->trx_id = trx->id;
 
962
        same_trx:                               
 
963
                node->state = INS_NODE_ALLOC_ROW_ID;
 
964
 
 
965
                if (node->ins_type == INS_SEARCHED) {
 
966
                        /* Reset the cursor */
 
967
                        sel_node->state = SEL_NODE_OPEN;
 
968
                
 
969
                        /* Fetch a row to insert */
 
970
                
 
971
                        thr->run_node = sel_node;
 
972
        
 
973
                        return(thr);
 
974
                }
 
975
        }
 
976
 
 
977
        if ((node->ins_type == INS_SEARCHED)
 
978
                                && (sel_node->state != SEL_NODE_FETCH)) {
 
979
 
 
980
                ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
 
981
 
 
982
                /* No more rows to insert */
 
983
                thr->run_node = parent;
 
984
        
 
985
                return(thr);
 
986
        }
 
987
 
 
988
        /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
 
989
 
 
990
        err = row_ins(node, thr);
 
991
 
 
992
error_handling:
 
993
        trx->error_state = err;
 
994
 
 
995
        if (err == DB_SUCCESS) {
 
996
                /* Ok: do nothing */
 
997
 
 
998
        } else if (err == DB_LOCK_WAIT) {
 
999
 
 
1000
                return(NULL);
 
1001
        } else {
 
1002
                /* SQL error detected */
 
1003
 
 
1004
                return(NULL);
 
1005
        }
 
1006
 
 
1007
        /* DO THE TRIGGER ACTIONS HERE */
 
1008
 
 
1009
        if (node->ins_type == INS_SEARCHED) {
 
1010
                /* Fetch a row to insert */
 
1011
                
 
1012
                thr->run_node = sel_node;
 
1013
        } else {
 
1014
                thr->run_node = que_node_get_parent(node);
 
1015
        }
 
1016
 
 
1017
        return(thr);
 
1018