Commit d0e8003b authored by sunny's avatar sunny

branches/innodb+: Merge revisions 2460:2579 from branches/zip

The followin mysql-tests failed (and they are known to fail):
main.information_schema        	[ fail ]
main.innodb_file_per_table_basic[ fail ]
main.type_bit_innodb           	[ fail ]

Tested against : MYSQL_SERVER_VERSION  "5.1.28"
parent 4abda95a
2008-06-09 The InnoDB Team
* mysql-test/innodb.result:
Fix the failing innodb test by merging changes that MySQL made to that
file
2008-06-06 The InnoDB Team
* buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h,
include/srv0srv.h, srv/srv0srv.c:
Fix Bug#36600 SHOW STATUS takes a lot of CPU in
buf_get_latched_pages_number
* handler/ha_innodb.cc, os/os0file.c:
Fix Bug#11894 innodb_file_per_table crashes w/ Windows .sym symbolic
link hack
* include/ut0ut.h, srv/srv0srv.c, ut/ut0ut.c:
Fix Bug#36819 ut_usectime does not handle errors from gettimeofday
* handler/ha_innodb.cc:
Fix Bug#35602 Failed to read auto-increment value from storage engine
* srv/srv0start.c:
Fix Bug#36149 Read buffer overflow in srv0start.c found during "make
test"
2008-05-08 The InnoDB Team
* btr/btr0btr.c, mysql-test/innodb_bug36172.result,
mysql-test/innodb_bug36172.test:
Fix Bug#36172 insert into compressed innodb table crashes
2008-05-08 The InnoDB Team
InnoDB Plugin 1.0.1 released
2008-05-06 The InnoDB Team
* handler/ha_innodb.cc, include/srv0srv.h, include/sync0sync.h,
......
......@@ -2215,7 +2215,7 @@ btr_node_ptr_delete(
/* Delete node pointer on father page */
btr_page_get_father(index, block, mtr, &cursor);
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, RB_NONE,
mtr);
ut_a(err == DB_SUCCESS);
......
......@@ -32,6 +32,7 @@ Created 10/16/1994 Heikki Tuuri
#include "btr0sea.h"
#include "row0upd.h"
#include "trx0rec.h"
#include "trx0roll.h" /* trx_is_recv() */
#include "que0que.h"
#include "row0row.h"
#include "srv0srv.h"
......@@ -116,6 +117,7 @@ btr_rec_free_updated_extern_fields(
part will be updated, or NULL */
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
const upd_t* update, /* in: update vector */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr); /* in: mini-transaction handle which contains
an X-latch to record page and to the tree */
/***************************************************************
......@@ -130,9 +132,7 @@ btr_rec_free_externally_stored_fields(
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
page_zip_des_t* page_zip,/* in: compressed page whose uncompressed
part will be updated, or NULL */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr); /* in: mini-transaction handle which contains
an X-latch to record page and to the index
tree */
......@@ -2279,8 +2279,9 @@ btr_cur_pessimistic_update(
ut_ad(big_rec_vec == NULL);
btr_rec_free_updated_extern_fields(index, rec, page_zip,
offsets, update, mtr);
btr_rec_free_updated_extern_fields(
index, rec, page_zip, offsets, update,
trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr);
}
/* We have to set appropriate extern storage bits in the new
......@@ -2951,7 +2952,7 @@ btr_cur_pessimistic_delete(
if compression does not occur, the cursor
stays valid: it points to successor of
deleted record on function exit */
ibool in_rollback,/* in: TRUE if called in rollback */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr) /* in: mtr */
{
buf_block_t* block;
......@@ -3005,7 +3006,7 @@ btr_cur_pessimistic_delete(
if (rec_offs_any_extern(offsets)) {
btr_rec_free_externally_stored_fields(index,
rec, offsets, page_zip,
in_rollback, mtr);
rb_ctx, mtr);
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
......@@ -3314,7 +3315,7 @@ btr_estimate_number_of_different_key_vals(
/* We sample some pages in the index to get an estimate */
for (i = 0; i < srv_stats_sample; i++) {
for (i = 0; i < srv_stats_sample_pages; i++) {
rec_t* supremum;
mtr_start(&mtr);
......@@ -3322,7 +3323,7 @@ btr_estimate_number_of_different_key_vals(
/* Count the number of different key values for each prefix of
the key on this index page. If the prefix does not determine
the index record uniquely in te B-tree, then we subtract one
the index record uniquely in the B-tree, then we subtract one
because otherwise our algorithm would give a wrong estimate
for an index where there is just one key value. */
......@@ -3403,7 +3404,7 @@ btr_estimate_number_of_different_key_vals(
}
/* If we saw k borders between different key values on
srv_stats_sample leaf pages, we can estimate how many
srv_stats_sample_pages leaf pages, we can estimate how many
there will be in index->stat_n_leaf_pages */
/* We must take into account that our sample actually represents
......@@ -3414,26 +3415,26 @@ btr_estimate_number_of_different_key_vals(
index->stat_n_diff_key_vals[j]
= ((n_diff[j]
* (ib_int64_t)index->stat_n_leaf_pages
+ srv_stats_sample - 1
+ srv_stats_sample_pages - 1
+ total_external_size
+ not_empty_flag)
/ (srv_stats_sample
/ (srv_stats_sample_pages
+ total_external_size));
/* If the tree is small, smaller than
10 * srv_stats_sample + total_external_size, then
10 * srv_stats_sample_pages + total_external_size, then
the above estimate is ok. For bigger trees it is common that we
do not see any borders between key values in the few pages
we pick. But still there may be srv_stats_sample
we pick. But still there may be srv_stats_sample_pages
different key values, or even more. Let us try to approximate
that: */
add_on = index->stat_n_leaf_pages
/ (10 * (srv_stats_sample
/ (10 * (srv_stats_sample_pages
+ total_external_size));
if (add_on > srv_stats_sample) {
add_on = srv_stats_sample;
if (add_on > srv_stats_sample_pages) {
add_on = srv_stats_sample_pages;
}
index->stat_n_diff_key_vals[j] += add_on;
......@@ -4224,9 +4225,7 @@ btr_free_externally_stored_field(
to rec, or NULL if rec == NULL */
ulint i, /* in: field number of field_ref;
ignored if rec == NULL */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* local_mtr __attribute__((unused))) /* in: mtr
containing the latch to data an an
X-latch to the index tree */
......@@ -4256,6 +4255,15 @@ btr_free_externally_stored_field(
}
#endif /* UNIV_DEBUG */
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE))) {
/* In the rollback of uncommitted transactions, we may
encounter a clustered index record whose BLOBs have
not been written. There is nothing to free then. */
ut_a(rb_ctx == RB_RECOVERY);
return;
}
space_id = mach_read_from_4(field_ref + BTR_EXTERN_SPACE_ID);
if (UNIV_UNLIKELY(space_id != dict_index_get_space(index))) {
......@@ -4300,7 +4308,7 @@ btr_free_externally_stored_field(
|| (mach_read_from_1(field_ref + BTR_EXTERN_LEN)
& BTR_EXTERN_OWNER_FLAG)
/* Rollback and inherited field */
|| (do_not_free_inherited
|| (rb_ctx != RB_NONE
&& (mach_read_from_1(field_ref + BTR_EXTERN_LEN)
& BTR_EXTERN_INHERITED_FLAG))) {
......@@ -4402,9 +4410,7 @@ btr_rec_free_externally_stored_fields(
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
page_zip_des_t* page_zip,/* in: compressed page whose uncompressed
part will be updated, or NULL */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr) /* in: mini-transaction handle which contains
an X-latch to record page and to the index
tree */
......@@ -4428,8 +4434,7 @@ btr_rec_free_externally_stored_fields(
btr_free_externally_stored_field(
index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
rec, offsets, page_zip, i,
do_not_free_inherited, mtr);
rec, offsets, page_zip, i, rb_ctx, mtr);
}
}
}
......@@ -4448,6 +4453,7 @@ btr_rec_free_updated_extern_fields(
part will be updated, or NULL */
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
const upd_t* update, /* in: update vector */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr) /* in: mini-transaction handle which contains
an X-latch to record page and to the tree */
{
......@@ -4473,7 +4479,7 @@ btr_rec_free_updated_extern_fields(
btr_free_externally_stored_field(
index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
rec, offsets, page_zip,
ufield->field_no, TRUE, mtr);
ufield->field_no, rb_ctx, mtr);
}
}
}
......
......@@ -208,6 +208,7 @@ btr_pcur_restore_position(
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
putc('\n', stderr);
if (cursor->trx_if_known) {
trx_print(stderr, cursor->trx_if_known, 0);
}
......
......@@ -188,6 +188,7 @@ btr_search_info_create(
info->magic_n = BTR_SEARCH_MAGIC_N;
#endif /* UNIV_DEBUG */
info->ref_count = 0;
info->root_guess = NULL;
info->hash_analysis = 0;
......@@ -211,6 +212,32 @@ btr_search_info_create(
return(info);
}
/*********************************************************************
Returns the value of ref_count. The value is protected by
btr_search_latch. */
UNIV_INTERN
ulint
btr_search_info_get_ref_count(
/*==========================*/
/* out: ref_count value. */
btr_search_t* info) /* in: search info. */
{
ulint ret;
ut_ad(info);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
rw_lock_s_lock(&btr_search_latch);
ret = info->ref_count;
rw_lock_s_unlock(&btr_search_latch);
return(ret);
}
/*************************************************************************
Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
......@@ -1070,8 +1097,12 @@ next_rec:
ha_remove_all_nodes_to_page(table, folds[i], page);
}
ut_a(index->search_info->ref_count > 0);
index->search_info->ref_count--;
block->is_hashed = FALSE;
block->index = NULL;
cleanup:
#ifdef UNIV_DEBUG
if (UNIV_UNLIKELY(block->n_pointers)) {
......@@ -1295,6 +1326,15 @@ btr_search_build_page_hash_index(
goto exit_func;
}
/* This counter is decremented every time we drop page
hash index entries and is incremented here. Since we can
rebuild hash index for a page that is already hashed, we
have to take care not to increment the counter in that
case. */
if (!block->is_hashed) {
index->search_info->ref_count++;
}
block->is_hashed = TRUE;
block->n_hash_helps = 0;
......
......@@ -406,7 +406,7 @@ buf_page_is_corrupted(
}
/* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
(always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
(always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
if (checksum_field != 0
&& checksum_field != BUF_NO_CHECKSUM_MAGIC
......@@ -443,7 +443,7 @@ buf_page_print(
fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
(ulong) size);
ut_print_buf(stderr, read_buf, size);
fputs("InnoDB: End of page dump\n", stderr);
fputs("\nInnoDB: End of page dump\n", stderr);
if (zip_size) {
/* Print compressed page. */
......@@ -3187,9 +3187,6 @@ corrupt:
ut_error;
}
mutex_exit(buf_page_get_mutex(bpage));
buf_pool_mutex_exit();
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr, "Has %s page space %lu page no %lu\n",
......@@ -3198,6 +3195,9 @@ corrupt:
(ulong) buf_page_get_page_no(bpage));
}
#endif /* UNIV_DEBUG */
mutex_exit(buf_page_get_mutex(bpage));
buf_pool_mutex_exit();
}
/*************************************************************************
......@@ -3563,6 +3563,7 @@ buf_print(void)
}
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
#ifdef UNIV_DEBUG
/*************************************************************************
Returns the number of latched pages in the buffer pool. */
UNIV_INTERN
......@@ -3649,6 +3650,7 @@ buf_get_latched_pages_number(void)
return(fixed_pages_number);
}
#endif /* UNIV_DEBUG */
/*************************************************************************
Returns the number of pending buf pool ios. */
......
......@@ -168,6 +168,7 @@ buf_flush_ready_for_replace(
" in the LRU list!\n",
(ulong) buf_page_get_state(bpage));
ut_print_buf(stderr, bpage, sizeof(buf_page_t));
putc('\n', stderr);
return(FALSE);
}
......@@ -634,6 +635,13 @@ buf_flush_init_for_writing(
return;
}
ut_print_timestamp(stderr);
fputs(" InnoDB: ERROR: The compressed page to be written"
" seems corrupt:", stderr);
ut_print_buf(stderr, page, zip_size);
fputs("\nInnoDB: Possibly older version of the page:", stderr);
ut_print_buf(stderr, page_zip->data, zip_size);
putc('\n', stderr);
ut_error;
}
......
......@@ -1246,6 +1246,12 @@ alloc:
if (buf_page_is_old(b)) {
buf_pool->LRU_old_len++;
if (UNIV_UNLIKELY
(buf_pool->LRU_old
== UT_LIST_GET_NEXT(LRU, b))) {
buf_pool->LRU_old = b;
}
}
lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
......@@ -1455,6 +1461,8 @@ buf_LRU_block_remove_hashed_page(
buf_block_modify_clock_inc((buf_block_t*) bpage);
if (bpage->zip.data) {
const page_t* page = ((buf_block_t*) bpage)->frame;
const ulint zip_size
= page_zip_get_size(&bpage->zip);
ut_a(!zip || bpage->oldest_modification == 0);
......@@ -1472,7 +1480,7 @@ buf_LRU_block_remove_hashed_page(
to the compressed page, which will
be preserved. */
memcpy(bpage->zip.data, page,
page_zip_get_size(&bpage->zip));
zip_size);
}
break;
case FIL_PAGE_TYPE_ZBLOB:
......@@ -1484,6 +1492,15 @@ buf_LRU_block_remove_hashed_page(
#endif /* UNIV_ZIP_DEBUG */
break;
default:
ut_print_timestamp(stderr);
fputs(" InnoDB: ERROR: The compressed page"
" to be evicted seems corrupt:", stderr);
ut_print_buf(stderr, page, zip_size);
fputs("\nInnoDB: Possibly older version"
" of the page:", stderr);
ut_print_buf(stderr, bpage->zip.data,
zip_size);
putc('\n', stderr);
ut_error;
}
......
......@@ -1446,12 +1446,59 @@ dict_index_remove_from_cache(
dict_index_t* index) /* in, own: index */
{
ulint size;
ulint retries = 0;
btr_search_t* info;
ut_ad(table && index);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mutex_own(&(dict_sys->mutex)));
/* We always create search info whether or not adaptive
hash index is enabled or not. */
info = index->search_info;
ut_ad(info);
/* We are not allowed to free the in-memory index struct
dict_index_t until all entries in the adaptive hash index
that point to any of the page belonging to his b-tree index
are dropped. This is so because dropping of these entries
require access to dict_index_t struct. To avoid such scenario
We keep a count of number of such pages in the search_info and
only free the dict_index_t struct when this count drops to
zero. */
for (;;) {
ulint ref_count = btr_search_info_get_ref_count(info);
if (ref_count == 0) {
break;
}
/* Sleep for 10ms before trying again. */
os_thread_sleep(10000);
++retries;
if (retries % 500 == 0) {
/* No luck after 5 seconds of wait. */
fprintf(stderr, "InnoDB: Error: Waited for"
" %lu secs for hash index"
" ref_count (%lu) to drop"
" to 0.\n"
"index: \"%s\""
" table: \"%s\"\n",
retries/100,
ref_count,
index->name,
table->name);
}
/* To avoid a hang here we commit suicide if the
ref_count doesn't drop to zero in 600 seconds. */
if (retries >= 60000) {
ut_error;
}
}
rw_lock_free(&index->lock);
/* Remove the index from the list of indexes of the table */
......
......@@ -1577,6 +1577,7 @@ fsp_alloc_free_page(
if (free == ULINT_UNDEFINED) {
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
putc('\n', stderr);
ut_error;
}
......@@ -1760,6 +1761,7 @@ fsp_free_extent(
if (xdes_get_state(descr, mtr) == XDES_FREE) {
ut_print_buf(stderr, (byte*)descr - 500, 1000);
putc('\n', stderr);
ut_error;
}
......
......@@ -373,11 +373,20 @@ ha_print_info(
FILE* file, /* in: file where to print */
hash_table_t* table) /* in: hash table */
{
#ifdef UNIV_DEBUG
/* Some of the code here is disabled for performance reasons in production
builds, see http://bugs.mysql.com/36941 */
#define PRINT_USED_CELLS
#endif /* UNIV_DEBUG */
#ifdef PRINT_USED_CELLS
hash_cell_t* cell;
ulint cells = 0;
ulint n_bufs;
ulint i;
#endif /* PRINT_USED_CELLS */
ulint n_bufs;
#ifdef PRINT_USED_CELLS
for (i = 0; i < hash_get_n_cells(table); i++) {
cell = hash_get_nth_cell(table, i);
......@@ -387,10 +396,14 @@ ha_print_info(
cells++;
}
}
#endif /* PRINT_USED_CELLS */
fprintf(file, "Hash table size %lu",
(ulong) hash_get_n_cells(table));
fprintf(file,
"Hash table size %lu, used cells %lu",
(ulong) hash_get_n_cells(table), (ulong) cells);
#ifdef PRINT_USED_CELLS
fprintf(file, ", used cells %lu", (ulong) cells);
#endif /* PRINT_USED_CELLS */
if (table->heaps == NULL && table->heap != NULL) {
......
......@@ -468,8 +468,10 @@ static SHOW_VAR innodb_status_variables[]= {
(char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG},
{"buffer_pool_pages_free",
(char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG},
#ifdef UNIV_DEBUG
{"buffer_pool_pages_latched",
(char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG},
#endif /* UNIV_DEBUG */
{"buffer_pool_pages_misc",
(char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG},
{"buffer_pool_pages_total",
......@@ -3709,7 +3711,8 @@ ha_innobase::innobase_autoinc_lock(void)
old style only if another transaction has already acquired
the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
etc. type of statement. */
if (thd_sql_command(user_thd) == SQLCOM_INSERT) {
if (thd_sql_command(user_thd) == SQLCOM_INSERT
|| thd_sql_command(user_thd) == SQLCOM_REPLACE) {
dict_table_t* table = prebuilt->table;
/* Acquire the AUTOINC mutex. */
......@@ -5614,6 +5617,29 @@ ha_innobase::create(
DBUG_ENTER("ha_innobase::create");
DBUG_ASSERT(thd != NULL);
DBUG_ASSERT(create_info != NULL);
#ifdef __WIN__
/* Names passed in from server are in two formats:
1. <database_name>/<table_name>: for normal table creation
2. full path: for temp table creation, or sym link
When srv_file_per_table is on, check for full path pattern, i.e.
X:\dir\..., X is a driver letter, or
\\dir1\dir2\..., UNC path
returns error if it is in full path format, but not creating a temp.
table. Currently InnoDB does not support symbolic link on Windows. */
if (srv_file_per_table
&& (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
if ((name[1] == ':')
|| (name[0] == '\\' && name[1] == '\\')) {
sql_print_error("Cannot create table %s\n", name);
DBUG_RETURN(HA_ERR_GENERIC);
}
}
#endif
if (form->s->fields > 1000) {
/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
......@@ -6615,6 +6641,14 @@ ha_innobase::info(
if (thd_sql_command(user_thd) == SQLCOM_TRUNCATE) {
n_rows = 0;
/* We need to reset the prebuilt value too, otherwise
checks for values greater than the last value written
to the table will fail and the autoinc counter will
not be updated. This will force write_row() into
attempting an update of the table's AUTOINC counter. */
prebuilt->last_value = 0;
}
stats.records = (ha_rows)n_rows;
......@@ -9024,7 +9058,7 @@ innodb_file_format_check_validate(
if (innobase_file_format_check_on_off(file_format_input)) {
sql_print_warning(
"InnoDB: invalid innodb_file_format_check"
"InnoDB: invalid innodb_file_format_check "
"value; on/off can only be set at startup or "
"in the configuration file");
} else if (innobase_file_format_check_validate(
......@@ -9209,6 +9243,11 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
NULL, NULL, TRUE);
static MYSQL_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
PLUGIN_VAR_RQCMDARG,
"The number of index pages to sample when calculating statistics (default 8)",
NULL, NULL, 8, 1, ~0ULL, 0);
static MYSQL_SYSVAR_BOOL(adaptive_hash_index, innobase_adaptive_hash_index,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Enable InnoDB adaptive hash index (enabled by default). "
......@@ -9286,12 +9325,6 @@ static MYSQL_SYSVAR_LONG(open_files, innobase_open_files,
"How many files at the maximum InnoDB keeps open at the same time.",
NULL, NULL, 300L, 10L, ~0L, 0);
static MYSQL_SYSVAR_ULONG(stats_sample, srv_stats_sample,
PLUGIN_VAR_OPCMDARG,
"When estimating number of different key values in an index, sample "
"this many index pages",
NULL, NULL, SRV_STATS_SAMPLE_DEFAULT, 1, 1000, 0);
static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
PLUGIN_VAR_RQCMDARG,
"Count of spin-loop rounds in InnoDB mutexes",
......@@ -9362,9 +9395,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(open_files),
MYSQL_SYSVAR(rollback_on_timeout),
MYSQL_SYSVAR(stats_on_metadata),
MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(replication_delay),
MYSQL_SYSVAR(stats_sample),
MYSQL_SYSVAR(status_file),
MYSQL_SYSVAR(strict_mode),
MYSQL_SYSVAR(support_xa),
......@@ -9432,9 +9465,10 @@ innodb_plugin_init(void)
/*====================*/
/* out: TRUE if the dynamic InnoDB plugin should start */
{
# if !MYSQL_STORAGE_ENGINE_PLUGIN
# error "MYSQL_STORAGE_ENGINE_PLUGIN must be nonzero."
# endif
#if !MYSQL_STORAGE_ENGINE_PLUGIN
#error "MYSQL_STORAGE_ENGINE_PLUGIN must be nonzero."
#endif
switch (builtin_innobase_plugin) {
case 0:
return(true);
......@@ -9445,54 +9479,79 @@ innodb_plugin_init(void)
}
/* Copy the system variables. */
struct st_mysql_plugin* builtin
= (struct st_mysql_plugin*) &builtin_innobase_plugin;
struct st_mysql_sys_var** v = builtin->system_vars;
struct st_mysql_sys_var** w = innobase_system_variables;
for (; *v; v++, w++) {
if (!*w) {
fprintf(stderr, "InnoDB: unknown parameter %s,0x%x\n",
(*v)->name, (*v)->flags);
return(false);
} else if (!innobase_match_parameter((*v)->name, (*w)->name)) {
/* Skip the destination parameter, since it doesn't
exist in the source. */
v--;
continue;
/* Ignore changes that affect the READONLY flag. */
} else if (((*v)->flags ^ (*w)->flags) & ~PLUGIN_VAR_READONLY) {
fprintf(stderr,
"InnoDB: parameter mismatch:"
" %s,%s,0x%x,0x%x\n",
(*v)->name, (*w)->name,
(*v)->flags, (*w)->flags);
return(false);
} else if ((*v)->flags & PLUGIN_VAR_THDLOCAL) {
/* Do not copy session variables. */
struct st_mysql_plugin* builtin;
struct st_mysql_sys_var** sta; /* static parameters */
struct st_mysql_sys_var** dyn; /* dynamic parameters */
builtin = (struct st_mysql_plugin*) &builtin_innobase_plugin;
for (sta = builtin->system_vars; *sta != NULL; sta++) {
/* do not copy session variables */
if ((*sta)->flags & PLUGIN_VAR_THDLOCAL) {
continue;
}
switch ((*v)->flags
& ~(PLUGIN_VAR_MASK | PLUGIN_VAR_UNSIGNED)) {
# define COPY_VAR(label, type) \
case label: \
*(type*)(*w)->value = *(type*)(*v)->value; \
break;
for (dyn = innobase_system_variables; *dyn != NULL; dyn++) {
COPY_VAR(PLUGIN_VAR_BOOL, char);
COPY_VAR(PLUGIN_VAR_INT, int);
COPY_VAR(PLUGIN_VAR_LONG, long);
COPY_VAR(PLUGIN_VAR_LONGLONG, long long);
COPY_VAR(PLUGIN_VAR_STR, char*);
if (innobase_match_parameter((*sta)->name,
(*dyn)->name)) {
default:
fprintf(stderr, "InnoDB: unknown flags 0x%x for %s\n",
(*v)->flags, (*v)->name);
}
/* found the corresponding parameter */
/* check if the flags are the same,
ignoring differences in the READONLY flag;
e.g. we are not copying string variable to
an integer one */
if (((*sta)->flags & ~PLUGIN_VAR_READONLY)
!= ((*dyn)->flags & ~PLUGIN_VAR_READONLY)) {
fprintf(stderr,
"InnoDB: %s in static InnoDB "
"(flags=0x%x) differs from "
"%s in dynamic InnoDB "
"(flags=0x%x)\n",
(*sta)->name, (*sta)->flags,
(*dyn)->name, (*dyn)->flags);
/* we could break; here leaving this
parameter uncopied */
return(false);
}
/* Make the static InnoDB variable point to the dynamic one */
(*v)->value = (*w)->value;
/* assign the value of the static parameter
to the dynamic one, according to their type */
#define COPY_VAR(label, type) \
case label: \
*(type*)(*dyn)->value = *(type*)(*sta)->value; \
break;
switch ((*sta)->flags
& ~(PLUGIN_VAR_MASK
| PLUGIN_VAR_UNSIGNED)) {
COPY_VAR(PLUGIN_VAR_BOOL, char);
COPY_VAR(PLUGIN_VAR_INT, int);
COPY_VAR(PLUGIN_VAR_LONG, long);
COPY_VAR(PLUGIN_VAR_LONGLONG, long long);
COPY_VAR(PLUGIN_VAR_STR, char*);
default:
fprintf(stderr,
"InnoDB: unknown flags "
"0x%x for %s\n",
(*sta)->flags, (*sta)->name);
}
/* Make the static InnoDB variable point to
the dynamic one */
(*sta)->value = (*dyn)->value;
break;
}
}
}
return(true);
......
......@@ -635,9 +635,6 @@ ha_innobase::add_index(
trx = trx_allocate_for_mysql();
trx_start_if_not_started(trx);
trans_register_ha(user_thd, FALSE, ht);
prebuilt->trx->active_trans = 1;
trx->mysql_thd = user_thd;
trx->mysql_query_str = thd_query(user_thd);
......@@ -1084,9 +1081,6 @@ ha_innobase::final_drop_index(
trx = trx_allocate_for_mysql();
trx_start_if_not_started(trx);
trans_register_ha(user_thd, FALSE, ht);
prebuilt->trx->active_trans = 1;
trx->mysql_thd = user_thd;
trx->mysql_query_str = thd_query(user_thd);
......
......@@ -3548,7 +3548,7 @@ ibuf_delete_rec(
root = ibuf_tree_root_get(mtr);
btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
FALSE, mtr);
RB_NONE, mtr);
ut_a(err == DB_SUCCESS);
#ifdef UNIV_IBUF_COUNT_DEBUG
......
......@@ -380,7 +380,7 @@ btr_cur_pessimistic_delete(
if compression does not occur, the cursor
stays valid: it points to successor of
deleted record on function exit */
ibool in_rollback,/* in: TRUE if called in rollback */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* mtr); /* in: mtr */
/***************************************************************
Parses a redo log record of updating a record in-place. */
......@@ -522,9 +522,7 @@ btr_free_externally_stored_field(
to rec, or NULL if rec == NULL */
ulint i, /* in: field number of field_ref;
ignored if rec == NULL */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
enum trx_rb_ctx rb_ctx, /* in: rollback context */
mtr_t* local_mtr); /* in: mtr containing the latch to
data an an X-latch to the index
tree */
......
......@@ -54,6 +54,15 @@ btr_search_info_create(
/*===================*/
/* out, own: search info struct */
mem_heap_t* heap); /* in: heap where created */
/*********************************************************************
Returns the value of ref_count. The value is protected by
btr_search_latch. */
UNIV_INTERN
ulint
btr_search_info_get_ref_count(
/*==========================*/
/* out: ref_count value. */
btr_search_t* info); /* in: search info. */
/*************************************************************************
Updates the search info. */
UNIV_INLINE
......@@ -162,6 +171,13 @@ extern ibool btr_search_disabled;
/* The search info struct in an index */
struct btr_search_struct{
ulint ref_count; /* Number of blocks in this index tree
that have search index built
i.e. block->index points to this index.
Protected by btr_search_latch except
when during initialization in
btr_search_info_create(). */
/* The following fields are not protected by any latch.
Unfortunately, this means that they must be aligned to
the machine word, i.e., they cannot be turned into bit-fields. */
......
......@@ -537,12 +537,14 @@ buf_page_print(
const byte* read_buf, /* in: a database page */
ulint zip_size); /* in: compressed page size, or
0 for uncompressed pages */
#ifdef UNIV_DEBUG
/*************************************************************************
Returns the number of latched pages in the buffer pool. */
UNIV_INTERN
ulint
buf_get_latched_pages_number(void);
/*==============================*/
#endif /* UNIV_DEBUG */
/*************************************************************************
Returns the number of pending buf pool ios. */
UNIV_INTERN
......@@ -1307,13 +1309,17 @@ struct buf_pool_struct{
/* base node of the LRU list */
buf_page_t* LRU_old; /* pointer to the about 3/8 oldest
blocks in the LRU list; NULL if LRU
length less than BUF_LRU_OLD_MIN_LEN */
length less than BUF_LRU_OLD_MIN_LEN;
NOTE: when LRU_old != NULL, its length
should always equal LRU_old_len */
ulint LRU_old_len; /* length of the LRU list from
the block to which LRU_old points
onward, including that block;
see buf0lru.c for the restrictions
on this value; not defined if
LRU_old == NULL */
LRU_old == NULL;
NOTE: LRU_old_len must be adjusted
whenever LRU_old shrinks or grows! */
UT_LIST_BASE_NODE_T(buf_block_t) unzip_LRU;
/* base node of the unzip_LRU list */
......
......@@ -221,7 +221,7 @@ struct dict_index_struct{
unsigned page:32;/* index tree root page number */
unsigned type:4; /* index type (DICT_CLUSTERED, DICT_UNIQUE,
DICT_UNIVERSAL, DICT_IBUF) */
unsigned trx_id_offset:10;/* position of the the trx id column
unsigned trx_id_offset:10;/* position of the trx id column
in a clustered index record, if the fields
before it are known to be of a fixed size,
0 otherwise */
......
......@@ -76,21 +76,6 @@ typedef struct page_zip_stat_struct page_zip_stat_t;
/** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */
extern page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE - 1];
/**************************************************************************
Write data to the compressed page. The data must already be written to
the uncompressed page. */
UNIV_INTERN
void
page_zip_write(
/*===========*/
page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* rec, /* in: record whose data is being written */
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
lint offset, /* in: start address of the block,
relative to rec */
ulint length) /* in: length of the data */
__attribute__((nonnull));
/**************************************************************************
Write the "deleted" flag of a record on a compressed page. The flag must
already have been written on the uncompressed page. */
......
......@@ -355,7 +355,15 @@ page_zip_write_header(
{
ulint pos;
#if 0
/* In btr_cur_pessimistic_insert(), we allocate temp_page
from the buffer pool to see if a record fits on a compressed
page by itself. The buf_block_align() call in
buf_frame_get_page_zip() only works for file pages, not
temporarily allocated blocks. Thus, we must unfortunately
disable the following assertion. */
ut_ad(buf_frame_get_page_zip(str) == page_zip);
#endif
ut_ad(page_zip_simple_validate(page_zip));
UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
......
......@@ -136,10 +136,7 @@ extern ibool srv_innodb_status;
extern ibool srv_stats_on_metadata;
/* When estimating number of different key values in an index, sample
this many index pages */
#define SRV_STATS_SAMPLE_DEFAULT 8
extern ulong srv_stats_sample;
extern unsigned long long srv_stats_sample_pages;
extern ibool srv_use_doublewrite_buf;
extern ibool srv_use_checksums;
......@@ -522,7 +519,9 @@ struct export_var_struct{
ulint innodb_buffer_pool_pages_dirty;
ulint innodb_buffer_pool_pages_misc;
ulint innodb_buffer_pool_pages_free;
#ifdef UNIV_DEBUG
ulint innodb_buffer_pool_pages_latched;
#endif /* UNIV_DEBUG */
ulint innodb_buffer_pool_read_requests;
ulint innodb_buffer_pool_reads;
ulint innodb_buffer_pool_wait_free;
......
......@@ -178,6 +178,9 @@ trx_undo_rec_get_partial_row(
record! */
dict_index_t* index, /* in: clustered index */
dtuple_t** row, /* out, own: partial row */
ibool ignore_prefix, /* in: flag to indicate if we
expect blob prefixes in undo. Used
only in the assertion. */
mem_heap_t* heap); /* in: memory heap from which the memory
needed is allocated */
/***************************************************************************
......
......@@ -15,6 +15,17 @@ Created 3/26/1996 Heikki Tuuri
#include "mtr0mtr.h"
#include "trx0sys.h"
/***********************************************************************
Determines if this transaction is rolling back an incomplete transaction
in crash recovery. */
UNIV_INTERN
ibool
trx_is_recv(
/*========*/
/* out: TRUE if trx is an incomplete
transaction that is being rolled back
in crash recovery */
const trx_t* trx); /* in: transaction */
/***********************************************************************
Returns a transaction savepoint taken at this point in time. */
UNIV_INTERN
......
......@@ -310,6 +310,15 @@ UNIV_INTERN
void
trx_sys_file_format_close(void);
/*===========================*/
/************************************************************************
Tags the system table space with minimum format id if it has not been
tagged yet.
WARNING: This function is only called during the startup and AFTER the
redo log application during recovery has finished. */
UNIV_INTERN
void
trx_sys_file_format_tag_init(void);
/*==============================*/
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
......@@ -319,14 +328,16 @@ trx_sys_file_format_id_to_name(
/* out: pointer to the name */
const uint id); /* in: id of the file format */
/*********************************************************************
Set the file format tag unconditonally. */
Set the file format id unconditionally except if it's already the
same value. */
UNIV_INTERN
ibool
trx_sys_file_format_max_set(
/*===========================*/
/*========================*/
/* out: TRUE if value updated */
ulint file_format, /* in: file format id */
char** name); /* out: max format name */
ulint format_id, /* in: file format id */
char** name); /* out: max file format name or
NULL if not needed. */
/*********************************************************************
Get the name representation of the file format from its id. */
UNIV_INTERN
......
......@@ -36,6 +36,14 @@ typedef struct roll_node_struct roll_node_t;
typedef struct commit_node_struct commit_node_t;
typedef struct trx_named_savept_struct trx_named_savept_t;
/* Rollback contexts */
enum trx_rb_ctx {
RB_NONE = 0, /* no rollback */
RB_NORMAL, /* normal rollback */
RB_RECOVERY, /* rolling back an incomplete transaction,
in crash recovery */
};
/* Transaction savepoint */
typedef struct trx_savept_struct trx_savept_t;
struct trx_savept_struct{
......
......@@ -232,10 +232,9 @@ ulint
trx_undo_assign_undo(
/*=================*/
/* out: DB_SUCCESS if undo log assign
* successful, possible error codes are:
* ER_TOO_MANY_CONCURRENT_TRXS
* DB_OUT_OF_FILE_SPAC
* DB_OUT_OF_MEMORY */
successful, possible error codes are:
DB_TOO_MANY_CONCURRENT_TRXS
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY*/
trx_t* trx, /* in: transaction */
ulint type); /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
/**********************************************************************
......
......@@ -150,11 +150,15 @@ ib_time_t
ut_time(void);
/*=========*/
/**************************************************************
Returns system time. */
Returns system time.
Upon successful completion, the value 0 is returned; otherwise the
value -1 is returned and the global variable errno is set to indicate the
error. */
UNIV_INTERN
void
int
ut_usectime(
/*========*/
/* out: 0 on success, -1 otherwise */
ulint* sec, /* out: seconds since the Epoch */
ulint* ms); /* out: microseconds since the Epoch+*sec */
......
......@@ -4264,6 +4264,15 @@ lock_rec_print(
}
#ifndef UNIV_HOTBACKUP
#ifdef UNIV_DEBUG
/* Print the number of lock structs from lock_print_info_summary() only
in non-production builds for performance reasons, see
http://bugs.mysql.com/36942 */
#define PRINT_NUM_OF_LOCK_STRUCTS
#endif /* UNIV_DEBUG */
#ifdef PRINT_NUM_OF_LOCK_STRUCTS
/*************************************************************************
Calculates the number of record lock structs in the record lock hash table. */
static
......@@ -4290,6 +4299,7 @@ lock_get_n_rec_locks(void)
return(n_locks);
}
#endif /* PRINT_NUM_OF_LOCK_STRUCTS */
/*************************************************************************
Prints info of locks for all transactions. */
......@@ -4331,9 +4341,11 @@ lock_print_info_summary(
"History list length %lu\n",
(ulong) trx_sys->rseg_history_len);
#ifdef PRINT_NUM_OF_LOCK_STRUCTS
fprintf(file,
"Total number of lock structs in row lock hash table %lu\n",
(ulong) lock_get_n_rec_locks());
#endif /* PRINT_NUM_OF_LOCK_STRUCTS */
}
/*************************************************************************
......
......@@ -491,6 +491,7 @@ mem_heap_validate_or_print(
if (print) {
ut_print_buf(stderr, user_field, len);
putc('\n', stderr);
}
total_len += len;
......
......@@ -330,40 +330,33 @@ mem_heap_create_block(
}
/* In dynamic allocation, calculate the size: block header + data. */
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
if (type == MEM_HEAP_DYNAMIC) {
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
ut_ad(type == MEM_HEAP_DYNAMIC || n <= MEM_MAX_ALLOC_IN_BUF);
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
block = mem_area_alloc(&len, mem_comm_pool);
} else {
ut_ad(n <= MEM_MAX_ALLOC_IN_BUF);
len = MEM_BLOCK_HEADER_SIZE + MEM_SPACE_NEEDED(n);
if (len < UNIV_PAGE_SIZE / 2) {
len = UNIV_PAGE_SIZE;
block = mem_area_alloc(&len, mem_comm_pool);
} else {
len = UNIV_PAGE_SIZE;
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
/* We cannot allocate the block from the
buffer pool, but must get the free block from
the heap header free block field */
if ((type & MEM_HEAP_BTR_SEARCH) && heap) {
/* We cannot allocate the block from the
buffer pool, but must get the free block from
the heap header free block field */
buf_block = heap->free_block;
heap->free_block = NULL;
buf_block = heap->free_block;
heap->free_block = NULL;
if (UNIV_UNLIKELY(!buf_block)) {
if (UNIV_UNLIKELY(!buf_block)) {
return(NULL);
}
} else {
buf_block = buf_block_alloc(0);
return(NULL);
}
block = (mem_block_t*) buf_block->frame;
} else {
buf_block = buf_block_alloc(0);
}
block = (mem_block_t*) buf_block->frame;
}
ut_ad(block);
......@@ -492,19 +485,14 @@ mem_heap_block_free(
UNIV_MEM_ASSERT_AND_FREE(block, len);
#endif /* UNIV_MEM_DEBUG */
if (type == MEM_HEAP_DYNAMIC) {
if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) {
ut_ad(!buf_block);
mem_area_free(block, mem_comm_pool);
} else {
ut_ad(type & MEM_HEAP_BUFFER);
if (len >= UNIV_PAGE_SIZE / 2) {
buf_block_free(buf_block);
} else {
ut_ad(!buf_block);
mem_area_free(block, mem_comm_pool);
}
buf_block_free(buf_block);
}
}
......
......@@ -87,3 +87,85 @@ SELECT * FROM t1;
c1 c2
18446744073709551615 NULL
DROP TABLE t1;
CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
c1
1
2
3
4
5
6
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
TRUNCATE TABLE t1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
c1
1
2
3
4
5
6
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
c1
1
2
3
4
5
6
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
DELETE FROM t1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
c1
1
2
3
7
8
9
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
DROP TABLE t1;
......@@ -105,3 +105,37 @@ INSERT INTO t1 VALUES (18446744073709551615, null);
INSERT INTO t1 (c2) VALUES ('innodb');
SELECT * FROM t1;
DROP TABLE t1;
#
# Bug 37531
# After truncate, auto_increment behaves incorrectly for InnoDB
#
CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
SHOW CREATE TABLE t1;
TRUNCATE TABLE t1;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
#
# Deleting all records should not reset the AUTOINC counter.
#
CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
SHOW CREATE TABLE t1;
DELETE FROM t1;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
SELECT c1 FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
......@@ -765,7 +765,6 @@ insert into t2 values ('jejdkrun87'),('adfd72nh9k'),
('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik');
create table t1(a int, b blob, c text, d text not null)
engine=innodb default charset = utf8;
insert into t1 values (null,null,null,'null');
insert into t1
select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3;
drop table t2, t3;
......@@ -775,7 +774,6 @@ count(*)
select a,
length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
a length(b) b=left(repeat(d,100*a),65535) length(c) c=repeat(d,20*a) d
NULL NULL NULL NULL NULL null
22 22000 1 4400 1 adfd72nh9k
22 35200 1 7040 1 adfdijn0loKNHJik
22 28600 1 5720 1 adfdijnmnb78k
......@@ -802,9 +800,6 @@ NULL NULL NULL NULL NULL null
66 65535 1 15840 1 adfdpplkeock
66 65535 1 13200 1 jejdkrun87
alter table t1 add primary key (a), add key (b(20));
ERROR 42000: All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead
delete from t1 where d='null';
alter table t1 add primary key (a), add key (b(20));
ERROR 23000: Duplicate entry '22' for key 'PRIMARY'
delete from t1 where a%2;
check table t1;
......@@ -847,7 +842,7 @@ Table Op Msg_type Msg_text
test.t1 check status OK
explain select * from t1 where b like 'adfd%';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range b b 769 NULL 11 Using where
1 SIMPLE t1 ALL b NULL NULL NULL 15 Using where
create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb;
insert into t2 select a,left(b,255) from t1;
drop table t1;
......
......@@ -239,16 +239,47 @@ insert into t2 values ('jejdkrun87'),('adfd72nh9k'),
create table t1(a int, b blob, c text, d text not null)
engine=innodb default charset = utf8;
insert into t1 values (null,null,null,'null');
# r2667 The following test is disabled because MySQL behavior changed.
# r2667 The test was added with this comment:
# r2667
# r2667 ------------------------------------------------------------------------
# r2667 r1699 | marko | 2007-08-10 19:53:19 +0300 (Fri, 10 Aug 2007) | 5 lines
# r2667
# r2667 branches/zip: Add changes that accidentally omitted from r1698:
# r2667
# r2667 innodb-index.test, innodb-index.result: Add a test for creating
# r2667 a PRIMARY KEY on a column that contains a NULL value.
# r2667 ------------------------------------------------------------------------
# r2667
# r2667 but in BZR-r2667:
# r2667 http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/davi%40mysql.com-20080617141221-8yre8ys9j4uw3xx5?start_revid=joerg%40mysql.com-20080630105418-7qoe5ehomgrcdb89
# r2667 MySQL changed the behavior to do full table copy when creating PRIMARY INDEX
# r2667 on a non-NULL column instead of calling ::add_index() which would fail (and
# r2667 this is what we were testing here). Before r2667 the code execution path was
# r2667 like this (when adding PRIMARY INDEX on a non-NULL column with ALTER TABLE):
# r2667
# r2667 mysql_alter_table()
# r2667 compare_tables() // would return ALTER_TABLE_INDEX_CHANGED
# r2667 ::add_index() // would fail with "primary index cannot contain NULL"
# r2667
# r2667 after r2667 the code execution path is the following:
# r2667
# r2667 mysql_alter_table()
# r2667 compare_tables() // returns ALTER_TABLE_DATA_CHANGED
# r2667 full copy is done, without calling ::add_index()
# r2667
# r2667 To enable, remove "# r2667: " below.
# r2667
# r2667: insert into t1 values (null,null,null,'null');
insert into t1
select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3;
drop table t2, t3;
select count(*) from t1 where a=44;
select a,
length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
--error ER_PRIMARY_CANT_HAVE_NULL
alter table t1 add primary key (a), add key (b(20));
delete from t1 where d='null';
# r2667: --error ER_PRIMARY_CANT_HAVE_NULL
# r2667: alter table t1 add primary key (a), add key (b(20));
# r2667: delete from t1 where d='null';
--error ER_DUP_ENTRY
alter table t1 add primary key (a), add key (b(20));
delete from t1 where a%2;
......
......@@ -3,11 +3,11 @@ create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=inn
select * from t1;
c1 c2 stamp
replace delayed into t1 (c1, c2) values ( "text1","11");
ERROR HY000: Table storage engine for 't1' doesn't have this option
ERROR HY000: DELAYED option not supported for table 't1'
select * from t1;
c1 c2 stamp
replace delayed into t1 (c1, c2) values ( "text1","12");
ERROR HY000: Table storage engine for 't1' doesn't have this option
ERROR HY000: DELAYED option not supported for table 't1'
select * from t1;
c1 c2 stamp
drop table t1;
......@@ -11,10 +11,10 @@ drop table if exists t1;
#
create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb;
select * from t1;
--error 1031
--error ER_DELAYED_NOT_SUPPORTED
replace delayed into t1 (c1, c2) values ( "text1","11");
select * from t1;
--error 1031
--error ER_DELAYED_NOT_SUPPORTED
replace delayed into t1 (c1, c2) values ( "text1","12");
select * from t1;
drop table t1;
......
......@@ -131,6 +131,25 @@ INSERT INTO t1 VALUES(
'FOXajs|.7@IR[dmv(2<FPZdnx+5?IS]gq{.8BLV`jt~1;EOYcmw*4>HR\fpz-7AKU_is}0:DNXblv)3=GQ[eoy,6@JT^hr|/9CMWaku(3>IT_ju)4?JU`kv*5@KValw+6ALWbmx,7BMXcny-8CNYdoz.9DOZep{/:EP[fq|0;FQ\gr}1<GR]hs~2=HS^it(4@LXdp|1=IUamy.:FR^jv+7CO[gs(4@LXdp|1=IUamy.:FR^jv+7CO[gs(4@LXdp|1=IUamy.:FR^jv+7CO[gs(5BO\iv,9FS`mz0=JWdq~4AN[hu+8ER_ly/<IVcp}3@MZgt*7DQ^kx.;HUbo|2?LYfs)6CP]jw-:GTan{1>KXer(6DR`n|3AO]ky0>LZhv-;IWes*8FTbp~5CQ_m{2@N\jx/=KYgu,:HVdr)7ESao}4BP^lz1?M[iw.<JXft+9GUcq(7FUds+:IXgv.=L[jy1@O^m|4CRap(7FUds+:IXgv.=L[jy1@O^m|4CRap(7FUds+:IXgv.=L[jy1@O^m|4CRap(8HXhx1AQaq*:JZjz3CScs,<L\l|5EUeu.>N^n~7GWgw0@P`p)9IYiy2BRbr+;K[k{4DTdt-=M]m}6FVfv/?O_o(9J[l}7HYj{5FWhy3DUfw1BSdu/@Qbs->O`q+<M^o):K\m~8IZk|6GXiz4EVgx2CTev0ARct.?Par,=N_p*;L]n(:L^p+=Oas.@Rdv1CUgy4FXj|7I[m(:L^p+=Oas.@Rdv1CUgy4FXj|7');
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
drop table t1;
create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
primary key(c1, c2(22), c3(22)))
engine = innodb row_format = dynamic;
begin;
insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
repeat('C', 20000));
update t1 set c3 = repeat('D', 20000) where c1 = 1;
commit;
select count(*) from t1 where c2 = repeat('A', 20000);
count(*)
1
select count(*) from t1 where c3 = repeat('D', 20000);
count(*)
1
select count(*) from t1 where c4 = repeat('C', 20000);
count(*)
1
update t1 set c3 = repeat('E', 20000) where c1 = 1;
drop table t1;
set global innodb_file_format=`0`;
select @@innodb_file_format;
@@innodb_file_format
......@@ -381,13 +400,4 @@ show table status;
select @@innodb_file_format_check;
@@innodb_file_format_check
Barracuda
set global innodb_file_format_check=`Cheetah`;
ERROR HY000: Incorrect arguments to SET
set global innodb_file_format_check=`on`;
ERROR HY000: Incorrect arguments to SET
set global innodb_file_format_check=`off`;
ERROR HY000: Incorrect arguments to SET
select @@innodb_file_format_check;
@@innodb_file_format_check
Barracuda
drop table normal_table, zip_table;
......@@ -100,6 +100,31 @@ INSERT INTO t1 VALUES(
'FOXajs|.7@IR[dmv(2<FPZdnx+5?IS]gq{.8BLV`jt~1;EOYcmw*4>HR\fpz-7AKU_is}0:DNXblv)3=GQ[eoy,6@JT^hr|/9CMWaku(3>IT_ju)4?JU`kv*5@KValw+6ALWbmx,7BMXcny-8CNYdoz.9DOZep{/:EP[fq|0;FQ\gr}1<GR]hs~2=HS^it(4@LXdp|1=IUamy.:FR^jv+7CO[gs(4@LXdp|1=IUamy.:FR^jv+7CO[gs(4@LXdp|1=IUamy.:FR^jv+7CO[gs(5BO\iv,9FS`mz0=JWdq~4AN[hu+8ER_ly/<IVcp}3@MZgt*7DQ^kx.;HUbo|2?LYfs)6CP]jw-:GTan{1>KXer(6DR`n|3AO]ky0>LZhv-;IWes*8FTbp~5CQ_m{2@N\jx/=KYgu,:HVdr)7ESao}4BP^lz1?M[iw.<JXft+9GUcq(7FUds+:IXgv.=L[jy1@O^m|4CRap(7FUds+:IXgv.=L[jy1@O^m|4CRap(7FUds+:IXgv.=L[jy1@O^m|4CRap(8HXhx1AQaq*:JZjz3CScs,<L\l|5EUeu.>N^n~7GWgw0@P`p)9IYiy2BRbr+;K[k{4DTdt-=M]m}6FVfv/?O_o(9J[l}7HYj{5FWhy3DUfw1BSdu/@Qbs->O`q+<M^o):K\m~8IZk|6GXiz4EVgx2CTev0ARct.?Par,=N_p*;L]n(:L^p+=Oas.@Rdv1CUgy4FXj|7I[m(:L^p+=Oas.@Rdv1CUgy4FXj|7');
drop table t1;
#
# Test blob column inheritance (mantis issue#36)
#
create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
primary key(c1, c2(22), c3(22)))
engine = innodb row_format = dynamic;
begin;
insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
repeat('C', 20000));
update t1 set c3 = repeat('D', 20000) where c1 = 1;
commit;
# one blob column which is unchanged in update and part of PK
# one blob column which is changed and part of of PK
# one blob column which is not part of PK and is unchanged
select count(*) from t1 where c2 = repeat('A', 20000);
select count(*) from t1 where c3 = repeat('D', 20000);
select count(*) from t1 where c4 = repeat('C', 20000);
update t1 set c3 = repeat('E', 20000) where c1 = 1;
drop table t1;
#
#
# Test innodb_file_format
#
......@@ -291,12 +316,5 @@ select @@innodb_file_format_check;
show table status;
-- enable_result_log
select @@innodb_file_format_check;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`Cheetah`;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`on`;
-- error ER_WRONG_ARGUMENTS
set global innodb_file_format_check=`off`;
select @@innodb_file_format_check;
drop table normal_table, zip_table;
-- disable_result_log
......@@ -925,7 +925,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL b 4 NULL # Using index
explain select a,b from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL PRIMARY 4 NULL #
1 SIMPLE t1 index NULL b 4 NULL # Using index
explain select a,b,c from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL #
......@@ -1166,14 +1166,14 @@ UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000;
SELECT * from t1;
a b
1 1
102 2
103 3
4 4
5 5
6 6
7 7
8 8
9 9
102 2
103 3
drop table t1;
CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb;
CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb;
......@@ -1197,6 +1197,7 @@ a b
update t1,t2 set t1.a=t1.a+100 where t1.a=101;
select * from t1;
a b
201 1
102 2
103 3
104 4
......@@ -1208,11 +1209,10 @@ a b
110 10
111 11
112 12
201 1
update t1,t2 set t1.b=t1.b+10 where t1.b=2;
select * from t1;
a b
102 12
201 1
103 3
104 4
105 5
......@@ -1222,34 +1222,34 @@ a b
109 9
110 10
111 11
102 12
112 12
201 1
update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100;
select * from t1;
a b
102 12
201 1
103 5
104 6
105 7
106 6
105 7
107 7
108 8
109 9
110 10
111 11
102 12
112 12
201 1
select * from t2;
a b
1 1
2 2
3 13
4 14
5 15
6 6
7 7
8 8
9 9
3 13
4 14
5 15
drop table t1,t2;
CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM;
CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB;
......@@ -1300,11 +1300,11 @@ insert into t1 (id) values (null),(null),(null),(null),(null);
update t1 set fk=69 where fk is null order by id limit 1;
SELECT * from t1;
id fk
1 69
2 NULL
3 NULL
4 NULL
5 NULL
1 69
drop table t1;
create table t1 (a int not null, b int not null, key (a));
insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3);
......@@ -1836,7 +1836,6 @@ set @a=repeat(' ',20);
insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
Warnings:
Note 1265 Data truncated for column 'v' at row 1
Note 1265 Data truncated for column 'c' at row 1
select concat('*',v,'*',c,'*',t,'*') from t1;
concat('*',v,'*',c,'*',t,'*')
*+ *+*+ *
......@@ -2440,8 +2439,8 @@ insert into t1 (b) values (1);
replace into t1 (b) values (2), (1), (3);
select * from t1;
a b
2 2
3 1
2 2
4 3
truncate table t1;
insert into t1 (b) values (1);
......@@ -2450,8 +2449,8 @@ replace into t1 (b) values (1);
replace into t1 (b) values (3);
select * from t1;
a b
2 2
3 1
2 2
4 3
drop table t1;
create table t1 (rowid int not null auto_increment, val int not null,primary
......
This directory contains patches that need to be applied to the MySQL
source tree in order to get the mysql-test suite to succeed (when
storage/innobase is replaced with this InnoDB branch). Things to keep
in mind when adding new patches here:
* The patch must be appliable from the mysql top-level source directory.
* The patch filename must end in ".diff".
* All patches here are expected to apply cleanly to the latest MySQL 5.1
tree with storage/innobase is replaced with this InnoDB branch. If
changes to either of those cause the patch to fail, then please check
whether the patch is still needed and, if yes, adjust it so it applies
cleanly.
* If applicable, always submit the patch at http://bugs.mysql.com and
name the file here like bug%d.diff. Once the patch is committed to
MySQL remove the file from here.
* If the patch cannot be proposed for inclusion in the MySQL source tree
(via http://bugs.mysql.com) then add a comment at the beginning of the
patch explaining the problem it is solving, how it does solve it and
why it is not applicable for inclusion in the MySQL source tree.
Obviously this is a very bad situation and should be avoided at all
costs, especially for files that are in the MySQL source repository
(not in storage/innobase).
* If you ever need to add a patch here that is not related to mysql-test
suite, then please move this directory from ./mysql-test/patches to
./patches and remove this text.
diff -pu sql/mysql_priv.h sql/mysql_priv.h
--- sql/mysql_priv.h 2007-11-14 15:28:19.000000000 +0200
+++ sql/mysql_priv.h 2008-01-08 10:45:53.000000000 +0200
@@ -2094,6 +2094,7 @@ uint build_table_shadow_filename(char *b
#define FN_TO_IS_TMP (1 << 1)
#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP)
#define NO_FRM_RENAME (1 << 2)
+#define FN_FRM_ONLY (1 << 3)
/* from hostname.cc */
struct in_addr;
diff -pu sql/sql_table.cc sql/sql_table.cc
--- sql/sql_table.cc 2007-11-02 00:48:11.000000000 +0200
+++ sql/sql_table.cc 2008-01-08 10:46:04.000000000 +0200
@@ -1791,8 +1791,9 @@ bool quick_rm_table(handlerton *base,con
if (my_delete(path,MYF(0)))
error= 1; /* purecov: inspected */
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
- DBUG_RETURN(ha_delete_table(current_thd, base, path, db, table_name, 0) ||
- error);
+ if (!(flags & FN_FRM_ONLY))
+ error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
+ DBUG_RETURN(error);
}
/*
@@ -6680,7 +6681,10 @@ err1:
close_temporary_table(thd, new_table, 1, 1);
}
else
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
+ VOID(quick_rm_table(new_db_type, new_db, tmp_name,
+ create_info->frm_only
+ ? FN_IS_TMP | FN_FRM_ONLY
+ : FN_IS_TMP));
err:
/*
--- mysql-test/t/date_formats.test.orig 2007-06-15 02:53:07.000000000 +0300
+++ mysql-test/t/date_formats.test 2008-03-19 17:25:10.000000000 +0200
@@ -7,9 +7,15 @@
--enable_warnings
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW GLOBAL VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.global_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW SESSION VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
#
# Test setting a lot of different formats to see which formats are accepted and
@@ -37,7 +43,10 @@
set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
--replace_result ROW <format> STATEMENT <format> MIXED <format>
-SHOW SESSION VARIABLES LIKE "%e_format";
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
--error 1231
SET time_format='%h:%i:%s';
--- mysql-test/r/date_formats.result.orig 2008-02-12 21:09:14.000000000 +0200
+++ mysql-test/r/date_formats.result 2008-03-19 17:26:33.000000000 +0200
@@ -1,14 +1,20 @@
drop table if exists t1;
-SHOW GLOBAL VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %d.%m.%Y
-datetime_format %Y-%m-%d %H:%i:%s
-time_format %H.%i.%s
-SHOW SESSION VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %d.%m.%Y
-datetime_format %Y-%m-%d %H:%i:%s
-time_format %H.%i.%s
+SELECT variable_name, variable_value
+FROM information_schema.global_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %Y-%m-%d %H:%i:%s
+DATE_FORMAT %d.%m.%Y
+TIME_FORMAT %H.%i.%s
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %Y-%m-%d %H:%i:%s
+DATE_FORMAT %d.%m.%Y
+TIME_FORMAT %H.%i.%s
SET time_format='%H%i%s';
SET time_format='%H:%i:%s.%f';
SET time_format='%h-%i-%s.%f%p';
@@ -26,11 +32,14 @@
set datetime_format= '%H:%i:%s.%f %m-%d-%Y';
set datetime_format= '%h:%i:%s %p %Y-%m-%d';
set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
-SHOW SESSION VARIABLES LIKE "%e_format";
-Variable_name Value
-date_format %m-%d-%Y
-datetime_format %h:%i:%s.%f %p %Y-%m-%d
-time_format %h:%i:%s%p
+SELECT variable_name, variable_value
+FROM information_schema.session_variables
+WHERE variable_name IN ('date_format', 'datetime_format', 'time_format')
+ORDER BY variable_name;
+variable_name variable_value
+DATETIME_FORMAT %h:%i:%s.%f %p %Y-%m-%d
+DATE_FORMAT %m-%d-%Y
+TIME_FORMAT %h:%i:%s%p
SET time_format='%h:%i:%s';
ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s'
SET time_format='%H %i:%s';
--- mysql-test/extra/binlog_tests/innodb_stat.test.orig 2008-06-10 15:12:02.000000000 +0300
+++ mysql-test/extra/binlog_tests/innodb_stat.test 2008-06-10 15:12:06.000000000 +0300
@@ -41,6 +41,7 @@
# Test for testable InnoDB status variables. This test
# uses previous ones(pages_created, rows_deleted, ...).
+-- replace_regex /51[12]/51_/
show status like "Innodb_buffer_pool_pages_total";
show status like "Innodb_page_size";
show status like "Innodb_rows_deleted";
--- mysql-test/suite/binlog/r/binlog_row_innodb_stat.result.orig 2008-06-10 15:29:44.000000000 +0300
+++ mysql-test/suite/binlog/r/binlog_row_innodb_stat.result 2008-06-10 15:30:04.000000000 +0300
@@ -24,7 +24,7 @@
drop table t1;
show status like "Innodb_buffer_pool_pages_total";
Variable_name Value
-Innodb_buffer_pool_pages_total 512
+Innodb_buffer_pool_pages_total 51_
show status like "Innodb_page_size";
Variable_name Value
Innodb_page_size 16384
--- mysql-test/suite/binlog/r/binlog_stm_innodb_stat.result.orig 2008-06-10 15:33:43.000000000 +0300
+++ mysql-test/suite/binlog/r/binlog_stm_innodb_stat.result 2008-06-10 15:33:55.000000000 +0300
@@ -24,7 +24,7 @@
drop table t1;
show status like "Innodb_buffer_pool_pages_total";
Variable_name Value
-Innodb_buffer_pool_pages_total 512
+Innodb_buffer_pool_pages_total 51_
show status like "Innodb_page_size";
Variable_name Value
Innodb_page_size 16384
This part of the innodb-index test causes mysqld to print some warnings
and subsequently the whole mysql-test suite to fail.
A permanent solution is probably to remove the printouts from the source
code or to somehow tell the mysql-test suite that warnings are expected.
Currently we simply do not execute the problematic tests. Please
coordinate a permanent solution with Marko, who added those tests.
This cannot be proposed to MySQL because it touches files that are not
in the MySQL source repository.
Index: storage/innobase/mysql-test/innodb-index.result
===================================================================
--- storage/innobase/mysql-test/innodb-index.result (revision 2229)
+++ storage/innobase/mysql-test/innodb-index.result (working copy)
@@ -43,19 +43,12 @@ t1 CREATE TABLE `t1` (
`b` int(11) DEFAULT NULL,
`c` char(10) NOT NULL,
`d` varchar(20) DEFAULT NULL,
KEY `d2` (`d`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
-CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB;
-alter table t1 add unique index (c), add index (d);
-ERROR HY000: Table 'test.t1#1' already exists
-rename table `t1#1` to `t1#2`;
-alter table t1 add unique index (c), add index (d);
-ERROR HY000: Table 'test.t1#2' already exists
-drop table `t1#2`;
alter table t1 add unique index (c), add index (d);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
Index: storage/innobase/mysql-test/innodb-index.test
===================================================================
--- storage/innobase/mysql-test/innodb-index.test (revision 2229)
+++ storage/innobase/mysql-test/innodb-index.test (working copy)
@@ -14,22 +14,12 @@ select * from t1 force index (d2) order
--error ER_DUP_ENTRY
alter table t1 add unique index (b);
show create table t1;
alter table t1 add index (b);
show create table t1;
-# Check how existing tables interfere with temporary tables.
-CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB;
-
---error 156
-alter table t1 add unique index (c), add index (d);
-rename table `t1#1` to `t1#2`;
---error 156
-alter table t1 add unique index (c), add index (d);
-drop table `t1#2`;
-
alter table t1 add unique index (c), add index (d);
show create table t1;
explain select * from t1 force index(c) order by c;
--error ER_REQUIRES_PRIMARY_KEY
drop index c on t1;
alter table t1 add primary key (a), drop index c;
......@@ -1241,9 +1241,19 @@ try_again:
if (file == INVALID_HANDLE_VALUE) {
*success = FALSE;
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
/* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in
case of unknown errors. */
if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
} else {
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
}
if (retry) {
goto try_again;
}
......@@ -1318,9 +1328,19 @@ try_again:
if (file == -1) {
*success = FALSE;
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
/* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in
case of unknown errors. */
if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
} else {
retry = os_file_handle_error(name,
create_mode == OS_FILE_CREATE ?
"create" : "open");
}
if (retry) {
goto try_again;
} else {
......
......@@ -726,7 +726,7 @@ os_fast_mutex_free(
ret = pthread_mutex_destroy(fast_mutex);
if (ret != 0) {
if (UNIV_UNLIKELY(ret != 0)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: error: return value %lu when calling\n"
......@@ -735,7 +735,7 @@ os_fast_mutex_free(
"InnoDB: Byte contents of the pthread mutex at %p:\n",
(void*) fast_mutex);
ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
fprintf(stderr, "\n");
putc('\n', stderr);
}
#endif
if (UNIV_LIKELY(os_sync_mutex_inited)) {
......
......@@ -848,6 +848,7 @@ page_cur_parse_insert_rec(
fputs("Dump of 300 bytes of log:\n", stderr);
ut_print_buf(stderr, ptr2, 300);
putc('\n', stderr);
buf_page_print(page, 0);
......
......@@ -598,6 +598,8 @@ page_copy_rec_list_end(
ut_ad(buf_block_get_frame(block) == page);
ut_ad(page_is_leaf(page) == page_is_leaf(new_page));
ut_ad(page_is_comp(page) == page_is_comp(new_page));
/* Here, "ret" may be pointing to a user record or the
predefined supremum record. */
if (UNIV_LIKELY_NULL(new_page_zip)) {
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
......@@ -620,6 +622,12 @@ page_copy_rec_list_end(
store the number of preceding records on the page. */
ulint ret_pos
= page_rec_get_n_recs_before(ret);
/* Before copying, "ret" was the successor of
the predefined infimum record. It must still
have at least one predecessor (the predefined
infimum record, or a freshly copied record
that is smaller than "ret"). */
ut_a(ret_pos > 0);
if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) {
......@@ -685,6 +693,9 @@ page_copy_rec_list_start(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
/* Here, "ret" may be pointing to a user record or the
predefined infimum record. */
if (page_rec_is_infimum(rec)) {
return(ret);
......@@ -725,6 +736,11 @@ page_copy_rec_list_start(
store the number of preceding records on the page. */
ulint ret_pos
= page_rec_get_n_recs_before(ret);
/* Before copying, "ret" was the predecessor
of the predefined supremum record. If it was
the predefined infimum record, then it would
still be the infimum. Thus, the assertion
ut_a(ret_pos > 0) would fail here. */
if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) {
......
......@@ -3203,7 +3203,15 @@ page_zip_write_rec(
ulint heap_no;
byte* slot;
#if 0
/* In btr_cur_pessimistic_insert(), we allocate temp_page
from the buffer pool to see if a record fits on a compressed
page by itself. The buf_block_align() call in
buf_frame_get_page_zip() only works for file pages, not
temporarily allocated blocks. Thus, we must unfortunately
disable the following assertion. */
ut_ad(buf_frame_get_page_zip(rec) == page_zip);
#endif
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
> PAGE_DATA + page_zip_dir_size(page_zip));
......
......@@ -144,7 +144,8 @@ row_purge_remove_clust_if_poss_low(
success = btr_cur_optimistic_delete(btr_cur, &mtr);
} else {
ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, &mtr);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
RB_NONE, &mtr);
if (err == DB_SUCCESS) {
success = TRUE;
......@@ -266,14 +267,9 @@ row_purge_remove_sec_if_poss_low_nonbuffered(
} else {
ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
FALSE, &mtr);
if (err == DB_SUCCESS) {
success = TRUE;
} else if (err == DB_OUT_OF_FILE_SPACE) {
success = FALSE;
} else {
ut_error;
}
RB_NONE, &mtr);
success = err == DB_SUCCESS;
ut_a(success || err == DB_OUT_OF_FILE_SPACE);
}
}
......@@ -575,7 +571,7 @@ skip_secondaries:
index,
data_field + dfield_get_len(&ufield->new_val)
- BTR_EXTERN_FIELD_REF_SIZE,
NULL, NULL, NULL, 0, FALSE, &mtr);
NULL, NULL, NULL, 0, RB_NONE, &mtr);
mtr_commit(&mtr);
}
}
......@@ -676,8 +672,10 @@ err_exit:
/* Read to the partial row the fields that occur in indexes */
if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
ptr = trx_undo_rec_get_partial_row(ptr, clust_index,
&node->row, node->heap);
ptr = trx_undo_rec_get_partial_row(
ptr, clust_index, &node->row,
type == TRX_UNDO_UPD_DEL_REC,
node->heap);
}
return(TRUE);
......
......@@ -97,12 +97,6 @@ row_build_index_entry(
} else {
dtuple_set_n_fields_cmp(
entry, dict_index_get_n_unique_in_tree(index));
if (dict_index_is_clust(index)) {
/* Do not fetch externally stored columns to
the clustered index. Such columns are handled
at a higher level. */
ext = NULL;
}
}
for (i = 0; i < entry_len; i++) {
......@@ -121,8 +115,15 @@ row_build_index_entry(
dfield_copy(dfield, dfield2);
if (dfield_is_null(dfield)) {
} else if (UNIV_LIKELY_NULL(ext)) {
if (dfield_is_null(dfield) || ind_field->prefix_len == 0) {
continue;
}
/* If a column prefix index, take only the prefix.
Prefix-indexed columns may be externally stored. */
ut_ad(col->ord_part);
if (UNIV_LIKELY_NULL(ext)) {
/* See if the column is stored externally. */
const byte* buf = row_ext_lookup(ext, col_no,
&len);
......@@ -139,15 +140,10 @@ row_build_index_entry(
|| dict_index_is_clust(index));
}
/* If a column prefix index, take only the prefix */
if (ind_field->prefix_len > 0 && !dfield_is_null(dfield)) {
ut_ad(col->ord_part);
len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen,
ind_field->prefix_len,
len, dfield_get_data(dfield));
dfield_set_len(dfield, len);
}
len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen,
ind_field->prefix_len, len, dfield_get_data(dfield));
dfield_set_len(dfield, len);
}
ut_ad(dtuple_check_typed(entry));
......
......@@ -2173,17 +2173,16 @@ row_fetch_print(
fprintf(stderr, " column %lu:\n", (ulong)i);
dtype_print(type);
fprintf(stderr, "\n");
putc('\n', stderr);
if (dfield_get_len(dfield) != UNIV_SQL_NULL) {
ut_print_buf(stderr, dfield_get_data(dfield),
dfield_get_len(dfield));
putc('\n', stderr);
} else {
fprintf(stderr, " <NULL>;");
fputs(" <NULL>;\n", stderr);
}
fprintf(stderr, "\n");
exp = que_node_get_next(exp);
i++;
}
......@@ -2466,7 +2465,7 @@ row_sel_convert_mysql_key_to_innobase(
(ulong) (key_ptr - key_end));
fflush(stderr);
ut_print_buf(stderr, original_key_ptr, key_len);
fprintf(stderr, "\n");
putc('\n', stderr);
if (!is_null) {
ulint len = dfield_get_len(dfield);
......
......@@ -87,7 +87,10 @@ retry:
&(node->pcur), &mtr);
ut_a(success);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
trx_is_recv(node->trx)
? RB_RECOVERY
: RB_NORMAL, &mtr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
......@@ -160,7 +163,14 @@ row_undo_ins_remove_sec_low(
} else {
ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
/* No need to distinguish RB_RECOVERY here, because we
are deleting a secondary index record: the distinction
between RB_NORMAL and RB_RECOVERY only matters when
deleting a record that contains externally stored
columns. */
ut_ad(!dict_index_is_clust(index));
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
RB_NORMAL, &mtr);
}
btr_pcur_close(&pcur);
......@@ -284,12 +294,24 @@ row_undo_ins(
entry = row_build_index_entry(node->row, node->ext,
node->index, node->heap);
ut_a(entry);
err = row_undo_ins_remove_sec(node->index, entry);
if (UNIV_UNLIKELY(!entry)) {
/* The database must have crashed after
inserting a clustered index record but before
writing all the externally stored columns of
that record. Because secondary index entries
are inserted after the clustered index record,
we may assume that the secondary index record
does not exist. However, this situation may
only occur during the rollback of incomplete
transactions. */
ut_a(trx_is_recv(node->trx));
} else {
err = row_undo_ins_remove_sec(node->index, entry);
if (err != DB_SUCCESS) {
if (err != DB_SUCCESS) {
return(err);
return(err);
}
}
node->index = dict_table_get_next_index(node->index);
......
......@@ -178,9 +178,9 @@ row_undo_mod_remove_clust_low(
/* Note that since this operation is analogous to purge,
we can free also inherited externally stored fields:
hence the last FALSE in the call below */
hence the RB_NONE in the call below */
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, mtr);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
......@@ -350,8 +350,14 @@ row_undo_mod_del_mark_or_remove_sec_low(
} else {
ut_ad(mode == BTR_MODIFY_TREE);
/* No need to distinguish RB_RECOVERY here, because we
are deleting a secondary index record: the distinction
between RB_NORMAL and RB_RECOVERY only matters when
deleting a record that contains externally stored
columns. */
ut_ad(!dict_index_is_clust(index));
btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
TRUE, &mtr);
RB_NORMAL, &mtr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
......@@ -506,7 +512,7 @@ row_undo_mod_upd_del_sec(
mem_heap_t* heap;
dtuple_t* entry;
dict_index_t* index;
ulint err;
ulint err = DB_SUCCESS;
heap = mem_heap_create(1024);
......@@ -515,22 +521,35 @@ row_undo_mod_upd_del_sec(
entry = row_build_index_entry(node->row, node->ext,
index, heap);
ut_a(entry);
err = row_undo_mod_del_mark_or_remove_sec(node, thr, index,
entry);
if (err != DB_SUCCESS) {
if (UNIV_UNLIKELY(!entry)) {
/* The database must have crashed after
inserting a clustered index record but before
writing all the externally stored columns of
that record. Because secondary index entries
are inserted after the clustered index record,
we may assume that the secondary index record
does not exist. However, this situation may
only occur during the rollback of incomplete
transactions. */
ut_a(trx_is_recv(thr_get_trx(thr)));
} else {
err = row_undo_mod_del_mark_or_remove_sec(
node, thr, index, entry);
mem_heap_free(heap);
if (err != DB_SUCCESS) {
return(err);
break;
}
}
mem_heap_empty(heap);
node->index = dict_table_get_next_index(node->index);
}
mem_heap_free(heap);
return(DB_SUCCESS);
return(err);
}
/***************************************************************
......
......@@ -163,6 +163,26 @@ row_vers_impl_x_locked_off_kernel(
clust_offsets = rec_get_offsets(
prev_version, clust_index, NULL,
ULINT_UNDEFINED, &heap);
vers_del = rec_get_deleted_flag(prev_version,
comp);
prev_trx_id = row_get_rec_trx_id(prev_version,
clust_index,
clust_offsets);
/* If the trx_id and prev_trx_id are
different and if the prev_version is marked
deleted then the prev_trx_id must have
already committed for the trx_id to be able to
modify the row. Therefore, prev_trx_id cannot
hold any implicit lock. */
if (0 != ut_dulint_cmp(trx_id, prev_trx_id)
&& vers_del) {
mutex_enter(&kernel_mutex);
break;
}
/* The stack of versions is locked by mtr.
Thus, it is safe to fetch the prefixes for
externally stored columns. */
......@@ -206,8 +226,6 @@ row_vers_impl_x_locked_off_kernel(
if prev_version would require rec to be in a different
state. */
vers_del = rec_get_deleted_flag(prev_version, comp);
/* We check if entry and rec are identified in the alphabetical
ordering */
if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
......@@ -243,9 +261,6 @@ row_vers_impl_x_locked_off_kernel(
break;
}
prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
clust_offsets);
if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) {
/* The versions modified by the trx_id transaction end
to prev_version: no implicit x-lock */
......
......@@ -305,7 +305,7 @@ UNIV_INTERN ibool srv_stats_on_metadata = TRUE;
/* When estimating number of different key values in an index, sample
this many index pages */
UNIV_INTERN ulong srv_stats_sample = SRV_STATS_SAMPLE_DEFAULT;
UNIV_INTERN ib_uint64_t srv_stats_sample_pages = 8;
UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
UNIV_INTERN ibool srv_use_checksums = TRUE;
......@@ -1422,8 +1422,11 @@ srv_suspend_mysql_thread(
srv_n_lock_wait_count++;
srv_n_lock_wait_current_count++;
ut_usectime(&sec, &ms);
start_time = (ib_int64_t)sec * 1000000 + ms;
if (ut_usectime(&sec, &ms) == -1) {
start_time = -1;
} else {
start_time = (ib_int64_t) sec * 1000000 + ms;
}
}
/* Wake the lock timeout monitor thread, if it is suspended */
......@@ -1486,14 +1489,20 @@ srv_suspend_mysql_thread(
wait_time = ut_difftime(ut_time(), slot->suspend_time);
if (thr->lock_state == QUE_THR_LOCK_ROW) {
ut_usectime(&sec, &ms);
finish_time = (ib_int64_t)sec * 1000000 + ms;
if (ut_usectime(&sec, &ms) == -1) {
finish_time = -1;
} else {
finish_time = (ib_int64_t) sec * 1000000 + ms;
}
diff_time = (ulint) (finish_time - start_time);
srv_n_lock_wait_current_count--;
srv_n_lock_wait_time = srv_n_lock_wait_time + diff_time;
if (diff_time > srv_n_lock_max_wait_time) {
if (diff_time > srv_n_lock_max_wait_time &&
/* only update the variable if we successfully
retrieved the start and finish times. See Bug#36819. */
start_time != -1 && finish_time != -1) {
srv_n_lock_max_wait_time = diff_time;
}
}
......@@ -1796,8 +1805,10 @@ srv_export_innodb_status(void)
= UT_LIST_GET_LEN(buf_pool->flush_list);
export_vars.innodb_buffer_pool_pages_free
= UT_LIST_GET_LEN(buf_pool->free);
#ifdef UNIV_DEBUG
export_vars.innodb_buffer_pool_pages_latched
= buf_get_latched_pages_number();
#endif /* UNIV_DEBUG */
export_vars.innodb_buffer_pool_pages_total = buf_pool->curr_size;
export_vars.innodb_buffer_pool_pages_misc = buf_pool->curr_size
......
......@@ -200,13 +200,13 @@ srv_parse_data_file_paths_and_sizes(
str = srv_parse_megabytes(str, &size);
if (0 == memcmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
if (0 == strncmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
str += (sizeof ":autoextend") - 1;
if (0 == memcmp(str, ":max:",
(sizeof ":max:") - 1)) {
if (0 == strncmp(str, ":max:",
(sizeof ":max:") - 1)) {
str += (sizeof ":max:") - 1;
......@@ -288,14 +288,15 @@ srv_parse_data_file_paths_and_sizes(
(*data_file_names)[i] = path;
(*data_file_sizes)[i] = size;
if (0 == memcmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
if (0 == strncmp(str, ":autoextend",
(sizeof ":autoextend") - 1)) {
*is_auto_extending = TRUE;
str += (sizeof ":autoextend") - 1;
if (0 == memcmp(str, ":max:", (sizeof ":max:") - 1)) {
if (0 == strncmp(str, ":max:",
(sizeof ":max:") - 1)) {
str += (sizeof ":max:") - 1;
......@@ -1236,6 +1237,19 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR);
}
#ifdef UNIV_DEBUG
/* We have observed deadlocks with a 5MB buffer pool but
the actual lower limit could very well be a little higher. */
if (srv_buf_pool_size <= 5 * 1024 * 1024) {
fprintf(stderr, "InnoDB: Warning: Small buffer pool size "
"(%luM), the flst_validate() debug function "
"can cause a deadlock if the buffer pool fills up.\n",
srv_buf_pool_size / 1024 / 1024);
}
#endif
fsp_init();
log_init();
......@@ -1448,7 +1462,17 @@ innobase_start_or_create_for_mysql(void)
} else {
/* Check if we support the max format that is stamped
on the system tablespace. */
on the system tablespace.
Note: We are NOT allowed to make any modifications to
the TRX_SYS_PAGE_NO page before recovery because this
page also contains the max_trx_id etc. important system
variables that are required for recovery. We need to
ensure that we return the system to a state where normal
recovery is guaranteed to work. We do this by
invalidating the buffer cache, this will force the
reread of the page and restoration to it's last known
consistent state, this is REQUIRED for the recovery
process to work. */
err = trx_sys_file_format_max_check(
srv_check_file_format_at_startup);
......@@ -1456,6 +1480,13 @@ innobase_start_or_create_for_mysql(void)
return(err);
}
/* Invalidate the buffer pool to ensure that we reread
the page that we read above, during recovery.
Note that this is not as heavy weight as it seems. At
this point there will be only ONE page in the buf_LRU
and there must be no page in the buf_flush list. */
buf_pool_invalidate();
/* We always try to do a recovery, even if the database had
been shut down normally: this is the normal startup path */
......@@ -1512,6 +1543,13 @@ innobase_start_or_create_for_mysql(void)
are initialized in trx_sys_init_at_db_start(). */
recv_recovery_from_checkpoint_finish();
/* It is possible that file_format tag has never
been set. In this case we initialize it to minimum
value. Important to note that we can do it ONLY after
we have finished the recovery process so that the
image of TRX_SYS_PAGE_NO is not stale. */
trx_sys_file_format_tag_init();
}
if (!create_new_db && sum_of_new_sizes > 0) {
......
......@@ -1089,6 +1089,9 @@ sync_thread_add_level(
|| sync_thread_levels_g(array, SYNC_REC_LOCK));
break;
case SYNC_IBUF_BITMAP:
/* Either the thread must own the master mutex to all
the bitmap pages, or it is allowed to latch only ONE
bitmap page. */
ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX)
&& sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1))
|| sync_thread_levels_g(array, SYNC_IBUF_BITMAP));
......
......@@ -391,7 +391,15 @@ fill_trx_row(
row->trx_weight = (ullint) ut_conv_dulint_to_longlong(TRX_WEIGHT(trx));
row->trx_mysql_thread_id = ib_thd_get_thread_id(trx->mysql_thd);
if (trx->mysql_thd != NULL) {
row->trx_mysql_thread_id
= ib_thd_get_thread_id(trx->mysql_thd);
} else {
/* For internal transactions e.g., purge and transactions
being recovered at startup there is no associated MySQL
thread data structure. */
row->trx_mysql_thread_id = 0;
}
if (trx->mysql_query_str != NULL && *trx->mysql_query_str != NULL) {
......
......@@ -533,6 +533,8 @@ trx_undo_page_report_modify(
ulint type_cmpl;
byte* type_cmpl_ptr;
ulint i;
dulint trx_id;
ibool ignore_prefix = FALSE;
byte ext_buf[REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE];
......@@ -565,6 +567,11 @@ trx_undo_page_report_modify(
type_cmpl = TRX_UNDO_DEL_MARK_REC;
} else if (rec_get_deleted_flag(rec, dict_table_is_comp(table))) {
type_cmpl = TRX_UNDO_UPD_DEL_REC;
/* We are about to update a delete marked record.
We don't typically need the prefix in this case unless
the delete marking is done by the same transaction
(which we check below). */
ignore_prefix = TRUE;
} else {
type_cmpl = TRX_UNDO_UPD_EXIST_REC;
}
......@@ -588,7 +595,16 @@ trx_undo_page_report_modify(
index, DATA_TRX_ID), &flen);
ut_ad(flen == DATA_TRX_ID_LEN);
ptr += mach_dulint_write_compressed(ptr, trx_read_trx_id(field));
trx_id = trx_read_trx_id(field);
/* If it is an update of a delete marked record, then we are
allowed to ignore blob prefixes if the delete marking was done
by some other trx as it must have committed by now for us to
allow an over-write. */
if (ignore_prefix) {
ignore_prefix = ut_dulint_cmp(trx_id, trx->id) != 0;
}
ptr += mach_dulint_write_compressed(ptr, trx_id);
field = rec_get_nth_field(rec, offsets,
dict_index_get_sys_col_pos(
......@@ -663,6 +679,7 @@ trx_undo_page_report_modify(
ptr,
dict_index_get_nth_col(index, pos)
->ord_part
&& !ignore_prefix
&& flen < REC_MAX_INDEX_COL_LEN
? ext_buf : NULL,
dict_table_zip_size(table),
......@@ -746,6 +763,7 @@ trx_undo_page_report_modify(
ptr = trx_undo_page_report_modify_ext(
ptr,
flen < REC_MAX_INDEX_COL_LEN
&& !ignore_prefix
? ext_buf : NULL,
dict_table_zip_size(table),
&field, &flen);
......@@ -996,6 +1014,9 @@ trx_undo_rec_get_partial_row(
record! */
dict_index_t* index, /* in: clustered index */
dtuple_t** row, /* out, own: partial row */
ibool ignore_prefix, /* in: flag to indicate if we
expect blob prefixes in undo. Used
only in the assertion. */
mem_heap_t* heap) /* in: memory heap from which the memory
needed is allocated */
{
......@@ -1045,7 +1066,8 @@ trx_undo_rec_get_partial_row(
/* If the prefix of this column is indexed,
ensure that enough prefix is stored in the
undo log record. */
ut_a(!col->ord_part
ut_a(ignore_prefix
|| !col->ord_part
|| dfield_get_len(dfield)
>= REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE);
......
......@@ -373,6 +373,21 @@ trx_release_savepoint_for_mysql(
return(DB_SUCCESS);
}
/***********************************************************************
Determines if this transaction is rolling back an incomplete transaction
in crash recovery. */
UNIV_INTERN
ibool
trx_is_recv(
/*========*/
/* out: TRUE if trx is an incomplete
transaction that is being rolled back
in crash recovery */
const trx_t* trx) /* in: transaction */
{
return(trx == trx_roll_crash_recv_trx);
}
/***********************************************************************
Returns a transaction savepoint taken at this point in time. */
UNIV_INTERN
......
......@@ -1106,7 +1106,8 @@ static
ulint
trx_sys_file_format_max_read(void)
/*==============================*/
/* out: the file format */
/* out: the file format or
ULINT_UNDEFINED if not set. */
{
mtr_t mtr;
const byte* ptr;
......@@ -1131,10 +1132,8 @@ trx_sys_file_format_max_read(void)
if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH
|| format_id >= FILE_FORMAT_NAME_N) {
/* Either it has never been tagged, or garbage in it.
Reset the tag in either case. */
format_id = DICT_TF_FORMAT_51;
trx_sys_file_format_max_write(format_id, NULL);
/* Either it has never been tagged, or garbage in it. */
return(ULINT_UNDEFINED);
}
return(format_id);
......@@ -1170,6 +1169,11 @@ trx_sys_file_format_max_check(
recover if the file format is not supported by the engine
unless forced by the user. */
format_id = trx_sys_file_format_max_read();
if (format_id == ULINT_UNDEFINED) {
/* Format ID was not set. Set it to minimum possible
value. */
format_id = DICT_TF_FORMAT_51;
}
ut_print_timestamp(stderr);
fprintf(stderr,
......@@ -1212,11 +1216,11 @@ trx_sys_file_format_max_set(
/*========================*/
/* out: TRUE if value updated */
ulint format_id, /* in: file format id */
char** name) /* out: max file format name */
char** name) /* out: max file format name or
NULL if not needed. */
{
ibool ret = FALSE;
ut_a(name);
ut_a(format_id <= DICT_TF_FORMAT_MAX);
mutex_enter(&file_format_max.mutex);
......@@ -1232,6 +1236,26 @@ trx_sys_file_format_max_set(
return(ret);
}
/************************************************************************
Tags the system table space with minimum format id if it has not been
tagged yet.
WARNING: This function is only called during the startup and AFTER the
redo log application during recovery has finished. */
UNIV_INTERN
void
trx_sys_file_format_tag_init(void)
/*==============================*/
{
ulint format_id;
format_id = trx_sys_file_format_max_read();
/* If format_id is not set then set it to the minimum. */
if (format_id == ULINT_UNDEFINED) {
trx_sys_file_format_max_set(DICT_TF_FORMAT_51, NULL);
}
}
/************************************************************************
Update the file format tag in the tablespace only if the given format id
is greater than the known max id. */
......
......@@ -264,6 +264,7 @@ trx_free(
trx_print(stderr, trx, 600);
ut_print_buf(stderr, trx, sizeof(trx_t));
putc('\n', stderr);
}
ut_a(trx->magic_n == TRX_MAGIC_N);
......@@ -805,6 +806,20 @@ trx_commit_off_kernel(
trx->conc_state = TRX_COMMITTED_IN_MEMORY;
/*--------------------------------------*/
/* If we release kernel_mutex below and we are still doing
recovery i.e.: back ground rollback thread is still active
then there is a chance that the rollback thread may see
this trx as COMMITTED_IN_MEMORY and goes adhead to clean it
up calling trx_cleanup_at_db_startup(). This can happen
in the case we are committing a trx here that is left in
PREPARED state during the crash. Note that commit of the
rollback of a PREPARED trx happens in the recovery thread
while the rollback of other transactions happen in the
background thread. To avoid this race we unconditionally
unset the is_recovered flag from the trx. */
trx->is_recovered = FALSE;
lock_release_off_kernel(trx);
if (trx->global_read_view) {
......
......@@ -1708,7 +1708,7 @@ trx_undo_assign_undo(
/*=================*/
/* out: DB_SUCCESS if undo log assign
successful, possible error codes are:
DD_TOO_MANY_CONCURRENT_TRXS
DB_TOO_MANY_CONCURRENT_TRXS
DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY*/
trx_t* trx, /* in: transaction */
ulint type) /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
......
......@@ -105,19 +105,45 @@ ut_time(void)
}
/**************************************************************
Returns system time. */
Returns system time.
Upon successful completion, the value 0 is returned; otherwise the
value -1 is returned and the global variable errno is set to indicate the
error. */
UNIV_INTERN
void
int
ut_usectime(
/*========*/
/* out: 0 on success, -1 otherwise */
ulint* sec, /* out: seconds since the Epoch */
ulint* ms) /* out: microseconds since the Epoch+*sec */
{
struct timeval tv;
int ret;
int errno_gettimeofday;
int i;
for (i = 0; i < 10; i++) {
ret = ut_gettimeofday(&tv, NULL);
if (ret == -1) {
errno_gettimeofday = errno;
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: gettimeofday(): %s\n",
strerror(errno_gettimeofday));
os_thread_sleep(100000); /* 0.1 sec */
errno = errno_gettimeofday;
} else {
break;
}
}
ut_gettimeofday(&tv, NULL);
*sec = (ulint) tv.tv_sec;
*ms = (ulint) tv.tv_usec;
if (ret != -1) {
*sec = (ulint) tv.tv_sec;
*ms = (ulint) tv.tv_usec;
}
return(ret);
}
/**************************************************************
......
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