Commit a422340f authored by Annamalai Gurusami's avatar Annamalai Gurusami

Bug #11765438 58406:

ISSUES WITH COPYING PARTITIONED INNODB TABLES FROM LINUX TO WINDOWS

This problem was already fixed in mysql-trunk as part of bug #11755924.  I am 
backporting the fix to mysql-5.1.  
parent 7c3bd8ad
...@@ -948,6 +948,19 @@ innobase_get_charset( ...@@ -948,6 +948,19 @@ innobase_get_charset(
return(thd_charset((THD*) mysql_thd)); 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) #if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
/*******************************************************************//** /*******************************************************************//**
...@@ -2579,19 +2592,29 @@ ha_innobase::bas_ext() const ...@@ -2579,19 +2592,29 @@ ha_innobase::bas_ext() const
return ha_innobase_exts; 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 Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example: database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the 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 static
void void
normalize_table_name( normalize_table_name_low(
/*=================*/ /*=====================*/
char* norm_name, /* out: normalized name as a char* norm_name, /* out: normalized name as a
null-terminated string */ 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* name_ptr;
char* db_ptr; char* db_ptr;
...@@ -2621,9 +2644,9 @@ normalize_table_name( ...@@ -2621,9 +2644,9 @@ normalize_table_name(
norm_name[name_ptr - db_ptr - 1] = '/'; norm_name[name_ptr - db_ptr - 1] = '/';
#ifdef __WIN__ if (set_lower_case) {
innobase_casedn_str(norm_name); innobase_casedn_str(norm_name);
#endif }
} }
/************************************************************************ /************************************************************************
...@@ -2806,6 +2829,8 @@ ha_innobase::open( ...@@ -2806,6 +2829,8 @@ ha_innobase::open(
THD* thd; THD* thd;
ulint retries = 0; ulint retries = 0;
char* is_part = NULL; char* is_part = NULL;
ibool par_case_name_set = FALSE;
char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open"); DBUG_ENTER("ha_innobase::open");
...@@ -2852,16 +2877,87 @@ ha_innobase::open( ...@@ -2852,16 +2877,87 @@ ha_innobase::open(
workaround for http://bugs.mysql.com/bug.php?id=33349. Look workaround for http://bugs.mysql.com/bug.php?id=33349. Look
at support issue https://support.mysql.com/view.php?id=21080 at support issue https://support.mysql.com/view.php?id=21080
for more details. */ for more details. */
#ifdef __WIN__
is_part = strstr(norm_name, "#p#");
#else
is_part = strstr(norm_name, "#P#"); is_part = strstr(norm_name, "#P#");
#endif /* __WIN__ */
retry: retry:
/* Get pointer to a table object in InnoDB dictionary cache */ /* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE); ib_table = dict_table_get(norm_name, TRUE);
if (NULL == ib_table) { if (NULL == ib_table) {
if (is_part && retries < 10) { if (is_part && retries < 10) {
++retries; /* MySQL partition engine hard codes the file name
os_thread_sleep(100000); separator as "#P#". The text case is fixed even if
goto retry; 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) { if (is_part) {
...@@ -2892,6 +2988,8 @@ ha_innobase::open( ...@@ -2892,6 +2988,8 @@ ha_innobase::open(
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
} }
table_opened:
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) { if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but " sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n" "the .ibd file for\ntable %s does not exist.\n"
......
...@@ -160,6 +160,24 @@ management to ensure correct alignment for doubles etc. */ ...@@ -160,6 +160,24 @@ management to ensure correct alignment for doubles etc. */
/* Maximum number of parallel threads in a parallelized operation */ /* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32 #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 UNIVERSAL TYPE DEFINITIONS
========================== ==========================
......
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 2012-01-04 The InnoDB Team
* row/row0mysql.c: * row/row0mysql.c:
......
...@@ -1038,6 +1038,20 @@ innobase_get_charset( ...@@ -1038,6 +1038,20 @@ innobase_get_charset(
return(thd_charset((THD*) mysql_thd)); 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);
}
/**********************************************************************//** /**********************************************************************//**
Determines the current SQL statement. Determines the current SQL statement.
@return SQL statement string */ @return SQL statement string */
...@@ -3008,18 +3022,29 @@ ha_innobase::primary_key_is_clustered() ...@@ -3008,18 +3022,29 @@ ha_innobase::primary_key_is_clustered()
return(true); 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 Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example: database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the 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 static
void void
normalize_table_name( normalize_table_name_low(
/*=================*/ /*=====================*/
char* norm_name, /*!< out: normalized name as a char* norm_name, /*!< out: normalized name as a
null-terminated string */ 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* name_ptr;
char* db_ptr; char* db_ptr;
...@@ -3049,9 +3074,9 @@ normalize_table_name( ...@@ -3049,9 +3074,9 @@ normalize_table_name(
norm_name[name_ptr - db_ptr - 1] = '/'; norm_name[name_ptr - db_ptr - 1] = '/';
#ifdef __WIN__ if (set_lower_case) {
innobase_casedn_str(norm_name); innobase_casedn_str(norm_name);
#endif }
} }
/********************************************************************//** /********************************************************************//**
...@@ -3445,6 +3470,8 @@ ha_innobase::open( ...@@ -3445,6 +3470,8 @@ ha_innobase::open(
THD* thd; THD* thd;
ulint retries = 0; ulint retries = 0;
char* is_part = NULL; char* is_part = NULL;
ibool par_case_name_set = FALSE;
char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open"); DBUG_ENTER("ha_innobase::open");
...@@ -3491,16 +3518,87 @@ ha_innobase::open( ...@@ -3491,16 +3518,87 @@ ha_innobase::open(
workaround for http://bugs.mysql.com/bug.php?id=33349. Look workaround for http://bugs.mysql.com/bug.php?id=33349. Look
at support issue https://support.mysql.com/view.php?id=21080 at support issue https://support.mysql.com/view.php?id=21080
for more details. */ for more details. */
#ifdef __WIN__
is_part = strstr(norm_name, "#p#");
#else
is_part = strstr(norm_name, "#P#"); is_part = strstr(norm_name, "#P#");
#endif /* __WIN__ */
retry: retry:
/* Get pointer to a table object in InnoDB dictionary cache */ /* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE); ib_table = dict_table_get(norm_name, TRUE);
if (NULL == ib_table) { if (NULL == ib_table) {
if (is_part && retries < 10) { if (is_part && retries < 10) {
++retries; /* MySQL partition engine hard codes the file name
os_thread_sleep(100000); separator as "#P#". The text case is fixed even if
goto retry; 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) { if (is_part) {
...@@ -3531,6 +3629,8 @@ ha_innobase::open( ...@@ -3531,6 +3629,8 @@ ha_innobase::open(
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
} }
table_opened:
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) { if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but " sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n" "the .ibd file for\ntable %s does not exist.\n"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment