PostgreSQL Source Code  git master
params.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * params.c
4  * Support for finding the values associated with Param nodes.
5  *
6  *
7  * Portions Copyright (c) 1996-2024, 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  */
44 makeParamList(int numParams)
45 {
46  ParamListInfo retval;
47  Size size;
48 
49  size = offsetof(ParamListInfoData, params) +
50  numParams * sizeof(ParamExternData);
51 
52  retval = (ParamListInfo) palloc(size);
53  retval->paramFetch = NULL;
54  retval->paramFetchArg = NULL;
55  retval->paramCompile = NULL;
56  retval->paramCompileArg = NULL;
58  retval->parserSetupArg = (void *) retval;
59  retval->paramValuesStr = NULL;
60  retval->numParams = numParams;
61 
62  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  */
79 {
80  ParamListInfo retval;
81 
82  if (from == NULL || from->numParams <= 0)
83  return NULL;
84 
85  retval = makeParamList(from->numParams);
86 
87  for (int i = 0; i < from->numParams; i++)
88  {
89  ParamExternData *oprm;
90  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  if (from->paramFetch != NULL)
97  oprm = from->paramFetch(from, i + 1, false, &prmdata);
98  else
99  oprm = &from->params[i];
100 
101  /* flat-copy the parameter info */
102  *nprm = *oprm;
103 
104  /* need datumCopy in case it's a pass-by-reference datatype */
105  if (nprm->isnull || !OidIsValid(nprm->ptype))
106  continue;
107  get_typlenbyval(nprm->ptype, &typLen, &typByVal);
108  nprm->value = datumCopy(nprm->value, typByVal, typLen);
109  }
110 
111  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
121 {
123  /* no need to use p_coerce_param_hook */
124  pstate->p_ref_hook_state = arg;
125 }
126 
127 /*
128  * Transform a ParamRef using parameter type data from a ParamListInfo.
129  */
130 static Node *
132 {
133  ParamListInfo paramLI = (ParamListInfo) pstate->p_ref_hook_state;
134  int paramno = pref->number;
135  ParamExternData *prm;
136  ParamExternData prmdata;
137  Param *param;
138 
139  /* check parameter number is valid */
140  if (paramno <= 0 || paramno > paramLI->numParams)
141  return NULL;
142 
143  /* give hook a chance in case parameter is dynamic */
144  if (paramLI->paramFetch != NULL)
145  prm = paramLI->paramFetch(paramLI, paramno, false, &prmdata);
146  else
147  prm = &paramLI->params[paramno - 1];
148 
149  if (!OidIsValid(prm->ptype))
150  return NULL;
151 
152  param = makeNode(Param);
153  param->paramkind = PARAM_EXTERN;
154  param->paramid = paramno;
155  param->paramtype = prm->ptype;
156  param->paramtypmod = -1;
157  param->paramcollid = get_typcollation(param->paramtype);
158  param->location = pref->location;
159 
160  return (Node *) param;
161 }
162 
163 /*
164  * Estimate the amount of space required to serialize a ParamListInfo.
165  */
166 Size
168 {
169  int i;
170  Size sz = sizeof(int);
171 
172  if (paramLI == NULL || paramLI->numParams <= 0)
173  return sz;
174 
175  for (i = 0; i < paramLI->numParams; i++)
176  {
177  ParamExternData *prm;
178  ParamExternData prmdata;
179  Oid typeOid;
180  int16 typLen;
181  bool typByVal;
182 
183  /* give hook a chance in case parameter is dynamic */
184  if (paramLI->paramFetch != NULL)
185  prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
186  else
187  prm = &paramLI->params[i];
188 
189  typeOid = prm->ptype;
190 
191  sz = add_size(sz, sizeof(Oid)); /* space for type OID */
192  sz = add_size(sz, sizeof(uint16)); /* space for pflags */
193 
194  /* space for datum/isnull */
195  if (OidIsValid(typeOid))
196  get_typlenbyval(typeOid, &typLen, &typByVal);
197  else
198  {
199  /* If no type OID, assume by-value, like copyParamList does. */
200  typLen = sizeof(Datum);
201  typByVal = true;
202  }
203  sz = add_size(sz,
204  datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
205  }
206 
207  return sz;
208 }
209 
210 /*
211  * Serialize a ParamListInfo structure into caller-provided storage.
212  *
213  * We write the number of parameters first, as a 4-byte integer, and then
214  * write details for each parameter in turn. The details for each parameter
215  * consist of a 4-byte type OID, 2 bytes of flags, and then the datum as
216  * serialized by datumSerialize(). The caller is responsible for ensuring
217  * that there is enough storage to store the number of bytes that will be
218  * written; use EstimateParamListSpace to find out how many will be needed.
219  * *start_address is updated to point to the byte immediately following those
220  * written.
221  *
222  * RestoreParamList can be used to recreate a ParamListInfo based on the
223  * serialized representation; this will be a static, self-contained copy
224  * just as copyParamList would create.
225  *
226  * paramValuesStr is not included.
227  */
228 void
229 SerializeParamList(ParamListInfo paramLI, char **start_address)
230 {
231  int nparams;
232  int i;
233 
234  /* Write number of parameters. */
235  if (paramLI == NULL || paramLI->numParams <= 0)
236  nparams = 0;
237  else
238  nparams = paramLI->numParams;
239  memcpy(*start_address, &nparams, sizeof(int));
240  *start_address += sizeof(int);
241 
242  /* Write each parameter in turn. */
243  for (i = 0; i < nparams; i++)
244  {
245  ParamExternData *prm;
246  ParamExternData prmdata;
247  Oid typeOid;
248  int16 typLen;
249  bool typByVal;
250 
251  /* give hook a chance in case parameter is dynamic */
252  if (paramLI->paramFetch != NULL)
253  prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
254  else
255  prm = &paramLI->params[i];
256 
257  typeOid = prm->ptype;
258 
259  /* Write type OID. */
260  memcpy(*start_address, &typeOid, sizeof(Oid));
261  *start_address += sizeof(Oid);
262 
263  /* Write flags. */
264  memcpy(*start_address, &prm->pflags, sizeof(uint16));
265  *start_address += sizeof(uint16);
266 
267  /* Write datum/isnull. */
268  if (OidIsValid(typeOid))
269  get_typlenbyval(typeOid, &typLen, &typByVal);
270  else
271  {
272  /* If no type OID, assume by-value, like copyParamList does. */
273  typLen = sizeof(Datum);
274  typByVal = true;
275  }
276  datumSerialize(prm->value, prm->isnull, typByVal, typLen,
277  start_address);
278  }
279 }
280 
281 /*
282  * Copy a ParamListInfo structure.
283  *
284  * The result is allocated in CurrentMemoryContext.
285  *
286  * Note: the intent of this function is to make a static, self-contained
287  * set of parameter values. If dynamic parameter hooks are present, we
288  * intentionally do not copy them into the result. Rather, we forcibly
289  * instantiate all available parameter values and copy the datum values.
290  */
292 RestoreParamList(char **start_address)
293 {
294  ParamListInfo paramLI;
295  int nparams;
296 
297  memcpy(&nparams, *start_address, sizeof(int));
298  *start_address += sizeof(int);
299 
300  paramLI = makeParamList(nparams);
301 
302  for (int i = 0; i < nparams; i++)
303  {
304  ParamExternData *prm = &paramLI->params[i];
305 
306  /* Read type OID. */
307  memcpy(&prm->ptype, *start_address, sizeof(Oid));
308  *start_address += sizeof(Oid);
309 
310  /* Read flags. */
311  memcpy(&prm->pflags, *start_address, sizeof(uint16));
312  *start_address += sizeof(uint16);
313 
314  /* Read datum/isnull. */
315  prm->value = datumRestore(start_address, &prm->isnull);
316  }
317 
318  return paramLI;
319 }
320 
321 /*
322  * BuildParamLogString
323  * Return a string that represents the parameter list, for logging.
324  *
325  * If caller already knows textual representations for some parameters, it can
326  * pass an array of exactly params->numParams values as knownTextValues, which
327  * can contain NULLs for any unknown individual values. NULL can be given if
328  * no parameters are known.
329  *
330  * If maxlen is >= 0, that's the maximum number of bytes of any one
331  * parameter value to be printed; an ellipsis is added if the string is
332  * longer. (Added quotes are not considered in this calculation.)
333  */
334 char *
335 BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
336 {
337  MemoryContext tmpCxt,
338  oldCxt;
340 
341  /*
342  * NB: think not of returning params->paramValuesStr! It may have been
343  * generated with a different maxlen, and so be unsuitable. Besides that,
344  * this is the function used to create that string.
345  */
346 
347  /*
348  * No work if the param fetch hook is in use. Also, it's not possible to
349  * do this in an aborted transaction. (It might be possible to improve on
350  * this last point when some knownTextValues exist, but it seems tricky.)
351  */
352  if (params->paramFetch != NULL ||
354  return NULL;
355 
356  /* Initialize the output stringinfo, in caller's memory context */
358 
359  /* Use a temporary context to call output functions, just in case */
361  "BuildParamLogString",
363  oldCxt = MemoryContextSwitchTo(tmpCxt);
364 
365  for (int paramno = 0; paramno < params->numParams; paramno++)
366  {
367  ParamExternData *param = &params->params[paramno];
368 
370  "%s$%d = ",
371  paramno > 0 ? ", " : "",
372  paramno + 1);
373 
374  if (param->isnull || !OidIsValid(param->ptype))
375  appendStringInfoString(&buf, "NULL");
376  else
377  {
378  if (knownTextValues != NULL && knownTextValues[paramno] != NULL)
379  appendStringInfoStringQuoted(&buf, knownTextValues[paramno],
380  maxlen);
381  else
382  {
383  Oid typoutput;
384  bool typisvarlena;
385  char *pstring;
386 
387  getTypeOutputInfo(param->ptype, &typoutput, &typisvarlena);
388  pstring = OidOutputFunctionCall(typoutput, param->value);
389  appendStringInfoStringQuoted(&buf, pstring, maxlen);
390  }
391  }
392  }
393 
394  MemoryContextSwitchTo(oldCxt);
395  MemoryContextDelete(tmpCxt);
396 
397  return buf.data;
398 }
399 
400 /*
401  * ParamsErrorCallback - callback for printing parameters in error context
402  *
403  * Note that this is a no-op unless BuildParamLogString has been called
404  * beforehand.
405  */
406 void
408 {
410 
411  if (data == NULL ||
412  data->params == NULL ||
413  data->params->paramValuesStr == NULL)
414  return;
415 
416  if (data->portalName && data->portalName[0] != '\0')
417  errcontext("portal \"%s\" with parameters: %s",
418  data->portalName, data->params->paramValuesStr);
419  else
420  errcontext("unnamed portal with parameters: %s",
421  data->params->paramValuesStr);
422 }
unsigned short uint16
Definition: c.h:505
signed short int16
Definition: c.h:493
#define OidIsValid(objectId)
Definition: c.h:775
size_t Size
Definition: c.h:605
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
Datum datumRestore(char **start_address, bool *isnull)
Definition: datum.c:521
void datumSerialize(Datum value, bool isnull, bool typByVal, int typLen, char **start_address)
Definition: datum.c:459
Size datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
Definition: datum.c:412
#define errcontext
Definition: elog.h:196
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2251
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3056
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1316
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define makeNode(_type_)
Definition: nodes.h:155
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:78
char * BuildParamLogString(ParamListInfo params, char **knownTextValues, int maxlen)
Definition: params.c:335
static Node * paramlist_param_ref(ParseState *pstate, ParamRef *pref)
Definition: params.c:131
static void paramlist_parser_setup(ParseState *pstate, void *arg)
Definition: params.c:120
Size EstimateParamListSpace(ParamListInfo paramLI)
Definition: params.c:167
void SerializeParamList(ParamListInfo paramLI, char **start_address)
Definition: params.c:229
void ParamsErrorCallback(void *arg)
Definition: params.c:407
ParamListInfo RestoreParamList(char **start_address)
Definition: params.c:292
struct ParamListInfoData * ParamListInfo
Definition: params.h:98
struct ParamExternData ParamExternData
void * arg
const void * data
static char * buf
Definition: pg_test_fsync.c:73
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
@ PARAM_EXTERN
Definition: primnodes.h:367
MemoryContextSwitchTo(old_ctx)
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
static pg_noinline void Size size
Definition: slab.c:607
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
void appendStringInfoStringQuoted(StringInfo str, const char *s, int maxlen)
Definition: stringinfo_mb.c:34
Definition: nodes.h:129
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125
char * paramValuesStr
Definition: params.h:118
ParserSetupHook parserSetup
Definition: params.h:116
ParamCompileHook paramCompile
Definition: params.h:114
void * parserSetupArg
Definition: params.h:117
void * paramCompileArg
Definition: params.h:115
ParamFetchHook paramFetch
Definition: params.h:112
void * paramFetchArg
Definition: params.h:113
ParseLoc location
Definition: parsenodes.h:305
int number
Definition: parsenodes.h:304
void * p_ref_hook_state
Definition: parse_node.h:239
ParseParamRefHook p_paramref_hook
Definition: parse_node.h:237
bool IsAbortedTransactionBlockState(void)
Definition: xact.c:404