LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - check.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 224 521 43.0 %
Date: 2023-12-11 15:11:28 Functions: 20 28 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  check.c
       3             :  *
       4             :  *  server checks and output routines
       5             :  *
       6             :  *  Copyright (c) 2010-2023, 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_collation.h"
      14             : #include "fe_utils/string_utils.h"
      15             : #include "mb/pg_wchar.h"
      16             : #include "pg_upgrade.h"
      17             : 
      18             : static void check_new_cluster_is_empty(void);
      19             : static void check_is_install_user(ClusterInfo *cluster);
      20             : static void check_proper_datallowconn(ClusterInfo *cluster);
      21             : static void check_for_prepared_transactions(ClusterInfo *cluster);
      22             : static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
      23             : static void check_for_user_defined_postfix_ops(ClusterInfo *cluster);
      24             : static void check_for_incompatible_polymorphics(ClusterInfo *cluster);
      25             : static void check_for_tables_with_oids(ClusterInfo *cluster);
      26             : static void check_for_composite_data_type_usage(ClusterInfo *cluster);
      27             : static void check_for_reg_data_type_usage(ClusterInfo *cluster);
      28             : static void check_for_aclitem_data_type_usage(ClusterInfo *cluster);
      29             : static void check_for_removed_data_type_usage(ClusterInfo *cluster,
      30             :                                               const char *version,
      31             :                                               const char *datatype);
      32             : static void check_for_jsonb_9_4_usage(ClusterInfo *cluster);
      33             : static void check_for_pg_role_prefix(ClusterInfo *cluster);
      34             : static void check_for_new_tablespace_dir(void);
      35             : static void check_for_user_defined_encoding_conversions(ClusterInfo *cluster);
      36             : static void check_new_cluster_logical_replication_slots(void);
      37             : static void check_old_cluster_for_valid_slots(bool live_check);
      38             : 
      39             : 
      40             : /*
      41             :  * fix_path_separator
      42             :  * For non-Windows, just return the argument.
      43             :  * For Windows convert any forward slash to a backslash
      44             :  * such as is suitable for arguments to builtin commands
      45             :  * like RMDIR and DEL.
      46             :  */
      47             : static char *
      48           4 : fix_path_separator(char *path)
      49             : {
      50             : #ifdef WIN32
      51             : 
      52             :     char       *result;
      53             :     char       *c;
      54             : 
      55             :     result = pg_strdup(path);
      56             : 
      57             :     for (c = result; *c != '\0'; c++)
      58             :         if (*c == '/')
      59             :             *c = '\\';
      60             : 
      61             :     return result;
      62             : #else
      63             : 
      64           4 :     return path;
      65             : #endif
      66             : }
      67             : 
      68             : void
      69          12 : output_check_banner(bool live_check)
      70             : {
      71          12 :     if (user_opts.check && live_check)
      72             :     {
      73           0 :         pg_log(PG_REPORT,
      74             :                "Performing Consistency Checks on Old Live Server\n"
      75             :                "------------------------------------------------");
      76             :     }
      77             :     else
      78             :     {
      79          12 :         pg_log(PG_REPORT,
      80             :                "Performing Consistency Checks\n"
      81             :                "-----------------------------");
      82             :     }
      83          12 : }
      84             : 
      85             : 
      86             : void
      87          12 : check_and_dump_old_cluster(bool live_check)
      88             : {
      89             :     /* -- OLD -- */
      90             : 
      91          12 :     if (!live_check)
      92          12 :         start_postmaster(&old_cluster, true);
      93             : 
      94             :     /*
      95             :      * Extract a list of databases, tables, and logical replication slots from
      96             :      * the old cluster.
      97             :      */
      98          12 :     get_db_rel_and_slot_infos(&old_cluster, live_check);
      99             : 
     100          10 :     init_tablespaces();
     101             : 
     102          10 :     get_loadable_libraries();
     103             : 
     104             : 
     105             :     /*
     106             :      * Check for various failure cases
     107             :      */
     108          10 :     check_is_install_user(&old_cluster);
     109          10 :     check_proper_datallowconn(&old_cluster);
     110          10 :     check_for_prepared_transactions(&old_cluster);
     111          10 :     check_for_composite_data_type_usage(&old_cluster);
     112          10 :     check_for_reg_data_type_usage(&old_cluster);
     113          10 :     check_for_isn_and_int8_passing_mismatch(&old_cluster);
     114             : 
     115             :     /*
     116             :      * Logical replication slots can be migrated since PG17. See comments atop
     117             :      * get_old_cluster_logical_slot_infos().
     118             :      */
     119          10 :     if (GET_MAJOR_VERSION(old_cluster.major_version) >= 1700)
     120          10 :         check_old_cluster_for_valid_slots(live_check);
     121             : 
     122             :     /*
     123             :      * PG 16 increased the size of the 'aclitem' type, which breaks the
     124             :      * on-disk format for existing data.
     125             :      */
     126           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1500)
     127           0 :         check_for_aclitem_data_type_usage(&old_cluster);
     128             : 
     129             :     /*
     130             :      * PG 12 removed types abstime, reltime, tinterval.
     131             :      */
     132           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1100)
     133             :     {
     134           0 :         check_for_removed_data_type_usage(&old_cluster, "12", "abstime");
     135           0 :         check_for_removed_data_type_usage(&old_cluster, "12", "reltime");
     136           0 :         check_for_removed_data_type_usage(&old_cluster, "12", "tinterval");
     137             :     }
     138             : 
     139             :     /*
     140             :      * PG 14 changed the function signature of encoding conversion functions.
     141             :      * Conversions from older versions cannot be upgraded automatically
     142             :      * because the user-defined functions used by the encoding conversions
     143             :      * need to be changed to match the new signature.
     144             :      */
     145           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
     146           0 :         check_for_user_defined_encoding_conversions(&old_cluster);
     147             : 
     148             :     /*
     149             :      * Pre-PG 14 allowed user defined postfix operators, which are not
     150             :      * supported anymore.  Verify there are none, iff applicable.
     151             :      */
     152           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
     153           0 :         check_for_user_defined_postfix_ops(&old_cluster);
     154             : 
     155             :     /*
     156             :      * PG 14 changed polymorphic functions from anyarray to
     157             :      * anycompatiblearray.
     158             :      */
     159           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1300)
     160           0 :         check_for_incompatible_polymorphics(&old_cluster);
     161             : 
     162             :     /*
     163             :      * Pre-PG 12 allowed tables to be declared WITH OIDS, which is not
     164             :      * supported anymore. Verify there are none, iff applicable.
     165             :      */
     166           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1100)
     167           0 :         check_for_tables_with_oids(&old_cluster);
     168             : 
     169             :     /*
     170             :      * PG 12 changed the 'sql_identifier' type storage to be based on name,
     171             :      * not varchar, which breaks on-disk format for existing data. So we need
     172             :      * to prevent upgrade when used in user objects (tables, indexes, ...).
     173             :      */
     174           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1100)
     175           0 :         old_11_check_for_sql_identifier_data_type_usage(&old_cluster);
     176             : 
     177             :     /*
     178             :      * Pre-PG 10 allowed tables with 'unknown' type columns and non WAL logged
     179             :      * hash indexes
     180             :      */
     181           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
     182             :     {
     183           0 :         old_9_6_check_for_unknown_data_type_usage(&old_cluster);
     184           0 :         if (user_opts.check)
     185           0 :             old_9_6_invalidate_hash_indexes(&old_cluster, true);
     186             :     }
     187             : 
     188             :     /* 9.5 and below should not have roles starting with pg_ */
     189           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 905)
     190           0 :         check_for_pg_role_prefix(&old_cluster);
     191             : 
     192           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) == 904 &&
     193           0 :         old_cluster.controldata.cat_ver < JSONB_FORMAT_CHANGE_CAT_VER)
     194           0 :         check_for_jsonb_9_4_usage(&old_cluster);
     195             : 
     196             :     /* Pre-PG 9.4 had a different 'line' data type internal format */
     197           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 903)
     198           0 :         old_9_3_check_for_line_data_type_usage(&old_cluster);
     199             : 
     200             :     /*
     201             :      * While not a check option, we do this now because this is the only time
     202             :      * the old server is running.
     203             :      */
     204           8 :     if (!user_opts.check)
     205           6 :         generate_old_dump();
     206             : 
     207           8 :     if (!live_check)
     208           8 :         stop_postmaster(false);
     209           8 : }
     210             : 
     211             : 
     212             : void
     213           8 : check_new_cluster(void)
     214             : {
     215           8 :     get_db_rel_and_slot_infos(&new_cluster, false);
     216             : 
     217           8 :     check_new_cluster_is_empty();
     218             : 
     219           8 :     check_loadable_libraries();
     220             : 
     221           8 :     switch (user_opts.transfer_mode)
     222             :     {
     223           0 :         case TRANSFER_MODE_CLONE:
     224           0 :             check_file_clone();
     225           0 :             break;
     226           8 :         case TRANSFER_MODE_COPY:
     227           8 :             break;
     228           0 :         case TRANSFER_MODE_LINK:
     229           0 :             check_hard_link();
     230           0 :             break;
     231             :     }
     232             : 
     233           8 :     check_is_install_user(&new_cluster);
     234             : 
     235           8 :     check_for_prepared_transactions(&new_cluster);
     236             : 
     237           8 :     check_for_new_tablespace_dir();
     238             : 
     239           8 :     check_new_cluster_logical_replication_slots();
     240           6 : }
     241             : 
     242             : 
     243             : void
     244           6 : report_clusters_compatible(void)
     245             : {
     246           6 :     if (user_opts.check)
     247             :     {
     248           2 :         pg_log(PG_REPORT, "\n*Clusters are compatible*");
     249             :         /* stops new cluster */
     250           2 :         stop_postmaster(false);
     251             : 
     252           2 :         cleanup_output_dirs();
     253           2 :         exit(0);
     254             :     }
     255             : 
     256           4 :     pg_log(PG_REPORT, "\n"
     257             :            "If pg_upgrade fails after this point, you must re-initdb the\n"
     258             :            "new cluster before continuing.");
     259           4 : }
     260             : 
     261             : 
     262             : void
     263           4 : issue_warnings_and_set_wal_level(void)
     264             : {
     265             :     /*
     266             :      * We unconditionally start/stop the new server because pg_resetwal -o set
     267             :      * wal_level to 'minimum'.  If the user is upgrading standby servers using
     268             :      * the rsync instructions, they will need pg_upgrade to write its final
     269             :      * WAL record showing wal_level as 'replica'.
     270             :      */
     271           4 :     start_postmaster(&new_cluster, true);
     272             : 
     273             :     /* Reindex hash indexes for old < 10.0 */
     274           4 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
     275           0 :         old_9_6_invalidate_hash_indexes(&new_cluster, false);
     276             : 
     277           4 :     report_extension_updates(&new_cluster);
     278             : 
     279           4 :     stop_postmaster(false);
     280           4 : }
     281             : 
     282             : 
     283             : void
     284           4 : output_completion_banner(char *deletion_script_file_name)
     285             : {
     286             :     PQExpBufferData user_specification;
     287             : 
     288           4 :     initPQExpBuffer(&user_specification);
     289           4 :     if (os_info.user_specified)
     290             :     {
     291           0 :         appendPQExpBufferStr(&user_specification, "-U ");
     292           0 :         appendShellString(&user_specification, os_info.user);
     293           0 :         appendPQExpBufferChar(&user_specification, ' ');
     294             :     }
     295             : 
     296           4 :     pg_log(PG_REPORT,
     297             :            "Optimizer statistics are not transferred by pg_upgrade.\n"
     298             :            "Once you start the new server, consider running:\n"
     299             :            "    %s/vacuumdb %s--all --analyze-in-stages", new_cluster.bindir, user_specification.data);
     300             : 
     301           4 :     if (deletion_script_file_name)
     302           4 :         pg_log(PG_REPORT,
     303             :                "Running this script will delete the old cluster's data files:\n"
     304             :                "    %s",
     305             :                deletion_script_file_name);
     306             :     else
     307           0 :         pg_log(PG_REPORT,
     308             :                "Could not create a script to delete the old cluster's data files\n"
     309             :                "because user-defined tablespaces or the new cluster's data directory\n"
     310             :                "exist in the old cluster directory.  The old cluster's contents must\n"
     311             :                "be deleted manually.");
     312             : 
     313           4 :     termPQExpBuffer(&user_specification);
     314           4 : }
     315             : 
     316             : 
     317             : void
     318          12 : check_cluster_versions(void)
     319             : {
     320          12 :     prep_status("Checking cluster versions");
     321             : 
     322             :     /* cluster versions should already have been obtained */
     323             :     Assert(old_cluster.major_version != 0);
     324             :     Assert(new_cluster.major_version != 0);
     325             : 
     326             :     /*
     327             :      * We allow upgrades from/to the same major version for alpha/beta
     328             :      * upgrades
     329             :      */
     330             : 
     331          12 :     if (GET_MAJOR_VERSION(old_cluster.major_version) < 902)
     332           0 :         pg_fatal("This utility can only upgrade from PostgreSQL version %s and later.",
     333             :                  "9.2");
     334             : 
     335             :     /* Only current PG version is supported as a target */
     336          12 :     if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
     337           0 :         pg_fatal("This utility can only upgrade to PostgreSQL version %s.",
     338             :                  PG_MAJORVERSION);
     339             : 
     340             :     /*
     341             :      * We can't allow downgrading because we use the target pg_dump, and
     342             :      * pg_dump cannot operate on newer database versions, only current and
     343             :      * older versions.
     344             :      */
     345          12 :     if (old_cluster.major_version > new_cluster.major_version)
     346           0 :         pg_fatal("This utility cannot be used to downgrade to older major PostgreSQL versions.");
     347             : 
     348             :     /* Ensure binaries match the designated data directories */
     349          12 :     if (GET_MAJOR_VERSION(old_cluster.major_version) !=
     350          12 :         GET_MAJOR_VERSION(old_cluster.bin_version))
     351           0 :         pg_fatal("Old cluster data and binary directories are from different major versions.");
     352          12 :     if (GET_MAJOR_VERSION(new_cluster.major_version) !=
     353          12 :         GET_MAJOR_VERSION(new_cluster.bin_version))
     354           0 :         pg_fatal("New cluster data and binary directories are from different major versions.");
     355             : 
     356          12 :     check_ok();
     357          12 : }
     358             : 
     359             : 
     360             : void
     361          12 : check_cluster_compatibility(bool live_check)
     362             : {
     363             :     /* get/check pg_control data of servers */
     364          12 :     get_control_data(&old_cluster, live_check);
     365          12 :     get_control_data(&new_cluster, false);
     366          12 :     check_control_data(&old_cluster.controldata, &new_cluster.controldata);
     367             : 
     368          12 :     if (live_check && old_cluster.port == new_cluster.port)
     369           0 :         pg_fatal("When checking a live server, "
     370             :                  "the old and new port numbers must be different.");
     371          12 : }
     372             : 
     373             : 
     374             : static void
     375           8 : check_new_cluster_is_empty(void)
     376             : {
     377             :     int         dbnum;
     378             : 
     379          24 :     for (dbnum = 0; dbnum < new_cluster.dbarr.ndbs; dbnum++)
     380             :     {
     381             :         int         relnum;
     382          16 :         RelInfoArr *rel_arr = &new_cluster.dbarr.dbs[dbnum].rel_arr;
     383             : 
     384          48 :         for (relnum = 0; relnum < rel_arr->nrels;
     385          32 :              relnum++)
     386             :         {
     387             :             /* pg_largeobject and its index should be skipped */
     388          32 :             if (strcmp(rel_arr->rels[relnum].nspname, "pg_catalog") != 0)
     389           0 :                 pg_fatal("New cluster database \"%s\" is not empty: found relation \"%s.%s\"",
     390           0 :                          new_cluster.dbarr.dbs[dbnum].db_name,
     391           0 :                          rel_arr->rels[relnum].nspname,
     392           0 :                          rel_arr->rels[relnum].relname);
     393             :         }
     394             :     }
     395           8 : }
     396             : 
     397             : /*
     398             :  * A previous run of pg_upgrade might have failed and the new cluster
     399             :  * directory recreated, but they might have forgotten to remove
     400             :  * the new cluster's tablespace directories.  Therefore, check that
     401             :  * new cluster tablespace directories do not already exist.  If
     402             :  * they do, it would cause an error while restoring global objects.
     403             :  * This allows the failure to be detected at check time, rather than
     404             :  * during schema restore.
     405             :  */
     406             : static void
     407           8 : check_for_new_tablespace_dir(void)
     408             : {
     409             :     int         tblnum;
     410             :     char        new_tablespace_dir[MAXPGPATH];
     411             : 
     412           8 :     prep_status("Checking for new cluster tablespace directories");
     413             : 
     414           8 :     for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
     415             :     {
     416             :         struct stat statbuf;
     417             : 
     418           0 :         snprintf(new_tablespace_dir, MAXPGPATH, "%s%s",
     419           0 :                  os_info.old_tablespaces[tblnum],
     420             :                  new_cluster.tablespace_suffix);
     421             : 
     422           0 :         if (stat(new_tablespace_dir, &statbuf) == 0 || errno != ENOENT)
     423           0 :             pg_fatal("new cluster tablespace directory already exists: \"%s\"",
     424             :                      new_tablespace_dir);
     425             :     }
     426             : 
     427           8 :     check_ok();
     428           8 : }
     429             : 
     430             : /*
     431             :  * create_script_for_old_cluster_deletion()
     432             :  *
     433             :  *  This is particularly useful for tablespace deletion.
     434             :  */
     435             : void
     436           4 : create_script_for_old_cluster_deletion(char **deletion_script_file_name)
     437             : {
     438           4 :     FILE       *script = NULL;
     439             :     int         tblnum;
     440             :     char        old_cluster_pgdata[MAXPGPATH],
     441             :                 new_cluster_pgdata[MAXPGPATH];
     442             : 
     443           4 :     *deletion_script_file_name = psprintf("%sdelete_old_cluster.%s",
     444             :                                           SCRIPT_PREFIX, SCRIPT_EXT);
     445             : 
     446           4 :     strlcpy(old_cluster_pgdata, old_cluster.pgdata, MAXPGPATH);
     447           4 :     canonicalize_path(old_cluster_pgdata);
     448             : 
     449           4 :     strlcpy(new_cluster_pgdata, new_cluster.pgdata, MAXPGPATH);
     450           4 :     canonicalize_path(new_cluster_pgdata);
     451             : 
     452             :     /* Some people put the new data directory inside the old one. */
     453           4 :     if (path_is_prefix_of_path(old_cluster_pgdata, new_cluster_pgdata))
     454             :     {
     455           0 :         pg_log(PG_WARNING,
     456             :                "\nWARNING:  new data directory should not be inside the old data directory, i.e. %s", old_cluster_pgdata);
     457             : 
     458             :         /* Unlink file in case it is left over from a previous run. */
     459           0 :         unlink(*deletion_script_file_name);
     460           0 :         pg_free(*deletion_script_file_name);
     461           0 :         *deletion_script_file_name = NULL;
     462           0 :         return;
     463             :     }
     464             : 
     465             :     /*
     466             :      * Some users (oddly) create tablespaces inside the cluster data
     467             :      * directory.  We can't create a proper old cluster delete script in that
     468             :      * case.
     469             :      */
     470           4 :     for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
     471             :     {
     472             :         char        old_tablespace_dir[MAXPGPATH];
     473             : 
     474           0 :         strlcpy(old_tablespace_dir, os_info.old_tablespaces[tblnum], MAXPGPATH);
     475           0 :         canonicalize_path(old_tablespace_dir);
     476           0 :         if (path_is_prefix_of_path(old_cluster_pgdata, old_tablespace_dir))
     477             :         {
     478             :             /* reproduce warning from CREATE TABLESPACE that is in the log */
     479           0 :             pg_log(PG_WARNING,
     480             :                    "\nWARNING:  user-defined tablespace locations should not be inside the data directory, i.e. %s", old_tablespace_dir);
     481             : 
     482             :             /* Unlink file in case it is left over from a previous run. */
     483           0 :             unlink(*deletion_script_file_name);
     484           0 :             pg_free(*deletion_script_file_name);
     485           0 :             *deletion_script_file_name = NULL;
     486           0 :             return;
     487             :         }
     488             :     }
     489             : 
     490           4 :     prep_status("Creating script to delete old cluster");
     491             : 
     492           4 :     if ((script = fopen_priv(*deletion_script_file_name, "w")) == NULL)
     493           0 :         pg_fatal("could not open file \"%s\": %s",
     494           0 :                  *deletion_script_file_name, strerror(errno));
     495             : 
     496             : #ifndef WIN32
     497             :     /* add shebang header */
     498           4 :     fprintf(script, "#!/bin/sh\n\n");
     499             : #endif
     500             : 
     501             :     /* delete old cluster's default tablespace */
     502           4 :     fprintf(script, RMDIR_CMD " %c%s%c\n", PATH_QUOTE,
     503             :             fix_path_separator(old_cluster.pgdata), PATH_QUOTE);
     504             : 
     505             :     /* delete old cluster's alternate tablespaces */
     506           4 :     for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
     507             :     {
     508             :         /*
     509             :          * Do the old cluster's per-database directories share a directory
     510             :          * with a new version-specific tablespace?
     511             :          */
     512           0 :         if (strlen(old_cluster.tablespace_suffix) == 0)
     513             :         {
     514             :             /* delete per-database directories */
     515             :             int         dbnum;
     516             : 
     517           0 :             fprintf(script, "\n");
     518             : 
     519           0 :             for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
     520           0 :                 fprintf(script, RMDIR_CMD " %c%s%c%u%c\n", PATH_QUOTE,
     521           0 :                         fix_path_separator(os_info.old_tablespaces[tblnum]),
     522           0 :                         PATH_SEPARATOR, old_cluster.dbarr.dbs[dbnum].db_oid,
     523             :                         PATH_QUOTE);
     524             :         }
     525             :         else
     526             :         {
     527           0 :             char       *suffix_path = pg_strdup(old_cluster.tablespace_suffix);
     528             : 
     529             :             /*
     530             :              * Simply delete the tablespace directory, which might be ".old"
     531             :              * or a version-specific subdirectory.
     532             :              */
     533           0 :             fprintf(script, RMDIR_CMD " %c%s%s%c\n", PATH_QUOTE,
     534           0 :                     fix_path_separator(os_info.old_tablespaces[tblnum]),
     535             :                     fix_path_separator(suffix_path), PATH_QUOTE);
     536           0 :             pfree(suffix_path);
     537             :         }
     538             :     }
     539             : 
     540           4 :     fclose(script);
     541             : 
     542             : #ifndef WIN32
     543           4 :     if (chmod(*deletion_script_file_name, S_IRWXU) != 0)
     544           0 :         pg_fatal("could not add execute permission to file \"%s\": %s",
     545           0 :                  *deletion_script_file_name, strerror(errno));
     546             : #endif
     547             : 
     548           4 :     check_ok();
     549             : }
     550             : 
     551             : 
     552             : /*
     553             :  *  check_is_install_user()
     554             :  *
     555             :  *  Check we are the install user, and that the new cluster
     556             :  *  has no other users.
     557             :  */
     558             : static void
     559          18 : check_is_install_user(ClusterInfo *cluster)
     560             : {
     561             :     PGresult   *res;
     562          18 :     PGconn     *conn = connectToServer(cluster, "template1");
     563             : 
     564          18 :     prep_status("Checking database user is the install user");
     565             : 
     566             :     /* Can't use pg_authid because only superusers can view it. */
     567          18 :     res = executeQueryOrDie(conn,
     568             :                             "SELECT rolsuper, oid "
     569             :                             "FROM pg_catalog.pg_roles "
     570             :                             "WHERE rolname = current_user "
     571             :                             "AND rolname !~ '^pg_'");
     572             : 
     573             :     /*
     574             :      * We only allow the install user in the new cluster (see comment below)
     575             :      * and we preserve pg_authid.oid, so this must be the install user in the
     576             :      * old cluster too.
     577             :      */
     578          18 :     if (PQntuples(res) != 1 ||
     579          18 :         atooid(PQgetvalue(res, 0, 1)) != BOOTSTRAP_SUPERUSERID)
     580           0 :         pg_fatal("database user \"%s\" is not the install user",
     581             :                  os_info.user);
     582             : 
     583          18 :     PQclear(res);
     584             : 
     585          18 :     res = executeQueryOrDie(conn,
     586             :                             "SELECT COUNT(*) "
     587             :                             "FROM pg_catalog.pg_roles "
     588             :                             "WHERE rolname !~ '^pg_'");
     589             : 
     590          18 :     if (PQntuples(res) != 1)
     591           0 :         pg_fatal("could not determine the number of users");
     592             : 
     593             :     /*
     594             :      * We only allow the install user in the new cluster because other defined
     595             :      * users might match users defined in the old cluster and generate an
     596             :      * error during pg_dump restore.
     597             :      */
     598          18 :     if (cluster == &new_cluster && strcmp(PQgetvalue(res, 0, 0), "1") != 0)
     599           0 :         pg_fatal("Only the install user can be defined in the new cluster.");
     600             : 
     601          18 :     PQclear(res);
     602             : 
     603          18 :     PQfinish(conn);
     604             : 
     605          18 :     check_ok();
     606          18 : }
     607             : 
     608             : 
     609             : /*
     610             :  *  check_proper_datallowconn
     611             :  *
     612             :  *  Ensure that all non-template0 databases allow connections since they
     613             :  *  otherwise won't be restored; and that template0 explicitly doesn't allow
     614             :  *  connections since it would make pg_dumpall --globals restore fail.
     615             :  */
     616             : static void
     617          10 : check_proper_datallowconn(ClusterInfo *cluster)
     618             : {
     619             :     int         dbnum;
     620             :     PGconn     *conn_template1;
     621             :     PGresult   *dbres;
     622             :     int         ntups;
     623             :     int         i_datname;
     624             :     int         i_datallowconn;
     625          10 :     FILE       *script = NULL;
     626             :     char        output_path[MAXPGPATH];
     627             : 
     628          10 :     prep_status("Checking database connection settings");
     629             : 
     630          10 :     snprintf(output_path, sizeof(output_path), "%s/%s",
     631             :              log_opts.basedir,
     632             :              "databases_with_datallowconn_false.txt");
     633             : 
     634          10 :     conn_template1 = connectToServer(cluster, "template1");
     635             : 
     636             :     /* get database names */
     637          10 :     dbres = executeQueryOrDie(conn_template1,
     638             :                               "SELECT  datname, datallowconn "
     639             :                               "FROM    pg_catalog.pg_database");
     640             : 
     641          10 :     i_datname = PQfnumber(dbres, "datname");
     642          10 :     i_datallowconn = PQfnumber(dbres, "datallowconn");
     643             : 
     644          10 :     ntups = PQntuples(dbres);
     645          56 :     for (dbnum = 0; dbnum < ntups; dbnum++)
     646             :     {
     647          46 :         char       *datname = PQgetvalue(dbres, dbnum, i_datname);
     648          46 :         char       *datallowconn = PQgetvalue(dbres, dbnum, i_datallowconn);
     649             : 
     650          46 :         if (strcmp(datname, "template0") == 0)
     651             :         {
     652             :             /* avoid restore failure when pg_dumpall tries to create template0 */
     653          10 :             if (strcmp(datallowconn, "t") == 0)
     654           0 :                 pg_fatal("template0 must not allow connections, "
     655             :                          "i.e. its pg_database.datallowconn must be false");
     656             :         }
     657             :         else
     658             :         {
     659             :             /*
     660             :              * avoid datallowconn == false databases from being skipped on
     661             :              * restore
     662             :              */
     663          36 :             if (strcmp(datallowconn, "f") == 0)
     664             :             {
     665           0 :                 if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
     666           0 :                     pg_fatal("could not open file \"%s\": %s",
     667           0 :                              output_path, strerror(errno));
     668             : 
     669           0 :                 fprintf(script, "%s\n", datname);
     670             :             }
     671             :         }
     672             :     }
     673             : 
     674          10 :     PQclear(dbres);
     675             : 
     676          10 :     PQfinish(conn_template1);
     677             : 
     678          10 :     if (script)
     679             :     {
     680           0 :         fclose(script);
     681           0 :         pg_log(PG_REPORT, "fatal");
     682           0 :         pg_fatal("All non-template0 databases must allow connections, i.e. their\n"
     683             :                  "pg_database.datallowconn must be true.  Your installation contains\n"
     684             :                  "non-template0 databases with their pg_database.datallowconn set to\n"
     685             :                  "false.  Consider allowing connection for all non-template0 databases\n"
     686             :                  "or drop the databases which do not allow connections.  A list of\n"
     687             :                  "databases with the problem is in the file:\n"
     688             :                  "    %s", output_path);
     689             :     }
     690             :     else
     691          10 :         check_ok();
     692          10 : }
     693             : 
     694             : 
     695             : /*
     696             :  *  check_for_prepared_transactions()
     697             :  *
     698             :  *  Make sure there are no prepared transactions because the storage format
     699             :  *  might have changed.
     700             :  */
     701             : static void
     702          18 : check_for_prepared_transactions(ClusterInfo *cluster)
     703             : {
     704             :     PGresult   *res;
     705          18 :     PGconn     *conn = connectToServer(cluster, "template1");
     706             : 
     707          18 :     prep_status("Checking for prepared transactions");
     708             : 
     709          18 :     res = executeQueryOrDie(conn,
     710             :                             "SELECT * "
     711             :                             "FROM pg_catalog.pg_prepared_xacts");
     712             : 
     713          18 :     if (PQntuples(res) != 0)
     714             :     {
     715           0 :         if (cluster == &old_cluster)
     716           0 :             pg_fatal("The source cluster contains prepared transactions");
     717             :         else
     718           0 :             pg_fatal("The target cluster contains prepared transactions");
     719             :     }
     720             : 
     721          18 :     PQclear(res);
     722             : 
     723          18 :     PQfinish(conn);
     724             : 
     725          18 :     check_ok();
     726          18 : }
     727             : 
     728             : 
     729             : /*
     730             :  *  check_for_isn_and_int8_passing_mismatch()
     731             :  *
     732             :  *  contrib/isn relies on data type int8, and in 8.4 int8 can now be passed
     733             :  *  by value.  The schema dumps the CREATE TYPE PASSEDBYVALUE setting so
     734             :  *  it must match for the old and new servers.
     735             :  */
     736             : static void
     737          10 : check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster)
     738             : {
     739             :     int         dbnum;
     740          10 :     FILE       *script = NULL;
     741             :     char        output_path[MAXPGPATH];
     742             : 
     743          10 :     prep_status("Checking for contrib/isn with bigint-passing mismatch");
     744             : 
     745          10 :     if (old_cluster.controldata.float8_pass_by_value ==
     746          10 :         new_cluster.controldata.float8_pass_by_value)
     747             :     {
     748             :         /* no mismatch */
     749          10 :         check_ok();
     750          10 :         return;
     751             :     }
     752             : 
     753           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
     754             :              log_opts.basedir,
     755             :              "contrib_isn_and_int8_pass_by_value.txt");
     756             : 
     757           0 :     for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
     758             :     {
     759             :         PGresult   *res;
     760           0 :         bool        db_used = false;
     761             :         int         ntups;
     762             :         int         rowno;
     763             :         int         i_nspname,
     764             :                     i_proname;
     765           0 :         DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
     766           0 :         PGconn     *conn = connectToServer(cluster, active_db->db_name);
     767             : 
     768             :         /* Find any functions coming from contrib/isn */
     769           0 :         res = executeQueryOrDie(conn,
     770             :                                 "SELECT n.nspname, p.proname "
     771             :                                 "FROM  pg_catalog.pg_proc p, "
     772             :                                 "      pg_catalog.pg_namespace n "
     773             :                                 "WHERE p.pronamespace = n.oid AND "
     774             :                                 "      p.probin = '$libdir/isn'");
     775             : 
     776           0 :         ntups = PQntuples(res);
     777           0 :         i_nspname = PQfnumber(res, "nspname");
     778           0 :         i_proname = PQfnumber(res, "proname");
     779           0 :         for (rowno = 0; rowno < ntups; rowno++)
     780             :         {
     781           0 :             if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
     782           0 :                 pg_fatal("could not open file \"%s\": %s",
     783           0 :                          output_path, strerror(errno));
     784           0 :             if (!db_used)
     785             :             {
     786           0 :                 fprintf(script, "In database: %s\n", active_db->db_name);
     787           0 :                 db_used = true;
     788             :             }
     789           0 :             fprintf(script, "  %s.%s\n",
     790             :                     PQgetvalue(res, rowno, i_nspname),
     791             :                     PQgetvalue(res, rowno, i_proname));
     792             :         }
     793             : 
     794           0 :         PQclear(res);
     795             : 
     796           0 :         PQfinish(conn);
     797             :     }
     798             : 
     799           0 :     if (script)
     800             :     {
     801           0 :         fclose(script);
     802           0 :         pg_log(PG_REPORT, "fatal");
     803           0 :         pg_fatal("Your installation contains \"contrib/isn\" functions which rely on the\n"
     804             :                  "bigint data type.  Your old and new clusters pass bigint values\n"
     805             :                  "differently so this cluster cannot currently be upgraded.  You can\n"
     806             :                  "manually dump databases in the old cluster that use \"contrib/isn\"\n"
     807             :                  "facilities, drop them, perform the upgrade, and then restore them.  A\n"
     808             :                  "list of the problem functions is in the file:\n"
     809             :                  "    %s", output_path);
     810             :     }
     811             :     else
     812           0 :         check_ok();
     813             : }
     814             : 
     815             : /*
     816             :  * Verify that no user defined postfix operators exist.
     817             :  */
     818             : static void
     819           0 : check_for_user_defined_postfix_ops(ClusterInfo *cluster)
     820             : {
     821             :     int         dbnum;
     822           0 :     FILE       *script = NULL;
     823             :     char        output_path[MAXPGPATH];
     824             : 
     825           0 :     prep_status("Checking for user-defined postfix operators");
     826             : 
     827           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
     828             :              log_opts.basedir,
     829             :              "postfix_ops.txt");
     830             : 
     831             :     /* Find any user defined postfix operators */
     832           0 :     for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
     833             :     {
     834             :         PGresult   *res;
     835           0 :         bool        db_used = false;
     836             :         int         ntups;
     837             :         int         rowno;
     838             :         int         i_oproid,
     839             :                     i_oprnsp,
     840             :                     i_oprname,
     841             :                     i_typnsp,
     842             :                     i_typname;
     843           0 :         DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
     844           0 :         PGconn     *conn = connectToServer(cluster, active_db->db_name);
     845             : 
     846             :         /*
     847             :          * The query below hardcodes FirstNormalObjectId as 16384 rather than
     848             :          * interpolating that C #define into the query because, if that
     849             :          * #define is ever changed, the cutoff we want to use is the value
     850             :          * used by pre-version 14 servers, not that of some future version.
     851             :          */
     852           0 :         res = executeQueryOrDie(conn,
     853             :                                 "SELECT o.oid AS oproid, "
     854             :                                 "       n.nspname AS oprnsp, "
     855             :                                 "       o.oprname, "
     856             :                                 "       tn.nspname AS typnsp, "
     857             :                                 "       t.typname "
     858             :                                 "FROM pg_catalog.pg_operator o, "
     859             :                                 "     pg_catalog.pg_namespace n, "
     860             :                                 "     pg_catalog.pg_type t, "
     861             :                                 "     pg_catalog.pg_namespace tn "
     862             :                                 "WHERE o.oprnamespace = n.oid AND "
     863             :                                 "      o.oprleft = t.oid AND "
     864             :                                 "      t.typnamespace = tn.oid AND "
     865             :                                 "      o.oprright = 0 AND "
     866             :                                 "      o.oid >= 16384");
     867           0 :         ntups = PQntuples(res);
     868           0 :         i_oproid = PQfnumber(res, "oproid");
     869           0 :         i_oprnsp = PQfnumber(res, "oprnsp");
     870           0 :         i_oprname = PQfnumber(res, "oprname");
     871           0 :         i_typnsp = PQfnumber(res, "typnsp");
     872           0 :         i_typname = PQfnumber(res, "typname");
     873           0 :         for (rowno = 0; rowno < ntups; rowno++)
     874             :         {
     875           0 :             if (script == NULL &&
     876           0 :                 (script = fopen_priv(output_path, "w")) == NULL)
     877           0 :                 pg_fatal("could not open file \"%s\": %s",
     878           0 :                          output_path, strerror(errno));
     879           0 :             if (!db_used)
     880             :             {
     881           0 :                 fprintf(script, "In database: %s\n", active_db->db_name);
     882           0 :                 db_used = true;
     883             :             }
     884           0 :             fprintf(script, "  (oid=%s) %s.%s (%s.%s, NONE)\n",
     885             :                     PQgetvalue(res, rowno, i_oproid),
     886             :                     PQgetvalue(res, rowno, i_oprnsp),
     887             :                     PQgetvalue(res, rowno, i_oprname),
     888             :                     PQgetvalue(res, rowno, i_typnsp),
     889             :                     PQgetvalue(res, rowno, i_typname));
     890             :         }
     891             : 
     892           0 :         PQclear(res);
     893             : 
     894           0 :         PQfinish(conn);
     895             :     }
     896             : 
     897           0 :     if (script)
     898             :     {
     899           0 :         fclose(script);
     900           0 :         pg_log(PG_REPORT, "fatal");
     901           0 :         pg_fatal("Your installation contains user-defined postfix operators, which are not\n"
     902             :                  "supported anymore.  Consider dropping the postfix operators and replacing\n"
     903             :                  "them with prefix operators or function calls.\n"
     904             :                  "A list of user-defined postfix operators is in the file:\n"
     905             :                  "    %s", output_path);
     906             :     }
     907             :     else
     908           0 :         check_ok();
     909           0 : }
     910             : 
     911             : /*
     912             :  *  check_for_incompatible_polymorphics()
     913             :  *
     914             :  *  Make sure nothing is using old polymorphic functions with
     915             :  *  anyarray/anyelement rather than the new anycompatible variants.
     916             :  */
     917             : static void
     918           0 : check_for_incompatible_polymorphics(ClusterInfo *cluster)
     919             : {
     920             :     PGresult   *res;
     921           0 :     FILE       *script = NULL;
     922             :     char        output_path[MAXPGPATH];
     923             :     PQExpBufferData old_polymorphics;
     924             : 
     925           0 :     prep_status("Checking for incompatible polymorphic functions");
     926             : 
     927           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
     928             :              log_opts.basedir,
     929             :              "incompatible_polymorphics.txt");
     930             : 
     931             :     /* The set of problematic functions varies a bit in different versions */
     932           0 :     initPQExpBuffer(&old_polymorphics);
     933             : 
     934           0 :     appendPQExpBufferStr(&old_polymorphics,
     935             :                          "'array_append(anyarray,anyelement)'"
     936             :                          ", 'array_cat(anyarray,anyarray)'"
     937             :                          ", 'array_prepend(anyelement,anyarray)'");
     938             : 
     939           0 :     if (GET_MAJOR_VERSION(cluster->major_version) >= 903)
     940           0 :         appendPQExpBufferStr(&old_polymorphics,
     941             :                              ", 'array_remove(anyarray,anyelement)'"
     942             :                              ", 'array_replace(anyarray,anyelement,anyelement)'");
     943             : 
     944           0 :     if (GET_MAJOR_VERSION(cluster->major_version) >= 905)
     945           0 :         appendPQExpBufferStr(&old_polymorphics,
     946             :                              ", 'array_position(anyarray,anyelement)'"
     947             :                              ", 'array_position(anyarray,anyelement,integer)'"
     948             :                              ", 'array_positions(anyarray,anyelement)'"
     949             :                              ", 'width_bucket(anyelement,anyarray)'");
     950             : 
     951           0 :     for (int dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
     952             :     {
     953           0 :         bool        db_used = false;
     954           0 :         DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
     955           0 :         PGconn     *conn = connectToServer(cluster, active_db->db_name);
     956             :         int         ntups;
     957             :         int         i_objkind,
     958             :                     i_objname;
     959             : 
     960             :         /*
     961             :          * The query below hardcodes FirstNormalObjectId as 16384 rather than
     962             :          * interpolating that C #define into the query because, if that
     963             :          * #define is ever changed, the cutoff we want to use is the value
     964             :          * used by pre-version 14 servers, not that of some future version.
     965             :          */
     966           0 :         res = executeQueryOrDie(conn,
     967             :         /* Aggregate transition functions */
     968             :                                 "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
     969             :                                 "FROM pg_proc AS p "
     970             :                                 "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
     971             :                                 "JOIN pg_proc AS transfn ON transfn.oid=a.aggtransfn "
     972             :                                 "WHERE p.oid >= 16384 "
     973             :                                 "AND a.aggtransfn = ANY(ARRAY[%s]::regprocedure[]) "
     974             :                                 "AND a.aggtranstype = ANY(ARRAY['anyarray', 'anyelement']::regtype[]) "
     975             : 
     976             :         /* Aggregate final functions */
     977             :                                 "UNION ALL "
     978             :                                 "SELECT 'aggregate' AS objkind, p.oid::regprocedure::text AS objname "
     979             :                                 "FROM pg_proc AS p "
     980             :                                 "JOIN pg_aggregate AS a ON a.aggfnoid=p.oid "
     981             :                                 "JOIN pg_proc AS finalfn ON finalfn.oid=a.aggfinalfn "
     982             :                                 "WHERE p.oid >= 16384 "
     983             :                                 "AND a.aggfinalfn = ANY(ARRAY[%s]::regprocedure[]) "
     984             :                                 "AND a.aggtranstype = ANY(ARRAY['anyarray', 'anyelement']::regtype[]) "
     985             : 
     986             :         /* Operators */
     987             :                                 "UNION ALL "
     988             :                                 "SELECT 'operator' AS objkind, op.oid::regoperator::text AS objname "
     989             :                                 "FROM pg_operator AS op "
     990             :                                 "WHERE op.oid >= 16384 "
     991             :                                 "AND oprcode = ANY(ARRAY[%s]::regprocedure[]) "
     992             :                                 "AND oprleft = ANY(ARRAY['anyarray', 'anyelement']::regtype[]);",
     993             :                                 old_polymorphics.data,
     994             :                                 old_polymorphics.data,
     995             :                                 old_polymorphics.data);
     996             : 
     997           0 :         ntups = PQntuples(res);
     998             : 
     999           0 :         i_objkind = PQfnumber(res, "objkind");
    1000           0 :         i_objname = PQfnumber(res, "objname");
    1001             : 
    1002           0 :         for (int rowno = 0; rowno < ntups; rowno++)
    1003             :         {
    1004           0 :             if (script == NULL &&
    1005           0 :                 (script = fopen_priv(output_path, "w")) == NULL)
    1006           0 :                 pg_fatal("could not open file \"%s\": %s",
    1007           0 :                          output_path, strerror(errno));
    1008           0 :             if (!db_used)
    1009             :             {
    1010           0 :                 fprintf(script, "In database: %s\n", active_db->db_name);
    1011           0 :                 db_used = true;
    1012             :             }
    1013             : 
    1014           0 :             fprintf(script, "  %s: %s\n",
    1015             :                     PQgetvalue(res, rowno, i_objkind),
    1016             :                     PQgetvalue(res, rowno, i_objname));
    1017             :         }
    1018             : 
    1019           0 :         PQclear(res);
    1020           0 :         PQfinish(conn);
    1021             :     }
    1022             : 
    1023           0 :     if (script)
    1024             :     {
    1025           0 :         fclose(script);
    1026           0 :         pg_log(PG_REPORT, "fatal");
    1027           0 :         pg_fatal("Your installation contains user-defined objects that refer to internal\n"
    1028             :                  "polymorphic functions with arguments of type \"anyarray\" or \"anyelement\".\n"
    1029             :                  "These user-defined objects must be dropped before upgrading and restored\n"
    1030             :                  "afterwards, changing them to refer to the new corresponding functions with\n"
    1031             :                  "arguments of type \"anycompatiblearray\" and \"anycompatible\".\n"
    1032             :                  "A list of the problematic objects is in the file:\n"
    1033             :                  "    %s", output_path);
    1034             :     }
    1035             :     else
    1036           0 :         check_ok();
    1037             : 
    1038           0 :     termPQExpBuffer(&old_polymorphics);
    1039           0 : }
    1040             : 
    1041             : /*
    1042             :  * Verify that no tables are declared WITH OIDS.
    1043             :  */
    1044             : static void
    1045           0 : check_for_tables_with_oids(ClusterInfo *cluster)
    1046             : {
    1047             :     int         dbnum;
    1048           0 :     FILE       *script = NULL;
    1049             :     char        output_path[MAXPGPATH];
    1050             : 
    1051           0 :     prep_status("Checking for tables WITH OIDS");
    1052             : 
    1053           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1054             :              log_opts.basedir,
    1055             :              "tables_with_oids.txt");
    1056             : 
    1057             :     /* Find any tables declared WITH OIDS */
    1058           0 :     for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
    1059             :     {
    1060             :         PGresult   *res;
    1061           0 :         bool        db_used = false;
    1062             :         int         ntups;
    1063             :         int         rowno;
    1064             :         int         i_nspname,
    1065             :                     i_relname;
    1066           0 :         DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
    1067           0 :         PGconn     *conn = connectToServer(cluster, active_db->db_name);
    1068             : 
    1069           0 :         res = executeQueryOrDie(conn,
    1070             :                                 "SELECT n.nspname, c.relname "
    1071             :                                 "FROM  pg_catalog.pg_class c, "
    1072             :                                 "      pg_catalog.pg_namespace n "
    1073             :                                 "WHERE c.relnamespace = n.oid AND "
    1074             :                                 "      c.relhasoids AND"
    1075             :                                 "       n.nspname NOT IN ('pg_catalog')");
    1076             : 
    1077           0 :         ntups = PQntuples(res);
    1078           0 :         i_nspname = PQfnumber(res, "nspname");
    1079           0 :         i_relname = PQfnumber(res, "relname");
    1080           0 :         for (rowno = 0; rowno < ntups; rowno++)
    1081             :         {
    1082           0 :             if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
    1083           0 :                 pg_fatal("could not open file \"%s\": %s",
    1084           0 :                          output_path, strerror(errno));
    1085           0 :             if (!db_used)
    1086             :             {
    1087           0 :                 fprintf(script, "In database: %s\n", active_db->db_name);
    1088           0 :                 db_used = true;
    1089             :             }
    1090           0 :             fprintf(script, "  %s.%s\n",
    1091             :                     PQgetvalue(res, rowno, i_nspname),
    1092             :                     PQgetvalue(res, rowno, i_relname));
    1093             :         }
    1094             : 
    1095           0 :         PQclear(res);
    1096             : 
    1097           0 :         PQfinish(conn);
    1098             :     }
    1099             : 
    1100           0 :     if (script)
    1101             :     {
    1102           0 :         fclose(script);
    1103           0 :         pg_log(PG_REPORT, "fatal");
    1104           0 :         pg_fatal("Your installation contains tables declared WITH OIDS, which is not\n"
    1105             :                  "supported anymore.  Consider removing the oid column using\n"
    1106             :                  "    ALTER TABLE ... SET WITHOUT OIDS;\n"
    1107             :                  "A list of tables with the problem is in the file:\n"
    1108             :                  "    %s", output_path);
    1109             :     }
    1110             :     else
    1111           0 :         check_ok();
    1112           0 : }
    1113             : 
    1114             : 
    1115             : /*
    1116             :  * check_for_composite_data_type_usage()
    1117             :  *  Check for system-defined composite types used in user tables.
    1118             :  *
    1119             :  *  The OIDs of rowtypes of system catalogs and information_schema views
    1120             :  *  can change across major versions; unlike user-defined types, we have
    1121             :  *  no mechanism for forcing them to be the same in the new cluster.
    1122             :  *  Hence, if any user table uses one, that's problematic for pg_upgrade.
    1123             :  */
    1124             : static void
    1125          10 : check_for_composite_data_type_usage(ClusterInfo *cluster)
    1126             : {
    1127             :     bool        found;
    1128             :     Oid         firstUserOid;
    1129             :     char        output_path[MAXPGPATH];
    1130             :     char       *base_query;
    1131             : 
    1132          10 :     prep_status("Checking for system-defined composite types in user tables");
    1133             : 
    1134          10 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1135             :              log_opts.basedir,
    1136             :              "tables_using_composite.txt");
    1137             : 
    1138             :     /*
    1139             :      * Look for composite types that were made during initdb *or* belong to
    1140             :      * information_schema; that's important in case information_schema was
    1141             :      * dropped and reloaded.
    1142             :      *
    1143             :      * The cutoff OID here should match the source cluster's value of
    1144             :      * FirstNormalObjectId.  We hardcode it rather than using that C #define
    1145             :      * because, if that #define is ever changed, our own version's value is
    1146             :      * NOT what to use.  Eventually we may need a test on the source cluster's
    1147             :      * version to select the correct value.
    1148             :      */
    1149          10 :     firstUserOid = 16384;
    1150             : 
    1151          10 :     base_query = psprintf("SELECT t.oid FROM pg_catalog.pg_type t "
    1152             :                           "LEFT JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid "
    1153             :                           " WHERE typtype = 'c' AND (t.oid < %u OR nspname = 'information_schema')",
    1154             :                           firstUserOid);
    1155             : 
    1156          10 :     found = check_for_data_types_usage(cluster, base_query, output_path);
    1157             : 
    1158          10 :     free(base_query);
    1159             : 
    1160          10 :     if (found)
    1161             :     {
    1162           0 :         pg_log(PG_REPORT, "fatal");
    1163           0 :         pg_fatal("Your installation contains system-defined composite types in user tables.\n"
    1164             :                  "These type OIDs are not stable across PostgreSQL versions,\n"
    1165             :                  "so this cluster cannot currently be upgraded.  You can\n"
    1166             :                  "drop the problem columns and restart the upgrade.\n"
    1167             :                  "A list of the problem columns is in the file:\n"
    1168             :                  "    %s", output_path);
    1169             :     }
    1170             :     else
    1171          10 :         check_ok();
    1172          10 : }
    1173             : 
    1174             : /*
    1175             :  * check_for_reg_data_type_usage()
    1176             :  *  pg_upgrade only preserves these system values:
    1177             :  *      pg_class.oid
    1178             :  *      pg_type.oid
    1179             :  *      pg_enum.oid
    1180             :  *
    1181             :  *  Many of the reg* data types reference system catalog info that is
    1182             :  *  not preserved, and hence these data types cannot be used in user
    1183             :  *  tables upgraded by pg_upgrade.
    1184             :  */
    1185             : static void
    1186          10 : check_for_reg_data_type_usage(ClusterInfo *cluster)
    1187             : {
    1188             :     bool        found;
    1189             :     char        output_path[MAXPGPATH];
    1190             : 
    1191          10 :     prep_status("Checking for reg* data types in user tables");
    1192             : 
    1193          10 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1194             :              log_opts.basedir,
    1195             :              "tables_using_reg.txt");
    1196             : 
    1197             :     /*
    1198             :      * Note: older servers will not have all of these reg* types, so we have
    1199             :      * to write the query like this rather than depending on casts to regtype.
    1200             :      */
    1201          10 :     found = check_for_data_types_usage(cluster,
    1202             :                                        "SELECT oid FROM pg_catalog.pg_type t "
    1203             :                                        "WHERE t.typnamespace = "
    1204             :                                        "        (SELECT oid FROM pg_catalog.pg_namespace "
    1205             :                                        "         WHERE nspname = 'pg_catalog') "
    1206             :                                        "  AND t.typname IN ( "
    1207             :     /* pg_class.oid is preserved, so 'regclass' is OK */
    1208             :                                        "           'regcollation', "
    1209             :                                        "           'regconfig', "
    1210             :                                        "           'regdictionary', "
    1211             :                                        "           'regnamespace', "
    1212             :                                        "           'regoper', "
    1213             :                                        "           'regoperator', "
    1214             :                                        "           'regproc', "
    1215             :                                        "           'regprocedure' "
    1216             :     /* pg_authid.oid is preserved, so 'regrole' is OK */
    1217             :     /* pg_type.oid is (mostly) preserved, so 'regtype' is OK */
    1218             :                                        "         )",
    1219             :                                        output_path);
    1220             : 
    1221          10 :     if (found)
    1222             :     {
    1223           0 :         pg_log(PG_REPORT, "fatal");
    1224           0 :         pg_fatal("Your installation contains one of the reg* data types in user tables.\n"
    1225             :                  "These data types reference system OIDs that are not preserved by\n"
    1226             :                  "pg_upgrade, so this cluster cannot currently be upgraded.  You can\n"
    1227             :                  "drop the problem columns and restart the upgrade.\n"
    1228             :                  "A list of the problem columns is in the file:\n"
    1229             :                  "    %s", output_path);
    1230             :     }
    1231             :     else
    1232          10 :         check_ok();
    1233          10 : }
    1234             : 
    1235             : /*
    1236             :  * check_for_aclitem_data_type_usage
    1237             :  *
    1238             :  *  aclitem changed its storage format in 16, so check for it.
    1239             :  */
    1240             : static void
    1241           0 : check_for_aclitem_data_type_usage(ClusterInfo *cluster)
    1242             : {
    1243             :     char        output_path[MAXPGPATH];
    1244             : 
    1245           0 :     prep_status("Checking for incompatible \"%s\" data type in user tables",
    1246             :                 "aclitem");
    1247             : 
    1248           0 :     snprintf(output_path, sizeof(output_path), "tables_using_aclitem.txt");
    1249             : 
    1250           0 :     if (check_for_data_type_usage(cluster, "pg_catalog.aclitem", output_path))
    1251             :     {
    1252           0 :         pg_log(PG_REPORT, "fatal");
    1253           0 :         pg_fatal("Your installation contains the \"aclitem\" data type in user tables.\n"
    1254             :                  "The internal format of \"aclitem\" changed in PostgreSQL version 16\n"
    1255             :                  "so this cluster cannot currently be upgraded.  You can drop the\n"
    1256             :                  "problem columns and restart the upgrade.  A list of the problem\n"
    1257             :                  "columns is in the file:\n"
    1258             :                  "    %s", output_path);
    1259             :     }
    1260             :     else
    1261           0 :         check_ok();
    1262           0 : }
    1263             : 
    1264             : /*
    1265             :  * check_for_removed_data_type_usage
    1266             :  *
    1267             :  *  Check for in-core data types that have been removed.  Callers know
    1268             :  *  the exact list.
    1269             :  */
    1270             : static void
    1271           0 : check_for_removed_data_type_usage(ClusterInfo *cluster, const char *version,
    1272             :                                   const char *datatype)
    1273             : {
    1274             :     char        output_path[MAXPGPATH];
    1275             :     char        typename[NAMEDATALEN];
    1276             : 
    1277           0 :     prep_status("Checking for removed \"%s\" data type in user tables",
    1278             :                 datatype);
    1279             : 
    1280           0 :     snprintf(output_path, sizeof(output_path), "tables_using_%s.txt",
    1281             :              datatype);
    1282           0 :     snprintf(typename, sizeof(typename), "pg_catalog.%s", datatype);
    1283             : 
    1284           0 :     if (check_for_data_type_usage(cluster, typename, output_path))
    1285             :     {
    1286           0 :         pg_log(PG_REPORT, "fatal");
    1287           0 :         pg_fatal("Your installation contains the \"%s\" data type in user tables.\n"
    1288             :                  "The \"%s\" type has been removed in PostgreSQL version %s,\n"
    1289             :                  "so this cluster cannot currently be upgraded.  You can drop the\n"
    1290             :                  "problem columns, or change them to another data type, and restart\n"
    1291             :                  "the upgrade.  A list of the problem columns is in the file:\n"
    1292             :                  "    %s", datatype, datatype, version, output_path);
    1293             :     }
    1294             :     else
    1295           0 :         check_ok();
    1296           0 : }
    1297             : 
    1298             : 
    1299             : /*
    1300             :  * check_for_jsonb_9_4_usage()
    1301             :  *
    1302             :  *  JSONB changed its storage format during 9.4 beta, so check for it.
    1303             :  */
    1304             : static void
    1305           0 : check_for_jsonb_9_4_usage(ClusterInfo *cluster)
    1306             : {
    1307             :     char        output_path[MAXPGPATH];
    1308             : 
    1309           0 :     prep_status("Checking for incompatible \"jsonb\" data type");
    1310             : 
    1311           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1312             :              log_opts.basedir,
    1313             :              "tables_using_jsonb.txt");
    1314             : 
    1315           0 :     if (check_for_data_type_usage(cluster, "pg_catalog.jsonb", output_path))
    1316             :     {
    1317           0 :         pg_log(PG_REPORT, "fatal");
    1318           0 :         pg_fatal("Your installation contains the \"jsonb\" data type in user tables.\n"
    1319             :                  "The internal format of \"jsonb\" changed during 9.4 beta so this\n"
    1320             :                  "cluster cannot currently be upgraded.  You can\n"
    1321             :                  "drop the problem columns and restart the upgrade.\n"
    1322             :                  "A list of the problem columns is in the file:\n"
    1323             :                  "    %s", output_path);
    1324             :     }
    1325             :     else
    1326           0 :         check_ok();
    1327           0 : }
    1328             : 
    1329             : /*
    1330             :  * check_for_pg_role_prefix()
    1331             :  *
    1332             :  *  Versions older than 9.6 should not have any pg_* roles
    1333             :  */
    1334             : static void
    1335           0 : check_for_pg_role_prefix(ClusterInfo *cluster)
    1336             : {
    1337             :     PGresult   *res;
    1338           0 :     PGconn     *conn = connectToServer(cluster, "template1");
    1339             :     int         ntups;
    1340             :     int         i_roloid;
    1341             :     int         i_rolname;
    1342           0 :     FILE       *script = NULL;
    1343             :     char        output_path[MAXPGPATH];
    1344             : 
    1345           0 :     prep_status("Checking for roles starting with \"pg_\"");
    1346             : 
    1347           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1348             :              log_opts.basedir,
    1349             :              "pg_role_prefix.txt");
    1350             : 
    1351           0 :     res = executeQueryOrDie(conn,
    1352             :                             "SELECT oid AS roloid, rolname "
    1353             :                             "FROM pg_catalog.pg_roles "
    1354             :                             "WHERE rolname ~ '^pg_'");
    1355             : 
    1356           0 :     ntups = PQntuples(res);
    1357           0 :     i_roloid = PQfnumber(res, "roloid");
    1358           0 :     i_rolname = PQfnumber(res, "rolname");
    1359           0 :     for (int rowno = 0; rowno < ntups; rowno++)
    1360             :     {
    1361           0 :         if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
    1362           0 :             pg_fatal("could not open file \"%s\": %s",
    1363           0 :                      output_path, strerror(errno));
    1364           0 :         fprintf(script, "%s (oid=%s)\n",
    1365             :                 PQgetvalue(res, rowno, i_rolname),
    1366             :                 PQgetvalue(res, rowno, i_roloid));
    1367             :     }
    1368             : 
    1369           0 :     PQclear(res);
    1370             : 
    1371           0 :     PQfinish(conn);
    1372             : 
    1373           0 :     if (script)
    1374             :     {
    1375           0 :         fclose(script);
    1376           0 :         pg_log(PG_REPORT, "fatal");
    1377           0 :         pg_fatal("Your installation contains roles starting with \"pg_\".\n"
    1378             :                  "\"pg_\" is a reserved prefix for system roles.  The cluster\n"
    1379             :                  "cannot be upgraded until these roles are renamed.\n"
    1380             :                  "A list of roles starting with \"pg_\" is in the file:\n"
    1381             :                  "    %s", output_path);
    1382             :     }
    1383             :     else
    1384           0 :         check_ok();
    1385           0 : }
    1386             : 
    1387             : /*
    1388             :  * Verify that no user-defined encoding conversions exist.
    1389             :  */
    1390             : static void
    1391           0 : check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
    1392             : {
    1393             :     int         dbnum;
    1394           0 :     FILE       *script = NULL;
    1395             :     char        output_path[MAXPGPATH];
    1396             : 
    1397           0 :     prep_status("Checking for user-defined encoding conversions");
    1398             : 
    1399           0 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1400             :              log_opts.basedir,
    1401             :              "encoding_conversions.txt");
    1402             : 
    1403             :     /* Find any user defined encoding conversions */
    1404           0 :     for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
    1405             :     {
    1406             :         PGresult   *res;
    1407           0 :         bool        db_used = false;
    1408             :         int         ntups;
    1409             :         int         rowno;
    1410             :         int         i_conoid,
    1411             :                     i_conname,
    1412             :                     i_nspname;
    1413           0 :         DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
    1414           0 :         PGconn     *conn = connectToServer(cluster, active_db->db_name);
    1415             : 
    1416             :         /*
    1417             :          * The query below hardcodes FirstNormalObjectId as 16384 rather than
    1418             :          * interpolating that C #define into the query because, if that
    1419             :          * #define is ever changed, the cutoff we want to use is the value
    1420             :          * used by pre-version 14 servers, not that of some future version.
    1421             :          */
    1422           0 :         res = executeQueryOrDie(conn,
    1423             :                                 "SELECT c.oid as conoid, c.conname, n.nspname "
    1424             :                                 "FROM pg_catalog.pg_conversion c, "
    1425             :                                 "     pg_catalog.pg_namespace n "
    1426             :                                 "WHERE c.connamespace = n.oid AND "
    1427             :                                 "      c.oid >= 16384");
    1428           0 :         ntups = PQntuples(res);
    1429           0 :         i_conoid = PQfnumber(res, "conoid");
    1430           0 :         i_conname = PQfnumber(res, "conname");
    1431           0 :         i_nspname = PQfnumber(res, "nspname");
    1432           0 :         for (rowno = 0; rowno < ntups; rowno++)
    1433             :         {
    1434           0 :             if (script == NULL &&
    1435           0 :                 (script = fopen_priv(output_path, "w")) == NULL)
    1436           0 :                 pg_fatal("could not open file \"%s\": %s",
    1437           0 :                          output_path, strerror(errno));
    1438           0 :             if (!db_used)
    1439             :             {
    1440           0 :                 fprintf(script, "In database: %s\n", active_db->db_name);
    1441           0 :                 db_used = true;
    1442             :             }
    1443           0 :             fprintf(script, "  (oid=%s) %s.%s\n",
    1444             :                     PQgetvalue(res, rowno, i_conoid),
    1445             :                     PQgetvalue(res, rowno, i_nspname),
    1446             :                     PQgetvalue(res, rowno, i_conname));
    1447             :         }
    1448             : 
    1449           0 :         PQclear(res);
    1450             : 
    1451           0 :         PQfinish(conn);
    1452             :     }
    1453             : 
    1454           0 :     if (script)
    1455             :     {
    1456           0 :         fclose(script);
    1457           0 :         pg_log(PG_REPORT, "fatal");
    1458           0 :         pg_fatal("Your installation contains user-defined encoding conversions.\n"
    1459             :                  "The conversion function parameters changed in PostgreSQL version 14\n"
    1460             :                  "so this cluster cannot currently be upgraded.  You can remove the\n"
    1461             :                  "encoding conversions in the old cluster and restart the upgrade.\n"
    1462             :                  "A list of user-defined encoding conversions is in the file:\n"
    1463             :                  "    %s", output_path);
    1464             :     }
    1465             :     else
    1466           0 :         check_ok();
    1467           0 : }
    1468             : 
    1469             : /*
    1470             :  * check_new_cluster_logical_replication_slots()
    1471             :  *
    1472             :  * Verify that there are no logical replication slots on the new cluster and
    1473             :  * that the parameter settings necessary for creating slots are sufficient.
    1474             :  */
    1475             : static void
    1476           8 : check_new_cluster_logical_replication_slots(void)
    1477             : {
    1478             :     PGresult   *res;
    1479             :     PGconn     *conn;
    1480             :     int         nslots_on_old;
    1481             :     int         nslots_on_new;
    1482             :     int         max_replication_slots;
    1483             :     char       *wal_level;
    1484             : 
    1485             :     /* Logical slots can be migrated since PG17. */
    1486           8 :     if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1600)
    1487           0 :         return;
    1488             : 
    1489           8 :     nslots_on_old = count_old_cluster_logical_slots();
    1490             : 
    1491             :     /* Quick return if there are no logical slots to be migrated. */
    1492           8 :     if (nslots_on_old == 0)
    1493           4 :         return;
    1494             : 
    1495           4 :     conn = connectToServer(&new_cluster, "template1");
    1496             : 
    1497           4 :     prep_status("Checking for new cluster logical replication slots");
    1498             : 
    1499           4 :     res = executeQueryOrDie(conn, "SELECT count(*) "
    1500             :                             "FROM pg_catalog.pg_replication_slots "
    1501             :                             "WHERE slot_type = 'logical' AND "
    1502             :                             "temporary IS FALSE;");
    1503             : 
    1504           4 :     if (PQntuples(res) != 1)
    1505           0 :         pg_fatal("could not count the number of logical replication slots");
    1506             : 
    1507           4 :     nslots_on_new = atoi(PQgetvalue(res, 0, 0));
    1508             : 
    1509           4 :     if (nslots_on_new)
    1510           0 :         pg_fatal("Expected 0 logical replication slots but found %d.",
    1511             :                  nslots_on_new);
    1512             : 
    1513           4 :     PQclear(res);
    1514             : 
    1515           4 :     res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings "
    1516             :                             "WHERE name IN ('wal_level', 'max_replication_slots') "
    1517             :                             "ORDER BY name DESC;");
    1518             : 
    1519           4 :     if (PQntuples(res) != 2)
    1520           0 :         pg_fatal("could not determine parameter settings on new cluster");
    1521             : 
    1522           4 :     wal_level = PQgetvalue(res, 0, 0);
    1523             : 
    1524           4 :     if (strcmp(wal_level, "logical") != 0)
    1525           0 :         pg_fatal("wal_level must be \"logical\", but is set to \"%s\"",
    1526             :                  wal_level);
    1527             : 
    1528           4 :     max_replication_slots = atoi(PQgetvalue(res, 1, 0));
    1529             : 
    1530           4 :     if (nslots_on_old > max_replication_slots)
    1531           2 :         pg_fatal("max_replication_slots (%d) must be greater than or equal to the number of "
    1532             :                  "logical replication slots (%d) on the old cluster",
    1533             :                  max_replication_slots, nslots_on_old);
    1534             : 
    1535           2 :     PQclear(res);
    1536           2 :     PQfinish(conn);
    1537             : 
    1538           2 :     check_ok();
    1539             : }
    1540             : 
    1541             : /*
    1542             :  * check_old_cluster_for_valid_slots()
    1543             :  *
    1544             :  * Verify that all the logical slots are valid and have consumed all the WAL
    1545             :  * before shutdown.
    1546             :  */
    1547             : static void
    1548          10 : check_old_cluster_for_valid_slots(bool live_check)
    1549             : {
    1550             :     char        output_path[MAXPGPATH];
    1551          10 :     FILE       *script = NULL;
    1552             : 
    1553          10 :     prep_status("Checking for valid logical replication slots");
    1554             : 
    1555          10 :     snprintf(output_path, sizeof(output_path), "%s/%s",
    1556             :              log_opts.basedir,
    1557             :              "invalid_logical_slots.txt");
    1558             : 
    1559          46 :     for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
    1560             :     {
    1561          36 :         LogicalSlotInfoArr *slot_arr = &old_cluster.dbarr.dbs[dbnum].slot_arr;
    1562             : 
    1563          46 :         for (int slotnum = 0; slotnum < slot_arr->nslots; slotnum++)
    1564             :         {
    1565          10 :             LogicalSlotInfo *slot = &slot_arr->slots[slotnum];
    1566             : 
    1567             :             /* Is the slot usable? */
    1568          10 :             if (slot->invalid)
    1569             :             {
    1570           0 :                 if (script == NULL &&
    1571           0 :                     (script = fopen_priv(output_path, "w")) == NULL)
    1572           0 :                     pg_fatal("could not open file \"%s\": %s",
    1573           0 :                              output_path, strerror(errno));
    1574             : 
    1575           0 :                 fprintf(script, "The slot \"%s\" is invalid\n",
    1576             :                         slot->slotname);
    1577             : 
    1578           0 :                 continue;
    1579             :             }
    1580             : 
    1581             :             /*
    1582             :              * Do additional check to ensure that all logical replication
    1583             :              * slots have consumed all the WAL before shutdown.
    1584             :              *
    1585             :              * Note: This can be satisfied only when the old cluster has been
    1586             :              * shut down, so we skip this for live checks.
    1587             :              */
    1588          10 :             if (!live_check && !slot->caught_up)
    1589             :             {
    1590           6 :                 if (script == NULL &&
    1591           2 :                     (script = fopen_priv(output_path, "w")) == NULL)
    1592           0 :                     pg_fatal("could not open file \"%s\": %s",
    1593           0 :                              output_path, strerror(errno));
    1594             : 
    1595           4 :                 fprintf(script,
    1596             :                         "The slot \"%s\" has not consumed the WAL yet\n",
    1597             :                         slot->slotname);
    1598             :             }
    1599             :         }
    1600             :     }
    1601             : 
    1602          10 :     if (script)
    1603             :     {
    1604           2 :         fclose(script);
    1605             : 
    1606           2 :         pg_log(PG_REPORT, "fatal");
    1607           2 :         pg_fatal("Your installation contains logical replication slots that can't be upgraded.\n"
    1608             :                  "You can remove invalid slots and/or consume the pending WAL for other slots,\n"
    1609             :                  "and then restart the upgrade.\n"
    1610             :                  "A list of the problematic slots is in the file:\n"
    1611             :                  "    %s", output_path);
    1612             :     }
    1613             : 
    1614           8 :     check_ok();
    1615           8 : }

Generated by: LCOV version 1.14