Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * check.c
3 : : *
4 : : * server checks and output routines
5 : : *
6 : : * Copyright (c) 2010-2024, PostgreSQL Global Development Group
7 : : * src/bin/pg_upgrade/check.c
8 : : */
9 : :
10 : : #include "postgres_fe.h"
11 : :
12 : : #include "catalog/pg_authid_d.h"
13 : : #include "catalog/pg_class_d.h"
14 : : #include "catalog/pg_collation.h"
15 : : #include "fe_utils/string_utils.h"
16 : : #include "mb/pg_wchar.h"
17 : : #include "pg_upgrade.h"
18 : :
19 : : static void check_new_cluster_is_empty(void);
20 : : static void check_is_install_user(ClusterInfo *cluster);
21 : : static void check_proper_datallowconn(ClusterInfo *cluster);
22 : : static void check_for_prepared_transactions(ClusterInfo *cluster);
23 : : static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
24 : : static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
25 : : static void check_for_incompatible_polymorphics(ClusterInfo *cluster);
26 : : static void check_for_tables_with_oids(ClusterInfo *cluster);
27 : : static void check_for_pg_role_prefix(ClusterInfo *cluster);
28 : : static void check_for_new_tablespace_dir(void);
29 : : static void check_for_user_defined_encoding_conversions(ClusterInfo *cluster);
30 : : static void check_new_cluster_logical_replication_slots(void);
31 : : static void check_new_cluster_subscription_configuration(void);
32 : : static void check_old_cluster_for_valid_slots(bool live_check);
33 : : static void check_old_cluster_subscription_state(void);
34 : :
35 : : /*
36 : : * DataTypesUsageChecks - definitions of data type checks for the old cluster
37 : : * in order to determine if an upgrade can be performed. See the comment on
38 : : * data_types_usage_checks below for a more detailed description.
39 : : */
40 : : typedef struct
41 : : {
42 : : /* Status line to print to the user */
43 : : const char *status;
44 : : /* Filename to store report to */
45 : : const char *report_filename;
46 : : /* Query to extract the oid of the datatype */
47 : : const char *base_query;
48 : : /* Text to store to report in case of error */
49 : : const char *report_text;
50 : : /* The latest version where the check applies */
51 : : int threshold_version;
52 : : /* A function pointer for determining if the check applies */
53 : : DataTypesUsageVersionCheck version_hook;
54 : : } DataTypesUsageChecks;
55 : :
56 : : /*
57 : : * Special values for threshold_version for indicating that a check applies to
58 : : * all versions, or that a custom function needs to be invoked to determine
59 : : * if the check applies.
60 : : */
61 : : #define MANUAL_CHECK 1
62 : : #define ALL_VERSIONS -1
63 : :
64 : : /*--
65 : : * Data type usage checks. Each check for problematic data type usage is
66 : : * defined in this array with metadata, SQL query for finding the data type
67 : : * and functionality for deciding if the check is applicable to the version
68 : : * of the old cluster. The struct members are described in detail below:
69 : : *
70 : : * status A oneline string which can be printed to the user to
71 : : * inform about progress. Should not end with newline.
72 : : * report_filename The filename in which the list of problems detected by
73 : : * the check will be printed.
74 : : * base_query A query which extracts the Oid of the datatype checked
75 : : * for.
76 : : * report_text The text which will be printed to the user to explain
77 : : * what the check did, and why it failed. The text should
78 : : * end with a newline, and does not need to refer to the
79 : : * report_filename as that is automatically appended to
80 : : * the report with the path to the log folder.
81 : : * threshold_version The major version of PostgreSQL for which to run the
82 : : * check. Iff the old cluster is less than, or equal to,
83 : : * the threshold version then the check will be executed.
84 : : * If the old version is greater than the threshold then
85 : : * the check is skipped. If the threshold_version is set
86 : : * to ALL_VERSIONS then it will be run unconditionally,
87 : : * if set to MANUAL_CHECK then the version_hook function
88 : : * will be executed in order to determine whether or not
89 : : * to run.
90 : : * version_hook A function pointer to a version check function of type
91 : : * DataTypesUsageVersionCheck which is used to determine
92 : : * if the check is applicable to the old cluster. If the
93 : : * version_hook returns true then the check will be run,
94 : : * else it will be skipped. The function will only be
95 : : * executed iff threshold_version is set to MANUAL_CHECK.
96 : : */
97 : : static DataTypesUsageChecks data_types_usage_checks[] =
98 : : {
99 : : /*
100 : : * Look for composite types that were made during initdb *or* belong to
101 : : * information_schema; that's important in case information_schema was
102 : : * dropped and reloaded.
103 : : *
104 : : * The cutoff OID here should match the source cluster's value of
105 : : * FirstNormalObjectId. We hardcode it rather than using that C #define
106 : : * because, if that #define is ever changed, our own version's value is
107 : : * NOT what to use. Eventually we may need a test on the source cluster's
108 : : * version to select the correct value.
109 : : */
110 : : {
111 : : .status = gettext_noop("Checking for system-defined composite types in user tables"),
112 : : .report_filename = "tables_using_composite.txt",
113 : : .base_query =
114 : : "SELECT t.oid FROM pg_catalog.pg_type t "
115 : : "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
116 : : " WHERE typtype = 'c' AND (t.oid < 16384 OR nspname = 'information_schema')",
117 : : .report_text =
118 : : gettext_noop("Your installation contains system-defined composite types in user tables.\n"
119 : : "These type OIDs are not stable across PostgreSQL versions,\n"
120 : : "so this cluster cannot currently be upgraded. You can drop the\n"
121 : : "problem columns and restart the upgrade.\n"),
122 : : .threshold_version = ALL_VERSIONS
123 : : },
124 : :
125 : : /*
126 : : * 9.3 -> 9.4 Fully implement the 'line' data type in 9.4, which
127 : : * previously returned "not enabled" by default and was only functionally
128 : : * enabled with a compile-time switch; as of 9.4 "line" has a different
129 : : * on-disk representation format.
130 : : */
131 : : {
132 : : .status = gettext_noop("Checking for incompatible \"line\" data type"),
133 : : .report_filename = "tables_using_line.txt",
134 : : .base_query =
135 : : "SELECT 'pg_catalog.line'::pg_catalog.regtype AS oid",
136 : : .report_text =
137 : : gettext_noop("Your installation contains the \"line\" data type in user tables.\n"
138 : : "This data type changed its internal and input/output format\n"
139 : : "between your old and new versions so this\n"
140 : : "cluster cannot currently be upgraded. You can\n"
141 : : "drop the problem columns and restart the upgrade.\n"),
142 : : .threshold_version = 903
143 : : },
144 : :
145 : : /*
146 : : * pg_upgrade only preserves these system values: pg_class.oid pg_type.oid
147 : : * pg_enum.oid
148 : : *
149 : : * Many of the reg* data types reference system catalog info that is not
150 : : * preserved, and hence these data types cannot be used in user tables
151 : : * upgraded by pg_upgrade.
152 : : */
153 : : {
154 : : .status = gettext_noop("Checking for reg* data types in user tables"),
155 : : .report_filename = "tables_using_reg.txt",
156 : :
157 : : /*
158 : : * Note: older servers will not have all of these reg* types, so we
159 : : * have to write the query like this rather than depending on casts to
160 : : * regtype.
161 : : */
162 : : .base_query =
163 : : "SELECT oid FROM pg_catalog.pg_type t "
164 : : "WHERE t.typnamespace = "
165 : : " (SELECT oid FROM pg_catalog.pg_namespace "
166 : : " WHERE nspname = 'pg_catalog') "
167 : : " AND t.typname IN ( "
168 : : /* pg_class.oid is preserved, so 'regclass' is OK */
169 : : " 'regcollation', "
170 : : " 'regconfig', "
171 : : " 'regdictionary', "
172 : : " 'regnamespace', "
173 : : " 'regoper', "
174 : : " 'regoperator', "
175 : : " 'regproc', "
176 : : " 'regprocedure' "
177 : : /* pg_authid.oid is preserved, so 'regrole' is OK */
178 : : /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
179 : : " )",
180 : : .report_text =
181 : : gettext_noop("Your installation contains one of the reg* data types in user tables.\n"
182 : : "These data types reference system OIDs that are not preserved by\n"
183 : : "pg_upgrade, so this cluster cannot currently be upgraded. You can\n"
184 : : "drop the problem columns and restart the upgrade.\n"),
185 : : .threshold_version = ALL_VERSIONS
186 : : },
187 : :
188 : : /*
189 : : * PG 16 increased the size of the 'aclitem' type, which breaks the
190 : : * on-disk format for existing data.
191 : : */
192 : : {
193 : : .status = gettext_noop("Checking for incompatible \"aclitem\" data type"),
194 : : .report_filename = "tables_using_aclitem.txt",
195 : : .base_query =
196 : : "SELECT 'pg_catalog.aclitem'::pg_catalog.regtype AS oid",
197 : : .report_text =
198 : : gettext_noop("Your installation contains the \"aclitem\" data type in user tables.\n"
199 : : "The internal format of \"aclitem\" changed in PostgreSQL version 16\n"
200 : : "so this cluster cannot currently be upgraded. You can drop the\n"
201 : : "problem columns and restart the upgrade.\n"),
202 : : .threshold_version = 1500
203 : : },
204 : :
205 : : /*
206 : : * It's no longer allowed to create tables or views with "unknown"-type
207 : : * columns. We do not complain about views with such columns, because
208 : : * they should get silently converted to "text" columns during the DDL
209 : : * dump and reload; it seems unlikely to be worth making users do that by
210 : : * hand. However, if there's a table with such a column, the DDL reload
211 : : * will fail, so we should pre-detect that rather than failing
212 : : * mid-upgrade. Worse, if there's a matview with such a column, the DDL
213 : : * reload will silently change it to "text" which won't match the on-disk
214 : : * storage (which is like "cstring"). So we *must* reject that.
215 : : */
216 : : {
217 : : .status = gettext_noop("Checking for invalid \"unknown\" user columns"),
218 : : .report_filename = "tables_using_unknown.txt",
219 : : .base_query =
220 : : "SELECT 'pg_catalog.unknown'::pg_catalog.regtype AS oid",
221 : : .report_text =
222 : : gettext_noop("Your installation contains the \"unknown\" data type in user tables.\n"
223 : : "This data type is no longer allowed in tables, so this cluster\n"
224 : : "cannot currently be upgraded. You can drop the problem columns\n"
225 : : "and restart the upgrade.\n"),
226 : : .threshold_version = 906
227 : : },
228 : :
229 : : /*
230 : : * PG 12 changed the 'sql_identifier' type storage to be based on name,
231 : : * not varchar, which breaks on-disk format for existing data. So we need
232 : : * to prevent upgrade when used in user objects (tables, indexes, ...). In
233 : : * 12, the sql_identifier data type was switched from name to varchar,
234 : : * which does affect the storage (name is by-ref, but not varlena). This
235 : : * means user tables using sql_identifier for columns are broken because
236 : : * the on-disk format is different.
237 : : */
238 : : {
239 : : .status = gettext_noop("Checking for invalid \"sql_identifier\" user columns"),
240 : : .report_filename = "tables_using_sql_identifier.txt",
241 : : .base_query =
242 : : "SELECT 'information_schema.sql_identifier'::pg_catalog.regtype AS oid",
243 : : .report_text =
244 : : gettext_noop("Your installation contains the \"sql_identifier\" data type in user tables.\n"
245 : : "The on-disk format for this data type has changed, so this\n"
246 : : "cluster cannot currently be upgraded. You can drop the problem\n"
247 : : "columns and restart the upgrade.\n"),
248 : : .threshold_version = 1100
249 : : },
250 : :
251 : : /*
252 : : * JSONB changed its storage format during 9.4 beta, so check for it.
253 : : */
254 : : {
255 : : .status = gettext_noop("Checking for incompatible \"jsonb\" data type in user tables"),
256 : : .report_filename = "tables_using_jsonb.txt",
257 : : .base_query =
258 : : "SELECT 'pg_catalog.jsonb'::pg_catalog.regtype AS oid",
259 : : .report_text =
260 : : gettext_noop("Your installation contains the \"jsonb\" data type in user tables.\n"
261 : : "The internal format of \"jsonb\" changed during 9.4 beta so this\n"
262 : : "cluster cannot currently be upgraded. You can drop the problem \n"
263 : : "columns and restart the upgrade.\n"),
264 : : .threshold_version = MANUAL_CHECK,
265 : : .version_hook = jsonb_9_4_check_applicable
266 : : },
267 : :
268 : : /*
269 : : * PG 12 removed types abstime, reltime, tinterval.
270 : : */
271 : : {
272 : : .status = gettext_noop("Checking for removed \"abstime\" data type in user tables"),
273 : : .report_filename = "tables_using_abstime.txt",
274 : : .base_query =
275 : : "SELECT 'pg_catalog.abstime'::pg_catalog.regtype AS oid",
276 : : .report_text =
277 : : gettext_noop("Your installation contains the \"abstime\" data type in user tables.\n"
278 : : "The \"abstime\" type has been removed in PostgreSQL version 12,\n"
279 : : "so this cluster cannot currently be upgraded. You can drop the\n"
280 : : "problem columns, or change them to another data type, and restart\n"
281 : : "the upgrade.\n"),
282 : : .threshold_version = 1100
283 : : },
284 : : {
285 : : .status = gettext_noop("Checking for removed \"reltime\" data type in user tables"),
286 : : .report_filename = "tables_using_reltime.txt",
287 : : .base_query =
288 : : "SELECT 'pg_catalog.reltime'::pg_catalog.regtype AS oid",
289 : : .report_text =
290 : : gettext_noop("Your installation contains the \"reltime\" data type in user tables.\n"
291 : : "The \"reltime\" type has been removed in PostgreSQL version 12,\n"
292 : : "so this cluster cannot currently be upgraded. You can drop the\n"
293 : : "problem columns, or change them to another data type, and restart\n"
294 : : "the upgrade.\n"),
295 : : .threshold_version = 1100
296 : : },
297 : : {
298 : : .status = gettext_noop("Checking for removed \"tinterval\" data type in user tables"),
299 : : .report_filename = "tables_using_tinterval.txt",
300 : : .base_query =
301 : : "SELECT 'pg_catalog.tinterval'::pg_catalog.regtype AS oid",
302 : : .report_text =
303 : : gettext_noop("Your installation contains the \"tinterval\" data type in user tables.\n"
304 : : "The \"tinterval\" type has been removed in PostgreSQL version 12,\n"
305 : : "so this cluster cannot currently be upgraded. You can drop the\n"
306 : : "problem columns, or change them to another data type, and restart\n"
307 : : "the upgrade.\n"),
308 : : .threshold_version = 1100
309 : : },
310 : :
311 : : /* End of checks marker, must remain last */
312 : : {
313 : : NULL, NULL, NULL, NULL, 0, NULL
314 : : }
315 : : };
316 : :
317 : : /*
318 : : * check_for_data_types_usage()
319 : : * Detect whether there are any stored columns depending on given type(s)
320 : : *
321 : : * If so, write a report to the given file name and signal a failure to the
322 : : * user.
323 : : *
324 : : * The checks to run are defined in a DataTypesUsageChecks structure where
325 : : * each check has a metadata for explaining errors to the user, a base_query,
326 : : * a report filename and a function pointer hook for validating if the check
327 : : * should be executed given the cluster at hand.
328 : : *
329 : : * base_query should be a SELECT yielding a single column named "oid",
330 : : * containing the pg_type OIDs of one or more types that are known to have
331 : : * inconsistent on-disk representations across server versions.
332 : : *
333 : : * We check for the type(s) in tables, matviews, and indexes, but not views;
334 : : * there's no storage involved in a view.
335 : : */
336 : : static void
26 dgustafsson@postgres 337 :GNC 6 : check_for_data_types_usage(ClusterInfo *cluster, DataTypesUsageChecks * checks)
338 : : {
339 : 6 : bool found = false;
340 : : bool *results;
341 : : PQExpBufferData report;
342 : 6 : DataTypesUsageChecks *tmp = checks;
343 : 6 : int n_data_types_usage_checks = 0;
344 : :
345 : 6 : prep_status("Checking for data type usage");
346 : :
347 : : /* Gather number of checks to perform */
348 [ + + ]: 66 : while (tmp->status != NULL)
349 : : {
350 : 60 : n_data_types_usage_checks++;
351 : 60 : tmp++;
352 : : }
353 : :
354 : : /* Prepare an array to store the results of checks in */
355 : 6 : results = pg_malloc0(sizeof(bool) * n_data_types_usage_checks);
356 : :
357 : : /*
358 : : * Connect to each database in the cluster and run all defined checks
359 : : * against that database before trying the next one.
360 : : */
361 [ + + ]: 26 : for (int dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
362 : : {
363 : 20 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
364 : 20 : PGconn *conn = connectToServer(cluster, active_db->db_name);
365 : :
366 [ + + ]: 220 : for (int checknum = 0; checknum < n_data_types_usage_checks; checknum++)
367 : : {
368 : : PGresult *res;
369 : : int ntups;
370 : : int i_nspname;
371 : : int i_relname;
372 : : int i_attname;
373 : 200 : FILE *script = NULL;
374 : 200 : bool db_used = false;
375 : : char output_path[MAXPGPATH];
376 : 200 : DataTypesUsageChecks *cur_check = &checks[checknum];
377 : :
378 [ + + ]: 200 : if (cur_check->threshold_version == MANUAL_CHECK)
379 : : {
380 [ - + ]: 20 : Assert(cur_check->version_hook);
381 : :
382 : : /*
383 : : * Make sure that the check applies to the current cluster
384 : : * version and skip if not. If no check hook has been defined
385 : : * we run the check for all versions.
386 : : */
387 [ + - ]: 20 : if (!cur_check->version_hook(cluster))
388 : 160 : continue;
389 : : }
390 [ + + ]: 180 : else if (cur_check->threshold_version != ALL_VERSIONS)
391 : : {
392 [ + - ]: 140 : if (GET_MAJOR_VERSION(cluster->major_version) > cur_check->threshold_version)
393 : 140 : continue;
394 : : }
395 : : else
396 [ - + ]: 40 : Assert(cur_check->threshold_version == ALL_VERSIONS);
397 : :
398 : 40 : snprintf(output_path, sizeof(output_path), "%s/%s",
399 : : log_opts.basedir,
400 : : cur_check->report_filename);
401 : :
402 : : /*
403 : : * The type(s) of interest might be wrapped in a domain, array,
404 : : * composite, or range, and these container types can be nested
405 : : * (to varying extents depending on server version, but that's not
406 : : * of concern here). To handle all these cases we need a
407 : : * recursive CTE.
408 : : */
409 : 40 : res = executeQueryOrDie(conn,
410 : : "WITH RECURSIVE oids AS ( "
411 : : /* start with the type(s) returned by base_query */
412 : : " %s "
413 : : " UNION ALL "
414 : : " SELECT * FROM ( "
415 : : /* inner WITH because we can only reference the CTE once */
416 : : " WITH x AS (SELECT oid FROM oids) "
417 : : /* domains on any type selected so far */
418 : : " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
419 : : " UNION ALL "
420 : : /* arrays over any type selected so far */
421 : : " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typelem = x.oid AND typtype = 'b' "
422 : : " UNION ALL "
423 : : /* composite types containing any type selected so far */
424 : : " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
425 : : " WHERE t.typtype = 'c' AND "
426 : : " t.oid = c.reltype AND "
427 : : " c.oid = a.attrelid AND "
428 : : " NOT a.attisdropped AND "
429 : : " a.atttypid = x.oid "
430 : : " UNION ALL "
431 : : /* ranges containing any type selected so far */
432 : : " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_range r, x "
433 : : " WHERE t.typtype = 'r' AND r.rngtypid = t.oid AND r.rngsubtype = x.oid"
434 : : " ) foo "
435 : : ") "
436 : : /* now look for stored columns of any such type */
437 : : "SELECT n.nspname, c.relname, a.attname "
438 : : "FROM pg_catalog.pg_class c, "
439 : : " pg_catalog.pg_namespace n, "
440 : : " pg_catalog.pg_attribute a "
441 : : "WHERE c.oid = a.attrelid AND "
442 : : " NOT a.attisdropped AND "
443 : : " a.atttypid IN (SELECT oid FROM oids) AND "
444 : : " c.relkind IN ("
445 : : CppAsString2(RELKIND_RELATION) ", "
446 : : CppAsString2(RELKIND_MATVIEW) ", "
447 : : CppAsString2(RELKIND_INDEX) ") AND "
448 : : " c.relnamespace = n.oid AND "
449 : : /* exclude possible orphaned temp tables */
450 : : " n.nspname !~ '^pg_temp_' AND "
451 : : " n.nspname !~ '^pg_toast_temp_' AND "
452 : : /* exclude system catalogs, too */
453 : : " n.nspname NOT IN ('pg_catalog', 'information_schema')",
454 : : cur_check->base_query);
455 : :
456 : 40 : ntups = PQntuples(res);
457 : :
458 : : /*
459 : : * The datatype was found, so extract the data and log to the
460 : : * requested filename. We need to open the file for appending
461 : : * since the check might have already found the type in another
462 : : * database earlier in the loop.
463 : : */
464 [ - + ]: 40 : if (ntups)
465 : : {
466 : : /*
467 : : * Make sure we have a buffer to save reports to now that we
468 : : * found a first failing check.
469 : : */
26 dgustafsson@postgres 470 [ # # ]:UNC 0 : if (!found)
471 : 0 : initPQExpBuffer(&report);
472 : 0 : found = true;
473 : :
474 : : /*
475 : : * If this is the first time we see an error for the check in
476 : : * question then print a status message of the failure.
477 : : */
478 [ # # ]: 0 : if (!results[checknum])
479 : : {
480 : 0 : pg_log(PG_REPORT, " failed check: %s", _(cur_check->status));
481 : 0 : appendPQExpBuffer(&report, "\n%s\n%s %s\n",
482 : : _(cur_check->report_text),
483 : : _("A list of the problem columns is in the file:"),
484 : : output_path);
485 : : }
486 : 0 : results[checknum] = true;
487 : :
488 : 0 : i_nspname = PQfnumber(res, "nspname");
489 : 0 : i_relname = PQfnumber(res, "relname");
490 : 0 : i_attname = PQfnumber(res, "attname");
491 : :
492 [ # # ]: 0 : for (int rowno = 0; rowno < ntups; rowno++)
493 : : {
494 [ # # # # ]: 0 : if (script == NULL && (script = fopen_priv(output_path, "a")) == NULL)
495 : 0 : pg_fatal("could not open file \"%s\": %m", output_path);
496 : :
497 [ # # ]: 0 : if (!db_used)
498 : : {
499 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
500 : 0 : db_used = true;
501 : : }
502 : 0 : fprintf(script, " %s.%s.%s\n",
503 : : PQgetvalue(res, rowno, i_nspname),
504 : : PQgetvalue(res, rowno, i_relname),
505 : : PQgetvalue(res, rowno, i_attname));
506 : : }
507 : :
508 [ # # ]: 0 : if (script)
509 : : {
510 : 0 : fclose(script);
511 : 0 : script = NULL;
512 : : }
513 : : }
514 : :
26 dgustafsson@postgres 515 :GNC 40 : PQclear(res);
516 : : }
517 : :
518 : 20 : PQfinish(conn);
519 : : }
520 : :
521 [ - + ]: 6 : if (found)
26 dgustafsson@postgres 522 :UNC 0 : pg_fatal("Data type checks failed: %s", report.data);
523 : :
21 tgl@sss.pgh.pa.us 524 :GNC 6 : pg_free(results);
525 : :
26 dgustafsson@postgres 526 : 6 : check_ok();
527 : 6 : }
528 : :
529 : : /*
530 : : * fix_path_separator
531 : : * For non-Windows, just return the argument.
532 : : * For Windows convert any forward slash to a backslash
533 : : * such as is suitable for arguments to builtin commands
534 : : * like RMDIR and DEL.
535 : : */
536 : : static char *
4241 andrew@dunslane.net 537 :CBC 3 : fix_path_separator(char *path)
538 : : {
539 : : #ifdef WIN32
540 : :
541 : : char *result;
542 : : char *c;
543 : :
544 : : result = pg_strdup(path);
545 : :
546 : : for (c = result; *c != '\0'; c++)
547 : : if (*c == '/')
548 : : *c = '\\';
549 : :
550 : : return result;
551 : : #else
552 : :
553 : 3 : return path;
554 : : #endif
555 : : }
556 : :
557 : : void
4098 bruce@momjian.us 558 : 9 : output_check_banner(bool live_check)
559 : : {
560 [ + + - + ]: 9 : if (user_opts.check && live_check)
561 : : {
2427 peter_e@gmx.net 562 :UBC 0 : pg_log(PG_REPORT,
563 : : "Performing Consistency Checks on Old Live Server\n"
564 : : "------------------------------------------------");
565 : : }
566 : : else
567 : : {
2427 peter_e@gmx.net 568 :CBC 9 : pg_log(PG_REPORT,
569 : : "Performing Consistency Checks\n"
570 : : "-----------------------------");
571 : : }
5086 bruce@momjian.us 572 : 9 : }
573 : :
574 : :
575 : : void
3520 576 : 9 : check_and_dump_old_cluster(bool live_check)
577 : : {
578 : : /* -- OLD -- */
579 : :
5086 580 [ + - ]: 9 : if (!live_check)
4098 581 : 9 : start_postmaster(&old_cluster, true);
582 : :
583 : : /*
584 : : * Extract a list of databases, tables, and logical replication slots from
585 : : * the old cluster.
586 : : */
171 akapila@postgresql.o 587 :GNC 9 : get_db_rel_and_slot_infos(&old_cluster, live_check);
588 : :
4926 bruce@momjian.us 589 :CBC 8 : init_tablespaces();
590 : :
591 : 8 : get_loadable_libraries();
592 : :
593 : :
594 : : /*
595 : : * Check for various failure cases
596 : : */
3541 597 : 8 : check_is_install_user(&old_cluster);
3256 598 : 8 : check_proper_datallowconn(&old_cluster);
4688 599 : 8 : check_for_prepared_transactions(&old_cluster);
4852 600 : 8 : check_for_isn_and_int8_passing_mismatch(&old_cluster);
601 : :
171 akapila@postgresql.o 602 [ + - ]:GNC 8 : if (GET_MAJOR_VERSION(old_cluster.major_version) >= 1700)
603 : : {
604 : : /*
605 : : * Logical replication slots can be migrated since PG17. See comments
606 : : * atop get_old_cluster_logical_slot_infos().
607 : : */
608 : 8 : check_old_cluster_for_valid_slots(live_check);
609 : :
610 : : /*
611 : : * Subscriptions and their dependencies can be migrated since PG17.
612 : : * See comments atop get_db_subscription_count().
613 : : */
103 614 : 7 : check_old_cluster_subscription_state();
615 : : }
616 : :
26 dgustafsson@postgres 617 : 6 : check_for_data_types_usage(&old_cluster, data_types_usage_checks);
618 : :
619 : : /*
620 : : * PG 14 changed the function signature of encoding conversion functions.
621 : : * Conversions from older versions cannot be upgraded automatically
622 : : * because the user-defined functions used by the encoding conversions
623 : : * need to be changed to match the new signature.
624 : : */
1109 heikki.linnakangas@i 625 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
1109 heikki.linnakangas@i 626 :UBC 0 : check_for_user_defined_encoding_conversions(&old_cluster);
627 : :
628 : : /*
629 : : * Pre-PG 14 allowed user defined postfix operators, which are not
630 : : * supported anymore. Verify there are none, iff applicable.
631 : : */
1305 tgl@sss.pgh.pa.us 632 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
1305 tgl@sss.pgh.pa.us 633 :UBC 0 : check_for_user_defined_postfix_ops(&old_cluster);
634 : :
635 : : /*
636 : : * PG 14 changed polymorphic functions from anyarray to
637 : : * anycompatiblearray.
638 : : */
649 tgl@sss.pgh.pa.us 639 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
649 tgl@sss.pgh.pa.us 640 :UBC 0 : check_for_incompatible_polymorphics(&old_cluster);
641 : :
642 : : /*
643 : : * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
644 : : * supported anymore. Verify there are none, iff applicable.
645 : : */
1972 andres@anarazel.de 646 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1100)
1972 andres@anarazel.de 647 :UBC 0 : check_for_tables_with_oids(&old_cluster);
648 : :
649 : : /*
650 : : * Pre-PG 10 allowed tables with 'unknown' type columns and non WAL logged
651 : : * hash indexes
652 : : */
2636 tgl@sss.pgh.pa.us 653 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
654 : : {
2522 rhaas@postgresql.org 655 [ # # ]:UBC 0 : if (user_opts.check)
656 : 0 : old_9_6_invalidate_hash_indexes(&old_cluster, true);
657 : : }
658 : :
659 : : /* 9.5 and below should not have roles starting with pg_ */
2928 sfrost@snowman.net 660 [ - + ]:CBC 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 905)
2928 sfrost@snowman.net 661 :UBC 0 : check_for_pg_role_prefix(&old_cluster);
662 : :
663 : : /*
664 : : * While not a check option, we do this now because this is the only time
665 : : * the old server is running.
666 : : */
4926 bruce@momjian.us 667 [ + + ]:CBC 6 : if (!user_opts.check)
668 : 4 : generate_old_dump();
669 : :
5086 670 [ + - ]: 6 : if (!live_check)
4738 671 : 6 : stop_postmaster(false);
5086 672 : 6 : }
673 : :
674 : :
675 : : void
4926 676 : 6 : check_new_cluster(void)
677 : : {
171 akapila@postgresql.o 678 :GNC 6 : get_db_rel_and_slot_infos(&new_cluster, false);
679 : :
4744 bruce@momjian.us 680 :CBC 6 : check_new_cluster_is_empty();
681 : :
4926 682 : 6 : check_loadable_libraries();
683 : :
1985 peter_e@gmx.net 684 [ - + - - : 6 : switch (user_opts.transfer_mode)
- ]
685 : : {
1985 peter_e@gmx.net 686 :UBC 0 : case TRANSFER_MODE_CLONE:
687 : 0 : check_file_clone();
688 : 0 : break;
1985 peter_e@gmx.net 689 :CBC 6 : case TRANSFER_MODE_COPY:
690 : 6 : break;
39 tmunro@postgresql.or 691 :UNC 0 : case TRANSFER_MODE_COPY_FILE_RANGE:
692 : 0 : check_copy_file_range();
693 : 0 : break;
1985 peter_e@gmx.net 694 :UBC 0 : case TRANSFER_MODE_LINK:
695 : 0 : check_hard_link();
696 : 0 : break;
697 : : }
698 : :
3541 bruce@momjian.us 699 :CBC 6 : check_is_install_user(&new_cluster);
700 : :
4323 701 : 6 : check_for_prepared_transactions(&new_cluster);
702 : :
235 dgustafsson@postgres 703 :GNC 6 : check_for_new_tablespace_dir();
704 : :
171 akapila@postgresql.o 705 : 6 : check_new_cluster_logical_replication_slots();
706 : :
103 707 : 5 : check_new_cluster_subscription_configuration();
5086 bruce@momjian.us 708 :CBC 4 : }
709 : :
710 : :
711 : : void
4926 712 : 4 : report_clusters_compatible(void)
713 : : {
714 [ + + ]: 4 : if (user_opts.check)
715 : : {
642 tgl@sss.pgh.pa.us 716 : 1 : pg_log(PG_REPORT, "\n*Clusters are compatible*");
717 : : /* stops new cluster */
4738 bruce@momjian.us 718 : 1 : stop_postmaster(false);
719 : :
676 michael@paquier.xyz 720 : 1 : cleanup_output_dirs();
4757 peter_e@gmx.net 721 : 1 : exit(0);
722 : : }
723 : :
4926 bruce@momjian.us 724 : 3 : pg_log(PG_REPORT, "\n"
725 : : "If pg_upgrade fails after this point, you must re-initdb the\n"
726 : : "new cluster before continuing.");
5086 727 : 3 : }
728 : :
729 : :
730 : : void
2490 731 : 3 : issue_warnings_and_set_wal_level(void)
732 : : {
733 : : /*
734 : : * We unconditionally start/stop the new server because pg_resetwal -o set
735 : : * wal_level to 'minimum'. If the user is upgrading standby servers using
736 : : * the rsync instructions, they will need pg_upgrade to write its final
737 : : * WAL record showing wal_level as 'replica'.
738 : : */
739 : 3 : start_postmaster(&new_cluster, true);
740 : :
741 : : /* Reindex hash indexes for old < 10.0 */
2522 rhaas@postgresql.org 742 [ - + ]: 3 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
2522 rhaas@postgresql.org 743 :UBC 0 : old_9_6_invalidate_hash_indexes(&new_cluster, false);
744 : :
985 bruce@momjian.us 745 :CBC 3 : report_extension_updates(&new_cluster);
746 : :
2490 747 : 3 : stop_postmaster(false);
5086 748 : 3 : }
749 : :
750 : :
751 : : void
1252 magnus@hagander.net 752 : 3 : output_completion_banner(char *deletion_script_file_name)
753 : : {
754 : : PQExpBufferData user_specification;
755 : :
756 : 3 : initPQExpBuffer(&user_specification);
757 [ - + ]: 3 : if (os_info.user_specified)
758 : : {
1252 magnus@hagander.net 759 :UBC 0 : appendPQExpBufferStr(&user_specification, "-U ");
760 : 0 : appendShellString(&user_specification, os_info.user);
761 : 0 : appendPQExpBufferChar(&user_specification, ' ');
762 : : }
763 : :
1286 bruce@momjian.us 764 :CBC 3 : pg_log(PG_REPORT,
765 : : "Optimizer statistics are not transferred by pg_upgrade.\n"
766 : : "Once you start the new server, consider running:\n"
767 : : " %s/vacuumdb %s--all --analyze-in-stages", new_cluster.bindir, user_specification.data);
768 : :
4077 769 [ + - ]: 3 : if (deletion_script_file_name)
770 : 3 : pg_log(PG_REPORT,
771 : : "Running this script will delete the old cluster's data files:\n"
772 : : " %s",
773 : : deletion_script_file_name);
774 : : else
4077 bruce@momjian.us 775 :UBC 0 : pg_log(PG_REPORT,
776 : : "Could not create a script to delete the old cluster's data files\n"
777 : : "because user-defined tablespaces or the new cluster's data directory\n"
778 : : "exist in the old cluster directory. The old cluster's contents must\n"
779 : : "be deleted manually.");
780 : :
1252 magnus@hagander.net 781 :CBC 3 : termPQExpBuffer(&user_specification);
5086 bruce@momjian.us 782 : 3 : }
783 : :
784 : :
785 : : void
4926 786 : 9 : check_cluster_versions(void)
787 : : {
4680 788 : 9 : prep_status("Checking cluster versions");
789 : :
790 : : /* cluster versions should already have been obtained */
2341 tgl@sss.pgh.pa.us 791 [ - + ]: 9 : Assert(old_cluster.major_version != 0);
792 [ - + ]: 9 : Assert(new_cluster.major_version != 0);
793 : :
794 : : /*
795 : : * We allow upgrades from/to the same major version for alpha/beta
796 : : * upgrades
797 : : */
798 : :
852 799 [ - + ]: 9 : if (GET_MAJOR_VERSION(old_cluster.major_version) < 902)
642 tgl@sss.pgh.pa.us 800 :UBC 0 : pg_fatal("This utility can only upgrade from PostgreSQL version %s and later.",
801 : : "9.2");
802 : :
803 : : /* Only current PG version is supported as a target */
4926 bruce@momjian.us 804 [ - + ]:CBC 9 : if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
642 tgl@sss.pgh.pa.us 805 :UBC 0 : pg_fatal("This utility can only upgrade to PostgreSQL version %s.",
806 : : PG_MAJORVERSION);
807 : :
808 : : /*
809 : : * We can't allow downgrading because we use the target pg_dump, and
810 : : * pg_dump cannot operate on newer database versions, only current and
811 : : * older versions.
812 : : */
4926 bruce@momjian.us 813 [ - + ]:CBC 9 : if (old_cluster.major_version > new_cluster.major_version)
642 tgl@sss.pgh.pa.us 814 :UBC 0 : pg_fatal("This utility cannot be used to downgrade to older major PostgreSQL versions.");
815 : :
816 : : /* Ensure binaries match the designated data directories */
4680 bruce@momjian.us 817 :CBC 9 : if (GET_MAJOR_VERSION(old_cluster.major_version) !=
818 [ - + ]: 9 : GET_MAJOR_VERSION(old_cluster.bin_version))
642 tgl@sss.pgh.pa.us 819 :UBC 0 : pg_fatal("Old cluster data and binary directories are from different major versions.");
4680 bruce@momjian.us 820 :CBC 9 : if (GET_MAJOR_VERSION(new_cluster.major_version) !=
821 [ - + ]: 9 : GET_MAJOR_VERSION(new_cluster.bin_version))
642 tgl@sss.pgh.pa.us 822 :UBC 0 : pg_fatal("New cluster data and binary directories are from different major versions.");
823 : :
4680 bruce@momjian.us 824 :CBC 9 : check_ok();
5086 825 : 9 : }
826 : :
827 : :
828 : : void
4926 829 : 9 : check_cluster_compatibility(bool live_check)
830 : : {
831 : : /* get/check pg_control data of servers */
832 : 9 : get_control_data(&old_cluster, live_check);
833 : 9 : get_control_data(&new_cluster, false);
834 : 9 : check_control_data(&old_cluster.controldata, &new_cluster.controldata);
835 : :
4241 836 [ - + - - ]: 9 : if (live_check && old_cluster.port == new_cluster.port)
3848 peter_e@gmx.net 837 :UBC 0 : pg_fatal("When checking a live server, "
838 : : "the old and new port numbers must be different.");
5086 bruce@momjian.us 839 :CBC 9 : }
840 : :
841 : :
842 : : static void
4744 843 : 6 : check_new_cluster_is_empty(void)
844 : : {
845 : : int dbnum;
846 : :
4926 847 [ + + ]: 18 : for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
848 : : {
849 : : int relnum;
850 : 12 : RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr;
851 : :
5086 852 [ + + ]: 36 : for (relnum = 0; relnum < rel_arr->nrels;
853 : 24 : relnum++)
854 : : {
855 : : /* pg_largeobject and its index should be skipped */
856 [ - + ]: 24 : if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0)
642 tgl@sss.pgh.pa.us 857 :UBC 0 : pg_fatal("New cluster database \"%s\" is not empty: found relation \"%s.%s\"",
2158 peter_e@gmx.net 858 : 0 : new_cluster.dbarr.dbs[dbnum].db_name,
859 : 0 : rel_arr->rels[relnum].nspname,
860 : 0 : rel_arr->rels[relnum].relname);
861 : : }
862 : : }
3474 heikki.linnakangas@i 863 :CBC 6 : }
864 : :
865 : : /*
866 : : * A previous run of pg_upgrade might have failed and the new cluster
867 : : * directory recreated, but they might have forgotten to remove
868 : : * the new cluster's tablespace directories. Therefore, check that
869 : : * new cluster tablespace directories do not already exist. If
870 : : * they do, it would cause an error while restoring global objects.
871 : : * This allows the failure to be detected at check time, rather than
872 : : * during schema restore.
873 : : */
874 : : static void
235 dgustafsson@postgres 875 :GNC 6 : check_for_new_tablespace_dir(void)
876 : : {
877 : : int tblnum;
878 : : char new_tablespace_dir[MAXPGPATH];
879 : :
1277 bruce@momjian.us 880 :CBC 6 : prep_status("Checking for new cluster tablespace directories");
881 : :
882 [ - + ]: 6 : for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
883 : : {
884 : : struct stat statbuf;
885 : :
1277 bruce@momjian.us 886 :UBC 0 : snprintf(new_tablespace_dir, MAXPGPATH, "%s%s",
1068 tgl@sss.pgh.pa.us 887 : 0 : os_info.old_tablespaces[tblnum],
888 : : new_cluster.tablespace_suffix);
889 : :
1277 bruce@momjian.us 890 [ # # # # ]: 0 : if (stat(new_tablespace_dir, &statbuf) == 0 || errno != ENOENT)
642 tgl@sss.pgh.pa.us 891 : 0 : pg_fatal("new cluster tablespace directory already exists: \"%s\"",
892 : : new_tablespace_dir);
893 : : }
894 : :
1277 bruce@momjian.us 895 :CBC 6 : check_ok();
896 : 6 : }
897 : :
898 : : /*
899 : : * create_script_for_old_cluster_deletion()
900 : : *
901 : : * This is particularly useful for tablespace deletion.
902 : : */
903 : : void
4680 904 : 3 : create_script_for_old_cluster_deletion(char **deletion_script_file_name)
905 : : {
5086 906 : 3 : FILE *script = NULL;
907 : : int tblnum;
908 : : char old_cluster_pgdata[MAXPGPATH],
909 : : new_cluster_pgdata[MAXPGPATH];
910 : :
3473 911 : 3 : *deletion_script_file_name = psprintf("%sdelete_old_cluster.%s",
912 : : SCRIPT_PREFIX, SCRIPT_EXT);
913 : :
2978 914 : 3 : strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH);
915 : 3 : canonicalize_path(old_cluster_pgdata);
916 : :
917 : 3 : strlcpy(new_cluster_pgdata, new_cluster.pgdata, MAXPGPATH);
918 : 3 : canonicalize_path(new_cluster_pgdata);
919 : :
920 : : /* Some people put the new data directory inside the old one. */
921 [ - + ]: 3 : if (path_is_prefix_of_path(old_cluster_pgdata, new_cluster_pgdata))
922 : : {
2978 bruce@momjian.us 923 :UBC 0 : pg_log(PG_WARNING,
924 : : "\nWARNING: new data directory should not be inside the old data directory, i.e. %s", old_cluster_pgdata);
925 : :
926 : : /* Unlink file in case it is left over from a previous run. */
927 : 0 : unlink(*deletion_script_file_name);
928 : 0 : pg_free(*deletion_script_file_name);
929 : 0 : *deletion_script_file_name = NULL;
930 : 0 : return;
931 : : }
932 : :
933 : : /*
934 : : * Some users (oddly) create tablespaces inside the cluster data
935 : : * directory. We can't create a proper old cluster delete script in that
936 : : * case.
937 : : */
4077 bruce@momjian.us 938 [ - + ]:CBC 3 : for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
939 : : {
940 : : char old_tablespace_dir[MAXPGPATH];
941 : :
4077 bruce@momjian.us 942 :UBC 0 : strlcpy(old_tablespace_dir, os_info.old_tablespaces[tblnum], MAXPGPATH);
943 : 0 : canonicalize_path(old_tablespace_dir);
944 [ # # ]: 0 : if (path_is_prefix_of_path(old_cluster_pgdata, old_tablespace_dir))
945 : : {
946 : : /* reproduce warning from CREATE TABLESPACE that is in the log */
3274 947 : 0 : pg_log(PG_WARNING,
948 : : "\nWARNING: user-defined tablespace locations should not be inside the data directory, i.e. %s", old_tablespace_dir);
949 : :
950 : : /* Unlink file in case it is left over from a previous run. */
4077 951 : 0 : unlink(*deletion_script_file_name);
952 : 0 : pg_free(*deletion_script_file_name);
953 : 0 : *deletion_script_file_name = NULL;
954 : 0 : return;
955 : : }
956 : : }
957 : :
4077 bruce@momjian.us 958 :CBC 3 : prep_status("Creating script to delete old cluster");
959 : :
4416 960 [ - + ]: 3 : if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL)
33 michael@paquier.xyz 961 :UNC 0 : pg_fatal("could not open file \"%s\": %m",
962 : : *deletion_script_file_name);
963 : :
964 : : #ifndef WIN32
965 : : /* add shebang header */
5086 bruce@momjian.us 966 :CBC 3 : fprintf(script, "#!/bin/sh\n\n");
967 : : #endif
968 : :
969 : : /* delete old cluster's default tablespace */
3261 970 : 3 : fprintf(script, RMDIR_CMD " %c%s%c\n", PATH_QUOTE,
971 : : fix_path_separator(old_cluster.pgdata), PATH_QUOTE);
972 : :
973 : : /* delete old cluster's alternate tablespaces */
4113 974 [ - + ]: 3 : for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
975 : : {
976 : : /*
977 : : * Do the old cluster's per-database directories share a directory
978 : : * with a new version-specific tablespace?
979 : : */
4926 bruce@momjian.us 980 [ # # ]:UBC 0 : if (strlen(old_cluster.tablespace_suffix) == 0)
981 : : {
982 : : /* delete per-database directories */
983 : : int dbnum;
984 : :
5086 985 : 0 : fprintf(script, "\n");
986 : :
4548 987 [ # # ]: 0 : for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
1098 peter@eisentraut.org 988 : 0 : fprintf(script, RMDIR_CMD " %c%s%c%u%c\n", PATH_QUOTE,
4113 bruce@momjian.us 989 : 0 : fix_path_separator(os_info.old_tablespaces[tblnum]),
3261 990 : 0 : PATH_SEPARATOR, old_cluster.dbarr.dbs[dbnum].db_oid,
991 : : PATH_QUOTE);
992 : : }
993 : : else
994 : : {
3631 995 : 0 : char *suffix_path = pg_strdup(old_cluster.tablespace_suffix);
996 : :
997 : : /*
998 : : * Simply delete the tablespace directory, which might be ".old"
999 : : * or a version-specific subdirectory.
1000 : : */
3261 1001 : 0 : fprintf(script, RMDIR_CMD " %c%s%s%c\n", PATH_QUOTE,
3973 1002 : 0 : fix_path_separator(os_info.old_tablespaces[tblnum]),
1003 : : fix_path_separator(suffix_path), PATH_QUOTE);
3714 1004 : 0 : pfree(suffix_path);
1005 : : }
1006 : : }
1007 : :
5086 bruce@momjian.us 1008 :CBC 3 : fclose(script);
1009 : :
1010 : : #ifndef WIN32
1011 [ - + ]: 3 : if (chmod(*deletion_script_file_name, S_IRWXU) != 0)
33 michael@paquier.xyz 1012 :UNC 0 : pg_fatal("could not add execute permission to file \"%s\": %m",
1013 : : *deletion_script_file_name);
1014 : : #endif
1015 : :
4926 bruce@momjian.us 1016 :CBC 3 : check_ok();
1017 : : }
1018 : :
1019 : :
1020 : : /*
1021 : : * check_is_install_user()
1022 : : *
1023 : : * Check we are the install user, and that the new cluster
1024 : : * has no other users.
1025 : : */
1026 : : static void
3541 1027 : 14 : check_is_install_user(ClusterInfo *cluster)
1028 : : {
1029 : : PGresult *res;
4726 1030 : 14 : PGconn *conn = connectToServer(cluster, "template1");
1031 : :
3541 1032 : 14 : prep_status("Checking database user is the install user");
1033 : :
1034 : : /* Can't use pg_authid because only superusers can view it. */
4726 1035 : 14 : res = executeQueryOrDie(conn,
1036 : : "SELECT rolsuper, oid "
1037 : : "FROM pg_catalog.pg_roles "
1038 : : "WHERE rolname = current_user "
1039 : : "AND rolname !~ '^pg_'");
1040 : :
1041 : : /*
1042 : : * We only allow the install user in the new cluster (see comment below)
1043 : : * and we preserve pg_authid.oid, so this must be the install user in the
1044 : : * old cluster too.
1045 : : */
3541 1046 [ + - ]: 14 : if (PQntuples(res) != 1 ||
1047 [ - + ]: 14 : atooid(PQgetvalue(res, 0, 1)) != BOOTSTRAP_SUPERUSERID)
642 tgl@sss.pgh.pa.us 1048 :UBC 0 : pg_fatal("database user \"%s\" is not the install user",
1049 : : os_info.user);
1050 : :
4323 bruce@momjian.us 1051 :CBC 14 : PQclear(res);
1052 : :
1053 : 14 : res = executeQueryOrDie(conn,
1054 : : "SELECT COUNT(*) "
1055 : : "FROM pg_catalog.pg_roles "
1056 : : "WHERE rolname !~ '^pg_'");
1057 : :
1058 [ - + ]: 14 : if (PQntuples(res) != 1)
642 tgl@sss.pgh.pa.us 1059 :UBC 0 : pg_fatal("could not determine the number of users");
1060 : :
1061 : : /*
1062 : : * We only allow the install user in the new cluster because other defined
1063 : : * users might match users defined in the old cluster and generate an
1064 : : * error during pg_dump restore.
1065 : : */
390 dgustafsson@postgres 1066 [ + + - + ]:CBC 14 : if (cluster == &new_cluster && strcmp(PQgetvalue(res, 0, 0), "1") != 0)
642 tgl@sss.pgh.pa.us 1067 :UBC 0 : pg_fatal("Only the install user can be defined in the new cluster.");
1068 : :
4726 bruce@momjian.us 1069 :CBC 14 : PQclear(res);
1070 : :
1071 : 14 : PQfinish(conn);
1072 : :
4724 1073 : 14 : check_ok();
4726 1074 : 14 : }
1075 : :
1076 : :
1077 : : /*
1078 : : * check_proper_datallowconn
1079 : : *
1080 : : * Ensure that all non-template0 databases allow connections since they
1081 : : * otherwise won't be restored; and that template0 explicitly doesn't allow
1082 : : * connections since it would make pg_dumpall --globals restore fail.
1083 : : */
1084 : : static void
3256 1085 : 8 : check_proper_datallowconn(ClusterInfo *cluster)
1086 : : {
1087 : : int dbnum;
1088 : : PGconn *conn_template1;
1089 : : PGresult *dbres;
1090 : : int ntups;
1091 : : int i_datname;
1092 : : int i_datallowconn;
752 dgustafsson@postgres 1093 : 8 : FILE *script = NULL;
1094 : : char output_path[MAXPGPATH];
1095 : :
3256 bruce@momjian.us 1096 : 8 : prep_status("Checking database connection settings");
1097 : :
752 dgustafsson@postgres 1098 : 8 : snprintf(output_path, sizeof(output_path), "%s/%s",
1099 : : log_opts.basedir,
1100 : : "databases_with_datallowconn_false.txt");
1101 : :
3256 bruce@momjian.us 1102 : 8 : conn_template1 = connectToServer(cluster, "template1");
1103 : :
1104 : : /* get database names */
1105 : 8 : dbres = executeQueryOrDie(conn_template1,
1106 : : "SELECT datname, datallowconn "
1107 : : "FROM pg_catalog.pg_database");
1108 : :
1109 : 8 : i_datname = PQfnumber(dbres, "datname");
1110 : 8 : i_datallowconn = PQfnumber(dbres, "datallowconn");
1111 : :
1112 : 8 : ntups = PQntuples(dbres);
1113 [ + + ]: 40 : for (dbnum = 0; dbnum < ntups; dbnum++)
1114 : : {
1115 : 32 : char *datname = PQgetvalue(dbres, dbnum, i_datname);
1116 : 32 : char *datallowconn = PQgetvalue(dbres, dbnum, i_datallowconn);
1117 : :
1118 [ + + ]: 32 : if (strcmp(datname, "template0") == 0)
1119 : : {
1120 : : /* avoid restore failure when pg_dumpall tries to create template0 */
1121 [ - + ]: 8 : if (strcmp(datallowconn, "t") == 0)
3256 bruce@momjian.us 1122 :UBC 0 : pg_fatal("template0 must not allow connections, "
1123 : : "i.e. its pg_database.datallowconn must be false");
1124 : : }
1125 : : else
1126 : : {
1127 : : /*
1128 : : * avoid datallowconn == false databases from being skipped on
1129 : : * restore
1130 : : */
3256 bruce@momjian.us 1131 [ - + ]:CBC 24 : if (strcmp(datallowconn, "f") == 0)
1132 : : {
752 dgustafsson@postgres 1133 [ # # # # ]:UBC 0 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1134 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1135 : :
752 dgustafsson@postgres 1136 :UBC 0 : fprintf(script, "%s\n", datname);
1137 : : }
1138 : : }
1139 : : }
1140 : :
3256 bruce@momjian.us 1141 :CBC 8 : PQclear(dbres);
1142 : :
1143 : 8 : PQfinish(conn_template1);
1144 : :
752 dgustafsson@postgres 1145 [ - + ]: 8 : if (script)
1146 : : {
592 dgustafsson@postgres 1147 :UBC 0 : fclose(script);
642 tgl@sss.pgh.pa.us 1148 : 0 : pg_log(PG_REPORT, "fatal");
752 dgustafsson@postgres 1149 : 0 : pg_fatal("All non-template0 databases must allow connections, i.e. their\n"
1150 : : "pg_database.datallowconn must be true. Your installation contains\n"
1151 : : "non-template0 databases with their pg_database.datallowconn set to\n"
1152 : : "false. Consider allowing connection for all non-template0 databases\n"
1153 : : "or drop the databases which do not allow connections. A list of\n"
1154 : : "databases with the problem is in the file:\n"
1155 : : " %s", output_path);
1156 : : }
1157 : : else
752 dgustafsson@postgres 1158 :CBC 8 : check_ok();
3256 bruce@momjian.us 1159 : 8 : }
1160 : :
1161 : :
1162 : : /*
1163 : : * check_for_prepared_transactions()
1164 : : *
1165 : : * Make sure there are no prepared transactions because the storage format
1166 : : * might have changed.
1167 : : */
1168 : : static void
4688 1169 : 14 : check_for_prepared_transactions(ClusterInfo *cluster)
1170 : : {
1171 : : PGresult *res;
1172 : 14 : PGconn *conn = connectToServer(cluster, "template1");
1173 : :
1174 : 14 : prep_status("Checking for prepared transactions");
1175 : :
1176 : 14 : res = executeQueryOrDie(conn,
1177 : : "SELECT * "
1178 : : "FROM pg_catalog.pg_prepared_xacts");
1179 : :
1180 [ - + ]: 14 : if (PQntuples(res) != 0)
1181 : : {
2466 alvherre@alvh.no-ip. 1182 [ # # ]:UBC 0 : if (cluster == &old_cluster)
642 tgl@sss.pgh.pa.us 1183 : 0 : pg_fatal("The source cluster contains prepared transactions");
1184 : : else
1185 : 0 : pg_fatal("The target cluster contains prepared transactions");
1186 : : }
1187 : :
4688 bruce@momjian.us 1188 :CBC 14 : PQclear(res);
1189 : :
1190 : 14 : PQfinish(conn);
1191 : :
1192 : 14 : check_ok();
1193 : 14 : }
1194 : :
1195 : :
1196 : : /*
1197 : : * check_for_isn_and_int8_passing_mismatch()
1198 : : *
1199 : : * contrib/isn relies on data type int8, and in 8.4 int8 can now be passed
1200 : : * by value. The schema dumps the CREATE TYPE PASSEDBYVALUE setting so
1201 : : * it must match for the old and new servers.
1202 : : */
1203 : : static void
4852 1204 : 8 : check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
1205 : : {
1206 : : int dbnum;
5012 1207 : 8 : FILE *script = NULL;
1208 : : char output_path[MAXPGPATH];
1209 : :
4714 peter_e@gmx.net 1210 : 8 : prep_status("Checking for contrib/isn with bigint-passing mismatch");
1211 : :
4926 bruce@momjian.us 1212 : 8 : if (old_cluster.controldata.float8_pass_by_value ==
1213 [ + - ]: 8 : new_cluster.controldata.float8_pass_by_value)
1214 : : {
1215 : : /* no mismatch */
1216 : 8 : check_ok();
5012 1217 : 8 : return;
1218 : : }
1219 : :
798 michael@paquier.xyz 1220 :UBC 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1221 : : log_opts.basedir,
1222 : : "contrib_isn_and_int8_pass_by_value.txt");
1223 : :
4852 bruce@momjian.us 1224 [ # # ]: 0 : for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1225 : : {
1226 : : PGresult *res;
5012 1227 : 0 : bool db_used = false;
1228 : : int ntups;
1229 : : int rowno;
1230 : : int i_nspname,
1231 : : i_proname;
4852 1232 : 0 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1233 : 0 : PGconn *conn = connectToServer(cluster, active_db->db_name);
1234 : :
1235 : : /* Find any functions coming from contrib/isn */
4926 1236 : 0 : res = executeQueryOrDie(conn,
1237 : : "SELECT n.nspname, p.proname "
1238 : : "FROM pg_catalog.pg_proc p, "
1239 : : " pg_catalog.pg_namespace n "
1240 : : "WHERE p.pronamespace = n.oid AND "
1241 : : " p.probin = '$libdir/isn'");
1242 : :
5012 1243 : 0 : ntups = PQntuples(res);
1244 : 0 : i_nspname = PQfnumber(res, "nspname");
1245 : 0 : i_proname = PQfnumber(res, "proname");
1246 [ # # ]: 0 : for (rowno = 0; rowno < ntups; rowno++)
1247 : : {
4416 1248 [ # # # # ]: 0 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1249 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
5012 bruce@momjian.us 1250 [ # # ]:UBC 0 : if (!db_used)
1251 : : {
1650 1252 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
5012 1253 : 0 : db_used = true;
1254 : : }
1255 : 0 : fprintf(script, " %s.%s\n",
1256 : : PQgetvalue(res, rowno, i_nspname),
1257 : : PQgetvalue(res, rowno, i_proname));
1258 : : }
1259 : :
1260 : 0 : PQclear(res);
1261 : :
1262 : 0 : PQfinish(conn);
1263 : : }
1264 : :
4786 1265 [ # # ]: 0 : if (script)
1266 : : {
592 dgustafsson@postgres 1267 : 0 : fclose(script);
642 tgl@sss.pgh.pa.us 1268 : 0 : pg_log(PG_REPORT, "fatal");
3848 peter_e@gmx.net 1269 : 0 : pg_fatal("Your installation contains \"contrib/isn\" functions which rely on the\n"
1270 : : "bigint data type. Your old and new clusters pass bigint values\n"
1271 : : "differently so this cluster cannot currently be upgraded. You can\n"
1272 : : "manually dump databases in the old cluster that use \"contrib/isn\"\n"
1273 : : "facilities, drop them, perform the upgrade, and then restore them. A\n"
1274 : : "list of the problem functions is in the file:\n"
1275 : : " %s", output_path);
1276 : : }
1277 : : else
4926 bruce@momjian.us 1278 : 0 : check_ok();
1279 : : }
1280 : :
1281 : : /*
1282 : : * Verify that no user defined postfix operators exist.
1283 : : */
1284 : : static void
1305 tgl@sss.pgh.pa.us 1285 : 0 : check_for_user_defined_postfix_ops(ClusterInfo *cluster)
1286 : : {
1287 : : int dbnum;
1288 : 0 : FILE *script = NULL;
1289 : : char output_path[MAXPGPATH];
1290 : :
1291 : 0 : prep_status("Checking for user-defined postfix operators");
1292 : :
798 michael@paquier.xyz 1293 : 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1294 : : log_opts.basedir,
1295 : : "postfix_ops.txt");
1296 : :
1297 : : /* Find any user defined postfix operators */
1305 tgl@sss.pgh.pa.us 1298 [ # # ]: 0 : for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1299 : : {
1300 : : PGresult *res;
1301 : 0 : bool db_used = false;
1302 : : int ntups;
1303 : : int rowno;
1304 : : int i_oproid,
1305 : : i_oprnsp,
1306 : : i_oprname,
1307 : : i_typnsp,
1308 : : i_typname;
1309 : 0 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1310 : 0 : PGconn *conn = connectToServer(cluster, active_db->db_name);
1311 : :
1312 : : /*
1313 : : * The query below hardcodes FirstNormalObjectId as 16384 rather than
1314 : : * interpolating that C #define into the query because, if that
1315 : : * #define is ever changed, the cutoff we want to use is the value
1316 : : * used by pre-version 14 servers, not that of some future version.
1317 : : */
1318 : 0 : res = executeQueryOrDie(conn,
1319 : : "SELECT o.oid AS oproid, "
1320 : : " n.nspname AS oprnsp, "
1321 : : " o.oprname, "
1322 : : " tn.nspname AS typnsp, "
1323 : : " t.typname "
1324 : : "FROM pg_catalog.pg_operator o, "
1325 : : " pg_catalog.pg_namespace n, "
1326 : : " pg_catalog.pg_type t, "
1327 : : " pg_catalog.pg_namespace tn "
1328 : : "WHERE o.oprnamespace = n.oid AND "
1329 : : " o.oprleft = t.oid AND "
1330 : : " t.typnamespace = tn.oid AND "
1331 : : " o.oprright = 0 AND "
1332 : : " o.oid >= 16384");
1333 : 0 : ntups = PQntuples(res);
1334 : 0 : i_oproid = PQfnumber(res, "oproid");
1335 : 0 : i_oprnsp = PQfnumber(res, "oprnsp");
1336 : 0 : i_oprname = PQfnumber(res, "oprname");
1337 : 0 : i_typnsp = PQfnumber(res, "typnsp");
1338 : 0 : i_typname = PQfnumber(res, "typname");
1339 [ # # ]: 0 : for (rowno = 0; rowno < ntups; rowno++)
1340 : : {
1341 [ # # # # ]: 0 : if (script == NULL &&
1342 : 0 : (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1343 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1305 tgl@sss.pgh.pa.us 1344 [ # # ]:UBC 0 : if (!db_used)
1345 : : {
1346 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
1347 : 0 : db_used = true;
1348 : : }
1349 : 0 : fprintf(script, " (oid=%s) %s.%s (%s.%s, NONE)\n",
1350 : : PQgetvalue(res, rowno, i_oproid),
1351 : : PQgetvalue(res, rowno, i_oprnsp),
1352 : : PQgetvalue(res, rowno, i_oprname),
1353 : : PQgetvalue(res, rowno, i_typnsp),
1354 : : PQgetvalue(res, rowno, i_typname));
1355 : : }
1356 : :
1357 : 0 : PQclear(res);
1358 : :
1359 : 0 : PQfinish(conn);
1360 : : }
1361 : :
1362 [ # # ]: 0 : if (script)
1363 : : {
592 dgustafsson@postgres 1364 : 0 : fclose(script);
642 tgl@sss.pgh.pa.us 1365 : 0 : pg_log(PG_REPORT, "fatal");
1305 1366 : 0 : pg_fatal("Your installation contains user-defined postfix operators, which are not\n"
1367 : : "supported anymore. Consider dropping the postfix operators and replacing\n"
1368 : : "them with prefix operators or function calls.\n"
1369 : : "A list of user-defined postfix operators is in the file:\n"
1370 : : " %s", output_path);
1371 : : }
1372 : : else
1373 : 0 : check_ok();
1374 : 0 : }
1375 : :
1376 : : /*
1377 : : * check_for_incompatible_polymorphics()
1378 : : *
1379 : : * Make sure nothing is using old polymorphic functions with
1380 : : * anyarray/anyelement rather than the new anycompatible variants.
1381 : : */
1382 : : static void
649 1383 : 0 : check_for_incompatible_polymorphics(ClusterInfo *cluster)
1384 : : {
1385 : : PGresult *res;
1386 : 0 : FILE *script = NULL;
1387 : : char output_path[MAXPGPATH];
1388 : : PQExpBufferData old_polymorphics;
1389 : :
1390 : 0 : prep_status("Checking for incompatible polymorphic functions");
1391 : :
1392 : 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1393 : : log_opts.basedir,
1394 : : "incompatible_polymorphics.txt");
1395 : :
1396 : : /* The set of problematic functions varies a bit in different versions */
1397 : 0 : initPQExpBuffer(&old_polymorphics);
1398 : :
1399 : 0 : appendPQExpBufferStr(&old_polymorphics,
1400 : : "'array_append(anyarray,anyelement)'"
1401 : : ", 'array_cat(anyarray,anyarray)'"
1402 : : ", 'array_prepend(anyelement,anyarray)'");
1403 : :
1404 [ # # ]: 0 : if (GET_MAJOR_VERSION(cluster->major_version) >= 903)
1405 : 0 : appendPQExpBufferStr(&old_polymorphics,
1406 : : ", 'array_remove(anyarray,anyelement)'"
1407 : : ", 'array_replace(anyarray,anyelement,anyelement)'");
1408 : :
1409 [ # # ]: 0 : if (GET_MAJOR_VERSION(cluster->major_version) >= 905)
1410 : 0 : appendPQExpBufferStr(&old_polymorphics,
1411 : : ", 'array_position(anyarray,anyelement)'"
1412 : : ", 'array_position(anyarray,anyelement,integer)'"
1413 : : ", 'array_positions(anyarray,anyelement)'"
1414 : : ", 'width_bucket(anyelement,anyarray)'");
1415 : :
1416 [ # # ]: 0 : for (int dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1417 : : {
1418 : 0 : bool db_used = false;
1419 : 0 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1420 : 0 : PGconn *conn = connectToServer(cluster, active_db->db_name);
1421 : : int ntups;
1422 : : int i_objkind,
1423 : : i_objname;
1424 : :
1425 : : /*
1426 : : * The query below hardcodes FirstNormalObjectId as 16384 rather than
1427 : : * interpolating that C #define into the query because, if that
1428 : : * #define is ever changed, the cutoff we want to use is the value
1429 : : * used by pre-version 14 servers, not that of some future version.
1430 : : */
1431 : 0 : res = executeQueryOrDie(conn,
1432 : : /* Aggregate transition functions */
1433 : : "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1434 : : "FROM pg_proc AS p "
1435 : : "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1436 : : "JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
1437 : : "WHERE p.oid >= 16384 "
1438 : : "AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
1439 : : "AND a.aggtranstype = ANY(ARRAY['anyarray', 'anyelement']::regtype[]) "
1440 : :
1441 : : /* Aggregate final functions */
1442 : : "UNION ALL "
1443 : : "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
1444 : : "FROM pg_proc AS p "
1445 : : "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
1446 : : "JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
1447 : : "WHERE p.oid >= 16384 "
1448 : : "AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
1449 : : "AND a.aggtranstype = ANY(ARRAY['anyarray', 'anyelement']::regtype[]) "
1450 : :
1451 : : /* Operators */
1452 : : "UNION ALL "
1453 : : "SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
1454 : : "FROM pg_operator AS op "
1455 : : "WHERE op.oid >= 16384 "
1456 : : "AND oprcode = ANY(ARRAY[%s]::regprocedure[]) "
1457 : : "AND oprleft = ANY(ARRAY['anyarray', 'anyelement']::regtype[]);",
1458 : : old_polymorphics.data,
1459 : : old_polymorphics.data,
1460 : : old_polymorphics.data);
1461 : :
1462 : 0 : ntups = PQntuples(res);
1463 : :
1464 : 0 : i_objkind = PQfnumber(res, "objkind");
1465 : 0 : i_objname = PQfnumber(res, "objname");
1466 : :
1467 [ # # ]: 0 : for (int rowno = 0; rowno < ntups; rowno++)
1468 : : {
1469 [ # # # # ]: 0 : if (script == NULL &&
1470 : 0 : (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1471 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
649 tgl@sss.pgh.pa.us 1472 [ # # ]:UBC 0 : if (!db_used)
1473 : : {
1474 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
1475 : 0 : db_used = true;
1476 : : }
1477 : :
1478 : 0 : fprintf(script, " %s: %s\n",
1479 : : PQgetvalue(res, rowno, i_objkind),
1480 : : PQgetvalue(res, rowno, i_objname));
1481 : : }
1482 : :
1483 : 0 : PQclear(res);
1484 : 0 : PQfinish(conn);
1485 : : }
1486 : :
1487 [ # # ]: 0 : if (script)
1488 : : {
1489 : 0 : fclose(script);
642 1490 : 0 : pg_log(PG_REPORT, "fatal");
649 1491 : 0 : pg_fatal("Your installation contains user-defined objects that refer to internal\n"
1492 : : "polymorphic functions with arguments of type \"anyarray\" or \"anyelement\".\n"
1493 : : "These user-defined objects must be dropped before upgrading and restored\n"
1494 : : "afterwards, changing them to refer to the new corresponding functions with\n"
1495 : : "arguments of type \"anycompatiblearray\" and \"anycompatible\".\n"
1496 : : "A list of the problematic objects is in the file:\n"
1497 : : " %s", output_path);
1498 : : }
1499 : : else
1500 : 0 : check_ok();
1501 : :
1502 : 0 : termPQExpBuffer(&old_polymorphics);
1503 : 0 : }
1504 : :
1505 : : /*
1506 : : * Verify that no tables are declared WITH OIDS.
1507 : : */
1508 : : static void
1972 andres@anarazel.de 1509 : 0 : check_for_tables_with_oids(ClusterInfo *cluster)
1510 : : {
1511 : : int dbnum;
1512 : 0 : FILE *script = NULL;
1513 : : char output_path[MAXPGPATH];
1514 : :
1812 alvherre@alvh.no-ip. 1515 : 0 : prep_status("Checking for tables WITH OIDS");
1516 : :
798 michael@paquier.xyz 1517 : 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1518 : : log_opts.basedir,
1519 : : "tables_with_oids.txt");
1520 : :
1521 : : /* Find any tables declared WITH OIDS */
1972 andres@anarazel.de 1522 [ # # ]: 0 : for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1523 : : {
1524 : : PGresult *res;
1525 : 0 : bool db_used = false;
1526 : : int ntups;
1527 : : int rowno;
1528 : : int i_nspname,
1529 : : i_relname;
1530 : 0 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1531 : 0 : PGconn *conn = connectToServer(cluster, active_db->db_name);
1532 : :
1533 : 0 : res = executeQueryOrDie(conn,
1534 : : "SELECT n.nspname, c.relname "
1535 : : "FROM pg_catalog.pg_class c, "
1536 : : " pg_catalog.pg_namespace n "
1537 : : "WHERE c.relnamespace = n.oid AND "
1538 : : " c.relhasoids AND"
1539 : : " n.nspname NOT IN ('pg_catalog')");
1540 : :
1541 : 0 : ntups = PQntuples(res);
1542 : 0 : i_nspname = PQfnumber(res, "nspname");
1543 : 0 : i_relname = PQfnumber(res, "relname");
1544 [ # # ]: 0 : for (rowno = 0; rowno < ntups; rowno++)
1545 : : {
1546 [ # # # # ]: 0 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1547 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1972 andres@anarazel.de 1548 [ # # ]:UBC 0 : if (!db_used)
1549 : : {
1650 bruce@momjian.us 1550 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
1972 andres@anarazel.de 1551 : 0 : db_used = true;
1552 : : }
1553 : 0 : fprintf(script, " %s.%s\n",
1554 : : PQgetvalue(res, rowno, i_nspname),
1555 : : PQgetvalue(res, rowno, i_relname));
1556 : : }
1557 : :
1558 : 0 : PQclear(res);
1559 : :
1560 : 0 : PQfinish(conn);
1561 : : }
1562 : :
1563 [ # # ]: 0 : if (script)
1564 : : {
592 dgustafsson@postgres 1565 : 0 : fclose(script);
642 tgl@sss.pgh.pa.us 1566 : 0 : pg_log(PG_REPORT, "fatal");
1600 bruce@momjian.us 1567 : 0 : pg_fatal("Your installation contains tables declared WITH OIDS, which is not\n"
1568 : : "supported anymore. Consider removing the oid column using\n"
1569 : : " ALTER TABLE ... SET WITHOUT OIDS;\n"
1570 : : "A list of tables with the problem is in the file:\n"
1571 : : " %s", output_path);
1572 : : }
1573 : : else
1972 andres@anarazel.de 1574 : 0 : check_ok();
1575 : 0 : }
1576 : :
1577 : :
1578 : : /*
1579 : : * check_for_pg_role_prefix()
1580 : : *
1581 : : * Versions older than 9.6 should not have any pg_* roles
1582 : : */
1583 : : static void
2928 sfrost@snowman.net 1584 : 0 : check_for_pg_role_prefix(ClusterInfo *cluster)
1585 : : {
1586 : : PGresult *res;
1587 : 0 : PGconn *conn = connectToServer(cluster, "template1");
1588 : : int ntups;
1589 : : int i_roloid;
1590 : : int i_rolname;
499 dgustafsson@postgres 1591 : 0 : FILE *script = NULL;
1592 : : char output_path[MAXPGPATH];
1593 : :
2427 peter_e@gmx.net 1594 : 0 : prep_status("Checking for roles starting with \"pg_\"");
1595 : :
499 dgustafsson@postgres 1596 : 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1597 : : log_opts.basedir,
1598 : : "pg_role_prefix.txt");
1599 : :
2928 sfrost@snowman.net 1600 : 0 : res = executeQueryOrDie(conn,
1601 : : "SELECT oid AS roloid, rolname "
1602 : : "FROM pg_catalog.pg_roles "
1603 : : "WHERE rolname ~ '^pg_'");
1604 : :
499 dgustafsson@postgres 1605 : 0 : ntups = PQntuples(res);
1606 : 0 : i_roloid = PQfnumber(res, "roloid");
1607 : 0 : i_rolname = PQfnumber(res, "rolname");
1608 [ # # ]: 0 : for (int rowno = 0; rowno < ntups; rowno++)
1609 : : {
1610 [ # # # # ]: 0 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1611 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
499 dgustafsson@postgres 1612 :UBC 0 : fprintf(script, "%s (oid=%s)\n",
1613 : : PQgetvalue(res, rowno, i_rolname),
1614 : : PQgetvalue(res, rowno, i_roloid));
1615 : : }
1616 : :
2928 sfrost@snowman.net 1617 : 0 : PQclear(res);
1618 : :
1619 : 0 : PQfinish(conn);
1620 : :
499 dgustafsson@postgres 1621 [ # # ]: 0 : if (script)
1622 : : {
1623 : 0 : fclose(script);
1624 : 0 : pg_log(PG_REPORT, "fatal");
1625 : 0 : pg_fatal("Your installation contains roles starting with \"pg_\".\n"
1626 : : "\"pg_\" is a reserved prefix for system roles. The cluster\n"
1627 : : "cannot be upgraded until these roles are renamed.\n"
1628 : : "A list of roles starting with \"pg_\" is in the file:\n"
1629 : : " %s", output_path);
1630 : : }
1631 : : else
1632 : 0 : check_ok();
2928 sfrost@snowman.net 1633 : 0 : }
1634 : :
1635 : : /*
1636 : : * Verify that no user-defined encoding conversions exist.
1637 : : */
1638 : : static void
1109 heikki.linnakangas@i 1639 : 0 : check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
1640 : : {
1641 : : int dbnum;
1642 : 0 : FILE *script = NULL;
1643 : : char output_path[MAXPGPATH];
1644 : :
1645 : 0 : prep_status("Checking for user-defined encoding conversions");
1646 : :
798 michael@paquier.xyz 1647 : 0 : snprintf(output_path, sizeof(output_path), "%s/%s",
1648 : : log_opts.basedir,
1649 : : "encoding_conversions.txt");
1650 : :
1651 : : /* Find any user defined encoding conversions */
1109 heikki.linnakangas@i 1652 [ # # ]: 0 : for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
1653 : : {
1654 : : PGresult *res;
1655 : 0 : bool db_used = false;
1656 : : int ntups;
1657 : : int rowno;
1658 : : int i_conoid,
1659 : : i_conname,
1660 : : i_nspname;
1661 : 0 : DbInfo *active_db = &cluster->dbarr.dbs[dbnum];
1662 : 0 : PGconn *conn = connectToServer(cluster, active_db->db_name);
1663 : :
1664 : : /*
1665 : : * The query below hardcodes FirstNormalObjectId as 16384 rather than
1666 : : * interpolating that C #define into the query because, if that
1667 : : * #define is ever changed, the cutoff we want to use is the value
1668 : : * used by pre-version 14 servers, not that of some future version.
1669 : : */
1670 : 0 : res = executeQueryOrDie(conn,
1671 : : "SELECT c.oid as conoid, c.conname, n.nspname "
1672 : : "FROM pg_catalog.pg_conversion c, "
1673 : : " pg_catalog.pg_namespace n "
1674 : : "WHERE c.connamespace = n.oid AND "
1675 : : " c.oid >= 16384");
1676 : 0 : ntups = PQntuples(res);
1677 : 0 : i_conoid = PQfnumber(res, "conoid");
1678 : 0 : i_conname = PQfnumber(res, "conname");
1679 : 0 : i_nspname = PQfnumber(res, "nspname");
1680 [ # # ]: 0 : for (rowno = 0; rowno < ntups; rowno++)
1681 : : {
1682 [ # # # # ]: 0 : if (script == NULL &&
1683 : 0 : (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1684 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1109 heikki.linnakangas@i 1685 [ # # ]:UBC 0 : if (!db_used)
1686 : : {
1687 : 0 : fprintf(script, "In database: %s\n", active_db->db_name);
1688 : 0 : db_used = true;
1689 : : }
1690 : 0 : fprintf(script, " (oid=%s) %s.%s\n",
1691 : : PQgetvalue(res, rowno, i_conoid),
1692 : : PQgetvalue(res, rowno, i_nspname),
1693 : : PQgetvalue(res, rowno, i_conname));
1694 : : }
1695 : :
1696 : 0 : PQclear(res);
1697 : :
1698 : 0 : PQfinish(conn);
1699 : : }
1700 : :
1701 [ # # ]: 0 : if (script)
1702 : : {
592 dgustafsson@postgres 1703 : 0 : fclose(script);
642 tgl@sss.pgh.pa.us 1704 : 0 : pg_log(PG_REPORT, "fatal");
1109 heikki.linnakangas@i 1705 : 0 : pg_fatal("Your installation contains user-defined encoding conversions.\n"
1706 : : "The conversion function parameters changed in PostgreSQL version 14\n"
1707 : : "so this cluster cannot currently be upgraded. You can remove the\n"
1708 : : "encoding conversions in the old cluster and restart the upgrade.\n"
1709 : : "A list of user-defined encoding conversions is in the file:\n"
1710 : : " %s", output_path);
1711 : : }
1712 : : else
1713 : 0 : check_ok();
1714 : 0 : }
1715 : :
1716 : : /*
1717 : : * check_new_cluster_logical_replication_slots()
1718 : : *
1719 : : * Verify that there are no logical replication slots on the new cluster and
1720 : : * that the parameter settings necessary for creating slots are sufficient.
1721 : : */
1722 : : static void
171 akapila@postgresql.o 1723 :GNC 6 : check_new_cluster_logical_replication_slots(void)
1724 : : {
1725 : : PGresult *res;
1726 : : PGconn *conn;
1727 : : int nslots_on_old;
1728 : : int nslots_on_new;
1729 : : int max_replication_slots;
1730 : : char *wal_level;
1731 : :
1732 : : /* Logical slots can be migrated since PG17. */
1733 [ - + ]: 6 : if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1600)
171 akapila@postgresql.o 1734 :UNC 0 : return;
1735 : :
171 akapila@postgresql.o 1736 :GNC 6 : nslots_on_old = count_old_cluster_logical_slots();
1737 : :
1738 : : /* Quick return if there are no logical slots to be migrated. */
1739 [ + + ]: 6 : if (nslots_on_old == 0)
1740 : 4 : return;
1741 : :
1742 : 2 : conn = connectToServer(&new_cluster, "template1");
1743 : :
1744 : 2 : prep_status("Checking for new cluster logical replication slots");
1745 : :
1746 : 2 : res = executeQueryOrDie(conn, "SELECT count(*) "
1747 : : "FROM pg_catalog.pg_replication_slots "
1748 : : "WHERE slot_type = 'logical' AND "
1749 : : "temporary IS FALSE;");
1750 : :
1751 [ - + ]: 2 : if (PQntuples(res) != 1)
171 akapila@postgresql.o 1752 :UNC 0 : pg_fatal("could not count the number of logical replication slots");
1753 : :
171 akapila@postgresql.o 1754 :GNC 2 : nslots_on_new = atoi(PQgetvalue(res, 0, 0));
1755 : :
1756 [ - + ]: 2 : if (nslots_on_new)
171 akapila@postgresql.o 1757 :UNC 0 : pg_fatal("Expected 0 logical replication slots but found %d.",
1758 : : nslots_on_new);
1759 : :
171 akapila@postgresql.o 1760 :GNC 2 : PQclear(res);
1761 : :
1762 : 2 : res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings "
1763 : : "WHERE name IN ('wal_level', 'max_replication_slots') "
1764 : : "ORDER BY name DESC;");
1765 : :
1766 [ - + ]: 2 : if (PQntuples(res) != 2)
171 akapila@postgresql.o 1767 :UNC 0 : pg_fatal("could not determine parameter settings on new cluster");
1768 : :
171 akapila@postgresql.o 1769 :GNC 2 : wal_level = PQgetvalue(res, 0, 0);
1770 : :
1771 [ - + ]: 2 : if (strcmp(wal_level, "logical") != 0)
171 akapila@postgresql.o 1772 :UNC 0 : pg_fatal("wal_level must be \"logical\", but is set to \"%s\"",
1773 : : wal_level);
1774 : :
171 akapila@postgresql.o 1775 :GNC 2 : max_replication_slots = atoi(PQgetvalue(res, 1, 0));
1776 : :
1777 [ + + ]: 2 : if (nslots_on_old > max_replication_slots)
1778 : 1 : pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of "
1779 : : "logical replication slots (%d) on the old cluster",
1780 : : max_replication_slots, nslots_on_old);
1781 : :
1782 : 1 : PQclear(res);
1783 : 1 : PQfinish(conn);
1784 : :
1785 : 1 : check_ok();
1786 : : }
1787 : :
1788 : : /*
1789 : : * check_new_cluster_subscription_configuration()
1790 : : *
1791 : : * Verify that the max_replication_slots configuration specified is enough for
1792 : : * creating the subscriptions. This is required to create the replication
1793 : : * origin for each subscription.
1794 : : */
1795 : : static void
103 1796 : 5 : check_new_cluster_subscription_configuration(void)
1797 : : {
1798 : : PGresult *res;
1799 : : PGconn *conn;
1800 : : int nsubs_on_old;
1801 : : int max_replication_slots;
1802 : :
1803 : : /* Subscriptions and their dependencies can be migrated since PG17. */
1804 [ - + ]: 5 : if (GET_MAJOR_VERSION(old_cluster.major_version) < 1700)
103 akapila@postgresql.o 1805 :UNC 0 : return;
1806 : :
103 akapila@postgresql.o 1807 :GNC 5 : nsubs_on_old = count_old_cluster_subscriptions();
1808 : :
1809 : : /* Quick return if there are no subscriptions to be migrated. */
1810 [ + + ]: 5 : if (nsubs_on_old == 0)
1811 : 3 : return;
1812 : :
1813 : 2 : prep_status("Checking for new cluster configuration for subscriptions");
1814 : :
1815 : 2 : conn = connectToServer(&new_cluster, "template1");
1816 : :
1817 : 2 : res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings "
1818 : : "WHERE name = 'max_replication_slots';");
1819 : :
1820 [ - + ]: 2 : if (PQntuples(res) != 1)
103 akapila@postgresql.o 1821 :UNC 0 : pg_fatal("could not determine parameter settings on new cluster");
1822 : :
103 akapila@postgresql.o 1823 :GNC 2 : max_replication_slots = atoi(PQgetvalue(res, 0, 0));
1824 [ + + ]: 2 : if (nsubs_on_old > max_replication_slots)
1825 : 1 : pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of "
1826 : : "subscriptions (%d) on the old cluster",
1827 : : max_replication_slots, nsubs_on_old);
1828 : :
1829 : 1 : PQclear(res);
1830 : 1 : PQfinish(conn);
1831 : :
1832 : 1 : check_ok();
1833 : : }
1834 : :
1835 : : /*
1836 : : * check_old_cluster_for_valid_slots()
1837 : : *
1838 : : * Verify that all the logical slots are valid and have consumed all the WAL
1839 : : * before shutdown.
1840 : : */
1841 : : static void
171 1842 : 8 : check_old_cluster_for_valid_slots(bool live_check)
1843 : : {
1844 : : char output_path[MAXPGPATH];
1845 : 8 : FILE *script = NULL;
1846 : :
1847 : 8 : prep_status("Checking for valid logical replication slots");
1848 : :
1849 : 8 : snprintf(output_path, sizeof(output_path), "%s/%s",
1850 : : log_opts.basedir,
1851 : : "invalid_logical_slots.txt");
1852 : :
1853 [ + + ]: 32 : for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
1854 : : {
1855 : 24 : LogicalSlotInfoArr *slot_arr = &old_cluster.dbarr.dbs[dbnum].slot_arr;
1856 : :
1857 [ + + ]: 29 : for (int slotnum = 0; slotnum < slot_arr->nslots; slotnum++)
1858 : : {
1859 : 5 : LogicalSlotInfo *slot = &slot_arr->slots[slotnum];
1860 : :
1861 : : /* Is the slot usable? */
1862 [ - + ]: 5 : if (slot->invalid)
1863 : : {
171 akapila@postgresql.o 1864 [ # # # # ]:UNC 0 : if (script == NULL &&
1865 : 0 : (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1866 : 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1867 : :
171 akapila@postgresql.o 1868 : 0 : fprintf(script, "The slot \"%s\" is invalid\n",
1869 : : slot->slotname);
1870 : :
1871 : 0 : continue;
1872 : : }
1873 : :
1874 : : /*
1875 : : * Do additional check to ensure that all logical replication
1876 : : * slots have consumed all the WAL before shutdown.
1877 : : *
1878 : : * Note: This can be satisfied only when the old cluster has been
1879 : : * shut down, so we skip this for live checks.
1880 : : */
171 akapila@postgresql.o 1881 [ + - + + ]:GNC 5 : if (!live_check && !slot->caught_up)
1882 : : {
1883 [ + + - + ]: 3 : if (script == NULL &&
1884 : 1 : (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1885 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
1886 : :
171 akapila@postgresql.o 1887 :GNC 2 : fprintf(script,
1888 : : "The slot \"%s\" has not consumed the WAL yet\n",
1889 : : slot->slotname);
1890 : : }
1891 : : }
1892 : : }
1893 : :
1894 [ + + ]: 8 : if (script)
1895 : : {
1896 : 1 : fclose(script);
1897 : :
1898 : 1 : pg_log(PG_REPORT, "fatal");
1899 : 1 : pg_fatal("Your installation contains logical replication slots that can't be upgraded.\n"
1900 : : "You can remove invalid slots and/or consume the pending WAL for other slots,\n"
1901 : : "and then restart the upgrade.\n"
1902 : : "A list of the problematic slots is in the file:\n"
1903 : : " %s", output_path);
1904 : : }
1905 : :
1906 : 7 : check_ok();
1907 : 7 : }
1908 : :
1909 : : /*
1910 : : * check_old_cluster_subscription_state()
1911 : : *
1912 : : * Verify that the replication origin corresponding to each of the
1913 : : * subscriptions are present and each of the subscribed tables is in
1914 : : * 'i' (initialize) or 'r' (ready) state.
1915 : : */
1916 : : static void
103 1917 : 7 : check_old_cluster_subscription_state(void)
1918 : : {
1919 : 7 : FILE *script = NULL;
1920 : : char output_path[MAXPGPATH];
1921 : : int ntup;
1922 : :
1923 : 7 : prep_status("Checking for subscription state");
1924 : :
1925 : 7 : snprintf(output_path, sizeof(output_path), "%s/%s",
1926 : : log_opts.basedir,
1927 : : "subs_invalid.txt");
1928 [ + + ]: 29 : for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
1929 : : {
1930 : : PGresult *res;
1931 : 22 : DbInfo *active_db = &old_cluster.dbarr.dbs[dbnum];
1932 : 22 : PGconn *conn = connectToServer(&old_cluster, active_db->db_name);
1933 : :
1934 : : /* We need to check for pg_replication_origin only once. */
1935 [ + + ]: 22 : if (dbnum == 0)
1936 : : {
1937 : : /*
1938 : : * Check that all the subscriptions have their respective
1939 : : * replication origin.
1940 : : */
1941 : 7 : res = executeQueryOrDie(conn,
1942 : : "SELECT d.datname, s.subname "
1943 : : "FROM pg_catalog.pg_subscription s "
1944 : : "LEFT OUTER JOIN pg_catalog.pg_replication_origin o "
1945 : : " ON o.roname = 'pg_' || s.oid "
1946 : : "INNER JOIN pg_catalog.pg_database d "
1947 : : " ON d.oid = s.subdbid "
1948 : : "WHERE o.roname iS NULL;");
1949 : :
1950 : 7 : ntup = PQntuples(res);
1951 [ + + ]: 8 : for (int i = 0; i < ntup; i++)
1952 : : {
1953 [ + - - + ]: 1 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 1954 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
103 akapila@postgresql.o 1955 :GNC 1 : fprintf(script, "The replication origin is missing for database:\"%s\" subscription:\"%s\"\n",
1956 : : PQgetvalue(res, i, 0),
1957 : : PQgetvalue(res, i, 1));
1958 : : }
1959 : 7 : PQclear(res);
1960 : : }
1961 : :
1962 : : /*
1963 : : * We don't allow upgrade if there is a risk of dangling slot or
1964 : : * origin corresponding to initial sync after upgrade.
1965 : : *
1966 : : * A slot/origin not created yet refers to the 'i' (initialize) state,
1967 : : * while 'r' (ready) state refers to a slot/origin created previously
1968 : : * but already dropped. These states are supported for pg_upgrade. The
1969 : : * other states listed below are not supported:
1970 : : *
1971 : : * a) SUBREL_STATE_DATASYNC: A relation upgraded while in this state
1972 : : * would retain a replication slot, which could not be dropped by the
1973 : : * sync worker spawned after the upgrade because the subscription ID
1974 : : * used for the slot name won't match anymore.
1975 : : *
1976 : : * b) SUBREL_STATE_SYNCDONE: A relation upgraded while in this state
1977 : : * would retain the replication origin when there is a failure in
1978 : : * tablesync worker immediately after dropping the replication slot in
1979 : : * the publisher.
1980 : : *
1981 : : * c) SUBREL_STATE_FINISHEDCOPY: A tablesync worker spawned to work on
1982 : : * a relation upgraded while in this state would expect an origin ID
1983 : : * with the OID of the subscription used before the upgrade, causing
1984 : : * it to fail.
1985 : : *
1986 : : * d) SUBREL_STATE_SYNCWAIT, SUBREL_STATE_CATCHUP and
1987 : : * SUBREL_STATE_UNKNOWN: These states are not stored in the catalog,
1988 : : * so we need not allow these states.
1989 : : */
1990 : 22 : res = executeQueryOrDie(conn,
1991 : : "SELECT r.srsubstate, s.subname, n.nspname, c.relname "
1992 : : "FROM pg_catalog.pg_subscription_rel r "
1993 : : "LEFT JOIN pg_catalog.pg_subscription s"
1994 : : " ON r.srsubid = s.oid "
1995 : : "LEFT JOIN pg_catalog.pg_class c"
1996 : : " ON r.srrelid = c.oid "
1997 : : "LEFT JOIN pg_catalog.pg_namespace n"
1998 : : " ON c.relnamespace = n.oid "
1999 : : "WHERE r.srsubstate NOT IN ('i', 'r') "
2000 : : "ORDER BY s.subname");
2001 : :
2002 : 22 : ntup = PQntuples(res);
2003 [ + + ]: 23 : for (int i = 0; i < ntup; i++)
2004 : : {
2005 [ - + - - ]: 1 : if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
33 michael@paquier.xyz 2006 :UNC 0 : pg_fatal("could not open file \"%s\": %m", output_path);
2007 : :
103 akapila@postgresql.o 2008 :GNC 1 : fprintf(script, "The table sync state \"%s\" is not allowed for database:\"%s\" subscription:\"%s\" schema:\"%s\" relation:\"%s\"\n",
2009 : : PQgetvalue(res, i, 0),
2010 : : active_db->db_name,
2011 : : PQgetvalue(res, i, 1),
2012 : : PQgetvalue(res, i, 2),
2013 : : PQgetvalue(res, i, 3));
2014 : : }
2015 : :
2016 : 22 : PQclear(res);
2017 : 22 : PQfinish(conn);
2018 : : }
2019 : :
2020 [ + + ]: 7 : if (script)
2021 : : {
2022 : 1 : fclose(script);
2023 : 1 : pg_log(PG_REPORT, "fatal");
2024 : 1 : pg_fatal("Your installation contains subscriptions without origin or having relations not in i (initialize) or r (ready) state.\n"
2025 : : "You can allow the initial sync to finish for all relations and then restart the upgrade.\n"
2026 : : "A list of the problematic subscriptions is in the file:\n"
2027 : : " %s", output_path);
2028 : : }
2029 : : else
2030 : 6 : check_ok();
2031 : 6 : }
|