~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Jay Pipes
  • Date: 2008-12-18 15:55:03 UTC
  • mto: This revision was merged to the branch mainline in revision 717.
  • Revision ID: jpipes@serialcoder-20081218155503-u45ygyunrdyyvquq
Fix for Bug#308457.  Gave UTF8 enclosure and escape character on LOAD DATA INFILE and changed the error message to be more descriptive

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (C) 2005, 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/row0merge.c
 
1
/******************************************************
21
2
New index creation routines using a merge sort
22
3
 
 
4
(c) 2005,2007 Innobase Oy
 
5
 
23
6
Created 12/4/2005 Jan Lindstrom
24
7
Completed by Sunny Bains and Marko Makela
25
8
*******************************************************/
56
39
#include "log0log.h"
57
40
#include "ut0sort.h"
58
41
#include "handler0alter.h"
59
 
#include <unistd.h>
60
 
 
61
 
/* Ignore posix_fadvise() on those platforms where it does not exist */
62
 
#if defined __WIN__
63
 
# define posix_fadvise(fd, offset, len, advice) /* nothing */
64
 
#endif /* __WIN__ */
65
42
 
66
43
#ifdef UNIV_DEBUG
67
 
/** Set these in order ot enable debug printout. */
68
 
/* @{ */
69
 
/** Log the outcome of each row_merge_cmp() call, comparing records. */
 
44
/* Set these in order ot enable debug printout. */
70
45
static ibool    row_merge_print_cmp;
71
 
/** Log each record read from temporary file. */
72
46
static ibool    row_merge_print_read;
73
 
/** Log each record write to temporary file. */
74
47
static ibool    row_merge_print_write;
75
 
/** Log each row_merge_blocks() call, merging two blocks of records to
76
 
a bigger one. */
77
 
static ibool    row_merge_print_block;
78
 
/** Log each block read from temporary file. */
79
 
static ibool    row_merge_print_block_read;
80
 
/** Log each block read from temporary file. */
81
 
static ibool    row_merge_print_block_write;
82
 
/* @} */
83
48
#endif /* UNIV_DEBUG */
84
49
 
85
 
/** @brief Block size for I/O operations in merge sort.
86
 
 
87
 
The minimum is UNIV_PAGE_SIZE, or page_get_free_space_of_empty()
88
 
rounded to a power of 2.
 
50
/* Block size for I/O operations in merge sort.  The minimum is
 
51
UNIV_PAGE_SIZE, or page_get_free_space_of_empty() rounded to a power of 2.
89
52
 
90
53
When not creating a PRIMARY KEY that contains column prefixes, this
91
54
can be set as small as UNIV_PAGE_SIZE / 2.  See the comment above
92
55
ut_ad(data_size < sizeof(row_merge_block_t)). */
 
56
 
93
57
typedef byte    row_merge_block_t[1048576];
94
58
 
95
 
/** @brief Secondary buffer for I/O operations of merge records.
 
59
/* Secondary buffer for I/O operations of merge records.  This buffer
 
60
is used for writing or reading a record that spans two row_merge_block_t.
 
61
Thus, it must be able to hold one merge record, whose maximum size is
 
62
the same as the minimum size of row_merge_block_t. */
96
63
 
97
 
This buffer is used for writing or reading a record that spans two
98
 
row_merge_block_t.  Thus, it must be able to hold one merge record,
99
 
whose maximum size is the same as the minimum size of
100
 
row_merge_block_t. */
101
64
typedef byte    mrec_buf_t[UNIV_PAGE_SIZE];
102
65
 
103
 
/** @brief Merge record in row_merge_block_t.
104
 
 
105
 
The format is the same as a record in ROW_FORMAT=COMPACT with the
106
 
exception that the REC_N_NEW_EXTRA_BYTES are omitted. */
 
66
/* Merge record in row_merge_block_t.  The format is the same as a
 
67
record in ROW_FORMAT=COMPACT with the exception that the
 
68
REC_N_NEW_EXTRA_BYTES are omitted. */
107
69
typedef byte    mrec_t;
108
70
 
109
 
/** Buffer for sorting in main memory. */
 
71
/* Buffer for sorting in main memory. */
110
72
struct row_merge_buf_struct {
111
 
        mem_heap_t*     heap;           /*!< memory heap where allocated */
112
 
        dict_index_t*   index;          /*!< the index the tuples belong to */
113
 
        ulint           total_size;     /*!< total amount of data bytes */
114
 
        ulint           n_tuples;       /*!< number of data tuples */
115
 
        ulint           max_tuples;     /*!< maximum number of data tuples */
116
 
        const dfield_t**tuples;         /*!< array of pointers to
 
73
        mem_heap_t*     heap;           /* memory heap where allocated */
 
74
        dict_index_t*   index;          /* the index the tuples belong to */
 
75
        ulint           total_size;     /* total amount of data bytes */
 
76
        ulint           n_tuples;       /* number of data tuples */
 
77
        ulint           max_tuples;     /* maximum number of data tuples */
 
78
        const dfield_t**tuples;         /* array of pointers to
117
79
                                        arrays of fields that form
118
80
                                        the data tuples */
119
 
        const dfield_t**tmp_tuples;     /*!< temporary copy of tuples,
 
81
        const dfield_t**tmp_tuples;     /* temporary copy of tuples,
120
82
                                        for sorting */
121
83
};
122
84
 
123
 
/** Buffer for sorting in main memory. */
124
85
typedef struct row_merge_buf_struct row_merge_buf_t;
125
86
 
126
 
/** Information about temporary files used in merge sort */
 
87
/* Information about temporary files used in merge sort are stored
 
88
to this structure */
 
89
 
127
90
struct merge_file_struct {
128
 
        int             fd;             /*!< file descriptor */
129
 
        ulint           offset;         /*!< file offset (end of file) */
130
 
        ib_uint64_t     n_rec;          /*!< number of records in the file */
 
91
        int     fd;             /* File descriptor */
 
92
        ulint   offset;         /* File offset */
131
93
};
132
94
 
133
 
/** Information about temporary files used in merge sort */
134
95
typedef struct merge_file_struct merge_file_t;
135
96
 
136
97
#ifdef UNIV_DEBUG
137
 
/******************************************************//**
 
98
/**********************************************************
138
99
Display a merge tuple. */
139
100
static
140
101
void
141
102
row_merge_tuple_print(
142
103
/*==================*/
143
 
        FILE*           f,      /*!< in: output stream */
144
 
        const dfield_t* entry,  /*!< in: tuple to print */
145
 
        ulint           n_fields)/*!< in: number of fields in the tuple */
 
104
        FILE*           f,      /* in: output stream */
 
105
        const dfield_t* entry,  /* in: tuple to print */
 
106
        ulint           n_fields)/* in: number of fields in the tuple */
146
107
{
147
108
        ulint   j;
148
109
 
169
130
}
170
131
#endif /* UNIV_DEBUG */
171
132
 
172
 
/******************************************************//**
173
 
Allocate a sort buffer.
174
 
@return own: sort buffer */
 
133
/**********************************************************
 
134
Allocate a sort buffer. */
175
135
static
176
136
row_merge_buf_t*
177
137
row_merge_buf_create_low(
178
138
/*=====================*/
179
 
        mem_heap_t*     heap,           /*!< in: heap where allocated */
180
 
        dict_index_t*   index,          /*!< in: secondary index */
181
 
        ulint           max_tuples,     /*!< in: maximum number of data tuples */
182
 
        ulint           buf_size)       /*!< in: size of the buffer, in bytes */
 
139
                                        /* out,own: sort buffer */
 
140
        mem_heap_t*     heap,           /* in: heap where allocated */
 
141
        dict_index_t*   index,          /* in: secondary index */
 
142
        ulint           max_tuples,     /* in: maximum number of data tuples */
 
143
        ulint           buf_size)       /* in: size of the buffer, in bytes */
183
144
{
184
145
        row_merge_buf_t*        buf;
185
146
 
187
148
        ut_ad(max_tuples <= sizeof(row_merge_block_t));
188
149
        ut_ad(max_tuples < buf_size);
189
150
 
190
 
        buf = static_cast<row_merge_buf_t *>(mem_heap_zalloc(heap, buf_size));
 
151
        buf = mem_heap_zalloc(heap, buf_size);
191
152
        buf->heap = heap;
192
153
        buf->index = index;
193
154
        buf->max_tuples = max_tuples;
194
 
        buf->tuples = static_cast<const dfield_t **>(mem_heap_alloc(heap,
195
 
                                     2 * max_tuples * sizeof *buf->tuples));
 
155
        buf->tuples = mem_heap_alloc(heap,
 
156
                                     2 * max_tuples * sizeof *buf->tuples);
196
157
        buf->tmp_tuples = buf->tuples + max_tuples;
197
158
 
198
159
        return(buf);
199
160
}
200
161
 
201
 
/******************************************************//**
202
 
Allocate a sort buffer.
203
 
@return own: sort buffer */
 
162
/**********************************************************
 
163
Allocate a sort buffer. */
204
164
static
205
165
row_merge_buf_t*
206
166
row_merge_buf_create(
207
167
/*=================*/
208
 
        dict_index_t*   index)  /*!< in: secondary index */
 
168
                                /* out,own: sort buffer */
 
169
        dict_index_t*   index)  /* in: secondary index */
209
170
{
210
171
        row_merge_buf_t*        buf;
211
172
        ulint                   max_tuples;
224
185
        return(buf);
225
186
}
226
187
 
227
 
/******************************************************//**
228
 
Empty a sort buffer.
229
 
@return sort buffer */
 
188
/**********************************************************
 
189
Empty a sort buffer. */
230
190
static
231
191
row_merge_buf_t*
232
192
row_merge_buf_empty(
233
193
/*================*/
234
 
        row_merge_buf_t*        buf)    /*!< in,own: sort buffer */
 
194
                                        /* out: sort buffer */
 
195
        row_merge_buf_t*        buf)    /* in,own: sort buffer */
235
196
{
236
197
        ulint           buf_size;
237
198
        ulint           max_tuples      = buf->max_tuples;
245
206
        return(row_merge_buf_create_low(heap, index, max_tuples, buf_size));
246
207
}
247
208
 
248
 
/******************************************************//**
 
209
/**********************************************************
249
210
Deallocate a sort buffer. */
250
211
static
251
212
void
252
213
row_merge_buf_free(
253
214
/*===============*/
254
 
        row_merge_buf_t*        buf)    /*!< in,own: sort buffer, to be freed */
 
215
        row_merge_buf_t*        buf)    /* in,own: sort buffer, to be freed */
255
216
{
256
217
        mem_heap_free(buf->heap);
257
218
}
258
219
 
259
 
/******************************************************//**
260
 
Insert a data tuple into a sort buffer.
261
 
@return TRUE if added, FALSE if out of space */
 
220
/**********************************************************
 
221
Insert a data tuple into a sort buffer. */
262
222
static
263
223
ibool
264
224
row_merge_buf_add(
265
225
/*==============*/
266
 
        row_merge_buf_t*        buf,    /*!< in/out: sort buffer */
267
 
        const dtuple_t*         row,    /*!< in: row in clustered index */
268
 
        const row_ext_t*        ext)    /*!< in: cache of externally stored
 
226
                                        /* out: TRUE if added,
 
227
                                        FALSE if out of space */
 
228
        row_merge_buf_t*        buf,    /* in/out: sort buffer */
 
229
        const dtuple_t*         row,    /* in: row in clustered index */
 
230
        const row_ext_t*        ext)    /* in: cache of externally stored
269
231
                                        column prefixes, or NULL */
270
232
{
271
233
        ulint                   i;
275
237
        const dict_index_t*     index;
276
238
        dfield_t*               entry;
277
239
        dfield_t*               field;
278
 
        const dict_field_t*     ifield;
279
240
 
280
241
        if (buf->n_tuples >= buf->max_tuples) {
281
242
                return(FALSE);
287
248
 
288
249
        n_fields = dict_index_get_n_fields(index);
289
250
 
290
 
        entry = static_cast<dfield_t *>(mem_heap_alloc(buf->heap, n_fields * sizeof *entry));
 
251
        entry = mem_heap_alloc(buf->heap, n_fields * sizeof *entry);
291
252
        buf->tuples[buf->n_tuples] = entry;
292
253
        field = entry;
293
254
 
294
255
        data_size = 0;
295
256
        extra_size = UT_BITS_IN_BYTES(index->n_nullable);
296
257
 
297
 
        ifield = dict_index_get_nth_field(index, 0);
298
 
 
299
 
        for (i = 0; i < n_fields; i++, field++, ifield++) {
 
258
        for (i = 0; i < n_fields; i++, field++) {
 
259
                const dict_field_t*     ifield;
300
260
                const dict_col_t*       col;
301
261
                ulint                   col_no;
302
262
                const dfield_t*         row_field;
303
263
                ulint                   len;
304
264
 
 
265
                ifield = dict_index_get_nth_field(index, i);
305
266
                col = ifield->col;
306
267
                col_no = dict_col_get_no(col);
307
268
                row_field = dtuple_get_nth_field(row, col_no);
314
275
                } else if (UNIV_LIKELY(!ext)) {
315
276
                } else if (dict_index_is_clust(index)) {
316
277
                        /* Flag externally stored fields. */
317
 
                        const byte*     row_buf = row_ext_lookup(ext, col_no,
 
278
                        const byte*     buf = row_ext_lookup(ext, col_no,
318
279
                                                             &len);
319
 
                        if (UNIV_LIKELY_NULL(row_buf)) {
320
 
                                ut_a(row_buf != field_ref_zero);
 
280
                        if (UNIV_LIKELY_NULL(buf)) {
 
281
                                ut_a(buf != field_ref_zero);
321
282
                                if (i < dict_index_get_n_unique(index)) {
322
 
                                        dfield_set_data(field, row_buf, len);
 
283
                                        dfield_set_data(field, buf, len);
323
284
                                } else {
324
285
                                        dfield_set_ext(field);
325
286
                                        len = dfield_get_len(field);
326
287
                                }
327
288
                        }
328
289
                } else {
329
 
                        const byte*     row_buf = row_ext_lookup(ext, col_no,
 
290
                        const byte*     buf = row_ext_lookup(ext, col_no,
330
291
                                                             &len);
331
 
                        if (UNIV_LIKELY_NULL(row_buf)) {
332
 
                                ut_a(row_buf != field_ref_zero);
333
 
                                dfield_set_data(field, row_buf, len);
 
292
                        if (UNIV_LIKELY_NULL(buf)) {
 
293
                                ut_a(buf != field_ref_zero);
 
294
                                dfield_set_data(field, buf, len);
334
295
                        }
335
296
                }
336
297
 
339
300
                if (ifield->prefix_len) {
340
301
                        len = dtype_get_at_most_n_mbchars(
341
302
                                col->prtype,
342
 
                                col->mbminmaxlen,
 
303
                                col->mbminlen, col->mbmaxlen,
343
304
                                ifield->prefix_len,
344
 
                                len, static_cast<const char *>(dfield_get_data(field)));
 
305
                                len, dfield_get_data(field));
345
306
                        dfield_set_len(field, len);
346
307
                }
347
308
 
412
373
        return(TRUE);
413
374
}
414
375
 
415
 
/** Structure for reporting duplicate records. */
 
376
/* Structure for reporting duplicate records. */
416
377
struct row_merge_dup_struct {
417
 
        const dict_index_t*     index;          /*!< index being sorted */
418
 
        TABLE*          table;          /*!< MySQL table object */
419
 
        ulint                   n_dup;          /*!< number of duplicates */
 
378
        const dict_index_t*     index;          /* index being sorted */
 
379
        TABLE*                  table;          /* MySQL table object */
 
380
        ulint                   n_dup;          /* number of duplicates */
420
381
};
421
382
 
422
 
/** Structure for reporting duplicate records. */
423
383
typedef struct row_merge_dup_struct row_merge_dup_t;
424
384
 
425
 
/*************************************************************//**
 
385
/*****************************************************************
426
386
Report a duplicate key. */
427
387
static
428
388
void
429
389
row_merge_dup_report(
430
390
/*=================*/
431
 
        row_merge_dup_t*        dup,    /*!< in/out: for reporting duplicates */
432
 
        const dfield_t*         entry)  /*!< in: duplicate index entry */
 
391
        row_merge_dup_t*        dup,    /* in/out: for reporting duplicates */
 
392
        const dfield_t*         entry)  /* in: duplicate index entry */
433
393
{
434
 
        mrec_buf_t*             buf;
 
394
        mrec_buf_t              buf;
435
395
        const dtuple_t*         tuple;
436
396
        dtuple_t                tuple_store;
437
397
        const rec_t*            rec;
438
398
        const dict_index_t*     index   = dup->index;
439
399
        ulint                   n_fields= dict_index_get_n_fields(index);
440
 
        mem_heap_t*             heap;
 
400
        mem_heap_t*             heap    = NULL;
 
401
        ulint                   offsets_[REC_OFFS_NORMAL_SIZE];
441
402
        ulint*                  offsets;
442
403
        ulint                   n_ext;
443
404
 
447
408
                return;
448
409
        }
449
410
 
 
411
        rec_offs_init(offsets_);
 
412
 
450
413
        /* Convert the tuple to a record and then to MySQL format. */
451
 
        heap = mem_heap_create((1 + REC_OFFS_HEADER_SIZE + n_fields)
452
 
                               * sizeof *offsets
453
 
                               + sizeof *buf);
454
 
 
455
 
        buf = static_cast<mrec_buf_t *>(mem_heap_alloc(heap, sizeof *buf));
456
414
 
457
415
        tuple = dtuple_from_fields(&tuple_store, entry, n_fields);
458
416
        n_ext = dict_index_is_clust(index) ? dtuple_get_n_ext(tuple) : 0;
459
417
 
460
 
        rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext);
461
 
        offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
 
418
        rec = rec_convert_dtuple_to_rec(buf, index, tuple, n_ext);
 
419
        offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED,
 
420
                                  &heap);
462
421
 
463
422
        innobase_rec_to_mysql(dup->table, rec, index, offsets);
464
423
 
465
 
        mem_heap_free(heap);
 
424
        if (UNIV_LIKELY_NULL(heap)) {
 
425
                mem_heap_free(heap);
 
426
        }
466
427
}
467
428
 
468
 
/*************************************************************//**
469
 
Compare two tuples.
470
 
@return 1, 0, -1 if a is greater, equal, less, respectively, than b */
 
429
/*****************************************************************
 
430
Compare two tuples. */
471
431
static
472
432
int
473
433
row_merge_tuple_cmp(
474
434
/*================*/
475
 
        ulint                   n_field,/*!< in: number of fields */
476
 
        const dfield_t*         a,      /*!< in: first tuple to be compared */
477
 
        const dfield_t*         b,      /*!< in: second tuple to be compared */
478
 
        row_merge_dup_t*        dup)    /*!< in/out: for reporting duplicates */
 
435
                                        /* out: 1, 0, -1 if a is greater,
 
436
                                        equal, less, respectively, than b */
 
437
        ulint                   n_field,/* in: number of fields */
 
438
        const dfield_t*         a,      /* in: first tuple to be compared */
 
439
        const dfield_t*         b,      /* in: second tuple to be compared */
 
440
        row_merge_dup_t*        dup)    /* in/out: for reporting duplicates */
479
441
{
480
442
        int             cmp;
481
443
        const dfield_t* field   = a;
482
444
 
483
 
        /* Compare the fields of the tuples until a difference is
484
 
        found or we run out of fields to compare.  If !cmp at the
485
 
        end, the tuples are equal. */
486
445
        do {
487
446
                cmp = cmp_dfield_dfield(a++, b++);
488
447
        } while (!cmp && --n_field);
489
448
 
490
449
        if (UNIV_UNLIKELY(!cmp) && UNIV_LIKELY_NULL(dup)) {
491
 
                /* Report a duplicate value error if the tuples are
492
 
                logically equal.  NULL columns are logically inequal,
493
 
                although they are equal in the sorting order.  Find
494
 
                out if any of the fields are NULL. */
495
 
                for (b = field; b != a; b++) {
496
 
                        if (dfield_is_null(b)) {
497
 
 
498
 
                                goto func_exit;
499
 
                        }
500
 
                }
501
 
 
502
450
                row_merge_dup_report(dup, field);
503
451
        }
504
452
 
505
 
func_exit:
506
453
        return(cmp);
507
454
}
508
455
 
509
 
/** Wrapper for row_merge_tuple_sort() to inject some more context to
510
 
UT_SORT_FUNCTION_BODY().
511
 
@param a        array of tuples that being sorted
512
 
@param b        aux (work area), same size as tuples[]
513
 
@param c        lower bound of the sorting area, inclusive
514
 
@param d        upper bound of the sorting area, inclusive */
515
 
#define row_merge_tuple_sort_ctx(a,b,c,d) \
516
 
        row_merge_tuple_sort(n_field, dup, a, b, c, d)
517
 
/** Wrapper for row_merge_tuple_cmp() to inject some more context to
518
 
UT_SORT_FUNCTION_BODY().
519
 
@param a        first tuple to be compared
520
 
@param b        second tuple to be compared
521
 
@return 1, 0, -1 if a is greater, equal, less, respectively, than b */
522
 
#define row_merge_tuple_cmp_ctx(a,b) row_merge_tuple_cmp(n_field, a, b, dup)
523
 
 
524
 
/**********************************************************************//**
 
456
/**************************************************************************
525
457
Merge sort the tuple buffer in main memory. */
526
458
static
527
459
void
528
460
row_merge_tuple_sort(
529
461
/*=================*/
530
 
        ulint                   n_field,/*!< in: number of fields */
531
 
        row_merge_dup_t*        dup,    /*!< in/out: for reporting duplicates */
532
 
        const dfield_t**        tuples, /*!< in/out: tuples */
533
 
        const dfield_t**        aux,    /*!< in/out: work area */
534
 
        ulint                   low,    /*!< in: lower bound of the
 
462
        ulint                   n_field,/* in: number of fields */
 
463
        row_merge_dup_t*        dup,    /* in/out: for reporting duplicates */
 
464
        const dfield_t**        tuples, /* in/out: tuples */
 
465
        const dfield_t**        aux,    /* in/out: work area */
 
466
        ulint                   low,    /* in: lower bound of the
535
467
                                        sorting area, inclusive */
536
 
        ulint                   high)   /*!< in: upper bound of the
 
468
        ulint                   high)   /* in: upper bound of the
537
469
                                        sorting area, exclusive */
538
470
{
 
471
#define row_merge_tuple_sort_ctx(a,b,c,d) \
 
472
        row_merge_tuple_sort(n_field, dup, a, b, c, d)
 
473
#define row_merge_tuple_cmp_ctx(a,b) row_merge_tuple_cmp(n_field, a, b, dup)
 
474
 
539
475
        UT_SORT_FUNCTION_BODY(row_merge_tuple_sort_ctx,
540
476
                              tuples, aux, low, high, row_merge_tuple_cmp_ctx);
541
477
}
542
478
 
543
 
/******************************************************//**
 
479
/**********************************************************
544
480
Sort a buffer. */
545
481
static
546
482
void
547
483
row_merge_buf_sort(
548
484
/*===============*/
549
 
        row_merge_buf_t*        buf,    /*!< in/out: sort buffer */
550
 
        row_merge_dup_t*        dup)    /*!< in/out: for reporting duplicates */
 
485
        row_merge_buf_t*        buf,    /* in/out: sort buffer */
 
486
        row_merge_dup_t*        dup)    /* in/out: for reporting duplicates */
551
487
{
552
488
        row_merge_tuple_sort(dict_index_get_n_unique(buf->index), dup,
553
489
                             buf->tuples, buf->tmp_tuples, 0, buf->n_tuples);
554
490
}
555
491
 
556
 
/******************************************************//**
 
492
/**********************************************************
557
493
Write a buffer to a block. */
558
494
static
559
495
void
560
496
row_merge_buf_write(
561
497
/*================*/
562
 
        const row_merge_buf_t*  buf,    /*!< in: sorted buffer */
 
498
        const row_merge_buf_t*  buf,    /* in: sorted buffer */
563
499
#ifdef UNIV_DEBUG
564
 
        const merge_file_t*     of,     /*!< in: output file */
 
500
        const merge_file_t*     of,     /* in: output file */
565
501
#endif /* UNIV_DEBUG */
566
 
        row_merge_block_t*      block)  /*!< out: buffer for writing to file */
 
502
        row_merge_block_t*      block)  /* out: buffer for writing to file */
567
503
#ifndef UNIV_DEBUG
568
504
# define row_merge_buf_write(buf, of, block) row_merge_buf_write(buf, block)
569
505
#endif /* !UNIV_DEBUG */
632
568
#endif /* UNIV_DEBUG */
633
569
}
634
570
 
635
 
/******************************************************//**
636
 
Create a memory heap and allocate space for row_merge_rec_offsets()
637
 
and mrec_buf_t[3].
638
 
@return memory heap */
 
571
/**********************************************************
 
572
Create a memory heap and allocate space for row_merge_rec_offsets(). */
639
573
static
640
574
mem_heap_t*
641
575
row_merge_heap_create(
642
576
/*==================*/
643
 
        const dict_index_t*     index,          /*!< in: record descriptor */
644
 
        mrec_buf_t**            buf,            /*!< out: 3 buffers */
645
 
        ulint**                 offsets1,       /*!< out: offsets */
646
 
        ulint**                 offsets2)       /*!< out: offsets */
 
577
                                                /* out: memory heap */
 
578
        const dict_index_t*     index,          /* in: record descriptor */
 
579
        ulint**                 offsets1,       /* out: offsets */
 
580
        ulint**                 offsets2)       /* out: offsets */
647
581
{
648
582
        ulint           i       = 1 + REC_OFFS_HEADER_SIZE
649
583
                + dict_index_get_n_fields(index);
650
 
        mem_heap_t*     heap    = mem_heap_create(2 * i * sizeof **offsets1
651
 
                                                  + 3 * sizeof **buf);
 
584
        mem_heap_t*     heap    = mem_heap_create(2 * i * sizeof *offsets1);
652
585
 
653
 
        *buf = static_cast<mrec_buf_t*>(mem_heap_alloc(heap, 3 * sizeof **buf));
654
 
        *offsets1 = static_cast<ulint*>(mem_heap_alloc(heap, i * sizeof **offsets1));
655
 
        *offsets2 = static_cast<ulint*>(mem_heap_alloc(heap, i * sizeof **offsets2));
 
586
        *offsets1 = mem_heap_alloc(heap, i * sizeof *offsets1);
 
587
        *offsets2 = mem_heap_alloc(heap, i * sizeof *offsets2);
656
588
 
657
589
        (*offsets1)[0] = (*offsets2)[0] = i;
658
590
        (*offsets1)[1] = (*offsets2)[1] = dict_index_get_n_fields(index);
660
592
        return(heap);
661
593
}
662
594
 
663
 
/**********************************************************************//**
 
595
/**************************************************************************
664
596
Search an index object by name and column names.  If several indexes match,
665
 
return the index with the max id.
666
 
@return matching index, NULL if not found */
 
597
return the index with the max id. */
667
598
static
668
599
dict_index_t*
669
600
row_merge_dict_table_get_index(
670
601
/*===========================*/
671
 
        dict_table_t*           table,          /*!< in: table */
672
 
        const merge_index_def_t*index_def)      /*!< in: index definition */
 
602
                                                /* out: matching index,
 
603
                                                NULL if not found */
 
604
        dict_table_t*           table,          /* in: table */
 
605
        const merge_index_def_t*index_def)      /* in: index definition */
673
606
{
674
607
        ulint           i;
675
608
        dict_index_t*   index;
676
609
        const char**    column_names;
677
610
 
678
 
        column_names = static_cast<const char **>(mem_alloc(index_def->n_fields * sizeof *column_names));
 
611
        column_names = mem_alloc(index_def->n_fields * sizeof *column_names);
679
612
 
680
613
        for (i = 0; i < index_def->n_fields; ++i) {
681
614
                column_names[i] = index_def->fields[i].field_name;
689
622
        return(index);
690
623
}
691
624
 
692
 
/********************************************************************//**
693
 
Read a merge block from the file system.
694
 
@return TRUE if request was successful, FALSE if fail */
 
625
/************************************************************************
 
626
Read a merge block from the file system. */
695
627
static
696
628
ibool
697
629
row_merge_read(
698
630
/*===========*/
699
 
        int                     fd,     /*!< in: file descriptor */
700
 
        ulint                   offset, /*!< in: offset where to read
701
 
                                        in number of row_merge_block_t
702
 
                                        elements */
703
 
        row_merge_block_t*      buf)    /*!< out: data */
 
631
                                        /* out: TRUE if request was
 
632
                                        successful, FALSE if fail */
 
633
        int                     fd,     /* in: file descriptor */
 
634
        ulint                   offset, /* in: offset where to read */
 
635
        row_merge_block_t*      buf)    /* out: data */
704
636
{
705
637
        ib_uint64_t     ofs = ((ib_uint64_t) offset) * sizeof *buf;
706
638
        ibool           success;
707
639
 
708
 
#ifdef UNIV_DEBUG
709
 
        if (row_merge_print_block_read) {
710
 
                fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n",
711
 
                        fd, (ulong) offset);
712
 
        }
713
 
#endif /* UNIV_DEBUG */
714
 
 
715
640
        success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf,
716
641
                                                 (ulint) (ofs & 0xFFFFFFFF),
717
642
                                                 (ulint) (ofs >> 32),
718
643
                                                 sizeof *buf);
719
 
#ifdef POSIX_FADV_DONTNEED
720
 
        /* Each block is read exactly once.  Free up the file cache. */
721
 
        posix_fadvise(fd, ofs, sizeof *buf, POSIX_FADV_DONTNEED);
722
 
#endif /* POSIX_FADV_DONTNEED */
723
 
 
724
644
        if (UNIV_UNLIKELY(!success)) {
725
645
                ut_print_timestamp(stderr);
726
646
                fprintf(stderr,
730
650
        return(UNIV_LIKELY(success));
731
651
}
732
652
 
733
 
/********************************************************************//**
734
 
Write a merge block to the file system.
735
 
@return TRUE if request was successful, FALSE if fail */
 
653
/************************************************************************
 
654
Read a merge block from the file system. */
736
655
static
737
656
ibool
738
657
row_merge_write(
739
658
/*============*/
740
 
        int             fd,     /*!< in: file descriptor */
741
 
        ulint           offset, /*!< in: offset where to write,
742
 
                                in number of row_merge_block_t elements */
743
 
        const void*     buf)    /*!< in: data */
 
659
                                /* out: TRUE if request was
 
660
                                successful, FALSE if fail */
 
661
        int             fd,     /* in: file descriptor */
 
662
        ulint           offset, /* in: offset where to write */
 
663
        const void*     buf)    /* in: data */
744
664
{
745
 
        size_t          buf_len = sizeof(row_merge_block_t);
746
 
        ib_uint64_t     ofs = buf_len * (ib_uint64_t) offset;
747
 
        ibool           ret;
748
 
 
749
 
        ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf,
750
 
                            (ulint) (ofs & 0xFFFFFFFF),
751
 
                            (ulint) (ofs >> 32),
752
 
                            buf_len);
753
 
 
754
 
#ifdef UNIV_DEBUG
755
 
        if (row_merge_print_block_write) {
756
 
                fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n",
757
 
                        fd, (ulong) offset);
758
 
        }
759
 
#endif /* UNIV_DEBUG */
760
 
 
761
 
#ifdef POSIX_FADV_DONTNEED
762
 
        /* The block will be needed on the next merge pass,
763
 
        but it can be evicted from the file cache meanwhile. */
764
 
        posix_fadvise(fd, ofs, buf_len, POSIX_FADV_DONTNEED);
765
 
#endif /* POSIX_FADV_DONTNEED */
766
 
 
767
 
        return(UNIV_LIKELY(ret));
 
665
        ib_uint64_t     ofs = ((ib_uint64_t) offset)
 
666
                * sizeof(row_merge_block_t);
 
667
 
 
668
        return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf,
 
669
                                         (ulint) (ofs & 0xFFFFFFFF),
 
670
                                         (ulint) (ofs >> 32),
 
671
                                         sizeof(row_merge_block_t))));
768
672
}
769
673
 
770
 
/********************************************************************//**
771
 
Read a merge record.
772
 
@return pointer to next record, or NULL on I/O error or end of list */
773
 
static __attribute__((nonnull))
 
674
/************************************************************************
 
675
Read a merge record. */
 
676
static
774
677
const byte*
775
678
row_merge_read_rec(
776
679
/*===============*/
777
 
        row_merge_block_t*      block,  /*!< in/out: file buffer */
778
 
        mrec_buf_t*             buf,    /*!< in/out: secondary buffer */
779
 
        const byte*             b,      /*!< in: pointer to record */
780
 
        const dict_index_t*     index,  /*!< in: index of the record */
781
 
        int                     fd,     /*!< in: file descriptor */
782
 
        ulint*                  foffs,  /*!< in/out: file offset */
783
 
        const mrec_t**          mrec,   /*!< out: pointer to merge record,
 
680
                                        /* out: pointer to next record,
 
681
                                        or NULL on I/O error
 
682
                                        or end of list */
 
683
        row_merge_block_t*      block,  /* in/out: file buffer */
 
684
        mrec_buf_t*             buf,    /* in/out: secondary buffer */
 
685
        const byte*             b,      /* in: pointer to record */
 
686
        const dict_index_t*     index,  /* in: index of the record */
 
687
        int                     fd,     /* in: file descriptor */
 
688
        ulint*                  foffs,  /* in/out: file offset */
 
689
        const mrec_t**          mrec,   /* out: pointer to merge record,
784
690
                                        or NULL on end of list
785
691
                                        (non-NULL on I/O error) */
786
 
        ulint*                  offsets)/*!< out: offsets of mrec */
 
692
        ulint*                  offsets)/* out: offsets of mrec */
787
693
{
788
694
        ulint   extra_size;
789
695
        ulint   data_size;
901
807
        avail_size = block[1] - b;
902
808
        memcpy(*buf, b, avail_size);
903
809
        *mrec = *buf + extra_size;
904
 
#ifdef UNIV_DEBUG
905
 
        /* We cannot invoke rec_offs_make_valid() here, because there
906
 
        are no REC_N_NEW_EXTRA_BYTES between extra_size and data_size.
907
 
        Similarly, rec_offs_validate() would fail, because it invokes
908
 
        rec_get_status(). */
909
 
        offsets[2] = (ulint) *mrec;
910
 
        offsets[3] = (ulint) index;
911
 
#endif /* UNIV_DEBUG */
 
810
        rec_offs_make_valid(*mrec, index, offsets);
912
811
 
913
812
        if (!row_merge_read(fd, ++(*foffs), block)) {
914
813
 
936
835
        return(b);
937
836
}
938
837
 
939
 
/********************************************************************//**
 
838
/************************************************************************
940
839
Write a merge record. */
941
840
static
942
841
void
943
842
row_merge_write_rec_low(
944
843
/*====================*/
945
 
        byte*           b,      /*!< out: buffer */
946
 
        ulint           e,      /*!< in: encoded extra_size */
 
844
        byte*           b,      /* out: buffer */
 
845
        ulint           e,      /* in: encoded extra_size */
947
846
#ifdef UNIV_DEBUG
948
 
        ulint           size,   /*!< in: total size to write */
949
 
        int             fd,     /*!< in: file descriptor */
950
 
        ulint           foffs,  /*!< in: file offset */
 
847
        ulint           size,   /* in: total size to write */
 
848
        int             fd,     /* in: file descriptor */
 
849
        ulint           foffs,  /* in: file offset */
951
850
#endif /* UNIV_DEBUG */
952
 
        const mrec_t*   mrec,   /*!< in: record to write */
953
 
        const ulint*    offsets)/*!< in: offsets of mrec */
 
851
        const mrec_t*   mrec,   /* in: record to write */
 
852
        const ulint*    offsets)/* in: offsets of mrec */
954
853
#ifndef UNIV_DEBUG
955
854
# define row_merge_write_rec_low(b, e, size, fd, foffs, mrec, offsets)  \
956
855
        row_merge_write_rec_low(b, e, mrec, offsets)
979
878
        ut_ad(b + rec_offs_size(offsets) == end);
980
879
}
981
880
 
982
 
/********************************************************************//**
983
 
Write a merge record.
984
 
@return pointer to end of block, or NULL on error */
 
881
/************************************************************************
 
882
Write a merge record. */
985
883
static
986
884
byte*
987
885
row_merge_write_rec(
988
886
/*================*/
989
 
        row_merge_block_t*      block,  /*!< in/out: file buffer */
990
 
        mrec_buf_t*             buf,    /*!< in/out: secondary buffer */
991
 
        byte*                   b,      /*!< in: pointer to end of block */
992
 
        int                     fd,     /*!< in: file descriptor */
993
 
        ulint*                  foffs,  /*!< in/out: file offset */
994
 
        const mrec_t*           mrec,   /*!< in: record to write */
995
 
        const ulint*            offsets)/*!< in: offsets of mrec */
 
887
                                        /* out: pointer to end of block,
 
888
                                        or NULL on error */
 
889
        row_merge_block_t*      block,  /* in/out: file buffer */
 
890
        mrec_buf_t*             buf,    /* in/out: secondary buffer */
 
891
        byte*                   b,      /* in: pointer to end of block */
 
892
        int                     fd,     /* in: file descriptor */
 
893
        ulint*                  foffs,  /* in/out: file offset */
 
894
        const mrec_t*           mrec,   /* in: record to write */
 
895
        const ulint*            offsets)/* in: offsets of mrec */
996
896
{
997
897
        ulint   extra_size;
998
898
        ulint   size;
1046
946
        return(b);
1047
947
}
1048
948
 
1049
 
/********************************************************************//**
1050
 
Write an end-of-list marker.
1051
 
@return pointer to end of block, or NULL on error */
 
949
/************************************************************************
 
950
Write an end-of-list marker. */
1052
951
static
1053
952
byte*
1054
953
row_merge_write_eof(
1055
954
/*================*/
1056
 
        row_merge_block_t*      block,  /*!< in/out: file buffer */
1057
 
        byte*                   b,      /*!< in: pointer to end of block */
1058
 
        int                     fd,     /*!< in: file descriptor */
1059
 
        ulint*                  foffs)  /*!< in/out: file offset */
 
955
                                        /* out: pointer to end of block,
 
956
                                        or NULL on error */
 
957
        row_merge_block_t*      block,  /* in/out: file buffer */
 
958
        byte*                   b,      /* in: pointer to end of block */
 
959
        int                     fd,     /* in: file descriptor */
 
960
        ulint*                  foffs)  /* in/out: file offset */
1060
961
{
1061
962
        ut_ad(block);
1062
963
        ut_ad(b >= block[0]);
1086
987
        return(block[0]);
1087
988
}
1088
989
 
1089
 
/*************************************************************//**
1090
 
Compare two merge records.
1091
 
@return 1, 0, -1 if mrec1 is greater, equal, less, respectively, than mrec2 */
 
990
/*****************************************************************
 
991
Compare two merge records. */
1092
992
static
1093
993
int
1094
994
row_merge_cmp(
1095
995
/*==========*/
1096
 
        const mrec_t*           mrec1,          /*!< in: first merge
1097
 
                                                record to be compared */
1098
 
        const mrec_t*           mrec2,          /*!< in: second merge
1099
 
                                                record to be compared */
1100
 
        const ulint*            offsets1,       /*!< in: first record offsets */
1101
 
        const ulint*            offsets2,       /*!< in: second record offsets */
1102
 
        const dict_index_t*     index,          /*!< in: index */
1103
 
        ibool*                  null_eq)        /*!< out: set to TRUE if
1104
 
                                                found matching null values */
 
996
                                                /* out: 1, 0, -1 if
 
997
                                                mrec1 is greater, equal, less,
 
998
                                                respectively, than mrec2 */
 
999
        const mrec_t*           mrec1,          /* in: first merge
 
1000
                                                record to be compared */
 
1001
        const mrec_t*           mrec2,          /* in: second merge
 
1002
                                                record to be compared */
 
1003
        const ulint*            offsets1,       /* in: first record offsets */
 
1004
        const ulint*            offsets2,       /* in: second record offsets */
 
1005
        const dict_index_t*     index)          /* in: index */
1105
1006
{
1106
1007
        int     cmp;
1107
1008
 
1108
 
        cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index,
1109
 
                                 null_eq);
 
1009
        cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index);
1110
1010
 
1111
1011
#ifdef UNIV_DEBUG
1112
1012
        if (row_merge_print_cmp) {
1121
1021
        return(cmp);
1122
1022
}
1123
1023
 
1124
 
/********************************************************************//**
 
1024
/************************************************************************
1125
1025
Reads clustered index of the table and create temporary files
1126
 
containing the index entries for the indexes to be built.
1127
 
@return DB_SUCCESS or error */
1128
 
static __attribute__((nonnull))
 
1026
containing the index entries for the indexes to be built. */
 
1027
static
1129
1028
ulint
1130
1029
row_merge_read_clustered_index(
1131
1030
/*===========================*/
1132
 
        trx_t*                  trx,    /*!< in: transaction */
1133
 
        TABLE*          table,  /*!< in/out: MySQL table object,
 
1031
                                        /* out: DB_SUCCESS or error */
 
1032
        trx_t*                  trx,    /* in: transaction */
 
1033
        TABLE*                  table,  /* in/out: MySQL table object,
1134
1034
                                        for reporting erroneous records */
1135
 
        const dict_table_t*     old_table,/*!< in: table where rows are
 
1035
        const dict_table_t*     old_table,/* in: table where rows are
1136
1036
                                        read from */
1137
 
        const dict_table_t*     new_table,/*!< in: table where indexes are
 
1037
        const dict_table_t*     new_table,/* in: table where indexes are
1138
1038
                                        created; identical to old_table
1139
1039
                                        unless creating a PRIMARY KEY */
1140
 
        dict_index_t**          index,  /*!< in: indexes to be created */
1141
 
        merge_file_t*           files,  /*!< in: temporary files */
1142
 
        ulint                   n_index,/*!< in: number of indexes to create */
1143
 
        row_merge_block_t*      block)  /*!< in/out: file buffer */
 
1040
        dict_index_t**          index,  /* in: indexes to be created */
 
1041
        merge_file_t*           files,  /* in: temporary files */
 
1042
        ulint                   n_index,/* in: number of indexes to create */
 
1043
        row_merge_block_t*      block)  /* in/out: file buffer */
1144
1044
{
1145
1045
        dict_index_t*           clust_index;    /* Clustered index */
1146
1046
        mem_heap_t*             row_heap;       /* Heap memory to create
1165
1065
 
1166
1066
        /* Create and initialize memory for record buffers */
1167
1067
 
1168
 
        merge_buf = static_cast<row_merge_buf_t **>(mem_alloc(n_index * sizeof *merge_buf));
 
1068
        merge_buf = mem_alloc(n_index * sizeof *merge_buf);
1169
1069
 
1170
1070
        for (i = 0; i < n_index; i++) {
1171
1071
                merge_buf[i] = row_merge_buf_create(index[i]);
1192
1092
 
1193
1093
                ut_a(n_cols == dict_table_get_n_cols(new_table));
1194
1094
 
1195
 
                nonnull = static_cast<ulint*>(mem_alloc(n_cols * sizeof *nonnull));
 
1095
                nonnull = mem_alloc(n_cols * sizeof *nonnull);
1196
1096
 
1197
1097
                for (i = 0; i < n_cols; i++) {
1198
1098
                        if (dict_table_get_nth_col(old_table, i)->prtype
1230
1130
                in order to release the latch on the old page. */
1231
1131
 
1232
1132
                if (btr_pcur_is_after_last_on_page(&pcur)) {
1233
 
                        if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1234
 
                                err = DB_INTERRUPTED;
1235
 
                                trx->error_key_num = 0;
1236
 
                                goto func_exit;
1237
 
                        }
1238
 
 
1239
1133
                        btr_pcur_store_position(&pcur, &mtr);
1240
1134
                        mtr_commit(&mtr);
1241
1135
                        mtr_start(&mtr);
1275
1169
 
1276
1170
                                        if (dfield_is_null(field)) {
1277
1171
                                                err = DB_PRIMARY_KEY_IS_NULL;
1278
 
                                                trx->error_key_num = 0;
1279
 
                                                goto func_exit;
 
1172
                                                i = 0;
 
1173
                                                goto err_exit;
1280
1174
                                        }
1281
1175
 
1282
1176
                                        field_type->prtype |= DATA_NOT_NULL;
1290
1184
                for (i = 0; i < n_index; i++) {
1291
1185
                        row_merge_buf_t*        buf     = merge_buf[i];
1292
1186
                        merge_file_t*           file    = &files[i];
1293
 
                        const dict_index_t*     buf_index       = buf->index;
 
1187
                        const dict_index_t*     index   = buf->index;
1294
1188
 
1295
1189
                        if (UNIV_LIKELY
1296
1190
                            (row && row_merge_buf_add(buf, row, ext))) {
1297
 
                                file->n_rec++;
1298
1191
                                continue;
1299
1192
                        }
1300
1193
 
1306
1199
                        Sort them and write to disk. */
1307
1200
 
1308
1201
                        if (buf->n_tuples) {
1309
 
                                if (dict_index_is_unique(buf_index)) {
 
1202
                                if (dict_index_is_unique(index)) {
1310
1203
                                        row_merge_dup_t dup;
1311
1204
                                        dup.index = buf->index;
1312
1205
                                        dup.table = table;
1316
1209
 
1317
1210
                                        if (dup.n_dup) {
1318
1211
                                                err = DB_DUPLICATE_KEY;
 
1212
err_exit:
1319
1213
                                                trx->error_key_num = i;
1320
1214
                                                goto func_exit;
1321
1215
                                        }
1329
1223
                        if (!row_merge_write(file->fd, file->offset++,
1330
1224
                                             block)) {
1331
1225
                                err = DB_OUT_OF_FILE_SPACE;
1332
 
                                trx->error_key_num = i;
1333
 
                                goto func_exit;
 
1226
                                goto err_exit;
1334
1227
                        }
1335
1228
 
1336
1229
                        UNIV_MEM_INVALID(block[0], sizeof block[0]);
1337
1230
                        merge_buf[i] = row_merge_buf_empty(buf);
1338
1231
 
1339
 
                        if (UNIV_LIKELY(row != NULL)) {
1340
 
                                /* Try writing the record again, now
1341
 
                                that the buffer has been written out
1342
 
                                and emptied. */
1343
 
 
1344
 
                                if (UNIV_UNLIKELY
1345
 
                                    (!row_merge_buf_add(buf, row, ext))) {
1346
 
                                        /* An empty buffer should have enough
1347
 
                                        room for at least one record. */
1348
 
                                        ut_error;
1349
 
                                }
1350
 
 
1351
 
                                file->n_rec++;
 
1232
                        /* Try writing the record again, now that
 
1233
                        the buffer has been written out and emptied. */
 
1234
 
 
1235
                        if (UNIV_UNLIKELY
 
1236
                            (row && !row_merge_buf_add(buf, row, ext))) {
 
1237
                                /* An empty buffer should have enough
 
1238
                                room for at least one record. */
 
1239
                                ut_error;
1352
1240
                        }
1353
1241
                }
1354
1242
 
1379
1267
        return(err);
1380
1268
}
1381
1269
 
1382
 
/** Write a record via buffer 2 and read the next record to buffer N.
1383
 
@param N        number of the buffer (0 or 1)
1384
 
@param AT_END   statement to execute at end of input */
 
1270
/*****************************************************************
 
1271
Merge two blocks of linked lists on disk and write a bigger block. */
 
1272
static
 
1273
ulint
 
1274
row_merge_blocks(
 
1275
/*=============*/
 
1276
                                        /* out: DB_SUCCESS or error code */
 
1277
        const dict_index_t*     index,  /* in: index being created */
 
1278
        merge_file_t*           file,   /* in/out: file containing
 
1279
                                        index entries */
 
1280
        row_merge_block_t*      block,  /* in/out: 3 buffers */
 
1281
        ulint*                  foffs0, /* in/out: offset of first
 
1282
                                        source list in the file */
 
1283
        ulint*                  foffs1, /* in/out: offset of second
 
1284
                                        source list in the file */
 
1285
        merge_file_t*           of,     /* in/out: output file */
 
1286
        TABLE*                  table)  /* in/out: MySQL table, for
 
1287
                                        reporting erroneous key value
 
1288
                                        if applicable */
 
1289
{
 
1290
        mem_heap_t*     heap;   /* memory heap for offsets0, offsets1 */
 
1291
 
 
1292
        mrec_buf_t      buf[3]; /* buffer for handling split mrec in block[] */
 
1293
        const byte*     b0;     /* pointer to block[0] */
 
1294
        const byte*     b1;     /* pointer to block[1] */
 
1295
        byte*           b2;     /* pointer to block[2] */
 
1296
        const mrec_t*   mrec0;  /* merge rec, points to block[0] or buf[0] */
 
1297
        const mrec_t*   mrec1;  /* merge rec, points to block[1] or buf[1] */
 
1298
        ulint*          offsets0;/* offsets of mrec0 */
 
1299
        ulint*          offsets1;/* offsets of mrec1 */
 
1300
 
 
1301
        heap = row_merge_heap_create(index, &offsets0, &offsets1);
 
1302
 
 
1303
        /* Write a record and read the next record.  Split the output
 
1304
        file in two halves, which can be merged on the following pass. */
1385
1305
#define ROW_MERGE_WRITE_GET_NEXT(N, AT_END)                             \
1386
1306
        do {                                                            \
1387
1307
                b2 = row_merge_write_rec(&block[2], &buf[2], b2,        \
1388
1308
                                         of->fd, &of->offset,           \
1389
1309
                                         mrec##N, offsets##N);          \
1390
 
                if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) {  \
 
1310
                if (UNIV_UNLIKELY(!b2)) {                               \
1391
1311
                        goto corrupt;                                   \
1392
1312
                }                                                       \
1393
1313
                b##N = row_merge_read_rec(&block[N], &buf[N],           \
1402
1322
                }                                                       \
1403
1323
        } while (0)
1404
1324
 
1405
 
/*************************************************************//**
1406
 
Merge two blocks of records on disk and write a bigger block.
1407
 
@return DB_SUCCESS or error code */
1408
 
static
1409
 
ulint
1410
 
row_merge_blocks(
1411
 
/*=============*/
1412
 
        const dict_index_t*     index,  /*!< in: index being created */
1413
 
        const merge_file_t*     file,   /*!< in: file containing
1414
 
                                        index entries */
1415
 
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1416
 
        ulint*                  foffs0, /*!< in/out: offset of first
1417
 
                                        source list in the file */
1418
 
        ulint*                  foffs1, /*!< in/out: offset of second
1419
 
                                        source list in the file */
1420
 
        merge_file_t*           of,     /*!< in/out: output file */
1421
 
        TABLE*          table)  /*!< in/out: MySQL table, for
1422
 
                                        reporting erroneous key value
1423
 
                                        if applicable */
1424
 
{
1425
 
        mem_heap_t*     heap;   /*!< memory heap for offsets0, offsets1 */
1426
 
 
1427
 
        mrec_buf_t*     buf;    /*!< buffer for handling
1428
 
                                split mrec in block[] */
1429
 
        const byte*     b0;     /*!< pointer to block[0] */
1430
 
        const byte*     b1;     /*!< pointer to block[1] */
1431
 
        byte*           b2;     /*!< pointer to block[2] */
1432
 
        const mrec_t*   mrec0;  /*!< merge rec, points to block[0] or buf[0] */
1433
 
        const mrec_t*   mrec1;  /*!< merge rec, points to block[1] or buf[1] */
1434
 
        ulint*          offsets0;/* offsets of mrec0 */
1435
 
        ulint*          offsets1;/* offsets of mrec1 */
1436
 
 
1437
 
#ifdef UNIV_DEBUG
1438
 
        if (row_merge_print_block) {
1439
 
                fprintf(stderr,
1440
 
                        "row_merge_blocks fd=%d ofs=%lu + fd=%d ofs=%lu"
1441
 
                        " = fd=%d ofs=%lu\n",
1442
 
                        file->fd, (ulong) *foffs0,
1443
 
                        file->fd, (ulong) *foffs1,
1444
 
                        of->fd, (ulong) of->offset);
1445
 
        }
1446
 
#endif /* UNIV_DEBUG */
1447
 
 
1448
 
        heap = row_merge_heap_create(index, &buf, &offsets0, &offsets1);
1449
 
 
1450
 
        buf = static_cast<mrec_buf_t *>(mem_heap_alloc(heap, sizeof(mrec_buf_t) * 3));
1451
 
 
1452
 
        /* Write a record and read the next record.  Split the output
1453
 
        file in two halves, which can be merged on the following pass. */
1454
 
 
1455
1325
        if (!row_merge_read(file->fd, *foffs0, &block[0])
1456
1326
            || !row_merge_read(file->fd, *foffs1, &block[1])) {
1457
1327
corrupt:
1474
1344
        }
1475
1345
 
1476
1346
        while (mrec0 && mrec1) {
1477
 
                ibool   null_eq = FALSE;
1478
1347
                switch (row_merge_cmp(mrec0, mrec1,
1479
 
                                      offsets0, offsets1, index,
1480
 
                                      &null_eq)) {
 
1348
                                      offsets0, offsets1, index)) {
1481
1349
                case 0:
1482
1350
                        if (UNIV_UNLIKELY
1483
 
                            (dict_index_is_unique(index) && !null_eq)) {
 
1351
                            (dict_index_is_unique(index))) {
1484
1352
                                innobase_rec_to_mysql(table, mrec0,
1485
1353
                                                      index, offsets0);
1486
1354
                                mem_heap_free(heap);
1520
1388
        return(b2 ? DB_SUCCESS : DB_CORRUPTION);
1521
1389
}
1522
1390
 
1523
 
/*************************************************************//**
1524
 
Copy a block of index entries.
1525
 
@return TRUE on success, FALSE on failure */
1526
 
static __attribute__((nonnull))
1527
 
ibool
1528
 
row_merge_blocks_copy(
1529
 
/*==================*/
1530
 
        const dict_index_t*     index,  /*!< in: index being created */
1531
 
        const merge_file_t*     file,   /*!< in: input file */
1532
 
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1533
 
        ulint*                  foffs0, /*!< in/out: input file offset */
1534
 
        merge_file_t*           of)     /*!< in/out: output file */
1535
 
{
1536
 
        mem_heap_t*     heap;   /*!< memory heap for offsets0, offsets1 */
1537
 
 
1538
 
        mrec_buf_t*     buf;    /*!< buffer for handling
1539
 
                                split mrec in block[] */
1540
 
        const byte*     b0;     /*!< pointer to block[0] */
1541
 
        byte*           b2;     /*!< pointer to block[2] */
1542
 
        const mrec_t*   mrec0;  /*!< merge rec, points to block[0] */
1543
 
        ulint*          offsets0;/* offsets of mrec0 */
1544
 
        ulint*          offsets1;/* dummy offsets */
1545
 
 
1546
 
#ifdef UNIV_DEBUG
1547
 
        if (row_merge_print_block) {
1548
 
                fprintf(stderr,
1549
 
                        "row_merge_blocks_copy fd=%d ofs=%lu"
1550
 
                        " = fd=%d ofs=%lu\n",
1551
 
                        file->fd, (ulong) foffs0,
1552
 
                        of->fd, (ulong) of->offset);
1553
 
        }
1554
 
#endif /* UNIV_DEBUG */
1555
 
 
1556
 
        heap = row_merge_heap_create(index, &buf, &offsets0, &offsets1);
1557
 
        buf = static_cast<mrec_buf_t *>(mem_heap_alloc(heap, sizeof(mrec_buf_t) * 3));
1558
 
 
1559
 
        /* Write a record and read the next record.  Split the output
1560
 
        file in two halves, which can be merged on the following pass. */
1561
 
 
1562
 
        if (!row_merge_read(file->fd, *foffs0, &block[0])) {
1563
 
corrupt:
1564
 
                mem_heap_free(heap);
1565
 
                return(FALSE);
1566
 
        }
1567
 
 
1568
 
        b0 = block[0];
1569
 
        b2 = block[2];
1570
 
 
1571
 
        b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd,
1572
 
                                foffs0, &mrec0, offsets0);
1573
 
        if (UNIV_UNLIKELY(!b0 && mrec0)) {
1574
 
 
1575
 
                goto corrupt;
1576
 
        }
1577
 
 
1578
 
        if (mrec0) {
1579
 
                /* append all mrec0 to output */
1580
 
                for (;;) {
1581
 
                        ROW_MERGE_WRITE_GET_NEXT(0, goto done0);
1582
 
                }
1583
 
        }
1584
 
done0:
1585
 
 
1586
 
        /* The file offset points to the beginning of the last page
1587
 
        that has been read.  Update it to point to the next block. */
1588
 
        (*foffs0)++;
1589
 
 
1590
 
        mem_heap_free(heap);
1591
 
        return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset)
1592
 
               != NULL);
1593
 
}
1594
 
 
1595
 
/*************************************************************//**
1596
 
Merge disk files.
1597
 
@return DB_SUCCESS or error code */
1598
 
static __attribute__((nonnull))
 
1391
/*****************************************************************
 
1392
Merge disk files. */
 
1393
static
1599
1394
ulint
1600
1395
row_merge(
1601
1396
/*======*/
1602
 
        trx_t*                  trx,    /*!< in: transaction */
1603
 
        const dict_index_t*     index,  /*!< in: index being created */
1604
 
        merge_file_t*           file,   /*!< in/out: file containing
 
1397
                                        /* out: DB_SUCCESS or error code */
 
1398
        const dict_index_t*     index,  /* in: index being created */
 
1399
        merge_file_t*           file,   /* in/out: file containing
1605
1400
                                        index entries */
1606
 
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1607
 
        int*                    tmpfd,  /*!< in/out: temporary file handle */
1608
 
        TABLE*          table,  /*!< in/out: MySQL table, for
1609
 
                                        reporting erroneous key value
1610
 
                                        if applicable */
1611
 
        ulint*                  num_run,/*!< in/out: Number of runs remain
1612
 
                                        to be merged */
1613
 
        ulint*                  run_offset) /*!< in/out: Array contains the
1614
 
                                        first offset number for each merge
1615
 
                                        run */
 
1401
        ulint                   half,   /* in: half the file */
 
1402
        row_merge_block_t*      block,  /* in/out: 3 buffers */
 
1403
        int*                    tmpfd,  /* in/out: temporary file handle */
 
1404
        TABLE*                  table)  /* in/out: MySQL table, for
 
1405
                                        reporting erroneous key value
 
1406
                                        if applicable */
1616
1407
{
1617
 
        ulint           foffs0; /*!< first input offset */
1618
 
        ulint           foffs1; /*!< second input offset */
1619
 
        ulint           error;  /*!< error code */
1620
 
        merge_file_t    of;     /*!< output file */
1621
 
        const ulint     ihalf   = run_offset[*num_run / 2];
1622
 
                                /*!< half the input file */
1623
 
        ulint           n_run   = 0;
1624
 
                                /*!< num of runs generated from this merge */
1625
 
 
 
1408
        ulint           foffs0; /* first input offset */
 
1409
        ulint           foffs1; /* second input offset */
 
1410
        ulint           error;  /* error code */
 
1411
        merge_file_t    of;     /* output file */
1626
1412
 
1627
1413
        UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
1628
 
        ut_ad(ihalf < file->offset);
 
1414
        ut_ad(half > 0);
1629
1415
 
1630
1416
        of.fd = *tmpfd;
1631
1417
        of.offset = 0;
1632
 
        of.n_rec = 0;
1633
 
 
1634
 
#ifdef POSIX_FADV_SEQUENTIAL
1635
 
        /* The input file will be read sequentially, starting from the
1636
 
        beginning and the middle.  In Linux, the POSIX_FADV_SEQUENTIAL
1637
 
        affects the entire file.  Each block will be read exactly once. */
1638
 
        posix_fadvise(file->fd, 0, 0,
1639
 
                      POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
1640
 
#endif /* POSIX_FADV_SEQUENTIAL */
1641
1418
 
1642
1419
        /* Merge blocks to the output file. */
1643
1420
        foffs0 = 0;
1644
 
        foffs1 = ihalf;
1645
 
 
1646
 
        UNIV_MEM_INVALID(run_offset, *num_run * sizeof *run_offset);
1647
 
 
1648
 
        for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
1649
 
 
1650
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1651
 
                        return(DB_INTERRUPTED);
1652
 
                }
1653
 
 
1654
 
                /* Remember the offset number for this run */
1655
 
                run_offset[n_run++] = of.offset;
1656
 
 
 
1421
        foffs1 = half;
 
1422
 
 
1423
        for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) {
1657
1424
                error = row_merge_blocks(index, file, block,
1658
1425
                                         &foffs0, &foffs1, &of, table);
1659
1426
 
1660
1427
                if (error != DB_SUCCESS) {
1661
1428
                        return(error);
1662
1429
                }
1663
 
 
1664
1430
        }
1665
1431
 
1666
 
        /* Copy the last blocks, if there are any. */
1667
 
 
1668
 
        while (foffs0 < ihalf) {
1669
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1670
 
                        return(DB_INTERRUPTED);
1671
 
                }
1672
 
 
1673
 
                /* Remember the offset number for this run */
1674
 
                run_offset[n_run++] = of.offset;
1675
 
 
1676
 
                if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) {
 
1432
        /* Copy the last block, if there is one. */
 
1433
        while (foffs0 < half) {
 
1434
                if (!row_merge_read(file->fd, foffs0++, block)
 
1435
                    || !row_merge_write(of.fd, of.offset++, block)) {
1677
1436
                        return(DB_CORRUPTION);
1678
1437
                }
1679
1438
        }
1680
 
 
1681
 
        ut_ad(foffs0 == ihalf);
1682
 
 
1683
1439
        while (foffs1 < file->offset) {
1684
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1685
 
                        return(DB_INTERRUPTED);
1686
 
                }
1687
 
 
1688
 
                /* Remember the offset number for this run */
1689
 
                run_offset[n_run++] = of.offset;
1690
 
 
1691
 
                if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
 
1440
                if (!row_merge_read(file->fd, foffs1++, block)
 
1441
                    || !row_merge_write(of.fd, of.offset++, block)) {
1692
1442
                        return(DB_CORRUPTION);
1693
1443
                }
1694
1444
        }
1695
1445
 
1696
 
        ut_ad(foffs1 == file->offset);
1697
 
 
1698
 
        if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) {
1699
 
                return(DB_CORRUPTION);
1700
 
        }
1701
 
 
1702
 
        ut_ad(n_run <= *num_run);
1703
 
 
1704
 
        *num_run = n_run;
1705
 
 
1706
 
        /* Each run can contain one or more offsets. As merge goes on,
1707
 
        the number of runs (to merge) will reduce until we have one
1708
 
        single run. So the number of runs will always be smaller than
1709
 
        the number of offsets in file */
1710
 
        ut_ad((*num_run) <= file->offset);
1711
 
 
1712
 
        /* The number of offsets in output file is always equal or
1713
 
        smaller than input file */
1714
 
        ut_ad(of.offset <= file->offset);
1715
 
 
1716
1446
        /* Swap file descriptors for the next pass. */
1717
1447
        *tmpfd = file->fd;
1718
1448
        *file = of;
1722
1452
        return(DB_SUCCESS);
1723
1453
}
1724
1454
 
1725
 
/*************************************************************//**
1726
 
Merge disk files.
1727
 
@return DB_SUCCESS or error code */
 
1455
/*****************************************************************
 
1456
Merge disk files. */
1728
1457
static
1729
1458
ulint
1730
1459
row_merge_sort(
1731
1460
/*===========*/
1732
 
        trx_t*                  trx,    /*!< in: transaction */
1733
 
        const dict_index_t*     index,  /*!< in: index being created */
1734
 
        merge_file_t*           file,   /*!< in/out: file containing
 
1461
                                        /* out: DB_SUCCESS or error code */
 
1462
        const dict_index_t*     index,  /* in: index being created */
 
1463
        merge_file_t*           file,   /* in/out: file containing
1735
1464
                                        index entries */
1736
 
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1737
 
        int*                    tmpfd,  /*!< in/out: temporary file handle */
1738
 
        TABLE*          table)  /*!< in/out: MySQL table, for
 
1465
        row_merge_block_t*      block,  /* in/out: 3 buffers */
 
1466
        int*                    tmpfd,  /* in/out: temporary file handle */
 
1467
        TABLE*                  table)  /* in/out: MySQL table, for
1739
1468
                                        reporting erroneous key value
1740
1469
                                        if applicable */
1741
1470
{
1742
 
        ulint   half = file->offset / 2;
1743
 
        ulint   num_runs;
1744
 
        ulint*  run_offset;
1745
 
        ulint   error = DB_SUCCESS;
1746
 
 
1747
 
        /* Record the number of merge runs we need to perform */
1748
 
        num_runs = file->offset;
1749
 
 
1750
 
        /* If num_runs are less than 1, nothing to merge */
1751
 
        if (num_runs <= 1) {
1752
 
                return(error);
1753
 
        }
1754
 
 
1755
 
        /* "run_offset" records each run's first offset number */
1756
 
        run_offset = (ulint*) mem_alloc(file->offset * sizeof(ulint));
1757
 
 
1758
 
        /* This tells row_merge() where to start for the first round
1759
 
        of merge. */
1760
 
        run_offset[half] = half;
1761
 
 
1762
 
        /* The file should always contain at least one byte (the end
1763
 
        of file marker).  Thus, it must be at least one block. */
1764
 
        ut_ad(file->offset > 0);
1765
 
 
1766
 
        /* Merge the runs until we have one big run */
1767
 
        do {
1768
 
                error = row_merge(trx, index, file, block, tmpfd,
1769
 
                                  table, &num_runs, run_offset);
1770
 
 
1771
 
                UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset);
 
1471
        ulint   blksz;  /* block size */
 
1472
 
 
1473
        for (blksz = 1; blksz < file->offset; blksz *= 2) {
 
1474
                ulint   half;
 
1475
                ulint   error;
 
1476
 
 
1477
                ut_ad(ut_is_2pow(blksz));
 
1478
                half = ut_2pow_round((file->offset + (blksz - 1)) / 2, blksz);
 
1479
                error = row_merge(index, file, half, block, tmpfd, table);
1772
1480
 
1773
1481
                if (error != DB_SUCCESS) {
1774
 
                        break;
 
1482
                        return(error);
1775
1483
                }
1776
 
        } while (num_runs > 1);
1777
 
 
1778
 
        mem_free(run_offset);
1779
 
 
1780
 
        return(error);
 
1484
        }
 
1485
 
 
1486
        return(DB_SUCCESS);
1781
1487
}
1782
1488
 
1783
 
/*************************************************************//**
 
1489
/*****************************************************************
1784
1490
Copy externally stored columns to the data tuple. */
1785
1491
static
1786
1492
void
1787
1493
row_merge_copy_blobs(
1788
1494
/*=================*/
1789
 
        const mrec_t*   mrec,   /*!< in: merge record */
1790
 
        const ulint*    offsets,/*!< in: offsets of mrec */
1791
 
        ulint           zip_size,/*!< in: compressed page size in bytes, or 0 */
1792
 
        dtuple_t*       tuple,  /*!< in/out: data tuple */
1793
 
        mem_heap_t*     heap)   /*!< in/out: memory heap */
 
1495
        const mrec_t*   mrec,   /* in: merge record */
 
1496
        const ulint*    offsets,/* in: offsets of mrec */
 
1497
        ulint           zip_size,/* in: compressed page size in bytes, or 0 */
 
1498
        dtuple_t*       tuple,  /* in/out: data tuple */
 
1499
        mem_heap_t*     heap)   /* in/out: memory heap */
1794
1500
{
1795
1501
        ulint   i;
1796
1502
        ulint   n_fields = dtuple_get_n_fields(tuple);
1813
1519
                (below). */
1814
1520
                data = btr_rec_copy_externally_stored_field(
1815
1521
                        mrec, offsets, zip_size, i, &len, heap);
1816
 
                /* Because we have locked the table, any records
1817
 
                written by incomplete transactions must have been
1818
 
                rolled back already. There must not be any incomplete
1819
 
                BLOB columns. */
1820
 
                ut_a(data);
1821
1522
 
1822
1523
                dfield_set_data(field, data, len);
1823
1524
        }
1824
1525
}
1825
1526
 
1826
 
/********************************************************************//**
 
1527
/************************************************************************
1827
1528
Read sorted file containing index data tuples and insert these data
1828
 
tuples to the index
1829
 
@return DB_SUCCESS or error number */
 
1529
tuples to the index */
1830
1530
static
1831
1531
ulint
1832
1532
row_merge_insert_index_tuples(
1833
1533
/*==========================*/
1834
 
        trx_t*                  trx,    /*!< in: transaction */
1835
 
        dict_index_t*           index,  /*!< in: index */
1836
 
        dict_table_t*           table,  /*!< in: new table */
1837
 
        ulint                   zip_size,/*!< in: compressed page size of
 
1534
                                        /* out: DB_SUCCESS or error number */
 
1535
        trx_t*                  trx,    /* in: transaction */
 
1536
        dict_index_t*           index,  /* in: index */
 
1537
        dict_table_t*           table,  /* in: new table */
 
1538
        ulint                   zip_size,/* in: compressed page size of
1838
1539
                                         the old table, or 0 if uncompressed */
1839
 
        int                     fd,     /*!< in: file descriptor */
1840
 
        row_merge_block_t*      block)  /*!< in/out: file buffer */
 
1540
        int                     fd,     /* in: file descriptor */
 
1541
        row_merge_block_t*      block)  /* in/out: file buffer */
1841
1542
{
 
1543
        mrec_buf_t              buf;
1842
1544
        const byte*             b;
1843
1545
        que_thr_t*              thr;
1844
1546
        ins_node_t*             node;
1857
1559
 
1858
1560
        trx->op_info = "inserting index entries";
1859
1561
 
1860
 
        graph_heap = mem_heap_create(500 + sizeof(mrec_buf_t));
 
1562
        graph_heap = mem_heap_create(500);
1861
1563
        node = ins_node_create(INS_DIRECT, table, graph_heap);
1862
1564
 
1863
1565
        thr = pars_complete_graph_for_exec(node, trx, graph_heap);
1869
1571
        {
1870
1572
                ulint i = 1 + REC_OFFS_HEADER_SIZE
1871
1573
                        + dict_index_get_n_fields(index);
1872
 
                offsets = static_cast<ulint *>(mem_heap_alloc(graph_heap, i * sizeof *offsets));
 
1574
                offsets = mem_heap_alloc(graph_heap, i * sizeof *offsets);
1873
1575
                offsets[0] = i;
1874
1576
                offsets[1] = dict_index_get_n_fields(index);
1875
1577
        }
1879
1581
        if (!row_merge_read(fd, foffs, block)) {
1880
1582
                error = DB_CORRUPTION;
1881
1583
        } else {
1882
 
                mrec_buf_t*     buf = static_cast<mrec_buf_t *>(mem_heap_alloc(graph_heap, sizeof *buf));
1883
 
 
1884
1584
                for (;;) {
1885
1585
                        const mrec_t*   mrec;
1886
1586
                        dtuple_t*       dtuple;
1887
1587
                        ulint           n_ext;
1888
1588
 
1889
 
                        b = row_merge_read_rec(block, buf, b, index,
 
1589
                        b = row_merge_read_rec(block, &buf, b, index,
1890
1590
                                               fd, &foffs, &mrec, offsets);
1891
1591
                        if (UNIV_UNLIKELY(!b)) {
1892
1592
                                /* End of list, or I/O error */
1946
1646
        return(error);
1947
1647
}
1948
1648
 
1949
 
/*********************************************************************//**
1950
 
Sets an exclusive lock on a table, for the duration of creating indexes.
1951
 
@return error code or DB_SUCCESS */
 
1649
/*************************************************************************
 
1650
Sets an exclusive lock on a table, for the duration of creating indexes. */
1952
1651
UNIV_INTERN
1953
1652
ulint
1954
1653
row_merge_lock_table(
1955
1654
/*=================*/
1956
 
        trx_t*          trx,            /*!< in/out: transaction */
1957
 
        dict_table_t*   table,          /*!< in: table to lock */
1958
 
        enum lock_mode  mode)           /*!< in: LOCK_X or LOCK_S */
 
1655
                                        /* out: error code or DB_SUCCESS */
 
1656
        trx_t*          trx,            /* in/out: transaction */
 
1657
        dict_table_t*   table,          /* in: table to lock */
 
1658
        enum lock_mode  mode)           /* in: LOCK_X or LOCK_S */
1959
1659
{
1960
1660
        mem_heap_t*     heap;
1961
1661
        que_thr_t*      thr;
1977
1677
        /* We use the select query graph as the dummy graph needed
1978
1678
        in the lock module call */
1979
1679
 
1980
 
        thr = que_fork_get_first_thr(static_cast<que_fork_t *>(que_node_get_parent(thr)));
 
1680
        thr = que_fork_get_first_thr(que_node_get_parent(thr));
1981
1681
        que_thr_move_to_run_state_for_mysql(thr, trx);
1982
1682
 
1983
1683
run_again:
2007
1707
                        que_node_t*     parent;
2008
1708
 
2009
1709
                        parent = que_node_get_parent(thr);
2010
 
                        run_thr = que_fork_start_command(static_cast<que_fork_t *>(parent));
 
1710
                        run_thr = que_fork_start_command(parent);
2011
1711
 
2012
1712
                        ut_a(run_thr == thr);
2013
1713
 
2025
1725
        return(err);
2026
1726
}
2027
1727
 
2028
 
/*********************************************************************//**
 
1728
/*************************************************************************
2029
1729
Drop an index from the InnoDB system tables.  The data dictionary must
2030
1730
have been locked exclusively by the caller, because the transaction
2031
1731
will not be committed. */
2033
1733
void
2034
1734
row_merge_drop_index(
2035
1735
/*=================*/
2036
 
        dict_index_t*   index,  /*!< in: index to be removed */
2037
 
        dict_table_t*   table,  /*!< in: table */
2038
 
        trx_t*          trx)    /*!< in: transaction handle */
 
1736
        dict_index_t*   index,  /* in: index to be removed */
 
1737
        dict_table_t*   table,  /* in: table */
 
1738
        trx_t*          trx)    /* in: transaction handle */
2039
1739
{
2040
1740
        ulint           err;
2041
1741
        pars_info_t*    info = pars_info_create();
2048
1748
        static const char str1[] =
2049
1749
                "PROCEDURE DROP_INDEX_PROC () IS\n"
2050
1750
                "BEGIN\n"
2051
 
                /* Rename the index, so that it will be dropped by
2052
 
                row_merge_drop_temp_indexes() at crash recovery
2053
 
                if the server crashes before this trx is committed. */
2054
 
                "UPDATE SYS_INDEXES SET NAME=CONCAT('"
2055
 
                TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
2056
 
                "COMMIT WORK;\n"
2057
 
                /* Drop the field definitions of the index. */
2058
1751
                "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
2059
 
                /* Drop the index definition and the B-tree. */
2060
 
                "DELETE FROM SYS_INDEXES WHERE ID = :indexid;\n"
 
1752
                "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n"
 
1753
                "               AND TABLE_ID = :tableid;\n"
2061
1754
                "END;\n";
2062
1755
 
2063
1756
        ut_ad(index && table && trx);
2064
1757
 
2065
 
        pars_info_add_ull_literal(info, "indexid", index->id);
 
1758
        pars_info_add_dulint_literal(info, "indexid", index->id);
 
1759
        pars_info_add_dulint_literal(info, "tableid", table->id);
2066
1760
 
2067
1761
        trx_start_if_not_started(trx);
2068
1762
        trx->op_info = "dropping index";
2076
1770
        /* Replace this index with another equivalent index for all
2077
1771
        foreign key constraints on this table where this index is used */
2078
1772
 
2079
 
        dict_table_replace_index_in_foreign_list(table, index, trx);
 
1773
        dict_table_replace_index_in_foreign_list(table, index);
2080
1774
        dict_index_remove_from_cache(table, index);
2081
1775
 
2082
1776
        trx->op_info = "";
2083
1777
}
2084
1778
 
2085
 
/*********************************************************************//**
 
1779
/*************************************************************************
2086
1780
Drop those indexes which were created before an error occurred when
2087
1781
building an index.  The data dictionary must have been locked
2088
1782
exclusively by the caller, because the transaction will not be
2091
1785
void
2092
1786
row_merge_drop_indexes(
2093
1787
/*===================*/
2094
 
        trx_t*          trx,            /*!< in: transaction */
2095
 
        dict_table_t*   table,          /*!< in: table containing the indexes */
2096
 
        dict_index_t**  index,          /*!< in: indexes to drop */
2097
 
        ulint           num_created)    /*!< in: number of elements in index[] */
 
1788
        trx_t*          trx,            /* in: transaction */
 
1789
        dict_table_t*   table,          /* in: table containing the indexes */
 
1790
        dict_index_t**  index,          /* in: indexes to drop */
 
1791
        ulint           num_created)    /* in: number of elements in index[] */
2098
1792
{
2099
1793
        ulint   key_num;
2100
1794
 
2103
1797
        }
2104
1798
}
2105
1799
 
2106
 
/*********************************************************************//**
 
1800
/*************************************************************************
2107
1801
Drop all partially created indexes during crash recovery. */
2108
1802
UNIV_INTERN
2109
1803
void
2111
1805
/*=============================*/
2112
1806
{
2113
1807
        trx_t*          trx;
2114
 
        btr_pcur_t      pcur;
2115
 
        mtr_t           mtr;
 
1808
        ulint           err;
2116
1809
 
2117
 
        /* Load the table definitions that contain partially defined
2118
 
        indexes, so that the data dictionary information can be checked
2119
 
        when accessing the tablename.ibd files. */
 
1810
        /* We use the private SQL parser of Innobase to generate the
 
1811
        query graphs needed in deleting the dictionary data from system
 
1812
        tables in Innobase. Deleting a row from SYS_INDEXES table also
 
1813
        frees the file segments of the B-tree associated with the index. */
 
1814
#if TEMP_INDEX_PREFIX != '\377'
 
1815
# error "TEMP_INDEX_PREFIX != '\377'"
 
1816
#endif
 
1817
        static const char drop_temp_indexes[] =
 
1818
                "PROCEDURE DROP_TEMP_INDEXES_PROC () IS\n"
 
1819
                "indexid CHAR;\n"
 
1820
                "DECLARE CURSOR c IS SELECT ID FROM SYS_INDEXES\n"
 
1821
                "WHERE SUBSTR(NAME,0,1)='\377' FOR UPDATE;\n"
 
1822
                "BEGIN\n"
 
1823
                "\tOPEN c;\n"
 
1824
                "\tWHILE 1 LOOP\n"
 
1825
                "\t\tFETCH c INTO indexid;\n"
 
1826
                "\t\tIF (SQL % NOTFOUND) THEN\n"
 
1827
                "\t\t\tEXIT;\n"
 
1828
                "\t\tEND IF;\n"
 
1829
                "\t\tDELETE FROM SYS_FIELDS WHERE INDEX_ID = indexid;\n"
 
1830
                "\t\tDELETE FROM SYS_INDEXES WHERE CURRENT OF c;\n"
 
1831
                "\tEND LOOP;\n"
 
1832
                "\tCLOSE c;\n"
 
1833
                "\tCOMMIT WORK;\n"
 
1834
                "END;\n";
2120
1835
 
2121
1836
        trx = trx_allocate_for_background();
2122
1837
        trx->op_info = "dropping partially created indexes";
2123
1838
        row_mysql_lock_data_dictionary(trx);
2124
1839
 
2125
 
        mtr_start(&mtr);
2126
 
 
2127
 
        btr_pcur_open_at_index_side(
2128
 
                TRUE,
2129
 
                dict_table_get_first_index(dict_sys->sys_indexes),
2130
 
                BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
2131
 
 
2132
 
        for (;;) {
2133
 
                const rec_t*    rec;
2134
 
                const byte*     field;
2135
 
                ulint           len;
2136
 
                table_id_t      table_id;
2137
 
                dict_table_t*   table;
2138
 
 
2139
 
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2140
 
 
2141
 
                if (!btr_pcur_is_on_user_rec(&pcur)) {
2142
 
                        break;
2143
 
                }
2144
 
 
2145
 
                rec = btr_pcur_get_rec(&pcur);
2146
 
                field = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_NAME_FIELD,
2147
 
                                              &len);
2148
 
                if (len == UNIV_SQL_NULL || len == 0
2149
 
                    || (char) *field != TEMP_INDEX_PREFIX) {
2150
 
                        continue;
2151
 
                }
2152
 
 
2153
 
                /* This is a temporary index. */
2154
 
 
2155
 
                field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
2156
 
                if (len != 8) {
2157
 
                        /* Corrupted TABLE_ID */
2158
 
                        continue;
2159
 
                }
2160
 
 
2161
 
                table_id = mach_read_from_8(field);
2162
 
 
2163
 
                btr_pcur_store_position(&pcur, &mtr);
2164
 
                btr_pcur_commit_specify_mtr(&pcur, &mtr);
2165
 
 
2166
 
                table = dict_table_get_on_id_low(table_id);
2167
 
 
2168
 
                if (table) {
2169
 
                        dict_index_t*   index;
2170
 
                        dict_index_t*   next_index;
2171
 
 
2172
 
                        for (index = dict_table_get_first_index(table);
2173
 
                             index; index = next_index) {
2174
 
 
2175
 
                                next_index = dict_table_get_next_index(index);
2176
 
 
2177
 
                                if (*index->name == TEMP_INDEX_PREFIX) {
2178
 
                                        row_merge_drop_index(index, table, trx);
2179
 
                                        trx_commit_for_mysql(trx);
2180
 
                                }
2181
 
                        }
2182
 
                }
2183
 
 
2184
 
                mtr_start(&mtr);
2185
 
                btr_pcur_restore_position(BTR_SEARCH_LEAF,
2186
 
                                          &pcur, &mtr);
2187
 
        }
2188
 
 
2189
 
        btr_pcur_close(&pcur);
2190
 
        mtr_commit(&mtr);
 
1840
        err = que_eval_sql(NULL, drop_temp_indexes, FALSE, trx);
 
1841
        ut_a(err == DB_SUCCESS);
 
1842
 
2191
1843
        row_mysql_unlock_data_dictionary(trx);
2192
1844
        trx_free_for_background(trx);
2193
1845
}
2194
1846
 
2195
 
/*********************************************************************//**
 
1847
/*************************************************************************
2196
1848
Create a merge file. */
2197
1849
static
2198
1850
void
2199
1851
row_merge_file_create(
2200
1852
/*==================*/
2201
 
        merge_file_t*   merge_file)     /*!< out: merge file structure */
 
1853
        merge_file_t*   merge_file)     /* out: merge file structure */
2202
1854
{
2203
 
#ifdef UNIV_PFS_IO
2204
 
        /* This temp file open does not go through normal
2205
 
        file APIs, add instrumentation to register with
2206
 
        performance schema */
2207
 
        struct PSI_file_locker* locker = NULL;
2208
 
        PSI_file_locker_state   state;
2209
 
        register_pfs_file_open_begin(&state, locker, innodb_file_temp_key,
2210
 
                                     PSI_FILE_OPEN,
2211
 
                                     "Innodb Merge Temp File",
2212
 
                                     __FILE__, __LINE__);
2213
 
#endif
2214
1855
        merge_file->fd = innobase_mysql_tmpfile();
2215
1856
        merge_file->offset = 0;
2216
 
        merge_file->n_rec = 0;
2217
 
#ifdef UNIV_PFS_IO
2218
 
        register_pfs_file_open_end(locker, merge_file->fd);
2219
 
#endif
2220
1857
}
2221
1858
 
2222
 
/*********************************************************************//**
 
1859
/*************************************************************************
2223
1860
Destroy a merge file. */
2224
1861
static
2225
1862
void
2226
1863
row_merge_file_destroy(
2227
1864
/*===================*/
2228
 
        merge_file_t*   merge_file)     /*!< out: merge file structure */
 
1865
        merge_file_t*   merge_file)     /* out: merge file structure */
2229
1866
{
2230
 
#ifdef UNIV_PFS_IO
2231
 
        struct PSI_file_locker* locker = NULL;
2232
 
        PSI_file_locker_state   state;
2233
 
        register_pfs_file_io_begin(&state, locker, merge_file->fd, 0, PSI_FILE_CLOSE,
2234
 
                                   __FILE__, __LINE__);
2235
 
#endif
2236
1867
        if (merge_file->fd != -1) {
2237
1868
                close(merge_file->fd);
2238
1869
                merge_file->fd = -1;
2239
1870
        }
2240
 
 
2241
 
#ifdef UNIV_PFS_IO
2242
 
        register_pfs_file_io_end(locker, 0);
2243
 
#endif
2244
1871
}
2245
1872
 
2246
 
/*********************************************************************//**
 
1873
/*************************************************************************
2247
1874
Determine the precise type of a column that is added to a tem
2248
 
if a column must be constrained NOT NULL.
2249
 
@return col->prtype, possibly ORed with DATA_NOT_NULL */
 
1875
if a column must be constrained NOT NULL. */
2250
1876
UNIV_INLINE
2251
1877
ulint
2252
1878
row_merge_col_prtype(
2253
1879
/*=================*/
2254
 
        const dict_col_t*       col,            /*!< in: column */
2255
 
        const char*             col_name,       /*!< in: name of the column */
2256
 
        const merge_index_def_t*index_def)      /*!< in: the index definition
 
1880
                                                /* out: col->prtype, possibly
 
1881
                                                ORed with DATA_NOT_NULL */
 
1882
        const dict_col_t*       col,            /* in: column */
 
1883
        const char*             col_name,       /* in: name of the column */
 
1884
        const merge_index_def_t*index_def)      /* in: the index definition
2257
1885
                                                of the primary key */
2258
1886
{
2259
1887
        ulint   prtype = col->prtype;
2278
1906
        return(prtype);
2279
1907
}
2280
1908
 
2281
 
/*********************************************************************//**
 
1909
/*************************************************************************
2282
1910
Create a temporary table for creating a primary key, using the definition
2283
 
of an existing table.
2284
 
@return table, or NULL on error */
 
1911
of an existing table. */
2285
1912
UNIV_INTERN
2286
1913
dict_table_t*
2287
1914
row_merge_create_temporary_table(
2288
1915
/*=============================*/
2289
 
        const char*             table_name,     /*!< in: new table name */
2290
 
        const merge_index_def_t*index_def,      /*!< in: the index definition
 
1916
                                                /* out: table,
 
1917
                                                or NULL on error */
 
1918
        const char*             table_name,     /* in: new table name */
 
1919
        const merge_index_def_t*index_def,      /* in: the index definition
2291
1920
                                                of the primary key */
2292
 
        const dict_table_t*     table,          /*!< in: old table definition */
2293
 
        trx_t*                  trx)            /*!< in/out: transaction
 
1921
        const dict_table_t*     table,          /* in: old table definition */
 
1922
        trx_t*                  trx)            /* in/out: transaction
2294
1923
                                                (sets error_state) */
2295
1924
{
2296
1925
        ulint           i;
2324
1953
 
2325
1954
        if (error != DB_SUCCESS) {
2326
1955
                trx->error_state = error;
 
1956
                dict_mem_table_free(new_table);
2327
1957
                new_table = NULL;
2328
1958
        }
2329
1959
 
2330
1960
        return(new_table);
2331
1961
}
2332
1962
 
2333
 
/*********************************************************************//**
 
1963
/*************************************************************************
2334
1964
Rename the temporary indexes in the dictionary to permanent ones.  The
2335
1965
data dictionary must have been locked exclusively by the caller,
2336
 
because the transaction will not be committed.
2337
 
@return DB_SUCCESS if all OK */
 
1966
because the transaction will not be committed. */
2338
1967
UNIV_INTERN
2339
1968
ulint
2340
1969
row_merge_rename_indexes(
2341
1970
/*=====================*/
2342
 
        trx_t*          trx,            /*!< in/out: transaction */
2343
 
        dict_table_t*   table)          /*!< in/out: table with new indexes */
 
1971
                                        /* out: DB_SUCCESS if all OK */
 
1972
        trx_t*          trx,            /* in/out: transaction */
 
1973
        dict_table_t*   table)          /* in/out: table with new indexes */
2344
1974
{
2345
1975
        ulint           err = DB_SUCCESS;
2346
1976
        pars_info_t*    info = pars_info_create();
2348
1978
        /* We use the private SQL parser of Innobase to generate the
2349
1979
        query graphs needed in renaming indexes. */
2350
1980
 
 
1981
#if TEMP_INDEX_PREFIX != '\377'
 
1982
# error "TEMP_INDEX_PREFIX != '\377'"
 
1983
#endif
 
1984
 
2351
1985
        static const char rename_indexes[] =
2352
1986
                "PROCEDURE RENAME_INDEXES_PROC () IS\n"
2353
1987
                "BEGIN\n"
2354
1988
                "UPDATE SYS_INDEXES SET NAME=SUBSTR(NAME,1,LENGTH(NAME)-1)\n"
2355
 
                "WHERE TABLE_ID = :tableid AND SUBSTR(NAME,0,1)='"
2356
 
                TEMP_INDEX_PREFIX_STR "';\n"
 
1989
                "WHERE TABLE_ID = :tableid AND SUBSTR(NAME,0,1)='\377';\n"
2357
1990
                "END;\n";
2358
1991
 
2359
1992
        ut_ad(table);
2362
1995
 
2363
1996
        trx->op_info = "renaming indexes";
2364
1997
 
2365
 
        pars_info_add_ull_literal(info, "tableid", table->id);
 
1998
        pars_info_add_dulint_literal(info, "tableid", table->id);
2366
1999
 
2367
2000
        err = que_eval_sql(info, rename_indexes, FALSE, trx);
2368
2001
 
2381
2014
        return(err);
2382
2015
}
2383
2016
 
2384
 
/*********************************************************************//**
 
2017
/*************************************************************************
2385
2018
Rename the tables in the data dictionary.  The data dictionary must
2386
2019
have been locked exclusively by the caller, because the transaction
2387
 
will not be committed.
2388
 
@return error code or DB_SUCCESS */
 
2020
will not be committed. */
2389
2021
UNIV_INTERN
2390
2022
ulint
2391
2023
row_merge_rename_tables(
2392
2024
/*====================*/
2393
 
        dict_table_t*   old_table,      /*!< in/out: old table, renamed to
 
2025
                                        /* out: error code or DB_SUCCESS */
 
2026
        dict_table_t*   old_table,      /* in/out: old table, renamed to
2394
2027
                                        tmp_name */
2395
 
        dict_table_t*   new_table,      /*!< in/out: new table, renamed to
 
2028
        dict_table_t*   new_table,      /* in/out: new table, renamed to
2396
2029
                                        old_table->name */
2397
 
        const char*     tmp_name,       /*!< in: new name for old_table */
2398
 
        trx_t*          trx)            /*!< in: transaction handle */
 
2030
        const char*     tmp_name,       /* in: new name for old_table */
 
2031
        trx_t*          trx)            /* in: transaction handle */
2399
2032
{
2400
2033
        ulint           err     = DB_ERROR;
2401
2034
        pars_info_t*    info;
2402
 
        char            old_name[MAX_TABLE_NAME_LEN + 1];
 
2035
        const char*     old_name= old_table->name;
2403
2036
 
2404
2037
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2405
2038
        ut_ad(old_table != new_table);
2407
2040
 
2408
2041
        ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
2409
2042
 
2410
 
        /* store the old/current name to an automatic variable */
2411
 
        if (strlen(old_table->name) + 1 <= sizeof(old_name)) {
2412
 
                memcpy(old_name, old_table->name, strlen(old_table->name) + 1);
2413
 
        } else {
2414
 
                ut_print_timestamp(stderr);
2415
 
                fprintf(stderr, "InnoDB: too long table name: '%s', "
2416
 
                        "max length is %d\n", old_table->name,
2417
 
                        MAX_TABLE_NAME_LEN);
2418
 
                ut_error;
2419
 
        }
2420
 
 
2421
 
        /* store the old/current name to an automatic variable */
2422
 
        if (strlen(old_table->name) + 1 <= sizeof(old_name)) {
2423
 
                memcpy(old_name, old_table->name, strlen(old_table->name) + 1);
2424
 
        } else {
2425
 
                ut_print_timestamp(stderr);
2426
 
                fprintf(stderr, "InnoDB: too long table name: '%s', "
2427
 
                        "max length is %d\n", old_table->name,
2428
 
                        MAX_TABLE_NAME_LEN);
2429
 
                ut_error;
2430
 
        }
2431
 
 
2432
2043
        trx->op_info = "renaming tables";
2433
2044
 
2434
2045
        /* We use the private SQL parser of Innobase to generate the query
2464
2075
                goto err_exit;
2465
2076
        }
2466
2077
 
2467
 
        err = dict_load_foreigns(old_name, FALSE, TRUE);
 
2078
        err = dict_load_foreigns(old_name, TRUE);
2468
2079
 
2469
2080
        if (err != DB_SUCCESS) {
2470
2081
err_exit:
2471
2082
                trx->error_state = DB_SUCCESS;
2472
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2083
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2473
2084
                trx->error_state = DB_SUCCESS;
2474
2085
        }
2475
2086
 
2478
2089
        return(err);
2479
2090
}
2480
2091
 
2481
 
/*********************************************************************//**
2482
 
Create and execute a query graph for creating an index.
2483
 
@return DB_SUCCESS or error code */
 
2092
/*************************************************************************
 
2093
Create and execute a query graph for creating an index. */
2484
2094
static
2485
2095
ulint
2486
2096
row_merge_create_index_graph(
2487
2097
/*=========================*/
2488
 
        trx_t*          trx,            /*!< in: trx */
2489
 
        dict_table_t*   table,          /*!< in: table */
2490
 
        dict_index_t*   index)          /*!< in: index */
 
2098
                                        /* out: DB_SUCCESS or error code */
 
2099
        trx_t*          trx,            /* in: trx */
 
2100
        dict_table_t*   table,          /* in: table */
 
2101
        dict_index_t*   index)          /* in: index */
2491
2102
{
2492
 
        ind_node_t*     node;           /*!< Index creation node */
2493
 
        mem_heap_t*     heap;           /*!< Memory heap */
2494
 
        que_thr_t*      thr;            /*!< Query thread */
 
2103
        ind_node_t*     node;           /* Index creation node */
 
2104
        mem_heap_t*     heap;           /* Memory heap */
 
2105
        que_thr_t*      thr;            /* Query thread */
2495
2106
        ulint           err;
2496
2107
 
2497
2108
        ut_ad(trx);
2504
2115
        node = ind_create_graph_create(index, heap);
2505
2116
        thr = pars_complete_graph_for_exec(node, trx, heap);
2506
2117
 
2507
 
        ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
 
2118
        ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2508
2119
 
2509
2120
        que_run_threads(thr);
2510
2121
 
2515
2126
        return(err);
2516
2127
}
2517
2128
 
2518
 
/*********************************************************************//**
2519
 
Create the index and load in to the dictionary.
2520
 
@return index, or NULL on error */
 
2129
/*************************************************************************
 
2130
Create the index and load in to the dictionary. */
2521
2131
UNIV_INTERN
2522
2132
dict_index_t*
2523
2133
row_merge_create_index(
2524
2134
/*===================*/
2525
 
        trx_t*                  trx,    /*!< in/out: trx (sets error_state) */
2526
 
        dict_table_t*           table,  /*!< in: the index is on this table */
2527
 
        const merge_index_def_t*index_def)
2528
 
                                        /*!< in: the index definition */
 
2135
                                        /* out: index, or NULL on error */
 
2136
        trx_t*          trx,            /* in/out: trx (sets error_state) */
 
2137
        dict_table_t*   table,          /* in: the index is on this table */
 
2138
        const merge_index_def_t*        /* in: the index definition */
 
2139
                        index_def)
2529
2140
{
2530
2141
        dict_index_t*   index;
2531
2142
        ulint           err;
2558
2169
 
2559
2170
                ut_a(index);
2560
2171
 
 
2172
#ifdef ROW_MERGE_IS_INDEX_USABLE
2561
2173
                /* Note the id of the transaction that created this
2562
2174
                index, we use it to restrict readers from accessing
2563
2175
                this index, to ensure read consistency. */
2564
2176
                index->trx_id = trx->id;
 
2177
#endif /* ROW_MERGE_IS_INDEX_USABLE */
2565
2178
        } else {
2566
2179
                index = NULL;
2567
2180
        }
2569
2182
        return(index);
2570
2183
}
2571
2184
 
2572
 
/*********************************************************************//**
 
2185
#ifdef ROW_MERGE_IS_INDEX_USABLE
 
2186
/*************************************************************************
2573
2187
Check if a transaction can use an index. */
2574
2188
UNIV_INTERN
2575
2189
ibool
2576
2190
row_merge_is_index_usable(
2577
2191
/*======================*/
2578
 
        const trx_t*            trx,    /*!< in: transaction */
2579
 
        const dict_index_t*     index)  /*!< in: index to check */
 
2192
        const trx_t*            trx,    /* in: transaction */
 
2193
        const dict_index_t*     index)  /* in: index to check */
2580
2194
{
2581
 
        return(!trx->read_view
2582
 
               || read_view_sees_trx_id(trx->read_view, index->trx_id));
 
2195
        if (!trx->read_view) {
 
2196
                return(TRUE);
 
2197
        }
 
2198
 
 
2199
        return(ut_dulint_cmp(index->trx_id, trx->read_view->low_limit_id) < 0);
2583
2200
}
 
2201
#endif /* ROW_MERGE_IS_INDEX_USABLE */
2584
2202
 
2585
 
/*********************************************************************//**
2586
 
Drop the old table.
2587
 
@return DB_SUCCESS or error code */
 
2203
/*************************************************************************
 
2204
Drop the old table. */
2588
2205
UNIV_INTERN
2589
2206
ulint
2590
2207
row_merge_drop_table(
2591
2208
/*=================*/
2592
 
        trx_t*          trx,            /*!< in: transaction */
2593
 
        dict_table_t*   table)          /*!< in: table to drop */
 
2209
                                        /* out: DB_SUCCESS or error code */
 
2210
        trx_t*          trx,            /* in: transaction */
 
2211
        dict_table_t*   table)          /* in: table to drop */
2594
2212
{
2595
2213
        /* There must be no open transactions on the table. */
2596
2214
        ut_a(table->n_mysql_handles_opened == 0);
2598
2216
        return(row_drop_table_for_mysql(table->name, trx, FALSE));
2599
2217
}
2600
2218
 
2601
 
/*********************************************************************//**
 
2219
/*************************************************************************
2602
2220
Build indexes on a table by reading a clustered index,
2603
2221
creating a temporary file containing index entries, merge sorting
2604
 
these index entries and inserting sorted index entries to indexes.
2605
 
@return DB_SUCCESS or error code */
 
2222
these index entries and inserting sorted index entries to indexes. */
2606
2223
UNIV_INTERN
2607
2224
ulint
2608
2225
row_merge_build_indexes(
2609
2226
/*====================*/
2610
 
        trx_t*          trx,            /*!< in: transaction */
2611
 
        dict_table_t*   old_table,      /*!< in: table where rows are
 
2227
                                        /* out: DB_SUCCESS or error code */
 
2228
        trx_t*          trx,            /* in: transaction */
 
2229
        dict_table_t*   old_table,      /* in: table where rows are
2612
2230
                                        read from */
2613
 
        dict_table_t*   new_table,      /*!< in: table where indexes are
 
2231
        dict_table_t*   new_table,      /* in: table where indexes are
2614
2232
                                        created; identical to old_table
2615
2233
                                        unless creating a PRIMARY KEY */
2616
 
        dict_index_t**  indexes,        /*!< in: indexes to be created */
2617
 
        ulint           n_indexes,      /*!< in: size of indexes[] */
2618
 
        TABLE*  table)          /*!< in/out: MySQL table, for
 
2234
        dict_index_t**  indexes,        /* in: indexes to be created */
 
2235
        ulint           n_indexes,      /* in: size of indexes[] */
 
2236
        TABLE*          table)          /* in/out: MySQL table, for
2619
2237
                                        reporting erroneous key value
2620
2238
                                        if applicable */
2621
2239
{
2637
2255
        /* Allocate memory for merge file data structure and initialize
2638
2256
        fields */
2639
2257
 
2640
 
        merge_files = static_cast<merge_file_t *>(mem_alloc(n_indexes * sizeof *merge_files));
 
2258
        merge_files = mem_alloc(n_indexes * sizeof *merge_files);
2641
2259
        block_size = 3 * sizeof *block;
2642
 
        block = static_cast<row_merge_block_t *>(os_mem_alloc_large(&block_size));
 
2260
        block = os_mem_alloc_large(&block_size);
2643
2261
 
2644
2262
        for (i = 0; i < n_indexes; i++) {
2645
2263
 
2668
2286
        sorting and inserting. */
2669
2287
 
2670
2288
        for (i = 0; i < n_indexes; i++) {
2671
 
                error = row_merge_sort(trx, indexes[i], &merge_files[i],
 
2289
                error = row_merge_sort(indexes[i], &merge_files[i],
2672
2290
                                       block, &tmpfd, table);
2673
2291
 
2674
2292
                if (error == DB_SUCCESS) {