LCOV - code coverage report
Current view: top level - src/backend/nodes - params.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.8 % 131 119
Test Date: 2026-03-01 23:14:58 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * params.c
       4              :  *    Support for finding the values associated with Param nodes.
       5              :  *
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/nodes/params.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres.h"
      17              : 
      18              : #include "access/xact.h"
      19              : #include "fmgr.h"
      20              : #include "mb/stringinfo_mb.h"
      21              : #include "nodes/params.h"
      22              : #include "parser/parse_node.h"
      23              : #include "storage/shmem.h"
      24              : #include "utils/datum.h"
      25              : #include "utils/lsyscache.h"
      26              : #include "utils/memutils.h"
      27              : 
      28              : 
      29              : static void paramlist_parser_setup(ParseState *pstate, void *arg);
      30              : static Node *paramlist_param_ref(ParseState *pstate, ParamRef *pref);
      31              : 
      32              : 
      33              : /*
      34              :  * Allocate and initialize a new ParamListInfo structure.
      35              :  *
      36              :  * To make a new structure for the "dynamic" way (with hooks), pass 0 for
      37              :  * numParams and set numParams manually.
      38              :  *
      39              :  * A default parserSetup function is supplied automatically.  Callers may
      40              :  * override it if they choose.  (Note that most use-cases for ParamListInfos
      41              :  * will never use the parserSetup function anyway.)
      42              :  */
      43              : ParamListInfo
      44        81542 : makeParamList(int numParams)
      45              : {
      46              :     ParamListInfo retval;
      47              :     Size        size;
      48              : 
      49        81542 :     size = offsetof(ParamListInfoData, params) +
      50              :         numParams * sizeof(ParamExternData);
      51              : 
      52        81542 :     retval = (ParamListInfo) palloc(size);
      53        81542 :     retval->paramFetch = NULL;
      54        81542 :     retval->paramFetchArg = NULL;
      55        81542 :     retval->paramCompile = NULL;
      56        81542 :     retval->paramCompileArg = NULL;
      57        81542 :     retval->parserSetup = paramlist_parser_setup;
      58        81542 :     retval->parserSetupArg = retval;
      59        81542 :     retval->paramValuesStr = NULL;
      60        81542 :     retval->numParams = numParams;
      61              : 
      62        81542 :     return retval;
      63              : }
      64              : 
      65              : /*
      66              :  * Copy a ParamListInfo structure.
      67              :  *
      68              :  * The result is allocated in CurrentMemoryContext.
      69              :  *
      70              :  * Note: the intent of this function is to make a static, self-contained
      71              :  * set of parameter values.  If dynamic parameter hooks are present, we
      72              :  * intentionally do not copy them into the result.  Rather, we forcibly
      73              :  * instantiate all available parameter values and copy the datum values.
      74              :  *
      75              :  * paramValuesStr is not copied, either.
      76              :  */
      77              : ParamListInfo
      78         2593 : copyParamList(ParamListInfo from)
      79              : {
      80              :     ParamListInfo retval;
      81              : 
      82         2593 :     if (from == NULL || from->numParams <= 0)
      83         1877 :         return NULL;
      84              : 
      85          716 :     retval = makeParamList(from->numParams);
      86              : 
      87         3418 :     for (int i = 0; i < from->numParams; i++)
      88              :     {
      89              :         ParamExternData *oprm;
      90         2702 :         ParamExternData *nprm = &retval->params[i];
      91              :         ParamExternData prmdata;
      92              :         int16       typLen;
      93              :         bool        typByVal;
      94              : 
      95              :         /* give hook a chance in case parameter is dynamic */
      96         2702 :         if (from->paramFetch != NULL)
      97         2116 :             oprm = from->paramFetch(from, i + 1, false, &prmdata);
      98              :         else
      99          586 :             oprm = &from->params[i];
     100              : 
     101              :         /* flat-copy the parameter info */
     102         2702 :         *nprm = *oprm;
     103              : 
     104              :         /* need datumCopy in case it's a pass-by-reference datatype */
     105         2702 :         if (nprm->isnull || !OidIsValid(nprm->ptype))
     106         1753 :             continue;
     107          949 :         get_typlenbyval(nprm->ptype, &typLen, &typByVal);
     108          949 :         nprm->value = datumCopy(nprm->value, typByVal, typLen);
     109              :     }
     110              : 
     111          716 :     return retval;
     112              : }
     113              : 
     114              : 
     115              : /*
     116              :  * Set up to parse a query containing references to parameters
     117              :  * sourced from a ParamListInfo.
     118              :  */
     119              : static void
     120          291 : paramlist_parser_setup(ParseState *pstate, void *arg)
     121              : {
     122          291 :     pstate->p_paramref_hook = paramlist_param_ref;
     123              :     /* no need to use p_coerce_param_hook */
     124          291 :     pstate->p_ref_hook_state = arg;
     125          291 : }
     126              : 
     127              : /*
     128              :  * Transform a ParamRef using parameter type data from a ParamListInfo.
     129              :  */
     130              : static Node *
     131          576 : paramlist_param_ref(ParseState *pstate, ParamRef *pref)
     132              : {
     133          576 :     ParamListInfo paramLI = (ParamListInfo) pstate->p_ref_hook_state;
     134          576 :     int         paramno = pref->number;
     135              :     ParamExternData *prm;
     136              :     ParamExternData prmdata;
     137              :     Param      *param;
     138              : 
     139              :     /* check parameter number is valid */
     140          576 :     if (paramno <= 0 || paramno > paramLI->numParams)
     141            0 :         return NULL;
     142              : 
     143              :     /* give hook a chance in case parameter is dynamic */
     144          576 :     if (paramLI->paramFetch != NULL)
     145            0 :         prm = paramLI->paramFetch(paramLI, paramno, false, &prmdata);
     146              :     else
     147          576 :         prm = &paramLI->params[paramno - 1];
     148              : 
     149          576 :     if (!OidIsValid(prm->ptype))
     150            0 :         return NULL;
     151              : 
     152          576 :     param = makeNode(Param);
     153          576 :     param->paramkind = PARAM_EXTERN;
     154          576 :     param->paramid = paramno;
     155          576 :     param->paramtype = prm->ptype;
     156          576 :     param->paramtypmod = -1;
     157          576 :     param->paramcollid = get_typcollation(param->paramtype);
     158          576 :     param->location = pref->location;
     159              : 
     160          576 :     return (Node *) param;
     161              : }
     162              : 
     163              : /*
     164              :  * Estimate the amount of space required to serialize a ParamListInfo.
     165              :  */
     166              : Size
     167          383 : EstimateParamListSpace(ParamListInfo paramLI)
     168              : {
     169          383 :     Size        sz = sizeof(int);
     170              : 
     171          383 :     if (paramLI == NULL || paramLI->numParams <= 0)
     172          365 :         return sz;
     173              : 
     174           60 :     for (int i = 0; i < paramLI->numParams; i++)
     175              :     {
     176              :         ParamExternData *prm;
     177              :         ParamExternData prmdata;
     178              :         Oid         typeOid;
     179              :         int16       typLen;
     180              :         bool        typByVal;
     181              : 
     182              :         /* give hook a chance in case parameter is dynamic */
     183           42 :         if (paramLI->paramFetch != NULL)
     184            0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     185              :         else
     186           42 :             prm = &paramLI->params[i];
     187              : 
     188           42 :         typeOid = prm->ptype;
     189              : 
     190           42 :         sz = add_size(sz, sizeof(Oid)); /* space for type OID */
     191           42 :         sz = add_size(sz, sizeof(uint16));  /* space for pflags */
     192              : 
     193              :         /* space for datum/isnull */
     194           42 :         if (OidIsValid(typeOid))
     195           42 :             get_typlenbyval(typeOid, &typLen, &typByVal);
     196              :         else
     197              :         {
     198              :             /* If no type OID, assume by-value, like copyParamList does. */
     199            0 :             typLen = sizeof(Datum);
     200            0 :             typByVal = true;
     201              :         }
     202           42 :         sz = add_size(sz,
     203           42 :                       datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
     204              :     }
     205              : 
     206           18 :     return sz;
     207              : }
     208              : 
     209              : /*
     210              :  * Serialize a ParamListInfo structure into caller-provided storage.
     211              :  *
     212              :  * We write the number of parameters first, as a 4-byte integer, and then
     213              :  * write details for each parameter in turn.  The details for each parameter
     214              :  * consist of a 4-byte type OID, 2 bytes of flags, and then the datum as
     215              :  * serialized by datumSerialize().  The caller is responsible for ensuring
     216              :  * that there is enough storage to store the number of bytes that will be
     217              :  * written; use EstimateParamListSpace to find out how many will be needed.
     218              :  * *start_address is updated to point to the byte immediately following those
     219              :  * written.
     220              :  *
     221              :  * RestoreParamList can be used to recreate a ParamListInfo based on the
     222              :  * serialized representation; this will be a static, self-contained copy
     223              :  * just as copyParamList would create.
     224              :  *
     225              :  * paramValuesStr is not included.
     226              :  */
     227              : void
     228          383 : SerializeParamList(ParamListInfo paramLI, char **start_address)
     229              : {
     230              :     int         nparams;
     231              : 
     232              :     /* Write number of parameters. */
     233          383 :     if (paramLI == NULL || paramLI->numParams <= 0)
     234          365 :         nparams = 0;
     235              :     else
     236           18 :         nparams = paramLI->numParams;
     237          383 :     memcpy(*start_address, &nparams, sizeof(int));
     238          383 :     *start_address += sizeof(int);
     239              : 
     240              :     /* Write each parameter in turn. */
     241          425 :     for (int i = 0; i < nparams; i++)
     242              :     {
     243              :         ParamExternData *prm;
     244              :         ParamExternData prmdata;
     245              :         Oid         typeOid;
     246              :         int16       typLen;
     247              :         bool        typByVal;
     248              : 
     249              :         /* give hook a chance in case parameter is dynamic */
     250           42 :         if (paramLI->paramFetch != NULL)
     251            0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     252              :         else
     253           42 :             prm = &paramLI->params[i];
     254              : 
     255           42 :         typeOid = prm->ptype;
     256              : 
     257              :         /* Write type OID. */
     258           42 :         memcpy(*start_address, &typeOid, sizeof(Oid));
     259           42 :         *start_address += sizeof(Oid);
     260              : 
     261              :         /* Write flags. */
     262           42 :         memcpy(*start_address, &prm->pflags, sizeof(uint16));
     263           42 :         *start_address += sizeof(uint16);
     264              : 
     265              :         /* Write datum/isnull. */
     266           42 :         if (OidIsValid(typeOid))
     267           42 :             get_typlenbyval(typeOid, &typLen, &typByVal);
     268              :         else
     269              :         {
     270              :             /* If no type OID, assume by-value, like copyParamList does. */
     271            0 :             typLen = sizeof(Datum);
     272            0 :             typByVal = true;
     273              :         }
     274           42 :         datumSerialize(prm->value, prm->isnull, typByVal, typLen,
     275              :                        start_address);
     276              :     }
     277          383 : }
     278              : 
     279              : /*
     280              :  * Copy a ParamListInfo structure.
     281              :  *
     282              :  * The result is allocated in CurrentMemoryContext.
     283              :  *
     284              :  * Note: the intent of this function is to make a static, self-contained
     285              :  * set of parameter values.  If dynamic parameter hooks are present, we
     286              :  * intentionally do not copy them into the result.  Rather, we forcibly
     287              :  * instantiate all available parameter values and copy the datum values.
     288              :  */
     289              : ParamListInfo
     290         1343 : RestoreParamList(char **start_address)
     291              : {
     292              :     ParamListInfo paramLI;
     293              :     int         nparams;
     294              : 
     295         1343 :     memcpy(&nparams, *start_address, sizeof(int));
     296         1343 :     *start_address += sizeof(int);
     297              : 
     298         1343 :     paramLI = makeParamList(nparams);
     299              : 
     300         1436 :     for (int i = 0; i < nparams; i++)
     301              :     {
     302           93 :         ParamExternData *prm = &paramLI->params[i];
     303              : 
     304              :         /* Read type OID. */
     305           93 :         memcpy(&prm->ptype, *start_address, sizeof(Oid));
     306           93 :         *start_address += sizeof(Oid);
     307              : 
     308              :         /* Read flags. */
     309           93 :         memcpy(&prm->pflags, *start_address, sizeof(uint16));
     310           93 :         *start_address += sizeof(uint16);
     311              : 
     312              :         /* Read datum/isnull. */
     313           93 :         prm->value = datumRestore(start_address, &prm->isnull);
     314              :     }
     315              : 
     316         1343 :     return paramLI;
     317              : }
     318              : 
     319              : /*
     320              :  * BuildParamLogString
     321              :  *      Return a string that represents the parameter list, for logging.
     322              :  *
     323              :  * If caller already knows textual representations for some parameters, it can
     324              :  * pass an array of exactly params->numParams values as knownTextValues, which
     325              :  * can contain NULLs for any unknown individual values.  NULL can be given if
     326              :  * no parameters are known.
     327              :  *
     328              :  * If maxlen is >= 0, that's the maximum number of bytes of any one
     329              :  * parameter value to be printed; an ellipsis is added if the string is
     330              :  * longer.  (Added quotes are not considered in this calculation.)
     331              :  */
     332              : char *
     333         2388 : BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
     334              : {
     335              :     MemoryContext tmpCxt,
     336              :                 oldCxt;
     337              :     StringInfoData buf;
     338              : 
     339              :     /*
     340              :      * NB: think not of returning params->paramValuesStr!  It may have been
     341              :      * generated with a different maxlen, and so be unsuitable.  Besides that,
     342              :      * this is the function used to create that string.
     343              :      */
     344              : 
     345              :     /*
     346              :      * No work if the param fetch hook is in use.  Also, it's not possible to
     347              :      * do this in an aborted transaction.  (It might be possible to improve on
     348              :      * this last point when some knownTextValues exist, but it seems tricky.)
     349              :      */
     350         4776 :     if (params->paramFetch != NULL ||
     351         2388 :         IsAbortedTransactionBlockState())
     352            0 :         return NULL;
     353              : 
     354              :     /* Initialize the output stringinfo, in caller's memory context */
     355         2388 :     initStringInfo(&buf);
     356              : 
     357              :     /* Use a temporary context to call output functions, just in case */
     358         2388 :     tmpCxt = AllocSetContextCreate(CurrentMemoryContext,
     359              :                                    "BuildParamLogString",
     360              :                                    ALLOCSET_DEFAULT_SIZES);
     361         2388 :     oldCxt = MemoryContextSwitchTo(tmpCxt);
     362              : 
     363         6483 :     for (int paramno = 0; paramno < params->numParams; paramno++)
     364              :     {
     365         4095 :         ParamExternData *param = &params->params[paramno];
     366              : 
     367         4095 :         appendStringInfo(&buf,
     368              :                          "%s$%d = ",
     369              :                          paramno > 0 ? ", " : "",
     370              :                          paramno + 1);
     371              : 
     372         4095 :         if (param->isnull || !OidIsValid(param->ptype))
     373            5 :             appendStringInfoString(&buf, "NULL");
     374              :         else
     375              :         {
     376         4090 :             if (knownTextValues != NULL && knownTextValues[paramno] != NULL)
     377            6 :                 appendStringInfoStringQuoted(&buf, knownTextValues[paramno],
     378              :                                              maxlen);
     379              :             else
     380              :             {
     381              :                 Oid         typoutput;
     382              :                 bool        typisvarlena;
     383              :                 char       *pstring;
     384              : 
     385         4084 :                 getTypeOutputInfo(param->ptype, &typoutput, &typisvarlena);
     386         4084 :                 pstring = OidOutputFunctionCall(typoutput, param->value);
     387         4084 :                 appendStringInfoStringQuoted(&buf, pstring, maxlen);
     388              :             }
     389              :         }
     390              :     }
     391              : 
     392         2388 :     MemoryContextSwitchTo(oldCxt);
     393         2388 :     MemoryContextDelete(tmpCxt);
     394              : 
     395         2388 :     return buf.data;
     396              : }
     397              : 
     398              : /*
     399              :  * ParamsErrorCallback - callback for printing parameters in error context
     400              :  *
     401              :  * Note that this is a no-op unless BuildParamLogString has been called
     402              :  * beforehand.
     403              :  */
     404              : void
     405           58 : ParamsErrorCallback(void *arg)
     406              : {
     407           58 :     ParamsErrorCbData *data = (ParamsErrorCbData *) arg;
     408              : 
     409           58 :     if (data == NULL ||
     410           58 :         data->params == NULL ||
     411           27 :         data->params->paramValuesStr == NULL)
     412           54 :         return;
     413              : 
     414            4 :     if (data->portalName && data->portalName[0] != '\0')
     415            0 :         errcontext("portal \"%s\" with parameters: %s",
     416            0 :                    data->portalName, data->params->paramValuesStr);
     417              :     else
     418            4 :         errcontext("unnamed portal with parameters: %s",
     419            4 :                    data->params->paramValuesStr);
     420              : }
        

Generated by: LCOV version 2.0-1