fmgr.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,224 行 · 第 1/4 页
C
2,224 行
* This is inherently somewhat bogus since we can't reliably duplicate * language-dependent subsidiary info. We cheat by zeroing fn_extra, * instead, meaning that subsidiary info will have to be recomputed. */voidfmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt){ memcpy(dstinfo, srcinfo, sizeof(FmgrInfo)); dstinfo->fn_mcxt = destcxt; if (dstinfo->fn_addr == fmgr_oldstyle) { /* For oldstyle functions we must copy fn_extra */ Oldstyle_fnextra *fnextra; fnextra = (Oldstyle_fnextra *) MemoryContextAlloc(destcxt, sizeof(Oldstyle_fnextra)); memcpy(fnextra, srcinfo->fn_extra, sizeof(Oldstyle_fnextra)); dstinfo->fn_extra = (void *) fnextra; } else dstinfo->fn_extra = NULL;}/* * Specialized lookup routine for fmgr_internal_validator: given the alleged * name of an internal function, return the OID of the function. * If the name is not recognized, return InvalidOid. */Oidfmgr_internal_function(const char *proname){ const FmgrBuiltin *fbp = fmgr_lookupByName(proname); if (fbp == NULL) return InvalidOid; return fbp->foid;}/* * Handler for old-style "C" language functions */static Datumfmgr_oldstyle(PG_FUNCTION_ARGS){ Oldstyle_fnextra *fnextra; int n_arguments = fcinfo->nargs; int i; bool isnull; func_ptr user_fn; char *returnValue; if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL) elog(ERROR, "fmgr_oldstyle received NULL pointer"); fnextra = (Oldstyle_fnextra *) fcinfo->flinfo->fn_extra; /* * Result is NULL if any argument is NULL, but we still call the function * (peculiar, but that's the way it worked before, and after all this is a * backwards-compatibility wrapper). Note, however, that we'll never get * here with NULL arguments if the function is marked strict. * * We also need to detoast any TOAST-ed inputs, since it's unlikely that * an old-style function knows about TOASTing. */ isnull = false; for (i = 0; i < n_arguments; i++) { if (PG_ARGISNULL(i)) isnull = true; else if (fnextra->arg_toastable[i]) fcinfo->arg[i] = PointerGetDatum(PG_DETOAST_DATUM(fcinfo->arg[i])); } fcinfo->isnull = isnull; user_fn = fnextra->func; switch (n_arguments) { case 0: returnValue = (char *) (*user_fn) (); break; case 1: /* * nullvalue() used to use isNull to check if arg is NULL; perhaps * there are other functions still out there that also rely on * this undocumented hack? */ returnValue = (char *) (*user_fn) (fcinfo->arg[0], &fcinfo->isnull); break; case 2: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1]); break; case 3: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2]); break; case 4: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3]); break; case 5: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4]); break; case 6: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5]); break; case 7: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6]); break; case 8: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7]); break; case 9: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8]); break; case 10: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9]); break; case 11: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10]); break; case 12: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10], fcinfo->arg[11]); break; case 13: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10], fcinfo->arg[11], fcinfo->arg[12]); break; case 14: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10], fcinfo->arg[11], fcinfo->arg[12], fcinfo->arg[13]); break; case 15: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10], fcinfo->arg[11], fcinfo->arg[12], fcinfo->arg[13], fcinfo->arg[14]); break; case 16: returnValue = (char *) (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], fcinfo->arg[2], fcinfo->arg[3], fcinfo->arg[4], fcinfo->arg[5], fcinfo->arg[6], fcinfo->arg[7], fcinfo->arg[8], fcinfo->arg[9], fcinfo->arg[10], fcinfo->arg[11], fcinfo->arg[12], fcinfo->arg[13], fcinfo->arg[14], fcinfo->arg[15]); break; default: /* * Increasing FUNC_MAX_ARGS doesn't automatically add cases to the * above code, so mention the actual value in this error not * FUNC_MAX_ARGS. You could add cases to the above if you needed * to support old-style functions with many arguments, but making * 'em be new-style is probably a better idea. */ ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("function %u has too many arguments (%d, maximum is %d)", fcinfo->flinfo->fn_oid, n_arguments, 16))); returnValue = NULL; /* keep compiler quiet */ break; } return (Datum) returnValue;}/* * Support for security-definer and proconfig-using functions. We support * both of these features using the same call handler, because they are * often used together and it would be inefficient (as well as notationally * messy) to have two levels of call handler involved. */struct fmgr_security_definer_cache{ FmgrInfo flinfo; /* lookup info for target function */ Oid userid; /* userid to set, or InvalidOid */ ArrayType *proconfig; /* GUC values to set, or NULL */};/* * Function handler for security-definer/proconfig functions. We extract the * OID of the actual function and do a fmgr lookup again. Then we fetch the * pg_proc row and copy the owner ID and proconfig fields. (All this info * is cached for the duration of the current query.) To execute a call, * we temporarily replace the flinfo with the cached/looked-up one, while * keeping the outer fcinfo (which contains all the actual arguments, etc.) * intact. This is not re-entrant, but then the fcinfo itself can't be used * re-entrantly anyway. */static Datumfmgr_security_definer(PG_FUNCTION_ARGS){ Datum result; struct fmgr_security_definer_cache *volatile fcache; FmgrInfo *save_flinfo; Oid save_userid; bool save_secdefcxt; volatile int save_nestlevel; if (!fcinfo->flinfo->fn_extra) { HeapTuple tuple; Form_pg_proc procedureStruct; Datum datum; bool isnull; MemoryContext oldcxt; fcache = MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*fcache)); fmgr_info_cxt_security(fcinfo->flinfo->fn_oid, &fcache->flinfo, fcinfo->flinfo->fn_mcxt, true); fcache->flinfo.fn_expr = fcinfo->flinfo->fn_expr; tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", fcinfo->flinfo->fn_oid); procedureStruct = (Form_pg_proc) GETSTRUCT(tuple); if (procedureStruct->prosecdef) fcache->userid = procedureStruct->proowner; datum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proconfig, &isnull); if (!isnull) { oldcxt = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); fcache->proconfig = DatumGetArrayTypePCopy(datum); MemoryContextSwitchTo(oldcxt); } ReleaseSysCache(tuple); fcinfo->flinfo->fn_extra = fcache; } else fcache = fcinfo->flinfo->fn_extra; /* GetUserIdAndContext is cheap enough that no harm in a wasted call */ GetUserIdAndContext(&save_userid, &save_secdefcxt); if (fcache->proconfig) /* Need a new GUC nesting level */ save_nestlevel = NewGUCNestLevel(); else save_nestlevel = 0; /* keep compiler quiet */ if (OidIsValid(fcache->userid)) SetUserIdAndContext(fcache->userid, true); if (fcache->proconfig) { ProcessGUCArray(fcache->proconfig, (superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, GUC_ACTION_SAVE); } /* * We don't need to restore GUC or userid settings on error, because the * ensuing xact or subxact abort will do that. The PG_TRY block is only * needed to clean up the flinfo link. */ save_flinfo = fcinfo->flinfo; PG_TRY(); { fcinfo->flinfo = &fcache->flinfo; result = FunctionCallInvoke(fcinfo); } PG_CATCH(); { fcinfo->flinfo = save_flinfo; PG_RE_THROW(); } PG_END_TRY(); fcinfo->flinfo = save_flinfo; if (fcache->proconfig) AtEOXact_GUC(true, save_nestlevel); if (OidIsValid(fcache->userid)) SetUserIdAndContext(save_userid, save_secdefcxt); return result;}/*------------------------------------------------------------------------- * Support routines for callers of fmgr-compatible functions *------------------------------------------------------------------------- *//* * These are for invocation of a specifically named function with a * directly-computed parameter list. Note that neither arguments nor result * are allowed to be NULL. Also, the function cannot be one that needs to * look at FmgrInfo, since there won't be any. */DatumDirectFunctionCall1(PGFunction func, Datum arg1){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.argnull[0] = false; result = (*func) (&fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) func); return result;}DatumDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 2, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; fcinfo.argnull[0] = false; fcinfo.argnull[1] = false; result = (*func) (&fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) func); return result;}DatumDirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2, Datum arg3){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 3, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; fcinfo.arg[2] = arg3; fcinfo.argnull[0] = false; fcinfo.argnull[1] = false; fcinfo.argnull[2] = false; result = (*func) (&fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) func); return result;}DatumDirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2, Datum arg3, Datum arg4){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 4, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; fcinfo.arg[2] = arg3; fcinfo.arg[3] = arg4; fcinfo.argnull[0] = false; fcinfo.argnull[1] = false; fcinfo.argnull[2] = false; fcinfo.argnull[3] = false; result = (*func) (&fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) func); return result;}DatumDirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 5, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; fcinfo.arg[2] = arg3; fcinfo.arg[3] = arg4; fcinfo.arg[4] = arg5; fcinfo.argnull[0] = false; fcinfo.argnull[1] = false; fcinfo.argnull[2] = false; fcinfo.argnull[3] = false; fcinfo.argnull[4] = false; result = (*func) (&fcinfo); /* Check for null result, since caller is clearly not expecting one */ if (fcinfo.isnull) elog(ERROR, "function %p returned NULL", (void *) func); return result;}DatumDirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6){ FunctionCallInfoData fcinfo; Datum result; InitFunctionCallInfoData(fcinfo, NULL, 6, NULL, NULL); fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; fcinfo.arg[2] = arg3; fcinfo.arg[3] = arg4; fcinfo.arg[4] = arg5; fcinfo.arg[5] = arg6; fcinfo.argnull[0] = false; fcinfo.argnull[1] = false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?