00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "postgres.h"
00019
00020 #include <netinet/in.h>
00021 #include <arpa/inet.h>
00022
00023 #include "access/htup_details.h"
00024 #include "access/xact.h"
00025 #include "catalog/objectaccess.h"
00026 #include "catalog/pg_proc.h"
00027 #include "libpq/libpq.h"
00028 #include "libpq/pqformat.h"
00029 #include "mb/pg_wchar.h"
00030 #include "miscadmin.h"
00031 #include "tcop/fastpath.h"
00032 #include "tcop/tcopprot.h"
00033 #include "utils/acl.h"
00034 #include "utils/lsyscache.h"
00035 #include "utils/snapmgr.h"
00036 #include "utils/syscache.h"
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 struct fp_info
00051 {
00052 Oid funcid;
00053 FmgrInfo flinfo;
00054 Oid namespace;
00055 Oid rettype;
00056 Oid argtypes[FUNC_MAX_ARGS];
00057 char fname[NAMEDATALEN];
00058 };
00059
00060
00061 static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
00062 FunctionCallInfo fcinfo);
00063 static int16 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
00064 FunctionCallInfo fcinfo);
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 static int
00079 GetOldFunctionMessage(StringInfo buf)
00080 {
00081 int32 ibuf;
00082 int nargs;
00083
00084
00085 if (pq_getstring(buf))
00086 return EOF;
00087
00088 if (pq_getbytes((char *) &ibuf, 4))
00089 return EOF;
00090 appendBinaryStringInfo(buf, (char *) &ibuf, 4);
00091
00092 if (pq_getbytes((char *) &ibuf, 4))
00093 return EOF;
00094 appendBinaryStringInfo(buf, (char *) &ibuf, 4);
00095 nargs = ntohl(ibuf);
00096
00097 while (nargs-- > 0)
00098 {
00099 int argsize;
00100
00101
00102 if (pq_getbytes((char *) &ibuf, 4))
00103 return EOF;
00104 appendBinaryStringInfo(buf, (char *) &ibuf, 4);
00105 argsize = ntohl(ibuf);
00106 if (argsize < -1)
00107 {
00108
00109 ereport(FATAL,
00110 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00111 errmsg("invalid argument size %d in function call message",
00112 argsize)));
00113 }
00114
00115 if (argsize > 0)
00116 {
00117
00118 enlargeStringInfo(buf, argsize);
00119
00120 if (pq_getbytes(buf->data + buf->len, argsize))
00121 return EOF;
00122 buf->len += argsize;
00123
00124 buf->data[buf->len] = '\0';
00125 }
00126 }
00127 return 0;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137 static void
00138 SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
00139 {
00140 bool newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3);
00141 StringInfoData buf;
00142
00143 pq_beginmessage(&buf, 'V');
00144
00145 if (isnull)
00146 {
00147 if (newstyle)
00148 pq_sendint(&buf, -1, 4);
00149 }
00150 else
00151 {
00152 if (!newstyle)
00153 pq_sendbyte(&buf, 'G');
00154
00155 if (format == 0)
00156 {
00157 Oid typoutput;
00158 bool typisvarlena;
00159 char *outputstr;
00160
00161 getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
00162 outputstr = OidOutputFunctionCall(typoutput, retval);
00163 pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
00164 pfree(outputstr);
00165 }
00166 else if (format == 1)
00167 {
00168 Oid typsend;
00169 bool typisvarlena;
00170 bytea *outputbytes;
00171
00172 getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
00173 outputbytes = OidSendFunctionCall(typsend, retval);
00174 pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
00175 pq_sendbytes(&buf, VARDATA(outputbytes),
00176 VARSIZE(outputbytes) - VARHDRSZ);
00177 pfree(outputbytes);
00178 }
00179 else
00180 ereport(ERROR,
00181 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00182 errmsg("unsupported format code: %d", format)));
00183 }
00184
00185 if (!newstyle)
00186 pq_sendbyte(&buf, '0');
00187
00188 pq_endmessage(&buf);
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 static void
00198 fetch_fp_info(Oid func_id, struct fp_info * fip)
00199 {
00200 HeapTuple func_htp;
00201 Form_pg_proc pp;
00202
00203 Assert(OidIsValid(func_id));
00204 Assert(fip != NULL);
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 MemSet(fip, 0, sizeof(struct fp_info));
00215 fip->funcid = InvalidOid;
00216
00217 fmgr_info(func_id, &fip->flinfo);
00218
00219 func_htp = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_id));
00220 if (!HeapTupleIsValid(func_htp))
00221 ereport(ERROR,
00222 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00223 errmsg("function with OID %u does not exist", func_id)));
00224 pp = (Form_pg_proc) GETSTRUCT(func_htp);
00225
00226
00227 if (pp->pronargs > FUNC_MAX_ARGS)
00228 elog(ERROR, "function %s has more than %d arguments",
00229 NameStr(pp->proname), FUNC_MAX_ARGS);
00230
00231 fip->namespace = pp->pronamespace;
00232 fip->rettype = pp->prorettype;
00233 memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid));
00234 strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN);
00235
00236 ReleaseSysCache(func_htp);
00237
00238
00239
00240
00241 fip->funcid = func_id;
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 int
00270 HandleFunctionRequest(StringInfo msgBuf)
00271 {
00272 Oid fid;
00273 AclResult aclresult;
00274 FunctionCallInfoData fcinfo;
00275 int16 rformat;
00276 Datum retval;
00277 struct fp_info my_fp;
00278 struct fp_info *fip;
00279 bool callit;
00280 bool was_logged = false;
00281 char msec_str[32];
00282
00283
00284
00285
00286 if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00287 {
00288 if (GetOldFunctionMessage(msgBuf))
00289 {
00290 if (IsTransactionState())
00291 ereport(COMMERROR,
00292 (errcode(ERRCODE_CONNECTION_FAILURE),
00293 errmsg("unexpected EOF on client connection with an open transaction")));
00294 else
00295 {
00296
00297
00298
00299
00300
00301 whereToSendOutput = DestNone;
00302 ereport(DEBUG1,
00303 (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
00304 errmsg("unexpected EOF on client connection")));
00305 }
00306 return EOF;
00307 }
00308 }
00309
00310
00311
00312
00313
00314
00315 if (IsAbortedTransactionBlockState())
00316 ereport(ERROR,
00317 (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
00318 errmsg("current transaction is aborted, "
00319 "commands ignored until end of transaction block")));
00320
00321
00322
00323
00324
00325 PushActiveSnapshot(GetTransactionSnapshot());
00326
00327
00328
00329
00330 if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00331 (void) pq_getmsgstring(msgBuf);
00332
00333 fid = (Oid) pq_getmsgint(msgBuf, 4);
00334
00335
00336
00337
00338
00339 fip = &my_fp;
00340 fetch_fp_info(fid, fip);
00341
00342
00343 if (log_statement == LOGSTMT_ALL)
00344 {
00345 ereport(LOG,
00346 (errmsg("fastpath function call: \"%s\" (OID %u)",
00347 fip->fname, fid)));
00348 was_logged = true;
00349 }
00350
00351
00352
00353
00354
00355 aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE);
00356 if (aclresult != ACLCHECK_OK)
00357 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00358 get_namespace_name(fip->namespace));
00359 InvokeNamespaceSearchHook(fip->namespace, true);
00360
00361 aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
00362 if (aclresult != ACLCHECK_OK)
00363 aclcheck_error(aclresult, ACL_KIND_PROC,
00364 get_func_name(fid));
00365 InvokeFunctionExecuteHook(fid);
00366
00367
00368
00369
00370
00371
00372
00373
00374 InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
00375
00376 if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
00377 rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
00378 else
00379 rformat = parse_fcall_arguments_20(msgBuf, fip, &fcinfo);
00380
00381
00382 pq_getmsgend(msgBuf);
00383
00384
00385
00386
00387 callit = true;
00388 if (fip->flinfo.fn_strict)
00389 {
00390 int i;
00391
00392 for (i = 0; i < fcinfo.nargs; i++)
00393 {
00394 if (fcinfo.argnull[i])
00395 {
00396 callit = false;
00397 break;
00398 }
00399 }
00400 }
00401
00402 if (callit)
00403 {
00404
00405 retval = FunctionCallInvoke(&fcinfo);
00406 }
00407 else
00408 {
00409 fcinfo.isnull = true;
00410 retval = (Datum) 0;
00411 }
00412
00413
00414 CHECK_FOR_INTERRUPTS();
00415
00416 SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
00417
00418
00419 PopActiveSnapshot();
00420
00421
00422
00423
00424 switch (check_log_duration(msec_str, was_logged))
00425 {
00426 case 1:
00427 ereport(LOG,
00428 (errmsg("duration: %s ms", msec_str)));
00429 break;
00430 case 2:
00431 ereport(LOG,
00432 (errmsg("duration: %s ms fastpath function call: \"%s\" (OID %u)",
00433 msec_str, fip->fname, fid)));
00434 break;
00435 }
00436
00437 return 0;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446 static int16
00447 parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
00448 FunctionCallInfo fcinfo)
00449 {
00450 int nargs;
00451 int i;
00452 int numAFormats;
00453 int16 *aformats = NULL;
00454 StringInfoData abuf;
00455
00456
00457 numAFormats = pq_getmsgint(msgBuf, 2);
00458 if (numAFormats > 0)
00459 {
00460 aformats = (int16 *) palloc(numAFormats * sizeof(int16));
00461 for (i = 0; i < numAFormats; i++)
00462 aformats[i] = pq_getmsgint(msgBuf, 2);
00463 }
00464
00465 nargs = pq_getmsgint(msgBuf, 2);
00466
00467 if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
00468 ereport(ERROR,
00469 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00470 errmsg("function call message contains %d arguments but function requires %d",
00471 nargs, fip->flinfo.fn_nargs)));
00472
00473 fcinfo->nargs = nargs;
00474
00475 if (numAFormats > 1 && numAFormats != nargs)
00476 ereport(ERROR,
00477 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00478 errmsg("function call message contains %d argument formats but %d arguments",
00479 numAFormats, nargs)));
00480
00481 initStringInfo(&abuf);
00482
00483
00484
00485
00486 for (i = 0; i < nargs; ++i)
00487 {
00488 int argsize;
00489 int16 aformat;
00490
00491 argsize = pq_getmsgint(msgBuf, 4);
00492 if (argsize == -1)
00493 {
00494 fcinfo->argnull[i] = true;
00495 }
00496 else
00497 {
00498 fcinfo->argnull[i] = false;
00499 if (argsize < 0)
00500 ereport(ERROR,
00501 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00502 errmsg("invalid argument size %d in function call message",
00503 argsize)));
00504
00505
00506 resetStringInfo(&abuf);
00507 appendBinaryStringInfo(&abuf,
00508 pq_getmsgbytes(msgBuf, argsize),
00509 argsize);
00510 }
00511
00512 if (numAFormats > 1)
00513 aformat = aformats[i];
00514 else if (numAFormats > 0)
00515 aformat = aformats[0];
00516 else
00517 aformat = 0;
00518
00519 if (aformat == 0)
00520 {
00521 Oid typinput;
00522 Oid typioparam;
00523 char *pstring;
00524
00525 getTypeInputInfo(fip->argtypes[i], &typinput, &typioparam);
00526
00527
00528
00529
00530
00531
00532
00533 if (argsize == -1)
00534 pstring = NULL;
00535 else
00536 pstring = pg_client_to_server(abuf.data, argsize);
00537
00538 fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
00539 typioparam, -1);
00540
00541 if (pstring && pstring != abuf.data)
00542 pfree(pstring);
00543 }
00544 else if (aformat == 1)
00545 {
00546 Oid typreceive;
00547 Oid typioparam;
00548 StringInfo bufptr;
00549
00550
00551 getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
00552
00553 if (argsize == -1)
00554 bufptr = NULL;
00555 else
00556 bufptr = &abuf;
00557
00558 fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
00559 typioparam, -1);
00560
00561
00562 if (argsize != -1 && abuf.cursor != abuf.len)
00563 ereport(ERROR,
00564 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00565 errmsg("incorrect binary data format in function argument %d",
00566 i + 1)));
00567 }
00568 else
00569 ereport(ERROR,
00570 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00571 errmsg("unsupported format code: %d", aformat)));
00572 }
00573
00574
00575 return (int16) pq_getmsgint(msgBuf, 2);
00576 }
00577
00578
00579
00580
00581
00582
00583
00584 static int16
00585 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
00586 FunctionCallInfo fcinfo)
00587 {
00588 int nargs;
00589 int i;
00590 StringInfoData abuf;
00591
00592 nargs = pq_getmsgint(msgBuf, 4);
00593
00594 if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
00595 ereport(ERROR,
00596 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00597 errmsg("function call message contains %d arguments but function requires %d",
00598 nargs, fip->flinfo.fn_nargs)));
00599
00600 fcinfo->nargs = nargs;
00601
00602 initStringInfo(&abuf);
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 for (i = 0; i < nargs; ++i)
00613 {
00614 int argsize;
00615 Oid typreceive;
00616 Oid typioparam;
00617
00618 getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
00619
00620 argsize = pq_getmsgint(msgBuf, 4);
00621 if (argsize == -1)
00622 {
00623 fcinfo->argnull[i] = true;
00624 fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
00625 typioparam, -1);
00626 continue;
00627 }
00628 fcinfo->argnull[i] = false;
00629 if (argsize < 0)
00630 ereport(ERROR,
00631 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00632 errmsg("invalid argument size %d in function call message",
00633 argsize)));
00634
00635
00636 resetStringInfo(&abuf);
00637 appendBinaryStringInfo(&abuf,
00638 pq_getmsgbytes(msgBuf, argsize),
00639 argsize);
00640
00641 fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
00642 typioparam, -1);
00643
00644
00645 if (abuf.cursor != abuf.len)
00646 ereport(ERROR,
00647 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00648 errmsg("incorrect binary data format in function argument %d",
00649 i + 1)));
00650 }
00651
00652
00653 return 1;
00654 }