From d6a213bcbf2c630f9000d14d2f23065d8017e6db Mon Sep 17 00:00:00 2001 From: Nishant Sharma Date: Wed, 5 Nov 2025 16:19:26 +0530 Subject: [PATCH v5 1/2] Supporting changes for pg_get_tablespace_ddl function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moving core logic of pg_tablespace_location() to new generic function get_tablespace_loc_string() Authors: Manni Wood and Nishant Sharma Reviewers: Vaibhav Dalvi, Ian Barwick, Jim Jones, Álvaro Herrera Discussion: https://www.postgresql.org/message-id/flat/CAKWEB6rmnmGKUA87Zmq-s=b3Scsnj02C0kObQjnbL2ajfPWGEw@mail.gmail.com --- src/backend/utils/adt/misc.c | 62 ++---------------------- src/backend/utils/adt/ruleutils.c | 79 +++++++++++++++++++++++++++++++ src/include/utils/ruleutils.h | 2 + 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index fa1cb675027..cb99d7435eb 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -315,66 +315,12 @@ Datum pg_tablespace_location(PG_FUNCTION_ARGS) { Oid tablespaceOid = PG_GETARG_OID(0); - char sourcepath[MAXPGPATH]; - char targetpath[MAXPGPATH]; - int rllen; - struct stat st; + char *tablespaceLoc; - /* - * It's useful to apply this function to pg_class.reltablespace, wherein - * zero means "the database's default tablespace". So, rather than - * throwing an error for zero, we choose to assume that's what is meant. - */ - if (tablespaceOid == InvalidOid) - tablespaceOid = MyDatabaseTableSpace; - - /* - * Return empty string for the cluster's default tablespaces - */ - if (tablespaceOid == DEFAULTTABLESPACE_OID || - tablespaceOid == GLOBALTABLESPACE_OID) - PG_RETURN_TEXT_P(cstring_to_text("")); - - /* - * Find the location of the tablespace by reading the symbolic link that - * is in pg_tblspc/. - */ - snprintf(sourcepath, sizeof(sourcepath), "%s/%u", PG_TBLSPC_DIR, 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. - */ - 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)); - - /* - * 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, - (errcode_for_file_access(), - errmsg("could not read symbolic link \"%s\": %m", - sourcepath))); - if (rllen >= sizeof(targetpath)) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("symbolic link \"%s\" target is too long", - sourcepath))); - targetpath[rllen] = '\0'; + /* Get LOCATION string from its OID */ + tablespaceLoc = get_tablespace_loc_string(tablespaceOid); - PG_RETURN_TEXT_P(cstring_to_text(targetpath)); + PG_RETURN_TEXT_P(cstring_to_text(tablespaceLoc)); } /* diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 5398679cce2..976a8345ce4 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "access/amapi.h" #include "access/htup_details.h" @@ -13742,3 +13743,81 @@ get_range_partbound_string(List *bound_datums) return buf->data; } + +/* + * get_tablespace_loc_string - get location for a tablespace in string. This is + * internal version which helps pg_tablespace_location() and others. + */ +char * +get_tablespace_loc_string(Oid tablespaceOid) +{ + char sourcepath[MAXPGPATH] = { '\0' }; + char targetpath[MAXPGPATH] = { '\0' }; + int rllen; + struct stat st; + StringInfoData buf; + + initStringInfo(&buf); + appendStringInfoString(&buf, ""); + + /* + * It's useful to apply this function to pg_class.reltablespace, wherein + * zero means "the database's default tablespace". So, rather than + * throwing an error for zero, we choose to assume that's what is meant. + */ + if (tablespaceOid == InvalidOid) + tablespaceOid = MyDatabaseTableSpace; + + /* + * Return empty string for the cluster's default tablespaces + */ + if (tablespaceOid == DEFAULTTABLESPACE_OID || + tablespaceOid == GLOBALTABLESPACE_OID) + return buf.data; + + /* + * Find the location of the tablespace by reading the symbolic link that + * is in pg_tblspc/. + */ + snprintf(sourcepath, sizeof(sourcepath), "%s/%u", PG_TBLSPC_DIR, 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. + */ + 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)) + { + appendStringInfoString(&buf, sourcepath); + return buf.data; + } + + /* + * 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, + (errcode_for_file_access(), + errmsg("could not read symbolic link \"%s\": %m", + sourcepath))); + if (rllen >= sizeof(targetpath)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("symbolic link \"%s\" target is too long", + sourcepath))); + targetpath[rllen] = '\0'; + + appendStringInfoString(&buf, targetpath); + + return buf.data; +} diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 7ba7d887914..6d74485f32a 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -54,4 +54,6 @@ extern char *get_range_partbound_string(List *bound_datums); extern char *pg_get_statisticsobjdef_string(Oid statextid); +extern char *get_tablespace_loc_string(Oid tablespaceOid); + #endif /* RULEUTILS_H */ -- 2.47.3