@@ -38,21 +38,61 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
3838 int * nmaps , const char * old_pgdata , const char * new_pgdata )
3939{
4040 FileNameMap * maps ;
41- int relnum ;
41+ int old_relnum , new_relnum ;
4242 int num_maps = 0 ;
4343
4444 maps = (FileNameMap * ) pg_malloc (sizeof (FileNameMap ) *
4545 old_db -> rel_arr .nrels );
4646
47- for (relnum = 0 ; relnum < Min (old_db -> rel_arr .nrels , new_db -> rel_arr .nrels );
48- relnum ++ )
47+ /*
48+ * The old database shouldn't have more relations than the new one.
49+ * We force the new cluster to have a TOAST table if the old table
50+ * had one.
51+ */
52+ if (old_db -> rel_arr .nrels > new_db -> rel_arr .nrels )
53+ pg_fatal ("old and new databases \"%s\" have a mismatched number of relations\n" ,
54+ old_db -> db_name );
55+
56+ /* Drive the loop using new_relnum, which might be higher. */
57+ for (old_relnum = new_relnum = 0 ; new_relnum < new_db -> rel_arr .nrels ;
58+ new_relnum ++ )
4959 {
50- RelInfo * old_rel = & old_db -> rel_arr .rels [relnum ];
51- RelInfo * new_rel = & new_db -> rel_arr .rels [relnum ];
60+ RelInfo * old_rel ;
61+ RelInfo * new_rel = & new_db -> rel_arr .rels [new_relnum ];
62+
63+ /*
64+ * It is possible that the new cluster has a TOAST table for a table
65+ * that didn't need one in the old cluster, e.g. 9.0 to 9.1 changed the
66+ * NUMERIC length computation. Therefore, if we have a TOAST table
67+ * in the new cluster that doesn't match, skip over it and continue
68+ * processing. It is possible this TOAST table used an OID that was
69+ * reserved in the old cluster, but we have no way of testing that,
70+ * and we would have already gotten an error at the new cluster schema
71+ * creation stage. Fortunately, since we only restore the OID counter
72+ * after schema restore, and restore in OID order via pg_dump, a
73+ * conflict would only happen if the new TOAST table had a very low
74+ * OID. However, TOAST tables created long after initial table
75+ * creation can have any OID, particularly after OID wraparound.
76+ */
77+ if (old_relnum == old_db -> rel_arr .nrels )
78+ {
79+ if (strcmp (new_rel -> nspname , "pg_toast" ) == 0 )
80+ continue ;
81+ else
82+ pg_fatal ("Extra non-TOAST relation found in database \"%s\": new OID %d\n" ,
83+ old_db -> db_name , new_rel -> reloid );
84+ }
85+
86+ old_rel = & old_db -> rel_arr .rels [old_relnum ];
5287
5388 if (old_rel -> reloid != new_rel -> reloid )
54- pg_fatal ("Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n" ,
55- old_db -> db_name , old_rel -> reloid , new_rel -> reloid );
89+ {
90+ if (strcmp (new_rel -> nspname , "pg_toast" ) == 0 )
91+ continue ;
92+ else
93+ pg_fatal ("Mismatch of relation OID in database \"%s\": old OID %d, new OID %d\n" ,
94+ old_db -> db_name , old_rel -> reloid , new_rel -> reloid );
95+ }
5696
5797 /*
5898 * TOAST table names initially match the heap pg_class oid. In
@@ -76,14 +116,12 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
76116 create_rel_filename_map (old_pgdata , new_pgdata , old_db , new_db ,
77117 old_rel , new_rel , maps + num_maps );
78118 num_maps ++ ;
119+ old_relnum ++ ;
79120 }
80121
81- /*
82- * Do this check after the loop so hopefully we will produce a clearer
83- * error above
84- */
85- if (old_db -> rel_arr .nrels != new_db -> rel_arr .nrels )
86- pg_fatal ("old and new databases \"%s\" have a different number of relations\n" ,
122+ /* Did we fail to exhaust the old array? */
123+ if (old_relnum != old_db -> rel_arr .nrels )
124+ pg_fatal ("old and new databases \"%s\" have a mismatched number of relations\n" ,
87125 old_db -> db_name );
88126
89127 * nmaps = num_maps ;
0 commit comments