LCOV - code coverage report
Current view: top level - src/backend/nodes - params.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 100 109 91.7 %
Date: 2020-05-28 23:07:14 Functions: 7 7 100.0 %
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-2020, 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 "mb/stringinfo_mb.h"
      20             : #include "nodes/bitmapset.h"
      21             : #include "nodes/params.h"
      22             : #include "storage/shmem.h"
      23             : #include "utils/datum.h"
      24             : #include "utils/lsyscache.h"
      25             : #include "utils/memutils.h"
      26             : 
      27             : 
      28             : /*
      29             :  * Allocate and initialize a new ParamListInfo structure.
      30             :  *
      31             :  * To make a new structure for the "dynamic" way (with hooks), pass 0 for
      32             :  * numParams and set numParams manually.
      33             :  */
      34             : ParamListInfo
      35      105172 : makeParamList(int numParams)
      36             : {
      37             :     ParamListInfo retval;
      38             :     Size        size;
      39             : 
      40      105172 :     size = offsetof(ParamListInfoData, params) +
      41             :         numParams * sizeof(ParamExternData);
      42             : 
      43      105172 :     retval = (ParamListInfo) palloc(size);
      44      105172 :     retval->paramFetch = NULL;
      45      105172 :     retval->paramFetchArg = NULL;
      46      105172 :     retval->paramCompile = NULL;
      47      105172 :     retval->paramCompileArg = NULL;
      48      105172 :     retval->parserSetup = NULL;
      49      105172 :     retval->parserSetupArg = NULL;
      50      105172 :     retval->paramValuesStr = NULL;
      51      105172 :     retval->numParams = numParams;
      52             : 
      53      105172 :     return retval;
      54             : }
      55             : 
      56             : /*
      57             :  * Copy a ParamListInfo structure.
      58             :  *
      59             :  * The result is allocated in CurrentMemoryContext.
      60             :  *
      61             :  * Note: the intent of this function is to make a static, self-contained
      62             :  * set of parameter values.  If dynamic parameter hooks are present, we
      63             :  * intentionally do not copy them into the result.  Rather, we forcibly
      64             :  * instantiate all available parameter values and copy the datum values.
      65             :  *
      66             :  * paramValuesStr is not copied, either.
      67             :  */
      68             : ParamListInfo
      69        3144 : copyParamList(ParamListInfo from)
      70             : {
      71             :     ParamListInfo retval;
      72             : 
      73        3144 :     if (from == NULL || from->numParams <= 0)
      74        1262 :         return NULL;
      75             : 
      76        1882 :     retval = makeParamList(from->numParams);
      77             : 
      78       11808 :     for (int i = 0; i < from->numParams; i++)
      79             :     {
      80             :         ParamExternData *oprm;
      81        9926 :         ParamExternData *nprm = &retval->params[i];
      82             :         ParamExternData prmdata;
      83             :         int16       typLen;
      84             :         bool        typByVal;
      85             : 
      86             :         /* give hook a chance in case parameter is dynamic */
      87        9926 :         if (from->paramFetch != NULL)
      88        8776 :             oprm = from->paramFetch(from, i + 1, false, &prmdata);
      89             :         else
      90        1150 :             oprm = &from->params[i];
      91             : 
      92             :         /* flat-copy the parameter info */
      93        9926 :         *nprm = *oprm;
      94             : 
      95             :         /* need datumCopy in case it's a pass-by-reference datatype */
      96        9926 :         if (nprm->isnull || !OidIsValid(nprm->ptype))
      97        7594 :             continue;
      98        2332 :         get_typlenbyval(nprm->ptype, &typLen, &typByVal);
      99        2332 :         nprm->value = datumCopy(nprm->value, typByVal, typLen);
     100             :     }
     101             : 
     102        1882 :     return retval;
     103             : }
     104             : 
     105             : /*
     106             :  * Estimate the amount of space required to serialize a ParamListInfo.
     107             :  */
     108             : Size
     109         370 : EstimateParamListSpace(ParamListInfo paramLI)
     110             : {
     111             :     int         i;
     112         370 :     Size        sz = sizeof(int);
     113             : 
     114         370 :     if (paramLI == NULL || paramLI->numParams <= 0)
     115         346 :         return sz;
     116             : 
     117          80 :     for (i = 0; i < paramLI->numParams; i++)
     118             :     {
     119             :         ParamExternData *prm;
     120             :         ParamExternData prmdata;
     121             :         Oid         typeOid;
     122             :         int16       typLen;
     123             :         bool        typByVal;
     124             : 
     125             :         /* give hook a chance in case parameter is dynamic */
     126          56 :         if (paramLI->paramFetch != NULL)
     127           0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     128             :         else
     129          56 :             prm = &paramLI->params[i];
     130             : 
     131          56 :         typeOid = prm->ptype;
     132             : 
     133          56 :         sz = add_size(sz, sizeof(Oid)); /* space for type OID */
     134          56 :         sz = add_size(sz, sizeof(uint16));  /* space for pflags */
     135             : 
     136             :         /* space for datum/isnull */
     137          56 :         if (OidIsValid(typeOid))
     138          56 :             get_typlenbyval(typeOid, &typLen, &typByVal);
     139             :         else
     140             :         {
     141             :             /* If no type OID, assume by-value, like copyParamList does. */
     142           0 :             typLen = sizeof(Datum);
     143           0 :             typByVal = true;
     144             :         }
     145          56 :         sz = add_size(sz,
     146          56 :                       datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
     147             :     }
     148             : 
     149          24 :     return sz;
     150             : }
     151             : 
     152             : /*
     153             :  * Serialize a ParamListInfo structure into caller-provided storage.
     154             :  *
     155             :  * We write the number of parameters first, as a 4-byte integer, and then
     156             :  * write details for each parameter in turn.  The details for each parameter
     157             :  * consist of a 4-byte type OID, 2 bytes of flags, and then the datum as
     158             :  * serialized by datumSerialize().  The caller is responsible for ensuring
     159             :  * that there is enough storage to store the number of bytes that will be
     160             :  * written; use EstimateParamListSpace to find out how many will be needed.
     161             :  * *start_address is updated to point to the byte immediately following those
     162             :  * written.
     163             :  *
     164             :  * RestoreParamList can be used to recreate a ParamListInfo based on the
     165             :  * serialized representation; this will be a static, self-contained copy
     166             :  * just as copyParamList would create.
     167             :  *
     168             :  * paramValuesStr is not included.
     169             :  */
     170             : void
     171         370 : SerializeParamList(ParamListInfo paramLI, char **start_address)
     172             : {
     173             :     int         nparams;
     174             :     int         i;
     175             : 
     176             :     /* Write number of parameters. */
     177         370 :     if (paramLI == NULL || paramLI->numParams <= 0)
     178         346 :         nparams = 0;
     179             :     else
     180          24 :         nparams = paramLI->numParams;
     181         370 :     memcpy(*start_address, &nparams, sizeof(int));
     182         370 :     *start_address += sizeof(int);
     183             : 
     184             :     /* Write each parameter in turn. */
     185         426 :     for (i = 0; i < nparams; i++)
     186             :     {
     187             :         ParamExternData *prm;
     188             :         ParamExternData prmdata;
     189             :         Oid         typeOid;
     190             :         int16       typLen;
     191             :         bool        typByVal;
     192             : 
     193             :         /* give hook a chance in case parameter is dynamic */
     194          56 :         if (paramLI->paramFetch != NULL)
     195           0 :             prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
     196             :         else
     197          56 :             prm = &paramLI->params[i];
     198             : 
     199          56 :         typeOid = prm->ptype;
     200             : 
     201             :         /* Write type OID. */
     202          56 :         memcpy(*start_address, &typeOid, sizeof(Oid));
     203          56 :         *start_address += sizeof(Oid);
     204             : 
     205             :         /* Write flags. */
     206          56 :         memcpy(*start_address, &prm->pflags, sizeof(uint16));
     207          56 :         *start_address += sizeof(uint16);
     208             : 
     209             :         /* Write datum/isnull. */
     210          56 :         if (OidIsValid(typeOid))
     211          56 :             get_typlenbyval(typeOid, &typLen, &typByVal);
     212             :         else
     213             :         {
     214             :             /* If no type OID, assume by-value, like copyParamList does. */
     215           0 :             typLen = sizeof(Datum);
     216           0 :             typByVal = true;
     217             :         }
     218          56 :         datumSerialize(prm->value, prm->isnull, typByVal, typLen,
     219             :                        start_address);
     220             :     }
     221         370 : }
     222             : 
     223             : /*
     224             :  * Copy a ParamListInfo structure.
     225             :  *
     226             :  * The result is allocated in CurrentMemoryContext.
     227             :  *
     228             :  * Note: the intent of this function is to make a static, self-contained
     229             :  * set of parameter values.  If dynamic parameter hooks are present, we
     230             :  * intentionally do not copy them into the result.  Rather, we forcibly
     231             :  * instantiate all available parameter values and copy the datum values.
     232             :  */
     233             : ParamListInfo
     234        1460 : RestoreParamList(char **start_address)
     235             : {
     236             :     ParamListInfo paramLI;
     237             :     int         nparams;
     238             : 
     239        1460 :     memcpy(&nparams, *start_address, sizeof(int));
     240        1460 :     *start_address += sizeof(int);
     241             : 
     242        1460 :     paramLI = makeParamList(nparams);
     243             : 
     244        1588 :     for (int i = 0; i < nparams; i++)
     245             :     {
     246         128 :         ParamExternData *prm = &paramLI->params[i];
     247             : 
     248             :         /* Read type OID. */
     249         128 :         memcpy(&prm->ptype, *start_address, sizeof(Oid));
     250         128 :         *start_address += sizeof(Oid);
     251             : 
     252             :         /* Read flags. */
     253         128 :         memcpy(&prm->pflags, *start_address, sizeof(uint16));
     254         128 :         *start_address += sizeof(uint16);
     255             : 
     256             :         /* Read datum/isnull. */
     257         128 :         prm->value = datumRestore(start_address, &prm->isnull);
     258             :     }
     259             : 
     260        1460 :     return paramLI;
     261             : }
     262             : 
     263             : /*
     264             :  * BuildParamLogString
     265             :  *      Return a string that represents the parameter list, for logging.
     266             :  *
     267             :  * If caller already knows textual representations for some parameters, it can
     268             :  * pass an array of exactly params->numParams values as knownTextValues, which
     269             :  * can contain NULLs for any unknown individual values.  NULL can be given if
     270             :  * no parameters are known.
     271             :  *
     272             :  * If maxlen is >= 0, that's the maximum number of bytes of any one
     273             :  * parameter value to be printed; an ellipsis is added if the string is
     274             :  * longer.  (Added quotes are not considered in this calculation.)
     275             :  */
     276             : char *
     277        2278 : BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
     278             : {
     279             :     MemoryContext tmpCxt,
     280             :                 oldCxt;
     281             :     StringInfoData buf;
     282             : 
     283             :     /*
     284             :      * NB: think not of returning params->paramValuesStr!  It may have been
     285             :      * generated with a different maxlen, and so be unsuitable.  Besides that,
     286             :      * this is the function used to create that string.
     287             :      */
     288             : 
     289             :     /*
     290             :      * No work if the param fetch hook is in use.  Also, it's not possible to
     291             :      * do this in an aborted transaction.  (It might be possible to improve on
     292             :      * this last point when some knownTextValues exist, but it seems tricky.)
     293             :      */
     294        4556 :     if (params->paramFetch != NULL ||
     295        2278 :         IsAbortedTransactionBlockState())
     296           0 :         return NULL;
     297             : 
     298             :     /* Initialize the output stringinfo, in caller's memory context */
     299        2278 :     initStringInfo(&buf);
     300             : 
     301             :     /* Use a temporary context to call output functions, just in case */
     302        2278 :     tmpCxt = AllocSetContextCreate(CurrentMemoryContext,
     303             :                                    "BuildParamLogString",
     304             :                                    ALLOCSET_DEFAULT_SIZES);
     305        2278 :     oldCxt = MemoryContextSwitchTo(tmpCxt);
     306             : 
     307        5658 :     for (int paramno = 0; paramno < params->numParams; paramno++)
     308             :     {
     309        3380 :         ParamExternData *param = &params->params[paramno];
     310             : 
     311        3380 :         appendStringInfo(&buf,
     312             :                          "%s$%d = ",
     313             :                          paramno > 0 ? ", " : "",
     314             :                          paramno + 1);
     315             : 
     316        3380 :         if (param->isnull || !OidIsValid(param->ptype))
     317          10 :             appendStringInfoString(&buf, "NULL");
     318             :         else
     319             :         {
     320        3370 :             if (knownTextValues != NULL && knownTextValues[paramno] != NULL)
     321          12 :                 appendStringInfoStringQuoted(&buf, knownTextValues[paramno],
     322             :                                              maxlen);
     323             :             else
     324             :             {
     325             :                 Oid         typoutput;
     326             :                 bool        typisvarlena;
     327             :                 char       *pstring;
     328             : 
     329        3358 :                 getTypeOutputInfo(param->ptype, &typoutput, &typisvarlena);
     330        3358 :                 pstring = OidOutputFunctionCall(typoutput, param->value);
     331        3358 :                 appendStringInfoStringQuoted(&buf, pstring, maxlen);
     332             :             }
     333             :         }
     334             :     }
     335             : 
     336        2278 :     MemoryContextSwitchTo(oldCxt);
     337        2278 :     MemoryContextDelete(tmpCxt);
     338             : 
     339        2278 :     return buf.data;
     340             : }
     341             : 
     342             : /*
     343             :  * ParamsErrorCallback - callback for printing parameters in error context
     344             :  *
     345             :  * Note that this is a no-op unless BuildParamLogString has been called
     346             :  * beforehand.
     347             :  */
     348             : void
     349          28 : ParamsErrorCallback(void *arg)
     350             : {
     351          28 :     ParamsErrorCbData *data = (ParamsErrorCbData *) arg;
     352             : 
     353          28 :     if (data == NULL ||
     354          28 :         data->params == NULL ||
     355          18 :         data->params->paramValuesStr == NULL)
     356          20 :         return;
     357             : 
     358           8 :     if (data->portalName && data->portalName[0] != '\0')
     359           0 :         errcontext("extended query \"%s\" with parameters: %s",
     360           0 :                    data->portalName, data->params->paramValuesStr);
     361             :     else
     362           8 :         errcontext("extended query with parameters: %s",
     363           8 :                    data->params->paramValuesStr);
     364             : }

Generated by: LCOV version 1.13