LCOV - code coverage report
Current view: top level - src/backend/tcop - fastpath.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 72.2 % 176 127
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 32.1 % 137 44

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * fastpath.c
       4                 :             :  *        routines to handle function requests from the frontend
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, 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_namespace.h"
      24                 :             : #include "catalog/pg_proc.h"
      25                 :             : #include "libpq/pqformat.h"
      26                 :             : #include "libpq/protocol.h"
      27                 :             : #include "mb/pg_wchar.h"
      28                 :             : #include "miscadmin.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                 :             : 
      62                 :             : /* ----------------
      63                 :             :  *              SendFunctionResult
      64                 :             :  * ----------------
      65                 :             :  */
      66                 :             : static void
      67                 :         259 : SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
      68                 :             : {
      69                 :         259 :         StringInfoData buf;
      70                 :             : 
      71                 :         259 :         pq_beginmessage(&buf, PqMsg_FunctionCallResponse);
      72                 :             : 
      73         [ -  + ]:         259 :         if (isnull)
      74                 :             :         {
      75                 :           0 :                 pq_sendint32(&buf, -1);
      76                 :           0 :         }
      77                 :             :         else
      78                 :             :         {
      79         [ +  - ]:         259 :                 if (format == 0)
      80                 :             :                 {
      81                 :           0 :                         Oid                     typoutput;
      82                 :           0 :                         bool            typisvarlena;
      83                 :           0 :                         char       *outputstr;
      84                 :             : 
      85                 :           0 :                         getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
      86                 :           0 :                         outputstr = OidOutputFunctionCall(typoutput, retval);
      87                 :           0 :                         pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
      88                 :           0 :                         pfree(outputstr);
      89                 :           0 :                 }
      90         [ +  - ]:         259 :                 else if (format == 1)
      91                 :             :                 {
      92                 :         259 :                         Oid                     typsend;
      93                 :         259 :                         bool            typisvarlena;
      94                 :         259 :                         bytea      *outputbytes;
      95                 :             : 
      96                 :         259 :                         getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
      97                 :         259 :                         outputbytes = OidSendFunctionCall(typsend, retval);
      98                 :         259 :                         pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
      99                 :         518 :                         pq_sendbytes(&buf, VARDATA(outputbytes),
     100                 :         259 :                                                  VARSIZE(outputbytes) - VARHDRSZ);
     101                 :         259 :                         pfree(outputbytes);
     102                 :         259 :                 }
     103                 :             :                 else
     104   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     105                 :             :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     106                 :             :                                          errmsg("unsupported format code: %d", format)));
     107                 :             :         }
     108                 :             : 
     109                 :         259 :         pq_endmessage(&buf);
     110                 :         259 : }
     111                 :             : 
     112                 :             : /*
     113                 :             :  * fetch_fp_info
     114                 :             :  *
     115                 :             :  * Performs catalog lookups to load a struct fp_info 'fip' for the
     116                 :             :  * function 'func_id'.
     117                 :             :  */
     118                 :             : static void
     119                 :         259 : fetch_fp_info(Oid func_id, struct fp_info *fip)
     120                 :             : {
     121                 :         259 :         HeapTuple       func_htp;
     122                 :         259 :         Form_pg_proc pp;
     123                 :             : 
     124         [ +  - ]:         259 :         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   [ +  -  +  -  :       17353 :         MemSet(fip, 0, sizeof(struct fp_info));
          +  -  -  +  +  
                      + ]
     135                 :         259 :         fip->funcid = InvalidOid;
     136                 :             : 
     137                 :         259 :         func_htp = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_id));
     138         [ +  - ]:         259 :         if (!HeapTupleIsValid(func_htp))
     139   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     140                 :             :                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     141                 :             :                                  errmsg("function with OID %u does not exist", func_id)));
     142                 :         259 :         pp = (Form_pg_proc) GETSTRUCT(func_htp);
     143                 :             : 
     144                 :             :         /* reject pg_proc entries that are unsafe to call via fastpath */
     145         [ +  - ]:         259 :         if (pp->prokind != PROKIND_FUNCTION || pp->proretset)
     146   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     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         [ +  - ]:         259 :         if (pp->pronargs > FUNC_MAX_ARGS)
     153   [ #  #  #  # ]:           0 :                 elog(ERROR, "function %s has more than %d arguments",
     154                 :             :                          NameStr(pp->proname), FUNC_MAX_ARGS);
     155                 :             : 
     156                 :         259 :         fip->namespace = pp->pronamespace;
     157                 :         259 :         fip->rettype = pp->prorettype;
     158                 :         259 :         memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid));
     159                 :         259 :         strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN);
     160                 :             : 
     161                 :         259 :         ReleaseSysCache(func_htp);
     162                 :             : 
     163                 :         259 :         fmgr_info(func_id, &fip->flinfo);
     164                 :             : 
     165                 :             :         /*
     166                 :             :          * This must be last!
     167                 :             :          */
     168                 :         259 :         fip->funcid = func_id;
     169                 :         259 : }
     170                 :             : 
     171                 :             : 
     172                 :             : /*
     173                 :             :  * HandleFunctionRequest
     174                 :             :  *
     175                 :             :  * Server side of PQfn (fastpath function calls from the frontend).
     176                 :             :  * This corresponds to the libpq protocol symbol "F".
     177                 :             :  *
     178                 :             :  * INPUT:
     179                 :             :  *              postgres.c has already read the message body and will pass it in
     180                 :             :  *              msgBuf.
     181                 :             :  *
     182                 :             :  * Note: palloc()s done here and in the called function do not need to be
     183                 :             :  * cleaned up explicitly.  We are called from PostgresMain() in the
     184                 :             :  * MessageContext memory context, which will be automatically reset when
     185                 :             :  * control returns to PostgresMain.
     186                 :             :  */
     187                 :             : void
     188                 :         259 : HandleFunctionRequest(StringInfo msgBuf)
     189                 :             : {
     190                 :         259 :         LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
     191                 :         259 :         Oid                     fid;
     192                 :         259 :         AclResult       aclresult;
     193                 :         259 :         int16           rformat;
     194                 :         259 :         Datum           retval;
     195                 :         259 :         struct fp_info my_fp;
     196                 :         259 :         struct fp_info *fip;
     197                 :         259 :         bool            callit;
     198                 :         259 :         bool            was_logged = false;
     199                 :         259 :         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                 :             :          */
     205         [ +  - ]:         259 :         if (IsAbortedTransactionBlockState())
     206   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     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                 :             :          */
     215                 :         259 :         PushActiveSnapshot(GetTransactionSnapshot());
     216                 :             : 
     217                 :             :         /*
     218                 :             :          * Begin parsing the buffer contents.
     219                 :             :          */
     220                 :         259 :         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                 :         259 :         fip = &my_fp;
     227                 :         259 :         fetch_fp_info(fid, fip);
     228                 :             : 
     229                 :             :         /* Log as soon as we have the function OID and name */
     230         [ -  + ]:         259 :         if (log_statement == LOGSTMT_ALL)
     231                 :             :         {
     232   [ -  +  +  - ]:         259 :                 ereport(LOG,
     233                 :             :                                 (errmsg("fastpath function call: \"%s\" (OID %u)",
     234                 :             :                                                 fip->fname, fid)));
     235                 :         259 :                 was_logged = true;
     236                 :         259 :         }
     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                 :         259 :         aclresult = object_aclcheck(NamespaceRelationId, fip->namespace, GetUserId(), ACL_USAGE);
     243         [ +  - ]:         259 :         if (aclresult != ACLCHECK_OK)
     244                 :           0 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
     245                 :           0 :                                            get_namespace_name(fip->namespace));
     246         [ -  + ]:         259 :         InvokeNamespaceSearchHook(fip->namespace, true);
     247                 :             : 
     248                 :         259 :         aclresult = object_aclcheck(ProcedureRelationId, fid, GetUserId(), ACL_EXECUTE);
     249         [ +  - ]:         259 :         if (aclresult != ACLCHECK_OK)
     250                 :           0 :                 aclcheck_error(aclresult, OBJECT_FUNCTION,
     251                 :           0 :                                            get_func_name(fid));
     252         [ +  - ]:         259 :         InvokeFunctionExecuteHook(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                 :         259 :         InitFunctionCallInfoData(*fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
     262                 :             : 
     263                 :         259 :         rformat = parse_fcall_arguments(msgBuf, fip, fcinfo);
     264                 :             : 
     265                 :             :         /* Verify we reached the end of the message where expected. */
     266                 :         259 :         pq_getmsgend(msgBuf);
     267                 :             : 
     268                 :             :         /*
     269                 :             :          * If func is strict, must not call it for null args.
     270                 :             :          */
     271                 :         259 :         callit = true;
     272         [ -  + ]:         259 :         if (fip->flinfo.fn_strict)
     273                 :             :         {
     274                 :         259 :                 int                     i;
     275                 :             : 
     276         [ +  + ]:         768 :                 for (i = 0; i < fcinfo->nargs; i++)
     277                 :             :                 {
     278         [ -  + ]:         509 :                         if (fcinfo->args[i].isnull)
     279                 :             :                         {
     280                 :           0 :                                 callit = false;
     281                 :           0 :                                 break;
     282                 :             :                         }
     283                 :         509 :                 }
     284                 :         259 :         }
     285                 :             : 
     286         [ +  - ]:         259 :         if (callit)
     287                 :             :         {
     288                 :             :                 /* Okay, do it ... */
     289                 :         259 :                 retval = FunctionCallInvoke(fcinfo);
     290                 :         259 :         }
     291                 :             :         else
     292                 :             :         {
     293                 :           0 :                 fcinfo->isnull = true;
     294                 :           0 :                 retval = (Datum) 0;
     295                 :             :         }
     296                 :             : 
     297                 :             :         /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
     298         [ +  - ]:         259 :         CHECK_FOR_INTERRUPTS();
     299                 :             : 
     300                 :         259 :         SendFunctionResult(retval, fcinfo->isnull, fip->rettype, rformat);
     301                 :             : 
     302                 :             :         /* We no longer need the snapshot */
     303                 :         259 :         PopActiveSnapshot();
     304                 :             : 
     305                 :             :         /*
     306                 :             :          * Emit duration logging if appropriate.
     307                 :             :          */
     308      [ +  -  - ]:         259 :         switch (check_log_duration(msec_str, was_logged))
     309                 :             :         {
     310                 :             :                 case 1:
     311   [ #  #  #  # ]:           0 :                         ereport(LOG,
     312                 :             :                                         (errmsg("duration: %s ms", msec_str)));
     313                 :           0 :                         break;
     314                 :             :                 case 2:
     315   [ #  #  #  # ]:           0 :                         ereport(LOG,
     316                 :             :                                         (errmsg("duration: %s ms  fastpath function call: \"%s\" (OID %u)",
     317                 :             :                                                         msec_str, fip->fname, fid)));
     318                 :           0 :                         break;
     319                 :             :         }
     320                 :         259 : }
     321                 :             : 
     322                 :             : /*
     323                 :             :  * Parse function arguments in a 3.0 protocol message
     324                 :             :  *
     325                 :             :  * Argument values are loaded into *fcinfo, and the desired result format
     326                 :             :  * is returned.
     327                 :             :  */
     328                 :             : static int16
     329                 :         259 : parse_fcall_arguments(StringInfo msgBuf, struct fp_info *fip,
     330                 :             :                                           FunctionCallInfo fcinfo)
     331                 :             : {
     332                 :         259 :         int                     nargs;
     333                 :         259 :         int                     i;
     334                 :         259 :         int                     numAFormats;
     335                 :         259 :         int16      *aformats = NULL;
     336                 :         259 :         StringInfoData abuf;
     337                 :             : 
     338                 :             :         /* Get the argument format codes */
     339                 :         259 :         numAFormats = pq_getmsgint(msgBuf, 2);
     340         [ -  + ]:         259 :         if (numAFormats > 0)
     341                 :             :         {
     342                 :         259 :                 aformats = (int16 *) palloc(numAFormats * sizeof(int16));
     343         [ +  + ]:         518 :                 for (i = 0; i < numAFormats; i++)
     344                 :         259 :                         aformats[i] = pq_getmsgint(msgBuf, 2);
     345                 :         259 :         }
     346                 :             : 
     347                 :         259 :         nargs = pq_getmsgint(msgBuf, 2);        /* # of arguments */
     348                 :             : 
     349         [ +  - ]:         259 :         if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
     350   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     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                 :         259 :         fcinfo->nargs = nargs;
     356                 :             : 
     357   [ -  +  #  # ]:         259 :         if (numAFormats > 1 && numAFormats != nargs)
     358   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     359                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     360                 :             :                                  errmsg("function call message contains %d argument formats but %d arguments",
     361                 :             :                                                 numAFormats, nargs)));
     362                 :             : 
     363                 :         259 :         initStringInfo(&abuf);
     364                 :             : 
     365                 :             :         /*
     366                 :             :          * Copy supplied arguments into arg vector.
     367                 :             :          */
     368         [ +  + ]:         768 :         for (i = 0; i < nargs; ++i)
     369                 :             :         {
     370                 :         509 :                 int                     argsize;
     371                 :         509 :                 int16           aformat;
     372                 :             : 
     373                 :         509 :                 argsize = pq_getmsgint(msgBuf, 4);
     374         [ +  - ]:         509 :                 if (argsize == -1)
     375                 :             :                 {
     376                 :           0 :                         fcinfo->args[i].isnull = true;
     377                 :           0 :                 }
     378                 :             :                 else
     379                 :             :                 {
     380                 :         509 :                         fcinfo->args[i].isnull = false;
     381         [ +  - ]:         509 :                         if (argsize < 0)
     382   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     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                 :         509 :                         resetStringInfo(&abuf);
     389                 :         509 :                         appendBinaryStringInfo(&abuf,
     390                 :         509 :                                                                    pq_getmsgbytes(msgBuf, argsize),
     391                 :         509 :                                                                    argsize);
     392                 :             :                 }
     393                 :             : 
     394         [ -  + ]:         509 :                 if (numAFormats > 1)
     395                 :           0 :                         aformat = aformats[i];
     396         [ +  - ]:         509 :                 else if (numAFormats > 0)
     397                 :         509 :                         aformat = aformats[0];
     398                 :             :                 else
     399                 :           0 :                         aformat = 0;            /* default = text */
     400                 :             : 
     401         [ +  - ]:         509 :                 if (aformat == 0)
     402                 :             :                 {
     403                 :           0 :                         Oid                     typinput;
     404                 :           0 :                         Oid                     typioparam;
     405                 :           0 :                         char       *pstring;
     406                 :             : 
     407                 :           0 :                         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         [ #  # ]:           0 :                         if (argsize == -1)
     416                 :           0 :                                 pstring = NULL;
     417                 :             :                         else
     418                 :           0 :                                 pstring = pg_client_to_server(abuf.data, argsize);
     419                 :             : 
     420                 :           0 :                         fcinfo->args[i].value = OidInputFunctionCall(typinput, pstring,
     421                 :           0 :                                                                                                                  typioparam, -1);
     422                 :             :                         /* Free result of encoding conversion, if any */
     423   [ #  #  #  # ]:           0 :                         if (pstring && pstring != abuf.data)
     424                 :           0 :                                 pfree(pstring);
     425                 :           0 :                 }
     426         [ +  - ]:         509 :                 else if (aformat == 1)
     427                 :             :                 {
     428                 :         509 :                         Oid                     typreceive;
     429                 :         509 :                         Oid                     typioparam;
     430                 :         509 :                         StringInfo      bufptr;
     431                 :             : 
     432                 :             :                         /* Call the argument type's binary input converter */
     433                 :         509 :                         getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
     434                 :             : 
     435         [ +  - ]:         509 :                         if (argsize == -1)
     436                 :           0 :                                 bufptr = NULL;
     437                 :             :                         else
     438                 :         509 :                                 bufptr = &abuf;
     439                 :             : 
     440                 :        1018 :                         fcinfo->args[i].value = OidReceiveFunctionCall(typreceive, bufptr,
     441                 :         509 :                                                                                                                    typioparam, -1);
     442                 :             : 
     443                 :             :                         /* Trouble if it didn't eat the whole buffer */
     444   [ +  -  +  - ]:         509 :                         if (argsize != -1 && abuf.cursor != abuf.len)
     445   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     446                 :             :                                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
     447                 :             :                                                  errmsg("incorrect binary data format in function argument %d",
     448                 :             :                                                                 i + 1)));
     449                 :         509 :                 }
     450                 :             :                 else
     451   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     452                 :             :                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     453                 :             :                                          errmsg("unsupported format code: %d", aformat)));
     454                 :         509 :         }
     455                 :             : 
     456                 :             :         /* Return result format code */
     457                 :         518 :         return (int16) pq_getmsgint(msgBuf, 2);
     458                 :         259 : }
        

Generated by: LCOV version 2.3.2-1