Header And Logo

PostgreSQL
| The world's most advanced open source database.

fastpath.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * fastpath.c
00004  *    routines to handle function requests from the frontend
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/tcop/fastpath.c
00012  *
00013  * NOTES
00014  *    This cruft is the server side of PQfn.
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  * Formerly, this code attempted to cache the function and type info
00041  * looked up by fetch_fp_info, but only for the duration of a single
00042  * transaction command (since in theory the info could change between
00043  * commands).  This was utterly useless, because postgres.c executes
00044  * each fastpath call as a separate transaction command, and so the
00045  * cached data could never actually have been reused.  If it had worked
00046  * as intended, it would have had problems anyway with dangling references
00047  * in the FmgrInfo struct.  So, forget about caching and just repeat the
00048  * syscache fetches on each usage.  They're not *that* expensive.
00049  */
00050 struct fp_info
00051 {
00052     Oid         funcid;
00053     FmgrInfo    flinfo;         /* function lookup info for funcid */
00054     Oid         namespace;      /* other stuff from pg_proc */
00055     Oid         rettype;
00056     Oid         argtypes[FUNC_MAX_ARGS];
00057     char        fname[NAMEDATALEN];     /* function name for logging */
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  *      GetOldFunctionMessage
00069  *
00070  * In pre-3.0 protocol, there is no length word on the message, so we have
00071  * to have code that understands the message layout to absorb the message
00072  * into a buffer.  We want to do this before we start execution, so that
00073  * we do not lose sync with the frontend if there's an error.
00074  *
00075  * The caller should already have initialized buf to empty.
00076  * ----------------
00077  */
00078 static int
00079 GetOldFunctionMessage(StringInfo buf)
00080 {
00081     int32       ibuf;
00082     int         nargs;
00083 
00084     /* Dummy string argument */
00085     if (pq_getstring(buf))
00086         return EOF;
00087     /* Function OID */
00088     if (pq_getbytes((char *) &ibuf, 4))
00089         return EOF;
00090     appendBinaryStringInfo(buf, (char *) &ibuf, 4);
00091     /* Number of arguments */
00092     if (pq_getbytes((char *) &ibuf, 4))
00093         return EOF;
00094     appendBinaryStringInfo(buf, (char *) &ibuf, 4);
00095     nargs = ntohl(ibuf);
00096     /* For each argument ... */
00097     while (nargs-- > 0)
00098     {
00099         int         argsize;
00100 
00101         /* argsize */
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             /* FATAL here since no hope of regaining message sync */
00109             ereport(FATAL,
00110                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
00111                   errmsg("invalid argument size %d in function call message",
00112                          argsize)));
00113         }
00114         /* and arg contents */
00115         if (argsize > 0)
00116         {
00117             /* Allocate space for arg */
00118             enlargeStringInfo(buf, argsize);
00119             /* And grab it */
00120             if (pq_getbytes(buf->data + buf->len, argsize))
00121                 return EOF;
00122             buf->len += argsize;
00123             /* Place a trailing null per StringInfo convention */
00124             buf->data[buf->len] = '\0';
00125         }
00126     }
00127     return 0;
00128 }
00129 
00130 /* ----------------
00131  *      SendFunctionResult
00132  *
00133  * Note: although this routine doesn't check, the format had better be 1
00134  * (binary) when talking to a pre-3.0 client.
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  * fetch_fp_info
00193  *
00194  * Performs catalog lookups to load a struct fp_info 'fip' for the
00195  * function 'func_id'.
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      * Since the validity of this structure is determined by whether the
00208      * funcid is OK, we clear the funcid here.  It must not be set to the
00209      * correct value until we are about to return with a good struct fp_info,
00210      * since we can be interrupted (i.e., with an ereport(ERROR, ...)) at any
00211      * time.  [No longer really an issue since we don't save the struct
00212      * fp_info across transactions anymore, but keep it anyway.]
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     /* watch out for catalog entries with more than FUNC_MAX_ARGS args */
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      * This must be last!
00240      */
00241     fip->funcid = func_id;
00242 }
00243 
00244 
00245 /*
00246  * HandleFunctionRequest
00247  *
00248  * Server side of PQfn (fastpath function calls from the frontend).
00249  * This corresponds to the libpq protocol symbol "F".
00250  *
00251  * INPUT:
00252  *      In protocol version 3, postgres.c has already read the message body
00253  *      and will pass it in msgBuf.
00254  *      In old protocol, the passed msgBuf is empty and we must read the
00255  *      message here.
00256  *
00257  * RETURNS:
00258  *      0 if successful completion, EOF if frontend connection lost.
00259  *
00260  * Note: All ordinary errors result in ereport(ERROR,...).  However,
00261  * if we lose the frontend connection there is no one to ereport to,
00262  * and no use in proceeding...
00263  *
00264  * Note: palloc()s done here and in the called function do not need to be
00265  * cleaned up explicitly.  We are called from PostgresMain() in the
00266  * MessageContext memory context, which will be automatically reset when
00267  * control returns to PostgresMain.
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      * Read message contents if not already done.
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                  * Can't send DEBUG log messages to client at this point.
00298                  * Since we're disconnecting right away, we don't need to
00299                  * restore whereToSendOutput.
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      * Now that we've eaten the input message, check to see if we actually
00312      * want to do the function call or not.  It's now safe to ereport(); we
00313      * won't lose sync with the frontend.
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      * Now that we know we are in a valid transaction, set snapshot in case
00323      * needed by function itself or one of the datatype I/O routines.
00324      */
00325     PushActiveSnapshot(GetTransactionSnapshot());
00326 
00327     /*
00328      * Begin parsing the buffer contents.
00329      */
00330     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00331         (void) pq_getmsgstring(msgBuf); /* dummy string */
00332 
00333     fid = (Oid) pq_getmsgint(msgBuf, 4);        /* function oid */
00334 
00335     /*
00336      * There used to be a lame attempt at caching lookup info here. Now we
00337      * just do the lookups on every call.
00338      */
00339     fip = &my_fp;
00340     fetch_fp_info(fid, fip);
00341 
00342     /* Log as soon as we have the function OID and name */
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      * Check permission to access and call function.  Since we didn't go
00353      * through a normal name lookup, we need to check schema usage too.
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      * Prepare function call info block and insert arguments.
00369      *
00370      * Note: for now we pass collation = InvalidOid, so collation-sensitive
00371      * functions can't be called this way.  Perhaps we should pass
00372      * DEFAULT_COLLATION_OID, instead?
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     /* Verify we reached the end of the message where expected. */
00382     pq_getmsgend(msgBuf);
00383 
00384     /*
00385      * If func is strict, must not call it for null args.
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         /* Okay, do it ... */
00405         retval = FunctionCallInvoke(&fcinfo);
00406     }
00407     else
00408     {
00409         fcinfo.isnull = true;
00410         retval = (Datum) 0;
00411     }
00412 
00413     /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
00414     CHECK_FOR_INTERRUPTS();
00415 
00416     SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
00417 
00418     /* We no longer need the snapshot */
00419     PopActiveSnapshot();
00420 
00421     /*
00422      * Emit duration logging if appropriate.
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  * Parse function arguments in a 3.0 protocol message
00442  *
00443  * Argument values are loaded into *fcinfo, and the desired result format
00444  * is returned.
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     /* Get the argument format codes */
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);    /* # of arguments */
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      * Copy supplied arguments into arg vector.
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             /* Reset abuf to empty, and insert raw data into it */
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;        /* default = text */
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              * Since stringinfo.c keeps a trailing null in place even for
00529              * binary data, the contents of abuf are a valid C string.  We
00530              * have to do encoding conversion before calling the typinput
00531              * routine, though.
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             /* Free result of encoding conversion, if any */
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             /* Call the argument type's binary input converter */
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             /* Trouble if it didn't eat the whole buffer */
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     /* Return result format code */
00575     return (int16) pq_getmsgint(msgBuf, 2);
00576 }
00577 
00578 /*
00579  * Parse function arguments in a 2.0 protocol message
00580  *
00581  * Argument values are loaded into *fcinfo, and the desired result format
00582  * is returned.
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);    /* # of arguments */
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      * Copy supplied arguments into arg vector.  In protocol 2.0 these are
00606      * always assumed to be supplied in binary format.
00607      *
00608      * Note: although the original protocol 2.0 code did not have any way for
00609      * the frontend to specify a NULL argument, we now choose to interpret
00610      * length == -1 as meaning a NULL.
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         /* Reset abuf to empty, and insert raw data into it */
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         /* Trouble if it didn't eat the whole buffer */
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     /* Desired result format is always binary in protocol 2.0 */
00653     return 1;
00654 }