typedefstruct CachedFunctionHashEntry
{
CachedFunctionHashKey key; /* hash key, must be first */
CachedFunction *function; /* points to data of language-specific size */
} CachedFunctionHashEntry;
if (cfunc_hashtable == NULL)
cfunc_hashtable_init();
hentry = (CachedFunctionHashEntry *) hash_search(cfunc_hashtable,
func_key,
HASH_ENTER,
&found); if (found)
elog(WARNING, "trying to insert a function that already exists");
hentry = (CachedFunctionHashEntry *) hash_search(cfunc_hashtable,
function->fn_hashkey,
HASH_REMOVE,
NULL); if (hentry == NULL)
elog(WARNING, "trying to delete function that does not exist");
/* Remove back link, which no longer points to allocated storage */
function->fn_hashkey = NULL;
/* Release the callResultType if present */ if (tupdesc)
FreeTupleDesc(tupdesc);
}
/* *Computethehashkeyforagivenfunctioninvocation * *Thehashkeyisreturnedintothecaller-providedstorageat*hashkey. *NotehoweverthatifacallResultTypeisincorporated,we'venotdone *anythingaboutcopyingthat.
*/ staticvoid
compute_function_hashkey(FunctionCallInfo fcinfo,
Form_pg_proc procStruct,
CachedFunctionHashKey *hashkey,
Size cacheEntrySize, bool includeResultType, bool forValidator)
{ /* Make sure pad bytes within fixed part of the struct are zero */
memset(hashkey, 0, offsetof(CachedFunctionHashKey, argtypes));
/* get function OID */
hashkey->funcOid = fcinfo->flinfo->fn_oid;
/* normal case, pass to standard routine */ if (!resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
call_expr))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("could not determine actual argument " "type for polymorphic function \"%s\"",
proname))); /* also, treat RECORD inputs (but not outputs) as polymorphic */
inargno = 0; for (i = 0; i < numargs; i++)
{ char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE) continue; if (argtypes[i] == RECORDOID || argtypes[i] == RECORDARRAYOID)
{
Oid resolvedtype = get_call_expr_argtype(call_expr,
inargno);
if (OidIsValid(resolvedtype))
argtypes[i] = resolvedtype;
}
inargno++;
}
} else
{ /* special validation case (no need to do anything for RECORD) */ for (i = 0; i < numargs; i++)
{ switch (argtypes[i])
{ case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: /* XXX dubious */ case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID:
argtypes[i] = INT4OID; break; case ANYARRAYOID: case ANYCOMPATIBLEARRAYOID:
argtypes[i] = INT4ARRAYOID; break; case ANYRANGEOID: case ANYCOMPATIBLERANGEOID:
argtypes[i] = INT4RANGEOID; break; case ANYMULTIRANGEOID:
argtypes[i] = INT4MULTIRANGEOID; break; default: break;
}
}
}
}
/* *delete_function-cleanupasmuchaspossibleofastalefunctioncache * *Wecan'treleasetheCachedFunctionstructitself,becauseofthe *possibilitythattherearefn_extrapointerstoit.Wecanrelease *thesubsidiarystorage,butonlyiftherearenoactiveevaluations *inprogress.Otherwisewe'lljustleakthatstorage.Sincethe *casewouldonlyoccurifapg_procupdateisdetectedduringanested *recursivecallonthefunction,aleakseemsacceptable. * *Notethatthiscanbecalledmorethanonceiftherearemultiplefn_extra *pointerstothesamefunctioncache.Hencebecarefulnottodothings *twice.
*/ staticvoid
delete_function(CachedFunction *func)
{ /* remove function from hash table (might be done already) */
cfunc_hashtable_delete(func);
/* release the function's storage if safe and not done already */ if (func->use_count == 0 &&
func->dcallback != NULL)
{
func->dcallback(func);
func->dcallback = NULL;
}
}
/* *Lookupthepg_proctuplebyOid;we'llneeditinanycase
*/
procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid)); if (!HeapTupleIsValid(procTup))
elog(ERROR, "cache lookup failed for function %u", funcOid);
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
/* *DowealreadyhaveacacheentryforthecurrentFmgrInfo?Ifnot,try *tofindoneinthehashtable.
*/
recheck: if (!function)
{ /* Compute hashkey using function signature and actual arg types */
compute_function_hashkey(fcinfo, procStruct, &hashkey,
cacheEntrySize, includeResultType,
forValidator);
hashkey_valid = true;
/* And do the lookup */
function = cfunc_hashtable_lookup(&hashkey);
}
if (function)
{ /* We have a compiled function, but is it still valid? */ if (function->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
ItemPointerEquals(&function->fn_tid, &procTup->t_self))
function_valid = true; else
{ /* *Nope,soremoveitfromhashtableandtrytodropassociated *storage(ifnotdonealready).
*/
delete_function(function);
/* *Ifthefunctionisn'tinactiveusethenwecanoverwritethe *funcstructwithnewdata,allowinganyotherexistingfn_extra *pointerstomakeuseofthenewdefinitionontheirnextuse. *Ifitisinusethenjustleaveitaloneandmakeanewone. *(Theactiveinvocationswillruntocompletionusingthe *previousdefinition,andthenthecacheentrywilljustbe *leaked;doesn'tseemworthaddingcodetocleanitup,given *whatacornercasethisis.) * *Ifwefoundthefunctionstructviafn_extrathenit'spossible *areplacementhasalreadybeenmade,sogobackandrecheckthe *hashtable.
*/ if (function->use_count != 0)
{
function = NULL; if (!hashkey_valid) goto recheck;
}
}
}
/* *Ifthefunctionwasn'tfoundorwasout-of-date,wehavetocompileit.
*/ if (!function_valid)
{ /* *Calculatehashkeyifwedidn'talready;we'llneedittostorethe *completedfunction.
*/ if (!hashkey_valid)
compute_function_hashkey(fcinfo, procStruct, &hashkey,
cacheEntrySize, includeResultType,
forValidator);
/* *Createthenewfunctionstruct,ifnotdonealready.Thefunction *cacheentrywillbekeptforthelifeofthebackend,soputitin *TopMemoryContext.
*/
Assert(cacheEntrySize >= sizeof(CachedFunction)); if (function == NULL)
{
function = (CachedFunction *)
MemoryContextAllocZero(TopMemoryContext, cacheEntrySize);
new_function = true;
} else
{ /* re-using a previously existing struct, so clear it out */
memset(function, 0, cacheEntrySize);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.