diff options
Diffstat (limited to 'src/backend/utils/cache/typcache.c')
-rw-r--r-- | src/backend/utils/cache/typcache.c | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index cf22306b207..874d8cd1c9e 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -259,12 +259,22 @@ static const dshash_parameters srtr_typmod_table_params = { LWTRANCHE_SESSION_TYPMOD_TABLE }; +/* hashtable for recognizing registered record types */ static HTAB *RecordCacheHash = NULL; +/* arrays of info about registered record types, indexed by assigned typmod */ static TupleDesc *RecordCacheArray = NULL; -static int32 RecordCacheArrayLen = 0; /* allocated length of array */ +static uint64 *RecordIdentifierArray = NULL; +static int32 RecordCacheArrayLen = 0; /* allocated length of above arrays */ static int32 NextRecordTypmod = 0; /* number of entries used */ +/* + * Process-wide counter for generating unique tupledesc identifiers. + * Zero and one (INVALID_TUPLEDESC_IDENTIFIER) aren't allowed to be chosen + * as identifiers, so we start the counter at INVALID_TUPLEDESC_IDENTIFIER. + */ +static uint64 tupledesc_id_counter = INVALID_TUPLEDESC_IDENTIFIER; + static void load_typcache_tupdesc(TypeCacheEntry *typentry); static void load_rangetype_info(TypeCacheEntry *typentry); static void load_domaintype_info(TypeCacheEntry *typentry); @@ -793,10 +803,10 @@ load_typcache_tupdesc(TypeCacheEntry *typentry) typentry->tupDesc->tdrefcount++; /* - * In future, we could take some pains to not increment the seqno if the - * tupdesc didn't really change; but for now it's not worth it. + * In future, we could take some pains to not change tupDesc_identifier if + * the tupdesc didn't really change; but for now it's not worth it. */ - typentry->tupDescSeqNo++; + typentry->tupDesc_identifier = ++tupledesc_id_counter; relation_close(rel, AccessShareLock); } @@ -1496,7 +1506,8 @@ cache_range_element_properties(TypeCacheEntry *typentry) } /* - * Make sure that RecordCacheArray is large enough to store 'typmod'. + * Make sure that RecordCacheArray and RecordIdentifierArray are large enough + * to store 'typmod'. */ static void ensure_record_cache_typmod_slot_exists(int32 typmod) @@ -1505,6 +1516,8 @@ ensure_record_cache_typmod_slot_exists(int32 typmod) { RecordCacheArray = (TupleDesc *) MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(TupleDesc)); + RecordIdentifierArray = (uint64 *) + MemoryContextAllocZero(CacheMemoryContext, 64 * sizeof(uint64)); RecordCacheArrayLen = 64; } @@ -1519,6 +1532,10 @@ ensure_record_cache_typmod_slot_exists(int32 typmod) newlen * sizeof(TupleDesc)); memset(RecordCacheArray + RecordCacheArrayLen, 0, (newlen - RecordCacheArrayLen) * sizeof(TupleDesc)); + RecordIdentifierArray = (uint64 *) repalloc(RecordIdentifierArray, + newlen * sizeof(uint64)); + memset(RecordIdentifierArray + RecordCacheArrayLen, 0, + (newlen - RecordCacheArrayLen) * sizeof(uint64)); RecordCacheArrayLen = newlen; } } @@ -1581,11 +1598,17 @@ lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError) /* * Our local array can now point directly to the TupleDesc - * in shared memory. + * in shared memory, which is non-reference-counted. */ RecordCacheArray[typmod] = tupdesc; Assert(tupdesc->tdrefcount == -1); + /* + * We don't share tupdesc identifiers across processes, so + * assign one locally. + */ + RecordIdentifierArray[typmod] = ++tupledesc_id_counter; + dshash_release_lock(CurrentSession->shared_typmod_table, entry); @@ -1790,6 +1813,9 @@ assign_record_type_typmod(TupleDesc tupDesc) RecordCacheArray[entDesc->tdtypmod] = entDesc; recentry->tupdesc = entDesc; + /* Assign a unique tupdesc identifier, too. */ + RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter; + /* Update the caller's tuple descriptor. */ tupDesc->tdtypmod = entDesc->tdtypmod; @@ -1797,6 +1823,52 @@ assign_record_type_typmod(TupleDesc tupDesc) } /* + * assign_record_type_identifier + * + * Get an identifier, which will be unique over the lifespan of this backend + * process, for the current tuple descriptor of the specified composite type. + * For named composite types, the value is guaranteed to change if the type's + * definition does. For registered RECORD types, the value will not change + * once assigned, since the registered type won't either. If an anonymous + * RECORD type is specified, we return a new identifier on each call. + */ +uint64 +assign_record_type_identifier(Oid type_id, int32 typmod) +{ + if (type_id != RECORDOID) + { + /* + * It's a named composite type, so use the regular typcache. + */ + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC); + if (typentry->tupDesc == NULL) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("type %s is not composite", + format_type_be(type_id)))); + Assert(typentry->tupDesc_identifier != 0); + return typentry->tupDesc_identifier; + } + else + { + /* + * It's a transient record type, so look in our record-type table. + */ + if (typmod >= 0 && typmod < RecordCacheArrayLen && + RecordCacheArray[typmod] != NULL) + { + Assert(RecordIdentifierArray[typmod] != 0); + return RecordIdentifierArray[typmod]; + } + + /* For anonymous or unrecognized record type, generate a new ID */ + return ++tupledesc_id_counter; + } +} + +/* * Return the amout of shmem required to hold a SharedRecordTypmodRegistry. * This exists only to avoid exposing private innards of * SharedRecordTypmodRegistry in a header. |