LCOV - differential code coverage report
Current view: top level - src/bin/pg_upgrade - info.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 64.1 % 245 157 7 8 39 34 4 77 28 48 48 88 2 13
Current Date: 2023-04-08 15:15:32 Functions: 72.7 % 11 8 3 7 1 3 8
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  *  info.c
       3                 :  *
       4                 :  *  information support functions
       5                 :  *
       6                 :  *  Copyright (c) 2010-2023, PostgreSQL Global Development Group
       7                 :  *  src/bin/pg_upgrade/info.c
       8                 :  */
       9                 : 
      10                 : #include "postgres_fe.h"
      11                 : 
      12                 : #include "access/transam.h"
      13                 : #include "catalog/pg_class_d.h"
      14                 : #include "pg_upgrade.h"
      15                 : 
      16                 : static void create_rel_filename_map(const char *old_data, const char *new_data,
      17                 :                                     const DbInfo *old_db, const DbInfo *new_db,
      18                 :                                     const RelInfo *old_rel, const RelInfo *new_rel,
      19                 :                                     FileNameMap *map);
      20                 : static void report_unmatched_relation(const RelInfo *rel, const DbInfo *db,
      21                 :                                       bool is_new_db);
      22                 : static void free_db_and_rel_infos(DbInfoArr *db_arr);
      23                 : static void get_template0_info(ClusterInfo *cluster);
      24                 : static void get_db_infos(ClusterInfo *cluster);
      25                 : static void get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo);
      26                 : static void free_rel_infos(RelInfoArr *rel_arr);
      27                 : static void print_db_infos(DbInfoArr *db_arr);
      28                 : static void print_rel_infos(RelInfoArr *rel_arr);
      29                 : 
      30                 : 
      31                 : /*
      32                 :  * gen_db_file_maps()
      33                 :  *
      34                 :  * generates a database mapping from "old_db" to "new_db".
      35                 :  *
      36                 :  * Returns a malloc'ed array of mappings.  The length of the array
      37                 :  * is returned into *nmaps.
      38                 :  */
      39                 : FileNameMap *
      40 GIC           6 : gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
      41 ECB             :                  int *nmaps,
      42                 :                  const char *old_pgdata, const char *new_pgdata)
      43                 : {
      44                 :     FileNameMap *maps;
      45                 :     int         old_relnum,
      46                 :                 new_relnum;
      47 GIC           6 :     int         num_maps = 0;
      48 CBC           6 :     bool        all_matched = true;
      49 ECB             : 
      50                 :     /* There will certainly not be more mappings than there are old rels */
      51 GIC           6 :     maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
      52 CBC           6 :                                      old_db->rel_arr.nrels);
      53 ECB             : 
      54                 :     /*
      55                 :      * Each of the RelInfo arrays should be sorted by OID.  Scan through them
      56                 :      * and match them up.  If we fail to match everything, we'll abort, but
      57                 :      * first print as much info as we can about mismatches.
      58                 :      */
      59 GIC           6 :     old_relnum = new_relnum = 0;
      60 CBC        1264 :     while (old_relnum < old_db->rel_arr.nrels ||
      61               6 :            new_relnum < new_db->rel_arr.nrels)
      62 ECB             :     {
      63 GIC        2516 :         RelInfo    *old_rel = (old_relnum < old_db->rel_arr.nrels) ?
      64 CBC        1258 :         &old_db->rel_arr.rels[old_relnum] : NULL;
      65            2516 :         RelInfo    *new_rel = (new_relnum < new_db->rel_arr.nrels) ?
      66            1258 :         &new_db->rel_arr.rels[new_relnum] : NULL;
      67 ECB             : 
      68                 :         /* handle running off one array before the other */
      69 GIC        1258 :         if (!new_rel)
      70 ECB             :         {
      71                 :             /*
      72                 :              * old_rel is unmatched.  This should never happen, because we
      73                 :              * force new rels to have TOAST tables if the old one did.
      74                 :              */
      75 UIC           0 :             report_unmatched_relation(old_rel, old_db, false);
      76 UBC           0 :             all_matched = false;
      77               0 :             old_relnum++;
      78               0 :             continue;
      79 EUB             :         }
      80 GIC        1258 :         if (!old_rel)
      81 ECB             :         {
      82                 :             /*
      83                 :              * new_rel is unmatched.  This shouldn't really happen either, but
      84                 :              * if it's a TOAST table, we can ignore it and continue
      85                 :              * processing, assuming that the new server made a TOAST table
      86                 :              * that wasn't needed.
      87                 :              */
      88 UIC           0 :             if (strcmp(new_rel->nspname, "pg_toast") != 0)
      89 EUB             :             {
      90 UIC           0 :                 report_unmatched_relation(new_rel, new_db, true);
      91 UBC           0 :                 all_matched = false;
      92 EUB             :             }
      93 UIC           0 :             new_relnum++;
      94 UBC           0 :             continue;
      95 EUB             :         }
      96                 : 
      97                 :         /* check for mismatched OID */
      98 GIC        1258 :         if (old_rel->reloid < new_rel->reloid)
      99 ECB             :         {
     100                 :             /* old_rel is unmatched, see comment above */
     101 UIC           0 :             report_unmatched_relation(old_rel, old_db, false);
     102 UBC           0 :             all_matched = false;
     103               0 :             old_relnum++;
     104               0 :             continue;
     105 EUB             :         }
     106 GIC        1258 :         else if (old_rel->reloid > new_rel->reloid)
     107 ECB             :         {
     108                 :             /* new_rel is unmatched, see comment above */
     109 UIC           0 :             if (strcmp(new_rel->nspname, "pg_toast") != 0)
     110 EUB             :             {
     111 UIC           0 :                 report_unmatched_relation(new_rel, new_db, true);
     112 UBC           0 :                 all_matched = false;
     113 EUB             :             }
     114 UIC           0 :             new_relnum++;
     115 UBC           0 :             continue;
     116 EUB             :         }
     117                 : 
     118                 :         /*
     119                 :          * Verify that rels of same OID have same name.  The namespace name
     120                 :          * should always match, but the relname might not match for TOAST
     121                 :          * tables (and, therefore, their indexes).
     122                 :          */
     123 GIC        1258 :         if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
     124 CBC        1258 :             strcmp(old_rel->relname, new_rel->relname) != 0)
     125 ECB             :         {
     126 UIC           0 :             pg_log(PG_WARNING, "Relation names for OID %u in database \"%s\" do not match: "
     127                 :                    "old name \"%s.%s\", new name \"%s.%s\"",
     128                 :                    old_rel->reloid, old_db->db_name,
     129                 :                    old_rel->nspname, old_rel->relname,
     130                 :                    new_rel->nspname, new_rel->relname);
     131               0 :             all_matched = false;
     132 UBC           0 :             old_relnum++;
     133               0 :             new_relnum++;
     134               0 :             continue;
     135 EUB             :         }
     136                 : 
     137                 :         /* OK, create a mapping entry */
     138 GIC        1258 :         create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
     139 CBC        1258 :                                 old_rel, new_rel, maps + num_maps);
     140            1258 :         num_maps++;
     141            1258 :         old_relnum++;
     142            1258 :         new_relnum++;
     143 ECB             :     }
     144                 : 
     145 GIC           6 :     if (!all_matched)
     146 UNC           0 :         pg_fatal("Failed to match up old and new tables in database \"%s\"",
     147 EUB             :                  old_db->db_name);
     148                 : 
     149 GIC           6 :     *nmaps = num_maps;
     150 CBC           6 :     return maps;
     151 ECB             : }
     152                 : 
     153                 : 
     154                 : /*
     155                 :  * create_rel_filename_map()
     156                 :  *
     157                 :  * fills a file node map structure and returns it in "map".
     158                 :  */
     159                 : static void
     160 GIC        1258 : create_rel_filename_map(const char *old_data, const char *new_data,
     161 ECB             :                         const DbInfo *old_db, const DbInfo *new_db,
     162                 :                         const RelInfo *old_rel, const RelInfo *new_rel,
     163                 :                         FileNameMap *map)
     164                 : {
     165                 :     /* In case old/new tablespaces don't match, do them separately. */
     166 GIC        1258 :     if (strlen(old_rel->tablespace) == 0)
     167 ECB             :     {
     168                 :         /*
     169                 :          * relation belongs to the default tablespace, hence relfiles should
     170                 :          * exist in the data directories.
     171                 :          */
     172 GIC        1258 :         map->old_tablespace = old_data;
     173 CBC        1258 :         map->old_tablespace_suffix = "/base";
     174 ECB             :     }
     175                 :     else
     176                 :     {
     177                 :         /* relation belongs to a tablespace, so use the tablespace location */
     178 UIC           0 :         map->old_tablespace = old_rel->tablespace;
     179 UBC           0 :         map->old_tablespace_suffix = old_cluster.tablespace_suffix;
     180 EUB             :     }
     181                 : 
     182                 :     /* Do the same for new tablespaces */
     183 GIC        1258 :     if (strlen(new_rel->tablespace) == 0)
     184 ECB             :     {
     185 GIC        1258 :         map->new_tablespace = new_data;
     186 CBC        1258 :         map->new_tablespace_suffix = "/base";
     187 ECB             :     }
     188                 :     else
     189                 :     {
     190 UIC           0 :         map->new_tablespace = new_rel->tablespace;
     191 UBC           0 :         map->new_tablespace_suffix = new_cluster.tablespace_suffix;
     192 EUB             :     }
     193                 : 
     194                 :     /* DB oid and relfilenumbers are preserved between old and new cluster */
     195 GIC        1258 :     map->db_oid = old_db->db_oid;
     196 GNC        1258 :     map->relfilenumber = old_rel->relfilenumber;
     197 ECB             : 
     198                 :     /* used only for logging and error reporting, old/new are identical */
     199 GIC        1258 :     map->nspname = old_rel->nspname;
     200 CBC        1258 :     map->relname = old_rel->relname;
     201            1258 : }
     202 ECB             : 
     203                 : 
     204                 : /*
     205                 :  * Complain about a relation we couldn't match to the other database,
     206                 :  * identifying it as best we can.
     207                 :  */
     208                 : static void
     209 UIC           0 : report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db)
     210 EUB             : {
     211 UIC           0 :     Oid         reloid = rel->reloid;    /* we might change rel below */
     212 EUB             :     char        reldesc[1000];
     213                 :     int         i;
     214                 : 
     215 UIC           0 :     snprintf(reldesc, sizeof(reldesc), "\"%s.%s\"",
     216 UBC           0 :              rel->nspname, rel->relname);
     217               0 :     if (rel->indtable)
     218 EUB             :     {
     219 UIC           0 :         for (i = 0; i < db->rel_arr.nrels; i++)
     220 EUB             :         {
     221 UIC           0 :             const RelInfo *hrel = &db->rel_arr.rels[i];
     222 EUB             : 
     223 UIC           0 :             if (hrel->reloid == rel->indtable)
     224 EUB             :             {
     225 UIC           0 :                 snprintf(reldesc + strlen(reldesc),
     226 UBC           0 :                          sizeof(reldesc) - strlen(reldesc),
     227               0 :                          _(" which is an index on \"%s.%s\""),
     228               0 :                          hrel->nspname, hrel->relname);
     229 EUB             :                 /* Shift attention to index's table for toast check */
     230 UIC           0 :                 rel = hrel;
     231 UBC           0 :                 break;
     232 EUB             :             }
     233                 :         }
     234 UIC           0 :         if (i >= db->rel_arr.nrels)
     235 UBC           0 :             snprintf(reldesc + strlen(reldesc),
     236               0 :                      sizeof(reldesc) - strlen(reldesc),
     237               0 :                      _(" which is an index on OID %u"), rel->indtable);
     238 EUB             :     }
     239 UIC           0 :     if (rel->toastheap)
     240 EUB             :     {
     241 UIC           0 :         for (i = 0; i < db->rel_arr.nrels; i++)
     242 EUB             :         {
     243 UIC           0 :             const RelInfo *brel = &db->rel_arr.rels[i];
     244 EUB             : 
     245 UIC           0 :             if (brel->reloid == rel->toastheap)
     246 EUB             :             {
     247 UIC           0 :                 snprintf(reldesc + strlen(reldesc),
     248 UBC           0 :                          sizeof(reldesc) - strlen(reldesc),
     249               0 :                          _(" which is the TOAST table for \"%s.%s\""),
     250               0 :                          brel->nspname, brel->relname);
     251               0 :                 break;
     252 EUB             :             }
     253                 :         }
     254 UIC           0 :         if (i >= db->rel_arr.nrels)
     255 UBC           0 :             snprintf(reldesc + strlen(reldesc),
     256               0 :                      sizeof(reldesc) - strlen(reldesc),
     257               0 :                      _(" which is the TOAST table for OID %u"), rel->toastheap);
     258 EUB             :     }
     259                 : 
     260 UIC           0 :     if (is_new_db)
     261 UNC           0 :         pg_log(PG_WARNING, "No match found in old cluster for new relation with OID %u in database \"%s\": %s",
     262 UBC           0 :                reloid, db->db_name, reldesc);
     263 EUB             :     else
     264 UNC           0 :         pg_log(PG_WARNING, "No match found in new cluster for old relation with OID %u in database \"%s\": %s",
     265 UBC           0 :                reloid, db->db_name, reldesc);
     266               0 : }
     267 EUB             : 
     268                 : /*
     269                 :  * get_db_and_rel_infos()
     270                 :  *
     271                 :  * higher level routine to generate dbinfos for the database running
     272                 :  * on the given "port". Assumes that server is already running.
     273                 :  */
     274                 : void
     275 GIC           5 : get_db_and_rel_infos(ClusterInfo *cluster)
     276 ECB             : {
     277                 :     int         dbnum;
     278                 : 
     279 GIC           5 :     if (cluster->dbarr.dbs != NULL)
     280 CBC           1 :         free_db_and_rel_infos(&cluster->dbarr);
     281 ECB             : 
     282 GNC           5 :     get_template0_info(cluster);
     283 GIC           5 :     get_db_infos(cluster);
     284 ECB             : 
     285 CBC          27 :     for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
     286 GIC          22 :         get_rel_infos(cluster, &cluster->dbarr.dbs[dbnum]);
     287 ECB             : 
     288 CBC           5 :     if (cluster == &old_cluster)
     289 GNC           2 :         pg_log(PG_VERBOSE, "\nsource databases:");
     290 ECB             :     else
     291 GNC           3 :         pg_log(PG_VERBOSE, "\ntarget databases:");
     292                 : 
     293 CBC           5 :     if (log_opts.verbose)
     294 UIC           0 :         print_db_infos(&cluster->dbarr);
     295 CBC           5 : }
     296 EUB             : 
     297 ECB             : 
     298                 : /*
     299                 :  * Get information about template0, which will be copied from the old cluster
     300                 :  * to the new cluster.
     301                 :  */
     302                 : static void
     303 GNC           5 : get_template0_info(ClusterInfo *cluster)
     304                 : {
     305               5 :     PGconn          *conn = connectToServer(cluster, "template1");
     306                 :     DbLocaleInfo    *locale;
     307                 :     PGresult        *dbres;
     308                 :     int              i_datencoding;
     309                 :     int              i_datlocprovider;
     310                 :     int              i_datcollate;
     311                 :     int              i_datctype;
     312                 :     int              i_daticulocale;
     313                 : 
     314               5 :     if (GET_MAJOR_VERSION(cluster->major_version) >= 1500)
     315               5 :         dbres = executeQueryOrDie(conn,
     316                 :                                   "SELECT encoding, datlocprovider, "
     317                 :                                   "       datcollate, datctype, daticulocale "
     318                 :                                   "FROM    pg_catalog.pg_database "
     319                 :                                   "WHERE datname='template0'");
     320                 :     else
     321 UNC           0 :         dbres = executeQueryOrDie(conn,
     322                 :                                   "SELECT encoding, 'c' AS datlocprovider, "
     323                 :                                   "       datcollate, datctype, NULL AS daticulocale "
     324                 :                                   "FROM    pg_catalog.pg_database "
     325                 :                                   "WHERE datname='template0'");
     326                 : 
     327                 : 
     328 GNC           5 :     if (PQntuples(dbres) != 1)
     329 UNC           0 :         pg_fatal("template0 not found");
     330                 : 
     331 GNC           5 :     locale = pg_malloc(sizeof(DbLocaleInfo));
     332                 : 
     333               5 :     i_datencoding = PQfnumber(dbres, "encoding");
     334               5 :     i_datlocprovider = PQfnumber(dbres, "datlocprovider");
     335               5 :     i_datcollate = PQfnumber(dbres, "datcollate");
     336               5 :     i_datctype = PQfnumber(dbres, "datctype");
     337               5 :     i_daticulocale = PQfnumber(dbres, "daticulocale");
     338                 : 
     339               5 :     locale->db_encoding = atoi(PQgetvalue(dbres, 0, i_datencoding));
     340               5 :     locale->db_collprovider = PQgetvalue(dbres, 0, i_datlocprovider)[0];
     341               5 :     locale->db_collate = pg_strdup(PQgetvalue(dbres, 0, i_datcollate));
     342               5 :     locale->db_ctype = pg_strdup(PQgetvalue(dbres, 0, i_datctype));
     343               5 :     if (PQgetisnull(dbres, 0, i_daticulocale))
     344               2 :         locale->db_iculocale = NULL;
     345                 :     else
     346               3 :         locale->db_iculocale = pg_strdup(PQgetvalue(dbres, 0, i_daticulocale));
     347                 : 
     348               5 :     cluster->template0 = locale;
     349                 : 
     350               5 :     PQclear(dbres);
     351               5 :     PQfinish(conn);
     352               5 : }
     353                 : 
     354                 : 
     355                 : /*
     356                 :  * get_db_infos()
     357                 :  *
     358                 :  * Scans pg_database system catalog and populates all user
     359                 :  * databases.
     360                 :  */
     361                 : static void
     362 CBC           5 : get_db_infos(ClusterInfo *cluster)
     363                 : {
     364               5 :     PGconn     *conn = connectToServer(cluster, "template1");
     365                 :     PGresult   *res;
     366                 :     int         ntups;
     367                 :     int         tupnum;
     368                 :     DbInfo     *dbinfos;
     369                 :     int         i_datname,
     370                 :                 i_oid,
     371                 :                 i_spclocation;
     372                 :     char        query[QUERY_ALLOC];
     373                 : 
     374 GIC           5 :     snprintf(query, sizeof(query),
     375 EUB             :              "SELECT d.oid, d.datname, d.encoding, d.datcollate, d.datctype, ");
     376 GIC           5 :     if (GET_MAJOR_VERSION(cluster->major_version) < 1500)
     377 UIC           0 :         snprintf(query + strlen(query), sizeof(query) - strlen(query),
     378                 :                  "'c' AS datlocprovider, NULL AS daticulocale, ");
     379                 :     else
     380 GIC           5 :         snprintf(query + strlen(query), sizeof(query) - strlen(query),
     381                 :                  "datlocprovider, daticulocale, ");
     382 CBC           5 :     snprintf(query + strlen(query), sizeof(query) - strlen(query),
     383 EUB             :              "pg_catalog.pg_tablespace_location(t.oid) AS spclocation "
     384                 :              "FROM pg_catalog.pg_database d "
     385 ECB             :              " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
     386                 :              " ON d.dattablespace = t.oid "
     387                 :              "WHERE d.datallowconn = true "
     388                 :              "ORDER BY 1");
     389                 : 
     390 CBC           5 :     res = executeQueryOrDie(conn, "%s", query);
     391 ECB             : 
     392 GIC           5 :     i_oid = PQfnumber(res, "oid");
     393 CBC           5 :     i_datname = PQfnumber(res, "datname");
     394 GIC           5 :     i_spclocation = PQfnumber(res, "spclocation");
     395 ECB             : 
     396 GIC           5 :     ntups = PQntuples(res);
     397 CBC           5 :     dbinfos = (DbInfo *) pg_malloc(sizeof(DbInfo) * ntups);
     398                 : 
     399              27 :     for (tupnum = 0; tupnum < ntups; tupnum++)
     400 ECB             :     {
     401 CBC          22 :         dbinfos[tupnum].db_oid = atooid(PQgetvalue(res, tupnum, i_oid));
     402 GIC          22 :         dbinfos[tupnum].db_name = pg_strdup(PQgetvalue(res, tupnum, i_datname));
     403 CBC          22 :         snprintf(dbinfos[tupnum].db_tablespace, sizeof(dbinfos[tupnum].db_tablespace), "%s",
     404                 :                  PQgetvalue(res, tupnum, i_spclocation));
     405 ECB             :     }
     406 GIC           5 :     PQclear(res);
     407                 : 
     408               5 :     PQfinish(conn);
     409                 : 
     410               5 :     cluster->dbarr.dbs = dbinfos;
     411               5 :     cluster->dbarr.ndbs = ntups;
     412               5 : }
     413                 : 
     414                 : 
     415 ECB             : /*
     416                 :  * get_rel_infos()
     417                 :  *
     418 EUB             :  * gets the relinfos for all the user tables and indexes of the database
     419                 :  * referred to by "dbinfo".
     420                 :  *
     421 ECB             :  * Note: the resulting RelInfo array is assumed to be sorted by OID.
     422                 :  * This allows later processing to match up old and new databases efficiently.
     423                 :  */
     424                 : static void
     425 GIC          22 : get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
     426                 : {
     427              22 :     PGconn     *conn = connectToServer(cluster,
     428              22 :                                        dbinfo->db_name);
     429                 :     PGresult   *res;
     430                 :     RelInfo    *relinfos;
     431 ECB             :     int         ntups;
     432                 :     int         relnum;
     433 CBC          22 :     int         num_rels = 0;
     434              22 :     char       *nspname = NULL;
     435              22 :     char       *relname = NULL;
     436 GIC          22 :     char       *tablespace = NULL;
     437 ECB             :     int         i_spclocation,
     438                 :                 i_nspname,
     439                 :                 i_relname,
     440                 :                 i_reloid,
     441                 :                 i_indtable,
     442                 :                 i_toastheap,
     443                 :                 i_relfilenumber,
     444                 :                 i_reltablespace;
     445                 :     char        query[QUERY_ALLOC];
     446 GIC          22 :     char       *last_namespace = NULL,
     447 CBC          22 :                *last_tablespace = NULL;
     448                 : 
     449              22 :     query[0] = '\0';            /* initialize query string to empty */
     450                 : 
     451 ECB             :     /*
     452                 :      * Create a CTE that collects OIDs of regular user tables and matviews,
     453                 :      * but excluding toast tables and indexes.  We assume that relations with
     454                 :      * OIDs >= FirstNormalObjectId belong to the user.  (That's probably
     455                 :      * redundant with the namespace-name exclusions, but let's be safe.)
     456                 :      *
     457                 :      * pg_largeobject contains user data that does not appear in pg_dump
     458                 :      * output, so we have to copy that system table.  It's easiest to do that
     459                 :      * by treating it as a user table.
     460                 :      */
     461 GIC          22 :     snprintf(query + strlen(query), sizeof(query) - strlen(query),
     462                 :              "WITH regular_heap (reloid, indtable, toastheap) AS ( "
     463                 :              "  SELECT c.oid, 0::oid, 0::oid "
     464                 :              "  FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
     465                 :              "         ON c.relnamespace = n.oid "
     466 ECB             :              "  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
     467                 :              CppAsString2(RELKIND_MATVIEW) ") AND "
     468                 :     /* exclude possible orphaned temp tables */
     469                 :              "    ((n.nspname !~ '^pg_temp_' AND "
     470                 :              "      n.nspname !~ '^pg_toast_temp_' AND "
     471                 :              "      n.nspname NOT IN ('pg_catalog', 'information_schema', "
     472                 :              "                        'binary_upgrade', 'pg_toast') AND "
     473                 :              "      c.oid >= %u::pg_catalog.oid) OR "
     474                 :              "     (n.nspname = 'pg_catalog' AND "
     475                 :              "      relname IN ('pg_largeobject') ))), ",
     476                 :              FirstNormalObjectId);
     477                 : 
     478                 :     /*
     479                 :      * Add a CTE that collects OIDs of toast tables belonging to the tables
     480                 :      * selected by the regular_heap CTE.  (We have to do this separately
     481                 :      * because the namespace-name rules above don't work for toast tables.)
     482                 :      */
     483 GIC          22 :     snprintf(query + strlen(query), sizeof(query) - strlen(query),
     484                 :              "  toast_heap (reloid, indtable, toastheap) AS ( "
     485                 :              "  SELECT c.reltoastrelid, 0::oid, c.oid "
     486                 :              "  FROM regular_heap JOIN pg_catalog.pg_class c "
     487 ECB             :              "      ON regular_heap.reloid = c.oid "
     488                 :              "  WHERE c.reltoastrelid != 0), ");
     489                 : 
     490                 :     /*
     491                 :      * Add a CTE that collects OIDs of all valid indexes on the previously
     492                 :      * selected tables.  We can ignore invalid indexes since pg_dump does.
     493                 :      * Testing indisready is necessary in 9.2, and harmless in earlier/later
     494                 :      * versions.
     495                 :      */
     496 GIC          22 :     snprintf(query + strlen(query), sizeof(query) - strlen(query),
     497                 :              "  all_index (reloid, indtable, toastheap) AS ( "
     498                 :              "  SELECT indexrelid, indrelid, 0::oid "
     499                 :              "  FROM pg_catalog.pg_index "
     500                 :              "  WHERE indisvalid AND indisready "
     501                 :              "    AND indrelid IN "
     502 ECB             :              "        (SELECT reloid FROM regular_heap "
     503                 :              "         UNION ALL "
     504                 :              "         SELECT reloid FROM toast_heap)) ");
     505                 : 
     506                 :     /*
     507                 :      * And now we can write the query that retrieves the data we want for each
     508                 :      * heap and index relation.  Make sure result is sorted by OID.
     509                 :      */
     510 GIC          22 :     snprintf(query + strlen(query), sizeof(query) - strlen(query),
     511                 :              "SELECT all_rels.*, n.nspname, c.relname, "
     512                 :              "  c.relfilenode, c.reltablespace, "
     513                 :              "  pg_catalog.pg_tablespace_location(t.oid) AS spclocation "
     514                 :              "FROM (SELECT * FROM regular_heap "
     515                 :              "      UNION ALL "
     516                 :              "      SELECT * FROM toast_heap "
     517                 :              "      UNION ALL "
     518                 :              "      SELECT * FROM all_index) all_rels "
     519                 :              "  JOIN pg_catalog.pg_class c "
     520                 :              "      ON all_rels.reloid = c.oid "
     521                 :              "  JOIN pg_catalog.pg_namespace n "
     522                 :              "     ON c.relnamespace = n.oid "
     523                 :              "  LEFT OUTER JOIN pg_catalog.pg_tablespace t "
     524 ECB             :              "     ON c.reltablespace = t.oid "
     525                 :              "ORDER BY 1;");
     526                 : 
     527 GIC          22 :     res = executeQueryOrDie(conn, "%s", query);
     528                 : 
     529              22 :     ntups = PQntuples(res);
     530                 : 
     531              22 :     relinfos = (RelInfo *) pg_malloc(sizeof(RelInfo) * ntups);
     532                 : 
     533              22 :     i_reloid = PQfnumber(res, "reloid");
     534              22 :     i_indtable = PQfnumber(res, "indtable");
     535              22 :     i_toastheap = PQfnumber(res, "toastheap");
     536              22 :     i_nspname = PQfnumber(res, "nspname");
     537 CBC          22 :     i_relname = PQfnumber(res, "relname");
     538 GNC          22 :     i_relfilenumber = PQfnumber(res, "relfilenode");
     539 GIC          22 :     i_reltablespace = PQfnumber(res, "reltablespace");
     540              22 :     i_spclocation = PQfnumber(res, "spclocation");
     541                 : 
     542            3804 :     for (relnum = 0; relnum < ntups; relnum++)
     543                 :     {
     544            3782 :         RelInfo    *curr = &relinfos[num_rels++];
     545                 : 
     546            3782 :         curr->reloid = atooid(PQgetvalue(res, relnum, i_reloid));
     547            3782 :         curr->indtable = atooid(PQgetvalue(res, relnum, i_indtable));
     548            3782 :         curr->toastheap = atooid(PQgetvalue(res, relnum, i_toastheap));
     549                 : 
     550            3782 :         nspname = PQgetvalue(res, relnum, i_nspname);
     551 CBC        3782 :         curr->nsp_alloc = false;
     552                 : 
     553                 :         /*
     554                 :          * Many of the namespace and tablespace strings are identical, so we
     555                 :          * try to reuse the allocated string pointers where possible to reduce
     556                 :          * memory consumption.
     557                 :          */
     558                 :         /* Can we reuse the previous string allocation? */
     559 GIC        3782 :         if (last_namespace && strcmp(nspname, last_namespace) == 0)
     560            2350 :             curr->nspname = last_namespace;
     561                 :         else
     562                 :         {
     563            1432 :             last_namespace = curr->nspname = pg_strdup(nspname);
     564            1432 :             curr->nsp_alloc = true;
     565                 :         }
     566                 : 
     567            3782 :         relname = PQgetvalue(res, relnum, i_relname);
     568 CBC        3782 :         curr->relname = pg_strdup(relname);
     569                 : 
     570 GNC        3782 :         curr->relfilenumber = atooid(PQgetvalue(res, relnum, i_relfilenumber));
     571 GIC        3782 :         curr->tblsp_alloc = false;
     572 ECB             : 
     573                 :         /* Is the tablespace oid non-default? */
     574 CBC        3782 :         if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0)
     575 ECB             :         {
     576                 :             /*
     577                 :              * The tablespace location might be "", meaning the cluster
     578                 :              * default location, i.e. pg_default or pg_global.
     579                 :              */
     580 LBC           0 :             tablespace = PQgetvalue(res, relnum, i_spclocation);
     581 ECB             : 
     582                 :             /* Can we reuse the previous string allocation? */
     583 LBC           0 :             if (last_tablespace && strcmp(tablespace, last_tablespace) == 0)
     584 UIC           0 :                 curr->tablespace = last_tablespace;
     585 ECB             :             else
     586                 :             {
     587 LBC           0 :                 last_tablespace = curr->tablespace = pg_strdup(tablespace);
     588               0 :                 curr->tblsp_alloc = true;
     589 ECB             :             }
     590                 :         }
     591                 :         else
     592                 :             /* A zero reltablespace oid indicates the database tablespace. */
     593 GIC        3782 :             curr->tablespace = dbinfo->db_tablespace;
     594                 :     }
     595              22 :     PQclear(res);
     596                 : 
     597              22 :     PQfinish(conn);
     598                 : 
     599              22 :     dbinfo->rel_arr.rels = relinfos;
     600 CBC          22 :     dbinfo->rel_arr.nrels = num_rels;
     601              22 : }
     602                 : 
     603                 : 
     604 ECB             : static void
     605 CBC           1 : free_db_and_rel_infos(DbInfoArr *db_arr)
     606                 : {
     607                 :     int         dbnum;
     608 ECB             : 
     609 CBC           3 :     for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
     610                 :     {
     611               2 :         free_rel_infos(&db_arr->dbs[dbnum].rel_arr);
     612               2 :         pg_free(db_arr->dbs[dbnum].db_name);
     613                 :     }
     614 GIC           1 :     pg_free(db_arr->dbs);
     615 CBC           1 :     db_arr->dbs = NULL;
     616 GIC           1 :     db_arr->ndbs = 0;
     617               1 : }
     618                 : 
     619                 : 
     620                 : static void
     621 GBC           2 : free_rel_infos(RelInfoArr *rel_arr)
     622                 : {
     623                 :     int         relnum;
     624 EUB             : 
     625 GBC           6 :     for (relnum = 0; relnum < rel_arr->nrels; relnum++)
     626                 :     {
     627 GIC           4 :         if (rel_arr->rels[relnum].nsp_alloc)
     628 GBC           2 :             pg_free(rel_arr->rels[relnum].nspname);
     629               4 :         pg_free(rel_arr->rels[relnum].relname);
     630 GIC           4 :         if (rel_arr->rels[relnum].tblsp_alloc)
     631 UIC           0 :             pg_free(rel_arr->rels[relnum].tablespace);
     632                 :     }
     633 GIC           2 :     pg_free(rel_arr->rels);
     634 CBC           2 :     rel_arr->nrels = 0;
     635 GIC           2 : }
     636 ECB             : 
     637                 : 
     638                 : static void
     639 UIC           0 : print_db_infos(DbInfoArr *db_arr)
     640 ECB             : {
     641                 :     int         dbnum;
     642                 : 
     643 UIC           0 :     for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
     644                 :     {
     645 UNC           0 :         pg_log(PG_VERBOSE, "Database: %s", db_arr->dbs[dbnum].db_name);
     646 LBC           0 :         print_rel_infos(&db_arr->dbs[dbnum].rel_arr);
     647                 :     }
     648 UIC           0 : }
     649 ECB             : 
     650                 : 
     651                 : static void
     652 LBC           0 : print_rel_infos(RelInfoArr *rel_arr)
     653                 : {
     654 ECB             :     int         relnum;
     655                 : 
     656 LBC           0 :     for (relnum = 0; relnum < rel_arr->nrels; relnum++)
     657 UNC           0 :         pg_log(PG_VERBOSE, "relname: %s.%s: reloid: %u reltblspace: %s",
     658 UIC           0 :                rel_arr->rels[relnum].nspname,
     659               0 :                rel_arr->rels[relnum].relname,
     660               0 :                rel_arr->rels[relnum].reloid,
     661 LBC           0 :                rel_arr->rels[relnum].tablespace);
     662 UIC           0 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a