Skip to content
This repository was archived by the owner on Aug 28, 2024. It is now read-only.

Commit a825399

Browse files
committed
Bug #21512106 FORMAT_PATH() DOES NOT CONSIDER DIRECTORY BOUNDARIES
Properly check directory boundaries on all variables now. If the variable does not include a path separator at the end of it, add one for comparison. NOTE: This stops the case of converting Windows paths to /, and now correctly shows \ for Windows hosts. Also added replacement for the basedir variable, and added a proper unit test that validates all variables are parsed correctly (though this requires disabling the test on Windows, as the path separator is now correctly shown as \ on that host too now).
1 parent 0715a36 commit a825399

File tree

6 files changed

+107
-50
lines changed

6 files changed

+107
-50
lines changed

functions/format_path.sql

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
1+
-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
22
--
33
-- This program is free software; you can redistribute it and/or modify
44
-- it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ DROP FUNCTION IF EXISTS format_path;
1818
DELIMITER $$
1919

2020
CREATE DEFINER='root'@'localhost' FUNCTION format_path (
21-
path VARCHAR(512)
21+
in_path VARCHAR(512)
2222
)
2323
RETURNS VARCHAR(512) CHARSET UTF8
2424
COMMENT '
@@ -68,30 +68,41 @@ BEGIN
6868
DECLARE v_path VARCHAR(512);
6969
DECLARE v_undo_dir VARCHAR(1024);
7070

71+
DECLARE path_separator CHAR(1) DEFAULT '/';
72+
73+
IF @@global.version_compile_os LIKE 'win%' THEN
74+
SET path_separator = '\\';
75+
END IF;
76+
7177
-- OSX hides /private/ in variables, but Performance Schema does not
72-
IF path LIKE '/private/%'
73-
THEN SET v_path = REPLACE(path, '/private', '');
74-
ELSE SET v_path = path;
78+
IF in_path LIKE '/private/%' THEN
79+
SET v_path = REPLACE(in_path, '/private', '');
80+
ELSE
81+
SET v_path = in_path;
7582
END IF;
7683

7784
-- @@global.innodb_undo_directory is only set when separate undo logs are used
78-
SET v_undo_dir = IFNULL((SELECT VARIABLE_NAME FROM information_schema.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'innodb_undo_directory'), '');
79-
80-
IF v_path IS NULL THEN RETURN NULL;
81-
ELSEIF v_path LIKE CONCAT(@@global.datadir, '%') ESCAPE '|' THEN
82-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.datadir, '@@datadir/'), '\\\\', ''), '\\', '/');
83-
ELSEIF v_path LIKE CONCAT(@@global.tmpdir, '%') ESCAPE '|' THEN
84-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.tmpdir, '@@tmpdir/'), '\\\\', ''), '\\', '/');
85-
ELSEIF v_path LIKE CONCAT(@@global.slave_load_tmpdir, '%') ESCAPE '|' THEN
86-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.slave_load_tmpdir, '@@slave_load_tmpdir/'), '\\\\', ''), '\\', '/');
87-
ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, '%') ESCAPE '|' THEN
88-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.innodb_data_home_dir, '@@innodb_data_home_dir/'), '\\\\', ''), '\\', '/');
89-
ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, '%') ESCAPE '|' THEN
90-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.innodb_log_group_home_dir, '@@innodb_log_group_home_dir/'), '\\\\', ''), '\\', '/');
91-
ELSEIF v_path LIKE CONCAT(v_undo_dir, '%') ESCAPE '|' THEN
92-
RETURN REPLACE(REPLACE(REPLACE(v_path, v_undo_dir, '@@innodb_undo_directory/'), '\\\\', ''), '\\', '/');
93-
ELSE RETURN v_path;
85+
SET v_undo_dir = IFNULL((SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'innodb_undo_directory'), '');
86+
87+
IF v_path IS NULL THEN
88+
RETURN NULL;
89+
ELSEIF v_path LIKE CONCAT(@@global.datadir, IF(SUBSTRING(@@global.datadir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
90+
SET v_path = REPLACE(v_path, @@global.datadir, CONCAT('@@datadir', IF(SUBSTRING(@@global.datadir, -1) = path_separator, path_separator, '')));
91+
ELSEIF v_path LIKE CONCAT(@@global.tmpdir, IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
92+
SET v_path = REPLACE(v_path, @@global.tmpdir, CONCAT('@@tmpdir', IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, path_separator, '')));
93+
ELSEIF v_path LIKE CONCAT(@@global.slave_load_tmpdir, IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
94+
SET v_path = REPLACE(v_path, @@global.slave_load_tmpdir, CONCAT('@@slave_load_tmpdir', IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, path_separator, '')));
95+
ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
96+
SET v_path = REPLACE(v_path, @@global.innodb_data_home_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, path_separator, '')));
97+
ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
98+
SET v_path = REPLACE(v_path, @@global.innodb_log_group_home_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, path_separator, '')));
99+
ELSEIF v_path LIKE CONCAT(v_undo_dir, IF(SUBSTRING(v_undo_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
100+
SET v_path = REPLACE(v_path, v_undo_dir, CONCAT('@@innodb_undo_directory', IF(SUBSTRING(v_undo_dir, -1) = path_separator, path_separator, '')));
101+
ELSEIF v_path LIKE CONCAT(@@global.basedir, IF(SUBSTRING(@@global.basedir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
102+
SET v_path = REPLACE(v_path, @@global.basedir, CONCAT('@@basedir', IF(SUBSTRING(@@global.basedir, -1) = path_separator, path_separator, '')));
94103
END IF;
104+
105+
RETURN v_path;
95106
END$$
96107

97108
DELIMITER ;

functions/format_path_57.sql

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
1+
-- Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
22
--
33
-- This program is free software; you can redistribute it and/or modify
44
-- it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ DROP FUNCTION IF EXISTS format_path;
1818
DELIMITER $$
1919

2020
CREATE DEFINER='root'@'localhost' FUNCTION format_path (
21-
path VARCHAR(512)
21+
in_path VARCHAR(512)
2222
)
2323
RETURNS VARCHAR(512) CHARSET UTF8
2424
COMMENT '
@@ -68,30 +68,41 @@ BEGIN
6868
DECLARE v_path VARCHAR(512);
6969
DECLARE v_undo_dir VARCHAR(1024);
7070

71+
DECLARE path_separator CHAR(1) DEFAULT '/';
72+
73+
IF @@global.version_compile_os LIKE 'win%' THEN
74+
SET path_separator = '\\';
75+
END IF;
76+
7177
-- OSX hides /private/ in variables, but Performance Schema does not
72-
IF path LIKE '/private/%'
73-
THEN SET v_path = REPLACE(path, '/private', '');
74-
ELSE SET v_path = path;
78+
IF in_path LIKE '/private/%' THEN
79+
SET v_path = REPLACE(in_path, '/private', '');
80+
ELSE
81+
SET v_path = in_path;
7582
END IF;
7683

7784
-- @@global.innodb_undo_directory is only set when separate undo logs are used
78-
SET v_undo_dir = IFNULL((SELECT VARIABLE_NAME FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'innodb_undo_directory'), '');
79-
80-
IF v_path IS NULL THEN RETURN NULL;
81-
ELSEIF v_path LIKE CONCAT(@@global.datadir, '%') ESCAPE '|' THEN
82-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.datadir, '@@datadir/'), '\\\\', ''), '\\', '/');
83-
ELSEIF v_path LIKE CONCAT(@@global.tmpdir, '%') ESCAPE '|' THEN
84-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.tmpdir, '@@tmpdir/'), '\\\\', ''), '\\', '/');
85-
ELSEIF v_path LIKE CONCAT(@@global.slave_load_tmpdir, '%') ESCAPE '|' THEN
86-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.slave_load_tmpdir, '@@slave_load_tmpdir/'), '\\\\', ''), '\\', '/');
87-
ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, '%') ESCAPE '|' THEN
88-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.innodb_data_home_dir, '@@innodb_data_home_dir/'), '\\\\', ''), '\\', '/');
89-
ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, '%') ESCAPE '|' THEN
90-
RETURN REPLACE(REPLACE(REPLACE(v_path, @@global.innodb_log_group_home_dir, '@@innodb_log_group_home_dir/'), '\\\\', ''), '\\', '/');
91-
ELSEIF v_path LIKE CONCAT(v_undo_dir, '%') ESCAPE '|' THEN
92-
RETURN REPLACE(REPLACE(REPLACE(v_path, v_undo_dir, '@@innodb_undo_directory/'), '\\\\', ''), '\\', '/');
93-
ELSE RETURN v_path;
85+
SET v_undo_dir = IFNULL((SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'innodb_undo_directory'), '');
86+
87+
IF v_path IS NULL THEN
88+
RETURN NULL;
89+
ELSEIF v_path LIKE CONCAT(@@global.datadir, IF(SUBSTRING(@@global.datadir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
90+
SET v_path = REPLACE(v_path, @@global.datadir, CONCAT('@@datadir', IF(SUBSTRING(@@global.datadir, -1) = path_separator, path_separator, '')));
91+
ELSEIF v_path LIKE CONCAT(@@global.tmpdir, IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
92+
SET v_path = REPLACE(v_path, @@global.tmpdir, CONCAT('@@tmpdir', IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, path_separator, '')));
93+
ELSEIF v_path LIKE CONCAT(@@global.slave_load_tmpdir, IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
94+
SET v_path = REPLACE(v_path, @@global.slave_load_tmpdir, CONCAT('@@slave_load_tmpdir', IF(SUBSTRING(@@global.slave_load_tmpdir, -1) = path_separator, path_separator, '')));
95+
ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
96+
SET v_path = REPLACE(v_path, @@global.innodb_data_home_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, path_separator, '')));
97+
ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
98+
SET v_path = REPLACE(v_path, @@global.innodb_log_group_home_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, path_separator, '')));
99+
ELSEIF v_path LIKE CONCAT(v_undo_dir, IF(SUBSTRING(v_undo_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
100+
SET v_path = REPLACE(v_path, v_undo_dir, CONCAT('@@innodb_undo_directory', IF(SUBSTRING(v_undo_dir, -1) = path_separator, path_separator, '')));
101+
ELSEIF v_path LIKE CONCAT(@@global.basedir, IF(SUBSTRING(@@global.basedir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN
102+
SET v_path = REPLACE(v_path, @@global.basedir, CONCAT('@@basedir', IF(SUBSTRING(@@global.basedir, -1) = path_separator, path_separator, '')));
94103
END IF;
104+
105+
RETURN v_path;
95106
END$$
96107

97108
DELIMITER ;
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
SELECT sys.format_path(NULL);
22
sys.format_path(NULL)
33
NULL
4+
SET @mypath := CONCAT(@@global.basedir, '/logs/binlog.000001');
5+
SELECT sys.format_path(@mypath);
6+
sys.format_path(@mypath)
7+
@@basedir/logs/binlog.000001
48
SET @mypath := CONCAT(@@global.datadir, 'foo/bar.foo');
59
SELECT sys.format_path(@mypath);
610
sys.format_path(@mypath)
711
@@datadir/foo/bar.foo
8-
SET @mypath := CONCAT(@@global.tmpdir, 'foo/bar.foo');
12+
SET @mypath := CONCAT(@@global.tmpdir, '/foo/bar.foo');
913
SELECT sys.format_path(@mypath);
1014
sys.format_path(@mypath)
1115
@@tmpdir/foo/bar.foo
12-
SET @mypath := CONCAT(@@global.innodb_log_group_home_dir, 'foo/bar.foo');
16+
SET @mypath := CONCAT(@@global.innodb_data_home_dir, '/foo/bar.ibd');
17+
SELECT sys.format_path(@mypath);
18+
sys.format_path(@mypath)
19+
@@innodb_data_home_dir/foo/bar.ibd
20+
SET @mypath := CONCAT(@@global.innodb_log_group_home_dir, '/ib_logfile0');
21+
SELECT sys.format_path(@mypath);
22+
sys.format_path(@mypath)
23+
@@innodb_log_group_home_dir/ib_logfile0
24+
SET @mypath := CONCAT(@@global.innodb_undo_directory, '/undo0');
1325
SELECT sys.format_path(@mypath);
1426
sys.format_path(@mypath)
15-
@@innodb_log_group_home_dir/foo/bar.foo
27+
@@innodb_undo_directory/undo0
1628
SELECT sys.format_path('/foo/bar/baz.foo');
1729
sys.format_path('/foo/bar/baz.foo')
1830
/foo/bar/baz.foo
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb_data_home_dir=$MYSQLTEST_VARDIR/tmp/innodb --innodb_log_group_home_dir=$MYSQLTEST_VARDIR/tmp/innodb_logs --innodb_undo_directory=$MYSQLTEST_VARDIR/tmp/innodb_undo
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
mkdir $MYSQLTEST_VARDIR/tmp/innodb
4+
cp $MYSQLTEST_VARDIR/install.db/ibdata1 $MYSQLTEST_VARDIR/tmp/innodb
5+
cp $MYSQLTEST_VARDIR/install.db/ib_buffer_pool $MYSQLTEST_VARDIR/tmp/innodb
6+
mkdir $MYSQLTEST_VARDIR/tmp/innodb_logs
7+
cp $MYSQLTEST_VARDIR/install.db/ib_logfile* $MYSQLTEST_VARDIR/tmp/innodb_logs
8+
mkdir $MYSQLTEST_VARDIR/tmp/innodb_undo

mysql-test/suite/sysschema/t/fn_format_path.test

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,40 @@
11
-- source include/not_embedded.inc
2+
# Windows paths are \ not /, so ignore here
3+
-- source include/not_windows.inc
24
# Tests for sys schema
35
# Verify the sys.format_path() function perfoms as expected
46
#
5-
# Note, innodb_data_home_dir replacement is not tested,
6-
# as this is not set by default
7-
#
87

98
# Passing NULL should return NULL
109
SELECT sys.format_path(NULL);
1110

11+
# Ensure basedir is recognized and stripped
12+
SET @mypath := CONCAT(@@global.basedir, '/logs/binlog.000001');
13+
14+
SELECT sys.format_path(@mypath);
15+
1216
# Ensure datadir is recognized and stripped
1317
SET @mypath := CONCAT(@@global.datadir, 'foo/bar.foo');
1418

1519
SELECT sys.format_path(@mypath);
1620

1721
# Ensure tmpdir is recognized and stripped
18-
SET @mypath := CONCAT(@@global.tmpdir, 'foo/bar.foo');
22+
SET @mypath := CONCAT(@@global.tmpdir, '/foo/bar.foo');
23+
24+
SELECT sys.format_path(@mypath);
25+
26+
# Ensure innodb_data_home_dir is recognized and stripped
27+
SET @mypath := CONCAT(@@global.innodb_data_home_dir, '/foo/bar.ibd');
1928

2029
SELECT sys.format_path(@mypath);
2130

2231
# Ensure innodb_log_group_home_dir is recognized and stripped
23-
SET @mypath := CONCAT(@@global.innodb_log_group_home_dir, 'foo/bar.foo');
32+
SET @mypath := CONCAT(@@global.innodb_log_group_home_dir, '/ib_logfile0');
33+
34+
SELECT sys.format_path(@mypath);
35+
36+
# Ensure innodb_undo_directory is recognized and stripped
37+
SET @mypath := CONCAT(@@global.innodb_undo_directory, '/undo0');
2438

2539
SELECT sys.format_path(@mypath);
2640

0 commit comments

Comments
 (0)