~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2009-01-24 09:43:35 UTC
  • Revision ID: brian@gir-3.local-20090124094335-6qdtvc35gl5fvivz
Adding in an example singe thread scheduler

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file row/row0upd.c
 
1
/******************************************************
21
2
Update of a row
22
3
 
 
4
(c) 1996 Innobase Oy
 
5
 
23
6
Created 12/27/1996 Heikki Tuuri
24
7
*******************************************************/
25
8
 
30
13
#endif
31
14
 
32
15
#include "dict0dict.h"
33
 
#include "trx0undo.h"
34
 
#include "rem0rec.h"
35
 
#ifndef UNIV_HOTBACKUP
36
16
#include "dict0boot.h"
37
17
#include "dict0crea.h"
38
18
#include "mach0data.h"
 
19
#include "trx0undo.h"
39
20
#include "btr0btr.h"
40
21
#include "btr0cur.h"
41
22
#include "que0que.h"
92
73
searched delete is obviously to keep the x-latch for several
93
74
steps of query graph execution. */
94
75
 
95
 
/*************************************************************************
96
 
IMPORTANT NOTE: Any operation that generates redo MUST check that there
97
 
is enough space in the redo log before for that operation. This is
98
 
done by calling log_free_check(). The reason for checking the
99
 
availability of the redo log space before the start of the operation is
100
 
that we MUST not hold any synchonization objects when performing the
101
 
check.
102
 
If you make a change in this module make sure that no codepath is
103
 
introduced where a call to log_free_check() is bypassed. */
104
 
 
105
 
/*************************************************************************
106
 
IMPORTANT NOTE: Any operation that generates redo MUST check that there
107
 
is enough space in the redo log before for that operation. This is
108
 
done by calling log_free_check(). The reason for checking the
109
 
availability of the redo log space before the start of the operation is
110
 
that we MUST not hold any synchonization objects when performing the
111
 
check.
112
 
If you make a change in this module make sure that no codepath is
113
 
introduced where a call to log_free_check() is bypassed. */
114
 
 
115
 
/***********************************************************//**
 
76
/***************************************************************
116
77
Checks if an update vector changes some of the first ordering fields of an
117
78
index record. This is only used in foreign key checks and we can assume
118
 
that index does not contain column prefixes.
119
 
@return TRUE if changes */
 
79
that index does not contain column prefixes. */
120
80
static
121
81
ibool
122
82
row_upd_changes_first_fields_binary(
123
83
/*================================*/
124
 
        dtuple_t*       entry,  /*!< in: old value of index entry */
125
 
        dict_index_t*   index,  /*!< in: index of entry */
126
 
        const upd_t*    update, /*!< in: update vector for the row */
127
 
        ulint           n);     /*!< in: how many first fields to check */
128
 
 
129
 
 
130
 
/*********************************************************************//**
 
84
                                /* out: TRUE if changes */
 
85
        dtuple_t*       entry,  /* in: old value of index entry */
 
86
        dict_index_t*   index,  /* in: index of entry */
 
87
        const upd_t*    update, /* in: update vector for the row */
 
88
        ulint           n);     /* in: how many first fields to check */
 
89
 
 
90
 
 
91
/*************************************************************************
131
92
Checks if index currently is mentioned as a referenced index in a foreign
132
 
key constraint.
133
 
 
134
 
NOTE that since we do not hold dict_operation_lock when leaving the
135
 
function, it may be that the referencing table has been dropped when
136
 
we leave this function: this function is only for heuristic use!
137
 
 
138
 
@return TRUE if referenced */
 
93
key constraint. */
139
94
static
140
95
ibool
141
96
row_upd_index_is_referenced(
142
97
/*========================*/
143
 
        dict_index_t*   index,  /*!< in: index */
144
 
        trx_t*          trx)    /*!< in: transaction */
 
98
                                /* out: TRUE if referenced; NOTE that since
 
99
                                we do not hold dict_operation_lock
 
100
                                when leaving the function, it may be that
 
101
                                the referencing table has been dropped when
 
102
                                we leave this function: this function is only
 
103
                                for heuristic use! */
 
104
        dict_index_t*   index,  /* in: index */
 
105
        trx_t*          trx)    /* in: transaction */
145
106
{
146
107
        dict_table_t*   table           = index->table;
147
108
        dict_foreign_t* foreign;
178
139
        return(is_referenced);
179
140
}
180
141
 
181
 
/*********************************************************************//**
 
142
/*************************************************************************
182
143
Checks if possible foreign key constraints hold after a delete of the record
183
 
under pcur.
184
 
 
185
 
NOTE that this function will temporarily commit mtr and lose the
186
 
pcur position!
187
 
 
188
 
@return DB_SUCCESS or an error code */
 
144
under pcur. NOTE that this function will temporarily commit mtr and lose the
 
145
pcur position! */
189
146
static
190
147
ulint
191
148
row_upd_check_references_constraints(
192
149
/*=================================*/
193
 
        upd_node_t*     node,   /*!< in: row update node */
194
 
        btr_pcur_t*     pcur,   /*!< in: cursor positioned on a record; NOTE: the
 
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
195
153
                                cursor position is lost in this function! */
196
 
        dict_table_t*   table,  /*!< in: table in question */
197
 
        dict_index_t*   index,  /*!< in: index of the cursor */
198
 
        ulint*          offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */
199
 
        que_thr_t*      thr,    /*!< in: query thread */
200
 
        mtr_t*          mtr)    /*!< in: mtr */
 
154
        dict_table_t*   table,  /* in: table in question */
 
155
        dict_index_t*   index,  /* in: index of the cursor */
 
156
        ulint*          offsets,/* in/out: rec_get_offsets(pcur.rec, index) */
 
157
        que_thr_t*      thr,    /* in: query thread */
 
158
        mtr_t*          mtr)    /* in: mtr */
201
159
{
202
160
        dict_foreign_t* foreign;
203
161
        mem_heap_t*     heap;
302
260
        return(err);
303
261
}
304
262
 
305
 
/*********************************************************************//**
306
 
Creates an update node for a query graph.
307
 
@return own: update node */
 
263
/*************************************************************************
 
264
Creates an update node for a query graph. */
308
265
UNIV_INTERN
309
266
upd_node_t*
310
267
upd_node_create(
311
268
/*============*/
312
 
        mem_heap_t*     heap)   /*!< in: mem heap where created */
 
269
                                /* out, own: update node */
 
270
        mem_heap_t*     heap)   /* in: mem heap where created */
313
271
{
314
272
        upd_node_t*     node;
315
273
 
317
275
        node->common.type = QUE_NODE_UPDATE;
318
276
 
319
277
        node->state = UPD_NODE_UPDATE_CLUSTERED;
 
278
        node->select_will_do_update = FALSE;
320
279
        node->in_mysql_interface = FALSE;
321
280
 
322
281
        node->row = NULL;
339
298
 
340
299
        return(node);
341
300
}
342
 
#endif /* !UNIV_HOTBACKUP */
343
301
 
344
 
/*********************************************************************//**
 
302
/*************************************************************************
345
303
Updates the trx id and roll ptr field in a clustered index record in database
346
304
recovery. */
347
305
UNIV_INTERN
348
306
void
349
307
row_upd_rec_sys_fields_in_recovery(
350
308
/*===============================*/
351
 
        rec_t*          rec,    /*!< in/out: record */
352
 
        page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
353
 
        const ulint*    offsets,/*!< in: array returned by rec_get_offsets() */
354
 
        ulint           pos,    /*!< in: TRX_ID position in rec */
355
 
        trx_id_t        trx_id, /*!< in: transaction id */
356
 
        roll_ptr_t      roll_ptr)/*!< in: roll ptr of the undo log record */
 
309
        rec_t*          rec,    /* in/out: record */
 
310
        page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
 
311
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
312
        ulint           pos,    /* in: TRX_ID position in rec */
 
313
        dulint          trx_id, /* in: transaction id */
 
314
        dulint          roll_ptr)/* in: roll ptr of the undo log record */
357
315
{
358
316
        ut_ad(rec_offs_validate(rec, NULL, offsets));
359
317
 
374
332
        }
375
333
}
376
334
 
377
 
#ifndef UNIV_HOTBACKUP
378
 
/*********************************************************************//**
 
335
/*************************************************************************
379
336
Sets the trx id or roll ptr field of a clustered index entry. */
380
337
UNIV_INTERN
381
338
void
382
339
row_upd_index_entry_sys_field(
383
340
/*==========================*/
384
 
        const dtuple_t* entry,  /*!< in: index entry, where the memory buffers
 
341
        const dtuple_t* entry,  /* in: index entry, where the memory buffers
385
342
                                for sys fields are already allocated:
386
343
                                the function just copies the new values to
387
344
                                them */
388
 
        dict_index_t*   index,  /*!< in: clustered index */
389
 
        ulint           type,   /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
390
 
        ib_uint64_t     val)    /*!< in: value to write */
 
345
        dict_index_t*   index,  /* in: clustered index */
 
346
        ulint           type,   /* in: DATA_TRX_ID or DATA_ROLL_PTR */
 
347
        dulint          val)    /* in: value to write */
391
348
{
392
349
        dfield_t*       dfield;
393
350
        byte*           field;
408
365
        }
409
366
}
410
367
 
411
 
/***********************************************************//**
 
368
/***************************************************************
412
369
Returns TRUE if row update changes size of some field in index or if some
413
 
field to be updated is stored externally in rec or update.
414
 
@return TRUE if the update changes the size of some field in index or
415
 
the field is external in rec or update */
 
370
field to be updated is stored externally in rec or update. */
416
371
UNIV_INTERN
417
372
ibool
418
373
row_upd_changes_field_size_or_external(
419
374
/*===================================*/
420
 
        dict_index_t*   index,  /*!< in: index */
421
 
        const ulint*    offsets,/*!< in: rec_get_offsets(rec, index) */
422
 
        const upd_t*    update) /*!< in: update vector */
 
375
                                /* out: TRUE if the update changes the size of
 
376
                                some field in index or the field is external
 
377
                                in rec or update */
 
378
        dict_index_t*   index,  /* in: index */
 
379
        const ulint*    offsets,/* in: rec_get_offsets(rec, index) */
 
380
        const upd_t*    update) /* in: update vector */
423
381
{
424
382
        const upd_field_t*      upd_field;
425
383
        const dfield_t*         new_val;
445
403
 
446
404
                        new_len = dict_col_get_sql_null_size(
447
405
                                dict_index_get_nth_col(index,
448
 
                                                       upd_field->field_no),
449
 
                                0);
 
406
                                                       upd_field->field_no));
450
407
                }
451
408
 
452
409
                old_len = rec_offs_nth_size(offsets, upd_field->field_no);
473
430
 
474
431
        return(FALSE);
475
432
}
476
 
#endif /* !UNIV_HOTBACKUP */
477
433
 
478
 
/***********************************************************//**
 
434
/***************************************************************
479
435
Replaces the new column values stored in the update vector to the record
480
436
given. No field size changes are allowed. */
481
437
UNIV_INTERN
482
438
void
483
439
row_upd_rec_in_place(
484
440
/*=================*/
485
 
        rec_t*          rec,    /*!< in/out: record where replaced */
486
 
        dict_index_t*   index,  /*!< in: the index the record belongs to */
487
 
        const ulint*    offsets,/*!< in: array returned by rec_get_offsets() */
488
 
        const upd_t*    update, /*!< in: update vector */
489
 
        page_zip_des_t* page_zip)/*!< in: compressed page with enough space
 
441
        rec_t*          rec,    /* in/out: record where replaced */
 
442
        dict_index_t*   index,  /* in: the index the record belongs to */
 
443
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
444
        const upd_t*    update, /* in: update vector */
 
445
        page_zip_des_t* page_zip)/* in: compressed page with enough space
490
446
                                available, or NULL */
491
447
{
492
448
        const upd_field_t*      upd_field;
520
476
        }
521
477
}
522
478
 
523
 
#ifndef UNIV_HOTBACKUP
524
 
/*********************************************************************//**
 
479
/*************************************************************************
525
480
Writes into the redo log the values of trx id and roll ptr and enough info
526
 
to determine their positions within a clustered index record.
527
 
@return new pointer to mlog */
 
481
to determine their positions within a clustered index record. */
528
482
UNIV_INTERN
529
483
byte*
530
484
row_upd_write_sys_vals_to_log(
531
485
/*==========================*/
532
 
        dict_index_t*   index,  /*!< in: clustered index */
533
 
        trx_t*          trx,    /*!< in: transaction */
534
 
        roll_ptr_t      roll_ptr,/*!< in: roll ptr of the undo log record */
535
 
        byte*           log_ptr,/*!< pointer to a buffer of size > 20 opened
 
486
                                /* out: new pointer to mlog */
 
487
        dict_index_t*   index,  /* in: clustered index */
 
488
        trx_t*          trx,    /* in: transaction */
 
489
        dulint          roll_ptr,/* in: roll ptr of the undo log record */
 
490
        byte*           log_ptr,/* pointer to a buffer of size > 20 opened
536
491
                                in mlog */
537
 
        mtr_t*          mtr __attribute__((unused))) /*!< in: mtr */
 
492
        mtr_t*          mtr __attribute__((unused))) /* in: mtr */
538
493
{
539
494
        ut_ad(dict_index_is_clust(index));
540
495
        ut_ad(mtr);
546
501
        trx_write_roll_ptr(log_ptr, roll_ptr);
547
502
        log_ptr += DATA_ROLL_PTR_LEN;
548
503
 
549
 
        log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
 
504
        log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
550
505
 
551
506
        return(log_ptr);
552
507
}
553
 
#endif /* !UNIV_HOTBACKUP */
554
508
 
555
 
/*********************************************************************//**
556
 
Parses the log data of system field values.
557
 
@return log data end or NULL */
 
509
/*************************************************************************
 
510
Parses the log data of system field values. */
558
511
UNIV_INTERN
559
512
byte*
560
513
row_upd_parse_sys_vals(
561
514
/*===================*/
562
 
        byte*           ptr,    /*!< in: buffer */
563
 
        byte*           end_ptr,/*!< in: buffer end */
564
 
        ulint*          pos,    /*!< out: TRX_ID position in record */
565
 
        trx_id_t*       trx_id, /*!< out: trx id */
566
 
        roll_ptr_t*     roll_ptr)/*!< out: roll ptr */
 
515
                        /* out: log data end or NULL */
 
516
        byte*   ptr,    /* in: buffer */
 
517
        byte*   end_ptr,/* in: buffer end */
 
518
        ulint*  pos,    /* out: TRX_ID position in record */
 
519
        dulint* trx_id, /* out: trx id */
 
520
        dulint* roll_ptr)/* out: roll ptr */
567
521
{
568
522
        ptr = mach_parse_compressed(ptr, end_ptr, pos);
569
523
 
580
534
        *roll_ptr = trx_read_roll_ptr(ptr);
581
535
        ptr += DATA_ROLL_PTR_LEN;
582
536
 
583
 
        ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
 
537
        ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
584
538
 
585
539
        return(ptr);
586
540
}
587
541
 
588
 
#ifndef UNIV_HOTBACKUP
589
 
/***********************************************************//**
 
542
/***************************************************************
590
543
Writes to the redo log the new values of the fields occurring in the index. */
591
544
UNIV_INTERN
592
545
void
593
546
row_upd_index_write_log(
594
547
/*====================*/
595
 
        const upd_t*    update, /*!< in: update vector */
596
 
        byte*           log_ptr,/*!< in: pointer to mlog buffer: must
 
548
        const upd_t*    update, /* in: update vector */
 
549
        byte*           log_ptr,/* in: pointer to mlog buffer: must
597
550
                                contain at least MLOG_BUF_MARGIN bytes
598
551
                                of free space; the buffer is closed
599
552
                                within this function */
600
 
        mtr_t*          mtr)    /*!< in: mtr into whose log to write */
 
553
        mtr_t*          mtr)    /* in: mtr into whose log to write */
601
554
{
602
555
        const upd_field_t*      upd_field;
603
556
        const dfield_t*         new_val;
656
609
 
657
610
        mlog_close(mtr, log_ptr);
658
611
}
659
 
#endif /* !UNIV_HOTBACKUP */
660
612
 
661
 
/*********************************************************************//**
662
 
Parses the log data written by row_upd_index_write_log.
663
 
@return log data end or NULL */
 
613
/*************************************************************************
 
614
Parses the log data written by row_upd_index_write_log. */
664
615
UNIV_INTERN
665
616
byte*
666
617
row_upd_index_parse(
667
618
/*================*/
668
 
        byte*           ptr,    /*!< in: buffer */
669
 
        byte*           end_ptr,/*!< in: buffer end */
670
 
        mem_heap_t*     heap,   /*!< in: memory heap where update vector is
 
619
                                /* out: log data end or NULL */
 
620
        byte*           ptr,    /* in: buffer */
 
621
        byte*           end_ptr,/* in: buffer end */
 
622
        mem_heap_t*     heap,   /* in: memory heap where update vector is
671
623
                                built */
672
 
        upd_t**         update_out)/*!< out: update vector */
 
624
        upd_t**         update_out)/* out: update vector */
673
625
{
674
626
        upd_t*          update;
675
627
        upd_field_t*    upd_field;
737
689
        return(ptr);
738
690
}
739
691
 
740
 
#ifndef UNIV_HOTBACKUP
741
 
/***************************************************************//**
 
692
/*******************************************************************
742
693
Builds an update vector from those fields which in a secondary index entry
743
694
differ from a record that has the equal ordering fields. NOTE: we compare
744
 
the fields as binary strings!
745
 
@return own: update vector of differing fields */
 
695
the fields as binary strings! */
746
696
UNIV_INTERN
747
697
upd_t*
748
698
row_upd_build_sec_rec_difference_binary(
749
699
/*====================================*/
750
 
        dict_index_t*   index,  /*!< in: index */
751
 
        const dtuple_t* entry,  /*!< in: entry to insert */
752
 
        const rec_t*    rec,    /*!< in: secondary index record */
753
 
        trx_t*          trx,    /*!< in: transaction */
754
 
        mem_heap_t*     heap)   /*!< in: memory heap from which allocated */
 
700
                                /* out, own: update vector of differing
 
701
                                fields */
 
702
        dict_index_t*   index,  /* in: index */
 
703
        const dtuple_t* entry,  /* in: entry to insert */
 
704
        const rec_t*    rec,    /* in: secondary index record */
 
705
        trx_t*          trx,    /* in: transaction */
 
706
        mem_heap_t*     heap)   /* in: memory heap from which allocated */
755
707
{
756
708
        upd_field_t*    upd_field;
757
709
        const dfield_t* dfield;
807
759
        return(update);
808
760
}
809
761
 
810
 
/***************************************************************//**
 
762
/*******************************************************************
811
763
Builds an update vector from those fields, excluding the roll ptr and
812
764
trx id fields, which in an index entry differ from a record that has
813
 
the equal ordering fields. NOTE: we compare the fields as binary strings!
814
 
@return own: update vector of differing fields, excluding roll ptr and
815
 
trx id */
 
765
the equal ordering fields. NOTE: we compare the fields as binary strings! */
816
766
UNIV_INTERN
817
767
upd_t*
818
768
row_upd_build_difference_binary(
819
769
/*============================*/
820
 
        dict_index_t*   index,  /*!< in: clustered index */
821
 
        const dtuple_t* entry,  /*!< in: entry to insert */
822
 
        const rec_t*    rec,    /*!< in: clustered index record */
823
 
        trx_t*          trx,    /*!< in: transaction */
824
 
        mem_heap_t*     heap)   /*!< in: memory heap from which allocated */
 
770
                                /* out, own: update vector of differing
 
771
                                fields, excluding roll ptr and trx id */
 
772
        dict_index_t*   index,  /* in: clustered index */
 
773
        const dtuple_t* entry,  /* in: entry to insert */
 
774
        const rec_t*    rec,    /* in: clustered index record */
 
775
        trx_t*          trx,    /* in: transaction */
 
776
        mem_heap_t*     heap)   /* in: memory heap from which allocated */
825
777
{
826
778
        upd_field_t*    upd_field;
827
779
        const dfield_t* dfield;
884
836
        return(update);
885
837
}
886
838
 
887
 
/***********************************************************//**
 
839
/***************************************************************
888
840
Fetch a prefix of an externally stored column.  This is similar
889
841
to row_ext_lookup(), but the row_ext_t holds the old values
890
 
of the column and must not be poisoned with the new values.
891
 
@return BLOB prefix */
 
842
of the column and must not be poisoned with the new values. */
892
843
static
893
844
byte*
894
845
row_upd_ext_fetch(
895
846
/*==============*/
896
 
        const byte*     data,           /*!< in: 'internally' stored part of the
 
847
                                        /* out: BLOB prefix */
 
848
        const byte*     data,           /* in: 'internally' stored part of the
897
849
                                        field containing also the reference to
898
850
                                        the external part */
899
 
        ulint           local_len,      /*!< in: length of data, in bytes */
900
 
        ulint           zip_size,       /*!< in: nonzero=compressed BLOB
 
851
        ulint           local_len,      /* in: length of data, in bytes */
 
852
        ulint           zip_size,       /* in: nonzero=compressed BLOB
901
853
                                        page size, zero for uncompressed
902
854
                                        BLOBs */
903
 
        ulint*          len,            /*!< in: length of prefix to fetch;
 
855
        ulint*          len,            /* in: length of prefix to fetch;
904
856
                                        out: fetched length of the prefix */
905
 
        mem_heap_t*     heap)           /*!< in: heap where to allocate */
 
857
        mem_heap_t*     heap)           /* in: heap where to allocate */
906
858
{
907
859
        byte*   buf = mem_heap_alloc(heap, *len);
908
860
 
915
867
        return(buf);
916
868
}
917
869
 
918
 
/***********************************************************//**
 
870
/***************************************************************
919
871
Replaces the new column value stored in the update vector in
920
872
the given index entry field. */
921
873
static
922
874
void
923
875
row_upd_index_replace_new_col_val(
924
876
/*==============================*/
925
 
        dfield_t*               dfield, /*!< in/out: data field
 
877
        dfield_t*               dfield, /* in/out: data field
926
878
                                        of the index entry */
927
 
        const dict_field_t*     field,  /*!< in: index field */
928
 
        const dict_col_t*       col,    /*!< in: field->col */
929
 
        const upd_field_t*      uf,     /*!< in: update field */
930
 
        mem_heap_t*             heap,   /*!< in: memory heap for allocating
 
879
        const dict_field_t*     field,  /* in: index field */
 
880
        const dict_col_t*       col,    /* in: field->col */
 
881
        const upd_field_t*      uf,     /* in: update field */
 
882
        mem_heap_t*             heap,   /* in: memory heap for allocating
931
883
                                        and copying the new value */
932
 
        ulint                   zip_size)/*!< in: compressed page
 
884
        ulint                   zip_size)/* in: compressed page
933
885
                                         size of the table, or 0 */
934
886
{
935
887
        ulint           len;
959
911
                }
960
912
 
961
913
                len = dtype_get_at_most_n_mbchars(col->prtype,
962
 
                                                  col->mbminmaxlen,
 
914
                                                  col->mbminlen, col->mbmaxlen,
963
915
                                                  field->prefix_len, len,
964
916
                                                  (const char*) data);
965
917
 
1008
960
        }
1009
961
}
1010
962
 
1011
 
/***********************************************************//**
 
963
/***************************************************************
1012
964
Replaces the new column values stored in the update vector to the index entry
1013
965
given. */
1014
966
UNIV_INTERN
1015
967
void
1016
968
row_upd_index_replace_new_col_vals_index_pos(
1017
969
/*=========================================*/
1018
 
        dtuple_t*       entry,  /*!< in/out: index entry where replaced;
 
970
        dtuple_t*       entry,  /* in/out: index entry where replaced;
1019
971
                                the clustered index record must be
1020
972
                                covered by a lock or a page latch to
1021
973
                                prevent deletion (rollback or purge) */
1022
 
        dict_index_t*   index,  /*!< in: index; NOTE that this may also be a
 
974
        dict_index_t*   index,  /* in: index; NOTE that this may also be a
1023
975
                                non-clustered index */
1024
 
        const upd_t*    update, /*!< in: an update vector built for the index so
 
976
        const upd_t*    update, /* in: an update vector built for the index so
1025
977
                                that the field number in an upd_field is the
1026
978
                                index position */
1027
979
        ibool           order_only,
1028
 
                                /*!< in: if TRUE, limit the replacement to
 
980
                                /* in: if TRUE, limit the replacement to
1029
981
                                ordering fields of index; note that this
1030
982
                                does not work for non-clustered indexes. */
1031
 
        mem_heap_t*     heap)   /*!< in: memory heap for allocating and
 
983
        mem_heap_t*     heap)   /* in: memory heap for allocating and
1032
984
                                copying the new values */
1033
985
{
1034
986
        ulint           i;
1062
1014
        }
1063
1015
}
1064
1016
 
1065
 
/***********************************************************//**
 
1017
/***************************************************************
1066
1018
Replaces the new column values stored in the update vector to the index entry
1067
1019
given. */
1068
1020
UNIV_INTERN
1069
1021
void
1070
1022
row_upd_index_replace_new_col_vals(
1071
1023
/*===============================*/
1072
 
        dtuple_t*       entry,  /*!< in/out: index entry where replaced;
 
1024
        dtuple_t*       entry,  /* in/out: index entry where replaced;
1073
1025
                                the clustered index record must be
1074
1026
                                covered by a lock or a page latch to
1075
1027
                                prevent deletion (rollback or purge) */
1076
 
        dict_index_t*   index,  /*!< in: index; NOTE that this may also be a
 
1028
        dict_index_t*   index,  /* in: index; NOTE that this may also be a
1077
1029
                                non-clustered index */
1078
 
        const upd_t*    update, /*!< in: an update vector built for the
 
1030
        const upd_t*    update, /* in: an update vector built for the
1079
1031
                                CLUSTERED index so that the field number in
1080
1032
                                an upd_field is the clustered index position */
1081
 
        mem_heap_t*     heap)   /*!< in: memory heap for allocating and
 
1033
        mem_heap_t*     heap)   /* in: memory heap for allocating and
1082
1034
                                copying the new values */
1083
1035
{
1084
1036
        ulint                   i;
1107
1059
        }
1108
1060
}
1109
1061
 
1110
 
/***********************************************************//**
 
1062
/***************************************************************
1111
1063
Replaces the new column values stored in the update vector. */
1112
1064
UNIV_INTERN
1113
1065
void
1114
1066
row_upd_replace(
1115
1067
/*============*/
1116
 
        dtuple_t*               row,    /*!< in/out: row where replaced,
 
1068
        dtuple_t*               row,    /* in/out: row where replaced,
1117
1069
                                        indexed by col_no;
1118
1070
                                        the clustered index record must be
1119
1071
                                        covered by a lock or a page latch to
1120
1072
                                        prevent deletion (rollback or purge) */
1121
 
        row_ext_t**             ext,    /*!< out, own: NULL, or externally
 
1073
        row_ext_t**             ext,    /* out, own: NULL, or externally
1122
1074
                                        stored column prefixes */
1123
 
        const dict_index_t*     index,  /*!< in: clustered index */
1124
 
        const upd_t*            update, /*!< in: an update vector built for the
 
1075
        const dict_index_t*     index,  /* in: clustered index */
 
1076
        const upd_t*            update, /* in: an update vector built for the
1125
1077
                                        clustered index */
1126
 
        mem_heap_t*             heap)   /*!< in: memory heap */
 
1078
        mem_heap_t*             heap)   /* in: memory heap */
1127
1079
{
1128
1080
        ulint                   col_no;
1129
1081
        ulint                   i;
1190
1142
        }
1191
1143
}
1192
1144
 
1193
 
/***********************************************************//**
 
1145
/***************************************************************
1194
1146
Checks if an update vector changes an ordering field of an index record.
1195
 
 
1196
1147
This function is fast if the update vector is short or the number of ordering
1197
1148
fields in the index is small. Otherwise, this can be quadratic.
1198
 
NOTE: we compare the fields as binary strings!
1199
 
@return TRUE if update vector changes an ordering field in the index record */
 
1149
NOTE: we compare the fields as binary strings! */
1200
1150
UNIV_INTERN
1201
1151
ibool
1202
1152
row_upd_changes_ord_field_binary(
1203
1153
/*=============================*/
1204
 
        const dtuple_t* row,    /*!< in: old value of row, or NULL if the
 
1154
                                /* out: TRUE if update vector changes
 
1155
                                an ordering field in the index record;
 
1156
                                NOTE: the fields are compared as binary
 
1157
                                strings */
 
1158
        const dtuple_t* row,    /* in: old value of row, or NULL if the
1205
1159
                                row and the data values in update are not
1206
1160
                                known when this function is called, e.g., at
1207
1161
                                compile time */
1208
 
        dict_index_t*   index,  /*!< in: index of the record */
1209
 
        const upd_t*    update) /*!< in: update vector for the row; NOTE: the
 
1162
        dict_index_t*   index,  /* in: index of the record */
 
1163
        const upd_t*    update) /* in: update vector for the row; NOTE: the
1210
1164
                                field numbers in this MUST be clustered index
1211
1165
                                positions! */
1212
1166
{
1259
1213
        return(FALSE);
1260
1214
}
1261
1215
 
1262
 
/***********************************************************//**
 
1216
/***************************************************************
1263
1217
Checks if an update vector changes an ordering field of an index record.
1264
 
NOTE: we compare the fields as binary strings!
1265
 
@return TRUE if update vector may change an ordering field in an index
1266
 
record */
 
1218
NOTE: we compare the fields as binary strings! */
1267
1219
UNIV_INTERN
1268
1220
ibool
1269
1221
row_upd_changes_some_index_ord_field_binary(
1270
1222
/*========================================*/
1271
 
        const dict_table_t*     table,  /*!< in: table */
1272
 
        const upd_t*            update) /*!< in: update vector for the row */
 
1223
                                        /* out: TRUE if update vector
 
1224
                                        may change an ordering field
 
1225
                                        in an index record */
 
1226
        const dict_table_t*     table,  /* in: table */
 
1227
        const upd_t*            update) /* in: update vector for the row */
1273
1228
{
1274
1229
        upd_field_t*    upd_field;
1275
1230
        dict_index_t*   index;
1292
1247
        return(FALSE);
1293
1248
}
1294
1249
 
1295
 
/***********************************************************//**
 
1250
/***************************************************************
1296
1251
Checks if an update vector changes some of the first ordering fields of an
1297
1252
index record. This is only used in foreign key checks and we can assume
1298
 
that index does not contain column prefixes.
1299
 
@return TRUE if changes */
 
1253
that index does not contain column prefixes. */
1300
1254
static
1301
1255
ibool
1302
1256
row_upd_changes_first_fields_binary(
1303
1257
/*================================*/
1304
 
        dtuple_t*       entry,  /*!< in: index entry */
1305
 
        dict_index_t*   index,  /*!< in: index of entry */
1306
 
        const upd_t*    update, /*!< in: update vector for the row */
1307
 
        ulint           n)      /*!< in: how many first fields to check */
 
1258
                                /* out: TRUE if changes */
 
1259
        dtuple_t*       entry,  /* in: index entry */
 
1260
        dict_index_t*   index,  /* in: index of entry */
 
1261
        const upd_t*    update, /* in: update vector for the row */
 
1262
        ulint           n)      /* in: how many first fields to check */
1308
1263
{
1309
1264
        ulint           n_upd_fields;
1310
1265
        ulint           i, j;
1346
1301
        return(FALSE);
1347
1302
}
1348
1303
 
1349
 
/*********************************************************************//**
 
1304
/*************************************************************************
1350
1305
Copies the column values from a record. */
1351
1306
UNIV_INLINE
1352
1307
void
1353
1308
row_upd_copy_columns(
1354
1309
/*=================*/
1355
 
        rec_t*          rec,    /*!< in: record in a clustered index */
1356
 
        const ulint*    offsets,/*!< in: array returned by rec_get_offsets() */
1357
 
        sym_node_t*     column) /*!< in: first column in a column list, or
 
1310
        rec_t*          rec,    /* in: record in a clustered index */
 
1311
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
1312
        sym_node_t*     column) /* in: first column in a column list, or
1358
1313
                                NULL */
1359
1314
{
1360
1315
        byte*   data;
1364
1319
                data = rec_get_nth_field(rec, offsets,
1365
1320
                                         column->field_nos[SYM_CLUST_FIELD_NO],
1366
1321
                                         &len);
 
1322
                if (len == UNIV_SQL_NULL) {
 
1323
                        len = UNIV_SQL_NULL;
 
1324
                }
1367
1325
                eval_node_copy_and_alloc_val(column, data, len);
1368
1326
 
1369
1327
                column = UT_LIST_GET_NEXT(col_var_list, column);
1370
1328
        }
1371
1329
}
1372
1330
 
1373
 
/*********************************************************************//**
 
1331
/*************************************************************************
1374
1332
Calculates the new values for fields to update. Note that row_upd_copy_columns
1375
1333
must have been called first. */
1376
1334
UNIV_INLINE
1377
1335
void
1378
1336
row_upd_eval_new_vals(
1379
1337
/*==================*/
1380
 
        upd_t*  update) /*!< in/out: update vector */
 
1338
        upd_t*  update) /* in/out: update vector */
1381
1339
{
1382
1340
        que_node_t*     exp;
1383
1341
        upd_field_t*    upd_field;
1397
1355
        }
1398
1356
}
1399
1357
 
1400
 
/***********************************************************//**
 
1358
/***************************************************************
1401
1359
Stores to the heap the row on which the node->pcur is positioned. */
1402
1360
static
1403
1361
void
1404
1362
row_upd_store_row(
1405
1363
/*==============*/
1406
 
        upd_node_t*     node)   /*!< in: row update node */
 
1364
        upd_node_t*     node)   /* in: row update node */
1407
1365
{
1408
1366
        dict_index_t*   clust_index;
1409
1367
        rec_t*          rec;
1410
1368
        mem_heap_t*     heap            = NULL;
1411
 
        row_ext_t**     ext;
1412
1369
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1413
1370
        const ulint*    offsets;
1414
1371
        rec_offs_init(offsets_);
1425
1382
 
1426
1383
        offsets = rec_get_offsets(rec, clust_index, offsets_,
1427
1384
                                  ULINT_UNDEFINED, &heap);
1428
 
 
1429
 
        if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) {
1430
 
                /* In DYNAMIC or COMPRESSED format, there is no prefix
1431
 
                of externally stored columns in the clustered index
1432
 
                record. Build a cache of column prefixes. */
1433
 
                ext = &node->ext;
1434
 
        } else {
1435
 
                /* REDUNDANT and COMPACT formats store a local
1436
 
                768-byte prefix of each externally stored column.
1437
 
                No cache is needed. */
1438
 
                ext = NULL;
1439
 
                node->ext = NULL;
1440
 
        }
1441
 
 
1442
1385
        node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1443
 
                              NULL, ext, node->heap);
 
1386
                              NULL, &node->ext, node->heap);
1444
1387
        if (node->is_delete) {
1445
1388
                node->upd_row = NULL;
1446
1389
                node->upd_ext = NULL;
1455
1398
        }
1456
1399
}
1457
1400
 
1458
 
/***********************************************************//**
1459
 
Updates a secondary index entry of a row.
1460
 
@return DB_SUCCESS if operation successfully completed, else error
1461
 
code or DB_LOCK_WAIT */
 
1401
/***************************************************************
 
1402
Updates a secondary index entry of a row. */
1462
1403
static
1463
1404
ulint
1464
1405
row_upd_sec_index_entry(
1465
1406
/*====================*/
1466
 
        upd_node_t*     node,   /*!< in: row update node */
1467
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1407
                                /* out: DB_SUCCESS if operation successfully
 
1408
                                completed, else error code or DB_LOCK_WAIT */
 
1409
        upd_node_t*     node,   /* in: row update node */
 
1410
        que_thr_t*      thr)    /* in: query thread */
1468
1411
{
1469
 
        mtr_t                   mtr;
1470
 
        const rec_t*            rec;
1471
 
        btr_pcur_t              pcur;
1472
 
        mem_heap_t*             heap;
1473
 
        dtuple_t*               entry;
1474
 
        dict_index_t*           index;
1475
 
        btr_cur_t*              btr_cur;
1476
 
        ibool                   referenced;
1477
 
        ulint                   err     = DB_SUCCESS;
1478
 
        trx_t*                  trx     = thr_get_trx(thr);
1479
 
        ulint                   mode    = BTR_MODIFY_LEAF;
1480
 
        enum row_search_result  search_result;
 
1412
        ibool           check_ref;
 
1413
        ibool           found;
 
1414
        dict_index_t*   index;
 
1415
        dtuple_t*       entry;
 
1416
        btr_pcur_t      pcur;
 
1417
        btr_cur_t*      btr_cur;
 
1418
        mem_heap_t*     heap;
 
1419
        rec_t*          rec;
 
1420
        ulint           err     = DB_SUCCESS;
 
1421
        mtr_t           mtr;
 
1422
        trx_t*          trx     = thr_get_trx(thr);
1481
1423
 
1482
1424
        index = node->index;
1483
1425
 
1484
 
        referenced = row_upd_index_is_referenced(index, trx);
 
1426
        check_ref = row_upd_index_is_referenced(index, trx);
1485
1427
 
1486
1428
        heap = mem_heap_create(1024);
1487
1429
 
1489
1431
        entry = row_build_index_entry(node->row, node->ext, index, heap);
1490
1432
        ut_a(entry);
1491
1433
 
 
1434
        log_free_check();
1492
1435
        mtr_start(&mtr);
1493
1436
 
1494
 
        /* Set the query thread, so that ibuf_insert_low() will be
1495
 
        able to invoke thd_get_trx(). */
1496
 
        btr_pcur_get_btr_cur(&pcur)->thr = thr;
1497
 
 
1498
 
        /* We can only try to use the insert/delete buffer to buffer
1499
 
        delete-mark operations if the index we're modifying has no foreign
1500
 
        key constraints referring to it. */
1501
 
        if (!referenced) {
1502
 
                mode |= BTR_DELETE_MARK;
1503
 
        }
1504
 
 
1505
 
        search_result = row_search_index_entry(index, entry, mode,
1506
 
                                               &pcur, &mtr);
1507
 
 
 
1437
        found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
 
1438
                                       &mtr);
1508
1439
        btr_cur = btr_pcur_get_btr_cur(&pcur);
1509
1440
 
1510
1441
        rec = btr_cur_get_rec(btr_cur);
1511
1442
 
1512
 
        switch (search_result) {
1513
 
        case ROW_NOT_DELETED_REF:       /* should only occur for BTR_DELETE */
1514
 
                ut_error;
1515
 
                break;
1516
 
        case ROW_BUFFERED:
1517
 
                /* Entry was delete marked already. */
1518
 
                break;
1519
 
 
1520
 
        case ROW_NOT_FOUND:
 
1443
        if (UNIV_UNLIKELY(!found)) {
1521
1444
                fputs("InnoDB: error in sec index entry update in\n"
1522
1445
                      "InnoDB: ", stderr);
1523
1446
                dict_index_name_print(stderr, trx, index);
1534
1457
                fputs("\n"
1535
1458
                      "InnoDB: Submit a detailed bug report"
1536
1459
                      " to http://bugs.mysql.com\n", stderr);
1537
 
                break;
1538
 
        case ROW_FOUND:
 
1460
        } else {
1539
1461
                /* Delete mark the old index record; it can already be
1540
1462
                delete marked if we return after a lock wait in
1541
1463
                row_ins_index_entry below */
1542
1464
 
1543
 
                if (!rec_get_deleted_flag(
1544
 
                        rec, dict_table_is_comp(index->table))) {
1545
 
 
1546
 
                        err = btr_cur_del_mark_set_sec_rec(
1547
 
                                0, btr_cur, TRUE, thr, &mtr);
1548
 
 
1549
 
                        if (err == DB_SUCCESS && referenced) {
1550
 
 
1551
 
                                ulint*  offsets;
1552
 
 
1553
 
                                offsets = rec_get_offsets(
1554
 
                                        rec, index, NULL, ULINT_UNDEFINED,
1555
 
                                        &heap);
1556
 
 
 
1465
                if (!rec_get_deleted_flag(rec,
 
1466
                                          dict_table_is_comp(index->table))) {
 
1467
                        err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
 
1468
                                                           thr, &mtr);
 
1469
                        if (err == DB_SUCCESS && check_ref) {
 
1470
 
 
1471
                                ulint*  offsets = rec_get_offsets(
 
1472
                                        rec, index, NULL,
 
1473
                                        ULINT_UNDEFINED, &heap);
1557
1474
                                /* NOTE that the following call loses
1558
1475
                                the position of pcur ! */
1559
1476
                                err = row_upd_check_references_constraints(
1561
1478
                                        index, offsets, thr, &mtr);
1562
1479
                        }
1563
1480
                }
1564
 
                break;
1565
1481
        }
1566
1482
 
1567
1483
        btr_pcur_close(&pcur);
1586
1502
        return(err);
1587
1503
}
1588
1504
 
1589
 
/***********************************************************//**
 
1505
/***************************************************************
1590
1506
Updates the secondary index record if it is changed in the row update or
1591
 
deletes it if this is a delete.
1592
 
@return DB_SUCCESS if operation successfully completed, else error
1593
 
code or DB_LOCK_WAIT */
1594
 
static
 
1507
deletes it if this is a delete. */
 
1508
UNIV_INLINE
1595
1509
ulint
1596
1510
row_upd_sec_step(
1597
1511
/*=============*/
1598
 
        upd_node_t*     node,   /*!< in: row update node */
1599
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1512
                                /* out: DB_SUCCESS if operation successfully
 
1513
                                completed, else error code or DB_LOCK_WAIT */
 
1514
        upd_node_t*     node,   /* in: row update node */
 
1515
        que_thr_t*      thr)    /* in: query thread */
1600
1516
{
1601
1517
        ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
1602
1518
              || (node->state == UPD_NODE_UPDATE_SOME_SEC));
1611
1527
        return(DB_SUCCESS);
1612
1528
}
1613
1529
 
1614
 
/***********************************************************//**
 
1530
/***************************************************************
1615
1531
Marks the clustered index record deleted and inserts the updated version
1616
1532
of the record to the index. This function should be used when the ordering
1617
1533
fields of the clustered index record change. This should be quite rare in
1618
 
database applications.
1619
 
@return DB_SUCCESS if operation successfully completed, else error
1620
 
code or DB_LOCK_WAIT */
 
1534
database applications. */
1621
1535
static
1622
1536
ulint
1623
1537
row_upd_clust_rec_by_insert(
1624
1538
/*========================*/
1625
 
        upd_node_t*     node,   /*!< in: row update node */
1626
 
        dict_index_t*   index,  /*!< in: clustered index of the record */
1627
 
        que_thr_t*      thr,    /*!< in: query thread */
1628
 
        ibool           referenced,/*!< in: TRUE if index may be referenced in
 
1539
                                /* out: DB_SUCCESS if operation successfully
 
1540
                                completed, else error code or DB_LOCK_WAIT */
 
1541
        upd_node_t*     node,   /* in: row update node */
 
1542
        dict_index_t*   index,  /* in: clustered index of the record */
 
1543
        que_thr_t*      thr,    /* in: query thread */
 
1544
        ibool           check_ref,/* in: TRUE if index may be referenced in
1629
1545
                                a foreign key constraint */
1630
 
        mtr_t*          mtr)    /*!< in: mtr; gets committed here */
 
1546
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1631
1547
{
1632
1548
        mem_heap_t*     heap    = NULL;
1633
1549
        btr_pcur_t*     pcur;
1636
1552
        dict_table_t*   table;
1637
1553
        dtuple_t*       entry;
1638
1554
        ulint           err;
1639
 
        ibool           change_ownership = FALSE;
1640
1555
 
1641
1556
        ut_ad(node);
1642
1557
        ut_ad(dict_index_is_clust(index));
1669
1584
                index = dict_table_get_first_index(table);
1670
1585
                offsets = rec_get_offsets(rec, index, offsets_,
1671
1586
                                          ULINT_UNDEFINED, &heap);
1672
 
                change_ownership = btr_cur_mark_extern_inherited_fields(
1673
 
                        btr_cur_get_page_zip(btr_cur), rec, index, offsets,
1674
 
                        node->update, mtr);
1675
 
                if (referenced) {
 
1587
                btr_cur_mark_extern_inherited_fields(
 
1588
                        btr_cur_get_page_zip(btr_cur),
 
1589
                        rec, index, offsets, node->update, mtr);
 
1590
                if (check_ref) {
1676
1591
                        /* NOTE that the following call loses
1677
1592
                        the position of pcur ! */
1678
 
 
1679
1593
                        err = row_upd_check_references_constraints(
1680
1594
                                node, pcur, table, index, offsets, thr, mtr);
1681
 
 
1682
1595
                        if (err != DB_SUCCESS) {
1683
 
 
1684
1596
                                mtr_commit(mtr);
1685
 
 
1686
1597
                                if (UNIV_LIKELY_NULL(heap)) {
1687
1598
                                        mem_heap_free(heap);
1688
1599
                                }
1689
 
 
1690
1600
                                return(err);
1691
1601
                        }
1692
1602
                }
1705
1615
 
1706
1616
        row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1707
1617
 
1708
 
        if (change_ownership) {
 
1618
        if (node->upd_ext) {
1709
1619
                /* If we return from a lock wait, for example, we may have
1710
1620
                extern fields marked as not-owned in entry (marked in the
1711
 
                if-branch above). We must unmark them, take the ownership
1712
 
                back. */
 
1621
                if-branch above). We must unmark them. */
1713
1622
 
1714
1623
                btr_cur_unmark_dtuple_extern_fields(entry);
1715
1624
 
1727
1636
        return(err);
1728
1637
}
1729
1638
 
1730
 
/***********************************************************//**
 
1639
/***************************************************************
1731
1640
Updates a clustered index record of a row when the ordering fields do
1732
 
not change.
1733
 
@return DB_SUCCESS if operation successfully completed, else error
1734
 
code or DB_LOCK_WAIT */
 
1641
not change. */
1735
1642
static
1736
1643
ulint
1737
1644
row_upd_clust_rec(
1738
1645
/*==============*/
1739
 
        upd_node_t*     node,   /*!< in: row update node */
1740
 
        dict_index_t*   index,  /*!< in: clustered index */
1741
 
        que_thr_t*      thr,    /*!< in: query thread */
1742
 
        mtr_t*          mtr)    /*!< in: mtr; gets committed here */
 
1646
                                /* out: DB_SUCCESS if operation successfully
 
1647
                                completed, else error code or DB_LOCK_WAIT */
 
1648
        upd_node_t*     node,   /* in: row update node */
 
1649
        dict_index_t*   index,  /* in: clustered index */
 
1650
        que_thr_t*      thr,    /* in: query thread */
 
1651
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1743
1652
{
1744
1653
        mem_heap_t*     heap    = NULL;
1745
1654
        big_rec_t*      big_rec = NULL;
1830
1739
        return(err);
1831
1740
}
1832
1741
 
1833
 
/***********************************************************//**
1834
 
Delete marks a clustered index record.
1835
 
@return DB_SUCCESS if operation successfully completed, else error code */
 
1742
/***************************************************************
 
1743
Delete marks a clustered index record. */
1836
1744
static
1837
1745
ulint
1838
1746
row_upd_del_mark_clust_rec(
1839
1747
/*=======================*/
1840
 
        upd_node_t*     node,   /*!< in: row update node */
1841
 
        dict_index_t*   index,  /*!< in: clustered index */
1842
 
        ulint*          offsets,/*!< in/out: rec_get_offsets() for the
 
1748
                                /* out: DB_SUCCESS if operation successfully
 
1749
                                completed, else error code */
 
1750
        upd_node_t*     node,   /* in: row update node */
 
1751
        dict_index_t*   index,  /* in: clustered index */
 
1752
        ulint*          offsets,/* in/out: rec_get_offsets() for the
1843
1753
                                record under the cursor */
1844
 
        que_thr_t*      thr,    /*!< in: query thread */
1845
 
        ibool           referenced,
1846
 
                                /*!< in: TRUE if index may be referenced in
 
1754
        que_thr_t*      thr,    /* in: query thread */
 
1755
        ibool           check_ref,/* in: TRUE if index may be referenced in
1847
1756
                                a foreign key constraint */
1848
 
        mtr_t*          mtr)    /*!< in: mtr; gets committed here */
 
1757
        mtr_t*          mtr)    /* in: mtr; gets committed here */
1849
1758
{
1850
1759
        btr_pcur_t*     pcur;
1851
1760
        btr_cur_t*      btr_cur;
1868
1777
 
1869
1778
        err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1870
1779
                                             btr_cur, TRUE, thr, mtr);
1871
 
        if (err == DB_SUCCESS && referenced) {
 
1780
        if (err == DB_SUCCESS && check_ref) {
1872
1781
                /* NOTE that the following call loses the position of pcur ! */
1873
1782
 
1874
 
                err = row_upd_check_references_constraints(
1875
 
                        node, pcur, index->table, index, offsets, thr, mtr);
 
1783
                err = row_upd_check_references_constraints(node,
 
1784
                                                           pcur, index->table,
 
1785
                                                           index, offsets,
 
1786
                                                           thr, mtr);
1876
1787
        }
1877
1788
 
1878
1789
        mtr_commit(mtr);
1880
1791
        return(err);
1881
1792
}
1882
1793
 
1883
 
/***********************************************************//**
1884
 
Updates the clustered index record.
1885
 
@return DB_SUCCESS if operation successfully completed, DB_LOCK_WAIT
1886
 
in case of a lock wait, else error code */
 
1794
/***************************************************************
 
1795
Updates the clustered index record. */
1887
1796
static
1888
1797
ulint
1889
1798
row_upd_clust_step(
1890
1799
/*===============*/
1891
 
        upd_node_t*     node,   /*!< in: row update node */
1892
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1800
                                /* out: DB_SUCCESS if operation successfully
 
1801
                                completed, DB_LOCK_WAIT in case of a lock wait,
 
1802
                                else error code */
 
1803
        upd_node_t*     node,   /* in: row update node */
 
1804
        que_thr_t*      thr)    /* in: query thread */
1893
1805
{
1894
1806
        dict_index_t*   index;
1895
1807
        btr_pcur_t*     pcur;
1896
1808
        ibool           success;
 
1809
        ibool           check_ref;
1897
1810
        ulint           err;
1898
1811
        mtr_t*          mtr;
1899
1812
        mtr_t           mtr_buf;
1901
1814
        mem_heap_t*     heap            = NULL;
1902
1815
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1903
1816
        ulint*          offsets;
1904
 
        ibool           referenced;
1905
1817
        rec_offs_init(offsets_);
1906
1818
 
1907
1819
        index = dict_table_get_first_index(node->table);
1908
1820
 
1909
 
        referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
 
1821
        check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
1910
1822
 
1911
1823
        pcur = node->pcur;
1912
1824
 
1939
1851
        then we have to free the file segments of the index tree associated
1940
1852
        with the index */
1941
1853
 
1942
 
        if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
 
1854
        if (node->is_delete
 
1855
            && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1943
1856
 
1944
1857
                dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1945
1858
 
1975
1888
        /* NOTE: the following function calls will also commit mtr */
1976
1889
 
1977
1890
        if (node->is_delete) {
1978
 
                err = row_upd_del_mark_clust_rec(
1979
 
                        node, index, offsets, thr, referenced, mtr);
1980
 
 
 
1891
                err = row_upd_del_mark_clust_rec(node, index, offsets,
 
1892
                                                 thr, check_ref, mtr);
1981
1893
                if (err == DB_SUCCESS) {
1982
1894
                        node->state = UPD_NODE_UPDATE_ALL_SEC;
1983
1895
                        node->index = dict_table_get_next_index(index);
2025
1937
                choosing records to update. MySQL solves now the problem
2026
1938
                externally! */
2027
1939
 
2028
 
                err = row_upd_clust_rec_by_insert(
2029
 
                        node, index, thr, referenced, mtr);
2030
 
 
 
1940
                err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
 
1941
                                                  mtr);
2031
1942
                if (err != DB_SUCCESS) {
2032
1943
 
2033
1944
                        return(err);
2050
1961
        return(err);
2051
1962
}
2052
1963
 
2053
 
/***********************************************************//**
 
1964
/***************************************************************
2054
1965
Updates the affected index records of a row. When the control is transferred
2055
1966
to this node, we assume that we have a persistent cursor which was on a
2056
 
record, and the position of the cursor is stored in the cursor.
2057
 
@return DB_SUCCESS if operation successfully completed, else error
2058
 
code or DB_LOCK_WAIT */
 
1967
record, and the position of the cursor is stored in the cursor. */
2059
1968
static
2060
1969
ulint
2061
1970
row_upd(
2062
1971
/*====*/
2063
 
        upd_node_t*     node,   /*!< in: row update node */
2064
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1972
                                /* out: DB_SUCCESS if operation successfully
 
1973
                                completed, else error code or DB_LOCK_WAIT */
 
1974
        upd_node_t*     node,   /* in: row update node */
 
1975
        que_thr_t*      thr)    /* in: query thread */
2065
1976
{
2066
1977
        ulint   err     = DB_SUCCESS;
2067
1978
 
2084
1995
        if (node->state == UPD_NODE_UPDATE_CLUSTERED
2085
1996
            || node->state == UPD_NODE_INSERT_CLUSTERED) {
2086
1997
 
2087
 
                log_free_check();
2088
1998
                err = row_upd_clust_step(node, thr);
2089
1999
 
2090
2000
                if (err != DB_SUCCESS) {
2099
2009
        }
2100
2010
 
2101
2011
        while (node->index != NULL) {
2102
 
 
2103
 
                log_free_check();
2104
2012
                err = row_upd_sec_step(node, thr);
2105
2013
 
2106
2014
                if (err != DB_SUCCESS) {
2129
2037
        return(err);
2130
2038
}
2131
2039
 
2132
 
/***********************************************************//**
 
2040
/***************************************************************
2133
2041
Updates a row in a table. This is a high-level function used in SQL execution
2134
 
graphs.
2135
 
@return query thread to run next or NULL */
 
2042
graphs. */
2136
2043
UNIV_INTERN
2137
2044
que_thr_t*
2138
2045
row_upd_step(
2139
2046
/*=========*/
2140
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2047
                                /* out: query thread to run next or NULL */
 
2048
        que_thr_t*      thr)    /* in: query thread */
2141
2049
{
2142
2050
        upd_node_t*     node;
2143
2051
        sel_node_t*     sel_node;
2243
2151
 
2244
2152
        return(thr);
2245
2153
}
2246
 
#endif /* !UNIV_HOTBACKUP */
 
2154
 
 
2155
/*************************************************************************
 
2156
Performs an in-place update for the current clustered index record in
 
2157
select. */
 
2158
UNIV_INTERN
 
2159
void
 
2160
row_upd_in_place_in_select(
 
2161
/*=======================*/
 
2162
        sel_node_t*     sel_node,       /* in: select node */
 
2163
        que_thr_t*      thr,            /* in: query thread */
 
2164
        mtr_t*          mtr)            /* in: mtr */
 
2165
{
 
2166
        upd_node_t*     node;
 
2167
        btr_pcur_t*     pcur;
 
2168
        btr_cur_t*      btr_cur;
 
2169
        ulint           err;
 
2170
        mem_heap_t*     heap            = NULL;
 
2171
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
2172
        rec_offs_init(offsets_);
 
2173
 
 
2174
        ut_ad(sel_node->select_will_do_update);
 
2175
        ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF);
 
2176
        ut_ad(sel_node->asc);
 
2177
 
 
2178
        node = que_node_get_parent(sel_node);
 
2179
 
 
2180
        ut_ad(que_node_get_type(node) == QUE_NODE_UPDATE);
 
2181
 
 
2182
        pcur = node->pcur;
 
2183
        btr_cur = btr_pcur_get_btr_cur(pcur);
 
2184
 
 
2185
        /* Copy the necessary columns from clust_rec and calculate the new
 
2186
        values to set */
 
2187
 
 
2188
        row_upd_copy_columns(btr_pcur_get_rec(pcur),
 
2189
                             rec_get_offsets(btr_pcur_get_rec(pcur),
 
2190
                                             btr_cur->index, offsets_,
 
2191
                                             ULINT_UNDEFINED, &heap),
 
2192
                             UT_LIST_GET_FIRST(node->columns));
 
2193
        if (UNIV_LIKELY_NULL(heap)) {
 
2194
                mem_heap_free(heap);
 
2195
        }
 
2196
        row_upd_eval_new_vals(node->update);
 
2197
 
 
2198
        ut_ad(!rec_get_deleted_flag(
 
2199
                      btr_pcur_get_rec(pcur),
 
2200
                      dict_table_is_comp(btr_cur->index->table)));
 
2201
 
 
2202
        ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE);
 
2203
        ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
 
2204
        ut_ad(node->select_will_do_update);
 
2205
 
 
2206
        err = btr_cur_update_in_place(BTR_NO_LOCKING_FLAG, btr_cur,
 
2207
                                      node->update, node->cmpl_info,
 
2208
                                      thr, mtr);
 
2209
        /* TODO: the above can fail with DB_ZIP_OVERFLOW if page_zip != NULL.
 
2210
        However, this function row_upd_in_place_in_select() is only invoked
 
2211
        when executing UPDATE statements of the built-in InnoDB SQL parser.
 
2212
        The built-in SQL is only used for InnoDB system tables, which
 
2213
        always are in the old, uncompressed format (ROW_FORMAT=REDUNDANT,
 
2214
        comp == FALSE, page_zip == NULL). */
 
2215
        ut_ad(err == DB_SUCCESS);
 
2216
}