487{
492 bool function_valid = false;
493 bool hashkey_valid = false;
494 bool new_function = false;
495
496 /*
497 * Lookup the pg_proc tuple by Oid; we'll need it in any case
498 */
501 elog(
ERROR,
"cache lookup failed for function %u", funcOid);
503
504 /*
505 * Do we already have a cache entry for the current FmgrInfo? If not, try
506 * to find one in the hash table.
507 */
508recheck:
510 {
511 /* Compute hashkey using function signature and actual arg types */
513 cacheEntrySize, includeResultType,
514 forValidator);
515 hashkey_valid = true;
516
517 /* And do the lookup */
519 }
520
522 {
523 /* We have a compiled function, but is it still valid? */
526 function_valid = true;
527 else
528 {
529 /*
530 * Nope, so remove it from hashtable and try to drop associated
531 * storage (if not done already).
532 */
534
535 /*
536 * If the function isn't in active use then we can overwrite the
537 * func struct with new data, allowing any other existing fn_extra
538 * pointers to make use of the new definition on their next use.
539 * If it is in use then just leave it alone and make a new one.
540 * (The active invocations will run to completion using the
541 * previous definition, and then the cache entry will just be
542 * leaked; doesn't seem worth adding code to clean it up, given
543 * what a corner case this is.)
544 *
545 * If we found the function struct via fn_extra then it's possible
546 * a replacement has already been made, so go back and recheck the
547 * hashtable.
548 */
550 {
552 if (!hashkey_valid)
553 goto recheck;
554 }
555 }
556 }
557
558 /*
559 * If the function wasn't found or was out-of-date, we have to compile it.
560 */
561 if (!function_valid)
562 {
563 /*
564 * Calculate hashkey if we didn't already; we'll need it to store the
565 * completed function.
566 */
567 if (!hashkey_valid)
569 cacheEntrySize, includeResultType,
570 forValidator);
571
572 /*
573 * Create the new function struct, if not done already. The function
574 * cache entry will be kept for the life of the backend, so put it in
575 * TopMemoryContext.
576 */
579 {
582 new_function = true;
583 }
584 else
585 {
586 /* re-using a previously existing struct, so clear it out */
587 memset(
function, 0, cacheEntrySize);
588 }
589
590 /*
591 * However, if function compilation fails, we'd like not to leak the
592 * function struct, so use a PG_TRY block to prevent that. (It's up
593 * to the compile callback function to avoid its own internal leakage
594 * in such cases.) Unfortunately, freeing the struct is only safe if
595 * we just allocated it: otherwise there are probably fn_extra
596 * pointers to it.
597 */
599 {
600 /*
601 * Do the hard, language-specific part.
602 */
603 ccallback(fcinfo, procTup, &hashkey,
function, forValidator);
604 }
606 {
607 if (new_function)
610 }
612
613 /*
614 * Fill in the CachedFunction part. (We do this last to prevent the
615 * function from looking valid before it's fully built.) fn_hashkey
616 * will be set by cfunc_hashtable_insert; use_count remains zero.
617 */
621
622 /*
623 * Add the completed struct to the hash table.
624 */
626 }
627
629
630 /*
631 * Finally return the compiled function
632 */
634}
static void compute_function_hashkey(FunctionCallInfo fcinfo, Form_pg_proc procStruct, CachedFunctionHashKey *hashkey, Size cacheEntrySize, bool includeResultType, bool forValidator)
static void cfunc_hashtable_insert(CachedFunction *function, CachedFunctionHashKey *func_key)
static CachedFunction * cfunc_hashtable_lookup(CachedFunctionHashKey *func_key)
static void delete_function(CachedFunction *func)
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
void * MemoryContextAllocZero(MemoryContext context, Size size)
void pfree(void *pointer)
MemoryContext TopMemoryContext
on_exit_nicely_callback function
FormData_pg_proc * Form_pg_proc
static Datum ObjectIdGetDatum(Oid X)
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)