summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
Diffstat (limited to 'storage')
-rw-r--r--storage/archive/archive_reader.c6
-rw-r--r--storage/blackhole/ha_blackhole.cc2
-rw-r--r--storage/blackhole/ha_blackhole.h2
-rw-r--r--storage/csv/ha_tina.cc11
-rw-r--r--storage/federated/ha_federated.cc2
-rw-r--r--storage/heap/ha_heap.cc2
-rw-r--r--storage/innobase/Makefile.am38
-rw-r--r--storage/innobase/btr/btr0sea.c39
-rw-r--r--storage/innobase/buf/buf0lru.c127
-rw-r--r--storage/innobase/dict/dict0dict.c72
-rw-r--r--storage/innobase/dict/dict0mem.c6
-rw-r--r--storage/innobase/handler/ha_innodb.cc675
-rw-r--r--storage/innobase/handler/ha_innodb.h9
-rw-r--r--storage/innobase/include/btr0sea.h15
-rw-r--r--storage/innobase/include/data0type.ic2
-rw-r--r--storage/innobase/include/dict0dict.h11
-rw-r--r--storage/innobase/include/dict0mem.h10
-rw-r--r--storage/innobase/include/ha_prototypes.h9
-rw-r--r--storage/innobase/include/hash0hash.ic3
-rw-r--r--storage/innobase/include/lock0lock.h17
-rw-r--r--storage/innobase/include/row0mysql.h18
-rw-r--r--storage/innobase/include/srv0srv.h2
-rw-r--r--storage/innobase/include/sync0sync.ic2
-rw-r--r--storage/innobase/include/ut0ut.h6
-rw-r--r--storage/innobase/lock/lock0lock.c83
-rw-r--r--storage/innobase/os/os0file.c32
-rw-r--r--storage/innobase/plug.in43
-rw-r--r--storage/innobase/row/row0mysql.c50
-rw-r--r--storage/innobase/row/row0sel.c74
-rw-r--r--storage/innobase/srv/srv0srv.c49
-rw-r--r--storage/innobase/srv/srv0start.c15
-rw-r--r--storage/innobase/trx/trx0trx.c4
-rw-r--r--storage/innobase/trx/trx0undo.c2
-rw-r--r--storage/innobase/ut/ut0ut.c35
-rw-r--r--storage/myisam/ft_boolean_search.c38
-rw-r--r--storage/myisam/ft_parser.c77
-rw-r--r--storage/myisam/ftdefs.h1
-rw-r--r--storage/myisam/ha_myisam.cc4
-rw-r--r--storage/myisam/mi_check.c5
-rw-r--r--storage/myisam/mi_open.c7
-rw-r--r--storage/myisam/myisamdef.h2
-rw-r--r--storage/myisam/myisampack.c2
-rw-r--r--storage/myisammrg/myrg_open.c27
-rwxr-xr-xstorage/ndb/docs/doxygen/postdoxy.pl4
-rw-r--r--storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp2
-rw-r--r--storage/ndb/test/run-test/atrt.hpp3
-rw-r--r--storage/ndb/test/tools/connect.cpp3
47 files changed, 1083 insertions, 565 deletions
diff --git a/storage/archive/archive_reader.c b/storage/archive/archive_reader.c
index bfc01073161..84d4e318b49 100644
--- a/storage/archive/archive_reader.c
+++ b/storage/archive/archive_reader.c
@@ -374,10 +374,8 @@ static struct my_option my_long_options[] =
static void usage(void)
{
print_version();
- puts("Copyright (C) 2007 MySQL AB");
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
- \nand you are welcome to modify and redistribute it under the GPL \
- license\n");
+ puts("Copyright 2007-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
puts("Read and modify Archive files directly\n");
printf("Usage: %s [OPTIONS] file_to_be_looked_at [file_for_backup]\n", my_progname);
print_defaults("my", load_default_groups);
diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc
index be747e2d1de..03ed57f38e8 100644
--- a/storage/blackhole/ha_blackhole.cc
+++ b/storage/blackhole/ha_blackhole.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h
index 085840cce43..289e449be10 100644
--- a/storage/blackhole/ha_blackhole.h
+++ b/storage/blackhole/ha_blackhole.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 MySQL AB
+/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
index cc801b33955..e40c2db77db 100644
--- a/storage/csv/ha_tina.cc
+++ b/storage/csv/ha_tina.cc
@@ -1456,6 +1456,17 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
a file, which descriptor is still open. EACCES will be returned
when trying to delete the "to"-file in my_rename().
*/
+ if (share->tina_write_opened)
+ {
+ /*
+ Data file might be opened twice, on table opening stage and
+ during write_row execution. We need to close both instances
+ to satisfy Win.
+ */
+ if (my_close(share->tina_write_filedes, MYF(0)))
+ DBUG_RETURN(my_errno ? my_errno : -1);
+ share->tina_write_opened= FALSE;
+ }
if (my_close(data_file,MYF(0)) || my_close(repair_file, MYF(0)) ||
my_rename(repaired_fname, share->data_file_name, MYF(0)))
DBUG_RETURN(-1);
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index 4b81edc1111..e46379c25c9 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -2856,7 +2856,7 @@ int ha_federated::info(uint flag)
if (!(row= mysql_fetch_row(result)))
goto error;
- if (flag & HA_STATUS_VARIABLE | HA_STATUS_CONST)
+ if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST))
{
/*
deleted is set in ha_federated::info
diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc
index 2cadfa1c24d..1f74ad0f941 100644
--- a/storage/heap/ha_heap.cc
+++ b/storage/heap/ha_heap.cc
@@ -92,7 +92,7 @@ const char **ha_heap::bas_ext() const
int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
if ((test_if_locked & HA_OPEN_INTERNAL_TABLE) ||
- !(file= heap_open(name, mode)) && my_errno == ENOENT)
+ (!(file= heap_open(name, mode)) && my_errno == ENOENT))
{
HA_CREATE_INFO create_info;
internal_table= test(test_if_locked & HA_OPEN_INTERNAL_TABLE);
diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am
index b5e5c5375dc..7410bf7e591 100644
--- a/storage/innobase/Makefile.am
+++ b/storage/innobase/Makefile.am
@@ -15,21 +15,21 @@
# Process this file with automake to create Makefile.in
-MYSQLDATAdir = $(localstatedir)
-MYSQLSHAREdir = $(pkgdatadir)
-MYSQLBASEdir= $(prefix)
-MYSQLLIBdir= $(pkglibdir)
-pkgplugindir = $(pkglibdir)/plugin
-INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
+MYSQLDATAdir= $(localstatedir)
+MYSQLSHAREdir= $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+MYSQLLIBdir= $(pkglibdir)
+pkgplugindir= $(pkglibdir)/plugin
+INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \
-I$(top_srcdir)/regex \
-I$(top_srcdir)/storage/innobase/include \
-I$(top_srcdir)/sql \
- -I$(srcdir)
+ -I$(srcdir)
-DEFS = @DEFS@
+DEFS= @DEFS@
-noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
+noinst_HEADERS= include/btr0btr.h include/btr0btr.ic \
include/btr0cur.h include/btr0cur.ic \
include/btr0pcur.h include/btr0pcur.ic \
include/btr0sea.h include/btr0sea.ic \
@@ -121,9 +121,9 @@ noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
include/ut0list.ic include/ut0wqueue.h \
include/ha_prototypes.h handler/ha_innodb.h
-EXTRA_LIBRARIES = libinnobase.a
-noinst_LIBRARIES = @plugin_innobase_static_target@
-libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
+EXTRA_LIBRARIES= libinnobase.a
+noinst_LIBRARIES= @plugin_innobase_static_target@
+libinnobase_a_SOURCES= btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
btr/btr0sea.c buf/buf0buf.c buf/buf0flu.c \
buf/buf0lru.c buf/buf0rea.c data/data0data.c \
data/data0type.c dict/dict0boot.c \
@@ -156,17 +156,17 @@ libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
handler/ha_innodb.cc
libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
-libinnobase_a_CFLAGS = $(AM_CFLAGS)
+libinnobase_a_CFLAGS= $(AM_CFLAGS)
-EXTRA_LTLIBRARIES = ha_innodb.la
+EXTRA_LTLIBRARIES= ha_innodb.la
pkgplugin_LTLIBRARIES= @plugin_innobase_shared_target@
-ha_innodb_la_LDFLAGS = -module -rpath $(pkgplugindir)
-ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
-ha_innodb_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
-ha_innodb_la_SOURCES = $(libinnobase_a_SOURCES)
+ha_innodb_la_LDFLAGS= -module -rpath $(pkgplugindir)
+ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
+ha_innodb_la_CFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
+ha_innodb_la_SOURCES= $(libinnobase_a_SOURCES)
-EXTRA_DIST = CMakeLists.txt plug.in \
+EXTRA_DIST= CMakeLists.txt plug.in \
pars/make_bison.sh pars/make_flex.sh \
pars/pars0grm.y pars/pars0lex.l
diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c
index b0ce5db6ccd..6a13ca863bd 100644
--- a/storage/innobase/btr/btr0sea.c
+++ b/storage/innobase/btr/btr0sea.c
@@ -161,6 +161,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;
@@ -184,6 +185,31 @@ btr_search_info_create(
return(info);
}
+/*********************************************************************
+Returns the value of ref_count. The value is protected by
+btr_search_latch. */
+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
@@ -1022,8 +1048,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:
if (UNIV_UNLIKELY(block->n_pointers)) {
/* Corruption */
@@ -1244,6 +1274,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;
diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c
index f3913ed49b7..d3c787d1578 100644
--- a/storage/innobase/buf/buf0lru.c
+++ b/storage/innobase/buf/buf0lru.c
@@ -42,6 +42,11 @@ initial segment in buf_LRU_get_recent_limit */
#define BUF_LRU_INITIAL_RATIO 8
+/* When dropping the search hash index entries before deleting an ibd
+file, we build a local array of pages belonging to that tablespace
+in the buffer pool. Following is the size of that array. */
+#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024
+
/* If we switch on the InnoDB monitor because there are too few available
frames in the buffer pool, we set this to TRUE */
ibool buf_lru_switched_on_innodb_mon = FALSE;
@@ -66,6 +71,120 @@ buf_LRU_block_free_hashed_page(
be in a state where it can be freed */
/**********************************************************************
+Attempts to drop page hash index on a batch of pages belonging to a
+particular space id. */
+static
+void
+buf_LRU_drop_page_hash_batch(
+/*=========================*/
+ ulint id, /* in: space id */
+ const ulint* arr, /* in: array of page_no */
+ ulint count) /* in: number of entries in array */
+{
+ ulint i;
+
+ ut_ad(arr != NULL);
+ ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
+
+ for (i = 0; i < count; ++i) {
+ btr_search_drop_page_hash_when_freed(id, arr[i]);
+ }
+}
+
+/**********************************************************************
+When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
+hash index entries belonging to that table. This function tries to
+do that in batch. Note that this is a 'best effort' attempt and does
+not guarantee that ALL hash entries will be removed. */
+static
+void
+buf_LRU_drop_page_hash_for_tablespace(
+/*==================================*/
+ ulint id) /* in: space id */
+{
+ buf_block_t* block;
+ ulint* page_arr;
+ ulint num_entries;
+
+ page_arr = ut_malloc(sizeof(ulint)
+ * BUF_LRU_DROP_SEARCH_HASH_SIZE);
+ mutex_enter(&buf_pool->mutex);
+
+scan_again:
+ num_entries = 0;
+ block = UT_LIST_GET_LAST(buf_pool->LRU);
+
+ while (block != NULL) {
+ buf_block_t* prev_block;
+
+ mutex_enter(&block->mutex);
+ prev_block = UT_LIST_GET_PREV(LRU, block);
+
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
+ if (block->space != id
+ || block->buf_fix_count > 0
+ || block->io_fix != 0) {
+ /* We leave the fixed pages as is in this scan.
+ To be dealt with later in the final scan. */
+ mutex_exit(&block->mutex);
+ goto next_page;
+ }
+
+ ut_ad(block->space == id);
+ if (block->is_hashed) {
+
+ /* Store the offset(i.e.: page_no) in the array
+ so that we can drop hash index in a batch
+ later. */
+ page_arr[num_entries] = block->offset;
+ mutex_exit(&block->mutex);
+ ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
+ ++num_entries;
+
+ if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
+ goto next_page;
+ }
+ /* Array full. We release the buf_pool->mutex to
+ obey the latching order. */
+ mutex_exit(&buf_pool->mutex);
+
+ buf_LRU_drop_page_hash_batch(id, page_arr,
+ num_entries);
+ num_entries = 0;
+ mutex_enter(&buf_pool->mutex);
+ } else {
+ mutex_exit(&block->mutex);
+ }
+
+next_page:
+ /* Note that we may have released the buf_pool->mutex
+ above after reading the prev_block during processing
+ of a page_hash_batch (i.e.: when the array was full).
+ This means that prev_block can change in LRU list.
+ This is OK because this function is a 'best effort'
+ to drop as many search hash entries as possible and
+ it does not guarantee that ALL such entries will be
+ dropped. */
+ block = prev_block;
+
+ /* If, however, block has been removed from LRU list
+ to the free list then we should restart the scan.
+ block->state is protected by buf_pool->mutex. */
+ if (block && block->state != BUF_BLOCK_FILE_PAGE) {
+ ut_a(num_entries == 0);
+ goto scan_again;
+ }
+ }
+
+ mutex_exit(&buf_pool->mutex);
+
+ /* Drop any remaining batch of search hashed pages. */
+ buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
+ ut_free(page_arr);
+}
+
+/**********************************************************************
Invalidates all pages belonging to a given tablespace when we are deleting
the data file(s) of that tablespace. */
@@ -78,6 +197,14 @@ buf_LRU_invalidate_tablespace(
ulint page_no;
ibool all_freed;
+ /* Before we attempt to drop pages one by one we first
+ attempt to drop page hash index entries in batches to make
+ it more efficient. The batching attempt is a best effort
+ attempt and does not guarantee that all pages hash entries
+ will be dropped. We get rid of remaining page hash entries
+ one by one below. */
+ buf_LRU_drop_page_hash_for_tablespace(id);
+
scan_again:
mutex_enter(&(buf_pool->mutex));
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
index 5eaa44b4615..c7a57d6a2b8 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innobase/dict/dict0dict.c
@@ -422,8 +422,7 @@ dict_table_autoinc_lock(
}
/************************************************************************
-Initializes the autoinc counter. It is not an error to initialize an already
-initialized counter. */
+Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
@@ -433,7 +432,6 @@ dict_table_autoinc_initialize(
{
ut_ad(mutex_own(&table->autoinc_mutex));
- table->autoinc_inited = TRUE;
table->autoinc = value;
}
@@ -447,32 +445,25 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
- ib_longlong value;
-
ut_ad(mutex_own(&table->autoinc_mutex));
- if (!table->autoinc_inited) {
-
- value = 0;
- } else {
- value = table->autoinc;
- }
-
- return(value);
+ return(table->autoinc);
}
/************************************************************************
Updates the autoinc counter if the value supplied is greater than the
-current value. If not inited, does nothing. */
+current value. */
void
-dict_table_autoinc_update(
-/*======================*/
+dict_table_autoinc_update_if_greater(
+/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value) /* in: value which was assigned to a row */
{
- if (table->autoinc_inited && value > table->autoinc) {
+ ut_ad(mutex_own(&table->autoinc_mutex));
+
+ if (value > table->autoinc) {
table->autoinc = value;
}
@@ -1394,12 +1385,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 */
diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
index 47cf7a0bc9c..168771ca307 100644
--- a/storage/innobase/dict/dict0mem.c
+++ b/storage/innobase/dict/dict0mem.c
@@ -89,11 +89,7 @@ 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;
+ table->autoinc = 0;
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 5c7366ef4c3..cffa79300c7 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -128,7 +128,7 @@ static my_bool innobase_file_per_table = FALSE;
static my_bool innobase_locks_unsafe_for_binlog = FALSE;
static my_bool innobase_rollback_on_timeout = FALSE;
static my_bool innobase_create_status_file = FALSE;
-static my_bool innobase_stats_on_metadata = TRUE;
+static my_bool innobase_stats_on_metadata = TRUE;
static my_bool innobase_adaptive_hash_index = TRUE;
static char* internal_innobase_data_file_path = NULL;
@@ -485,7 +485,7 @@ innodb_srv_conc_exit_innodb(
/*========================*/
trx_t* trx) /* in: transaction handle */
{
- if (UNIV_LIKELY(!srv_thread_concurrency)) {
+ if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
return;
}
@@ -531,6 +531,18 @@ thd_has_edited_nontrans_tables(
return((ibool) thd_non_transactional_update((THD*) thd));
}
+/**********************************************************************
+Returns true if the thread is executing a SELECT statement. */
+extern "C"
+ibool
+thd_is_select(
+/*==========*/
+ /* out: true if thd is executing SELECT */
+ const void* thd) /* in: thread handle (THD*) */
+{
+ return(thd_sql_command((const THD*) thd) == SQLCOM_SELECT);
+}
+
/************************************************************************
Obtain the InnoDB transaction of a MySQL thread. */
inline
@@ -934,6 +946,81 @@ innobase_convert_string(
}
/*************************************************************************
+Compute the next autoinc value.
+
+For MySQL replication the autoincrement values can be partitioned among
+the nodes. The offset is the start or origin of the autoincrement value
+for a particular node. For n nodes the increment will be n and the offset
+will be in the interval [1, n]. The formula tries to allocate the next
+value for a particular node.
+
+Note: This function is also called with increment set to the number of
+values we want to reserve for multi-value inserts e.g.,
+
+ INSERT INTO T VALUES(), (), ();
+
+innobase_next_autoinc() will be called with increment set to
+n * 3 where autoinc_lock_mode != TRADITIONAL because we want
+to reserve 3 values for the multi-value INSERT above. */
+static
+ulonglong
+innobase_next_autoinc(
+/*==================*/
+ /* out: the next value */
+ ulonglong current, /* in: Current value */
+ ulonglong increment, /* in: increment current by */
+ ulonglong offset, /* in: AUTOINC offset */
+ ulonglong max_value) /* in: max value for type */
+{
+ ulonglong next_value;
+
+ /* Should never be 0. */
+ ut_a(increment > 0);
+
+ if (max_value <= current) {
+ next_value = max_value;
+ } else if (offset <= 1) {
+ /* Offset 0 and 1 are the same, because there must be at
+ least one node in the system. */
+ if (max_value - current <= increment) {
+ next_value = max_value;
+ } else {
+ next_value = current + increment;
+ }
+ } else {
+ if (current > offset) {
+ next_value = ((current - offset) / increment) + 1;
+ } else {
+ next_value = ((offset - current) / increment) + 1;
+ }
+
+ ut_a(increment > 0);
+ ut_a(next_value > 0);
+
+ /* Check for multiplication overflow. */
+ if (increment > (max_value / next_value)) {
+
+ next_value = max_value;
+ } else {
+ next_value *= increment;
+
+ ut_a(max_value >= next_value);
+
+ /* Check for overflow. */
+ if (max_value - next_value <= offset) {
+ next_value = max_value;
+ } else {
+ next_value += offset;
+ }
+ }
+ }
+
+ ut_a(next_value <= max_value);
+
+ return(next_value);
+}
+
+/*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still
lacks one. */
@@ -1658,8 +1745,6 @@ innobase_init(
srv_max_n_open_files = (ulint) innobase_open_files;
srv_innodb_status = (ibool) innobase_create_status_file;
- srv_stats_on_metadata = (ibool) innobase_stats_on_metadata;
-
srv_use_adaptive_hash_indexes =
(ibool) innobase_adaptive_hash_index;
@@ -2294,6 +2379,44 @@ normalize_table_name(
#endif
}
+/************************************************************************
+Set the autoinc column max value. This should only be called once from
+ha_innobase::open(). Therefore there's no need for a covering lock. */
+
+ulong
+ha_innobase::innobase_initialize_autoinc()
+/*======================================*/
+{
+ dict_index_t* index;
+ ulonglong auto_inc;
+ const char* col_name;
+ ulint error = DB_SUCCESS;
+ dict_table_t* innodb_table = prebuilt->table;
+
+ col_name = table->found_next_number_field->field_name;
+ index = innobase_get_index(table->s->next_number_index);
+
+ /* Execute SELECT MAX(col_name) FROM TABLE; */
+ error = row_search_max_autoinc(index, col_name, &auto_inc);
+
+ if (error == DB_SUCCESS) {
+
+ /* At the this stage we dont' know the increment
+ or the offset, so use default inrement of 1. */
+ ++auto_inc;
+
+ dict_table_autoinc_initialize(innodb_table, auto_inc);
+
+ } else {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
+ "the MAX(%s) autoinc value from the "
+ "index (%s).\n", error, col_name, index->name);
+ }
+
+ return(ulong(error));
+}
+
/*********************************************************************
Creates and opens a handle to a table which already exists in an InnoDB
database. */
@@ -2318,6 +2441,14 @@ ha_innobase::open(
UT_NOT_USED(test_if_locked);
thd = ha_thd();
+
+ /* Under some cases MySQL seems to call this function while
+ holding btr_search_latch. This breaks the latching order as
+ we acquire dict_sys->mutex below and leads to a deadlock. */
+ if (thd != NULL) {
+ innobase_release_temporary_latches(ht, thd);
+ }
+
normalize_table_name(norm_name, name);
user_thd = NULL;
@@ -2409,6 +2540,8 @@ retry:
prebuilt = row_create_prebuilt(ib_table);
prebuilt->mysql_row_len = table->s->reclength;
+ prebuilt->default_rec = table->s->default_values;
+ ut_ad(prebuilt->default_rec);
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
@@ -2477,6 +2610,26 @@ retry:
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ /* Only if the table has an AUTOINC column. */
+ if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
+ ulint error;
+
+ dict_table_autoinc_lock(prebuilt->table);
+
+ /* Since a table can already be "open" in InnoDB's internal
+ data dictionary, we only init the autoinc counter once, the
+ first time the table is loaded. We can safely reuse the
+ autoinc value from a previous MySQL open. */
+ if (dict_table_autoinc_read(prebuilt->table) == 0) {
+
+ error = innobase_initialize_autoinc();
+ /* Should always succeed! */
+ ut_a(error == DB_SUCCESS);
+ }
+
+ dict_table_autoinc_unlock(prebuilt->table);
+ }
+
DBUG_RETURN(0);
}
@@ -3284,6 +3437,59 @@ skip_field:
}
/************************************************************************
+Get the upper limit of the MySQL integral type. */
+
+ulonglong
+ha_innobase::innobase_get_int_col_max_value(
+/*========================================*/
+ const Field* field)
+{
+ ulonglong max_value = 0;
+
+ switch(field->key_type()) {
+ /* TINY */
+ case HA_KEYTYPE_BINARY:
+ max_value = 0xFFULL;
+ break;
+ case HA_KEYTYPE_INT8:
+ max_value = 0x7FULL;
+ break;
+ /* SHORT */
+ case HA_KEYTYPE_USHORT_INT:
+ max_value = 0xFFFFULL;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ max_value = 0x7FFFULL;
+ break;
+ /* MEDIUM */
+ case HA_KEYTYPE_UINT24:
+ max_value = 0xFFFFFFULL;
+ break;
+ case HA_KEYTYPE_INT24:
+ max_value = 0x7FFFFFULL;
+ break;
+ /* LONG */
+ case HA_KEYTYPE_ULONG_INT:
+ max_value = 0xFFFFFFFFULL;
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ max_value = 0x7FFFFFFFULL;
+ break;
+ /* BIG */
+ case HA_KEYTYPE_ULONGLONG:
+ max_value = 0xFFFFFFFFFFFFFFFFULL;
+ break;
+ case HA_KEYTYPE_LONGLONG:
+ max_value = 0x7FFFFFFFFFFFFFFFULL;
+ break;
+ default:
+ ut_error;
+ }
+
+ return(max_value);
+}
+
+/************************************************************************
This special handling is really to overcome the limitations of MySQL's
binlogging. We need to eliminate the non-determinism that will arise in
INSERT ... SELECT type of statements, since MySQL binlog only stores the
@@ -3291,7 +3497,7 @@ min value of the autoinc interval. Once that is fixed we can get rid of
the special lock handling.*/
ulong
-ha_innobase::innobase_autoinc_lock(void)
+ha_innobase::innobase_lock_autoinc(void)
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
@@ -3356,7 +3562,7 @@ ha_innobase::innobase_reset_autoinc(
{
ulint error;
- error = innobase_autoinc_lock();
+ error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
@@ -3381,11 +3587,11 @@ ha_innobase::innobase_set_max_autoinc(
{
ulint error;
- error = innobase_autoinc_lock();
+ error = innobase_lock_autoinc();
if (error == DB_SUCCESS) {
- dict_table_autoinc_update(prebuilt->table, auto_inc);
+ dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
dict_table_autoinc_unlock(prebuilt->table);
}
@@ -3403,7 +3609,8 @@ ha_innobase::write_row(
/* out: error code */
uchar* record) /* in: a row in MySQL format */
{
- int error = 0;
+ ulint error = 0;
+ int error_result= 0;
ibool auto_inc_used= FALSE;
ulint sql_command;
trx_t* trx = thd_to_trx(user_thd);
@@ -3505,8 +3712,21 @@ no_commit:
/* This is the case where the table has an auto-increment column */
if (table->next_number_field && record == table->record[0]) {
+ /* Reset the error code before calling
+ innobase_get_auto_increment(). */
+ prebuilt->autoinc_error = DB_SUCCESS;
+
if ((error = update_auto_increment())) {
+ /* We don't want to mask autoinc overflow errors. */
+ if (prebuilt->autoinc_error != DB_SUCCESS) {
+ error = (int) prebuilt->autoinc_error;
+
+ goto report_error;
+ }
+
+ /* MySQL errors are passed straight back. */
+ error_result = (int) error;
goto func_exit;
}
@@ -3530,6 +3750,7 @@ no_commit:
if (auto_inc_used) {
ulint err;
ulonglong auto_inc;
+ ulonglong col_max_value;
/* Note the number of rows processed for this statement, used
by get_auto_increment() to determine the number of AUTO-INC
@@ -3539,6 +3760,11 @@ no_commit:
--trx->n_autoinc_rows;
}
+ /* We need the upper limit of the col type to check for
+ whether we update the table autoinc counter or not. */
+ col_max_value = innobase_get_int_col_max_value(
+ table->next_number_field);
+
/* Get the value that MySQL attempted to store in the table.*/
auto_inc = table->next_number_field->val_int();
@@ -3577,27 +3803,24 @@ no_commit:
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
- if (auto_inc > prebuilt->last_value) {
+ if (auto_inc <= col_max_value
+ && auto_inc > prebuilt->autoinc_last_value) {
set_max_autoinc:
- ut_a(prebuilt->table->autoinc_increment > 0);
+ ut_a(prebuilt->autoinc_increment > 0);
- ulonglong have;
ulonglong need;
+ ulonglong offset;
- /* Check for overflow conditions. */
- need = prebuilt->table->autoinc_increment;
- have = ~0x0ULL - auto_inc;
+ offset = prebuilt->autoinc_offset;
+ need = prebuilt->autoinc_increment;
- if (have < need) {
- need = have;
- }
-
- auto_inc += need;
+ auto_inc = innobase_next_autoinc(
+ auto_inc, need, offset, col_max_value);
err = innobase_set_max_autoinc(auto_inc);
if (err != DB_SUCCESS) {
- error = (int) err;
+ error = err;
}
}
break;
@@ -3606,12 +3829,13 @@ set_max_autoinc:
innodb_srv_conc_exit_innodb(prebuilt->trx);
- error = convert_error_code_to_mysql(error, user_thd);
+report_error:
+ error_result = convert_error_code_to_mysql((int) error, user_thd);
func_exit:
innobase_active_small();
- DBUG_RETURN(error);
+ DBUG_RETURN(error_result);
}
/**************************************************************************
@@ -3787,6 +4011,8 @@ ha_innobase::update_row(
ut_a(prebuilt->trx == trx);
+ ha_statistic_increment(&SSV::ha_update_count);
+
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
@@ -3827,12 +4053,26 @@ ha_innobase::update_row(
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
- longlong auto_inc;
+ ulonglong auto_inc;
+ ulonglong col_max_value;
auto_inc = table->next_number_field->val_int();
- if (auto_inc != 0) {
- auto_inc += prebuilt->table->autoinc_increment;
+ /* We need the upper limit of the col type to check for
+ whether we update the table autoinc counter or not. */
+ col_max_value = innobase_get_int_col_max_value(
+ table->next_number_field);
+
+ if (auto_inc <= col_max_value && auto_inc != 0) {
+
+ ulonglong need;
+ ulonglong offset;
+
+ offset = prebuilt->autoinc_offset;
+ need = prebuilt->autoinc_increment;
+
+ auto_inc = innobase_next_autoinc(
+ auto_inc, need, offset, col_max_value);
error = innobase_set_max_autoinc(auto_inc);
}
@@ -3876,29 +4116,7 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx);
- /* Only if the table has an AUTOINC column */
- if (table->found_next_number_field && record == table->record[0]) {
- ulonglong dummy = 0;
-
- /* First check whether the AUTOINC sub-system has been
- initialized using the AUTOINC mutex. If not then we
- do it the "proper" way, by acquiring the heavier locks. */
- dict_table_autoinc_lock(prebuilt->table);
-
- if (!prebuilt->table->autoinc_inited) {
- dict_table_autoinc_unlock(prebuilt->table);
-
- error = innobase_get_auto_increment(&dummy);
-
- if (error == DB_SUCCESS) {
- dict_table_autoinc_unlock(prebuilt->table);
- } else {
- goto error_exit;
- }
- } else {
- dict_table_autoinc_unlock(prebuilt->table);
- }
- }
+ ha_statistic_increment(&SSV::ha_delete_count);
if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt);
@@ -3914,7 +4132,6 @@ ha_innobase::delete_row(
innodb_srv_conc_exit_innodb(trx);
-error_exit:
error = convert_error_code_to_mysql(error, user_thd);
/* Tell the InnoDB server that there might be work for
@@ -3946,7 +4163,8 @@ ha_innobase::unlock_row(void)
switch (prebuilt->row_read_type) {
case ROW_READ_WITH_LOCKS:
if (!srv_locks_unsafe_for_binlog
- || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) {
+ && prebuilt->trx->isolation_level
+ != TRX_ISO_READ_COMMITTED) {
break;
}
/* fall through */
@@ -5018,6 +5236,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,
@@ -5248,7 +5489,8 @@ ha_innobase::delete_all_rows(void)
if (thd_sql_command(user_thd) != SQLCOM_TRUNCATE) {
fallback:
/* We only handle TRUNCATE TABLE t as a special case.
- DELETE FROM t will have to use ha_innobase::delete_row(). */
+ DELETE FROM t will have to use ha_innobase::delete_row(),
+ because DELETE is transactional while TRUNCATE is not. */
DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND);
}
@@ -5769,7 +6011,7 @@ ha_innobase::info(
ib_table = prebuilt->table;
if (flag & HA_STATUS_TIME) {
- if (srv_stats_on_metadata) {
+ if (innobase_stats_on_metadata) {
/* In sql_show we call with this flag: update
then statistics so that they are up-to-date */
@@ -5817,11 +6059,13 @@ ha_innobase::info(
n_rows++;
}
- /* Fix bug#29507: TRUNCATE shows too many rows affected.
- Do not show the estimates for TRUNCATE command. */
+ /* Fix bug#40386: Not flushing query cache after truncate.
+ n_rows can not be 0 unless the table is empty, set to 1
+ instead. The original problem of bug#29507 is actually
+ fixed in the server code. */
if (thd_sql_command(user_thd) == SQLCOM_TRUNCATE) {
- n_rows = 0;
+ n_rows = 1;
/* We need to reset the prebuilt value too, otherwise
checks for values greater than the last value written
@@ -5829,7 +6073,7 @@ ha_innobase::info(
not be updated. This will force write_row() into
attempting an update of the table's AUTOINC counter. */
- prebuilt->last_value = 0;
+ prebuilt->autoinc_last_value = 0;
}
stats.records = (ha_rows)n_rows;
@@ -5850,9 +6094,39 @@ ha_innobase::info(
so the "old" value can remain. delete_length is initialized
to 0 in the ha_statistics' constructor. */
if (!(flag & HA_STATUS_NO_LOCK)) {
- stats.delete_length =
- fsp_get_available_space_in_free_extents(
- ib_table->space) * 1024;
+
+ /* lock the data dictionary to avoid races with
+ ibd_file_missing and tablespace_discarded */
+ row_mysql_lock_data_dictionary(prebuilt->trx);
+
+ /* ib_table->space must be an existent tablespace */
+ if (!ib_table->ibd_file_missing
+ && !ib_table->tablespace_discarded) {
+
+ stats.delete_length =
+ fsp_get_available_space_in_free_extents(
+ ib_table->space) * 1024;
+ } else {
+
+ THD* thd;
+
+ thd = ha_thd();
+
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_GET_STAT,
+ "InnoDB: Trying to get the free "
+ "space for table %s but its "
+ "tablespace has been discarded or "
+ "the .ibd file is missing. Setting "
+ "the free space to zero.",
+ ib_table->name);
+
+ stats.delete_length = 0;
+ }
+
+ row_mysql_unlock_data_dictionary(prebuilt->trx);
}
stats.check_time = 0;
@@ -5937,29 +6211,7 @@ ha_innobase::info(
}
if (flag & HA_STATUS_AUTO && table->found_next_number_field) {
- ulonglong auto_inc;
- int ret;
-
- /* The following function call can the first time fail in
- a lock wait timeout error because it reserves the auto-inc
- lock on the table. If it fails, then someone is already initing
- the auto-inc counter, and the second call is guaranteed to
- succeed. */
-
- ret = innobase_read_and_init_auto_inc(&auto_inc);
-
- if (ret != 0) {
- ret = innobase_read_and_init_auto_inc(&auto_inc);
-
- if (ret != 0) {
- sql_print_error("Cannot get table %s auto-inc"
- "counter value in ::info\n",
- ib_table->name);
- auto_inc = 0;
- }
- }
-
- stats.auto_increment_value = auto_inc;
+ stats.auto_increment_value = innobase_peek_autoinc();
}
prebuilt->trx->op_info = (char*)"";
@@ -6422,15 +6674,26 @@ ha_innobase::extra(
return(0);
}
+/**********************************************************************
+Reset state of file to after 'open'.
+This function is called after every statement for all tables used
+by that statement. */
int ha_innobase::reset()
{
- if (prebuilt->blob_heap) {
- row_mysql_prebuilt_free_blob_heap(prebuilt);
- }
- reset_template(prebuilt);
- return 0;
-}
+ if (prebuilt->blob_heap) {
+ row_mysql_prebuilt_free_blob_heap(prebuilt);
+ }
+ reset_template(prebuilt);
+
+ /* TODO: This should really be reset in reset_template() but for now
+ it's safer to do it explicitly here. */
+
+ /* This is a statement level counter. */
+ prebuilt->autoinc_last_value = 0;
+
+ return(0);
+}
/**********************************************************************
MySQL calls this function at the start of each SQL statement inside LOCK
@@ -7305,169 +7568,59 @@ ha_innobase::store_lock(
return(to);
}
-/***********************************************************************
-This function initializes the auto-inc counter if it has not been
-initialized yet. This function does not change the value of the auto-inc
-counter if it already has been initialized. In parameter ret returns
-the value of the auto-inc counter. */
-
-int
-ha_innobase::innobase_read_and_init_auto_inc(
-/*=========================================*/
- /* out: 0 or generic MySQL
- error code */
- ulonglong* value) /* out: the autoinc value */
-{
- ulonglong auto_inc;
- ibool stmt_start;
- int mysql_error = 0;
- dict_table_t* innodb_table = prebuilt->table;
- ibool trx_was_not_started = FALSE;
-
- ut_a(prebuilt);
- ut_a(prebuilt->table);
-
- /* Remember if we are in the beginning of an SQL statement.
- This function must not change that flag. */
- stmt_start = prebuilt->sql_stat_start;
-
- /* Prepare prebuilt->trx in the table handle */
- update_thd(ha_thd());
-
- if (prebuilt->trx->conc_state == TRX_NOT_STARTED) {
- trx_was_not_started = TRUE;
- }
-
- /* In case MySQL calls this in the middle of a SELECT query, release
- possible adaptive hash latch to avoid deadlocks of threads */
-
- trx_search_latch_release_if_reserved(prebuilt->trx);
-
- dict_table_autoinc_lock(prebuilt->table);
-
- auto_inc = dict_table_autoinc_read(prebuilt->table);
-
- /* Was the AUTOINC counter reset during normal processing, if
- so then we simply start count from 1. No need to go to the index.*/
- if (auto_inc == 0 && innodb_table->autoinc_inited) {
- ++auto_inc;
- dict_table_autoinc_initialize(innodb_table, auto_inc);
- }
-
- if (auto_inc == 0) {
- dict_index_t* index;
- ulint error;
- const char* autoinc_col_name;
-
- ut_a(!innodb_table->autoinc_inited);
-
- index = innobase_get_index(table->s->next_number_index);
-
- autoinc_col_name = table->found_next_number_field->field_name;
-
- error = row_search_max_autoinc(
- index, autoinc_col_name, &auto_inc);
-
- if (error == DB_SUCCESS) {
- if (auto_inc < ~0x0ULL) {
- ++auto_inc;
- }
- dict_table_autoinc_initialize(innodb_table, auto_inc);
- } else {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
- "the max AUTOINC value from the index (%s).\n",
- error, index->name);
-
- mysql_error = 1;
- }
- }
-
- *value = auto_inc;
-
- dict_table_autoinc_unlock(prebuilt->table);
-
- /* Since MySQL does not seem to call autocommit after SHOW TABLE
- STATUS (even if we would register the trx here), we commit our
- transaction here if it was started here. This is to eliminate a
- dangling transaction. If the user had AUTOCOMMIT=0, then SHOW
- TABLE STATUS does leave a dangling transaction if the user does not
- himself call COMMIT. */
-
- if (trx_was_not_started) {
-
- innobase_commit_low(prebuilt->trx);
- }
-
- prebuilt->sql_stat_start = stmt_start;
-
- return(mysql_error);
-}
-
/*******************************************************************************
-Read the next autoinc value, initialize the table if it's not initialized.
-On return if there is no error then the tables AUTOINC lock is locked.*/
+Read the next autoinc value. Acquire the relevant locks before reading
+the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
+on return and all relevant locks acquired. */
ulong
-ha_innobase::innobase_get_auto_increment(
-/*=====================================*/
+ha_innobase::innobase_get_autoinc(
+/*==============================*/
+ /* out: DB_SUCCESS or error code */
ulonglong* value) /* out: autoinc value */
{
- ulong error;
+ *value = 0;
+
+ prebuilt->autoinc_error = innobase_lock_autoinc();
- *value = 0;
+ if (prebuilt->autoinc_error == DB_SUCCESS) {
- /* Note: If the table is not initialized when we attempt the
- read below. We initialize the table's auto-inc counter and
- always do a reread of the AUTOINC value. */
- do {
- error = innobase_autoinc_lock();
+ /* Determine the first value of the interval */
+ *value = dict_table_autoinc_read(prebuilt->table);
- if (error == DB_SUCCESS) {
- ulonglong autoinc;
+ /* It should have been initialized during open. */
+ ut_a(*value != 0);
+ }
+
+ return(ulong(prebuilt->autoinc_error));
+}
- /* Determine the first value of the interval */
- autoinc = dict_table_autoinc_read(prebuilt->table);
+/***********************************************************************
+This function reads the global auto-inc counter. It doesn't use the
+AUTOINC lock even if the lock mode is set to TRADITIONAL. */
- /* We need to initialize the AUTO-INC value, for
- that we release all locks.*/
- if (autoinc == 0) {
- trx_t* trx;
+ulonglong
+ha_innobase::innobase_peek_autoinc()
+/*================================*/
+ /* out: the autoinc value */
+{
+ ulonglong auto_inc;
+ dict_table_t* innodb_table;
- trx = prebuilt->trx;
- dict_table_autoinc_unlock(prebuilt->table);
+ ut_a(prebuilt != NULL);
+ ut_a(prebuilt->table != NULL);
- /* If we had reserved the AUTO-INC
- lock in this SQL statement we release
- it before retrying.*/
- row_unlock_table_autoinc_for_mysql(trx);
+ innodb_table = prebuilt->table;
- /* Just to make sure */
- ut_a(!trx->auto_inc_lock);
+ dict_table_autoinc_lock(innodb_table);
- int mysql_error;
+ auto_inc = dict_table_autoinc_read(innodb_table);
- mysql_error = innobase_read_and_init_auto_inc(
- &autoinc);
+ ut_a(auto_inc > 0);
- if (mysql_error) {
- error = DB_ERROR;
- }
- } else {
- *value = autoinc;
- }
- /* A deadlock error during normal processing is OK
- and can be ignored. */
- } else if (error != DB_DEADLOCK) {
-
- sql_print_error("InnoDB: Error: %lu in "
- "::innobase_get_auto_increment()",
- error);
- }
-
- } while (*value == 0 && error == DB_SUCCESS);
-
- return(error);
+ dict_table_autoinc_unlock(innodb_table);
+
+ return(auto_inc);
}
/*******************************************************************************
@@ -7494,7 +7647,7 @@ ha_innobase::get_auto_increment(
/* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd());
- error = innobase_get_auto_increment(&autoinc);
+ error = innobase_get_autoinc(&autoinc);
if (error != DB_SUCCESS) {
*first_value = (~(ulonglong) 0);
@@ -7530,7 +7683,7 @@ ha_innobase::get_auto_increment(
set_if_bigger(*first_value, autoinc);
/* Not in the middle of a mult-row INSERT. */
- } else if (prebuilt->last_value == 0) {
+ } else if (prebuilt->autoinc_last_value == 0) {
set_if_bigger(*first_value, autoinc);
}
@@ -7539,35 +7692,40 @@ ha_innobase::get_auto_increment(
/* With old style AUTOINC locking we only update the table's
AUTOINC counter after attempting to insert the row. */
if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
- ulonglong have;
ulonglong need;
+ ulonglong next_value;
+ ulonglong col_max_value;
- /* Check for overflow conditions. */
- need = *nb_reserved_values * increment;
- have = ~0x0ULL - *first_value;
+ /* We need the upper limit of the col type to check for
+ whether we update the table autoinc counter or not. */
+ col_max_value = innobase_get_int_col_max_value(
+ table->next_number_field);
- if (have < need) {
- need = have;
- }
+ need = *nb_reserved_values * increment;
/* Compute the last value in the interval */
- prebuilt->last_value = *first_value + need;
+ next_value = innobase_next_autoinc(
+ *first_value, need, offset, col_max_value);
- ut_a(prebuilt->last_value >= *first_value);
+ prebuilt->autoinc_last_value = next_value;
+
+ ut_a(prebuilt->autoinc_last_value >= *first_value);
/* Update the table autoinc variable */
- dict_table_autoinc_update(
- prebuilt->table, prebuilt->last_value);
+ dict_table_autoinc_update_if_greater(
+ prebuilt->table, prebuilt->autoinc_last_value);
} else {
/* This will force write_row() into attempting an update
of the table's AUTOINC counter. */
- prebuilt->last_value = 0;
+ prebuilt->autoinc_last_value = 0;
}
/* The increment to be used to increase the AUTOINC value, we use
this in write_row() and update_row() to increase the autoinc counter
- for columns that are filled by the user.*/
- prebuilt->table->autoinc_increment = increment;
+ for columns that are filled by the user. We need the offset and
+ the increment. */
+ prebuilt->autoinc_offset = offset;
+ prebuilt->autoinc_increment = increment;
dict_table_autoinc_unlock(prebuilt->table);
}
@@ -7592,6 +7750,11 @@ ha_innobase::reset_auto_increment(
DBUG_RETURN(error);
}
+ /* The next value can never be 0. */
+ if (value == 0) {
+ value = 1;
+ }
+
innobase_reset_autoinc(value);
DBUG_RETURN(0);
@@ -8146,7 +8309,7 @@ static MYSQL_SYSVAR_BOOL(status_file, innobase_create_status_file,
NULL, NULL, FALSE);
static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
- PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
+ PLUGIN_VAR_OPCMDARG,
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
NULL, NULL, TRUE);
@@ -8159,7 +8322,7 @@ static MYSQL_SYSVAR_BOOL(adaptive_hash_index, innobase_adaptive_hash_index,
static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
- NULL, NULL, 8*1024*1024L, 2*1024*1024L, ~0L, 1024);
+ NULL, NULL, 8*1024*1024L, 2*1024*1024L, LONG_MAX, 1024);
static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment,
PLUGIN_VAR_RQCMDARG,
@@ -8209,7 +8372,7 @@ static MYSQL_SYSVAR_LONG(lock_wait_timeout, innobase_lock_wait_timeout,
static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
- NULL, NULL, 16*1024*1024L, 2*1024*1024L, ~0L, 1024);
+ NULL, NULL, 16*1024*1024L, 2*1024*1024L, LONG_MAX, 1024);
static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -8229,7 +8392,7 @@ static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
static MYSQL_SYSVAR_LONG(open_files, innobase_open_files,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"How many files at the maximum InnoDB keeps open at the same time.",
- NULL, NULL, 300L, 10L, ~0L, 0);
+ NULL, NULL, 300L, 10L, LONG_MAX, 0);
static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
PLUGIN_VAR_RQCMDARG,
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 4ffcdb1e3c2..8ca72ee1a60 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -72,12 +72,15 @@ class ha_innobase: public handler
int update_thd(THD* thd);
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
- int innobase_read_and_init_auto_inc(ulonglong* ret);
- ulong innobase_autoinc_lock();
+ ulong innobase_lock_autoinc();
+ ulonglong innobase_peek_autoinc();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
- ulong innobase_get_auto_increment(ulonglong* value);
+ ulong innobase_get_autoinc(ulonglong* value);
+ ulong innobase_update_autoinc(ulonglong auto_inc);
+ ulong innobase_initialize_autoinc();
dict_index_t* innobase_get_index(uint keynr);
+ ulonglong innobase_get_int_col_max_value(const Field* field);
/* Init values for the class: */
public:
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 281587ad060..6d1c2bb86d3 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -40,6 +40,14 @@ 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. */
+ulint
+btr_search_info_get_ref_count(
+/*==========================*/
+ /* out: ref_count value. */
+ btr_search_t* info); /* in: search info. */
/*************************************************************************
Updates the search info. */
UNIV_INLINE
@@ -137,6 +145,13 @@ btr_search_validate(void);
/* 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. */
diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic
index b8c24bb074a..ad0f95755d2 100644
--- a/storage/innobase/include/data0type.ic
+++ b/storage/innobase/include/data0type.ic
@@ -558,5 +558,5 @@ dtype_get_sql_null_size(
const dtype_t* type) /* in: type */
{
return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len,
- type->mbminlen, type->mbmaxlen) > 0);
+ type->mbminlen, type->mbmaxlen));
}
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index f60775c8c2f..7d5ff09c7a6 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -178,8 +178,7 @@ 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. */
+Unconditionally set the autoinc counter. */
void
dict_table_autoinc_initialize(
@@ -196,12 +195,12 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
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. */
+Updates the autoinc counter if the value supplied is greater than the
+current value. */
void
-dict_table_autoinc_update(
-/*======================*/
+dict_table_autoinc_update_if_greater(
+/*=================================*/
dict_table_t* table, /* in: table */
ib_ulonglong value); /* in: value which was assigned to a row */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 2fe72498989..ac28fdb1bae 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -405,17 +405,8 @@ struct dict_table_struct{
mutex_t autoinc_mutex;
/* mutex protecting the autoincrement
counter */
- ibool autoinc_inited;
- /* TRUE if the autoinc counter has been
- inited; MySQL gets the init value by executing
- SELECT MAX(auto inc column) */
ib_ulonglong 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 */
ulong n_waiting_or_granted_auto_inc_locks;
/* This counter is used to track the number
of granted and pending autoinc locks on this
@@ -425,6 +416,7 @@ struct dict_table_struct{
acquired the AUTOINC lock or not. Of course
only one transaction can be granted the
lock but there can be multiple waiters. */
+ /*----------------------*/
#ifdef UNIV_DEBUG
ulint magic_n;/* magic number */
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index ef0722321af..6bfc43579b3 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -63,5 +63,14 @@ thd_has_edited_nontrans_tables(
been edited */
void* thd); /* in: thread handle (THD*) */
+/**********************************************************************
+Returns true if the thread is executing a SELECT statement. */
+
+ibool
+thd_is_select(
+/*==========*/
+ /* out: true if thd is executing SELECT */
+ const void* thd); /* in: thread handle (THD*) */
+
#endif
#endif
diff --git a/storage/innobase/include/hash0hash.ic b/storage/innobase/include/hash0hash.ic
index 49bcc7b31d0..d246d8ee831 100644
--- a/storage/innobase/include/hash0hash.ic
+++ b/storage/innobase/include/hash0hash.ic
@@ -58,7 +58,8 @@ hash_get_mutex_no(
hash_table_t* table, /* in: hash table */
ulint fold) /* in: fold */
{
- return(ut_2pow_remainder(fold, table->n_mutexes));
+ return(ut_2pow_remainder(hash_calc_hash(fold, table),
+ table->n_mutexes));
}
/****************************************************************
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 8b08b6284f6..635724bf5a1 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -463,14 +463,21 @@ void
lock_cancel_waiting_and_release(
/*============================*/
lock_t* lock); /* in: waiting lock request */
+
/*************************************************************************
-Resets all locks, both table and record locks, on a table to be dropped.
-No lock is allowed to be a wait lock. */
+Removes locks on a table to be dropped or truncated.
+If remove_also_table_sx_locks is TRUE then table-level S and X locks are
+also removed in addition to other table-level and record-level locks.
+No lock, that is going to be removed, is allowed to be a wait lock. */
void
-lock_reset_all_on_table(
-/*====================*/
- dict_table_t* table); /* in: table to be dropped */
+lock_remove_all_on_table(
+/*=====================*/
+ dict_table_t* table, /* in: table to be dropped
+ or truncated */
+ ibool remove_also_table_sx_locks);/* in: also removes
+ table S and X locks */
+
/*************************************************************************
Calculates the fold value of a page file address: used in inserting or
searching for a lock in the hash table. */
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index ca9d9c6b8f8..9b2f3250486 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -594,6 +594,8 @@ struct row_prebuilt_struct {
byte* ins_upd_rec_buff;/* buffer for storing data converted
to the Innobase format from the MySQL
format */
+ const byte* default_rec; /* the default values of all columns
+ (a "default row") in MySQL format */
ulint hint_need_to_fetch_extra_cols;
/* normally this is set to 0; if this
is set to ROW_RETRIEVE_PRIMARY_KEY,
@@ -683,7 +685,21 @@ 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 */
+ /*----------------------*/
+ ulonglong autoinc_last_value;/* last value of AUTO-INC interval */
+ ulonglong autoinc_increment;/* The increment step of the auto
+ increment column. Value must be
+ greater than or equal to 1. Required to
+ calculate the next value */
+ ulonglong autoinc_offset; /* The offset passed to
+ get_auto_increment() by MySQL. Required
+ to calculate the next value */
+ ulint autoinc_error; /* The actual error code encountered
+ while trying to init or read the
+ autoinc value from the table. We
+ store it here so that we can return
+ it to MySQL */
+ /*----------------------*/
ulint magic_n2; /* this should be the same as
magic_n */
};
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 3f9465175c1..6816823641c 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -139,8 +139,6 @@ extern ulint srv_fast_shutdown; /* If this is 1, do not do a
transactions). */
extern ibool srv_innodb_status;
-extern ibool srv_stats_on_metadata;
-
extern ibool srv_use_doublewrite_buf;
extern ibool srv_use_checksums;
diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic
index f48077e43fe..f5a85e0e7fb 100644
--- a/storage/innobase/include/sync0sync.ic
+++ b/storage/innobase/include/sync0sync.ic
@@ -185,7 +185,7 @@ mutex_exit(
{
ut_ad(mutex_own(mutex));
- ut_d(mutex->thread_id = ULINT_UNDEFINED);
+ ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
#ifdef UNIV_SYNC_DEBUG
sync_thread_reset_level(mutex);
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
index 17c5f0a665c..95d7ba017f1 100644
--- a/storage/innobase/include/ut0ut.h
+++ b/storage/innobase/include/ut0ut.h
@@ -163,11 +163,15 @@ ib_time_t
ut_time(void);
/*=========*/
/**************************************************************
-Returns system time in args, 0 on success. */
+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. */
int
ut_usectime(
/*========*/
+ /* out: 0 on success, -1 otherwise */
ulint* sec, /* out: seconds since the Epoch */
ulint* ms); /* out: microseconds since the Epoch+*sec */
diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c
index c2ede22dccb..173d074cb82 100644
--- a/storage/innobase/lock/lock0lock.c
+++ b/storage/innobase/lock/lock0lock.c
@@ -3920,15 +3920,25 @@ lock_cancel_waiting_and_release(
trx_end_lock_wait(lock->trx);
}
+/* True if a lock mode is S or X */
+#define IS_LOCK_S_OR_X(lock) \
+ (lock_get_mode(lock) == LOCK_S \
+ || lock_get_mode(lock) == LOCK_X)
+
+
/*************************************************************************
-Resets all record and table locks of a transaction on a table to be dropped.
-No lock is allowed to be a wait lock. */
+Removes locks of a transaction on a table to be dropped.
+If remove_also_table_sx_locks is TRUE then table-level S and X locks are
+also removed in addition to other table-level and record-level locks.
+No lock, that is going to be removed, is allowed to be a wait lock. */
static
void
-lock_reset_all_on_table_for_trx(
-/*============================*/
- dict_table_t* table, /* in: table to be dropped */
- trx_t* trx) /* in: a transaction */
+lock_remove_all_on_table_for_trx(
+/*=============================*/
+ dict_table_t* table, /* in: table to be dropped */
+ trx_t* trx, /* in: a transaction */
+ ibool remove_also_table_sx_locks)/* in: also removes
+ table S and X locks */
{
lock_t* lock;
lock_t* prev_lock;
@@ -3946,7 +3956,9 @@ lock_reset_all_on_table_for_trx(
lock_rec_discard(lock);
} else if (lock_get_type(lock) & LOCK_TABLE
- && lock->un_member.tab_lock.table == table) {
+ && lock->un_member.tab_lock.table == table
+ && (remove_also_table_sx_locks
+ || !IS_LOCK_S_OR_X(lock))) {
ut_a(!lock_get_wait(lock));
@@ -3958,26 +3970,65 @@ lock_reset_all_on_table_for_trx(
}
/*************************************************************************
-Resets all locks, both table and record locks, on a table to be dropped.
-No lock is allowed to be a wait lock. */
+Removes locks on a table to be dropped or truncated.
+If remove_also_table_sx_locks is TRUE then table-level S and X locks are
+also removed in addition to other table-level and record-level locks.
+No lock, that is going to be removed, is allowed to be a wait lock. */
void
-lock_reset_all_on_table(
-/*====================*/
- dict_table_t* table) /* in: table to be dropped */
+lock_remove_all_on_table(
+/*=====================*/
+ dict_table_t* table, /* in: table to be dropped
+ or truncated */
+ ibool remove_also_table_sx_locks)/* in: also removes
+ table S and X locks */
{
lock_t* lock;
+ lock_t* prev_lock;
mutex_enter(&kernel_mutex);
lock = UT_LIST_GET_FIRST(table->locks);
- while (lock) {
- ut_a(!lock_get_wait(lock));
+ while (lock != NULL) {
- lock_reset_all_on_table_for_trx(table, lock->trx);
+ prev_lock = UT_LIST_GET_PREV(un_member.tab_lock.locks,
+ lock);
- lock = UT_LIST_GET_FIRST(table->locks);
+ /* If we should remove all locks (remove_also_table_sx_locks
+ is TRUE), or if the lock is not table-level S or X lock,
+ then check we are not going to remove a wait lock. */
+ if (remove_also_table_sx_locks
+ || !(lock_get_type(lock) == LOCK_TABLE
+ && IS_LOCK_S_OR_X(lock))) {
+
+ ut_a(!lock_get_wait(lock));
+ }
+
+ lock_remove_all_on_table_for_trx(table, lock->trx,
+ remove_also_table_sx_locks);
+
+ if (prev_lock == NULL) {
+ if (lock == UT_LIST_GET_FIRST(table->locks)) {
+ /* lock was not removed, pick its successor */
+ lock = UT_LIST_GET_NEXT(
+ un_member.tab_lock.locks, lock);
+ } else {
+ /* lock was removed, pick the first one */
+ lock = UT_LIST_GET_FIRST(table->locks);
+ }
+ } else if (UT_LIST_GET_NEXT(un_member.tab_lock.locks,
+ prev_lock) != lock) {
+ /* If lock was removed by
+ lock_remove_all_on_table_for_trx() then pick the
+ successor of prev_lock ... */
+ lock = UT_LIST_GET_NEXT(
+ un_member.tab_lock.locks, prev_lock);
+ } else {
+ /* ... otherwise pick the successor of lock. */
+ lock = UT_LIST_GET_NEXT(
+ un_member.tab_lock.locks, lock);
+ }
}
mutex_exit(&kernel_mutex);
diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c
index 2907fddc33b..4a9d3334e7d 100644
--- a/storage/innobase/os/os0file.c
+++ b/storage/innobase/os/os0file.c
@@ -1330,9 +1330,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;
}
@@ -1407,9 +1417,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 {
diff --git a/storage/innobase/plug.in b/storage/innobase/plug.in
index b252d471fba..f7d2abed751 100644
--- a/storage/innobase/plug.in
+++ b/storage/innobase/plug.in
@@ -15,25 +15,30 @@ MYSQL_PLUGIN_ACTIONS(innobase, [
AC_CHECK_FUNCS(localtime_r)
AC_C_BIGENDIAN
case "$target_os" in
- lin*)
- CFLAGS="$CFLAGS -DUNIV_LINUX";;
- hpux10*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";;
- hp*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";;
- aix*)
- CFLAGS="$CFLAGS -DUNIV_AIX";;
- irix*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
- osf*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
- *solaris*|*SunOS*)
- CFLAGS="$CFLAGS -DUNIV_SOLARIS";;
- sysv5uw7*)
- # Problem when linking on SCO
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
- openbsd*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
+ lin*)
+ CFLAGS="$CFLAGS -DUNIV_LINUX";;
+ hpux10*)
+ CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";;
+ hp*)
+ CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";;
+ aix*)
+ CFLAGS="$CFLAGS -DUNIV_AIX";;
+ irix*|osf*|sysv5uw7*|openbsd*)
+ CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
+ *solaris*|*SunOS*)
+ CFLAGS="$CFLAGS -DUNIV_SOLARIS";;
esac
+ INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN"
+ case "$target_cpu" in
+ x86_64)
+ # The AMD64 ABI forbids absolute addresses in shared libraries
+ ;;
+ *86)
+ # Use absolute addresses on IA-32
+ INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic"
+ ;;
+ esac
+ AC_SUBST(INNODB_DYNAMIC_CFLAGS)
])
+# vim: set ft=config:
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index d5ef12d0af2..088d944cb91 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -342,7 +342,7 @@ row_mysql_store_col_in_innobase_format(
/* In some cases we strip trailing spaces from UTF-8 and other
multibyte charsets, from FIXED-length CHAR columns, to save
space. UTF-8 would otherwise normally use 3 * the string length
- bytes to store a latin1 string! */
+ bytes to store an ASCII string! */
/* We assume that this CHAR field is encoded in a
variable-length character set where spaces have
@@ -620,6 +620,7 @@ row_create_prebuilt(
prebuilt->ins_node = NULL;
prebuilt->ins_upd_rec_buff = NULL;
+ prebuilt->default_rec = NULL;
prebuilt->upd_node = NULL;
prebuilt->ins_graph = NULL;
@@ -661,7 +662,14 @@ row_create_prebuilt(
prebuilt->old_vers_heap = NULL;
- prebuilt->last_value = 0;
+ prebuilt->autoinc_error = 0;
+ prebuilt->autoinc_offset = 0;
+
+ /* Default to 1, we will set the actual value later in
+ ha_innobase::get_auto_increment(). */
+ prebuilt->autoinc_increment = 1;
+
+ prebuilt->autoinc_last_value = 0;
return(prebuilt);
}
@@ -1478,12 +1486,13 @@ row_unlock_for_mysql(
ut_ad(prebuilt && trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
- if (!(srv_locks_unsafe_for_binlog
- || trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
+ if (UNIV_UNLIKELY
+ (!srv_locks_unsafe_for_binlog
+ && trx->isolation_level != TRX_ISO_READ_COMMITTED)) {
fprintf(stderr,
"InnoDB: Error: calling row_unlock_for_mysql though\n"
- "InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n"
+ "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
"InnoDB: this session is not using"
" READ COMMITTED isolation level.\n");
@@ -1963,6 +1972,7 @@ row_create_index_for_mysql(
ulint err;
ulint i, j;
ulint len;
+ char* table_name;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
@@ -1972,6 +1982,11 @@ row_create_index_for_mysql(
trx->op_info = "creating index";
+ /* Copy the table name because we may want to drop the
+ table later, after the index object is freed (inside
+ que_run_threads()) and thus index->table_name is not available. */
+ table_name = mem_strdup(index->table_name);
+
trx_start_if_not_started(trx);
/* Check that the same column does not appear twice in the index.
@@ -2044,13 +2059,15 @@ error_handling:
trx_general_rollback_for_mysql(trx, FALSE, NULL);
- row_drop_table_for_mysql(index->table_name, trx, FALSE);
+ row_drop_table_for_mysql(table_name, trx, FALSE);
trx->error_state = DB_SUCCESS;
}
trx->op_info = "";
+ mem_free(table_name);
+
return((int) err);
}
@@ -2443,8 +2460,8 @@ row_discard_tablespace_for_mysql(
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
- /* Remove any locks there are on the table or its records */
- lock_reset_all_on_table(table);
+ /* Remove all locks except the table-level S and X locks. */
+ lock_remove_all_on_table(table, FALSE);
info = pars_info_create();
@@ -2779,9 +2796,8 @@ row_truncate_table_for_mysql(
goto funct_exit;
}
- /* Remove any locks there are on the table or its records */
-
- lock_reset_all_on_table(table);
+ /* Remove all locks except the table-level S and X locks. */
+ lock_remove_all_on_table(table, FALSE);
trx->table_id = table->id;
@@ -2896,7 +2912,7 @@ next_rec:
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_lock(table);
- dict_table_autoinc_initialize(table, 0);
+ dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table);
dict_update_statistics(table);
@@ -3131,9 +3147,8 @@ check_next_foreign:
goto funct_exit;
}
- /* Remove any locks there are on the table or its records */
-
- lock_reset_all_on_table(table);
+ /* Remove all locks there are on the table or its records */
+ lock_remove_all_on_table(table, TRUE);
trx->dict_operation = TRUE;
trx->table_id = table->id;
@@ -3429,8 +3444,6 @@ loop:
err = row_drop_table_for_mysql(table_name, trx, TRUE);
- mem_free(table_name);
-
if (err != DB_SUCCESS) {
fputs("InnoDB: DROP DATABASE ", stderr);
ut_print_name(stderr, trx, TRUE, name);
@@ -3438,8 +3451,11 @@ loop:
(ulint) err);
ut_print_name(stderr, trx, TRUE, table_name);
putc('\n', stderr);
+ mem_free(table_name);
break;
}
+
+ mem_free(table_name);
}
if (err == DB_SUCCESS) {
diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
index 05721014078..8c3b00a7841 100644
--- a/storage/innobase/row/row0sel.c
+++ b/storage/innobase/row/row0sel.c
@@ -32,6 +32,7 @@ Created 12/19/1997 Heikki Tuuri
#include "row0mysql.h"
#include "read0read.h"
#include "buf0lru.h"
+#include "ha_prototypes.h"
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
#define SEL_MAX_N_PREFETCH 16
@@ -2596,6 +2597,7 @@ row_sel_store_mysql_rec(
ulint i;
ut_ad(prebuilt->mysql_template);
+ ut_ad(prebuilt->default_rec);
ut_ad(rec_offs_validate(rec, NULL, offsets));
if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
@@ -2682,58 +2684,14 @@ row_sel_store_mysql_rec(
&= ~(byte) templ->mysql_null_bit_mask;
}
} else {
- /* MySQL seems to assume the field for an SQL NULL
- value is set to zero or space. Not taking this into
- account caused seg faults with NULL BLOB fields, and
- bug number 154 in the MySQL bug database: GROUP BY
- and DISTINCT could treat NULL values inequal. */
- int pad_char;
+ /* MySQL assumes that the field for an SQL
+ NULL value is set to the default value. */
mysql_rec[templ->mysql_null_byte_offset]
|= (byte) templ->mysql_null_bit_mask;
- switch (templ->type) {
- case DATA_VARCHAR:
- case DATA_BINARY:
- case DATA_VARMYSQL:
- if (templ->mysql_type
- == DATA_MYSQL_TRUE_VARCHAR) {
- /* This is a >= 5.0.3 type
- true VARCHAR. Zero the field. */
- pad_char = 0x00;
- break;
- }
- /* Fall through */
- case DATA_CHAR:
- case DATA_FIXBINARY:
- case DATA_MYSQL:
- /* MySQL pads all string types (except
- BLOB, TEXT and true VARCHAR) with space. */
- if (UNIV_UNLIKELY(templ->mbminlen == 2)) {
- /* Treat UCS2 as a special case. */
- data = mysql_rec
- + templ->mysql_col_offset;
- len = templ->mysql_col_len;
- /* There are two UCS2 bytes per char,
- so the length has to be even. */
- ut_a(!(len & 1));
- /* Pad with 0x0020. */
- while (len) {
- *data++ = 0x00;
- *data++ = 0x20;
- len -= 2;
- }
- continue;
- }
- pad_char = 0x20;
- break;
- default:
- pad_char = 0x00;
- break;
- }
-
- ut_ad(!pad_char || templ->mbminlen == 1);
- memset(mysql_rec + templ->mysql_col_offset,
- pad_char, templ->mysql_col_len);
+ memcpy(mysql_rec + templ->mysql_col_offset,
+ prebuilt->default_rec + templ->mysql_col_offset,
+ templ->mysql_col_len);
}
}
@@ -3577,20 +3535,12 @@ shortcut_fails_too_big_rec:
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& prebuilt->select_lock_type != LOCK_NONE
- && trx->mysql_query_str != NULL
- && *trx->mysql_query_str != NULL
- && trx->mysql_thd != NULL) {
-
- /* Scan the MySQL query string; check if SELECT is the first
- word there */
+ && trx->mysql_thd != NULL
+ && thd_is_select(trx->mysql_thd)) {
+ /* It is a plain locking SELECT and the isolation
+ level is low: do not lock gaps */
- if (dict_str_starts_with_keyword(
- trx->mysql_thd, *trx->mysql_query_str, "SELECT")) {
- /* It is a plain locking SELECT and the isolation
- level is low: do not lock gaps */
-
- set_also_gap_locks = FALSE;
- }
+ set_also_gap_locks = FALSE;
}
/* Note that if the search mode was GE or G, then the cursor
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index c721a1f18e3..e0fe6f40197 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -293,14 +293,17 @@ ulong srv_commit_concurrency = 0;
os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data
structures */
-lint srv_conc_n_threads = 0; /* number of OS threads currently
- inside InnoDB; it is not an error
- if this drops temporarily below zero
- because we do not demand that every
- thread increments this, but a thread
- waiting for a lock decrements this
- temporarily */
-ulint srv_conc_n_waiting_threads = 0; /* number of OS threads waiting in the
+lint srv_conc_n_threads = 0; /* number of transactions that
+ have declared_to_be_inside_innodb
+ set. It used to be a non-error
+ for this value to drop below
+ zero temporarily. This is no
+ longer true. We'll, however,
+ keep the lint datatype to add
+ assertions to catch any corner
+ cases that we may have
+ missed. */
+ulint srv_conc_n_waiting_threads = 0; /* number of OS threads waiting in the
FIFO for a permission to enter InnoDB
*/
@@ -338,8 +341,6 @@ ulint srv_fast_shutdown = 0;
/* Generate a innodb_status.<pid> file */
ibool srv_innodb_status = FALSE;
-ibool srv_stats_on_metadata = TRUE;
-
ibool srv_use_doublewrite_buf = TRUE;
ibool srv_use_checksums = TRUE;
@@ -1196,6 +1197,8 @@ retry:
return;
}
+ ut_ad(srv_conc_n_threads >= 0);
+
if (srv_conc_n_threads < (lint)srv_thread_concurrency) {
srv_conc_n_threads++;
@@ -1323,6 +1326,7 @@ srv_conc_force_enter_innodb(
return;
}
+ ut_ad(srv_conc_n_threads >= 0);
#ifdef UNIV_SYNC_ATOMIC
if (srv_thread_concurrency_timer_based) {
lint conc_n_threads;
@@ -1352,11 +1356,6 @@ srv_conc_force_exit_innodb(
{
srv_conc_slot_t* slot = NULL;
- if (UNIV_LIKELY(!srv_thread_concurrency)) {
-
- return;
- }
-
if (trx->mysql_thd != NULL
&& thd_is_replication_slave_thread(trx->mysql_thd)) {
@@ -1378,6 +1377,7 @@ srv_conc_force_exit_innodb(
os_fast_mutex_lock(&srv_conc_mutex);
+ ut_ad(srv_conc_n_threads > 0);
srv_conc_n_threads--;
trx->declared_to_be_inside_innodb = FALSE;
trx->n_tickets_to_enter_innodb = 0;
@@ -1644,8 +1644,11 @@ srv_suspend_mysql_thread(
srv_n_lock_wait_count++;
srv_n_lock_wait_current_count++;
- ut_usectime(&sec, &ms);
- start_time = (ib_longlong)sec * 1000000 + ms;
+ if (ut_usectime(&sec, &ms) == -1) {
+ start_time = -1;
+ } else {
+ start_time = (ib_longlong)sec * 1000000 + ms;
+ }
}
/* Wake the lock timeout monitor thread, if it is suspended */
@@ -1699,14 +1702,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_longlong)sec * 1000000 + ms;
+ if (ut_usectime(&sec, &ms) == -1) {
+ finish_time = -1;
+ } else {
+ finish_time = (ib_longlong)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;
}
}
diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
index f64ebab1281..2acefbb22c2 100644
--- a/storage/innobase/srv/srv0start.c
+++ b/storage/innobase/srv/srv0start.c
@@ -202,13 +202,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;
@@ -290,14 +290,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;
diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
index 69b72451f2b..1fceaa3562c 100644
--- a/storage/innobase/trx/trx0trx.c
+++ b/storage/innobase/trx/trx0trx.c
@@ -287,6 +287,10 @@ trx_free(
"InnoDB: inside InnoDB.\n", stderr);
trx_print(stderr, trx, 600);
putc('\n', stderr);
+
+ /* This is an error but not a fatal error. We must keep
+ the counters like srv_conc_n_threads accurate. */
+ srv_conc_force_exit_innodb(trx);
}
if (trx->n_mysql_tables_in_use != 0
diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c
index 2aa7752d292..b31580d0ce0 100644
--- a/storage/innobase/trx/trx0undo.c
+++ b/storage/innobase/trx/trx0undo.c
@@ -410,7 +410,7 @@ trx_undo_seg_create(
if (slot_no == ULINT_UNDEFINED) {
ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Warning: cannot find a free slot for"
+ " InnoDB: Warning: cannot find a free slot for"
" an undo log. Do you have too\n"
"InnoDB: many active transactions"
" running concurrently?\n");
diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c
index 4a0bd802404..1ae43172894 100644
--- a/storage/innobase/ut/ut0ut.c
+++ b/storage/innobase/ut/ut0ut.c
@@ -112,20 +112,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. */
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;
+ }
+ }
+
+ if (ret != -1) {
+ *sec = (ulint) tv.tv_sec;
+ *ms = (ulint) tv.tv_usec;
+ }
- int r = ut_gettimeofday(&tv, NULL);
- *sec = (ulint) tv.tv_sec;
- *ms = (ulint) tv.tv_usec;
- return r;
+ return(ret);
}
/**************************************************************
diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c
index 051a21b3307..66097864622 100644
--- a/storage/myisam/ft_boolean_search.c
+++ b/storage/myisam/ft_boolean_search.c
@@ -161,11 +161,11 @@ static int FTB_WORD_cmp(my_off_t *v, FTB_WORD *a, FTB_WORD *b)
static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
{
- /* ORDER BY word DESC, ndepth DESC */
- int i= ha_compare_text(cs, (uchar*) (*b)->word+1,(*b)->len-1,
- (uchar*) (*a)->word+1,(*a)->len-1,0,0);
+ /* ORDER BY word, ndepth */
+ int i= ha_compare_text(cs, (uchar*) (*a)->word + 1, (*a)->len - 1,
+ (uchar*) (*b)->word + 1, (*b)->len - 1, 0, 0);
if (!i)
- i=CMP_NUM((*b)->ndepth,(*a)->ndepth);
+ i= CMP_NUM((*a)->ndepth, (*b)->ndepth);
return i;
}
@@ -865,23 +865,49 @@ static int ftb_find_relevance_add_word(MYSQL_FTPARSER_PARAM *param,
FT_INFO *ftb= ftb_param->ftb;
FTB_WORD *ftbw;
int a, b, c;
+ /*
+ Find right-most element in the array of query words matching this
+ word from a document.
+ */
for (a= 0, b= ftb->queue.elements, c= (a+b)/2; b-a>1; c= (a+b)/2)
{
ftbw= ftb->list[c];
if (ha_compare_text(ftb->charset, (uchar*)word, len,
(uchar*)ftbw->word+1, ftbw->len-1,
- (my_bool)(ftbw->flags&FTB_FLAG_TRUNC), 0) > 0)
+ (my_bool) (ftbw->flags & FTB_FLAG_TRUNC), 0) < 0)
b= c;
else
a= c;
}
+ /*
+ If there were no words with truncation operator, we iterate to the
+ beginning of an array until array element is equal to the word from
+ a document. This is done mainly because the same word may be
+ mentioned twice (or more) in the query.
+
+ In case query has words with truncation operator we must iterate
+ to the beginning of the array. There may be non-matching query words
+ between matching word with truncation operator and the right-most
+ matching element. E.g., if we're looking for 'aaa15' in an array of
+ 'aaa1* aaa14 aaa15 aaa16'.
+
+ Worse of that there still may be match even if the binary search
+ above didn't find matching element. E.g., if we're looking for
+ 'aaa15' in an array of 'aaa1* aaa14 aaa16'. The binary search will
+ stop at 'aaa16'.
+ */
for (; c >= 0; c--)
{
ftbw= ftb->list[c];
if (ha_compare_text(ftb->charset, (uchar*)word, len,
(uchar*)ftbw->word + 1,ftbw->len - 1,
(my_bool)(ftbw->flags & FTB_FLAG_TRUNC), 0))
- break;
+ {
+ if (ftb->with_scan & FTB_FLAG_TRUNC)
+ continue;
+ else
+ break;
+ }
if (ftbw->docid[1] == ftb->info->lastpos)
continue;
ftbw->docid[1]= ftb->info->lastpos;
diff --git a/storage/myisam/ft_parser.c b/storage/myisam/ft_parser.c
index 042a999fffa..4cde3834ed7 100644
--- a/storage/myisam/ft_parser.c
+++ b/storage/myisam/ft_parser.c
@@ -323,60 +323,41 @@ int ft_parse(TREE *wtree, uchar *doc, int doclen,
DBUG_RETURN(parser->parse(param));
}
+
#define MAX_PARAM_NR 2
-MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
- uint keynr, uint paramnr)
+
+MYSQL_FTPARSER_PARAM* ftparser_alloc_param(MI_INFO *info)
{
- uint32 ftparser_nr;
- struct st_mysql_ftparser *parser;
- if (! info->ftparser_param)
+ if (!info->ftparser_param)
{
- /* info->ftparser_param can not be zero after the initialization,
- because it always includes built-in fulltext parser. And built-in
- parser can be called even if the table has no fulltext indexes and
- no varchar/text fields. */
- if (! info->s->ftparsers)
- {
- /* It's ok that modification to shared structure is done w/o mutex
- locks, because all threads would set the same variables to the
- same values. */
- uint i, j, keys= info->s->state.header.keys, ftparsers= 1;
- for (i= 0; i < keys; i++)
- {
- MI_KEYDEF *keyinfo= &info->s->keyinfo[i];
- if (keyinfo->flag & HA_FULLTEXT)
- {
- for (j= 0;; j++)
- {
- if (j == i)
- {
- keyinfo->ftparser_nr= ftparsers++;
- break;
- }
- if (info->s->keyinfo[j].flag & HA_FULLTEXT &&
- keyinfo->parser == info->s->keyinfo[j].parser)
- {
- keyinfo->ftparser_nr= info->s->keyinfo[j].ftparser_nr;
- break;
- }
- }
- }
- }
- info->s->ftparsers= ftparsers;
- }
- /*
- We have to allocate two MYSQL_FTPARSER_PARAM structures per plugin
- because in a boolean search a parser is called recursively
- ftb_find_relevance* calls ftb_check_phrase*
- (MAX_PARAM_NR=2)
+ /*
+. info->ftparser_param can not be zero after the initialization,
+ because it always includes built-in fulltext parser. And built-in
+ parser can be called even if the table has no fulltext indexes and
+ no varchar/text fields.
+
+ ftb_find_relevance... parser (ftb_find_relevance_parse,
+ ftb_find_relevance_add_word) calls ftb_check_phrase... parser
+ (ftb_check_phrase_internal, ftb_phrase_add_word). Thus MAX_PARAM_NR=2.
*/
info->ftparser_param= (MYSQL_FTPARSER_PARAM *)
my_malloc(MAX_PARAM_NR * sizeof(MYSQL_FTPARSER_PARAM) *
- info->s->ftparsers, MYF(MY_WME|MY_ZEROFILL));
+ info->s->ftkeys, MYF(MY_WME | MY_ZEROFILL));
init_alloc_root(&info->ft_memroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
- if (! info->ftparser_param)
- return 0;
}
+ return info->ftparser_param;
+}
+
+
+MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
+ uint keynr, uint paramnr)
+{
+ uint32 ftparser_nr;
+ struct st_mysql_ftparser *parser;
+
+ if (!ftparser_alloc_param(info))
+ return 0;
+
if (keynr == NO_SUCH_KEY)
{
ftparser_nr= 0;
@@ -384,7 +365,7 @@ MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
}
else
{
- ftparser_nr= info->s->keyinfo[keynr].ftparser_nr;
+ ftparser_nr= info->s->keyinfo[keynr].ftkey_nr;
parser= info->s->keyinfo[keynr].parser;
}
DBUG_ASSERT(paramnr < MAX_PARAM_NR);
@@ -416,7 +397,7 @@ void ftparser_call_deinitializer(MI_INFO *info)
for (j=0; j < MAX_PARAM_NR; j++)
{
MYSQL_FTPARSER_PARAM *ftparser_param=
- &info->ftparser_param[keyinfo->ftparser_nr*MAX_PARAM_NR + j];
+ &info->ftparser_param[keyinfo->ftkey_nr * MAX_PARAM_NR + j];
if (keyinfo->flag & HA_FULLTEXT && ftparser_param->mysql_add_word)
{
if (keyinfo->parser->deinit)
diff --git a/storage/myisam/ftdefs.h b/storage/myisam/ftdefs.h
index 22443807b87..ddcf1a8dc26 100644
--- a/storage/myisam/ftdefs.h
+++ b/storage/myisam/ftdefs.h
@@ -146,6 +146,7 @@ void ft_boolean_close_search(FT_INFO *);
float ft_boolean_get_relevance(FT_INFO *);
my_off_t ft_boolean_get_docid(FT_INFO *);
void ft_boolean_reinit_search(FT_INFO *);
+MYSQL_FTPARSER_PARAM* ftparser_alloc_param(MI_INFO *info);
extern MYSQL_FTPARSER_PARAM *ftparser_call_initializer(MI_INFO *info,
uint keynr,
uint paramnr);
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 4b0fb15a5c6..c6411a6a273 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -1261,7 +1261,7 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
ulonglong map;
TABLE_LIST *table_list= table->pos_in_table_list;
my_bool ignore_leaves= table_list->ignore_leaves;
- char buf[ERRMSGSIZE+20];
+ char buf[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("ha_myisam::preload_keys");
@@ -1289,7 +1289,7 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
errmsg= "Failed to allocate buffer";
break;
default:
- my_snprintf(buf, ERRMSGSIZE,
+ my_snprintf(buf, sizeof(buf),
"Failed to read from index file (errno: %d)", my_errno);
errmsg= buf;
}
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index b132000b356..bdca1a1f0b8 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -2397,7 +2397,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
Note, built-in parser is always nr. 0 - see ftparser_call_initializer()
*/
- if (sort_param.keyinfo->ftparser_nr == 0)
+ if (sort_param.keyinfo->ftkey_nr == 0)
{
/*
for built-in parser the number of generated index entries
@@ -2895,6 +2895,9 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
sort_param[0].fix_datafile= (my_bool)(! rep_quick);
sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
+ if (!ftparser_alloc_param(info))
+ goto err;
+
sort_info.got_error=0;
pthread_mutex_lock(&sort_info.mutex);
diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index 605dea6594e..78749d50fe5 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/myisam/mi_open.c
@@ -331,6 +331,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->blocksize=min(IO_SIZE,myisam_block_size);
{
HA_KEYSEG *pos=share->keyparts;
+ uint32 ftkey_nr= 1;
for (i=0 ; i < keys ; i++)
{
share->keyinfo[i].share= share;
@@ -412,6 +413,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->ft2_keyinfo.end=pos;
setup_key_functions(& share->ft2_keyinfo);
}
+ share->keyinfo[i].ftkey_nr= ftkey_nr++;
}
setup_key_functions(share->keyinfo+i);
share->keyinfo[i].end=pos;
@@ -421,6 +423,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
pos->flag=0; /* For purify */
pos++;
}
+
for (i=0 ; i < uniques ; i++)
{
disk_pos=mi_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
@@ -449,7 +452,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
pos->flag=0;
pos++;
}
- share->ftparsers= 0;
+ share->ftkeys= ftkey_nr;
}
disk_pos_assert(disk_pos + share->base.fields *MI_COLUMNDEF_SIZE, end_pos);
@@ -1112,7 +1115,7 @@ uchar *mi_keydef_read(uchar *ptr, MI_KEYDEF *keydef)
keydef->underflow_block_length=keydef->block_length/3;
keydef->version = 0; /* Not saved */
keydef->parser = &ft_default_parser;
- keydef->ftparser_nr = 0;
+ keydef->ftkey_nr = 0;
return ptr;
}
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index 2ca79608408..9af3f652c5f 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -193,7 +193,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */
ulong state_diff_length;
uint rec_reflength; /* rec_reflength in use now */
uint unique_name_length;
- uint32 ftparsers; /* Number of distinct ftparsers + 1 */
+ uint32 ftkeys; /* Number of full-text keys + 1 */
File kfile; /* Shared keyfile */
File data_file; /* Shared data file */
int mode; /* mode of file on open */
diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c
index 0ca6a10fad4..908c32e48d3 100644
--- a/storage/myisam/myisampack.c
+++ b/storage/myisam/myisampack.c
@@ -300,7 +300,7 @@ static void print_version(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2002 MySQL AB");
+ puts("Copyright 2002-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
puts("and you are welcome to modify and redistribute it under the GPL license\n");
diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c
index b5002116164..64b4be2b7ca 100644
--- a/storage/myisammrg/myrg_open.c
+++ b/storage/myisammrg/myrg_open.c
@@ -47,6 +47,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
MI_INFO *isam=0;
uint found_merge_insert_method= 0;
size_t name_buff_length;
+ my_bool bad_children= FALSE;
DBUG_ENTER("myrg_open");
LINT_INIT(key_parts);
@@ -97,13 +98,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
fn_format(buff, buff, "", "", 0);
if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
{
- my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
if (handle_locking & HA_OPEN_FOR_REPAIR)
{
myrg_print_wrong_table(buff);
+ bad_children= TRUE;
continue;
}
- goto err;
+ goto bad_children;
}
if (!m_info) /* First file */
{
@@ -128,13 +129,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
files++;
if (m_info->reclength != isam->s->base.reclength)
{
- my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
if (handle_locking & HA_OPEN_FOR_REPAIR)
{
myrg_print_wrong_table(buff);
+ bad_children= TRUE;
continue;
}
- goto err;
+ goto bad_children;
}
m_info->options|= isam->s->options;
m_info->records+= isam->state->records;
@@ -147,8 +148,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
m_info->tables);
}
- if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
- goto err;
+ if (bad_children)
+ goto bad_children;
if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO),
MYF(MY_WME | MY_ZEROFILL))))
goto err;
@@ -178,12 +179,14 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_RETURN(m_info);
+bad_children:
+ my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
err:
save_errno=my_errno;
switch (errpos) {
case 3:
while (files)
- mi_close(m_info->open_tables[--files].table);
+ (void) mi_close(m_info->open_tables[--files].table);
my_free((char*) m_info,MYF(0));
/* Fall through */
case 2:
@@ -392,6 +395,7 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
uint child_nr;
uint key_parts;
uint min_keys;
+ my_bool bad_children= FALSE;
DBUG_ENTER("myrg_attach_children");
DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking));
@@ -441,13 +445,13 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
DBUG_PRINT("error", ("definition mismatch table: '%s' repair: %d",
myisam->filename,
(handle_locking & HA_OPEN_FOR_REPAIR)));
- my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
if (handle_locking & HA_OPEN_FOR_REPAIR)
{
myrg_print_wrong_table(myisam->filename);
+ bad_children= TRUE;
continue;
}
- goto err;
+ goto bad_children;
}
m_info->options|= myisam->s->options;
@@ -462,6 +466,9 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
child_nr++;
}
+ if (bad_children)
+ goto bad_children;
+ /* Note: callback() resets my_errno, so it is safe to check it here */
if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF)
goto err;
if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
@@ -477,6 +484,8 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
pthread_mutex_unlock(&m_info->mutex);
DBUG_RETURN(0);
+bad_children:
+ my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
err:
save_errno= my_errno;
switch (errpos) {
diff --git a/storage/ndb/docs/doxygen/postdoxy.pl b/storage/ndb/docs/doxygen/postdoxy.pl
index ad0edb44a31..3bf54e4ff75 100755
--- a/storage/ndb/docs/doxygen/postdoxy.pl
+++ b/storage/ndb/docs/doxygen/postdoxy.pl
@@ -81,9 +81,9 @@ open (OUTFILE, "> ${destdir}/doxygen.sty.new")
while (<INFILE>)
{
if (/\\rfoot/) {
- print OUTFILE "\\rfoot[\\fancyplain{}{\\bfseries\\small \\copyright~Copyright 2003-2004 MySQL AB\\hfill support-cluster\@mysql.com}]{}\n";
+ print OUTFILE "\\rfoot[\\fancyplain{}{\\bfseries\\small \\copyright~Copyright 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.\\hfill support-cluster\@mysql.com}]{}\n";
} elsif (/\\lfoot/) {
- print OUTFILE "\\lfoot[]{\\fancyplain{}{\\bfseries\\small support-cluster\@mysql.com\\hfill \\copyright~Copyright 2003-2004 MySQL AB}}\n";
+ print OUTFILE "\\lfoot[]{\\fancyplain{}{\\bfseries\\small support-cluster\@mysql.com\\hfill \\copyright~Copyright 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.}}\n";
} else {
print OUTFILE;
}
diff --git a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
index 043df5d5038..7bd61dfe8b3 100644
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
@@ -551,7 +551,7 @@ Dbtc::execDROP_TAB_REQ(Signal* signal)
Uint32 senderRef = req->senderRef;
Uint32 senderData = req->senderData;
DropTabReq::RequestType rt = (DropTabReq::RequestType)req->requestType;
-
+
if(!tabPtr.p->get_enabled() && rt == DropTabReq::OnlineDropTab){
jam();
DropTabRef* ref = (DropTabRef*)signal->getDataPtrSend();
diff --git a/storage/ndb/test/run-test/atrt.hpp b/storage/ndb/test/run-test/atrt.hpp
index 14d2dccd245..db26bd9bfc0 100644
--- a/storage/ndb/test/run-test/atrt.hpp
+++ b/storage/ndb/test/run-test/atrt.hpp
@@ -2,8 +2,7 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/storage/ndb/test/tools/connect.cpp b/storage/ndb/test/tools/connect.cpp
index 2d3ac34d3e8..278dbe833ea 100644
--- a/storage/ndb/test/tools/connect.cpp
+++ b/storage/ndb/test/tools/connect.cpp
@@ -2,8 +2,7 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of