#include "lib/stringinfo.h"

Go to the source code of this file.
Functions | |
| int | HandleFunctionRequest (StringInfo msgBuf) |
| int HandleFunctionRequest | ( | StringInfo | msgBuf | ) |
Definition at line 270 of file fastpath.c.
References ACL_EXECUTE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoData::argnull, CHECK_FOR_INTERRUPTS, check_log_duration(), COMMERROR, DEBUG1, ereport, errcode(), errmsg(), ERROR, fetch_fp_info(), fp_info::flinfo, FmgrInfo::fn_strict, fp_info::fname, FrontendProtocol, FunctionCallInvoke, get_func_name(), get_namespace_name(), GetOldFunctionMessage(), GetTransactionSnapshot(), GetUserId(), i, InitFunctionCallInfoData, InvalidOid, InvokeFunctionExecuteHook, InvokeNamespaceSearchHook, IsAbortedTransactionBlockState(), FunctionCallInfoData::isnull, IsTransactionState(), LOG, log_statement, LOGSTMT_ALL, FunctionCallInfoData::nargs, NULL, parse_fcall_arguments(), parse_fcall_arguments_20(), pg_namespace_aclcheck(), pg_proc_aclcheck(), PG_PROTOCOL_MAJOR, PopActiveSnapshot(), pq_getmsgend(), pq_getmsgint(), pq_getmsgstring(), PushActiveSnapshot(), fp_info::rettype, SendFunctionResult(), and whereToSendOutput.
Referenced by PostgresMain().
{
Oid fid;
AclResult aclresult;
FunctionCallInfoData fcinfo;
int16 rformat;
Datum retval;
struct fp_info my_fp;
struct fp_info *fip;
bool callit;
bool was_logged = false;
char msec_str[32];
/*
* Read message contents if not already done.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
{
if (GetOldFunctionMessage(msgBuf))
{
if (IsTransactionState())
ereport(COMMERROR,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("unexpected EOF on client connection with an open transaction")));
else
{
/*
* Can't send DEBUG log messages to client at this point.
* Since we're disconnecting right away, we don't need to
* restore whereToSendOutput.
*/
whereToSendOutput = DestNone;
ereport(DEBUG1,
(errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
errmsg("unexpected EOF on client connection")));
}
return EOF;
}
}
/*
* Now that we've eaten the input message, check to see if we actually
* want to do the function call or not. It's now safe to ereport(); we
* won't lose sync with the frontend.
*/
if (IsAbortedTransactionBlockState())
ereport(ERROR,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("current transaction is aborted, "
"commands ignored until end of transaction block")));
/*
* Now that we know we are in a valid transaction, set snapshot in case
* needed by function itself or one of the datatype I/O routines.
*/
PushActiveSnapshot(GetTransactionSnapshot());
/*
* Begin parsing the buffer contents.
*/
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
(void) pq_getmsgstring(msgBuf); /* dummy string */
fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */
/*
* There used to be a lame attempt at caching lookup info here. Now we
* just do the lookups on every call.
*/
fip = &my_fp;
fetch_fp_info(fid, fip);
/* Log as soon as we have the function OID and name */
if (log_statement == LOGSTMT_ALL)
{
ereport(LOG,
(errmsg("fastpath function call: \"%s\" (OID %u)",
fip->fname, fid)));
was_logged = true;
}
/*
* Check permission to access and call function. Since we didn't go
* through a normal name lookup, we need to check schema usage too.
*/
aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(fip->namespace));
InvokeNamespaceSearchHook(fip->namespace, true);
aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(fid));
InvokeFunctionExecuteHook(fid);
/*
* Prepare function call info block and insert arguments.
*
* Note: for now we pass collation = InvalidOid, so collation-sensitive
* functions can't be called this way. Perhaps we should pass
* DEFAULT_COLLATION_OID, instead?
*/
InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
else
rformat = parse_fcall_arguments_20(msgBuf, fip, &fcinfo);
/* Verify we reached the end of the message where expected. */
pq_getmsgend(msgBuf);
/*
* If func is strict, must not call it for null args.
*/
callit = true;
if (fip->flinfo.fn_strict)
{
int i;
for (i = 0; i < fcinfo.nargs; i++)
{
if (fcinfo.argnull[i])
{
callit = false;
break;
}
}
}
if (callit)
{
/* Okay, do it ... */
retval = FunctionCallInvoke(&fcinfo);
}
else
{
fcinfo.isnull = true;
retval = (Datum) 0;
}
/* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
CHECK_FOR_INTERRUPTS();
SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
/* We no longer need the snapshot */
PopActiveSnapshot();
/*
* Emit duration logging if appropriate.
*/
switch (check_log_duration(msec_str, was_logged))
{
case 1:
ereport(LOG,
(errmsg("duration: %s ms", msec_str)));
break;
case 2:
ereport(LOG,
(errmsg("duration: %s ms fastpath function call: \"%s\" (OID %u)",
msec_str, fip->fname, fid)));
break;
}
return 0;
}
1.7.1