@@ -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
- * Thepg_catalog.line typemay be wrapped in a domain or composite
136
- *type , orboth (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 typeof interest might be wrapped in a domain, array,
134
+ *composite , orrange, 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
- "FROMpg_catalog.pg_class c, "
161
- "pg_catalog.pg_namespace n, "
162
- "pg_catalog.pg_attribute a "
163
- "WHEREc.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
+ "FROMpg_catalog.pg_class c, "
176
+ "pg_catalog.pg_namespace n, "
177
+ "pg_catalog.pg_attribute a "
178
+ "WHEREc.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
- "FROMpg_catalog.pg_class c, "
287
- "pg_catalog.pg_namespace n, "
288
- "pg_catalog.pg_attribute a "
289
- "WHEREc.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"