Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * controldata.c
3 : : *
4 : : * controldata functions
5 : : *
6 : : * Copyright (c) 2010-2026, PostgreSQL Global Development Group
7 : : * src/bin/pg_upgrade/controldata.c
8 : : */
9 : :
10 : : #include "postgres_fe.h"
11 : :
12 : : #include <ctype.h>
13 : : #include <limits.h> /* for CHAR_MIN */
14 : :
15 : : #include "access/xlog_internal.h"
16 : : #include "common/string.h"
17 : : #include "pg_upgrade.h"
18 : : #include "storage/checksum.h"
19 : :
20 : :
21 : : /*
22 : : * get_control_data()
23 : : *
24 : : * gets pg_control information in "ctrl". Assumes that bindir and
25 : : * datadir are valid absolute paths to postgresql bin and pgdata
26 : : * directories respectively *and* pg_resetwal is version compatible
27 : : * with datadir. The main purpose of this function is to get pg_control
28 : : * data in a version independent manner.
29 : : *
30 : : * The approach taken here is to invoke pg_resetwal with -n option
31 : : * and then pipe its output. With little string parsing we get the
32 : : * pg_control data. pg_resetwal cannot be run while the server is running
33 : : * so we use pg_controldata; pg_controldata doesn't provide all the fields
34 : : * we need to actually perform the upgrade, but it provides enough for
35 : : * check mode. We do not implement pg_resetwal -n because it is hard to
36 : : * return valid xid data for a running server.
37 : : */
38 : : void
729 nathan@postgresql.or 39 :CBC 36 : get_control_data(ClusterInfo *cluster)
40 : : {
41 : : char cmd[MAXPGPATH];
42 : : char bufin[MAX_STRING];
43 : : FILE *output;
44 : : char *p;
5918 bruce@momjian.us 45 : 36 : bool got_xid = false;
46 : 36 : bool got_oid = false;
4931 alvherre@alvh.no-ip. 47 : 36 : bool got_multi = false;
48 : 36 : bool got_oldestmulti = false;
1825 bruce@momjian.us 49 : 36 : bool got_oldestxid = false;
3938 50 : 36 : bool got_mxoff = false;
51 : 36 : bool got_nextxlogfile = false;
52 : 36 : bool got_float8_pass_by_value = false;
5918 53 : 36 : bool got_align = false;
54 : 36 : bool got_blocksz = false;
55 : 36 : bool got_largesz = false;
56 : 36 : bool got_walsz = false;
57 : 36 : bool got_walseg = false;
58 : 36 : bool got_ident = false;
59 : 36 : bool got_index = false;
60 : 36 : bool got_toast = false;
4336 61 : 36 : bool got_large_object = false;
5918 62 : 36 : bool got_date_is_int = false;
4834 simon@2ndQuadrant.co 63 : 36 : bool got_data_checksum_version = false;
2919 bruce@momjian.us 64 : 36 : bool got_cluster_state = false;
519 msawada@postgresql.o 65 : 36 : bool got_default_char_signedness = false;
5800 bruce@momjian.us 66 : 36 : char *lc_collate = NULL;
67 : 36 : char *lc_ctype = NULL;
68 : 36 : char *lc_monetary = NULL;
69 : 36 : char *lc_numeric = NULL;
70 : 36 : char *lc_time = NULL;
5918 71 : 36 : char *lang = NULL;
5800 72 : 36 : char *language = NULL;
73 : 36 : char *lc_all = NULL;
74 : 36 : char *lc_messages = NULL;
75 : : int rc;
729 nathan@postgresql.or 76 [ + + - + ]: 36 : bool live_check = (cluster == &old_cluster && user_opts.live_check);
77 : :
78 : : /*
79 : : * Because we test the pg_resetwal output as strings, it has to be in
80 : : * English. Copied from pg_regress.c.
81 : : */
5800 bruce@momjian.us 82 [ - + ]: 36 : if (getenv("LC_COLLATE"))
5758 bruce@momjian.us 83 :UBC 0 : lc_collate = pg_strdup(getenv("LC_COLLATE"));
5800 bruce@momjian.us 84 [ - + ]:CBC 36 : if (getenv("LC_CTYPE"))
5758 bruce@momjian.us 85 :UBC 0 : lc_ctype = pg_strdup(getenv("LC_CTYPE"));
5800 bruce@momjian.us 86 [ - + ]:CBC 36 : if (getenv("LC_MONETARY"))
5758 bruce@momjian.us 87 :UBC 0 : lc_monetary = pg_strdup(getenv("LC_MONETARY"));
5800 bruce@momjian.us 88 [ + - ]:CBC 36 : if (getenv("LC_NUMERIC"))
5758 89 : 36 : lc_numeric = pg_strdup(getenv("LC_NUMERIC"));
5800 90 [ - + ]: 36 : if (getenv("LC_TIME"))
5758 bruce@momjian.us 91 :UBC 0 : lc_time = pg_strdup(getenv("LC_TIME"));
5918 bruce@momjian.us 92 [ + - ]:CBC 36 : if (getenv("LANG"))
5758 93 : 36 : lang = pg_strdup(getenv("LANG"));
5800 94 [ - + ]: 36 : if (getenv("LANGUAGE"))
5758 bruce@momjian.us 95 :UBC 0 : language = pg_strdup(getenv("LANGUAGE"));
5800 bruce@momjian.us 96 [ - + ]:CBC 36 : if (getenv("LC_ALL"))
5758 bruce@momjian.us 97 :UBC 0 : lc_all = pg_strdup(getenv("LC_ALL"));
5800 bruce@momjian.us 98 [ + - ]:CBC 36 : if (getenv("LC_MESSAGES"))
5758 99 : 36 : lc_messages = pg_strdup(getenv("LC_MESSAGES"));
100 : :
2033 tgl@sss.pgh.pa.us 101 : 36 : unsetenv("LC_COLLATE");
102 : 36 : unsetenv("LC_CTYPE");
103 : 36 : unsetenv("LC_MONETARY");
104 : 36 : unsetenv("LC_NUMERIC");
105 : 36 : unsetenv("LC_TIME");
106 : : #ifndef WIN32
107 : 36 : unsetenv("LANG");
108 : : #else
109 : : /* On Windows the default locale may not be English, so force it */
110 : : setenv("LANG", "en", 1);
111 : : #endif
112 : 36 : unsetenv("LANGUAGE");
113 : 36 : unsetenv("LC_ALL");
114 : 36 : setenv("LC_MESSAGES", "C", 1);
115 : :
116 : : /*
117 : : * Check for clean shutdown
118 : : */
2916 bruce@momjian.us 119 [ - + - - ]: 36 : if (!live_check || cluster == &new_cluster)
120 : : {
121 : : /* only pg_controldata outputs the cluster state */
122 : 36 : snprintf(cmd, sizeof(cmd), "\"%s/pg_controldata\" \"%s\"",
123 : : cluster->bindir, cluster->pgdata);
1426 tgl@sss.pgh.pa.us 124 : 36 : fflush(NULL);
125 : :
2916 bruce@momjian.us 126 [ - + ]: 36 : if ((output = popen(cmd, "r")) == NULL)
865 michael@paquier.xyz 127 :UBC 0 : pg_fatal("could not get control data using %s: %m", cmd);
128 : :
129 : : /* we have the result of cmd in "output". so parse it line by line now */
2916 bruce@momjian.us 130 [ + + ]:CBC 2016 : while (fgets(bufin, sizeof(bufin), output))
131 : : {
132 [ + + ]: 1944 : if ((p = strstr(bufin, "Database cluster state:")) != NULL)
133 : : {
134 : 36 : p = strchr(p, ':');
135 : :
136 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 137 :UBC 0 : pg_fatal("%d: database cluster state problem", __LINE__);
138 : :
2621 tgl@sss.pgh.pa.us 139 :CBC 36 : p++; /* remove ':' char */
140 : :
141 : : /*
142 : : * We checked earlier for a postmaster lock file, and if we
143 : : * found one, we tried to start/stop the server to replay the
144 : : * WAL. However, pg_ctl -m immediate doesn't leave a lock
145 : : * file, but does require WAL replay, so we check here that
146 : : * the server was shut down cleanly, from the controldata
147 : : * perspective.
148 : : */
149 : : /* Remove trailing newline and leading spaces */
1101 dgustafsson@postgres 150 : 36 : (void) pg_strip_crlf(p);
2916 bruce@momjian.us 151 [ + + ]: 576 : while (*p == ' ')
152 : 540 : p++;
1101 dgustafsson@postgres 153 [ - + ]: 36 : if (strcmp(p, "shut down in recovery") == 0)
154 : : {
2899 bruce@momjian.us 155 [ # # ]:UBC 0 : if (cluster == &old_cluster)
1474 tgl@sss.pgh.pa.us 156 : 0 : pg_fatal("The source cluster was shut down while in recovery mode. To upgrade, use \"rsync\" as documented or shut it down as a primary.");
157 : : else
158 : 0 : pg_fatal("The target cluster was shut down while in recovery mode. To upgrade, use \"rsync\" as documented or shut it down as a primary.");
159 : : }
1101 dgustafsson@postgres 160 [ - + ]:CBC 36 : else if (strcmp(p, "shut down") != 0)
161 : : {
2916 bruce@momjian.us 162 [ # # ]:UBC 0 : if (cluster == &old_cluster)
1101 dgustafsson@postgres 163 : 0 : pg_fatal("The source cluster was not shut down cleanly, state reported as: \"%s\"", p);
164 : : else
165 : 0 : pg_fatal("The target cluster was not shut down cleanly, state reported as: \"%s\"", p);
166 : : }
2916 bruce@momjian.us 167 :CBC 36 : got_cluster_state = true;
168 : : }
169 : : }
170 : :
1348 peter@eisentraut.org 171 : 36 : rc = pclose(output);
172 [ - + ]: 36 : if (rc != 0)
1348 peter@eisentraut.org 173 :UBC 0 : pg_fatal("could not get control data using %s: %s",
174 : : cmd, wait_result_to_str(rc));
175 : :
2916 bruce@momjian.us 176 [ - + ]:CBC 36 : if (!got_cluster_state)
177 : : {
2916 bruce@momjian.us 178 [ # # ]:UBC 0 : if (cluster == &old_cluster)
1474 tgl@sss.pgh.pa.us 179 : 0 : pg_fatal("The source cluster lacks cluster state information:");
180 : : else
181 : 0 : pg_fatal("The target cluster lacks cluster state information:");
182 : : }
183 : : }
184 : :
4464 heikki.linnakangas@i 185 [ - + ]:CBC 36 : snprintf(cmd, sizeof(cmd), "\"%s/%s \"%s\"",
186 : : cluster->bindir,
187 : : live_check ? "pg_controldata\"" : "pg_resetwal\" -n",
188 : : cluster->pgdata);
1426 tgl@sss.pgh.pa.us 189 : 36 : fflush(NULL);
190 : :
5918 bruce@momjian.us 191 [ - + ]: 36 : if ((output = popen(cmd, "r")) == NULL)
865 michael@paquier.xyz 192 :UBC 0 : pg_fatal("could not get control data using %s: %m", cmd);
193 : :
194 : : /* we have the result of cmd in "output". so parse it line by line now */
5918 bruce@momjian.us 195 [ + + ]:CBC 1368 : while (fgets(bufin, sizeof(bufin), output))
196 : : {
197 : : /* In verbose mode, log each line */
1474 tgl@sss.pgh.pa.us 198 : 1332 : pg_strip_crlf(bufin);
5248 bruce@momjian.us 199 : 1332 : pg_log(PG_VERBOSE, "%s", bufin);
200 : :
5918 201 [ + + ]: 1332 : if ((p = strstr(bufin, "pg_control version number:")) != NULL)
202 : : {
203 : 36 : p = strchr(p, ':');
204 : :
205 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 206 :UBC 0 : pg_fatal("%d: pg_resetwal problem", __LINE__);
207 : :
4335 bruce@momjian.us 208 :CBC 36 : p++; /* remove ':' char */
5779 209 : 36 : cluster->controldata.ctrl_ver = str2uint(p);
210 : : }
5918 211 [ + + ]: 1296 : else if ((p = strstr(bufin, "Catalog version number:")) != NULL)
212 : : {
213 : 36 : p = strchr(p, ':');
214 : :
215 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 216 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
217 : :
4335 bruce@momjian.us 218 :CBC 36 : p++; /* remove ':' char */
5779 219 : 36 : cluster->controldata.cat_ver = str2uint(p);
220 : : }
5918 221 [ + + ]: 1260 : else if ((p = strstr(bufin, "Latest checkpoint's NextXID:")) != NULL)
222 : : {
4341 223 : 36 : p = strchr(p, ':');
224 : :
225 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 226 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
227 : :
4335 bruce@momjian.us 228 :CBC 36 : p++; /* remove ':' char */
4341 229 : 36 : cluster->controldata.chkpnt_nxtepoch = str2uint(p);
230 : :
23 nathan@postgresql.or 231 :GNC 36 : p = strchr(p, ':');
232 : :
4341 bruce@momjian.us 233 [ + - - + ]:CBC 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 234 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
235 : :
23 nathan@postgresql.or 236 :GNC 36 : p++; /* remove ':' char */
4341 bruce@momjian.us 237 :CBC 36 : cluster->controldata.chkpnt_nxtxid = str2uint(p);
5918 238 : 36 : got_xid = true;
239 : : }
240 [ + + ]: 1224 : else if ((p = strstr(bufin, "Latest checkpoint's NextOID:")) != NULL)
241 : : {
242 : 36 : p = strchr(p, ':');
243 : :
244 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 245 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
246 : :
4335 bruce@momjian.us 247 :CBC 36 : p++; /* remove ':' char */
5779 248 : 36 : cluster->controldata.chkpnt_nxtoid = str2uint(p);
5918 249 : 36 : got_oid = true;
250 : : }
4931 alvherre@alvh.no-ip. 251 [ + + ]: 1188 : else if ((p = strstr(bufin, "Latest checkpoint's NextMultiXactId:")) != NULL)
252 : : {
253 : 36 : p = strchr(p, ':');
254 : :
255 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 256 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
257 : :
4335 bruce@momjian.us 258 :CBC 36 : p++; /* remove ':' char */
4931 alvherre@alvh.no-ip. 259 : 36 : cluster->controldata.chkpnt_nxtmulti = str2uint(p);
260 : 36 : got_multi = true;
261 : : }
1825 bruce@momjian.us 262 [ + + ]: 1152 : else if ((p = strstr(bufin, "Latest checkpoint's oldestXID:")) != NULL)
263 : : {
264 : 36 : p = strchr(p, ':');
265 : :
266 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 267 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
268 : :
1825 bruce@momjian.us 269 :CBC 36 : p++; /* remove ':' char */
270 : 36 : cluster->controldata.chkpnt_oldstxid = str2uint(p);
271 : 36 : got_oldestxid = true;
272 : : }
4931 alvherre@alvh.no-ip. 273 [ + + ]: 1116 : else if ((p = strstr(bufin, "Latest checkpoint's oldestMultiXid:")) != NULL)
274 : : {
275 : 36 : p = strchr(p, ':');
276 : :
277 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 278 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
279 : :
4335 bruce@momjian.us 280 :CBC 36 : p++; /* remove ':' char */
4931 alvherre@alvh.no-ip. 281 : 36 : cluster->controldata.chkpnt_oldstMulti = str2uint(p);
282 : 36 : got_oldestmulti = true;
283 : : }
284 [ + + ]: 1080 : else if ((p = strstr(bufin, "Latest checkpoint's NextMultiOffset:")) != NULL)
285 : : {
286 : 36 : p = strchr(p, ':');
287 : :
288 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 289 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
290 : :
4335 bruce@momjian.us 291 :CBC 36 : p++; /* remove ':' char */
4931 alvherre@alvh.no-ip. 292 : 36 : cluster->controldata.chkpnt_nxtmxoff = str2uint(p);
293 : 36 : got_mxoff = true;
294 : : }
1409 tgl@sss.pgh.pa.us 295 [ + + ]: 1044 : else if ((p = strstr(bufin, "First log segment after reset:")) != NULL)
296 : : {
297 : : /* Skip the colon and any whitespace after it */
4090 bruce@momjian.us 298 : 36 : p = strchr(p, ':');
299 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 300 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
95 michael@paquier.xyz 301 :CBC 36 : p = strpbrk(p, "0123456789ABCDEF");
4090 bruce@momjian.us 302 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 303 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
304 : :
305 : : /* Make sure it looks like a valid WAL file name */
4090 bruce@momjian.us 306 [ - + ]:CBC 36 : if (strspn(p, "0123456789ABCDEF") != 24)
1474 tgl@sss.pgh.pa.us 307 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
308 : :
4090 bruce@momjian.us 309 :CBC 36 : strlcpy(cluster->controldata.nextxlogfile, p, 25);
310 : 36 : got_nextxlogfile = true;
311 : : }
3938 312 [ + + ]: 1008 : else if ((p = strstr(bufin, "Float8 argument passing:")) != NULL)
313 : : {
314 : 36 : p = strchr(p, ':');
315 : :
316 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 317 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
318 : :
3938 bruce@momjian.us 319 :CBC 36 : p++; /* remove ':' char */
320 : : /* used later for contrib check */
321 : 36 : cluster->controldata.float8_pass_by_value = strstr(p, "by value") != NULL;
322 : 36 : got_float8_pass_by_value = true;
323 : : }
5918 324 [ + + ]: 972 : else if ((p = strstr(bufin, "Maximum data alignment:")) != NULL)
325 : : {
326 : 36 : p = strchr(p, ':');
327 : :
328 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 329 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
330 : :
4335 bruce@momjian.us 331 :CBC 36 : p++; /* remove ':' char */
5779 332 : 36 : cluster->controldata.align = str2uint(p);
5918 333 : 36 : got_align = true;
334 : : }
335 [ + + ]: 936 : else if ((p = strstr(bufin, "Database block size:")) != NULL)
336 : : {
337 : 36 : p = strchr(p, ':');
338 : :
339 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 340 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
341 : :
4335 bruce@momjian.us 342 :CBC 36 : p++; /* remove ':' char */
5779 343 : 36 : cluster->controldata.blocksz = str2uint(p);
5918 344 : 36 : got_blocksz = true;
345 : : }
346 [ + + ]: 900 : else if ((p = strstr(bufin, "Blocks per segment of large relation:")) != NULL)
347 : : {
348 : 36 : p = strchr(p, ':');
349 : :
350 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 351 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
352 : :
4335 bruce@momjian.us 353 :CBC 36 : p++; /* remove ':' char */
5779 354 : 36 : cluster->controldata.largesz = str2uint(p);
5918 355 : 36 : got_largesz = true;
356 : : }
357 [ + + ]: 864 : else if ((p = strstr(bufin, "WAL block size:")) != NULL)
358 : : {
359 : 36 : p = strchr(p, ':');
360 : :
361 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 362 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
363 : :
4335 bruce@momjian.us 364 :CBC 36 : p++; /* remove ':' char */
5779 365 : 36 : cluster->controldata.walsz = str2uint(p);
5918 366 : 36 : got_walsz = true;
367 : : }
368 [ + + ]: 828 : else if ((p = strstr(bufin, "Bytes per WAL segment:")) != NULL)
369 : : {
370 : 36 : p = strchr(p, ':');
371 : :
372 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 373 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
374 : :
4335 bruce@momjian.us 375 :CBC 36 : p++; /* remove ':' char */
5779 376 : 36 : cluster->controldata.walseg = str2uint(p);
5918 377 : 36 : got_walseg = true;
378 : : }
379 [ + + ]: 792 : else if ((p = strstr(bufin, "Maximum length of identifiers:")) != NULL)
380 : : {
381 : 36 : p = strchr(p, ':');
382 : :
383 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 384 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
385 : :
4335 bruce@momjian.us 386 :CBC 36 : p++; /* remove ':' char */
5779 387 : 36 : cluster->controldata.ident = str2uint(p);
5918 388 : 36 : got_ident = true;
389 : : }
390 [ + + ]: 756 : else if ((p = strstr(bufin, "Maximum columns in an index:")) != NULL)
391 : : {
392 : 36 : p = strchr(p, ':');
393 : :
394 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 395 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
396 : :
4335 bruce@momjian.us 397 :CBC 36 : p++; /* remove ':' char */
5779 398 : 36 : cluster->controldata.index = str2uint(p);
5918 399 : 36 : got_index = true;
400 : : }
401 [ + + ]: 720 : else if ((p = strstr(bufin, "Maximum size of a TOAST chunk:")) != NULL)
402 : : {
403 : 36 : p = strchr(p, ':');
404 : :
405 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 406 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
407 : :
4335 bruce@momjian.us 408 :CBC 36 : p++; /* remove ':' char */
5779 409 : 36 : cluster->controldata.toast = str2uint(p);
5918 410 : 36 : got_toast = true;
411 : : }
4336 412 [ + + ]: 684 : else if ((p = strstr(bufin, "Size of a large-object chunk:")) != NULL)
413 : : {
414 : 36 : p = strchr(p, ':');
415 : :
416 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 417 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
418 : :
4335 bruce@momjian.us 419 :CBC 36 : p++; /* remove ':' char */
4336 420 : 36 : cluster->controldata.large_object = str2uint(p);
421 : 36 : got_large_object = true;
422 : : }
5918 423 [ + + ]: 648 : else if ((p = strstr(bufin, "Date/time type storage:")) != NULL)
424 : : {
425 : 36 : p = strchr(p, ':');
426 : :
427 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 428 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
429 : :
4335 bruce@momjian.us 430 :CBC 36 : p++; /* remove ':' char */
5918 431 : 36 : cluster->controldata.date_is_int = strstr(p, "64-bit integers") != NULL;
432 : 36 : got_date_is_int = true;
433 : : }
4834 simon@2ndQuadrant.co 434 [ + + ]: 612 : else if ((p = strstr(bufin, "checksum")) != NULL)
435 : : {
4873 436 : 36 : p = strchr(p, ':');
437 : :
438 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
1474 tgl@sss.pgh.pa.us 439 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
440 : :
4335 bruce@momjian.us 441 :CBC 36 : p++; /* remove ':' char */
4834 simon@2ndQuadrant.co 442 : 36 : cluster->controldata.data_checksum_version = str2uint(p);
443 : 36 : got_data_checksum_version = true;
444 : : }
519 msawada@postgresql.o 445 [ + + ]: 576 : else if ((p = strstr(bufin, "Default char data signedness:")) != NULL)
446 : : {
447 : 36 : p = strchr(p, ':');
448 : :
449 [ + - - + ]: 36 : if (p == NULL || strlen(p) <= 1)
519 msawada@postgresql.o 450 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
451 : :
452 : : /* Skip the colon and any whitespace after it */
519 msawada@postgresql.o 453 :CBC 36 : p++;
454 [ + + ]: 360 : while (isspace((unsigned char) *p))
455 : 324 : p++;
456 : :
457 : : /* The value should be either 'signed' or 'unsigned' */
458 [ + + - + ]: 36 : if (strcmp(p, "signed") != 0 && strcmp(p, "unsigned") != 0)
519 msawada@postgresql.o 459 :UBC 0 : pg_fatal("%d: controldata retrieval problem", __LINE__);
460 : :
519 msawada@postgresql.o 461 :CBC 36 : cluster->controldata.default_char_signedness = strcmp(p, "signed") == 0;
462 : 36 : got_default_char_signedness = true;
463 : : }
464 : : }
465 : :
1348 peter@eisentraut.org 466 : 36 : rc = pclose(output);
467 [ - + ]: 36 : if (rc != 0)
1348 peter@eisentraut.org 468 :UBC 0 : pg_fatal("could not get control data using %s: %s",
469 : : cmd, wait_result_to_str(rc));
470 : :
471 : : /*
472 : : * Restore environment variables. Note all but LANG and LC_MESSAGES were
473 : : * unset above.
474 : : */
2033 tgl@sss.pgh.pa.us 475 [ - + ]:CBC 36 : if (lc_collate)
2033 tgl@sss.pgh.pa.us 476 :UBC 0 : setenv("LC_COLLATE", lc_collate, 1);
2033 tgl@sss.pgh.pa.us 477 [ - + ]:CBC 36 : if (lc_ctype)
2033 tgl@sss.pgh.pa.us 478 :UBC 0 : setenv("LC_CTYPE", lc_ctype, 1);
2033 tgl@sss.pgh.pa.us 479 [ - + ]:CBC 36 : if (lc_monetary)
2033 tgl@sss.pgh.pa.us 480 :UBC 0 : setenv("LC_MONETARY", lc_monetary, 1);
2033 tgl@sss.pgh.pa.us 481 [ + - ]:CBC 36 : if (lc_numeric)
482 : 36 : setenv("LC_NUMERIC", lc_numeric, 1);
483 [ - + ]: 36 : if (lc_time)
2033 tgl@sss.pgh.pa.us 484 :UBC 0 : setenv("LC_TIME", lc_time, 1);
2033 tgl@sss.pgh.pa.us 485 [ + - ]:CBC 36 : if (lang)
486 : 36 : setenv("LANG", lang, 1);
487 : : else
2033 tgl@sss.pgh.pa.us 488 :UBC 0 : unsetenv("LANG");
2033 tgl@sss.pgh.pa.us 489 [ - + ]:CBC 36 : if (language)
2033 tgl@sss.pgh.pa.us 490 :UBC 0 : setenv("LANGUAGE", language, 1);
2033 tgl@sss.pgh.pa.us 491 [ - + ]:CBC 36 : if (lc_all)
2033 tgl@sss.pgh.pa.us 492 :UBC 0 : setenv("LC_ALL", lc_all, 1);
2033 tgl@sss.pgh.pa.us 493 [ + - ]:CBC 36 : if (lc_messages)
494 : 36 : setenv("LC_MESSAGES", lc_messages, 1);
495 : : else
2033 tgl@sss.pgh.pa.us 496 :UBC 0 : unsetenv("LC_MESSAGES");
497 : :
5800 bruce@momjian.us 498 :CBC 36 : pg_free(lc_collate);
499 : 36 : pg_free(lc_ctype);
500 : 36 : pg_free(lc_monetary);
501 : 36 : pg_free(lc_numeric);
502 : 36 : pg_free(lc_time);
503 : 36 : pg_free(lang);
504 : 36 : pg_free(language);
505 : 36 : pg_free(lc_all);
506 : 36 : pg_free(lc_messages);
507 : :
508 : : /*
509 : : * Pre-v18 database clusters don't have the default char signedness
510 : : * information. We use the char signedness of the platform where
511 : : * pg_upgrade was built.
512 : : */
519 msawada@postgresql.o 513 [ - + ]: 36 : if (cluster->controldata.cat_ver < DEFAULT_CHAR_SIGNEDNESS_CAT_VER)
514 : : {
519 msawada@postgresql.o 515 [ # # ]:UBC 0 : Assert(!got_default_char_signedness);
516 : : #if CHAR_MIN != 0
517 : 0 : cluster->controldata.default_char_signedness = true;
518 : : #else
519 : : cluster->controldata.default_char_signedness = false;
520 : : #endif
521 : : }
522 : :
523 : : /* verify that we got all the mandatory pg_control data */
5918 bruce@momjian.us 524 [ + - + - ]:CBC 36 : if (!got_xid || !got_oid ||
1825 525 [ + - + - ]: 36 : !got_multi || !got_oldestxid ||
23 nathan@postgresql.or 526 [ + - ]:GNC 36 : !got_oldestmulti ||
4090 bruce@momjian.us 527 [ + - + - :CBC 36 : !got_mxoff || (!live_check && !got_nextxlogfile) ||
+ - ]
3938 528 [ + - + - : 36 : !got_float8_pass_by_value || !got_align || !got_blocksz ||
+ - ]
529 [ + - + - : 36 : !got_largesz || !got_walsz || !got_walseg || !got_ident ||
+ - + - ]
530 [ + - + - ]: 36 : !got_index || !got_toast ||
23 nathan@postgresql.or 531 [ + - ]:GNC 36 : !got_large_object ||
519 msawada@postgresql.o 532 [ + - + - ]:CBC 36 : !got_date_is_int || !got_data_checksum_version ||
533 [ - + ]: 36 : (!got_default_char_signedness &&
519 msawada@postgresql.o 534 [ # # ]:UBC 0 : cluster->controldata.cat_ver >= DEFAULT_CHAR_SIGNEDNESS_CAT_VER))
535 : : {
3298 alvherre@alvh.no-ip. 536 [ # # ]: 0 : if (cluster == &old_cluster)
537 : 0 : pg_log(PG_REPORT,
538 : : "The source cluster lacks some required control information:");
539 : : else
540 : 0 : pg_log(PG_REPORT,
541 : : "The target cluster lacks some required control information:");
542 : :
5918 bruce@momjian.us 543 [ # # ]: 0 : if (!got_xid)
1474 tgl@sss.pgh.pa.us 544 : 0 : pg_log(PG_REPORT, " checkpoint next XID");
545 : :
5918 bruce@momjian.us 546 [ # # ]: 0 : if (!got_oid)
1474 tgl@sss.pgh.pa.us 547 : 0 : pg_log(PG_REPORT, " latest checkpoint next OID");
548 : :
4931 alvherre@alvh.no-ip. 549 [ # # ]: 0 : if (!got_multi)
1474 tgl@sss.pgh.pa.us 550 : 0 : pg_log(PG_REPORT, " latest checkpoint next MultiXactId");
551 : :
23 nathan@postgresql.or 552 [ # # ]:UNC 0 : if (!got_oldestmulti)
1474 tgl@sss.pgh.pa.us 553 :UBC 0 : pg_log(PG_REPORT, " latest checkpoint oldest MultiXactId");
554 : :
1825 bruce@momjian.us 555 [ # # ]: 0 : if (!got_oldestxid)
1474 tgl@sss.pgh.pa.us 556 : 0 : pg_log(PG_REPORT, " latest checkpoint oldestXID");
557 : :
4090 bruce@momjian.us 558 [ # # ]: 0 : if (!got_mxoff)
1474 tgl@sss.pgh.pa.us 559 : 0 : pg_log(PG_REPORT, " latest checkpoint next MultiXactOffset");
560 : :
5142 heikki.linnakangas@i 561 [ # # # # ]: 0 : if (!live_check && !got_nextxlogfile)
1474 tgl@sss.pgh.pa.us 562 : 0 : pg_log(PG_REPORT, " first WAL segment after reset");
563 : :
3938 bruce@momjian.us 564 [ # # ]: 0 : if (!got_float8_pass_by_value)
1474 tgl@sss.pgh.pa.us 565 : 0 : pg_log(PG_REPORT, " float8 argument passing method");
566 : :
5918 bruce@momjian.us 567 [ # # ]: 0 : if (!got_align)
1474 tgl@sss.pgh.pa.us 568 : 0 : pg_log(PG_REPORT, " maximum alignment");
569 : :
5918 bruce@momjian.us 570 [ # # ]: 0 : if (!got_blocksz)
1474 tgl@sss.pgh.pa.us 571 : 0 : pg_log(PG_REPORT, " block size");
572 : :
5918 bruce@momjian.us 573 [ # # ]: 0 : if (!got_largesz)
1474 tgl@sss.pgh.pa.us 574 : 0 : pg_log(PG_REPORT, " large relation segment size");
575 : :
5918 bruce@momjian.us 576 [ # # ]: 0 : if (!got_walsz)
1474 tgl@sss.pgh.pa.us 577 : 0 : pg_log(PG_REPORT, " WAL block size");
578 : :
5918 bruce@momjian.us 579 [ # # ]: 0 : if (!got_walseg)
1474 tgl@sss.pgh.pa.us 580 : 0 : pg_log(PG_REPORT, " WAL segment size");
581 : :
5918 bruce@momjian.us 582 [ # # ]: 0 : if (!got_ident)
1474 tgl@sss.pgh.pa.us 583 : 0 : pg_log(PG_REPORT, " maximum identifier length");
584 : :
5918 bruce@momjian.us 585 [ # # ]: 0 : if (!got_index)
1474 tgl@sss.pgh.pa.us 586 : 0 : pg_log(PG_REPORT, " maximum number of indexed columns");
587 : :
5918 bruce@momjian.us 588 [ # # ]: 0 : if (!got_toast)
1474 tgl@sss.pgh.pa.us 589 : 0 : pg_log(PG_REPORT, " maximum TOAST chunk size");
590 : :
23 nathan@postgresql.or 591 [ # # ]:UNC 0 : if (!got_large_object)
1474 tgl@sss.pgh.pa.us 592 :UBC 0 : pg_log(PG_REPORT, " large-object chunk size");
593 : :
5918 bruce@momjian.us 594 [ # # ]: 0 : if (!got_date_is_int)
1474 tgl@sss.pgh.pa.us 595 : 0 : pg_log(PG_REPORT, " dates/times are integers?");
596 : :
597 : : /* value added in Postgres 9.3 */
4834 simon@2ndQuadrant.co 598 [ # # ]: 0 : if (!got_data_checksum_version)
1474 tgl@sss.pgh.pa.us 599 : 0 : pg_log(PG_REPORT, " data checksum version");
600 : :
601 : : /* value added in Postgres 18 */
519 msawada@postgresql.o 602 [ # # ]: 0 : if (!got_default_char_signedness)
603 : 0 : pg_log(PG_REPORT, " default char signedness");
604 : :
1474 tgl@sss.pgh.pa.us 605 : 0 : pg_fatal("Cannot continue without required control information, terminating");
606 : : }
5918 bruce@momjian.us 607 :CBC 36 : }
608 : :
609 : :
610 : : /*
611 : : * check_control_data()
612 : : *
613 : : * check to make sure the control data settings are compatible
614 : : */
615 : : void
5758 616 : 18 : check_control_data(ControlData *oldctrl,
617 : : ControlData *newctrl)
618 : : {
5918 619 [ + - - + ]: 18 : if (oldctrl->align == 0 || oldctrl->align != newctrl->align)
1474 tgl@sss.pgh.pa.us 620 :UBC 0 : pg_fatal("old and new pg_controldata alignments are invalid or do not match.\n"
621 : : "Likely one cluster is a 32-bit install, the other 64-bit");
622 : :
5918 bruce@momjian.us 623 [ + - - + ]:CBC 18 : if (oldctrl->blocksz == 0 || oldctrl->blocksz != newctrl->blocksz)
1474 tgl@sss.pgh.pa.us 624 :UBC 0 : pg_fatal("old and new pg_controldata block sizes are invalid or do not match");
625 : :
5918 bruce@momjian.us 626 [ + - - + ]:CBC 18 : if (oldctrl->largesz == 0 || oldctrl->largesz != newctrl->largesz)
1474 tgl@sss.pgh.pa.us 627 :UBC 0 : pg_fatal("old and new pg_controldata maximum relation segment sizes are invalid or do not match");
628 : :
5918 bruce@momjian.us 629 [ + - - + ]:CBC 18 : if (oldctrl->walsz == 0 || oldctrl->walsz != newctrl->walsz)
1474 tgl@sss.pgh.pa.us 630 :UBC 0 : pg_fatal("old and new pg_controldata WAL block sizes are invalid or do not match");
631 : :
5918 bruce@momjian.us 632 [ + - - + ]:CBC 18 : if (oldctrl->walseg == 0 || oldctrl->walseg != newctrl->walseg)
1474 tgl@sss.pgh.pa.us 633 :UBC 0 : pg_fatal("old and new pg_controldata WAL segment sizes are invalid or do not match");
634 : :
5918 bruce@momjian.us 635 [ + - - + ]:CBC 18 : if (oldctrl->ident == 0 || oldctrl->ident != newctrl->ident)
1474 tgl@sss.pgh.pa.us 636 :UBC 0 : pg_fatal("old and new pg_controldata maximum identifier lengths are invalid or do not match");
637 : :
5918 bruce@momjian.us 638 [ + - - + ]:CBC 18 : if (oldctrl->index == 0 || oldctrl->index != newctrl->index)
1474 tgl@sss.pgh.pa.us 639 :UBC 0 : pg_fatal("old and new pg_controldata maximum indexed columns are invalid or do not match");
640 : :
5918 bruce@momjian.us 641 [ + - - + ]:CBC 18 : if (oldctrl->toast == 0 || oldctrl->toast != newctrl->toast)
1474 tgl@sss.pgh.pa.us 642 :UBC 0 : pg_fatal("old and new pg_controldata maximum TOAST chunk sizes are invalid or do not match");
643 : :
23 nathan@postgresql.or 644 [ + - ]:GNC 18 : if (oldctrl->large_object == 0 ||
4336 bruce@momjian.us 645 [ - + ]:CBC 18 : oldctrl->large_object != newctrl->large_object)
1474 tgl@sss.pgh.pa.us 646 :UBC 0 : pg_fatal("old and new pg_controldata large-object chunk sizes are invalid or do not match");
647 : :
5918 bruce@momjian.us 648 [ - + ]:CBC 18 : if (oldctrl->date_is_int != newctrl->date_is_int)
1474 tgl@sss.pgh.pa.us 649 :UBC 0 : pg_fatal("old and new pg_controldata date/time storage types do not match");
650 : :
651 : : /*
652 : : * float8_pass_by_value does not need to match, but is used in
653 : : * check_for_isn_and_int8_passing_mismatch().
654 : : */
655 : :
656 : : /*
657 : : * If data checksums are in any in-progress state then disallow the
658 : : * upgrade. The user should either let the process finish, or turn off
659 : : * data checksums, before retrying.
660 : : */
113 dgustafsson@postgres 661 [ - + ]:CBC 18 : if (oldctrl->data_checksum_version > PG_DATA_CHECKSUM_VERSION)
4 peter@eisentraut.org 662 :UBC 0 : pg_fatal("data checksums are being enabled in the old cluster");
663 : :
664 : : /*
665 : : * We might eventually allow upgrades from checksum to no-checksum
666 : : * clusters.
667 : : */
110 dgustafsson@postgres 668 [ - + ]:CBC 18 : if (oldctrl->data_checksum_version == PG_DATA_CHECKSUM_OFF &&
110 dgustafsson@postgres 669 [ # # ]:UBC 0 : newctrl->data_checksum_version != PG_DATA_CHECKSUM_OFF)
1474 tgl@sss.pgh.pa.us 670 : 0 : pg_fatal("old cluster does not use data checksums but the new one does");
110 dgustafsson@postgres 671 [ + - ]:CBC 18 : else if (oldctrl->data_checksum_version != PG_DATA_CHECKSUM_OFF &&
672 [ - + ]: 18 : newctrl->data_checksum_version == PG_DATA_CHECKSUM_OFF)
1474 tgl@sss.pgh.pa.us 673 :UBC 0 : pg_fatal("old cluster uses data checksums but the new one does not");
4182 bruce@momjian.us 674 [ - + ]:CBC 18 : else if (oldctrl->data_checksum_version != newctrl->data_checksum_version)
1474 tgl@sss.pgh.pa.us 675 :UBC 0 : pg_fatal("old and new cluster pg_controldata checksum versions do not match");
5918 bruce@momjian.us 676 :CBC 18 : }
677 : :
678 : :
679 : : void
487 nathan@postgresql.or 680 : 2 : disable_old_cluster(transferMode transfer_mode)
681 : : {
682 : : char old_path[MAXPGPATH],
683 : : new_path[MAXPGPATH];
684 : :
685 : : /* rename pg_control so old server cannot be accidentally started */
686 : : /* translator: %s is the file path of the control file */
463 fujii@postgresql.org 687 : 2 : prep_status("Adding \".old\" suffix to old \"%s\"", XLOG_CONTROL_FILE);
688 : :
474 689 : 2 : snprintf(old_path, sizeof(old_path), "%s/%s", old_cluster.pgdata, XLOG_CONTROL_FILE);
690 : 2 : snprintf(new_path, sizeof(new_path), "%s/%s.old", old_cluster.pgdata, XLOG_CONTROL_FILE);
5918 bruce@momjian.us 691 [ - + ]: 2 : if (pg_mv_file(old_path, new_path) != 0)
1474 tgl@sss.pgh.pa.us 692 :UBC 0 : pg_fatal("could not rename file \"%s\" to \"%s\": %m",
693 : : old_path, new_path);
5758 bruce@momjian.us 694 :CBC 2 : check_ok();
695 : :
487 nathan@postgresql.or 696 [ + + ]: 2 : if (transfer_mode == TRANSFER_MODE_LINK)
697 : : /* translator: %s/%s is the file path of the control file */
698 : 1 : pg_log(PG_REPORT, "\n"
699 : : "If you want to start the old cluster, you will need to remove\n"
700 : : "the \".old\" suffix from \"%s/%s.old\".\n"
701 : : "Because \"link\" mode was used, the old cluster cannot be safely\n"
702 : : "started once the new cluster has been started.",
703 : : old_cluster.pgdata, XLOG_CONTROL_FILE);
704 [ + - ]: 1 : else if (transfer_mode == TRANSFER_MODE_SWAP)
705 : 1 : pg_log(PG_REPORT, "\n"
706 : : "Because \"swap\" mode was used, the old cluster can no longer be\n"
707 : : "safely started.");
708 : : else
487 nathan@postgresql.or 709 :UBC 0 : pg_fatal("unrecognized transfer mode");
5918 bruce@momjian.us 710 :CBC 2 : }
|