Fix assign_record_type_typmod().
If an error occurred in the wrong place, it was possible to leave an
unintialized entry in the hash table, leading to a crash. Fixed.
Also, be more careful about the order of operations so that an
allocation error doesn't leak memory in CacheMemoryContext or
unnecessarily advance NextRecordTypmod.
Backpatch through version 11. Earlier versions (prior to 35ea75632a
)
do not exhibit the problem, because an uninitialized hash entry
contains a valid empty list.
Author: Sait Talha Nisanci <Sait.Nisanci@microsoft.com>
Reviewed-by: Andres Freund
Discussion: https://postgr.es/m/HE1PR8303MB009069D476225B9A9E194B8891779@HE1PR8303MB0090.EURPRD83.prod.outlook.com
Backpatch-through: 11
This commit is contained in:
parent
9fca23c1d6
commit
edd9a2bf74
|
@ -1855,10 +1855,14 @@ assign_record_type_typmod(TupleDesc tupDesc)
|
|||
CreateCacheMemoryContext();
|
||||
}
|
||||
|
||||
/* Find or create a hashtable entry for this tuple descriptor */
|
||||
/*
|
||||
* Find a hashtable entry for this tuple descriptor. We don't use
|
||||
* HASH_ENTER yet, because if it's missing, we need to make sure that all
|
||||
* the allocations succeed before we create the new entry.
|
||||
*/
|
||||
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
|
||||
(void *) &tupDesc,
|
||||
HASH_ENTER, &found);
|
||||
HASH_FIND, &found);
|
||||
if (found && recentry->tupdesc != NULL)
|
||||
{
|
||||
tupDesc->tdtypmod = recentry->tupdesc->tdtypmod;
|
||||
|
@ -1866,25 +1870,39 @@ assign_record_type_typmod(TupleDesc tupDesc)
|
|||
}
|
||||
|
||||
/* Not present, so need to manufacture an entry */
|
||||
recentry->tupdesc = NULL;
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* Look in the SharedRecordTypmodRegistry, if attached */
|
||||
entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
|
||||
if (entDesc == NULL)
|
||||
{
|
||||
/*
|
||||
* Make sure we have room before we CreateTupleDescCopy() or advance
|
||||
* NextRecordTypmod.
|
||||
*/
|
||||
ensure_record_cache_typmod_slot_exists(NextRecordTypmod);
|
||||
|
||||
/* Reference-counted local cache only. */
|
||||
entDesc = CreateTupleDescCopy(tupDesc);
|
||||
entDesc->tdrefcount = 1;
|
||||
entDesc->tdtypmod = NextRecordTypmod++;
|
||||
}
|
||||
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
|
||||
else
|
||||
{
|
||||
ensure_record_cache_typmod_slot_exists(entDesc->tdtypmod);
|
||||
}
|
||||
|
||||
RecordCacheArray[entDesc->tdtypmod] = entDesc;
|
||||
recentry->tupdesc = entDesc;
|
||||
|
||||
/* Assign a unique tupdesc identifier, too. */
|
||||
RecordIdentifierArray[entDesc->tdtypmod] = ++tupledesc_id_counter;
|
||||
|
||||
/* Fully initialized; create the hash table entry */
|
||||
recentry = (RecordCacheEntry *) hash_search(RecordCacheHash,
|
||||
(void *) &tupDesc,
|
||||
HASH_ENTER, NULL);
|
||||
recentry->tupdesc = entDesc;
|
||||
|
||||
/* Update the caller's tuple descriptor. */
|
||||
tupDesc->tdtypmod = entDesc->tdtypmod;
|
||||
|
||||
|
|
Loading…
Reference in New Issue