LCOV - code coverage report
Current view: top level - src/backend/tcop - fastpath.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 94 182 51.6 %
Date: 2019-11-13 23:06:49 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : GetOldFunctionMessage(StringInfo buf)
      78             : {
      79             :     int32       ibuf;
      80             :     int         nargs;
      81             : 
      82             :     /* Dummy string argument */
      83           0 :     if (pq_getstring(buf))
      84           0 :         return EOF;
      85             :     /* Function OID */
      86           0 :     if (pq_getbytes((char *) &ibuf, 4))
      87           0 :         return EOF;
      88           0 :     appendBinaryStringInfo(buf, (char *) &ibuf, 4);
      89             :     /* Number of arguments */
      90           0 :     if (pq_getbytes((char *) &ibuf, 4))
      91           0 :         return EOF;
      92           0 :     appendBinaryStringInfo(buf, (char *) &ibuf, 4);
      93           0 :     nargs = pg_ntoh32(ibuf);
      94             :     /* For each argument ... */
      95           0 :     while (nargs-- > 0)
      96             :     {
      97             :         int         argsize;
      98             : 
      99             :         /* argsize */
     100           0 :         if (pq_getbytes((char *) &ibuf, 4))
     101           0 :             return EOF;
     102           0 :         appendBinaryStringInfo(buf, (char *) &ibuf, 4);
     103           0 :         argsize = pg_ntoh32(ibuf);
     104           0 :         if (argsize < -1)
     105             :         {
     106             :             /* FATAL here since no hope of regaining message sync */
     107           0 :             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           0 :         if (argsize > 0)
     114             :         {
     115             :             /* Allocate space for arg */
     116           0 :             enlargeStringInfo(buf, argsize);
     117             :             /* And grab it */
     118           0 :             if (pq_getbytes(buf->data + buf->len, argsize))
     119           0 :                 return EOF;
     120           0 :             buf->len += argsize;
     121             :             /* Place a trailing null per StringInfo convention */
     122           0 :             buf->data[buf->len] = '\0';
     123             :         }
     124             :     }
     125           0 :     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        1228 : SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
     137             : {
     138        1228 :     bool        newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3);
     139             :     StringInfoData buf;
     140             : 
     141        1228 :     pq_beginmessage(&buf, 'V');
     142             : 
     143        1228 :     if (isnull)
     144             :     {
     145           0 :         if (newstyle)
     146           0 :             pq_sendint32(&buf, -1);
     147             :     }
     148             :     else
     149             :     {
     150        1228 :         if (!newstyle)
     151           0 :             pq_sendbyte(&buf, 'G');
     152             : 
     153        1228 :         if (format == 0)
     154             :         {
     155             :             Oid         typoutput;
     156             :             bool        typisvarlena;
     157             :             char       *outputstr;
     158             : 
     159           0 :             getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
     160           0 :             outputstr = OidOutputFunctionCall(typoutput, retval);
     161           0 :             pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
     162           0 :             pfree(outputstr);
     163             :         }
     164        1228 :         else if (format == 1)
     165             :         {
     166             :             Oid         typsend;
     167             :             bool        typisvarlena;
     168             :             bytea      *outputbytes;
     169             : 
     170        1228 :             getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
     171        1228 :             outputbytes = OidSendFunctionCall(typsend, retval);
     172        1228 :             pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
     173        1228 :             pq_sendbytes(&buf, VARDATA(outputbytes),
     174        1228 :                          VARSIZE(outputbytes) - VARHDRSZ);
     175        1228 :             pfree(outputbytes);
     176             :         }
     177             :         else
     178           0 :             ereport(ERROR,
     179             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     180             :                      errmsg("unsupported format code: %d", format)));
     181             :     }
     182             : 
     183        1228 :     if (!newstyle)
     184           0 :         pq_sendbyte(&buf, '0');
     185             : 
     186        1228 :     pq_endmessage(&buf);
     187        1228 : }
     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        1228 : 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        1228 :     MemSet(fip, 0, sizeof(struct fp_info));
     213        1228 :     fip->funcid = InvalidOid;
     214             : 
     215        1228 :     fmgr_info(func_id, &fip->flinfo);
     216             : 
     217        1228 :     func_htp = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_id));
     218        1228 :     if (!HeapTupleIsValid(func_htp))
     219           0 :         ereport(ERROR,
     220             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     221             :                  errmsg("function with OID %u does not exist", func_id)));
     222        1228 :     pp = (Form_pg_proc) GETSTRUCT(func_htp);
     223             : 
     224             :     /* watch out for catalog entries with more than FUNC_MAX_ARGS args */
     225        1228 :     if (pp->pronargs > FUNC_MAX_ARGS)
     226           0 :         elog(ERROR, "function %s has more than %d arguments",
     227             :              NameStr(pp->proname), FUNC_MAX_ARGS);
     228             : 
     229        1228 :     fip->namespace = pp->pronamespace;
     230        1228 :     fip->rettype = pp->prorettype;
     231        1228 :     memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid));
     232        1228 :     strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN);
     233             : 
     234        1228 :     ReleaseSysCache(func_htp);
     235             : 
     236             :     /*
     237             :      * This must be last!
     238             :      */
     239        1228 :     fip->funcid = func_id;
     240        1228 : }
     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        1228 : HandleFunctionRequest(StringInfo msgBuf)
     260             : {
     261        1228 :     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        1228 :     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        1228 :     if (IsAbortedTransactionBlockState())
     277           0 :         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        1228 :     PushActiveSnapshot(GetTransactionSnapshot());
     287             : 
     288             :     /*
     289             :      * Begin parsing the buffer contents.
     290             :      */
     291        1228 :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
     292           0 :         (void) pq_getmsgstring(msgBuf); /* dummy string */
     293             : 
     294        1228 :     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        1228 :     fip = &my_fp;
     301        1228 :     fetch_fp_info(fid, fip);
     302             : 
     303             :     /* Log as soon as we have the function OID and name */
     304        1228 :     if (log_statement == LOGSTMT_ALL)
     305             :     {
     306         152 :         ereport(LOG,
     307             :                 (errmsg("fastpath function call: \"%s\" (OID %u)",
     308             :                         fip->fname, fid)));
     309         152 :         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        1228 :     aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE);
     317        1228 :     if (aclresult != ACLCHECK_OK)
     318           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
     319           0 :                        get_namespace_name(fip->namespace));
     320        1228 :     InvokeNamespaceSearchHook(fip->namespace, true);
     321             : 
     322        1228 :     aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
     323        1228 :     if (aclresult != ACLCHECK_OK)
     324           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     325           0 :                        get_func_name(fid));
     326        1228 :     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        1228 :     InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
     336             : 
     337        1228 :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
     338        1228 :         rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
     339             :     else
     340           0 :         rformat = parse_fcall_arguments_20(msgBuf, fip, fcinfo);
     341             : 
     342             :     /* Verify we reached the end of the message where expected. */
     343        1228 :     pq_getmsgend(msgBuf);
     344             : 
     345             :     /*
     346             :      * If func is strict, must not call it for null args.
     347             :      */
     348        1228 :     callit = true;
     349        1228 :     if (fip->flinfo.fn_strict)
     350             :     {
     351             :         int         i;
     352             : 
     353        3602 :         for (i = 0; i < fcinfo->nargs; i++)
     354             :         {
     355        2374 :             if (fcinfo->args[i].isnull)
     356             :             {
     357           0 :                 callit = false;
     358           0 :                 break;
     359             :             }
     360             :         }
     361             :     }
     362             : 
     363        1228 :     if (callit)
     364             :     {
     365             :         /* Okay, do it ... */
     366        1228 :         retval = FunctionCallInvoke(fcinfo);
     367             :     }
     368             :     else
     369             :     {
     370           0 :         fcinfo->isnull = true;
     371           0 :         retval = (Datum) 0;
     372             :     }
     373             : 
     374             :     /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
     375        1228 :     CHECK_FOR_INTERRUPTS();
     376             : 
     377        1228 :     SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat);
     378             : 
     379             :     /* We no longer need the snapshot */
     380        1228 :     PopActiveSnapshot();
     381             : 
     382             :     /*
     383             :      * Emit duration logging if appropriate.
     384             :      */
     385        1228 :     switch (check_log_duration(msec_str, was_logged))
     386             :     {
     387             :         case 1:
     388           0 :             ereport(LOG,
     389             :                     (errmsg("duration: %s ms", msec_str)));
     390           0 :             break;
     391             :         case 2:
     392           0 :             ereport(LOG,
     393             :                     (errmsg("duration: %s ms  fastpath function call: \"%s\" (OID %u)",
     394             :                             msec_str, fip->fname, fid)));
     395           0 :             break;
     396             :     }
     397        1228 : }
     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        1228 : parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
     407             :                       FunctionCallInfo fcinfo)
     408             : {
     409             :     int         nargs;
     410             :     int         i;
     411             :     int         numAFormats;
     412        1228 :     int16      *aformats = NULL;
     413             :     StringInfoData abuf;
     414             : 
     415             :     /* Get the argument format codes */
     416        1228 :     numAFormats = pq_getmsgint(msgBuf, 2);
     417        1228 :     if (numAFormats > 0)
     418             :     {
     419        1228 :         aformats = (int16 *) palloc(numAFormats * sizeof(int16));
     420        2456 :         for (i = 0; i < numAFormats; i++)
     421        1228 :             aformats[i] = pq_getmsgint(msgBuf, 2);
     422             :     }
     423             : 
     424        1228 :     nargs = pq_getmsgint(msgBuf, 2);    /* # of arguments */
     425             : 
     426        1228 :     if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
     427           0 :         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        1228 :     fcinfo->nargs = nargs;
     433             : 
     434        1228 :     if (numAFormats > 1 && numAFormats != nargs)
     435           0 :         ereport(ERROR,
     436             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     437             :                  errmsg("function call message contains %d argument formats but %d arguments",
     438             :                         numAFormats, nargs)));
     439             : 
     440        1228 :     initStringInfo(&abuf);
     441             : 
     442             :     /*
     443             :      * Copy supplied arguments into arg vector.
     444             :      */
     445        3602 :     for (i = 0; i < nargs; ++i)
     446             :     {
     447             :         int         argsize;
     448             :         int16       aformat;
     449             : 
     450        2374 :         argsize = pq_getmsgint(msgBuf, 4);
     451        2374 :         if (argsize == -1)
     452             :         {
     453           0 :             fcinfo->args[i].isnull = true;
     454             :         }
     455             :         else
     456             :         {
     457        2374 :             fcinfo->args[i].isnull = false;
     458        2374 :             if (argsize < 0)
     459           0 :                 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        2374 :             resetStringInfo(&abuf);
     466        2374 :             appendBinaryStringInfo(&abuf,
     467             :                                    pq_getmsgbytes(msgBuf, argsize),
     468             :                                    argsize);
     469             :         }
     470             : 
     471        2374 :         if (numAFormats > 1)
     472           0 :             aformat = aformats[i];
     473        2374 :         else if (numAFormats > 0)
     474        2374 :             aformat = aformats[0];
     475             :         else
     476           0 :             aformat = 0;        /* default = text */
     477             : 
     478        2374 :         if (aformat == 0)
     479             :         {
     480             :             Oid         typinput;
     481             :             Oid         typioparam;
     482             :             char       *pstring;
     483             : 
     484           0 :             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           0 :             if (argsize == -1)
     493           0 :                 pstring = NULL;
     494             :             else
     495           0 :                 pstring = pg_client_to_server(abuf.data, argsize);
     496             : 
     497           0 :             fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring,
     498             :                                                          typioparam, -1);
     499             :             /* Free result of encoding conversion, if any */
     500           0 :             if (pstring && pstring != abuf.data)
     501           0 :                 pfree(pstring);
     502             :         }
     503        2374 :         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        2374 :             getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
     511             : 
     512        2374 :             if (argsize == -1)
     513           0 :                 bufptr = NULL;
     514             :             else
     515        2374 :                 bufptr = &abuf;
     516             : 
     517        2374 :             fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr,
     518             :                                                            typioparam, -1);
     519             : 
     520             :             /* Trouble if it didn't eat the whole buffer */
     521        2374 :             if (argsize != -1 && abuf.cursor != abuf.len)
     522           0 :                 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           0 :             ereport(ERROR,
     529             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     530             :                      errmsg("unsupported format code: %d", aformat)));
     531             :     }
     532             : 
     533             :     /* Return result format code */
     534        1228 :     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           0 : 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           0 :     nargs = pq_getmsgint(msgBuf, 4);    /* # of arguments */
     552             : 
     553           0 :     if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
     554           0 :         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           0 :     fcinfo->nargs = nargs;
     560             : 
     561           0 :     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           0 :     for (i = 0; i < nargs; ++i)
     572             :     {
     573             :         int         argsize;
     574             :         Oid         typreceive;
     575             :         Oid         typioparam;
     576             : 
     577           0 :         getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
     578             : 
     579           0 :         argsize = pq_getmsgint(msgBuf, 4);
     580           0 :         if (argsize == -1)
     581             :         {
     582           0 :             fcinfo->args[i].isnull = true;
     583           0 :             fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, NULL,
     584             :                                                            typioparam, -1);
     585           0 :             continue;
     586             :         }
     587           0 :         fcinfo->args[i].isnull = false;
     588           0 :         if (argsize < 0)
     589           0 :             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           0 :         resetStringInfo(&abuf);
     596           0 :         appendBinaryStringInfo(&abuf,
     597             :                                pq_getmsgbytes(msgBuf, argsize),
     598             :                                argsize);
     599             : 
     600           0 :         fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, &abuf,
     601             :                                                        typioparam, -1);
     602             : 
     603             :         /* Trouble if it didn't eat the whole buffer */
     604           0 :         if (abuf.cursor != abuf.len)
     605           0 :             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           0 :     return 1;
     613             : }

Generated by: LCOV version 1.13