Commit fc65b08f authored by marko's avatar marko

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.
parent 4d6805f2
...@@ -383,6 +383,7 @@ dfield_print_also_hex( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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);
} }
......
This diff is collapsed.
...@@ -476,32 +476,12 @@ dict_load_columns( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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;
......
This diff is collapsed.
...@@ -85,13 +85,9 @@ class ha_innobase: public handler ...@@ -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 ...@@ -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 ...@@ -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( ...@@ -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 ...@@ -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
......
This diff is collapsed.
...@@ -647,28 +647,3 @@ dict_table_get_on_id_low( ...@@ -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 ...@@ -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 ...@@ -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 */ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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{ ...@@ -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 ...@@ -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; ...@@ -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. */ ...@@ -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. */ ...@@ -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( ...@@ -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( ...@@ -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 */ ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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{ ...@@ -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 */
......
/******************************************************
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 ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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 { ...@@ -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 { ...@@ -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( ...@@ -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; ...@@ -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( ...@@ -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( ...@@ -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{ ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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{ ...@@ -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{ ...@@ -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( ...@@ -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( ...@@ -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) ...@@ -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);
}
This diff is collapsed.
-- 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; ...@@ -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;
......
...@@ -497,17 +497,6 @@ os_io_init_simple(void) ...@@ -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.
......
This diff is collapsed.
/* 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( ...@@ -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 ...@@ -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( ...@@ -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(
/*=======================*/ /*=======================*/
......
This diff is collapsed.
This diff is collapsed.
...@@ -227,7 +227,7 @@ row_purge_remove_sec_if_poss_low( ...@@ -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( ...@@ -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 */
......
...@@ -28,6 +28,7 @@ Created 2/25/1997 Heikki Tuuri ...@@ -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( ...@@ -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( ...@@ -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: ...@@ -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( ...@@ -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;
if (node->table->ibd_file_missing) { trx = node->trx;
/* We skip undo operations to missing .ibd files */
node->table = NULL;
return; /* 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);
clust_index = dict_table_get_first_index(node->table); /* 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) {
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref), node->table = NULL;
node->heap); } 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);
}
}
} }
/*************************************************************** /***************************************************************
...@@ -265,44 +351,49 @@ row_undo_ins( ...@@ -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 {
}
/* Iterate over all the indexes and undo the insert.*/
node->index = dict_table_get_next_index( /* Skip the clustered index (the first index) */
dict_table_get_first_index(node->table)); node->index = dict_table_get_next_index(
dict_table_get_first_index(node->table));
while (node->index != NULL) { while (node->index != NULL) {
entry = row_build_index_entry(node->row, node->ext, dtuple_t* entry;
node->index, node->heap);
err = row_undo_ins_remove_sec(node->index, entry);
if (err != DB_SUCCESS) { entry = row_build_index_entry(node->row, node->ext,
node->index, node->heap);
return(err); 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( ...@@ -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"
......
This diff is collapsed.
This diff is collapsed.
...@@ -425,7 +425,8 @@ trx_rollback_or_clean_all_without_sess( ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment