mirror of
https://github.com/MariaDB/server.git
synced 2025-12-12 08:01:43 +03:00
branches/zip: Merge branches/fast-index-creation -r1413.
Fix some bugs. The tests innodb and innodb-index fail, but that might be due to an old MySQL source tree being used.
This commit is contained in:
124
data/data0data.c
124
data/data0data.c
@@ -383,6 +383,7 @@ dfield_print_also_hex(
|
||||
const byte* data;
|
||||
ulint len;
|
||||
ulint mtype;
|
||||
ulint prtype;
|
||||
ulint i;
|
||||
ibool print_also_hex;
|
||||
|
||||
@@ -396,6 +397,7 @@ dfield_print_also_hex(
|
||||
}
|
||||
|
||||
mtype = dtype_get_mtype(dfield_get_type(dfield));
|
||||
prtype = dtype_get_prtype(dfield_get_type(dfield));
|
||||
|
||||
if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
|
||||
|
||||
@@ -403,12 +405,15 @@ dfield_print_also_hex(
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = *data++;
|
||||
|
||||
if (!isprint(c)) {
|
||||
print_also_hex = TRUE;
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
fprintf(stderr, "\\x%02x", (unsigned char) c);
|
||||
} else {
|
||||
putc(c, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!print_also_hex) {
|
||||
|
||||
@@ -422,13 +427,122 @@ dfield_print_also_hex(
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02lx", (ulint)*data);
|
||||
|
||||
data++;
|
||||
}
|
||||
} else if (mtype == DATA_BINARY) {
|
||||
data = dfield_get_data(dfield);
|
||||
fputs(" Hex: ",stderr);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02lx", (ulint)*data);
|
||||
data++;
|
||||
}
|
||||
} else if (mtype == DATA_INT) {
|
||||
ut_a(len == 4); /* only works for 32-bit integers */
|
||||
fprintf(stderr, "%d", (int)mach_read_from_4(data));
|
||||
dulint big_val;
|
||||
|
||||
if (len == 1) {
|
||||
ulint val;
|
||||
|
||||
val = (ulint)mach_read_from_1(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x80;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
ut_error;
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
|
||||
} else if (len == 2) {
|
||||
ulint val;
|
||||
|
||||
val = (ulint)mach_read_from_2(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x8000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
|
||||
} else if (len == 3) {
|
||||
ulint val;
|
||||
|
||||
val = (ulint)mach_read_from_3(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x800000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
|
||||
} else if (len == 4) {
|
||||
ulint val;
|
||||
|
||||
val = (ulint)mach_read_from_4(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x80000000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
|
||||
} else if (len == 6) {
|
||||
big_val = (dulint)mach_read_from_6(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(big_val),
|
||||
ut_dulint_get_low(big_val));
|
||||
} else if (len == 7) {
|
||||
big_val = (dulint)mach_read_from_7(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(big_val),
|
||||
ut_dulint_get_low(big_val));
|
||||
} else if (len == 8) {
|
||||
big_val = (dulint)mach_read_from_8(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(big_val),
|
||||
ut_dulint_get_low(big_val));
|
||||
} else {
|
||||
fputs(" Hex: ",stderr);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02lx", (ulint)*data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
} else if (mtype == DATA_SYS) {
|
||||
dulint id;
|
||||
|
||||
if (prtype & DATA_TRX_ID) {
|
||||
id = mach_read_from_6(data);
|
||||
|
||||
fprintf(stderr, "trx_id {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
} else if (prtype & DATA_ROLL_PTR) {
|
||||
id = mach_read_from_7(data);
|
||||
|
||||
fprintf(stderr, "roll_ptr {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
} else if (prtype & DATA_ROW_ID) {
|
||||
id = mach_read_from_6(data);
|
||||
|
||||
fprintf(stderr, "row_id {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
} else {
|
||||
id = mach_dulint_read_compressed(data);
|
||||
|
||||
fprintf(stderr, "mix_id {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
}
|
||||
|
||||
} else {
|
||||
fputs(" Hex: ",stderr);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02lx", (ulint)*data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -540,7 +540,11 @@ dict_build_index_def_step(
|
||||
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
|
||||
|| dict_index_is_clust(index));
|
||||
|
||||
/* For fast index creation we have already allocated an index id
|
||||
for this index so that we could write an UNDO log record for it.*/
|
||||
if (ut_dulint_is_zero(index->id)) {
|
||||
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
|
||||
}
|
||||
|
||||
/* Inherit the space id from the table; we store all indexes of a
|
||||
table in the same tablespace */
|
||||
@@ -552,6 +556,9 @@ dict_build_index_def_step(
|
||||
|
||||
ins_node_set_new_row(node->ind_def, row);
|
||||
|
||||
/* Note that the index was created by this transaction. */
|
||||
index->trx_id = trx->id;
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
655
dict/dict0dict.c
655
dict/dict0dict.c
@@ -26,6 +26,7 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#include "pars0sym.h"
|
||||
#include "que0que.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "row0merge.h"
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
# include "m_ctype.h" /* my_isspace() */
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
@@ -366,19 +367,6 @@ dict_table_get_next_index_noninline(
|
||||
return(dict_table_get_next_index(index));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns an index object. */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_noninline(
|
||||
/*===========================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name) /* in: index name */
|
||||
{
|
||||
return(dict_table_get_index(table, name));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns a column's name. */
|
||||
|
||||
@@ -539,6 +527,33 @@ dict_table_autoinc_update(
|
||||
mutex_exit(&(table->autoinc_mutex));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Looks for an index with the given table and index id.
|
||||
NOTE that we do not reserve the dictionary mutex. */
|
||||
dict_index_t*
|
||||
dict_index_get_on_id_low(
|
||||
/*=====================*/
|
||||
/* out: index or NULL if not found from cache */
|
||||
dict_table_t* table, /* in: table */
|
||||
dulint id) /* in: index id */
|
||||
{
|
||||
dict_index_t* index;
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index) {
|
||||
if (0 == ut_dulint_cmp(id, index->id)) {
|
||||
/* Found */
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Looks for column n in an index. */
|
||||
|
||||
@@ -1358,20 +1373,6 @@ dict_index_add_to_cache(
|
||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
||||
|
||||
ut_ad(mem_heap_validate(index->heap));
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
{
|
||||
dict_index_t* index2;
|
||||
index2 = UT_LIST_GET_FIRST(table->indexes);
|
||||
|
||||
while (index2 != NULL) {
|
||||
ut_ad(ut_strcmp(index->name, index2->name) != 0);
|
||||
|
||||
index2 = UT_LIST_GET_NEXT(indexes, index2);
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
ut_a(!dict_index_is_clust(index)
|
||||
|| UT_LIST_GET_LEN(table->indexes) == 0);
|
||||
|
||||
@@ -1412,7 +1413,10 @@ dict_index_add_to_cache(
|
||||
dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
|
||||
}
|
||||
|
||||
new_index->page = (unsigned int) page_no;
|
||||
new_index->stat_index_size = 1;
|
||||
new_index->stat_n_leaf_pages = 1;
|
||||
|
||||
new_index->page = page_no;
|
||||
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
|
||||
|
||||
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
|
||||
@@ -1497,7 +1501,7 @@ dict_index_find_cols(
|
||||
/* It is an error not to find a matching column. */
|
||||
ut_error;
|
||||
|
||||
found:
|
||||
found:
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -1873,18 +1877,92 @@ dict_index_build_internal_non_clust(
|
||||
Checks if a table is referenced by foreign keys. */
|
||||
|
||||
ibool
|
||||
dict_table_referenced_by_foreign_key(
|
||||
/*=================================*/
|
||||
/* out: TRUE if table is referenced by a
|
||||
foreign key */
|
||||
dict_table_t* table) /* in: InnoDB table */
|
||||
dict_table_is_referenced_by_foreign_key(
|
||||
/*====================================*/
|
||||
/* out: TRUE if table is referenced
|
||||
by a foreign key */
|
||||
const dict_table_t* table) /* in: InnoDB table */
|
||||
{
|
||||
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
|
||||
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
/*************************************************************************
|
||||
Check if the index is referenced by a foreign key, if TRUE return foreign
|
||||
else return NULL */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_table_get_referenced_constraint(
|
||||
/*=================================*/
|
||||
/* out: pointer to foreign key struct if index
|
||||
is defined for foreign key, otherwise NULL */
|
||||
dict_table_t* table, /* in: InnoDB table */
|
||||
dict_index_t* index) /* in: InnoDB index */
|
||||
{
|
||||
dict_foreign_t* foreign = NULL;
|
||||
|
||||
ut_ad(index && table);
|
||||
|
||||
/* If the referenced list is empty, nothing to do */
|
||||
|
||||
if (UT_LIST_GET_LEN(table->referenced_list) == 0) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index
|
||||
|| foreign->referenced_index == index) {
|
||||
|
||||
return(foreign);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a index is defined for a foreign key constraint. Index is a part
|
||||
of a foreign key constraint if the index is referenced by foreign key
|
||||
or index is a foreign key index. */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_table_get_foreign_constraint(
|
||||
/*==============================*/
|
||||
/* out: pointer to foreign key struct if index
|
||||
is defined for foreign key, otherwise NULL */
|
||||
dict_table_t* table, /* in: InnoDB table */
|
||||
dict_index_t* index) /* in: InnoDB index */
|
||||
{
|
||||
dict_foreign_t* foreign = NULL;
|
||||
|
||||
ut_ad(index && table);
|
||||
|
||||
/* If list empty then nothgin to do */
|
||||
|
||||
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Check whether this index is defined for a foreign key */
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->foreign_index == index
|
||||
|| foreign->referenced_index == index) {
|
||||
|
||||
return(foreign);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@@ -1967,7 +2045,8 @@ dict_foreign_find(
|
||||
|
||||
/*************************************************************************
|
||||
Tries to find an index whose first fields are the columns in the array,
|
||||
in the same order. */
|
||||
in the same order and is not marked for deletion and is not the same
|
||||
as types_idx. */
|
||||
static
|
||||
dict_index_t*
|
||||
dict_foreign_find_index(
|
||||
@@ -1986,16 +2065,23 @@ dict_foreign_find_index(
|
||||
be declared NOT NULL */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dict_field_t* field;
|
||||
const char* col_name;
|
||||
ulint i;
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
if (dict_index_get_n_fields(index) >= n_cols) {
|
||||
/* Ignore matches that refer to the same instance
|
||||
or the index is to be dropped */
|
||||
if (index->to_be_dropped || types_idx == index) {
|
||||
|
||||
goto next_rec;
|
||||
|
||||
} else if (dict_index_get_n_fields(index) >= n_cols) {
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < n_cols; i++) {
|
||||
dict_field_t* field;
|
||||
const char* col_name;
|
||||
|
||||
field = dict_index_get_nth_field(index, i);
|
||||
|
||||
col_name = dict_table_get_col_name(
|
||||
@@ -2036,12 +2122,73 @@ dict_foreign_find_index(
|
||||
}
|
||||
}
|
||||
|
||||
next_rec:
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Tries to find an index whose fields match exactly, in the same order. If
|
||||
more than one index is found then return the index with the higher id.*/
|
||||
static
|
||||
dict_index_t*
|
||||
dict_find_index_by_max_id(
|
||||
/*======================*/
|
||||
/* out: matching index, NULL if not found */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name, /* in: the index name to find */
|
||||
const char** columns,/* in: array of column names */
|
||||
ulint n_cols) /* in: number of columns */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dict_index_t* found;
|
||||
|
||||
found = NULL;
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
if (ut_strcmp(index->name, name) == 0
|
||||
&& dict_index_get_n_ordering_defined_by_user(index)
|
||||
== n_cols) {
|
||||
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < n_cols; i++) {
|
||||
dict_field_t* field;
|
||||
const char* col_name;
|
||||
|
||||
field = dict_index_get_nth_field(index, i);
|
||||
|
||||
col_name = dict_table_get_col_name(
|
||||
table, dict_col_get_no(field->col));
|
||||
|
||||
if (0 != innobase_strcasecmp(
|
||||
columns[i], col_name)) {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == n_cols) {
|
||||
/* We found a matching index, select
|
||||
the index with the higher id*/
|
||||
|
||||
if (!found
|
||||
|| ut_dulint_cmp(index->id, found->id) > 0) {
|
||||
|
||||
found = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(found);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Report an error in a foreign key definition. */
|
||||
static
|
||||
@@ -4013,6 +4160,7 @@ dict_index_print_low(
|
||||
{
|
||||
ib_longlong n_vals;
|
||||
ulint i;
|
||||
const char* type_string;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
@@ -4023,6 +4171,14 @@ dict_index_print_low(
|
||||
n_vals = index->stat_n_diff_key_vals[1];
|
||||
}
|
||||
|
||||
if (index->type & DICT_CLUSTERED) {
|
||||
type_string = "clustered index";
|
||||
} else if (index->type & DICT_UNIQUE) {
|
||||
type_string = "unique index";
|
||||
} else {
|
||||
type_string = "secondary index";
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
|
||||
" uniq %lu, type %lu\n"
|
||||
@@ -4261,6 +4417,7 @@ dict_print_info_on_foreign_keys(
|
||||
|
||||
/************************************************************************
|
||||
Displays the names of the index and the table. */
|
||||
|
||||
void
|
||||
dict_index_name_print(
|
||||
/*==================*/
|
||||
@@ -4273,3 +4430,417 @@ dict_index_name_print(
|
||||
fputs(" of table ", file);
|
||||
ut_print_name(file, trx, TRUE, index->table_name);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Get index by name */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_on_name(
|
||||
/*=========================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name) /* in: name of the index to find */
|
||||
{
|
||||
dict_index_t* index;
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
if (ut_strcmp(index->name, name) == 0) {
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Find and index that is equivalent to the one passed in. */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_find_equivalent_index(
|
||||
/*=============================*/
|
||||
dict_table_t* table, /* in/out: table */
|
||||
dict_index_t* index) /* in: index to match */
|
||||
{
|
||||
ulint i;
|
||||
const char** column_names;
|
||||
dict_index_t* equiv_index;
|
||||
|
||||
if (UT_LIST_GET_LEN(table->foreign_list) == 0) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
column_names = mem_alloc(index->n_fields * sizeof *column_names);
|
||||
|
||||
/* Convert the column names to the format & type accepted by the find
|
||||
index function */
|
||||
for (i = 0; i < index->n_fields; i++) {
|
||||
column_names[i] = index->fields[i].name;
|
||||
}
|
||||
|
||||
equiv_index = dict_foreign_find_index(
|
||||
table, (const char**)column_names, index->n_fields,
|
||||
index, TRUE, FALSE);
|
||||
|
||||
mem_free(column_names);
|
||||
|
||||
return(equiv_index);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Replace the index passed in with another equivalent index in the tables
|
||||
foreign key list. */
|
||||
|
||||
void
|
||||
dict_table_replace_index_in_foreign_list(
|
||||
/*=====================================*/
|
||||
dict_table_t* table, /* in/out: table */
|
||||
dict_index_t* index) /* in: index to be replaced */
|
||||
{
|
||||
dict_index_t* new_index;
|
||||
|
||||
new_index = dict_table_find_equivalent_index(table, index);
|
||||
|
||||
/* If match found */
|
||||
if (new_index) {
|
||||
dict_foreign_t* foreign;
|
||||
|
||||
ut_a(new_index != index);
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
/* If the list is not empty then this should hold */
|
||||
ut_a(foreign);
|
||||
|
||||
/* Iterate over the foreign index list and replace the index
|
||||
passed in with the new index */
|
||||
while (foreign) {
|
||||
|
||||
if (foreign->foreign_index == index) {
|
||||
foreign->foreign_index = new_index;
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
In case there is more than one index with the same name return the index
|
||||
with the min(id). */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_on_name_and_min_id(
|
||||
/*=====================================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name) /* in: name of the index to find */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dict_index_t* min_index; /* Index with matching name and min(id) */
|
||||
|
||||
min_index = NULL;
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
if (ut_strcmp(index->name, name) == 0) {
|
||||
if (!min_index
|
||||
|| ut_dulint_cmp(index->id, min_index->id) < 0) {
|
||||
|
||||
min_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(min_index);
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns an index object by matching on the name and column names and
|
||||
if more than one index matches return the index with the max id */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_by_max_id(
|
||||
/*===========================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name, /* in: index name to find*/
|
||||
const char** column_names, /* in: column names to match */
|
||||
ulint n_cols) /* in: number of columns */
|
||||
{
|
||||
/* Find an exact match with the passed in index */
|
||||
return(dict_find_index_by_max_id(table, name, column_names, n_cols));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Check for duplicate index entries in a table [using the index name] */
|
||||
#ifdef UNIV_DEBUG
|
||||
|
||||
void
|
||||
dict_table_check_for_dup_indexes(
|
||||
/*=============================*/
|
||||
dict_table_t* table) /* in: Check for dup indexes in this table */
|
||||
{
|
||||
/* Check for duplicates, ignoring indexes that are marked
|
||||
as to be dropped */
|
||||
|
||||
dict_index_t* index1;
|
||||
dict_index_t* index2;
|
||||
|
||||
/* The primary index _must_ exist */
|
||||
ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
|
||||
|
||||
index1 = UT_LIST_GET_FIRST(table->indexes);
|
||||
index2 = UT_LIST_GET_NEXT(indexes, index1);
|
||||
|
||||
while (index1 && index2) {
|
||||
|
||||
while (index2) {
|
||||
|
||||
if (!index2->to_be_dropped) {
|
||||
ut_ad(ut_strcmp(index1->name, index2->name));
|
||||
}
|
||||
|
||||
index2 = UT_LIST_GET_NEXT(indexes, index2);
|
||||
}
|
||||
|
||||
index1 = UT_LIST_GET_NEXT(indexes, index1);
|
||||
index2 = UT_LIST_GET_NEXT(indexes, index1);
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/**************************************************************************
|
||||
Create an undo list for the trx.*/
|
||||
|
||||
void
|
||||
dict_undo_create_list(
|
||||
/*==================*/
|
||||
trx_t* trx) /* out: dict_undo_t list */
|
||||
{
|
||||
ut_a(!trx->dict_undo_list);
|
||||
|
||||
trx->dict_undo_list = mem_alloc(sizeof(*trx->dict_undo_list));
|
||||
|
||||
UT_LIST_INIT(*trx->dict_undo_list);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Create an dict_undo_t element and append to the undo list of the trx.*/
|
||||
|
||||
dict_undo_t*
|
||||
dict_undo_create_element(
|
||||
/*=====================*/ /* out: dict_undo_t element*/
|
||||
trx_t* trx) /* in: create & add elem to this trx */
|
||||
{
|
||||
dict_undo_t* dict_undo;
|
||||
|
||||
ut_a(trx->dict_undo_list);
|
||||
|
||||
dict_undo = mem_alloc(sizeof(*dict_undo));
|
||||
memset(dict_undo, '\0', sizeof(*dict_undo));
|
||||
|
||||
UT_LIST_ADD_LAST(node, *trx->dict_undo_list, dict_undo);
|
||||
|
||||
return(dict_undo);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Free all the nodes on the undo list and free list.*/
|
||||
|
||||
void
|
||||
dict_undo_free_list(
|
||||
/*================*/
|
||||
trx_t* trx)
|
||||
{
|
||||
dict_undo_t* dict_undo;
|
||||
|
||||
ut_a(trx->dict_undo_list);
|
||||
|
||||
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
|
||||
|
||||
while (dict_undo) {
|
||||
|
||||
UT_LIST_REMOVE(node, *trx->dict_undo_list, dict_undo);
|
||||
|
||||
mem_free(dict_undo);
|
||||
|
||||
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
|
||||
}
|
||||
|
||||
mem_free(trx->dict_undo_list);
|
||||
|
||||
trx->dict_undo_list = NULL;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Create an undo list for the trx.*/
|
||||
|
||||
void
|
||||
dict_redo_create_list(
|
||||
/*==================*/
|
||||
trx_t* trx) /* out: dict_undo_t list */
|
||||
{
|
||||
ut_a(!trx->dict_redo_list);
|
||||
|
||||
trx->dict_redo_list = mem_alloc(sizeof(*trx->dict_redo_list));
|
||||
|
||||
UT_LIST_INIT(*trx->dict_redo_list);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Create an dict_undo_t element and append to the undo list of the trx.*/
|
||||
|
||||
dict_redo_t*
|
||||
dict_redo_create_element(
|
||||
/*=====================*/ /* out: dict_undo_t element*/
|
||||
trx_t* trx) /* in: create & add elem to this trx */
|
||||
{
|
||||
dict_redo_t* dict_redo;
|
||||
|
||||
ut_a(trx->dict_redo_list);
|
||||
|
||||
dict_redo = mem_alloc(sizeof(*dict_redo));
|
||||
memset(dict_redo, '\0', sizeof(*dict_redo));
|
||||
|
||||
UT_LIST_ADD_LAST(node, *trx->dict_redo_list, dict_redo);
|
||||
|
||||
return(dict_redo);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Free all the nodes on the undo list and free list.*/
|
||||
|
||||
void
|
||||
dict_redo_free_list(
|
||||
/*================*/
|
||||
trx_t* trx)
|
||||
{
|
||||
dict_redo_t* dict_redo;
|
||||
|
||||
ut_a(trx->dict_redo_list);
|
||||
|
||||
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
|
||||
|
||||
while (dict_redo) {
|
||||
|
||||
UT_LIST_REMOVE(node, *trx->dict_redo_list, dict_redo);
|
||||
|
||||
mem_free(dict_redo);
|
||||
|
||||
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
|
||||
}
|
||||
|
||||
mem_free(trx->dict_redo_list);
|
||||
|
||||
trx->dict_redo_list = NULL;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Get the index by name from the transaction's REDO list.*/
|
||||
|
||||
dict_index_t*
|
||||
dict_redo_get_index_on_name(
|
||||
/*========================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table, /* in: table the index belongs to */
|
||||
const char* name) /* in: index name */
|
||||
{
|
||||
dict_redo_t* dict_redo;
|
||||
|
||||
ut_a(trx->dict_redo_list);
|
||||
|
||||
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
|
||||
|
||||
while (dict_redo) {
|
||||
|
||||
if (dict_redo->index->table == table
|
||||
&& ut_strcmp(dict_redo->index->name, name) == 0) {
|
||||
|
||||
return(dict_redo->index);
|
||||
}
|
||||
|
||||
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Remove the index from the transaction's REDO list.*/
|
||||
|
||||
void
|
||||
dict_redo_remove_index(
|
||||
/*===================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index) /* in: index to remove */
|
||||
{
|
||||
dict_redo_t* dict_redo;
|
||||
|
||||
ut_a(trx->dict_redo_list);
|
||||
|
||||
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
|
||||
|
||||
while (dict_redo) {
|
||||
|
||||
if (dict_redo->index == index) {
|
||||
UT_LIST_REMOVE(node, *trx->dict_redo_list, dict_redo);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Add the indexes to SYS_INDEX.*/
|
||||
|
||||
ulint
|
||||
dict_rename_indexes(
|
||||
/*================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
ibool commit_flag) /* in: UNUSED */
|
||||
{
|
||||
dict_redo_t* dict_redo;
|
||||
ulint err = DB_SUCCESS;
|
||||
|
||||
ut_a(trx->dict_redo_list);
|
||||
ut_a(commit_flag);
|
||||
|
||||
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
|
||||
|
||||
while (dict_redo && err == DB_SUCCESS) {
|
||||
dict_index_t* index;
|
||||
|
||||
index = dict_redo->index;
|
||||
|
||||
ut_a(index->table);
|
||||
ut_a(!ut_dulint_is_zero(index->id));
|
||||
ut_a(index->space == index->table->space);
|
||||
#ifdef UNIV_DEBUG
|
||||
fprintf(stderr, "Renaming index: %s\n", index->name);
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
err = row_merge_rename_index(trx, index->table, index);
|
||||
|
||||
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
|
||||
}
|
||||
|
||||
/* We free the list anyway - even if there is an error of some sort,
|
||||
let the UNDO code handle the errors.*/
|
||||
dict_redo_free_list(trx);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -476,32 +476,12 @@ dict_load_columns(
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Report that an index field or index for a table has been delete marked. */
|
||||
static
|
||||
void
|
||||
dict_load_report_deleted_index(
|
||||
/*===========================*/
|
||||
const char* name, /* in: table name */
|
||||
ulint field) /* in: index field, or ULINT_UNDEFINED */
|
||||
{
|
||||
fprintf(stderr, "InnoDB: Error: data dictionary entry"
|
||||
" for table %s is corrupt!\n", name);
|
||||
if (field != ULINT_UNDEFINED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Index field %lu is delete marked.\n", field);
|
||||
} else {
|
||||
fputs("InnoDB: An index is delete marked.\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Loads definitions for index fields. */
|
||||
static
|
||||
void
|
||||
dict_load_fields(
|
||||
/*=============*/
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index, /* in: index whose fields to load */
|
||||
mem_heap_t* heap) /* in: memory heap for temporary storage */
|
||||
{
|
||||
@@ -543,13 +523,18 @@ dict_load_fields(
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
|
||||
|
||||
/* There could be delete marked records in SYS_FIELDS
|
||||
because SYS_FIELDS.INDEX_ID can be updated
|
||||
by ALTER TABLE ADD INDEX. */
|
||||
|
||||
if (rec_get_deleted_flag(rec, 0)) {
|
||||
dict_load_report_deleted_index(table->name, i);
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
field = rec_get_nth_field_old(rec, 0, &len);
|
||||
ut_ad(len == 8);
|
||||
ut_a(ut_memcmp(buf, field, len) == 0);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 1, &len);
|
||||
ut_a(len == 4);
|
||||
@@ -584,6 +569,7 @@ dict_load_fields(
|
||||
(char*) field, len),
|
||||
prefix_len);
|
||||
|
||||
next_rec:
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
}
|
||||
|
||||
@@ -662,16 +648,9 @@ dict_load_indexes(
|
||||
|
||||
if (ut_memcmp(buf, field, len) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec, 0)) {
|
||||
dict_load_report_deleted_index(table->name,
|
||||
ULINT_UNDEFINED);
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(FALSE);
|
||||
} else if (rec_get_deleted_flag(rec, 0)) {
|
||||
/* Skip delete marked records */
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
field = rec_get_nth_field_old(rec, 1, &len);
|
||||
@@ -714,12 +693,15 @@ dict_load_indexes(
|
||||
if ((type & DICT_CLUSTERED) == 0
|
||||
&& NULL == dict_table_get_first_index(table)) {
|
||||
|
||||
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to load index %s"
|
||||
" for table %s\n"
|
||||
"InnoDB: Error: trying to"
|
||||
" load index %s for table %s\n"
|
||||
"InnoDB: but the first index"
|
||||
" is not clustered!\n",
|
||||
name_buf, table->name);
|
||||
}
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
@@ -741,10 +723,11 @@ dict_load_indexes(
|
||||
space, type, n_fields);
|
||||
index->id = id;
|
||||
|
||||
dict_load_fields(table, index, heap);
|
||||
dict_load_fields(index, heap);
|
||||
dict_index_add_to_cache(table, index, page_no);
|
||||
}
|
||||
|
||||
next_rec:
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ dict_mem_table_create(
|
||||
table->n_foreign_key_checks_running = 0;
|
||||
|
||||
table->cached = FALSE;
|
||||
table->to_be_dropped = 0;
|
||||
|
||||
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
||||
* sizeof(dict_col_t));
|
||||
@@ -75,6 +76,7 @@ dict_mem_table_create(
|
||||
UT_LIST_INIT(table->locks);
|
||||
UT_LIST_INIT(table->foreign_list);
|
||||
UT_LIST_INIT(table->referenced_list);
|
||||
UT_LIST_INIT(table->prebuilts);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
table->does_not_fit_in_memory = FALSE;
|
||||
@@ -236,6 +238,7 @@ dict_mem_index_create(
|
||||
heap = mem_heap_create(DICT_HEAP_SIZE);
|
||||
index = mem_heap_alloc(heap, sizeof(dict_index_t));
|
||||
|
||||
index->id = ut_dulint_create(0, 0);
|
||||
index->heap = heap;
|
||||
|
||||
index->type = type;
|
||||
@@ -253,6 +256,8 @@ dict_mem_index_create(
|
||||
index->stat_n_diff_key_vals = NULL;
|
||||
|
||||
index->cached = FALSE;
|
||||
index->to_be_dropped = FALSE;
|
||||
index->trx_id = ut_dulint_create(0, 0);
|
||||
memset(&index->lock, 0, sizeof index->lock);
|
||||
#ifdef UNIV_DEBUG
|
||||
index->magic_n = DICT_INDEX_MAGIC_N;
|
||||
|
||||
1250
handler/ha_innodb.cc
1250
handler/ha_innodb.cc
File diff suppressed because it is too large
Load Diff
@@ -85,13 +85,9 @@ class ha_innobase: public handler
|
||||
const char *index_type(uint key_number) { return "BTREE"; }
|
||||
const char** bas_ext() const;
|
||||
ulonglong table_flags() const { return int_table_flags; }
|
||||
ulong index_flags(uint idx, uint part, bool all_parts) const
|
||||
{
|
||||
return (HA_READ_NEXT |
|
||||
HA_READ_PREV |
|
||||
HA_READ_ORDER |
|
||||
HA_READ_RANGE |
|
||||
HA_KEYREAD_ONLY);
|
||||
ulong index_flags(uint idx, uint part, bool all_parts) const {
|
||||
return(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
|
||||
| HA_READ_RANGE | HA_KEYREAD_ONLY);
|
||||
}
|
||||
uint max_supported_keys() const { return MAX_KEY; }
|
||||
/* An InnoDB page must store >= 2 keys;
|
||||
@@ -117,6 +113,7 @@ class ha_innobase: public handler
|
||||
void try_semi_consistent_read(bool yes);
|
||||
void unlock_row();
|
||||
|
||||
bool is_index_available(uint index);
|
||||
int index_init(uint index, bool sorted);
|
||||
int index_end();
|
||||
int index_read(byte * buf, const byte * key,
|
||||
@@ -185,6 +182,10 @@ class ha_innobase: public handler
|
||||
static ulonglong get_mysql_bin_log_pos();
|
||||
bool primary_key_is_clustered() { return true; }
|
||||
int cmp_ref(const byte *ref1, const byte *ref2);
|
||||
int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
|
||||
int prepare_drop_index(TABLE *table_arg, uint *key_num,
|
||||
uint num_of_keys);
|
||||
int final_drop_index(TABLE *table_arg);
|
||||
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
||||
uint table_changes);
|
||||
};
|
||||
|
||||
@@ -279,8 +279,13 @@ dtuple_create(
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
(tuple->fields + i)->data = &data_error;
|
||||
dfield_get_type(tuple->fields + i)->mtype = DATA_ERROR;
|
||||
dfield_t* field;
|
||||
|
||||
field = dtuple_get_nth_field(tuple, i);
|
||||
|
||||
dfield_set_len(field, UNIV_SQL_NULL);
|
||||
field->data = &data_error;
|
||||
dfield_get_type(field)->mtype = DATA_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -62,6 +62,9 @@ Created 5/24/1996 Heikki Tuuri
|
||||
activated by the operation would
|
||||
lead to a duplicate key in some
|
||||
table */
|
||||
#define DB_CANNOT_DROP_FOREIGN_INDEX 47 /* we cannot drop an index because
|
||||
it is needed on foreign key
|
||||
constraint */
|
||||
|
||||
/* The following are partial failure codes */
|
||||
#define DB_FAIL 1000
|
||||
|
||||
@@ -53,6 +53,15 @@ dict_remove_db_name(
|
||||
/* out: table name */
|
||||
const char* name); /* in: table name in the form
|
||||
dbname '/' tablename */
|
||||
/**************************************************************************
|
||||
Returns a table object based on table id. */
|
||||
|
||||
dict_table_t*
|
||||
dict_table_get_on_id(
|
||||
/*=================*/
|
||||
/* out: table, NULL if does not exist */
|
||||
dulint table_id, /* in: table id */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/************************************************************************
|
||||
Decrements the count of open MySQL handles to a table. */
|
||||
|
||||
@@ -248,6 +257,14 @@ dict_table_rename_in_cache(
|
||||
to preserve the original table name
|
||||
in constraints which reference it */
|
||||
/**************************************************************************
|
||||
Removes an index from the dictionary cache. */
|
||||
|
||||
void
|
||||
dict_index_remove_from_cache(
|
||||
/*=========================*/
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index); /* in, own: index */
|
||||
/**************************************************************************
|
||||
Change the id of a table object in the dictionary cache. This is used in
|
||||
DISCARD TABLESPACE. */
|
||||
|
||||
@@ -270,14 +287,34 @@ dict_foreign_add_to_cache(
|
||||
ibool check_charsets);/* in: TRUE=check charset
|
||||
compatibility */
|
||||
/*************************************************************************
|
||||
Check if the index is referenced by a foreign key, if TRUE return the
|
||||
matching instance NULL otherwise. */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_table_get_referenced_constraint(
|
||||
/*=================================*/
|
||||
/* out: pointer to foreign key struct if index
|
||||
is defined for foreign key, otherwise NULL */
|
||||
dict_table_t* table, /* in: InnoDB table */
|
||||
dict_index_t* index); /* in: InnoDB index */
|
||||
/*************************************************************************
|
||||
Checks if a table is referenced by foreign keys. */
|
||||
|
||||
ibool
|
||||
dict_table_referenced_by_foreign_key(
|
||||
/*=================================*/
|
||||
/* out: TRUE if table is referenced by a
|
||||
foreign key */
|
||||
dict_table_t* table); /* in: InnoDB table */
|
||||
dict_table_is_referenced_by_foreign_key(
|
||||
/*====================================*/
|
||||
/* out: TRUE if table is referenced
|
||||
by a foreign key */
|
||||
const dict_table_t* table); /* in: InnoDB table */
|
||||
/**************************************************************************
|
||||
Replace the index in the foreign key list that matches this index's
|
||||
definition with an equivalent index. */
|
||||
|
||||
void
|
||||
dict_table_replace_index_in_foreign_list(
|
||||
/*=====================================*/
|
||||
dict_table_t* table, /* in/out: table */
|
||||
dict_index_t* index); /* in: index to be replaced */
|
||||
/**************************************************************************
|
||||
Determines whether a string starts with the specified keyword. */
|
||||
|
||||
@@ -290,6 +327,18 @@ dict_str_starts_with_keyword(
|
||||
const char* str, /* in: string to scan for keyword */
|
||||
const char* keyword); /* in: keyword to look for */
|
||||
/*************************************************************************
|
||||
Checks if a index is defined for a foreign key constraint. Index is a part
|
||||
of a foreign key constraint if the index is referenced by foreign key
|
||||
or index is a foreign key index */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_table_get_foreign_constraint(
|
||||
/*==============================*/
|
||||
/* out: pointer to foreign key struct if index
|
||||
is defined for foreign key, otherwise NULL */
|
||||
dict_table_t* table, /* in: InnoDB table */
|
||||
dict_index_t* index); /* in: InnoDB index */
|
||||
/*************************************************************************
|
||||
Scans a table create SQL string and adds to the data dictionary
|
||||
the foreign key constraints declared in the string. This function
|
||||
should be called after the indexes for a table have been created.
|
||||
@@ -350,24 +399,18 @@ dict_table_get(
|
||||
/* in: whether to increment the open
|
||||
handle count on the table */
|
||||
/**************************************************************************
|
||||
Returns a table object based on table id. */
|
||||
Returns a index object, based on table and index id, and memoryfixes it. */
|
||||
|
||||
dict_table_t*
|
||||
dict_table_get_on_id(
|
||||
/*=================*/
|
||||
/* out: table, NULL if does not exist */
|
||||
dulint table_id, /* in: table id */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/**************************************************************************
|
||||
Returns a table object based on table id. */
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_get_on_id_low(
|
||||
dict_index_t*
|
||||
dict_index_get_on_id_low(
|
||||
/*=====================*/
|
||||
/* out: table, NULL if does not exist */
|
||||
dulint table_id); /* in: table id */
|
||||
/* out: index, NULL if does not
|
||||
exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
dulint index_id); /* in: index id */
|
||||
/**************************************************************************
|
||||
Checks if a table is in the dictionary cache. */
|
||||
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_check_if_in_cache_low(
|
||||
@@ -384,6 +427,14 @@ dict_table_get_low(
|
||||
/* out: table, NULL if not found */
|
||||
const char* table_name); /* in: table name */
|
||||
/**************************************************************************
|
||||
Returns a table object based on table id. */
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_get_on_id_low(
|
||||
/*=====================*/
|
||||
/* out: table, NULL if does not exist */
|
||||
dulint table_id); /* in: table id */
|
||||
/**************************************************************************
|
||||
A noninlined version of dict_table_get_low. */
|
||||
|
||||
dict_table_t*
|
||||
@@ -392,23 +443,17 @@ dict_table_get_low_noninlined(
|
||||
/* out: table, NULL if not found */
|
||||
const char* table_name); /* in: table name */
|
||||
/**************************************************************************
|
||||
Returns an index object. */
|
||||
UNIV_INLINE
|
||||
dict_index_t*
|
||||
dict_table_get_index(
|
||||
/*=================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name); /* in: index name */
|
||||
/**************************************************************************
|
||||
Returns an index object. */
|
||||
Returns an index object by matching on the name and column names and if
|
||||
more than index is found return the index with the higher id.*/
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_noninline(
|
||||
dict_table_get_index_by_max_id(
|
||||
/*===========================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name); /* in: index name */
|
||||
const char* name, /* in: index name to find*/
|
||||
const char** column_names, /* in: column names to match */
|
||||
ulint n_cols);/* in: number of columns */
|
||||
/**************************************************************************
|
||||
Returns a column's name. */
|
||||
|
||||
@@ -855,6 +900,14 @@ dict_index_check_search_tuple(
|
||||
/* out: TRUE if ok */
|
||||
dict_index_t* index, /* in: index */
|
||||
const dtuple_t* tuple); /* in: tuple used in a search */
|
||||
/**************************************************************************
|
||||
Check for duplicate index entries in a table [using the index name] */
|
||||
|
||||
void
|
||||
dict_table_check_for_dup_indexes(
|
||||
/*=============================*/
|
||||
dict_table_t* table); /* in: Check for dup indexes in this table */
|
||||
|
||||
#endif /* UNIV_DEBUG */
|
||||
/**************************************************************************
|
||||
Builds a node pointer out of a physical record and a page number. */
|
||||
@@ -1012,6 +1065,118 @@ dict_scan_to(
|
||||
/* out: scanned up to this */
|
||||
const char* ptr, /* in: scan from */
|
||||
const char* string);/* in: look for this */
|
||||
/*************************************************************************
|
||||
Removes an index from the cache */
|
||||
|
||||
void
|
||||
dict_index_remove_from_cache(
|
||||
/*=========================*/
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index); /* in, own: index */
|
||||
/**************************************************************************
|
||||
Get index by name */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_on_name(
|
||||
/*=========================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name); /* in: name of the index to find */
|
||||
/**************************************************************************
|
||||
Find and index that is equivalent to the one passed in and is not marked
|
||||
for deletion. */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_find_equivalent_index(
|
||||
/*=============================*/
|
||||
dict_table_t* table, /* in/out: table */
|
||||
dict_index_t* index); /* in: index to match */
|
||||
/**************************************************************************
|
||||
Find and return an index in the table that matches the index id.*/
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_on_id_noninline(
|
||||
/*=================================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
dulint index_id);/* in: table id */
|
||||
/**************************************************************************
|
||||
In case there is more than one index with the same name return the index
|
||||
with the min(id). */
|
||||
|
||||
dict_index_t*
|
||||
dict_table_get_index_on_name_and_min_id(
|
||||
/*====================================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name); /* in: name of the index to find */
|
||||
/**************************************************************************
|
||||
Create and return an undo list. */
|
||||
|
||||
void
|
||||
dict_undo_create_list(
|
||||
/*==================*/
|
||||
trx_t* trx); /* in: create undo list for this trx.*/
|
||||
/**************************************************************************
|
||||
Create element of the undo list and append to the passed in list. */
|
||||
|
||||
dict_undo_t*
|
||||
dict_undo_create_element(
|
||||
/*=====================*/ /* out: dict_undo_t element*/
|
||||
trx_t* trx); /* in: create & add elem to this trx.*/
|
||||
/**************************************************************************
|
||||
Free all the nodes on the undo list and free list.*/
|
||||
|
||||
void
|
||||
dict_undo_free_list(
|
||||
/*================*/
|
||||
trx_t* trx); /* in: free this trx's undo list */
|
||||
/**************************************************************************
|
||||
Create and return a redo list. */
|
||||
|
||||
void
|
||||
dict_redo_create_list(
|
||||
/*==================*/
|
||||
trx_t* trx); /* in: create redo list for this trx.*/
|
||||
/**************************************************************************
|
||||
Create element of the redo list and append to the passed in transaction. */
|
||||
|
||||
dict_redo_t*
|
||||
dict_redo_create_element(
|
||||
/*=====================*/ /* out: dict_redo_t element*/
|
||||
trx_t* trx); /* in: create & add elem to this trx.*/
|
||||
/**************************************************************************
|
||||
Free all the nodes on the redo list and free list.*/
|
||||
|
||||
void
|
||||
dict_redo_free_list(
|
||||
/*================*/
|
||||
trx_t* trx); /* in: free this trx's redo list */
|
||||
/**************************************************************************
|
||||
Add the indexes to SYS_INDEX.*/
|
||||
|
||||
ulint
|
||||
dict_rename_indexes(
|
||||
/*================*/
|
||||
trx_t* trx,/* in: transaction */
|
||||
ibool commit_flag); /* in: ignored for now */
|
||||
/**************************************************************************
|
||||
Remove the index from the transaction's REDO list.*/
|
||||
|
||||
void
|
||||
dict_redo_remove_index(
|
||||
/*===================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index); /* in: index to remove */
|
||||
/**************************************************************************
|
||||
Get the index by name from the transaction's REDO list.*/
|
||||
|
||||
dict_index_t*
|
||||
dict_redo_get_index_on_name(
|
||||
/*========================*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table, /* in: the table the index belongs to */
|
||||
const char* name); /* in: index name */
|
||||
/* Buffers for storing detailed information about the latest foreign key
|
||||
and unique key errors */
|
||||
extern FILE* dict_foreign_err_file;
|
||||
@@ -1050,6 +1215,10 @@ struct dict_sys_struct{
|
||||
dict_table_t* sys_fields; /* SYS_FIELDS table */
|
||||
};
|
||||
|
||||
#define TEMP_TABLE_PREFIX '/' /* Table name prefix for temporary
|
||||
internal tables. Used in fast index
|
||||
creation etc. */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "dict0dict.ic"
|
||||
#endif
|
||||
|
||||
@@ -647,28 +647,3 @@ dict_table_get_on_id_low(
|
||||
return(table);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns an index object. */
|
||||
UNIV_INLINE
|
||||
dict_index_t*
|
||||
dict_table_get_index(
|
||||
/*=================*/
|
||||
/* out: index, NULL if does not exist */
|
||||
dict_table_t* table, /* in: table */
|
||||
const char* name) /* in: index name */
|
||||
{
|
||||
dict_index_t* index = NULL;
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
if (ut_strcmp(name, index->name) == 0) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ Created 4/24/1996 Heikki Tuuri
|
||||
#include "univ.i"
|
||||
#include "dict0types.h"
|
||||
#include "ut0byte.h"
|
||||
#include "mem0mem.h"
|
||||
|
||||
/************************************************************************
|
||||
In a crash recovery we already have all the tablespace objects created.
|
||||
|
||||
@@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#include "lock0types.h"
|
||||
#include "hash0hash.h"
|
||||
#include "que0types.h"
|
||||
#include "row0types.h"
|
||||
|
||||
/* Type flags of an index: OR'ing of the flags is allowed to define a
|
||||
combination of types */
|
||||
@@ -32,6 +33,7 @@ combination of types */
|
||||
#define DICT_UNIVERSAL 4 /* index which can contain records from any
|
||||
other index */
|
||||
#define DICT_IBUF 8 /* insert buffer tree */
|
||||
#define DICT_NOT_READY 16 /* this index is being build */
|
||||
|
||||
/* Types for a table object */
|
||||
#define DICT_TABLE_ORDINARY 1
|
||||
@@ -185,7 +187,7 @@ struct dict_index_struct{
|
||||
dulint id; /* id of the index */
|
||||
mem_heap_t* heap; /* memory heap */
|
||||
ulint type; /* index type */
|
||||
const char* name; /* index name */
|
||||
char* name; /* index name */
|
||||
const char* table_name; /* table name */
|
||||
dict_table_t* table; /* back pointer to table */
|
||||
unsigned space:32;
|
||||
@@ -207,6 +209,10 @@ struct dict_index_struct{
|
||||
unsigned n_nullable:10;/* number of nullable fields */
|
||||
unsigned cached:1;/* TRUE if the index object is in the
|
||||
dictionary cache */
|
||||
unsigned to_be_dropped:1;
|
||||
/* TRUE if this index is marked to be
|
||||
dropped in ha_innobase::prepare_drop_index(),
|
||||
otherwise FALSE */
|
||||
dict_field_t* fields; /* array of field descriptions */
|
||||
UT_LIST_NODE_T(dict_index_t)
|
||||
indexes;/* list of indexes of the table */
|
||||
@@ -224,6 +230,9 @@ struct dict_index_struct{
|
||||
index tree */
|
||||
rw_lock_t lock; /* read-write lock protecting the upper levels
|
||||
of the index tree */
|
||||
dulint trx_id; /* id of the transaction that created this
|
||||
index. It can be zero which implies that
|
||||
it was created on database startup.*/
|
||||
#ifdef UNIV_DEBUG
|
||||
ulint magic_n;/* magic number */
|
||||
# define DICT_INDEX_MAGIC_N 76789786
|
||||
@@ -290,6 +299,14 @@ struct dict_table_struct{
|
||||
innodb_file_per_table is defined in my.cnf;
|
||||
in Unix this is usually /tmp/..., in Windows
|
||||
\temp\... */
|
||||
unsigned version_number:32;
|
||||
/* version number of this table definition.
|
||||
Version number is 0 when table is created.
|
||||
Every schema change implemented without
|
||||
creating a new table and copying rows from
|
||||
the old table to new table will increase this
|
||||
number. For example adding or removing index,
|
||||
adding or removing a column. */
|
||||
unsigned space:32;
|
||||
/* space where the clustered index of the
|
||||
table is placed */
|
||||
@@ -303,6 +320,8 @@ struct dict_table_struct{
|
||||
calls DISCARD TABLESPACE on this
|
||||
table, and reset to FALSE in IMPORT
|
||||
TABLESPACE */
|
||||
unsigned to_be_dropped:1; /* if set then this table will
|
||||
dropped when n_mysql_handles_opened is 0 */
|
||||
unsigned cached:1;/* TRUE if the table object has been added
|
||||
to the dictionary cache */
|
||||
unsigned flags:8;/* DICT_TF_COMPACT, ... */
|
||||
@@ -406,6 +425,10 @@ struct dict_table_struct{
|
||||
SELECT MAX(auto inc column) */
|
||||
ib_longlong autoinc;/* autoinc counter value to give to the
|
||||
next inserted row */
|
||||
/*----------------------*/
|
||||
UT_LIST_BASE_NODE_T(row_prebuilt_t) prebuilts;
|
||||
/* base node for the prebuilts defined
|
||||
for the table */
|
||||
#ifdef UNIV_DEBUG
|
||||
ulint magic_n;/* magic number */
|
||||
# define DICT_TABLE_MAGIC_N 76333786
|
||||
|
||||
@@ -9,6 +9,8 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#ifndef dict0types_h
|
||||
#define dict0types_h
|
||||
|
||||
#include "ut0list.h"
|
||||
|
||||
typedef struct dict_sys_struct dict_sys_t;
|
||||
typedef struct dict_col_struct dict_col_t;
|
||||
typedef struct dict_field_struct dict_field_t;
|
||||
@@ -24,4 +26,48 @@ typedef dict_table_t dict_cluster_t;
|
||||
typedef struct ind_node_struct ind_node_t;
|
||||
typedef struct tab_node_struct tab_node_t;
|
||||
|
||||
/* Data types for dict_undo */
|
||||
union dict_undo_data_union {
|
||||
|
||||
dict_index_t* index; /* The index to be dropped */
|
||||
|
||||
struct {
|
||||
dict_table_t* old_table; /* All fields are required only for*/
|
||||
dict_table_t* tmp_table; /*RENAME, for CREATE and DROP we */
|
||||
dict_table_t* new_table; /*use only old_table */
|
||||
} table;
|
||||
};
|
||||
|
||||
typedef union dict_undo_data_union dict_undo_data_t;
|
||||
|
||||
/* During recovery these are the operations that need to be undone */
|
||||
struct dict_undo_struct {
|
||||
ulint op_type; /* Discriminator one of :
|
||||
TRX_UNDO_INDEX_CREATE_REC,
|
||||
TRX_UNDO_TABLE_DROP_REC,
|
||||
TRX_UNDO_TABLE_CREATE_REC,
|
||||
TRX_UNDO_TABLE_RENAME_REC.*/
|
||||
dict_undo_data_t
|
||||
data; /* Data required for UNDO */
|
||||
|
||||
UT_LIST_NODE_T(struct dict_undo_struct)
|
||||
node; /* UNDO list node */
|
||||
};
|
||||
|
||||
typedef struct dict_undo_struct dict_undo_t;
|
||||
typedef UT_LIST_BASE_NODE_T(dict_undo_t) dict_undo_list_t;
|
||||
|
||||
/* TODO: Currently this data structure is a place holder for indexes
|
||||
created by a transaction.* The REDO is a misnomer*/
|
||||
struct dict_redo_struct {
|
||||
ulint op_type; /* Discriminator one of :
|
||||
TRX_UNDO_INDEX_CREATE_REC.*/
|
||||
dict_index_t* index; /* The index created.*/
|
||||
|
||||
UT_LIST_NODE_T(struct dict_redo_struct)
|
||||
node; /* REDO list node */
|
||||
};
|
||||
|
||||
typedef struct dict_redo_struct dict_redo_t;
|
||||
typedef UT_LIST_BASE_NODE_T(dict_redo_t) dict_redo_list_t;
|
||||
#endif
|
||||
|
||||
@@ -73,6 +73,12 @@ heap creation. */
|
||||
Use this macro instead of the corresponding function! Macro for memory
|
||||
heap creation. */
|
||||
|
||||
#define mem_heap_create_noninline(N) mem_heap_create_func_noninline(\
|
||||
(N), MEM_HEAP_DYNAMIC, __FILE__, __LINE__)
|
||||
/******************************************************************
|
||||
Use this macro instead of the corresponding function! Macro for memory
|
||||
heap creation. */
|
||||
|
||||
#define mem_heap_create_in_buffer(N) mem_heap_create_func(\
|
||||
(N), MEM_HEAP_BUFFER, __FILE__, __LINE__)
|
||||
/******************************************************************
|
||||
@@ -89,6 +95,12 @@ heap freeing. */
|
||||
|
||||
#define mem_heap_free(heap) mem_heap_free_func(\
|
||||
(heap), __FILE__, __LINE__)
|
||||
/******************************************************************
|
||||
Use this macro instead of the corresponding function! Macro for memory
|
||||
heap freeing. */
|
||||
|
||||
#define mem_heap_free_noninline(heap) mem_heap_free_func_noninline(\
|
||||
(heap), __FILE__, __LINE__)
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macros instead of this function. Creates a
|
||||
memory heap. For debugging purposes, takes also the file name and line as
|
||||
@@ -118,6 +130,37 @@ mem_heap_free_func(
|
||||
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||
const char* file_name, /* in: file name where freed */
|
||||
ulint line); /* in: line where freed */
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macros instead of this function. Creates a
|
||||
memory heap. For debugging purposes, takes also the file name and line as
|
||||
arguments. */
|
||||
|
||||
mem_heap_t*
|
||||
mem_heap_create_func_noninline(
|
||||
/*===========================*/
|
||||
/* out, own: memory heap, NULL if
|
||||
did not succeed (only possible for
|
||||
MEM_HEAP_BTR_SEARCH type heaps)*/
|
||||
ulint n, /* in: desired start block size,
|
||||
this means that a single user buffer
|
||||
of size n will fit in the block,
|
||||
0 creates a default size block;
|
||||
if init_block is not NULL, n tells
|
||||
its size in bytes */
|
||||
ulint type, /* in: heap type */
|
||||
const char* file_name, /* in: file name where created */
|
||||
ulint line); /* in: line where created */
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function. Frees the space
|
||||
occupied by a memory heap. In the debug version erases the heap memory
|
||||
blocks. */
|
||||
|
||||
void
|
||||
mem_heap_free_func_noninline(
|
||||
/*=========================*/
|
||||
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||
const char* file_name, /* in: file name where freed */
|
||||
ulint line); /* in: line where freed */
|
||||
/*******************************************************************
|
||||
Allocates n bytes of memory from a memory heap. */
|
||||
UNIV_INLINE
|
||||
@@ -131,6 +174,19 @@ mem_heap_alloc(
|
||||
ulint n); /* in: number of bytes; if the heap is allowed
|
||||
to grow into the buffer pool, this must be
|
||||
<= MEM_MAX_ALLOC_IN_BUF */
|
||||
/*******************************************************************
|
||||
Allocates n bytes of memory from a memory heap. */
|
||||
|
||||
void*
|
||||
mem_heap_alloc_noninline(
|
||||
/*=====================*/
|
||||
/* out: allocated storage, NULL if did not
|
||||
succeed (only possible for
|
||||
MEM_HEAP_BTR_SEARCH type heaps) */
|
||||
mem_heap_t* heap, /* in: memory heap */
|
||||
ulint n); /* in: number of bytes; if the heap is allowed
|
||||
to grow into the buffer pool, this must be
|
||||
<= MEM_MAX_ALLOC_IN_BUF */
|
||||
/*********************************************************************
|
||||
Returns a pointer to the heap top. */
|
||||
UNIV_INLINE
|
||||
@@ -193,6 +249,12 @@ Macro for memory buffer allocation */
|
||||
|
||||
#define mem_alloc_noninline(N) mem_alloc_func_noninline(\
|
||||
(N), __FILE__, __LINE__)
|
||||
/******************************************************************
|
||||
Use this macro instead of the corresponding function!
|
||||
Macro for memory buffer allocation */
|
||||
|
||||
#define mem_free_noninline(N) mem_free_func_noninline(\
|
||||
(N), __FILE__, __LINE__)
|
||||
/*******************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function.
|
||||
Allocates a single buffer of memory from the dynamic memory of
|
||||
@@ -238,6 +300,18 @@ mem_free_func(
|
||||
const char* file_name, /* in: file name where created */
|
||||
ulint line /* in: line where created */
|
||||
);
|
||||
/*******************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function.
|
||||
Frees a single buffer of storage from
|
||||
the dynamic memory of C compiler. Similar to free of C. */
|
||||
|
||||
void
|
||||
mem_free_func_noninline(
|
||||
/*====================*/
|
||||
void* ptr, /* in, own: buffer to be freed */
|
||||
const char* file_name, /* in: file name where created */
|
||||
ulint line /* in: line where created */
|
||||
);
|
||||
|
||||
/**************************************************************************
|
||||
Duplicates a NUL-terminated string. */
|
||||
|
||||
@@ -729,4 +729,15 @@ os_file_get_status(
|
||||
os_file_stat_t* stat_info); /* information of a file in a
|
||||
directory */
|
||||
|
||||
#if !defined(UNIV_HOTBACKUP) && !defined(__NETWARE__)
|
||||
/*************************************************************************
|
||||
Creates a temporary file that will be deleted on close.
|
||||
This function is defined in ha_innodb.cc. */
|
||||
|
||||
int
|
||||
innobase_mysql_tmpfile(void);
|
||||
/*========================*/
|
||||
/* out: temporary file descriptor, or < 0 on error */
|
||||
#endif /* !UNIV_HOTBACKUP && !__NETWARE__ */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -93,6 +93,13 @@ row_ins_step(
|
||||
/*=========*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/***************************************************************
|
||||
Creates an entry template for each index of a table. */
|
||||
|
||||
void
|
||||
ins_node_create_entry_list(
|
||||
/*=======================*/
|
||||
ins_node_t* node); /* in: row insert node */
|
||||
|
||||
/* Insert node structure */
|
||||
|
||||
@@ -112,6 +119,11 @@ struct ins_node_struct{
|
||||
this should be reset to NULL */
|
||||
UT_LIST_BASE_NODE_T(dtuple_t)
|
||||
entry_list;/* list of entries, one for each index */
|
||||
ulint table_version_number;
|
||||
/* entry_list is created for this version
|
||||
of the table. If this version is not same
|
||||
as table->version_number, entry_list must
|
||||
be re-created. */
|
||||
byte* row_id_buf;/* buffer for the row id sys field in row */
|
||||
dulint trx_id; /* trx id or the last trx which executed the
|
||||
node */
|
||||
|
||||
305
include/row0merge.h
Normal file
305
include/row0merge.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/******************************************************
|
||||
Index build routines using a merge sort
|
||||
|
||||
(c) 2005 Innobase Oy
|
||||
|
||||
Created 13/06/2005 Jan Lindstrom
|
||||
*******************************************************/
|
||||
|
||||
#ifndef row0merge_h
|
||||
#define row0merge_h
|
||||
|
||||
#include "univ.i"
|
||||
#include "data0data.h"
|
||||
#include "dict0types.h"
|
||||
#include "trx0types.h"
|
||||
#include "que0types.h"
|
||||
#include "mtr0mtr.h"
|
||||
#include "rem0types.h"
|
||||
#include "rem0rec.h"
|
||||
#include "read0types.h"
|
||||
#include "btr0types.h"
|
||||
#include "row0mysql.h"
|
||||
|
||||
/* Block size for I/O operations in merge sort */
|
||||
|
||||
#define MERGE_BLOCK_SIZE 1048576 /* 1M */
|
||||
|
||||
/* Intentional free space on every block */
|
||||
#define MERGE_BLOCK_SAFETY_MARGIN 128
|
||||
|
||||
/* Enable faster index creation debug code */
|
||||
/* #define UNIV_DEBUG_INDEX_CREATE 1 */
|
||||
|
||||
/* This block header structure is used to create linked list of the
|
||||
blocks to the disk. Every block contains one header.*/
|
||||
|
||||
struct merge_block_header_struct {
|
||||
ulint n_records; /* Number of records in the block. */
|
||||
dulint offset; /* Offset of this block in the disk. */
|
||||
dulint next; /* Offset to next block in the disk. */
|
||||
};
|
||||
|
||||
typedef struct merge_block_header_struct merge_block_header_t;
|
||||
|
||||
/* This block structure is used to hold index records in the disk
|
||||
and the memory */
|
||||
|
||||
struct merge_block_struct {
|
||||
merge_block_header_t header; /* Block header information */
|
||||
char data[MERGE_BLOCK_SIZE - sizeof(merge_block_header_t)];/* Data area i.e. heap */
|
||||
};
|
||||
|
||||
typedef struct merge_block_struct merge_block_t;
|
||||
|
||||
/* Records are stored in the memory for main memory linked list
|
||||
to this structure */
|
||||
|
||||
struct merge_rec_struct {
|
||||
struct merge_rec_struct *next; /* Pointer to next record
|
||||
in the list */
|
||||
rec_t* rec; /* Record */
|
||||
};
|
||||
|
||||
typedef struct merge_rec_struct merge_rec_t;
|
||||
|
||||
/* This structure is head element for main memory linked list
|
||||
used for main memory linked list merge sort */
|
||||
|
||||
struct merge_rec_list_struct {
|
||||
merge_rec_t* head; /* Pointer to head of the
|
||||
list */
|
||||
merge_rec_t* tail; /* Pointer to tail of the
|
||||
list */
|
||||
ulint n_records; /* Number of records in
|
||||
the list */
|
||||
ulint total_size; /* Total size of all records in
|
||||
the list */
|
||||
mem_heap_t* heap; /* Heap where memory for this
|
||||
list is allocated */
|
||||
};
|
||||
|
||||
typedef struct merge_rec_list_struct merge_rec_list_t;
|
||||
|
||||
/* Information about temporary files used in merge sort are stored
|
||||
to this structure */
|
||||
|
||||
struct merge_file_struct {
|
||||
os_file_t file; /* File descriptor */
|
||||
dulint offset; /* File offset */
|
||||
ulint num_of_blocks; /* Number of blocks */
|
||||
};
|
||||
|
||||
typedef struct merge_file_struct merge_file_t;
|
||||
|
||||
/* This structure holds parameters to thread which does a
|
||||
disk based merge sort and inserts index records */
|
||||
|
||||
struct merge_thread_struct {
|
||||
dict_index_t* index; /* in: Index to be created */
|
||||
row_prebuilt_t* prebuilt; /* in: Prebuilt */
|
||||
trx_t* trx; /* in: trx */
|
||||
os_file_t file; /* in: File handle */
|
||||
int error; /* out: error code or 0 */
|
||||
};
|
||||
|
||||
typedef struct merge_thread_struct merge_thread_t;
|
||||
|
||||
/* This structure holds index field definitions */
|
||||
|
||||
struct merge_index_field_struct {
|
||||
ulint col_type; /* Column type */
|
||||
ulint prefix_len; /* Prefix len */
|
||||
char* field_name; /* Field name */
|
||||
};
|
||||
|
||||
typedef struct merge_index_field_struct merge_index_field_t;
|
||||
|
||||
/* This structure holds index definitions */
|
||||
|
||||
struct merge_index_def_struct {
|
||||
ulint n_fields; /* Number of fields in index */
|
||||
ulint ind_type; /* 0, DICT_UNIQUE or DICT_CLUSTERED */
|
||||
char* name; /* Index name */
|
||||
merge_index_field_t** fields; /* Field definitions */
|
||||
};
|
||||
|
||||
typedef struct merge_index_def_struct merge_index_def_t;
|
||||
|
||||
/************************************************************************
|
||||
Reads clustered index of the table and create temporary files
|
||||
containing index entries for indexes to be built. */
|
||||
|
||||
ulint
|
||||
row_merge_read_clustered_index(
|
||||
/*===========================*/
|
||||
/* out: DB_SUCCESS if successfull,
|
||||
or ERROR code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table, /* in: table where index is created */
|
||||
dict_index_t** index, /* in: indexes to be created */
|
||||
merge_file_t** files, /* in: Files where to write index
|
||||
entries */
|
||||
ulint num_of_idx); /* in: number of indexes to be
|
||||
created */
|
||||
/************************************************************************
|
||||
Read sorted file containing index data tuples and insert these data
|
||||
data tuples to the index */
|
||||
|
||||
ulint
|
||||
row_merge_insert_index_tuples(
|
||||
/*==========================*/
|
||||
/* out: 0 or error number */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index, /* in: index */
|
||||
dict_table_t* table, /* in: table */
|
||||
os_file_t file, /* in: file handle */
|
||||
dulint offset); /* in: offset where to start
|
||||
reading */
|
||||
/*****************************************************************
|
||||
Merge sort for linked list in the disk. */
|
||||
|
||||
dulint
|
||||
row_merge_sort_linked_list_in_disk(
|
||||
/*===============================*/
|
||||
/* out: offset to first block in
|
||||
the list or ut_dulint_max in
|
||||
case of error */
|
||||
dict_index_t* index, /* in: index to be created */
|
||||
os_file_t file, /* in: File handle */
|
||||
int* error); /* out: 0 or error */
|
||||
|
||||
/*************************************************************************
|
||||
Allocate and initialize memory for a merge file structure */
|
||||
|
||||
merge_file_t*
|
||||
row_merge_create_file_structure(
|
||||
/*============================*/
|
||||
/* out: pointer to merge file
|
||||
structure */
|
||||
mem_heap_t* heap); /* in: heap where merge file structure
|
||||
is allocated */
|
||||
/*************************************************************************
|
||||
A thread which merge sorts given file and inserts sorted records to
|
||||
the index. */
|
||||
|
||||
#ifndef __WIN__
|
||||
void *
|
||||
#else
|
||||
ulint
|
||||
#endif
|
||||
row_merge_sort_and_insert_thread(
|
||||
/*=============================*/
|
||||
/* out: a dummy parameter */
|
||||
void* arg); /* in: parameters */
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Remove a index from system tables */
|
||||
|
||||
ulint
|
||||
row_merge_remove_index(
|
||||
/*===================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
dict_index_t* index, /* in: index to be removed */
|
||||
dict_table_t* table, /* in: table */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
|
||||
/*************************************************************************
|
||||
Print definition of a table in the dictionary */
|
||||
|
||||
void
|
||||
row_merge_print_table(
|
||||
/*==================*/
|
||||
dict_table_t* table); /* in: table */
|
||||
/*************************************************************************
|
||||
Mark all prebuilts using the table obsolete. These prebuilts are
|
||||
rebuilded later. */
|
||||
|
||||
void
|
||||
row_merge_mark_prebuilt_obsolete(
|
||||
/*=============================*/
|
||||
|
||||
trx_t* trx, /* in: trx */
|
||||
dict_table_t* table); /* in: table */
|
||||
/*************************************************************************
|
||||
Create a temporary table using a definition of the old table. You must
|
||||
lock data dictionary before calling this function. */
|
||||
|
||||
dict_table_t*
|
||||
row_merge_create_temporary_table(
|
||||
/*=============================*/
|
||||
/* out: new temporary table
|
||||
definition */
|
||||
const char* table_name, /* in: new table name */
|
||||
dict_table_t* table, /* in: old table definition */
|
||||
trx_t* trx, /* in: trx */
|
||||
ulint* error); /* in:out/ error code or DB_SUCCESS */
|
||||
/*************************************************************************
|
||||
Update all prebuilts for this table */
|
||||
|
||||
void
|
||||
row_merge_prebuilts_update(
|
||||
/*=======================*/
|
||||
|
||||
trx_t* trx, /* in: trx */
|
||||
dict_table_t* old_table); /* in: old table */
|
||||
/*************************************************************************
|
||||
Create a temporary table using a definition of the old table. You must
|
||||
lock data dictionary before calling this function. */
|
||||
|
||||
dict_table_t*
|
||||
row_merge_create_temporary_table(
|
||||
/*=============================*/
|
||||
/* out: new temporary table
|
||||
definition */
|
||||
const char* table_name, /* in: new table name */
|
||||
dict_table_t* table, /* in: old table definition */
|
||||
trx_t* trx, /* in: trx */
|
||||
ulint* error); /* in:out/ error code or DB_SUCCESS */
|
||||
/*************************************************************************
|
||||
Rename the indexes in the dicitionary. */
|
||||
|
||||
ulint
|
||||
row_merge_rename_index(
|
||||
/*===================*/
|
||||
/* out: DB_SUCCESS if all OK */
|
||||
trx_t* trx, /* in: Transaction */
|
||||
dict_table_t* table, /* in: Table for index */
|
||||
dict_index_t* index); /* in: Index to rename */
|
||||
/*************************************************************************
|
||||
Create the index and load in to the dicitionary. */
|
||||
|
||||
ulint
|
||||
row_merge_create_index(
|
||||
/*===================*/
|
||||
/* out: DB_SUCCESS if all OK */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t** index, /* out: the instance of the index */
|
||||
dict_table_t* table, /* in: the index is on this table */
|
||||
const merge_index_def_t* /* in: the index definition */
|
||||
index_def);
|
||||
/*************************************************************************
|
||||
Check if a transaction can use an index.*/
|
||||
|
||||
ibool
|
||||
row_merge_is_index_usable(
|
||||
/*======================*/
|
||||
/* out: TRUE if index can be used by
|
||||
the transaction else FALSE*/
|
||||
const trx_t* trx, /* in: transaction */
|
||||
const dict_index_t* /* in: index to check */
|
||||
index);
|
||||
/*************************************************************************
|
||||
If there are views that refer to the old table name then we "attach" to
|
||||
the new instance of the table else we drop it immediately.*/
|
||||
|
||||
ulint
|
||||
row_merge_drop_table(
|
||||
/*=================*/
|
||||
/* out: DB_SUCCESS if all OK else
|
||||
error code.*/
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table); /* in: table instance to drop */
|
||||
#endif /* row0merge.h */
|
||||
|
||||
@@ -21,7 +21,7 @@ Created 9/17/2000 Heikki Tuuri
|
||||
|
||||
extern ibool row_rollback_on_timeout;
|
||||
|
||||
typedef struct row_prebuilt_struct row_prebuilt_t;
|
||||
/* typedef struct row_prebuilt_struct row_prebuilt_t; */
|
||||
|
||||
/***********************************************************************
|
||||
Frees the blob heap in prebuilt when no longer needed. */
|
||||
@@ -153,6 +153,14 @@ row_update_prebuilt_trx(
|
||||
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/************************************************************************
|
||||
Update a prebuilt struct for a MySQL table handle. */
|
||||
|
||||
void
|
||||
row_update_prebuilt(
|
||||
/*================*/
|
||||
row_prebuilt_t* prebuilt, /* in: Innobase table handle */
|
||||
dict_table_t* table); /* in: table */
|
||||
/*************************************************************************
|
||||
Unlocks an AUTO_INC type lock possibly reserved by trx. */
|
||||
|
||||
@@ -188,6 +196,16 @@ row_lock_table_for_mysql(
|
||||
prebuilt->select_lock_type */
|
||||
ulint mode); /* in: lock mode of table
|
||||
(ignored if table==NULL) */
|
||||
/*************************************************************************
|
||||
Sets a table lock on the table. */
|
||||
|
||||
int
|
||||
row_lock_table_for_merge(
|
||||
/*=====================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: lock table for this trx */
|
||||
dict_table_t* table, /* in: table to lock */
|
||||
ulint mode); /* in: lock mode of table */
|
||||
|
||||
/*************************************************************************
|
||||
Does an insert for MySQL. */
|
||||
@@ -413,6 +431,19 @@ row_drop_table_for_mysql(
|
||||
ibool drop_db);/* in: TRUE=dropping whole database */
|
||||
|
||||
/*************************************************************************
|
||||
Drops a table for MySQL. If the name of the dropped table ends to
|
||||
characters INNODB_MONITOR, then this also stops printing of monitor
|
||||
output by the master thread. But does not commit the transaction, this
|
||||
is required for UNDOing dictionary records during recovery.*/
|
||||
|
||||
int
|
||||
row_drop_table_for_mysql_no_commit(
|
||||
/*===============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* name, /* in: table name */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool drop_db);/* in: TRUE=dropping whole database */
|
||||
/*************************************************************************
|
||||
Discards the tablespace of a table which stored in an .ibd file. Discarding
|
||||
means that this function deletes the .ibd file and assigns a new table id for
|
||||
the table. Also the flag table->ibd_file_missing is set TRUE. */
|
||||
@@ -451,7 +482,8 @@ row_rename_table_for_mysql(
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* old_name, /* in: old table name */
|
||||
const char* new_name, /* in: new table name */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool commit); /* in: if TRUE then commit trx */
|
||||
/*************************************************************************
|
||||
Checks a table for corruption. */
|
||||
|
||||
@@ -462,7 +494,93 @@ row_check_table_for_mysql(
|
||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
/*************************************************************************
|
||||
Build new indexes to a table by reading a cluster index,
|
||||
creating a temporary file containing index entries, merge sorting
|
||||
these index entries and inserting sorted index entries to indexes. */
|
||||
|
||||
ulint
|
||||
row_build_index_for_mysql(
|
||||
/*====================*/
|
||||
/* out: 0 or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* old_table, /* in: Table where rows are
|
||||
read from */
|
||||
dict_table_t* new_table, /* in: Table where indexes are
|
||||
created. Note that old_table ==
|
||||
new_table if we are creating a
|
||||
secondary keys. */
|
||||
dict_index_t** index, /* in: Indexes to be created */
|
||||
ibool new_primary, /* in: new primary key
|
||||
i.e. clustered index will be build
|
||||
for this table */
|
||||
ulint num_of_keys); /* in: Number of indexes to be
|
||||
created */
|
||||
/*************************************************************************
|
||||
Create query graph for a index creation */
|
||||
|
||||
ulint
|
||||
row_create_index_graph_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: trx */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index); /* in: index */
|
||||
/*************************************************************************
|
||||
Remove those indexes which were created before a error happened in
|
||||
the index build */
|
||||
|
||||
ulint
|
||||
row_remove_indexes_for_mysql(
|
||||
/*=========================*/
|
||||
/* out: 0 or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table, /* in: Table where index is created */
|
||||
dict_index_t** index, /* in: Indexes to be created */
|
||||
ulint num_created); /* in: Number of indexes created
|
||||
before error and now must be removed */
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, create_table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_create_table_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* table_name); /* in: table name created. */
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, rename_table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_create_index_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index); /* in: index created. */
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, rename_table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_rename_table_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* from_table_name,/* in: rename from table name. */
|
||||
const char* to_table_name, /* in: rename to table table. */
|
||||
const char* tmp_table_name);/* in: intermediate table name */
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, drop table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_drop_table_dict_operation(
|
||||
/*======================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: query thread */
|
||||
const char* table_name); /* in: table name dropped */
|
||||
/* A struct describing a place for an individual column in the MySQL
|
||||
row format which is presented to the table handler in ha_innobase.
|
||||
This template struct is used to speed up row transformations between
|
||||
@@ -512,16 +630,18 @@ struct mysql_row_templ_struct {
|
||||
|
||||
#define ROW_PREBUILT_ALLOCATED 78540783
|
||||
#define ROW_PREBUILT_FREED 26423527
|
||||
#define ROW_PREBUILT_OBSOLETE 12367541
|
||||
|
||||
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
|
||||
handle used within MySQL; these are used to save CPU time. */
|
||||
|
||||
struct row_prebuilt_struct {
|
||||
ulint magic_n; /* this magic number is set to
|
||||
ROW_PREBUILT_ALLOCATED when created
|
||||
and to ROW_PREBUILT_FREED when the
|
||||
struct has been freed; used in
|
||||
debugging */
|
||||
ROW_PREBUILT_ALLOCATED when created,
|
||||
or ROW_PREBUILT_FREED when the
|
||||
struct has been freed or
|
||||
ROW_PREBUILT_OBSOLETE when struct
|
||||
needs a rebuilt */
|
||||
dict_table_t* table; /* Innobase table handle */
|
||||
trx_t* trx; /* current transaction handle */
|
||||
ibool sql_stat_start; /* TRUE when we start processing of
|
||||
@@ -668,10 +788,12 @@ struct row_prebuilt_struct {
|
||||
fetched row in fetch_cache */
|
||||
ulint n_fetch_cached; /* number of not yet fetched rows
|
||||
in fetch_cache */
|
||||
mem_heap_t* blob_heap; /* in SELECTS BLOB fie lds are copied
|
||||
mem_heap_t* blob_heap; /* in SELECTS BLOB fields are copied
|
||||
to this heap */
|
||||
mem_heap_t* old_vers_heap; /* memory heap where a previous
|
||||
version is built in consistent read */
|
||||
UT_LIST_NODE_T(row_prebuilt_t) prebuilts;
|
||||
/* list node of table->prebuilts */
|
||||
ulint magic_n2; /* this should be the same as
|
||||
magic_n */
|
||||
};
|
||||
|
||||
@@ -52,15 +52,16 @@ row_get_rec_roll_ptr(
|
||||
dict_index_t* index, /* in: clustered index */
|
||||
const ulint* offsets);/* in: rec_get_offsets(rec, index) */
|
||||
/*********************************************************************
|
||||
When an insert to a table is performed, this function builds the entry which
|
||||
has to be inserted to an index on the table. */
|
||||
When an insert or purge to a table is performed, this function builds
|
||||
the entry to be inserted into or purged from an index on the table. */
|
||||
|
||||
dtuple_t*
|
||||
row_build_index_entry(
|
||||
/*==================*/
|
||||
/* out: index entry which should be inserted */
|
||||
const dtuple_t* row, /* in: row which should be inserted to the
|
||||
table */
|
||||
/* out: index entry which should be
|
||||
inserted or purged */
|
||||
const dtuple_t* row, /* in: row which should be
|
||||
inserted or purged */
|
||||
row_ext_t* ext, /* in: externally stored column prefixes,
|
||||
or NULL */
|
||||
dict_index_t* index, /* in: index on the table */
|
||||
|
||||
@@ -36,4 +36,6 @@ typedef struct purge_node_struct purge_node_t;
|
||||
|
||||
typedef struct row_ext_struct row_ext_t;
|
||||
|
||||
typedef struct row_prebuilt_struct row_prebuilt_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,15 @@ row_undo_ins(
|
||||
/* out: DB_SUCCESS */
|
||||
undo_node_t* node); /* in: row undo node */
|
||||
|
||||
/***************************************************************
|
||||
Parses the rec_type undo record. */
|
||||
|
||||
byte*
|
||||
row_undo_ins_parse_rec_type_and_table_id(
|
||||
/*=====================================*/
|
||||
/* out: ptr to next field to parse */
|
||||
undo_node_t* node, /* in: row undo node */
|
||||
dulint* table_id); /* out: table id */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "row0uins.ic"
|
||||
|
||||
@@ -51,6 +51,24 @@ row_undo_step(
|
||||
/*==========*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/***************************************************************
|
||||
Build the dict undo list*/
|
||||
|
||||
ulint
|
||||
row_undo_build_dict_undo_list(
|
||||
/*==========================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
undo_node_t* node); /* in: row undo node */
|
||||
|
||||
/***************************************************************
|
||||
Undo or redo a dictionary change */
|
||||
|
||||
ulint
|
||||
row_undo_dictionary(
|
||||
/*================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: the transaction */
|
||||
dict_undo_t* dict_undo); /* in: dict op to undo */
|
||||
|
||||
/* A single query thread will try to perform the undo for all successive
|
||||
versions of a clustered index record, if the transaction has modified it
|
||||
@@ -78,6 +96,20 @@ struct undo_node_struct{
|
||||
dulint undo_no;/* undo number of the record */
|
||||
ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
|
||||
... */
|
||||
ulint rec_sub_type; /* undo log record subtype:
|
||||
used when rec_type is
|
||||
TRX_UNDO_DICTIONARY_REC or 0*/
|
||||
char* new_table_name;/* table name in
|
||||
TRX_UNDO_TABLE_CREATE_REC or
|
||||
TRX_UNDO_TABLE_RENAME_REC or
|
||||
TRX_UNDO_TABLE_DROP_REC or NULL */
|
||||
char* old_table_name;/* old table name in
|
||||
TRX_UNDO_TABLE_RENAME_REC or NULL */
|
||||
char* tmp_table_name; /* intermediate table name used
|
||||
during rename & drop operation in
|
||||
ha_innobase::add_index().*/
|
||||
dulint index_id;/* index id in TRX_UNDO_INDEX_CREATE_REC
|
||||
or ut_dulint_zero */
|
||||
dulint new_roll_ptr; /* roll ptr to restore to clustered index
|
||||
record */
|
||||
dulint new_trx_id; /* trx id to restore to clustered index
|
||||
|
||||
@@ -60,6 +60,17 @@ trx_undo_rec_get_undo_no(
|
||||
/*=====================*/
|
||||
/* out: undo no */
|
||||
trx_undo_rec_t* undo_rec); /* in: undo log record */
|
||||
/**************************************************************************
|
||||
* Returns the start of the undo record data area. */
|
||||
|
||||
UNIV_INLINE
|
||||
byte*
|
||||
trx_undo_rec_get_ptr(
|
||||
/*==================*/
|
||||
/* out: compiler info */
|
||||
trx_undo_rec_t* undo_rec, /* in: undo log record */
|
||||
dulint undo_no); /* in: undo no read from node */
|
||||
|
||||
/**************************************************************************
|
||||
Reads from an undo log record the general parameters. */
|
||||
|
||||
@@ -201,6 +212,31 @@ trx_undo_report_row_operation(
|
||||
inserted undo log record,
|
||||
ut_dulint_zero if BTR_NO_UNDO_LOG
|
||||
flag was specified */
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation e.g.
|
||||
rename_table, create_table, create_index, drop table. This information
|
||||
is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
trx_undo_report_dict_operation(
|
||||
/*===========================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
|
||||
TRX_UNDO_TABLE_RENAME_OP,
|
||||
TRX_UNDO_TABLE_DROP_OP, or
|
||||
TRX_UNDO_INDEX_CREATE_OP */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index, /* in:
|
||||
if TRX_UNDO_INDEX_CREATE_OP
|
||||
index to be created*/
|
||||
const char* table_name, /* in: table name or NULL, used in
|
||||
create table, rename table and
|
||||
drop table*/
|
||||
const char* old_table_name, /* in: old table name or NULL.
|
||||
used in rename table */
|
||||
const char* tmp_table_name, /* in: the intermediate name used */
|
||||
dulint* roll_ptr); /* out: rollback pointer to the
|
||||
inserted undo log record */
|
||||
/**********************************************************************
|
||||
Copies an undo record to heap. This function can be called if we know that
|
||||
the undo log record exists. */
|
||||
@@ -279,6 +315,7 @@ trx_undo_parse_erase_page_end(
|
||||
/* Types of an undo log record: these have to be smaller than 16, as the
|
||||
compilation info multiplied by 16 is ORed to this value in an undo log
|
||||
record */
|
||||
|
||||
#define TRX_UNDO_INSERT_REC 11 /* fresh insert into clustered index */
|
||||
#define TRX_UNDO_UPD_EXIST_REC 12 /* update of a non-delete-marked
|
||||
record */
|
||||
@@ -287,6 +324,9 @@ record */
|
||||
fields of the record can change */
|
||||
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
|
||||
do not change */
|
||||
#define TRX_UNDO_DICTIONARY_REC 15 /* dictionary operation, detailed
|
||||
operation type can be found from
|
||||
undo log records subtype */
|
||||
#define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by
|
||||
this and ORed to the type above */
|
||||
#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
|
||||
@@ -294,9 +334,21 @@ record */
|
||||
storage fields: used by purge to
|
||||
free the external storage */
|
||||
|
||||
/* Operation type flags used in trx_undo_report_row_operation */
|
||||
/* Operation type flags used in trx_undo_report_row_operation
|
||||
and trx_undo_report_dict_operation */
|
||||
#define TRX_UNDO_INSERT_OP 1
|
||||
#define TRX_UNDO_MODIFY_OP 2
|
||||
#define TRX_UNDO_INDEX_CREATE_OP 3 /* alter table add index */
|
||||
#define TRX_UNDO_TABLE_CREATE_OP 4 /* create table */
|
||||
#define TRX_UNDO_TABLE_RENAME_OP 5 /* rename table */
|
||||
#define TRX_UNDO_TABLE_DROP_OP 6 /* drop table */
|
||||
|
||||
/* Subtypes for dictionary operation */
|
||||
#define TRX_UNDO_NULL_REC 0 /* No subtype */
|
||||
#define TRX_UNDO_INDEX_CREATE_REC 1 /* index create record */
|
||||
#define TRX_UNDO_TABLE_CREATE_REC 2 /* table create record */
|
||||
#define TRX_UNDO_TABLE_RENAME_REC 3 /* table rename record */
|
||||
#define TRX_UNDO_TABLE_DROP_REC 4 /* table drop record */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "trx0rec.ic"
|
||||
|
||||
@@ -63,6 +63,20 @@ trx_undo_rec_get_undo_no(
|
||||
return(mach_dulint_read_much_compressed(ptr));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns the start of the undo record data area. */
|
||||
UNIV_INLINE
|
||||
byte*
|
||||
trx_undo_rec_get_ptr(
|
||||
/*=================*/
|
||||
/* out: compiler info */
|
||||
trx_undo_rec_t* undo_rec, /* in: undo log record */
|
||||
dulint undo_no) /* in: undo no read from node */
|
||||
{
|
||||
return (((byte*) undo_rec) + 3
|
||||
+ mach_dulint_get_much_compressed_size(undo_no));
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Copies the undo record to the heap. */
|
||||
UNIV_INLINE
|
||||
|
||||
@@ -450,8 +450,19 @@ struct trx_struct{
|
||||
table. This is a hint that the table
|
||||
may need to be dropped in crash
|
||||
recovery. */
|
||||
dulint table_id; /* table id if the preceding field is
|
||||
TRUE */
|
||||
dict_undo_list_t*
|
||||
dict_undo_list; /* List of undo records are created
|
||||
during recovery.*/
|
||||
dict_redo_list_t*
|
||||
dict_redo_list; /* List of indexes created by this
|
||||
transaction.*/
|
||||
ulint (*sync_cb)(trx_t*, ibool);
|
||||
/* Transaction synchronization
|
||||
callback, if ibool parameter is TRUE
|
||||
then callback invoked for commit else
|
||||
rollback.*/
|
||||
dulint table_id; /* Table to drop iff dict_operation
|
||||
is TRUE.*/
|
||||
/*------------------------------*/
|
||||
int active_trans; /* 1 - if a transaction in MySQL
|
||||
is active. 2 - if prepare_commit_mutex
|
||||
@@ -567,6 +578,9 @@ struct trx_struct{
|
||||
void* error_info; /* if the error number indicates a
|
||||
duplicate key error, a pointer to
|
||||
the problematic index is stored here */
|
||||
ulint error_key_num; /* if the index creation fails to a
|
||||
duplicate key error, a mysql key
|
||||
number of that index is stored here */
|
||||
sess_t* sess; /* session of the trx, NULL if none */
|
||||
ulint que_state; /* TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
|
||||
... */
|
||||
|
||||
@@ -3678,7 +3678,9 @@ lock_table_enqueue_waiting(
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
||||
if (trx->dict_operation) {
|
||||
/* We have little choice here during index merge operations, and so
|
||||
we suppress the printing of the message.*/
|
||||
if (trx->dict_operation && *table->name != TEMP_TABLE_PREFIX) {
|
||||
ut_print_timestamp(stderr);
|
||||
fputs(" InnoDB: Error: a table lock wait happens"
|
||||
" in a dictionary operation!\n"
|
||||
|
||||
@@ -101,6 +101,21 @@ mem_alloc_func_noninline(
|
||||
return(mem_alloc_func(n, file_name, line));
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function.
|
||||
Frees a single buffer of storage from
|
||||
the dynamic memory of C compiler. Similar to free of C. */
|
||||
|
||||
void
|
||||
mem_free_func_noninline(
|
||||
/*====================*/
|
||||
void* ptr, /* in, own: buffer to be freed */
|
||||
const char* file_name, /* in: file name where created */
|
||||
ulint line) /* in: line where created */
|
||||
{
|
||||
return(mem_free_func(ptr, file_name, line));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Duplicates a NUL-terminated string, allocated from a memory heap. */
|
||||
|
||||
@@ -566,3 +581,60 @@ mem_validate_all_blocks(void)
|
||||
mem_pool_mutex_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************
|
||||
Allocates n bytes of memory from a memory heap. */
|
||||
|
||||
void*
|
||||
mem_heap_alloc_noninline(
|
||||
/*=====================*/
|
||||
/* out: allocated storage, NULL if did not
|
||||
succeed (only possible for
|
||||
MEM_HEAP_BTR_SEARCH type heaps) */
|
||||
mem_heap_t* heap, /* in: memory heap */
|
||||
ulint n) /* in: number of bytes; if the heap is allowed
|
||||
to grow into the buffer pool, this must be
|
||||
<= MEM_MAX_ALLOC_IN_BUF */
|
||||
{
|
||||
return (mem_heap_alloc(heap, n));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macros instead of this function. Creates a
|
||||
memory heap. For debugging purposes, takes also the file name and line as
|
||||
argument. */
|
||||
|
||||
mem_heap_t*
|
||||
mem_heap_create_func_noninline(
|
||||
/*===========================*/
|
||||
/* out, own: memory heap, NULL if
|
||||
did not succeed (only possible for
|
||||
MEM_HEAP_BTR_SEARCH type heaps)*/
|
||||
ulint n, /* in: desired start block size,
|
||||
this means that a single user buffer
|
||||
of size n will fit in the block,
|
||||
0 creates a default size block;
|
||||
if init_block is not NULL, n tells
|
||||
its size in bytes */
|
||||
ulint type, /* in: heap type */
|
||||
const char* file_name, /* in: file name where created */
|
||||
ulint line) /* in: line where created */
|
||||
{
|
||||
return(mem_heap_create_func(n, type, file_name, line));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
NOTE: Use the corresponding macro instead of this function. Frees the space
|
||||
occupied by a memory heap. In the debug version erases the heap memory
|
||||
blocks. */
|
||||
|
||||
void
|
||||
mem_heap_free_func_noninline(
|
||||
/*=========================*/
|
||||
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||
const char* file_name __attribute__((unused)),
|
||||
/* in: file name where freed */
|
||||
ulint line __attribute__((unused)))
|
||||
{
|
||||
mem_heap_free_func(heap, file_name, line);
|
||||
}
|
||||
|
||||
974
mysql-test/innodb-index.result
Normal file
974
mysql-test/innodb-index.result
Normal file
@@ -0,0 +1,974 @@
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak');
|
||||
commit;
|
||||
alter table t1 add index b (b), add index b (b);
|
||||
ERROR 42000: Duplicate key name 'b'
|
||||
alter table t1 add index (b,b);
|
||||
ERROR 42S21: Duplicate column name 'b'
|
||||
alter table t1 add index d2 (d);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `d2` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL d2 23 NULL 4
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
3 4 ad ad
|
||||
2 3 ak ak
|
||||
5 5 oo oo
|
||||
4 4 tr tr
|
||||
alter table t1 add unique index (b);
|
||||
ERROR 23000: Duplicate entry '0' for key 'b'
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `d2` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `d2` (`d`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `d2` (`d`),
|
||||
KEY `b` (`b`),
|
||||
KEY `d` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 11 NULL 4
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
3 4 ad ad
|
||||
2 3 ak ak
|
||||
5 5 oo oo
|
||||
4 4 tr tr
|
||||
alter table t1 drop index b, add index (b);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `d2` (`d`),
|
||||
KEY `d` (`d`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
insert into t1 values(6,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
a b c d
|
||||
2 3 ak ak
|
||||
3 4 ad ad
|
||||
4 4 tr tr
|
||||
5 5 oo oo
|
||||
6 1 ggg ggg
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
6 1 ggg ggg
|
||||
2 3 ak ak
|
||||
3 4 ad ad
|
||||
4 4 tr tr
|
||||
5 5 oo oo
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
3 4 ad ad
|
||||
2 3 ak ak
|
||||
6 1 ggg ggg
|
||||
5 5 oo oo
|
||||
4 4 tr tr
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
3 4 ad ad
|
||||
2 3 ak ak
|
||||
6 1 ggg ggg
|
||||
5 5 oo oo
|
||||
4 4 tr tr
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 5
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 11 NULL 5
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL d2 23 NULL 5
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `d2` (`d`),
|
||||
KEY `d` (`d`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add index (c(2));
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `c` (`c`(2))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 add unique index (d(10));
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `d` (`d`(10)),
|
||||
KEY `c` (`c`(2))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
insert into t1 values(5,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
5 1 ggg ggg
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
5 1 ggg ggg
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
5 1 ggg ggg
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
5 1 ggg ggg
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `d` (`d`(10)),
|
||||
KEY `c` (`c`(2))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 drop index d;
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
5 1 ggg ggg
|
||||
8 9 fff fff
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
5 1 ggg ggg
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
5 1 ggg ggg
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 3 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
5 1 ggg ggg
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `c` (`c`(2))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b,c);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 16 NULL 5
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `b` (`b`,`c`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 add index (b,c);
|
||||
insert into t1 values(11,11,'kkk','kkk');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 16 NULL 6
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `b` (`b`,`c`),
|
||||
KEY `b_2` (`b`,`c`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
alter table t1 add unique index (c,d);
|
||||
insert into t1 values(13,13,'yyy','aaa');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
13 13 yyy aaa
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
13 13 yyy aaa
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
13 13 yyy aaa
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
13 13 yyy aaa
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
11 11 kkk kkk
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 16 NULL 7
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 34 NULL 7
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `b` (`b`,`c`),
|
||||
UNIQUE KEY `c` (`c`,`d`),
|
||||
KEY `b_2` (`b`,`c`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb;
|
||||
create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
|
||||
create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
|
||||
create table t2(a int not null, b int not null, c int not null, d int not null, e int,
|
||||
primary key (a), foreign key (b) references t1(b), foreign key (c) references t3(c),
|
||||
foreign key (d) references t4(d)) engine = innodb;
|
||||
alter table t1 drop index b;
|
||||
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
|
||||
alter table t3 drop index c;
|
||||
ERROR HY000: Cannot drop index 'c': needed in a foreign key constraint
|
||||
alter table t4 drop index d;
|
||||
ERROR HY000: Cannot drop index 'd': needed in a foreign key constraint
|
||||
alter table t2 drop index b;
|
||||
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
|
||||
alter table t2 drop index b, drop index c, drop index d;
|
||||
ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
|
||||
set foreign_key_checks=0;
|
||||
insert into t1 values (1,1,1);
|
||||
insert into t3 values (1,1,1);
|
||||
insert into t4 values (1,1,1);
|
||||
insert into t2 values (1,1,1,1,1);
|
||||
commit;
|
||||
alter table t2 drop index b, add index (b);
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) NOT NULL,
|
||||
`c` int(11) NOT NULL,
|
||||
`d` int(11) NOT NULL,
|
||||
`e` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `c` (`c`),
|
||||
KEY `d` (`d`),
|
||||
KEY `b` (`b`),
|
||||
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`),
|
||||
CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t3` (`c`),
|
||||
CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`d`) REFERENCES `t4` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
set foreign_key_checks=1;
|
||||
set foreign_key_checks=0;
|
||||
drop table if exists t1,t2,t3,t4;
|
||||
set foreign_key_checks=1;
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
|
||||
engine = innodb default charset=utf8;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b);
|
||||
ERROR 23000: Duplicate entry '0' for key 'b'
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(10,10,'kkk','iii');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 6
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(11,11,'aaa','mmm');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
11 11 aaa mmm
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 7
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 31 NULL 7
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL d 63 NULL 7
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `b` (`b`),
|
||||
KEY `d` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
|
||||
engine = innodb default charset=ucs2;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b);
|
||||
ERROR 23000: Duplicate entry '0' for key 'b'
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 5
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(10,10,'aaa','kkk');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 aaa kkk
|
||||
select * from t1 order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 aaa kkk
|
||||
select * from t1 order by c;
|
||||
a b c d
|
||||
10 10 aaa kkk
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
select * from t1 order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 aaa kkk
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 6
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 21 NULL 6
|
||||
explain select * from t1 order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL d 43 NULL 6
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `b` (`b`),
|
||||
KEY `d` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int) engine = innodb;
|
||||
insert into t1 values (1,1),(1,1),(1,1),(1,1);
|
||||
alter table t1 add unique index (a);
|
||||
ERROR 23000: Duplicate entry '0' for key 'a'
|
||||
alter table t1 add unique index (b);
|
||||
ERROR 23000: Duplicate entry '0' for key 'b'
|
||||
alter table t1 add unique index (a), add unique index(b);
|
||||
ERROR 23000: Duplicate entry '0' for key 'a'
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb;
|
||||
alter table t1 drop index c, drop index b;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`c` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, primary key(a)) engine = innodb;
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe');
|
||||
alter table t1 add unique index (b), add unique index (c), add unique index (d);
|
||||
ERROR 23000: Duplicate entry '' for key 'c'
|
||||
alter table t1 add unique index (b), add index (d), add unique index (c);
|
||||
ERROR 23000: Duplicate entry '' for key 'c'
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb;
|
||||
insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1);
|
||||
alter table t1 add unique index (b);
|
||||
insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) NOT NULL,
|
||||
`c` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `b` (`b`),
|
||||
KEY `c` (`c`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
explain select * from t1 order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 5 NULL 9
|
||||
explain select * from t1 order by a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL PRIMARY 4 NULL 9
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 4 NULL 9
|
||||
select * from t1 order by a;
|
||||
a b c
|
||||
1 5 1
|
||||
2 4 2
|
||||
3 3 3
|
||||
4 2 4
|
||||
5 1 5
|
||||
10 20 20
|
||||
11 19 19
|
||||
12 18 18
|
||||
13 17 17
|
||||
select * from t1 order by b;
|
||||
a b c
|
||||
5 1 5
|
||||
4 2 4
|
||||
3 3 3
|
||||
2 4 2
|
||||
1 5 1
|
||||
13 17 17
|
||||
12 18 18
|
||||
11 19 19
|
||||
10 20 20
|
||||
select * from t1 order by c;
|
||||
a b c
|
||||
1 5 1
|
||||
2 4 2
|
||||
3 3 3
|
||||
4 2 4
|
||||
5 1 5
|
||||
13 17 17
|
||||
12 18 18
|
||||
11 19 19
|
||||
10 20 20
|
||||
drop table t1;
|
||||
create table t1(a int not null, b int not null) engine=innodb;
|
||||
insert into t1 values (1,1);
|
||||
alter table t1 add primary key(b);
|
||||
insert into t1 values (2,2);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) NOT NULL,
|
||||
PRIMARY KEY (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
explain select * from t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
|
||||
explain select * from t1 order by a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using filesort
|
||||
explain select * from t1 order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL PRIMARY 4 NULL 2
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
test.t1 582702641
|
||||
drop table t1;
|
||||
create table t1(a int not null) engine=innodb;
|
||||
insert into t1 values (1);
|
||||
alter table t1 add primary key(a);
|
||||
insert into t1 values (2);
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
commit;
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
explain select * from t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
|
||||
explain select * from t1 order by a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
test.t1 1531596814
|
||||
drop table t1;
|
||||
create table t1(a int, b blob,c text) engine=innodb default charset = utf8;
|
||||
insert into t1 values (1,repeat('jejdkrun87',220),repeat('jejdkrun87',440));
|
||||
insert into t1 values (2,repeat('adfd72nh9k',440),repeat('adfd72nh9k',1100));
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
test.t1 1121933170
|
||||
alter table t1 add primary key (a), add key (b(20));
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
test.t1 335046842
|
||||
insert into t1 values (3,repeat('adfdpplkeock',440),repeat('adfdpplkeock',1100));
|
||||
insert into t1 values (4,repeat('adfdijnmnb78k',440),repeat('adfdijnmnb78k',1100));
|
||||
insert into t1 values (5,repeat('adfdijn0loKNHJik',440),repeat('adfdijn0loKNHJik',1100));
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL DEFAULT '0',
|
||||
`b` blob,
|
||||
`c` text,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `b` (`b`(20))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
explain select * from t1 where b like 'adfd%';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range b b 23 NULL 2 Using where
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
test.t1 1008226368
|
||||
drop table t1;
|
||||
282
mysql-test/innodb-index.test
Normal file
282
mysql-test/innodb-index.test
Normal file
@@ -0,0 +1,282 @@
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak');
|
||||
commit;
|
||||
--error 1061
|
||||
alter table t1 add index b (b), add index b (b);
|
||||
--error 1060
|
||||
alter table t1 add index (b,b);
|
||||
alter table t1 add index d2 (d);
|
||||
show create table t1;
|
||||
explain select * from t1 order by d;
|
||||
select * from t1 order by d;
|
||||
--error 1582
|
||||
alter table t1 add unique index (b);
|
||||
show create table t1;
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
show create table t1;
|
||||
explain select * from t1 order by c;
|
||||
select * from t1 order by c;
|
||||
alter table t1 drop index b, add index (b);
|
||||
show create table t1;
|
||||
insert into t1 values(6,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add index (c(2));
|
||||
show create table t1;
|
||||
alter table t1 add unique index (d(10));
|
||||
show create table t1;
|
||||
insert into t1 values(5,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 drop index d;
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b,c);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 add index (b,c);
|
||||
insert into t1 values(11,11,'kkk','kkk');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c,d);
|
||||
insert into t1 values(13,13,'yyy','aaa');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb;
|
||||
create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
|
||||
create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
|
||||
create table t2(a int not null, b int not null, c int not null, d int not null, e int,
|
||||
primary key (a), foreign key (b) references t1(b), foreign key (c) references t3(c),
|
||||
foreign key (d) references t4(d)) engine = innodb;
|
||||
--error 1542
|
||||
alter table t1 drop index b;
|
||||
--error 1542
|
||||
alter table t3 drop index c;
|
||||
--error 1542
|
||||
alter table t4 drop index d;
|
||||
--error 1542
|
||||
alter table t2 drop index b;
|
||||
--error 1542
|
||||
alter table t2 drop index b, drop index c, drop index d;
|
||||
set foreign_key_checks=0;
|
||||
insert into t1 values (1,1,1);
|
||||
insert into t3 values (1,1,1);
|
||||
insert into t4 values (1,1,1);
|
||||
insert into t2 values (1,1,1,1,1);
|
||||
commit;
|
||||
alter table t2 drop index b, add index (b);
|
||||
show create table t2;
|
||||
set foreign_key_checks=1;
|
||||
|
||||
set foreign_key_checks=0;
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3,t4;
|
||||
--enable_warnings
|
||||
set foreign_key_checks=1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
|
||||
engine = innodb default charset=utf8;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
--error 1582
|
||||
alter table t1 add unique index (b);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(10,10,'kkk','iii');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(11,11,'aaa','mmm');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
check table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a))
|
||||
engine = innodb default charset=ucs2;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
--error 1582
|
||||
alter table t1 add unique index (b);
|
||||
show create table t1;
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(10,10,'aaa','kkk');
|
||||
select * from t1;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
select * from t1 order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
check table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int) engine = innodb;
|
||||
insert into t1 values (1,1),(1,1),(1,1),(1,1);
|
||||
--error 1582
|
||||
alter table t1 add unique index (a);
|
||||
--error 1582
|
||||
alter table t1 add unique index (b);
|
||||
--error 1582
|
||||
alter table t1 add unique index (a), add unique index(b);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb;
|
||||
alter table t1 drop index c, drop index b;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, primary key(a)) engine = innodb;
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe');
|
||||
--error 1582
|
||||
alter table t1 add unique index (b), add unique index (c), add unique index (d);
|
||||
--error 1582
|
||||
alter table t1 add unique index (b), add index (d), add unique index (c);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb;
|
||||
insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1);
|
||||
alter table t1 add unique index (b);
|
||||
insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
explain select * from t1 order by c;
|
||||
explain select * from t1 order by a;
|
||||
explain select * from t1 order by b;
|
||||
select * from t1 order by a;
|
||||
select * from t1 order by b;
|
||||
select * from t1 order by c;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null) engine=innodb;
|
||||
insert into t1 values (1,1);
|
||||
alter table t1 add primary key(b);
|
||||
insert into t1 values (2,2);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
select * from t1;
|
||||
explain select * from t1;
|
||||
explain select * from t1 order by a;
|
||||
explain select * from t1 order by b;
|
||||
checksum table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null) engine=innodb;
|
||||
insert into t1 values (1);
|
||||
alter table t1 add primary key(a);
|
||||
insert into t1 values (2);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
commit;
|
||||
select * from t1;
|
||||
explain select * from t1;
|
||||
explain select * from t1 order by a;
|
||||
checksum table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int, b blob,c text) engine=innodb default charset = utf8;
|
||||
insert into t1 values (1,repeat('jejdkrun87',220),repeat('jejdkrun87',440));
|
||||
insert into t1 values (2,repeat('adfd72nh9k',440),repeat('adfd72nh9k',1100));
|
||||
checksum table t1;
|
||||
alter table t1 add primary key (a), add key (b(20));
|
||||
checksum table t1;
|
||||
insert into t1 values (3,repeat('adfdpplkeock',440),repeat('adfdpplkeock',1100));
|
||||
insert into t1 values (4,repeat('adfdijnmnb78k',440),repeat('adfdijnmnb78k',1100));
|
||||
insert into t1 values (5,repeat('adfdijn0loKNHJik',440),repeat('adfdijn0loKNHJik',1100));
|
||||
show create table t1;
|
||||
check table t1;
|
||||
explain select * from t1 where b like 'adfd%';
|
||||
checksum table t1;
|
||||
drop table t1;
|
||||
@@ -1095,7 +1095,7 @@ show create table t2;
|
||||
create index id2 on t2 (id);
|
||||
show create table t2;
|
||||
drop index id2 on t2;
|
||||
--error 1025,1025
|
||||
--error 1540,1540
|
||||
drop index id on t2;
|
||||
show create table t2;
|
||||
drop table t2;
|
||||
|
||||
11
os/os0file.c
11
os/os0file.c
@@ -497,17 +497,6 @@ os_io_init_simple(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(UNIV_HOTBACKUP) && !defined(__NETWARE__)
|
||||
/*************************************************************************
|
||||
Creates a temporary file that will be deleted on close.
|
||||
This function is defined in ha_innodb.cc. */
|
||||
|
||||
int
|
||||
innobase_mysql_tmpfile(void);
|
||||
/*========================*/
|
||||
/* out: temporary file descriptor, or < 0 on error */
|
||||
#endif /* !UNIV_HOTBACKUP && !__NETWARE__ */
|
||||
|
||||
/***************************************************************************
|
||||
Creates a temporary file. This function is like tmpfile(3), but
|
||||
the temporary file is created in the MySQL temporary directory.
|
||||
|
||||
440
pars/pars0grm.c
440
pars/pars0grm.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/* A Bison parser, made by GNU Bison 1.875d. */
|
||||
/* A Bison parser, made by GNU Bison 2.0. */
|
||||
|
||||
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
@@ -336,6 +336,9 @@ que_fork_start_command(
|
||||
|
||||
fork->last_sel_node = NULL;
|
||||
|
||||
suspended_thr = NULL;
|
||||
completed_thr = NULL;
|
||||
|
||||
/* Choose the query thread to run: usually there is just one thread,
|
||||
but in a parallelized select, which necessarily is non-scrollable,
|
||||
there may be several to choose from */
|
||||
|
||||
@@ -17,7 +17,7 @@ include ../include/Makefile.i
|
||||
|
||||
noinst_LIBRARIES = librow.a
|
||||
|
||||
librow_a_SOURCES = row0ext.c\
|
||||
librow_a_SOURCES = row0ext.c row0merge.c\
|
||||
row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\
|
||||
row0uins.c row0umod.c row0undo.c row0upd.c row0vers.c
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ ins_node_create(
|
||||
|
||||
/***************************************************************
|
||||
Creates an entry template for each index of a table. */
|
||||
static
|
||||
|
||||
void
|
||||
ins_node_create_entry_list(
|
||||
/*=======================*/
|
||||
|
||||
2231
row/row0merge.c
Normal file
2231
row/row0merge.c
Normal file
File diff suppressed because it is too large
Load Diff
584
row/row0mysql.c
584
row/row0mysql.c
@@ -25,12 +25,15 @@ Created 9/17/2000 Heikki Tuuri
|
||||
#include "dict0boot.h"
|
||||
#include "trx0roll.h"
|
||||
#include "trx0purge.h"
|
||||
#include "trx0rec.h"
|
||||
#include "trx0undo.h"
|
||||
#include "lock0lock.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "log0log.h"
|
||||
#include "btr0sea.h"
|
||||
#include "fil0fil.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "row0merge.h"
|
||||
|
||||
/* A dummy variable used to fool the compiler */
|
||||
ibool row_mysql_identically_false = FALSE;
|
||||
@@ -79,6 +82,9 @@ row_mysql_is_system_table(
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
static ibool row_add_table_to_background_drop_list(dict_table_t* table);
|
||||
/*====================================================================*/
|
||||
|
||||
/***********************************************************************
|
||||
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
|
||||
static
|
||||
@@ -548,7 +554,6 @@ handle_new_error:
|
||||
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
|
||||
"forcing-recovery.html"
|
||||
" for help.\n", stderr);
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "InnoDB: unknown error code %lu\n",
|
||||
(ulong) err);
|
||||
@@ -656,9 +661,39 @@ row_create_prebuilt(
|
||||
|
||||
prebuilt->old_vers_heap = NULL;
|
||||
|
||||
UT_LIST_ADD_LAST(prebuilts, table->prebuilts, prebuilt);
|
||||
|
||||
return(prebuilt);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Update a prebuilt struct for a MySQL table handle. */
|
||||
|
||||
void
|
||||
row_update_prebuilt(
|
||||
/*================*/
|
||||
row_prebuilt_t* prebuilt, /* in: Innobase table handle */
|
||||
dict_table_t* table) /* in: table */
|
||||
{
|
||||
dict_index_t* clust_index;
|
||||
|
||||
ut_ad(prebuilt && prebuilt->heap && table);
|
||||
ut_ad(prebuilt->magic_n == ROW_PREBUILT_OBSOLETE);
|
||||
|
||||
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
|
||||
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
|
||||
|
||||
clust_index = dict_table_get_first_index(table);
|
||||
|
||||
if (!prebuilt->index) {
|
||||
prebuilt->index = clust_index;
|
||||
}
|
||||
|
||||
if (prebuilt->ins_node) {
|
||||
ins_node_create_entry_list(prebuilt->ins_node);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Free a prebuilt struct for a MySQL table handle. */
|
||||
|
||||
@@ -669,12 +704,15 @@ row_prebuilt_free(
|
||||
{
|
||||
ulint i;
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
|
||||
if ((prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE)
|
||||
|| (prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED
|
||||
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE)) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu,"
|
||||
" magic n2 %lu, table name",
|
||||
" magic n2 %lu, table name ",
|
||||
(ulong) prebuilt->magic_n,
|
||||
(ulong) prebuilt->magic_n2);
|
||||
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
|
||||
@@ -738,6 +776,35 @@ row_prebuilt_free(
|
||||
|
||||
dict_table_decrement_handle_count(prebuilt->table);
|
||||
|
||||
/* If there were references to this table when a primary index on
|
||||
this table was created then we drop it here since there are no
|
||||
references to it now.*/
|
||||
if (prebuilt->table->to_be_dropped
|
||||
&& prebuilt->table->n_mysql_handles_opened == 0) {
|
||||
ibool added;
|
||||
|
||||
added = row_add_table_to_background_drop_list(prebuilt->table);
|
||||
|
||||
assert(*prebuilt->table->name == TEMP_TABLE_PREFIX);
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
if (added) {
|
||||
fputs(" InnoDB: Dropping table ", stderr);
|
||||
ut_print_name(stderr, NULL, TRUE,
|
||||
prebuilt->table->name);
|
||||
putc('\n', stderr);
|
||||
} else {
|
||||
fputs(" InnoDB: Error: failed trying to add ",
|
||||
stderr);
|
||||
ut_print_name(stderr, NULL, TRUE,
|
||||
prebuilt->table->name);
|
||||
fputs(" to the background drop list.\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
UT_LIST_REMOVE(prebuilts, prebuilt->table->prebuilts, prebuilt);
|
||||
|
||||
mem_heap_free(prebuilt->heap);
|
||||
}
|
||||
|
||||
@@ -767,9 +834,9 @@ row_update_prebuilt_trx(
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to use a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu, table name",
|
||||
"InnoDB: table handle. Magic n %lu, table name ",
|
||||
(ulong) prebuilt->magic_n);
|
||||
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
|
||||
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
|
||||
putc('\n', stderr);
|
||||
|
||||
mem_analyze_corruption(prebuilt);
|
||||
@@ -1048,6 +1115,88 @@ run_again:
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Sets a table lock on the table */
|
||||
|
||||
int
|
||||
row_lock_table_for_merge(
|
||||
/*=====================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: lock table for this trx */
|
||||
dict_table_t* table, /* in: table to lock */
|
||||
ulint mode) /* in: lock mode of table */
|
||||
{
|
||||
mem_heap_t* heap; /* Memory heap */
|
||||
que_thr_t* thr;
|
||||
ulint err;
|
||||
sel_node_t* node;
|
||||
|
||||
ut_ad(trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
|
||||
trx->op_info = "setting table lock for index merge";
|
||||
|
||||
node = sel_node_create(heap);
|
||||
thr = pars_complete_graph_for_exec(node, trx, heap);
|
||||
/* SB: Not sure about this - Ask Heikki */
|
||||
thr->graph->state = QUE_FORK_ACTIVE;
|
||||
|
||||
/* We use the select query graph as the dummy graph needed
|
||||
in the lock module call */
|
||||
|
||||
thr = que_fork_get_first_thr(que_node_get_parent(thr));
|
||||
que_thr_move_to_run_state_for_mysql(thr, trx);
|
||||
|
||||
run_again:
|
||||
thr->run_node = thr;
|
||||
thr->prev_node = thr->common.parent;
|
||||
|
||||
err = lock_table(0, table, mode, thr);
|
||||
|
||||
trx->error_state = err;
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
que_thr_stop_for_mysql(thr);
|
||||
|
||||
if (err != DB_QUE_THR_SUSPENDED) {
|
||||
ibool was_lock_wait;
|
||||
|
||||
was_lock_wait = row_mysql_handle_errors(
|
||||
&err, trx, thr, NULL);
|
||||
|
||||
if (was_lock_wait) {
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
} else {
|
||||
que_thr_t* run_thr;
|
||||
que_node_t* parent;
|
||||
|
||||
parent = que_node_get_parent(thr);
|
||||
run_thr = que_fork_start_command(parent);
|
||||
|
||||
ut_a(run_thr == thr);
|
||||
|
||||
/* There was a lock wait but the thread was not
|
||||
in a ready to run or running state.*/
|
||||
trx->error_state = DB_LOCK_WAIT;
|
||||
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
que_thr_stop_for_mysql_no_error(thr, trx);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
/*************************************************************************
|
||||
Does an insert for MySQL. */
|
||||
|
||||
@@ -1065,6 +1214,7 @@ row_insert_for_mysql(
|
||||
ibool was_lock_wait;
|
||||
trx_t* trx = prebuilt->trx;
|
||||
ins_node_t* node = prebuilt->ins_node;
|
||||
dict_table_t* table;
|
||||
|
||||
ut_ad(trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
@@ -1087,13 +1237,13 @@ row_insert_for_mysql(
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu, table name",
|
||||
"InnoDB: table handle. Magic n %lu, table name ",
|
||||
(ulong) prebuilt->magic_n);
|
||||
ut_print_name(stderr, prebuilt->trx, TRUE,
|
||||
prebuilt->table->name);
|
||||
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
|
||||
putc('\n', stderr);
|
||||
|
||||
mem_analyze_corruption(prebuilt);
|
||||
@@ -1101,6 +1251,10 @@ row_insert_for_mysql(
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||
}
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
@@ -1122,6 +1276,14 @@ row_insert_for_mysql(
|
||||
if (node == NULL) {
|
||||
row_get_prebuilt_insert_row(prebuilt);
|
||||
node = prebuilt->ins_node;
|
||||
} else {
|
||||
table = dict_table_get(prebuilt->table->name, FALSE);
|
||||
|
||||
if (prebuilt->ins_node->table_version_number !=
|
||||
table->version_number) {
|
||||
row_get_prebuilt_insert_row(prebuilt);
|
||||
node = prebuilt->ins_node;
|
||||
}
|
||||
}
|
||||
|
||||
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
|
||||
@@ -1143,6 +1305,10 @@ run_again:
|
||||
thr->run_node = node;
|
||||
thr->prev_node = node;
|
||||
|
||||
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||
}
|
||||
|
||||
row_ins_step(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
@@ -1325,13 +1491,13 @@ row_update_for_mysql(
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to free a corrupt\n"
|
||||
"InnoDB: table handle. Magic n %lu, table name",
|
||||
"InnoDB: table handle. Magic n %lu, table name ",
|
||||
(ulong) prebuilt->magic_n);
|
||||
ut_print_name(stderr, prebuilt->trx, TRUE,
|
||||
prebuilt->table->name);
|
||||
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
|
||||
putc('\n', stderr);
|
||||
|
||||
mem_analyze_corruption(prebuilt);
|
||||
@@ -1339,6 +1505,10 @@ row_update_for_mysql(
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||
}
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
@@ -1391,6 +1561,10 @@ run_again:
|
||||
thr->run_node = node;
|
||||
thr->prev_node = node;
|
||||
|
||||
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||
}
|
||||
|
||||
row_upd_step(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
@@ -1749,6 +1923,9 @@ row_create_table_for_mysql(
|
||||
ulint table_name_len;
|
||||
ulint err;
|
||||
ulint i;
|
||||
ibool retry;
|
||||
|
||||
retry = FALSE;
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
@@ -1868,6 +2045,7 @@ row_create_table_for_mysql(
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
|
||||
retry_create:
|
||||
trx->dict_operation = TRUE;
|
||||
|
||||
node = tab_create_graph_create(table, heap);
|
||||
@@ -1884,9 +2062,10 @@ row_create_table_for_mysql(
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
if (err == DB_OUT_OF_FILE_SPACE) {
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fputs(" InnoDB: Warning: cannot create table ",
|
||||
@@ -1903,6 +2082,10 @@ row_create_table_for_mysql(
|
||||
} else if (err == DB_DUPLICATE_KEY) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||
trx_general_rollback_for_mysql(
|
||||
trx, FALSE, NULL);
|
||||
|
||||
fputs(" InnoDB: Error: table ", stderr);
|
||||
ut_print_name(stderr, trx, TRUE, table->name);
|
||||
fputs(" already exists in InnoDB internal\n"
|
||||
@@ -1924,9 +2107,26 @@ row_create_table_for_mysql(
|
||||
" and DROP TABLE will\n"
|
||||
"InnoDB: succeed.\n"
|
||||
"InnoDB: You can look for further help from\n"
|
||||
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
|
||||
"InnoDB: "
|
||||
"http://dev.mysql.com/doc/refman/5.1/en/"
|
||||
"innodb-troubleshooting.html\n",
|
||||
stderr);
|
||||
} else if (!retry) {
|
||||
fputs(" InnoDB: Warning: table ", stderr);
|
||||
ut_print_name(stderr, trx, TRUE, table->name);
|
||||
fputs(" already exists in InnoDB internal\n"
|
||||
"InnoDB: dropping old temporary table\n",
|
||||
stderr);
|
||||
|
||||
row_drop_table_for_mysql(table->name, trx,
|
||||
FALSE);
|
||||
|
||||
retry = TRUE;
|
||||
goto retry_create;
|
||||
} else {
|
||||
trx_general_rollback_for_mysql(
|
||||
trx, FALSE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* We may also get err == DB_ERROR if the .ibd file for the
|
||||
@@ -1964,7 +2164,7 @@ row_create_index_for_mysql(
|
||||
mem_heap_t* heap;
|
||||
que_thr_t* thr;
|
||||
ulint err;
|
||||
ulint i, j;
|
||||
ulint i;
|
||||
ulint len;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
@@ -1982,11 +2182,12 @@ row_create_index_for_mysql(
|
||||
safer not to allow them. */
|
||||
|
||||
for (i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
ulint j;
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (0 == ut_strcmp(
|
||||
dict_index_get_nth_field(index, j)->name,
|
||||
dict_index_get_nth_field(index, i)->name)) {
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fputs(" InnoDB: Error: column ", stderr);
|
||||
@@ -2433,10 +2634,10 @@ row_discard_tablespace_for_mysql(
|
||||
ut_print_timestamp(ef);
|
||||
|
||||
fputs(" Cannot DISCARD table ", ef);
|
||||
ut_print_name(ef, trx, TRUE, name);
|
||||
ut_print_name(stderr, trx, TRUE, name);
|
||||
fputs("\n"
|
||||
"because it is referenced by ", ef);
|
||||
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
|
||||
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
|
||||
putc('\n', ef);
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
@@ -2761,10 +2962,10 @@ row_truncate_table_for_mysql(
|
||||
ut_print_timestamp(ef);
|
||||
|
||||
fputs(" Cannot truncate table ", ef);
|
||||
ut_print_name(ef, trx, TRUE, table->name);
|
||||
ut_print_name(stderr, trx, TRUE, table->name);
|
||||
fputs(" by DROP+CREATE\n"
|
||||
"InnoDB: because it is referenced by ", ef);
|
||||
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
|
||||
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
|
||||
putc('\n', ef);
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
@@ -2982,6 +3183,30 @@ row_drop_table_for_mysql(
|
||||
const char* name, /* in: table name */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool drop_db)/* in: TRUE=dropping whole database */
|
||||
{
|
||||
ulint err;
|
||||
|
||||
err = row_drop_table_for_mysql_no_commit(name, trx, drop_db);
|
||||
|
||||
if (!srv_created_new_raw) {
|
||||
trx_commit_for_mysql(trx);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Drops a table for MySQL. If the name of the table to be dropped is equal
|
||||
with one of the predefined magic table names, then this also stops printing
|
||||
the corresponding monitor output by the master thread. */
|
||||
|
||||
int
|
||||
row_drop_table_for_mysql_no_commit(
|
||||
/*===============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* name, /* in: table name */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool drop_db)/* in: TRUE=dropping whole database */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
dict_table_t* table;
|
||||
@@ -3111,10 +3336,10 @@ check_next_foreign:
|
||||
ut_print_timestamp(ef);
|
||||
|
||||
fputs(" Cannot drop table ", ef);
|
||||
ut_print_name(ef, trx, TRUE, name);
|
||||
ut_print_name(stderr, trx, TRUE, name);
|
||||
fputs("\n"
|
||||
"because it is referenced by ", ef);
|
||||
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
|
||||
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
|
||||
putc('\n', ef);
|
||||
mutex_exit(&dict_foreign_err_mutex);
|
||||
|
||||
@@ -3131,6 +3356,9 @@ check_next_foreign:
|
||||
added = row_add_table_to_background_drop_list(table);
|
||||
|
||||
if (added) {
|
||||
/* Temporary tables can have read views and we don't
|
||||
print any warning. */
|
||||
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||
ut_print_timestamp(stderr);
|
||||
fputs(" InnoDB: Warning: MySQL is"
|
||||
" trying to drop table ", stderr);
|
||||
@@ -3141,10 +3369,12 @@ check_next_foreign:
|
||||
"InnoDB: Adding the table to the"
|
||||
" background drop queue.\n",
|
||||
stderr);
|
||||
} else {
|
||||
ut_a(table->to_be_dropped);
|
||||
}
|
||||
|
||||
/* We return DB_SUCCESS to MySQL though the drop will
|
||||
happen lazily later */
|
||||
|
||||
err = DB_SUCCESS;
|
||||
} else {
|
||||
/* The table is already in the background drop list */
|
||||
@@ -3219,7 +3449,6 @@ check_next_foreign:
|
||||
"WHERE NAME = :table_name\n"
|
||||
"LOCK IN SHARE MODE;\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"found := 1;\n"
|
||||
@@ -3272,7 +3501,6 @@ check_next_foreign:
|
||||
"WHERE TABLE_ID = table_id;\n"
|
||||
"DELETE FROM SYS_TABLES\n"
|
||||
"WHERE ID = table_id;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n"
|
||||
, FALSE, trx);
|
||||
|
||||
@@ -3354,8 +3582,6 @@ check_next_foreign:
|
||||
}
|
||||
funct_exit:
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
if (locked_dictionary) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
@@ -3532,7 +3758,8 @@ row_rename_table_for_mysql(
|
||||
/* out: error code or DB_SUCCESS */
|
||||
const char* old_name, /* in: old table name */
|
||||
const char* new_name, /* in: new table name */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
trx_t* trx, /* in: transaction handle */
|
||||
ibool commit) /* in: if TRUE then commit trx */
|
||||
{
|
||||
dict_table_t* table;
|
||||
ulint err;
|
||||
@@ -3557,9 +3784,7 @@ row_rename_table_for_mysql(
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (row_mysql_is_system_table(new_name)) {
|
||||
} else if (row_mysql_is_system_table(new_name)) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to create a MySQL"
|
||||
@@ -3578,11 +3803,6 @@ row_rename_table_for_mysql(
|
||||
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
|
||||
new_is_tmp = row_is_mysql_tmp_table_name(new_name);
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
table = dict_table_get_low(old_name);
|
||||
|
||||
if (!table) {
|
||||
@@ -3603,9 +3823,7 @@ row_rename_table_for_mysql(
|
||||
"innodb-troubleshooting.html\n",
|
||||
stderr);
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (table->ibd_file_missing) {
|
||||
} else if (table->ibd_file_missing) {
|
||||
err = DB_TABLE_NOT_FOUND;
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
@@ -3618,9 +3836,7 @@ row_rename_table_for_mysql(
|
||||
"innodb-troubleshooting.html\n",
|
||||
stderr);
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
if (new_is_tmp) {
|
||||
} else if (new_is_tmp) {
|
||||
/* MySQL is doing an ALTER TABLE command and it renames the
|
||||
original table to a temporary table name. We want to preserve
|
||||
the original foreign key constraint definitions despite the
|
||||
@@ -3660,9 +3876,7 @@ row_rename_table_for_mysql(
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!new_is_tmp) {
|
||||
} else if (!new_is_tmp) {
|
||||
/* Rename all constraints. */
|
||||
|
||||
info = pars_info_create();
|
||||
@@ -3860,8 +4074,10 @@ end:
|
||||
}
|
||||
|
||||
funct_exit:
|
||||
|
||||
if (commit) {
|
||||
trx_commit_for_mysql(trx);
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (UNIV_LIKELY_NULL(heap)) {
|
||||
mem_heap_free(heap);
|
||||
@@ -4066,8 +4282,7 @@ row_check_table_for_mysql(
|
||||
if (!btr_validate_index(index, prebuilt->trx)) {
|
||||
ret = DB_ERROR;
|
||||
} else {
|
||||
if (!row_scan_and_check_index(prebuilt,
|
||||
index, &n_rows)) {
|
||||
if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
|
||||
ret = DB_ERROR;
|
||||
}
|
||||
|
||||
@@ -4118,4 +4333,273 @@ row_check_table_for_mysql(
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation e.g.
|
||||
rename_table, create_table, create_index, drop table. This information
|
||||
is used in a rollback of the transaction. */
|
||||
static
|
||||
ulint
|
||||
row_undo_report_dict_operation(
|
||||
/*===========================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
|
||||
TRX_UNDO_TABLE_RENAME_OP,
|
||||
TRX_UNDO_TABLE_DROP_OP, or
|
||||
TRX_UNDO_INDEX_CREATE_OP */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index, /* in:
|
||||
if TRX_UNDO_INDEX_CREATE_OP
|
||||
index to be created*/
|
||||
const char* table_name, /* in: table name or NULL, used in
|
||||
create table, rename table and
|
||||
drop table*/
|
||||
const char* old_table_name, /* in: old table name or NULL. */
|
||||
const char* tmp_table_name) /* in: the intermediate name or NULL */
|
||||
{
|
||||
dulint roll_ptr;
|
||||
|
||||
return trx_undo_report_dict_operation(
|
||||
op_type, trx, index, table_name, old_table_name,
|
||||
tmp_table_name, &roll_ptr);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, create_table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_create_table_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* table_name) /* in: table name to create. */
|
||||
{
|
||||
return row_undo_report_dict_operation(
|
||||
TRX_UNDO_TABLE_CREATE_OP, trx, NULL, table_name, NULL, NULL);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, create_index.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_create_index_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index) /* in: index created. */
|
||||
{
|
||||
return row_undo_report_dict_operation(
|
||||
TRX_UNDO_INDEX_CREATE_OP, trx, index, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, rename_table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_rename_table_dict_operation(
|
||||
/*========================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* from_table_name,/* in: rename from table table. */
|
||||
const char* to_table_name, /* in: rename to table name. */
|
||||
const char* tmp_table_name) /* in: intermediate name for table */
|
||||
{
|
||||
return row_undo_report_dict_operation(
|
||||
TRX_UNDO_TABLE_RENAME_OP, trx, NULL,
|
||||
to_table_name, from_table_name, tmp_table_name);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation, drop table.
|
||||
This information is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
row_undo_report_drop_table_dict_operation(
|
||||
/*======================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: query thread */
|
||||
const char* table_name) /* in: table name dropped */
|
||||
{
|
||||
return row_undo_report_dict_operation(
|
||||
TRX_UNDO_TABLE_DROP_OP, trx, NULL, table_name, NULL, NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Create query graph for an index creation */
|
||||
|
||||
ulint
|
||||
row_create_index_graph_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: trx */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
ind_node_t* node; /* Index creation node */
|
||||
mem_heap_t* heap; /* Memory heap */
|
||||
que_thr_t* thr; /* Query thread */
|
||||
ulint err = DB_SUCCESS;
|
||||
|
||||
ut_ad(trx && index);
|
||||
|
||||
heap = mem_heap_create(512);
|
||||
|
||||
index->table = table;
|
||||
node = ind_create_graph_create(index, heap);
|
||||
thr = pars_complete_graph_for_exec(node, trx, heap);
|
||||
|
||||
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
err = trx->error_state;
|
||||
|
||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Build new indexes to a table by reading a cluster index,
|
||||
creating a temporary file containing index entries, merge sorting
|
||||
these index entries and inserting sorted index entries to indexes. */
|
||||
|
||||
ulint
|
||||
row_build_index_for_mysql(
|
||||
/*======================*/
|
||||
/* out: 0 or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* old_table, /* in: Table where rows are
|
||||
read from */
|
||||
dict_table_t* new_table, /* in: Table where indexes are
|
||||
created. Note that old_table ==
|
||||
new_table if we are creating a
|
||||
secondary keys. */
|
||||
dict_index_t** index, /* in: Indexes to be created */
|
||||
ibool new_primary, /* in: new primary key
|
||||
i.e. clustered index will be build
|
||||
for this table */
|
||||
ulint num_of_keys) /* in: Number of indexes to be
|
||||
created */
|
||||
{
|
||||
merge_file_t** merge_files;
|
||||
mem_heap_t* file_heap;
|
||||
ulint index_num;
|
||||
ulint error = DB_SUCCESS;
|
||||
|
||||
ut_ad(trx && old_table && new_table && index && num_of_keys);
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
|
||||
/* Allocate memory for merge file data structure and initialize
|
||||
fields */
|
||||
|
||||
file_heap = mem_heap_create(
|
||||
num_of_keys * (sizeof(merge_file_t) + sizeof(merge_file_t*)));
|
||||
|
||||
merge_files = mem_heap_alloc(
|
||||
file_heap, num_of_keys * sizeof(merge_file_t*));
|
||||
|
||||
for (index_num = 0; index_num < num_of_keys; index_num++) {
|
||||
|
||||
merge_files[index_num] =
|
||||
row_merge_create_file_structure(file_heap);
|
||||
}
|
||||
|
||||
|
||||
/* Read clustered index of the table and create files for
|
||||
secondary index entries for merge sort */
|
||||
|
||||
error = row_merge_read_clustered_index(
|
||||
trx, old_table, index, merge_files, num_of_keys);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
|
||||
/* Now we have files containing index entries ready for
|
||||
sorting and inserting. */
|
||||
|
||||
for (index_num = 0; index_num < num_of_keys; index_num++) {
|
||||
|
||||
/* Do a merge sort and insert from those files
|
||||
which we have written at least one block */
|
||||
|
||||
if (merge_files[index_num]->num_of_blocks > 0) {
|
||||
dulint offset = ut_dulint_create(0, 0);
|
||||
|
||||
/* Merge sort file using linked list merge
|
||||
sort for files. */
|
||||
|
||||
offset = row_merge_sort_linked_list_in_disk(
|
||||
index[index_num],
|
||||
merge_files[index_num]->file,
|
||||
(int *)&error);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
trx->error_key_num = index_num;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* Insert sorted index entries to the table. */
|
||||
|
||||
error = row_merge_insert_index_tuples(
|
||||
trx,
|
||||
index[index_num],
|
||||
new_table,
|
||||
merge_files[index_num]->file,
|
||||
ut_dulint_create(0,0));
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
trx->error_key_num = index_num;
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func_exit:
|
||||
if (error == DB_SUCCESS && new_primary) {
|
||||
row_merge_mark_prebuilt_obsolete(trx, old_table);
|
||||
}
|
||||
|
||||
mem_heap_free(file_heap);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Remove those indexes which were created before a error happened in
|
||||
the index build */
|
||||
|
||||
ulint
|
||||
row_remove_indexes_for_mysql(
|
||||
/*=========================*/
|
||||
/* out: 0 or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_table_t* table, /* in: Table where index is created */
|
||||
dict_index_t** index, /* in: Indexes to be created */
|
||||
ulint num_created) /* in: Number of indexes created
|
||||
before error and now must be removed */
|
||||
{
|
||||
ulint key_num;
|
||||
ulint error = DB_SUCCESS;
|
||||
|
||||
ut_ad(trx && table && index);
|
||||
|
||||
for (key_num = 0; key_num < num_created; key_num++) {
|
||||
error = row_merge_remove_index(index[key_num], table, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(error);
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
@@ -227,7 +227,7 @@ row_purge_remove_sec_if_poss_low(
|
||||
/* Not found */
|
||||
|
||||
/* fputs("PURGE:........sec entry not found\n", stderr); */
|
||||
/* dtuple_print(entry); */
|
||||
/* dtuple_print(stderr, entry); */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
@@ -57,15 +57,16 @@ row_get_trx_id_offset(
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
When an insert to a table is performed, this function builds the entry which
|
||||
has to be inserted to an index on the table. */
|
||||
When an insert or purge to a table is performed, this function builds
|
||||
the entry to be inserted into or purged from an index on the table. */
|
||||
|
||||
dtuple_t*
|
||||
row_build_index_entry(
|
||||
/*==================*/
|
||||
/* out: index entry which should be inserted */
|
||||
const dtuple_t* row, /* in: row which should be inserted to the
|
||||
table */
|
||||
/* out: index entry which should be
|
||||
inserted or purged */
|
||||
const dtuple_t* row, /* in: row which should be
|
||||
inserted or purged */
|
||||
row_ext_t* ext, /* in: externally stored column prefixes,
|
||||
or NULL */
|
||||
dict_index_t* index, /* in: index on the table */
|
||||
|
||||
151
row/row0uins.c
151
row/row0uins.c
@@ -28,6 +28,7 @@ Created 2/25/1997 Heikki Tuuri
|
||||
#include "que0que.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "log0log.h"
|
||||
#include "row0merge.h"
|
||||
|
||||
/*******************************************************************
|
||||
Removes a clustered index record. The pcur in node was positioned on the
|
||||
@@ -52,6 +53,25 @@ row_undo_ins_remove_clust_rec(
|
||||
ut_a(success);
|
||||
|
||||
if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
|
||||
trx_t* trx;
|
||||
ibool thawed_dictionary = FALSE;
|
||||
ibool locked_dictionary = FALSE;
|
||||
|
||||
trx = node->trx;
|
||||
|
||||
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
|
||||
thawed_dictionary = TRUE;
|
||||
}
|
||||
|
||||
if (trx->dict_operation_lock_mode == 0
|
||||
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
locked_dictionary = TRUE;
|
||||
}
|
||||
|
||||
/* Drop the index tree associated with the row in
|
||||
SYS_INDEXES table: */
|
||||
@@ -65,6 +85,14 @@ row_undo_ins_remove_clust_rec(
|
||||
success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
|
||||
&(node->pcur), &mtr);
|
||||
ut_a(success);
|
||||
|
||||
if (locked_dictionary) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (thawed_dictionary) {
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
}
|
||||
|
||||
btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
|
||||
@@ -211,6 +239,36 @@ retry:
|
||||
return(err);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Parses the rec_type undo record. */
|
||||
|
||||
byte*
|
||||
row_undo_ins_parse_rec_type_and_table_id(
|
||||
/*=====================================*/
|
||||
/* out: ptr to next field to parse */
|
||||
undo_node_t* node, /* in: row undo node */
|
||||
dulint* table_id) /* out: table id */
|
||||
{
|
||||
byte* ptr;
|
||||
dulint undo_no;
|
||||
ulint type;
|
||||
ulint dummy;
|
||||
ibool dummy_extern;
|
||||
|
||||
ut_ad(node && node->trx);
|
||||
|
||||
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
|
||||
&dummy_extern, &undo_no, table_id);
|
||||
|
||||
node->rec_type = type;
|
||||
|
||||
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
|
||||
node->trx->dict_operation = TRUE;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Parses the row reference and other info in a fresh insert undo record. */
|
||||
static
|
||||
@@ -219,39 +277,67 @@ row_undo_ins_parse_undo_rec(
|
||||
/*========================*/
|
||||
undo_node_t* node) /* in: row undo node */
|
||||
{
|
||||
dict_index_t* clust_index;
|
||||
byte* ptr;
|
||||
dulint undo_no;
|
||||
dulint table_id;
|
||||
ulint type;
|
||||
ulint dummy;
|
||||
ibool dummy_extern;
|
||||
|
||||
ut_ad(node);
|
||||
|
||||
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
|
||||
&dummy_extern, &undo_no, &table_id);
|
||||
ut_ad(type == TRX_UNDO_INSERT_REC);
|
||||
node->rec_type = type;
|
||||
ptr = row_undo_ins_parse_rec_type_and_table_id(node, &table_id);
|
||||
|
||||
node->table = dict_table_get_on_id(table_id, node->trx);
|
||||
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC
|
||||
|| node->rec_type == TRX_UNDO_DICTIONARY_REC);
|
||||
|
||||
if (node->table == NULL) {
|
||||
if (node->rec_type == TRX_UNDO_INSERT_REC) {
|
||||
|
||||
return;
|
||||
trx_t* trx;
|
||||
ibool thawed_dictionary = FALSE;
|
||||
ibool locked_dictionary = FALSE;
|
||||
|
||||
trx = node->trx;
|
||||
|
||||
/* If it's sytem table then we have to acquire the
|
||||
dictionary lock in X mode.*/
|
||||
|
||||
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0) {
|
||||
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
|
||||
thawed_dictionary = TRUE;
|
||||
}
|
||||
|
||||
if (node->table->ibd_file_missing) {
|
||||
/* We skip undo operations to missing .ibd files */
|
||||
if (trx->dict_operation_lock_mode == 0
|
||||
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
locked_dictionary = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
node->table = dict_table_get_on_id(table_id, trx);
|
||||
|
||||
/* If we can't find the table or .ibd file is missing,
|
||||
we skip the UNDO.*/
|
||||
if (node->table == NULL || node->table->ibd_file_missing) {
|
||||
|
||||
node->table = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dict_index_t* clust_index;
|
||||
|
||||
clust_index = dict_table_get_first_index(node->table);
|
||||
|
||||
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
|
||||
node->heap);
|
||||
ptr = trx_undo_rec_get_row_ref(
|
||||
ptr, clust_index, &node->ref, node->heap);
|
||||
}
|
||||
|
||||
if (locked_dictionary) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (thawed_dictionary) {
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
@@ -265,33 +351,37 @@ row_undo_ins(
|
||||
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
|
||||
undo_node_t* node) /* in: row undo node */
|
||||
{
|
||||
dtuple_t* entry;
|
||||
ibool found;
|
||||
ulint err;
|
||||
ulint err = DB_SUCCESS;
|
||||
|
||||
ut_ad(node);
|
||||
ut_ad(node->state == UNDO_NODE_INSERT);
|
||||
|
||||
row_undo_ins_parse_undo_rec(node);
|
||||
|
||||
if (node->table == NULL) {
|
||||
found = FALSE;
|
||||
} else {
|
||||
found = row_undo_search_clust_to_pcur(node);
|
||||
}
|
||||
/* Dictionary records are undone in a separate function */
|
||||
|
||||
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
|
||||
|
||||
err = row_undo_build_dict_undo_list(node);
|
||||
|
||||
} else if (!node->table || !row_undo_search_clust_to_pcur(node)) {
|
||||
|
||||
if (!found) {
|
||||
trx_undo_rec_release(node->trx, node->undo_no);
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Iterate over all the indexes and undo the insert.*/
|
||||
|
||||
/* Skip the clustered index (the first index) */
|
||||
node->index = dict_table_get_next_index(
|
||||
dict_table_get_first_index(node->table));
|
||||
|
||||
while (node->index != NULL) {
|
||||
dtuple_t* entry;
|
||||
|
||||
entry = row_build_index_entry(node->row, node->ext,
|
||||
node->index, node->heap);
|
||||
|
||||
err = row_undo_ins_remove_sec(node->index, entry);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
@@ -303,6 +393,7 @@ row_undo_ins(
|
||||
}
|
||||
|
||||
err = row_undo_ins_remove_clust_rec(node);
|
||||
}
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
@@ -426,7 +426,15 @@ row_undo_mod_del_unmark_sec_and_undo_update(
|
||||
log_free_check();
|
||||
mtr_start(&mtr);
|
||||
|
||||
/* Check if the index was created after this transaction was
|
||||
started because then this index will not have the changes made
|
||||
by this transaction.*/
|
||||
if (*index->name != TEMP_TABLE_PREFIX) {
|
||||
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
|
||||
} else {
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fputs("InnoDB: error in sec index entry del undo in\n"
|
||||
|
||||
351
row/row0undo.c
351
row/row0undo.c
@@ -26,6 +26,7 @@ Created 1/8/1997 Heikki Tuuri
|
||||
#include "row0umod.h"
|
||||
#include "row0mysql.h"
|
||||
#include "srv0srv.h"
|
||||
#include "row0merge.h"
|
||||
|
||||
/* How to undo row operations?
|
||||
(1) For an insert, we have stored a prefix of the clustered index record
|
||||
@@ -124,6 +125,7 @@ row_undo_node_create(
|
||||
|
||||
undo->state = UNDO_NODE_FETCH_NEXT;
|
||||
undo->trx = trx;
|
||||
undo->rec_sub_type = TRX_UNDO_NULL_REC;
|
||||
|
||||
btr_pcur_init(&(undo->pcur));
|
||||
|
||||
@@ -350,3 +352,352 @@ row_undo_step(
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Parses the info in a fresh insert undo record containing a
|
||||
dictionary change. */
|
||||
static
|
||||
ulint
|
||||
row_undo_dictionary_parse_undo_rec(
|
||||
/*===============================*/
|
||||
/* out: DB_SUCCESS or DB_ERROR */
|
||||
undo_node_t* node) /* in: row undo node */
|
||||
{
|
||||
byte* ptr;
|
||||
dulint table_id;
|
||||
dulint index_id;
|
||||
ulint len;
|
||||
|
||||
ut_ad(node);
|
||||
|
||||
node->rec_type = trx_undo_rec_get_type(node->undo_rec);
|
||||
node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec);
|
||||
|
||||
ptr = trx_undo_rec_get_ptr(node->undo_rec, node->undo_no);
|
||||
|
||||
ut_a(node->rec_type == TRX_UNDO_DICTIONARY_REC);
|
||||
|
||||
/* Read dictionary rec sub type */
|
||||
node->rec_sub_type = mach_read_from_1(ptr);
|
||||
ptr++;
|
||||
|
||||
/* Parse subtype parameters */
|
||||
|
||||
switch (node->rec_sub_type) {
|
||||
|
||||
case TRX_UNDO_INDEX_CREATE_REC:
|
||||
|
||||
table_id = mach_dulint_read_much_compressed(ptr);
|
||||
len = mach_dulint_get_much_compressed_size(table_id);
|
||||
ptr += len;
|
||||
|
||||
index_id = mach_dulint_read_much_compressed(ptr);
|
||||
len = mach_dulint_get_much_compressed_size(index_id);
|
||||
ptr += len;
|
||||
|
||||
node->table = dict_table_get_on_id(table_id, node->trx);
|
||||
node->index = NULL;
|
||||
|
||||
if (!node->table) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: [Error]: Table %lu %lu not found "
|
||||
"in index create undo rec\n",
|
||||
(ulong) ut_dulint_get_high(table_id),
|
||||
(ulong) ut_dulint_get_low(table_id));
|
||||
goto err_exit;
|
||||
} else if (ut_dulint_is_zero(index_id)) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: [Error]: Index id missing from "
|
||||
"index create undo rec\n");
|
||||
err_exit:
|
||||
mutex_enter(&kernel_mutex);
|
||||
trx_print(stderr, node->trx, 1024);
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
return(DB_ERROR);
|
||||
} else {
|
||||
node->index = dict_index_get_on_id_low(
|
||||
node->table, index_id);
|
||||
}
|
||||
|
||||
if (node->table->ibd_file_missing || !node->index) {
|
||||
/* We skip undo operations to missing .ibd files
|
||||
and missing indexes */
|
||||
node->table = NULL;
|
||||
node->index = NULL;
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_CREATE_REC:
|
||||
case TRX_UNDO_TABLE_DROP_REC:
|
||||
len = strlen((char *)ptr) + 1;
|
||||
|
||||
node->new_table_name = mem_heap_strdup(node->heap, (char *)ptr);
|
||||
ptr += len;
|
||||
|
||||
ut_ad(*node->new_table_name == TEMP_TABLE_PREFIX);
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_RENAME_REC:
|
||||
len = strlen((char *)ptr) + 1;
|
||||
|
||||
node->new_table_name = mem_heap_strdup(node->heap, (char *)ptr);
|
||||
ptr += len;
|
||||
|
||||
ut_ad(*node->new_table_name == TEMP_TABLE_PREFIX);
|
||||
|
||||
len = strlen((char *)ptr) + 1;
|
||||
|
||||
node->old_table_name = mem_heap_strdup(node->heap, (char *)ptr);
|
||||
ptr += len;
|
||||
|
||||
len = strlen((char *)ptr) + 1;
|
||||
|
||||
node->tmp_table_name = mem_heap_strdup(node->heap, (char *)ptr);
|
||||
ptr += len;
|
||||
|
||||
ut_ad(*node->tmp_table_name == TEMP_TABLE_PREFIX);
|
||||
break;
|
||||
|
||||
default:
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
" InnoDB: [Error]: Undefined rec_sub_type = %lu at "
|
||||
"row_undo_dictionary_parse_undo_rec\n",
|
||||
(ulong)node->rec_sub_type);
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
trx_print(stderr, node->trx, 1024);
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Currently we gather all the information that is required to do the
|
||||
UNDO. The actual UNDO is done later in row_undo_dictionary().*/
|
||||
|
||||
ulint
|
||||
row_undo_build_dict_undo_list(
|
||||
/*==========================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
undo_node_t* node) /* in: row undo node */
|
||||
{
|
||||
trx_t* trx;
|
||||
dict_undo_t* dict_undo;
|
||||
ulint err = DB_SUCCESS;
|
||||
ibool locked_dictionary = FALSE;
|
||||
ibool thawed_dictionary = FALSE;
|
||||
|
||||
ut_ad(node);
|
||||
ut_ad(node->state == UNDO_NODE_INSERT);
|
||||
ut_a(node->trx->dict_operation);
|
||||
|
||||
err = row_undo_dictionary_parse_undo_rec(node);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
trx = node->trx;
|
||||
|
||||
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
|
||||
thawed_dictionary = TRUE;
|
||||
}
|
||||
|
||||
if (trx->dict_operation_lock_mode == 0
|
||||
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
locked_dictionary = TRUE;
|
||||
}
|
||||
|
||||
/* We will do our own deletes */
|
||||
trx->table_id = ut_dulint_create(0, 0);
|
||||
|
||||
if (trx->dict_undo_list == NULL) {
|
||||
dict_undo_create_list(trx);
|
||||
}
|
||||
|
||||
/* Create an element and append to the list */
|
||||
dict_undo = dict_undo_create_element(trx);
|
||||
|
||||
dict_undo->op_type = node->rec_sub_type;
|
||||
|
||||
switch (node->rec_sub_type) {
|
||||
|
||||
case TRX_UNDO_INDEX_CREATE_REC:
|
||||
|
||||
if (node->table && node->index) {
|
||||
ut_a(node->index->table == node->table);
|
||||
|
||||
dict_undo->data.index = node->index;
|
||||
} else {
|
||||
dict_undo->data.index = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_DROP_REC:
|
||||
case TRX_UNDO_TABLE_CREATE_REC:
|
||||
|
||||
dict_undo->data.table.old_table = dict_table_get_low(
|
||||
node->new_table_name);
|
||||
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_RENAME_REC:
|
||||
|
||||
dict_undo->data.table.old_table = dict_table_get_low(
|
||||
node->old_table_name);
|
||||
|
||||
dict_undo->data.table.tmp_table = dict_table_get_low(
|
||||
node->tmp_table_name);
|
||||
|
||||
dict_undo->data.table.new_table = dict_table_get_low(
|
||||
node->new_table_name);
|
||||
|
||||
if (dict_undo->data.table.tmp_table
|
||||
&& dict_undo->data.table.old_table
|
||||
&& dict_undo->data.table.new_table) {
|
||||
|
||||
/* This can't happen */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
ut_error;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (locked_dictionary) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (thawed_dictionary) {
|
||||
row_mysql_freeze_data_dictionary(trx);
|
||||
}
|
||||
|
||||
func_exit:
|
||||
trx_undo_rec_release(node->trx, node->undo_no);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
ulint
|
||||
row_undo_dictionary(
|
||||
/*================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_undo_t* dict_undo) /* in: dict undo info */
|
||||
{
|
||||
ulint err = DB_SUCCESS;
|
||||
|
||||
switch (dict_undo->op_type) {
|
||||
case TRX_UNDO_INDEX_CREATE_REC:
|
||||
|
||||
err = row_merge_remove_index(
|
||||
dict_undo->data.index, dict_undo->data.index->table,
|
||||
trx);
|
||||
|
||||
break;
|
||||
|
||||
/* TODO: We are REDOing the DROP ? */
|
||||
case TRX_UNDO_TABLE_DROP_REC:
|
||||
case TRX_UNDO_TABLE_CREATE_REC:
|
||||
|
||||
if (dict_undo->data.table.old_table) {
|
||||
|
||||
err = row_drop_table_for_mysql_no_commit(
|
||||
dict_undo->data.table.old_table->name,
|
||||
trx, FALSE);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_RENAME_REC:
|
||||
if (!dict_undo->data.table.new_table) {
|
||||
|
||||
/* Old name to tmp name succeeded and new name to old
|
||||
name succeeded too. We have to be very careful here as
|
||||
the user could loose the entire table if not done
|
||||
carefully.*/
|
||||
ut_ad(dict_undo->data.table.old_table);
|
||||
|
||||
err = row_rename_table_for_mysql(
|
||||
dict_undo->data.table.old_table->name,
|
||||
dict_undo->data.table.new_table->name,
|
||||
trx, FALSE);
|
||||
|
||||
if (err == DB_SUCCESS) {
|
||||
err = row_rename_table_for_mysql(
|
||||
dict_undo->data.table.tmp_table->name,
|
||||
dict_undo->data.table.old_table->name,
|
||||
trx, FALSE);
|
||||
}
|
||||
|
||||
if (err == DB_SUCCESS) {
|
||||
|
||||
err = row_drop_table_for_mysql_no_commit(
|
||||
dict_undo->data.table.new_table->name,
|
||||
trx, FALSE);
|
||||
}
|
||||
|
||||
} else if (dict_undo->data.table.old_table) {
|
||||
/* Rename to tmp failed.*/
|
||||
|
||||
ut_ad(!dict_undo->data.table.tmp_table);
|
||||
|
||||
if (dict_undo->data.table.new_table) {
|
||||
|
||||
err = row_drop_table_for_mysql_no_commit(
|
||||
dict_undo->data.table.new_table->name,
|
||||
trx, FALSE);
|
||||
}
|
||||
|
||||
} else if (dict_undo->data.table.tmp_table) {
|
||||
/* Rename to tmp was OK. We need to UNDO it.*/
|
||||
|
||||
ut_ad(!dict_undo->data.table.old_table);
|
||||
|
||||
err = row_rename_table_for_mysql(
|
||||
dict_undo->data.table.tmp_table->name,
|
||||
dict_undo->data.table.old_table->name,
|
||||
trx, FALSE);
|
||||
|
||||
if (dict_undo->data.table.new_table) {
|
||||
|
||||
err = row_drop_table_for_mysql_no_commit(
|
||||
dict_undo->data.table.new_table->name,
|
||||
trx, FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Shouldn't happen */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
510
trx/trx0rec.c
510
trx/trx0rec.c
@@ -130,6 +130,105 @@ trx_undo_left(
|
||||
return(UNIV_PAGE_SIZE - (ptr - page) - 10 - FIL_PAGE_DATA_END);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Get the pointer to where the data for the undo log record will be written.*/
|
||||
static
|
||||
byte*
|
||||
trx_undo_page_get_ptr(
|
||||
/*==================*/
|
||||
/* out: ptr to where the undo log
|
||||
record data will be written,
|
||||
0 if not enough space.*/
|
||||
page_t* undo_page, /* in: undo log page */
|
||||
ulint need) /* in: need these man bytes */
|
||||
{
|
||||
byte* ptr; /* pointer within undo_page */
|
||||
ulint first_free; /* offset within undo page */
|
||||
|
||||
ut_ad(undo_page);
|
||||
|
||||
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
|
||||
+ TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
|
||||
|
||||
first_free = mach_read_from_2(
|
||||
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE);
|
||||
|
||||
/* Start writing the undo information from the first free
|
||||
bytes in the undo page */
|
||||
ptr = undo_page + first_free;
|
||||
|
||||
ut_ad(first_free <= UNIV_PAGE_SIZE);
|
||||
|
||||
/* NOTE: the value need must be big enough such that the
|
||||
general fields written below fit on the undo log page */
|
||||
|
||||
if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < need)) {
|
||||
|
||||
/* Error, not enough space */
|
||||
ptr = 0;
|
||||
|
||||
} else {
|
||||
/* Reserve 2 bytes for the pointer to the next undo log
|
||||
record */
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Set the next and previous pointers in the undo page for the undo record
|
||||
that was written to ptr. Update the first free value by the number of bytes
|
||||
written for this undo record.*/
|
||||
static
|
||||
ulint
|
||||
trx_undo_page_set_next_prev_and_add(
|
||||
/*================================*/
|
||||
/* out: offset of the inserted entry
|
||||
on the page if succeeded, 0 if fail */
|
||||
page_t* undo_page, /* in/out: undo log page */
|
||||
byte* ptr, /* in: ptr up to where data has been
|
||||
written on this undo page. */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ulint first_free; /* offset within undo_page */
|
||||
ulint end_of_rec; /* offset within undo_page */
|
||||
byte* ptr_to_first_free;
|
||||
/* pointer within undo_page
|
||||
that points to the next free
|
||||
offset value within undo_page.*/
|
||||
|
||||
ut_ad(ptr > undo_page);
|
||||
ut_ad(ptr < undo_page + UNIV_PAGE_SIZE);
|
||||
|
||||
if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < 2)) {
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
ptr_to_first_free = undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE;
|
||||
|
||||
first_free = mach_read_from_2(ptr_to_first_free);
|
||||
|
||||
/* Write offset of the previous undo log record */
|
||||
mach_write_to_2(ptr, first_free);
|
||||
ptr += 2;
|
||||
|
||||
end_of_rec = ptr - undo_page;
|
||||
|
||||
/* Write offset of the next undo log record */
|
||||
mach_write_to_2(undo_page + first_free, end_of_rec);
|
||||
|
||||
/* Update the offset to first free undo record */
|
||||
mach_write_to_2(ptr_to_first_free, end_of_rec);
|
||||
|
||||
/* Write this log entry to the UNDO log */
|
||||
trx_undof_page_add_undo_rec_log(undo_page, first_free,
|
||||
end_of_rec, mtr);
|
||||
|
||||
return(first_free);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Reports in the undo log of an insert of a clustered index record. */
|
||||
static
|
||||
@@ -147,9 +246,6 @@ trx_undo_page_report_insert(
|
||||
{
|
||||
ulint first_free;
|
||||
byte* ptr;
|
||||
ulint len;
|
||||
const dfield_t* field;
|
||||
ulint flen;
|
||||
ulint i;
|
||||
|
||||
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
|
||||
@@ -172,31 +268,24 @@ trx_undo_page_report_insert(
|
||||
ptr += 2;
|
||||
|
||||
/* Store first some general parameters to the undo log */
|
||||
mach_write_to_1(ptr, TRX_UNDO_INSERT_REC);
|
||||
ptr++;
|
||||
|
||||
len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
ptr += len;
|
||||
|
||||
len = mach_dulint_write_much_compressed(ptr, (index->table)->id);
|
||||
ptr += len;
|
||||
*ptr++ = TRX_UNDO_INSERT_REC;
|
||||
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
|
||||
/*----------------------------------------*/
|
||||
/* Store then the fields required to uniquely determine the record
|
||||
to be inserted in the clustered index */
|
||||
|
||||
for (i = 0; i < dict_index_get_n_unique(index); i++) {
|
||||
|
||||
field = dtuple_get_nth_field(clust_entry, i);
|
||||
|
||||
flen = dfield_get_len(field);
|
||||
const dfield_t* field = dtuple_get_nth_field(clust_entry, i);
|
||||
ulint flen = dfield_get_len(field);
|
||||
|
||||
if (trx_undo_left(undo_page, ptr) < 5) {
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
len = mach_write_compressed(ptr, flen);
|
||||
ptr += len;
|
||||
ptr += mach_write_compressed(ptr, flen);
|
||||
|
||||
if (flen != UNIV_SQL_NULL) {
|
||||
if (trx_undo_left(undo_page, ptr) < flen) {
|
||||
@@ -209,27 +298,192 @@ trx_undo_page_report_insert(
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------*/
|
||||
/* Write pointers to the previous and the next undo log records */
|
||||
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||
}
|
||||
|
||||
if (trx_undo_left(undo_page, ptr) < 2) {
|
||||
/**************************************************************************
|
||||
Reports in the undo log of an index create */
|
||||
static
|
||||
ulint
|
||||
trx_undo_page_report_index_create(
|
||||
/*==============================*/
|
||||
/* out: offset of the inserted entry
|
||||
on the page if succeed, 0 if fail */
|
||||
page_t* undo_page, /* in: undo log page */
|
||||
trx_t* trx, /* in: transaction */
|
||||
dict_index_t* index, /* in: index */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
byte* ptr;
|
||||
|
||||
ut_ad(undo_page && trx && index && mtr);
|
||||
|
||||
/* Get the pointer to where we will write our undo data. */
|
||||
|
||||
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + 11 + 11);
|
||||
|
||||
if (UNIV_UNLIKELY(!ptr)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
mach_write_to_2(ptr, first_free);
|
||||
ptr += 2;
|
||||
/* This is our internal dictionary undo log record. */
|
||||
*ptr++ = TRX_UNDO_DICTIONARY_REC;
|
||||
|
||||
mach_write_to_2(undo_page + first_free, ptr - undo_page);
|
||||
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
|
||||
mach_write_to_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE,
|
||||
ptr - undo_page);
|
||||
/* The sub type (discriminator) of this undo dictionary record */
|
||||
*ptr++ = TRX_UNDO_INDEX_CREATE_REC;
|
||||
|
||||
/* Write the log entry to the REDO log of this change in the UNDO
|
||||
log */
|
||||
trx_undof_page_add_undo_rec_log(undo_page, first_free,
|
||||
ptr - undo_page, mtr);
|
||||
return(first_free);
|
||||
/* For index create, we need both the table id and the index id
|
||||
to be stored in the undo log record.*/
|
||||
|
||||
ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
|
||||
ptr += mach_dulint_write_much_compressed(ptr, index->id);
|
||||
|
||||
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Reports in the undo log of a table create */
|
||||
static
|
||||
ulint
|
||||
trx_undo_page_report_table_create(
|
||||
/*==============================*/
|
||||
/* out: offset of the inserted entry
|
||||
on the page if succeed, 0 if fail */
|
||||
page_t* undo_page, /* in: undo log page */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* table_name, /* in: table name */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
byte* ptr;
|
||||
ulint name_len;
|
||||
|
||||
ut_ad(undo_page && trx && table_name && mtr);
|
||||
|
||||
name_len = strlen(table_name) + 1;
|
||||
|
||||
/* Get the pointer to where we will write our undo data */
|
||||
|
||||
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + name_len);
|
||||
|
||||
if (UNIV_UNLIKELY(!ptr)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* The type (discriminator) of this undo log */
|
||||
*ptr++ = TRX_UNDO_DICTIONARY_REC;
|
||||
|
||||
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
|
||||
/* The sub type (discriminator) of this dictionary undo log */
|
||||
*ptr++ = TRX_UNDO_TABLE_CREATE_REC;
|
||||
|
||||
/* For table create we need to store table name */
|
||||
memcpy(ptr, table_name, name_len);
|
||||
ptr += name_len;
|
||||
|
||||
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Reports in the undo log of a table drop */
|
||||
static
|
||||
ulint
|
||||
trx_undo_page_report_table_drop(
|
||||
/*============================*/
|
||||
/* out: offset of the inserted entry
|
||||
on the page if succeed, 0 if fail */
|
||||
page_t* undo_page, /* in: undo log page */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* table_name, /* in: table name */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
byte* ptr;
|
||||
ulint name_len;
|
||||
|
||||
ut_ad(undo_page && trx && table_name && mtr);
|
||||
|
||||
name_len = strlen(table_name) + 1;
|
||||
|
||||
/* Get the pointer to where we will write our undo data */
|
||||
|
||||
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + name_len);
|
||||
|
||||
if (UNIV_UNLIKELY(!ptr)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
*ptr++ = TRX_UNDO_DICTIONARY_REC;
|
||||
|
||||
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
|
||||
/* The sub type (discriminator) of this dictionary undo log */
|
||||
*ptr++ = TRX_UNDO_TABLE_DROP_REC;
|
||||
|
||||
/* For table drop we need to store a table name */
|
||||
memcpy(ptr, table_name, name_len);
|
||||
ptr += name_len;
|
||||
|
||||
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Reports in the undo log of a table rename */
|
||||
static
|
||||
ulint
|
||||
trx_undo_page_report_table_rename(
|
||||
/*==============================*/
|
||||
/* out: offset of the inserted entry
|
||||
on the page if succeed, 0 if fail */
|
||||
page_t* undo_page, /* in: undo log page */
|
||||
trx_t* trx, /* in: transaction */
|
||||
const char* new_table_name, /* in: new table name */
|
||||
const char* old_table_name, /* in: old table name */
|
||||
const char* tmp_table_name, /* in: the temp name */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
byte* ptr;
|
||||
ulint new_name_len;
|
||||
ulint old_name_len;
|
||||
ulint tmp_name_len;
|
||||
|
||||
ut_ad(undo_page && trx && new_table_name && old_table_name && mtr);
|
||||
|
||||
new_name_len = strlen(new_table_name) + 1;
|
||||
old_name_len = strlen(old_table_name) + 1;
|
||||
tmp_name_len = strlen(tmp_table_name) + 1;
|
||||
|
||||
/* Get the pointer to where we will write our undo data. */
|
||||
|
||||
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1
|
||||
+ new_name_len + old_name_len
|
||||
+ tmp_name_len);
|
||||
|
||||
if (UNIV_UNLIKELY(!ptr)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* The type (discriminator) of this undo log */
|
||||
*ptr++ = TRX_UNDO_DICTIONARY_REC;
|
||||
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||
|
||||
/* The sub type (discriminator) of this dictionary undo log */
|
||||
*ptr++ = TRX_UNDO_TABLE_RENAME_REC;
|
||||
|
||||
/* For table rename we need to store the new table name and
|
||||
the old table name */
|
||||
|
||||
memcpy(ptr, new_table_name, new_name_len);
|
||||
ptr += new_name_len;
|
||||
|
||||
memcpy(ptr, old_table_name, old_name_len);
|
||||
ptr += old_name_len;
|
||||
|
||||
memcpy(ptr, tmp_table_name, tmp_name_len);
|
||||
ptr += tmp_name_len;
|
||||
|
||||
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -251,7 +505,6 @@ trx_undo_rec_get_pars(
|
||||
dulint* table_id) /* out: table id */
|
||||
{
|
||||
byte* ptr;
|
||||
ulint len;
|
||||
ulint type_cmpl;
|
||||
|
||||
ptr = undo_rec + 2;
|
||||
@@ -270,12 +523,10 @@ trx_undo_rec_get_pars(
|
||||
*cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
|
||||
|
||||
*undo_no = mach_dulint_read_much_compressed(ptr);
|
||||
len = mach_dulint_get_much_compressed_size(*undo_no);
|
||||
ptr += len;
|
||||
ptr += mach_dulint_get_much_compressed_size(*undo_no);
|
||||
|
||||
*table_id = mach_dulint_read_much_compressed(ptr);
|
||||
len = mach_dulint_get_much_compressed_size(*table_id);
|
||||
ptr += len;
|
||||
ptr += mach_dulint_get_much_compressed_size(*table_id);
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
@@ -671,8 +922,6 @@ trx_undo_update_rec_get_sys_cols(
|
||||
dulint* roll_ptr, /* out: roll ptr */
|
||||
ulint* info_bits) /* out: info bits state */
|
||||
{
|
||||
ulint len;
|
||||
|
||||
/* Read the state of the info bits */
|
||||
*info_bits = mach_read_from_1(ptr);
|
||||
ptr += 1;
|
||||
@@ -680,12 +929,10 @@ trx_undo_update_rec_get_sys_cols(
|
||||
/* Read the values of the system columns */
|
||||
|
||||
*trx_id = mach_dulint_read_compressed(ptr);
|
||||
len = mach_dulint_get_compressed_size(*trx_id);
|
||||
ptr += len;
|
||||
ptr += mach_dulint_get_compressed_size(*trx_id);
|
||||
|
||||
*roll_ptr = mach_dulint_read_compressed(ptr);
|
||||
len = mach_dulint_get_compressed_size(*roll_ptr);
|
||||
ptr += len;
|
||||
ptr += mach_dulint_get_compressed_size(*roll_ptr);
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
@@ -1142,6 +1389,189 @@ trx_undo_report_row_operation(
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Writes information to an undo log about dictionary operation e.g.
|
||||
rename_table, create_table, create_index, drop table. This information
|
||||
is used in a rollback of the transaction. */
|
||||
|
||||
ulint
|
||||
trx_undo_report_dict_operation(
|
||||
/*===========================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
|
||||
TRX_UNDO_TABLE_RENAME_OP,
|
||||
TRX_UNDO_TABLE_DROP_OP, or
|
||||
TRX_UNDO_INDEX_CREATE_OP */
|
||||
trx_t* trx, /* in: trx */
|
||||
dict_index_t* index, /* in:
|
||||
if TRX_UNDO_INDEX_CREATE_OP
|
||||
index to be created*/
|
||||
const char* table_name, /* in: table name or NULL, used in
|
||||
create table, rename table and
|
||||
drop table*/
|
||||
const char* old_table_name, /* in: old table name or NULL.
|
||||
used in rename table */
|
||||
const char* tmp_table_name, /* in: the intermediate name used
|
||||
for renaming */
|
||||
dulint* roll_ptr) /* out: rollback pointer to the
|
||||
inserted undo log record */
|
||||
{
|
||||
trx_undo_t* undo;
|
||||
buf_block_t* undo_block;
|
||||
ulint offset;
|
||||
ulint page_no;
|
||||
trx_rseg_t* rseg;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(trx);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
switch (op_type) {
|
||||
case TRX_UNDO_TABLE_RENAME_OP:
|
||||
ut_ad(old_table_name);
|
||||
case TRX_UNDO_TABLE_DROP_OP:
|
||||
case TRX_UNDO_TABLE_CREATE_OP:
|
||||
ut_ad(table_name);
|
||||
break;
|
||||
|
||||
case TRX_UNDO_INDEX_CREATE_OP:
|
||||
ut_ad(index);
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
#endif
|
||||
|
||||
rseg = trx->rseg;
|
||||
|
||||
mutex_enter(&(trx->undo_mutex));
|
||||
|
||||
/* If the undo log is not assigned yet, assign one */
|
||||
|
||||
if (trx->insert_undo == NULL) {
|
||||
|
||||
trx_undo_assign_undo(trx, TRX_UNDO_INSERT);
|
||||
}
|
||||
|
||||
undo = trx->insert_undo;
|
||||
|
||||
if (undo == NULL) {
|
||||
/* Did not succeed: out of space */
|
||||
mutex_exit(&(trx->undo_mutex));
|
||||
|
||||
return(DB_OUT_OF_FILE_SPACE);
|
||||
}
|
||||
|
||||
page_no = undo->last_page_no;
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
for (;;) {
|
||||
undo_block = buf_page_get_gen(undo->space, undo->zip_size,
|
||||
page_no, RW_X_LATCH,
|
||||
undo->guess_block, BUF_GET,
|
||||
__FILE__, __LINE__, &mtr);
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
switch (op_type) {
|
||||
|
||||
case TRX_UNDO_TABLE_CREATE_OP:
|
||||
offset = trx_undo_page_report_table_create(
|
||||
undo_block->frame, trx, table_name, &mtr);
|
||||
break;
|
||||
|
||||
case TRX_UNDO_INDEX_CREATE_OP:
|
||||
offset = trx_undo_page_report_index_create(
|
||||
undo_block->frame, trx, index, &mtr);
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_RENAME_OP:
|
||||
offset = trx_undo_page_report_table_rename(
|
||||
undo_block->frame, trx, table_name,
|
||||
old_table_name, tmp_table_name, &mtr);
|
||||
break;
|
||||
|
||||
case TRX_UNDO_TABLE_DROP_OP:
|
||||
offset = trx_undo_page_report_table_drop(
|
||||
undo_block->frame, trx, table_name, &mtr);
|
||||
break;
|
||||
|
||||
default:
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: [Error]: Undefined op_type = %lu "
|
||||
"at trx_undo_report_dict_operation\n",
|
||||
(ulong) op_type);
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
trx_print(stderr, trx, 1024);
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
/* The record did not fit on the page. We erase the
|
||||
end segment of the undo log page and write a log
|
||||
record of it: this is to ensure that in the debug
|
||||
version the replicate page constructed using the log
|
||||
records stays identical to the original page */
|
||||
|
||||
trx_undo_erase_page_end(undo_block->frame, &mtr);
|
||||
}
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
if (offset != 0) {
|
||||
/* Success */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ut_ad(page_no == undo->last_page_no);
|
||||
|
||||
/* We have to extend the undo log by one page */
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
/* When we add a page to an undo log, this is analogous to
|
||||
a pessimistic insert in a B-tree, and we must reserve the
|
||||
counterpart of the tree latch, which is the rseg mutex. */
|
||||
|
||||
mutex_enter(&(rseg->mutex));
|
||||
|
||||
page_no = trx_undo_add_page(trx, undo, &mtr);
|
||||
|
||||
mutex_exit(&(rseg->mutex));
|
||||
|
||||
if (page_no == FIL_NULL) {
|
||||
/* Did not succeed: out of space */
|
||||
|
||||
mutex_exit(&(trx->undo_mutex));
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(DB_OUT_OF_FILE_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
undo->empty = FALSE;
|
||||
undo->top_page_no = page_no;
|
||||
undo->top_offset = offset;
|
||||
undo->top_undo_no = trx->undo_no;
|
||||
undo->guess_block = undo_block;
|
||||
|
||||
UT_DULINT_INC(trx->undo_no);
|
||||
|
||||
mutex_exit(&(trx->undo_mutex));
|
||||
|
||||
*roll_ptr = trx_undo_build_roll_ptr(TRUE, rseg->id, page_no, offset);
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
@@ -425,7 +425,8 @@ trx_rollback_or_clean_all_without_sess(
|
||||
dict_table_t* table;
|
||||
ib_longlong rows_to_undo;
|
||||
const char* unit = "";
|
||||
int err;
|
||||
int err = DB_SUCCESS;
|
||||
ibool dictionary_locked = FALSE;
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
@@ -530,8 +531,10 @@ loop:
|
||||
|
||||
trx->mysql_process_no = os_proc_get_number();
|
||||
|
||||
/* TODO: Doesn't seem right */
|
||||
if (trx->dict_operation) {
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
dictionary_locked = TRUE;
|
||||
}
|
||||
|
||||
que_run_threads(thr);
|
||||
@@ -552,7 +555,8 @@ loop:
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (trx->dict_operation) {
|
||||
if (trx->dict_operation && !ut_dulint_is_zero(trx->table_id)) {
|
||||
|
||||
/* If the transaction was for a dictionary operation, we
|
||||
drop the relevant table, if it still exists */
|
||||
|
||||
@@ -573,9 +577,35 @@ loop:
|
||||
|
||||
ut_a(err == (int) DB_SUCCESS);
|
||||
}
|
||||
} else if (trx->dict_undo_list) {
|
||||
|
||||
dict_undo_t* dict_undo;
|
||||
|
||||
ut_a(trx->dict_undo_list);
|
||||
|
||||
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
|
||||
|
||||
fputs("InnoDB: UNDO dict entries\n", stderr);
|
||||
|
||||
while (dict_undo && err == DB_SUCCESS) {
|
||||
|
||||
dict_undo = UT_LIST_GET_NEXT(node, dict_undo);
|
||||
|
||||
if (dict_undo) {
|
||||
err = row_undo_dictionary(trx, dict_undo);
|
||||
}
|
||||
}
|
||||
|
||||
if (trx->dict_operation) {
|
||||
ut_a(err == (int) DB_SUCCESS);
|
||||
|
||||
dict_undo_free_list(trx);
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
trx_commit_off_kernel(trx);
|
||||
mutex_exit(&kernel_mutex);
|
||||
}
|
||||
|
||||
if (dictionary_locked) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
@@ -1245,7 +1275,11 @@ trx_finish_rollback_off_kernel(
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/* If there are dict UNDO records that need to be undone then
|
||||
we commit the transaction after these dictionary changes are undone.*/
|
||||
if (!trx->dict_undo_list) {
|
||||
trx_commit_off_kernel(trx);
|
||||
}
|
||||
|
||||
/* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and
|
||||
send reply messages to them */
|
||||
|
||||
@@ -127,6 +127,10 @@ trx_create(
|
||||
trx->must_flush_log_later = FALSE;
|
||||
|
||||
trx->dict_operation = FALSE;
|
||||
trx->table_id = ut_dulint_create(0, 0);
|
||||
trx->dict_undo_list = NULL;
|
||||
trx->dict_redo_list = NULL;
|
||||
trx->sync_cb = NULL;
|
||||
|
||||
trx->mysql_thd = NULL;
|
||||
trx->mysql_query_str = NULL;
|
||||
@@ -153,6 +157,7 @@ trx_create(
|
||||
trx->undo_no_arr = NULL;
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
trx->error_key_num = 0;
|
||||
trx->detailed_error[0] = '\0';
|
||||
|
||||
trx->sess = sess;
|
||||
@@ -349,6 +354,8 @@ trx_free(
|
||||
trx->global_read_view = NULL;
|
||||
|
||||
ut_a(trx->read_view == NULL);
|
||||
ut_a(trx->dict_undo_list == NULL);
|
||||
ut_a(trx->dict_redo_list == NULL);
|
||||
|
||||
mem_free(trx);
|
||||
}
|
||||
@@ -740,6 +747,10 @@ trx_commit_off_kernel(
|
||||
|
||||
ut_ad(mutex_own(&kernel_mutex));
|
||||
|
||||
/* Can't commit if we have dictionary UNDO records */
|
||||
ut_a(!trx->dict_undo_list);
|
||||
ut_a(!trx->dict_redo_list);
|
||||
|
||||
trx->must_flush_log_later = FALSE;
|
||||
|
||||
rseg = trx->rseg;
|
||||
@@ -1558,6 +1569,14 @@ trx_commit_for_mysql(
|
||||
|
||||
ut_a(trx);
|
||||
|
||||
if (trx->sync_cb) {
|
||||
ulint err;
|
||||
|
||||
err = trx->sync_cb(trx, TRUE);
|
||||
ut_a(err);
|
||||
trx->sync_cb = NULL;
|
||||
}
|
||||
|
||||
trx->op_info = "committing";
|
||||
|
||||
/* If we are doing the XA recovery of prepared transactions, then
|
||||
|
||||
Reference in New Issue
Block a user