1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-15 03:41:20 +03:00

Split out innards of pg_tablespace_location()

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 <manni.wood@enterprisedb.com>
Author: Nishant Sharma <nishant.sharma@enterprisedb.com>
Reviewed-by: Vaibhav Dalvi <vaibhav.dalvi@enterprisedb.com>
Reviewed-by: Ian Lawrence Barwick <barwick@gmail.com>
Reviewed-by: Jim Jones <jim.jones@uni-muenster.de>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/CAKWEB6rmnmGKUA87Zmq-s=b3Scsnj02C0kObQjnbL2ajfPWGEw@mail.gmail.com
This commit is contained in:
Álvaro Herrera
2025-11-12 16:39:55 +01:00
parent a1f7f91be2
commit 877a024902
5 changed files with 98 additions and 58 deletions

View File

@@ -44,6 +44,7 @@ OBJS = \
pg_range.o \
pg_shdepend.o \
pg_subscription.o \
pg_tablespace.o \
pg_type.o \
storage.o \
toasting.o

View File

@@ -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',

View File

@@ -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 <unistd.h>
#include <sys/stat.h>
#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/<oid>.
*/
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);
}

View File

@@ -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/<oid>.
*/
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));
}
/*

View File

@@ -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 */