@@ -100,78 +100,96 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode)
100
100
101
101
102
102
/*
103
- * old_9_3_check_for_line_data_type_usage()
104
- * 9.3 -> 9.4
105
- * Fully implement the 'line' data type in 9.4, which previously returned
106
- * "not enabled" by default and was only functionally enabled with a
107
- * compile-time switch; 9.4 "line" has different binary and text
108
- * representation formats; checks tables and indexes.
103
+ * check_for_data_type_usage
104
+ * Detect whether there are any stored columns depending on the given type
105
+ *
106
+ * If so, write a report to the given file name, and return true.
107
+ *
108
+ * We check for the type in tables, matviews, and indexes, but not views;
109
+ * there's no storage involved in a view.
109
110
*/
110
- void
111
- old_9_3_check_for_line_data_type_usage (ClusterInfo * cluster )
111
+ static bool
112
+ check_for_data_type_usage (ClusterInfo * cluster , const char * typename ,
113
+ char * output_path )
112
114
{
113
- int dbnum ;
114
- FILE * script = NULL ;
115
115
bool found = false;
116
- char output_path [MAXPGPATH ];
117
-
118
- prep_status ("Checking for incompatible \"line\" data type" );
119
-
120
- snprintf (output_path , sizeof (output_path ), "tables_using_line.txt" );
116
+ FILE * script = NULL ;
117
+ int dbnum ;
121
118
122
119
for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
123
120
{
121
+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
122
+ PGconn * conn = connectToServer (cluster , active_db -> db_name );
123
+ PQExpBufferData querybuf ;
124
124
PGresult * res ;
125
125
bool db_used = false;
126
126
int ntups ;
127
127
int rowno ;
128
128
int i_nspname ,
129
129
i_relname ,
130
130
i_attname ;
131
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
132
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
133
131
134
132
/*
135
- * The pg_catalog.line type may be wrapped in a domain or composite
136
- * type , or both (9.3 did not allow domains on composite types, but
137
- * there may be multi-level composite type). To detect these cases
138
- * we need a recursive CTE.
133
+ * The type of interest might be wrapped in a domain, array,
134
+ * composite , or range, and these container types can be nested (to
135
+ * varying extents depending on server version, but that's not of
136
+ * concern here). To handle all these cases we need a recursive CTE.
139
137
*/
140
- res = executeQueryOrDie (conn ,
141
- "WITH RECURSIVE oids AS ( "
142
- /* the pg_catalog.line type itself */
143
- " SELECT 'pg_catalog.line'::pg_catalog.regtype AS oid "
144
- " UNION ALL "
145
- " SELECT * FROM ( "
146
- /* domains on the type */
147
- " WITH x AS (SELECT oid FROM oids) "
148
- " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
149
- " UNION "
150
- /* composite types containing the type */
151
- " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
152
- " WHERE t.typtype = 'c' AND "
153
- " t.oid = c.reltype AND "
154
- " c.oid = a.attrelid AND "
155
- " NOT a.attisdropped AND "
156
- " a.atttypid = x.oid "
157
- " ) foo "
158
- ") "
159
- "SELECT n.nspname, c.relname, a.attname "
160
- "FROM pg_catalog.pg_class c, "
161
- " pg_catalog.pg_namespace n, "
162
- " pg_catalog.pg_attribute a "
163
- "WHERE c.oid = a.attrelid AND "
164
- " NOT a.attisdropped AND "
165
- " a.atttypid IN (SELECT oid FROM oids) AND "
166
- " c.relkind IN ("
167
- CppAsString2 (RELKIND_RELATION ) ", "
168
- CppAsString2 (RELKIND_MATVIEW ) ", "
169
- CppAsString2 (RELKIND_INDEX ) ") AND "
170
- " c.relnamespace = n.oid AND "
138
+ initPQExpBuffer (& querybuf );
139
+ appendPQExpBuffer (& querybuf ,
140
+ "WITH RECURSIVE oids AS ( "
141
+ /* the target type itself */
142
+ " SELECT '%s'::pg_catalog.regtype AS oid "
143
+ " UNION ALL "
144
+ " SELECT * FROM ( "
145
+ /* inner WITH because we can only reference the CTE once */
146
+ " WITH x AS (SELECT oid FROM oids) "
147
+ /* domains on any type selected so far */
148
+ " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
149
+ " UNION ALL "
150
+ /* arrays over any type selected so far */
151
+ " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typelem = x.oid AND typtype = 'b' "
152
+ " UNION ALL "
153
+ /* composite types containing any type selected so far */
154
+ " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
155
+ " WHERE t.typtype = 'c' AND "
156
+ " t.oid = c.reltype AND "
157
+ " c.oid = a.attrelid AND "
158
+ " NOT a.attisdropped AND "
159
+ " a.atttypid = x.oid " ,
160
+ typename );
161
+
162
+ /* Ranges came in in 9.2 */
163
+ if (GET_MAJOR_VERSION (cluster -> major_version ) >= 902 )
164
+ appendPQExpBuffer (& querybuf ,
165
+ " UNION ALL "
166
+ /* ranges containing any type selected so far */
167
+ " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_range r, x "
168
+ " WHERE t.typtype = 'r' AND r.rngtypid = t.oid AND r.rngsubtype = x.oid" );
169
+
170
+ appendPQExpBuffer (& querybuf ,
171
+ " ) foo "
172
+ ") "
173
+ /* now look for stored columns of any such type */
174
+ "SELECT n.nspname, c.relname, a.attname "
175
+ "FROM pg_catalog.pg_class c, "
176
+ " pg_catalog.pg_namespace n, "
177
+ " pg_catalog.pg_attribute a "
178
+ "WHERE c.oid = a.attrelid AND "
179
+ " NOT a.attisdropped AND "
180
+ " a.atttypid IN (SELECT oid FROM oids) AND "
181
+ " c.relkind IN ("
182
+ CppAsString2 (RELKIND_RELATION ) ", "
183
+ CppAsString2 (RELKIND_MATVIEW ) ", "
184
+ CppAsString2 (RELKIND_INDEX ) ") AND "
185
+ " c.relnamespace = n.oid AND "
171
186
/* exclude possible orphaned temp tables */
172
- " n.nspname !~ '^pg_temp_' AND "
173
- " n.nspname !~ '^pg_toast_temp_' AND "
174
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
187
+ " n.nspname !~ '^pg_temp_' AND "
188
+ " n.nspname !~ '^pg_toast_temp_' AND "
189
+ /* exclude system catalogs, too */
190
+ " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
191
+
192
+ res = executeQueryOrDie (conn , "%s" , querybuf .data );
175
193
176
194
ntups = PQntuples (res );
177
195
i_nspname = PQfnumber (res , "nspname" );
@@ -185,7 +203,7 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
185
203
strerror (errno ));
186
204
if (!db_used )
187
205
{
188
- fprintf (script , "Database : %s\n" , active_db -> db_name );
206
+ fprintf (script , "In database : %s\n" , active_db -> db_name );
189
207
db_used = true;
190
208
}
191
209
fprintf (script , " %s.%s.%s\n" ,
@@ -196,13 +214,36 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
196
214
197
215
PQclear (res );
198
216
217
+ termPQExpBuffer (& querybuf );
218
+
199
219
PQfinish (conn );
200
220
}
201
221
202
222
if (script )
203
223
fclose (script );
204
224
205
- if (found )
225
+ return found ;
226
+ }
227
+
228
+
229
+ /*
230
+ * old_9_3_check_for_line_data_type_usage()
231
+ * 9.3 -> 9.4
232
+ * Fully implement the 'line' data type in 9.4, which previously returned
233
+ * "not enabled" by default and was only functionally enabled with a
234
+ * compile-time switch; as of 9.4 "line" has a different on-disk
235
+ * representation format.
236
+ */
237
+ void
238
+ old_9_3_check_for_line_data_type_usage (ClusterInfo * cluster )
239
+ {
240
+ char output_path [MAXPGPATH ];
241
+
242
+ prep_status ("Checking for incompatible \"line\" data type" );
243
+
244
+ snprintf (output_path , sizeof (output_path ), "tables_using_line.txt" );
245
+
246
+ if (check_for_data_type_usage (cluster , "pg_catalog.line" , output_path ))
206
247
{
207
248
pg_log (PG_REPORT , "fatal\n" );
208
249
pg_fatal ("Your installation contains the \"line\" data type in user tables. This\n"
@@ -229,105 +270,17 @@ old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster)
229
270
* mid-upgrade. Worse, if there's a matview with such a column, the
230
271
* DDL reload will silently change it to "text" which won't match the
231
272
* on-disk storage (which is like "cstring"). So we *must* reject that.
232
- * Also check composite types and domains on the "unknwown" type (even
233
- * combinations of both), in case they are used for table columns.
234
- * We needn't check indexes, because "unknown" has no opclasses.
235
273
*/
236
274
void
237
275
old_9_6_check_for_unknown_data_type_usage (ClusterInfo * cluster )
238
276
{
239
- int dbnum ;
240
- FILE * script = NULL ;
241
- bool found = false;
242
277
char output_path [MAXPGPATH ];
243
278
244
279
prep_status ("Checking for invalid \"unknown\" user columns" );
245
280
246
281
snprintf (output_path , sizeof (output_path ), "tables_using_unknown.txt" );
247
282
248
- for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
249
- {
250
- PGresult * res ;
251
- bool db_used = false;
252
- int ntups ;
253
- int rowno ;
254
- int i_nspname ,
255
- i_relname ,
256
- i_attname ;
257
- DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
258
- PGconn * conn = connectToServer (cluster , active_db -> db_name );
259
-
260
- /*
261
- * The pg_catalog.unknown type may be wrapped in a domain or composite
262
- * type, or both (9.3 did not allow domains on composite types, but
263
- * there may be multi-level composite type). To detect these cases
264
- * we need a recursive CTE.
265
- */
266
- res = executeQueryOrDie (conn ,
267
- "WITH RECURSIVE oids AS ( "
268
- /* the pg_catalog.unknown type itself */
269
- " SELECT 'pg_catalog.unknown'::pg_catalog.regtype AS oid "
270
- " UNION ALL "
271
- " SELECT * FROM ( "
272
- /* domains on the type */
273
- " WITH x AS (SELECT oid FROM oids) "
274
- " SELECT t.oid FROM pg_catalog.pg_type t, x WHERE typbasetype = x.oid AND typtype = 'd' "
275
- " UNION "
276
- /* composite types containing the type */
277
- " SELECT t.oid FROM pg_catalog.pg_type t, pg_catalog.pg_class c, pg_catalog.pg_attribute a, x "
278
- " WHERE t.typtype = 'c' AND "
279
- " t.oid = c.reltype AND "
280
- " c.oid = a.attrelid AND "
281
- " NOT a.attisdropped AND "
282
- " a.atttypid = x.oid "
283
- " ) foo "
284
- ") "
285
- "SELECT n.nspname, c.relname, a.attname "
286
- "FROM pg_catalog.pg_class c, "
287
- " pg_catalog.pg_namespace n, "
288
- " pg_catalog.pg_attribute a "
289
- "WHERE c.oid = a.attrelid AND "
290
- " NOT a.attisdropped AND "
291
- " a.atttypid IN (SELECT oid FROM oids) AND "
292
- " c.relkind IN ("
293
- CppAsString2 (RELKIND_RELATION ) ", "
294
- CppAsString2 (RELKIND_MATVIEW ) ") AND "
295
- " c.relnamespace = n.oid AND "
296
- /* exclude possible orphaned temp tables */
297
- " n.nspname !~ '^pg_temp_' AND "
298
- " n.nspname !~ '^pg_toast_temp_' AND "
299
- " n.nspname NOT IN ('pg_catalog', 'information_schema')" );
300
-
301
- ntups = PQntuples (res );
302
- i_nspname = PQfnumber (res , "nspname" );
303
- i_relname = PQfnumber (res , "relname" );
304
- i_attname = PQfnumber (res , "attname" );
305
- for (rowno = 0 ; rowno < ntups ; rowno ++ )
306
- {
307
- found = true;
308
- if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
309
- pg_fatal ("could not open file \"%s\": %s\n" , output_path ,
310
- strerror (errno ));
311
- if (!db_used )
312
- {
313
- fprintf (script , "Database: %s\n" , active_db -> db_name );
314
- db_used = true;
315
- }
316
- fprintf (script , " %s.%s.%s\n" ,
317
- PQgetvalue (res , rowno , i_nspname ),
318
- PQgetvalue (res , rowno , i_relname ),
319
- PQgetvalue (res , rowno , i_attname ));
320
- }
321
-
322
- PQclear (res );
323
-
324
- PQfinish (conn );
325
- }
326
-
327
- if (script )
328
- fclose (script );
329
-
330
- if (found )
283
+ if (check_for_data_type_usage (cluster , "pg_catalog.unknown" , output_path ))
331
284
{
332
285
pg_log (PG_REPORT , "fatal\n" );
333
286
pg_fatal ("Your installation contains the \"unknown\" data type in user tables. This\n"
0 commit comments