@@ -38,21 +38,61 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
38
38
int * nmaps , const char * old_pgdata , const char * new_pgdata )
39
39
{
40
40
FileNameMap * maps ;
41
- int relnum ;
41
+ int old_relnum , new_relnum ;
42
42
int num_maps = 0 ;
43
43
44
44
maps = (FileNameMap * ) pg_malloc (sizeof (FileNameMap ) *
45
45
old_db -> rel_arr .nrels );
46
46
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 ++ )
49
59
{
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 ];
52
87
53
88
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
+ }
56
96
57
97
/*
58
98
* 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,
76
116
create_rel_filename_map (old_pgdata , new_pgdata , old_db , new_db ,
77
117
old_rel , new_rel , maps + num_maps );
78
118
num_maps ++ ;
119
+ old_relnum ++ ;
79
120
}
80
121
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" ,
87
125
old_db -> db_name );
88
126
89
127
* nmaps = num_maps ;
0 commit comments