@@ -37,21 +37,61 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
37
37
int * nmaps , const char * old_pgdata , const char * new_pgdata )
38
38
{
39
39
FileNameMap * maps ;
40
- int relnum ;
40
+ int old_relnum , new_relnum ;
41
41
int num_maps = 0 ;
42
42
43
43
maps = (FileNameMap * ) pg_malloc (sizeof (FileNameMap ) *
44
44
old_db -> rel_arr .nrels );
45
45
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 ++ )
48
58
{
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 ];
51
86
52
87
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
+ }
55
95
56
96
/*
57
97
* 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,
73
113
create_rel_filename_map (old_pgdata , new_pgdata , old_db , new_db ,
74
114
old_rel , new_rel , maps + num_maps );
75
115
num_maps ++ ;
116
+ old_relnum ++ ;
76
117
}
77
118
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" ,
81
122
old_db -> db_name );
82
123
83
124
* nmaps = num_maps ;
0 commit comments