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