From f6f0db4d62400ff88f523dcc4d7e25f9506bc0d8 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 17 Mar 2022 11:25:02 +0900 Subject: [PATCH] Fix pg_tablespace_location() with in-place tablespaces Using this system function with an in-place tablespace (created when allow_in_place_tablespaces is enabled by specifying an empty string as location) caused a failure when using readlink(), as the tablespace is, in this case, not a symbolic link in pg_tblspc/ but a directory. Rather than getting a failure, the commit changes pg_tablespace_location() so as a relative path to the data directory is returned for in-place tablespaces, to make a difference between tablespaces created when allow_in_place_tablespaces is enabled or not. Getting a path rather than an empty string that would match the CREATE TABLESPACE command in this case is more useful for tests that would like to rely on this function. While on it, a regression test is added for this case. This is simple to add in the main regression test suite thanks to regexp_replace() to mask the part of the tablespace location dependent on its OID. Author: Michael Paquier Reviewed-by: Kyotaro Horiguchi, Thomas Munro Discussion: https://postgr.es/m/YiG1RleON1WBcLnX@paquier.xyz --- doc/src/sgml/func.sgml | 8 ++++++- src/backend/utils/adt/misc.c | 29 ++++++++++++++++++++++++ src/test/regress/expected/tablespace.out | 9 ++++++++ src/test/regress/sql/tablespace.sql | 4 ++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 8a802fb2253..89a5e17884c 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -23924,7 +23924,13 @@ SELECT currval(pg_get_serial_sequence('sometable', 'id')); Returns the file system path that this tablespace is located in. - + + + A relative path to the data directory is returned for tablespaces + created when is + enabled. + + diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 4568749d230..89690be2ed1 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -15,6 +15,7 @@ #include "postgres.h" #include +#include #include #include #include @@ -282,6 +283,9 @@ pg_tablespace_location(PG_FUNCTION_ARGS) char sourcepath[MAXPGPATH]; char targetpath[MAXPGPATH]; int rllen; +#ifndef WIN32 + struct stat st; +#endif /* * It's useful to apply this function to pg_class.reltablespace, wherein @@ -306,6 +310,31 @@ pg_tablespace_location(PG_FUNCTION_ARGS) */ snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid); + /* + * Before reading the link, check if the source path is a link or a + * junction point. Note that a directory is possible for a tablespace + * created with allow_in_place_tablespaces enabled. If a directory is + * found, a relative path to the data directory is returned. + */ +#ifdef WIN32 + if (!pgwin32_is_junction(sourcepath)) + PG_RETURN_TEXT_P(cstring_to_text(sourcepath)); +#else + if (lstat(sourcepath, &st) < 0) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", + sourcepath))); + } + + if (!S_ISLNK(st.st_mode)) + PG_RETURN_TEXT_P(cstring_to_text(sourcepath)); +#endif + + /* + * In presence of a link or a junction point, return the path pointing to. + */ rllen = readlink(sourcepath, targetpath, sizeof(targetpath)); if (rllen < 0) ereport(ERROR, diff --git a/src/test/regress/expected/tablespace.out b/src/test/regress/expected/tablespace.out index 2dfbcfdebe1..473fe8c28e0 100644 --- a/src/test/regress/expected/tablespace.out +++ b/src/test/regress/expected/tablespace.out @@ -24,6 +24,15 @@ SELECT spcoptions FROM pg_tablespace WHERE spcname = 'regress_tblspacewith'; DROP TABLESPACE regress_tblspacewith; -- create a tablespace we can use CREATE TABLESPACE regress_tblspace LOCATION ''; +-- This returns a relative path as of an effect of allow_in_place_tablespaces, +-- masking the tablespace OID used in the path name. +SELECT regexp_replace(pg_tablespace_location(oid), '(pg_tblspc)/(\d+)', '\1/NNN') + FROM pg_tablespace WHERE spcname = 'regress_tblspace'; + regexp_replace +---------------- + pg_tblspc/NNN +(1 row) + -- try setting and resetting some properties for the new tablespace ALTER TABLESPACE regress_tblspace SET (random_page_cost = 1.0, seq_page_cost = 1.1); ALTER TABLESPACE regress_tblspace SET (some_nonexistent_parameter = true); -- fail diff --git a/src/test/regress/sql/tablespace.sql b/src/test/regress/sql/tablespace.sql index 896f05cea32..0949a28488d 100644 --- a/src/test/regress/sql/tablespace.sql +++ b/src/test/regress/sql/tablespace.sql @@ -22,6 +22,10 @@ DROP TABLESPACE regress_tblspacewith; -- create a tablespace we can use CREATE TABLESPACE regress_tblspace LOCATION ''; +-- This returns a relative path as of an effect of allow_in_place_tablespaces, +-- masking the tablespace OID used in the path name. +SELECT regexp_replace(pg_tablespace_location(oid), '(pg_tblspc)/(\d+)', '\1/NNN') + FROM pg_tablespace WHERE spcname = 'regress_tblspace'; -- try setting and resetting some properties for the new tablespace ALTER TABLESPACE regress_tblspace SET (random_page_cost = 1.0, seq_page_cost = 1.1); -- 2.30.2