@@ -2047,6 +2047,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2047
2047
HeapTuple extTup ;
2048
2048
Datum arrayDatum ;
2049
2049
Datum elementDatum ;
2050
+ int arrayLength ;
2050
2051
int arrayIndex ;
2051
2052
bool isnull ;
2052
2053
Datum repl_val [Natts_pg_extension ];
@@ -2066,8 +2067,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2066
2067
2067
2068
/*
2068
2069
* Check that the table exists and is a member of the extension being
2069
- * created. This ensures that we don't need to register a dependency to
2070
- * protect the extconfig entry.
2070
+ * created. This ensures that we don't need to register an additional
2071
+ * dependency to protect the extconfig entry.
2071
2072
*/
2072
2073
tablename = get_rel_name (tableoid );
2073
2074
if (tablename == NULL )
@@ -2084,6 +2085,9 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2084
2085
/*
2085
2086
* Add the table OID and WHERE condition to the extension's extconfig and
2086
2087
* extcondition arrays.
2088
+ *
2089
+ * If the table is already in extconfig, treat this as an update of the
2090
+ * WHERE condition.
2087
2091
*/
2088
2092
2089
2093
/* Find the pg_extension tuple */
@@ -2114,18 +2118,41 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2114
2118
RelationGetDescr (extRel ), & isnull );
2115
2119
if (isnull )
2116
2120
{
2121
+ /* Previously empty extconfig, so build 1-element array */
2122
+ arrayLength = 0 ;
2123
+ arrayIndex = 1 ;
2124
+
2117
2125
a = construct_array (& elementDatum , 1 ,
2118
2126
OIDOID ,
2119
2127
sizeof (Oid ), true, 'i' );
2120
2128
}
2121
2129
else
2122
2130
{
2131
+ /* Modify or extend existing extconfig array */
2132
+ Oid * arrayData ;
2133
+ int i ;
2134
+
2123
2135
a = DatumGetArrayTypeP (arrayDatum );
2124
- Assert (ARR_ELEMTYPE (a ) == OIDOID );
2125
- Assert (ARR_NDIM (a ) == 1 );
2126
- Assert (ARR_LBOUND (a )[0 ] == 1 );
2127
2136
2128
- arrayIndex = ARR_DIMS (a )[0 ] + 1 ; /* add after end */
2137
+ arrayLength = ARR_DIMS (a )[0 ];
2138
+ if (ARR_NDIM (a ) != 1 ||
2139
+ ARR_LBOUND (a )[0 ] != 1 ||
2140
+ arrayLength < 0 ||
2141
+ ARR_HASNULL (a ) ||
2142
+ ARR_ELEMTYPE (a ) != OIDOID )
2143
+ elog (ERROR , "extconfig is not a 1-D Oid array" );
2144
+ arrayData = (Oid * ) ARR_DATA_PTR (a );
2145
+
2146
+ arrayIndex = arrayLength + 1 ; /* set up to add after end */
2147
+
2148
+ for (i = 0 ; i < arrayLength ; i ++ )
2149
+ {
2150
+ if (arrayData [i ] == tableoid )
2151
+ {
2152
+ arrayIndex = i + 1 ; /* replace this element instead */
2153
+ break ;
2154
+ }
2155
+ }
2129
2156
2130
2157
a = array_set (a , 1 , & arrayIndex ,
2131
2158
elementDatum ,
@@ -2145,19 +2172,26 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2145
2172
RelationGetDescr (extRel ), & isnull );
2146
2173
if (isnull )
2147
2174
{
2175
+ if (arrayLength != 0 )
2176
+ elog (ERROR , "extconfig and extcondition arrays do not match" );
2177
+
2148
2178
a = construct_array (& elementDatum , 1 ,
2149
2179
TEXTOID ,
2150
2180
-1 , false, 'i' );
2151
2181
}
2152
2182
else
2153
2183
{
2154
2184
a = DatumGetArrayTypeP (arrayDatum );
2155
- Assert (ARR_ELEMTYPE (a ) == TEXTOID );
2156
- Assert (ARR_NDIM (a ) == 1 );
2157
- Assert (ARR_LBOUND (a )[0 ] == 1 );
2158
2185
2159
- arrayIndex = ARR_DIMS (a )[0 ] + 1 ; /* add after end */
2186
+ if (ARR_NDIM (a ) != 1 ||
2187
+ ARR_LBOUND (a )[0 ] != 1 ||
2188
+ ARR_HASNULL (a ) ||
2189
+ ARR_ELEMTYPE (a ) != TEXTOID )
2190
+ elog (ERROR , "extcondition is not a 1-D text array" );
2191
+ if (ARR_DIMS (a )[0 ] != arrayLength )
2192
+ elog (ERROR , "extconfig and extcondition arrays do not match" );
2160
2193
2194
+ /* Add or replace at same index as in extconfig */
2161
2195
a = array_set (a , 1 , & arrayIndex ,
2162
2196
elementDatum ,
2163
2197
false,
@@ -2182,6 +2216,182 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
2182
2216
PG_RETURN_VOID ();
2183
2217
}
2184
2218
2219
+ /*
2220
+ * extension_config_remove
2221
+ *
2222
+ * Remove the specified table OID from extension's extconfig, if present.
2223
+ * This is not currently exposed as a function, but it could be;
2224
+ * for now, we just invoke it from ALTER EXTENSION DROP.
2225
+ */
2226
+ static void
2227
+ extension_config_remove (Oid extensionoid , Oid tableoid )
2228
+ {
2229
+ Relation extRel ;
2230
+ ScanKeyData key [1 ];
2231
+ SysScanDesc extScan ;
2232
+ HeapTuple extTup ;
2233
+ Datum arrayDatum ;
2234
+ int arrayLength ;
2235
+ int arrayIndex ;
2236
+ bool isnull ;
2237
+ Datum repl_val [Natts_pg_extension ];
2238
+ bool repl_null [Natts_pg_extension ];
2239
+ bool repl_repl [Natts_pg_extension ];
2240
+ ArrayType * a ;
2241
+
2242
+ /* Find the pg_extension tuple */
2243
+ extRel = heap_open (ExtensionRelationId , RowExclusiveLock );
2244
+
2245
+ ScanKeyInit (& key [0 ],
2246
+ ObjectIdAttributeNumber ,
2247
+ BTEqualStrategyNumber , F_OIDEQ ,
2248
+ ObjectIdGetDatum (extensionoid ));
2249
+
2250
+ extScan = systable_beginscan (extRel , ExtensionOidIndexId , true,
2251
+ SnapshotNow , 1 , key );
2252
+
2253
+ extTup = systable_getnext (extScan );
2254
+
2255
+ if (!HeapTupleIsValid (extTup )) /* should not happen */
2256
+ elog (ERROR , "extension with oid %u does not exist" ,
2257
+ extensionoid );
2258
+
2259
+ /* Search extconfig for the tableoid */
2260
+ arrayDatum = heap_getattr (extTup , Anum_pg_extension_extconfig ,
2261
+ RelationGetDescr (extRel ), & isnull );
2262
+ if (isnull )
2263
+ {
2264
+ /* nothing to do */
2265
+ a = NULL ;
2266
+ arrayLength = 0 ;
2267
+ arrayIndex = -1 ;
2268
+ }
2269
+ else
2270
+ {
2271
+ Oid * arrayData ;
2272
+ int i ;
2273
+
2274
+ a = DatumGetArrayTypeP (arrayDatum );
2275
+
2276
+ arrayLength = ARR_DIMS (a )[0 ];
2277
+ if (ARR_NDIM (a ) != 1 ||
2278
+ ARR_LBOUND (a )[0 ] != 1 ||
2279
+ arrayLength < 0 ||
2280
+ ARR_HASNULL (a ) ||
2281
+ ARR_ELEMTYPE (a ) != OIDOID )
2282
+ elog (ERROR , "extconfig is not a 1-D Oid array" );
2283
+ arrayData = (Oid * ) ARR_DATA_PTR (a );
2284
+
2285
+ arrayIndex = -1 ; /* flag for no deletion needed */
2286
+
2287
+ for (i = 0 ; i < arrayLength ; i ++ )
2288
+ {
2289
+ if (arrayData [i ] == tableoid )
2290
+ {
2291
+ arrayIndex = i ; /* index to remove */
2292
+ break ;
2293
+ }
2294
+ }
2295
+ }
2296
+
2297
+ /* If tableoid is not in extconfig, nothing to do */
2298
+ if (arrayIndex < 0 )
2299
+ {
2300
+ systable_endscan (extScan );
2301
+ heap_close (extRel , RowExclusiveLock );
2302
+ return ;
2303
+ }
2304
+
2305
+ /* Modify or delete the extconfig value */
2306
+ memset (repl_val , 0 , sizeof (repl_val ));
2307
+ memset (repl_null , false, sizeof (repl_null ));
2308
+ memset (repl_repl , false, sizeof (repl_repl ));
2309
+
2310
+ if (arrayLength <= 1 )
2311
+ {
2312
+ /* removing only element, just set array to null */
2313
+ repl_null [Anum_pg_extension_extconfig - 1 ] = true;
2314
+ }
2315
+ else
2316
+ {
2317
+ /* squeeze out the target element */
2318
+ Datum * dvalues ;
2319
+ bool * dnulls ;
2320
+ int nelems ;
2321
+ int i ;
2322
+
2323
+ deconstruct_array (a , OIDOID , sizeof (Oid ), true, 'i' ,
2324
+ & dvalues , & dnulls , & nelems );
2325
+
2326
+ /* We already checked there are no nulls, so ignore dnulls */
2327
+ for (i = arrayIndex ; i < arrayLength - 1 ; i ++ )
2328
+ dvalues [i ] = dvalues [i + 1 ];
2329
+
2330
+ a = construct_array (dvalues , arrayLength - 1 ,
2331
+ OIDOID , sizeof (Oid ), true, 'i' );
2332
+
2333
+ repl_val [Anum_pg_extension_extconfig - 1 ] = PointerGetDatum (a );
2334
+ }
2335
+ repl_repl [Anum_pg_extension_extconfig - 1 ] = true;
2336
+
2337
+ /* Modify or delete the extcondition value */
2338
+ arrayDatum = heap_getattr (extTup , Anum_pg_extension_extcondition ,
2339
+ RelationGetDescr (extRel ), & isnull );
2340
+ if (isnull )
2341
+ {
2342
+ elog (ERROR , "extconfig and extcondition arrays do not match" );
2343
+ }
2344
+ else
2345
+ {
2346
+ a = DatumGetArrayTypeP (arrayDatum );
2347
+
2348
+ if (ARR_NDIM (a ) != 1 ||
2349
+ ARR_LBOUND (a )[0 ] != 1 ||
2350
+ ARR_HASNULL (a ) ||
2351
+ ARR_ELEMTYPE (a ) != TEXTOID )
2352
+ elog (ERROR , "extcondition is not a 1-D text array" );
2353
+ if (ARR_DIMS (a )[0 ] != arrayLength )
2354
+ elog (ERROR , "extconfig and extcondition arrays do not match" );
2355
+ }
2356
+
2357
+ if (arrayLength <= 1 )
2358
+ {
2359
+ /* removing only element, just set array to null */
2360
+ repl_null [Anum_pg_extension_extcondition - 1 ] = true;
2361
+ }
2362
+ else
2363
+ {
2364
+ /* squeeze out the target element */
2365
+ Datum * dvalues ;
2366
+ bool * dnulls ;
2367
+ int nelems ;
2368
+ int i ;
2369
+
2370
+ deconstruct_array (a , TEXTOID , -1 , false, 'i' ,
2371
+ & dvalues , & dnulls , & nelems );
2372
+
2373
+ /* We already checked there are no nulls, so ignore dnulls */
2374
+ for (i = arrayIndex ; i < arrayLength - 1 ; i ++ )
2375
+ dvalues [i ] = dvalues [i + 1 ];
2376
+
2377
+ a = construct_array (dvalues , arrayLength - 1 ,
2378
+ TEXTOID , -1 , false, 'i' );
2379
+
2380
+ repl_val [Anum_pg_extension_extcondition - 1 ] = PointerGetDatum (a );
2381
+ }
2382
+ repl_repl [Anum_pg_extension_extcondition - 1 ] = true;
2383
+
2384
+ extTup = heap_modify_tuple (extTup , RelationGetDescr (extRel ),
2385
+ repl_val , repl_null , repl_repl );
2386
+
2387
+ simple_heap_update (extRel , & extTup -> t_self , extTup );
2388
+ CatalogUpdateIndexes (extRel , extTup );
2389
+
2390
+ systable_endscan (extScan );
2391
+
2392
+ heap_close (extRel , RowExclusiveLock );
2393
+ }
2394
+
2185
2395
/*
2186
2396
* Execute ALTER EXTENSION SET SCHEMA
2187
2397
*/
@@ -2742,6 +2952,13 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
2742
2952
ExtensionRelationId ,
2743
2953
DEPENDENCY_EXTENSION ) != 1 )
2744
2954
elog (ERROR , "unexpected number of extension dependency records" );
2955
+
2956
+ /*
2957
+ * If it's a relation, it might have an entry in the extension's
2958
+ * extconfig array, which we must remove.
2959
+ */
2960
+ if (object .classId == RelationRelationId )
2961
+ extension_config_remove (extension .objectId , object .objectId );
2745
2962
}
2746
2963
2747
2964
/*
0 commit comments