#At file:///Users/mattiasj/clones/bzrroot/b32430_2-60-bugteam/
2753 Mattias Jonsson 2008-09-03
Bug#32430:'show innodb status' causes errors Invalid (old?) table
or database name in logs
Problem was that InnoDB used filename_to_tablename,
which do not handle partitions (due to the '#' in
the filename).
Solution is to add a new function to use to explain
what the filename means, explain_filename
It expands to Database, Table, [Temporary|Renamed] Partition,
Subpartition and uses errmsg.txt for localization.
This will first go through review in Sun for the server part,
and if approved, go through review by Oracle/InnoBASE and if
approved it will then be included in both server and InnoDB.
modified:
mysql-test/r/partition_innodb.result
mysql-test/t/partition_innodb.test
sql/mysql_priv.h
sql/share/errmsg.txt
sql/sql_table.cc
storage/innobase/dict/dict0dict.c
storage/innobase/handler/ha_innodb.cc
storage/innobase/ut/ut0ut.c
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
Added deterministic test.
sql/mysql_priv.h
Bug#32430:'show innodb status' causes errors Invalid (old?) table
or database name in logs
Added explain_filename function.
sql/share/errmsg.txt
Bug#32430:'show innodb status' causes errors Invalid (old?) table or database name in logs
Added messages (localized names) for explain_filename function.
sql/sql_table.cc
Bug#32430:'show innodb status' causes errors Invalid (old?) table
or database name in logs
Added explain_filename function. (To be used by SE instead of
filename_to_tablename, since the SE cannot use that for
partitions).
The function splits the name from:
[.../db/]t[<#P#>p[<#SP#>sp][#TMP#|#REN#]]
to:
[Database `db`, ]Table `t`[, [Temporary |Renamed ]Partition `p`
[, Subpartition `sp`]]
Where the words 'Database, Table, Temporary, Renamed, Partition
and Subpartition is taken from errmsg.txt
storage/innobase/dict/dict0dict.c
Bug#32430:'show innodb status' causes errors Invalid (old?) table or database name in logs
Proposed change for better message in 'SHOW ENGINE INNODB STATUS'.
storage/innobase/handler/ha_innodb.cc
Bug#32430:'show innodb status' causes errors Invalid (old?) table
or database name in logs
Proposed update to use explain_filename instead of
filename_to_tablename.
storage/innobase/ut/ut0ut.c
Bug#32430:'show innodb status' causes errors Invalid (old?) table or database name in logs
Proposed change for better message in 'SHOW ENGINE INNODB STATUS'.
=== 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-09-03 20:07:50 +0000
@@ -1,3 +1,36 @@
+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
+UPDATE t1 SET a = 4 WHERE a = 22;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+# First table reported in 'SHOW ENGINE InnoDB STATUS'
+SHOW ENGINE InnoDB STATUS;
+Type Name Status
+InnoDB Database `test`, Table `t1`, Partition `p0`, Subpartition `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-09-03 20:07:50 +0000
@@ -1,6 +1,56 @@
--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;
+let $id_1= `SELECT CONNECTION_ID()`;
+SEND;
+UPDATE t1 SET a = 12 WHERE a = 0;
+--echo # default connection
+connection default;
+let $wait_timeout= 2;
+let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE ID = $id_1 AND STATE = 'Searching rows for update';
+--source include/wait_condition.inc
+#--echo # tested wait condition $wait_condition_reps times
+--error ER_LOCK_DEADLOCK
+UPDATE t1 SET a = 4 WHERE a = 22;
+--echo # First table reported in 'SHOW ENGINE InnoDB STATUS'
+--replace_regex /.* index .* in (.*) trx id .*/\1/
+SHOW ENGINE InnoDB STATUS;
+--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-08-07 03:05:33 +0000
+++ b/sql/mysql_priv.h 2008-09-03 20:07:50 +0000
@@ -2322,6 +2322,9 @@ 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);
+/* depends on errmsg.txt Database `db`, Table `t` ... */
+#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
+uint explain_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/share/errmsg.txt'
--- a/sql/share/errmsg.txt 2008-08-06 14:39:03 +0000
+++ b/sql/share/errmsg.txt 2008-09-03 20:07:50 +0000
@@ -6372,3 +6372,23 @@ ER_BACKUP_OBTAIN_NAME_LOCK_FAILED
eng "Restore failed to obtain the name locks on the tables."
ER_BACKUP_RELEASE_NAME_LOCK_FAILED
eng "Restore failed to release the name locks on the tables."
+# When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in
+# mysql_priv.h with the new maximal additional length for explain_filename.
+ER_DATABASE_NAME
+ eng "Database `%s`"
+ swe "Databas `%s`"
+ER_TABLE_NAME
+ eng "Table `%s`"
+ swe "Tabell `%s`"
+ER_PARTITION_NAME
+ eng "Partition `%s`"
+ swe "Partition `%s`"
+ER_SUBPARTITION_NAME
+ eng "Subpartition `%s`"
+ swe "Subpartition `%s`"
+ER_TEMPORARY_NAME
+ eng "Temporary"
+ swe "Temporär"
+ER_RENAMED_NAME
+ eng "Renamed"
+ swe "Namnändrad"
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2008-07-26 16:38:20 +0000
+++ b/sql/sql_table.cc 2008-09-03 20:07:50 +0000
@@ -68,6 +68,186 @@ static void wait_for_kill_signal(THD *th
#endif
+/**
+ @brief Helper function for explain_filename
+*/
+static char* add_identifier(char *to_p, const char * end_p,
+ const char* name, uint name_len, int errcode)
+{
+ uint res;
+ uint errors;
+ const char *conv_name;
+ char tmp_name[FN_REFLEN];
+ char conv_string[FN_REFLEN];
+
+ DBUG_ENTER("add_identifier");
+ if (!name[name_len])
+ conv_name= name;
+ else
+ {
+ strnmov(tmp_name, name, name_len);
+ tmp_name[name_len]= 0;
+ conv_name= tmp_name;
+ }
+ res= strconvert(&my_charset_filename, conv_name, system_charset_info,
+ conv_string, FN_REFLEN, &errors);
+ if (!res || errors)
+ conv_name= name;
+ else
+ {
+ DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
+ conv_name= conv_string;
+ }
+
+ to_p+= my_snprintf(to_p, end_p - to_p, ER(errcode), conv_name);
+ return to_p;
+}
+
+
+/**
+ @brief Explain a file name by split it to [database,]tablename[,partname...]
+
+ @details Break down the filename to its logic parts and add the partname
+ (database, table, partition, subpartition).
+ 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.
+
+ @param from The file name in my_charset_filename.
+ @param to The explained name in my_charset_filename.
+ @param to_length size of to buffer
+ @param lpt alter table data structure
+
+ @retval length of returned string
+*/
+
+uint explain_filename(const char *from, char *to, uint to_length)
+{
+ uint res= 0;
+ char *to_p= to;
+ char *end_p= to_p + to_length;
+ const char *db_name= NULL;
+ int db_name_len= 0;
+ const char *table_name;
+ int table_name_len= 0;
+ const char *part_name= NULL;
+ int part_name_len= 0;
+ const char *subpart_name= NULL;
+ int subpart_name_len= 0;
+ int temp_or_renamed= 0; /* 1= temp, 2= renamed */
+ const char *tmp_p;
+ DBUG_ENTER("explain_filename");
+ DBUG_PRINT("enter", ("from '%s'", from));
+ /*
+ if '/' then take last directory part as database
+ Compose the explained name as
+ [Database %s, ]Table %s[,[ Temporary| Renamed] Partition %s
+ [, Subpartition %s]]
+ */
+ tmp_p= from;
+ table_name= from;
+ while ((tmp_p= strchr(tmp_p, '/')))
+ {
+ db_name= table_name;
+ /* calculate the length */
+ db_name_len= tmp_p - db_name;
+ tmp_p++;
+ table_name= tmp_p;
+ }
+ tmp_p= table_name;
+ while (!res && (tmp_p= strchr(tmp_p, '#')))
+ {
+ tmp_p++;
+ switch (tmp_p[0]) {
+ case 'P':
+ case 'p':
+ if (tmp_p[1] == '#')
+ part_name= tmp_p + 2;
+ else
+ res= 1;
+ tmp_p+= 2;
+ break;
+ case 'S':
+ case 's':
+ if (tmp_p[2] == '#' && (tmp_p[1] == 'P' || tmp_p[1] == 'p'))
+ {
+ part_name_len= tmp_p - part_name - 1;
+ subpart_name= tmp_p + 3;
+ }
+ else
+ res= 2;
+ tmp_p+= 3;
+ break;
+ case 'T':
+ case 't':
+ if (tmp_p[3] == '#' && (tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
+ (tmp_p[1] == 'P' || tmp_p[1] == 'p') && !tmp_p[4])
+ temp_or_renamed= 1; /* 1= temp, 2= renamed */
+ else
+ res= 3;
+ tmp_p+= 4;
+ break;
+ case 'R':
+ case 'r':
+ if (tmp_p[3] == '#' && (tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
+ (tmp_p[1] == 'N' || tmp_p[1] == 'n') && !tmp_p[4])
+ temp_or_renamed= 2; /* 1= temp, 2= renamed */
+ else
+ res= 4;
+ tmp_p+= 4;
+ break;
+ default:
+ res= 5;
+ }
+ }
+ if (part_name)
+ {
+ table_name_len= part_name - table_name - 3;
+ if (subpart_name)
+ subpart_name_len= strlen(subpart_name);
+ else
+ part_name_len= strlen(part_name);
+ if (temp_or_renamed)
+ {
+ if (subpart_name)
+ subpart_name_len-= 5;
+ else
+ part_name_len-= 5;
+ }
+ }
+ if (db_name)
+ {
+ to_p= add_identifier(to_p, end_p, db_name, db_name_len,
+ ER_DATABASE_NAME);
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ }
+ to_p= add_identifier(to_p, end_p, table_name, table_name_len,
+ ER_TABLE_NAME);
+ if (part_name)
+ {
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ if (temp_or_renamed)
+ {
+ if (temp_or_renamed == 1)
+ to_p= strnmov(to_p, ER(ER_TEMPORARY_NAME), end_p - to_p);
+ else
+ to_p= strnmov(to_p, ER(ER_RENAMED_NAME), end_p - to_p);
+ to_p= strnmov(to_p, " ", end_p - to_p);
+ }
+ to_p= add_identifier(to_p, end_p, part_name, part_name_len,
+ ER_PARTITION_NAME);
+ if (subpart_name)
+ {
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len,
+ ER_SUBPARTITION_NAME);
+ }
+ }
+ DBUG_PRINT("exit", ("to '%s'", to));
+ DBUG_RETURN(to_p - to);
+}
+
+
/*
Translate a file name to a table name (WL #1324).
=== modified file 'storage/innobase/dict/dict0dict.c'
--- a/storage/innobase/dict/dict0dict.c 2008-06-12 00:08:07 +0000
+++ b/storage/innobase/dict/dict0dict.c 2008-09-03 20:07:50 +0000
@@ -4210,6 +4210,6 @@ dict_index_name_print(
{
fputs("index ", file);
ut_print_name(file, trx, FALSE, index->name);
- fputs(" of table ", file);
+ fputs(" in ", file);
ut_print_name(file, trx, TRUE, index->table_name);
}
=== 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-09-03 20:07:50 +0000
@@ -1271,14 +1271,14 @@ innobase_print_identifier(
int q;
if (table_id) {
- /* Decode the table name. The filename_to_tablename()
+ /* Decode the table name. The explain_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
characters than [0-9A-Z_a-z]. */
char* temp_name = (char*) my_malloc((uint) namelen + 1, MYF(MY_WME));
uint qnamelen = (uint) (namelen
- + (1 + sizeof srv_mysql50_table_name_prefix));
+ + (1 + EXPLAIN_FILENAME_MAX_EXTRA_LENGTH));
if (temp_name) {
qname = (char*) my_malloc(qnamelen, MYF(MY_WME));
@@ -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 = explain_filename(temp_name,
qname, qnamelen);
}
my_free(temp_name, MYF(0));
@@ -1301,7 +1301,7 @@ innobase_print_identifier(
s, (int) namelen);
}
- if (q == EOF) {
+ if (q == EOF || table_id) {
fwrite(s, 1, namelen, f);
} else {
const char* e = s + namelen;
=== modified file 'storage/innobase/ut/ut0ut.c'
--- a/storage/innobase/ut/ut0ut.c 2008-06-12 00:08:07 +0000
+++ b/storage/innobase/ut/ut0ut.c 2008-09-03 20:07:50 +0000
@@ -487,22 +487,7 @@ ut_print_namel(
#ifdef UNIV_HOTBACKUP
fwrite(name, 1, namelen, f);
#else
- if (table_id) {
- char* slash = memchr(name, '/', namelen);
- if (!slash) {
-
- goto no_db_name;
- }
-
- /* Print the database name and table name separately. */
- innobase_print_identifier(f, trx, TRUE, name, slash - name);
- putc('.', f);
- innobase_print_identifier(f, trx, TRUE, slash + 1,
- namelen - (slash - name) - 1);
- } else {
-no_db_name:
- innobase_print_identifier(f, trx, table_id, name, namelen);
- }
+ innobase_print_identifier(f, trx, table_id, name, namelen);
#endif
}