summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorGeorgi Kodinov <Georgi.Kodinov@Oracle.com>2012-02-06 18:24:51 +0200
committerGeorgi Kodinov <Georgi.Kodinov@Oracle.com>2012-02-06 18:24:51 +0200
commitd29ae4918e7062896d9a5f50a2bc2bbc5f0c6f06 (patch)
treee6b5bfa6ab416bf84f4d296d6f3006feec3d40cd /storage
parent7f0f18cd6ecd5a40f45393bfcc678350855f1513 (diff)
parent1c4fd3bb546a501fc95ca52def2c728681d62b28 (diff)
downloadmariadb-git-d29ae4918e7062896d9a5f50a2bc2bbc5f0c6f06.tar.gz
merged mysql-5.1->mysql-5.1-security
Diffstat (limited to 'storage')
-rw-r--r--storage/archive/ha_archive.cc6
-rw-r--r--storage/innobase/btr/btr0cur.c5
-rw-r--r--storage/innobase/fil/fil0fil.c24
-rw-r--r--storage/innobase/handler/ha_innodb.cc212
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.c10
-rw-r--r--storage/innobase/include/univ.i18
-rw-r--r--storage/innodb_plugin/ChangeLog31
-rw-r--r--storage/innodb_plugin/btr/btr0cur.c5
-rw-r--r--storage/innodb_plugin/buf/buf0buf.c2
-rw-r--r--storage/innodb_plugin/fil/fil0fil.c31
-rw-r--r--storage/innodb_plugin/handler/ha_innodb.cc214
-rw-r--r--storage/innodb_plugin/ibuf/ibuf0ibuf.c12
-rw-r--r--storage/innodb_plugin/row/row0merge.c4
-rw-r--r--storage/myisam/mi_check.c16
14 files changed, 528 insertions, 62 deletions
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index 79053f284b3..dc88f1d652f 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1310,6 +1310,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
azio_stream writer;
char writer_filename[FN_REFLEN];
+ pthread_mutex_lock(&share->mutex);
init_archive_reader();
// now we close both our writer and our reader for the rename
@@ -1324,7 +1325,10 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
MY_REPLACE_EXT | MY_UNPACK_FILENAME);
if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY)))
+ {
+ pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
+ }
/*
An extended rebuild is a lot more effort. We open up each row and re-record it.
@@ -1403,10 +1407,12 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
rc = my_rename(writer_filename,share->data_file_name,MYF(0));
+ pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(rc);
error:
DBUG_PRINT("ha_archive", ("Failed to recover, error was %d", rc));
azclose(&writer);
+ pthread_mutex_unlock(&share->mutex);
DBUG_RETURN(rc);
}
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
index 3c12e28feb6..c09d6408fa0 100644
--- a/storage/innobase/btr/btr0cur.c
+++ b/storage/innobase/btr/btr0cur.c
@@ -321,7 +321,12 @@ btr_cur_search_to_nth_level(
ut_ad(dict_index_check_search_tuple(index, tuple));
ut_ad(!(index->type & DICT_IBUF) || ibuf_inside());
ut_ad(dtuple_check_typed(tuple));
+ ut_ad(index->page != FIL_NULL);
+ UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match);
+ UNIV_MEM_INVALID(&cursor->up_bytes, sizeof cursor->up_bytes);
+ UNIV_MEM_INVALID(&cursor->low_match, sizeof cursor->low_match);
+ UNIV_MEM_INVALID(&cursor->low_bytes, sizeof cursor->low_bytes);
#ifdef UNIV_DEBUG
cursor->up_match = ULINT_UNDEFINED;
cursor->low_match = ULINT_UNDEFINED;
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
index 6ca8381ebdf..1d3cdc6e227 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innobase/fil/fil0fil.c
@@ -772,11 +772,6 @@ retry:
return;
}
- if (system->n_open < system->max_n_open) {
-
- return;
- }
-
HASH_SEARCH(hash, system->spaces, space_id, space,
space->id == space_id);
if (space != NULL && space->stop_ios) {
@@ -793,6 +788,18 @@ retry:
mutex_exit(&(system->mutex));
+#ifndef UNIV_HOTBACKUP
+ /* Wake the i/o-handler threads to make sure pending
+ i/o's are performed */
+ os_aio_simulated_wake_handler_threads();
+
+ os_thread_sleep(20000);
+#endif /* UNIV_HOTBACKUP */
+
+ /* Flush tablespaces so that we can close modified
+ files in the LRU list */
+ fil_flush_file_spaces(FIL_TABLESPACE);
+
os_thread_sleep(20000);
count2++;
@@ -800,6 +807,11 @@ retry:
goto retry;
}
+ if (system->n_open < system->max_n_open) {
+
+ return;
+ }
+
/* If the file is already open, no need to do anything; if the space
does not exist, we handle the situation in the function which called
this function */
@@ -2290,7 +2302,7 @@ fil_rename_tablespace(
retry:
count++;
- if (count > 1000) {
+ if (!(count % 1000)) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: problems renaming ", stderr);
ut_print_filename(stderr, old_name);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 573e0a4455a..20ab9c7a101 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -948,6 +948,19 @@ innobase_get_charset(
return(thd_charset((THD*) mysql_thd));
}
+/**********************************************************************//**
+Get the current setting of the lower_case_table_names global parameter from
+mysqld.cc. We do a dirty read because for one there is no synchronization
+object and secondly there is little harm in doing so even if we get a torn
+read.
+@return value of lower_case_table_names */
+ulint
+innobase_get_lower_case_table_names(void)
+/*=====================================*/
+{
+ return(lower_case_table_names);
+}
+
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
/*******************************************************************//**
@@ -2579,52 +2592,139 @@ ha_innobase::bas_ext() const
return ha_innobase_exts;
}
+/** Always normalize table name to lower case on Windows */
+#ifdef __WIN__
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, TRUE)
+#else
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, FALSE)
+#endif /* __WIN__ */
/*********************************************************************
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case. */
+table name always to lower case if "set_lower_case" is set to TRUE. */
static
void
-normalize_table_name(
-/*=================*/
+normalize_table_name_low(
+/*=====================*/
char* norm_name, /* out: normalized name as a
null-terminated string */
- const char* name) /* in: table name string */
+ const char* name, /* in: table name string */
+ ibool set_lower_case) /* in: TRUE if we want to set
+ name to lower case */
{
char* name_ptr;
char* db_ptr;
+ ulint db_len;
char* ptr;
/* Scan name from the end */
- ptr = strend(name)-1;
+ ptr = strend(name) - 1;
+ /* seek to the last path separator */
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
}
name_ptr = ptr + 1;
- DBUG_ASSERT(ptr > name);
+ /* skip any number of path separators */
+ while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
+ ptr--;
+ }
- ptr--;
+ DBUG_ASSERT(ptr >= name);
+ /* seek to the last but one path separator or one char before
+ the beginning of name */
+ db_len = 0;
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
+ db_len++;
}
db_ptr = ptr + 1;
- memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
+ memcpy(norm_name, db_ptr, db_len);
- norm_name[name_ptr - db_ptr - 1] = '/';
+ norm_name[db_len] = '/';
-#ifdef __WIN__
- innobase_casedn_str(norm_name);
-#endif
+ memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1);
+
+ if (set_lower_case) {
+ innobase_casedn_str(norm_name);
+ }
+}
+
+#if !defined(DBUG_OFF)
+/*********************************************************************
+Test normalize_table_name_low(). */
+static
+void
+test_normalize_table_name_low()
+/*===========================*/
+{
+ char norm_name[128];
+ const char* test_data[][2] = {
+ /* input, expected result */
+ {"./mysqltest/t1", "mysqltest/t1"},
+ {"./test/#sql-842b_2", "test/#sql-842b_2"},
+ {"./test/#sql-85a3_10", "test/#sql-85a3_10"},
+ {"./test/#sql2-842b-2", "test/#sql2-842b-2"},
+ {"./test/bug29807", "test/bug29807"},
+ {"./test/foo", "test/foo"},
+ {"./test/innodb_bug52663", "test/innodb_bug52663"},
+ {"./test/t", "test/t"},
+ {"./test/t1", "test/t1"},
+ {"./test/t10", "test/t10"},
+ {"/a/b/db/table", "db/table"},
+ {"/a/b/db///////table", "db/table"},
+ {"/a/b////db///////table", "db/table"},
+ {"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db/table", "db/table"},
+ {"ddd/t", "ddd/t"},
+ {"d/ttt", "d/ttt"},
+ {"d/t", "d/t"},
+ {".\\mysqltest\\t1", "mysqltest/t1"},
+ {".\\test\\#sql-842b_2", "test/#sql-842b_2"},
+ {".\\test\\#sql-85a3_10", "test/#sql-85a3_10"},
+ {".\\test\\#sql2-842b-2", "test/#sql2-842b-2"},
+ {".\\test\\bug29807", "test/bug29807"},
+ {".\\test\\foo", "test/foo"},
+ {".\\test\\innodb_bug52663", "test/innodb_bug52663"},
+ {".\\test\\t", "test/t"},
+ {".\\test\\t1", "test/t1"},
+ {".\\test\\t10", "test/t10"},
+ {"C:\\a\\b\\db\\table", "db/table"},
+ {"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db\\table", "db/table"},
+ {"ddd\\t", "ddd/t"},
+ {"d\\ttt", "d/ttt"},
+ {"d\\t", "d/t"},
+ };
+
+ for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
+ printf("test_normalize_table_name_low(): "
+ "testing \"%s\", expected \"%s\"... ",
+ test_data[i][0], test_data[i][1]);
+
+ normalize_table_name_low(norm_name, test_data[i][0], FALSE);
+
+ if (strcmp(norm_name, test_data[i][1]) == 0) {
+ printf("ok\n");
+ } else {
+ printf("got \"%s\"\n", norm_name);
+ ut_error;
+ }
+ }
}
+#endif /* !DBUG_OFF */
/************************************************************************
Get the upper limit of the MySQL integral and floating-point type. */
@@ -2806,6 +2906,8 @@ ha_innobase::open(
THD* thd;
ulint retries = 0;
char* is_part = NULL;
+ ibool par_case_name_set = FALSE;
+ char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open");
@@ -2852,16 +2954,87 @@ ha_innobase::open(
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
at support issue https://support.mysql.com/view.php?id=21080
for more details. */
+#ifdef __WIN__
+ is_part = strstr(norm_name, "#p#");
+#else
is_part = strstr(norm_name, "#P#");
+#endif /* __WIN__ */
+
retry:
/* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE);
-
+
if (NULL == ib_table) {
if (is_part && retries < 10) {
- ++retries;
- os_thread_sleep(100000);
- goto retry;
+ /* MySQL partition engine hard codes the file name
+ separator as "#P#". The text case is fixed even if
+ lower_case_table_names is set to 1 or 2. This is true
+ for sub-partition names as well. InnoDB always
+ normalises file names to lower case on Windows, this
+ can potentially cause problems when copying/moving
+ tables between platforms.
+
+ 1) If boot against an installation from Windows
+ platform, then its partition table name could
+ be all be in lower case in system tables. So we
+ will need to check lower case name when load table.
+
+ 2) If we boot an installation from other case
+ sensitive platform in Windows, we might need to
+ check the existence of table name without lowering
+ case them in the system table. */
+ if (innobase_get_lower_case_table_names() == 1) {
+
+ if (!par_case_name_set) {
+#ifndef __WIN__
+ /* Check for the table using lower
+ case name, including the partition
+ separator "P" */
+ memcpy(par_case_name, norm_name,
+ strlen(norm_name));
+ par_case_name[strlen(norm_name)] = 0;
+ innobase_casedn_str(par_case_name);
+#else
+ /* On Windows platfrom, check
+ whether there exists table name in
+ system table whose name is
+ not being normalized to lower case */
+ normalize_table_name_low(
+ par_case_name, name, FALSE);
+#endif
+ par_case_name_set = TRUE;
+ }
+
+ ib_table = dict_table_get(
+ par_case_name, FALSE);
+ }
+ if (!ib_table) {
+ ++retries;
+ os_thread_sleep(100000);
+ goto retry;
+ } else {
+#ifndef __WIN__
+ sql_print_warning("Partition table %s opened "
+ "after converting to lower "
+ "case. The table may have "
+ "been moved from a case "
+ "in-sensitive file system. "
+ "Please recreate table in "
+ "the current file system\n",
+ norm_name);
+#else
+ sql_print_warning("Partition table %s opened "
+ "after skipping the step to "
+ "lower case the table name. "
+ "The table may have been "
+ "moved from a case sensitive "
+ "file system. Please "
+ "recreate table in the "
+ "current file system\n",
+ norm_name);
+#endif
+ goto table_opened;
+ }
}
if (is_part) {
@@ -2892,6 +3065,8 @@ retry:
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
+table_opened:
+
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n"
@@ -5892,6 +6067,11 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
+ DBUG_EXECUTE_IF(
+ "test_normalize_table_name_low",
+ test_normalize_table_name_low();
+ );
+
/* Strangely, MySQL passes the table name without the '.frm'
extension, in contrast to ::create */
normalize_table_name(norm_name, name);
diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c
index 1406b2de4e9..476d78e79ba 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.c
+++ b/storage/innobase/ibuf/ibuf0ibuf.c
@@ -2009,7 +2009,15 @@ ibuf_get_merge_page_nos(
} else {
rec_page_no = ibuf_rec_get_page_no(rec);
rec_space_id = ibuf_rec_get_space(rec);
- ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
+ /* In the system tablespace, the smallest
+ possible secondary index leaf page number is
+ bigger than IBUF_TREE_ROOT_PAGE_NO (4). In
+ other tablespaces, the clustered index tree is
+ created at page 3, which makes page 4 the
+ smallest possible secondary index leaf page
+ (and that only after DROP INDEX). */
+ ut_ad(rec_page_no
+ > IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0));
}
#ifdef UNIV_IBUF_DEBUG
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 4ac0809bcd2..804f0e35605 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -160,6 +160,24 @@ management to ensure correct alignment for doubles etc. */
/* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32
+/** The maximum length of a table name. This is the MySQL limit and is
+defined in mysql_com.h like NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN, the
+number does not include a terminating '\0'. InnoDB probably can handle
+longer names internally */
+#define MAX_TABLE_NAME_LEN 192
+
+/** The maximum length of a database name. Like MAX_TABLE_NAME_LEN this is
+the MySQL's NAME_LEN, see check_and_convert_db_name(). */
+#define MAX_DATABASE_NAME_LEN MAX_TABLE_NAME_LEN
+
+/** MAX_FULL_NAME_LEN defines the full name path including the
+database name and table name. In addition, 14 bytes is added for:
+ 2 for surrounding quotes around table name
+ 1 for the separating dot (.)
+ 9 for the #mysql50# prefix */
+#define MAX_FULL_NAME_LEN \
+ (MAX_TABLE_NAME_LEN + MAX_DATABASE_NAME_LEN + 14)
+
/*
UNIVERSAL TYPE DEFINITIONS
==========================
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index 9c13c9e6645..77bd3283c47 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,3 +1,26 @@
+2012-02-06 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug #11754376 45976: INNODB LOST FILES FOR TEMPORARY TABLES ON
+ GRACEFUL SHUTDOWN
+
+2012-01-30 The InnoDB Team
+
+ * fil/fil0fil.c:
+ Fix Bug#13636122 THE ORIGINAL TABLE MISSING WHILE EXECUTE THE
+ DDL 'ALTER TABLE ADD COLUMN'
+
+2012-01-16 The InnoDB Team
+
+ * ibuf/ibuf0ibuf.c:
+ Fix Bug#13496818 ASSERTION: REC_PAGE_NO > 4 IN IBUF CONTRACTION
+
+2012-01-16 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug#11765438: 58406: ISSUES WITH COPYING PARTITIONED INNODB
+ TABLES FROM LINUX TO WINDOWS
+
2012-01-04 The InnoDB Team
* row/row0mysql.c:
@@ -15,8 +38,8 @@
2011-12-13 The InnoDB Team
* handler/ha_innodb.cc, innodb.test, innodb.result:
- Fix Bug#13117023: InnoDB was incrementing the handler_read_key,
- also the SSV::ha_read_key_count, at the wrong place.
+ Fix Bug#13117023: InnoDB was incrementing the handler_read_key,
+ also the SSV::ha_read_key_count, at the wrong place.
2011-12-10 The InnoDB Team
@@ -277,7 +300,7 @@
2011-01-06 The InnoDB Team
* dict/dict0dict.c, handler/ha_innodb.cc, handler/i_s.cc,
- include/univ.i:
+ include/univ.i:
Fix Bug#58643 InnoDB: too long table name
2011-01-06 The InnoDB Team
@@ -543,7 +566,7 @@
* handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c:
Fix Bug#53592: crash replacing duplicates into table after fast
- alter table added unique key
+ alter table added unique key
2010-05-24 The InnoDB Team
diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c
index 9f4be053a43..46e850bb218 100644
--- a/storage/innodb_plugin/btr/btr0cur.c
+++ b/storage/innodb_plugin/btr/btr0cur.c
@@ -393,7 +393,12 @@ btr_cur_search_to_nth_level(
ut_ad(dict_index_check_search_tuple(index, tuple));
ut_ad(!dict_index_is_ibuf(index) || ibuf_inside());
ut_ad(dtuple_check_typed(tuple));
+ ut_ad(index->page != FIL_NULL);
+ UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match);
+ UNIV_MEM_INVALID(&cursor->up_bytes, sizeof cursor->up_bytes);
+ UNIV_MEM_INVALID(&cursor->low_match, sizeof cursor->low_match);
+ UNIV_MEM_INVALID(&cursor->low_bytes, sizeof cursor->low_bytes);
#ifdef UNIV_DEBUG
cursor->up_match = ULINT_UNDEFINED;
cursor->low_match = ULINT_UNDEFINED;
diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c
index 6daaacb0ac0..c2000d67303 100644
--- a/storage/innodb_plugin/buf/buf0buf.c
+++ b/storage/innodb_plugin/buf/buf0buf.c
@@ -2148,7 +2148,7 @@ buf_page_get_known_nowait(
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(block->page.file_page_was_freed == FALSE);
+ ut_a(mode == BUF_KEEP_OLD || !block->page.file_page_was_freed);
#endif
#ifdef UNIV_IBUF_COUNT_DEBUG
diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c
index 0f774dcaaa1..01057c26d94 100644
--- a/storage/innodb_plugin/fil/fil0fil.c
+++ b/storage/innodb_plugin/fil/fil0fil.c
@@ -918,11 +918,6 @@ retry:
return;
}
- if (fil_system->n_open < fil_system->max_n_open) {
-
- return;
- }
-
space = fil_space_get_by_id(space_id);
if (space != NULL && space->stop_ios) {
@@ -939,6 +934,25 @@ retry:
mutex_exit(&fil_system->mutex);
+#ifndef UNIV_HOTBACKUP
+
+ /* Wake the i/o-handler threads to make sure pending
+ i/o's are performed */
+ os_aio_simulated_wake_handler_threads();
+
+ /* The sleep here is just to give IO helper threads a
+ bit of time to do some work. It is not required that
+ all IO related to the tablespace being renamed must
+ be flushed here as we do fil_flush() in
+ fil_rename_tablespace() as well. */
+ os_thread_sleep(20000);
+
+#endif /* UNIV_HOTBACKUP */
+
+ /* Flush tablespaces so that we can close modified
+ files in the LRU list */
+ fil_flush_file_spaces(FIL_TABLESPACE);
+
os_thread_sleep(20000);
count2++;
@@ -946,6 +960,11 @@ retry:
goto retry;
}
+ if (fil_system->n_open < fil_system->max_n_open) {
+
+ return;
+ }
+
/* If the file is already open, no need to do anything; if the space
does not exist, we handle the situation in the function which called
this function */
@@ -2496,7 +2515,7 @@ fil_rename_tablespace(
retry:
count++;
- if (count > 1000) {
+ if (!(count % 1000)) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: problems renaming ", stderr);
ut_print_filename(stderr, old_name);
diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc
index 149e660e36e..f23642d6af8 100644
--- a/storage/innodb_plugin/handler/ha_innodb.cc
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
@@ -1039,6 +1039,20 @@ innobase_get_charset(
}
/**********************************************************************//**
+Get the current setting of the lower_case_table_names global parameter from
+mysqld.cc. We do a dirty read because for one there is no synchronization
+object and secondly there is little harm in doing so even if we get a torn
+read.
+@return value of lower_case_table_names */
+ulint
+innobase_get_lower_case_table_names(void)
+/*=====================================*/
+{
+ return(lower_case_table_names);
+}
+
+
+/**********************************************************************//**
Determines the current SQL statement.
@return SQL statement string */
extern "C" UNIV_INTERN
@@ -3008,52 +3022,140 @@ ha_innobase::primary_key_is_clustered()
return(true);
}
+/** Always normalize table name to lower case on Windows */
+#ifdef __WIN__
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, TRUE)
+#else
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, FALSE)
+#endif /* __WIN__ */
+
/*****************************************************************//**
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case. */
+table name always to lower case if "set_lower_case" is set to TRUE. */
static
void
-normalize_table_name(
-/*=================*/
+normalize_table_name_low(
+/*=====================*/
char* norm_name, /*!< out: normalized name as a
null-terminated string */
- const char* name) /*!< in: table name string */
+ const char* name, /*!< in: table name string */
+ ibool set_lower_case) /*!< in: TRUE if we want to set
+ name to lower case */
{
char* name_ptr;
char* db_ptr;
+ ulint db_len;
char* ptr;
/* Scan name from the end */
- ptr = strend(name)-1;
+ ptr = strend(name) - 1;
+ /* seek to the last path separator */
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
}
name_ptr = ptr + 1;
- DBUG_ASSERT(ptr > name);
+ /* skip any number of path separators */
+ while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
+ ptr--;
+ }
- ptr--;
+ DBUG_ASSERT(ptr >= name);
+ /* seek to the last but one path separator or one char before
+ the beginning of name */
+ db_len = 0;
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
+ db_len++;
}
db_ptr = ptr + 1;
- memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
+ memcpy(norm_name, db_ptr, db_len);
- norm_name[name_ptr - db_ptr - 1] = '/';
+ norm_name[db_len] = '/';
-#ifdef __WIN__
- innobase_casedn_str(norm_name);
-#endif
+ memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1);
+
+ if (set_lower_case) {
+ innobase_casedn_str(norm_name);
+ }
}
+#if !defined(DBUG_OFF)
+/*********************************************************************
+Test normalize_table_name_low(). */
+static
+void
+test_normalize_table_name_low()
+/*===========================*/
+{
+ char norm_name[128];
+ const char* test_data[][2] = {
+ /* input, expected result */
+ {"./mysqltest/t1", "mysqltest/t1"},
+ {"./test/#sql-842b_2", "test/#sql-842b_2"},
+ {"./test/#sql-85a3_10", "test/#sql-85a3_10"},
+ {"./test/#sql2-842b-2", "test/#sql2-842b-2"},
+ {"./test/bug29807", "test/bug29807"},
+ {"./test/foo", "test/foo"},
+ {"./test/innodb_bug52663", "test/innodb_bug52663"},
+ {"./test/t", "test/t"},
+ {"./test/t1", "test/t1"},
+ {"./test/t10", "test/t10"},
+ {"/a/b/db/table", "db/table"},
+ {"/a/b/db///////table", "db/table"},
+ {"/a/b////db///////table", "db/table"},
+ {"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db/table", "db/table"},
+ {"ddd/t", "ddd/t"},
+ {"d/ttt", "d/ttt"},
+ {"d/t", "d/t"},
+ {".\\mysqltest\\t1", "mysqltest/t1"},
+ {".\\test\\#sql-842b_2", "test/#sql-842b_2"},
+ {".\\test\\#sql-85a3_10", "test/#sql-85a3_10"},
+ {".\\test\\#sql2-842b-2", "test/#sql2-842b-2"},
+ {".\\test\\bug29807", "test/bug29807"},
+ {".\\test\\foo", "test/foo"},
+ {".\\test\\innodb_bug52663", "test/innodb_bug52663"},
+ {".\\test\\t", "test/t"},
+ {".\\test\\t1", "test/t1"},
+ {".\\test\\t10", "test/t10"},
+ {"C:\\a\\b\\db\\table", "db/table"},
+ {"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db\\table", "db/table"},
+ {"ddd\\t", "ddd/t"},
+ {"d\\ttt", "d/ttt"},
+ {"d\\t", "d/t"},
+ };
+
+ for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
+ printf("test_normalize_table_name_low(): "
+ "testing \"%s\", expected \"%s\"... ",
+ test_data[i][0], test_data[i][1]);
+
+ normalize_table_name_low(norm_name, test_data[i][0], FALSE);
+
+ if (strcmp(norm_name, test_data[i][1]) == 0) {
+ printf("ok\n");
+ } else {
+ printf("got \"%s\"\n", norm_name);
+ ut_error;
+ }
+ }
+}
+#endif /* !DBUG_OFF */
+
/********************************************************************//**
Get the upper limit of the MySQL integral and floating-point type.
@return maximum allowed value for the field */
@@ -3445,6 +3547,8 @@ ha_innobase::open(
THD* thd;
ulint retries = 0;
char* is_part = NULL;
+ ibool par_case_name_set = FALSE;
+ char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open");
@@ -3491,16 +3595,87 @@ ha_innobase::open(
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
at support issue https://support.mysql.com/view.php?id=21080
for more details. */
+#ifdef __WIN__
+ is_part = strstr(norm_name, "#p#");
+#else
is_part = strstr(norm_name, "#P#");
+#endif /* __WIN__ */
+
retry:
/* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE);
-
+
if (NULL == ib_table) {
if (is_part && retries < 10) {
- ++retries;
- os_thread_sleep(100000);
- goto retry;
+ /* MySQL partition engine hard codes the file name
+ separator as "#P#". The text case is fixed even if
+ lower_case_table_names is set to 1 or 2. This is true
+ for sub-partition names as well. InnoDB always
+ normalises file names to lower case on Windows, this
+ can potentially cause problems when copying/moving
+ tables between platforms.
+
+ 1) If boot against an installation from Windows
+ platform, then its partition table name could
+ be all be in lower case in system tables. So we
+ will need to check lower case name when load table.
+
+ 2) If we boot an installation from other case
+ sensitive platform in Windows, we might need to
+ check the existence of table name without lowering
+ case them in the system table. */
+ if (innobase_get_lower_case_table_names() == 1) {
+
+ if (!par_case_name_set) {
+#ifndef __WIN__
+ /* Check for the table using lower
+ case name, including the partition
+ separator "P" */
+ memcpy(par_case_name, norm_name,
+ strlen(norm_name));
+ par_case_name[strlen(norm_name)] = 0;
+ innobase_casedn_str(par_case_name);
+#else
+ /* On Windows platfrom, check
+ whether there exists table name in
+ system table whose name is
+ not being normalized to lower case */
+ normalize_table_name_low(
+ par_case_name, name, FALSE);
+#endif
+ par_case_name_set = TRUE;
+ }
+
+ ib_table = dict_table_get(
+ par_case_name, FALSE);
+ }
+ if (!ib_table) {
+ ++retries;
+ os_thread_sleep(100000);
+ goto retry;
+ } else {
+#ifndef __WIN__
+ sql_print_warning("Partition table %s opened "
+ "after converting to lower "
+ "case. The table may have "
+ "been moved from a case "
+ "in-sensitive file system. "
+ "Please recreate table in "
+ "the current file system\n",
+ norm_name);
+#else
+ sql_print_warning("Partition table %s opened "
+ "after skipping the step to "
+ "lower case the table name. "
+ "The table may have been "
+ "moved from a case sensitive "
+ "file system. Please "
+ "recreate table in the "
+ "current file system\n",
+ norm_name);
+#endif
+ goto table_opened;
+ }
}
if (is_part) {
@@ -3531,6 +3706,8 @@ retry:
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
+table_opened:
+
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n"
@@ -6947,6 +7124,11 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
+ DBUG_EXECUTE_IF(
+ "test_normalize_table_name_low",
+ test_normalize_table_name_low();
+ );
+
/* Strangely, MySQL passes the table name without the '.frm'
extension, in contrast to ::create */
normalize_table_name(norm_name, name);
diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c
index a22de3b0e70..9a243d83bd5 100644
--- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c
+++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -2090,7 +2090,15 @@ ibuf_get_merge_page_nos(
} else {
rec_page_no = ibuf_rec_get_page_no(rec);
rec_space_id = ibuf_rec_get_space(rec);
- ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
+ /* In the system tablespace, the smallest
+ possible secondary index leaf page number is
+ bigger than IBUF_TREE_ROOT_PAGE_NO (4). In
+ other tablespaces, the clustered index tree is
+ created at page 3, which makes page 4 the
+ smallest possible secondary index leaf page
+ (and that only after DROP INDEX). */
+ ut_ad(rec_page_no
+ > IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0));
}
#ifdef UNIV_IBUF_DEBUG
diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c
index 647d0031635..8c18cfa078b 100644
--- a/storage/innodb_plugin/row/row0merge.c
+++ b/storage/innodb_plugin/row/row0merge.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -576,7 +576,7 @@ row_merge_buf_write(
REC_STATUS_ORDINARY,
entry, n_fields,
&extra_size);
- ut_ad(size > extra_size);
+ ut_ad(size >= extra_size);
ut_ad(extra_size >= REC_N_NEW_EXTRA_BYTES);
extra_size -= REC_N_NEW_EXTRA_BYTES;
size -= REC_N_NEW_EXTRA_BYTES;
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index 4a0c2da5559..35d28facdd8 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -4314,13 +4314,6 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
u_ptr->seg=keyseg;
keyseg+=u_ptr->keysegs+1;
}
- if (share.options & HA_OPTION_COMPRESS_RECORD)
- share.base.records=max_records=info.state->records;
- else if (share.base.min_pack_length)
- max_records=(ha_rows) (my_seek(info.dfile,0L,MY_SEEK_END,MYF(0)) /
- (ulong) share.base.min_pack_length);
- else
- max_records=0;
unpack= (share.options & HA_OPTION_COMPRESS_RECORD) &&
(param->testflag & T_UNPACK);
share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
@@ -4330,10 +4323,17 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
set_if_bigger(file_length,param->max_data_file_length);
set_if_bigger(file_length,tmp_length);
set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length);
+
+ if (share.options & HA_OPTION_COMPRESS_RECORD)
+ share.base.records= max_records= info.state->records;
+ else if (!(share.options & HA_OPTION_PACK_RECORD))
+ max_records= (ha_rows) (file_length / share.base.pack_reclength);
+ else
+ max_records= 0;
VOID(mi_close(*org_info));
bzero((char*) &create_info,sizeof(create_info));
- create_info.max_rows=max(max_records,share.base.records);
+ create_info.max_rows= max_records;
create_info.reloc_rows=share.base.reloc;
create_info.old_options=(share.options |
(unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));