2007-04-04 13:05:33 +02:00
|
|
|
/******************************************************
|
|
|
|
New index creation routines using a merge sort
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
(c) 2005,2007 Innobase Oy
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
Created 12/4/2005 Jan Lindstrom
|
2007-06-08 09:37:07 +02:00
|
|
|
Completed by Sunny Bains and Marko Makela
|
2007-04-04 13:05:33 +02:00
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#include "row0merge.h"
|
|
|
|
#include "row0ext.h"
|
|
|
|
#include "row0row.h"
|
|
|
|
#include "row0upd.h"
|
|
|
|
#include "row0ins.h"
|
|
|
|
#include "row0sel.h"
|
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "dict0mem.h"
|
|
|
|
#include "dict0boot.h"
|
|
|
|
#include "dict0crea.h"
|
|
|
|
#include "dict0load.h"
|
|
|
|
#include "btr0btr.h"
|
|
|
|
#include "mach0data.h"
|
|
|
|
#include "trx0rseg.h"
|
|
|
|
#include "trx0trx.h"
|
|
|
|
#include "trx0roll.h"
|
|
|
|
#include "trx0undo.h"
|
|
|
|
#include "trx0purge.h"
|
|
|
|
#include "trx0rec.h"
|
|
|
|
#include "que0que.h"
|
|
|
|
#include "rem0cmp.h"
|
|
|
|
#include "read0read.h"
|
|
|
|
#include "os0file.h"
|
|
|
|
#include "lock0lock.h"
|
|
|
|
#include "data0data.h"
|
|
|
|
#include "data0type.h"
|
|
|
|
#include "que0que.h"
|
|
|
|
#include "pars0pars.h"
|
|
|
|
#include "mem0mem.h"
|
|
|
|
#include "log0log.h"
|
2007-06-08 09:37:07 +02:00
|
|
|
#include "ut0sort.h"
|
2007-04-11 10:16:14 +02:00
|
|
|
|
2007-04-11 14:17:55 +02:00
|
|
|
/* Block size for I/O operations in merge sort */
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
typedef byte row_merge_block_t[1048576];
|
|
|
|
|
|
|
|
/* Secondary buffer for I/O operations of merge records */
|
|
|
|
|
|
|
|
typedef byte mrec_buf_t[UNIV_PAGE_SIZE / 2];
|
|
|
|
|
|
|
|
/* Merge record in row_merge_block_t. The format is the same as a
|
|
|
|
record in ROW_FORMAT=COMPACT with the exception that the
|
|
|
|
REC_N_NEW_EXTRA_BYTES are omitted. */
|
|
|
|
typedef byte mrec_t;
|
|
|
|
|
|
|
|
/* Buffer for sorting in main memory. */
|
|
|
|
struct row_merge_buf_struct {
|
|
|
|
mem_heap_t* heap; /* memory heap where allocated */
|
|
|
|
dict_index_t* index; /* the index the tuples belong to */
|
|
|
|
ulint total_size; /* total amount of data bytes */
|
|
|
|
ulint n_tuples; /* number of data tuples */
|
|
|
|
ulint max_tuples; /* maximum number of data tuples */
|
|
|
|
const dfield_t**tuples; /* array of pointers to
|
|
|
|
arrays of fields that form
|
|
|
|
the data tuples */
|
|
|
|
const dfield_t**tmp_tuples; /* temporary copy of tuples,
|
|
|
|
for sorting */
|
2007-04-11 14:17:55 +02:00
|
|
|
};
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
typedef struct row_merge_buf_struct row_merge_buf_t;
|
2007-04-11 14:17:55 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Information about temporary files used in merge sort are stored
|
|
|
|
to this structure */
|
2007-04-11 14:17:55 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
struct merge_file_struct {
|
|
|
|
int fd; /* File descriptor */
|
|
|
|
ulint offset; /* File offset */
|
2007-04-11 14:17:55 +02:00
|
|
|
};
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
typedef struct merge_file_struct merge_file_t;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Allocate a sort buffer. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_t*
|
|
|
|
row_merge_buf_create_low(
|
|
|
|
/*=====================*/
|
|
|
|
/* out,own: sort buffer */
|
|
|
|
mem_heap_t* heap, /* in: heap where allocated */
|
|
|
|
dict_index_t* index, /* in: secondary index */
|
2007-08-03 13:49:51 +02:00
|
|
|
ulint max_tuples, /* in: maximum number of data tuples */
|
|
|
|
ulint buf_size) /* in: size of the buffer, in bytes */
|
2007-04-12 12:32:16 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_t* buf;
|
|
|
|
|
2007-08-03 13:49:51 +02:00
|
|
|
ut_ad(max_tuples > 0);
|
|
|
|
ut_ad(max_tuples <= sizeof(row_merge_block_t));
|
|
|
|
ut_ad(max_tuples < buf_size);
|
|
|
|
|
2007-06-19 11:39:27 +02:00
|
|
|
buf = mem_heap_calloc(heap, buf_size);
|
2007-06-08 09:37:07 +02:00
|
|
|
buf->heap = heap;
|
|
|
|
buf->index = index;
|
|
|
|
buf->max_tuples = max_tuples;
|
|
|
|
buf->tuples = mem_heap_alloc(heap,
|
|
|
|
2 * max_tuples * sizeof *buf->tuples);
|
|
|
|
buf->tmp_tuples = buf->tuples + max_tuples;
|
|
|
|
|
|
|
|
return(buf);
|
2007-04-12 12:32:16 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Allocate a sort buffer. */
|
2007-04-12 12:32:16 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_t*
|
|
|
|
row_merge_buf_create(
|
2007-04-04 13:05:33 +02:00
|
|
|
/*=================*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out,own: sort buffer */
|
|
|
|
dict_index_t* index) /* in: secondary index */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_t* buf;
|
|
|
|
ulint max_tuples;
|
|
|
|
ulint buf_size;
|
|
|
|
mem_heap_t* heap;
|
2007-04-12 12:32:16 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
max_tuples = sizeof(row_merge_block_t)
|
|
|
|
/ ut_max(1, dict_index_get_min_size(index));
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
buf_size = (sizeof *buf) + (max_tuples - 1) * sizeof *buf->tuples;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
heap = mem_heap_create(buf_size + sizeof(row_merge_block_t));
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
buf = row_merge_buf_create_low(heap, index, max_tuples, buf_size);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(buf);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Empty a sort buffer. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-08-03 13:49:51 +02:00
|
|
|
row_merge_buf_t*
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_empty(
|
|
|
|
/*================*/
|
2007-08-03 13:49:51 +02:00
|
|
|
/* out: sort buffer */
|
|
|
|
row_merge_buf_t* buf) /* in,own: sort buffer */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint buf_size;
|
|
|
|
ulint max_tuples = buf->max_tuples;
|
|
|
|
mem_heap_t* heap = buf->heap;
|
|
|
|
dict_index_t* index = buf->index;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
buf_size = (sizeof *buf) + (max_tuples - 1) * sizeof *buf->tuples;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_empty(heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-08-03 13:49:51 +02:00
|
|
|
return(row_merge_buf_create_low(heap, index, max_tuples, buf_size));
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Deallocate a sort buffer. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
void
|
|
|
|
row_merge_buf_free(
|
|
|
|
/*===============*/
|
|
|
|
row_merge_buf_t* buf) /* in,own: sort buffer, to be freed */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_free(buf->heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Insert a data tuple into a sort buffer. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
ibool
|
|
|
|
row_merge_buf_add(
|
|
|
|
/*==============*/
|
|
|
|
/* out: TRUE if added,
|
|
|
|
FALSE if out of space */
|
|
|
|
row_merge_buf_t* buf, /* in/out: sort buffer */
|
|
|
|
const dtuple_t* row, /* in: row in clustered index */
|
|
|
|
row_ext_t* ext) /* in/out: cache of externally stored
|
|
|
|
column prefixes, or NULL */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint i;
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ulint j;
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint n_fields;
|
|
|
|
ulint data_size;
|
|
|
|
ulint extra_size;
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dict_index_t* index;
|
2007-06-08 09:37:07 +02:00
|
|
|
dfield_t* entry;
|
|
|
|
dfield_t* field;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (buf->n_tuples >= buf->max_tuples) {
|
|
|
|
return(FALSE);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
index = buf->index;
|
|
|
|
|
|
|
|
n_fields = dict_index_get_n_fields(index);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
entry = mem_heap_alloc(buf->heap, n_fields * sizeof *entry);
|
|
|
|
buf->tuples[buf->n_tuples] = entry;
|
|
|
|
field = entry;
|
|
|
|
|
|
|
|
data_size = 0;
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
extra_size = UT_BITS_IN_BYTES(index->n_nullable);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
for (i = j = 0; i < n_fields; i++, field++) {
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_field_t* ifield;
|
|
|
|
const dict_col_t* col;
|
|
|
|
ulint col_no;
|
|
|
|
const dfield_t* row_field;
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ifield = dict_index_get_nth_field(index, i);
|
2007-06-08 09:37:07 +02:00
|
|
|
col = ifield->col;
|
|
|
|
col_no = dict_col_get_no(col);
|
|
|
|
row_field = dtuple_get_nth_field(row, col_no);
|
|
|
|
dfield_copy(field, row_field);
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
if (dfield_is_null(field)) {
|
|
|
|
ut_ad(!(col->prtype & DATA_NOT_NULL));
|
|
|
|
field->data = NULL;
|
|
|
|
continue;
|
|
|
|
} else if (UNIV_LIKELY(!ext)) {
|
|
|
|
} else if (dict_index_is_clust(index)) {
|
|
|
|
/* Flag externally stored fields. */
|
|
|
|
if (j < ext->n_ext && col_no == ext->ext[j]) {
|
|
|
|
j++;
|
|
|
|
|
|
|
|
ut_a(field->len >= BTR_EXTERN_FIELD_REF_SIZE);
|
|
|
|
dfield_set_ext(field);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ulint len = field->len;
|
2007-06-08 09:37:07 +02:00
|
|
|
byte* buf = row_ext_lookup(ext, col_no,
|
|
|
|
row_field->data,
|
|
|
|
row_field->len,
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
&len);
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_LIKELY_NULL(buf)) {
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dfield_set_data(field, buf, len);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* If a column prefix index, take only the prefix */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (ifield->prefix_len) {
|
|
|
|
field->len = dtype_get_at_most_n_mbchars(
|
|
|
|
col->prtype,
|
|
|
|
col->mbminlen, col->mbmaxlen,
|
|
|
|
ifield->prefix_len,
|
|
|
|
field->len, field->data);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(field->len <= col->len || col->mtype == DATA_BLOB);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (ifield->fixed_len) {
|
|
|
|
ut_ad(field->len == ifield->fixed_len);
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ut_ad(!dfield_is_ext(field));
|
|
|
|
} else if (dfield_is_ext(field)) {
|
|
|
|
extra_size += 2;
|
2007-06-08 09:37:07 +02:00
|
|
|
} else if (field->len < 128
|
|
|
|
|| (col->len < 256 && col->mtype != DATA_BLOB)) {
|
|
|
|
extra_size++;
|
|
|
|
} else {
|
|
|
|
extra_size += 2;
|
|
|
|
}
|
|
|
|
data_size += field->len;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ut_ad(!ext || !dict_index_is_clust(index) || j == ext->n_ext);
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
{
|
|
|
|
ulint size;
|
|
|
|
ulint extra;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
size = rec_get_converted_size_comp(index,
|
2007-06-08 09:37:07 +02:00
|
|
|
REC_STATUS_ORDINARY,
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
entry, n_fields, &extra);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(data_size + extra_size + REC_N_NEW_EXTRA_BYTES == size);
|
|
|
|
ut_ad(extra_size + REC_N_NEW_EXTRA_BYTES == extra);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
#endif /* UNIV_DEBUG */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Add to the total size of the record in row_merge_block_t
|
|
|
|
the encoded length of extra_size and the extra bytes (extra_size).
|
|
|
|
See row_merge_buf_write() for the variable-length encoding
|
|
|
|
of extra_size. */
|
2007-06-08 22:30:26 +02:00
|
|
|
data_size += (extra_size + 1) + ((extra_size + 1) >= 0x80);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Reserve one byte for the end marker of row_merge_block_t. */
|
|
|
|
if (buf->total_size + data_size >= sizeof(row_merge_block_t) - 1) {
|
|
|
|
return(FALSE);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
buf->total_size += data_size;
|
|
|
|
buf->n_tuples++;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
field = entry;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the data fields. */
|
|
|
|
for (i = 0; i < n_fields; i++, field++) {
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
if (!dfield_is_null(field)) {
|
2007-06-08 09:37:07 +02:00
|
|
|
field->data = mem_heap_dup(buf->heap,
|
|
|
|
field->data, field->len);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(TRUE);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Compare two tuples. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-04-16 11:13:44 +02:00
|
|
|
int
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_tuple_cmp(
|
|
|
|
/*================*/
|
|
|
|
/* out: 1, 0, -1 if a is greater,
|
|
|
|
equal, less, respectively, than b */
|
|
|
|
ulint n_field,/* in: number of fields */
|
|
|
|
ulint* n_dup, /* in/out: number of duplicates */
|
|
|
|
const dfield_t* a, /* in: first tuple to be compared */
|
|
|
|
const dfield_t* b) /* in: second tuple to be compared */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
int cmp;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
do {
|
|
|
|
cmp = cmp_dfield_dfield(a++, b++);
|
|
|
|
} while (!cmp && --n_field);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (!cmp) {
|
|
|
|
(*n_dup)++;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-04-16 11:13:44 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(cmp);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**************************************************************************
|
|
|
|
Merge sort the tuple buffer in main memory. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
void
|
|
|
|
row_merge_tuple_sort(
|
|
|
|
/*=================*/
|
|
|
|
ulint n_field,/* in: number of fields */
|
|
|
|
ulint* n_dup, /* in/out: number of duplicates */
|
|
|
|
const dfield_t** tuples, /* in/out: tuples */
|
|
|
|
const dfield_t** aux, /* in/out: work area */
|
|
|
|
ulint low, /* in: lower bound of the
|
|
|
|
sorting area, inclusive */
|
|
|
|
ulint high) /* in: upper bound of the
|
|
|
|
sorting area, exclusive */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
#define row_merge_tuple_sort_ctx(a,b,c,d) \
|
|
|
|
row_merge_tuple_sort(n_field, n_dup, a, b, c, d)
|
|
|
|
#define row_merge_tuple_cmp_ctx(a,b) row_merge_tuple_cmp(n_field, n_dup, a, b)
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
UT_SORT_FUNCTION_BODY(row_merge_tuple_sort_ctx,
|
|
|
|
tuples, aux, low, high, row_merge_tuple_cmp_ctx);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Sort a buffer. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint
|
|
|
|
row_merge_buf_sort(
|
2007-04-04 13:05:33 +02:00
|
|
|
/*===============*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out: number of duplicates
|
|
|
|
encountered */
|
|
|
|
row_merge_buf_t* buf) /* in/out: sort buffer */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint n_dup = 0;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
row_merge_tuple_sort(dict_index_get_n_unique(buf->index), &n_dup,
|
2007-06-08 09:37:07 +02:00
|
|
|
buf->tuples, buf->tmp_tuples, 0, buf->n_tuples);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(n_dup);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Write a buffer to a block. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
void
|
|
|
|
row_merge_buf_write(
|
|
|
|
/*================*/
|
|
|
|
const row_merge_buf_t* buf, /* in: sorted buffer */
|
|
|
|
row_merge_block_t* block) /* out: buffer for writing to file */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_index_t* index = buf->index;
|
|
|
|
ulint n_fields= dict_index_get_n_fields(index);
|
|
|
|
byte* b = &(*block)[0];
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ulint i;
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
for (i = 0; i < buf->n_tuples; i++) {
|
|
|
|
ulint size;
|
|
|
|
ulint extra_size;
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
const dfield_t* entry = buf->tuples[i];
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
size = rec_get_converted_size_comp(buf->index,
|
|
|
|
REC_STATUS_ORDINARY,
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
entry, n_fields,
|
2007-06-08 09:37:07 +02:00
|
|
|
&extra_size);
|
|
|
|
ut_ad(size > extra_size);
|
|
|
|
ut_ad(extra_size >= REC_N_NEW_EXTRA_BYTES);
|
|
|
|
extra_size -= REC_N_NEW_EXTRA_BYTES;
|
|
|
|
size -= REC_N_NEW_EXTRA_BYTES;
|
|
|
|
|
|
|
|
/* Encode extra_size + 1 */
|
|
|
|
if (extra_size + 1 < 0x80) {
|
|
|
|
*b++ = extra_size + 1;
|
|
|
|
} else {
|
2007-06-08 22:30:26 +02:00
|
|
|
ut_ad((extra_size + 1) < 0x8000);
|
2007-06-08 09:37:07 +02:00
|
|
|
*b++ = 0x80 | ((extra_size + 1) >> 8);
|
|
|
|
*b++ = (byte) (extra_size + 1);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(b + size < block[1]);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
rec_convert_dtuple_to_rec_comp(b + extra_size, 0, index,
|
|
|
|
REC_STATUS_ORDINARY,
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
entry, n_fields);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
b += size;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Write an "end-of-chunk" marker. */
|
|
|
|
ut_a(b < block[1]);
|
2007-06-08 22:30:26 +02:00
|
|
|
ut_a(b == block[0] + buf->total_size);
|
2007-06-08 09:37:07 +02:00
|
|
|
*b++ = 0;
|
|
|
|
#ifdef UNIV_DEBUG_VALGRIND
|
|
|
|
/* The rest of the block is uninitialized. Initialize it
|
|
|
|
to avoid bogus warnings. */
|
|
|
|
memset(b, 0, block[1] - b);
|
|
|
|
#endif /* UNIV_DEBUG_VALGRIND */
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**********************************************************
|
|
|
|
Create a memory heap and allocate space for row_merge_rec_offsets(). */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_t*
|
|
|
|
row_merge_heap_create(
|
|
|
|
/*==================*/
|
|
|
|
/* out: memory heap */
|
|
|
|
dict_index_t* index, /* in: record descriptor */
|
|
|
|
ulint** offsets1, /* out: offsets */
|
|
|
|
ulint** offsets2) /* out: offsets */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 22:30:26 +02:00
|
|
|
ulint i = 1 + REC_OFFS_HEADER_SIZE
|
2007-06-08 09:37:07 +02:00
|
|
|
+ dict_index_get_n_fields(index);
|
|
|
|
mem_heap_t* heap = mem_heap_create(2 * i * sizeof *offsets1);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
*offsets1 = mem_heap_alloc(heap, i * sizeof *offsets1);
|
|
|
|
*offsets2 = mem_heap_alloc(heap, i * sizeof *offsets2);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
(*offsets1)[0] = (*offsets2)[0] = i;
|
|
|
|
(*offsets1)[1] = (*offsets2)[1] = dict_index_get_n_fields(index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/**************************************************************************
|
|
|
|
Search an index object by name and column names. If several indexes match,
|
|
|
|
return the index with the max id. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_index_t*
|
|
|
|
row_merge_dict_table_get_index(
|
|
|
|
/*===========================*/
|
|
|
|
/* out: matching index,
|
|
|
|
NULL if not found */
|
|
|
|
dict_table_t* table, /* in: table */
|
|
|
|
const merge_index_def_t*index_def) /* in: index definition */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint i;
|
|
|
|
dict_index_t* index;
|
|
|
|
const char** column_names;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
column_names = mem_alloc(index_def->n_fields * sizeof *column_names);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
for (i = 0; i < index_def->n_fields; ++i) {
|
|
|
|
column_names[i] = index_def->fields[i].field_name;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
index = dict_table_get_index_by_max_id(
|
|
|
|
table, index_def->name, column_names, index_def->n_fields);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_free(column_names);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(index);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/************************************************************************
|
|
|
|
Read a merge block from the file system. */
|
|
|
|
static
|
|
|
|
ibool
|
|
|
|
row_merge_read(
|
|
|
|
/*===========*/
|
|
|
|
/* out: TRUE if request was
|
|
|
|
successful, FALSE if fail */
|
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
ulint offset, /* in: offset where to read */
|
|
|
|
row_merge_block_t* buf) /* out: data */
|
|
|
|
{
|
|
|
|
ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(UNIV_LIKELY(os_file_read(OS_FILE_FROM_FD(fd), buf,
|
|
|
|
(ulint) (ofs & 0xFFFFFFFF),
|
|
|
|
(ulint) (ofs >> 32),
|
|
|
|
sizeof *buf)));
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/************************************************************************
|
|
|
|
Read a merge block from the file system. */
|
|
|
|
static
|
|
|
|
ibool
|
|
|
|
row_merge_write(
|
|
|
|
/*============*/
|
|
|
|
/* out: TRUE if request was
|
|
|
|
successful, FALSE if fail */
|
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
ulint offset, /* in: offset where to write */
|
|
|
|
const void* buf) /* in: data */
|
|
|
|
{
|
|
|
|
ib_uint64_t ofs = ((ib_uint64_t) offset)
|
|
|
|
* sizeof(row_merge_block_t);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf,
|
|
|
|
(ulint) (ofs & 0xFFFFFFFF),
|
|
|
|
(ulint) (ofs >> 32),
|
|
|
|
sizeof(row_merge_block_t))));
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/************************************************************************
|
|
|
|
Read a merge record. */
|
|
|
|
static
|
|
|
|
const byte*
|
|
|
|
row_merge_read_rec(
|
|
|
|
/*===============*/
|
|
|
|
/* out: pointer to next record,
|
|
|
|
or NULL on I/O error
|
|
|
|
or end of list */
|
|
|
|
row_merge_block_t* block, /* in/out: file buffer */
|
|
|
|
mrec_buf_t* buf, /* in/out: secondary buffer */
|
|
|
|
const byte* b, /* in: pointer to record */
|
|
|
|
dict_index_t* index, /* in: index of the record */
|
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
ulint* foffs, /* in/out: file offset */
|
|
|
|
const mrec_t** mrec, /* out: pointer to merge record,
|
|
|
|
or NULL on end of list
|
|
|
|
(non-NULL on I/O error) */
|
|
|
|
ulint* offsets)/* out: offsets of mrec */
|
|
|
|
{
|
|
|
|
ulint extra_size;
|
|
|
|
ulint data_size;
|
|
|
|
ulint avail_size;
|
|
|
|
|
|
|
|
ut_ad(block);
|
|
|
|
ut_ad(buf);
|
|
|
|
ut_ad(b >= block[0]);
|
|
|
|
ut_ad(b < block[1]);
|
|
|
|
ut_ad(index);
|
|
|
|
ut_ad(foffs);
|
|
|
|
ut_ad(mrec);
|
|
|
|
ut_ad(offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 22:30:26 +02:00
|
|
|
ut_ad(*offsets == 1 + REC_OFFS_HEADER_SIZE
|
2007-06-08 09:37:07 +02:00
|
|
|
+ dict_index_get_n_fields(index));
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
extra_size = *b++;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_UNLIKELY(!extra_size)) {
|
|
|
|
/* End of list */
|
|
|
|
*mrec = NULL;
|
|
|
|
return(NULL);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (extra_size >= 0x80) {
|
|
|
|
/* Read another byte of extra_size. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_UNLIKELY(b >= block[1])) {
|
|
|
|
if (!row_merge_read(fd, ++(*foffs), block)) {
|
|
|
|
err_exit:
|
|
|
|
/* Signal I/O error. */
|
|
|
|
*mrec = b;
|
|
|
|
return(NULL);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Wrap around to the beginning of the buffer. */
|
|
|
|
b = block[0];
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
extra_size = (extra_size & 0x7f) << 8;
|
|
|
|
extra_size |= *b++;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Normalize extra_size. Above, value 0 signals "end of list. */
|
|
|
|
extra_size--;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Read the extra bytes. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_UNLIKELY(b + extra_size >= block[1])) {
|
|
|
|
/* The record spans two blocks. Copy the entire record
|
|
|
|
to the auxiliary buffer and handle this as a special
|
|
|
|
case. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
avail_size = block[1] - b;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
memcpy(*buf, b, avail_size);
|
2007-04-12 12:32:16 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (!row_merge_read(fd, ++(*foffs), block)) {
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-04-13 14:11:43 +02:00
|
|
|
goto err_exit;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Wrap around to the beginning of the buffer. */
|
|
|
|
b = block[0];
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the record. */
|
|
|
|
memcpy(*buf + avail_size, b, extra_size - avail_size);
|
|
|
|
b += extra_size - avail_size;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
*mrec = *buf + extra_size;
|
2007-04-12 14:58:09 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
data_size = rec_offs_data_size(offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* These overflows should be impossible given that
|
|
|
|
records are much smaller than either buffer, and
|
|
|
|
the record starts near the beginning of each buffer. */
|
|
|
|
ut_a(extra_size + data_size < sizeof *buf);
|
|
|
|
ut_a(b + data_size < block[1]);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the data bytes. */
|
|
|
|
memcpy(*buf + extra_size, b, data_size);
|
|
|
|
b += data_size;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(b);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
*mrec = b + extra_size;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
rec_init_offsets_comp_ordinary(*mrec, 0, index, offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
data_size = rec_offs_data_size(offsets);
|
|
|
|
ut_ad(extra_size + data_size < sizeof *buf);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
b += extra_size + data_size;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_LIKELY(b < block[1])) {
|
|
|
|
/* The record fits entirely in the block.
|
|
|
|
This is the normal case. */
|
|
|
|
return(b);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* The record spans two blocks. Copy it to buf. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
avail_size = block[1] - b;
|
|
|
|
memcpy(*buf, b, avail_size);
|
|
|
|
*mrec = *buf + extra_size;
|
|
|
|
rec_offs_make_valid(*mrec, index, offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (!row_merge_read(fd, ++(*foffs), block)) {
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
goto err_exit;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Wrap around to the beginning of the buffer. */
|
|
|
|
b = block[0];
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the rest of the record. */
|
|
|
|
memcpy(*buf + avail_size, b, extra_size + data_size - avail_size);
|
|
|
|
b += extra_size + data_size - avail_size;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(b);
|
|
|
|
}
|
2007-04-11 11:42:50 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/************************************************************************
|
|
|
|
Write a merge record. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
row_merge_write_rec_low(
|
|
|
|
/*====================*/
|
|
|
|
byte* b, /* out: buffer */
|
|
|
|
ulint e, /* in: encoded extra_size */
|
|
|
|
const mrec_t* mrec, /* in: record to write */
|
|
|
|
const ulint* offsets)/* in: offsets of mrec */
|
|
|
|
{
|
|
|
|
if (e < 0x80) {
|
|
|
|
*b++ = e;
|
|
|
|
} else {
|
|
|
|
*b++ = 0x80 | (e >> 8);
|
|
|
|
*b++ = (byte) e;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
memcpy(b, mrec - rec_offs_extra_size(offsets), rec_offs_size(offsets));
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Write a merge record. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
byte*
|
|
|
|
row_merge_write_rec(
|
|
|
|
/*================*/
|
|
|
|
/* out: pointer to end of block,
|
|
|
|
or NULL on error */
|
|
|
|
row_merge_block_t* block, /* in/out: file buffer */
|
|
|
|
mrec_buf_t* buf, /* in/out: secondary buffer */
|
|
|
|
byte* b, /* in: pointer to end of block */
|
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
ulint* foffs, /* in/out: file offset */
|
|
|
|
const mrec_t* mrec, /* in: record to write */
|
|
|
|
const ulint* offsets)/* in: offsets of mrec */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint extra_size;
|
|
|
|
ulint size;
|
|
|
|
ulint avail_size;
|
|
|
|
|
|
|
|
ut_ad(block);
|
|
|
|
ut_ad(buf);
|
|
|
|
ut_ad(b >= block[0]);
|
|
|
|
ut_ad(b < block[1]);
|
|
|
|
ut_ad(mrec);
|
|
|
|
ut_ad(foffs);
|
|
|
|
ut_ad(mrec < block[0] || mrec > block[1]);
|
|
|
|
ut_ad(mrec < buf[0] || mrec > buf[1]);
|
|
|
|
|
|
|
|
/* Normalize extra_size. Value 0 signals "end of list". */
|
|
|
|
extra_size = rec_offs_extra_size(offsets) + 1;
|
|
|
|
|
|
|
|
size = extra_size + (extra_size >= 0x80)
|
|
|
|
+ rec_offs_data_size(offsets);
|
|
|
|
|
|
|
|
if (UNIV_UNLIKELY(b + size >= block[1])) {
|
|
|
|
/* The record spans two blocks.
|
|
|
|
Copy it to the temporary buffer first. */
|
|
|
|
avail_size = block[1] - b;
|
|
|
|
|
|
|
|
row_merge_write_rec_low(buf[0], extra_size, mrec, offsets);
|
|
|
|
|
|
|
|
/* Copy the head of the temporary buffer, write
|
|
|
|
the completed block, and copy the tail of the
|
|
|
|
record to the head of the new block. */
|
|
|
|
memcpy(b, buf[0], avail_size);
|
|
|
|
|
|
|
|
if (!row_merge_write(fd, (*foffs)++, block)) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the rest. */
|
|
|
|
b = block[0];
|
|
|
|
memcpy(b, buf[0] + avail_size, size - avail_size);
|
|
|
|
b += size - avail_size;
|
|
|
|
} else {
|
|
|
|
row_merge_write_rec_low(b, extra_size, mrec, offsets);
|
|
|
|
b += rec_offs_size(offsets);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(b);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Write an end-of-list marker. */
|
2007-04-04 13:05:33 +02:00
|
|
|
static
|
2007-06-08 09:37:07 +02:00
|
|
|
byte*
|
|
|
|
row_merge_write_eof(
|
|
|
|
/*================*/
|
|
|
|
/* out: pointer to end of block,
|
|
|
|
or NULL on error */
|
|
|
|
row_merge_block_t* block, /* in/out: file buffer */
|
|
|
|
byte* b, /* in: pointer to end of block */
|
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
ulint* foffs) /* in/out: file offset */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(block);
|
|
|
|
ut_ad(b >= block[0]);
|
|
|
|
ut_ad(b < block[1]);
|
|
|
|
ut_ad(foffs);
|
|
|
|
|
|
|
|
*b++ = 0;
|
|
|
|
#ifdef UNIV_DEBUG_VALGRIND
|
|
|
|
/* The rest of the block is uninitialized. Initialize it
|
|
|
|
to avoid bogus warnings. */
|
|
|
|
memset(b, 0, block[1] - b);
|
|
|
|
#endif /* UNIV_DEBUG_VALGRIND */
|
|
|
|
|
|
|
|
if (!row_merge_write(fd, (*foffs)++, block)) {
|
|
|
|
return(NULL);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(block[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
|
|
Compare two merge records. */
|
|
|
|
static
|
|
|
|
int
|
|
|
|
row_merge_cmp(
|
|
|
|
/*==========*/
|
|
|
|
/* out: 1, 0, -1 if mrec1 is
|
|
|
|
greater, equal, less,
|
|
|
|
respectively, than mrec2 */
|
|
|
|
const mrec_t* mrec1, /* in: first merge record to be
|
|
|
|
compared */
|
|
|
|
const mrec_t* mrec2, /* in: second merge record to be
|
|
|
|
compared */
|
|
|
|
const ulint* offsets1, /* in: first record offsets */
|
|
|
|
const ulint* offsets2, /* in: second record offsets */
|
|
|
|
dict_index_t* index) /* in: index */
|
|
|
|
{
|
|
|
|
return(cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index));
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Reads clustered index of the table and create temporary files
|
2007-08-10 17:52:09 +02:00
|
|
|
containing the index entries for the indexes to be built. */
|
2007-06-08 09:37:07 +02:00
|
|
|
static
|
2007-04-04 13:05:33 +02:00
|
|
|
ulint
|
|
|
|
row_merge_read_clustered_index(
|
|
|
|
/*===========================*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out: DB_SUCCESS or error */
|
|
|
|
trx_t* trx, /* in: transaction */
|
2007-08-10 17:52:09 +02:00
|
|
|
dict_table_t* old_table,/* in: table where rows are
|
|
|
|
read from */
|
|
|
|
dict_table_t* new_table,/* in: table where indexes are
|
|
|
|
created; identical to old_table
|
|
|
|
unless creating a PRIMARY KEY */
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_index_t** index, /* in: indexes to be created */
|
|
|
|
merge_file_t* files, /* in: temporary files */
|
|
|
|
ulint n_index,/* in: number of indexes to create */
|
|
|
|
row_merge_block_t* block) /* in/out: file buffer */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_index_t* clust_index; /* Clustered index */
|
|
|
|
mem_heap_t* row_heap; /* Heap memory to create
|
2007-04-04 13:05:33 +02:00
|
|
|
clustered index records */
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_t** merge_buf; /* Temporary list for records*/
|
|
|
|
btr_pcur_t pcur; /* Persistent cursor on the
|
2007-05-22 08:48:53 +02:00
|
|
|
clustered index */
|
2007-06-08 09:37:07 +02:00
|
|
|
mtr_t mtr; /* Mini transaction */
|
|
|
|
ulint err = DB_SUCCESS;/* Return code */
|
|
|
|
ulint i;
|
2007-08-10 17:52:09 +02:00
|
|
|
ulint n_nonnull = 0; /* number of columns
|
|
|
|
changed to NOT NULL */
|
|
|
|
ulint* nonnull = NULL; /* NOT NULL columns */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
trx->op_info = "reading clustered index";
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-05-22 08:48:53 +02:00
|
|
|
ut_ad(trx);
|
2007-08-10 17:52:09 +02:00
|
|
|
ut_ad(old_table);
|
|
|
|
ut_ad(new_table);
|
2007-05-22 08:48:53 +02:00
|
|
|
ut_ad(index);
|
|
|
|
ut_ad(files);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Create and initialize memory for record buffers */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
merge_buf = mem_alloc(n_index * sizeof *merge_buf);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
for (i = 0; i < n_index; i++) {
|
|
|
|
merge_buf[i] = row_merge_buf_create(index[i]);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mtr_start(&mtr);
|
|
|
|
|
|
|
|
/* Find the clustered index and create a persistent cursor
|
|
|
|
based on that. */
|
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
clust_index = dict_table_get_first_index(old_table);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
btr_pcur_open_at_index_side(
|
|
|
|
TRUE, clust_index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
|
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
if (UNIV_UNLIKELY(old_table != new_table)) {
|
|
|
|
ulint n_cols = dict_table_get_n_cols(old_table);
|
|
|
|
|
|
|
|
/* A primary key will be created. Identify the
|
|
|
|
columns that were flagged NOT NULL in the new table,
|
|
|
|
so that we can quickly check that the records in the
|
|
|
|
(old) clustered index do not violate the added NOT
|
|
|
|
NULL constraints. */
|
|
|
|
|
|
|
|
ut_a(n_cols == dict_table_get_n_cols(new_table));
|
|
|
|
|
|
|
|
nonnull = mem_alloc(n_cols * sizeof *nonnull);
|
|
|
|
|
|
|
|
for (i = 0; i < n_cols; i++) {
|
|
|
|
if (dict_table_get_nth_col(old_table, i)->prtype
|
|
|
|
& DATA_NOT_NULL) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dict_table_get_nth_col(new_table, i)->prtype
|
|
|
|
& DATA_NOT_NULL) {
|
|
|
|
|
|
|
|
nonnull[n_nonnull++] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!n_nonnull) {
|
|
|
|
mem_free(nonnull);
|
|
|
|
nonnull = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
row_heap = mem_heap_create(UNIV_PAGE_SIZE);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Scan the clustered index. */
|
2007-05-22 08:48:53 +02:00
|
|
|
for (;;) {
|
|
|
|
const rec_t* rec;
|
2007-08-01 09:52:05 +02:00
|
|
|
dtuple_t* row = NULL;
|
2007-04-04 13:05:33 +02:00
|
|
|
row_ext_t* ext;
|
2007-08-01 09:52:05 +02:00
|
|
|
ibool has_next = TRUE;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-07 10:14:42 +02:00
|
|
|
btr_pcur_move_to_next_on_page(&pcur, &mtr);
|
|
|
|
|
2007-05-22 08:48:53 +02:00
|
|
|
/* When switching pages, commit the mini-transaction
|
|
|
|
in order to release the latch on the old page. */
|
|
|
|
|
|
|
|
if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
|
|
|
|
btr_pcur_store_position(&pcur, &mtr);
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
mtr_start(&mtr);
|
|
|
|
btr_pcur_restore_position(BTR_SEARCH_LEAF,
|
|
|
|
&pcur, &mtr);
|
2007-06-08 09:37:07 +02:00
|
|
|
has_next = btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
2007-05-22 08:48:53 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_LIKELY(has_next)) {
|
|
|
|
rec = btr_pcur_get_rec(&pcur);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Skip delete marked records. */
|
2007-08-10 17:52:09 +02:00
|
|
|
if (rec_get_deleted_flag(
|
|
|
|
rec, dict_table_is_comp(old_table))) {
|
2007-06-08 09:37:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
srv_n_rows_inserted++;
|
2007-06-08 09:37:07 +02:00
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
/* Build a row based on the clustered index. */
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
row = row_build(ROW_COPY_POINTERS, clust_index,
|
|
|
|
rec, NULL, &ext, row_heap);
|
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
if (UNIV_LIKELY_NULL(nonnull)) {
|
|
|
|
for (i = 0; i < n_nonnull; i++) {
|
|
|
|
dfield_t* field
|
|
|
|
= &row->fields[nonnull[i]];
|
|
|
|
|
|
|
|
ut_a(!(field->type.prtype
|
|
|
|
& DATA_NOT_NULL));
|
|
|
|
|
|
|
|
if (dfield_is_null(field)) {
|
|
|
|
trx->error_key_num = 0;
|
|
|
|
err = DB_PRIMARY_KEY_IS_NULL;
|
|
|
|
goto func_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
field->type.prtype |= DATA_NOT_NULL;
|
|
|
|
}
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
/* Build all entries for all the indexes to be created
|
|
|
|
in a single scan of the clustered index. */
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
for (i = 0; i < n_index; i++) {
|
|
|
|
row_merge_buf_t* buf = merge_buf[i];
|
|
|
|
merge_file_t* file = &files[i];
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_LIKELY
|
2007-08-01 09:52:05 +02:00
|
|
|
(row && row_merge_buf_add(buf, row, ext))) {
|
2007-06-08 09:37:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(buf->n_tuples || !has_next);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* We have enough data tuples to form a block.
|
|
|
|
Sort them and write to disk. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (buf->n_tuples
|
|
|
|
&& row_merge_buf_sort(buf)
|
|
|
|
&& dict_index_is_unique(buf->index)) {
|
2007-08-10 17:52:09 +02:00
|
|
|
trx->error_key_num = i;
|
2007-06-08 09:37:07 +02:00
|
|
|
err = DB_DUPLICATE_KEY;
|
|
|
|
goto func_exit;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
row_merge_buf_write(buf, block);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (!row_merge_write(file->fd, file->offset++,
|
|
|
|
block)) {
|
|
|
|
trx->error_key_num = i;
|
|
|
|
err = DB_OUT_OF_FILE_SPACE;
|
|
|
|
goto func_exit;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-08-03 13:49:51 +02:00
|
|
|
merge_buf[i] = row_merge_buf_empty(buf);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_empty(row_heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_UNLIKELY(!has_next)) {
|
|
|
|
goto func_exit;
|
|
|
|
}
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
func_exit:
|
|
|
|
btr_pcur_close(&pcur);
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
mem_heap_free(row_heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-08-10 17:52:09 +02:00
|
|
|
if (UNIV_LIKELY_NULL(nonnull)) {
|
|
|
|
mem_free(nonnull);
|
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
for (i = 0; i < n_index; i++) {
|
|
|
|
row_merge_buf_free(merge_buf[i]);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_free(merge_buf);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
trx->op_info = "";
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(err);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/*****************************************************************
|
|
|
|
Merge two blocks of linked lists on disk and write a bigger block. */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_merge_blocks(
|
|
|
|
/*=============*/
|
|
|
|
/* out: DB_SUCCESS or error code */
|
|
|
|
dict_index_t* index, /* in: index being created */
|
|
|
|
merge_file_t* file, /* in/out: file containing
|
|
|
|
index entries */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
row_merge_block_t* block, /* in/out: 3 buffers */
|
|
|
|
ulint* foffs0, /* in/out: offset of first
|
2007-06-08 09:37:07 +02:00
|
|
|
source list in the file */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
ulint* foffs1, /* in/out: offset of second
|
2007-06-08 09:37:07 +02:00
|
|
|
source list in the file */
|
|
|
|
merge_file_t* of) /* in/out: output file */
|
|
|
|
{
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
mem_heap_t* heap; /* memory heap for offsets0, offsets1 */
|
|
|
|
|
|
|
|
mrec_buf_t buf[3]; /* buffer for handling split mrec in block[] */
|
|
|
|
const byte* b0; /* pointer to block[0] */
|
|
|
|
const byte* b1; /* pointer to block[1] */
|
|
|
|
byte* b2; /* pointer to block[2] */
|
|
|
|
const mrec_t* mrec0; /* merge rec, points to block[0] or buf[0] */
|
|
|
|
const mrec_t* mrec1; /* merge rec, points to block[1] or buf[1] */
|
|
|
|
ulint* offsets0;/* offsets of mrec0 */
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint* offsets1;/* offsets of mrec1 */
|
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
heap = row_merge_heap_create(index, &offsets0, &offsets1);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
/* Write a record and read the next record. Split the output
|
|
|
|
file in two halves, which can be merged on the following pass. */
|
|
|
|
#define ROW_MERGE_WRITE_GET_NEXT(N, AT_END) \
|
|
|
|
do { \
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
b2 = row_merge_write_rec(&block[2], &buf[2], b2, \
|
2007-06-08 09:37:07 +02:00
|
|
|
of->fd, &of->offset, \
|
|
|
|
mrec##N, offsets##N); \
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
if (UNIV_UNLIKELY(!b2)) { \
|
2007-06-08 09:37:07 +02:00
|
|
|
goto corrupt; \
|
|
|
|
} \
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
b##N = row_merge_read_rec(&block[N], &buf[N], \
|
2007-06-08 09:37:07 +02:00
|
|
|
b##N, index, \
|
|
|
|
file->fd, foffs##N, \
|
|
|
|
&mrec##N, offsets##N); \
|
|
|
|
if (UNIV_UNLIKELY(!b##N)) { \
|
|
|
|
if (mrec##N) { \
|
|
|
|
goto corrupt; \
|
|
|
|
} \
|
|
|
|
AT_END; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
if (!row_merge_read(file->fd, *foffs0, &block[0])
|
|
|
|
|| !row_merge_read(file->fd, *foffs1, &block[1])) {
|
2007-06-08 09:37:07 +02:00
|
|
|
corrupt:
|
|
|
|
mem_heap_free(heap);
|
|
|
|
return(DB_CORRUPTION);
|
|
|
|
}
|
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
b0 = block[0];
|
|
|
|
b1 = block[1];
|
|
|
|
b2 = block[2];
|
2007-06-08 09:37:07 +02:00
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd,
|
|
|
|
foffs0, &mrec0, offsets0);
|
|
|
|
b1 = row_merge_read_rec(&block[1], &buf[1], b1, index, file->fd,
|
2007-06-08 09:37:07 +02:00
|
|
|
foffs1, &mrec1, offsets1);
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
if (UNIV_UNLIKELY(!b0 && mrec0)
|
|
|
|
|| UNIV_UNLIKELY(!b1 && mrec1)) {
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
goto corrupt;
|
|
|
|
}
|
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
while (mrec0 && mrec1) {
|
|
|
|
switch (row_merge_cmp(mrec0, mrec1,
|
|
|
|
offsets0, offsets1, index)) {
|
2007-06-08 09:37:07 +02:00
|
|
|
case 0:
|
|
|
|
if (UNIV_UNLIKELY
|
|
|
|
(dict_index_is_unique(index))) {
|
|
|
|
mem_heap_free(heap);
|
|
|
|
return(DB_DUPLICATE_KEY);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
/* fall through */
|
|
|
|
case -1:
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
ROW_MERGE_WRITE_GET_NEXT(0, goto merged);
|
2007-06-08 09:37:07 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
ROW_MERGE_WRITE_GET_NEXT(1, goto merged);
|
2007-06-08 09:37:07 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ut_error;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
merged:
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
if (mrec0) {
|
|
|
|
/* append all mrec0 to output */
|
2007-06-08 09:37:07 +02:00
|
|
|
for (;;) {
|
2007-06-08 22:30:26 +02:00
|
|
|
ROW_MERGE_WRITE_GET_NEXT(0, goto done0);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
}
|
2007-06-08 22:30:26 +02:00
|
|
|
done0:
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
if (mrec1) {
|
|
|
|
/* append all mrec1 to output */
|
2007-06-08 09:37:07 +02:00
|
|
|
for (;;) {
|
2007-06-08 22:30:26 +02:00
|
|
|
ROW_MERGE_WRITE_GET_NEXT(1, goto done1);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
}
|
2007-06-08 22:30:26 +02:00
|
|
|
done1:
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_free(heap);
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
b2 = row_merge_write_eof(&block[2], b2, of->fd, &of->offset);
|
|
|
|
return(b2 ? DB_SUCCESS : DB_CORRUPTION);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/*****************************************************************
|
|
|
|
Merge disk files. */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_merge(
|
|
|
|
/*======*/
|
|
|
|
/* out: DB_SUCCESS
|
|
|
|
or error code */
|
|
|
|
dict_index_t* index, /* in: index being created */
|
|
|
|
merge_file_t* file, /* in/out: file containing
|
|
|
|
index entries */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
row_merge_block_t* block, /* in/out: 3 buffers */
|
2007-06-08 09:37:07 +02:00
|
|
|
int* tmpfd) /* in/out: temporary file
|
|
|
|
handle */
|
|
|
|
{
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
ulint foffs0; /* first input offset */
|
|
|
|
ulint foffs1; /* second input offset */
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint half; /* upper limit of foffs1 */
|
|
|
|
ulint error; /* error code */
|
|
|
|
merge_file_t of; /* output file */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
of.fd = *tmpfd;
|
|
|
|
of.offset = 0;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Split the input file in two halves. */
|
|
|
|
half = file->offset / 2;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Merge blocks to the output file. */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
foffs0 = 0;
|
|
|
|
foffs1 = half;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
for (; foffs0 < half; foffs0++, foffs1++) {
|
|
|
|
error = row_merge_blocks(index, file, block,
|
|
|
|
&foffs0, &foffs1, &of);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
return(error);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Copy the last block, if there is one. */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
while (foffs1 < file->offset) {
|
|
|
|
if (!row_merge_read(file->fd, foffs1++, block)
|
|
|
|
|| !row_merge_write(of.fd, of.offset++, block)) {
|
2007-06-08 09:37:07 +02:00
|
|
|
return(DB_CORRUPTION);
|
2007-04-13 14:11:43 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Swap file descriptors for the next pass. */
|
|
|
|
*tmpfd = file->fd;
|
|
|
|
*file = of;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(DB_SUCCESS);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/*****************************************************************
|
|
|
|
Merge disk files. */
|
|
|
|
static
|
|
|
|
ulint
|
|
|
|
row_merge_sort(
|
|
|
|
/*===========*/
|
|
|
|
/* out: DB_SUCCESS
|
|
|
|
or error code */
|
|
|
|
dict_index_t* index, /* in: index being created */
|
|
|
|
merge_file_t* file, /* in/out: file containing
|
|
|
|
index entries */
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
row_merge_block_t* block, /* in/out: 3 buffers */
|
2007-06-08 09:37:07 +02:00
|
|
|
int* tmpfd) /* in/out: temporary file
|
|
|
|
handle */
|
|
|
|
{
|
|
|
|
ulint blksz; /* block size */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
blksz = 1;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
for (;; blksz *= 2) {
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
ulint error = row_merge(index, file, block, tmpfd);
|
2007-06-08 09:37:07 +02:00
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
return(error);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (blksz >= file->offset) {
|
|
|
|
/* everything is in a single block */
|
|
|
|
break;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Round up the file size to a multiple of blksz. */
|
|
|
|
file->offset = ut_2pow_round(file->offset - 1, blksz) + blksz;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
return(DB_SUCCESS);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
/*****************************************************************
|
|
|
|
Copy externally stored columns to the data tuple. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
row_merge_copy_blobs(
|
|
|
|
/*=================*/
|
|
|
|
const mrec_t* mrec, /* in: merge record */
|
|
|
|
const ulint* offsets,/* in: offsets of mrec */
|
|
|
|
ulint zip_size,/* in: compressed page size in bytes, or 0 */
|
|
|
|
dtuple_t* tuple, /* in/out: data tuple */
|
|
|
|
mem_heap_t* heap) /* in/out: memory heap */
|
|
|
|
{
|
|
|
|
ulint i;
|
|
|
|
ulint n_fields = dtuple_get_n_fields(tuple);
|
|
|
|
|
|
|
|
for (i = 0; i < n_fields; i++) {
|
|
|
|
ulint len;
|
|
|
|
const void* data;
|
|
|
|
dfield_t* field = dtuple_get_nth_field(tuple, i);
|
|
|
|
|
|
|
|
if (!dfield_is_ext(field)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(!dfield_is_null(field));
|
|
|
|
|
|
|
|
data = btr_rec_copy_externally_stored_field(
|
|
|
|
mrec, offsets, zip_size, i, &len, heap);
|
|
|
|
|
|
|
|
dfield_set_data(field, data, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-04 13:05:33 +02:00
|
|
|
/************************************************************************
|
|
|
|
Read sorted file containing index data tuples and insert these data
|
|
|
|
tuples to the index */
|
2007-06-08 09:37:07 +02:00
|
|
|
static
|
2007-04-04 13:05:33 +02:00
|
|
|
ulint
|
|
|
|
row_merge_insert_index_tuples(
|
|
|
|
/*==========================*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out: DB_SUCCESS or error number */
|
|
|
|
trx_t* trx, /* in: transaction */
|
|
|
|
dict_index_t* index, /* in: index */
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dict_table_t* table, /* in: new table */
|
|
|
|
ulint zip_size,/* in: compressed page size of
|
|
|
|
the old table, or 0 if uncompressed */
|
2007-06-08 09:37:07 +02:00
|
|
|
int fd, /* in: file descriptor */
|
|
|
|
row_merge_block_t* block) /* in/out: file buffer */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
mrec_buf_t buf;
|
|
|
|
const byte* b;
|
|
|
|
que_thr_t* thr;
|
|
|
|
ins_node_t* node;
|
|
|
|
mem_heap_t* tuple_heap;
|
|
|
|
mem_heap_t* graph_heap;
|
|
|
|
ulint error = DB_SUCCESS;
|
|
|
|
ulint foffs = 0;
|
|
|
|
ulint* offsets;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(trx);
|
|
|
|
ut_ad(index);
|
|
|
|
ut_ad(table);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* We use the insert query graph as the dummy graph
|
|
|
|
needed in the row module call */
|
|
|
|
|
|
|
|
trx->op_info = "inserting index entries";
|
|
|
|
|
2007-04-13 14:11:43 +02:00
|
|
|
graph_heap = mem_heap_create(500);
|
2007-04-04 13:05:33 +02:00
|
|
|
node = ins_node_create(INS_DIRECT, table, graph_heap);
|
|
|
|
|
|
|
|
thr = pars_complete_graph_for_exec(node, trx, graph_heap);
|
|
|
|
|
|
|
|
que_thr_move_to_run_state_for_mysql(thr, trx);
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
tuple_heap = mem_heap_create(1000);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
{
|
2007-06-08 22:30:26 +02:00
|
|
|
ulint i = 1 + REC_OFFS_HEADER_SIZE
|
2007-06-08 09:37:07 +02:00
|
|
|
+ dict_index_get_n_fields(index);
|
|
|
|
offsets = mem_heap_alloc(graph_heap, i * sizeof *offsets);
|
|
|
|
offsets[0] = i;
|
|
|
|
offsets[1] = dict_index_get_n_fields(index);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
b = *block;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (!row_merge_read(fd, foffs, block)) {
|
|
|
|
error = DB_CORRUPTION;
|
|
|
|
} else {
|
|
|
|
for (;;) {
|
|
|
|
const mrec_t* mrec;
|
|
|
|
dtuple_t* dtuple;
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
ulint n_ext;
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
b = row_merge_read_rec(block, &buf, b, index,
|
|
|
|
fd, &foffs, &mrec, offsets);
|
|
|
|
if (UNIV_UNLIKELY(!b)) {
|
|
|
|
/* End of list, or I/O error */
|
|
|
|
if (mrec) {
|
|
|
|
error = DB_CORRUPTION;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
n_ext = 0;
|
2007-06-08 09:37:07 +02:00
|
|
|
dtuple = row_rec_to_index_entry_low(
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
mrec, index, offsets, &n_ext, tuple_heap);
|
|
|
|
|
|
|
|
if (UNIV_UNLIKELY(n_ext)) {
|
|
|
|
row_merge_copy_blobs(mrec, offsets, zip_size,
|
|
|
|
dtuple, tuple_heap);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
node->row = dtuple;
|
|
|
|
node->table = table;
|
|
|
|
node->trx_id = trx->id;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
ut_ad(dtuple_validate(dtuple));
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
do {
|
|
|
|
thr->run_node = thr;
|
|
|
|
thr->prev_node = thr->common.parent;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
error = row_ins_index_entry(index, dtuple,
|
|
|
|
0, FALSE, thr);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
if (UNIV_LIKELY(error == DB_SUCCESS)) {
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
goto next_rec;
|
|
|
|
}
|
2007-04-13 14:11:43 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
thr->lock_state = QUE_THR_LOCK_ROW;
|
|
|
|
trx->error_state = error;
|
|
|
|
que_thr_stop_for_mysql(thr);
|
|
|
|
thr->lock_state = QUE_THR_LOCK_NOLOCK;
|
|
|
|
} while (row_mysql_handle_errors(&error, trx,
|
|
|
|
thr, NULL));
|
2007-04-13 14:11:43 +02:00
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
goto err_exit;
|
2007-04-13 14:11:43 +02:00
|
|
|
next_rec:
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_empty(tuple_heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
que_thr_stop_for_mysql_no_error(thr, trx);
|
2007-04-13 14:11:43 +02:00
|
|
|
err_exit:
|
2007-04-04 13:05:33 +02:00
|
|
|
que_graph_free(thr->graph);
|
|
|
|
|
|
|
|
trx->op_info = "";
|
|
|
|
|
2007-06-08 09:37:07 +02:00
|
|
|
mem_heap_free(tuple_heap);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
return(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-04 09:49:31 +02:00
|
|
|
Drop an index from the InnoDB system tables. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-04 09:49:31 +02:00
|
|
|
void
|
|
|
|
row_merge_drop_index(
|
|
|
|
/*=================*/
|
2007-04-04 13:05:33 +02:00
|
|
|
dict_index_t* index, /* in: index to be removed */
|
|
|
|
dict_table_t* table, /* in: table */
|
|
|
|
trx_t* trx) /* in: transaction handle */
|
|
|
|
{
|
|
|
|
ulint err;
|
|
|
|
ibool dict_lock = FALSE;
|
2007-04-11 14:42:54 +02:00
|
|
|
pars_info_t* info = pars_info_create();
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* We use the private SQL parser of Innobase to generate the
|
|
|
|
query graphs needed in deleting the dictionary data from system
|
|
|
|
tables in Innobase. Deleting a row from SYS_INDEXES table also
|
|
|
|
frees the file segments of the B-tree associated with the index. */
|
|
|
|
|
|
|
|
static const char str1[] =
|
|
|
|
"PROCEDURE DROP_INDEX_PROC () IS\n"
|
|
|
|
"BEGIN\n"
|
2007-04-11 14:42:54 +02:00
|
|
|
"DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
|
|
|
|
"DELETE FROM SYS_INDEXES WHERE ID = :indexid\n"
|
|
|
|
" AND TABLE_ID = :tableid;\n"
|
2007-04-04 13:05:33 +02:00
|
|
|
"END;\n";
|
|
|
|
|
|
|
|
ut_ad(index && table && trx);
|
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
pars_info_add_dulint_literal(info, "indexid", index->id);
|
|
|
|
pars_info_add_dulint_literal(info, "tableid", table->id);
|
|
|
|
|
2007-04-04 13:05:33 +02:00
|
|
|
trx_start_if_not_started(trx);
|
|
|
|
trx->op_info = "dropping index";
|
|
|
|
|
|
|
|
if (trx->dict_operation_lock_mode == 0) {
|
|
|
|
row_mysql_lock_data_dictionary(trx);
|
|
|
|
dict_lock = TRUE;
|
|
|
|
}
|
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
err = que_eval_sql(info, str1, FALSE, trx);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
ut_a(err == DB_SUCCESS);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
/* Replace this index with another equivalent index for all
|
|
|
|
foreign key constraints on this table where this index is used */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
dict_table_replace_index_in_foreign_list(table, index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
if (trx->dict_redo_list) {
|
|
|
|
dict_redo_remove_index(trx, index);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
dict_index_remove_from_cache(table, index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
if (dict_lock) {
|
|
|
|
row_mysql_unlock_data_dictionary(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->op_info = "";
|
2007-06-04 09:49:31 +02:00
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-04 09:49:31 +02:00
|
|
|
/*************************************************************************
|
|
|
|
Drop those indexes which were created before an error occurred
|
|
|
|
when building an index. */
|
|
|
|
|
|
|
|
void
|
|
|
|
row_merge_drop_indexes(
|
|
|
|
/*===================*/
|
|
|
|
trx_t* trx, /* in: transaction */
|
|
|
|
dict_table_t* table, /* in: table containing the indexes */
|
|
|
|
dict_index_t** index, /* in: indexes to drop */
|
|
|
|
ulint num_created) /* in: number of elements in index[] */
|
|
|
|
{
|
|
|
|
ulint key_num;
|
|
|
|
|
|
|
|
for (key_num = 0; key_num < num_created; key_num++) {
|
|
|
|
row_merge_drop_index(index[key_num], table, trx);
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Create a merge file. */
|
|
|
|
static
|
2007-04-11 10:16:14 +02:00
|
|
|
void
|
|
|
|
row_merge_file_create(
|
|
|
|
/*==================*/
|
|
|
|
merge_file_t* merge_file) /* out: merge file structure */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
2007-06-08 09:37:07 +02:00
|
|
|
merge_file->fd = innobase_mysql_tmpfile();
|
2007-04-12 12:32:16 +02:00
|
|
|
merge_file->offset = 0;
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Destroy a merge file. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
row_merge_file_destroy(
|
|
|
|
/*===================*/
|
|
|
|
merge_file_t* merge_file) /* out: merge file structure */
|
|
|
|
{
|
|
|
|
if (merge_file->fd != -1) {
|
|
|
|
close(merge_file->fd);
|
|
|
|
merge_file->fd = -1;
|
|
|
|
}
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-08-10 17:52:09 +02:00
|
|
|
Determine the precise type of a column that is added to a tem
|
|
|
|
if a column must be constrained NOT NULL. */
|
|
|
|
UNIV_INLINE
|
|
|
|
ulint
|
|
|
|
row_merge_col_prtype(
|
|
|
|
/*=================*/
|
|
|
|
/* out: col->prtype, possibly
|
|
|
|
ORed with DATA_NOT_NULL */
|
|
|
|
const dict_col_t* col, /* in: column */
|
|
|
|
const char* col_name, /* in: name of the column */
|
|
|
|
const merge_index_def_t*index_def) /* in: the index definition
|
|
|
|
of the primary key */
|
|
|
|
{
|
|
|
|
ulint prtype = col->prtype;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
ut_ad(index_def->ind_type & DICT_CLUSTERED);
|
|
|
|
|
|
|
|
if (prtype & DATA_NOT_NULL) {
|
|
|
|
|
|
|
|
return(prtype);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All columns that are included
|
|
|
|
in the PRIMARY KEY must be NOT NULL. */
|
|
|
|
|
|
|
|
for (i = 0; i < index_def->n_fields; i++) {
|
|
|
|
if (!strcmp(col_name, index_def->fields[i].field_name)) {
|
|
|
|
return(prtype | DATA_NOT_NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(prtype);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Create a temporary table for creating a primary key, using the definition
|
|
|
|
of an existing table. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
dict_table_t*
|
|
|
|
row_merge_create_temporary_table(
|
|
|
|
/*=============================*/
|
2007-08-10 17:52:09 +02:00
|
|
|
/* out: table,
|
|
|
|
or NULL on error */
|
|
|
|
const char* table_name, /* in: new table name */
|
|
|
|
const merge_index_def_t*index_def, /* in: the index definition
|
|
|
|
of the primary key */
|
|
|
|
const dict_table_t* table, /* in: old table definition */
|
|
|
|
trx_t* trx) /* in/out: transaction
|
|
|
|
(sets error_state) */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
|
|
|
ulint i;
|
|
|
|
dict_table_t* new_table = NULL;
|
|
|
|
ulint n_cols = dict_table_get_n_user_cols(table);
|
2007-06-06 22:25:35 +02:00
|
|
|
ulint error;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-08-02 11:46:28 +02:00
|
|
|
ut_ad(table_name);
|
2007-08-10 17:52:09 +02:00
|
|
|
ut_ad(index_def);
|
2007-08-02 11:46:28 +02:00
|
|
|
ut_ad(table);
|
2007-04-04 13:05:33 +02:00
|
|
|
ut_ad(mutex_own(&dict_sys->mutex));
|
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
error = row_undo_report_create_table_dict_operation(trx, table_name);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
if (error == DB_SUCCESS) {
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
mem_heap_t* heap = mem_heap_create(1000);
|
|
|
|
log_buffer_flush_to_disk();
|
|
|
|
|
|
|
|
new_table = dict_mem_table_create(
|
|
|
|
table_name, 0, n_cols, table->flags);
|
|
|
|
|
|
|
|
for (i = 0; i < n_cols; i++) {
|
|
|
|
const dict_col_t* col;
|
2007-08-10 17:52:09 +02:00
|
|
|
const char* col_name;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
col = dict_table_get_nth_col(table, i);
|
2007-08-10 17:52:09 +02:00
|
|
|
col_name = dict_table_get_col_name(table, i);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
dict_mem_table_add_col(
|
2007-08-10 17:52:09 +02:00
|
|
|
new_table, heap, col_name, col->mtype,
|
|
|
|
row_merge_col_prtype(col, col_name, index_def),
|
|
|
|
col->len);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
error = row_create_table_for_mysql(new_table, trx);
|
2007-04-04 16:26:06 +02:00
|
|
|
mem_heap_free(heap);
|
2007-06-06 22:25:35 +02:00
|
|
|
|
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
dict_mem_table_free(new_table);
|
|
|
|
new_table = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
trx->error_state = error;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return(new_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Rename the indexes in the dictionary. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
ulint
|
|
|
|
row_merge_rename_index(
|
|
|
|
/*===================*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out: DB_SUCCESS if all OK */
|
2007-04-04 13:05:33 +02:00
|
|
|
trx_t* trx, /* in: Transaction */
|
|
|
|
dict_table_t* table, /* in: Table for index */
|
|
|
|
dict_index_t* index) /* in: Index to rename */
|
|
|
|
{
|
|
|
|
ibool dict_lock = FALSE;
|
|
|
|
ulint err = DB_SUCCESS;
|
2007-04-11 14:42:54 +02:00
|
|
|
pars_info_t* info = pars_info_create();
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* Only rename from temp names */
|
|
|
|
ut_a(*index->name == TEMP_TABLE_PREFIX);
|
|
|
|
|
|
|
|
/* We use the private SQL parser of Innobase to generate the
|
|
|
|
query graphs needed in renaming index. */
|
|
|
|
|
|
|
|
static const char str1[] =
|
|
|
|
"PROCEDURE RENAME_INDEX_PROC () IS\n"
|
|
|
|
"BEGIN\n"
|
2007-04-11 14:42:54 +02:00
|
|
|
"UPDATE SYS_INDEXES SET NAME = :name\n"
|
|
|
|
" WHERE ID = :indexid AND TABLE_ID = :tableid;\n"
|
2007-04-04 13:05:33 +02:00
|
|
|
"END;\n";
|
|
|
|
|
|
|
|
table = index->table;
|
|
|
|
|
|
|
|
ut_ad(index && table && trx);
|
|
|
|
|
|
|
|
trx_start_if_not_started(trx);
|
|
|
|
trx->op_info = "renaming index";
|
|
|
|
|
2007-06-13 13:01:26 +02:00
|
|
|
pars_info_add_str_literal(info, "name", index->name + 1);
|
2007-04-11 14:42:54 +02:00
|
|
|
pars_info_add_dulint_literal(info, "indexid", index->id);
|
|
|
|
pars_info_add_dulint_literal(info, "tableid", table->id);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
if (trx->dict_operation_lock_mode == 0) {
|
|
|
|
row_mysql_lock_data_dictionary(trx);
|
|
|
|
dict_lock = TRUE;
|
|
|
|
}
|
|
|
|
|
2007-04-11 14:42:54 +02:00
|
|
|
err = que_eval_sql(info, str1, FALSE, trx);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
if (err == DB_SUCCESS) {
|
2007-04-11 14:42:54 +02:00
|
|
|
index->name++;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dict_lock) {
|
|
|
|
row_mysql_unlock_data_dictionary(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
trx->op_info = "";
|
|
|
|
|
|
|
|
return(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-06 22:25:35 +02:00
|
|
|
Create the index and load in to the dictionary. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
dict_index_t*
|
2007-04-04 13:05:33 +02:00
|
|
|
row_merge_create_index(
|
|
|
|
/*===================*/
|
2007-06-06 22:25:35 +02:00
|
|
|
/* out: index, or NULL on error */
|
|
|
|
trx_t* trx, /* in/out: trx (sets error_state) */
|
2007-04-04 13:05:33 +02:00
|
|
|
dict_table_t* table, /* in: the index is on this table */
|
|
|
|
const merge_index_def_t* /* in: the index definition */
|
|
|
|
index_def)
|
|
|
|
{
|
2007-06-06 22:25:35 +02:00
|
|
|
dict_index_t* index;
|
2007-04-04 13:05:33 +02:00
|
|
|
ulint err = DB_SUCCESS;
|
|
|
|
ulint n_fields = index_def->n_fields;
|
|
|
|
|
|
|
|
/* Create the index prototype, using the passed in def, this is not
|
|
|
|
a persistent operation. We pass 0 as the space id, and determine at
|
2007-06-08 09:37:07 +02:00
|
|
|
a lower level the space id where to store the table. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
index = dict_mem_index_create(table->name, index_def->name,
|
|
|
|
0, index_def->ind_type, n_fields);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
ut_a(index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* Create the index id, as it will be required when we build
|
|
|
|
the index. We assign the id here because we want to write an
|
2007-06-06 22:25:35 +02:00
|
|
|
UNDO record before we insert the entry into SYS_INDEXES. */
|
|
|
|
ut_a(ut_dulint_is_zero(index->id));
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
|
|
|
|
index->table = table;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* Write the UNDO record for the create index */
|
2007-06-06 22:25:35 +02:00
|
|
|
err = row_undo_report_create_index_dict_operation(trx, index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
if (err == DB_SUCCESS) {
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
/* Make sure the UNDO record gets to disk */
|
|
|
|
log_buffer_flush_to_disk();
|
|
|
|
|
|
|
|
for (i = 0; i < n_fields; i++) {
|
|
|
|
merge_index_field_t* ifield;
|
|
|
|
|
2007-04-11 14:17:55 +02:00
|
|
|
ifield = &index_def->fields[i];
|
2007-04-04 13:05:33 +02:00
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
dict_mem_index_add_field(index,
|
2007-04-11 14:17:55 +02:00
|
|
|
ifield->field_name,
|
|
|
|
ifield->prefix_len);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the index to SYS_INDEXES, this will use the prototype
|
2007-06-06 22:25:35 +02:00
|
|
|
to create an entry in SYS_INDEXES. */
|
|
|
|
err = row_create_index_graph_for_mysql(trx, table, index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
if (err == DB_SUCCESS) {
|
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
index = row_merge_dict_table_get_index(
|
2007-04-04 13:05:33 +02:00
|
|
|
table, index_def);
|
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
ut_a(index);
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* Note the id of the transaction that created this
|
|
|
|
index, we use it to restrict readers from accessing
|
2007-06-06 22:25:35 +02:00
|
|
|
this index, to ensure read consistency. */
|
|
|
|
index->trx_id = trx->id;
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
/* Create element and append to list in trx. So that
|
2007-06-06 22:25:35 +02:00
|
|
|
we can rename from temp name to real name. */
|
2007-04-04 13:05:33 +02:00
|
|
|
if (trx->dict_redo_list) {
|
|
|
|
dict_redo_t* dict_redo;
|
|
|
|
|
|
|
|
dict_redo = dict_redo_create_element(trx);
|
2007-06-06 22:25:35 +02:00
|
|
|
dict_redo->index = index;
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-06 22:25:35 +02:00
|
|
|
if (err != DB_SUCCESS) {
|
|
|
|
trx->error_state = err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(index);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Check if a transaction can use an index. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
ibool
|
|
|
|
row_merge_is_index_usable(
|
|
|
|
/*======================*/
|
2007-04-11 10:16:14 +02:00
|
|
|
const trx_t* trx, /* in: transaction */
|
|
|
|
const dict_index_t* index) /* in: index to check */
|
2007-04-04 13:05:33 +02:00
|
|
|
{
|
|
|
|
if (!trx->read_view) {
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(ut_dulint_cmp(index->trx_id, trx->read_view->low_limit_id) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
2007-06-08 09:37:07 +02:00
|
|
|
Drop the old table. */
|
2007-04-04 13:05:33 +02:00
|
|
|
|
|
|
|
ulint
|
|
|
|
row_merge_drop_table(
|
|
|
|
/*=================*/
|
2007-06-08 09:37:07 +02:00
|
|
|
/* out: DB_SUCCESS or error code */
|
2007-04-04 13:05:33 +02:00
|
|
|
trx_t* trx, /* in: transaction */
|
|
|
|
dict_table_t* table) /* in: table to drop */
|
|
|
|
{
|
|
|
|
ulint err = DB_SUCCESS;
|
|
|
|
ibool dict_locked = FALSE;
|
|
|
|
|
|
|
|
if (trx->dict_operation_lock_mode == 0) {
|
|
|
|
row_mysql_lock_data_dictionary(trx);
|
|
|
|
dict_locked = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_a(*table->name == TEMP_TABLE_PREFIX);
|
|
|
|
|
2007-08-10 17:22:47 +02:00
|
|
|
/* Drop the table immediately if it is not referenced by MySQL */
|
2007-04-04 13:05:33 +02:00
|
|
|
if (table->n_mysql_handles_opened == 0) {
|
2007-06-13 15:40:29 +02:00
|
|
|
/* Copy table->name, because table will have been
|
|
|
|
freed when row_drop_table_for_mysql_no_commit()
|
|
|
|
checks with dict_load_table() that the table was
|
|
|
|
indeed dropped. */
|
|
|
|
char* table_name = mem_strdup(table->name);
|
2007-06-08 09:37:07 +02:00
|
|
|
/* Set the commit flag to FALSE. */
|
2007-06-13 15:40:29 +02:00
|
|
|
err = row_drop_table_for_mysql(table_name, trx, FALSE);
|
|
|
|
mem_free(table_name);
|
2007-04-04 13:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dict_locked) {
|
|
|
|
row_mysql_unlock_data_dictionary(trx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(err);
|
|
|
|
}
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Build indexes on a table by reading a clustered index,
|
|
|
|
creating a temporary file containing index entries, merge sorting
|
|
|
|
these index entries and inserting sorted index entries to indexes. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
row_merge_build_indexes(
|
|
|
|
/*====================*/
|
|
|
|
/* out: DB_SUCCESS or error code */
|
|
|
|
trx_t* trx, /* in: transaction */
|
2007-08-10 17:22:47 +02:00
|
|
|
dict_table_t* old_table, /* in: table where rows are
|
2007-06-08 09:37:07 +02:00
|
|
|
read from */
|
2007-08-10 17:22:47 +02:00
|
|
|
dict_table_t* new_table, /* in: table where indexes are
|
|
|
|
created; identical to old_table
|
|
|
|
unless creating a PRIMARY KEY */
|
2007-06-08 09:37:07 +02:00
|
|
|
dict_index_t** indexes, /* in: indexes to be created */
|
|
|
|
ulint n_indexes) /* in: size of indexes[] */
|
|
|
|
{
|
|
|
|
merge_file_t* merge_files;
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
row_merge_block_t* block;
|
|
|
|
ulint block_size;
|
2007-06-08 09:37:07 +02:00
|
|
|
ulint i;
|
|
|
|
ulint error;
|
|
|
|
int tmpfd;
|
|
|
|
|
|
|
|
ut_ad(trx);
|
|
|
|
ut_ad(old_table);
|
|
|
|
ut_ad(new_table);
|
|
|
|
ut_ad(indexes);
|
|
|
|
ut_ad(n_indexes);
|
|
|
|
|
|
|
|
trx_start_if_not_started(trx);
|
|
|
|
|
|
|
|
/* Allocate memory for merge file data structure and initialize
|
|
|
|
fields */
|
|
|
|
|
|
|
|
merge_files = mem_alloc(n_indexes * sizeof *merge_files);
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
block_size = 3 * sizeof *block;
|
|
|
|
block = os_mem_alloc_large(&block_size);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
for (i = 0; i < n_indexes; i++) {
|
|
|
|
|
|
|
|
row_merge_file_create(&merge_files[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpfd = innobase_mysql_tmpfile();
|
|
|
|
|
|
|
|
/* Read clustered index of the table and create files for
|
|
|
|
secondary index entries for merge sort */
|
|
|
|
|
|
|
|
error = row_merge_read_clustered_index(
|
2007-08-10 17:52:09 +02:00
|
|
|
trx, old_table, new_table, indexes,
|
|
|
|
merge_files, n_indexes, block);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
|
|
|
|
goto func_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
trx_start_if_not_started(trx);
|
|
|
|
|
|
|
|
/* Now we have files containing index entries ready for
|
|
|
|
sorting and inserting. */
|
|
|
|
|
|
|
|
for (i = 0; i < n_indexes; i++) {
|
|
|
|
error = row_merge_sort(indexes[i], &merge_files[i],
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
block, &tmpfd);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
if (error == DB_SUCCESS) {
|
|
|
|
error = row_merge_insert_index_tuples(
|
|
|
|
trx, indexes[i], new_table,
|
branches/zip: Make merge sort handle externally stored columns.
Some things still fail in innodb-index.test, and there seems to be
a race condition (data dictionary lock wait) when running with --valgrind.
dfield_t: Add an "external storage" flag, dfield->ext.
dfield_is_null(), dfield_is_ext(), dfield_set_ext(), dfield_set_null():
New functions.
dfield_copy(), dfield_copy_data(): Add const qualifiers, fix in/out comments.
data_write_sql_null(): Use memset().
big_rec_field_t: Replace byte* data with const void* data.
ut_ulint_sort(): Remove.
upd_field_t: Remove extern_storage.
upd_node_t: Replace ext_vec, n_ext_vec with n_ext.
row_merge_copy_blobs(): New function.
row_ins_index_entry(): Add the parameter "ibool foreign" for suppressing
foreign key checks during fast index creation or when inserting into
secondary indexes.
btr_page_insert_fits(): Add const qualifiers.
btr_cur_add_ext(), upd_ext_vec_contains(): Remove.
dfield_print_also_hex(), dfield_print(): Replace if...else if with switch.
Observe dfield_is_ext().
2007-06-21 11:43:15 +02:00
|
|
|
dict_table_zip_size(old_table),
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
merge_files[i].fd, block);
|
2007-06-08 09:37:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the temporary file to free up space. */
|
|
|
|
row_merge_file_destroy(&merge_files[i]);
|
|
|
|
|
|
|
|
if (error != DB_SUCCESS) {
|
|
|
|
trx->error_key_num = i;
|
|
|
|
goto func_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func_exit:
|
|
|
|
close(tmpfd);
|
|
|
|
|
|
|
|
for (i = 0; i < n_indexes; i++) {
|
|
|
|
row_merge_file_destroy(&merge_files[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(merge_files);
|
branches/zip: row_merge_build_indexes(): Allocate all buffers with a
single os_mem_alloc_large() call. The function mem_alloc() that was
used previously allocates unaligned memory.
row_merge_blocks(): Replace block1, block2, block3 with a single array.
Replace buf1, buf2, buf3 with buf[3]. Replace b1..b3 with b0..b2.
Replace mrec1,2 with mrec0,1. Replace offsets1,2 with offsets0,1.
row_merge(), row_merge_sort(): Replace block1, block2, block3 with a
single array.
2007-06-08 11:49:50 +02:00
|
|
|
os_mem_free_large(block, block_size);
|
2007-06-08 09:37:07 +02:00
|
|
|
|
|
|
|
return(error);
|
|
|
|
}
|