~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-02-07 01:33:54 UTC
  • Revision ID: brian@gaz-20100207013354-d2pg1n68u5c09pgo
Remove giant include header to its own file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************
2
 
Update of a row
3
 
 
4
 
(c) 1996 Innobase Oy
5
 
 
6
 
Created 12/27/1996 Heikki Tuuri
7
 
*******************************************************/
8
 
 
9
 
#include "row0upd.h"
10
 
 
11
 
#ifdef UNIV_NONINL
12
 
#include "row0upd.ic"
13
 
#endif
14
 
 
15
 
#include "dict0dict.h"
16
 
#include "dict0boot.h"
17
 
#include "dict0crea.h"
18
 
#include "mach0data.h"
19
 
#include "trx0undo.h"
20
 
#include "btr0btr.h"
21
 
#include "btr0cur.h"
22
 
#include "que0que.h"
23
 
#include "row0ins.h"
24
 
#include "row0sel.h"
25
 
#include "row0row.h"
26
 
#include "rem0cmp.h"
27
 
#include "lock0lock.h"
28
 
#include "log0log.h"
29
 
#include "pars0sym.h"
30
 
#include "eval0eval.h"
31
 
#include "buf0lru.h"
32
 
 
33
 
 
34
 
/* What kind of latch and lock can we assume when the control comes to
35
 
   -------------------------------------------------------------------
36
 
an update node?
37
 
--------------
38
 
Efficiency of massive updates would require keeping an x-latch on a
39
 
clustered index page through many updates, and not setting an explicit
40
 
x-lock on clustered index records, as they anyway will get an implicit
41
 
x-lock when they are updated. A problem is that the read nodes in the
42
 
graph should know that they must keep the latch when passing the control
43
 
up to the update node, and not set any record lock on the record which
44
 
will be updated. Another problem occurs if the execution is stopped,
45
 
as the kernel switches to another query thread, or the transaction must
46
 
wait for a lock. Then we should be able to release the latch and, maybe,
47
 
acquire an explicit x-lock on the record.
48
 
        Because this seems too complicated, we conclude that the less
49
 
efficient solution of releasing all the latches when the control is
50
 
transferred to another node, and acquiring explicit x-locks, is better. */
51
 
 
52
 
/* How is a delete performed? If there is a delete without an
53
 
explicit cursor, i.e., a searched delete, there are at least
54
 
two different situations:
55
 
the implicit select cursor may run on (1) the clustered index or
56
 
on (2) a secondary index. The delete is performed by setting
57
 
the delete bit in the record and substituting the id of the
58
 
deleting transaction for the original trx id, and substituting a
59
 
new roll ptr for previous roll ptr. The old trx id and roll ptr
60
 
are saved in the undo log record. Thus, no physical changes occur
61
 
in the index tree structure at the time of the delete. Only
62
 
when the undo log is purged, the index records will be physically
63
 
deleted from the index trees.
64
 
 
65
 
The query graph executing a searched delete would consist of
66
 
a delete node which has as a subtree a select subgraph.
67
 
The select subgraph should return a (persistent) cursor
68
 
in the clustered index, placed on page which is x-latched.
69
 
The delete node should look for all secondary index records for
70
 
this clustered index entry and mark them as deleted. When is
71
 
the x-latch freed? The most efficient way for performing a
72
 
searched delete is obviously to keep the x-latch for several
73
 
steps of query graph execution. */
74
 
 
75
 
/***************************************************************
76
 
Checks if an update vector changes some of the first ordering fields of an
77
 
index record. This is only used in foreign key checks and we can assume
78
 
that index does not contain column prefixes. */
79
 
static
80
 
ibool
81
 
row_upd_changes_first_fields_binary(
82
 
/*================================*/
83
 
                                /* out: TRUE if changes */
84
 
        dtuple_t*       entry,  /* in: old value of index entry */
85
 
        dict_index_t*   index,  /* in: index of entry */
86
 
        upd_t*          update, /* in: update vector for the row */
87
 
        ulint           n);     /* in: how many first fields to check */
88
 
 
89
 
 
90
 
/*************************************************************************
91
 
Checks if index currently is mentioned as a referenced index in a foreign
92
 
key constraint. */
93
 
static
94
 
ibool
95
 
row_upd_index_is_referenced(
96
 
/*========================*/
97
 
                                /* out: TRUE if referenced; NOTE that since
98
 
                                we do not hold dict_operation_lock
99
 
                                when leaving the function, it may be that
100
 
                                the referencing table has been dropped when
101
 
                                we leave this function: this function is only
102
 
                                for heuristic use! */
103
 
        dict_index_t*   index,  /* in: index */
104
 
        trx_t*          trx)    /* in: transaction */
105
 
{
106
 
        dict_table_t*   table           = index->table;
107
 
        dict_foreign_t* foreign;
108
 
        ibool           froze_data_dict = FALSE;
109
 
 
110
 
        if (!UT_LIST_GET_FIRST(table->referenced_list)) {
111
 
 
112
 
                return(FALSE);
113
 
        }
114
 
 
115
 
        if (trx->dict_operation_lock_mode == 0) {
116
 
                row_mysql_freeze_data_dictionary(trx);
117
 
                froze_data_dict = TRUE;
118
 
        }
119
 
 
120
 
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
121
 
 
122
 
        while (foreign) {
123
 
                if (foreign->referenced_index == index) {
124
 
 
125
 
                        if (froze_data_dict) {
126
 
                                row_mysql_unfreeze_data_dictionary(trx);
127
 
                        }
128
 
 
129
 
                        return(TRUE);
130
 
                }
131
 
 
132
 
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
133
 
        }
134
 
 
135
 
        if (froze_data_dict) {
136
 
                row_mysql_unfreeze_data_dictionary(trx);
137
 
        }
138
 
 
139
 
        return(FALSE);
140
 
}
141
 
 
142
 
/*************************************************************************
143
 
Checks if possible foreign key constraints hold after a delete of the record
144
 
under pcur. NOTE that this function will temporarily commit mtr and lose the
145
 
pcur position! */
146
 
static
147
 
ulint
148
 
row_upd_check_references_constraints(
149
 
/*=================================*/
150
 
                                /* out: DB_SUCCESS or an error code */
151
 
        upd_node_t*     node,   /* in: row update node */
152
 
        btr_pcur_t*     pcur,   /* in: cursor positioned on a record; NOTE: the
153
 
                                cursor position is lost in this function! */
154
 
        dict_table_t*   table,  /* in: table in question */
155
 
        dict_index_t*   index,  /* in: index of the cursor */
156
 
        que_thr_t*      thr,    /* in: query thread */
157
 
        mtr_t*          mtr)    /* in: mtr */
158
 
{
159
 
        dict_foreign_t* foreign;
160
 
        mem_heap_t*     heap;
161
 
        dtuple_t*       entry;
162
 
        trx_t*          trx;
163
 
        rec_t*          rec;
164
 
        ulint           err;
165
 
        ibool           got_s_lock      = FALSE;
166
 
 
167
 
        if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
168
 
 
169
 
                return(DB_SUCCESS);
170
 
        }
171
 
 
172
 
        trx = thr_get_trx(thr);
173
 
 
174
 
        rec = btr_pcur_get_rec(pcur);
175
 
 
176
 
        heap = mem_heap_create(500);
177
 
 
178
 
        entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
179
 
 
180
 
        mtr_commit(mtr);
181
 
 
182
 
        mtr_start(mtr);
183
 
 
184
 
        if (trx->dict_operation_lock_mode == 0) {
185
 
                got_s_lock = TRUE;
186
 
 
187
 
                row_mysql_freeze_data_dictionary(trx);
188
 
        }
189
 
 
190
 
        foreign = UT_LIST_GET_FIRST(table->referenced_list);
191
 
 
192
 
        while (foreign) {
193
 
                /* Note that we may have an update which updates the index
194
 
                record, but does NOT update the first fields which are
195
 
                referenced in a foreign key constraint. Then the update does
196
 
                NOT break the constraint. */
197
 
 
198
 
                if (foreign->referenced_index == index
199
 
                    && (node->is_delete
200
 
                        || row_upd_changes_first_fields_binary(
201
 
                                entry, index, node->update,
202
 
                                foreign->n_fields))) {
203
 
 
204
 
                        if (foreign->foreign_table == NULL) {
205
 
                                dict_table_get(foreign->foreign_table_name,
206
 
                                               FALSE);
207
 
                        }
208
 
 
209
 
                        if (foreign->foreign_table) {
210
 
                                mutex_enter(&(dict_sys->mutex));
211
 
 
212
 
                                (foreign->foreign_table
213
 
                                 ->n_foreign_key_checks_running)++;
214
 
 
215
 
                                mutex_exit(&(dict_sys->mutex));
216
 
                        }
217
 
 
218
 
                        /* NOTE that if the thread ends up waiting for a lock
219
 
                        we will release dict_operation_lock temporarily!
220
 
                        But the counter on the table protects 'foreign' from
221
 
                        being dropped while the check is running. */
222
 
 
223
 
                        err = row_ins_check_foreign_constraint(
224
 
                                FALSE, foreign, table, entry, thr);
225
 
 
226
 
                        if (foreign->foreign_table) {
227
 
                                mutex_enter(&(dict_sys->mutex));
228
 
 
229
 
                                ut_a(foreign->foreign_table
230
 
                                     ->n_foreign_key_checks_running > 0);
231
 
 
232
 
                                (foreign->foreign_table
233
 
                                 ->n_foreign_key_checks_running)--;
234
 
 
235
 
                                mutex_exit(&(dict_sys->mutex));
236
 
                        }
237
 
 
238
 
                        if (err != DB_SUCCESS) {
239
 
                                if (got_s_lock) {
240
 
                                        row_mysql_unfreeze_data_dictionary(
241
 
                                                trx);
242
 
                                }
243
 
 
244
 
                                mem_heap_free(heap);
245
 
 
246
 
                                return(err);
247
 
                        }
248
 
                }
249
 
 
250
 
                foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
251
 
        }
252
 
 
253
 
        if (got_s_lock) {
254
 
                row_mysql_unfreeze_data_dictionary(trx);
255
 
        }
256
 
 
257
 
        mem_heap_free(heap);
258
 
 
259
 
        return(DB_SUCCESS);
260
 
}
261
 
 
262
 
/*************************************************************************
263
 
Creates an update node for a query graph. */
264
 
 
265
 
upd_node_t*
266
 
upd_node_create(
267
 
/*============*/
268
 
                                /* out, own: update node */
269
 
        mem_heap_t*     heap)   /* in: mem heap where created */
270
 
{
271
 
        upd_node_t*     node;
272
 
 
273
 
        node = mem_heap_alloc(heap, sizeof(upd_node_t));
274
 
        node->common.type = QUE_NODE_UPDATE;
275
 
 
276
 
        node->state = UPD_NODE_UPDATE_CLUSTERED;
277
 
        node->select_will_do_update = FALSE;
278
 
        node->in_mysql_interface = FALSE;
279
 
 
280
 
        node->row = NULL;
281
 
        node->ext_vec = NULL;
282
 
        node->index = NULL;
283
 
        node->update = NULL;
284
 
 
285
 
        node->foreign = NULL;
286
 
        node->cascade_heap = NULL;
287
 
        node->cascade_node = NULL;
288
 
 
289
 
        node->select = NULL;
290
 
 
291
 
        node->heap = mem_heap_create(128);
292
 
        node->magic_n = UPD_NODE_MAGIC_N;
293
 
 
294
 
        node->cmpl_info = 0;
295
 
 
296
 
        return(node);
297
 
}
298
 
 
299
 
/*************************************************************************
300
 
Updates the trx id and roll ptr field in a clustered index record in database
301
 
recovery. */
302
 
 
303
 
void
304
 
row_upd_rec_sys_fields_in_recovery(
305
 
/*===============================*/
306
 
        rec_t*          rec,    /* in: record */
307
 
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
308
 
        ulint           pos,    /* in: TRX_ID position in rec */
309
 
        dulint          trx_id, /* in: transaction id */
310
 
        dulint          roll_ptr)/* in: roll ptr of the undo log record */
311
 
{
312
 
        byte*   field;
313
 
        ulint   len;
314
 
 
315
 
        field = rec_get_nth_field(rec, offsets, pos, &len);
316
 
        ut_ad(len == DATA_TRX_ID_LEN);
317
 
        trx_write_trx_id(field, trx_id);
318
 
 
319
 
        field = rec_get_nth_field(rec, offsets, pos + 1, &len);
320
 
        ut_ad(len == DATA_ROLL_PTR_LEN);
321
 
        trx_write_roll_ptr(field, roll_ptr);
322
 
}
323
 
 
324
 
/*************************************************************************
325
 
Sets the trx id or roll ptr field of a clustered index entry. */
326
 
 
327
 
void
328
 
row_upd_index_entry_sys_field(
329
 
/*==========================*/
330
 
        dtuple_t*       entry,  /* in: index entry, where the memory buffers
331
 
                                for sys fields are already allocated:
332
 
                                the function just copies the new values to
333
 
                                them */
334
 
        dict_index_t*   index,  /* in: clustered index */
335
 
        ulint           type,   /* in: DATA_TRX_ID or DATA_ROLL_PTR */
336
 
        dulint          val)    /* in: value to write */
337
 
{
338
 
        dfield_t*       dfield;
339
 
        byte*           field;
340
 
        ulint           pos;
341
 
 
342
 
        ut_ad(index->type & DICT_CLUSTERED);
343
 
 
344
 
        pos = dict_index_get_sys_col_pos(index, type);
345
 
 
346
 
        dfield = dtuple_get_nth_field(entry, pos);
347
 
        field = dfield_get_data(dfield);
348
 
 
349
 
        if (type == DATA_TRX_ID) {
350
 
                trx_write_trx_id(field, val);
351
 
        } else {
352
 
                ut_ad(type == DATA_ROLL_PTR);
353
 
                trx_write_roll_ptr(field, val);
354
 
        }
355
 
}
356
 
 
357
 
/***************************************************************
358
 
Returns TRUE if row update changes size of some field in index or if some
359
 
field to be updated is stored externally in rec or update. */
360
 
 
361
 
ibool
362
 
row_upd_changes_field_size_or_external(
363
 
/*===================================*/
364
 
                                /* out: TRUE if the update changes the size of
365
 
                                some field in index or the field is external
366
 
                                in rec or update */
367
 
        dict_index_t*   index,  /* in: index */
368
 
        const ulint*    offsets,/* in: rec_get_offsets(rec, index) */
369
 
        upd_t*          update) /* in: update vector */
370
 
{
371
 
        upd_field_t*    upd_field;
372
 
        dfield_t*       new_val;
373
 
        ulint           old_len;
374
 
        ulint           new_len;
375
 
        ulint           n_fields;
376
 
        ulint           i;
377
 
 
378
 
        ut_ad(rec_offs_validate(NULL, index, offsets));
379
 
        n_fields = upd_get_n_fields(update);
380
 
 
381
 
        for (i = 0; i < n_fields; i++) {
382
 
                upd_field = upd_get_nth_field(update, i);
383
 
 
384
 
                new_val = &(upd_field->new_val);
385
 
                new_len = new_val->len;
386
 
 
387
 
                if (new_len == UNIV_SQL_NULL && !rec_offs_comp(offsets)) {
388
 
                        /* A bug fixed on Dec 31st, 2004: we looked at the
389
 
                        SQL NULL size from the wrong field! We may backport
390
 
                        this fix also to 4.0. The merge to 5.0 will be made
391
 
                        manually immediately after we commit this to 4.1. */
392
 
 
393
 
                        new_len = dict_col_get_sql_null_size(
394
 
                                dict_index_get_nth_col(index,
395
 
                                                       upd_field->field_no));
396
 
                }
397
 
 
398
 
                old_len = rec_offs_nth_size(offsets, upd_field->field_no);
399
 
 
400
 
                if (rec_offs_comp(offsets)
401
 
                    && rec_offs_nth_sql_null(offsets,
402
 
                                             upd_field->field_no)) {
403
 
                        /* Note that in the compact table format, for a
404
 
                        variable length field, an SQL NULL will use zero
405
 
                        bytes in the offset array at the start of the physical
406
 
                        record, but a zero-length value (empty string) will
407
 
                        use one byte! Thus, we cannot use update-in-place
408
 
                        if we update an SQL NULL varchar to an empty string! */
409
 
 
410
 
                        old_len = UNIV_SQL_NULL;
411
 
                }
412
 
 
413
 
                if (old_len != new_len) {
414
 
 
415
 
                        return(TRUE);
416
 
                }
417
 
 
418
 
                if (rec_offs_nth_extern(offsets, upd_field->field_no)) {
419
 
 
420
 
                        return(TRUE);
421
 
                }
422
 
 
423
 
                if (upd_field->extern_storage) {
424
 
 
425
 
                        return(TRUE);
426
 
                }
427
 
        }
428
 
 
429
 
        return(FALSE);
430
 
}
431
 
 
432
 
/***************************************************************
433
 
Replaces the new column values stored in the update vector to the record
434
 
given. No field size changes are allowed. This function is used only for
435
 
a clustered index */
436
 
 
437
 
void
438
 
row_upd_rec_in_place(
439
 
/*=================*/
440
 
        rec_t*          rec,    /* in/out: record where replaced */
441
 
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
442
 
        upd_t*          update) /* in: update vector */
443
 
{
444
 
        upd_field_t*    upd_field;
445
 
        dfield_t*       new_val;
446
 
        ulint           n_fields;
447
 
        ulint           i;
448
 
 
449
 
        ut_ad(rec_offs_validate(rec, NULL, offsets));
450
 
 
451
 
        rec_set_info_bits(rec, rec_offs_comp(offsets), update->info_bits);
452
 
 
453
 
        n_fields = upd_get_n_fields(update);
454
 
 
455
 
        for (i = 0; i < n_fields; i++) {
456
 
                upd_field = upd_get_nth_field(update, i);
457
 
                new_val = &(upd_field->new_val);
458
 
 
459
 
                rec_set_nth_field(rec, offsets, upd_field->field_no,
460
 
                                  dfield_get_data(new_val),
461
 
                                  dfield_get_len(new_val));
462
 
        }
463
 
}
464
 
 
465
 
/*************************************************************************
466
 
Writes into the redo log the values of trx id and roll ptr and enough info
467
 
to determine their positions within a clustered index record. */
468
 
 
469
 
byte*
470
 
row_upd_write_sys_vals_to_log(
471
 
/*==========================*/
472
 
                                /* out: new pointer to mlog */
473
 
        dict_index_t*   index,  /* in: clustered index */
474
 
        trx_t*          trx,    /* in: transaction */
475
 
        dulint          roll_ptr,/* in: roll ptr of the undo log record */
476
 
        byte*           log_ptr,/* pointer to a buffer of size > 20 opened
477
 
                                in mlog */
478
 
        mtr_t*          mtr __attribute__((unused))) /* in: mtr */
479
 
{
480
 
        ut_ad(index->type & DICT_CLUSTERED);
481
 
        ut_ad(mtr);
482
 
 
483
 
        log_ptr += mach_write_compressed(log_ptr,
484
 
                                         dict_index_get_sys_col_pos(
485
 
                                                 index, DATA_TRX_ID));
486
 
 
487
 
        trx_write_roll_ptr(log_ptr, roll_ptr);
488
 
        log_ptr += DATA_ROLL_PTR_LEN;
489
 
 
490
 
        log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
491
 
 
492
 
        return(log_ptr);
493
 
}
494
 
 
495
 
/*************************************************************************
496
 
Parses the log data of system field values. */
497
 
 
498
 
byte*
499
 
row_upd_parse_sys_vals(
500
 
/*===================*/
501
 
                        /* out: log data end or NULL */
502
 
        byte*   ptr,    /* in: buffer */
503
 
        byte*   end_ptr,/* in: buffer end */
504
 
        ulint*  pos,    /* out: TRX_ID position in record */
505
 
        dulint* trx_id, /* out: trx id */
506
 
        dulint* roll_ptr)/* out: roll ptr */
507
 
{
508
 
        ptr = mach_parse_compressed(ptr, end_ptr, pos);
509
 
 
510
 
        if (ptr == NULL) {
511
 
 
512
 
                return(NULL);
513
 
        }
514
 
 
515
 
        if (end_ptr < ptr + DATA_ROLL_PTR_LEN) {
516
 
 
517
 
                return(NULL);
518
 
        }
519
 
 
520
 
        *roll_ptr = trx_read_roll_ptr(ptr);
521
 
        ptr += DATA_ROLL_PTR_LEN;
522
 
 
523
 
        ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
524
 
 
525
 
        return(ptr);
526
 
}
527
 
 
528
 
/***************************************************************
529
 
Writes to the redo log the new values of the fields occurring in the index. */
530
 
 
531
 
void
532
 
row_upd_index_write_log(
533
 
/*====================*/
534
 
        upd_t*  update, /* in: update vector */
535
 
        byte*   log_ptr,/* in: pointer to mlog buffer: must contain at least
536
 
                        MLOG_BUF_MARGIN bytes of free space; the buffer is
537
 
                        closed within this function */
538
 
        mtr_t*  mtr)    /* in: mtr into whose log to write */
539
 
{
540
 
        upd_field_t*    upd_field;
541
 
        dfield_t*       new_val;
542
 
        ulint           len;
543
 
        ulint           n_fields;
544
 
        byte*           buf_end;
545
 
        ulint           i;
546
 
 
547
 
        n_fields = upd_get_n_fields(update);
548
 
 
549
 
        buf_end = log_ptr + MLOG_BUF_MARGIN;
550
 
 
551
 
        mach_write_to_1(log_ptr, update->info_bits);
552
 
        log_ptr++;
553
 
        log_ptr += mach_write_compressed(log_ptr, n_fields);
554
 
 
555
 
        for (i = 0; i < n_fields; i++) {
556
 
 
557
 
#if MLOG_BUF_MARGIN <= 30
558
 
# error "MLOG_BUF_MARGIN <= 30"
559
 
#endif
560
 
 
561
 
                if (log_ptr + 30 > buf_end) {
562
 
                        mlog_close(mtr, log_ptr);
563
 
 
564
 
                        log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
565
 
                        buf_end = log_ptr + MLOG_BUF_MARGIN;
566
 
                }
567
 
 
568
 
                upd_field = upd_get_nth_field(update, i);
569
 
 
570
 
                new_val = &(upd_field->new_val);
571
 
 
572
 
                len = new_val->len;
573
 
 
574
 
                log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
575
 
                log_ptr += mach_write_compressed(log_ptr, len);
576
 
 
577
 
                if (len != UNIV_SQL_NULL) {
578
 
                        if (log_ptr + len < buf_end) {
579
 
                                ut_memcpy(log_ptr, new_val->data, len);
580
 
 
581
 
                                log_ptr += len;
582
 
                        } else {
583
 
                                mlog_close(mtr, log_ptr);
584
 
 
585
 
                                mlog_catenate_string(mtr, new_val->data, len);
586
 
 
587
 
                                log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
588
 
                                buf_end = log_ptr + MLOG_BUF_MARGIN;
589
 
                        }
590
 
                }
591
 
        }
592
 
 
593
 
        mlog_close(mtr, log_ptr);
594
 
}
595
 
 
596
 
/*************************************************************************
597
 
Parses the log data written by row_upd_index_write_log. */
598
 
 
599
 
byte*
600
 
row_upd_index_parse(
601
 
/*================*/
602
 
                                /* out: log data end or NULL */
603
 
        byte*           ptr,    /* in: buffer */
604
 
        byte*           end_ptr,/* in: buffer end */
605
 
        mem_heap_t*     heap,   /* in: memory heap where update vector is
606
 
                                built */
607
 
        upd_t**         update_out)/* out: update vector */
608
 
{
609
 
        upd_t*          update;
610
 
        upd_field_t*    upd_field;
611
 
        dfield_t*       new_val;
612
 
        ulint           len;
613
 
        ulint           n_fields;
614
 
        byte*           buf;
615
 
        ulint           info_bits;
616
 
        ulint           i;
617
 
 
618
 
        if (end_ptr < ptr + 1) {
619
 
 
620
 
                return(NULL);
621
 
        }
622
 
 
623
 
        info_bits = mach_read_from_1(ptr);
624
 
        ptr++;
625
 
        ptr = mach_parse_compressed(ptr, end_ptr, &n_fields);
626
 
 
627
 
        if (ptr == NULL) {
628
 
 
629
 
                return(NULL);
630
 
        }
631
 
 
632
 
        update = upd_create(n_fields, heap);
633
 
        update->info_bits = info_bits;
634
 
 
635
 
        for (i = 0; i < n_fields; i++) {
636
 
                upd_field = upd_get_nth_field(update, i);
637
 
                new_val = &(upd_field->new_val);
638
 
 
639
 
                ptr = mach_parse_compressed(ptr, end_ptr,
640
 
                                            &(upd_field->field_no));
641
 
                if (ptr == NULL) {
642
 
 
643
 
                        return(NULL);
644
 
                }
645
 
 
646
 
                ptr = mach_parse_compressed(ptr, end_ptr, &len);
647
 
 
648
 
                if (ptr == NULL) {
649
 
 
650
 
                        return(NULL);
651
 
                }
652
 
 
653
 
                new_val->len = len;
654
 
 
655
 
                if (len != UNIV_SQL_NULL) {
656
 
 
657
 
                        if (end_ptr < ptr + len) {
658
 
 
659
 
                                return(NULL);
660
 
                        } else {
661
 
                                buf = mem_heap_alloc(heap, len);
662
 
                                ut_memcpy(buf, ptr, len);
663
 
 
664
 
                                ptr += len;
665
 
 
666
 
                                new_val->data = buf;
667
 
                        }
668
 
                }
669
 
        }
670
 
 
671
 
        *update_out = update;
672
 
 
673
 
        return(ptr);
674
 
}
675
 
 
676
 
/*******************************************************************
677
 
Returns TRUE if ext_vec contains i. */
678
 
static
679
 
ibool
680
 
upd_ext_vec_contains(
681
 
/*=================*/
682
 
                                /* out: TRUE if i is in ext_vec */
683
 
        ulint*  ext_vec,        /* in: array of indexes or NULL */
684
 
        ulint   n_ext_vec,      /* in: number of numbers in ext_vec */
685
 
        ulint   i)              /* in: a number */
686
 
{
687
 
        ulint   j;
688
 
 
689
 
        if (ext_vec == NULL) {
690
 
 
691
 
                return(FALSE);
692
 
        }
693
 
 
694
 
        for (j = 0; j < n_ext_vec; j++) {
695
 
                if (ext_vec[j] == i) {
696
 
 
697
 
                        return(TRUE);
698
 
                }
699
 
        }
700
 
 
701
 
        return(FALSE);
702
 
}
703
 
 
704
 
/*******************************************************************
705
 
Builds an update vector from those fields which in a secondary index entry
706
 
differ from a record that has the equal ordering fields. NOTE: we compare
707
 
the fields as binary strings! */
708
 
 
709
 
upd_t*
710
 
row_upd_build_sec_rec_difference_binary(
711
 
/*====================================*/
712
 
                                /* out, own: update vector of differing
713
 
                                fields */
714
 
        dict_index_t*   index,  /* in: index */
715
 
        dtuple_t*       entry,  /* in: entry to insert */
716
 
        rec_t*          rec,    /* in: secondary index record */
717
 
        trx_t*          trx,    /* in: transaction */
718
 
        mem_heap_t*     heap)   /* in: memory heap from which allocated */
719
 
{
720
 
        upd_field_t*    upd_field;
721
 
        dfield_t*       dfield;
722
 
        byte*           data;
723
 
        ulint           len;
724
 
        upd_t*          update;
725
 
        ulint           n_diff;
726
 
        ulint           i;
727
 
        ulint           offsets_[REC_OFFS_SMALL_SIZE];
728
 
        const ulint*    offsets;
729
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
730
 
 
731
 
        /* This function is used only for a secondary index */
732
 
        ut_a(0 == (index->type & DICT_CLUSTERED));
733
 
 
734
 
        update = upd_create(dtuple_get_n_fields(entry), heap);
735
 
 
736
 
        n_diff = 0;
737
 
        offsets = rec_get_offsets(rec, index, offsets_,
738
 
                                  ULINT_UNDEFINED, &heap);
739
 
 
740
 
        for (i = 0; i < dtuple_get_n_fields(entry); i++) {
741
 
 
742
 
                data = rec_get_nth_field(rec, offsets, i, &len);
743
 
 
744
 
                dfield = dtuple_get_nth_field(entry, i);
745
 
 
746
 
                /* NOTE that it may be that len != dfield_get_len(dfield) if we
747
 
                are updating in a character set and collation where strings of
748
 
                different length can be equal in an alphabetical comparison,
749
 
                and also in the case where we have a column prefix index
750
 
                and the last characters in the index field are spaces; the
751
 
                latter case probably caused the assertion failures reported at
752
 
                row0upd.c line 713 in versions 4.0.14 - 4.0.16. */
753
 
 
754
 
                /* NOTE: we compare the fields as binary strings!
755
 
                (No collation) */
756
 
 
757
 
                if (!dfield_data_is_binary_equal(dfield, len, data)) {
758
 
 
759
 
                        upd_field = upd_get_nth_field(update, n_diff);
760
 
 
761
 
                        dfield_copy(&(upd_field->new_val), dfield);
762
 
 
763
 
                        upd_field_set_field_no(upd_field, i, index, trx);
764
 
 
765
 
                        upd_field->extern_storage = FALSE;
766
 
 
767
 
                        n_diff++;
768
 
                }
769
 
        }
770
 
 
771
 
        update->n_fields = n_diff;
772
 
 
773
 
        return(update);
774
 
}
775
 
 
776
 
/*******************************************************************
777
 
Builds an update vector from those fields, excluding the roll ptr and
778
 
trx id fields, which in an index entry differ from a record that has
779
 
the equal ordering fields. NOTE: we compare the fields as binary strings! */
780
 
 
781
 
upd_t*
782
 
row_upd_build_difference_binary(
783
 
/*============================*/
784
 
                                /* out, own: update vector of differing
785
 
                                fields, excluding roll ptr and trx id */
786
 
        dict_index_t*   index,  /* in: clustered index */
787
 
        dtuple_t*       entry,  /* in: entry to insert */
788
 
        ulint*          ext_vec,/* in: array containing field numbers of
789
 
                                externally stored fields in entry, or NULL */
790
 
        ulint           n_ext_vec,/* in: number of fields in ext_vec */
791
 
        rec_t*          rec,    /* in: clustered index record */
792
 
        trx_t*          trx,    /* in: transaction */
793
 
        mem_heap_t*     heap)   /* in: memory heap from which allocated */
794
 
{
795
 
        upd_field_t*    upd_field;
796
 
        dfield_t*       dfield;
797
 
        byte*           data;
798
 
        ulint           len;
799
 
        upd_t*          update;
800
 
        ulint           n_diff;
801
 
        ulint           roll_ptr_pos;
802
 
        ulint           trx_id_pos;
803
 
        ibool           extern_bit;
804
 
        ulint           i;
805
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
806
 
        const ulint*    offsets;
807
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
808
 
 
809
 
        /* This function is used only for a clustered index */
810
 
        ut_a(index->type & DICT_CLUSTERED);
811
 
 
812
 
        update = upd_create(dtuple_get_n_fields(entry), heap);
813
 
 
814
 
        n_diff = 0;
815
 
 
816
 
        roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
817
 
        trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
818
 
 
819
 
        offsets = rec_get_offsets(rec, index, offsets_,
820
 
                                  ULINT_UNDEFINED, &heap);
821
 
 
822
 
        for (i = 0; i < dtuple_get_n_fields(entry); i++) {
823
 
 
824
 
                data = rec_get_nth_field(rec, offsets, i, &len);
825
 
 
826
 
                dfield = dtuple_get_nth_field(entry, i);
827
 
 
828
 
                /* NOTE: we compare the fields as binary strings!
829
 
                (No collation) */
830
 
 
831
 
                if (i == trx_id_pos || i == roll_ptr_pos) {
832
 
 
833
 
                        goto skip_compare;
834
 
                }
835
 
 
836
 
                extern_bit = upd_ext_vec_contains(ext_vec, n_ext_vec, i);
837
 
 
838
 
                if (UNIV_UNLIKELY(extern_bit
839
 
                                  == (ibool)!rec_offs_nth_extern(offsets, i))
840
 
                    || !dfield_data_is_binary_equal(dfield, len, data)) {
841
 
 
842
 
                        upd_field = upd_get_nth_field(update, n_diff);
843
 
 
844
 
                        dfield_copy(&(upd_field->new_val), dfield);
845
 
 
846
 
                        upd_field_set_field_no(upd_field, i, index, trx);
847
 
 
848
 
                        upd_field->extern_storage = extern_bit;
849
 
 
850
 
                        n_diff++;
851
 
                }
852
 
skip_compare:
853
 
                ;
854
 
        }
855
 
 
856
 
        update->n_fields = n_diff;
857
 
 
858
 
        return(update);
859
 
}
860
 
 
861
 
/***************************************************************
862
 
Replaces the new column values stored in the update vector to the index entry
863
 
given. */
864
 
 
865
 
void
866
 
row_upd_index_replace_new_col_vals_index_pos(
867
 
/*=========================================*/
868
 
        dtuple_t*       entry,  /* in/out: index entry where replaced */
869
 
        dict_index_t*   index,  /* in: index; NOTE that this may also be a
870
 
                                non-clustered index */
871
 
        upd_t*          update, /* in: an update vector built for the index so
872
 
                                that the field number in an upd_field is the
873
 
                                index position */
874
 
        ibool           order_only,
875
 
                                /* in: if TRUE, limit the replacement to
876
 
                                ordering fields of index; note that this
877
 
                                does not work for non-clustered indexes. */
878
 
        mem_heap_t*     heap)   /* in: memory heap to which we allocate and
879
 
                                copy the new values, set this as NULL if you
880
 
                                do not want allocation */
881
 
{
882
 
        dict_field_t*   field;
883
 
        upd_field_t*    upd_field;
884
 
        dfield_t*       dfield;
885
 
        dfield_t*       new_val;
886
 
        ulint           j;
887
 
        ulint           i;
888
 
        ulint           n_fields;
889
 
 
890
 
        ut_ad(index);
891
 
 
892
 
        dtuple_set_info_bits(entry, update->info_bits);
893
 
 
894
 
        if (order_only) {
895
 
                n_fields = dict_index_get_n_unique(index);
896
 
        } else {
897
 
                n_fields = dict_index_get_n_fields(index);
898
 
        }
899
 
 
900
 
        for (j = 0; j < n_fields; j++) {
901
 
 
902
 
                field = dict_index_get_nth_field(index, j);
903
 
 
904
 
                for (i = 0; i < upd_get_n_fields(update); i++) {
905
 
 
906
 
                        upd_field = upd_get_nth_field(update, i);
907
 
 
908
 
                        if (upd_field->field_no == j) {
909
 
 
910
 
                                dfield = dtuple_get_nth_field(entry, j);
911
 
 
912
 
                                new_val = &(upd_field->new_val);
913
 
 
914
 
                                dfield_set_data(dfield, new_val->data,
915
 
                                                new_val->len);
916
 
                                if (heap && new_val->len != UNIV_SQL_NULL) {
917
 
                                        dfield->data = mem_heap_alloc(
918
 
                                                heap, new_val->len);
919
 
                                        ut_memcpy(dfield->data, new_val->data,
920
 
                                                  new_val->len);
921
 
                                }
922
 
 
923
 
                                if (field->prefix_len > 0
924
 
                                    && new_val->len != UNIV_SQL_NULL) {
925
 
 
926
 
                                        const dict_col_t*       col
927
 
                                                = dict_field_get_col(field);
928
 
 
929
 
                                        dfield->len
930
 
                                                = dtype_get_at_most_n_mbchars(
931
 
                                                        col->prtype,
932
 
                                                        col->mbminlen,
933
 
                                                        col->mbmaxlen,
934
 
                                                        field->prefix_len,
935
 
                                                        new_val->len,
936
 
                                                        new_val->data);
937
 
                                }
938
 
                        }
939
 
                }
940
 
        }
941
 
}
942
 
 
943
 
/***************************************************************
944
 
Replaces the new column values stored in the update vector to the index entry
945
 
given. */
946
 
 
947
 
void
948
 
row_upd_index_replace_new_col_vals(
949
 
/*===============================*/
950
 
        dtuple_t*       entry,  /* in/out: index entry where replaced */
951
 
        dict_index_t*   index,  /* in: index; NOTE that this may also be a
952
 
                                non-clustered index */
953
 
        upd_t*          update, /* in: an update vector built for the
954
 
                                CLUSTERED index so that the field number in
955
 
                                an upd_field is the clustered index position */
956
 
        mem_heap_t*     heap)   /* in: memory heap to which we allocate and
957
 
                                copy the new values, set this as NULL if you
958
 
                                do not want allocation */
959
 
{
960
 
        upd_field_t*    upd_field;
961
 
        dfield_t*       dfield;
962
 
        dfield_t*       new_val;
963
 
        ulint           j;
964
 
        ulint           i;
965
 
        dict_index_t*   clust_index;
966
 
 
967
 
        ut_ad(index);
968
 
 
969
 
        clust_index = dict_table_get_first_index(index->table);
970
 
 
971
 
        dtuple_set_info_bits(entry, update->info_bits);
972
 
 
973
 
        for (j = 0; j < dict_index_get_n_fields(index); j++) {
974
 
 
975
 
                ulint           clust_pos;
976
 
                dict_field_t*   field = dict_index_get_nth_field(index, j);
977
 
 
978
 
                clust_pos = dict_col_get_clust_pos(field->col, clust_index);
979
 
 
980
 
                for (i = 0; i < upd_get_n_fields(update); i++) {
981
 
 
982
 
                        upd_field = upd_get_nth_field(update, i);
983
 
 
984
 
                        if (upd_field->field_no == clust_pos) {
985
 
 
986
 
                                dfield = dtuple_get_nth_field(entry, j);
987
 
 
988
 
                                new_val = &(upd_field->new_val);
989
 
 
990
 
                                dfield_set_data(dfield, new_val->data,
991
 
                                                new_val->len);
992
 
                                if (heap && new_val->len != UNIV_SQL_NULL) {
993
 
                                        dfield->data = mem_heap_alloc(
994
 
                                                heap, new_val->len);
995
 
                                        ut_memcpy(dfield->data, new_val->data,
996
 
                                                  new_val->len);
997
 
                                }
998
 
 
999
 
                                if (field->prefix_len > 0
1000
 
                                    && new_val->len != UNIV_SQL_NULL) {
1001
 
 
1002
 
                                        const dict_col_t*       col
1003
 
                                                = dict_field_get_col(field);
1004
 
 
1005
 
                                        dfield->len
1006
 
                                                = dtype_get_at_most_n_mbchars(
1007
 
                                                        col->prtype,
1008
 
                                                        col->mbminlen,
1009
 
                                                        col->mbmaxlen,
1010
 
                                                        field->prefix_len,
1011
 
                                                        new_val->len,
1012
 
                                                        new_val->data);
1013
 
                                }
1014
 
                        }
1015
 
                }
1016
 
        }
1017
 
}
1018
 
 
1019
 
/***************************************************************
1020
 
Checks if an update vector changes an ordering field of an index record.
1021
 
This function is fast if the update vector is short or the number of ordering
1022
 
fields in the index is small. Otherwise, this can be quadratic.
1023
 
NOTE: we compare the fields as binary strings! */
1024
 
 
1025
 
ibool
1026
 
row_upd_changes_ord_field_binary(
1027
 
/*=============================*/
1028
 
                                /* out: TRUE if update vector changes
1029
 
                                an ordering field in the index record;
1030
 
                                NOTE: the fields are compared as binary
1031
 
                                strings */
1032
 
        dtuple_t*       row,    /* in: old value of row, or NULL if the
1033
 
                                row and the data values in update are not
1034
 
                                known when this function is called, e.g., at
1035
 
                                compile time */
1036
 
        dict_index_t*   index,  /* in: index of the record */
1037
 
        upd_t*          update) /* in: update vector for the row; NOTE: the
1038
 
                                field numbers in this MUST be clustered index
1039
 
                                positions! */
1040
 
{
1041
 
        ulint           n_unique;
1042
 
        ulint           n_upd_fields;
1043
 
        ulint           i, j;
1044
 
        dict_index_t*   clust_index;
1045
 
 
1046
 
        ut_ad(update && index);
1047
 
 
1048
 
        n_unique = dict_index_get_n_unique(index);
1049
 
        n_upd_fields = upd_get_n_fields(update);
1050
 
 
1051
 
        clust_index = dict_table_get_first_index(index->table);
1052
 
 
1053
 
        for (i = 0; i < n_unique; i++) {
1054
 
 
1055
 
                const dict_field_t*     ind_field;
1056
 
                const dict_col_t*       col;
1057
 
                ulint                   col_pos;
1058
 
                ulint                   col_no;
1059
 
 
1060
 
                ind_field = dict_index_get_nth_field(index, i);
1061
 
                col = dict_field_get_col(ind_field);
1062
 
                col_pos = dict_col_get_clust_pos(col, clust_index);
1063
 
                col_no = dict_col_get_no(col);
1064
 
 
1065
 
                for (j = 0; j < n_upd_fields; j++) {
1066
 
 
1067
 
                        upd_field_t*    upd_field
1068
 
                                = upd_get_nth_field(update, j);
1069
 
 
1070
 
                        /* Note that if the index field is a column prefix
1071
 
                        then it may be that row does not contain an externally
1072
 
                        stored part of the column value, and we cannot compare
1073
 
                        the datas */
1074
 
 
1075
 
                        if (col_pos == upd_field->field_no
1076
 
                            && (row == NULL
1077
 
                                || ind_field->prefix_len > 0
1078
 
                                || !dfield_datas_are_binary_equal(
1079
 
                                        dtuple_get_nth_field(row, col_no),
1080
 
                                        &(upd_field->new_val)))) {
1081
 
 
1082
 
                                return(TRUE);
1083
 
                        }
1084
 
                }
1085
 
        }
1086
 
 
1087
 
        return(FALSE);
1088
 
}
1089
 
 
1090
 
/***************************************************************
1091
 
Checks if an update vector changes an ordering field of an index record.
1092
 
NOTE: we compare the fields as binary strings! */
1093
 
 
1094
 
ibool
1095
 
row_upd_changes_some_index_ord_field_binary(
1096
 
/*========================================*/
1097
 
                                /* out: TRUE if update vector may change
1098
 
                                an ordering field in an index record */
1099
 
        dict_table_t*   table,  /* in: table */
1100
 
        upd_t*          update) /* in: update vector for the row */
1101
 
{
1102
 
        upd_field_t*    upd_field;
1103
 
        dict_index_t*   index;
1104
 
        ulint           i;
1105
 
 
1106
 
        index = dict_table_get_first_index(table);
1107
 
 
1108
 
        for (i = 0; i < upd_get_n_fields(update); i++) {
1109
 
 
1110
 
                upd_field = upd_get_nth_field(update, i);
1111
 
 
1112
 
                if (dict_field_get_col(dict_index_get_nth_field(
1113
 
                                               index, upd_field->field_no))
1114
 
                    ->ord_part) {
1115
 
 
1116
 
                        return(TRUE);
1117
 
                }
1118
 
        }
1119
 
 
1120
 
        return(FALSE);
1121
 
}
1122
 
 
1123
 
/***************************************************************
1124
 
Checks if an update vector changes some of the first ordering fields of an
1125
 
index record. This is only used in foreign key checks and we can assume
1126
 
that index does not contain column prefixes. */
1127
 
static
1128
 
ibool
1129
 
row_upd_changes_first_fields_binary(
1130
 
/*================================*/
1131
 
                                /* out: TRUE if changes */
1132
 
        dtuple_t*       entry,  /* in: index entry */
1133
 
        dict_index_t*   index,  /* in: index of entry */
1134
 
        upd_t*          update, /* in: update vector for the row */
1135
 
        ulint           n)      /* in: how many first fields to check */
1136
 
{
1137
 
        ulint           n_upd_fields;
1138
 
        ulint           i, j;
1139
 
        dict_index_t*   clust_index;
1140
 
 
1141
 
        ut_ad(update && index);
1142
 
        ut_ad(n <= dict_index_get_n_fields(index));
1143
 
 
1144
 
        n_upd_fields = upd_get_n_fields(update);
1145
 
        clust_index = dict_table_get_first_index(index->table);
1146
 
 
1147
 
        for (i = 0; i < n; i++) {
1148
 
 
1149
 
                const dict_field_t*     ind_field;
1150
 
                const dict_col_t*       col;
1151
 
                ulint                   col_pos;
1152
 
 
1153
 
                ind_field = dict_index_get_nth_field(index, i);
1154
 
                col = dict_field_get_col(ind_field);
1155
 
                col_pos = dict_col_get_clust_pos(col, clust_index);
1156
 
 
1157
 
                ut_a(ind_field->prefix_len == 0);
1158
 
 
1159
 
                for (j = 0; j < n_upd_fields; j++) {
1160
 
 
1161
 
                        upd_field_t*    upd_field
1162
 
                                = upd_get_nth_field(update, j);
1163
 
 
1164
 
                        if (col_pos == upd_field->field_no
1165
 
                            && !dfield_datas_are_binary_equal(
1166
 
                                    dtuple_get_nth_field(entry, i),
1167
 
                                    &(upd_field->new_val))) {
1168
 
 
1169
 
                                return(TRUE);
1170
 
                        }
1171
 
                }
1172
 
        }
1173
 
 
1174
 
        return(FALSE);
1175
 
}
1176
 
 
1177
 
/*************************************************************************
1178
 
Copies the column values from a record. */
1179
 
UNIV_INLINE
1180
 
void
1181
 
row_upd_copy_columns(
1182
 
/*=================*/
1183
 
        rec_t*          rec,    /* in: record in a clustered index */
1184
 
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
1185
 
        sym_node_t*     column) /* in: first column in a column list, or
1186
 
                                NULL */
1187
 
{
1188
 
        byte*   data;
1189
 
        ulint   len;
1190
 
 
1191
 
        while (column) {
1192
 
                data = rec_get_nth_field(rec, offsets,
1193
 
                                         column->field_nos[SYM_CLUST_FIELD_NO],
1194
 
                                         &len);
1195
 
                eval_node_copy_and_alloc_val(column, data, len);
1196
 
 
1197
 
                column = UT_LIST_GET_NEXT(col_var_list, column);
1198
 
        }
1199
 
}
1200
 
 
1201
 
/*************************************************************************
1202
 
Calculates the new values for fields to update. Note that row_upd_copy_columns
1203
 
must have been called first. */
1204
 
UNIV_INLINE
1205
 
void
1206
 
row_upd_eval_new_vals(
1207
 
/*==================*/
1208
 
        upd_t*  update) /* in: update vector */
1209
 
{
1210
 
        que_node_t*     exp;
1211
 
        upd_field_t*    upd_field;
1212
 
        ulint           n_fields;
1213
 
        ulint           i;
1214
 
 
1215
 
        n_fields = upd_get_n_fields(update);
1216
 
 
1217
 
        for (i = 0; i < n_fields; i++) {
1218
 
                upd_field = upd_get_nth_field(update, i);
1219
 
 
1220
 
                exp = upd_field->exp;
1221
 
 
1222
 
                eval_exp(exp);
1223
 
 
1224
 
                dfield_copy_data(&(upd_field->new_val), que_node_get_val(exp));
1225
 
        }
1226
 
}
1227
 
 
1228
 
/***************************************************************
1229
 
Stores to the heap the row on which the node->pcur is positioned. */
1230
 
static
1231
 
void
1232
 
row_upd_store_row(
1233
 
/*==============*/
1234
 
        upd_node_t*     node)   /* in: row update node */
1235
 
{
1236
 
        dict_index_t*   clust_index;
1237
 
        upd_t*          update;
1238
 
        rec_t*          rec;
1239
 
        mem_heap_t*     heap            = NULL;
1240
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1241
 
        const ulint*    offsets;
1242
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1243
 
 
1244
 
        ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
1245
 
 
1246
 
        if (node->row != NULL) {
1247
 
                mem_heap_empty(node->heap);
1248
 
                node->row = NULL;
1249
 
        }
1250
 
 
1251
 
        clust_index = dict_table_get_first_index(node->table);
1252
 
 
1253
 
        rec = btr_pcur_get_rec(node->pcur);
1254
 
 
1255
 
        offsets = rec_get_offsets(rec, clust_index, offsets_,
1256
 
                                  ULINT_UNDEFINED, &heap);
1257
 
        node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1258
 
                              node->heap);
1259
 
        node->ext_vec = mem_heap_alloc(node->heap, sizeof(ulint)
1260
 
                                       * rec_offs_n_fields(offsets));
1261
 
        if (node->is_delete) {
1262
 
                update = NULL;
1263
 
        } else {
1264
 
                update = node->update;
1265
 
        }
1266
 
 
1267
 
        node->n_ext_vec = btr_push_update_extern_fields(node->ext_vec,
1268
 
                                                        offsets, update);
1269
 
        if (UNIV_LIKELY_NULL(heap)) {
1270
 
                mem_heap_free(heap);
1271
 
        }
1272
 
}
1273
 
 
1274
 
/***************************************************************
1275
 
Updates a secondary index entry of a row. */
1276
 
static
1277
 
ulint
1278
 
row_upd_sec_index_entry(
1279
 
/*====================*/
1280
 
                                /* out: DB_SUCCESS if operation successfully
1281
 
                                completed, else error code or DB_LOCK_WAIT */
1282
 
        upd_node_t*     node,   /* in: row update node */
1283
 
        que_thr_t*      thr)    /* in: query thread */
1284
 
{
1285
 
        ibool           check_ref;
1286
 
        ibool           found;
1287
 
        dict_index_t*   index;
1288
 
        dtuple_t*       entry;
1289
 
        btr_pcur_t      pcur;
1290
 
        btr_cur_t*      btr_cur;
1291
 
        mem_heap_t*     heap;
1292
 
        rec_t*          rec;
1293
 
        ulint           err     = DB_SUCCESS;
1294
 
        mtr_t           mtr;
1295
 
        trx_t*          trx     = thr_get_trx(thr);
1296
 
 
1297
 
        index = node->index;
1298
 
 
1299
 
        check_ref = row_upd_index_is_referenced(index, trx);
1300
 
 
1301
 
        heap = mem_heap_create(1024);
1302
 
 
1303
 
        /* Build old index entry */
1304
 
        entry = row_build_index_entry(node->row, index, heap);
1305
 
 
1306
 
        log_free_check();
1307
 
        mtr_start(&mtr);
1308
 
 
1309
 
        found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
1310
 
                                       &mtr);
1311
 
        btr_cur = btr_pcur_get_btr_cur(&pcur);
1312
 
 
1313
 
        rec = btr_cur_get_rec(btr_cur);
1314
 
 
1315
 
        if (UNIV_UNLIKELY(!found)) {
1316
 
                fputs("InnoDB: error in sec index entry update in\n"
1317
 
                      "InnoDB: ", stderr);
1318
 
                dict_index_name_print(stderr, trx, index);
1319
 
                fputs("\n"
1320
 
                      "InnoDB: tuple ", stderr);
1321
 
                dtuple_print(stderr, entry);
1322
 
                fputs("\n"
1323
 
                      "InnoDB: record ", stderr);
1324
 
                rec_print(stderr, rec, index);
1325
 
                putc('\n', stderr);
1326
 
 
1327
 
                trx_print(stderr, trx, 0);
1328
 
 
1329
 
                fputs("\n"
1330
 
                      "InnoDB: Submit a detailed bug report"
1331
 
                      " to http://bugs.mysql.com\n", stderr);
1332
 
        } else {
1333
 
                /* Delete mark the old index record; it can already be
1334
 
                delete marked if we return after a lock wait in
1335
 
                row_ins_index_entry below */
1336
 
 
1337
 
                if (!rec_get_deleted_flag(rec,
1338
 
                                          dict_table_is_comp(index->table))) {
1339
 
                        err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
1340
 
                                                           thr, &mtr);
1341
 
                        if (err == DB_SUCCESS && check_ref) {
1342
 
 
1343
 
                                /* NOTE that the following call loses
1344
 
                                the position of pcur ! */
1345
 
                                err = row_upd_check_references_constraints(
1346
 
                                        node, &pcur, index->table,
1347
 
                                        index, thr, &mtr);
1348
 
                                if (err != DB_SUCCESS) {
1349
 
 
1350
 
                                        goto close_cur;
1351
 
                                }
1352
 
                        }
1353
 
 
1354
 
                }
1355
 
        }
1356
 
close_cur:
1357
 
        btr_pcur_close(&pcur);
1358
 
        mtr_commit(&mtr);
1359
 
 
1360
 
        if (node->is_delete || err != DB_SUCCESS) {
1361
 
 
1362
 
                mem_heap_free(heap);
1363
 
 
1364
 
                return(err);
1365
 
        }
1366
 
 
1367
 
        /* Build a new index entry */
1368
 
        row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
1369
 
 
1370
 
        /* Insert new index entry */
1371
 
        err = row_ins_index_entry(index, entry, NULL, 0, thr);
1372
 
 
1373
 
        mem_heap_free(heap);
1374
 
 
1375
 
        return(err);
1376
 
}
1377
 
 
1378
 
/***************************************************************
1379
 
Updates the secondary index record if it is changed in the row update or
1380
 
deletes it if this is a delete. */
1381
 
UNIV_INLINE
1382
 
ulint
1383
 
row_upd_sec_step(
1384
 
/*=============*/
1385
 
                                /* out: DB_SUCCESS if operation successfully
1386
 
                                completed, else error code or DB_LOCK_WAIT */
1387
 
        upd_node_t*     node,   /* in: row update node */
1388
 
        que_thr_t*      thr)    /* in: query thread */
1389
 
{
1390
 
        ulint   err;
1391
 
 
1392
 
        ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1393
 
              || (node->state == UPD_NODE_UPDATE_SOME_SEC));
1394
 
        ut_ad(!(node->index->type & DICT_CLUSTERED));
1395
 
 
1396
 
        if (node->state == UPD_NODE_UPDATE_ALL_SEC
1397
 
            || row_upd_changes_ord_field_binary(node->row, node->index,
1398
 
                                                node->update)) {
1399
 
                err = row_upd_sec_index_entry(node, thr);
1400
 
 
1401
 
                return(err);
1402
 
        }
1403
 
 
1404
 
        return(DB_SUCCESS);
1405
 
}
1406
 
 
1407
 
/***************************************************************
1408
 
Marks the clustered index record deleted and inserts the updated version
1409
 
of the record to the index. This function should be used when the ordering
1410
 
fields of the clustered index record change. This should be quite rare in
1411
 
database applications. */
1412
 
static
1413
 
ulint
1414
 
row_upd_clust_rec_by_insert(
1415
 
/*========================*/
1416
 
                                /* out: DB_SUCCESS if operation successfully
1417
 
                                completed, else error code or DB_LOCK_WAIT */
1418
 
        upd_node_t*     node,   /* in: row update node */
1419
 
        dict_index_t*   index,  /* in: clustered index of the record */
1420
 
        que_thr_t*      thr,    /* in: query thread */
1421
 
        ibool           check_ref,/* in: TRUE if index may be referenced in
1422
 
                                a foreign key constraint */
1423
 
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1424
 
{
1425
 
        mem_heap_t*     heap    = NULL;
1426
 
        btr_pcur_t*     pcur;
1427
 
        btr_cur_t*      btr_cur;
1428
 
        trx_t*          trx;
1429
 
        dict_table_t*   table;
1430
 
        dtuple_t*       entry;
1431
 
        ulint           err;
1432
 
 
1433
 
        ut_ad(node);
1434
 
        ut_ad(index->type & DICT_CLUSTERED);
1435
 
 
1436
 
        trx = thr_get_trx(thr);
1437
 
        table = node->table;
1438
 
        pcur = node->pcur;
1439
 
        btr_cur = btr_pcur_get_btr_cur(pcur);
1440
 
 
1441
 
        if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1442
 
                ulint   offsets_[REC_OFFS_NORMAL_SIZE];
1443
 
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1444
 
 
1445
 
                err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1446
 
                                                     btr_cur, TRUE, thr, mtr);
1447
 
                if (err != DB_SUCCESS) {
1448
 
                        mtr_commit(mtr);
1449
 
                        return(err);
1450
 
                }
1451
 
 
1452
 
                /* Mark as not-owned the externally stored fields which the new
1453
 
                row inherits from the delete marked record: purge should not
1454
 
                free those externally stored fields even if the delete marked
1455
 
                record is removed from the index tree, or updated. */
1456
 
 
1457
 
                btr_cur_mark_extern_inherited_fields(
1458
 
                        btr_cur_get_rec(btr_cur),
1459
 
                        rec_get_offsets(btr_cur_get_rec(btr_cur),
1460
 
                                        dict_table_get_first_index(table),
1461
 
                                        offsets_, ULINT_UNDEFINED, &heap),
1462
 
                        node->update, mtr);
1463
 
                if (check_ref) {
1464
 
                        /* NOTE that the following call loses
1465
 
                        the position of pcur ! */
1466
 
                        err = row_upd_check_references_constraints(
1467
 
                                node, pcur, table, index, thr, mtr);
1468
 
                        if (err != DB_SUCCESS) {
1469
 
                                mtr_commit(mtr);
1470
 
                                if (UNIV_LIKELY_NULL(heap)) {
1471
 
                                        mem_heap_free(heap);
1472
 
                                }
1473
 
                                return(err);
1474
 
                        }
1475
 
                }
1476
 
 
1477
 
        }
1478
 
 
1479
 
        mtr_commit(mtr);
1480
 
 
1481
 
        if (!heap) {
1482
 
                heap = mem_heap_create(500);
1483
 
        }
1484
 
        node->state = UPD_NODE_INSERT_CLUSTERED;
1485
 
 
1486
 
        entry = row_build_index_entry(node->row, index, heap);
1487
 
 
1488
 
        row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
1489
 
 
1490
 
        row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1491
 
 
1492
 
        /* If we return from a lock wait, for example, we may have
1493
 
        extern fields marked as not-owned in entry (marked in the
1494
 
        if-branch above). We must unmark them. */
1495
 
 
1496
 
        btr_cur_unmark_dtuple_extern_fields(entry, node->ext_vec,
1497
 
                                            node->n_ext_vec);
1498
 
        /* We must mark non-updated extern fields in entry as inherited,
1499
 
        so that a possible rollback will not free them */
1500
 
 
1501
 
        btr_cur_mark_dtuple_inherited_extern(entry, node->ext_vec,
1502
 
                                             node->n_ext_vec,
1503
 
                                             node->update);
1504
 
 
1505
 
        err = row_ins_index_entry(index, entry, node->ext_vec,
1506
 
                                  node->n_ext_vec, thr);
1507
 
        mem_heap_free(heap);
1508
 
 
1509
 
        return(err);
1510
 
}
1511
 
 
1512
 
/***************************************************************
1513
 
Updates a clustered index record of a row when the ordering fields do
1514
 
not change. */
1515
 
static
1516
 
ulint
1517
 
row_upd_clust_rec(
1518
 
/*==============*/
1519
 
                                /* out: DB_SUCCESS if operation successfully
1520
 
                                completed, else error code or DB_LOCK_WAIT */
1521
 
        upd_node_t*     node,   /* in: row update node */
1522
 
        dict_index_t*   index,  /* in: clustered index */
1523
 
        que_thr_t*      thr,    /* in: query thread */
1524
 
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1525
 
{
1526
 
        big_rec_t*      big_rec = NULL;
1527
 
        btr_pcur_t*     pcur;
1528
 
        btr_cur_t*      btr_cur;
1529
 
        ulint           err;
1530
 
 
1531
 
        ut_ad(node);
1532
 
        ut_ad(index->type & DICT_CLUSTERED);
1533
 
 
1534
 
        pcur = node->pcur;
1535
 
        btr_cur = btr_pcur_get_btr_cur(pcur);
1536
 
 
1537
 
        ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1538
 
                                    dict_table_is_comp(index->table)));
1539
 
 
1540
 
        /* Try optimistic updating of the record, keeping changes within
1541
 
        the page; we do not check locks because we assume the x-lock on the
1542
 
        record to update */
1543
 
 
1544
 
        if (node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE) {
1545
 
                err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG,
1546
 
                                              btr_cur, node->update,
1547
 
                                              node->cmpl_info, thr, mtr);
1548
 
        } else {
1549
 
                err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG,
1550
 
                                                btr_cur, node->update,
1551
 
                                                node->cmpl_info, thr, mtr);
1552
 
        }
1553
 
 
1554
 
        mtr_commit(mtr);
1555
 
 
1556
 
        if (err == DB_SUCCESS) {
1557
 
 
1558
 
                return(err);
1559
 
        }
1560
 
 
1561
 
        if (buf_LRU_buf_pool_running_out()) {
1562
 
 
1563
 
                return(DB_LOCK_TABLE_FULL);
1564
 
        }
1565
 
        /* We may have to modify the tree structure: do a pessimistic descent
1566
 
        down the index tree */
1567
 
 
1568
 
        mtr_start(mtr);
1569
 
 
1570
 
        /* NOTE: this transaction has an s-lock or x-lock on the record and
1571
 
        therefore other transactions cannot modify the record when we have no
1572
 
        latch on the page. In addition, we assume that other query threads of
1573
 
        the same transaction do not modify the record in the meantime.
1574
 
        Therefore we can assert that the restoration of the cursor succeeds. */
1575
 
 
1576
 
        ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1577
 
 
1578
 
        ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
1579
 
                                    dict_table_is_comp(index->table)));
1580
 
 
1581
 
        err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
1582
 
                                         &big_rec, node->update,
1583
 
                                         node->cmpl_info, thr, mtr);
1584
 
        mtr_commit(mtr);
1585
 
 
1586
 
        if (err == DB_SUCCESS && big_rec) {
1587
 
                mem_heap_t*     heap            = NULL;
1588
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1589
 
                rec_t*          rec;
1590
 
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1591
 
 
1592
 
                mtr_start(mtr);
1593
 
 
1594
 
                ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
1595
 
                rec = btr_cur_get_rec(btr_cur);
1596
 
                err = btr_store_big_rec_extern_fields(
1597
 
                        index, rec,
1598
 
                        rec_get_offsets(rec, index, offsets_,
1599
 
                                        ULINT_UNDEFINED, &heap),
1600
 
                         big_rec, mtr);
1601
 
                if (UNIV_LIKELY_NULL(heap)) {
1602
 
                        mem_heap_free(heap);
1603
 
                }
1604
 
                mtr_commit(mtr);
1605
 
        }
1606
 
 
1607
 
        if (big_rec) {
1608
 
                dtuple_big_rec_free(big_rec);
1609
 
        }
1610
 
 
1611
 
        return(err);
1612
 
}
1613
 
 
1614
 
/***************************************************************
1615
 
Delete marks a clustered index record. */
1616
 
static
1617
 
ulint
1618
 
row_upd_del_mark_clust_rec(
1619
 
/*=======================*/
1620
 
                                /* out: DB_SUCCESS if operation successfully
1621
 
                                completed, else error code */
1622
 
        upd_node_t*     node,   /* in: row update node */
1623
 
        dict_index_t*   index,  /* in: clustered index */
1624
 
        que_thr_t*      thr,    /* in: query thread */
1625
 
        ibool           check_ref,/* in: TRUE if index may be referenced in
1626
 
                                a foreign key constraint */
1627
 
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1628
 
{
1629
 
        btr_pcur_t*     pcur;
1630
 
        btr_cur_t*      btr_cur;
1631
 
        ulint           err;
1632
 
 
1633
 
        ut_ad(node);
1634
 
        ut_ad(index->type & DICT_CLUSTERED);
1635
 
        ut_ad(node->is_delete);
1636
 
 
1637
 
        pcur = node->pcur;
1638
 
        btr_cur = btr_pcur_get_btr_cur(pcur);
1639
 
 
1640
 
        /* Store row because we have to build also the secondary index
1641
 
        entries */
1642
 
 
1643
 
        row_upd_store_row(node);
1644
 
 
1645
 
        /* Mark the clustered index record deleted; we do not have to check
1646
 
        locks, because we assume that we have an x-lock on the record */
1647
 
 
1648
 
        err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1649
 
                                             btr_cur, TRUE, thr, mtr);
1650
 
        if (err == DB_SUCCESS && check_ref) {
1651
 
                /* NOTE that the following call loses the position of pcur ! */
1652
 
 
1653
 
                err = row_upd_check_references_constraints(node,
1654
 
                                                           pcur, index->table,
1655
 
                                                           index, thr, mtr);
1656
 
                if (err != DB_SUCCESS) {
1657
 
                        mtr_commit(mtr);
1658
 
 
1659
 
                        return(err);
1660
 
                }
1661
 
        }
1662
 
 
1663
 
        mtr_commit(mtr);
1664
 
 
1665
 
        return(err);
1666
 
}
1667
 
 
1668
 
/***************************************************************
1669
 
Updates the clustered index record. */
1670
 
static
1671
 
ulint
1672
 
row_upd_clust_step(
1673
 
/*===============*/
1674
 
                                /* out: DB_SUCCESS if operation successfully
1675
 
                                completed, DB_LOCK_WAIT in case of a lock wait,
1676
 
                                else error code */
1677
 
        upd_node_t*     node,   /* in: row update node */
1678
 
        que_thr_t*      thr)    /* in: query thread */
1679
 
{
1680
 
        dict_index_t*   index;
1681
 
        btr_pcur_t*     pcur;
1682
 
        ibool           success;
1683
 
        ibool           check_ref;
1684
 
        ulint           err;
1685
 
        mtr_t*          mtr;
1686
 
        mtr_t           mtr_buf;
1687
 
        rec_t*          rec;
1688
 
        mem_heap_t*     heap            = NULL;
1689
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1690
 
        const ulint*    offsets;
1691
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1692
 
 
1693
 
        index = dict_table_get_first_index(node->table);
1694
 
 
1695
 
        check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
1696
 
 
1697
 
        pcur = node->pcur;
1698
 
 
1699
 
        /* We have to restore the cursor to its position */
1700
 
        mtr = &mtr_buf;
1701
 
 
1702
 
        mtr_start(mtr);
1703
 
 
1704
 
        /* If the restoration does not succeed, then the same
1705
 
        transaction has deleted the record on which the cursor was,
1706
 
        and that is an SQL error. If the restoration succeeds, it may
1707
 
        still be that the same transaction has successively deleted
1708
 
        and inserted a record with the same ordering fields, but in
1709
 
        that case we know that the transaction has at least an
1710
 
        implicit x-lock on the record. */
1711
 
 
1712
 
        ut_a(pcur->rel_pos == BTR_PCUR_ON);
1713
 
 
1714
 
        success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1715
 
 
1716
 
        if (!success) {
1717
 
                err = DB_RECORD_NOT_FOUND;
1718
 
 
1719
 
                mtr_commit(mtr);
1720
 
 
1721
 
                return(err);
1722
 
        }
1723
 
 
1724
 
        /* If this is a row in SYS_INDEXES table of the data dictionary,
1725
 
        then we have to free the file segments of the index tree associated
1726
 
        with the index */
1727
 
 
1728
 
        if (node->is_delete
1729
 
            && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1730
 
 
1731
 
                dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1732
 
 
1733
 
                mtr_commit(mtr);
1734
 
 
1735
 
                mtr_start(mtr);
1736
 
 
1737
 
                success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur,
1738
 
                                                    mtr);
1739
 
                if (!success) {
1740
 
                        err = DB_ERROR;
1741
 
 
1742
 
                        mtr_commit(mtr);
1743
 
 
1744
 
                        return(err);
1745
 
                }
1746
 
        }
1747
 
 
1748
 
        rec = btr_pcur_get_rec(pcur);
1749
 
        offsets = rec_get_offsets(rec, index, offsets_,
1750
 
                                  ULINT_UNDEFINED, &heap);
1751
 
 
1752
 
        if (!node->has_clust_rec_x_lock) {
1753
 
                err = lock_clust_rec_modify_check_and_lock(
1754
 
                        0, rec, index, offsets, thr);
1755
 
                if (err != DB_SUCCESS) {
1756
 
                        mtr_commit(mtr);
1757
 
                        goto exit_func;
1758
 
                }
1759
 
        }
1760
 
 
1761
 
        /* NOTE: the following function calls will also commit mtr */
1762
 
 
1763
 
        if (node->is_delete) {
1764
 
                err = row_upd_del_mark_clust_rec(node, index, thr, check_ref,
1765
 
                                                 mtr);
1766
 
                if (err == DB_SUCCESS) {
1767
 
                        node->state = UPD_NODE_UPDATE_ALL_SEC;
1768
 
                        node->index = dict_table_get_next_index(index);
1769
 
                }
1770
 
exit_func:
1771
 
                if (UNIV_LIKELY_NULL(heap)) {
1772
 
                        mem_heap_free(heap);
1773
 
                }
1774
 
                return(err);
1775
 
        }
1776
 
 
1777
 
        /* If the update is made for MySQL, we already have the update vector
1778
 
        ready, else we have to do some evaluation: */
1779
 
 
1780
 
        if (!node->in_mysql_interface) {
1781
 
                /* Copy the necessary columns from clust_rec and calculate the
1782
 
                new values to set */
1783
 
                row_upd_copy_columns(rec, offsets,
1784
 
                                     UT_LIST_GET_FIRST(node->columns));
1785
 
                row_upd_eval_new_vals(node->update);
1786
 
        }
1787
 
 
1788
 
        if (UNIV_LIKELY_NULL(heap)) {
1789
 
                mem_heap_free(heap);
1790
 
        }
1791
 
 
1792
 
        if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
1793
 
 
1794
 
                err = row_upd_clust_rec(node, index, thr, mtr);
1795
 
                return(err);
1796
 
        }
1797
 
 
1798
 
        row_upd_store_row(node);
1799
 
 
1800
 
        if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
1801
 
 
1802
 
                /* Update causes an ordering field (ordering fields within
1803
 
                the B-tree) of the clustered index record to change: perform
1804
 
                the update by delete marking and inserting.
1805
 
 
1806
 
                TODO! What to do to the 'Halloween problem', where an update
1807
 
                moves the record forward in index so that it is again
1808
 
                updated when the cursor arrives there? Solution: the
1809
 
                read operation must check the undo record undo number when
1810
 
                choosing records to update. MySQL solves now the problem
1811
 
                externally! */
1812
 
 
1813
 
                err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
1814
 
                                                  mtr);
1815
 
                if (err != DB_SUCCESS) {
1816
 
 
1817
 
                        return(err);
1818
 
                }
1819
 
 
1820
 
                node->state = UPD_NODE_UPDATE_ALL_SEC;
1821
 
        } else {
1822
 
                err = row_upd_clust_rec(node, index, thr, mtr);
1823
 
 
1824
 
                if (err != DB_SUCCESS) {
1825
 
 
1826
 
                        return(err);
1827
 
                }
1828
 
 
1829
 
                node->state = UPD_NODE_UPDATE_SOME_SEC;
1830
 
        }
1831
 
 
1832
 
        node->index = dict_table_get_next_index(index);
1833
 
 
1834
 
        return(err);
1835
 
}
1836
 
 
1837
 
/***************************************************************
1838
 
Updates the affected index records of a row. When the control is transferred
1839
 
to this node, we assume that we have a persistent cursor which was on a
1840
 
record, and the position of the cursor is stored in the cursor. */
1841
 
static
1842
 
ulint
1843
 
row_upd(
1844
 
/*====*/
1845
 
                                /* out: DB_SUCCESS if operation successfully
1846
 
                                completed, else error code or DB_LOCK_WAIT */
1847
 
        upd_node_t*     node,   /* in: row update node */
1848
 
        que_thr_t*      thr)    /* in: query thread */
1849
 
{
1850
 
        ulint   err     = DB_SUCCESS;
1851
 
 
1852
 
        ut_ad(node && thr);
1853
 
 
1854
 
        if (UNIV_LIKELY(node->in_mysql_interface)) {
1855
 
 
1856
 
                /* We do not get the cmpl_info value from the MySQL
1857
 
                interpreter: we must calculate it on the fly: */
1858
 
 
1859
 
                if (node->is_delete
1860
 
                    || row_upd_changes_some_index_ord_field_binary(
1861
 
                            node->table, node->update)) {
1862
 
                        node->cmpl_info = 0;
1863
 
                } else {
1864
 
                        node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
1865
 
                }
1866
 
        }
1867
 
 
1868
 
        if (node->state == UPD_NODE_UPDATE_CLUSTERED
1869
 
            || node->state == UPD_NODE_INSERT_CLUSTERED) {
1870
 
 
1871
 
                err = row_upd_clust_step(node, thr);
1872
 
 
1873
 
                if (err != DB_SUCCESS) {
1874
 
 
1875
 
                        goto function_exit;
1876
 
                }
1877
 
        }
1878
 
 
1879
 
        if (!node->is_delete && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1880
 
 
1881
 
                goto function_exit;
1882
 
        }
1883
 
 
1884
 
        while (node->index != NULL) {
1885
 
                err = row_upd_sec_step(node, thr);
1886
 
 
1887
 
                if (err != DB_SUCCESS) {
1888
 
 
1889
 
                        goto function_exit;
1890
 
                }
1891
 
 
1892
 
                node->index = dict_table_get_next_index(node->index);
1893
 
        }
1894
 
 
1895
 
function_exit:
1896
 
        if (err == DB_SUCCESS) {
1897
 
                /* Do some cleanup */
1898
 
 
1899
 
                if (node->row != NULL) {
1900
 
                        node->row = NULL;
1901
 
                        node->n_ext_vec = 0;
1902
 
                        mem_heap_empty(node->heap);
1903
 
                }
1904
 
 
1905
 
                node->state = UPD_NODE_UPDATE_CLUSTERED;
1906
 
        }
1907
 
 
1908
 
        return(err);
1909
 
}
1910
 
 
1911
 
/***************************************************************
1912
 
Updates a row in a table. This is a high-level function used in SQL execution
1913
 
graphs. */
1914
 
 
1915
 
que_thr_t*
1916
 
row_upd_step(
1917
 
/*=========*/
1918
 
                                /* out: query thread to run next or NULL */
1919
 
        que_thr_t*      thr)    /* in: query thread */
1920
 
{
1921
 
        upd_node_t*     node;
1922
 
        sel_node_t*     sel_node;
1923
 
        que_node_t*     parent;
1924
 
        ulint           err             = DB_SUCCESS;
1925
 
        trx_t*          trx;
1926
 
 
1927
 
        ut_ad(thr);
1928
 
 
1929
 
        trx = thr_get_trx(thr);
1930
 
 
1931
 
        trx_start_if_not_started(trx);
1932
 
 
1933
 
        node = thr->run_node;
1934
 
 
1935
 
        sel_node = node->select;
1936
 
 
1937
 
        parent = que_node_get_parent(node);
1938
 
 
1939
 
        ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
1940
 
 
1941
 
        if (thr->prev_node == parent) {
1942
 
                node->state = UPD_NODE_SET_IX_LOCK;
1943
 
        }
1944
 
 
1945
 
        if (node->state == UPD_NODE_SET_IX_LOCK) {
1946
 
 
1947
 
                if (!node->has_clust_rec_x_lock) {
1948
 
                        /* It may be that the current session has not yet
1949
 
                        started its transaction, or it has been committed: */
1950
 
 
1951
 
                        err = lock_table(0, node->table, LOCK_IX, thr);
1952
 
 
1953
 
                        if (err != DB_SUCCESS) {
1954
 
 
1955
 
                                goto error_handling;
1956
 
                        }
1957
 
                }
1958
 
 
1959
 
                node->state = UPD_NODE_UPDATE_CLUSTERED;
1960
 
 
1961
 
                if (node->searched_update) {
1962
 
                        /* Reset the cursor */
1963
 
                        sel_node->state = SEL_NODE_OPEN;
1964
 
 
1965
 
                        /* Fetch a row to update */
1966
 
 
1967
 
                        thr->run_node = sel_node;
1968
 
 
1969
 
                        return(thr);
1970
 
                }
1971
 
        }
1972
 
 
1973
 
        /* sel_node is NULL if we are in the MySQL interface */
1974
 
 
1975
 
        if (sel_node && (sel_node->state != SEL_NODE_FETCH)) {
1976
 
 
1977
 
                if (!node->searched_update) {
1978
 
                        /* An explicit cursor should be positioned on a row
1979
 
                        to update */
1980
 
 
1981
 
                        ut_error;
1982
 
 
1983
 
                        err = DB_ERROR;
1984
 
 
1985
 
                        goto error_handling;
1986
 
                }
1987
 
 
1988
 
                ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
1989
 
 
1990
 
                /* No more rows to update, or the select node performed the
1991
 
                updates directly in-place */
1992
 
 
1993
 
                thr->run_node = parent;
1994
 
 
1995
 
                return(thr);
1996
 
        }
1997
 
 
1998
 
        /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
1999
 
 
2000
 
        err = row_upd(node, thr);
2001
 
 
2002
 
error_handling:
2003
 
        trx->error_state = err;
2004
 
 
2005
 
        if (err != DB_SUCCESS) {
2006
 
                return(NULL);
2007
 
        }
2008
 
 
2009
 
        /* DO THE TRIGGER ACTIONS HERE */
2010
 
 
2011
 
        if (node->searched_update) {
2012
 
                /* Fetch next row to update */
2013
 
 
2014
 
                thr->run_node = sel_node;
2015
 
        } else {
2016
 
                /* It was an explicit cursor update */
2017
 
 
2018
 
                thr->run_node = parent;
2019
 
        }
2020
 
 
2021
 
        node->state = UPD_NODE_UPDATE_CLUSTERED;
2022
 
 
2023
 
        return(thr);
2024
 
}
2025
 
 
2026
 
/*************************************************************************
2027
 
Performs an in-place update for the current clustered index record in
2028
 
select. */
2029
 
 
2030
 
void
2031
 
row_upd_in_place_in_select(
2032
 
/*=======================*/
2033
 
        sel_node_t*     sel_node,       /* in: select node */
2034
 
        que_thr_t*      thr,            /* in: query thread */
2035
 
        mtr_t*          mtr)            /* in: mtr */
2036
 
{
2037
 
        upd_node_t*     node;
2038
 
        btr_pcur_t*     pcur;
2039
 
        btr_cur_t*      btr_cur;
2040
 
        ulint           err;
2041
 
        mem_heap_t*     heap            = NULL;
2042
 
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
2043
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
2044
 
 
2045
 
        ut_ad(sel_node->select_will_do_update);
2046
 
        ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF);
2047
 
        ut_ad(sel_node->asc);
2048
 
 
2049
 
        node = que_node_get_parent(sel_node);
2050
 
 
2051
 
        ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
2052
 
 
2053
 
        pcur = node->pcur;
2054
 
        btr_cur = btr_pcur_get_btr_cur(pcur);
2055
 
 
2056
 
        /* Copy the necessary columns from clust_rec and calculate the new
2057
 
        values to set */
2058
 
 
2059
 
        row_upd_copy_columns(btr_pcur_get_rec(pcur),
2060
 
                             rec_get_offsets(btr_pcur_get_rec(pcur),
2061
 
                                             btr_cur->index, offsets_,
2062
 
                                             ULINT_UNDEFINED, &heap),
2063
 
                             UT_LIST_GET_FIRST(node->columns));
2064
 
        if (UNIV_LIKELY_NULL(heap)) {
2065
 
                mem_heap_free(heap);
2066
 
        }
2067
 
        row_upd_eval_new_vals(node->update);
2068
 
 
2069
 
        ut_ad(!rec_get_deleted_flag(
2070
 
                      btr_pcur_get_rec(pcur),
2071
 
                      dict_table_is_comp(btr_cur->index->table)));
2072
 
 
2073
 
        ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE);
2074
 
        ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
2075
 
        ut_ad(node->select_will_do_update);
2076
 
 
2077
 
        err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG, btr_cur,
2078
 
                                      node->update, node->cmpl_info,
2079
 
                                      thr, mtr);
2080
 
        ut_ad(err == DB_SUCCESS);
2081
 
}