57
58
#include "handler0alter.h"
60
/* Set these in order ot enable debug printout. */
61
/** Set these in order ot enable debug printout. */
61
63
static ibool row_merge_print_cmp;
62
64
static ibool row_merge_print_read;
63
65
static ibool row_merge_print_write;
64
67
#endif /* UNIV_DEBUG */
66
/* Block size for I/O operations in merge sort. The minimum is
67
UNIV_PAGE_SIZE, or page_get_free_space_of_empty() rounded to a power of 2.
69
/** @brief Block size for I/O operations in merge sort.
71
The minimum is UNIV_PAGE_SIZE, or page_get_free_space_of_empty()
72
rounded to a power of 2.
69
74
When not creating a PRIMARY KEY that contains column prefixes, this
70
75
can be set as small as UNIV_PAGE_SIZE / 2. See the comment above
71
76
ut_ad(data_size < sizeof(row_merge_block_t)). */
73
77
typedef byte row_merge_block_t[1048576];
75
/* Secondary buffer for I/O operations of merge records. This buffer
76
is used for writing or reading a record that spans two row_merge_block_t.
77
Thus, it must be able to hold one merge record, whose maximum size is
78
the same as the minimum size of row_merge_block_t. */
79
/** @brief Secondary buffer for I/O operations of merge records.
81
This buffer is used for writing or reading a record that spans two
82
row_merge_block_t. Thus, it must be able to hold one merge record,
83
whose maximum size is the same as the minimum size of
80
85
typedef byte mrec_buf_t[UNIV_PAGE_SIZE];
82
/* Merge record in row_merge_block_t. The format is the same as a
83
record in ROW_FORMAT=COMPACT with the exception that the
84
REC_N_NEW_EXTRA_BYTES are omitted. */
87
/** @brief Merge record in row_merge_block_t.
89
The format is the same as a record in ROW_FORMAT=COMPACT with the
90
exception that the REC_N_NEW_EXTRA_BYTES are omitted. */
85
91
typedef byte mrec_t;
87
/* Buffer for sorting in main memory. */
93
/** Buffer for sorting in main memory. */
88
94
struct row_merge_buf_struct {
89
mem_heap_t* heap; /* memory heap where allocated */
90
dict_index_t* index; /* the index the tuples belong to */
91
ulint total_size; /* total amount of data bytes */
92
ulint n_tuples; /* number of data tuples */
93
ulint max_tuples; /* maximum number of data tuples */
94
const dfield_t**tuples; /* array of pointers to
95
mem_heap_t* heap; /*!< memory heap where allocated */
96
dict_index_t* index; /*!< the index the tuples belong to */
97
ulint total_size; /*!< total amount of data bytes */
98
ulint n_tuples; /*!< number of data tuples */
99
ulint max_tuples; /*!< maximum number of data tuples */
100
const dfield_t**tuples; /*!< array of pointers to
95
101
arrays of fields that form
96
102
the data tuples */
97
const dfield_t**tmp_tuples; /* temporary copy of tuples,
103
const dfield_t**tmp_tuples; /*!< temporary copy of tuples,
107
/** Buffer for sorting in main memory. */
101
108
typedef struct row_merge_buf_struct row_merge_buf_t;
103
/* Information about temporary files used in merge sort are stored
110
/** Information about temporary files used in merge sort */
106
111
struct merge_file_struct {
107
int fd; /* File descriptor */
108
ulint offset; /* File offset */
112
int fd; /*!< file descriptor */
113
ulint offset; /*!< file offset */
116
/** Information about temporary files used in merge sort */
111
117
typedef struct merge_file_struct merge_file_t;
113
119
#ifdef UNIV_DEBUG
114
/**********************************************************
120
/******************************************************//**
115
121
Display a merge tuple. */
118
124
row_merge_tuple_print(
119
125
/*==================*/
120
FILE* f, /* in: output stream */
121
const dfield_t* entry, /* in: tuple to print */
122
ulint n_fields)/* in: number of fields in the tuple */
126
FILE* f, /*!< in: output stream */
127
const dfield_t* entry, /*!< in: tuple to print */
128
ulint n_fields)/*!< in: number of fields in the tuple */
147
153
#endif /* UNIV_DEBUG */
149
/**********************************************************
150
Allocate a sort buffer. */
155
/******************************************************//**
156
Allocate a sort buffer.
157
@return own: sort buffer */
153
160
row_merge_buf_create_low(
154
161
/*=====================*/
155
/* out,own: sort buffer */
156
mem_heap_t* heap, /* in: heap where allocated */
157
dict_index_t* index, /* in: secondary index */
158
ulint max_tuples, /* in: maximum number of data tuples */
159
ulint buf_size) /* in: size of the buffer, in bytes */
162
mem_heap_t* heap, /*!< in: heap where allocated */
163
dict_index_t* index, /*!< in: secondary index */
164
ulint max_tuples, /*!< in: maximum number of data tuples */
165
ulint buf_size) /*!< in: size of the buffer, in bytes */
161
167
row_merge_buf_t* buf;
222
228
return(row_merge_buf_create_low(heap, index, max_tuples, buf_size));
225
/**********************************************************
231
/******************************************************//**
226
232
Deallocate a sort buffer. */
229
235
row_merge_buf_free(
230
236
/*===============*/
231
row_merge_buf_t* buf) /* in,own: sort buffer, to be freed */
237
row_merge_buf_t* buf) /*!< in,own: sort buffer, to be freed */
233
239
mem_heap_free(buf->heap);
236
/**********************************************************
237
Insert a data tuple into a sort buffer. */
242
/******************************************************//**
243
Insert a data tuple into a sort buffer.
244
@return TRUE if added, FALSE if out of space */
240
247
row_merge_buf_add(
241
248
/*==============*/
242
/* out: TRUE if added,
243
FALSE if out of space */
244
row_merge_buf_t* buf, /* in/out: sort buffer */
245
const dtuple_t* row, /* in: row in clustered index */
246
const row_ext_t* ext) /* in: cache of externally stored
249
row_merge_buf_t* buf, /*!< in/out: sort buffer */
250
const dtuple_t* row, /*!< in: row in clustered index */
251
const row_ext_t* ext) /*!< in: cache of externally stored
247
252
column prefixes, or NULL */
392
/* Structure for reporting duplicate records. */
397
/** Structure for reporting duplicate records. */
393
398
struct row_merge_dup_struct {
394
const dict_index_t* index; /* index being sorted */
395
TABLE* table; /* MySQL table object */
396
ulint n_dup; /* number of duplicates */
399
const dict_index_t* index; /*!< index being sorted */
400
TABLE* table; /*!< MySQL table object */
401
ulint n_dup; /*!< number of duplicates */
404
/** Structure for reporting duplicate records. */
399
405
typedef struct row_merge_dup_struct row_merge_dup_t;
401
/*****************************************************************
407
/*************************************************************//**
402
408
Report a duplicate key. */
405
411
row_merge_dup_report(
406
412
/*=================*/
407
row_merge_dup_t* dup, /* in/out: for reporting duplicates */
408
const dfield_t* entry) /* in: duplicate index entry */
413
row_merge_dup_t* dup, /*!< in/out: for reporting duplicates */
414
const dfield_t* entry) /*!< in: duplicate index entry */
411
417
const dtuple_t* tuple;
445
/*****************************************************************
446
Compare two tuples. */
451
/*************************************************************//**
453
@return 1, 0, -1 if a is greater, equal, less, respectively, than b */
449
456
row_merge_tuple_cmp(
450
457
/*================*/
451
/* out: 1, 0, -1 if a is greater,
452
equal, less, respectively, than b */
453
ulint n_field,/* in: number of fields */
454
const dfield_t* a, /* in: first tuple to be compared */
455
const dfield_t* b, /* in: second tuple to be compared */
456
row_merge_dup_t* dup) /* in/out: for reporting duplicates */
458
ulint n_field,/*!< in: number of fields */
459
const dfield_t* a, /*!< in: first tuple to be compared */
460
const dfield_t* b, /*!< in: second tuple to be compared */
461
row_merge_dup_t* dup) /*!< in/out: for reporting duplicates */
459
464
const dfield_t* field = a;
487
/**************************************************************************
492
/** Wrapper for row_merge_tuple_sort() to inject some more context to
493
UT_SORT_FUNCTION_BODY().
494
@param a array of tuples that being sorted
495
@param b aux (work area), same size as tuples[]
496
@param c lower bound of the sorting area, inclusive
497
@param d upper bound of the sorting area, inclusive */
498
#define row_merge_tuple_sort_ctx(a,b,c,d) \
499
row_merge_tuple_sort(n_field, dup, a, b, c, d)
500
/** Wrapper for row_merge_tuple_cmp() to inject some more context to
501
UT_SORT_FUNCTION_BODY().
502
@param a first tuple to be compared
503
@param b second tuple to be compared
504
@return 1, 0, -1 if a is greater, equal, less, respectively, than b */
505
#define row_merge_tuple_cmp_ctx(a,b) row_merge_tuple_cmp(n_field, a, b, dup)
507
/**********************************************************************//**
488
508
Merge sort the tuple buffer in main memory. */
491
511
row_merge_tuple_sort(
492
512
/*=================*/
493
ulint n_field,/* in: number of fields */
494
row_merge_dup_t* dup, /* in/out: for reporting duplicates */
495
const dfield_t** tuples, /* in/out: tuples */
496
const dfield_t** aux, /* in/out: work area */
497
ulint low, /* in: lower bound of the
513
ulint n_field,/*!< in: number of fields */
514
row_merge_dup_t* dup, /*!< in/out: for reporting duplicates */
515
const dfield_t** tuples, /*!< in/out: tuples */
516
const dfield_t** aux, /*!< in/out: work area */
517
ulint low, /*!< in: lower bound of the
498
518
sorting area, inclusive */
499
ulint high) /* in: upper bound of the
519
ulint high) /*!< in: upper bound of the
500
520
sorting area, exclusive */
502
#define row_merge_tuple_sort_ctx(a,b,c,d) \
503
row_merge_tuple_sort(n_field, dup, a, b, c, d)
504
#define row_merge_tuple_cmp_ctx(a,b) row_merge_tuple_cmp(n_field, a, b, dup)
506
522
UT_SORT_FUNCTION_BODY(row_merge_tuple_sort_ctx,
507
523
tuples, aux, low, high, row_merge_tuple_cmp_ctx);
510
/**********************************************************
526
/******************************************************//**
511
527
Sort a buffer. */
514
530
row_merge_buf_sort(
515
531
/*===============*/
516
row_merge_buf_t* buf, /* in/out: sort buffer */
517
row_merge_dup_t* dup) /* in/out: for reporting duplicates */
532
row_merge_buf_t* buf, /*!< in/out: sort buffer */
533
row_merge_dup_t* dup) /*!< in/out: for reporting duplicates */
519
535
row_merge_tuple_sort(dict_index_get_n_unique(buf->index), dup,
520
536
buf->tuples, buf->tmp_tuples, 0, buf->n_tuples);
523
/**********************************************************
539
/******************************************************//**
524
540
Write a buffer to a block. */
527
543
row_merge_buf_write(
528
544
/*================*/
529
const row_merge_buf_t* buf, /* in: sorted buffer */
545
const row_merge_buf_t* buf, /*!< in: sorted buffer */
530
546
#ifdef UNIV_DEBUG
531
const merge_file_t* of, /* in: output file */
547
const merge_file_t* of, /*!< in: output file */
532
548
#endif /* UNIV_DEBUG */
533
row_merge_block_t* block) /* out: buffer for writing to file */
549
row_merge_block_t* block) /*!< out: buffer for writing to file */
534
550
#ifndef UNIV_DEBUG
535
551
# define row_merge_buf_write(buf, of, block) row_merge_buf_write(buf, block)
536
552
#endif /* !UNIV_DEBUG */
599
615
#endif /* UNIV_DEBUG */
602
/**********************************************************
603
Create a memory heap and allocate space for row_merge_rec_offsets(). */
618
/******************************************************//**
619
Create a memory heap and allocate space for row_merge_rec_offsets().
620
@return memory heap */
606
623
row_merge_heap_create(
607
624
/*==================*/
608
/* out: memory heap */
609
const dict_index_t* index, /* in: record descriptor */
610
ulint** offsets1, /* out: offsets */
611
ulint** offsets2) /* out: offsets */
625
const dict_index_t* index, /*!< in: record descriptor */
626
ulint** offsets1, /*!< out: offsets */
627
ulint** offsets2) /*!< out: offsets */
613
629
ulint i = 1 + REC_OFFS_HEADER_SIZE
614
630
+ dict_index_get_n_fields(index);
626
/**************************************************************************
642
/**********************************************************************//**
627
643
Search an index object by name and column names. If several indexes match,
628
return the index with the max id. */
644
return the index with the max id.
645
@return matching index, NULL if not found */
631
648
row_merge_dict_table_get_index(
632
649
/*===========================*/
633
/* out: matching index,
635
dict_table_t* table, /* in: table */
636
const merge_index_def_t*index_def) /* in: index definition */
650
dict_table_t* table, /*!< in: table */
651
const merge_index_def_t*index_def) /*!< in: index definition */
639
654
dict_index_t* index;
656
/************************************************************************
657
Read a merge block from the file system. */
671
/********************************************************************//**
672
Read a merge block from the file system.
673
@return TRUE if request was successful, FALSE if fail */
662
/* out: TRUE if request was
663
successful, FALSE if fail */
664
int fd, /* in: file descriptor */
665
ulint offset, /* in: offset where to read */
666
row_merge_block_t* buf) /* out: data */
678
int fd, /*!< in: file descriptor */
679
ulint offset, /*!< in: offset where to read */
680
row_merge_block_t* buf) /*!< out: data */
668
682
ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf;
681
695
return(UNIV_LIKELY(success));
684
/************************************************************************
685
Read a merge block from the file system. */
698
/********************************************************************//**
699
Read a merge block from the file system.
700
@return TRUE if request was successful, FALSE if fail */
690
/* out: TRUE if request was
691
successful, FALSE if fail */
692
int fd, /* in: file descriptor */
693
ulint offset, /* in: offset where to write */
694
const void* buf) /* in: data */
705
int fd, /*!< in: file descriptor */
706
ulint offset, /*!< in: offset where to write */
707
const void* buf) /*!< in: data */
696
709
ib_uint64_t ofs = ((ib_uint64_t) offset)
697
710
* sizeof(row_merge_block_t);
702
715
sizeof(row_merge_block_t))));
705
/************************************************************************
706
Read a merge record. */
718
/********************************************************************//**
720
@return pointer to next record, or NULL on I/O error or end of list */
709
723
row_merge_read_rec(
710
724
/*===============*/
711
/* out: pointer to next record,
714
row_merge_block_t* block, /* in/out: file buffer */
715
mrec_buf_t* buf, /* in/out: secondary buffer */
716
const byte* b, /* in: pointer to record */
717
const dict_index_t* index, /* in: index of the record */
718
int fd, /* in: file descriptor */
719
ulint* foffs, /* in/out: file offset */
720
const mrec_t** mrec, /* out: pointer to merge record,
725
row_merge_block_t* block, /*!< in/out: file buffer */
726
mrec_buf_t* buf, /*!< in/out: secondary buffer */
727
const byte* b, /*!< in: pointer to record */
728
const dict_index_t* index, /*!< in: index of the record */
729
int fd, /*!< in: file descriptor */
730
ulint* foffs, /*!< in/out: file offset */
731
const mrec_t** mrec, /*!< out: pointer to merge record,
721
732
or NULL on end of list
722
733
(non-NULL on I/O error) */
723
ulint* offsets)/* out: offsets of mrec */
734
ulint* offsets)/*!< out: offsets of mrec */
725
736
ulint extra_size;
838
849
avail_size = block[1] - b;
839
850
memcpy(*buf, b, avail_size);
840
851
*mrec = *buf + extra_size;
841
rec_offs_make_valid(*mrec, index, offsets);
853
/* We cannot invoke rec_offs_make_valid() here, because there
854
are no REC_N_NEW_EXTRA_BYTES between extra_size and data_size.
855
Similarly, rec_offs_validate() would fail, because it invokes
857
offsets[2] = (ulint) *mrec;
858
offsets[3] = (ulint) index;
859
#endif /* UNIV_DEBUG */
843
861
if (!row_merge_read(fd, ++(*foffs), block)) {
869
/************************************************************************
887
/********************************************************************//**
870
888
Write a merge record. */
873
891
row_merge_write_rec_low(
874
892
/*====================*/
875
byte* b, /* out: buffer */
876
ulint e, /* in: encoded extra_size */
893
byte* b, /*!< out: buffer */
894
ulint e, /*!< in: encoded extra_size */
877
895
#ifdef UNIV_DEBUG
878
ulint size, /* in: total size to write */
879
int fd, /* in: file descriptor */
880
ulint foffs, /* in: file offset */
896
ulint size, /*!< in: total size to write */
897
int fd, /*!< in: file descriptor */
898
ulint foffs, /*!< in: file offset */
881
899
#endif /* UNIV_DEBUG */
882
const mrec_t* mrec, /* in: record to write */
883
const ulint* offsets)/* in: offsets of mrec */
900
const mrec_t* mrec, /*!< in: record to write */
901
const ulint* offsets)/*!< in: offsets of mrec */
884
902
#ifndef UNIV_DEBUG
885
903
# define row_merge_write_rec_low(b, e, size, fd, foffs, mrec, offsets) \
886
904
row_merge_write_rec_low(b, e, mrec, offsets)
909
927
ut_ad(b + rec_offs_size(offsets) == end);
912
/************************************************************************
913
Write a merge record. */
930
/********************************************************************//**
931
Write a merge record.
932
@return pointer to end of block, or NULL on error */
916
935
row_merge_write_rec(
917
936
/*================*/
918
/* out: pointer to end of block,
920
row_merge_block_t* block, /* in/out: file buffer */
921
mrec_buf_t* buf, /* in/out: secondary buffer */
922
byte* b, /* in: pointer to end of block */
923
int fd, /* in: file descriptor */
924
ulint* foffs, /* in/out: file offset */
925
const mrec_t* mrec, /* in: record to write */
926
const ulint* offsets)/* in: offsets of mrec */
937
row_merge_block_t* block, /*!< in/out: file buffer */
938
mrec_buf_t* buf, /*!< in/out: secondary buffer */
939
byte* b, /*!< in: pointer to end of block */
940
int fd, /*!< in: file descriptor */
941
ulint* foffs, /*!< in/out: file offset */
942
const mrec_t* mrec, /*!< in: record to write */
943
const ulint* offsets)/*!< in: offsets of mrec */
928
945
ulint extra_size;
980
/************************************************************************
981
Write an end-of-list marker. */
997
/********************************************************************//**
998
Write an end-of-list marker.
999
@return pointer to end of block, or NULL on error */
984
1002
row_merge_write_eof(
985
1003
/*================*/
986
/* out: pointer to end of block,
988
row_merge_block_t* block, /* in/out: file buffer */
989
byte* b, /* in: pointer to end of block */
990
int fd, /* in: file descriptor */
991
ulint* foffs) /* in/out: file offset */
1004
row_merge_block_t* block, /*!< in/out: file buffer */
1005
byte* b, /*!< in: pointer to end of block */
1006
int fd, /*!< in: file descriptor */
1007
ulint* foffs) /*!< in/out: file offset */
994
1010
ut_ad(b >= block[0]);
1018
1034
return(block[0]);
1021
/*****************************************************************
1022
Compare two merge records. */
1037
/*************************************************************//**
1038
Compare two merge records.
1039
@return 1, 0, -1 if mrec1 is greater, equal, less, respectively, than mrec2 */
1028
mrec1 is greater, equal, less,
1029
respectively, than mrec2 */
1030
const mrec_t* mrec1, /* in: first merge
1031
record to be compared */
1032
const mrec_t* mrec2, /* in: second merge
1033
record to be compared */
1034
const ulint* offsets1, /* in: first record offsets */
1035
const ulint* offsets2, /* in: second record offsets */
1036
const dict_index_t* index) /* in: index */
1044
const mrec_t* mrec1, /*!< in: first merge
1045
record to be compared */
1046
const mrec_t* mrec2, /*!< in: second merge
1047
record to be compared */
1048
const ulint* offsets1, /*!< in: first record offsets */
1049
const ulint* offsets2, /*!< in: second record offsets */
1050
const dict_index_t* index) /*!< in: index */
1055
/************************************************************************
1069
/********************************************************************//**
1056
1070
Reads clustered index of the table and create temporary files
1057
containing the index entries for the indexes to be built. */
1071
containing the index entries for the indexes to be built.
1072
@return DB_SUCCESS or error */
1060
1075
row_merge_read_clustered_index(
1061
1076
/*===========================*/
1062
/* out: DB_SUCCESS or error */
1063
trx_t* trx, /* in: transaction */
1064
TABLE* table, /* in/out: MySQL table object,
1077
trx_t* trx, /*!< in: transaction */
1078
TABLE* table, /*!< in/out: MySQL table object,
1065
1079
for reporting erroneous records */
1066
const dict_table_t* old_table,/* in: table where rows are
1080
const dict_table_t* old_table,/*!< in: table where rows are
1068
const dict_table_t* new_table,/* in: table where indexes are
1082
const dict_table_t* new_table,/*!< in: table where indexes are
1069
1083
created; identical to old_table
1070
1084
unless creating a PRIMARY KEY */
1071
dict_index_t** index, /* in: indexes to be created */
1072
merge_file_t* files, /* in: temporary files */
1073
ulint n_index,/* in: number of indexes to create */
1074
row_merge_block_t* block) /* in/out: file buffer */
1085
dict_index_t** index, /*!< in: indexes to be created */
1086
merge_file_t* files, /*!< in: temporary files */
1087
ulint n_index,/*!< in: number of indexes to create */
1088
row_merge_block_t* block) /*!< in/out: file buffer */
1076
1090
dict_index_t* clust_index; /* Clustered index */
1077
1091
mem_heap_t* row_heap; /* Heap memory to create
1301
/*****************************************************************
1302
Merge two blocks of linked lists on disk and write a bigger block. */
1307
/* out: DB_SUCCESS or error code */
1308
const dict_index_t* index, /* in: index being created */
1309
merge_file_t* file, /* in/out: file containing
1311
row_merge_block_t* block, /* in/out: 3 buffers */
1312
ulint* foffs0, /* in/out: offset of first
1313
source list in the file */
1314
ulint* foffs1, /* in/out: offset of second
1315
source list in the file */
1316
merge_file_t* of, /* in/out: output file */
1317
TABLE* table) /* in/out: MySQL table, for
1318
reporting erroneous key value
1321
mem_heap_t* heap; /* memory heap for offsets0, offsets1 */
1323
mrec_buf_t buf[3]; /* buffer for handling split mrec in block[] */
1324
const byte* b0; /* pointer to block[0] */
1325
const byte* b1; /* pointer to block[1] */
1326
byte* b2; /* pointer to block[2] */
1327
const mrec_t* mrec0; /* merge rec, points to block[0] or buf[0] */
1328
const mrec_t* mrec1; /* merge rec, points to block[1] or buf[1] */
1329
ulint* offsets0;/* offsets of mrec0 */
1330
ulint* offsets1;/* offsets of mrec1 */
1332
heap = row_merge_heap_create(index, &offsets0, &offsets1);
1334
/* Write a record and read the next record. Split the output
1335
file in two halves, which can be merged on the following pass. */
1315
/** Write a record via buffer 2 and read the next record to buffer N.
1316
@param N number of the buffer (0 or 1)
1317
@param AT_END statement to execute at end of input */
1336
1318
#define ROW_MERGE_WRITE_GET_NEXT(N, AT_END) \
1338
1320
b2 = row_merge_write_rec(&block[2], &buf[2], b2, \
1338
/*************************************************************//**
1339
Merge two blocks of linked lists on disk and write a bigger block.
1340
@return DB_SUCCESS or error code */
1345
const dict_index_t* index, /*!< in: index being created */
1346
merge_file_t* file, /*!< in/out: file containing
1348
row_merge_block_t* block, /*!< in/out: 3 buffers */
1349
ulint* foffs0, /*!< in/out: offset of first
1350
source list in the file */
1351
ulint* foffs1, /*!< in/out: offset of second
1352
source list in the file */
1353
merge_file_t* of, /*!< in/out: output file */
1354
TABLE* table) /*!< in/out: MySQL table, for
1355
reporting erroneous key value
1358
mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */
1360
mrec_buf_t buf[3]; /*!< buffer for handling split mrec in block[] */
1361
const byte* b0; /*!< pointer to block[0] */
1362
const byte* b1; /*!< pointer to block[1] */
1363
byte* b2; /*!< pointer to block[2] */
1364
const mrec_t* mrec0; /*!< merge rec, points to block[0] or buf[0] */
1365
const mrec_t* mrec1; /*!< merge rec, points to block[1] or buf[1] */
1366
ulint* offsets0;/* offsets of mrec0 */
1367
ulint* offsets1;/* offsets of mrec1 */
1369
heap = row_merge_heap_create(index, &offsets0, &offsets1);
1371
/* Write a record and read the next record. Split the output
1372
file in two halves, which can be merged on the following pass. */
1356
1374
if (!row_merge_read(file->fd, *foffs0, &block[0])
1357
1375
|| !row_merge_read(file->fd, *foffs1, &block[1])) {
1419
1437
return(b2 ? DB_SUCCESS : DB_CORRUPTION);
1422
/*****************************************************************
1423
Merge disk files. */
1440
/*************************************************************//**
1442
@return DB_SUCCESS or error code */
1428
/* out: DB_SUCCESS or error code */
1429
const dict_index_t* index, /* in: index being created */
1430
merge_file_t* file, /* in/out: file containing
1447
const dict_index_t* index, /*!< in: index being created */
1448
merge_file_t* file, /*!< in/out: file containing
1431
1449
index entries */
1432
ulint half, /* in: half the file */
1433
row_merge_block_t* block, /* in/out: 3 buffers */
1434
int* tmpfd, /* in/out: temporary file handle */
1435
TABLE* table) /* in/out: MySQL table, for
1450
ulint half, /*!< in: half the file */
1451
row_merge_block_t* block, /*!< in/out: 3 buffers */
1452
int* tmpfd, /*!< in/out: temporary file handle */
1453
TABLE* table) /*!< in/out: MySQL table, for
1436
1454
reporting erroneous key value
1437
1455
if applicable */
1439
ulint foffs0; /* first input offset */
1440
ulint foffs1; /* second input offset */
1441
ulint error; /* error code */
1442
merge_file_t of; /* output file */
1457
ulint foffs0; /*!< first input offset */
1458
ulint foffs1; /*!< second input offset */
1459
ulint error; /*!< error code */
1460
merge_file_t of; /*!< output file */
1444
1462
UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
1445
1463
ut_ad(half > 0);
1483
1501
return(DB_SUCCESS);
1486
/*****************************************************************
1487
Merge disk files. */
1504
/*************************************************************//**
1506
@return DB_SUCCESS or error code */
1490
1509
row_merge_sort(
1491
1510
/*===========*/
1492
/* out: DB_SUCCESS or error code */
1493
const dict_index_t* index, /* in: index being created */
1494
merge_file_t* file, /* in/out: file containing
1511
const dict_index_t* index, /*!< in: index being created */
1512
merge_file_t* file, /*!< in/out: file containing
1495
1513
index entries */
1496
row_merge_block_t* block, /* in/out: 3 buffers */
1497
int* tmpfd, /* in/out: temporary file handle */
1498
TABLE* table) /* in/out: MySQL table, for
1514
row_merge_block_t* block, /*!< in/out: 3 buffers */
1515
int* tmpfd, /*!< in/out: temporary file handle */
1516
TABLE* table) /*!< in/out: MySQL table, for
1499
1517
reporting erroneous key value
1500
1518
if applicable */
1502
ulint blksz; /* block size */
1520
ulint blksz; /*!< block size */
1504
1522
for (blksz = 1; blksz < file->offset; blksz *= 2) {
1517
1535
return(DB_SUCCESS);
1520
/*****************************************************************
1538
/*************************************************************//**
1521
1539
Copy externally stored columns to the data tuple. */
1524
1542
row_merge_copy_blobs(
1525
1543
/*=================*/
1526
const mrec_t* mrec, /* in: merge record */
1527
const ulint* offsets,/* in: offsets of mrec */
1528
ulint zip_size,/* in: compressed page size in bytes, or 0 */
1529
dtuple_t* tuple, /* in/out: data tuple */
1530
mem_heap_t* heap) /* in/out: memory heap */
1544
const mrec_t* mrec, /*!< in: merge record */
1545
const ulint* offsets,/*!< in: offsets of mrec */
1546
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
1547
dtuple_t* tuple, /*!< in/out: data tuple */
1548
mem_heap_t* heap) /*!< in/out: memory heap */
1533
1551
ulint n_fields = dtuple_get_n_fields(tuple);
1558
/************************************************************************
1576
/********************************************************************//**
1559
1577
Read sorted file containing index data tuples and insert these data
1560
tuples to the index */
1579
@return DB_SUCCESS or error number */
1563
1582
row_merge_insert_index_tuples(
1564
1583
/*==========================*/
1565
/* out: DB_SUCCESS or error number */
1566
trx_t* trx, /* in: transaction */
1567
dict_index_t* index, /* in: index */
1568
dict_table_t* table, /* in: new table */
1569
ulint zip_size,/* in: compressed page size of
1584
trx_t* trx, /*!< in: transaction */
1585
dict_index_t* index, /*!< in: index */
1586
dict_table_t* table, /*!< in: new table */
1587
ulint zip_size,/*!< in: compressed page size of
1570
1588
the old table, or 0 if uncompressed */
1571
int fd, /* in: file descriptor */
1572
row_merge_block_t* block) /* in/out: file buffer */
1589
int fd, /*!< in: file descriptor */
1590
row_merge_block_t* block) /*!< in/out: file buffer */
1574
1592
mrec_buf_t buf;
1680
/*************************************************************************
1681
Sets an exclusive lock on a table, for the duration of creating indexes. */
1698
/*********************************************************************//**
1699
Sets an exclusive lock on a table, for the duration of creating indexes.
1700
@return error code or DB_SUCCESS */
1684
1703
row_merge_lock_table(
1685
1704
/*=================*/
1686
/* out: error code or DB_SUCCESS */
1687
trx_t* trx, /* in/out: transaction */
1688
dict_table_t* table, /* in: table to lock */
1689
enum lock_mode mode) /* in: LOCK_X or LOCK_S */
1705
trx_t* trx, /*!< in/out: transaction */
1706
dict_table_t* table, /*!< in: table to lock */
1707
enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */
1691
1709
mem_heap_t* heap;
1692
1710
que_thr_t* thr;
1913
/*************************************************************************
1928
/*********************************************************************//**
1914
1929
Determine the precise type of a column that is added to a tem
1915
if a column must be constrained NOT NULL. */
1930
if a column must be constrained NOT NULL.
1931
@return col->prtype, possibly ORed with DATA_NOT_NULL */
1918
1934
row_merge_col_prtype(
1919
1935
/*=================*/
1920
/* out: col->prtype, possibly
1921
ORed with DATA_NOT_NULL */
1922
const dict_col_t* col, /* in: column */
1923
const char* col_name, /* in: name of the column */
1924
const merge_index_def_t*index_def) /* in: the index definition
1936
const dict_col_t* col, /*!< in: column */
1937
const char* col_name, /*!< in: name of the column */
1938
const merge_index_def_t*index_def) /*!< in: the index definition
1925
1939
of the primary key */
1927
1941
ulint prtype = col->prtype;
1946
1960
return(prtype);
1949
/*************************************************************************
1963
/*********************************************************************//**
1950
1964
Create a temporary table for creating a primary key, using the definition
1951
of an existing table. */
1965
of an existing table.
1966
@return table, or NULL on error */
1954
1969
row_merge_create_temporary_table(
1955
1970
/*=============================*/
1958
const char* table_name, /* in: new table name */
1959
const merge_index_def_t*index_def, /* in: the index definition
1971
const char* table_name, /*!< in: new table name */
1972
const merge_index_def_t*index_def, /*!< in: the index definition
1960
1973
of the primary key */
1961
const dict_table_t* table, /* in: old table definition */
1962
trx_t* trx) /* in/out: transaction
1974
const dict_table_t* table, /*!< in: old table definition */
1975
trx_t* trx) /*!< in/out: transaction
1963
1976
(sets error_state) */
1999
2012
return(new_table);
2002
/*************************************************************************
2015
/*********************************************************************//**
2003
2016
Rename the temporary indexes in the dictionary to permanent ones. The
2004
2017
data dictionary must have been locked exclusively by the caller,
2005
because the transaction will not be committed. */
2018
because the transaction will not be committed.
2019
@return DB_SUCCESS if all OK */
2008
2022
row_merge_rename_indexes(
2009
2023
/*=====================*/
2010
/* out: DB_SUCCESS if all OK */
2011
trx_t* trx, /* in/out: transaction */
2012
dict_table_t* table) /* in/out: table with new indexes */
2024
trx_t* trx, /*!< in/out: transaction */
2025
dict_table_t* table) /*!< in/out: table with new indexes */
2014
2027
ulint err = DB_SUCCESS;
2015
2028
pars_info_t* info = pars_info_create();
2056
/*************************************************************************
2066
/*********************************************************************//**
2057
2067
Rename the tables in the data dictionary. The data dictionary must
2058
2068
have been locked exclusively by the caller, because the transaction
2059
will not be committed. */
2069
will not be committed.
2070
@return error code or DB_SUCCESS */
2062
2073
row_merge_rename_tables(
2063
2074
/*====================*/
2064
/* out: error code or DB_SUCCESS */
2065
dict_table_t* old_table, /* in/out: old table, renamed to
2075
dict_table_t* old_table, /*!< in/out: old table, renamed to
2067
dict_table_t* new_table, /* in/out: new table, renamed to
2077
dict_table_t* new_table, /*!< in/out: new table, renamed to
2068
2078
old_table->name */
2069
const char* tmp_name, /* in: new name for old_table */
2070
trx_t* trx) /* in: transaction handle */
2079
const char* tmp_name, /*!< in: new name for old_table */
2080
trx_t* trx) /*!< in: transaction handle */
2072
2082
ulint err = DB_ERROR;
2073
2083
pars_info_t* info;
2131
/*************************************************************************
2132
Create and execute a query graph for creating an index. */
2141
/*********************************************************************//**
2142
Create and execute a query graph for creating an index.
2143
@return DB_SUCCESS or error code */
2135
2146
row_merge_create_index_graph(
2136
2147
/*=========================*/
2137
/* out: DB_SUCCESS or error code */
2138
trx_t* trx, /* in: trx */
2139
dict_table_t* table, /* in: table */
2140
dict_index_t* index) /* in: index */
2148
trx_t* trx, /*!< in: trx */
2149
dict_table_t* table, /*!< in: table */
2150
dict_index_t* index) /*!< in: index */
2142
ind_node_t* node; /* Index creation node */
2143
mem_heap_t* heap; /* Memory heap */
2144
que_thr_t* thr; /* Query thread */
2152
ind_node_t* node; /*!< Index creation node */
2153
mem_heap_t* heap; /*!< Memory heap */
2154
que_thr_t* thr; /*!< Query thread */
2168
/*************************************************************************
2169
Create the index and load in to the dictionary. */
2178
/*********************************************************************//**
2179
Create the index and load in to the dictionary.
2180
@return index, or NULL on error */
2172
2183
row_merge_create_index(
2173
2184
/*===================*/
2174
/* out: index, or NULL on error */
2175
trx_t* trx, /* in/out: trx (sets error_state) */
2176
dict_table_t* table, /* in: the index is on this table */
2177
const merge_index_def_t* /* in: the index definition */
2185
trx_t* trx, /*!< in/out: trx (sets error_state) */
2186
dict_table_t* table, /*!< in: the index is on this table */
2187
const merge_index_def_t*index_def)
2188
/*!< in: the index definition */
2180
2190
dict_index_t* index;
2224
#ifdef ROW_MERGE_IS_INDEX_USABLE
2225
/*************************************************************************
2233
/*********************************************************************//**
2226
2234
Check if a transaction can use an index. */
2229
2237
row_merge_is_index_usable(
2230
2238
/*======================*/
2231
const trx_t* trx, /* in: transaction */
2232
const dict_index_t* index) /* in: index to check */
2239
const trx_t* trx, /*!< in: transaction */
2240
const dict_index_t* index) /*!< in: index to check */
2234
if (!trx->read_view) {
2238
return(ut_dulint_cmp(index->trx_id, trx->read_view->low_limit_id) < 0);
2242
return(!trx->read_view || read_view_sees_trx_id(
2244
ut_dulint_create((ulint) (index->trx_id >> 32),
2245
(ulint) index->trx_id & 0xFFFFFFFF)));
2240
#endif /* ROW_MERGE_IS_INDEX_USABLE */
2242
/*************************************************************************
2243
Drop the old table. */
2248
/*********************************************************************//**
2250
@return DB_SUCCESS or error code */
2246
2253
row_merge_drop_table(
2247
2254
/*=================*/
2248
/* out: DB_SUCCESS or error code */
2249
trx_t* trx, /* in: transaction */
2250
dict_table_t* table) /* in: table to drop */
2255
trx_t* trx, /*!< in: transaction */
2256
dict_table_t* table) /*!< in: table to drop */
2252
2258
/* There must be no open transactions on the table. */
2253
2259
ut_a(table->n_mysql_handles_opened == 0);
2255
2261
return(row_drop_table_for_mysql(table->name, trx, FALSE));
2258
/*************************************************************************
2264
/*********************************************************************//**
2259
2265
Build indexes on a table by reading a clustered index,
2260
2266
creating a temporary file containing index entries, merge sorting
2261
these index entries and inserting sorted index entries to indexes. */
2267
these index entries and inserting sorted index entries to indexes.
2268
@return DB_SUCCESS or error code */
2264
2271
row_merge_build_indexes(
2265
2272
/*====================*/
2266
/* out: DB_SUCCESS or error code */
2267
trx_t* trx, /* in: transaction */
2268
dict_table_t* old_table, /* in: table where rows are
2273
trx_t* trx, /*!< in: transaction */
2274
dict_table_t* old_table, /*!< in: table where rows are
2270
dict_table_t* new_table, /* in: table where indexes are
2276
dict_table_t* new_table, /*!< in: table where indexes are
2271
2277
created; identical to old_table
2272
2278
unless creating a PRIMARY KEY */
2273
dict_index_t** indexes, /* in: indexes to be created */
2274
ulint n_indexes, /* in: size of indexes[] */
2275
TABLE* table) /* in/out: MySQL table, for
2279
dict_index_t** indexes, /*!< in: indexes to be created */
2280
ulint n_indexes, /*!< in: size of indexes[] */
2281
TABLE* table) /*!< in/out: MySQL table, for
2276
2282
reporting erroneous key value
2277
2283
if applicable */