Bug #23926 Symlinked data directory - fails to create table with same DATA DIRECTORY
Submitted: 3 Nov 2006 9:51 Modified: 15 Jul 2008 0:35
Reporter: Magnus Blåudd Email Updates:
Status: Won't fix Impact on me:
None 
Category:MySQL Server: General Severity:S3 (Non-critical)
Version:4.1.23 OS:Any (powergmacg5)
Assigned to: CPU Architecture:Any

[3 Nov 2006 9:51] Magnus Blåudd
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.
[15 Jul 2008 0:35] Trudy Pelzer
Won't be fixed in extended maintenance version.