Skip to content

Commit c1315d0

Browse files
author
Rahul Agarkar
committed
Bug#29492113 TABLE NOT ACCESSIBLE AFTER MOVING THE IBD FILE, WHEN THE
DATABASE NAME HAS "/" The problems happen because of incorrect parsing of dbname and tablename if they have a "/" in their names. The server considers them as directory separator and not part of the name itself. This leads to situations where incorrect strings are considered as dbname or filename leading to multiple issues. Solution: The dbname and filename are correctly parsed when converted to the filesystem charset. However, in some cases, the name strings were in the tablespace charset leading to the problems. The solution is to use these names consistently in filesystem charset and convert them to the tablespace charset as and when needed. RB# 21921 Reviewer: Kevin Lewis ([email protected])
1 parent 03a00da commit c1315d0

File tree

5 files changed

+353
-9
lines changed

5 files changed

+353
-9
lines changed

mysql-test/suite/innodb/r/innodb_tablespace.result

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,94 @@ FLUSH TABLES t1 FOR EXPORT;
635635
ERROR HY000: Tablespace has been discarded for table 't1'
636636
UNLOCK TABLES;
637637
DROP TABLE t1;
638+
#
639+
# Bug#29492113 TABLE NOT ACCESSIBLE AFTER MOVING THE IBD FILE,
640+
# WHEN THE DATABASE NAME HAS "/"
641+
#
642+
#
643+
# Scenario-1
644+
# create database `abc/def`
645+
# create table `abc/def`.`xyz/123` in MYSQL_TMP_DIR/my_dir1
646+
# The directory structure after creating the table should be
647+
# MYSQL_TMP_DIR/my_dir1/abc@002fdef/[email protected]
648+
#
649+
CREATE DATABASE `abc/def`;
650+
CREATE TABLE `abc/def`.`xyz/123` (c1 INT) DATA DIRECTORY 'MYSQL_TMP_DIR/my_dir1';
651+
SHOW WARNINGS;
652+
Level Code Message
653+
#
654+
# Validate the directory structure
655+
#
656+
abc@002fdef
657+
658+
INSERT INTO `abc/def`.`xyz/123` VALUES (1), (2), (3);
659+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
660+
COUNT(*)
661+
3
662+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
663+
FILE_NAME TABLESPACE_NAME
664+
MYSQL_TMP_DIR/my_dir1/abc@002fdef/[email protected] abc/def/xyz/123
665+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
666+
name space_type
667+
abc/def/xyz/123 Single
668+
#
669+
# Shutdown the server
670+
#
671+
#
672+
# Scenario-2
673+
# Move the IBD file from MYSQL_TMP_DIR/my_dir1 to MYSQL_TMP_DIR/my_dir2
674+
# Restart the server with --innodb_directories MYSQL_TMP_DIR/my_dir2
675+
# Query the table
676+
# Restart the server without --innodb_directories option
677+
#
678+
#
679+
# Move IBD file in MYSQL_TMP_DIR/my_dir1 to MYSQL_TMP_DIR/my_dir2
680+
#
681+
#
682+
# Resart server with --innodb_directories MYSQL_TMP_DIR/my_dir2
683+
#
684+
# restart: --innodb_directories=MYSQL_TMP_DIR/my_dir2
685+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
686+
COUNT(*)
687+
3
688+
#
689+
# Restart server without --innodb_directories option
690+
#
691+
# restart:
692+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
693+
COUNT(*)
694+
3
695+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
696+
FILE_NAME TABLESPACE_NAME
697+
MYSQL_TMP_DIR/my_dir2/abc@002fdef/[email protected] abc/def/xyz/123
698+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
699+
name space_type
700+
abc/def/xyz/123 Single
701+
#
702+
# Shutdown server
703+
#
704+
#
705+
# Scenario-3
706+
# Move the IBD file from MYSQL_TMP_DIR/my_dir2 to MYSQL_TMP_DIR/my_dir1
707+
# Restart the server with --innodb_directories MYSQL_TMP_DIR/my_dir1
708+
#
709+
#
710+
# Move IBD file from MYSQL_TMP_DIR/my_dir2 to MYSQL_TMP_DIR/my_dir1
711+
#
712+
#
713+
# Restart server with --innodb_directories MYSQL_TMP_DIR/my_dir1
714+
#
715+
# restart: --innodb_directories=MYSQL_TMP_DIR/my_dir1
716+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
717+
COUNT(*)
718+
3
719+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
720+
FILE_NAME TABLESPACE_NAME
721+
MYSQL_TMP_DIR/my_dir1/abc@002fdef/[email protected] abc/def/xyz/123
722+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
723+
name space_type
724+
abc/def/xyz/123 Single
725+
#
726+
# Cleanup
727+
#
728+
DROP DATABASE `abc/def`;

mysql-test/suite/innodb/t/innodb_tablespace.test

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,114 @@ ALTER TABLE t1 DISCARD TABLESPACE;
437437
FLUSH TABLES t1 FOR EXPORT;
438438
UNLOCK TABLES;
439439
DROP TABLE t1;
440+
441+
--echo #
442+
--echo # Bug#29492113 TABLE NOT ACCESSIBLE AFTER MOVING THE IBD FILE,
443+
--echo # WHEN THE DATABASE NAME HAS "/"
444+
--echo #
445+
446+
--echo #
447+
--echo # Scenario-1
448+
--echo # create database `abc/def`
449+
--echo # create table `abc/def`.`xyz/123` in MYSQL_TMP_DIR/my_dir1
450+
--echo # The directory structure after creating the table should be
451+
--echo # MYSQL_TMP_DIR/my_dir1/abc@002fdef/[email protected]
452+
--echo #
453+
454+
CREATE DATABASE `abc/def`;
455+
456+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
457+
eval CREATE TABLE `abc/def`.`xyz/123` (c1 INT) DATA DIRECTORY '$MYSQL_TMP_DIR/my_dir1';
458+
SHOW WARNINGS;
459+
460+
--echo #
461+
--echo # Validate the directory structure
462+
--echo #
463+
--list_files $MYSQL_TMP_DIR/my_dir1 *
464+
--list_files $MYSQL_TMP_DIR/my_dir1/abc@002fdef *
465+
466+
INSERT INTO `abc/def`.`xyz/123` VALUES (1), (2), (3);
467+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
468+
469+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
470+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
471+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
472+
473+
--echo #
474+
--echo # Shutdown the server
475+
--echo #
476+
--source include/shutdown_mysqld.inc
477+
478+
--echo #
479+
--echo # Scenario-2
480+
--echo # Move the IBD file from MYSQL_TMP_DIR/my_dir1 to MYSQL_TMP_DIR/my_dir2
481+
--echo # Restart the server with --innodb_directories MYSQL_TMP_DIR/my_dir2
482+
--echo # Query the table
483+
--echo # Restart the server without --innodb_directories option
484+
--echo #
485+
486+
--echo #
487+
--echo # Move IBD file in MYSQL_TMP_DIR/my_dir1 to MYSQL_TMP_DIR/my_dir2
488+
--echo #
489+
--mkdir $MYSQL_TMP_DIR/my_dir2
490+
--mkdir $MYSQL_TMP_DIR/my_dir2/abc@002fdef
491+
--copy_files_wildcard $MYSQL_TMP_DIR/my_dir1/abc@002fdef/ $MYSQL_TMP_DIR/my_dir2/abc@002fdef/ *
492+
--remove_files_wildcard $MYSQL_TMP_DIR/my_dir1/abc@002fdef/ *
493+
494+
--echo #
495+
--echo # Resart server with --innodb_directories MYSQL_TMP_DIR/my_dir2
496+
--echo #
497+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
498+
--let $restart_parameters = "restart: --innodb_directories=$MYSQL_TMP_DIR/my_dir2"
499+
--source include/start_mysqld.inc
500+
501+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
502+
503+
--echo #
504+
--echo # Restart server without --innodb_directories option
505+
--echo #
506+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
507+
--let $restart_parameters = "restart:"
508+
--source include/restart_mysqld.inc
509+
510+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
511+
512+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
513+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
514+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
515+
516+
--echo #
517+
--echo # Shutdown server
518+
--echo #
519+
--source include/shutdown_mysqld.inc
520+
521+
--echo #
522+
--echo # Scenario-3
523+
--echo # Move the IBD file from MYSQL_TMP_DIR/my_dir2 to MYSQL_TMP_DIR/my_dir1
524+
--echo # Restart the server with --innodb_directories MYSQL_TMP_DIR/my_dir1
525+
--echo #
526+
527+
--echo #
528+
--echo # Move IBD file from MYSQL_TMP_DIR/my_dir2 to MYSQL_TMP_DIR/my_dir1
529+
--echo #
530+
--copy_files_wildcard $MYSQL_TMP_DIR/my_dir2/abc@002fdef/ $MYSQL_TMP_DIR/my_dir1/abc@002fdef/ *
531+
--force-rmdir $MYSQL_TMP_DIR/my_dir2
532+
533+
--echo #
534+
--echo # Restart server with --innodb_directories MYSQL_TMP_DIR/my_dir1
535+
--echo #
536+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
537+
--let $restart_parameters="restart: --innodb_directories=$MYSQL_TMP_DIR/my_dir1"
538+
--source include/start_mysqld.inc
539+
540+
SELECT COUNT(*) FROM `abc/def`.`xyz/123`;
541+
542+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
543+
SELECT file_name, tablespace_name FROM information_schema.files WHERE file_name LIKE '%123%';
544+
SELECT name, space_type FROM information_schema.innodb_tablespaces WHERE name LIKE '%123%';
545+
546+
--echo #
547+
--echo # Cleanup
548+
--echo #
549+
DROP DATABASE `abc/def`;
550+
--force-rmdir $MYSQL_TMP_DIR/my_dir1

sql/sql_parse.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6517,23 +6517,30 @@ bool prepare_index_and_data_dir_path(THD *thd, const char **data_file_name,
65176517

65186518
int append_file_to_dir(THD *thd, const char **filename_ptr,
65196519
const char *table_name) {
6520-
char buff[FN_REFLEN], *ptr, *end;
6520+
char tbbuff[FN_REFLEN];
6521+
char buff[FN_REFLEN];
6522+
char *ptr;
6523+
char *end;
6524+
65216525
if (!*filename_ptr) return 0; // nothing to do
65226526

6527+
/* Convert tablename to filename charset so that "/" gets converted
6528+
appropriately */
6529+
size_t tab_len = tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
6530+
65236531
/* Check that the filename is not too long and it's a hard path */
6524-
if (strlen(*filename_ptr) + strlen(table_name) >= FN_REFLEN - 1)
6525-
return ER_PATH_LENGTH;
6532+
if (strlen(*filename_ptr) + tab_len >= FN_REFLEN - 1) return ER_PATH_LENGTH;
65266533

65276534
if (!test_if_hard_path(*filename_ptr)) return ER_WRONG_VALUE;
65286535

65296536
/* Fix is using unix filename format on dos */
65306537
my_stpcpy(buff, *filename_ptr);
65316538
end = convert_dirname(buff, *filename_ptr, NullS);
6532-
if (!(ptr =
6533-
(char *)thd->alloc((size_t)(end - buff) + strlen(table_name) + 1)))
6534-
return ER_OUTOFMEMORY; // End of memory
6539+
6540+
ptr = (char *)thd->alloc((size_t)(end - buff) + tab_len + 1);
6541+
if (ptr == nullptr) return ER_OUTOFMEMORY; // End of memory
65356542
*filename_ptr = ptr;
6536-
strxmov(ptr, buff, table_name, NullS);
6543+
strxmov(ptr, buff, tbbuff, NullS);
65376544
return 0;
65386545
}
65396546

storage/innobase/dict/dict0dd.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3790,7 +3790,7 @@ void dd_load_tablespace(const Table *dd_table, dict_table_t *table,
37903790
is in the DD even if the datafile was moved. So let's use
37913791
that path to open this tablespace. */
37923792
mutex_exit(&dict_sys->mutex);
3793-
char *filepath = dd_get_first_path(heap, table, dd_table);
3793+
filepath = dd_get_first_path(heap, table, dd_table);
37943794
mutex_enter(&dict_sys->mutex);
37953795

37963796
if (filepath == nullptr) {

0 commit comments

Comments
 (0)