diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2013-02-21 22:46:17 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2013-02-21 22:46:17 -0300 |
commit | a73018392636ce832b09b5c31f6ad1f18a4643ea (patch) | |
tree | 45ff73dc25699e9156147948e7f4ba2a85961a33 /src/common/relpath.c | |
parent | 6e3fd964632e95c7359457b7d67aa20c72a71679 (diff) | |
download | postgresql-a73018392636ce832b09b5c31f6ad1f18a4643ea.tar.gz postgresql-a73018392636ce832b09b5c31f6ad1f18a4643ea.zip |
Move relpath() to libpgcommon
This enables non-backend code, such as pg_xlogdump, to use it easily.
The previous location, in src/backend/catalog/catalog.c, made that
essentially impossible because that file depends on many backend-only
facilities; so this needs to live separately.
Diffstat (limited to 'src/common/relpath.c')
-rw-r--r-- | src/common/relpath.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/common/relpath.c b/src/common/relpath.c new file mode 100644 index 00000000000..18fe4d1fe36 --- /dev/null +++ b/src/common/relpath.c @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------- + * relpath.c + * Shared frontend/backend code to find out pathnames of relation files + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/relpath.c + * + *------------------------------------------------------------------------- + */ +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "catalog/pg_tablespace.h" +#include "common/relpath.h" +#include "storage/backendid.h" + +#define FORKNAMECHARS 4 /* max chars for a fork name */ + +/* + * Lookup table of fork name by fork number. + * + * If you add a new entry, remember to update the errhint below, and the + * documentation for pg_relation_size(). Also keep FORKNAMECHARS above + * up-to-date. + */ +const char *forkNames[] = { + "main", /* MAIN_FORKNUM */ + "fsm", /* FSM_FORKNUM */ + "vm", /* VISIBILITYMAP_FORKNUM */ + "init" /* INIT_FORKNUM */ +}; + +/* + * forkname_chars + * We use this to figure out whether a filename could be a relation + * fork (as opposed to an oddly named stray file that somehow ended + * up in the database directory). If the passed string begins with + * a fork name (other than the main fork name), we return its length, + * and set *fork (if not NULL) to the fork number. If not, we return 0. + * + * Note that the present coding assumes that there are no fork names which + * are prefixes of other fork names. + */ +int +forkname_chars(const char *str, ForkNumber *fork) +{ + ForkNumber forkNum; + + for (forkNum = 1; forkNum <= MAX_FORKNUM; forkNum++) + { + int len = strlen(forkNames[forkNum]); + + if (strncmp(forkNames[forkNum], str, len) == 0) + { + if (fork) + *fork = forkNum; + return len; + } + } + return 0; +} + +/* + * relpathbackend - construct path to a relation's file + * + * Result is a palloc'd string. + */ +char * +relpathbackend(RelFileNode rnode, BackendId backend, ForkNumber forknum) +{ + int pathlen; + char *path; + + if (rnode.spcNode == GLOBALTABLESPACE_OID) + { + /* Shared system relations live in {datadir}/global */ + Assert(rnode.dbNode == 0); + Assert(backend == InvalidBackendId); + pathlen = 7 + OIDCHARS + 1 + FORKNAMECHARS + 1; + path = (char *) palloc(pathlen); + if (forknum != MAIN_FORKNUM) + snprintf(path, pathlen, "global/%u_%s", + rnode.relNode, forkNames[forknum]); + else + snprintf(path, pathlen, "global/%u", rnode.relNode); + } + else if (rnode.spcNode == DEFAULTTABLESPACE_OID) + { + /* The default tablespace is {datadir}/base */ + if (backend == InvalidBackendId) + { + pathlen = 5 + OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1; + path = (char *) palloc(pathlen); + if (forknum != MAIN_FORKNUM) + snprintf(path, pathlen, "base/%u/%u_%s", + rnode.dbNode, rnode.relNode, + forkNames[forknum]); + else + snprintf(path, pathlen, "base/%u/%u", + rnode.dbNode, rnode.relNode); + } + else + { + /* OIDCHARS will suffice for an integer, too */ + pathlen = 5 + OIDCHARS + 2 + OIDCHARS + 1 + OIDCHARS + 1 + + FORKNAMECHARS + 1; + path = (char *) palloc(pathlen); + if (forknum != MAIN_FORKNUM) + snprintf(path, pathlen, "base/%u/t%d_%u_%s", + rnode.dbNode, backend, rnode.relNode, + forkNames[forknum]); + else + snprintf(path, pathlen, "base/%u/t%d_%u", + rnode.dbNode, backend, rnode.relNode); + } + } + else + { + /* All other tablespaces are accessed via symlinks */ + if (backend == InvalidBackendId) + { + pathlen = 9 + 1 + OIDCHARS + 1 + + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 1 + + OIDCHARS + 1 + FORKNAMECHARS + 1; + path = (char *) palloc(pathlen); + if (forknum != MAIN_FORKNUM) + snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/%u_%s", + rnode.spcNode, TABLESPACE_VERSION_DIRECTORY, + rnode.dbNode, rnode.relNode, + forkNames[forknum]); + else + snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/%u", + rnode.spcNode, TABLESPACE_VERSION_DIRECTORY, + rnode.dbNode, rnode.relNode); + } + else + { + /* OIDCHARS will suffice for an integer, too */ + pathlen = 9 + 1 + OIDCHARS + 1 + + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 + OIDCHARS + 2 + + OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1; + path = (char *) palloc(pathlen); + if (forknum != MAIN_FORKNUM) + snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/t%d_%u_%s", + rnode.spcNode, TABLESPACE_VERSION_DIRECTORY, + rnode.dbNode, backend, rnode.relNode, + forkNames[forknum]); + else + snprintf(path, pathlen, "pg_tblspc/%u/%s/%u/t%d_%u", + rnode.spcNode, TABLESPACE_VERSION_DIRECTORY, + rnode.dbNode, backend, rnode.relNode); + } + } + return path; +} + |