PostgreSQL Source Code git master
fastpath.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "libpq/pqformat.h"
#include "libpq/protocol.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "tcop/fastpath.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for fastpath.c:

Go to the source code of this file.

Data Structures

struct  fp_info
 

Functions

static int16 parse_fcall_arguments (StringInfo msgBuf, struct fp_info *fip, FunctionCallInfo fcinfo)
 
static void SendFunctionResult (Datum retval, bool isnull, Oid rettype, int16 format)
 
static void fetch_fp_info (Oid func_id, struct fp_info *fip)
 
void HandleFunctionRequest (StringInfo msgBuf)
 

Function Documentation

◆ fetch_fp_info()

static void fetch_fp_info ( Oid  func_id,
struct fp_info fip 
)
static

Definition at line 119 of file fastpath.c.

120{
121 HeapTuple func_htp;
122 Form_pg_proc pp;
123
124 Assert(fip != NULL);
125
126 /*
127 * Since the validity of this structure is determined by whether the
128 * funcid is OK, we clear the funcid here. It must not be set to the
129 * correct value until we are about to return with a good struct fp_info,
130 * since we can be interrupted (i.e., with an ereport(ERROR, ...)) at any
131 * time. [No longer really an issue since we don't save the struct
132 * fp_info across transactions anymore, but keep it anyway.]
133 */
134 MemSet(fip, 0, sizeof(struct fp_info));
135 fip->funcid = InvalidOid;
136
137 func_htp = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_id));
138 if (!HeapTupleIsValid(func_htp))
140 (errcode(ERRCODE_UNDEFINED_FUNCTION),
141 errmsg("function with OID %u does not exist", func_id)));
142 pp = (Form_pg_proc) GETSTRUCT(func_htp);
143
144 /* reject pg_proc entries that are unsafe to call via fastpath */
145 if (pp->prokind != PROKIND_FUNCTION || pp->proretset)
147 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
148 errmsg("cannot call function \"%s\" via fastpath interface",
149 NameStr(pp->proname))));
150
151 /* watch out for catalog entries with more than FUNC_MAX_ARGS args */
152 if (pp->pronargs > FUNC_MAX_ARGS)
153 elog(ERROR, "function %s has more than %d arguments",
154 NameStr(pp->proname), FUNC_MAX_ARGS);
155
156 fip->namespace = pp->pronamespace;
157 fip->rettype = pp->prorettype;
158 memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid));
159 strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN);
160
161 ReleaseSysCache(func_htp);
162
163 fmgr_info(func_id, &fip->flinfo);
164
165 /*
166 * This must be last!
167 */
168 fip->funcid = func_id;
169}
#define NameStr(name)
Definition: c.h:703
#define Assert(condition)
Definition: c.h:815
#define MemSet(start, val, len)
Definition: c.h:977
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define NAMEDATALEN
#define FUNC_MAX_ARGS
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
Oid rettype
Definition: fastpath.c:52
Oid funcid
Definition: fastpath.c:50
char fname[NAMEDATALEN]
Definition: fastpath.c:55
Oid argtypes[FUNC_MAX_ARGS]
Definition: fastpath.c:54
FmgrInfo flinfo
Definition: fastpath.c:51
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References fp_info::argtypes, Assert, elog, ereport, errcode(), errmsg(), ERROR, fp_info::flinfo, fmgr_info(), fp_info::fname, FUNC_MAX_ARGS, fp_info::funcid, GETSTRUCT, HeapTupleIsValid, InvalidOid, MemSet, NAMEDATALEN, NameStr, ObjectIdGetDatum(), ReleaseSysCache(), fp_info::rettype, SearchSysCache1(), and strlcpy().

Referenced by HandleFunctionRequest().

◆ HandleFunctionRequest()

void HandleFunctionRequest ( StringInfo  msgBuf)

Definition at line 188 of file fastpath.c.

189{
191 Oid fid;
192 AclResult aclresult;
193 int16 rformat;
194 Datum retval;
195 struct fp_info my_fp;
196 struct fp_info *fip;
197 bool callit;
198 bool was_logged = false;
199 char msec_str[32];
200
201 /*
202 * We only accept COMMIT/ABORT if we are in an aborted transaction, and
203 * COMMIT/ABORT cannot be executed through the fastpath interface.
204 */
207 (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
208 errmsg("current transaction is aborted, "
209 "commands ignored until end of transaction block")));
210
211 /*
212 * Now that we know we are in a valid transaction, set snapshot in case
213 * needed by function itself or one of the datatype I/O routines.
214 */
216
217 /*
218 * Begin parsing the buffer contents.
219 */
220 fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */
221
222 /*
223 * There used to be a lame attempt at caching lookup info here. Now we
224 * just do the lookups on every call.
225 */
226 fip = &my_fp;
227 fetch_fp_info(fid, fip);
228
229 /* Log as soon as we have the function OID and name */
231 {
232 ereport(LOG,
233 (errmsg("fastpath function call: \"%s\" (OID %u)",
234 fip->fname, fid)));
235 was_logged = true;
236 }
237
238 /*
239 * Check permission to access and call function. Since we didn't go
240 * through a normal name lookup, we need to check schema usage too.
241 */
242 aclresult = object_aclcheck(NamespaceRelationId, fip->namespace, GetUserId(), ACL_USAGE);
243 if (aclresult != ACLCHECK_OK)
244 aclcheck_error(aclresult, OBJECT_SCHEMA,
245 get_namespace_name(fip->namespace));
246 InvokeNamespaceSearchHook(fip->namespace, true);
247
248 aclresult = object_aclcheck(ProcedureRelationId, fid, GetUserId(), ACL_EXECUTE);
249 if (aclresult != ACLCHECK_OK)
251 get_func_name(fid));
253
254 /*
255 * Prepare function call info block and insert arguments.
256 *
257 * Note: for now we pass collation = InvalidOid, so collation-sensitive
258 * functions can't be called this way. Perhaps we should pass
259 * DEFAULT_COLLATION_OID, instead?
260 */
261 InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
262
263 rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
264
265 /* Verify we reached the end of the message where expected. */
266 pq_getmsgend(msgBuf);
267
268 /*
269 * If func is strict, must not call it for null args.
270 */
271 callit = true;
272 if (fip->flinfo.fn_strict)
273 {
274 int i;
275
276 for (i = 0; i < fcinfo->nargs; i++)
277 {
278 if (fcinfo->args[i].isnull)
279 {
280 callit = false;
281 break;
282 }
283 }
284 }
285
286 if (callit)
287 {
288 /* Okay, do it ... */
289 retval = FunctionCallInvoke(fcinfo);
290 }
291 else
292 {
293 fcinfo->isnull = true;
294 retval = (Datum) 0;
295 }
296
297 /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
299
300 SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat);
301
302 /* We no longer need the snapshot */
304
305 /*
306 * Emit duration logging if appropriate.
307 */
308 switch (check_log_duration(msec_str, was_logged))
309 {
310 case 1:
311 ereport(LOG,
312 (errmsg("duration: %s ms", msec_str)));
313 break;
314 case 2:
315 ereport(LOG,
316 (errmsg("duration: %s ms fastpath function call: \"%s\" (OID %u)",
317 msec_str, fip->fname, fid)));
318 break;
319 }
320}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
int16_t int16
Definition: c.h:483
#define LOG
Definition: elog.h:31
static void fetch_fp_info(Oid func_id, struct fp_info *fip)
Definition: fastpath.c:119
static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, FunctionCallInfo fcinfo)
Definition: fastpath.c:329
static void SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
Definition: fastpath.c:67
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
int i
Definition: isn.c:72
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:517
#define InvokeNamespaceSearchHook(objectId, ereport_on_violation)
Definition: objectaccess.h:208
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
#define ACL_USAGE
Definition: parsenodes.h:84
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
#define ACL_EXECUTE
Definition: parsenodes.h:83
int log_statement
Definition: postgres.c:95
int check_log_duration(char *msec_str, bool was_logged)
Definition: postgres.c:2398
uintptr_t Datum
Definition: postgres.h:69
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:635
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:212
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:610
void PopActiveSnapshot(void)
Definition: snapmgr.c:703
bool fn_strict
Definition: fmgr.h:61
@ LOGSTMT_ALL
Definition: tcopprot.h:36
bool IsAbortedTransactionBlockState(void)
Definition: xact.c:406

References ACL_EXECUTE, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CHECK_FOR_INTERRUPTS, check_log_duration(), ereport, errcode(), errmsg(), ERROR, fetch_fp_info(), fp_info::flinfo, FmgrInfo::fn_strict, fp_info::fname, FUNC_MAX_ARGS, FunctionCallInvoke, get_func_name(), get_namespace_name(), GetTransactionSnapshot(), GetUserId(), i, InitFunctionCallInfoData, InvalidOid, InvokeFunctionExecuteHook, InvokeNamespaceSearchHook, IsAbortedTransactionBlockState(), LOCAL_FCINFO, LOG, log_statement, LOGSTMT_ALL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_SCHEMA, parse_fcall_arguments(), PopActiveSnapshot(), pq_getmsgend(), pq_getmsgint(), PushActiveSnapshot(), fp_info::rettype, and SendFunctionResult().

Referenced by PostgresMain().

◆ parse_fcall_arguments()

static int16 parse_fcall_arguments ( StringInfo  msgBuf,
struct fp_info fip,
FunctionCallInfo  fcinfo 
)
static

Definition at line 329 of file fastpath.c.

331{
332 int nargs;
333 int i;
334 int numAFormats;
335 int16 *aformats = NULL;
336 StringInfoData abuf;
337
338 /* Get the argument format codes */
339 numAFormats = pq_getmsgint(msgBuf, 2);
340 if (numAFormats > 0)
341 {
342 aformats = (int16 *) palloc(numAFormats * sizeof(int16));
343 for (i = 0; i < numAFormats; i++)
344 aformats[i] = pq_getmsgint(msgBuf, 2);
345 }
346
347 nargs = pq_getmsgint(msgBuf, 2); /* # of arguments */
348
349 if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
351 (errcode(ERRCODE_PROTOCOL_VIOLATION),
352 errmsg("function call message contains %d arguments but function requires %d",
353 nargs, fip->flinfo.fn_nargs)));
354
355 fcinfo->nargs = nargs;
356
357 if (numAFormats > 1 && numAFormats != nargs)
359 (errcode(ERRCODE_PROTOCOL_VIOLATION),
360 errmsg("function call message contains %d argument formats but %d arguments",
361 numAFormats, nargs)));
362
363 initStringInfo(&abuf);
364
365 /*
366 * Copy supplied arguments into arg vector.
367 */
368 for (i = 0; i < nargs; ++i)
369 {
370 int argsize;
371 int16 aformat;
372
373 argsize = pq_getmsgint(msgBuf, 4);
374 if (argsize == -1)
375 {
376 fcinfo->args[i].isnull = true;
377 }
378 else
379 {
380 fcinfo->args[i].isnull = false;
381 if (argsize < 0)
383 (errcode(ERRCODE_PROTOCOL_VIOLATION),
384 errmsg("invalid argument size %d in function call message",
385 argsize)));
386
387 /* Reset abuf to empty, and insert raw data into it */
388 resetStringInfo(&abuf);
390 pq_getmsgbytes(msgBuf, argsize),
391 argsize);
392 }
393
394 if (numAFormats > 1)
395 aformat = aformats[i];
396 else if (numAFormats > 0)
397 aformat = aformats[0];
398 else
399 aformat = 0; /* default = text */
400
401 if (aformat == 0)
402 {
403 Oid typinput;
404 Oid typioparam;
405 char *pstring;
406
407 getTypeInputInfo(fip->argtypes[i], &typinput, &typioparam);
408
409 /*
410 * Since stringinfo.c keeps a trailing null in place even for
411 * binary data, the contents of abuf are a valid C string. We
412 * have to do encoding conversion before calling the typinput
413 * routine, though.
414 */
415 if (argsize == -1)
416 pstring = NULL;
417 else
418 pstring = pg_client_to_server(abuf.data, argsize);
419
420 fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring,
421 typioparam, -1);
422 /* Free result of encoding conversion, if any */
423 if (pstring && pstring != abuf.data)
424 pfree(pstring);
425 }
426 else if (aformat == 1)
427 {
428 Oid typreceive;
429 Oid typioparam;
430 StringInfo bufptr;
431
432 /* Call the argument type's binary input converter */
433 getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
434
435 if (argsize == -1)
436 bufptr = NULL;
437 else
438 bufptr = &abuf;
439
440 fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr,
441 typioparam, -1);
442
443 /* Trouble if it didn't eat the whole buffer */
444 if (argsize != -1 && abuf.cursor != abuf.len)
446 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
447 errmsg("incorrect binary data format in function argument %d",
448 i + 1)));
449 }
450 else
452 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
453 errmsg("unsupported format code: %d", aformat)));
454 }
455
456 /* Return result format code */
457 return (int16) pq_getmsgint(msgBuf, 2);
458}
Datum OidReceiveFunctionCall(Oid functionId, StringInfo buf, Oid typioparam, int32 typmod)
Definition: fmgr.c:1772
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1754
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
Definition: lsyscache.c:2940
char * pg_client_to_server(const char *s, int len)
Definition: mbutils.c:660
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:508
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
short fn_nargs
Definition: fmgr.h:60
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Datum value
Definition: postgres.h:80
bool isnull
Definition: postgres.h:82

References appendBinaryStringInfo(), FunctionCallInfoBaseData::args, fp_info::argtypes, StringInfoData::cursor, StringInfoData::data, ereport, errcode(), errmsg(), ERROR, fp_info::flinfo, FmgrInfo::fn_nargs, FUNC_MAX_ARGS, getTypeBinaryInputInfo(), getTypeInputInfo(), i, initStringInfo(), NullableDatum::isnull, StringInfoData::len, FunctionCallInfoBaseData::nargs, OidInputFunctionCall(), OidReceiveFunctionCall(), palloc(), pfree(), pg_client_to_server(), pq_getmsgbytes(), pq_getmsgint(), resetStringInfo(), and NullableDatum::value.

Referenced by HandleFunctionRequest().

◆ SendFunctionResult()

static void SendFunctionResult ( Datum  retval,
bool  isnull,
Oid  rettype,
int16  format 
)
static

Definition at line 67 of file fastpath.c.

68{
70
72
73 if (isnull)
74 {
75 pq_sendint32(&buf, -1);
76 }
77 else
78 {
79 if (format == 0)
80 {
81 Oid typoutput;
82 bool typisvarlena;
83 char *outputstr;
84
85 getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
86 outputstr = OidOutputFunctionCall(typoutput, retval);
87 pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
88 pfree(outputstr);
89 }
90 else if (format == 1)
91 {
92 Oid typsend;
93 bool typisvarlena;
94 bytea *outputbytes;
95
96 getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
97 outputbytes = OidSendFunctionCall(typsend, retval);
98 pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
99 pq_sendbytes(&buf, VARDATA(outputbytes),
100 VARSIZE(outputbytes) - VARHDRSZ);
101 pfree(outputbytes);
102 }
103 else
105 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
106 errmsg("unsupported format code: %d", format)));
107 }
108
110}
#define VARHDRSZ
Definition: c.h:649
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
bytea * OidSendFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1782
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
Definition: lsyscache.c:2973
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
static char format
static char * buf
Definition: pg_test_fsync.c:72
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_endmessage(StringInfo buf)
Definition: pqformat.c:296
void pq_beginmessage(StringInfo buf, char msgtype)
Definition: pqformat.c:88
void pq_sendcountedtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:142
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
#define PqMsg_FunctionCallResponse
Definition: protocol.h:53
Definition: c.h:644
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARSIZE(PTR)
Definition: varatt.h:279

References buf, ereport, errcode(), errmsg(), ERROR, format, getTypeBinaryOutputInfo(), getTypeOutputInfo(), OidOutputFunctionCall(), OidSendFunctionCall(), pfree(), pq_beginmessage(), pq_endmessage(), pq_sendbytes(), pq_sendcountedtext(), pq_sendint32(), PqMsg_FunctionCallResponse, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by HandleFunctionRequest().