Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  info.c

  Sprache: C
 

/*
 * info.c
 *
 * information support functions
 *
 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
 * src/bin/pg_upgrade/info.c
 */


#include "postgres_fe.h"

#include "access/transam.h"
#include "catalog/pg_class_d.h"
#include "pg_upgrade.h"
#include "pqexpbuffer.h"

static void create_rel_filename_map(const char *old_data, const char *new_data,
         const DbInfo *old_db, const DbInfo *new_db,
         const RelInfo *old_rel, const RelInfo *new_rel,
         FileNameMap *map);
static void report_unmatched_relation(const RelInfo *rel, const DbInfo *db,
           bool is_new_db);
static void free_db_and_rel_infos(DbInfoArr *db_arr);
static void get_template0_info(ClusterInfo *cluster);
static void get_db_infos(ClusterInfo *cluster);
static char *get_rel_infos_query(void);
static void process_rel_infos(DbInfo *dbinfo, PGresult *res, void *arg);
static void free_rel_infos(RelInfoArr *rel_arr);
static void print_db_infos(DbInfoArr *db_arr);
static void print_rel_infos(RelInfoArr *rel_arr);
static void print_slot_infos(LogicalSlotInfoArr *slot_arr);
static char *get_old_cluster_logical_slot_infos_query(void);
static void process_old_cluster_logical_slot_infos(DbInfo *dbinfo, PGresult *res, void *arg);


/*
 * gen_db_file_maps()
 *
 * generates a database mapping from "old_db" to "new_db".
 *
 * Returns a malloc'ed array of mappings.  The length of the array
 * is returned into *nmaps.
 */

FileNameMap *
gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
     int *nmaps,
     const char *old_pgdata, const char *new_pgdata)
{
 FileNameMap *maps;
 int   old_relnum,
    new_relnum;
 int   num_maps = 0;
 bool  all_matched = true;

 /* There will certainly not be more mappings than there are old rels */
 maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
          old_db->rel_arr.nrels);

 /*
  * Each of the RelInfo arrays should be sorted by OID.  Scan through them
  * and match them up.  If we fail to match everything, we'll abort, but
  * first print as much info as we can about mismatches.
 */

 old_relnum = new_relnum = 0;
 while (old_relnum < old_db->rel_arr.nrels ||
     new_relnum < new_db->rel_arr.nrels)
 {
  RelInfo    *old_rel = (old_relnum < old_db->rel_arr.nrels) ?
   &old_db->rel_arr.rels[old_relnum] : NULL;
  RelInfo    *new_rel = (new_relnum < new_db->rel_arr.nrels) ?
   &new_db->rel_arr.rels[new_relnum] : NULL;

  /* handle running off one array before the other */
  if (!new_rel)
  {
   /*
    * old_rel is unmatched.  This should never happen, because we
    * force new rels to have TOAST tables if the old one did.
 */

   report_unmatched_relation(old_rel, old_db, false);
   all_matched = false;
   old_relnum++;
   continue;
  }
  if (!old_rel)
  {
   /*
    * new_rel is unmatched.  This shouldn't really happen either, but
    * if it's a TOAST table, we can ignore it and continue
    * processing, assuming that the new server made a TOAST table
    * that wasn't needed.
 */

   if (strcmp(new_rel->nspname, "pg_toast") != 0)
   {
    report_unmatched_relation(new_rel, new_db, true);
    all_matched = false;
   }
   new_relnum++;
   continue;
  }

  /* check for mismatched OID */
  if (old_rel->reloid < new_rel->reloid)
  {
   /* old_rel is unmatched, see comment above */
   report_unmatched_relation(old_rel, old_db, false);
   all_matched = false;
   old_relnum++;
   continue;
  }
  else if (old_rel->reloid > new_rel->reloid)
  {
   /* new_rel is unmatched, see comment above */
   if (strcmp(new_rel->nspname, "pg_toast") != 0)
   {
    report_unmatched_relation(new_rel, new_db, true);
    all_matched = false;
   }
   new_relnum++;
   continue;
  }

  /*
   * Verify that rels of same OID have same name.  The namespace name
   * should always match, but the relname might not match for TOAST
   * tables (and, therefore, their indexes).
 */

  if (strcmp(old_rel->nspname, new_rel->nspname) != 0 ||
   strcmp(old_rel->relname, new_rel->relname) != 0)
  {
   pg_log(PG_WARNING, "Relation names for OID %u in database \"%s\" do not match: "
       "old name \"%s.%s\", new name \"%s.%s\"",
       old_rel->reloid, old_db->db_name,
       old_rel->nspname, old_rel->relname,
       new_rel->nspname, new_rel->relname);
   all_matched = false;
   old_relnum++;
   new_relnum++;
   continue;
  }

  /* OK, create a mapping entry */
  create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
        old_rel, new_rel, maps + num_maps);
  num_maps++;
  old_relnum++;
  new_relnum++;
 }

 if (!all_matched)
  pg_fatal("Failed to match up old and new tables in database \"%s\"",
     old_db->db_name);

 *nmaps = num_maps;
 return maps;
}


/*
 * create_rel_filename_map()
 *
 * fills a file node map structure and returns it in "map".
 */

static void
create_rel_filename_map(const char *old_data, const char *new_data,
      const DbInfo *old_db, const DbInfo *new_db,
      const RelInfo *old_rel, const RelInfo *new_rel,
      FileNameMap *map)
{
 /* In case old/new tablespaces don't match, do them separately. */
 if (strlen(old_rel->tablespace) == 0)
 {
  /*
   * relation belongs to the default tablespace, hence relfiles should
   * exist in the data directories.
 */

  map->old_tablespace = old_data;
  map->old_tablespace_suffix = "/base";
 }
 else
 {
  /* relation belongs to a tablespace, so use the tablespace location */
  map->old_tablespace = old_rel->tablespace;
  map->old_tablespace_suffix = old_cluster.tablespace_suffix;
 }

 /* Do the same for new tablespaces */
 if (strlen(new_rel->tablespace) == 0)
 {
  map->new_tablespace = new_data;
  map->new_tablespace_suffix = "/base";
 }
 else
 {
  map->new_tablespace = new_rel->tablespace;
  map->new_tablespace_suffix = new_cluster.tablespace_suffix;
 }

 /* DB oid and relfilenumbers are preserved between old and new cluster */
 map->db_oid = old_db->db_oid;
 map->relfilenumber = old_rel->relfilenumber;

 /* used only for logging and error reporting, old/new are identical */
 map->nspname = old_rel->nspname;
 map->relname = old_rel->relname;
}


/*
 * Complain about a relation we couldn't match to the other database,
 * identifying it as best we can.
 */

static void
report_unmatched_relation(const RelInfo *rel, const DbInfo *db, bool is_new_db)
{
 Oid   reloid = rel->reloid; /* we might change rel below */
 char  reldesc[1000];
 int   i;

 snprintf(reldesc, sizeof(reldesc), "\"%s.%s\"",
    rel->nspname, rel->relname);
 if (rel->indtable)
 {
  for (i = 0; i < db->rel_arr.nrels; i++)
  {
   const RelInfo *hrel = &db->rel_arr.rels[i];

   if (hrel->reloid == rel->indtable)
   {
    snprintf(reldesc + strlen(reldesc),
       sizeof(reldesc) - strlen(reldesc),
       _(" which is an index on \"%s.%s\""),
       hrel->nspname, hrel->relname);
    /* Shift attention to index's table for toast check */
    rel = hrel;
    break;
   }
  }
  if (i >= db->rel_arr.nrels)
   snprintf(reldesc + strlen(reldesc),
      sizeof(reldesc) - strlen(reldesc),
      _(" which is an index on OID %u"), rel->indtable);
 }
 if (rel->toastheap)
 {
  for (i = 0; i < db->rel_arr.nrels; i++)
  {
   const RelInfo *brel = &db->rel_arr.rels[i];

   if (brel->reloid == rel->toastheap)
   {
    snprintf(reldesc + strlen(reldesc),
       sizeof(reldesc) - strlen(reldesc),
       _(" which is the TOAST table for \"%s.%s\""),
       brel->nspname, brel->relname);
    break;
   }
  }
  if (i >= db->rel_arr.nrels)
   snprintf(reldesc + strlen(reldesc),
      sizeof(reldesc) - strlen(reldesc),
      _(" which is the TOAST table for OID %u"), rel->toastheap);
 }

 if (is_new_db)
  pg_log(PG_WARNING, "No match found in old cluster for new relation with OID %u in database \"%s\": %s",
      reloid, db->db_name, reldesc);
 else
  pg_log(PG_WARNING, "No match found in new cluster for old relation with OID %u in database \"%s\": %s",
      reloid, db->db_name, reldesc);
}

/*
 * get_db_rel_and_slot_infos()
 *
 * higher level routine to generate dbinfos for the database running
 * on the given "port". Assumes that server is already running.
 */

void
get_db_rel_and_slot_infos(ClusterInfo *cluster)
{
 UpgradeTask *task = upgrade_task_create();
 char    *rel_infos_query = NULL;
 char    *logical_slot_infos_query = NULL;

 if (cluster->dbarr.dbs != NULL)
  free_db_and_rel_infos(&cluster->dbarr);

 get_template0_info(cluster);
 get_db_infos(cluster);

 rel_infos_query = get_rel_infos_query();
 upgrade_task_add_step(task,
        rel_infos_query,
        process_rel_infos,
        true, NULL);

 /*
  * Logical slots are only carried over to the new cluster when the old
  * cluster is on PG17 or newer.  This is because before that the logical
  * slots are not saved at shutdown, so there is no guarantee that the
  * latest confirmed_flush_lsn is saved to disk which can lead to data
  * loss. It is still not guaranteed for manually created slots in PG17, so
  * subsequent checks done in check_old_cluster_for_valid_slots() would
  * raise a FATAL error if such slots are included.
 */

 if (cluster == &old_cluster &&
  GET_MAJOR_VERSION(cluster->major_version) > 1600)
 {
  logical_slot_infos_query = get_old_cluster_logical_slot_infos_query();
  upgrade_task_add_step(task,
         logical_slot_infos_query,
         process_old_cluster_logical_slot_infos,
         true, NULL);
 }

 upgrade_task_run(task, cluster);
 upgrade_task_free(task);

 pg_free(rel_infos_query);
 if (logical_slot_infos_query)
  pg_free(logical_slot_infos_query);

 if (cluster == &old_cluster)
  pg_log(PG_VERBOSE, "\nsource databases:");
 else
  pg_log(PG_VERBOSE, "\ntarget databases:");

 if (log_opts.verbose)
  print_db_infos(&cluster->dbarr);
}


/*
 * Get information about template0, which will be copied from the old cluster
 * to the new cluster.
 */

static void
get_template0_info(ClusterInfo *cluster)
{
 PGconn    *conn = connectToServer(cluster, "template1");
 DbLocaleInfo *locale;
 PGresult   *dbres;
 int   i_datencoding;
 int   i_datlocprovider;
 int   i_datcollate;
 int   i_datctype;
 int   i_datlocale;

 if (GET_MAJOR_VERSION(cluster->major_version) >= 1700)
  dbres = executeQueryOrDie(conn,
          "SELECT encoding, datlocprovider, "
          "       datcollate, datctype, datlocale "
          "FROM pg_catalog.pg_database "
          "WHERE datname='template0'");
 else if (GET_MAJOR_VERSION(cluster->major_version) >= 1500)
  dbres = executeQueryOrDie(conn,
          "SELECT encoding, datlocprovider, "
          "       datcollate, datctype, daticulocale AS datlocale "
          "FROM pg_catalog.pg_database "
          "WHERE datname='template0'");
 else
  dbres = executeQueryOrDie(conn,
          "SELECT encoding, 'c' AS datlocprovider, "
          "       datcollate, datctype, NULL AS datlocale "
          "FROM pg_catalog.pg_database "
          "WHERE datname='template0'");


 if (PQntuples(dbres) != 1)
  pg_fatal("template0 not found");

 locale = pg_malloc(sizeof(DbLocaleInfo));

 i_datencoding = PQfnumber(dbres, "encoding");
 i_datlocprovider = PQfnumber(dbres, "datlocprovider");
 i_datcollate = PQfnumber(dbres, "datcollate");
 i_datctype = PQfnumber(dbres, "datctype");
 i_datlocale = PQfnumber(dbres, "datlocale");

 locale->db_encoding = atoi(PQgetvalue(dbres, 0, i_datencoding));
 locale->db_collprovider = PQgetvalue(dbres, 0, i_datlocprovider)[0];
 locale->db_collate = pg_strdup(PQgetvalue(dbres, 0, i_datcollate));
 locale->db_ctype = pg_strdup(PQgetvalue(dbres, 0, i_datctype));
 if (PQgetisnull(dbres, 0, i_datlocale))
  locale->db_locale = NULL;
 else
  locale->db_locale = pg_strdup(PQgetvalue(dbres, 0, i_datlocale));

 cluster->template0 = locale;

 PQclear(dbres);
 PQfinish(conn);
}


/*
 * get_db_infos()
 *
 * Scans pg_database system catalog and populates all user
 * databases.
 */

static void
get_db_infos(ClusterInfo *cluster)
{
 PGconn    *conn = connectToServer(cluster, "template1");
 PGresult   *res;
 int   ntups;
 int   tupnum;
 DbInfo    *dbinfos;
 int   i_datname,
    i_oid,
    i_spclocation;
 char  query[QUERY_ALLOC];

 snprintf(query, sizeof(query),
    "SELECT d.oid, d.datname, d.encoding, d.datcollate, d.datctype, ");
 if (GET_MAJOR_VERSION(cluster->major_version) >= 1700)
  snprintf(query + strlen(query), sizeof(query) - strlen(query),
     "datlocprovider, datlocale, ");
 else if (GET_MAJOR_VERSION(cluster->major_version) >= 1500)
  snprintf(query + strlen(query), sizeof(query) - strlen(query),
     "datlocprovider, daticulocale AS datlocale, ");
 else
  snprintf(query + strlen(query), sizeof(query) - strlen(query),
     "'c' AS datlocprovider, NULL AS datlocale, ");
 snprintf(query + strlen(query), sizeof(query) - strlen(query),
    "pg_catalog.pg_tablespace_location(t.oid) AS spclocation "
    "FROM pg_catalog.pg_database d "
    " LEFT OUTER JOIN pg_catalog.pg_tablespace t "
    " ON d.dattablespace = t.oid "
    "WHERE d.datallowconn = true "
    "ORDER BY 1");

 res = executeQueryOrDie(conn, "%s", query);

 i_oid = PQfnumber(res, "oid");
 i_datname = PQfnumber(res, "datname");
 i_spclocation = PQfnumber(res, "spclocation");

 ntups = PQntuples(res);
 dbinfos = (DbInfo *) pg_malloc0(sizeof(DbInfo) * ntups);

 for (tupnum = 0; tupnum < ntups; tupnum++)
 {
  dbinfos[tupnum].db_oid = atooid(PQgetvalue(res, tupnum, i_oid));
  dbinfos[tupnum].db_name = pg_strdup(PQgetvalue(res, tupnum, i_datname));
  snprintf(dbinfos[tupnum].db_tablespace, sizeof(dbinfos[tupnum].db_tablespace), "%s",
     PQgetvalue(res, tupnum, i_spclocation));
 }
 PQclear(res);

 PQfinish(conn);

 cluster->dbarr.dbs = dbinfos;
 cluster->dbarr.ndbs = ntups;
}


/*
 * get_rel_infos_query()
 *
 * Returns the query for retrieving the relation information for all the user
 * tables and indexes in the database, for use by get_db_rel_and_slot_infos()'s
 * UpgradeTask.
 *
 * Note: the result is assumed to be sorted by OID.  This allows later
 * processing to match up old and new databases efficiently.
 */

static char *
get_rel_infos_query(void)
{
 PQExpBufferData query;

 initPQExpBuffer(&query);

 /*
  * Create a CTE that collects OIDs of regular user tables and matviews,
  * but excluding toast tables and indexes.  We assume that relations with
  * OIDs >= FirstNormalObjectId belong to the user.  (That's probably
  * redundant with the namespace-name exclusions, but let's be safe.)
  *
  * pg_largeobject contains user data that does not appear in pg_dump
  * output, so we have to copy that system table.  It's easiest to do that
  * by treating it as a user table.
 */

 appendPQExpBuffer(&query,
       "WITH regular_heap (reloid, indtable, toastheap) AS ( "
       "  SELECT c.oid, 0::oid, 0::oid "
       "  FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
       "         ON c.relnamespace = n.oid "
       "  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
       CppAsString2(RELKIND_MATVIEW) "%s) AND "
 /* exclude possible orphaned temp tables */
       "    ((n.nspname !~ '^pg_temp_' AND "
       "      n.nspname !~ '^pg_toast_temp_' AND "
       "      n.nspname NOT IN ('pg_catalog', 'information_schema', "
       "                        'binary_upgrade', 'pg_toast') AND "
       "      c.oid >= %u::pg_catalog.oid) OR "
       "     (n.nspname = 'pg_catalog' AND "
       "      relname IN ('pg_largeobject') ))), ",
       (user_opts.transfer_mode == TRANSFER_MODE_SWAP) ?
       ", " CppAsString2(RELKIND_SEQUENCE) : "",
       FirstNormalObjectId);

 /*
  * Add a CTE that collects OIDs of toast tables belonging to the tables
  * selected by the regular_heap CTE.  (We have to do this separately
  * because the namespace-name rules above don't work for toast tables.)
 */

 appendPQExpBufferStr(&query,
       "  toast_heap (reloid, indtable, toastheap) AS ( "
       "  SELECT c.reltoastrelid, 0::oid, c.oid "
       "  FROM regular_heap JOIN pg_catalog.pg_class c "
       "      ON regular_heap.reloid = c.oid "
       "  WHERE c.reltoastrelid != 0), ");

 /*
  * Add a CTE that collects OIDs of all valid indexes on the previously
  * selected tables.  We can ignore invalid indexes since pg_dump does.
  * Testing indisready is necessary in 9.2, and harmless in earlier/later
  * versions.
 */

 appendPQExpBufferStr(&query,
       "  all_index (reloid, indtable, toastheap) AS ( "
       "  SELECT indexrelid, indrelid, 0::oid "
       "  FROM pg_catalog.pg_index "
       "  WHERE indisvalid AND indisready "
       "    AND indrelid IN "
       "        (SELECT reloid FROM regular_heap "
       "         UNION ALL "
       "         SELECT reloid FROM toast_heap)) ");

 /*
  * And now we can write the query that retrieves the data we want for each
  * heap and index relation.  Make sure result is sorted by OID.
 */

 appendPQExpBufferStr(&query,
       "SELECT all_rels.*, n.nspname, c.relname, "
       "  c.relfilenode, c.reltablespace, "
       "  pg_catalog.pg_tablespace_location(t.oid) AS spclocation "
       "FROM (SELECT * FROM regular_heap "
       "      UNION ALL "
       "      SELECT * FROM toast_heap "
       "      UNION ALL "
       "      SELECT * FROM all_index) all_rels "
       "  JOIN pg_catalog.pg_class c "
       "      ON all_rels.reloid = c.oid "
       "  JOIN pg_catalog.pg_namespace n "
       "     ON c.relnamespace = n.oid "
       "  LEFT OUTER JOIN pg_catalog.pg_tablespace t "
       "     ON c.reltablespace = t.oid "
       "ORDER BY 1");

 return query.data;
}

/*
 * Callback function for processing results of the query returned by
 * get_rel_infos_query(), which is used for get_db_rel_and_slot_infos()'s
 * UpgradeTask.  This function stores the relation information for later use.
 */

static void
process_rel_infos(DbInfo *dbinfo, PGresult *res, void *arg)
{
 int   ntups = PQntuples(res);
 RelInfo    *relinfos = (RelInfo *) pg_malloc(sizeof(RelInfo) * ntups);
 int   i_reloid = PQfnumber(res, "reloid");
 int   i_indtable = PQfnumber(res, "indtable");
 int   i_toastheap = PQfnumber(res, "toastheap");
 int   i_nspname = PQfnumber(res, "nspname");
 int   i_relname = PQfnumber(res, "relname");
 int   i_relfilenumber = PQfnumber(res, "relfilenode");
 int   i_reltablespace = PQfnumber(res, "reltablespace");
 int   i_spclocation = PQfnumber(res, "spclocation");
 int   num_rels = 0;
 char    *nspname = NULL;
 char    *relname = NULL;
 char    *tablespace = NULL;
 char    *last_namespace = NULL;
 char    *last_tablespace = NULL;

 AssertVariableIsOfType(&process_rel_infos, UpgradeTaskProcessCB);

 for (int relnum = 0; relnum < ntups; relnum++)
 {
  RelInfo    *curr = &relinfos[num_rels++];

  curr->reloid = atooid(PQgetvalue(res, relnum, i_reloid));
  curr->indtable = atooid(PQgetvalue(res, relnum, i_indtable));
  curr->toastheap = atooid(PQgetvalue(res, relnum, i_toastheap));

  nspname = PQgetvalue(res, relnum, i_nspname);
  curr->nsp_alloc = false;

  /*
   * Many of the namespace and tablespace strings are identical, so we
   * try to reuse the allocated string pointers where possible to reduce
   * memory consumption.
 */

  /* Can we reuse the previous string allocation? */
  if (last_namespace && strcmp(nspname, last_namespace) == 0)
   curr->nspname = last_namespace;
  else
  {
   last_namespace = curr->nspname = pg_strdup(nspname);
   curr->nsp_alloc = true;
  }

  relname = PQgetvalue(res, relnum, i_relname);
  curr->relname = pg_strdup(relname);

  curr->relfilenumber = atooid(PQgetvalue(res, relnum, i_relfilenumber));
  curr->tblsp_alloc = false;

  /* Is the tablespace oid non-default? */
  if (atooid(PQgetvalue(res, relnum, i_reltablespace)) != 0)
  {
   /*
    * The tablespace location might be "", meaning the cluster
    * default location, i.e. pg_default or pg_global.
 */

   tablespace = PQgetvalue(res, relnum, i_spclocation);

   /* Can we reuse the previous string allocation? */
   if (last_tablespace && strcmp(tablespace, last_tablespace) == 0)
    curr->tablespace = last_tablespace;
   else
   {
    last_tablespace = curr->tablespace = pg_strdup(tablespace);
    curr->tblsp_alloc = true;
   }
  }
  else
   /* A zero reltablespace oid indicates the database tablespace. */
   curr->tablespace = dbinfo->db_tablespace;
 }

 dbinfo->rel_arr.rels = relinfos;
 dbinfo->rel_arr.nrels = num_rels;
}

/*
 * get_old_cluster_logical_slot_infos_query()
 *
 * Returns the query for retrieving the logical slot information for all the
 * logical replication slots in the database, for use by
 * get_db_rel_and_slot_infos()'s UpgradeTask.  The status of each logical slot
 * is checked in check_old_cluster_for_valid_slots().
 */

static char *
get_old_cluster_logical_slot_infos_query(void)
{
 /*
  * Fetch the logical replication slot information. The check whether the
  * slot is considered caught up is done by an upgrade function. This
  * regards the slot as caught up if we don't find any decodable changes.
  * See binary_upgrade_logical_slot_has_caught_up().
  *
  * Note that we can't ensure whether the slot is caught up during
  * live_check as the new WAL records could be generated.
  *
  * We intentionally skip checking the WALs for invalidated slots as the
  * corresponding WALs could have been removed for such slots.
  *
  * The temporary slots are explicitly ignored while checking because such
  * slots cannot exist after the upgrade. During the upgrade, clusters are
  * started and stopped several times causing any temporary slots to be
  * removed.
 */

 return psprintf("SELECT slot_name, plugin, two_phase, failover, "
     "%s as caught_up, invalidation_reason IS NOT NULL as invalid "
     "FROM pg_catalog.pg_replication_slots "
     "WHERE slot_type = 'logical' AND "
     "database = current_database() AND "
     "temporary IS FALSE;",
     user_opts.live_check ? "FALSE" :
     "(CASE WHEN invalidation_reason IS NOT NULL THEN FALSE "
     "ELSE (SELECT pg_catalog.binary_upgrade_logical_slot_has_caught_up(slot_name)) "
     "END)");
}

/*
 * Callback function for processing results of the query returned by
 * get_old_cluster_logical_slot_infos_query(), which is used for
 * get_db_rel_and_slot_infos()'s UpgradeTask.  This function stores the logical
 * slot information for later use.
 */

static void
process_old_cluster_logical_slot_infos(DbInfo *dbinfo, PGresult *res, void *arg)
{
 LogicalSlotInfo *slotinfos = NULL;
 int   num_slots = PQntuples(res);

 AssertVariableIsOfType(&process_old_cluster_logical_slot_infos,
         UpgradeTaskProcessCB);

 if (num_slots)
 {
  int   i_slotname;
  int   i_plugin;
  int   i_twophase;
  int   i_failover;
  int   i_caught_up;
  int   i_invalid;

  slotinfos = (LogicalSlotInfo *) pg_malloc(sizeof(LogicalSlotInfo) * num_slots);

  i_slotname = PQfnumber(res, "slot_name");
  i_plugin = PQfnumber(res, "plugin");
  i_twophase = PQfnumber(res, "two_phase");
  i_failover = PQfnumber(res, "failover");
  i_caught_up = PQfnumber(res, "caught_up");
  i_invalid = PQfnumber(res, "invalid");

  for (int slotnum = 0; slotnum < num_slots; slotnum++)
  {
   LogicalSlotInfo *curr = &slotinfos[slotnum];

   curr->slotname = pg_strdup(PQgetvalue(res, slotnum, i_slotname));
   curr->plugin = pg_strdup(PQgetvalue(res, slotnum, i_plugin));
   curr->two_phase = (strcmp(PQgetvalue(res, slotnum, i_twophase), "t") == 0);
   curr->failover = (strcmp(PQgetvalue(res, slotnum, i_failover), "t") == 0);
   curr->caught_up = (strcmp(PQgetvalue(res, slotnum, i_caught_up), "t") == 0);
   curr->invalid = (strcmp(PQgetvalue(res, slotnum, i_invalid), "t") == 0);
  }
 }

 dbinfo->slot_arr.slots = slotinfos;
 dbinfo->slot_arr.nslots = num_slots;
}


/*
 * count_old_cluster_logical_slots()
 *
 * Returns the number of logical replication slots for all databases.
 *
 * Note: this function always returns 0 if the old_cluster is PG16 and prior
 * because we gather slot information only for cluster versions greater than or
 * equal to PG17. See get_old_cluster_logical_slot_infos().
 */

int
count_old_cluster_logical_slots(void)
{
 int   slot_count = 0;

 for (int dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
  slot_count += old_cluster.dbarr.dbs[dbnum].slot_arr.nslots;

 return slot_count;
}

/*
 * get_subscription_count()
 *
 * Gets the number of subscriptions in the cluster.
 */

void
get_subscription_count(ClusterInfo *cluster)
{
 PGconn    *conn;
 PGresult   *res;

 conn = connectToServer(cluster, "template1");
 res = executeQueryOrDie(conn, "SELECT count(*) "
       "FROM pg_catalog.pg_subscription");
 cluster->nsubs = atoi(PQgetvalue(res, 00));

 PQclear(res);
 PQfinish(conn);
}

static void
free_db_and_rel_infos(DbInfoArr *db_arr)
{
 int   dbnum;

 for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
 {
  free_rel_infos(&db_arr->dbs[dbnum].rel_arr);
  pg_free(db_arr->dbs[dbnum].db_name);
 }
 pg_free(db_arr->dbs);
 db_arr->dbs = NULL;
 db_arr->ndbs = 0;
}


static void
free_rel_infos(RelInfoArr *rel_arr)
{
 int   relnum;

 for (relnum = 0; relnum < rel_arr->nrels; relnum++)
 {
  if (rel_arr->rels[relnum].nsp_alloc)
   pg_free(rel_arr->rels[relnum].nspname);
  pg_free(rel_arr->rels[relnum].relname);
  if (rel_arr->rels[relnum].tblsp_alloc)
   pg_free(rel_arr->rels[relnum].tablespace);
 }
 pg_free(rel_arr->rels);
 rel_arr->nrels = 0;
}


static void
print_db_infos(DbInfoArr *db_arr)
{
 int   dbnum;

 for (dbnum = 0; dbnum < db_arr->ndbs; dbnum++)
 {
  DbInfo    *pDbInfo = &db_arr->dbs[dbnum];

  pg_log(PG_VERBOSE, "Database: \"%s\"", pDbInfo->db_name);
  print_rel_infos(&pDbInfo->rel_arr);
  print_slot_infos(&pDbInfo->slot_arr);
 }
}


static void
print_rel_infos(RelInfoArr *rel_arr)
{
 int   relnum;

 for (relnum = 0; relnum < rel_arr->nrels; relnum++)
  pg_log(PG_VERBOSE, "relname: \"%s.%s\", reloid: %u, reltblspace: \"%s\"",
      rel_arr->rels[relnum].nspname,
      rel_arr->rels[relnum].relname,
      rel_arr->rels[relnum].reloid,
      rel_arr->rels[relnum].tablespace);
}

static void
print_slot_infos(LogicalSlotInfoArr *slot_arr)
{
 /* Quick return if there are no logical slots. */
 if (slot_arr->nslots == 0)
  return;

 pg_log(PG_VERBOSE, "Logical replication slots in the database:");

 for (int slotnum = 0; slotnum < slot_arr->nslots; slotnum++)
 {
  LogicalSlotInfo *slot_info = &slot_arr->slots[slotnum];

  pg_log(PG_VERBOSE, "slot name: \"%s\", output plugin: \"%s\", two_phase: %s",
      slot_info->slotname,
      slot_info->plugin,
      slot_info->two_phase ? "true" : "false");
 }
}

Messung V0.5 in Prozent
C=95 H=91 G=92

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet am  2026-08-07) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002