1/*
2 * tablespace.c
3 *
4 * tablespace functions
5 *
6 * Copyright (c) 2010-2019, PostgreSQL Global Development Group
7 * src/bin/pg_upgrade/tablespace.c
8 */
9
10#include "postgres_fe.h"
11
12#include "pg_upgrade.h"
13
14static void get_tablespace_paths(void);
15static void set_tablespace_directory_suffix(ClusterInfo *cluster);
16
17
18void
19init_tablespaces(void)
20{
21 get_tablespace_paths();
22
23 set_tablespace_directory_suffix(&old_cluster);
24 set_tablespace_directory_suffix(&new_cluster);
25
26 if (os_info.num_old_tablespaces > 0 &&
27 strcmp(old_cluster.tablespace_suffix, new_cluster.tablespace_suffix) == 0)
28 pg_fatal("Cannot upgrade to/from the same system catalog version when\n"
29 "using tablespaces.\n");
30}
31
32
33/*
34 * get_tablespace_paths()
35 *
36 * Scans pg_tablespace and returns a malloc'ed array of all tablespace
37 * paths. It's the caller's responsibility to free the array.
38 */
39static void
40get_tablespace_paths(void)
41{
42 PGconn *conn = connectToServer(&old_cluster, "template1");
43 PGresult *res;
44 int tblnum;
45 int i_spclocation;
46 char query[QUERY_ALLOC];
47
48 snprintf(query, sizeof(query),
49 "SELECT %s "
50 "FROM pg_catalog.pg_tablespace "
51 "WHERE spcname != 'pg_default' AND "
52 " spcname != 'pg_global'",
53 /* 9.2 removed the spclocation column */
54 (GET_MAJOR_VERSION(old_cluster.major_version) <= 901) ?
55 "spclocation" : "pg_catalog.pg_tablespace_location(oid) AS spclocation");
56
57 res = executeQueryOrDie(conn, "%s", query);
58
59 if ((os_info.num_old_tablespaces = PQntuples(res)) != 0)
60 os_info.old_tablespaces = (char **) pg_malloc(
61 os_info.num_old_tablespaces * sizeof(char *));
62 else
63 os_info.old_tablespaces = NULL;
64
65 i_spclocation = PQfnumber(res, "spclocation");
66
67 for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
68 {
69 struct stat statBuf;
70
71 os_info.old_tablespaces[tblnum] = pg_strdup(
72 PQgetvalue(res, tblnum, i_spclocation));
73
74 /*
75 * Check that the tablespace path exists and is a directory.
76 * Effectively, this is checking only for tables/indexes in
77 * non-existent tablespace directories. Databases located in
78 * non-existent tablespaces already throw a backend error.
79 * Non-existent tablespace directories can occur when a data directory
80 * that contains user tablespaces is moved as part of pg_upgrade
81 * preparation and the symbolic links are not updated.
82 */
83 if (stat(os_info.old_tablespaces[tblnum], &statBuf) != 0)
84 {
85 if (errno == ENOENT)
86 report_status(PG_FATAL,
87 "tablespace directory \"%s\" does not exist\n",
88 os_info.old_tablespaces[tblnum]);
89 else
90 report_status(PG_FATAL,
91 "could not stat tablespace directory \"%s\": %s\n",
92 os_info.old_tablespaces[tblnum], strerror(errno));
93 }
94 if (!S_ISDIR(statBuf.st_mode))
95 report_status(PG_FATAL,
96 "tablespace path \"%s\" is not a directory\n",
97 os_info.old_tablespaces[tblnum]);
98 }
99
100 PQclear(res);
101
102 PQfinish(conn);
103
104 return;
105}
106
107
108static void
109set_tablespace_directory_suffix(ClusterInfo *cluster)
110{
111 if (GET_MAJOR_VERSION(cluster->major_version) <= 804)
112 cluster->tablespace_suffix = pg_strdup("");
113 else
114 {
115 /* This cluster has a version-specific subdirectory */
116
117 /* The leading slash is needed to start a new directory. */
118 cluster->tablespace_suffix = psprintf("/PG_%s_%d",
119 cluster->major_version_str,
120 cluster->controldata.cat_ver);
121 }
122}
123