1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * fastpath.c |
4 | * routines to handle function requests from the frontend |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * |
10 | * IDENTIFICATION |
11 | * src/backend/tcop/fastpath.c |
12 | * |
13 | * NOTES |
14 | * This cruft is the server side of PQfn. |
15 | * |
16 | *------------------------------------------------------------------------- |
17 | */ |
18 | #include "postgres.h" |
19 | |
20 | #include "access/htup_details.h" |
21 | #include "access/xact.h" |
22 | #include "catalog/objectaccess.h" |
23 | #include "catalog/pg_proc.h" |
24 | #include "libpq/libpq.h" |
25 | #include "libpq/pqformat.h" |
26 | #include "mb/pg_wchar.h" |
27 | #include "miscadmin.h" |
28 | #include "port/pg_bswap.h" |
29 | #include "tcop/fastpath.h" |
30 | #include "tcop/tcopprot.h" |
31 | #include "utils/acl.h" |
32 | #include "utils/lsyscache.h" |
33 | #include "utils/snapmgr.h" |
34 | #include "utils/syscache.h" |
35 | |
36 | |
37 | /* |
38 | * Formerly, this code attempted to cache the function and type info |
39 | * looked up by fetch_fp_info, but only for the duration of a single |
40 | * transaction command (since in theory the info could change between |
41 | * commands). This was utterly useless, because postgres.c executes |
42 | * each fastpath call as a separate transaction command, and so the |
43 | * cached data could never actually have been reused. If it had worked |
44 | * as intended, it would have had problems anyway with dangling references |
45 | * in the FmgrInfo struct. So, forget about caching and just repeat the |
46 | * syscache fetches on each usage. They're not *that* expensive. |
47 | */ |
48 | struct fp_info |
49 | { |
50 | Oid funcid; |
51 | FmgrInfo flinfo; /* function lookup info for funcid */ |
52 | Oid namespace; /* other stuff from pg_proc */ |
53 | Oid rettype; |
54 | Oid argtypes[FUNC_MAX_ARGS]; |
55 | char fname[NAMEDATALEN]; /* function name for logging */ |
56 | }; |
57 | |
58 | |
59 | static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, |
60 | FunctionCallInfo fcinfo); |
61 | static int16 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, |
62 | FunctionCallInfo fcinfo); |
63 | |
64 | |
65 | /* ---------------- |
66 | * GetOldFunctionMessage |
67 | * |
68 | * In pre-3.0 protocol, there is no length word on the message, so we have |
69 | * to have code that understands the message layout to absorb the message |
70 | * into a buffer. We want to do this before we start execution, so that |
71 | * we do not lose sync with the frontend if there's an error. |
72 | * |
73 | * The caller should already have initialized buf to empty. |
74 | * ---------------- |
75 | */ |
76 | int |
77 | GetOldFunctionMessage(StringInfo buf) |
78 | { |
79 | int32 ibuf; |
80 | int nargs; |
81 | |
82 | /* Dummy string argument */ |
83 | if (pq_getstring(buf)) |
84 | return EOF; |
85 | /* Function OID */ |
86 | if (pq_getbytes((char *) &ibuf, 4)) |
87 | return EOF; |
88 | appendBinaryStringInfo(buf, (char *) &ibuf, 4); |
89 | /* Number of arguments */ |
90 | if (pq_getbytes((char *) &ibuf, 4)) |
91 | return EOF; |
92 | appendBinaryStringInfo(buf, (char *) &ibuf, 4); |
93 | nargs = pg_ntoh32(ibuf); |
94 | /* For each argument ... */ |
95 | while (nargs-- > 0) |
96 | { |
97 | int argsize; |
98 | |
99 | /* argsize */ |
100 | if (pq_getbytes((char *) &ibuf, 4)) |
101 | return EOF; |
102 | appendBinaryStringInfo(buf, (char *) &ibuf, 4); |
103 | argsize = pg_ntoh32(ibuf); |
104 | if (argsize < -1) |
105 | { |
106 | /* FATAL here since no hope of regaining message sync */ |
107 | ereport(FATAL, |
108 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
109 | errmsg("invalid argument size %d in function call message" , |
110 | argsize))); |
111 | } |
112 | /* and arg contents */ |
113 | if (argsize > 0) |
114 | { |
115 | /* Allocate space for arg */ |
116 | enlargeStringInfo(buf, argsize); |
117 | /* And grab it */ |
118 | if (pq_getbytes(buf->data + buf->len, argsize)) |
119 | return EOF; |
120 | buf->len += argsize; |
121 | /* Place a trailing null per StringInfo convention */ |
122 | buf->data[buf->len] = '\0'; |
123 | } |
124 | } |
125 | return 0; |
126 | } |
127 | |
128 | /* ---------------- |
129 | * SendFunctionResult |
130 | * |
131 | * Note: although this routine doesn't check, the format had better be 1 |
132 | * (binary) when talking to a pre-3.0 client. |
133 | * ---------------- |
134 | */ |
135 | static void |
136 | SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format) |
137 | { |
138 | bool newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3); |
139 | StringInfoData buf; |
140 | |
141 | pq_beginmessage(&buf, 'V'); |
142 | |
143 | if (isnull) |
144 | { |
145 | if (newstyle) |
146 | pq_sendint32(&buf, -1); |
147 | } |
148 | else |
149 | { |
150 | if (!newstyle) |
151 | pq_sendbyte(&buf, 'G'); |
152 | |
153 | if (format == 0) |
154 | { |
155 | Oid typoutput; |
156 | bool typisvarlena; |
157 | char *outputstr; |
158 | |
159 | getTypeOutputInfo(rettype, &typoutput, &typisvarlena); |
160 | outputstr = OidOutputFunctionCall(typoutput, retval); |
161 | pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false); |
162 | pfree(outputstr); |
163 | } |
164 | else if (format == 1) |
165 | { |
166 | Oid typsend; |
167 | bool typisvarlena; |
168 | bytea *outputbytes; |
169 | |
170 | getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena); |
171 | outputbytes = OidSendFunctionCall(typsend, retval); |
172 | pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ); |
173 | pq_sendbytes(&buf, VARDATA(outputbytes), |
174 | VARSIZE(outputbytes) - VARHDRSZ); |
175 | pfree(outputbytes); |
176 | } |
177 | else |
178 | ereport(ERROR, |
179 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
180 | errmsg("unsupported format code: %d" , format))); |
181 | } |
182 | |
183 | if (!newstyle) |
184 | pq_sendbyte(&buf, '0'); |
185 | |
186 | pq_endmessage(&buf); |
187 | } |
188 | |
189 | /* |
190 | * fetch_fp_info |
191 | * |
192 | * Performs catalog lookups to load a struct fp_info 'fip' for the |
193 | * function 'func_id'. |
194 | */ |
195 | static void |
196 | fetch_fp_info(Oid func_id, struct fp_info *fip) |
197 | { |
198 | HeapTuple func_htp; |
199 | Form_pg_proc pp; |
200 | |
201 | Assert(OidIsValid(func_id)); |
202 | Assert(fip != NULL); |
203 | |
204 | /* |
205 | * Since the validity of this structure is determined by whether the |
206 | * funcid is OK, we clear the funcid here. It must not be set to the |
207 | * correct value until we are about to return with a good struct fp_info, |
208 | * since we can be interrupted (i.e., with an ereport(ERROR, ...)) at any |
209 | * time. [No longer really an issue since we don't save the struct |
210 | * fp_info across transactions anymore, but keep it anyway.] |
211 | */ |
212 | MemSet(fip, 0, sizeof(struct fp_info)); |
213 | fip->funcid = InvalidOid; |
214 | |
215 | fmgr_info(func_id, &fip->flinfo); |
216 | |
217 | func_htp = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_id)); |
218 | if (!HeapTupleIsValid(func_htp)) |
219 | ereport(ERROR, |
220 | (errcode(ERRCODE_UNDEFINED_FUNCTION), |
221 | errmsg("function with OID %u does not exist" , func_id))); |
222 | pp = (Form_pg_proc) GETSTRUCT(func_htp); |
223 | |
224 | /* watch out for catalog entries with more than FUNC_MAX_ARGS args */ |
225 | if (pp->pronargs > FUNC_MAX_ARGS) |
226 | elog(ERROR, "function %s has more than %d arguments" , |
227 | NameStr(pp->proname), FUNC_MAX_ARGS); |
228 | |
229 | fip->namespace = pp->pronamespace; |
230 | fip->rettype = pp->prorettype; |
231 | memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid)); |
232 | strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN); |
233 | |
234 | ReleaseSysCache(func_htp); |
235 | |
236 | /* |
237 | * This must be last! |
238 | */ |
239 | fip->funcid = func_id; |
240 | } |
241 | |
242 | |
243 | /* |
244 | * HandleFunctionRequest |
245 | * |
246 | * Server side of PQfn (fastpath function calls from the frontend). |
247 | * This corresponds to the libpq protocol symbol "F". |
248 | * |
249 | * INPUT: |
250 | * postgres.c has already read the message body and will pass it in |
251 | * msgBuf. |
252 | * |
253 | * Note: palloc()s done here and in the called function do not need to be |
254 | * cleaned up explicitly. We are called from PostgresMain() in the |
255 | * MessageContext memory context, which will be automatically reset when |
256 | * control returns to PostgresMain. |
257 | */ |
258 | void |
259 | HandleFunctionRequest(StringInfo msgBuf) |
260 | { |
261 | LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); |
262 | Oid fid; |
263 | AclResult aclresult; |
264 | int16 rformat; |
265 | Datum retval; |
266 | struct fp_info my_fp; |
267 | struct fp_info *fip; |
268 | bool callit; |
269 | bool was_logged = false; |
270 | char msec_str[32]; |
271 | |
272 | /* |
273 | * We only accept COMMIT/ABORT if we are in an aborted transaction, and |
274 | * COMMIT/ABORT cannot be executed through the fastpath interface. |
275 | */ |
276 | if (IsAbortedTransactionBlockState()) |
277 | ereport(ERROR, |
278 | (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), |
279 | errmsg("current transaction is aborted, " |
280 | "commands ignored until end of transaction block" ))); |
281 | |
282 | /* |
283 | * Now that we know we are in a valid transaction, set snapshot in case |
284 | * needed by function itself or one of the datatype I/O routines. |
285 | */ |
286 | PushActiveSnapshot(GetTransactionSnapshot()); |
287 | |
288 | /* |
289 | * Begin parsing the buffer contents. |
290 | */ |
291 | if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) |
292 | (void) pq_getmsgstring(msgBuf); /* dummy string */ |
293 | |
294 | fid = (Oid) pq_getmsgint(msgBuf, 4); /* function oid */ |
295 | |
296 | /* |
297 | * There used to be a lame attempt at caching lookup info here. Now we |
298 | * just do the lookups on every call. |
299 | */ |
300 | fip = &my_fp; |
301 | fetch_fp_info(fid, fip); |
302 | |
303 | /* Log as soon as we have the function OID and name */ |
304 | if (log_statement == LOGSTMT_ALL) |
305 | { |
306 | ereport(LOG, |
307 | (errmsg("fastpath function call: \"%s\" (OID %u)" , |
308 | fip->fname, fid))); |
309 | was_logged = true; |
310 | } |
311 | |
312 | /* |
313 | * Check permission to access and call function. Since we didn't go |
314 | * through a normal name lookup, we need to check schema usage too. |
315 | */ |
316 | aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE); |
317 | if (aclresult != ACLCHECK_OK) |
318 | aclcheck_error(aclresult, OBJECT_SCHEMA, |
319 | get_namespace_name(fip->namespace)); |
320 | InvokeNamespaceSearchHook(fip->namespace, true); |
321 | |
322 | aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE); |
323 | if (aclresult != ACLCHECK_OK) |
324 | aclcheck_error(aclresult, OBJECT_FUNCTION, |
325 | get_func_name(fid)); |
326 | InvokeFunctionExecuteHook(fid); |
327 | |
328 | /* |
329 | * Prepare function call info block and insert arguments. |
330 | * |
331 | * Note: for now we pass collation = InvalidOid, so collation-sensitive |
332 | * functions can't be called this way. Perhaps we should pass |
333 | * DEFAULT_COLLATION_OID, instead? |
334 | */ |
335 | InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL); |
336 | |
337 | if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) |
338 | rformat = parse_fcall_arguments(msgBuf, fip, fcinfo); |
339 | else |
340 | rformat = parse_fcall_arguments_20(msgBuf, fip, fcinfo); |
341 | |
342 | /* Verify we reached the end of the message where expected. */ |
343 | pq_getmsgend(msgBuf); |
344 | |
345 | /* |
346 | * If func is strict, must not call it for null args. |
347 | */ |
348 | callit = true; |
349 | if (fip->flinfo.fn_strict) |
350 | { |
351 | int i; |
352 | |
353 | for (i = 0; i < fcinfo->nargs; i++) |
354 | { |
355 | if (fcinfo->args[i].isnull) |
356 | { |
357 | callit = false; |
358 | break; |
359 | } |
360 | } |
361 | } |
362 | |
363 | if (callit) |
364 | { |
365 | /* Okay, do it ... */ |
366 | retval = FunctionCallInvoke(fcinfo); |
367 | } |
368 | else |
369 | { |
370 | fcinfo->isnull = true; |
371 | retval = (Datum) 0; |
372 | } |
373 | |
374 | /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */ |
375 | CHECK_FOR_INTERRUPTS(); |
376 | |
377 | SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat); |
378 | |
379 | /* We no longer need the snapshot */ |
380 | PopActiveSnapshot(); |
381 | |
382 | /* |
383 | * Emit duration logging if appropriate. |
384 | */ |
385 | switch (check_log_duration(msec_str, was_logged)) |
386 | { |
387 | case 1: |
388 | ereport(LOG, |
389 | (errmsg("duration: %s ms" , msec_str))); |
390 | break; |
391 | case 2: |
392 | ereport(LOG, |
393 | (errmsg("duration: %s ms fastpath function call: \"%s\" (OID %u)" , |
394 | msec_str, fip->fname, fid))); |
395 | break; |
396 | } |
397 | } |
398 | |
399 | /* |
400 | * Parse function arguments in a 3.0 protocol message |
401 | * |
402 | * Argument values are loaded into *fcinfo, and the desired result format |
403 | * is returned. |
404 | */ |
405 | static int16 |
406 | parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip, |
407 | FunctionCallInfo fcinfo) |
408 | { |
409 | int nargs; |
410 | int i; |
411 | int numAFormats; |
412 | int16 *aformats = NULL; |
413 | StringInfoData abuf; |
414 | |
415 | /* Get the argument format codes */ |
416 | numAFormats = pq_getmsgint(msgBuf, 2); |
417 | if (numAFormats > 0) |
418 | { |
419 | aformats = (int16 *) palloc(numAFormats * sizeof(int16)); |
420 | for (i = 0; i < numAFormats; i++) |
421 | aformats[i] = pq_getmsgint(msgBuf, 2); |
422 | } |
423 | |
424 | nargs = pq_getmsgint(msgBuf, 2); /* # of arguments */ |
425 | |
426 | if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) |
427 | ereport(ERROR, |
428 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
429 | errmsg("function call message contains %d arguments but function requires %d" , |
430 | nargs, fip->flinfo.fn_nargs))); |
431 | |
432 | fcinfo->nargs = nargs; |
433 | |
434 | if (numAFormats > 1 && numAFormats != nargs) |
435 | ereport(ERROR, |
436 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
437 | errmsg("function call message contains %d argument formats but %d arguments" , |
438 | numAFormats, nargs))); |
439 | |
440 | initStringInfo(&abuf); |
441 | |
442 | /* |
443 | * Copy supplied arguments into arg vector. |
444 | */ |
445 | for (i = 0; i < nargs; ++i) |
446 | { |
447 | int argsize; |
448 | int16 aformat; |
449 | |
450 | argsize = pq_getmsgint(msgBuf, 4); |
451 | if (argsize == -1) |
452 | { |
453 | fcinfo->args[i].isnull = true; |
454 | } |
455 | else |
456 | { |
457 | fcinfo->args[i].isnull = false; |
458 | if (argsize < 0) |
459 | ereport(ERROR, |
460 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
461 | errmsg("invalid argument size %d in function call message" , |
462 | argsize))); |
463 | |
464 | /* Reset abuf to empty, and insert raw data into it */ |
465 | resetStringInfo(&abuf); |
466 | appendBinaryStringInfo(&abuf, |
467 | pq_getmsgbytes(msgBuf, argsize), |
468 | argsize); |
469 | } |
470 | |
471 | if (numAFormats > 1) |
472 | aformat = aformats[i]; |
473 | else if (numAFormats > 0) |
474 | aformat = aformats[0]; |
475 | else |
476 | aformat = 0; /* default = text */ |
477 | |
478 | if (aformat == 0) |
479 | { |
480 | Oid typinput; |
481 | Oid typioparam; |
482 | char *pstring; |
483 | |
484 | getTypeInputInfo(fip->argtypes[i], &typinput, &typioparam); |
485 | |
486 | /* |
487 | * Since stringinfo.c keeps a trailing null in place even for |
488 | * binary data, the contents of abuf are a valid C string. We |
489 | * have to do encoding conversion before calling the typinput |
490 | * routine, though. |
491 | */ |
492 | if (argsize == -1) |
493 | pstring = NULL; |
494 | else |
495 | pstring = pg_client_to_server(abuf.data, argsize); |
496 | |
497 | fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring, |
498 | typioparam, -1); |
499 | /* Free result of encoding conversion, if any */ |
500 | if (pstring && pstring != abuf.data) |
501 | pfree(pstring); |
502 | } |
503 | else if (aformat == 1) |
504 | { |
505 | Oid typreceive; |
506 | Oid typioparam; |
507 | StringInfo bufptr; |
508 | |
509 | /* Call the argument type's binary input converter */ |
510 | getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam); |
511 | |
512 | if (argsize == -1) |
513 | bufptr = NULL; |
514 | else |
515 | bufptr = &abuf; |
516 | |
517 | fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr, |
518 | typioparam, -1); |
519 | |
520 | /* Trouble if it didn't eat the whole buffer */ |
521 | if (argsize != -1 && abuf.cursor != abuf.len) |
522 | ereport(ERROR, |
523 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), |
524 | errmsg("incorrect binary data format in function argument %d" , |
525 | i + 1))); |
526 | } |
527 | else |
528 | ereport(ERROR, |
529 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
530 | errmsg("unsupported format code: %d" , aformat))); |
531 | } |
532 | |
533 | /* Return result format code */ |
534 | return (int16) pq_getmsgint(msgBuf, 2); |
535 | } |
536 | |
537 | /* |
538 | * Parse function arguments in a 2.0 protocol message |
539 | * |
540 | * Argument values are loaded into *fcinfo, and the desired result format |
541 | * is returned. |
542 | */ |
543 | static int16 |
544 | parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info *fip, |
545 | FunctionCallInfo fcinfo) |
546 | { |
547 | int nargs; |
548 | int i; |
549 | StringInfoData abuf; |
550 | |
551 | nargs = pq_getmsgint(msgBuf, 4); /* # of arguments */ |
552 | |
553 | if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) |
554 | ereport(ERROR, |
555 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
556 | errmsg("function call message contains %d arguments but function requires %d" , |
557 | nargs, fip->flinfo.fn_nargs))); |
558 | |
559 | fcinfo->nargs = nargs; |
560 | |
561 | initStringInfo(&abuf); |
562 | |
563 | /* |
564 | * Copy supplied arguments into arg vector. In protocol 2.0 these are |
565 | * always assumed to be supplied in binary format. |
566 | * |
567 | * Note: although the original protocol 2.0 code did not have any way for |
568 | * the frontend to specify a NULL argument, we now choose to interpret |
569 | * length == -1 as meaning a NULL. |
570 | */ |
571 | for (i = 0; i < nargs; ++i) |
572 | { |
573 | int argsize; |
574 | Oid typreceive; |
575 | Oid typioparam; |
576 | |
577 | getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam); |
578 | |
579 | argsize = pq_getmsgint(msgBuf, 4); |
580 | if (argsize == -1) |
581 | { |
582 | fcinfo->args[i].isnull = true; |
583 | fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL, |
584 | typioparam, -1); |
585 | continue; |
586 | } |
587 | fcinfo->args[i].isnull = false; |
588 | if (argsize < 0) |
589 | ereport(ERROR, |
590 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
591 | errmsg("invalid argument size %d in function call message" , |
592 | argsize))); |
593 | |
594 | /* Reset abuf to empty, and insert raw data into it */ |
595 | resetStringInfo(&abuf); |
596 | appendBinaryStringInfo(&abuf, |
597 | pq_getmsgbytes(msgBuf, argsize), |
598 | argsize); |
599 | |
600 | fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf, |
601 | typioparam, -1); |
602 | |
603 | /* Trouble if it didn't eat the whole buffer */ |
604 | if (abuf.cursor != abuf.len) |
605 | ereport(ERROR, |
606 | (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), |
607 | errmsg("incorrect binary data format in function argument %d" , |
608 | i + 1))); |
609 | } |
610 | |
611 | /* Desired result format is always binary in protocol 2.0 */ |
612 | return 1; |
613 | } |
614 | |