7777/* The main type cache hashtable searched by lookup_type_cache */
7878static HTAB * TypeCacheHash = NULL ;
7979
80- /*
81- * The mapping of relation's OID to the corresponding composite type OID.
82- * We're keeping the map entry when the corresponding typentry has something
83- * to clear i.e it has either TCFLAGS_HAVE_PG_TYPE_DATA, or
84- * TCFLAGS_OPERATOR_FLAGS, or tupdesc.
85- */
86- static HTAB * RelIdToTypeIdCacheHash = NULL ;
87-
88- typedef struct RelIdToTypeIdCacheEntry
89- {
90- Oid relid ;/* OID of the relation */
91- Oid composite_typid ;/* OID of the relation's composite type */
92- }RelIdToTypeIdCacheEntry ;
93-
9480/* List of type cache entries for domain types */
9581static TypeCacheEntry * firstDomainTypeEntry = NULL ;
9682
@@ -343,8 +329,6 @@ static void shared_record_typmod_registry_detach(dsm_segment *segment,
343329static TupleDesc find_or_make_matching_shared_tupledesc (TupleDesc tupdesc );
344330static dsa_pointer share_tupledesc (dsa_area * area ,TupleDesc tupdesc ,
345331uint32 typmod );
346- static void insert_rel_type_cache_if_needed (TypeCacheEntry * typentry );
347- static void delete_rel_type_cache_if_needed (TypeCacheEntry * typentry );
348332
349333
350334/*
@@ -392,13 +376,6 @@ lookup_type_cache(Oid type_id, int flags)
392376TypeCacheHash = hash_create ("Type information cache" ,64 ,
393377& ctl ,HASH_ELEM |HASH_FUNCTION );
394378
395- Assert (RelIdToTypeIdCacheHash == NULL );
396-
397- ctl .keysize = sizeof (Oid );
398- ctl .entrysize = sizeof (RelIdToTypeIdCacheEntry );
399- RelIdToTypeIdCacheHash = hash_create ("Map from relid to OID of cached composite type" ,64 ,
400- & ctl ,HASH_ELEM |HASH_BLOBS );
401-
402379/* Also set up callbacks for SI invalidations */
403380CacheRegisterRelcacheCallback (TypeCacheRelCallback , (Datum )0 );
404381CacheRegisterSyscacheCallback (TYPEOID ,TypeCacheTypCallback , (Datum )0 );
@@ -410,8 +387,6 @@ lookup_type_cache(Oid type_id, int flags)
410387CreateCacheMemoryContext ();
411388}
412389
413- Assert (TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL );
414-
415390/* Try to look up an existing entry */
416391typentry = (TypeCacheEntry * )hash_search (TypeCacheHash ,
417392& type_id ,
@@ -463,7 +438,6 @@ lookup_type_cache(Oid type_id, int flags)
463438typentry -> typelem = typtup -> typelem ;
464439typentry -> typcollation = typtup -> typcollation ;
465440typentry -> flags |=TCFLAGS_HAVE_PG_TYPE_DATA ;
466- insert_rel_type_cache_if_needed (typentry );
467441
468442/* If it's a domain, immediately thread it into the domain cache list */
469443if (typentry -> typtype == TYPTYPE_DOMAIN )
@@ -509,7 +483,6 @@ lookup_type_cache(Oid type_id, int flags)
509483typentry -> typelem = typtup -> typelem ;
510484typentry -> typcollation = typtup -> typcollation ;
511485typentry -> flags |=TCFLAGS_HAVE_PG_TYPE_DATA ;
512- insert_rel_type_cache_if_needed (typentry );
513486
514487ReleaseSysCache (tp );
515488}
@@ -2308,53 +2281,6 @@ SharedRecordTypmodRegistryAttach(SharedRecordTypmodRegistry *registry)
23082281CurrentSession -> shared_typmod_table = typmod_table ;
23092282}
23102283
2311- /*
2312- * InvalidateCompositeTypeCacheEntry
2313- *Invalidate particular TypeCacheEntry on Relcache inval callback
2314- *
2315- * Delete the cached tuple descriptor (if any) for the given composite
2316- * type, and reset whatever info we have cached about the composite type's
2317- * comparability.
2318- */
2319- static void
2320- InvalidateCompositeTypeCacheEntry (TypeCacheEntry * typentry )
2321- {
2322- bool hadTupDescOrOpclass ;
2323-
2324- Assert (typentry -> typtype == TYPTYPE_COMPOSITE &&
2325- OidIsValid (typentry -> typrelid ));
2326-
2327- hadTupDescOrOpclass = (typentry -> tupDesc != NULL )||
2328- (typentry -> flags & TCFLAGS_OPERATOR_FLAGS );
2329-
2330- /* Delete tupdesc if we have it */
2331- if (typentry -> tupDesc != NULL )
2332- {
2333- /*
2334- * Release our refcount and free the tupdesc if none remain. We can't
2335- * use DecrTupleDescRefCount here because this reference is not logged
2336- * by the current resource owner.
2337- */
2338- Assert (typentry -> tupDesc -> tdrefcount > 0 );
2339- if (-- typentry -> tupDesc -> tdrefcount == 0 )
2340- FreeTupleDesc (typentry -> tupDesc );
2341- typentry -> tupDesc = NULL ;
2342-
2343- /*
2344- * Also clear tupDesc_identifier, so that anyone watching it will
2345- * realize that the tupdesc has changed.
2346- */
2347- typentry -> tupDesc_identifier = 0 ;
2348- }
2349-
2350- /* Reset equality/comparison/hashing validity information */
2351- typentry -> flags &= ~TCFLAGS_OPERATOR_FLAGS ;
2352-
2353- /* Call check_delete_rel_type_cache() if we actually cleared something */
2354- if (hadTupDescOrOpclass )
2355- delete_rel_type_cache_if_needed (typentry );
2356- }
2357-
23582284/*
23592285 * TypeCacheRelCallback
23602286 *Relcache inval callback function
@@ -2364,55 +2290,63 @@ InvalidateCompositeTypeCacheEntry(TypeCacheEntry *typentry)
23642290 * whatever info we have cached about the composite type's comparability.
23652291 *
23662292 * This is called when a relcache invalidation event occurs for the given
2367- * relid. We can't use syscache to find a type corresponding to the given
2368- * relation because the code can be called outside of transaction. Thus we use
2369- * the RelIdToTypeIdCacheHash map to locate appropriate typcache entry.
2293+ * relid. We must scan the whole typcache hash since we don't know the
2294+ * type OID corresponding to the relid. We could do a direct search if this
2295+ * were a syscache-flush callback on pg_type, but then we would need all
2296+ * ALTER-TABLE-like commands that could modify a rowtype to issue syscache
2297+ * invals against the rel's pg_type OID. The extra SI signaling could very
2298+ * well cost more than we'd save, since in most usages there are not very
2299+ * many entries in a backend's typcache. The risk of bugs-of-omission seems
2300+ * high, too.
2301+ *
2302+ * Another possibility, with only localized impact, is to maintain a second
2303+ * hashtable that indexes composite-type typcache entries by their typrelid.
2304+ * But it's still not clear it's worth the trouble.
23702305 */
23712306static void
23722307TypeCacheRelCallback (Datum arg ,Oid relid )
23732308{
2309+ HASH_SEQ_STATUS status ;
23742310TypeCacheEntry * typentry ;
23752311
2376- /*
2377- * RelIdToTypeIdCacheHash and TypeCacheHash should exist, otherwise this
2378- * callback wouldn't be registered
2379- */
2380- if (OidIsValid (relid ))
2312+ /* TypeCacheHash must exist, else this callback wouldn't be registered */
2313+ hash_seq_init (& status ,TypeCacheHash );
2314+ while ((typentry = (TypeCacheEntry * )hash_seq_search (& status ))!= NULL )
23812315{
2382- RelIdToTypeIdCacheEntry * relentry ;
2383-
2384- /*
2385- * Find an RelIdToTypeIdCacheHash entry, which should exist as soon as
2386- * corresponding typcache entry has something to clean.
2387- */
2388- relentry = (RelIdToTypeIdCacheEntry * )hash_search (RelIdToTypeIdCacheHash ,
2389- & relid ,
2390- HASH_FIND ,NULL );
2391-
2392- if (relentry != NULL )
2316+ if (typentry -> typtype == TYPTYPE_COMPOSITE )
23932317{
2394- typentry = ( TypeCacheEntry * ) hash_search ( TypeCacheHash ,
2395- & relentry -> composite_typid ,
2396- HASH_FIND , NULL ) ;
2318+ /* Skip if no match, unless we're zapping all composite types */
2319+ if ( relid != typentry -> typrelid && relid != InvalidOid )
2320+ continue ;
23972321
2398- if (typentry != NULL )
2322+ /* Delete tupdesc if we have it */
2323+ if (typentry -> tupDesc != NULL )
23992324{
2400- Assert (typentry -> typtype == TYPTYPE_COMPOSITE );
2401- Assert (relid == typentry -> typrelid );
2325+ /*
2326+ * Release our refcount, and free the tupdesc if none remain.
2327+ * (Can't use DecrTupleDescRefCount because this reference is
2328+ * not logged in current resource owner.)
2329+ */
2330+ Assert (typentry -> tupDesc -> tdrefcount > 0 );
2331+ if (-- typentry -> tupDesc -> tdrefcount == 0 )
2332+ FreeTupleDesc (typentry -> tupDesc );
2333+ typentry -> tupDesc = NULL ;
24022334
2403- InvalidateCompositeTypeCacheEntry (typentry );
2335+ /*
2336+ * Also clear tupDesc_identifier, so that anything watching
2337+ * that will realize that the tupdesc has possibly changed.
2338+ * (Alternatively, we could specify that to detect possible
2339+ * tupdesc change, one must check for tupDesc != NULL as well
2340+ * as tupDesc_identifier being the same as what was previously
2341+ * seen. That seems error-prone.)
2342+ */
2343+ typentry -> tupDesc_identifier = 0 ;
24042344}
2405- }
24062345
2407- /*
2408- * Visit all the domain types sequentially. Typically this shouldn't
2409- * affect performance since domain types are less tended to bloat.
2410- * Domain types are created manually, unlike composite types which are
2411- * automatically created for every temporary table.
2412- */
2413- for (typentry = firstDomainTypeEntry ;
2414- typentry != NULL ;
2415- typentry = typentry -> nextDomain )
2346+ /* Reset equality/comparison/hashing validity information */
2347+ typentry -> flags &= ~TCFLAGS_OPERATOR_FLAGS ;
2348+ }
2349+ else if (typentry -> typtype == TYPTYPE_DOMAIN )
24162350{
24172351/*
24182352 * If it's domain over composite, reset flags. (We don't bother
@@ -2424,36 +2358,6 @@ TypeCacheRelCallback(Datum arg, Oid relid)
24242358typentry -> flags &= ~TCFLAGS_OPERATOR_FLAGS ;
24252359}
24262360}
2427- else
2428- {
2429- HASH_SEQ_STATUS status ;
2430-
2431- /*
2432- * Relid is invalid. By convention we need to reset all composite
2433- * types in cache. Also, we should reset flags for domain types, and
2434- * we loop over all entries in hash, so, do it in a single scan.
2435- */
2436- hash_seq_init (& status ,TypeCacheHash );
2437- while ((typentry = (TypeCacheEntry * )hash_seq_search (& status ))!= NULL )
2438- {
2439- if (typentry -> typtype == TYPTYPE_COMPOSITE )
2440- {
2441- InvalidateCompositeTypeCacheEntry (typentry );
2442- }
2443- else if (typentry -> typtype == TYPTYPE_DOMAIN )
2444- {
2445- /*
2446- * If it's domain over composite, reset flags. (We don't
2447- * bother trying to determine whether the specific base type
2448- * needs a reset.) Note that if we haven't determined whether
2449- * the base type is composite, we don't need to reset
2450- * anything.
2451- */
2452- if (typentry -> flags & TCFLAGS_DOMAIN_BASE_IS_COMPOSITE )
2453- typentry -> flags &= ~TCFLAGS_OPERATOR_FLAGS ;
2454- }
2455- }
2456- }
24572361}
24582362
24592363/*
@@ -2484,8 +2388,6 @@ TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
24842388
24852389while ((typentry = (TypeCacheEntry * )hash_seq_search (& status ))!= NULL )
24862390{
2487- bool hadPgTypeData = (typentry -> flags & TCFLAGS_HAVE_PG_TYPE_DATA );
2488-
24892391Assert (hashvalue == 0 || typentry -> type_id_hash == hashvalue );
24902392
24912393/*
@@ -2495,13 +2397,6 @@ TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
24952397 */
24962398typentry -> flags &= ~(TCFLAGS_HAVE_PG_TYPE_DATA |
24972399TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS );
2498-
2499- /*
2500- * Call check_delete_rel_type_cache() if we cleaned
2501- * TCFLAGS_HAVE_PG_TYPE_DATA flag previously.
2502- */
2503- if (hadPgTypeData )
2504- delete_rel_type_cache_if_needed (typentry );
25052400}
25062401}
25072402
@@ -3010,85 +2905,3 @@ shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
30102905}
30112906CurrentSession -> shared_typmod_registry = NULL ;
30122907}
3013-
3014- /*
3015- * Insert RelIdToTypeIdCacheHash entry after setting of the
3016- * TCFLAGS_HAVE_PG_TYPE_DATA flag if needed.
3017- */
3018- static void
3019- insert_rel_type_cache_if_needed (TypeCacheEntry * typentry )
3020- {
3021- Assert (typentry -> flags & TCFLAGS_HAVE_PG_TYPE_DATA );
3022-
3023- /* Immediately quit for non-composite types */
3024- if (typentry -> typtype != TYPTYPE_COMPOSITE )
3025- return ;
3026-
3027- /* typrelid should be given for composite types */
3028- Assert (OidIsValid (typentry -> typrelid ));
3029-
3030- /*
3031- * Insert a RelIdToTypeIdCacheHash entry if the typentry doesn't have any
3032- * information indicating there should be such an entry already.
3033- */
3034- if (!(typentry -> flags & TCFLAGS_OPERATOR_FLAGS )&&
3035- typentry -> tupDesc == NULL )
3036- {
3037- RelIdToTypeIdCacheEntry * relentry ;
3038- bool found ;
3039-
3040- relentry = (RelIdToTypeIdCacheEntry * )hash_search (RelIdToTypeIdCacheHash ,
3041- & typentry -> typrelid ,
3042- HASH_ENTER ,& found );
3043- Assert (!found );
3044- relentry -> relid = typentry -> typrelid ;
3045- relentry -> composite_typid = typentry -> type_id ;
3046- }
3047- }
3048-
3049- /*
3050- * Delete entry RelIdToTypeIdCacheHash if needed after resetting of the
3051- * TCFLAGS_HAVE_PG_TYPE_DATA flag, or any of TCFLAGS_OPERATOR_FLAGS flags,
3052- * or tupDesc.
3053- */
3054- static void
3055- delete_rel_type_cache_if_needed (TypeCacheEntry * typentry )
3056- {
3057- /* Immediately quit for non-composite types */
3058- if (typentry -> typtype != TYPTYPE_COMPOSITE )
3059- return ;
3060-
3061- /* typrelid should be given for composite types */
3062- Assert (OidIsValid (typentry -> typrelid ));
3063-
3064- /*
3065- * Delete a RelIdToTypeIdCacheHash entry if the typentry doesn't have any
3066- * information indicating entry should be still there.
3067- */
3068- if (!(typentry -> flags & TCFLAGS_HAVE_PG_TYPE_DATA )&&
3069- !(typentry -> flags & TCFLAGS_OPERATOR_FLAGS )&&
3070- typentry -> tupDesc == NULL )
3071- {
3072- bool found ;
3073-
3074- (void )hash_search (RelIdToTypeIdCacheHash ,
3075- & typentry -> typrelid ,
3076- HASH_REMOVE ,& found );
3077- Assert (found );
3078- }
3079- else
3080- {
3081- #ifdef USE_ASSERT_CHECKING
3082- /*
3083- * In assert-enabled builds otherwise check for RelIdToTypeIdCacheHash
3084- * entry if it should exist.
3085- */
3086- bool found ;
3087-
3088- (void )hash_search (RelIdToTypeIdCacheHash ,
3089- & typentry -> typrelid ,
3090- HASH_FIND ,& found );
3091- Assert (found );
3092- #endif
3093- }
3094- }