LCOV - code coverage report
Current view: top level - src/backend/nodes - params.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 90.8 % 131 119
Test Date: 2026-07-08 05:15:38 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.1 % 68 49

             Branch data     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                 :       97293 : makeParamList(int numParams)
      45                 :             : {
      46                 :             :     ParamListInfo retval;
      47                 :             :     Size        size;
      48                 :             : 
      49                 :       97293 :     size = offsetof(ParamListInfoData, params) +
      50                 :             :         numParams * sizeof(ParamExternData);
      51                 :             : 
      52                 :       97293 :     retval = (ParamListInfo) palloc(size);
      53                 :       97293 :     retval->paramFetch = NULL;
      54                 :       97293 :     retval->paramFetchArg = NULL;
      55                 :       97293 :     retval->paramCompile = NULL;
      56                 :       97293 :     retval->paramCompileArg = NULL;
      57                 :       97293 :     retval->parserSetup = paramlist_parser_setup;
      58                 :       97293 :     retval->parserSetupArg = retval;
      59                 :       97293 :     retval->paramValuesStr = NULL;
      60                 :       97293 :     retval->numParams = numParams;
      61                 :             : 
      62                 :       97293 :     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                 :        3125 : copyParamList(ParamListInfo from)
      79                 :             : {
      80                 :             :     ParamListInfo retval;
      81                 :             : 
      82   [ +  +  -  + ]:        3125 :     if (from == NULL || from->numParams <= 0)
      83                 :        2303 :         return NULL;
      84                 :             : 
      85                 :         822 :     retval = makeParamList(from->numParams);
      86                 :             : 
      87         [ +  + ]:        4128 :     for (int i = 0; i < from->numParams; i++)
      88                 :             :     {
      89                 :             :         ParamExternData *oprm;
      90                 :        3306 :         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         [ +  + ]:        3306 :         if (from->paramFetch != NULL)
      97                 :        2716 :             oprm = from->paramFetch(from, i + 1, false, &prmdata);
      98                 :             :         else
      99                 :         590 :             oprm = &from->params[i];
     100                 :             : 
     101                 :             :         /* flat-copy the parameter info */
     102                 :        3306 :         *nprm = *oprm;
     103                 :             : 
     104                 :             :         /* need datumCopy in case it's a pass-by-reference datatype */
     105   [ +  +  -  + ]:        3306 :         if (nprm->isnull || !OidIsValid(nprm->ptype))
     106                 :        2241 :             continue;
     107                 :        1065 :         get_typlenbyval(nprm->ptype, &typLen, &typByVal);
     108                 :        1065 :         nprm->value = datumCopy(nprm->value, typByVal, typLen);
     109                 :             :     }
     110                 :             : 
     111                 :         822 :     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                 :         297 : paramlist_parser_setup(ParseState *pstate, void *arg)
     121                 :             : {
     122                 :         297 :     pstate->p_paramref_hook = paramlist_param_ref;
     123                 :             :     /* no need to use p_coerce_param_hook */
     124                 :         297 :     pstate->p_ref_hook_state = arg;
     125                 :         297 : }
     126                 :             : 
     127                 :             : /*
     128                 :             :  * Transform a ParamRef using parameter type data from a ParamListInfo.
     129                 :             :  */
     130                 :             : static Node *
     131                 :         586 : paramlist_param_ref(ParseState *pstate, ParamRef *pref)
     132                 :             : {
     133                 :         586 :     ParamListInfo paramLI = (ParamListInfo) pstate->p_ref_hook_state;
     134                 :         586 :     int         paramno = pref->number;
     135                 :             :     ParamExternData *prm;
     136                 :             :     ParamExternData prmdata;
     137                 :             :     Param      *param;
     138                 :             : 
     139                 :             :     /* check parameter number is valid */
     140   [ +  -  -  + ]:         586 :     if (paramno <= 0 || paramno > paramLI->numParams)
     141                 :           0 :         return NULL;
     142                 :             : 
     143                 :             :     /* give hook a chance in case parameter is dynamic */
     144         [ -  + ]:         586 :     if (paramLI->paramFetch != NULL)
     145                 :           0 :         prm = paramLI->paramFetch(paramLI, paramno, false, &prmdata);
     146                 :             :     else
     147                 :         586 :         prm = &paramLI->params[paramno - 1];
     148                 :             : 
     149         [ -  + ]:         586 :     if (!OidIsValid(prm->ptype))
     150                 :           0 :         return NULL;
     151                 :             : 
     152                 :         586 :     param = makeNode(Param);
     153                 :         586 :     param->paramkind = PARAM_EXTERN;
     154                 :         586 :     param->paramid = paramno;
     155                 :         586 :     param->paramtype = prm->ptype;
     156                 :         586 :     param->paramtypmod = -1;
     157                 :         586 :     param->paramcollid = get_typcollation(param->paramtype);
     158                 :         586 :     param->location = pref->location;
     159                 :             : 
     160                 :         586 :     return (Node *) param;
     161                 :             : }
     162                 :             : 
     163                 :             : /*
     164                 :             :  * Estimate the amount of space required to serialize a ParamListInfo.
     165                 :             :  */
     166                 :             : Size
     167                 :         523 : EstimateParamListSpace(ParamListInfo paramLI)
     168                 :             : {
     169                 :         523 :     Size        sz = sizeof(int);
     170                 :             : 
     171   [ +  +  -  + ]:         523 :     if (paramLI == NULL || paramLI->numParams <= 0)
     172                 :         499 :         return sz;
     173                 :             : 
     174         [ +  + ]:          80 :     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         [ -  + ]:          56 :         if (paramLI->paramFetch != NULL)
     184                 :           0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     185                 :             :         else
     186                 :          56 :             prm = &paramLI->params[i];
     187                 :             : 
     188                 :          56 :         typeOid = prm->ptype;
     189                 :             : 
     190                 :          56 :         sz = add_size(sz, sizeof(Oid)); /* space for type OID */
     191                 :          56 :         sz = add_size(sz, sizeof(uint16));  /* space for pflags */
     192                 :             : 
     193                 :             :         /* space for datum/isnull */
     194         [ +  - ]:          56 :         if (OidIsValid(typeOid))
     195                 :          56 :             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                 :          56 :         sz = add_size(sz,
     203                 :          56 :                       datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
     204                 :             :     }
     205                 :             : 
     206                 :          24 :     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                 :         523 : SerializeParamList(ParamListInfo paramLI, char **start_address)
     229                 :             : {
     230                 :             :     int         nparams;
     231                 :             : 
     232                 :             :     /* Write number of parameters. */
     233   [ +  +  -  + ]:         523 :     if (paramLI == NULL || paramLI->numParams <= 0)
     234                 :         499 :         nparams = 0;
     235                 :             :     else
     236                 :          24 :         nparams = paramLI->numParams;
     237                 :         523 :     memcpy(*start_address, &nparams, sizeof(int));
     238                 :         523 :     *start_address += sizeof(int);
     239                 :             : 
     240                 :             :     /* Write each parameter in turn. */
     241         [ +  + ]:         579 :     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         [ -  + ]:          56 :         if (paramLI->paramFetch != NULL)
     251                 :           0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     252                 :             :         else
     253                 :          56 :             prm = &paramLI->params[i];
     254                 :             : 
     255                 :          56 :         typeOid = prm->ptype;
     256                 :             : 
     257                 :             :         /* Write type OID. */
     258                 :          56 :         memcpy(*start_address, &typeOid, sizeof(Oid));
     259                 :          56 :         *start_address += sizeof(Oid);
     260                 :             : 
     261                 :             :         /* Write flags. */
     262                 :          56 :         memcpy(*start_address, &prm->pflags, sizeof(uint16));
     263                 :          56 :         *start_address += sizeof(uint16);
     264                 :             : 
     265                 :             :         /* Write datum/isnull. */
     266         [ +  - ]:          56 :         if (OidIsValid(typeOid))
     267                 :          56 :             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                 :          56 :         datumSerialize(prm->value, prm->isnull, typByVal, typLen,
     275                 :             :                        start_address);
     276                 :             :     }
     277                 :         523 : }
     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                 :        1814 : RestoreParamList(char **start_address)
     291                 :             : {
     292                 :             :     ParamListInfo paramLI;
     293                 :             :     int         nparams;
     294                 :             : 
     295                 :        1814 :     memcpy(&nparams, *start_address, sizeof(int));
     296                 :        1814 :     *start_address += sizeof(int);
     297                 :             : 
     298                 :        1814 :     paramLI = makeParamList(nparams);
     299                 :             : 
     300         [ +  + ]:        1937 :     for (int i = 0; i < nparams; i++)
     301                 :             :     {
     302                 :         123 :         ParamExternData *prm = &paramLI->params[i];
     303                 :             : 
     304                 :             :         /* Read type OID. */
     305                 :         123 :         memcpy(&prm->ptype, *start_address, sizeof(Oid));
     306                 :         123 :         *start_address += sizeof(Oid);
     307                 :             : 
     308                 :             :         /* Read flags. */
     309                 :         123 :         memcpy(&prm->pflags, *start_address, sizeof(uint16));
     310                 :         123 :         *start_address += sizeof(uint16);
     311                 :             : 
     312                 :             :         /* Read datum/isnull. */
     313                 :         123 :         prm->value = datumRestore(start_address, &prm->isnull);
     314                 :             :     }
     315                 :             : 
     316                 :        1814 :     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                 :        2545 : 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   [ +  -  -  + ]:        5090 :     if (params->paramFetch != NULL ||
     351                 :        2545 :         IsAbortedTransactionBlockState())
     352                 :           0 :         return NULL;
     353                 :             : 
     354                 :             :     /* Initialize the output stringinfo, in caller's memory context */
     355                 :        2545 :     initStringInfo(&buf);
     356                 :             : 
     357                 :             :     /* Use a temporary context to call output functions, just in case */
     358                 :        2545 :     tmpCxt = AllocSetContextCreate(CurrentMemoryContext,
     359                 :             :                                    "BuildParamLogString",
     360                 :             :                                    ALLOCSET_DEFAULT_SIZES);
     361                 :        2545 :     oldCxt = MemoryContextSwitchTo(tmpCxt);
     362                 :             : 
     363         [ +  + ]:        6865 :     for (int paramno = 0; paramno < params->numParams; paramno++)
     364                 :             :     {
     365                 :        4320 :         ParamExternData *param = &params->params[paramno];
     366                 :             : 
     367         [ +  + ]:        4320 :         appendStringInfo(&buf,
     368                 :             :                          "%s$%d = ",
     369                 :             :                          paramno > 0 ? ", " : "",
     370                 :             :                          paramno + 1);
     371                 :             : 
     372   [ +  +  -  + ]:        4320 :         if (param->isnull || !OidIsValid(param->ptype))
     373                 :           5 :             appendStringInfoString(&buf, "NULL");
     374                 :             :         else
     375                 :             :         {
     376   [ +  +  +  - ]:        4315 :             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                 :        4309 :                 getTypeOutputInfo(param->ptype, &typoutput, &typisvarlena);
     386                 :        4309 :                 pstring = OidOutputFunctionCall(typoutput, param->value);
     387                 :        4309 :                 appendStringInfoStringQuoted(&buf, pstring, maxlen);
     388                 :             :             }
     389                 :             :         }
     390                 :             :     }
     391                 :             : 
     392                 :        2545 :     MemoryContextSwitchTo(oldCxt);
     393                 :        2545 :     MemoryContextDelete(tmpCxt);
     394                 :             : 
     395                 :        2545 :     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                 :          64 : ParamsErrorCallback(void *arg)
     406                 :             : {
     407                 :          64 :     ParamsErrorCbData *data = (ParamsErrorCbData *) arg;
     408                 :             : 
     409         [ +  - ]:          64 :     if (data == NULL ||
     410         [ +  + ]:          64 :         data->params == NULL ||
     411         [ +  + ]:          28 :         data->params->paramValuesStr == NULL)
     412                 :          60 :         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