From 877a024902a73732d9f976804aee9699dcbe1d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Herrera?= Date: Wed, 12 Nov 2025 16:39:55 +0100 Subject: [PATCH] Split out innards of pg_tablespace_location() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This creates a src/backend/catalog/pg_tablespace.c supporting file containing a new function get_tablespace_location(), which lets the code underlying pg_tablespace_location() be reused for other purposes. Author: Manni Wood Author: Nishant Sharma Reviewed-by: Vaibhav Dalvi Reviewed-by: Ian Lawrence Barwick Reviewed-by: Jim Jones Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/CAKWEB6rmnmGKUA87Zmq-s=b3Scsnj02C0kObQjnbL2ajfPWGEw@mail.gmail.com --- src/backend/catalog/Makefile | 1 + src/backend/catalog/meson.build | 1 + src/backend/catalog/pg_tablespace.c | 90 +++++++++++++++++++++++++++++ src/backend/utils/adt/misc.c | 62 ++------------------ src/include/catalog/pg_tablespace.h | 2 + 5 files changed, 98 insertions(+), 58 deletions(-) create mode 100644 src/backend/catalog/pg_tablespace.c diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index c090094ed08..8e40e1b8189 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -44,6 +44,7 @@ OBJS = \ pg_range.o \ pg_shdepend.o \ pg_subscription.o \ + pg_tablespace.o \ pg_type.o \ storage.o \ toasting.o diff --git a/src/backend/catalog/meson.build b/src/backend/catalog/meson.build index 1958ea9238a..58674ffeee6 100644 --- a/src/backend/catalog/meson.build +++ b/src/backend/catalog/meson.build @@ -31,6 +31,7 @@ backend_sources += files( 'pg_range.c', 'pg_shdepend.c', 'pg_subscription.c', + 'pg_tablespace.c', 'pg_type.c', 'storage.c', 'toasting.c', diff --git a/src/backend/catalog/pg_tablespace.c b/src/backend/catalog/pg_tablespace.c new file mode 100644 index 00000000000..6aca24c231e --- /dev/null +++ b/src/backend/catalog/pg_tablespace.c @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * pg_tablespace.c + * routines to support manipulation of the pg_tablespace relation + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/catalog/pg_tablespace.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include + +#include "catalog/pg_tablespace.h" +#include "commands/tablespace.h" +#include "miscadmin.h" + + +/* + * get_tablespace_location + * Get a tablespace's location as a C-string, by its OID + */ +char * +get_tablespace_location(Oid tablespaceOid) +{ + char sourcepath[MAXPGPATH]; + char targetpath[MAXPGPATH]; + int rllen; + struct stat st; + + /* + * It's useful to apply this 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 pstrdup(""); + + /* + * 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)) + return pstrdup(sourcepath); + + /* + * In presence of a link or a junction point, return the path pointed 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'; + + return pstrdup(targetpath); +} diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index fa1cb675027..a365c432d34 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; + /* Get LOCATION string from its OID */ + tablespaceLoc = get_tablespace_location(tablespaceOid); - /* - * 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'; - - PG_RETURN_TEXT_P(cstring_to_text(targetpath)); + PG_RETURN_TEXT_P(cstring_to_text(tablespaceLoc)); } /* diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h index 5293488c630..7816d779d8c 100644 --- a/src/include/catalog/pg_tablespace.h +++ b/src/include/catalog/pg_tablespace.h @@ -54,4 +54,6 @@ DECLARE_UNIQUE_INDEX(pg_tablespace_spcname_index, 2698, TablespaceNameIndexId, p MAKE_SYSCACHE(TABLESPACEOID, pg_tablespace_oid_index, 4); +extern char *get_tablespace_location(Oid tablespaceOid); + #endif /* PG_TABLESPACE_H */