LCOV - code coverage report
Current view: top level - src/backend/nodes - params.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 89.8 % 177 159
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 62.0 % 71 44

             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                 :      412736 : makeParamList(int numParams)
      45                 :             : {
      46                 :      412736 :         ParamListInfo retval;
      47                 :      412736 :         Size            size;
      48                 :             : 
      49                 :      412736 :         size = offsetof(ParamListInfoData, params) +
      50                 :      412736 :                 numParams * sizeof(ParamExternData);
      51                 :             : 
      52                 :      412736 :         retval = (ParamListInfo) palloc(size);
      53                 :      412736 :         retval->paramFetch = NULL;
      54                 :      412736 :         retval->paramFetchArg = NULL;
      55                 :      412736 :         retval->paramCompile = NULL;
      56                 :      412736 :         retval->paramCompileArg = NULL;
      57                 :      412736 :         retval->parserSetup = paramlist_parser_setup;
      58                 :      412736 :         retval->parserSetupArg = retval;
      59                 :      412736 :         retval->paramValuesStr = NULL;
      60                 :      412736 :         retval->numParams = numParams;
      61                 :             : 
      62                 :      825472 :         return retval;
      63                 :      412736 : }
      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                 :         488 : copyParamList(ParamListInfo from)
      79                 :             : {
      80                 :         488 :         ParamListInfo retval;
      81                 :             : 
      82   [ +  +  -  + ]:         488 :         if (from == NULL || from->numParams <= 0)
      83                 :         387 :                 return NULL;
      84                 :             : 
      85                 :         101 :         retval = makeParamList(from->numParams);
      86                 :             : 
      87         [ +  + ]:         652 :         for (int i = 0; i < from->numParams; i++)
      88                 :             :         {
      89                 :         551 :                 ParamExternData *oprm;
      90                 :         551 :                 ParamExternData *nprm = &retval->params[i];
      91                 :         551 :                 ParamExternData prmdata;
      92                 :         551 :                 int16           typLen;
      93                 :         551 :                 bool            typByVal;
      94                 :             : 
      95                 :             :                 /* give hook a chance in case parameter is dynamic */
      96         [ +  + ]:         551 :                 if (from->paramFetch != NULL)
      97                 :         548 :                         oprm = from->paramFetch(from, i + 1, false, &prmdata);
      98                 :             :                 else
      99                 :           3 :                         oprm = &from->params[i];
     100                 :             : 
     101                 :             :                 /* flat-copy the parameter info */
     102                 :         551 :                 *nprm = *oprm;
     103                 :             : 
     104                 :             :                 /* need datumCopy in case it's a pass-by-reference datatype */
     105   [ +  +  -  + ]:         551 :                 if (nprm->isnull || !OidIsValid(nprm->ptype))
     106                 :         440 :                         continue;
     107                 :         111 :                 get_typlenbyval(nprm->ptype, &typLen, &typByVal);
     108                 :         111 :                 nprm->value = datumCopy(nprm->value, typByVal, typLen);
     109      [ -  +  + ]:         551 :         }
     110                 :             : 
     111                 :         101 :         return retval;
     112                 :         488 : }
     113                 :             : 
     114                 :             : 
     115                 :             : /*
     116                 :             :  * Set up to parse a query containing references to parameters
     117                 :             :  * sourced from a ParamListInfo.
     118                 :             :  */
     119                 :             : static void
     120                 :           6 : paramlist_parser_setup(ParseState *pstate, void *arg)
     121                 :             : {
     122                 :           6 :         pstate->p_paramref_hook = paramlist_param_ref;
     123                 :             :         /* no need to use p_coerce_param_hook */
     124                 :           6 :         pstate->p_ref_hook_state = arg;
     125                 :           6 : }
     126                 :             : 
     127                 :             : /*
     128                 :             :  * Transform a ParamRef using parameter type data from a ParamListInfo.
     129                 :             :  */
     130                 :             : static Node *
     131                 :          10 : paramlist_param_ref(ParseState *pstate, ParamRef *pref)
     132                 :             : {
     133                 :          10 :         ParamListInfo paramLI = (ParamListInfo) pstate->p_ref_hook_state;
     134                 :          10 :         int                     paramno = pref->number;
     135                 :          10 :         ParamExternData *prm;
     136                 :          10 :         ParamExternData prmdata;
     137                 :          10 :         Param      *param;
     138                 :             : 
     139                 :             :         /* check parameter number is valid */
     140   [ +  -  -  + ]:          10 :         if (paramno <= 0 || paramno > paramLI->numParams)
     141                 :           0 :                 return NULL;
     142                 :             : 
     143                 :             :         /* give hook a chance in case parameter is dynamic */
     144         [ -  + ]:          10 :         if (paramLI->paramFetch != NULL)
     145                 :           0 :                 prm = paramLI->paramFetch(paramLI, paramno, false, &prmdata);
     146                 :             :         else
     147                 :          10 :                 prm = &paramLI->params[paramno - 1];
     148                 :             : 
     149         [ +  - ]:          10 :         if (!OidIsValid(prm->ptype))
     150                 :           0 :                 return NULL;
     151                 :             : 
     152                 :          10 :         param = makeNode(Param);
     153                 :          10 :         param->paramkind = PARAM_EXTERN;
     154                 :          10 :         param->paramid = paramno;
     155                 :          10 :         param->paramtype = prm->ptype;
     156                 :          10 :         param->paramtypmod = -1;
     157                 :          10 :         param->paramcollid = get_typcollation(param->paramtype);
     158                 :          10 :         param->location = pref->location;
     159                 :             : 
     160                 :          10 :         return (Node *) param;
     161                 :          10 : }
     162                 :             : 
     163                 :             : /*
     164                 :             :  * Estimate the amount of space required to serialize a ParamListInfo.
     165                 :             :  */
     166                 :             : Size
     167                 :         121 : EstimateParamListSpace(ParamListInfo paramLI)
     168                 :             : {
     169                 :         121 :         Size            sz = sizeof(int);
     170                 :             : 
     171   [ +  +  -  + ]:         121 :         if (paramLI == NULL || paramLI->numParams <= 0)
     172                 :         115 :                 return sz;
     173                 :             : 
     174         [ +  + ]:          20 :         for (int i = 0; i < paramLI->numParams; i++)
     175                 :             :         {
     176                 :          14 :                 ParamExternData *prm;
     177                 :          14 :                 ParamExternData prmdata;
     178                 :          14 :                 Oid                     typeOid;
     179                 :          14 :                 int16           typLen;
     180                 :          14 :                 bool            typByVal;
     181                 :             : 
     182                 :             :                 /* give hook a chance in case parameter is dynamic */
     183         [ -  + ]:          14 :                 if (paramLI->paramFetch != NULL)
     184                 :           0 :                         prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     185                 :             :                 else
     186                 :          14 :                         prm = &paramLI->params[i];
     187                 :             : 
     188                 :          14 :                 typeOid = prm->ptype;
     189                 :             : 
     190                 :          14 :                 sz = add_size(sz, sizeof(Oid)); /* space for type OID */
     191                 :          14 :                 sz = add_size(sz, sizeof(uint16));      /* space for pflags */
     192                 :             : 
     193                 :             :                 /* space for datum/isnull */
     194         [ +  - ]:          14 :                 if (OidIsValid(typeOid))
     195                 :          14 :                         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                 :          28 :                 sz = add_size(sz,
     203                 :          14 :                                           datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
     204                 :          14 :         }
     205                 :             : 
     206                 :           6 :         return sz;
     207                 :         121 : }
     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                 :         121 : SerializeParamList(ParamListInfo paramLI, char **start_address)
     229                 :             : {
     230                 :         121 :         int                     nparams;
     231                 :             : 
     232                 :             :         /* Write number of parameters. */
     233   [ +  +  -  + ]:         121 :         if (paramLI == NULL || paramLI->numParams <= 0)
     234                 :         115 :                 nparams = 0;
     235                 :             :         else
     236                 :           6 :                 nparams = paramLI->numParams;
     237                 :         121 :         memcpy(*start_address, &nparams, sizeof(int));
     238                 :         121 :         *start_address += sizeof(int);
     239                 :             : 
     240                 :             :         /* Write each parameter in turn. */
     241         [ +  + ]:         135 :         for (int i = 0; i < nparams; i++)
     242                 :             :         {
     243                 :          14 :                 ParamExternData *prm;
     244                 :          14 :                 ParamExternData prmdata;
     245                 :          14 :                 Oid                     typeOid;
     246                 :          14 :                 int16           typLen;
     247                 :          14 :                 bool            typByVal;
     248                 :             : 
     249                 :             :                 /* give hook a chance in case parameter is dynamic */
     250         [ -  + ]:          14 :                 if (paramLI->paramFetch != NULL)
     251                 :           0 :                         prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     252                 :             :                 else
     253                 :          14 :                         prm = &paramLI->params[i];
     254                 :             : 
     255                 :          14 :                 typeOid = prm->ptype;
     256                 :             : 
     257                 :             :                 /* Write type OID. */
     258                 :          14 :                 memcpy(*start_address, &typeOid, sizeof(Oid));
     259                 :          14 :                 *start_address += sizeof(Oid);
     260                 :             : 
     261                 :             :                 /* Write flags. */
     262                 :          14 :                 memcpy(*start_address, &prm->pflags, sizeof(uint16));
     263                 :          14 :                 *start_address += sizeof(uint16);
     264                 :             : 
     265                 :             :                 /* Write datum/isnull. */
     266         [ +  - ]:          14 :                 if (OidIsValid(typeOid))
     267                 :          14 :                         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                 :          28 :                 datumSerialize(prm->value, prm->isnull, typByVal, typLen,
     275                 :          14 :                                            start_address);
     276                 :          14 :         }
     277                 :         121 : }
     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                 :         436 : RestoreParamList(char **start_address)
     291                 :             : {
     292                 :         436 :         ParamListInfo paramLI;
     293                 :         436 :         int                     nparams;
     294                 :             : 
     295                 :         436 :         memcpy(&nparams, *start_address, sizeof(int));
     296                 :         436 :         *start_address += sizeof(int);
     297                 :             : 
     298                 :         436 :         paramLI = makeParamList(nparams);
     299                 :             : 
     300         [ +  + ]:         468 :         for (int i = 0; i < nparams; i++)
     301                 :             :         {
     302                 :          32 :                 ParamExternData *prm = &paramLI->params[i];
     303                 :             : 
     304                 :             :                 /* Read type OID. */
     305                 :          32 :                 memcpy(&prm->ptype, *start_address, sizeof(Oid));
     306                 :          32 :                 *start_address += sizeof(Oid);
     307                 :             : 
     308                 :             :                 /* Read flags. */
     309                 :          32 :                 memcpy(&prm->pflags, *start_address, sizeof(uint16));
     310                 :          32 :                 *start_address += sizeof(uint16);
     311                 :             : 
     312                 :             :                 /* Read datum/isnull. */
     313                 :          32 :                 prm->value = datumRestore(start_address, &prm->isnull);
     314                 :          32 :         }
     315                 :             : 
     316                 :         872 :         return paramLI;
     317                 :         436 : }
     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                 :          56 : BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
     334                 :             : {
     335                 :          56 :         MemoryContext tmpCxt,
     336                 :             :                                 oldCxt;
     337                 :          56 :         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   [ +  -  -  + ]:          56 :         if (params->paramFetch != NULL ||
     351                 :          56 :                 IsAbortedTransactionBlockState())
     352                 :           0 :                 return NULL;
     353                 :             : 
     354                 :             :         /* Initialize the output stringinfo, in caller's memory context */
     355                 :          56 :         initStringInfo(&buf);
     356                 :             : 
     357                 :             :         /* Use a temporary context to call output functions, just in case */
     358                 :          56 :         tmpCxt = AllocSetContextCreate(CurrentMemoryContext,
     359                 :             :                                                                    "BuildParamLogString",
     360                 :             :                                                                    ALLOCSET_DEFAULT_SIZES);
     361                 :          56 :         oldCxt = MemoryContextSwitchTo(tmpCxt);
     362                 :             : 
     363         [ +  + ]:         123 :         for (int paramno = 0; paramno < params->numParams; paramno++)
     364                 :             :         {
     365                 :          67 :                 ParamExternData *param = &params->params[paramno];
     366                 :             : 
     367                 :          67 :                 appendStringInfo(&buf,
     368                 :             :                                                  "%s$%d = ",
     369                 :          67 :                                                  paramno > 0 ? ", " : "",
     370                 :          67 :                                                  paramno + 1);
     371                 :             : 
     372   [ +  -  -  + ]:          67 :                 if (param->isnull || !OidIsValid(param->ptype))
     373                 :           0 :                         appendStringInfoString(&buf, "NULL");
     374                 :             :                 else
     375                 :             :                 {
     376   [ -  +  #  # ]:          67 :                         if (knownTextValues != NULL && knownTextValues[paramno] != NULL)
     377                 :           0 :                                 appendStringInfoStringQuoted(&buf, knownTextValues[paramno],
     378                 :           0 :                                                                                          maxlen);
     379                 :             :                         else
     380                 :             :                         {
     381                 :          67 :                                 Oid                     typoutput;
     382                 :          67 :                                 bool            typisvarlena;
     383                 :          67 :                                 char       *pstring;
     384                 :             : 
     385                 :          67 :                                 getTypeOutputInfo(param->ptype, &typoutput, &typisvarlena);
     386                 :          67 :                                 pstring = OidOutputFunctionCall(typoutput, param->value);
     387                 :          67 :                                 appendStringInfoStringQuoted(&buf, pstring, maxlen);
     388                 :          67 :                         }
     389                 :             :                 }
     390                 :          67 :         }
     391                 :             : 
     392                 :          56 :         MemoryContextSwitchTo(oldCxt);
     393                 :          56 :         MemoryContextDelete(tmpCxt);
     394                 :             : 
     395                 :          56 :         return buf.data;
     396                 :          56 : }
     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                 :           6 : ParamsErrorCallback(void *arg)
     406                 :             : {
     407                 :           6 :         ParamsErrorCbData *data = (ParamsErrorCbData *) arg;
     408                 :             : 
     409         [ +  - ]:           6 :         if (data == NULL ||
     410   [ +  +  +  - ]:           6 :                 data->params == NULL ||
     411                 :           1 :                 data->params->paramValuesStr == NULL)
     412                 :           6 :                 return;
     413                 :             : 
     414   [ #  #  #  # ]:           0 :         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                 :           0 :                 errcontext("unnamed portal with parameters: %s",
     419                 :           0 :                                    data->params->paramValuesStr);
     420         [ -  + ]:           6 : }
        

Generated by: LCOV version 2.3.2-1