~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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
}