aboutsummaryrefslogtreecommitdiff
path: root/src/common/relpath.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2013-02-21 22:46:17 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2013-02-21 22:46:17 -0300
commita73018392636ce832b09b5c31f6ad1f18a4643ea (patch)
tree45ff73dc25699e9156147948e7f4ba2a85961a33 /src/common/relpath.c
parent6e3fd964632e95c7359457b7d67aa20c72a71679 (diff)
downloadpostgresql-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.c162
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;
+}
+