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;
|
const byte* data;
|
||||||
ulint len;
|
ulint len;
|
||||||
ulint mtype;
|
ulint mtype;
|
||||||
|
ulint prtype;
|
||||||
ulint i;
|
ulint i;
|
||||||
ibool print_also_hex;
|
ibool print_also_hex;
|
||||||
|
|
||||||
@@ -396,6 +397,7 @@ dfield_print_also_hex(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mtype = dtype_get_mtype(dfield_get_type(dfield));
|
mtype = dtype_get_mtype(dfield_get_type(dfield));
|
||||||
|
prtype = dtype_get_prtype(dfield_get_type(dfield));
|
||||||
|
|
||||||
if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
|
if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
|
||||||
|
|
||||||
@@ -403,11 +405,14 @@ dfield_print_also_hex(
|
|||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
int c = *data++;
|
int c = *data++;
|
||||||
|
|
||||||
if (!isprint(c)) {
|
if (!isprint(c)) {
|
||||||
print_also_hex = TRUE;
|
print_also_hex = TRUE;
|
||||||
c = ' ';
|
|
||||||
|
fprintf(stderr, "\\x%02x", (unsigned char) c);
|
||||||
|
} else {
|
||||||
|
putc(c, stderr);
|
||||||
}
|
}
|
||||||
putc(c, stderr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!print_also_hex) {
|
if (!print_also_hex) {
|
||||||
@@ -422,13 +427,122 @@ dfield_print_also_hex(
|
|||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
fprintf(stderr, "%02lx", (ulint)*data);
|
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++;
|
data++;
|
||||||
}
|
}
|
||||||
} else if (mtype == DATA_INT) {
|
} else if (mtype == DATA_INT) {
|
||||||
ut_a(len == 4); /* only works for 32-bit integers */
|
dulint big_val;
|
||||||
fprintf(stderr, "%d", (int)mach_read_from_4(data));
|
|
||||||
|
if (len == 1) {
|
||||||
|
ulint val;
|
||||||
|
|
||||||
|
val = (ulint)mach_read_from_1(data);
|
||||||
|
|
||||||
|
if (!(prtype & DATA_UNSIGNED)) {
|
||||||
|
val &= ~0x80;
|
||||||
|
fprintf(stderr, "%ld", (long) val);
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
ut_error;
|
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)
|
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
|
||||||
|| dict_index_is_clust(index));
|
|| dict_index_is_clust(index));
|
||||||
|
|
||||||
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
|
/* 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
|
/* Inherit the space id from the table; we store all indexes of a
|
||||||
table in the same tablespace */
|
table in the same tablespace */
|
||||||
@@ -552,6 +556,9 @@ dict_build_index_def_step(
|
|||||||
|
|
||||||
ins_node_set_new_row(node->ind_def, row);
|
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);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
657
dict/dict0dict.c
657
dict/dict0dict.c
@@ -26,6 +26,7 @@ Created 1/8/1996 Heikki Tuuri
|
|||||||
#include "pars0sym.h"
|
#include "pars0sym.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "rem0cmp.h"
|
#include "rem0cmp.h"
|
||||||
|
#include "row0merge.h"
|
||||||
#ifndef UNIV_HOTBACKUP
|
#ifndef UNIV_HOTBACKUP
|
||||||
# include "m_ctype.h" /* my_isspace() */
|
# include "m_ctype.h" /* my_isspace() */
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#endif /* !UNIV_HOTBACKUP */
|
||||||
@@ -366,19 +367,6 @@ dict_table_get_next_index_noninline(
|
|||||||
return(dict_table_get_next_index(index));
|
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. */
|
Returns a column's name. */
|
||||||
|
|
||||||
@@ -539,6 +527,33 @@ dict_table_autoinc_update(
|
|||||||
mutex_exit(&(table->autoinc_mutex));
|
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. */
|
Looks for column n in an index. */
|
||||||
|
|
||||||
@@ -806,7 +821,7 @@ dict_table_get(
|
|||||||
does not exist */
|
does not exist */
|
||||||
const char* table_name, /* in: table name */
|
const char* table_name, /* in: table name */
|
||||||
ibool inc_mysql_count)
|
ibool inc_mysql_count)
|
||||||
/* in: whether to increment the open
|
/* in: whether to increment the open
|
||||||
handle count on the table */
|
handle count on the table */
|
||||||
{
|
{
|
||||||
dict_table_t* table;
|
dict_table_t* table;
|
||||||
@@ -1358,20 +1373,6 @@ dict_index_add_to_cache(
|
|||||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
||||||
|
|
||||||
ut_ad(mem_heap_validate(index->heap));
|
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_a(!dict_index_is_clust(index)
|
||||||
|| UT_LIST_GET_LEN(table->indexes) == 0);
|
|| 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;
|
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);
|
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
|
||||||
|
|
||||||
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
|
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. */
|
/* It is an error not to find a matching column. */
|
||||||
ut_error;
|
ut_error;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1873,18 +1877,92 @@ dict_index_build_internal_non_clust(
|
|||||||
Checks if a table is referenced by foreign keys. */
|
Checks if a table is referenced by foreign keys. */
|
||||||
|
|
||||||
ibool
|
ibool
|
||||||
dict_table_referenced_by_foreign_key(
|
dict_table_is_referenced_by_foreign_key(
|
||||||
/*=================================*/
|
/*====================================*/
|
||||||
/* out: TRUE if table is referenced by a
|
/* out: TRUE if table is referenced
|
||||||
foreign key */
|
by a foreign key */
|
||||||
dict_table_t* table) /* in: InnoDB table */
|
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,
|
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
|
static
|
||||||
dict_index_t*
|
dict_index_t*
|
||||||
dict_foreign_find_index(
|
dict_foreign_find_index(
|
||||||
@@ -1986,16 +2065,23 @@ dict_foreign_find_index(
|
|||||||
be declared NOT NULL */
|
be declared NOT NULL */
|
||||||
{
|
{
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
dict_field_t* field;
|
|
||||||
const char* col_name;
|
|
||||||
ulint i;
|
|
||||||
|
|
||||||
index = dict_table_get_first_index(table);
|
index = dict_table_get_first_index(table);
|
||||||
|
|
||||||
while (index != NULL) {
|
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++) {
|
for (i = 0; i < n_cols; i++) {
|
||||||
|
dict_field_t* field;
|
||||||
|
const char* col_name;
|
||||||
|
|
||||||
field = dict_index_get_nth_field(index, i);
|
field = dict_index_get_nth_field(index, i);
|
||||||
|
|
||||||
col_name = dict_table_get_col_name(
|
col_name = dict_table_get_col_name(
|
||||||
@@ -2036,12 +2122,73 @@ dict_foreign_find_index(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_rec:
|
||||||
index = dict_table_get_next_index(index);
|
index = dict_table_get_next_index(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(NULL);
|
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. */
|
Report an error in a foreign key definition. */
|
||||||
static
|
static
|
||||||
@@ -4013,6 +4160,7 @@ dict_index_print_low(
|
|||||||
{
|
{
|
||||||
ib_longlong n_vals;
|
ib_longlong n_vals;
|
||||||
ulint i;
|
ulint i;
|
||||||
|
const char* type_string;
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
@@ -4023,6 +4171,14 @@ dict_index_print_low(
|
|||||||
n_vals = index->stat_n_diff_key_vals[1];
|
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,
|
fprintf(stderr,
|
||||||
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
|
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
|
||||||
" uniq %lu, type %lu\n"
|
" uniq %lu, type %lu\n"
|
||||||
@@ -4261,6 +4417,7 @@ dict_print_info_on_foreign_keys(
|
|||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
Displays the names of the index and the table. */
|
Displays the names of the index and the table. */
|
||||||
|
|
||||||
void
|
void
|
||||||
dict_index_name_print(
|
dict_index_name_print(
|
||||||
/*==================*/
|
/*==================*/
|
||||||
@@ -4273,3 +4430,417 @@ dict_index_name_print(
|
|||||||
fputs(" of table ", file);
|
fputs(" of table ", file);
|
||||||
ut_print_name(file, trx, TRUE, index->table_name);
|
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);
|
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. */
|
Loads definitions for index fields. */
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
dict_load_fields(
|
dict_load_fields(
|
||||||
/*=============*/
|
/*=============*/
|
||||||
dict_table_t* table, /* in: table */
|
|
||||||
dict_index_t* index, /* in: index whose fields to load */
|
dict_index_t* index, /* in: index whose fields to load */
|
||||||
mem_heap_t* heap) /* in: memory heap for temporary storage */
|
mem_heap_t* heap) /* in: memory heap for temporary storage */
|
||||||
{
|
{
|
||||||
@@ -543,13 +523,18 @@ dict_load_fields(
|
|||||||
rec = btr_pcur_get_rec(&pcur);
|
rec = btr_pcur_get_rec(&pcur);
|
||||||
|
|
||||||
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
|
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)) {
|
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);
|
field = rec_get_nth_field_old(rec, 0, &len);
|
||||||
ut_ad(len == 8);
|
ut_ad(len == 8);
|
||||||
ut_a(ut_memcmp(buf, field, len) == 0);
|
|
||||||
|
|
||||||
field = rec_get_nth_field_old(rec, 1, &len);
|
field = rec_get_nth_field_old(rec, 1, &len);
|
||||||
ut_a(len == 4);
|
ut_a(len == 4);
|
||||||
@@ -584,6 +569,7 @@ dict_load_fields(
|
|||||||
(char*) field, len),
|
(char*) field, len),
|
||||||
prefix_len);
|
prefix_len);
|
||||||
|
|
||||||
|
next_rec:
|
||||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,16 +648,9 @@ dict_load_indexes(
|
|||||||
|
|
||||||
if (ut_memcmp(buf, field, len) != 0) {
|
if (ut_memcmp(buf, field, len) != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
} else if (rec_get_deleted_flag(rec, 0)) {
|
||||||
|
/* Skip delete marked records */
|
||||||
if (rec_get_deleted_flag(rec, 0)) {
|
goto next_rec;
|
||||||
dict_load_report_deleted_index(table->name,
|
|
||||||
ULINT_UNDEFINED);
|
|
||||||
|
|
||||||
btr_pcur_close(&pcur);
|
|
||||||
mtr_commit(&mtr);
|
|
||||||
|
|
||||||
return(FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
field = rec_get_nth_field_old(rec, 1, &len);
|
field = rec_get_nth_field_old(rec, 1, &len);
|
||||||
@@ -714,12 +693,15 @@ dict_load_indexes(
|
|||||||
if ((type & DICT_CLUSTERED) == 0
|
if ((type & DICT_CLUSTERED) == 0
|
||||||
&& NULL == dict_table_get_first_index(table)) {
|
&& NULL == dict_table_get_first_index(table)) {
|
||||||
|
|
||||||
fprintf(stderr,
|
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||||
"InnoDB: Error: trying to load index %s"
|
|
||||||
" for table %s\n"
|
fprintf(stderr,
|
||||||
"InnoDB: but the first index"
|
"InnoDB: Error: trying to"
|
||||||
" is not clustered!\n",
|
" load index %s for table %s\n"
|
||||||
name_buf, table->name);
|
"InnoDB: but the first index"
|
||||||
|
" is not clustered!\n",
|
||||||
|
name_buf, table->name);
|
||||||
|
}
|
||||||
|
|
||||||
btr_pcur_close(&pcur);
|
btr_pcur_close(&pcur);
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
@@ -741,10 +723,11 @@ dict_load_indexes(
|
|||||||
space, type, n_fields);
|
space, type, n_fields);
|
||||||
index->id = id;
|
index->id = id;
|
||||||
|
|
||||||
dict_load_fields(table, index, heap);
|
dict_load_fields(index, heap);
|
||||||
dict_index_add_to_cache(table, index, page_no);
|
dict_index_add_to_cache(table, index, page_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_rec:
|
||||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
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->n_foreign_key_checks_running = 0;
|
||||||
|
|
||||||
table->cached = FALSE;
|
table->cached = FALSE;
|
||||||
|
table->to_be_dropped = 0;
|
||||||
|
|
||||||
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
||||||
* sizeof(dict_col_t));
|
* sizeof(dict_col_t));
|
||||||
@@ -75,6 +76,7 @@ dict_mem_table_create(
|
|||||||
UT_LIST_INIT(table->locks);
|
UT_LIST_INIT(table->locks);
|
||||||
UT_LIST_INIT(table->foreign_list);
|
UT_LIST_INIT(table->foreign_list);
|
||||||
UT_LIST_INIT(table->referenced_list);
|
UT_LIST_INIT(table->referenced_list);
|
||||||
|
UT_LIST_INIT(table->prebuilts);
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
table->does_not_fit_in_memory = FALSE;
|
table->does_not_fit_in_memory = FALSE;
|
||||||
@@ -236,6 +238,7 @@ dict_mem_index_create(
|
|||||||
heap = mem_heap_create(DICT_HEAP_SIZE);
|
heap = mem_heap_create(DICT_HEAP_SIZE);
|
||||||
index = mem_heap_alloc(heap, sizeof(dict_index_t));
|
index = mem_heap_alloc(heap, sizeof(dict_index_t));
|
||||||
|
|
||||||
|
index->id = ut_dulint_create(0, 0);
|
||||||
index->heap = heap;
|
index->heap = heap;
|
||||||
|
|
||||||
index->type = type;
|
index->type = type;
|
||||||
@@ -253,6 +256,8 @@ dict_mem_index_create(
|
|||||||
index->stat_n_diff_key_vals = NULL;
|
index->stat_n_diff_key_vals = NULL;
|
||||||
|
|
||||||
index->cached = FALSE;
|
index->cached = FALSE;
|
||||||
|
index->to_be_dropped = FALSE;
|
||||||
|
index->trx_id = ut_dulint_create(0, 0);
|
||||||
memset(&index->lock, 0, sizeof index->lock);
|
memset(&index->lock, 0, sizeof index->lock);
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
index->magic_n = DICT_INDEX_MAGIC_N;
|
index->magic_n = DICT_INDEX_MAGIC_N;
|
||||||
|
|||||||
1292
handler/ha_innodb.cc
1292
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 *index_type(uint key_number) { return "BTREE"; }
|
||||||
const char** bas_ext() const;
|
const char** bas_ext() const;
|
||||||
ulonglong table_flags() const { return int_table_flags; }
|
ulonglong table_flags() const { return int_table_flags; }
|
||||||
ulong index_flags(uint idx, uint part, bool all_parts) const
|
ulong index_flags(uint idx, uint part, bool all_parts) const {
|
||||||
{
|
return(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
|
||||||
return (HA_READ_NEXT |
|
| HA_READ_RANGE | HA_KEYREAD_ONLY);
|
||||||
HA_READ_PREV |
|
|
||||||
HA_READ_ORDER |
|
|
||||||
HA_READ_RANGE |
|
|
||||||
HA_KEYREAD_ONLY);
|
|
||||||
}
|
}
|
||||||
uint max_supported_keys() const { return MAX_KEY; }
|
uint max_supported_keys() const { return MAX_KEY; }
|
||||||
/* An InnoDB page must store >= 2 keys;
|
/* An InnoDB page must store >= 2 keys;
|
||||||
@@ -117,6 +113,7 @@ class ha_innobase: public handler
|
|||||||
void try_semi_consistent_read(bool yes);
|
void try_semi_consistent_read(bool yes);
|
||||||
void unlock_row();
|
void unlock_row();
|
||||||
|
|
||||||
|
bool is_index_available(uint index);
|
||||||
int index_init(uint index, bool sorted);
|
int index_init(uint index, bool sorted);
|
||||||
int index_end();
|
int index_end();
|
||||||
int index_read(byte * buf, const byte * key,
|
int index_read(byte * buf, const byte * key,
|
||||||
@@ -185,6 +182,10 @@ class ha_innobase: public handler
|
|||||||
static ulonglong get_mysql_bin_log_pos();
|
static ulonglong get_mysql_bin_log_pos();
|
||||||
bool primary_key_is_clustered() { return true; }
|
bool primary_key_is_clustered() { return true; }
|
||||||
int cmp_ref(const byte *ref1, const byte *ref2);
|
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,
|
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
||||||
uint table_changes);
|
uint table_changes);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -279,8 +279,13 @@ dtuple_create(
|
|||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
for (i = 0; i < n_fields; i++) {
|
for (i = 0; i < n_fields; i++) {
|
||||||
(tuple->fields + i)->data = &data_error;
|
dfield_t* field;
|
||||||
dfield_get_type(tuple->fields + i)->mtype = DATA_ERROR;
|
|
||||||
|
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
|
#endif
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ Created 5/24/1996 Heikki Tuuri
|
|||||||
activated by the operation would
|
activated by the operation would
|
||||||
lead to a duplicate key in some
|
lead to a duplicate key in some
|
||||||
table */
|
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 */
|
/* The following are partial failure codes */
|
||||||
#define DB_FAIL 1000
|
#define DB_FAIL 1000
|
||||||
|
|||||||
@@ -53,6 +53,15 @@ dict_remove_db_name(
|
|||||||
/* out: table name */
|
/* out: table name */
|
||||||
const char* name); /* in: table name in the form
|
const char* name); /* in: table name in the form
|
||||||
dbname '/' tablename */
|
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. */
|
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
|
to preserve the original table name
|
||||||
in constraints which reference it */
|
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
|
Change the id of a table object in the dictionary cache. This is used in
|
||||||
DISCARD TABLESPACE. */
|
DISCARD TABLESPACE. */
|
||||||
|
|
||||||
@@ -270,14 +287,34 @@ dict_foreign_add_to_cache(
|
|||||||
ibool check_charsets);/* in: TRUE=check charset
|
ibool check_charsets);/* in: TRUE=check charset
|
||||||
compatibility */
|
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. */
|
Checks if a table is referenced by foreign keys. */
|
||||||
|
|
||||||
ibool
|
ibool
|
||||||
dict_table_referenced_by_foreign_key(
|
dict_table_is_referenced_by_foreign_key(
|
||||||
/*=================================*/
|
/*====================================*/
|
||||||
/* out: TRUE if table is referenced by a
|
/* out: TRUE if table is referenced
|
||||||
foreign key */
|
by a foreign key */
|
||||||
dict_table_t* table); /* in: InnoDB table */
|
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. */
|
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* str, /* in: string to scan for keyword */
|
||||||
const char* keyword); /* in: keyword to look for */
|
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
|
Scans a table create SQL string and adds to the data dictionary
|
||||||
the foreign key constraints declared in the string. This function
|
the foreign key constraints declared in the string. This function
|
||||||
should be called after the indexes for a table have been created.
|
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
|
/* in: whether to increment the open
|
||||||
handle count on the table */
|
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_index_t*
|
||||||
dict_table_get_on_id(
|
dict_index_get_on_id_low(
|
||||||
/*=================*/
|
|
||||||
/* 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(
|
|
||||||
/*=====================*/
|
/*=====================*/
|
||||||
/* out: table, NULL if does not exist */
|
/* out: index, NULL if does not
|
||||||
dulint table_id); /* in: table id */
|
exist */
|
||||||
|
dict_table_t* table, /* in: table */
|
||||||
|
dulint index_id); /* in: index id */
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Checks if a table is in the dictionary cache. */
|
Checks if a table is in the dictionary cache. */
|
||||||
|
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
dict_table_t*
|
dict_table_t*
|
||||||
dict_table_check_if_in_cache_low(
|
dict_table_check_if_in_cache_low(
|
||||||
@@ -384,6 +427,14 @@ dict_table_get_low(
|
|||||||
/* out: table, NULL if not found */
|
/* out: table, NULL if not found */
|
||||||
const char* table_name); /* in: table name */
|
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. */
|
A noninlined version of dict_table_get_low. */
|
||||||
|
|
||||||
dict_table_t*
|
dict_table_t*
|
||||||
@@ -392,23 +443,17 @@ dict_table_get_low_noninlined(
|
|||||||
/* out: table, NULL if not found */
|
/* out: table, NULL if not found */
|
||||||
const char* table_name); /* in: table name */
|
const char* table_name); /* in: table name */
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Returns an index object. */
|
Returns an index object by matching on the name and column names and if
|
||||||
UNIV_INLINE
|
more than index is found return the index with the higher id.*/
|
||||||
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. */
|
|
||||||
|
|
||||||
dict_index_t*
|
dict_index_t*
|
||||||
dict_table_get_index_noninline(
|
dict_table_get_index_by_max_id(
|
||||||
/*===========================*/
|
/*===========================*/
|
||||||
/* out: index, NULL if does not exist */
|
/* out: index, NULL if does not exist */
|
||||||
dict_table_t* table, /* in: table */
|
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. */
|
Returns a column's name. */
|
||||||
|
|
||||||
@@ -855,6 +900,14 @@ dict_index_check_search_tuple(
|
|||||||
/* out: TRUE if ok */
|
/* out: TRUE if ok */
|
||||||
dict_index_t* index, /* in: index */
|
dict_index_t* index, /* in: index */
|
||||||
const dtuple_t* tuple); /* in: tuple used in a search */
|
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 */
|
#endif /* UNIV_DEBUG */
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Builds a node pointer out of a physical record and a page number. */
|
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 */
|
/* out: scanned up to this */
|
||||||
const char* ptr, /* in: scan from */
|
const char* ptr, /* in: scan from */
|
||||||
const char* string);/* in: look for this */
|
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
|
/* Buffers for storing detailed information about the latest foreign key
|
||||||
and unique key errors */
|
and unique key errors */
|
||||||
extern FILE* dict_foreign_err_file;
|
extern FILE* dict_foreign_err_file;
|
||||||
@@ -1050,6 +1215,10 @@ struct dict_sys_struct{
|
|||||||
dict_table_t* sys_fields; /* SYS_FIELDS table */
|
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
|
#ifndef UNIV_NONINL
|
||||||
#include "dict0dict.ic"
|
#include "dict0dict.ic"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -647,28 +647,3 @@ dict_table_get_on_id_low(
|
|||||||
return(table);
|
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 "univ.i"
|
||||||
#include "dict0types.h"
|
#include "dict0types.h"
|
||||||
#include "ut0byte.h"
|
#include "ut0byte.h"
|
||||||
|
#include "mem0mem.h"
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
In a crash recovery we already have all the tablespace objects created.
|
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 "lock0types.h"
|
||||||
#include "hash0hash.h"
|
#include "hash0hash.h"
|
||||||
#include "que0types.h"
|
#include "que0types.h"
|
||||||
|
#include "row0types.h"
|
||||||
|
|
||||||
/* Type flags of an index: OR'ing of the flags is allowed to define a
|
/* Type flags of an index: OR'ing of the flags is allowed to define a
|
||||||
combination of types */
|
combination of types */
|
||||||
@@ -31,7 +32,8 @@ combination of types */
|
|||||||
#define DICT_UNIQUE 2 /* unique index */
|
#define DICT_UNIQUE 2 /* unique index */
|
||||||
#define DICT_UNIVERSAL 4 /* index which can contain records from any
|
#define DICT_UNIVERSAL 4 /* index which can contain records from any
|
||||||
other index */
|
other index */
|
||||||
#define DICT_IBUF 8 /* insert buffer tree */
|
#define DICT_IBUF 8 /* insert buffer tree */
|
||||||
|
#define DICT_NOT_READY 16 /* this index is being build */
|
||||||
|
|
||||||
/* Types for a table object */
|
/* Types for a table object */
|
||||||
#define DICT_TABLE_ORDINARY 1
|
#define DICT_TABLE_ORDINARY 1
|
||||||
@@ -185,7 +187,7 @@ struct dict_index_struct{
|
|||||||
dulint id; /* id of the index */
|
dulint id; /* id of the index */
|
||||||
mem_heap_t* heap; /* memory heap */
|
mem_heap_t* heap; /* memory heap */
|
||||||
ulint type; /* index type */
|
ulint type; /* index type */
|
||||||
const char* name; /* index name */
|
char* name; /* index name */
|
||||||
const char* table_name; /* table name */
|
const char* table_name; /* table name */
|
||||||
dict_table_t* table; /* back pointer to table */
|
dict_table_t* table; /* back pointer to table */
|
||||||
unsigned space:32;
|
unsigned space:32;
|
||||||
@@ -207,6 +209,10 @@ struct dict_index_struct{
|
|||||||
unsigned n_nullable:10;/* number of nullable fields */
|
unsigned n_nullable:10;/* number of nullable fields */
|
||||||
unsigned cached:1;/* TRUE if the index object is in the
|
unsigned cached:1;/* TRUE if the index object is in the
|
||||||
dictionary cache */
|
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 */
|
dict_field_t* fields; /* array of field descriptions */
|
||||||
UT_LIST_NODE_T(dict_index_t)
|
UT_LIST_NODE_T(dict_index_t)
|
||||||
indexes;/* list of indexes of the table */
|
indexes;/* list of indexes of the table */
|
||||||
@@ -224,6 +230,9 @@ struct dict_index_struct{
|
|||||||
index tree */
|
index tree */
|
||||||
rw_lock_t lock; /* read-write lock protecting the upper levels
|
rw_lock_t lock; /* read-write lock protecting the upper levels
|
||||||
of the index tree */
|
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
|
#ifdef UNIV_DEBUG
|
||||||
ulint magic_n;/* magic number */
|
ulint magic_n;/* magic number */
|
||||||
# define DICT_INDEX_MAGIC_N 76789786
|
# define DICT_INDEX_MAGIC_N 76789786
|
||||||
@@ -290,6 +299,14 @@ struct dict_table_struct{
|
|||||||
innodb_file_per_table is defined in my.cnf;
|
innodb_file_per_table is defined in my.cnf;
|
||||||
in Unix this is usually /tmp/..., in Windows
|
in Unix this is usually /tmp/..., in Windows
|
||||||
\temp\... */
|
\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;
|
unsigned space:32;
|
||||||
/* space where the clustered index of the
|
/* space where the clustered index of the
|
||||||
table is placed */
|
table is placed */
|
||||||
@@ -303,6 +320,8 @@ struct dict_table_struct{
|
|||||||
calls DISCARD TABLESPACE on this
|
calls DISCARD TABLESPACE on this
|
||||||
table, and reset to FALSE in IMPORT
|
table, and reset to FALSE in IMPORT
|
||||||
TABLESPACE */
|
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
|
unsigned cached:1;/* TRUE if the table object has been added
|
||||||
to the dictionary cache */
|
to the dictionary cache */
|
||||||
unsigned flags:8;/* DICT_TF_COMPACT, ... */
|
unsigned flags:8;/* DICT_TF_COMPACT, ... */
|
||||||
@@ -406,6 +425,10 @@ struct dict_table_struct{
|
|||||||
SELECT MAX(auto inc column) */
|
SELECT MAX(auto inc column) */
|
||||||
ib_longlong autoinc;/* autoinc counter value to give to the
|
ib_longlong autoinc;/* autoinc counter value to give to the
|
||||||
next inserted row */
|
next inserted row */
|
||||||
|
/*----------------------*/
|
||||||
|
UT_LIST_BASE_NODE_T(row_prebuilt_t) prebuilts;
|
||||||
|
/* base node for the prebuilts defined
|
||||||
|
for the table */
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
ulint magic_n;/* magic number */
|
ulint magic_n;/* magic number */
|
||||||
# define DICT_TABLE_MAGIC_N 76333786
|
# define DICT_TABLE_MAGIC_N 76333786
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ Created 1/8/1996 Heikki Tuuri
|
|||||||
#ifndef dict0types_h
|
#ifndef dict0types_h
|
||||||
#define dict0types_h
|
#define dict0types_h
|
||||||
|
|
||||||
|
#include "ut0list.h"
|
||||||
|
|
||||||
typedef struct dict_sys_struct dict_sys_t;
|
typedef struct dict_sys_struct dict_sys_t;
|
||||||
typedef struct dict_col_struct dict_col_t;
|
typedef struct dict_col_struct dict_col_t;
|
||||||
typedef struct dict_field_struct dict_field_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 ind_node_struct ind_node_t;
|
||||||
typedef struct tab_node_struct tab_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
|
#endif
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ heap creation. */
|
|||||||
Use this macro instead of the corresponding function! Macro for memory
|
Use this macro instead of the corresponding function! Macro for memory
|
||||||
heap creation. */
|
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(\
|
#define mem_heap_create_in_buffer(N) mem_heap_create_func(\
|
||||||
(N), MEM_HEAP_BUFFER, __FILE__, __LINE__)
|
(N), MEM_HEAP_BUFFER, __FILE__, __LINE__)
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
@@ -89,6 +95,12 @@ heap freeing. */
|
|||||||
|
|
||||||
#define mem_heap_free(heap) mem_heap_free_func(\
|
#define mem_heap_free(heap) mem_heap_free_func(\
|
||||||
(heap), __FILE__, __LINE__)
|
(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
|
NOTE: Use the corresponding macros instead of this function. Creates a
|
||||||
memory heap. For debugging purposes, takes also the file name and line as
|
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 */
|
mem_heap_t* heap, /* in, own: heap to be freed */
|
||||||
const char* file_name, /* in: file name where freed */
|
const char* file_name, /* in: file name where freed */
|
||||||
ulint line); /* in: line 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. */
|
Allocates n bytes of memory from a memory heap. */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
@@ -131,6 +174,19 @@ mem_heap_alloc(
|
|||||||
ulint n); /* in: number of bytes; if the heap is allowed
|
ulint n); /* in: number of bytes; if the heap is allowed
|
||||||
to grow into the buffer pool, this must be
|
to grow into the buffer pool, this must be
|
||||||
<= MEM_MAX_ALLOC_IN_BUF */
|
<= 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. */
|
Returns a pointer to the heap top. */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
@@ -193,6 +249,12 @@ Macro for memory buffer allocation */
|
|||||||
|
|
||||||
#define mem_alloc_noninline(N) mem_alloc_func_noninline(\
|
#define mem_alloc_noninline(N) mem_alloc_func_noninline(\
|
||||||
(N), __FILE__, __LINE__)
|
(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.
|
NOTE: Use the corresponding macro instead of this function.
|
||||||
Allocates a single buffer of memory from the dynamic memory of
|
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 */
|
const char* file_name, /* in: file name where created */
|
||||||
ulint line /* in: line 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. */
|
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
|
os_file_stat_t* stat_info); /* information of a file in a
|
||||||
directory */
|
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
|
#endif
|
||||||
|
|||||||
@@ -93,6 +93,13 @@ row_ins_step(
|
|||||||
/*=========*/
|
/*=========*/
|
||||||
/* out: query thread to run next or NULL */
|
/* out: query thread to run next or NULL */
|
||||||
que_thr_t* thr); /* in: query thread */
|
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 */
|
/* Insert node structure */
|
||||||
|
|
||||||
@@ -112,6 +119,11 @@ struct ins_node_struct{
|
|||||||
this should be reset to NULL */
|
this should be reset to NULL */
|
||||||
UT_LIST_BASE_NODE_T(dtuple_t)
|
UT_LIST_BASE_NODE_T(dtuple_t)
|
||||||
entry_list;/* list of entries, one for each index */
|
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 */
|
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
|
dulint trx_id; /* trx id or the last trx which executed the
|
||||||
node */
|
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;
|
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. */
|
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
|
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
|
||||||
handle */
|
handle */
|
||||||
trx_t* trx); /* in: transaction 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. */
|
Unlocks an AUTO_INC type lock possibly reserved by trx. */
|
||||||
|
|
||||||
@@ -188,6 +196,16 @@ row_lock_table_for_mysql(
|
|||||||
prebuilt->select_lock_type */
|
prebuilt->select_lock_type */
|
||||||
ulint mode); /* in: lock mode of table
|
ulint mode); /* in: lock mode of table
|
||||||
(ignored if table==NULL) */
|
(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. */
|
Does an insert for MySQL. */
|
||||||
@@ -413,6 +431,19 @@ row_drop_table_for_mysql(
|
|||||||
ibool drop_db);/* in: TRUE=dropping whole database */
|
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
|
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
|
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. */
|
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 */
|
/* out: error code or DB_SUCCESS */
|
||||||
const char* old_name, /* in: old table name */
|
const char* old_name, /* in: old table name */
|
||||||
const char* new_name, /* in: new 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. */
|
Checks a table for corruption. */
|
||||||
|
|
||||||
@@ -462,7 +494,93 @@ row_check_table_for_mysql(
|
|||||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||||
handle */
|
handle */
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#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
|
/* A struct describing a place for an individual column in the MySQL
|
||||||
row format which is presented to the table handler in ha_innobase.
|
row format which is presented to the table handler in ha_innobase.
|
||||||
This template struct is used to speed up row transformations between
|
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_ALLOCATED 78540783
|
||||||
#define ROW_PREBUILT_FREED 26423527
|
#define ROW_PREBUILT_FREED 26423527
|
||||||
|
#define ROW_PREBUILT_OBSOLETE 12367541
|
||||||
|
|
||||||
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
|
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
|
||||||
handle used within MySQL; these are used to save CPU time. */
|
handle used within MySQL; these are used to save CPU time. */
|
||||||
|
|
||||||
struct row_prebuilt_struct {
|
struct row_prebuilt_struct {
|
||||||
ulint magic_n; /* this magic number is set to
|
ulint magic_n; /* this magic number is set to
|
||||||
ROW_PREBUILT_ALLOCATED when created
|
ROW_PREBUILT_ALLOCATED when created,
|
||||||
and to ROW_PREBUILT_FREED when the
|
or ROW_PREBUILT_FREED when the
|
||||||
struct has been freed; used in
|
struct has been freed or
|
||||||
debugging */
|
ROW_PREBUILT_OBSOLETE when struct
|
||||||
|
needs a rebuilt */
|
||||||
dict_table_t* table; /* Innobase table handle */
|
dict_table_t* table; /* Innobase table handle */
|
||||||
trx_t* trx; /* current transaction handle */
|
trx_t* trx; /* current transaction handle */
|
||||||
ibool sql_stat_start; /* TRUE when we start processing of
|
ibool sql_stat_start; /* TRUE when we start processing of
|
||||||
@@ -668,10 +788,12 @@ struct row_prebuilt_struct {
|
|||||||
fetched row in fetch_cache */
|
fetched row in fetch_cache */
|
||||||
ulint n_fetch_cached; /* number of not yet fetched rows
|
ulint n_fetch_cached; /* number of not yet fetched rows
|
||||||
in fetch_cache */
|
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 */
|
to this heap */
|
||||||
mem_heap_t* old_vers_heap; /* memory heap where a previous
|
mem_heap_t* old_vers_heap; /* memory heap where a previous
|
||||||
version is built in consistent read */
|
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
|
ulint magic_n2; /* this should be the same as
|
||||||
magic_n */
|
magic_n */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,15 +52,16 @@ row_get_rec_roll_ptr(
|
|||||||
dict_index_t* index, /* in: clustered index */
|
dict_index_t* index, /* in: clustered index */
|
||||||
const ulint* offsets);/* in: rec_get_offsets(rec, index) */
|
const ulint* offsets);/* in: rec_get_offsets(rec, index) */
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
When an insert to a table is performed, this function builds the entry which
|
When an insert or purge to a table is performed, this function builds
|
||||||
has to be inserted to an index on the table. */
|
the entry to be inserted into or purged from an index on the table. */
|
||||||
|
|
||||||
dtuple_t*
|
dtuple_t*
|
||||||
row_build_index_entry(
|
row_build_index_entry(
|
||||||
/*==================*/
|
/*==================*/
|
||||||
/* out: index entry which should be inserted */
|
/* out: index entry which should be
|
||||||
const dtuple_t* row, /* in: row which should be inserted to the
|
inserted or purged */
|
||||||
table */
|
const dtuple_t* row, /* in: row which should be
|
||||||
|
inserted or purged */
|
||||||
row_ext_t* ext, /* in: externally stored column prefixes,
|
row_ext_t* ext, /* in: externally stored column prefixes,
|
||||||
or NULL */
|
or NULL */
|
||||||
dict_index_t* index, /* in: index on the table */
|
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_ext_struct row_ext_t;
|
||||||
|
|
||||||
|
typedef struct row_prebuilt_struct row_prebuilt_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ row_undo_ins(
|
|||||||
/* out: DB_SUCCESS */
|
/* out: DB_SUCCESS */
|
||||||
undo_node_t* node); /* in: row undo node */
|
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
|
#ifndef UNIV_NONINL
|
||||||
#include "row0uins.ic"
|
#include "row0uins.ic"
|
||||||
|
|||||||
@@ -51,6 +51,24 @@ row_undo_step(
|
|||||||
/*==========*/
|
/*==========*/
|
||||||
/* out: query thread to run next or NULL */
|
/* out: query thread to run next or NULL */
|
||||||
que_thr_t* thr); /* in: query thread */
|
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
|
/* 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
|
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 */
|
dulint undo_no;/* undo number of the record */
|
||||||
ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
|
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
|
dulint new_roll_ptr; /* roll ptr to restore to clustered index
|
||||||
record */
|
record */
|
||||||
dulint new_trx_id; /* trx id to restore to clustered index
|
dulint new_trx_id; /* trx id to restore to clustered index
|
||||||
|
|||||||
@@ -60,6 +60,17 @@ trx_undo_rec_get_undo_no(
|
|||||||
/*=====================*/
|
/*=====================*/
|
||||||
/* out: undo no */
|
/* out: undo no */
|
||||||
trx_undo_rec_t* undo_rec); /* in: undo log record */
|
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. */
|
Reads from an undo log record the general parameters. */
|
||||||
|
|
||||||
@@ -201,6 +212,31 @@ trx_undo_report_row_operation(
|
|||||||
inserted undo log record,
|
inserted undo log record,
|
||||||
ut_dulint_zero if BTR_NO_UNDO_LOG
|
ut_dulint_zero if BTR_NO_UNDO_LOG
|
||||||
flag was specified */
|
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
|
Copies an undo record to heap. This function can be called if we know that
|
||||||
the undo log record exists. */
|
the undo log record exists. */
|
||||||
@@ -279,24 +315,40 @@ trx_undo_parse_erase_page_end(
|
|||||||
/* Types of an undo log record: these have to be smaller than 16, as the
|
/* 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
|
compilation info multiplied by 16 is ORed to this value in an undo log
|
||||||
record */
|
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
|
#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 */
|
record */
|
||||||
#define TRX_UNDO_UPD_DEL_REC 13 /* update of a delete marked record to
|
#define TRX_UNDO_UPD_DEL_REC 13 /* update of a delete marked record to
|
||||||
a not delete marked record; also the
|
a not delete marked record; also the
|
||||||
fields of the record can change */
|
fields of the record can change */
|
||||||
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
|
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
|
||||||
do not change */
|
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
|
#define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by
|
||||||
this and ORed to the type above */
|
this and ORed to the type above */
|
||||||
#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
|
#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
|
||||||
to denote that we updated external
|
to denote that we updated external
|
||||||
storage fields: used by purge to
|
storage fields: used by purge to
|
||||||
free the external storage */
|
free the external storage */
|
||||||
|
|
||||||
/* Operation type flags used in trx_undo_report_row_operation */
|
/* Operation type flags used in trx_undo_report_row_operation
|
||||||
#define TRX_UNDO_INSERT_OP 1
|
and trx_undo_report_dict_operation */
|
||||||
#define TRX_UNDO_MODIFY_OP 2
|
#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
|
#ifndef UNIV_NONINL
|
||||||
#include "trx0rec.ic"
|
#include "trx0rec.ic"
|
||||||
|
|||||||
@@ -63,6 +63,20 @@ trx_undo_rec_get_undo_no(
|
|||||||
return(mach_dulint_read_much_compressed(ptr));
|
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. */
|
Copies the undo record to the heap. */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
|
|||||||
@@ -450,8 +450,19 @@ struct trx_struct{
|
|||||||
table. This is a hint that the table
|
table. This is a hint that the table
|
||||||
may need to be dropped in crash
|
may need to be dropped in crash
|
||||||
recovery. */
|
recovery. */
|
||||||
dulint table_id; /* table id if the preceding field is
|
dict_undo_list_t*
|
||||||
TRUE */
|
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
|
int active_trans; /* 1 - if a transaction in MySQL
|
||||||
is active. 2 - if prepare_commit_mutex
|
is active. 2 - if prepare_commit_mutex
|
||||||
@@ -567,6 +578,9 @@ struct trx_struct{
|
|||||||
void* error_info; /* if the error number indicates a
|
void* error_info; /* if the error number indicates a
|
||||||
duplicate key error, a pointer to
|
duplicate key error, a pointer to
|
||||||
the problematic index is stored here */
|
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 */
|
sess_t* sess; /* session of the trx, NULL if none */
|
||||||
ulint que_state; /* TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
|
ulint que_state; /* TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
|
||||||
... */
|
... */
|
||||||
|
|||||||
@@ -3678,7 +3678,9 @@ lock_table_enqueue_waiting(
|
|||||||
|
|
||||||
trx = thr_get_trx(thr);
|
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);
|
ut_print_timestamp(stderr);
|
||||||
fputs(" InnoDB: Error: a table lock wait happens"
|
fputs(" InnoDB: Error: a table lock wait happens"
|
||||||
" in a dictionary operation!\n"
|
" in a dictionary operation!\n"
|
||||||
|
|||||||
@@ -101,6 +101,21 @@ mem_alloc_func_noninline(
|
|||||||
return(mem_alloc_func(n, file_name, line));
|
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. */
|
Duplicates a NUL-terminated string, allocated from a memory heap. */
|
||||||
|
|
||||||
@@ -566,3 +581,60 @@ mem_validate_all_blocks(void)
|
|||||||
mem_pool_mutex_exit();
|
mem_pool_mutex_exit();
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
create index id2 on t2 (id);
|
||||||
show create table t2;
|
show create table t2;
|
||||||
drop index id2 on t2;
|
drop index id2 on t2;
|
||||||
--error 1025,1025
|
--error 1540,1540
|
||||||
drop index id on t2;
|
drop index id on t2;
|
||||||
show create table t2;
|
show create table t2;
|
||||||
drop 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
|
Creates a temporary file. This function is like tmpfile(3), but
|
||||||
the temporary file is created in the MySQL temporary directory.
|
the temporary file is created in the MySQL temporary directory.
|
||||||
|
|||||||
444
pars/pars0grm.c
444
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,
|
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
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;
|
fork->last_sel_node = NULL;
|
||||||
|
|
||||||
|
suspended_thr = NULL;
|
||||||
|
completed_thr = NULL;
|
||||||
|
|
||||||
/* Choose the query thread to run: usually there is just one thread,
|
/* Choose the query thread to run: usually there is just one thread,
|
||||||
but in a parallelized select, which necessarily is non-scrollable,
|
but in a parallelized select, which necessarily is non-scrollable,
|
||||||
there may be several to choose from */
|
there may be several to choose from */
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ include ../include/Makefile.i
|
|||||||
|
|
||||||
noinst_LIBRARIES = librow.a
|
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\
|
row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\
|
||||||
row0uins.c row0umod.c row0undo.c row0upd.c row0vers.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. */
|
Creates an entry template for each index of a table. */
|
||||||
static
|
|
||||||
void
|
void
|
||||||
ins_node_create_entry_list(
|
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
652
row/row0mysql.c
652
row/row0mysql.c
@@ -25,12 +25,15 @@ Created 9/17/2000 Heikki Tuuri
|
|||||||
#include "dict0boot.h"
|
#include "dict0boot.h"
|
||||||
#include "trx0roll.h"
|
#include "trx0roll.h"
|
||||||
#include "trx0purge.h"
|
#include "trx0purge.h"
|
||||||
|
#include "trx0rec.h"
|
||||||
|
#include "trx0undo.h"
|
||||||
#include "lock0lock.h"
|
#include "lock0lock.h"
|
||||||
#include "rem0cmp.h"
|
#include "rem0cmp.h"
|
||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
#include "btr0sea.h"
|
#include "btr0sea.h"
|
||||||
#include "fil0fil.h"
|
#include "fil0fil.h"
|
||||||
#include "ibuf0ibuf.h"
|
#include "ibuf0ibuf.h"
|
||||||
|
#include "row0merge.h"
|
||||||
|
|
||||||
/* A dummy variable used to fool the compiler */
|
/* A dummy variable used to fool the compiler */
|
||||||
ibool row_mysql_identically_false = FALSE;
|
ibool row_mysql_identically_false = FALSE;
|
||||||
@@ -79,6 +82,9 @@ row_mysql_is_system_table(
|
|||||||
}
|
}
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#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. */
|
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
|
||||||
static
|
static
|
||||||
@@ -548,7 +554,6 @@ handle_new_error:
|
|||||||
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
|
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
|
||||||
"forcing-recovery.html"
|
"forcing-recovery.html"
|
||||||
" for help.\n", stderr);
|
" for help.\n", stderr);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "InnoDB: unknown error code %lu\n",
|
fprintf(stderr, "InnoDB: unknown error code %lu\n",
|
||||||
(ulong) err);
|
(ulong) err);
|
||||||
@@ -656,9 +661,39 @@ row_create_prebuilt(
|
|||||||
|
|
||||||
prebuilt->old_vers_heap = NULL;
|
prebuilt->old_vers_heap = NULL;
|
||||||
|
|
||||||
|
UT_LIST_ADD_LAST(prebuilts, table->prebuilts, prebuilt);
|
||||||
|
|
||||||
return(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. */
|
Free a prebuilt struct for a MySQL table handle. */
|
||||||
|
|
||||||
@@ -669,12 +704,15 @@ row_prebuilt_free(
|
|||||||
{
|
{
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
if ((prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
|
||||||
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
|
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE)
|
||||||
|
|| (prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED
|
||||||
|
&& prebuilt->magic_n != ROW_PREBUILT_OBSOLETE)) {
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to free a corrupt\n"
|
"InnoDB: Error: trying to free a corrupt\n"
|
||||||
"InnoDB: table handle. Magic n %lu,"
|
"InnoDB: table handle. Magic n %lu,"
|
||||||
" magic n2 %lu, table name",
|
" magic n2 %lu, table name ",
|
||||||
(ulong) prebuilt->magic_n,
|
(ulong) prebuilt->magic_n,
|
||||||
(ulong) prebuilt->magic_n2);
|
(ulong) prebuilt->magic_n2);
|
||||||
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
|
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
|
||||||
@@ -738,6 +776,35 @@ row_prebuilt_free(
|
|||||||
|
|
||||||
dict_table_decrement_handle_count(prebuilt->table);
|
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);
|
mem_heap_free(prebuilt->heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,9 +834,9 @@ row_update_prebuilt_trx(
|
|||||||
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to use a corrupt\n"
|
"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);
|
(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);
|
putc('\n', stderr);
|
||||||
|
|
||||||
mem_analyze_corruption(prebuilt);
|
mem_analyze_corruption(prebuilt);
|
||||||
@@ -1048,6 +1115,88 @@ run_again:
|
|||||||
return((int) err);
|
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. */
|
Does an insert for MySQL. */
|
||||||
|
|
||||||
@@ -1065,6 +1214,7 @@ row_insert_for_mysql(
|
|||||||
ibool was_lock_wait;
|
ibool was_lock_wait;
|
||||||
trx_t* trx = prebuilt->trx;
|
trx_t* trx = prebuilt->trx;
|
||||||
ins_node_t* node = prebuilt->ins_node;
|
ins_node_t* node = prebuilt->ins_node;
|
||||||
|
dict_table_t* table;
|
||||||
|
|
||||||
ut_ad(trx);
|
ut_ad(trx);
|
||||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||||
@@ -1087,13 +1237,13 @@ row_insert_for_mysql(
|
|||||||
return(DB_ERROR);
|
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,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to free a corrupt\n"
|
"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);
|
(ulong) prebuilt->magic_n);
|
||||||
ut_print_name(stderr, prebuilt->trx, TRUE,
|
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
|
||||||
prebuilt->table->name);
|
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
|
||||||
mem_analyze_corruption(prebuilt);
|
mem_analyze_corruption(prebuilt);
|
||||||
@@ -1101,6 +1251,10 @@ row_insert_for_mysql(
|
|||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||||
|
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||||
|
}
|
||||||
|
|
||||||
if (srv_created_new_raw || srv_force_recovery) {
|
if (srv_created_new_raw || srv_force_recovery) {
|
||||||
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
||||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||||
@@ -1122,6 +1276,14 @@ row_insert_for_mysql(
|
|||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
row_get_prebuilt_insert_row(prebuilt);
|
row_get_prebuilt_insert_row(prebuilt);
|
||||||
node = prebuilt->ins_node;
|
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);
|
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
|
||||||
@@ -1143,6 +1305,10 @@ run_again:
|
|||||||
thr->run_node = node;
|
thr->run_node = node;
|
||||||
thr->prev_node = node;
|
thr->prev_node = node;
|
||||||
|
|
||||||
|
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||||
|
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||||
|
}
|
||||||
|
|
||||||
row_ins_step(thr);
|
row_ins_step(thr);
|
||||||
|
|
||||||
err = trx->error_state;
|
err = trx->error_state;
|
||||||
@@ -1325,13 +1491,13 @@ row_update_for_mysql(
|
|||||||
return(DB_ERROR);
|
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,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to free a corrupt\n"
|
"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);
|
(ulong) prebuilt->magic_n);
|
||||||
ut_print_name(stderr, prebuilt->trx, TRUE,
|
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
|
||||||
prebuilt->table->name);
|
|
||||||
putc('\n', stderr);
|
putc('\n', stderr);
|
||||||
|
|
||||||
mem_analyze_corruption(prebuilt);
|
mem_analyze_corruption(prebuilt);
|
||||||
@@ -1339,6 +1505,10 @@ row_update_for_mysql(
|
|||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||||
|
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||||
|
}
|
||||||
|
|
||||||
if (srv_created_new_raw || srv_force_recovery) {
|
if (srv_created_new_raw || srv_force_recovery) {
|
||||||
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
fputs("InnoDB: A new raw disk partition was initialized or\n"
|
||||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||||
@@ -1391,6 +1561,10 @@ run_again:
|
|||||||
thr->run_node = node;
|
thr->run_node = node;
|
||||||
thr->prev_node = node;
|
thr->prev_node = node;
|
||||||
|
|
||||||
|
if (prebuilt->magic_n == ROW_PREBUILT_OBSOLETE) {
|
||||||
|
row_update_prebuilt(prebuilt, prebuilt->table);
|
||||||
|
}
|
||||||
|
|
||||||
row_upd_step(thr);
|
row_upd_step(thr);
|
||||||
|
|
||||||
err = trx->error_state;
|
err = trx->error_state;
|
||||||
@@ -1749,6 +1923,9 @@ row_create_table_for_mysql(
|
|||||||
ulint table_name_len;
|
ulint table_name_len;
|
||||||
ulint err;
|
ulint err;
|
||||||
ulint i;
|
ulint i;
|
||||||
|
ibool retry;
|
||||||
|
|
||||||
|
retry = FALSE;
|
||||||
|
|
||||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||||
#ifdef UNIV_SYNC_DEBUG
|
#ifdef UNIV_SYNC_DEBUG
|
||||||
@@ -1868,6 +2045,7 @@ row_create_table_for_mysql(
|
|||||||
|
|
||||||
heap = mem_heap_create(512);
|
heap = mem_heap_create(512);
|
||||||
|
|
||||||
|
retry_create:
|
||||||
trx->dict_operation = TRUE;
|
trx->dict_operation = TRUE;
|
||||||
|
|
||||||
node = tab_create_graph_create(table, heap);
|
node = tab_create_graph_create(table, heap);
|
||||||
@@ -1884,9 +2062,10 @@ row_create_table_for_mysql(
|
|||||||
|
|
||||||
trx->error_state = DB_SUCCESS;
|
trx->error_state = DB_SUCCESS;
|
||||||
|
|
||||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
|
||||||
|
|
||||||
if (err == DB_OUT_OF_FILE_SPACE) {
|
if (err == DB_OUT_OF_FILE_SPACE) {
|
||||||
|
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||||
|
|
||||||
ut_print_timestamp(stderr);
|
ut_print_timestamp(stderr);
|
||||||
|
|
||||||
fputs(" InnoDB: Warning: cannot create table ",
|
fputs(" InnoDB: Warning: cannot create table ",
|
||||||
@@ -1903,30 +2082,51 @@ row_create_table_for_mysql(
|
|||||||
} else if (err == DB_DUPLICATE_KEY) {
|
} else if (err == DB_DUPLICATE_KEY) {
|
||||||
ut_print_timestamp(stderr);
|
ut_print_timestamp(stderr);
|
||||||
|
|
||||||
fputs(" InnoDB: Error: table ", stderr);
|
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||||
ut_print_name(stderr, trx, TRUE, table->name);
|
trx_general_rollback_for_mysql(
|
||||||
fputs(" already exists in InnoDB internal\n"
|
trx, FALSE, NULL);
|
||||||
"InnoDB: data dictionary. Have you deleted"
|
|
||||||
" the .frm file\n"
|
fputs(" InnoDB: Error: table ", stderr);
|
||||||
"InnoDB: and not used DROP TABLE?"
|
ut_print_name(stderr, trx, TRUE, table->name);
|
||||||
" Have you used DROP DATABASE\n"
|
fputs(" already exists in InnoDB internal\n"
|
||||||
"InnoDB: for InnoDB tables in"
|
"InnoDB: data dictionary. Have you deleted"
|
||||||
" MySQL version <= 3.23.43?\n"
|
" the .frm file\n"
|
||||||
"InnoDB: See the Restrictions section"
|
"InnoDB: and not used DROP TABLE?"
|
||||||
" of the InnoDB manual.\n"
|
" Have you used DROP DATABASE\n"
|
||||||
"InnoDB: You can drop the orphaned table"
|
"InnoDB: for InnoDB tables in"
|
||||||
" inside InnoDB by\n"
|
" MySQL version <= 3.23.43?\n"
|
||||||
"InnoDB: creating an InnoDB table with"
|
"InnoDB: See the Restrictions section"
|
||||||
" the same name in another\n"
|
" of the InnoDB manual.\n"
|
||||||
"InnoDB: database and copying the .frm file"
|
"InnoDB: You can drop the orphaned table"
|
||||||
" to the current database.\n"
|
" inside InnoDB by\n"
|
||||||
"InnoDB: Then MySQL thinks the table exists,"
|
"InnoDB: creating an InnoDB table with"
|
||||||
" and DROP TABLE will\n"
|
" the same name in another\n"
|
||||||
"InnoDB: succeed.\n"
|
"InnoDB: database and copying the .frm file"
|
||||||
"InnoDB: You can look for further help from\n"
|
" to the current database.\n"
|
||||||
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
|
"InnoDB: Then MySQL thinks the table exists,"
|
||||||
"innodb-troubleshooting.html\n",
|
" and DROP TABLE will\n"
|
||||||
stderr);
|
"InnoDB: succeed.\n"
|
||||||
|
"InnoDB: You can look for further help from\n"
|
||||||
|
"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
|
/* 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;
|
mem_heap_t* heap;
|
||||||
que_thr_t* thr;
|
que_thr_t* thr;
|
||||||
ulint err;
|
ulint err;
|
||||||
ulint i, j;
|
ulint i;
|
||||||
ulint len;
|
ulint len;
|
||||||
|
|
||||||
#ifdef UNIV_SYNC_DEBUG
|
#ifdef UNIV_SYNC_DEBUG
|
||||||
@@ -1982,11 +2182,12 @@ row_create_index_for_mysql(
|
|||||||
safer not to allow them. */
|
safer not to allow them. */
|
||||||
|
|
||||||
for (i = 0; i < dict_index_get_n_fields(index); i++) {
|
for (i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||||
|
ulint j;
|
||||||
|
|
||||||
for (j = 0; j < i; j++) {
|
for (j = 0; j < i; j++) {
|
||||||
if (0 == ut_strcmp(
|
if (0 == ut_strcmp(
|
||||||
dict_index_get_nth_field(index, j)->name,
|
dict_index_get_nth_field(index, j)->name,
|
||||||
dict_index_get_nth_field(index, i)->name)) {
|
dict_index_get_nth_field(index, i)->name)) {
|
||||||
|
|
||||||
ut_print_timestamp(stderr);
|
ut_print_timestamp(stderr);
|
||||||
|
|
||||||
fputs(" InnoDB: Error: column ", stderr);
|
fputs(" InnoDB: Error: column ", stderr);
|
||||||
@@ -2433,10 +2634,10 @@ row_discard_tablespace_for_mysql(
|
|||||||
ut_print_timestamp(ef);
|
ut_print_timestamp(ef);
|
||||||
|
|
||||||
fputs(" Cannot DISCARD table ", ef);
|
fputs(" Cannot DISCARD table ", ef);
|
||||||
ut_print_name(ef, trx, TRUE, name);
|
ut_print_name(stderr, trx, TRUE, name);
|
||||||
fputs("\n"
|
fputs("\n"
|
||||||
"because it is referenced by ", ef);
|
"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);
|
putc('\n', ef);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
@@ -2761,10 +2962,10 @@ row_truncate_table_for_mysql(
|
|||||||
ut_print_timestamp(ef);
|
ut_print_timestamp(ef);
|
||||||
|
|
||||||
fputs(" Cannot truncate table ", 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"
|
fputs(" by DROP+CREATE\n"
|
||||||
"InnoDB: because it is referenced by ", ef);
|
"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);
|
putc('\n', ef);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
@@ -2982,6 +3183,30 @@ row_drop_table_for_mysql(
|
|||||||
const char* name, /* in: table name */
|
const char* name, /* in: table name */
|
||||||
trx_t* trx, /* in: transaction handle */
|
trx_t* trx, /* in: transaction handle */
|
||||||
ibool drop_db)/* in: TRUE=dropping whole database */
|
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_foreign_t* foreign;
|
||||||
dict_table_t* table;
|
dict_table_t* table;
|
||||||
@@ -3111,10 +3336,10 @@ check_next_foreign:
|
|||||||
ut_print_timestamp(ef);
|
ut_print_timestamp(ef);
|
||||||
|
|
||||||
fputs(" Cannot drop table ", ef);
|
fputs(" Cannot drop table ", ef);
|
||||||
ut_print_name(ef, trx, TRUE, name);
|
ut_print_name(stderr, trx, TRUE, name);
|
||||||
fputs("\n"
|
fputs("\n"
|
||||||
"because it is referenced by ", ef);
|
"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);
|
putc('\n', ef);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
@@ -3131,20 +3356,25 @@ check_next_foreign:
|
|||||||
added = row_add_table_to_background_drop_list(table);
|
added = row_add_table_to_background_drop_list(table);
|
||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
ut_print_timestamp(stderr);
|
/* Temporary tables can have read views and we don't
|
||||||
fputs(" InnoDB: Warning: MySQL is"
|
print any warning. */
|
||||||
" trying to drop table ", stderr);
|
if (*table->name != TEMP_TABLE_PREFIX) {
|
||||||
ut_print_name(stderr, trx, TRUE, table->name);
|
ut_print_timestamp(stderr);
|
||||||
fputs("\n"
|
fputs(" InnoDB: Warning: MySQL is"
|
||||||
"InnoDB: though there are still"
|
" trying to drop table ", stderr);
|
||||||
" open handles to it.\n"
|
ut_print_name(stderr, trx, TRUE, table->name);
|
||||||
"InnoDB: Adding the table to the"
|
fputs("\n"
|
||||||
" background drop queue.\n",
|
"InnoDB: though there are still"
|
||||||
stderr);
|
" open handles to it.\n"
|
||||||
|
"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
|
/* We return DB_SUCCESS to MySQL though the drop will
|
||||||
happen lazily later */
|
happen lazily later */
|
||||||
|
|
||||||
err = DB_SUCCESS;
|
err = DB_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
/* The table is already in the background drop list */
|
/* The table is already in the background drop list */
|
||||||
@@ -3219,7 +3449,6 @@ check_next_foreign:
|
|||||||
"WHERE NAME = :table_name\n"
|
"WHERE NAME = :table_name\n"
|
||||||
"LOCK IN SHARE MODE;\n"
|
"LOCK IN SHARE MODE;\n"
|
||||||
"IF (SQL % NOTFOUND) THEN\n"
|
"IF (SQL % NOTFOUND) THEN\n"
|
||||||
" COMMIT WORK;\n"
|
|
||||||
" RETURN;\n"
|
" RETURN;\n"
|
||||||
"END IF;\n"
|
"END IF;\n"
|
||||||
"found := 1;\n"
|
"found := 1;\n"
|
||||||
@@ -3272,7 +3501,6 @@ check_next_foreign:
|
|||||||
"WHERE TABLE_ID = table_id;\n"
|
"WHERE TABLE_ID = table_id;\n"
|
||||||
"DELETE FROM SYS_TABLES\n"
|
"DELETE FROM SYS_TABLES\n"
|
||||||
"WHERE ID = table_id;\n"
|
"WHERE ID = table_id;\n"
|
||||||
"COMMIT WORK;\n"
|
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, FALSE, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
@@ -3354,8 +3582,6 @@ check_next_foreign:
|
|||||||
}
|
}
|
||||||
funct_exit:
|
funct_exit:
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
|
|
||||||
if (locked_dictionary) {
|
if (locked_dictionary) {
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
}
|
}
|
||||||
@@ -3532,7 +3758,8 @@ row_rename_table_for_mysql(
|
|||||||
/* out: error code or DB_SUCCESS */
|
/* out: error code or DB_SUCCESS */
|
||||||
const char* old_name, /* in: old table name */
|
const char* old_name, /* in: old table name */
|
||||||
const char* new_name, /* in: new 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;
|
dict_table_t* table;
|
||||||
ulint err;
|
ulint err;
|
||||||
@@ -3557,9 +3784,7 @@ row_rename_table_for_mysql(
|
|||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
} else if (row_mysql_is_system_table(new_name)) {
|
||||||
|
|
||||||
if (row_mysql_is_system_table(new_name)) {
|
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to create a MySQL"
|
"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);
|
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
|
||||||
new_is_tmp = row_is_mysql_tmp_table_name(new_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);
|
table = dict_table_get_low(old_name);
|
||||||
|
|
||||||
if (!table) {
|
if (!table) {
|
||||||
@@ -3603,9 +3823,7 @@ row_rename_table_for_mysql(
|
|||||||
"innodb-troubleshooting.html\n",
|
"innodb-troubleshooting.html\n",
|
||||||
stderr);
|
stderr);
|
||||||
goto funct_exit;
|
goto funct_exit;
|
||||||
}
|
} else if (table->ibd_file_missing) {
|
||||||
|
|
||||||
if (table->ibd_file_missing) {
|
|
||||||
err = DB_TABLE_NOT_FOUND;
|
err = DB_TABLE_NOT_FOUND;
|
||||||
ut_print_timestamp(stderr);
|
ut_print_timestamp(stderr);
|
||||||
|
|
||||||
@@ -3618,9 +3836,7 @@ row_rename_table_for_mysql(
|
|||||||
"innodb-troubleshooting.html\n",
|
"innodb-troubleshooting.html\n",
|
||||||
stderr);
|
stderr);
|
||||||
goto funct_exit;
|
goto funct_exit;
|
||||||
}
|
} else if (new_is_tmp) {
|
||||||
|
|
||||||
if (new_is_tmp) {
|
|
||||||
/* MySQL is doing an ALTER TABLE command and it renames the
|
/* MySQL is doing an ALTER TABLE command and it renames the
|
||||||
original table to a temporary table name. We want to preserve
|
original table to a temporary table name. We want to preserve
|
||||||
the original foreign key constraint definitions despite the
|
the original foreign key constraint definitions despite the
|
||||||
@@ -3660,9 +3876,7 @@ row_rename_table_for_mysql(
|
|||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
} else if (!new_is_tmp) {
|
||||||
|
|
||||||
if (!new_is_tmp) {
|
|
||||||
/* Rename all constraints. */
|
/* Rename all constraints. */
|
||||||
|
|
||||||
info = pars_info_create();
|
info = pars_info_create();
|
||||||
@@ -3860,8 +4074,10 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
funct_exit:
|
funct_exit:
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
if (commit) {
|
||||||
|
trx_commit_for_mysql(trx);
|
||||||
|
}
|
||||||
|
|
||||||
if (UNIV_LIKELY_NULL(heap)) {
|
if (UNIV_LIKELY_NULL(heap)) {
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
@@ -4066,8 +4282,7 @@ row_check_table_for_mysql(
|
|||||||
if (!btr_validate_index(index, prebuilt->trx)) {
|
if (!btr_validate_index(index, prebuilt->trx)) {
|
||||||
ret = DB_ERROR;
|
ret = DB_ERROR;
|
||||||
} else {
|
} else {
|
||||||
if (!row_scan_and_check_index(prebuilt,
|
if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
|
||||||
index, &n_rows)) {
|
|
||||||
ret = DB_ERROR;
|
ret = DB_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4118,4 +4333,273 @@ row_check_table_for_mysql(
|
|||||||
|
|
||||||
return(ret);
|
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 */
|
#endif /* !UNIV_HOTBACKUP */
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ row_purge_remove_sec_if_poss_low(
|
|||||||
/* Not found */
|
/* Not found */
|
||||||
|
|
||||||
/* fputs("PURGE:........sec entry not found\n", stderr); */
|
/* fputs("PURGE:........sec entry not found\n", stderr); */
|
||||||
/* dtuple_print(entry); */
|
/* dtuple_print(stderr, entry); */
|
||||||
|
|
||||||
btr_pcur_close(&pcur);
|
btr_pcur_close(&pcur);
|
||||||
mtr_commit(&mtr);
|
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
|
When an insert or purge to a table is performed, this function builds
|
||||||
has to be inserted to an index on the table. */
|
the entry to be inserted into or purged from an index on the table. */
|
||||||
|
|
||||||
dtuple_t*
|
dtuple_t*
|
||||||
row_build_index_entry(
|
row_build_index_entry(
|
||||||
/*==================*/
|
/*==================*/
|
||||||
/* out: index entry which should be inserted */
|
/* out: index entry which should be
|
||||||
const dtuple_t* row, /* in: row which should be inserted to the
|
inserted or purged */
|
||||||
table */
|
const dtuple_t* row, /* in: row which should be
|
||||||
|
inserted or purged */
|
||||||
row_ext_t* ext, /* in: externally stored column prefixes,
|
row_ext_t* ext, /* in: externally stored column prefixes,
|
||||||
or NULL */
|
or NULL */
|
||||||
dict_index_t* index, /* in: index on the table */
|
dict_index_t* index, /* in: index on the table */
|
||||||
|
|||||||
183
row/row0uins.c
183
row/row0uins.c
@@ -28,6 +28,7 @@ Created 2/25/1997 Heikki Tuuri
|
|||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "ibuf0ibuf.h"
|
#include "ibuf0ibuf.h"
|
||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
|
#include "row0merge.h"
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Removes a clustered index record. The pcur in node was positioned on the
|
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);
|
ut_a(success);
|
||||||
|
|
||||||
if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
|
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
|
/* Drop the index tree associated with the row in
|
||||||
SYS_INDEXES table: */
|
SYS_INDEXES table: */
|
||||||
@@ -65,6 +85,14 @@ row_undo_ins_remove_clust_rec(
|
|||||||
success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
|
success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
|
||||||
&(node->pcur), &mtr);
|
&(node->pcur), &mtr);
|
||||||
ut_a(success);
|
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));
|
btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
|
||||||
@@ -211,6 +239,36 @@ retry:
|
|||||||
return(err);
|
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. */
|
Parses the row reference and other info in a fresh insert undo record. */
|
||||||
static
|
static
|
||||||
@@ -219,39 +277,67 @@ row_undo_ins_parse_undo_rec(
|
|||||||
/*========================*/
|
/*========================*/
|
||||||
undo_node_t* node) /* in: row undo node */
|
undo_node_t* node) /* in: row undo node */
|
||||||
{
|
{
|
||||||
dict_index_t* clust_index;
|
|
||||||
byte* ptr;
|
byte* ptr;
|
||||||
dulint undo_no;
|
|
||||||
dulint table_id;
|
dulint table_id;
|
||||||
ulint type;
|
|
||||||
ulint dummy;
|
|
||||||
ibool dummy_extern;
|
|
||||||
|
|
||||||
ut_ad(node);
|
ut_ad(node);
|
||||||
|
|
||||||
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
|
ptr = row_undo_ins_parse_rec_type_and_table_id(node, &table_id);
|
||||||
&dummy_extern, &undo_no, &table_id);
|
|
||||||
ut_ad(type == TRX_UNDO_INSERT_REC);
|
|
||||||
node->rec_type = type;
|
|
||||||
|
|
||||||
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 (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;
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locked_dictionary) {
|
||||||
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thawed_dictionary) {
|
||||||
|
row_mysql_freeze_data_dictionary(trx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->table->ibd_file_missing) {
|
|
||||||
/* We skip undo operations to missing .ibd files */
|
|
||||||
node->table = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
clust_index = dict_table_get_first_index(node->table);
|
|
||||||
|
|
||||||
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
|
|
||||||
node->heap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
@@ -265,44 +351,49 @@ row_undo_ins(
|
|||||||
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
|
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
|
||||||
undo_node_t* node) /* in: row undo node */
|
undo_node_t* node) /* in: row undo node */
|
||||||
{
|
{
|
||||||
dtuple_t* entry;
|
ulint err = DB_SUCCESS;
|
||||||
ibool found;
|
|
||||||
ulint err;
|
|
||||||
|
|
||||||
ut_ad(node);
|
ut_ad(node);
|
||||||
ut_ad(node->state == UNDO_NODE_INSERT);
|
ut_ad(node->state == UNDO_NODE_INSERT);
|
||||||
|
|
||||||
row_undo_ins_parse_undo_rec(node);
|
row_undo_ins_parse_undo_rec(node);
|
||||||
|
|
||||||
if (node->table == NULL) {
|
/* Dictionary records are undone in a separate function */
|
||||||
found = FALSE;
|
|
||||||
} else {
|
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
|
||||||
found = row_undo_search_clust_to_pcur(node);
|
|
||||||
}
|
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);
|
trx_undo_rec_release(node->trx, node->undo_no);
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
node->index = dict_table_get_next_index(
|
/* Iterate over all the indexes and undo the insert.*/
|
||||||
dict_table_get_first_index(node->table));
|
|
||||||
|
|
||||||
while (node->index != NULL) {
|
/* Skip the clustered index (the first index) */
|
||||||
entry = row_build_index_entry(node->row, node->ext,
|
node->index = dict_table_get_next_index(
|
||||||
node->index, node->heap);
|
dict_table_get_first_index(node->table));
|
||||||
err = row_undo_ins_remove_sec(node->index, entry);
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
while (node->index != NULL) {
|
||||||
|
dtuple_t* entry;
|
||||||
|
|
||||||
return(err);
|
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) {
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->index = dict_table_get_next_index(node->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
node->index = dict_table_get_next_index(node->index);
|
err = row_undo_ins_remove_clust_rec(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = row_undo_ins_remove_clust_rec(node);
|
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -426,7 +426,15 @@ row_undo_mod_del_unmark_sec_and_undo_update(
|
|||||||
log_free_check();
|
log_free_check();
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
|
|
||||||
found = row_search_index_entry(index, entry, mode, &pcur, &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) {
|
if (!found) {
|
||||||
fputs("InnoDB: error in sec index entry del undo in\n"
|
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 "row0umod.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
|
#include "row0merge.h"
|
||||||
|
|
||||||
/* How to undo row operations?
|
/* How to undo row operations?
|
||||||
(1) For an insert, we have stored a prefix of the clustered index record
|
(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->state = UNDO_NODE_FETCH_NEXT;
|
||||||
undo->trx = trx;
|
undo->trx = trx;
|
||||||
|
undo->rec_sub_type = TRX_UNDO_NULL_REC;
|
||||||
|
|
||||||
btr_pcur_init(&(undo->pcur));
|
btr_pcur_init(&(undo->pcur));
|
||||||
|
|
||||||
@@ -350,3 +352,352 @@ row_undo_step(
|
|||||||
|
|
||||||
return(thr);
|
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);
|
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. */
|
Reports in the undo log of an insert of a clustered index record. */
|
||||||
static
|
static
|
||||||
@@ -147,9 +246,6 @@ trx_undo_page_report_insert(
|
|||||||
{
|
{
|
||||||
ulint first_free;
|
ulint first_free;
|
||||||
byte* ptr;
|
byte* ptr;
|
||||||
ulint len;
|
|
||||||
const dfield_t* field;
|
|
||||||
ulint flen;
|
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
|
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
|
||||||
@@ -172,31 +268,24 @@ trx_undo_page_report_insert(
|
|||||||
ptr += 2;
|
ptr += 2;
|
||||||
|
|
||||||
/* Store first some general parameters to the undo log */
|
/* Store first some general parameters to the undo log */
|
||||||
mach_write_to_1(ptr, TRX_UNDO_INSERT_REC);
|
*ptr++ = TRX_UNDO_INSERT_REC;
|
||||||
ptr++;
|
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
||||||
|
ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
|
||||||
len = mach_dulint_write_much_compressed(ptr, trx->undo_no);
|
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
len = mach_dulint_write_much_compressed(ptr, (index->table)->id);
|
|
||||||
ptr += len;
|
|
||||||
/*----------------------------------------*/
|
/*----------------------------------------*/
|
||||||
/* Store then the fields required to uniquely determine the record
|
/* Store then the fields required to uniquely determine the record
|
||||||
to be inserted in the clustered index */
|
to be inserted in the clustered index */
|
||||||
|
|
||||||
for (i = 0; i < dict_index_get_n_unique(index); i++) {
|
for (i = 0; i < dict_index_get_n_unique(index); i++) {
|
||||||
|
|
||||||
field = dtuple_get_nth_field(clust_entry, i);
|
const dfield_t* field = dtuple_get_nth_field(clust_entry, i);
|
||||||
|
ulint flen = dfield_get_len(field);
|
||||||
flen = dfield_get_len(field);
|
|
||||||
|
|
||||||
if (trx_undo_left(undo_page, ptr) < 5) {
|
if (trx_undo_left(undo_page, ptr) < 5) {
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = mach_write_compressed(ptr, flen);
|
ptr += mach_write_compressed(ptr, flen);
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
if (flen != UNIV_SQL_NULL) {
|
if (flen != UNIV_SQL_NULL) {
|
||||||
if (trx_undo_left(undo_page, ptr) < flen) {
|
if (trx_undo_left(undo_page, ptr) < flen) {
|
||||||
@@ -209,27 +298,192 @@ trx_undo_page_report_insert(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------*/
|
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
|
||||||
/* Write pointers to the previous and the next undo log records */
|
}
|
||||||
|
|
||||||
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);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mach_write_to_2(ptr, first_free);
|
/* This is our internal dictionary undo log record. */
|
||||||
ptr += 2;
|
*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,
|
/* The sub type (discriminator) of this undo dictionary record */
|
||||||
ptr - undo_page);
|
*ptr++ = TRX_UNDO_INDEX_CREATE_REC;
|
||||||
|
|
||||||
/* Write the log entry to the REDO log of this change in the UNDO
|
/* For index create, we need both the table id and the index id
|
||||||
log */
|
to be stored in the undo log record.*/
|
||||||
trx_undof_page_add_undo_rec_log(undo_page, first_free,
|
|
||||||
ptr - undo_page, mtr);
|
ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
|
||||||
return(first_free);
|
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 */
|
dulint* table_id) /* out: table id */
|
||||||
{
|
{
|
||||||
byte* ptr;
|
byte* ptr;
|
||||||
ulint len;
|
|
||||||
ulint type_cmpl;
|
ulint type_cmpl;
|
||||||
|
|
||||||
ptr = undo_rec + 2;
|
ptr = undo_rec + 2;
|
||||||
@@ -270,12 +523,10 @@ trx_undo_rec_get_pars(
|
|||||||
*cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
|
*cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT;
|
||||||
|
|
||||||
*undo_no = mach_dulint_read_much_compressed(ptr);
|
*undo_no = mach_dulint_read_much_compressed(ptr);
|
||||||
len = mach_dulint_get_much_compressed_size(*undo_no);
|
ptr += mach_dulint_get_much_compressed_size(*undo_no);
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
*table_id = mach_dulint_read_much_compressed(ptr);
|
*table_id = mach_dulint_read_much_compressed(ptr);
|
||||||
len = mach_dulint_get_much_compressed_size(*table_id);
|
ptr += mach_dulint_get_much_compressed_size(*table_id);
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
@@ -671,8 +922,6 @@ trx_undo_update_rec_get_sys_cols(
|
|||||||
dulint* roll_ptr, /* out: roll ptr */
|
dulint* roll_ptr, /* out: roll ptr */
|
||||||
ulint* info_bits) /* out: info bits state */
|
ulint* info_bits) /* out: info bits state */
|
||||||
{
|
{
|
||||||
ulint len;
|
|
||||||
|
|
||||||
/* Read the state of the info bits */
|
/* Read the state of the info bits */
|
||||||
*info_bits = mach_read_from_1(ptr);
|
*info_bits = mach_read_from_1(ptr);
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
@@ -680,12 +929,10 @@ trx_undo_update_rec_get_sys_cols(
|
|||||||
/* Read the values of the system columns */
|
/* Read the values of the system columns */
|
||||||
|
|
||||||
*trx_id = mach_dulint_read_compressed(ptr);
|
*trx_id = mach_dulint_read_compressed(ptr);
|
||||||
len = mach_dulint_get_compressed_size(*trx_id);
|
ptr += mach_dulint_get_compressed_size(*trx_id);
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
*roll_ptr = mach_dulint_read_compressed(ptr);
|
*roll_ptr = mach_dulint_read_compressed(ptr);
|
||||||
len = mach_dulint_get_compressed_size(*roll_ptr);
|
ptr += mach_dulint_get_compressed_size(*roll_ptr);
|
||||||
ptr += len;
|
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
@@ -1142,6 +1389,189 @@ trx_undo_report_row_operation(
|
|||||||
return(DB_SUCCESS);
|
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 ===============*/
|
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|||||||
@@ -425,7 +425,8 @@ trx_rollback_or_clean_all_without_sess(
|
|||||||
dict_table_t* table;
|
dict_table_t* table;
|
||||||
ib_longlong rows_to_undo;
|
ib_longlong rows_to_undo;
|
||||||
const char* unit = "";
|
const char* unit = "";
|
||||||
int err;
|
int err = DB_SUCCESS;
|
||||||
|
ibool dictionary_locked = FALSE;
|
||||||
|
|
||||||
mutex_enter(&kernel_mutex);
|
mutex_enter(&kernel_mutex);
|
||||||
|
|
||||||
@@ -530,8 +531,10 @@ loop:
|
|||||||
|
|
||||||
trx->mysql_process_no = os_proc_get_number();
|
trx->mysql_process_no = os_proc_get_number();
|
||||||
|
|
||||||
|
/* TODO: Doesn't seem right */
|
||||||
if (trx->dict_operation) {
|
if (trx->dict_operation) {
|
||||||
row_mysql_lock_data_dictionary(trx);
|
row_mysql_lock_data_dictionary(trx);
|
||||||
|
dictionary_locked = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
que_run_threads(thr);
|
que_run_threads(thr);
|
||||||
@@ -552,7 +555,8 @@ loop:
|
|||||||
|
|
||||||
mutex_exit(&kernel_mutex);
|
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
|
/* If the transaction was for a dictionary operation, we
|
||||||
drop the relevant table, if it still exists */
|
drop the relevant table, if it still exists */
|
||||||
|
|
||||||
@@ -573,9 +577,35 @@ loop:
|
|||||||
|
|
||||||
ut_a(err == (int) DB_SUCCESS);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (trx->dict_operation) {
|
if (dictionary_locked) {
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,7 +1275,11 @@ trx_finish_rollback_off_kernel(
|
|||||||
}
|
}
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
trx_commit_off_kernel(trx);
|
/* 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
|
/* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and
|
||||||
send reply messages to them */
|
send reply messages to them */
|
||||||
|
|||||||
@@ -127,6 +127,10 @@ trx_create(
|
|||||||
trx->must_flush_log_later = FALSE;
|
trx->must_flush_log_later = FALSE;
|
||||||
|
|
||||||
trx->dict_operation = 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_thd = NULL;
|
||||||
trx->mysql_query_str = NULL;
|
trx->mysql_query_str = NULL;
|
||||||
@@ -153,6 +157,7 @@ trx_create(
|
|||||||
trx->undo_no_arr = NULL;
|
trx->undo_no_arr = NULL;
|
||||||
|
|
||||||
trx->error_state = DB_SUCCESS;
|
trx->error_state = DB_SUCCESS;
|
||||||
|
trx->error_key_num = 0;
|
||||||
trx->detailed_error[0] = '\0';
|
trx->detailed_error[0] = '\0';
|
||||||
|
|
||||||
trx->sess = sess;
|
trx->sess = sess;
|
||||||
@@ -349,6 +354,8 @@ trx_free(
|
|||||||
trx->global_read_view = NULL;
|
trx->global_read_view = NULL;
|
||||||
|
|
||||||
ut_a(trx->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);
|
mem_free(trx);
|
||||||
}
|
}
|
||||||
@@ -740,6 +747,10 @@ trx_commit_off_kernel(
|
|||||||
|
|
||||||
ut_ad(mutex_own(&kernel_mutex));
|
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;
|
trx->must_flush_log_later = FALSE;
|
||||||
|
|
||||||
rseg = trx->rseg;
|
rseg = trx->rseg;
|
||||||
@@ -1558,6 +1569,14 @@ trx_commit_for_mysql(
|
|||||||
|
|
||||||
ut_a(trx);
|
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";
|
trx->op_info = "committing";
|
||||||
|
|
||||||
/* If we are doing the XA recovery of prepared transactions, then
|
/* If we are doing the XA recovery of prepared transactions, then
|
||||||
@@ -1575,7 +1594,7 @@ trx_commit_for_mysql(
|
|||||||
|
|
||||||
trx->sess = trx_dummy_sess;
|
trx->sess = trx_dummy_sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&kernel_mutex);
|
mutex_exit(&kernel_mutex);
|
||||||
|
|
||||||
trx_start_if_not_started(trx);
|
trx_start_if_not_started(trx);
|
||||||
|
|||||||
Reference in New Issue
Block a user