Skip to content

Commit 759c9fb

Browse files
committed
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
1 parent 981518e commit 759c9fb

File tree

1 file changed

+51
-10
lines changed

1 file changed

+51
-10
lines changed

contrib/pg_upgrade/info.c

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,61 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
3737
int *nmaps, const char *old_pgdata, const char *new_pgdata)
3838
{
3939
FileNameMap *maps;
40-
int relnum;
40+
int old_relnum, new_relnum;
4141
int num_maps = 0;
4242

4343
maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
4444
old_db->rel_arr.nrels);
4545

46-
for (relnum = 0; relnum < Min(old_db->rel_arr.nrels, new_db->rel_arr.nrels);
47-
relnum++)
46+
/*
47+
* The old database shouldn't have more relations than the new one.
48+
* We force the new cluster to have a TOAST table if the old table
49+
* had one.
50+
*/
51+
if (old_db->rel_arr.nrels > new_db->rel_arr.nrels)
52+
pg_log(PG_FATAL, "old and new databases \"%s\" have a mismatched number of relations\n",
53+
old_db->db_name);
54+
55+
/* Drive the loop using new_relnum, which might be higher. */
56+
for (old_relnum = new_relnum = 0; new_relnum < new_db->rel_arr.nrels;
57+
new_relnum++)
4858
{
49-
RelInfo *old_rel = &old_db->rel_arr.rels[relnum];
50-
RelInfo *new_rel = &new_db->rel_arr.rels[relnum];
59+
RelInfo *old_rel;
60+
RelInfo *new_rel = &new_db->rel_arr.rels[new_relnum];
61+
62+
/*
63+
* It is possible that the new cluster has a TOAST table for a table
64+
* that didn't need one in the old cluster, e.g. 9.0 to 9.1 changed the
65+
* NUMERIC length computation. Therefore, if we have a TOAST table
66+
* in the new cluster that doesn't match, skip over it and continue
67+
* processing. It is possible this TOAST table used an OID that was
68+
* reserved in the old cluster, but we have no way of testing that,
69+
* and we would have already gotten an error at the new cluster schema
70+
* creation stage. Fortunately, since we only restore the OID counter
71+
* after schema restore, and restore in OID order via pg_dump, a
72+
* conflict would only happen if the new TOAST table had a very low
73+
* OID. However, TOAST tables created long after initial table
74+
* creation can have any OID, particularly after OID wraparound.
75+
*/
76+
if (old_relnum == old_db->rel_arr.nrels)
77+
{
78+
if (strcmp(new_rel->nspname, "pg_toast") == 0)
79+
continue;
80+
else
81+
pg_log(PG_FATAL, "Extra non-TOAST relation found in database \"%s\": new OID %d\n",
82+
old_db->db_name, new_rel->reloid);
83+
}
84+
85+
old_rel = &old_db->rel_arr.rels[old_relnum];
5186

5287
if (old_rel->reloid != new_rel->reloid)
53-
pg_log(PG_FATAL, "Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n",
54-
old_db->db_name, old_rel->reloid, new_rel->reloid);
88+
{
89+
if (strcmp(new_rel->nspname, "pg_toast") == 0)
90+
continue;
91+
else
92+
pg_log(PG_FATAL, "Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n",
93+
old_db->db_name, old_rel->reloid, new_rel->reloid);
94+
}
5595

5696
/*
5797
* 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,
73113
create_rel_filename_map(old_pgdata, new_pgdata, old_db, new_db,
74114
old_rel, new_rel, maps + num_maps);
75115
num_maps++;
116+
old_relnum++;
76117
}
77118

78-
/* Do this check after the loop so hopefully we will produce a clearer error above */
79-
if (old_db->rel_arr.nrels != new_db->rel_arr.nrels)
80-
pg_log(PG_FATAL, "old and new databases \"%s\" have a different number of relations\n",
119+
/* Did we fail to exhaust the old array? */
120+
if (old_relnum != old_db->rel_arr.nrels)
121+
pg_log(PG_FATAL, "old and new databases \"%s\" have a mismatched number of relations\n",
81122
old_db->db_name);
82123

83124
*nmaps = num_maps;

0 commit comments

Comments
 (0)