summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2014-07-07 13:24:08 -0400
committerBruce Momjian <bruce@momjian.us>2014-07-07 13:24:08 -0400
commit759c9fb631fbb3a1d28b24979e0d512e3a571d5c (patch)
treef3f2d9969e4e41c7220127a527e4f780544dbb9b /contrib
parent981518ea19325d9949c80aea4627a2b935b4ffee (diff)
downloadpostgresql-759c9fb631fbb3a1d28b24979e0d512e3a571d5c.tar.gz
pg_upgrade: allow upgrades for new-only TOAST tables
Previously, when calculations on the need for toast tables changed, pg_upgrade could not handle cases where the new cluster needed a TOAST table and the old cluster did not. (It already handled the opposite case.) This fixes the "OID mismatch" error typically generated in this case. Backpatch through 9.2
Diffstat (limited to 'contrib')
-rw-r--r--contrib/pg_upgrade/info.c61
1 files changed, 51 insertions, 10 deletions
diff --git a/contrib/pg_upgrade/info.c b/contrib/pg_upgrade/info.c
index 6cc10c7b5a..eec087fc48 100644
--- a/contrib/pg_upgrade/info.c
+++ b/contrib/pg_upgrade/info.c
@@ -37,21 +37,61 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
int *nmaps, const char *old_pgdata, const char *new_pgdata)
{
FileNameMap *maps;
- int relnum;
+ int old_relnum, new_relnum;
int num_maps = 0;
maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
old_db->rel_arr.nrels);
- for (relnum = 0; relnum < Min(old_db->rel_arr.nrels, new_db->rel_arr.nrels);
- relnum++)
+ /*
+ * The old database shouldn't have more relations than the new one.
+ * We force the new cluster to have a TOAST table if the old table
+ * had one.
+ */
+ if (old_db->rel_arr.nrels > new_db->rel_arr.nrels)
+ pg_log(PG_FATAL, "old and new databases \"%s\" have a mismatched number of relations\n",
+ old_db->db_name);
+
+ /* Drive the loop using new_relnum, which might be higher. */
+ for (old_relnum = new_relnum = 0; new_relnum < new_db->rel_arr.nrels;
+ new_relnum++)
{
- RelInfo *old_rel = &old_db->rel_arr.rels[relnum];
- RelInfo *new_rel = &new_db->rel_arr.rels[relnum];
+ RelInfo *old_rel;
+ RelInfo *new_rel = &new_db->rel_arr.rels[new_relnum];
+
+ /*
+ * It is possible that the new cluster has a TOAST table for a table
+ * that didn't need one in the old cluster, e.g. 9.0 to 9.1 changed the
+ * NUMERIC length computation. Therefore, if we have a TOAST table
+ * in the new cluster that doesn't match, skip over it and continue
+ * processing. It is possible this TOAST table used an OID that was
+ * reserved in the old cluster, but we have no way of testing that,
+ * and we would have already gotten an error at the new cluster schema
+ * creation stage. Fortunately, since we only restore the OID counter
+ * after schema restore, and restore in OID order via pg_dump, a
+ * conflict would only happen if the new TOAST table had a very low
+ * OID. However, TOAST tables created long after initial table
+ * creation can have any OID, particularly after OID wraparound.
+ */
+ if (old_relnum == old_db->rel_arr.nrels)
+ {
+ if (strcmp(new_rel->nspname, "pg_toast") == 0)
+ continue;
+ else
+ pg_log(PG_FATAL, "Extra non-TOAST relation found in database \"%s\": new OID %d\n",
+ old_db->db_name, new_rel->reloid);
+ }
+
+ old_rel = &old_db->rel_arr.rels[old_relnum];
if (old_rel->reloid != new_rel->reloid)
- pg_log(PG_FATAL, "Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n",
- old_db->db_name, old_rel->reloid, new_rel->reloid);
+ {
+ if (strcmp(new_rel->nspname, "pg_toast") == 0)
+ continue;
+ else
+ pg_log(PG_FATAL, "Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n",
+ old_db->db_name, old_rel->reloid, new_rel->reloid);
+ }
/*
* TOAST table names initially match the heap pg_class oid. In
@@ -73,11 +113,12 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
old_rel, new_rel, maps + num_maps);
num_maps++;
+ old_relnum++;
}
- /* Do this check after the loop so hopefully we will produce a clearer error above */
- if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
- pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
+ /* Did we fail to exhaust the old array? */
+ if (old_relnum != old_db->rel_arr.nrels)
+ pg_log(PG_FATAL, "old and new databases \"%s\" have a mismatched number of relations\n",
old_db->db_name);
*nmaps = num_maps;