Apply InnoDB snapshot innodb-5.1-ss1726.

Bug #16979: AUTO_INC lock in InnoDB works a table level lock
  - this is a major change in InnoDB auto-inc handling.
Bug #27950: Duplicate entry error in auto-inc after mysqld restart
  - Init AUTOINC from delete_row().
Bug #28781: InnoDB increments auto-increment value incorrectly with ON DUPLICATE KEY UPDATE
  - Use value specified by MySQL, in update_row().
parent 7f429ecc
......@@ -501,7 +501,7 @@ ERROR 23000: Duplicate entry 'test2' for key 'ggid'
select * from t1;
id ggid email passwd
1 this will work
3 test2 this will work
4 test2 this will work
select * from t1 where id=1;
id ggid email passwd
1 this will work
......
......@@ -410,14 +410,27 @@ dict_table_get_col_name(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
s = table->col_names;
if (s) {
for (i = 0; i < col_nr; i++) {
s += strlen(s) + 1;
}
}
return(s);
}
/************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table)
{
mutex_enter(&table->autoinc_mutex);
}
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
......@@ -428,54 +441,8 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */
ib_longlong value) /* in: next value to assign to a row */
{
mutex_enter(&(table->autoinc_mutex));
table->autoinc_inited = TRUE;
table->autoinc = value;
mutex_exit(&(table->autoinc_mutex));
}
/************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
table->autoinc = table->autoinc + 1;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table) /* in: table */
{
mutex_enter(&(table->autoinc_mutex));
table->autoinc = table->autoinc - 1;
mutex_exit(&(table->autoinc_mutex));
}
/************************************************************************
......@@ -490,8 +457,6 @@ dict_table_autoinc_read(
{
ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
......@@ -499,35 +464,11 @@ dict_table_autoinc_read(
value = table->autoinc;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table) /* in: table */
{
ib_longlong value;
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
}
return(value);
}
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the
Updates the autoinc counter if the value supplied is greater than the
current value. If not inited, does nothing. */
void
......@@ -537,15 +478,21 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */
ib_longlong value) /* in: value which was assigned to a row */
{
mutex_enter(&(table->autoinc_mutex));
if (table->autoinc_inited && value > table->autoinc) {
if (table->autoinc_inited) {
if (value >= table->autoinc) {
table->autoinc = value + 1;
}
table->autoinc = value;
}
}
mutex_exit(&(table->autoinc_mutex));
/************************************************************************
Release the autoinc lock.*/
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table) /* in: release autoinc lock for this table */
{
mutex_exit(&table->autoinc_mutex);
}
/************************************************************************
......@@ -842,28 +789,18 @@ dict_table_get(
}
/**************************************************************************
Adds a table object to the dictionary cache. */
Adds system columns to a table object. */
void
dict_table_add_to_cache(
/*====================*/
dict_table_t* table) /* in: table */
dict_table_add_system_columns(
/*==========================*/
dict_table_t* table, /* in/out: table */
mem_heap_t* heap) /* in: temporary heap */
{
ulint fold;
ulint id_fold;
ulint i;
ulint row_len;
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(table->cached == FALSE);
fold = ut_fold_string(table->name);
id_fold = ut_fold_dulint(table->id);
table->cached = TRUE;
ut_ad(!table->cached);
/* NOTE: the system columns MUST be added in the following order
(so that they can be indexed by the numerical value of DATA_ROW_ID,
......@@ -871,19 +808,19 @@ dict_table_add_to_cache(
The clustered index will not always physically contain all
system columns. */
dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS,
dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
DATA_ROW_ID | DATA_NOT_NULL,
DATA_ROW_ID_LEN);
#if DATA_ROW_ID != 0
#error "DATA_ROW_ID != 0"
#endif
dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS,
dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
DATA_TRX_ID | DATA_NOT_NULL,
DATA_TRX_ID_LEN);
#if DATA_TRX_ID != 1
#error "DATA_TRX_ID != 1"
#endif
dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS,
dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
DATA_ROLL_PTR | DATA_NOT_NULL,
DATA_ROLL_PTR_LEN);
#if DATA_ROLL_PTR != 2
......@@ -895,10 +832,34 @@ dict_table_add_to_cache(
#if DATA_N_SYS_COLS != 3
#error "DATA_N_SYS_COLS != 3"
#endif
}
/**************************************************************************
Adds a table object to the dictionary cache. */
void
dict_table_add_to_cache(
/*====================*/
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: temporary heap */
{
ulint fold;
ulint id_fold;
ulint i;
ulint row_len;
/* The lower limit for what we consider a "big" row */
#define BIG_ROW_SIZE 1024
ut_ad(mutex_own(&(dict_sys->mutex)));
dict_table_add_system_columns(table, heap);
table->cached = TRUE;
fold = ut_fold_string(table->name);
id_fold = ut_fold_dulint(table->id);
row_len = 0;
for (i = 0; i < table->n_def; i++) {
ulint col_len = dict_col_get_max_size(
......
......@@ -90,6 +90,11 @@ dict_mem_table_create(
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc_inited = FALSE;
/* The actual increment value will be set by MySQL, we simply
default to 1 here.*/
table->autoinc_increment = 1;
#ifdef UNIV_DEBUG
table->magic_n = DICT_TABLE_MAGIC_N;
#endif /* UNIV_DEBUG */
......@@ -108,18 +113,11 @@ dict_mem_table_free(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
mutex_free(&(table->autoinc_mutex));
if (table->col_names && (table->n_def < table->n_cols)) {
ut_free((void*)table->col_names);
}
mem_heap_free(table->heap);
}
/********************************************************************
Add 'name' to end of the col_names array (see dict_table_t::col_names). Call
ut_free on col_names (if not NULL), allocate new array (if heap, from it,
otherwise with ut_malloc), and copy col_names + name to it. */
Append 'name' to 'col_names' (@see dict_table_t::col_names). */
static
const char*
dict_add_col_name(
......@@ -129,21 +127,19 @@ dict_add_col_name(
NULL */
ulint cols, /* in: number of existing columns */
const char* name, /* in: new column name */
mem_heap_t* heap) /* in: heap, or NULL */
mem_heap_t* heap) /* in: heap */
{
ulint i;
ulint old_len;
ulint new_len;
ulint total_len;
const char* s;
char* res;
ut_a(((cols == 0) && !col_names) || ((cols > 0) && col_names));
ut_a(*name);
ut_ad(!cols == !col_names);
/* Find out length of existing array. */
if (col_names) {
s = col_names;
const char* s = col_names;
ulint i;
for (i = 0; i < cols; i++) {
s += strlen(s) + 1;
......@@ -157,11 +153,7 @@ dict_add_col_name(
new_len = strlen(name) + 1;
total_len = old_len + new_len;
if (heap) {
res = mem_heap_alloc(heap, total_len);
} else {
res = ut_malloc(total_len);
}
if (old_len > 0) {
memcpy(res, col_names, old_len);
......@@ -169,10 +161,6 @@ dict_add_col_name(
memcpy(res + old_len, name, new_len);
if (col_names) {
ut_free((char*)col_names);
}
return(res);
}
......@@ -183,7 +171,8 @@ void
dict_mem_table_add_col(
/*===================*/
dict_table_t* table, /* in: table */
const char* name, /* in: column name */
mem_heap_t* heap, /* in: temporary memory heap, or NULL */
const char* name, /* in: column name, or NULL */
ulint mtype, /* in: main datatype */
ulint prtype, /* in: precise type */
ulint len) /* in: precision */
......@@ -191,21 +180,32 @@ dict_mem_table_add_col(
dict_col_t* col;
ulint mbminlen;
ulint mbmaxlen;
mem_heap_t* heap;
ulint i;
ut_ad(table && name);
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(!heap == !name);
table->n_def++;
i = table->n_def++;
if (name) {
if (UNIV_UNLIKELY(table->n_def == table->n_cols)) {
heap = table->heap;
}
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
/* All preceding column names are empty. */
char* s = mem_heap_alloc(heap, table->n_def);
memset(s, 0, table->n_def);
table->col_names = s;
}
heap = table->n_def < table->n_cols ? NULL : table->heap;
table->col_names = dict_add_col_name(table->col_names,
table->n_def - 1,
name, heap);
i, name, heap);
}
col = (dict_col_t*) dict_table_get_nth_col(table, table->n_def - 1);
col = (dict_col_t*) dict_table_get_nth_col(table, i);
col->ind = table->n_def - 1;
col->ind = i;
col->ord_part = 0;
col->mtype = (unsigned int) mtype;
......@@ -318,7 +318,7 @@ dict_mem_index_add_field(
{
dict_field_t* field;
ut_ad(index && name);
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
index->n_def++;
......
This diff is collapsed.
......@@ -32,7 +32,10 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
struct dict_index_struct;
struct row_prebuilt_struct;
typedef struct dict_index_struct dict_index_t;
typedef struct row_prebuilt_struct row_prebuilt_t;
/* The class defining a handle to an Innodb table */
......@@ -70,6 +73,11 @@ class ha_innobase: public handler
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
int innobase_read_and_init_auto_inc(longlong* ret);
ulong innobase_autoinc_lock();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
ulong innobase_get_auto_increment(ulonglong* value);
dict_index_t* innobase_get_index(uint keynr);
/* Init values for the class: */
public:
......
......@@ -462,7 +462,8 @@ ibuf_data_init_for_space(
page_t* root;
page_t* header_page;
mtr_t mtr;
char buf[50];
char* buf;
mem_heap_t* heap;
dict_table_t* table;
dict_index_t* index;
ulint n_used;
......@@ -516,16 +517,20 @@ ibuf_data_init_for_space(
ibuf_exit();
heap = mem_heap_create(450);
buf = mem_heap_alloc(heap, 50);
sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space);
/* use old-style record format for the insert buffer */
table = dict_mem_table_create(buf, space, 2, 0);
dict_mem_table_add_col(table, "PAGE_NO", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "TYPES", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "TYPES", DATA_BINARY, 0, 0);
table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
dict_table_add_to_cache(table);
dict_table_add_to_cache(table, heap);
mem_heap_free(heap);
index = dict_mem_index_create(
buf, "CLUST_IND", space,
......@@ -1139,7 +1144,7 @@ ibuf_dummy_index_add_col(
ulint len) /* in: length of the column */
{
ulint i = index->table->n_def;
dict_mem_table_add_col(index->table, "DUMMY",
dict_mem_table_add_col(index->table, NULL, NULL,
dtype_get_mtype(type),
dtype_get_prtype(type),
dtype_get_len(type));
......@@ -1161,11 +1166,6 @@ ibuf_dummy_index_free(
dict_mem_table_free(table);
}
void
dict_index_print_low(
/*=================*/
dict_index_t* index); /* in: index */
/*************************************************************************
Builds the entry to insert into a non-clustered index when we have the
corresponding record in an ibuf index. */
......
......@@ -171,6 +171,13 @@ dict_col_name_is_reserved(
/* out: TRUE if name is reserved */
const char* name); /* in: column name */
/************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table); /* in: table */
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
......@@ -180,22 +187,6 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */
ib_longlong value); /* in: next value to assign to a row */
/************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table); /* in: table */
/************************************************************************
Reads the next autoinc value (== autoinc counter value), 0 if not yet
initialized. */
......@@ -205,15 +196,6 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table); /* in: table */
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the
current value. If not inited, does nothing. */
......@@ -223,13 +205,29 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */
ib_longlong value); /* in: value which was assigned to a row */
/************************************************************************
Release the autoinc lock.*/
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table); /* in: table */
/**************************************************************************
Adds system columns to a table object. */
void
dict_table_add_system_columns(
/*==========================*/
dict_table_t* table, /* in/out: table */
mem_heap_t* heap); /* in: temporary heap */
/**************************************************************************
Adds a table object to the dictionary cache. */
void
dict_table_add_to_cache(
/*====================*/
dict_table_t* table); /* in: table */
dict_table_t* table, /* in: table */
mem_heap_t* heap); /* in: temporary heap */
/**************************************************************************
Removes a table object from the dictionary cache. */
......
......@@ -72,7 +72,8 @@ void
dict_mem_table_add_col(
/*===================*/
dict_table_t* table, /* in: table */
const char* name, /* in: column name */
mem_heap_t* heap, /* in: temporary memory heap, or NULL */
const char* name, /* in: column name, or NULL */
ulint mtype, /* in: main datatype */
ulint prtype, /* in: precise type */
ulint len); /* in: precision */
......@@ -410,6 +411,11 @@ struct dict_table_struct{
SELECT MAX(auto inc column) */
ib_longlong autoinc;/* autoinc counter value to give to the
next inserted row */
ib_longlong autoinc_increment;
/* The increment step of the auto increment
column. Value must be greater than or equal
to 1 */
#ifdef UNIV_DEBUG
ulint magic_n;/* magic number */
# define DICT_TABLE_MAGIC_N 76333786
......
......@@ -609,7 +609,7 @@ lock_validate(void);
/* out: TRUE if ok */
/*************************************************************************
Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records maybe removed, the
this transaction. Since delete-marked records may be removed, the
record count will not be precise. */
ulint
......
......@@ -670,6 +670,7 @@ struct row_prebuilt_struct {
to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */
ulonglong last_value; /* last value of AUTO-INC interval */
ulint magic_n2; /* this should be the same as
magic_n */
};
......
......@@ -171,7 +171,17 @@ row_search_check_if_query_cache_permitted(
trx_t* trx, /* in: transaction object */
const char* norm_name); /* in: concatenation of database name,
'/' char, table name */
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: autoinc column name */
ib_longlong* value); /* out: AUTOINC value read */
/* A structure for caching column values for prefetched rows */
struct sel_buf_struct{
......
......@@ -681,6 +681,9 @@ struct trx_struct{
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
records which are currently processed
by a rollback operation */
ulint n_autoinc_rows; /* no. of AUTO-INC rows required for
an SQL statement. This is useful for
multi-row INSERTs */
/*------------------------------*/
char detailed_error[256]; /* detailed error message for last
error, or empty. */
......
......@@ -63,7 +63,7 @@ ut_test_malloc(
/* out: TRUE if succeeded */
ulint n); /* in: try to allocate this many bytes */
/**************************************************************************
Frees a memory bloock allocated with ut_malloc. */
Frees a memory block allocated with ut_malloc. */
void
ut_free(
......
......@@ -2481,7 +2481,6 @@ recv_init_crash_recovery(void)
"InnoDB: buffer...\n");
trx_sys_doublewrite_init_or_restore_pages(TRUE);
}
}
/************************************************************
......
......@@ -655,6 +655,8 @@ row_create_prebuilt(
prebuilt->old_vers_heap = NULL;
prebuilt->last_value = 0;
return(prebuilt);
}
......@@ -2894,6 +2896,8 @@ next_rec:
dict_table_change_id_in_cache(table, new_id);
}
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_initialize(table, 0);
dict_update_statistics(table);
......
......@@ -4519,3 +4519,169 @@ row_search_check_if_query_cache_permitted(
return(ret);
}
/***********************************************************************
Read the AUTOINC column from the current row. */
static
ib_longlong
row_search_autoinc_read_column(
/*===========================*/
/* out: value read from the column */
dict_index_t* index, /* in: index to read from */
const rec_t* rec, /* in: current rec */
ulint col_no, /* in: column number */
ibool unsigned_type) /* in: signed or unsigned flag */
{
ulint len;
byte* ptr;
const byte* data;
ib_longlong value;
mem_heap_t* heap = NULL;
byte dest[sizeof(value)];
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
*offsets_ = sizeof offsets_ / sizeof *offsets_;
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
offsets = rec_get_offsets(
(rec_t*) rec, index, offsets, ULINT_UNDEFINED, &heap);
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
data = rec_get_nth_field((rec_t*)rec, offsets, col_no, &len);
ut_a(len != UNIV_SQL_NULL);
ut_a(len <= sizeof value);
/* Convert integer data from Innobase to a little-endian format,
sign bit restored to normal */
for (ptr = dest + len; ptr != dest; ++data) {
--ptr;
*ptr = *data;
}
if (!unsigned_type) {
dest[len - 1] ^= 128;
}
/* The assumption here is that the AUTOINC value can't be negative.*/
switch (len) {
case 8:
value = *(ib_longlong*) ptr;
break;
case 4:
value = *(ib_uint32_t*) ptr;
break;
case 2:
value = *(uint16 *) ptr;
break;
case 1:
value = *ptr;
break;
default:
ut_error;
}
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
ut_a(value >= 0);
return(value);
}
/***********************************************************************
Get the last row. */
static
const rec_t*
row_search_autoinc_get_rec(
/*=======================*/
/* out: current rec or NULL */
btr_pcur_t* pcur, /* in: the current cursor */
mtr_t* mtr) /* in: mini transaction */
{
do {
const rec_t* rec = btr_pcur_get_rec(pcur);
if (page_rec_is_user_rec(rec)) {
return(rec);
}
} while (btr_pcur_move_to_prev(pcur, mtr));
return(NULL);
}
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code, DB_RECORD_NOT_FOUND if
column name can't be found in index */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: name of autoinc column */
ib_longlong* value) /* out: AUTOINC value read */
{
ulint i;
ulint n_cols;
dict_field_t* dfield = NULL;
ulint error = DB_SUCCESS;
n_cols = dict_index_get_n_ordering_defined_by_user(index);
/* Search the index for the AUTOINC column name */
for (i = 0; i < n_cols; ++i) {
dfield = dict_index_get_nth_field(index, i);
if (strcmp(col_name, dfield->name) == 0) {
break;
}
}
*value = 0;
/* Must find the AUTOINC column name */
if (i < n_cols && dfield) {
mtr_t mtr;
btr_pcur_t pcur;
mtr_start(&mtr);
/* Open at the high/right end (FALSE), and INIT
cursor (TRUE) */
btr_pcur_open_at_index_side(
FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
const rec_t* rec;
rec = row_search_autoinc_get_rec(&pcur, &mtr);
if (rec != NULL) {
ibool unsigned_type = (
dfield->col->prtype & DATA_UNSIGNED);
*value = row_search_autoinc_read_column(
index, rec, i, unsigned_type);
}
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
} else {
error = DB_RECORD_NOT_FOUND;
}
return(error);
}
......@@ -195,6 +195,8 @@ trx_create(
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
trx->n_autoinc_rows = 0;
trx_reset_new_rec_lock_info(trx);
return(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