4 * controldata functions
6 * Copyright (c) 2010-2013, PostgreSQL Global Development Group
7 * contrib/pg_upgrade/controldata.c
12 #include "pg_upgrade.h"
19 * gets pg_control information in "ctrl". Assumes that bindir and
20 * datadir are valid absolute paths to postgresql bin and pgdata
21 * directories respectively *and* pg_resetxlog is version compatible
22 * with datadir. The main purpose of this function is to get pg_control
23 * data in a version independent manner.
25 * The approach taken here is to invoke pg_resetxlog with -n option
26 * and then pipe its output. With little string parsing we get the
27 * pg_control data. pg_resetxlog cannot be run while the server is running
28 * so we use pg_controldata; pg_controldata doesn't provide all the fields
29 * we need to actually perform the upgrade, but it provides enough for
30 * check mode. We do not implement pg_resetxlog -n because it is hard to
31 * return valid xid data for a running server.
34 get_control_data(ClusterInfo *cluster, bool live_check)
37 char bufin[MAX_STRING];
42 bool got_nextxlogfile = false;
43 bool got_multi = false;
44 bool got_mxoff = false;
45 bool got_oldestmulti = false;
46 bool got_log_id = false;
47 bool got_log_seg = false;
49 bool got_align = false;
50 bool got_blocksz = false;
51 bool got_largesz = false;
52 bool got_walsz = false;
53 bool got_walseg = false;
54 bool got_ident = false;
55 bool got_index = false;
56 bool got_toast = false;
57 bool got_date_is_int = false;
58 bool got_float8_pass_by_value = false;
59 char *lc_collate = NULL;
60 char *lc_ctype = NULL;
61 char *lc_monetary = NULL;
62 char *lc_numeric = NULL;
65 char *language = NULL;
67 char *lc_messages = NULL;
74 * Because we test the pg_resetxlog output as strings, it has to be in
75 * English. Copied from pg_regress.c.
77 if (getenv("LC_COLLATE"))
78 lc_collate = pg_strdup(getenv("LC_COLLATE"));
79 if (getenv("LC_CTYPE"))
80 lc_ctype = pg_strdup(getenv("LC_CTYPE"));
81 if (getenv("LC_MONETARY"))
82 lc_monetary = pg_strdup(getenv("LC_MONETARY"));
83 if (getenv("LC_NUMERIC"))
84 lc_numeric = pg_strdup(getenv("LC_NUMERIC"));
85 if (getenv("LC_TIME"))
86 lc_time = pg_strdup(getenv("LC_TIME"));
88 lang = pg_strdup(getenv("LANG"));
89 if (getenv("LANGUAGE"))
90 language = pg_strdup(getenv("LANGUAGE"));
92 lc_all = pg_strdup(getenv("LC_ALL"));
93 if (getenv("LC_MESSAGES"))
94 lc_messages = pg_strdup(getenv("LC_MESSAGES"));
96 pg_putenv("LC_COLLATE", NULL);
97 pg_putenv("LC_CTYPE", NULL);
98 pg_putenv("LC_MONETARY", NULL);
99 pg_putenv("LC_NUMERIC", NULL);
100 pg_putenv("LC_TIME", NULL);
105 /* On Windows the default locale cannot be English, so force it */
108 pg_putenv("LANGUAGE", NULL);
109 pg_putenv("LC_ALL", NULL);
110 pg_putenv("LC_MESSAGES", "C");
112 snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/%s \"%s\"" SYSTEMQUOTE,
114 live_check ? "pg_controldata\"" : "pg_resetxlog\" -n",
119 if ((output = popen(cmd, "r")) == NULL)
120 pg_log(PG_FATAL, "Could not get control data using %s: %s\n",
121 cmd, getErrorText(errno));
123 /* Only pre-8.4 has these so if they are not set below we will check later */
124 cluster->controldata.lc_collate = NULL;
125 cluster->controldata.lc_ctype = NULL;
128 if (GET_MAJOR_VERSION(cluster->major_version) <= 803)
130 cluster->controldata.float8_pass_by_value = false;
131 got_float8_pass_by_value = true;
134 /* we have the result of cmd in "output". so parse it line by line now */
135 while (fgets(bufin, sizeof(bufin), output))
137 pg_log(PG_VERBOSE, "%s", bufin);
142 * Due to an installer bug, LANG=C doesn't work for PG 8.3.3, but does
143 * work 8.2.6 and 8.3.7, so check for non-ASCII output and suggest a
146 if (GET_MAJOR_VERSION(cluster->major_version) <= 803)
148 for (p = bufin; *p; p++)
151 "The 8.3 cluster's pg_controldata is incapable of outputting ASCII, even\n"
152 "with LANG=C. You must upgrade this cluster to a newer version of PostgreSQL\n"
153 "8.3 to fix this bug. PostgreSQL 8.3.7 and later are known to work properly.\n");
157 if ((p = strstr(bufin, "pg_control version number:")) != NULL)
161 if (p == NULL || strlen(p) <= 1)
162 pg_log(PG_FATAL, "%d: pg_resetxlog problem\n", __LINE__);
164 p++; /* removing ':' char */
165 cluster->controldata.ctrl_ver = str2uint(p);
167 else if ((p = strstr(bufin, "Catalog version number:")) != NULL)
171 if (p == NULL || strlen(p) <= 1)
172 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
174 p++; /* removing ':' char */
175 cluster->controldata.cat_ver = str2uint(p);
177 else if ((p = strstr(bufin, "First log segment after reset:")) != NULL)
179 /* Skip the colon and any whitespace after it */
181 if (p == NULL || strlen(p) <= 1)
182 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
183 p = strpbrk(p, "01234567890ABCDEF");
184 if (p == NULL || strlen(p) <= 1)
185 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
187 /* Make sure it looks like a valid WAL file name */
188 if (strspn(p, "0123456789ABCDEF") != 24)
189 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
191 strlcpy(cluster->controldata.nextxlogfile, p, 25);
192 got_nextxlogfile = true;
194 else if ((p = strstr(bufin, "First log file ID after reset:")) != NULL)
198 if (p == NULL || strlen(p) <= 1)
199 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
201 p++; /* removing ':' char */
205 else if ((p = strstr(bufin, "First log file segment after reset:")) != NULL)
209 if (p == NULL || strlen(p) <= 1)
210 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
212 p++; /* removing ':' char */
216 else if ((p = strstr(bufin, "Latest checkpoint's TimeLineID:")) != NULL)
220 if (p == NULL || strlen(p) <= 1)
221 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
223 p++; /* removing ':' char */
224 cluster->controldata.chkpnt_tli = str2uint(p);
227 else if ((p = strstr(bufin, "Latest checkpoint's NextXID:")) != NULL)
229 char *op = strchr(p, '/');
234 if (op == NULL || strlen(op) <= 1)
235 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
237 op++; /* removing ':' char */
238 cluster->controldata.chkpnt_nxtxid = str2uint(op);
241 else if ((p = strstr(bufin, "Latest checkpoint's NextOID:")) != NULL)
245 if (p == NULL || strlen(p) <= 1)
246 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
248 p++; /* removing ':' char */
249 cluster->controldata.chkpnt_nxtoid = str2uint(p);
252 else if ((p = strstr(bufin, "Latest checkpoint's NextMultiXactId:")) != NULL)
256 if (p == NULL || strlen(p) <= 1)
257 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
259 p++; /* removing ':' char */
260 cluster->controldata.chkpnt_nxtmulti = str2uint(p);
263 else if ((p = strstr(bufin, "Latest checkpoint's oldestMultiXid:")) != NULL)
267 if (p == NULL || strlen(p) <= 1)
268 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
270 p++; /* removing ':' char */
271 cluster->controldata.chkpnt_oldstMulti = str2uint(p);
272 got_oldestmulti = true;
274 else if ((p = strstr(bufin, "Latest checkpoint's NextMultiOffset:")) != NULL)
278 if (p == NULL || strlen(p) <= 1)
279 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
281 p++; /* removing ':' char */
282 cluster->controldata.chkpnt_nxtmxoff = str2uint(p);
285 else if ((p = strstr(bufin, "Maximum data alignment:")) != NULL)
289 if (p == NULL || strlen(p) <= 1)
290 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
292 p++; /* removing ':' char */
293 cluster->controldata.align = str2uint(p);
296 else if ((p = strstr(bufin, "Database block size:")) != NULL)
300 if (p == NULL || strlen(p) <= 1)
301 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
303 p++; /* removing ':' char */
304 cluster->controldata.blocksz = str2uint(p);
307 else if ((p = strstr(bufin, "Blocks per segment of large relation:")) != NULL)
311 if (p == NULL || strlen(p) <= 1)
312 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
314 p++; /* removing ':' char */
315 cluster->controldata.largesz = str2uint(p);
318 else if ((p = strstr(bufin, "WAL block size:")) != NULL)
322 if (p == NULL || strlen(p) <= 1)
323 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
325 p++; /* removing ':' char */
326 cluster->controldata.walsz = str2uint(p);
329 else if ((p = strstr(bufin, "Bytes per WAL segment:")) != NULL)
333 if (p == NULL || strlen(p) <= 1)
334 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
336 p++; /* removing ':' char */
337 cluster->controldata.walseg = str2uint(p);
340 else if ((p = strstr(bufin, "Maximum length of identifiers:")) != NULL)
344 if (p == NULL || strlen(p) <= 1)
345 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
347 p++; /* removing ':' char */
348 cluster->controldata.ident = str2uint(p);
351 else if ((p = strstr(bufin, "Maximum columns in an index:")) != NULL)
355 if (p == NULL || strlen(p) <= 1)
356 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
358 p++; /* removing ':' char */
359 cluster->controldata.index = str2uint(p);
362 else if ((p = strstr(bufin, "Maximum size of a TOAST chunk:")) != NULL)
366 if (p == NULL || strlen(p) <= 1)
367 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
369 p++; /* removing ':' char */
370 cluster->controldata.toast = str2uint(p);
373 else if ((p = strstr(bufin, "Date/time type storage:")) != NULL)
377 if (p == NULL || strlen(p) <= 1)
378 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
380 p++; /* removing ':' char */
381 cluster->controldata.date_is_int = strstr(p, "64-bit integers") != NULL;
382 got_date_is_int = true;
384 else if ((p = strstr(bufin, "Float8 argument passing:")) != NULL)
388 if (p == NULL || strlen(p) <= 1)
389 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
391 p++; /* removing ':' char */
392 /* used later for contrib check */
393 cluster->controldata.float8_pass_by_value = strstr(p, "by value") != NULL;
394 got_float8_pass_by_value = true;
396 /* In pre-8.4 only */
397 else if ((p = strstr(bufin, "LC_COLLATE:")) != NULL)
401 if (p == NULL || strlen(p) <= 1)
402 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
404 p++; /* removing ':' char */
405 /* skip leading spaces and remove trailing newline */
407 if (strlen(p) > 0 && *(p + strlen(p) - 1) == '\n')
408 *(p + strlen(p) - 1) = '\0';
409 cluster->controldata.lc_collate = pg_strdup(p);
411 /* In pre-8.4 only */
412 else if ((p = strstr(bufin, "LC_CTYPE:")) != NULL)
416 if (p == NULL || strlen(p) <= 1)
417 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
419 p++; /* removing ':' char */
420 /* skip leading spaces and remove trailing newline */
422 if (strlen(p) > 0 && *(p + strlen(p) - 1) == '\n')
423 *(p + strlen(p) - 1) = '\0';
424 cluster->controldata.lc_ctype = pg_strdup(p);
432 * Restore environment variables
434 pg_putenv("LC_COLLATE", lc_collate);
435 pg_putenv("LC_CTYPE", lc_ctype);
436 pg_putenv("LC_MONETARY", lc_monetary);
437 pg_putenv("LC_NUMERIC", lc_numeric);
438 pg_putenv("LC_TIME", lc_time);
439 pg_putenv("LANG", lang);
440 pg_putenv("LANGUAGE", language);
441 pg_putenv("LC_ALL", lc_all);
442 pg_putenv("LC_MESSAGES", lc_messages);
446 pg_free(lc_monetary);
452 pg_free(lc_messages);
455 * Before 9.3, pg_resetxlog reported the xlogid and segno of the first
456 * log file after reset as separate lines. Starting with 9.3, it reports
457 * the WAL file name. If the old cluster is older than 9.3, we construct
458 * the WAL file name from the xlogid and segno.
460 if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
462 if (got_log_id && got_log_seg)
464 snprintf(cluster->controldata.nextxlogfile, 25, "%08X%08X%08X",
466 got_nextxlogfile = true;
470 /* verify that we got all the mandatory pg_control data */
471 if (!got_xid || !got_oid ||
472 !got_multi || !got_mxoff || !got_oldestmulti ||
473 (!live_check && !got_nextxlogfile) ||
475 !got_align || !got_blocksz || !got_largesz || !got_walsz ||
476 !got_walseg || !got_ident || !got_index || !got_toast ||
477 !got_date_is_int || !got_float8_pass_by_value)
480 "The %s cluster lacks some required control information:\n",
481 CLUSTER_NAME(cluster));
484 pg_log(PG_REPORT, " checkpoint next XID\n");
487 pg_log(PG_REPORT, " latest checkpoint next OID\n");
490 pg_log(PG_REPORT, " latest checkpoint next MultiXactId\n");
493 pg_log(PG_REPORT, " latest checkpoint next MultiXactOffset\n");
495 if (!got_oldestmulti)
496 pg_log(PG_REPORT, " latest checkpoint oldest MultiXactId\n");
498 if (!live_check && !got_nextxlogfile)
499 pg_log(PG_REPORT, " first WAL segment after reset\n");
502 pg_log(PG_REPORT, " latest checkpoint timeline ID\n");
505 pg_log(PG_REPORT, " maximum alignment\n");
508 pg_log(PG_REPORT, " block size\n");
511 pg_log(PG_REPORT, " large relation segment size\n");
514 pg_log(PG_REPORT, " WAL block size\n");
517 pg_log(PG_REPORT, " WAL segment size\n");
520 pg_log(PG_REPORT, " maximum identifier length\n");
523 pg_log(PG_REPORT, " maximum number of indexed columns\n");
526 pg_log(PG_REPORT, " maximum TOAST chunk size\n");
528 if (!got_date_is_int)
529 pg_log(PG_REPORT, " dates/times are integers?\n");
531 /* value added in Postgres 8.4 */
532 if (!got_float8_pass_by_value)
533 pg_log(PG_REPORT, " float8 argument passing method\n");
536 "Cannot continue without required control information, terminating\n");
542 * check_control_data()
544 * check to make sure the control data settings are compatible
547 check_control_data(ControlData *oldctrl,
548 ControlData *newctrl)
550 if (oldctrl->align == 0 || oldctrl->align != newctrl->align)
552 "old and new pg_controldata alignments are invalid or do not match\n"
553 "Likely one cluster is a 32-bit install, the other 64-bit\n");
555 if (oldctrl->blocksz == 0 || oldctrl->blocksz != newctrl->blocksz)
557 "old and new pg_controldata block sizes are invalid or do not match\n");
559 if (oldctrl->largesz == 0 || oldctrl->largesz != newctrl->largesz)
561 "old and new pg_controldata maximum relation segement sizes are invalid or do not match\n");
563 if (oldctrl->walsz == 0 || oldctrl->walsz != newctrl->walsz)
565 "old and new pg_controldata WAL block sizes are invalid or do not match\n");
567 if (oldctrl->walseg == 0 || oldctrl->walseg != newctrl->walseg)
569 "old and new pg_controldata WAL segment sizes are invalid or do not match\n");
571 if (oldctrl->ident == 0 || oldctrl->ident != newctrl->ident)
573 "old and new pg_controldata maximum identifier lengths are invalid or do not match\n");
575 if (oldctrl->index == 0 || oldctrl->index != newctrl->index)
577 "old and new pg_controldata maximum indexed columns are invalid or do not match\n");
579 if (oldctrl->toast == 0 || oldctrl->toast != newctrl->toast)
581 "old and new pg_controldata maximum TOAST chunk sizes are invalid or do not match\n");
583 if (oldctrl->date_is_int != newctrl->date_is_int)
586 "\nOld and new pg_controldata date/time storage types do not match.\n");
589 * This is a common 8.3 -> 8.4 upgrade problem, so we are more verbose
592 "You will need to rebuild the new server with configure option\n"
593 "--disable-integer-datetimes or get server binaries built with those\n"
600 disable_old_cluster(void)
602 char old_path[MAXPGPATH],
605 /* rename pg_control so old server cannot be accidentally started */
606 prep_status("Adding \".old\" suffix to old global/pg_control");
608 snprintf(old_path, sizeof(old_path), "%s/global/pg_control", old_cluster.pgdata);
609 snprintf(new_path, sizeof(new_path), "%s/global/pg_control.old", old_cluster.pgdata);
610 if (pg_mv_file(old_path, new_path) != 0)
611 pg_log(PG_FATAL, "Unable to rename %s to %s.\n", old_path, new_path);
614 pg_log(PG_REPORT, "\n"
615 "If you want to start the old cluster, you will need to remove\n"
616 "the \".old\" suffix from %s/global/pg_control.old.\n"
617 "Because \"link\" mode was used, the old cluster cannot be safely\n"
618 "started once the new cluster has been started.\n\n", old_cluster.pgdata);