@@ -2112,6 +2112,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2112
2112
HeapTuple extTup ;
2113
2113
Datum arrayDatum ;
2114
2114
Datum elementDatum ;
2115
+ int arrayLength ;
2115
2116
int arrayIndex ;
2116
2117
bool isnull ;
2117
2118
Datum repl_val [Natts_pg_extension ];
@@ -2131,8 +2132,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2131
2132
2132
2133
/*
2133
2134
* Check that the table exists and is a member of the extension being
2134
- * created. This ensures that we don't need to registera dependency to
2135
- * protect the extconfig entry.
2135
+ * created. This ensures that we don't need to registeran additional
2136
+ *dependency to protect the extconfig entry.
2136
2137
*/
2137
2138
tablename = get_rel_name (tableoid );
2138
2139
if (tablename == NULL )
@@ -2149,6 +2150,9 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2149
2150
/*
2150
2151
* Add the table OID and WHERE condition to the extension's extconfig and
2151
2152
* extcondition arrays.
2153
+ *
2154
+ * If the table is already in extconfig, treat this as an update of the
2155
+ * WHERE condition.
2152
2156
*/
2153
2157
2154
2158
/* Find the pg_extension tuple */
@@ -2179,18 +2183,41 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2179
2183
RelationGetDescr (extRel ),& isnull );
2180
2184
if (isnull )
2181
2185
{
2186
+ /* Previously empty extconfig, so build 1-element array */
2187
+ arrayLength = 0 ;
2188
+ arrayIndex = 1 ;
2189
+
2182
2190
a = construct_array (& elementDatum ,1 ,
2183
2191
OIDOID ,
2184
2192
sizeof (Oid ), true,'i' );
2185
2193
}
2186
2194
else
2187
2195
{
2196
+ /* Modify or extend existing extconfig array */
2197
+ Oid * arrayData ;
2198
+ int i ;
2199
+
2188
2200
a = DatumGetArrayTypeP (arrayDatum );
2189
- Assert (ARR_ELEMTYPE (a )== OIDOID );
2190
- Assert (ARR_NDIM (a )== 1 );
2191
- Assert (ARR_LBOUND (a )[0 ]== 1 );
2192
2201
2193
- arrayIndex = ARR_DIMS (a )[0 ]+ 1 ;/* add after end */
2202
+ arrayLength = ARR_DIMS (a )[0 ];
2203
+ if (ARR_NDIM (a )!= 1 ||
2204
+ ARR_LBOUND (a )[0 ]!= 1 ||
2205
+ arrayLength < 0 ||
2206
+ ARR_HASNULL (a )||
2207
+ ARR_ELEMTYPE (a )!= OIDOID )
2208
+ elog (ERROR ,"extconfig is not a 1-D Oid array" );
2209
+ arrayData = (Oid * )ARR_DATA_PTR (a );
2210
+
2211
+ arrayIndex = arrayLength + 1 ;/* set up to add after end */
2212
+
2213
+ for (i = 0 ;i < arrayLength ;i ++ )
2214
+ {
2215
+ if (arrayData [i ]== tableoid )
2216
+ {
2217
+ arrayIndex = i + 1 ;/* replace this element instead */
2218
+ break ;
2219
+ }
2220
+ }
2194
2221
2195
2222
a = array_set (a ,1 ,& arrayIndex ,
2196
2223
elementDatum ,
@@ -2210,19 +2237,26 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2210
2237
RelationGetDescr (extRel ),& isnull );
2211
2238
if (isnull )
2212
2239
{
2240
+ if (arrayLength != 0 )
2241
+ elog (ERROR ,"extconfig and extcondition arrays do not match" );
2242
+
2213
2243
a = construct_array (& elementDatum ,1 ,
2214
2244
TEXTOID ,
2215
2245
-1 , false,'i' );
2216
2246
}
2217
2247
else
2218
2248
{
2219
2249
a = DatumGetArrayTypeP (arrayDatum );
2220
- Assert (ARR_ELEMTYPE (a )== TEXTOID );
2221
- Assert (ARR_NDIM (a )== 1 );
2222
- Assert (ARR_LBOUND (a )[0 ]== 1 );
2223
2250
2224
- arrayIndex = ARR_DIMS (a )[0 ]+ 1 ;/* add after end */
2251
+ if (ARR_NDIM (a )!= 1 ||
2252
+ ARR_LBOUND (a )[0 ]!= 1 ||
2253
+ ARR_HASNULL (a )||
2254
+ ARR_ELEMTYPE (a )!= TEXTOID )
2255
+ elog (ERROR ,"extcondition is not a 1-D text array" );
2256
+ if (ARR_DIMS (a )[0 ]!= arrayLength )
2257
+ elog (ERROR ,"extconfig and extcondition arrays do not match" );
2225
2258
2259
+ /* Add or replace at same index as in extconfig */
2226
2260
a = array_set (a ,1 ,& arrayIndex ,
2227
2261
elementDatum ,
2228
2262
false,
@@ -2247,6 +2281,182 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2247
2281
PG_RETURN_VOID ();
2248
2282
}
2249
2283
2284
+ /*
2285
+ * extension_config_remove
2286
+ *
2287
+ * Remove the specified table OID from extension's extconfig, if present.
2288
+ * This is not currently exposed as a function, but it could be;
2289
+ * for now, we just invoke it from ALTER EXTENSION DROP.
2290
+ */
2291
+ static void
2292
+ extension_config_remove (Oid extensionoid ,Oid tableoid )
2293
+ {
2294
+ Relation extRel ;
2295
+ ScanKeyData key [1 ];
2296
+ SysScanDesc extScan ;
2297
+ HeapTuple extTup ;
2298
+ Datum arrayDatum ;
2299
+ int arrayLength ;
2300
+ int arrayIndex ;
2301
+ bool isnull ;
2302
+ Datum repl_val [Natts_pg_extension ];
2303
+ bool repl_null [Natts_pg_extension ];
2304
+ bool repl_repl [Natts_pg_extension ];
2305
+ ArrayType * a ;
2306
+
2307
+ /* Find the pg_extension tuple */
2308
+ extRel = heap_open (ExtensionRelationId ,RowExclusiveLock );
2309
+
2310
+ ScanKeyInit (& key [0 ],
2311
+ ObjectIdAttributeNumber ,
2312
+ BTEqualStrategyNumber ,F_OIDEQ ,
2313
+ ObjectIdGetDatum (extensionoid ));
2314
+
2315
+ extScan = systable_beginscan (extRel ,ExtensionOidIndexId , true,
2316
+ SnapshotNow ,1 ,key );
2317
+
2318
+ extTup = systable_getnext (extScan );
2319
+
2320
+ if (!HeapTupleIsValid (extTup ))/* should not happen */
2321
+ elog (ERROR ,"extension with oid %u does not exist" ,
2322
+ extensionoid );
2323
+
2324
+ /* Search extconfig for the tableoid */
2325
+ arrayDatum = heap_getattr (extTup ,Anum_pg_extension_extconfig ,
2326
+ RelationGetDescr (extRel ),& isnull );
2327
+ if (isnull )
2328
+ {
2329
+ /* nothing to do */
2330
+ a = NULL ;
2331
+ arrayLength = 0 ;
2332
+ arrayIndex = -1 ;
2333
+ }
2334
+ else
2335
+ {
2336
+ Oid * arrayData ;
2337
+ int i ;
2338
+
2339
+ a = DatumGetArrayTypeP (arrayDatum );
2340
+
2341
+ arrayLength = ARR_DIMS (a )[0 ];
2342
+ if (ARR_NDIM (a )!= 1 ||
2343
+ ARR_LBOUND (a )[0 ]!= 1 ||
2344
+ arrayLength < 0 ||
2345
+ ARR_HASNULL (a )||
2346
+ ARR_ELEMTYPE (a )!= OIDOID )
2347
+ elog (ERROR ,"extconfig is not a 1-D Oid array" );
2348
+ arrayData = (Oid * )ARR_DATA_PTR (a );
2349
+
2350
+ arrayIndex = -1 ;/* flag for no deletion needed */
2351
+
2352
+ for (i = 0 ;i < arrayLength ;i ++ )
2353
+ {
2354
+ if (arrayData [i ]== tableoid )
2355
+ {
2356
+ arrayIndex = i ;/* index to remove */
2357
+ break ;
2358
+ }
2359
+ }
2360
+ }
2361
+
2362
+ /* If tableoid is not in extconfig, nothing to do */
2363
+ if (arrayIndex < 0 )
2364
+ {
2365
+ systable_endscan (extScan );
2366
+ heap_close (extRel ,RowExclusiveLock );
2367
+ return ;
2368
+ }
2369
+
2370
+ /* Modify or delete the extconfig value */
2371
+ memset (repl_val ,0 ,sizeof (repl_val ));
2372
+ memset (repl_null , false,sizeof (repl_null ));
2373
+ memset (repl_repl , false,sizeof (repl_repl ));
2374
+
2375
+ if (arrayLength <=1 )
2376
+ {
2377
+ /* removing only element, just set array to null */
2378
+ repl_null [Anum_pg_extension_extconfig - 1 ]= true;
2379
+ }
2380
+ else
2381
+ {
2382
+ /* squeeze out the target element */
2383
+ Datum * dvalues ;
2384
+ bool * dnulls ;
2385
+ int nelems ;
2386
+ int i ;
2387
+
2388
+ deconstruct_array (a ,OIDOID ,sizeof (Oid ), true,'i' ,
2389
+ & dvalues ,& dnulls ,& nelems );
2390
+
2391
+ /* We already checked there are no nulls, so ignore dnulls */
2392
+ for (i = arrayIndex ;i < arrayLength - 1 ;i ++ )
2393
+ dvalues [i ]= dvalues [i + 1 ];
2394
+
2395
+ a = construct_array (dvalues ,arrayLength - 1 ,
2396
+ OIDOID ,sizeof (Oid ), true,'i' );
2397
+
2398
+ repl_val [Anum_pg_extension_extconfig - 1 ]= PointerGetDatum (a );
2399
+ }
2400
+ repl_repl [Anum_pg_extension_extconfig - 1 ]= true;
2401
+
2402
+ /* Modify or delete the extcondition value */
2403
+ arrayDatum = heap_getattr (extTup ,Anum_pg_extension_extcondition ,
2404
+ RelationGetDescr (extRel ),& isnull );
2405
+ if (isnull )
2406
+ {
2407
+ elog (ERROR ,"extconfig and extcondition arrays do not match" );
2408
+ }
2409
+ else
2410
+ {
2411
+ a = DatumGetArrayTypeP (arrayDatum );
2412
+
2413
+ if (ARR_NDIM (a )!= 1 ||
2414
+ ARR_LBOUND (a )[0 ]!= 1 ||
2415
+ ARR_HASNULL (a )||
2416
+ ARR_ELEMTYPE (a )!= TEXTOID )
2417
+ elog (ERROR ,"extcondition is not a 1-D text array" );
2418
+ if (ARR_DIMS (a )[0 ]!= arrayLength )
2419
+ elog (ERROR ,"extconfig and extcondition arrays do not match" );
2420
+ }
2421
+
2422
+ if (arrayLength <=1 )
2423
+ {
2424
+ /* removing only element, just set array to null */
2425
+ repl_null [Anum_pg_extension_extcondition - 1 ]= true;
2426
+ }
2427
+ else
2428
+ {
2429
+ /* squeeze out the target element */
2430
+ Datum * dvalues ;
2431
+ bool * dnulls ;
2432
+ int nelems ;
2433
+ int i ;
2434
+
2435
+ deconstruct_array (a ,TEXTOID ,-1 , false,'i' ,
2436
+ & dvalues ,& dnulls ,& nelems );
2437
+
2438
+ /* We already checked there are no nulls, so ignore dnulls */
2439
+ for (i = arrayIndex ;i < arrayLength - 1 ;i ++ )
2440
+ dvalues [i ]= dvalues [i + 1 ];
2441
+
2442
+ a = construct_array (dvalues ,arrayLength - 1 ,
2443
+ TEXTOID ,-1 , false,'i' );
2444
+
2445
+ repl_val [Anum_pg_extension_extcondition - 1 ]= PointerGetDatum (a );
2446
+ }
2447
+ repl_repl [Anum_pg_extension_extcondition - 1 ]= true;
2448
+
2449
+ extTup = heap_modify_tuple (extTup ,RelationGetDescr (extRel ),
2450
+ repl_val ,repl_null ,repl_repl );
2451
+
2452
+ simple_heap_update (extRel ,& extTup -> t_self ,extTup );
2453
+ CatalogUpdateIndexes (extRel ,extTup );
2454
+
2455
+ systable_endscan (extScan );
2456
+
2457
+ heap_close (extRel ,RowExclusiveLock );
2458
+ }
2459
+
2250
2460
/*
2251
2461
* Execute ALTER EXTENSION SET SCHEMA
2252
2462
*/
@@ -2807,6 +3017,13 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
2807
3017
ExtensionRelationId ,
2808
3018
DEPENDENCY_EXTENSION )!= 1 )
2809
3019
elog (ERROR ,"unexpected number of extension dependency records" );
3020
+
3021
+ /*
3022
+ * If it's a relation, it might have an entry in the extension's
3023
+ * extconfig array, which we must remove.
3024
+ */
3025
+ if (object .classId == RelationRelationId )
3026
+ extension_config_remove (extension .objectId ,object .objectId );
2810
3027
}
2811
3028
2812
3029
/*