]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/check.c
cb4d17635ea984df0958dcfa137dce96c21cf8b7
[postgresql] / contrib / pg_upgrade / check.c
1 /*
2  *      check.c
3  *
4  *      server checks and output routines
5  *
6  *      Copyright (c) 2010, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/check.c
8  */
9
10 #include "pg_upgrade.h"
11
12
13 static void set_locale_and_encoding(Cluster whichCluster);
14 static void check_new_db_is_empty(void);
15 static void check_locale_and_encoding(ControlData *oldctrl,
16                                                   ControlData *newctrl);
17 static void check_for_isn_and_int8_passing_mismatch(
18                                                                                 Cluster whichCluster);
19 static void check_for_reg_data_type_usage(Cluster whichCluster);
20
21
22 void
23 output_check_banner(bool *live_check)
24 {
25         if (user_opts.check && is_server_running(old_cluster.pgdata))
26         {
27                 *live_check = true;
28                 if (old_cluster.port == new_cluster.port)
29                         pg_log(PG_FATAL, "When checking a live server, "
30                                    "the old and new port numbers must be different.\n");
31                 pg_log(PG_REPORT, "PerForming Consistency Checks on Old Live Server\n");
32                 pg_log(PG_REPORT, "------------------------------------------------\n");
33         }
34         else
35         {
36                 pg_log(PG_REPORT, "Performing Consistency Checks\n");
37                 pg_log(PG_REPORT, "-----------------------------\n");
38         }
39 }
40
41
42 void
43 check_old_cluster(bool live_check,
44                                   char **sequence_script_file_name)
45 {
46         /* -- OLD -- */
47
48         if (!live_check)
49                 start_postmaster(CLUSTER_OLD, false);
50
51         set_locale_and_encoding(CLUSTER_OLD);
52
53         get_pg_database_relfilenode(CLUSTER_OLD);
54
55         /* Extract a list of databases and tables from the old cluster */
56         get_db_and_rel_infos(&old_cluster.dbarr, CLUSTER_OLD);
57
58         init_tablespaces();
59
60         get_loadable_libraries();
61
62
63         /*
64          * Check for various failure cases
65          */
66
67         check_for_reg_data_type_usage(CLUSTER_OLD);
68         check_for_isn_and_int8_passing_mismatch(CLUSTER_OLD);
69
70         /* old = PG 8.3 checks? */
71         if (GET_MAJOR_VERSION(old_cluster.major_version) <= 803)
72         {
73                 old_8_3_check_for_name_data_type_usage(CLUSTER_OLD);
74                 old_8_3_check_for_tsquery_usage(CLUSTER_OLD);
75                 if (user_opts.check)
76                 {
77                         old_8_3_rebuild_tsvector_tables(true, CLUSTER_OLD);
78                         old_8_3_invalidate_hash_gin_indexes(true, CLUSTER_OLD);
79                         old_8_3_invalidate_bpchar_pattern_ops_indexes(true, CLUSTER_OLD);
80                 }
81                 else
82
83                         /*
84                          * While we have the old server running, create the script to
85                          * properly restore its sequence values but we report this at the
86                          * end.
87                          */
88                         *sequence_script_file_name =
89                                 old_8_3_create_sequence_script(CLUSTER_OLD);
90         }
91
92         /* Pre-PG 9.0 had no large object permissions */
93         if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
94                 new_9_0_populate_pg_largeobject_metadata(true, CLUSTER_OLD);
95
96         /*
97          * While not a check option, we do this now because this is the only time
98          * the old server is running.
99          */
100         if (!user_opts.check)
101         {
102                 generate_old_dump();
103                 split_old_dump();
104         }
105
106         if (!live_check)
107                 stop_postmaster(false, false);
108 }
109
110
111 void
112 check_new_cluster(void)
113 {
114         set_locale_and_encoding(CLUSTER_NEW);
115
116         check_new_db_is_empty();
117
118         check_loadable_libraries();
119
120         check_locale_and_encoding(&old_cluster.controldata, &new_cluster.controldata);
121
122         if (user_opts.transfer_mode == TRANSFER_MODE_LINK)
123                 check_hard_link();
124 }
125
126
127 void
128 report_clusters_compatible(void)
129 {
130         if (user_opts.check)
131         {
132                 pg_log(PG_REPORT, "\n*Clusters are compatible*\n");
133                 /* stops new cluster */
134                 stop_postmaster(false, false);
135                 exit_nicely(false);
136         }
137
138         pg_log(PG_REPORT, "\n"
139                    "| If pg_upgrade fails after this point, you must\n"
140                    "| re-initdb the new cluster before continuing.\n"
141                    "| You will also need to remove the \".old\" suffix\n"
142                    "| from %s/global/pg_control.old.\n", old_cluster.pgdata);
143 }
144
145
146 void
147 issue_warnings(char *sequence_script_file_name)
148 {
149         /* old = PG 8.3 warnings? */
150         if (GET_MAJOR_VERSION(old_cluster.major_version) <= 803)
151         {
152                 start_postmaster(CLUSTER_NEW, true);
153
154                 /* restore proper sequence values using file created from old server */
155                 if (sequence_script_file_name)
156                 {
157                         prep_status("Adjusting sequences");
158                         exec_prog(true,
159                                           SYSTEMQUOTE "\"%s/psql\" --set ON_ERROR_STOP=on "
160                                           "--no-psqlrc --port %d --username \"%s\" "
161                                           "-f \"%s\" --dbname template1 >> \"%s\"" SYSTEMQUOTE,
162                                           new_cluster.bindir, new_cluster.port, os_info.user,
163                                           sequence_script_file_name, log_opts.filename);
164                         unlink(sequence_script_file_name);
165                         check_ok();
166                 }
167
168                 old_8_3_rebuild_tsvector_tables(false, CLUSTER_NEW);
169                 old_8_3_invalidate_hash_gin_indexes(false, CLUSTER_NEW);
170                 old_8_3_invalidate_bpchar_pattern_ops_indexes(false, CLUSTER_NEW);
171                 stop_postmaster(false, true);
172         }
173
174         /* Create dummy large object permissions for old < PG 9.0? */
175         if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
176         {
177                 start_postmaster(CLUSTER_NEW, true);
178                 new_9_0_populate_pg_largeobject_metadata(false, CLUSTER_NEW);
179                 stop_postmaster(false, true);
180         }
181 }
182
183
184 void
185 output_completion_banner(char *deletion_script_file_name)
186 {
187         /* Did we migrate the free space files? */
188         if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
189                 pg_log(PG_REPORT,
190                            "| Optimizer statistics is not transferred by pg_upgrade\n"
191                            "| so consider running:\n"
192                            "| \tvacuumdb --all --analyze-only\n"
193                            "| on the newly-upgraded cluster.\n\n");
194         else
195                 pg_log(PG_REPORT,
196                            "| Optimizer statistics and free space information\n"
197                            "| are not transferred by pg_upgrade so consider\n"
198                            "| running:\n"
199                            "| \tvacuumdb --all --analyze\n"
200                            "| on the newly-upgraded cluster.\n\n");
201
202         pg_log(PG_REPORT,
203                    "| Running this script will delete the old cluster's data files:\n"
204                    "| \t%s\n",
205                    deletion_script_file_name);
206 }
207
208
209 void
210 check_cluster_versions(void)
211 {
212         /* get old and new cluster versions */
213         old_cluster.major_version = get_major_server_version(&old_cluster.major_version_str, CLUSTER_OLD);
214         new_cluster.major_version = get_major_server_version(&new_cluster.major_version_str, CLUSTER_NEW);
215
216         /* We allow migration from/to the same major version for beta upgrades */
217
218         if (GET_MAJOR_VERSION(old_cluster.major_version) < 803)
219                 pg_log(PG_FATAL, "This utility can only upgrade from PostgreSQL version 8.3 and later.\n");
220
221         /* Only current PG version is supported as a target */
222         if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
223                 pg_log(PG_FATAL, "This utility can only upgrade to PostgreSQL version %s.\n",
224                            PG_MAJORVERSION);
225
226         /*
227          * We can't allow downgrading because we use the target pg_dumpall, and
228          * pg_dumpall cannot operate on new datbase versions, only older versions.
229          */
230         if (old_cluster.major_version > new_cluster.major_version)
231                 pg_log(PG_FATAL, "This utility cannot be used to downgrade to older major PostgreSQL versions.\n");
232 }
233
234
235 void
236 check_cluster_compatibility(bool live_check)
237 {
238         char            libfile[MAXPGPATH];
239         FILE       *lib_test;
240
241         /*
242          * Test pg_upgrade_support.so is in the proper place.    We cannot copy it
243          * ourselves because install directories are typically root-owned.
244          */
245         snprintf(libfile, sizeof(libfile), "%s/pg_upgrade_support%s", new_cluster.libpath,
246                          DLSUFFIX);
247
248         if ((lib_test = fopen(libfile, "r")) == NULL)
249                 pg_log(PG_FATAL,
250                            "\npg_upgrade_support%s must be created and installed in %s\n", DLSUFFIX, libfile);
251         else
252                 fclose(lib_test);
253
254         /* get/check pg_control data of servers */
255         get_control_data(&old_cluster, live_check);
256         get_control_data(&new_cluster, false);
257         check_control_data(&old_cluster.controldata, &new_cluster.controldata);
258
259         /* Is it 9.0 but without tablespace directories? */
260         if (GET_MAJOR_VERSION(new_cluster.major_version) == 900 &&
261                 new_cluster.controldata.cat_ver < TABLE_SPACE_SUBDIRS)
262                 pg_log(PG_FATAL, "This utility can only upgrade to PostgreSQL version 9.0 after 2010-01-11\n"
263                            "because of backend API changes made during development.\n");
264 }
265
266
267 /*
268  * set_locale_and_encoding()
269  *
270  * query the database to get the template0 locale
271  */
272 static void
273 set_locale_and_encoding(Cluster whichCluster)
274 {
275         ClusterInfo *active_cluster = ACTIVE_CLUSTER(whichCluster);
276         ControlData *ctrl = &active_cluster->controldata;
277         PGconn     *conn;
278         PGresult   *res;
279         int                     i_encoding;
280         int                     cluster_version = active_cluster->major_version;
281
282         conn = connectToServer("template1", whichCluster);
283
284         /* for pg < 80400, we got the values from pg_controldata */
285         if (cluster_version >= 80400)
286         {
287                 int                     i_datcollate;
288                 int                     i_datctype;
289
290                 res = executeQueryOrDie(conn,
291                                                                 "SELECT datcollate, datctype "
292                                                                 "FROM   pg_catalog.pg_database "
293                                                                 "WHERE  datname = 'template0' ");
294                 assert(PQntuples(res) == 1);
295
296                 i_datcollate = PQfnumber(res, "datcollate");
297                 i_datctype = PQfnumber(res, "datctype");
298
299                 ctrl->lc_collate = pg_strdup(PQgetvalue(res, 0, i_datcollate));
300                 ctrl->lc_ctype = pg_strdup(PQgetvalue(res, 0, i_datctype));
301
302                 PQclear(res);
303         }
304
305         res = executeQueryOrDie(conn,
306                                                         "SELECT pg_catalog.pg_encoding_to_char(encoding) "
307                                                         "FROM   pg_catalog.pg_database "
308                                                         "WHERE  datname = 'template0' ");
309         assert(PQntuples(res) == 1);
310
311         i_encoding = PQfnumber(res, "pg_encoding_to_char");
312         ctrl->encoding = pg_strdup(PQgetvalue(res, 0, i_encoding));
313
314         PQclear(res);
315
316         PQfinish(conn);
317 }
318
319
320 /*
321  * check_locale_and_encoding()
322  *
323  *      locale is not in pg_controldata in 8.4 and later so
324  *      we probably had to get via a database query.
325  */
326 static void
327 check_locale_and_encoding(ControlData *oldctrl,
328                                                   ControlData *newctrl)
329 {
330         if (strcmp(oldctrl->lc_collate, newctrl->lc_collate) != 0)
331                 pg_log(PG_FATAL,
332                            "old and new cluster lc_collate values do not match\n");
333         if (strcmp(oldctrl->lc_ctype, newctrl->lc_ctype) != 0)
334                 pg_log(PG_FATAL,
335                            "old and new cluster lc_ctype values do not match\n");
336         if (strcmp(oldctrl->encoding, newctrl->encoding) != 0)
337                 pg_log(PG_FATAL,
338                            "old and new cluster encoding values do not match\n");
339 }
340
341
342 static void
343 check_new_db_is_empty(void)
344 {
345         int                     dbnum;
346         bool            found = false;
347
348         get_db_and_rel_infos(&new_cluster.dbarr, CLUSTER_NEW);
349
350         for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
351         {
352                 int                     relnum;
353                 RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr;
354
355                 for (relnum = 0; relnum < rel_arr->nrels;
356                          relnum++)
357                 {
358                         /* pg_largeobject and its index should be skipped */
359                         if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0)
360                         {
361                                 found = true;
362                                 break;
363                         }
364                 }
365         }
366
367         dbarr_free(&new_cluster.dbarr);
368
369         if (found)
370                 pg_log(PG_FATAL, "New cluster is not empty; exiting\n");
371 }
372
373
374 /*
375  * create_script_for_old_cluster_deletion()
376  *
377  *      This is particularly useful for tablespace deletion.
378  */
379 void
380 create_script_for_old_cluster_deletion(
381                                                                            char **deletion_script_file_name)
382 {
383         FILE       *script = NULL;
384         int                     tblnum;
385
386         *deletion_script_file_name = pg_malloc(MAXPGPATH);
387
388         prep_status("Creating script to delete old cluster");
389
390         snprintf(*deletion_script_file_name, MAXPGPATH, "%s/delete_old_cluster.%s",
391                          os_info.cwd, SCRIPT_EXT);
392
393         if ((script = fopen(*deletion_script_file_name, "w")) == NULL)
394                 pg_log(PG_FATAL, "Could not create necessary file:  %s\n",
395                            *deletion_script_file_name);
396
397 #ifndef WIN32
398         /* add shebang header */
399         fprintf(script, "#!/bin/sh\n\n");
400 #endif
401
402         /* delete old cluster's default tablespace */
403         fprintf(script, RMDIR_CMD " %s\n", old_cluster.pgdata);
404
405         /* delete old cluster's alternate tablespaces */
406         for (tblnum = 0; tblnum < os_info.num_tablespaces; tblnum++)
407         {
408                 /*
409                  * Do the old cluster's per-database directories share a directory
410                  * with a new version-specific tablespace?
411                  */
412                 if (strlen(old_cluster.tablespace_suffix) == 0)
413                 {
414                         /* delete per-database directories */
415                         int                     dbnum;
416
417                         fprintf(script, "\n");
418                         /* remove PG_VERSION? */
419                         if (GET_MAJOR_VERSION(old_cluster.major_version) <= 804)
420                                 fprintf(script, RM_CMD " %s%s/PG_VERSION\n",
421                                  os_info.tablespaces[tblnum], old_cluster.tablespace_suffix);
422
423                         for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
424                         {
425                                 fprintf(script, RMDIR_CMD " %s%s/%d\n",
426                                   os_info.tablespaces[tblnum], old_cluster.tablespace_suffix,
427                                                 old_cluster.dbarr.dbs[dbnum].db_oid);
428                         }
429                 }
430                 else
431
432                         /*
433                          * Simply delete the tablespace directory, which might be ".old"
434                          * or a version-specific subdirectory.
435                          */
436                         fprintf(script, RMDIR_CMD " %s%s\n",
437                                  os_info.tablespaces[tblnum], old_cluster.tablespace_suffix);
438         }
439
440         fclose(script);
441
442 #ifndef WIN32
443         if (chmod(*deletion_script_file_name, S_IRWXU) != 0)
444                 pg_log(PG_FATAL, "Could not add execute permission to file:  %s\n",
445                            *deletion_script_file_name);
446 #endif
447
448         check_ok();
449 }
450
451
452 /*
453  *      check_for_isn_and_int8_passing_mismatch()
454  *
455  *      /contrib/isn relies on data type int8, and in 8.4 int8 can now be passed
456  *      by value.  The schema dumps the CREATE TYPE PASSEDBYVALUE setting so
457  *      it must match for the old and new servers.
458  */
459 void
460 check_for_isn_and_int8_passing_mismatch(Cluster whichCluster)
461 {
462         ClusterInfo *active_cluster = ACTIVE_CLUSTER(whichCluster);
463         int                     dbnum;
464         FILE       *script = NULL;
465         bool            found = false;
466         char            output_path[MAXPGPATH];
467
468         prep_status("Checking for /contrib/isn with bigint-passing mismatch");
469
470         if (old_cluster.controldata.float8_pass_by_value ==
471                 new_cluster.controldata.float8_pass_by_value)
472         {
473                 /* no mismatch */
474                 check_ok();
475                 return;
476         }
477
478         snprintf(output_path, sizeof(output_path), "%s/contrib_isn_and_int8_pass_by_value.txt",
479                          os_info.cwd);
480
481         for (dbnum = 0; dbnum < active_cluster->dbarr.ndbs; dbnum++)
482         {
483                 PGresult   *res;
484                 bool            db_used = false;
485                 int                     ntups;
486                 int                     rowno;
487                 int                     i_nspname,
488                                         i_proname;
489                 DbInfo     *active_db = &active_cluster->dbarr.dbs[dbnum];
490                 PGconn     *conn = connectToServer(active_db->db_name, whichCluster);
491
492                 /* Find any functions coming from contrib/isn */
493                 res = executeQueryOrDie(conn,
494                                                                 "SELECT n.nspname, p.proname "
495                                                                 "FROM   pg_catalog.pg_proc p, "
496                                                                 "               pg_catalog.pg_namespace n "
497                                                                 "WHERE  p.pronamespace = n.oid AND "
498                                                                 "               p.probin = '$libdir/isn'");
499
500                 ntups = PQntuples(res);
501                 i_nspname = PQfnumber(res, "nspname");
502                 i_proname = PQfnumber(res, "proname");
503                 for (rowno = 0; rowno < ntups; rowno++)
504                 {
505                         found = true;
506                         if (script == NULL && (script = fopen(output_path, "w")) == NULL)
507                                 pg_log(PG_FATAL, "Could not create necessary file:  %s\n", output_path);
508                         if (!db_used)
509                         {
510                                 fprintf(script, "Database:  %s\n", active_db->db_name);
511                                 db_used = true;
512                         }
513                         fprintf(script, "  %s.%s\n",
514                                         PQgetvalue(res, rowno, i_nspname),
515                                         PQgetvalue(res, rowno, i_proname));
516                 }
517
518                 PQclear(res);
519
520                 PQfinish(conn);
521         }
522
523         if (found)
524         {
525                 fclose(script);
526                 pg_log(PG_REPORT, "fatal\n");
527                 pg_log(PG_FATAL,
528                            "| Your installation contains \"/contrib/isn\" functions\n"
529                            "| which rely on the bigint data type.  Your old and\n"
530                            "| new clusters pass bigint values differently so this\n"
531                            "| cluster cannot currently be upgraded.  You can\n"
532                            "| manually migrate data that use \"/contrib/isn\"\n"
533                            "| facilities and remove \"/contrib/isn\" from the\n"
534                            "| old cluster and restart the migration.  A list\n"
535                            "| of the problem functions is in the file:\n"
536                            "| \t%s\n\n", output_path);
537         }
538         else
539                 check_ok();
540 }
541
542
543 /*
544  * check_for_reg_data_type_usage()
545  *      pg_upgrade only preserves these system values:
546  *              pg_class.relfilenode
547  *              pg_type.oid
548  *              pg_enum.oid
549  *
550  *      Most of the reg* data types reference system catalog info that is
551  *      not preserved, and hence these data types cannot be used in user
552  *      tables upgraded by pg_upgrade.
553  */
554 void
555 check_for_reg_data_type_usage(Cluster whichCluster)
556 {
557         ClusterInfo *active_cluster = ACTIVE_CLUSTER(whichCluster);
558         int                     dbnum;
559         FILE       *script = NULL;
560         bool            found = false;
561         char            output_path[MAXPGPATH];
562
563         prep_status("Checking for reg* system oid user data types");
564
565         snprintf(output_path, sizeof(output_path), "%s/tables_using_reg.txt",
566                          os_info.cwd);
567
568         for (dbnum = 0; dbnum < active_cluster->dbarr.ndbs; dbnum++)
569         {
570                 PGresult   *res;
571                 bool            db_used = false;
572                 int                     ntups;
573                 int                     rowno;
574                 int                     i_nspname,
575                                         i_relname,
576                                         i_attname;
577                 DbInfo     *active_db = &active_cluster->dbarr.dbs[dbnum];
578                 PGconn     *conn = connectToServer(active_db->db_name, whichCluster);
579
580                 res = executeQueryOrDie(conn,
581                                                                 "SELECT n.nspname, c.relname, a.attname "
582                                                                 "FROM   pg_catalog.pg_class c, "
583                                                                 "               pg_catalog.pg_namespace n, "
584                                                                 "               pg_catalog.pg_attribute a "
585                                                                 "WHERE  c.oid = a.attrelid AND "
586                                                                 "               NOT a.attisdropped AND "
587                                                                 "               a.atttypid IN ( "
588                   "                     'pg_catalog.regproc'::pg_catalog.regtype, "
589                                                                 "                       'pg_catalog.regprocedure'::pg_catalog.regtype, "
590                   "                     'pg_catalog.regoper'::pg_catalog.regtype, "
591                                                                 "                       'pg_catalog.regoperator'::pg_catalog.regtype, "
592                  "                      'pg_catalog.regclass'::pg_catalog.regtype, "
593                 /* regtype.oid is preserved, so 'regtype' is OK */
594                 "                       'pg_catalog.regconfig'::pg_catalog.regtype, "
595                                                                 "                       'pg_catalog.regdictionary'::pg_catalog.regtype) AND "
596                                                                 "               c.relnamespace = n.oid AND "
597                                                           "             n.nspname != 'pg_catalog' AND "
598                                                  "              n.nspname != 'information_schema'");
599
600                 ntups = PQntuples(res);
601                 i_nspname = PQfnumber(res, "nspname");
602                 i_relname = PQfnumber(res, "relname");
603                 i_attname = PQfnumber(res, "attname");
604                 for (rowno = 0; rowno < ntups; rowno++)
605                 {
606                         found = true;
607                         if (script == NULL && (script = fopen(output_path, "w")) == NULL)
608                                 pg_log(PG_FATAL, "Could not create necessary file:  %s\n", output_path);
609                         if (!db_used)
610                         {
611                                 fprintf(script, "Database:  %s\n", active_db->db_name);
612                                 db_used = true;
613                         }
614                         fprintf(script, "  %s.%s.%s\n",
615                                         PQgetvalue(res, rowno, i_nspname),
616                                         PQgetvalue(res, rowno, i_relname),
617                                         PQgetvalue(res, rowno, i_attname));
618                 }
619
620                 PQclear(res);
621
622                 PQfinish(conn);
623         }
624
625         if (found)
626         {
627                 fclose(script);
628                 pg_log(PG_REPORT, "fatal\n");
629                 pg_log(PG_FATAL,
630                            "| Your installation contains one of the reg* data types in\n"
631                            "| user tables.  These data types reference system oids that\n"
632                            "| are not preserved by pg_upgrade, so this cluster cannot\n"
633                            "| currently be upgraded.  You can remove the problem tables\n"
634                            "| and restart the migration.  A list of the problem columns\n"
635                            "| is in the file:\n"
636                            "| \t%s\n\n", output_path);
637         }
638         else
639                 check_ok();
640 }