#At file:///Users/mattiasj/clones/bzrroot/b32430-60-bugteam/
2691 Mattias Jonsson 2008-07-07
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Problem was the function filename_to_tablename in conjuction with
partitions, since partitions intentionally uses the '#' character,
which is not included in the filename charset.
Solution was to implement the unescape filename function that
allows the '#' character and only converts the filename from
filename charset to system_charset_info.
modified:
mysql-test/r/partition_innodb.result
mysql-test/t/partition_innodb.test
sql/mysql_priv.h
sql/sql_table.cc
storage/innobase/handler/ha_innodb.cc
per-file messages:
mysql-test/r/partition_innodb.result
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Updated test result.
mysql-test/t/partition_innodb.test
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Created test to generate deadlock and extract the first table name
given in 'SHOW ENGINE INNODB STATUS' (used the perl feature in
mysqltest).
sql/mysql_priv.h
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Added unescape_filename function
sql/sql_table.cc
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Created unescape_filename function to convert a string from
filname charset (including the '#' character not allowed in
that charset) to system_charset_info.
This could be used for presenting info from a storage engine
in SHOW ENGINE SE STATUS.
storage/innobase/handler/ha_innodb.cc
Bug#32430 'show innodb status' causes errors Invalid (old?)
table or database name in logs
Using the new unescape_filename function instead of
filname_to_tablename since it does not work for partitions.
=== modified file 'mysql-test/r/partition_innodb.result'
--- a/mysql-test/r/partition_innodb.result 2008-06-12 00:08:07 +0000
+++ b/mysql-test/r/partition_innodb.result 2008-07-07 10:58:15 +0000
@@ -1,3 +1,37 @@
+SET NAMES utf8;
+CREATE TABLE t1 (a INT, primary key (a))
+ENGINE=InnoDB
+PARTITION BY RANGE (a)
+SUBPARTITION BY HASH (a)
+(PARTITION p0 VALUES LESS THAN (100)
+(SUBPARTITION sp0,
+SUBPARTITION sp1),
+PARTITION p1 VALUES LESS THAN (MAXVALUE)
+(SUBPARTITION sp2,
+SUBPARTITION sp3));
+INSERT INTO t1 VALUES (0), (2), (6), (10), (14), (18), (22);
+START TRANSACTION;
+# con1
+SET NAMES utf8;
+START TRANSACTION;
+# default connection
+UPDATE t1 SET a = 16 WHERE a = 0;
+# con1
+UPDATE t1 SET a = 8 WHERE a = 22;
+UPDATE t1 SET a = 12 WHERE a = 0;
+# default connection
+SELECT sleep(2);
+sleep(2)
+0
+UPDATE t1 SET a = 4 WHERE a = 22;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+# First table name reported in 'SHOW ENGINE InnoDB STATUS'
+`test`.`t1#p#p0#sp#sp0`
+# con1
+ROLLBACK;
+# default connection
+DROP TABLE t1;
+SET NAMES DEFAULT;
# Bug#32948
CREATE TABLE t1 (c1 INT, PRIMARY KEY (c1)) ENGINE=INNODB;
CREATE TABLE t2 (c1 INT, PRIMARY KEY (c1),
=== modified file 'mysql-test/t/partition_innodb.test'
--- a/mysql-test/t/partition_innodb.test 2008-06-12 00:08:07 +0000
+++ b/mysql-test/t/partition_innodb.test 2008-07-07 10:58:15 +0000
@@ -1,6 +1,63 @@
--source include/have_partition.inc
--source include/have_innodb.inc
+# Bug#32430 - show engine innodb status causes errors
+#
+SET NAMES utf8;
+CREATE TABLE t1 (a INT, primary key (a))
+ENGINE=InnoDB
+PARTITION BY RANGE (a)
+SUBPARTITION BY HASH (a)
+(PARTITION p0 VALUES LESS THAN (100)
+ (SUBPARTITION sp0,
+ SUBPARTITION sp1),
+ PARTITION p1 VALUES LESS THAN (MAXVALUE)
+ (SUBPARTITION sp2,
+ SUBPARTITION sp3));
+INSERT INTO t1 VALUES (0), (2), (6), (10), (14), (18), (22);
+START TRANSACTION;
+--echo # con1
+connect(con1,localhost,root,,);
+SET NAMES utf8;
+START TRANSACTION;
+--echo # default connection
+connection default;
+UPDATE t1 SET a = 16 WHERE a = 0;
+--echo # con1
+connection con1;
+UPDATE t1 SET a = 8 WHERE a = 22;
+SEND;
+UPDATE t1 SET a = 12 WHERE a = 0;
+--echo # default connection
+connection default;
+SELECT sleep(2);
+--error ER_LOCK_DEADLOCK
+UPDATE t1 SET a = 4 WHERE a = 22;
+--exec $MYSQL -e "SHOW ENGINE InnoDB STATUS" >
$MYSQLTEST_VARDIR/tmp/innodb_status.txt;
+--echo # First table name reported in 'SHOW ENGINE InnoDB STATUS'
+perl;
+open FH, "< var/tmp/innodb_status.txt" or die "Error when open";
+while (<FH>)
+{
+ next if not / of table .* trx id /;
+ my ($line) = m/of table (.*?) trx id /;
+ # must be in lower case, to be consistent on both linux
+ # and windows, since InnoDB always converts to lowercase on win.
+ print lc $line . "\n";
+}
+close FH;
+EOF
+--remove_file $MYSQLTEST_VARDIR/tmp/innodb_status.txt
+--echo # con1
+connection con1;
+REAP;
+ROLLBACK;
+disconnect con1;
+--echo # default connection
+connection default;
+DROP TABLE t1;
+SET NAMES DEFAULT;
+
# Bug#32948 - FKs allowed to reference partitioned table
#
-- echo # Bug#32948
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2008-05-21 10:17:29 +0000
+++ b/sql/mysql_priv.h 2008-07-07 10:58:15 +0000
@@ -2307,6 +2307,7 @@ char *fn_rext(char *name);
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
uint strconvert(CHARSET_INFO *from_cs, const char *from,
CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors);
+uint unescape_filename(const char *from, char *to, uint to_length);
uint filename_to_tablename(const char *from, char *to, uint to_length);
uint tablename_to_filename(const char *from, char *to, uint to_length);
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2008-06-25 11:13:03 +0000
+++ b/sql/sql_table.cc 2008-07-07 10:58:15 +0000
@@ -69,6 +69,58 @@ static void wait_for_kill_signal(THD *th
/*
+ Translate a file name to a non escaped name.
+ filename_to_tablename cannot be used on partitions, due to the #P# part.
+ There can be up to 6 '#', #P# for partition, #SP# for subpartition
+ and #TMP# or #REN# for temporary or renamed partitions.
+
+ SYNOPSIS
+ unescape_filename()
+ from The file name in my_charset_filename + '#'.
+ to OUT The file name in system_charset_info.
+ to_length The size of the table name buffer.
+
+ RETURN
+ Table name length.
+*/
+
+uint unescape_filename(const char *from, char *to, uint to_length)
+{
+ uint errors;
+ uint res;
+ char *delim_p;
+ char *end_p;
+ const char *from_p;
+ char *tmp_p;
+ char tmp_name[FN_REFLEN + 6 * 4]; /* extra for #->@0023 */
+ DBUG_ENTER("unescape_filename");
+ DBUG_PRINT("enter", ("from '%s'", from));
+
+ /*
+ copy 'from' to 'tmp_name' and escape '#' to '@0023'.
+ Since '#' does not exist in filename characterset.
+ */
+ end_p= tmp_name + sizeof(tmp_name) - 1;
+ tmp_p= tmp_name;
+ from_p= from;
+ while (*from_p && (delim_p= strchr(from_p, '#')))
+ {
+ tmp_p= strnmov(tmp_p, from_p, delim_p - from_p);
+ tmp_p= strmov(tmp_p, "@0023");
+ from_p= delim_p + 1;
+ }
+ if (*from_p)
+ from_p= strnmov(tmp_p, from_p, end_p - tmp_p);
+
+ res= strconvert(&my_charset_filename, tmp_name,
+ system_charset_info, to, to_length, &errors);
+
+ DBUG_PRINT("exit", ("to '%s'", to));
+ DBUG_RETURN(res);
+}
+
+
+/*
Translate a file name to a table name (WL #1324).
SYNOPSIS
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc 2008-06-12 00:08:07 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2008-07-07 10:58:15 +0000
@@ -1271,7 +1271,7 @@ innobase_print_identifier(
int q;
if (table_id) {
- /* Decode the table name. The filename_to_tablename()
+ /* Decode the table name. The unescape_filename()
function expects a NUL-terminated string. The input and
output strings buffers must not be shared. The function
only produces more output when the name contains other
@@ -1286,7 +1286,7 @@ innobase_print_identifier(
memcpy(temp_name, name, namelen);
temp_name[namelen] = 0;
s = qname;
- namelen = filename_to_tablename(temp_name,
+ namelen = unescape_filename(temp_name,
qname, qnamelen);
}
my_free(temp_name, MYF(0));