Description:
If mysqld is run with data directory in a symlinked dir, the creation of a table with DATA DIRECTORY set to the synlink dir will fail.
This occurs as the symlink name is canonicalized with my_realpath and that will "expand" the symlinkname to the physical name.
How to repeat:
ln -s var var7
cd var/master-data
mysqld &
mysql> create table t1 (i int) data directory = "<full_path>/var/master-data/test/"
failed: 25: Can't create symlink './test/t1.MYD' pointing at '/Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/master-data/test/t1.MYD' (Error 17)
Or, much more easy:
./mysql-test-run.pl --do-test=symlink --var=var7
<snip>
symlink                        [ fail ]
Errors are (from /Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/log/mysqltest-time) :
mysqltest: At line 126: query 'create table t1 (i int) data directory = "$MYSQL_TEST_DIR/var/master-data/test/"' failed: 25: Can't create symlink './test/t1.MYD' pointing at '/Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/master-data/test/t1.MYD' (Error 17)
(the last lines may be the most important ones)
Result from queries before failure can be found in r/symlink.log
Stopping All Servers
Restoring snapshot of databases
Resuming Tests
The above way to test works only in 4.1, in higher versions the --var switch will no create a symlink but pass the path directly to mysqld.
Suggested fix:
===== my_symlink2.c 1.8 vs edited =====
--- 1.8/mysys/my_symlink2.c     2006-11-03 10:43:54 +01:00
+++ edited/my_symlink2.c        2006-11-03 10:43:10 +01:00
@@ -32,7 +32,7 @@ File my_create_with_symlink(const char *
   int tmp_errno;
   /* Test if we should create a link */
   int create_link;
-  char abs_linkname[FN_REFLEN];
+  char abs_linkname[FN_REFLEN], abs_filename[FN_REFLEN];
   DBUG_ENTER("my_create_with_symlink");
 
   if (my_disable_symlinks)
@@ -45,8 +45,11 @@ File my_create_with_symlink(const char *
   else
   {
     if (linkname)
+    {
       my_realpath(abs_linkname, linkname, MYF(0));
-    create_link= (linkname && strcmp(abs_linkname,filename));
+      my_realpath(abs_filename, filename, MYF(0));
+    }
+    create_link= (linkname && strcmp(abs_linkname, abs_filename));
   }
 
   if (!(MyFlags & MY_DELETE_OLD))
But maybe there is a nicer way to do this that doesn't relies so heavily on realpath. I would suggest some new function like "my_same_path" that traverse the to links from bottom and exits as soon as a different path part is found.
  
 
 
Description: If mysqld is run with data directory in a symlinked dir, the creation of a table with DATA DIRECTORY set to the synlink dir will fail. This occurs as the symlink name is canonicalized with my_realpath and that will "expand" the symlinkname to the physical name. How to repeat: ln -s var var7 cd var/master-data mysqld & mysql> create table t1 (i int) data directory = "<full_path>/var/master-data/test/" failed: 25: Can't create symlink './test/t1.MYD' pointing at '/Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/master-data/test/t1.MYD' (Error 17) Or, much more easy: ./mysql-test-run.pl --do-test=symlink --var=var7 <snip> symlink [ fail ] Errors are (from /Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/log/mysqltest-time) : mysqltest: At line 126: query 'create table t1 (i int) data directory = "$MYSQL_TEST_DIR/var/master-data/test/"' failed: 25: Can't create symlink './test/t1.MYD' pointing at '/Users/henry/pb/mysql-4.1-maint/66/mysql-4.1.23-pb66/mysql-test/var/master-data/test/t1.MYD' (Error 17) (the last lines may be the most important ones) Result from queries before failure can be found in r/symlink.log Stopping All Servers Restoring snapshot of databases Resuming Tests The above way to test works only in 4.1, in higher versions the --var switch will no create a symlink but pass the path directly to mysqld. Suggested fix: ===== my_symlink2.c 1.8 vs edited ===== --- 1.8/mysys/my_symlink2.c 2006-11-03 10:43:54 +01:00 +++ edited/my_symlink2.c 2006-11-03 10:43:10 +01:00 @@ -32,7 +32,7 @@ File my_create_with_symlink(const char * int tmp_errno; /* Test if we should create a link */ int create_link; - char abs_linkname[FN_REFLEN]; + char abs_linkname[FN_REFLEN], abs_filename[FN_REFLEN]; DBUG_ENTER("my_create_with_symlink"); if (my_disable_symlinks) @@ -45,8 +45,11 @@ File my_create_with_symlink(const char * else { if (linkname) + { my_realpath(abs_linkname, linkname, MYF(0)); - create_link= (linkname && strcmp(abs_linkname,filename)); + my_realpath(abs_filename, filename, MYF(0)); + } + create_link= (linkname && strcmp(abs_linkname, abs_filename)); } if (!(MyFlags & MY_DELETE_OLD)) But maybe there is a nicer way to do this that doesn't relies so heavily on realpath. I would suggest some new function like "my_same_path" that traverse the to links from bottom and exits as soon as a different path part is found.