Using the sys.format_path() Function to Dynamically Replace a Subpath with its Equivalent System Variable in MySQL

In MySQL, the sys.format_path() function is a stored function in the sys schema. It accepts a path name, and returns the modified path name after replacing subpaths that match the values of certain system variables.

So we can use the function to dynamically replace part or all of our path with a system variable that matches that path segment.

These system variables are as follows:

datadir
tmpdir
slave_load_tmpdir
replica_load_tmpdir
innodb_data_home_dir
innodb_log_group_home_dir
innodb_undo_directory
basedir

So if the given path, or a segment of the given path, matches a path that’s stored in any of the above system variables, then sys.format_path() replaces it with the system variable. If it’s just a segment of the path that matches, then only that segment is replaced, and the rest of the path remains intact.

Syntax

The syntax goes like this:

sys.format_path(path)

Where path is a VARCHAR(512) that represents the path to format.

Example

Here’s an example to demonstrate:

SELECT sys.format_path(
    '/opt/homebrew/var/mysql/krankykranes/Products.ibd'
    );

Result:

@@datadir/krankykranes/Products.ibd

In this example, /opt/homebrew/var/mysql is my data directory. The reason the sys.format_path() function returned @@datadir is because that’s the name of a system variable that contains the data directory, which in my case is /opt/homebrew/var/mysql/.

In MySQL, the data directory stores information managed by the MySQL server. Each subdirectory of the data directory is a database directory and corresponds to a database managed by the server. In my case, krankykranes is one of many directories in the data directory. It was created when I created a database called krankykranes. This database has a table called Products, hence the Products.ibd part of the path.

We can find out where our data directory is located by returning the @@datadir in a SELECT statement:

SELECT @@datadir;

Result:

/opt/homebrew/var/mysql/

Here’s another example:

SELECT sys.format_path(
    '/opt/homebrew/Cellar/mysql/8.0.29/'
    );

Result:

@@basedir/

This time I passed a path that matches the base directory, and so MySQL replaced it with @@basedir/.

Let’s check the base directory:

SELECT @@basedir;

Result:

/opt/homebrew/Cellar/mysql/8.0.29/

Passing a Non-Existent Path

Here’s what happens when I pass a path that doesn’t exist:

SELECT sys.format_path(
    '/opt/homebrew/var/mysql/oops/Products.ibd'
    );

Result:

@@datadir/oops/Products.ibd

So it didn’t actually check whether or not the path exists (I don’t actually have a directory called oops).

Non-Matching Path

Here’s what happens when no part of the given path matches any of the system variables listed above:

SELECT sys.format_path(
    '/Users/Shared/bak/Solutions.bak'
    );

Result:

/Users/Shared/bak/Solutions.bak

So format_path() simply returned the full path unchanged.

Passing an Empty String

Passing an empty string simply returns an empty string without error:

SELECT sys.format_path( '' );

Result:

+-----------------------+
| sys.format_path( '' ) |
+-----------------------+
|                       |
+-----------------------+
1 row in set (0.00 sec)

Passing NULL

Passing NULL returns NULL:

SELECT sys.format_path( NULL );

Result:

+-------------------------+
| sys.format_path( NULL ) |
+-------------------------+
| NULL                    |
+-------------------------+
1 row in set (0.00 sec)

Omitting the Path

Omitting the path altogether (i.e. calling the function without an argument) results in an error:

SELECT sys.format_path( );

Result:

ERROR 1318 (42000): Incorrect number of arguments for FUNCTION sys.format_path; expected 1, got 0