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(
const byte* data;
ulint len;
ulint mtype;
ulint prtype;
ulint i;
ibool print_also_hex;
......@@ -396,6 +397,7 @@ dfield_print_also_hex(
}
mtype = dtype_get_mtype(dfield_get_type(dfield));
prtype = dtype_get_prtype(dfield_get_type(dfield));
if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
......@@ -403,12 +405,15 @@ dfield_print_also_hex(
for (i = 0; i < len; i++) {
int c = *data++;
if (!isprint(c)) {
print_also_hex = TRUE;
c = ' ';
}
fprintf(stderr, "\\x%02x", (unsigned char) c);
} else {
putc(c, stderr);
}
}
if (!print_also_hex) {
......@@ -422,13 +427,122 @@ dfield_print_also_hex(
for (i = 0; i < len; i++) {
fprintf(stderr, "%02lx", (ulint)*data);
data++;
}
} else if (mtype == DATA_BINARY) {
data = dfield_get_data(dfield);
fputs(" Hex: ",stderr);
for (i = 0; i < len; i++) {
fprintf(stderr, "%02lx", (ulint)*data);
data++;
}
} else if (mtype == DATA_INT) {
ut_a(len == 4); /* only works for 32-bit integers */
fprintf(stderr, "%d", (int)mach_read_from_4(data));
dulint big_val;
if (len == 1) {
ulint val;
val = (ulint)mach_read_from_1(data);
if (!(prtype & DATA_UNSIGNED)) {
val &= ~0x80;
fprintf(stderr, "%ld", (long) val);
} else {
ut_error;
fprintf(stderr, "%lu", (ulong) val);
}
} else if (len == 2) {
ulint val;
val = (ulint)mach_read_from_2(data);
if (!(prtype & DATA_UNSIGNED)) {
val &= ~0x8000;
fprintf(stderr, "%ld", (long) val);
} else {
fprintf(stderr, "%lu", (ulong) val);
}
} else if (len == 3) {
ulint val;
val = (ulint)mach_read_from_3(data);
if (!(prtype & DATA_UNSIGNED)) {
val &= ~0x800000;
fprintf(stderr, "%ld", (long) val);
} else {
fprintf(stderr, "%lu", (ulong) val);
}
} else if (len == 4) {
ulint val;
val = (ulint)mach_read_from_4(data);
if (!(prtype & DATA_UNSIGNED)) {
val &= ~0x80000000;
fprintf(stderr, "%ld", (long) val);
} else {
fprintf(stderr, "%lu", (ulong) val);
}
} else if (len == 6) {
big_val = (dulint)mach_read_from_6(data);
fprintf(stderr, "{%lu %lu}",
ut_dulint_get_high(big_val),
ut_dulint_get_low(big_val));
} else if (len == 7) {
big_val = (dulint)mach_read_from_7(data);
fprintf(stderr, "{%lu %lu}",
ut_dulint_get_high(big_val),
ut_dulint_get_low(big_val));
} else if (len == 8) {
big_val = (dulint)mach_read_from_8(data);
fprintf(stderr, "{%lu %lu}",
ut_dulint_get_high(big_val),
ut_dulint_get_low(big_val));
} else {
fputs(" Hex: ",stderr);
for (i = 0; i < len; i++) {
fprintf(stderr, "%02lx", (ulint)*data);
data++;
}
}
} else if (mtype == DATA_SYS) {
dulint id;
if (prtype & DATA_TRX_ID) {
id = mach_read_from_6(data);
fprintf(stderr, "trx_id {%lu %lu}",
ut_dulint_get_high(id), ut_dulint_get_low(id));
} else if (prtype & DATA_ROLL_PTR) {
id = mach_read_from_7(data);
fprintf(stderr, "roll_ptr {%lu %lu}",
ut_dulint_get_high(id), ut_dulint_get_low(id));
} else if (prtype & DATA_ROW_ID) {
id = mach_read_from_6(data);
fprintf(stderr, "row_id {%lu %lu}",
ut_dulint_get_high(id), ut_dulint_get_low(id));
} else {
id = mach_dulint_read_compressed(data);
fprintf(stderr, "mix_id {%lu %lu}",
ut_dulint_get_high(id), ut_dulint_get_low(id));
}
} else {
fputs(" Hex: ",stderr);
for (i = 0; i < len; i++) {
fprintf(stderr, "%02lx", (ulint)*data);
data++;
}
}
}
......
......@@ -540,7 +540,11 @@ dict_build_index_def_step(
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
|| dict_index_is_clust(index));
/* For fast index creation we have already allocated an index id
for this index so that we could write an UNDO log record for it.*/
if (ut_dulint_is_zero(index->id)) {
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
}
/* Inherit the space id from the table; we store all indexes of a
table in the same tablespace */
......@@ -552,6 +556,9 @@ dict_build_index_def_step(
ins_node_set_new_row(node->ind_def, row);
/* Note that the index was created by this transaction. */
index->trx_id = trx->id;
return(DB_SUCCESS);
}
......
This diff is collapsed.
......@@ -476,32 +476,12 @@ dict_load_columns(
mtr_commit(&mtr);
}
/************************************************************************
Report that an index field or index for a table has been delete marked. */
static
void
dict_load_report_deleted_index(
/*===========================*/
const char* name, /* in: table name */
ulint field) /* in: index field, or ULINT_UNDEFINED */
{
fprintf(stderr, "InnoDB: Error: data dictionary entry"
" for table %s is corrupt!\n", name);
if (field != ULINT_UNDEFINED) {
fprintf(stderr,
"InnoDB: Index field %lu is delete marked.\n", field);
} else {
fputs("InnoDB: An index is delete marked.\n", stderr);
}
}
/************************************************************************
Loads definitions for index fields. */
static
void
dict_load_fields(
/*=============*/
dict_table_t* table, /* in: table */
dict_index_t* index, /* in: index whose fields to load */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
......@@ -543,13 +523,18 @@ dict_load_fields(
rec = btr_pcur_get_rec(&pcur);
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
/* There could be delete marked records in SYS_FIELDS
because SYS_FIELDS.INDEX_ID can be updated
by ALTER TABLE ADD INDEX. */
if (rec_get_deleted_flag(rec, 0)) {
dict_load_report_deleted_index(table->name, i);
goto next_rec;
}
field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
ut_a(ut_memcmp(buf, field, len) == 0);
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
......@@ -584,6 +569,7 @@ dict_load_fields(
(char*) field, len),
prefix_len);
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
......@@ -662,16 +648,9 @@ dict_load_indexes(
if (ut_memcmp(buf, field, len) != 0) {
break;
}
if (rec_get_deleted_flag(rec, 0)) {
dict_load_report_deleted_index(table->name,
ULINT_UNDEFINED);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
return(FALSE);
} else if (rec_get_deleted_flag(rec, 0)) {
/* Skip delete marked records */
goto next_rec;
}
field = rec_get_nth_field_old(rec, 1, &len);
......@@ -714,12 +693,15 @@ dict_load_indexes(
if ((type & DICT_CLUSTERED) == 0
&& NULL == dict_table_get_first_index(table)) {
if (*table->name != TEMP_TABLE_PREFIX) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s"
" for table %s\n"
"InnoDB: Error: trying to"
" load index %s for table %s\n"
"InnoDB: but the first index"
" is not clustered!\n",
name_buf, table->name);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
......@@ -741,10 +723,11 @@ dict_load_indexes(
space, type, n_fields);
index->id = id;
dict_load_fields(table, index, heap);
dict_load_fields(index, heap);
dict_index_add_to_cache(table, index, page_no);
}
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
......
......@@ -62,6 +62,7 @@ dict_mem_table_create(
table->n_foreign_key_checks_running = 0;
table->cached = FALSE;
table->to_be_dropped = 0;
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
......@@ -75,6 +76,7 @@ dict_mem_table_create(
UT_LIST_INIT(table->locks);
UT_LIST_INIT(table->foreign_list);
UT_LIST_INIT(table->referenced_list);
UT_LIST_INIT(table->prebuilts);
#ifdef UNIV_DEBUG
table->does_not_fit_in_memory = FALSE;
......@@ -236,6 +238,7 @@ dict_mem_index_create(
heap = mem_heap_create(DICT_HEAP_SIZE);
index = mem_heap_alloc(heap, sizeof(dict_index_t));
index->id = ut_dulint_create(0, 0);
index->heap = heap;
index->type = type;
......@@ -253,6 +256,8 @@ dict_mem_index_create(
index->stat_n_diff_key_vals = NULL;
index->cached = FALSE;
index->to_be_dropped = FALSE;
index->trx_id = ut_dulint_create(0, 0);
memset(&index->lock, 0, sizeof index->lock);
#ifdef UNIV_DEBUG
index->magic_n = DICT_INDEX_MAGIC_N;
......
This diff is collapsed.
......@@ -85,13 +85,9 @@ class ha_innobase: public handler
const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
ulonglong table_flags() const { return int_table_flags; }
ulong index_flags(uint idx, uint part, bool all_parts) const
{
return (HA_READ_NEXT |
HA_READ_PREV |
HA_READ_ORDER |
HA_READ_RANGE |
HA_KEYREAD_ONLY);
ulong index_flags(uint idx, uint part, bool all_parts) const {
return(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
| HA_READ_RANGE | HA_KEYREAD_ONLY);
}
uint max_supported_keys() const { return MAX_KEY; }
/* An InnoDB page must store >= 2 keys;
......@@ -117,6 +113,7 @@ class ha_innobase: public handler
void try_semi_consistent_read(bool yes);
void unlock_row();
bool is_index_available(uint index);
int index_init(uint index, bool sorted);
int index_end();
int index_read(byte * buf, const byte * key,
......@@ -185,6 +182,10 @@ class ha_innobase: public handler
static ulonglong get_mysql_bin_log_pos();
bool primary_key_is_clustered() { return true; }
int cmp_ref(const byte *ref1, const byte *ref2);
int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
int prepare_drop_index(TABLE *table_arg, uint *key_num,
uint num_of_keys);
int final_drop_index(TABLE *table_arg);
bool check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes);
};
......
......@@ -279,8 +279,13 @@ dtuple_create(
ulint i;
for (i = 0; i < n_fields; i++) {
(tuple->fields + i)->data = &data_error;
dfield_get_type(tuple->fields + i)->mtype = DATA_ERROR;
dfield_t* field;
field = dtuple_get_nth_field(tuple, i);
dfield_set_len(field, UNIV_SQL_NULL);
field->data = &data_error;
dfield_get_type(field)->mtype = DATA_ERROR;
}
}
#endif
......
......@@ -62,6 +62,9 @@ Created 5/24/1996 Heikki Tuuri
activated by the operation would
lead to a duplicate key in some
table */
#define DB_CANNOT_DROP_FOREIGN_INDEX 47 /* we cannot drop an index because
it is needed on foreign key
constraint */
/* The following are partial failure codes */
#define DB_FAIL 1000
......
This diff is collapsed.
......@@ -647,28 +647,3 @@ dict_table_get_on_id_low(
return(table);
}
/**************************************************************************
Returns an index object. */
UNIV_INLINE
dict_index_t*
dict_table_get_index(
/*=================*/
/* out: index, NULL if does not exist */
dict_table_t* table, /* in: table */
const char* name) /* in: index name */
{
dict_index_t* index = NULL;
index = dict_table_get_first_index(table);
while (index != NULL) {
if (ut_strcmp(name, index->name) == 0) {
break;
}
index = dict_table_get_next_index(index);
}
return(index);
}
......@@ -13,6 +13,7 @@ Created 4/24/1996 Heikki Tuuri
#include "univ.i"
#include "dict0types.h"
#include "ut0byte.h"
#include "mem0mem.h"
/************************************************************************
In a crash recovery we already have all the tablespace objects created.
......
......@@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri
#include "lock0types.h"
#include "hash0hash.h"
#include "que0types.h"
#include "row0types.h"
/* Type flags of an index: OR'ing of the flags is allowed to define a
combination of types */
......@@ -32,6 +33,7 @@ combination of types */
#define DICT_UNIVERSAL 4 /* index which can contain records from any
other index */
#define DICT_IBUF 8 /* insert buffer tree */
#define DICT_NOT_READY 16 /* this index is being build */
/* Types for a table object */
#define DICT_TABLE_ORDINARY 1
......@@ -185,7 +187,7 @@ struct dict_index_struct{
dulint id; /* id of the index */
mem_heap_t* heap; /* memory heap */
ulint type; /* index type */
const char* name; /* index name */
char* name; /* index name */
const char* table_name; /* table name */
dict_table_t* table; /* back pointer to table */
unsigned space:32;
......@@ -207,6 +209,10 @@ struct dict_index_struct{
unsigned n_nullable:10;/* number of nullable fields */
unsigned cached:1;/* TRUE if the index object is in the
dictionary cache */
unsigned to_be_dropped:1;
/* TRUE if this index is marked to be
dropped in ha_innobase::prepare_drop_index(),
otherwise FALSE */
dict_field_t* fields; /* array of field descriptions */
UT_LIST_NODE_T(dict_index_t)
indexes;/* list of indexes of the table */
......@@ -224,6 +230,9 @@ struct dict_index_struct{
index tree */
rw_lock_t lock; /* read-write lock protecting the upper levels
of the index tree */
dulint trx_id; /* id of the transaction that created this
index. It can be zero which implies that
it was created on database startup.*/
#ifdef UNIV_DEBUG
ulint magic_n;/* magic number */
# define DICT_INDEX_MAGIC_N 76789786
......@@ -290,6 +299,14 @@ struct dict_table_struct{
innodb_file_per_table is defined in my.cnf;
in Unix this is usually /tmp/..., in Windows
\temp\... */
unsigned version_number:32;
/* version number of this table definition.
Version number is 0 when table is created.
Every schema change implemented without
creating a new table and copying rows from
the old table to new table will increase this
number. For example adding or removing index,
adding or removing a column. */
unsigned space:32;
/* space where the clustered index of the
table is placed */
......@@ -303,6 +320,8 @@ struct dict_table_struct{
calls DISCARD TABLESPACE on this
table, and reset to FALSE in IMPORT
TABLESPACE */
unsigned to_be_dropped:1; /* if set then this table will
dropped when n_mysql_handles_opened is 0 */
unsigned cached:1;/* TRUE if the table object has been added
to the dictionary cache */
unsigned flags:8;/* DICT_TF_COMPACT, ... */
......@@ -406,6 +425,10 @@ struct dict_table_struct{
SELECT MAX(auto inc column) */
ib_longlong autoinc;/* autoinc counter value to give to the
next inserted row */
/*----------------------*/
UT_LIST_BASE_NODE_T(row_prebuilt_t) prebuilts;
/* base node for the prebuilts defined
for the table */
#ifdef UNIV_DEBUG
ulint magic_n;/* magic number */
# define DICT_TABLE_MAGIC_N 76333786
......
......@@ -9,6 +9,8 @@ Created 1/8/1996 Heikki Tuuri
#ifndef dict0types_h
#define dict0types_h
#include "ut0list.h"
typedef struct dict_sys_struct dict_sys_t;
typedef struct dict_col_struct dict_col_t;
typedef struct dict_field_struct dict_field_t;
......@@ -24,4 +26,48 @@ typedef dict_table_t dict_cluster_t;
typedef struct ind_node_struct ind_node_t;
typedef struct tab_node_struct tab_node_t;
/* Data types for dict_undo */
union dict_undo_data_union {
dict_index_t* index; /* The index to be dropped */
struct {
dict_table_t* old_table; /* All fields are required only for*/
dict_table_t* tmp_table; /*RENAME, for CREATE and DROP we */
dict_table_t* new_table; /*use only old_table */
} table;
};
typedef union dict_undo_data_union dict_undo_data_t;
/* During recovery these are the operations that need to be undone */
struct dict_undo_struct {
ulint op_type; /* Discriminator one of :
TRX_UNDO_INDEX_CREATE_REC,
TRX_UNDO_TABLE_DROP_REC,
TRX_UNDO_TABLE_CREATE_REC,
TRX_UNDO_TABLE_RENAME_REC.*/
dict_undo_data_t
data; /* Data required for UNDO */
UT_LIST_NODE_T(struct dict_undo_struct)
node; /* UNDO list node */
};
typedef struct dict_undo_struct dict_undo_t;
typedef UT_LIST_BASE_NODE_T(dict_undo_t) dict_undo_list_t;
/* TODO: Currently this data structure is a place holder for indexes
created by a transaction.* The REDO is a misnomer*/
struct dict_redo_struct {
ulint op_type; /* Discriminator one of :
TRX_UNDO_INDEX_CREATE_REC.*/
dict_index_t* index; /* The index created.*/
UT_LIST_NODE_T(struct dict_redo_struct)
node; /* REDO list node */
};
typedef struct dict_redo_struct dict_redo_t;
typedef UT_LIST_BASE_NODE_T(dict_redo_t) dict_redo_list_t;
#endif
......@@ -73,6 +73,12 @@ heap creation. */
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
#define mem_heap_create_noninline(N) mem_heap_create_func_noninline(\
(N), MEM_HEAP_DYNAMIC, __FILE__, __LINE__)
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
#define mem_heap_create_in_buffer(N) mem_heap_create_func(\
(N), MEM_HEAP_BUFFER, __FILE__, __LINE__)
/******************************************************************
......@@ -89,6 +95,12 @@ heap freeing. */
#define mem_heap_free(heap) mem_heap_free_func(\
(heap), __FILE__, __LINE__)
/******************************************************************
Use this macro instead of the corresponding function! Macro for memory
heap freeing. */
#define mem_heap_free_noninline(heap) mem_heap_free_func_noninline(\
(heap), __FILE__, __LINE__)
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap. For debugging purposes, takes also the file name and line as
......@@ -118,6 +130,37 @@ mem_heap_free_func(
mem_heap_t* heap, /* in, own: heap to be freed */
const char* file_name, /* in: file name where freed */
ulint line); /* in: line where freed */
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap. For debugging purposes, takes also the file name and line as
arguments. */
mem_heap_t*
mem_heap_create_func_noninline(
/*===========================*/
/* out, own: memory heap, NULL if
did not succeed (only possible for
MEM_HEAP_BTR_SEARCH type heaps)*/
ulint n, /* in: desired start block size,
this means that a single user buffer
of size n will fit in the block,
0 creates a default size block;
if init_block is not NULL, n tells
its size in bytes */
ulint type, /* in: heap type */
const char* file_name, /* in: file name where created */
ulint line); /* in: line where created */
/*********************************************************************
NOTE: Use the corresponding macro instead of this function. Frees the space
occupied by a memory heap. In the debug version erases the heap memory
blocks. */
void
mem_heap_free_func_noninline(
/*=========================*/
mem_heap_t* heap, /* in, own: heap to be freed */
const char* file_name, /* in: file name where freed */
ulint line); /* in: line where freed */
/*******************************************************************
Allocates n bytes of memory from a memory heap. */
UNIV_INLINE
......@@ -131,6 +174,19 @@ mem_heap_alloc(
ulint n); /* in: number of bytes; if the heap is allowed
to grow into the buffer pool, this must be
<= MEM_MAX_ALLOC_IN_BUF */
/*******************************************************************
Allocates n bytes of memory from a memory heap. */
void*
mem_heap_alloc_noninline(
/*=====================*/
/* out: allocated storage, NULL if did not
succeed (only possible for
MEM_HEAP_BTR_SEARCH type heaps) */
mem_heap_t* heap, /* in: memory heap */
ulint n); /* in: number of bytes; if the heap is allowed
to grow into the buffer pool, this must be
<= MEM_MAX_ALLOC_IN_BUF */
/*********************************************************************
Returns a pointer to the heap top. */
UNIV_INLINE
......@@ -193,6 +249,12 @@ Macro for memory buffer allocation */
#define mem_alloc_noninline(N) mem_alloc_func_noninline(\
(N), __FILE__, __LINE__)
/******************************************************************
Use this macro instead of the corresponding function!
Macro for memory buffer allocation */
#define mem_free_noninline(N) mem_free_func_noninline(\
(N), __FILE__, __LINE__)
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Allocates a single buffer of memory from the dynamic memory of
......@@ -238,6 +300,18 @@ mem_free_func(
const char* file_name, /* in: file name where created */
ulint line /* in: line where created */
);
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Frees a single buffer of storage from
the dynamic memory of C compiler. Similar to free of C. */
void
mem_free_func_noninline(
/*====================*/
void* ptr, /* in, own: buffer to be freed */
const char* file_name, /* in: file name where created */
ulint line /* in: line where created */
);
/**************************************************************************
Duplicates a NUL-terminated string. */
......
......@@ -729,4 +729,15 @@ os_file_get_status(
os_file_stat_t* stat_info); /* information of a file in a
directory */
#if !defined(UNIV_HOTBACKUP) && !defined(__NETWARE__)
/*************************************************************************
Creates a temporary file that will be deleted on close.
This function is defined in ha_innodb.cc. */
int
innobase_mysql_tmpfile(void);
/*========================*/
/* out: temporary file descriptor, or < 0 on error */
#endif /* !UNIV_HOTBACKUP && !__NETWARE__ */
#endif
......@@ -93,6 +93,13 @@ row_ins_step(
/*=========*/
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/***************************************************************
Creates an entry template for each index of a table. */
void
ins_node_create_entry_list(
/*=======================*/
ins_node_t* node); /* in: row insert node */
/* Insert node structure */
......@@ -112,6 +119,11 @@ struct ins_node_struct{
this should be reset to NULL */
UT_LIST_BASE_NODE_T(dtuple_t)
entry_list;/* list of entries, one for each index */
ulint table_version_number;
/* entry_list is created for this version
of the table. If this version is not same
as table->version_number, entry_list must
be re-created. */
byte* row_id_buf;/* buffer for the row id sys field in row */
dulint trx_id; /* trx id or the last trx which executed the
node */
......
/******************************************************
Index build routines using a merge sort
(c) 2005 Innobase Oy
Created 13/06/2005 Jan Lindstrom
*******************************************************/
#ifndef row0merge_h
#define row0merge_h
#include "univ.i"
#include "data0data.h"
#include "dict0types.h"
#include "trx0types.h"
#include "que0types.h"
#include "mtr0mtr.h"
#include "rem0types.h"
#include "rem0rec.h"
#include "read0types.h"
#include "btr0types.h"
#include "row0mysql.h"
/* Block size for I/O operations in merge sort */
#define MERGE_BLOCK_SIZE 1048576 /* 1M */
/* Intentional free space on every block */
#define MERGE_BLOCK_SAFETY_MARGIN 128
/* Enable faster index creation debug code */
/* #define UNIV_DEBUG_INDEX_CREATE 1 */
/* This block header structure is used to create linked list of the
blocks to the disk. Every block contains one header.*/
struct merge_block_header_struct {
ulint n_records; /* Number of records in the block. */
dulint offset; /* Offset of this block in the disk. */
dulint next; /* Offset to next block in the disk. */
};
typedef struct merge_block_header_struct merge_block_header_t;
/* This block structure is used to hold index records in the disk
and the memory */
struct merge_block_struct {
merge_block_header_t header; /* Block header information */
char data[MERGE_BLOCK_SIZE - sizeof(merge_block_header_t)];/* Data area i.e. heap */
};
typedef struct merge_block_struct merge_block_t;
/* Records are stored in the memory for main memory linked list
to this structure */
struct merge_rec_struct {
struct merge_rec_struct *next; /* Pointer to next record
in the list */
rec_t* rec; /* Record */
};
typedef struct merge_rec_struct merge_rec_t;
/* This structure is head element for main memory linked list
used for main memory linked list merge sort */
struct merge_rec_list_struct {
merge_rec_t* head; /* Pointer to head of the
list */
merge_rec_t* tail; /* Pointer to tail of the
list */
ulint n_records; /* Number of records in
the list */
ulint total_size; /* Total size of all records in
the list */
mem_heap_t* heap; /* Heap where memory for this
list is allocated */
};
typedef struct merge_rec_list_struct merge_rec_list_t;
/* Information about temporary files used in merge sort are stored
to this structure */
struct merge_file_struct {
os_file_t file; /* File descriptor */
dulint offset; /* File offset */
ulint num_of_blocks; /* Number of blocks */
};
typedef struct merge_file_struct merge_file_t;
/* This structure holds parameters to thread which does a
disk based merge sort and inserts index records */
struct merge_thread_struct {
dict_index_t* index; /* in: Index to be created */
row_prebuilt_t* prebuilt; /* in: Prebuilt */
trx_t* trx; /* in: trx */
os_file_t file; /* in: File handle */
int error; /* out: error code or 0 */
};
typedef struct merge_thread_struct merge_thread_t;
/* This structure holds index field definitions */
struct merge_index_field_struct {
ulint col_type; /* Column type */
ulint prefix_len; /* Prefix len */
char* field_name; /* Field name */
};
typedef struct merge_index_field_struct merge_index_field_t;
/* This structure holds index definitions */
struct merge_index_def_struct {
ulint n_fields; /* Number of fields in index */
ulint ind_type; /* 0, DICT_UNIQUE or DICT_CLUSTERED */
char* name; /* Index name */
merge_index_field_t** fields; /* Field definitions */
};
typedef struct merge_index_def_struct merge_index_def_t;
/************************************************************************
Reads clustered index of the table and create temporary files
containing index entries for indexes to be built. */
ulint
row_merge_read_clustered_index(
/*===========================*/
/* out: DB_SUCCESS if successfull,
or ERROR code */
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: table where index is created */
dict_index_t** index, /* in: indexes to be created */
merge_file_t** files, /* in: Files where to write index
entries */
ulint num_of_idx); /* in: number of indexes to be
created */
/************************************************************************
Read sorted file containing index data tuples and insert these data
data tuples to the index */
ulint
row_merge_insert_index_tuples(
/*==========================*/
/* out: 0 or error number */
trx_t* trx, /* in: transaction */
dict_index_t* index, /* in: index */
dict_table_t* table, /* in: table */
os_file_t file, /* in: file handle */
dulint offset); /* in: offset where to start
reading */
/*****************************************************************
Merge sort for linked list in the disk. */
dulint
row_merge_sort_linked_list_in_disk(
/*===============================*/
/* out: offset to first block in
the list or ut_dulint_max in
case of error */
dict_index_t* index, /* in: index to be created */
os_file_t file, /* in: File handle */
int* error); /* out: 0 or error */
/*************************************************************************
Allocate and initialize memory for a merge file structure */
merge_file_t*
row_merge_create_file_structure(
/*============================*/
/* out: pointer to merge file
structure */
mem_heap_t* heap); /* in: heap where merge file structure
is allocated */
/*************************************************************************
A thread which merge sorts given file and inserts sorted records to
the index. */
#ifndef __WIN__
void *
#else
ulint
#endif
row_merge_sort_and_insert_thread(
/*=============================*/
/* out: a dummy parameter */
void* arg); /* in: parameters */
/*************************************************************************
Remove a index from system tables */
ulint
row_merge_remove_index(
/*===================*/
/* out: error code or DB_SUCCESS */
dict_index_t* index, /* in: index to be removed */
dict_table_t* table, /* in: table */
trx_t* trx); /* in: transaction handle */
/*************************************************************************
Print definition of a table in the dictionary */
void
row_merge_print_table(
/*==================*/
dict_table_t* table); /* in: table */
/*************************************************************************
Mark all prebuilts using the table obsolete. These prebuilts are
rebuilded later. */
void
row_merge_mark_prebuilt_obsolete(
/*=============================*/
trx_t* trx, /* in: trx */
dict_table_t* table); /* in: table */
/*************************************************************************
Create a temporary table using a definition of the old table. You must
lock data dictionary before calling this function. */
dict_table_t*
row_merge_create_temporary_table(
/*=============================*/
/* out: new temporary table
definition */
const char* table_name, /* in: new table name */
dict_table_t* table, /* in: old table definition */
trx_t* trx, /* in: trx */
ulint* error); /* in:out/ error code or DB_SUCCESS */
/*************************************************************************
Update all prebuilts for this table */
void
row_merge_prebuilts_update(
/*=======================*/
trx_t* trx, /* in: trx */
dict_table_t* old_table); /* in: old table */
/*************************************************************************
Create a temporary table using a definition of the old table. You must
lock data dictionary before calling this function. */
dict_table_t*
row_merge_create_temporary_table(
/*=============================*/
/* out: new temporary table
definition */
const char* table_name, /* in: new table name */
dict_table_t* table, /* in: old table definition */
trx_t* trx, /* in: trx */
ulint* error); /* in:out/ error code or DB_SUCCESS */
/*************************************************************************
Rename the indexes in the dicitionary. */
ulint
row_merge_rename_index(
/*===================*/
/* out: DB_SUCCESS if all OK */
trx_t* trx, /* in: Transaction */
dict_table_t* table, /* in: Table for index */
dict_index_t* index); /* in: Index to rename */
/*************************************************************************
Create the index and load in to the dicitionary. */
ulint
row_merge_create_index(
/*===================*/
/* out: DB_SUCCESS if all OK */
trx_t* trx, /* in: transaction */
dict_index_t** index, /* out: the instance of the index */
dict_table_t* table, /* in: the index is on this table */
const merge_index_def_t* /* in: the index definition */
index_def);
/*************************************************************************
Check if a transaction can use an index.*/
ibool
row_merge_is_index_usable(
/*======================*/
/* out: TRUE if index can be used by
the transaction else FALSE*/
const trx_t* trx, /* in: transaction */
const dict_index_t* /* in: index to check */
index);
/*************************************************************************
If there are views that refer to the old table name then we "attach" to
the new instance of the table else we drop it immediately.*/
ulint
row_merge_drop_table(
/*=================*/
/* out: DB_SUCCESS if all OK else
error code.*/
trx_t* trx, /* in: transaction */
dict_table_t* table); /* in: table instance to drop */
#endif /* row0merge.h */
......@@ -21,7 +21,7 @@ Created 9/17/2000 Heikki Tuuri
extern ibool row_rollback_on_timeout;
typedef struct row_prebuilt_struct row_prebuilt_t;
/* typedef struct row_prebuilt_struct row_prebuilt_t; */
/***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
......@@ -153,6 +153,14 @@ row_update_prebuilt_trx(
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
handle */
trx_t* trx); /* in: transaction handle */
/************************************************************************
Update a prebuilt struct for a MySQL table handle. */
void
row_update_prebuilt(
/*================*/
row_prebuilt_t* prebuilt, /* in: Innobase table handle */
dict_table_t* table); /* in: table */
/*************************************************************************
Unlocks an AUTO_INC type lock possibly reserved by trx. */
......@@ -188,6 +196,16 @@ row_lock_table_for_mysql(
prebuilt->select_lock_type */
ulint mode); /* in: lock mode of table
(ignored if table==NULL) */
/*************************************************************************
Sets a table lock on the table. */
int
row_lock_table_for_merge(
/*=====================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: lock table for this trx */
dict_table_t* table, /* in: table to lock */
ulint mode); /* in: lock mode of table */
/*************************************************************************
Does an insert for MySQL. */
......@@ -413,6 +431,19 @@ row_drop_table_for_mysql(
ibool drop_db);/* in: TRUE=dropping whole database */
/*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends to
characters INNODB_MONITOR, then this also stops printing of monitor
output by the master thread. But does not commit the transaction, this
is required for UNDOing dictionary records during recovery.*/
int
row_drop_table_for_mysql_no_commit(
/*===============================*/
/* out: error code or DB_SUCCESS */
const char* name, /* in: table name */
trx_t* trx, /* in: transaction handle */
ibool drop_db);/* in: TRUE=dropping whole database */
/*************************************************************************
Discards the tablespace of a table which stored in an .ibd file. Discarding
means that this function deletes the .ibd file and assigns a new table id for
the table. Also the flag table->ibd_file_missing is set TRUE. */
......@@ -451,7 +482,8 @@ row_rename_table_for_mysql(
/* out: error code or DB_SUCCESS */
const char* old_name, /* in: old table name */
const char* new_name, /* in: new table name */
trx_t* trx); /* in: transaction handle */
trx_t* trx, /* in: transaction handle */
ibool commit); /* in: if TRUE then commit trx */
/*************************************************************************
Checks a table for corruption. */
......@@ -462,7 +494,93 @@ row_check_table_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */
#endif /* !UNIV_HOTBACKUP */
/*************************************************************************
Build new indexes to a table by reading a cluster index,
creating a temporary file containing index entries, merge sorting
these index entries and inserting sorted index entries to indexes. */
ulint
row_build_index_for_mysql(
/*====================*/
/* out: 0 or error code */
trx_t* trx, /* in: transaction */
dict_table_t* old_table, /* in: Table where rows are
read from */
dict_table_t* new_table, /* in: Table where indexes are
created. Note that old_table ==
new_table if we are creating a
secondary keys. */
dict_index_t** index, /* in: Indexes to be created */
ibool new_primary, /* in: new primary key
i.e. clustered index will be build
for this table */
ulint num_of_keys); /* in: Number of indexes to be
created */
/*************************************************************************
Create query graph for a index creation */
ulint
row_create_index_graph_for_mysql(
/*=============================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: trx */
dict_table_t* table, /* in: table */
dict_index_t* index); /* in: index */
/*************************************************************************
Remove those indexes which were created before a error happened in
the index build */
ulint
row_remove_indexes_for_mysql(
/*=========================*/
/* out: 0 or error code */
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: Table where index is created */
dict_index_t** index, /* in: Indexes to be created */
ulint num_created); /* in: Number of indexes created
before error and now must be removed */
/***************************************************************************
Writes information to an undo log about dictionary operation, create_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* table_name); /* in: table name created. */
/***************************************************************************
Writes information to an undo log about dictionary operation, rename_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_index_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
dict_index_t* index); /* in: index created. */
/***************************************************************************
Writes information to an undo log about dictionary operation, rename_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_rename_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* from_table_name,/* in: rename from table name. */
const char* to_table_name, /* in: rename to table table. */
const char* tmp_table_name);/* in: intermediate table name */
/***************************************************************************
Writes information to an undo log about dictionary operation, drop table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_drop_table_dict_operation(
/*======================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: query thread */
const char* table_name); /* in: table name dropped */
/* A struct describing a place for an individual column in the MySQL
row format which is presented to the table handler in ha_innobase.
This template struct is used to speed up row transformations between
......@@ -512,16 +630,18 @@ struct mysql_row_templ_struct {
#define ROW_PREBUILT_ALLOCATED 78540783
#define ROW_PREBUILT_FREED 26423527
#define ROW_PREBUILT_OBSOLETE 12367541
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
handle used within MySQL; these are used to save CPU time. */
struct row_prebuilt_struct {
ulint magic_n; /* this magic number is set to
ROW_PREBUILT_ALLOCATED when created
and to ROW_PREBUILT_FREED when the
struct has been freed; used in
debugging */
ROW_PREBUILT_ALLOCATED when created,
or ROW_PREBUILT_FREED when the
struct has been freed or
ROW_PREBUILT_OBSOLETE when struct
needs a rebuilt */
dict_table_t* table; /* Innobase table handle */
trx_t* trx; /* current transaction handle */
ibool sql_stat_start; /* TRUE when we start processing of
......@@ -668,10 +788,12 @@ struct row_prebuilt_struct {
fetched row in fetch_cache */
ulint n_fetch_cached; /* number of not yet fetched rows
in fetch_cache */
mem_heap_t* blob_heap; /* in SELECTS BLOB fie lds are copied
mem_heap_t* blob_heap; /* in SELECTS BLOB fields are copied
to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */
UT_LIST_NODE_T(row_prebuilt_t) prebuilts;
/* list node of table->prebuilts */
ulint magic_n2; /* this should be the same as
magic_n */
};
......
......@@ -52,15 +52,16 @@ row_get_rec_roll_ptr(
dict_index_t* index, /* in: clustered index */
const ulint* offsets);/* in: rec_get_offsets(rec, index) */
/*********************************************************************
When an insert to a table is performed, this function builds the entry which
has to be inserted to an index on the table. */
When an insert or purge to a table is performed, this function builds
the entry to be inserted into or purged from an index on the table. */
dtuple_t*
row_build_index_entry(
/*==================*/
/* out: index entry which should be inserted */
const dtuple_t* row, /* in: row which should be inserted to the
table */
/* out: index entry which should be
inserted or purged */
const dtuple_t* row, /* in: row which should be
inserted or purged */
row_ext_t* ext, /* in: externally stored column prefixes,
or NULL */
dict_index_t* index, /* in: index on the table */
......
......@@ -36,4 +36,6 @@ typedef struct purge_node_struct purge_node_t;
typedef struct row_ext_struct row_ext_t;
typedef struct row_prebuilt_struct row_prebuilt_t;
#endif
......@@ -28,6 +28,15 @@ row_undo_ins(
/* out: DB_SUCCESS */
undo_node_t* node); /* in: row undo node */
/***************************************************************
Parses the rec_type undo record. */
byte*
row_undo_ins_parse_rec_type_and_table_id(
/*=====================================*/
/* out: ptr to next field to parse */
undo_node_t* node, /* in: row undo node */
dulint* table_id); /* out: table id */
#ifndef UNIV_NONINL
#include "row0uins.ic"
......
......@@ -51,6 +51,24 @@ row_undo_step(
/*==========*/
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/***************************************************************
Build the dict undo list*/
ulint
row_undo_build_dict_undo_list(
/*==========================*/
/* out: DB_SUCCESS or error code */
undo_node_t* node); /* in: row undo node */
/***************************************************************
Undo or redo a dictionary change */
ulint
row_undo_dictionary(
/*================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: the transaction */
dict_undo_t* dict_undo); /* in: dict op to undo */
/* A single query thread will try to perform the undo for all successive
versions of a clustered index record, if the transaction has modified it
......@@ -78,6 +96,20 @@ struct undo_node_struct{
dulint undo_no;/* undo number of the record */
ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
... */
ulint rec_sub_type; /* undo log record subtype:
used when rec_type is
TRX_UNDO_DICTIONARY_REC or 0*/
char* new_table_name;/* table name in
TRX_UNDO_TABLE_CREATE_REC or
TRX_UNDO_TABLE_RENAME_REC or
TRX_UNDO_TABLE_DROP_REC or NULL */
char* old_table_name;/* old table name in
TRX_UNDO_TABLE_RENAME_REC or NULL */
char* tmp_table_name; /* intermediate table name used
during rename & drop operation in
ha_innobase::add_index().*/
dulint index_id;/* index id in TRX_UNDO_INDEX_CREATE_REC
or ut_dulint_zero */
dulint new_roll_ptr; /* roll ptr to restore to clustered index
record */
dulint new_trx_id; /* trx id to restore to clustered index
......
......@@ -60,6 +60,17 @@ trx_undo_rec_get_undo_no(
/*=====================*/
/* out: undo no */
trx_undo_rec_t* undo_rec); /* in: undo log record */
/**************************************************************************
* Returns the start of the undo record data area. */
UNIV_INLINE
byte*
trx_undo_rec_get_ptr(
/*==================*/
/* out: compiler info */
trx_undo_rec_t* undo_rec, /* in: undo log record */
dulint undo_no); /* in: undo no read from node */
/**************************************************************************
Reads from an undo log record the general parameters. */
......@@ -201,6 +212,31 @@ trx_undo_report_row_operation(
inserted undo log record,
ut_dulint_zero if BTR_NO_UNDO_LOG
flag was specified */
/***************************************************************************
Writes information to an undo log about dictionary operation e.g.
rename_table, create_table, create_index, drop table. This information
is used in a rollback of the transaction. */
ulint
trx_undo_report_dict_operation(
/*===========================*/
/* out: DB_SUCCESS or error code */
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
TRX_UNDO_TABLE_RENAME_OP,
TRX_UNDO_TABLE_DROP_OP, or
TRX_UNDO_INDEX_CREATE_OP */
trx_t* trx, /* in: transaction */
dict_index_t* index, /* in:
if TRX_UNDO_INDEX_CREATE_OP
index to be created*/
const char* table_name, /* in: table name or NULL, used in
create table, rename table and
drop table*/
const char* old_table_name, /* in: old table name or NULL.
used in rename table */
const char* tmp_table_name, /* in: the intermediate name used */
dulint* roll_ptr); /* out: rollback pointer to the
inserted undo log record */
/**********************************************************************
Copies an undo record to heap. This function can be called if we know that
the undo log record exists. */
......@@ -279,6 +315,7 @@ trx_undo_parse_erase_page_end(
/* Types of an undo log record: these have to be smaller than 16, as the
compilation info multiplied by 16 is ORed to this value in an undo log
record */
#define TRX_UNDO_INSERT_REC 11 /* fresh insert into clustered index */
#define TRX_UNDO_UPD_EXIST_REC 12 /* update of a non-delete-marked
record */
......@@ -287,6 +324,9 @@ record */
fields of the record can change */
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
do not change */
#define TRX_UNDO_DICTIONARY_REC 15 /* dictionary operation, detailed
operation type can be found from
undo log records subtype */
#define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by
this and ORed to the type above */
#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
......@@ -294,9 +334,21 @@ record */
storage fields: used by purge to
free the external storage */
/* Operation type flags used in trx_undo_report_row_operation */
/* Operation type flags used in trx_undo_report_row_operation
and trx_undo_report_dict_operation */
#define TRX_UNDO_INSERT_OP 1
#define TRX_UNDO_MODIFY_OP 2
#define TRX_UNDO_INDEX_CREATE_OP 3 /* alter table add index */
#define TRX_UNDO_TABLE_CREATE_OP 4 /* create table */
#define TRX_UNDO_TABLE_RENAME_OP 5 /* rename table */
#define TRX_UNDO_TABLE_DROP_OP 6 /* drop table */
/* Subtypes for dictionary operation */
#define TRX_UNDO_NULL_REC 0 /* No subtype */
#define TRX_UNDO_INDEX_CREATE_REC 1 /* index create record */
#define TRX_UNDO_TABLE_CREATE_REC 2 /* table create record */
#define TRX_UNDO_TABLE_RENAME_REC 3 /* table rename record */
#define TRX_UNDO_TABLE_DROP_REC 4 /* table drop record */
#ifndef UNIV_NONINL
#include "trx0rec.ic"
......
......@@ -63,6 +63,20 @@ trx_undo_rec_get_undo_no(
return(mach_dulint_read_much_compressed(ptr));
}
/**************************************************************************
Returns the start of the undo record data area. */
UNIV_INLINE
byte*
trx_undo_rec_get_ptr(
/*=================*/
/* out: compiler info */
trx_undo_rec_t* undo_rec, /* in: undo log record */
dulint undo_no) /* in: undo no read from node */
{
return (((byte*) undo_rec) + 3
+ mach_dulint_get_much_compressed_size(undo_no));
}
/***************************************************************************
Copies the undo record to the heap. */
UNIV_INLINE
......
......@@ -450,8 +450,19 @@ struct trx_struct{
table. This is a hint that the table
may need to be dropped in crash
recovery. */
dulint table_id; /* table id if the preceding field is
TRUE */
dict_undo_list_t*
dict_undo_list; /* List of undo records are created
during recovery.*/
dict_redo_list_t*
dict_redo_list; /* List of indexes created by this
transaction.*/
ulint (*sync_cb)(trx_t*, ibool);
/* Transaction synchronization
callback, if ibool parameter is TRUE
then callback invoked for commit else
rollback.*/
dulint table_id; /* Table to drop iff dict_operation
is TRUE.*/
/*------------------------------*/
int active_trans; /* 1 - if a transaction in MySQL
is active. 2 - if prepare_commit_mutex
......@@ -567,6 +578,9 @@ struct trx_struct{
void* error_info; /* if the error number indicates a
duplicate key error, a pointer to
the problematic index is stored here */
ulint error_key_num; /* if the index creation fails to a
duplicate key error, a mysql key
number of that index is stored here */
sess_t* sess; /* session of the trx, NULL if none */
ulint que_state; /* TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
... */
......
......@@ -3678,7 +3678,9 @@ lock_table_enqueue_waiting(
trx = thr_get_trx(thr);
if (trx->dict_operation) {
/* We have little choice here during index merge operations, and so
we suppress the printing of the message.*/
if (trx->dict_operation && *table->name != TEMP_TABLE_PREFIX) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: a table lock wait happens"
" in a dictionary operation!\n"
......
......@@ -101,6 +101,21 @@ mem_alloc_func_noninline(
return(mem_alloc_func(n, file_name, line));
}
/*******************************************************************
NOTE: Use the corresponding macro instead of this function.
Frees a single buffer of storage from
the dynamic memory of C compiler. Similar to free of C. */
void
mem_free_func_noninline(
/*====================*/
void* ptr, /* in, own: buffer to be freed */
const char* file_name, /* in: file name where created */
ulint line) /* in: line where created */
{
return(mem_free_func(ptr, file_name, line));
}
/**************************************************************************
Duplicates a NUL-terminated string, allocated from a memory heap. */
......@@ -566,3 +581,60 @@ mem_validate_all_blocks(void)
mem_pool_mutex_exit();
}
#endif
/*******************************************************************
Allocates n bytes of memory from a memory heap. */
void*
mem_heap_alloc_noninline(
/*=====================*/
/* out: allocated storage, NULL if did not
succeed (only possible for
MEM_HEAP_BTR_SEARCH type heaps) */
mem_heap_t* heap, /* in: memory heap */
ulint n) /* in: number of bytes; if the heap is allowed
to grow into the buffer pool, this must be
<= MEM_MAX_ALLOC_IN_BUF */
{
return (mem_heap_alloc(heap, n));
}
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap. For debugging purposes, takes also the file name and line as
argument. */
mem_heap_t*
mem_heap_create_func_noninline(
/*===========================*/
/* out, own: memory heap, NULL if
did not succeed (only possible for
MEM_HEAP_BTR_SEARCH type heaps)*/
ulint n, /* in: desired start block size,
this means that a single user buffer
of size n will fit in the block,
0 creates a default size block;
if init_block is not NULL, n tells
its size in bytes */
ulint type, /* in: heap type */
const char* file_name, /* in: file name where created */
ulint line) /* in: line where created */
{
return(mem_heap_create_func(n, type, file_name, line));
}
/*********************************************************************
NOTE: Use the corresponding macro instead of this function. Frees the space
occupied by a memory heap. In the debug version erases the heap memory
blocks. */
void
mem_heap_free_func_noninline(
/*=========================*/
mem_heap_t* heap, /* in, own: heap to be freed */
const char* file_name __attribute__((unused)),
/* in: file name where freed */
ulint line __attribute__((unused)))
{
mem_heap_free_func(heap, file_name, line);
}
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;
create index id2 on t2 (id);
show create table t2;
drop index id2 on t2;
--error 1025,1025
--error 1540,1540
drop index id on t2;
show create table t2;
drop table t2;
......
......@@ -497,17 +497,6 @@ os_io_init_simple(void)
}
}
#if !defined(UNIV_HOTBACKUP) && !defined(__NETWARE__)
/*************************************************************************
Creates a temporary file that will be deleted on close.
This function is defined in ha_innodb.cc. */
int
innobase_mysql_tmpfile(void);
/*========================*/
/* out: temporary file descriptor, or < 0 on error */
#endif /* !UNIV_HOTBACKUP && !__NETWARE__ */
/***************************************************************************
Creates a temporary file. This function is like tmpfile(3), but
the temporary file is created in the MySQL temporary directory.
......
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,
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
......
......@@ -336,6 +336,9 @@ que_fork_start_command(
fork->last_sel_node = NULL;
suspended_thr = NULL;
completed_thr = NULL;
/* Choose the query thread to run: usually there is just one thread,
but in a parallelized select, which necessarily is non-scrollable,
there may be several to choose from */
......
......@@ -17,7 +17,7 @@ include ../include/Makefile.i
noinst_LIBRARIES = librow.a
librow_a_SOURCES = row0ext.c\
librow_a_SOURCES = row0ext.c row0merge.c\
row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\
row0uins.c row0umod.c row0undo.c row0upd.c row0vers.c
......
......@@ -103,7 +103,7 @@ ins_node_create(
/***************************************************************
Creates an entry template for each index of a table. */
static
void
ins_node_create_entry_list(
/*=======================*/
......
This diff is collapsed.
This diff is collapsed.
......@@ -227,7 +227,7 @@ row_purge_remove_sec_if_poss_low(
/* Not found */
/* fputs("PURGE:........sec entry not found\n", stderr); */
/* dtuple_print(entry); */
/* dtuple_print(stderr, entry); */
btr_pcur_close(&pcur);
mtr_commit(&mtr);
......
......@@ -57,15 +57,16 @@ row_get_trx_id_offset(
}
/*********************************************************************
When an insert to a table is performed, this function builds the entry which
has to be inserted to an index on the table. */
When an insert or purge to a table is performed, this function builds
the entry to be inserted into or purged from an index on the table. */
dtuple_t*
row_build_index_entry(
/*==================*/
/* out: index entry which should be inserted */
const dtuple_t* row, /* in: row which should be inserted to the
table */
/* out: index entry which should be
inserted or purged */
const dtuple_t* row, /* in: row which should be
inserted or purged */
row_ext_t* ext, /* in: externally stored column prefixes,
or NULL */
dict_index_t* index, /* in: index on the table */
......
......@@ -28,6 +28,7 @@ Created 2/25/1997 Heikki Tuuri
#include "que0que.h"
#include "ibuf0ibuf.h"
#include "log0log.h"
#include "row0merge.h"
/*******************************************************************
Removes a clustered index record. The pcur in node was positioned on the
......@@ -52,6 +53,25 @@ row_undo_ins_remove_clust_rec(
ut_a(success);
if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
trx_t* trx;
ibool thawed_dictionary = FALSE;
ibool locked_dictionary = FALSE;
trx = node->trx;
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
row_mysql_unfreeze_data_dictionary(trx);
thawed_dictionary = TRUE;
}
if (trx->dict_operation_lock_mode == 0
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
row_mysql_lock_data_dictionary(trx);
locked_dictionary = TRUE;
}
/* Drop the index tree associated with the row in
SYS_INDEXES table: */
......@@ -65,6 +85,14 @@ row_undo_ins_remove_clust_rec(
success = btr_pcur_restore_position(BTR_MODIFY_LEAF,
&(node->pcur), &mtr);
ut_a(success);
if (locked_dictionary) {
row_mysql_unlock_data_dictionary(trx);
}
if (thawed_dictionary) {
row_mysql_freeze_data_dictionary(trx);
}
}
btr_cur = btr_pcur_get_btr_cur(&(node->pcur));
......@@ -211,6 +239,36 @@ retry:
return(err);
}
/***************************************************************
Parses the rec_type undo record. */
byte*
row_undo_ins_parse_rec_type_and_table_id(
/*=====================================*/
/* out: ptr to next field to parse */
undo_node_t* node, /* in: row undo node */
dulint* table_id) /* out: table id */
{
byte* ptr;
dulint undo_no;
ulint type;
ulint dummy;
ibool dummy_extern;
ut_ad(node && node->trx);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
&dummy_extern, &undo_no, table_id);
node->rec_type = type;
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
node->trx->dict_operation = TRUE;
}
return ptr;
}
/***************************************************************
Parses the row reference and other info in a fresh insert undo record. */
static
......@@ -219,39 +277,67 @@ row_undo_ins_parse_undo_rec(
/*========================*/
undo_node_t* node) /* in: row undo node */
{
dict_index_t* clust_index;
byte* ptr;
dulint undo_no;
dulint table_id;
ulint type;
ulint dummy;
ibool dummy_extern;
ut_ad(node);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
&dummy_extern, &undo_no, &table_id);
ut_ad(type == TRX_UNDO_INSERT_REC);
node->rec_type = type;
ptr = row_undo_ins_parse_rec_type_and_table_id(node, &table_id);
node->table = dict_table_get_on_id(table_id, node->trx);
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC
|| node->rec_type == TRX_UNDO_DICTIONARY_REC);
if (node->table == NULL) {
if (node->rec_type == TRX_UNDO_INSERT_REC) {
return;
trx_t* trx;
ibool thawed_dictionary = FALSE;
ibool locked_dictionary = FALSE;
trx = node->trx;
/* If it's sytem table then we have to acquire the
dictionary lock in X mode.*/
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0) {
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
row_mysql_unfreeze_data_dictionary(trx);
thawed_dictionary = TRUE;
}
if (node->table->ibd_file_missing) {
/* We skip undo operations to missing .ibd files */
node->table = NULL;
if (trx->dict_operation_lock_mode == 0
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
return;
row_mysql_lock_data_dictionary(trx);
locked_dictionary = TRUE;
}
}
node->table = dict_table_get_on_id(table_id, trx);
/* If we can't find the table or .ibd file is missing,
we skip the UNDO.*/
if (node->table == NULL || node->table->ibd_file_missing) {
node->table = NULL;
} else {
dict_index_t* clust_index;
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
node->heap);
ptr = trx_undo_rec_get_row_ref(
ptr, clust_index, &node->ref, node->heap);
}
if (locked_dictionary) {
row_mysql_unlock_data_dictionary(trx);
}
if (thawed_dictionary) {
row_mysql_freeze_data_dictionary(trx);
}
}
}
/***************************************************************
......@@ -265,33 +351,37 @@ row_undo_ins(
/* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
undo_node_t* node) /* in: row undo node */
{
dtuple_t* entry;
ibool found;
ulint err;
ulint err = DB_SUCCESS;
ut_ad(node);
ut_ad(node->state == UNDO_NODE_INSERT);
row_undo_ins_parse_undo_rec(node);
if (node->table == NULL) {
found = FALSE;
} else {
found = row_undo_search_clust_to_pcur(node);
}
/* Dictionary records are undone in a separate function */
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
err = row_undo_build_dict_undo_list(node);
} else if (!node->table || !row_undo_search_clust_to_pcur(node)) {
if (!found) {
trx_undo_rec_release(node->trx, node->undo_no);
return(DB_SUCCESS);
}
} else {
/* Iterate over all the indexes and undo the insert.*/
/* Skip the clustered index (the first index) */
node->index = dict_table_get_next_index(
dict_table_get_first_index(node->table));
while (node->index != NULL) {
dtuple_t* entry;
entry = row_build_index_entry(node->row, node->ext,
node->index, node->heap);
err = row_undo_ins_remove_sec(node->index, entry);
if (err != DB_SUCCESS) {
......@@ -303,6 +393,7 @@ row_undo_ins(
}
err = row_undo_ins_remove_clust_rec(node);
}
return(err);
}
......@@ -426,7 +426,15 @@ row_undo_mod_del_unmark_sec_and_undo_update(
log_free_check();
mtr_start(&mtr);
/* Check if the index was created after this transaction was
started because then this index will not have the changes made
by this transaction.*/
if (*index->name != TEMP_TABLE_PREFIX) {
found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
} else {
return(err);
}
if (!found) {
fputs("InnoDB: error in sec index entry del undo in\n"
......
This diff is collapsed.
This diff is collapsed.
......@@ -425,7 +425,8 @@ trx_rollback_or_clean_all_without_sess(
dict_table_t* table;
ib_longlong rows_to_undo;
const char* unit = "";
int err;
int err = DB_SUCCESS;
ibool dictionary_locked = FALSE;
mutex_enter(&kernel_mutex);
......@@ -530,8 +531,10 @@ loop:
trx->mysql_process_no = os_proc_get_number();
/* TODO: Doesn't seem right */
if (trx->dict_operation) {
row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE;
}
que_run_threads(thr);
......@@ -552,7 +555,8 @@ loop:
mutex_exit(&kernel_mutex);
if (trx->dict_operation) {
if (trx->dict_operation && !ut_dulint_is_zero(trx->table_id)) {
/* If the transaction was for a dictionary operation, we
drop the relevant table, if it still exists */
......@@ -573,9 +577,35 @@ loop:
ut_a(err == (int) DB_SUCCESS);
}
} else if (trx->dict_undo_list) {
dict_undo_t* dict_undo;
ut_a(trx->dict_undo_list);
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
fputs("InnoDB: UNDO dict entries\n", stderr);
while (dict_undo && err == DB_SUCCESS) {
dict_undo = UT_LIST_GET_NEXT(node, dict_undo);
if (dict_undo) {
err = row_undo_dictionary(trx, dict_undo);
}
}
if (trx->dict_operation) {
ut_a(err == (int) DB_SUCCESS);
dict_undo_free_list(trx);
mutex_enter(&kernel_mutex);
trx_commit_off_kernel(trx);
mutex_exit(&kernel_mutex);
}
if (dictionary_locked) {
row_mysql_unlock_data_dictionary(trx);
}
......@@ -1245,7 +1275,11 @@ trx_finish_rollback_off_kernel(
}
#endif /* UNIV_DEBUG */
/* If there are dict UNDO records that need to be undone then
we commit the transaction after these dictionary changes are undone.*/
if (!trx->dict_undo_list) {
trx_commit_off_kernel(trx);
}
/* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and
send reply messages to them */
......
......@@ -127,6 +127,10 @@ trx_create(
trx->must_flush_log_later = FALSE;
trx->dict_operation = FALSE;
trx->table_id = ut_dulint_create(0, 0);
trx->dict_undo_list = NULL;
trx->dict_redo_list = NULL;
trx->sync_cb = NULL;
trx->mysql_thd = NULL;
trx->mysql_query_str = NULL;
......@@ -153,6 +157,7 @@ trx_create(
trx->undo_no_arr = NULL;
trx->error_state = DB_SUCCESS;
trx->error_key_num = 0;
trx->detailed_error[0] = '\0';
trx->sess = sess;
......@@ -349,6 +354,8 @@ trx_free(
trx->global_read_view = NULL;
ut_a(trx->read_view == NULL);
ut_a(trx->dict_undo_list == NULL);
ut_a(trx->dict_redo_list == NULL);
mem_free(trx);
}
......@@ -740,6 +747,10 @@ trx_commit_off_kernel(
ut_ad(mutex_own(&kernel_mutex));
/* Can't commit if we have dictionary UNDO records */
ut_a(!trx->dict_undo_list);
ut_a(!trx->dict_redo_list);
trx->must_flush_log_later = FALSE;
rseg = trx->rseg;
......@@ -1558,6 +1569,14 @@ trx_commit_for_mysql(
ut_a(trx);
if (trx->sync_cb) {
ulint err;
err = trx->sync_cb(trx, TRUE);
ut_a(err);
trx->sync_cb = NULL;
}
trx->op_info = "committing";
/* If we are doing the XA recovery of prepared transactions, then
......
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