1/*-------------------------------------------------------------------------
2 *
3 * params.c
4 * Support for finding the values associated with Param nodes.
5 *
6 *
7 * Portions Copyright (c) 1996-2019, 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 "nodes/bitmapset.h"
19#include "nodes/params.h"
20#include "storage/shmem.h"
21#include "utils/datum.h"
22#include "utils/lsyscache.h"
23
24
25/*
26 * Allocate and initialize a new ParamListInfo structure.
27 *
28 * To make a new structure for the "dynamic" way (with hooks), pass 0 for
29 * numParams and set numParams manually.
30 */
31ParamListInfo
32makeParamList(int numParams)
33{
34 ParamListInfo retval;
35 Size size;
36
37 size = offsetof(ParamListInfoData, params) +
38 numParams * sizeof(ParamExternData);
39
40 retval = (ParamListInfo) palloc(size);
41 retval->paramFetch = NULL;
42 retval->paramFetchArg = NULL;
43 retval->paramCompile = NULL;
44 retval->paramCompileArg = NULL;
45 retval->parserSetup = NULL;
46 retval->parserSetupArg = NULL;
47 retval->numParams = numParams;
48
49 return retval;
50}
51
52/*
53 * Copy a ParamListInfo structure.
54 *
55 * The result is allocated in CurrentMemoryContext.
56 *
57 * Note: the intent of this function is to make a static, self-contained
58 * set of parameter values. If dynamic parameter hooks are present, we
59 * intentionally do not copy them into the result. Rather, we forcibly
60 * instantiate all available parameter values and copy the datum values.
61 */
62ParamListInfo
63copyParamList(ParamListInfo from)
64{
65 ParamListInfo retval;
66
67 if (from == NULL || from->numParams <= 0)
68 return NULL;
69
70 retval = makeParamList(from->numParams);
71
72 for (int i = 0; i < from->numParams; i++)
73 {
74 ParamExternData *oprm;
75 ParamExternData *nprm = &retval->params[i];
76 ParamExternData prmdata;
77 int16 typLen;
78 bool typByVal;
79
80 /* give hook a chance in case parameter is dynamic */
81 if (from->paramFetch != NULL)
82 oprm = from->paramFetch(from, i + 1, false, &prmdata);
83 else
84 oprm = &from->params[i];
85
86 /* flat-copy the parameter info */
87 *nprm = *oprm;
88
89 /* need datumCopy in case it's a pass-by-reference datatype */
90 if (nprm->isnull || !OidIsValid(nprm->ptype))
91 continue;
92 get_typlenbyval(nprm->ptype, &typLen, &typByVal);
93 nprm->value = datumCopy(nprm->value, typByVal, typLen);
94 }
95
96 return retval;
97}
98
99/*
100 * Estimate the amount of space required to serialize a ParamListInfo.
101 */
102Size
103EstimateParamListSpace(ParamListInfo paramLI)
104{
105 int i;
106 Size sz = sizeof(int);
107
108 if (paramLI == NULL || paramLI->numParams <= 0)
109 return sz;
110
111 for (i = 0; i < paramLI->numParams; i++)
112 {
113 ParamExternData *prm;
114 ParamExternData prmdata;
115 Oid typeOid;
116 int16 typLen;
117 bool typByVal;
118
119 /* give hook a chance in case parameter is dynamic */
120 if (paramLI->paramFetch != NULL)
121 prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
122 else
123 prm = &paramLI->params[i];
124
125 typeOid = prm->ptype;
126
127 sz = add_size(sz, sizeof(Oid)); /* space for type OID */
128 sz = add_size(sz, sizeof(uint16)); /* space for pflags */
129
130 /* space for datum/isnull */
131 if (OidIsValid(typeOid))
132 get_typlenbyval(typeOid, &typLen, &typByVal);
133 else
134 {
135 /* If no type OID, assume by-value, like copyParamList does. */
136 typLen = sizeof(Datum);
137 typByVal = true;
138 }
139 sz = add_size(sz,
140 datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
141 }
142
143 return sz;
144}
145
146/*
147 * Serialize a paramListInfo structure into caller-provided storage.
148 *
149 * We write the number of parameters first, as a 4-byte integer, and then
150 * write details for each parameter in turn. The details for each parameter
151 * consist of a 4-byte type OID, 2 bytes of flags, and then the datum as
152 * serialized by datumSerialize(). The caller is responsible for ensuring
153 * that there is enough storage to store the number of bytes that will be
154 * written; use EstimateParamListSpace to find out how many will be needed.
155 * *start_address is updated to point to the byte immediately following those
156 * written.
157 *
158 * RestoreParamList can be used to recreate a ParamListInfo based on the
159 * serialized representation; this will be a static, self-contained copy
160 * just as copyParamList would create.
161 */
162void
163SerializeParamList(ParamListInfo paramLI, char **start_address)
164{
165 int nparams;
166 int i;
167
168 /* Write number of parameters. */
169 if (paramLI == NULL || paramLI->numParams <= 0)
170 nparams = 0;
171 else
172 nparams = paramLI->numParams;
173 memcpy(*start_address, &nparams, sizeof(int));
174 *start_address += sizeof(int);
175
176 /* Write each parameter in turn. */
177 for (i = 0; i < nparams; i++)
178 {
179 ParamExternData *prm;
180 ParamExternData prmdata;
181 Oid typeOid;
182 int16 typLen;
183 bool typByVal;
184
185 /* give hook a chance in case parameter is dynamic */
186 if (paramLI->paramFetch != NULL)
187 prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
188 else
189 prm = &paramLI->params[i];
190
191 typeOid = prm->ptype;
192
193 /* Write type OID. */
194 memcpy(*start_address, &typeOid, sizeof(Oid));
195 *start_address += sizeof(Oid);
196
197 /* Write flags. */
198 memcpy(*start_address, &prm->pflags, sizeof(uint16));
199 *start_address += sizeof(uint16);
200
201 /* Write datum/isnull. */
202 if (OidIsValid(typeOid))
203 get_typlenbyval(typeOid, &typLen, &typByVal);
204 else
205 {
206 /* If no type OID, assume by-value, like copyParamList does. */
207 typLen = sizeof(Datum);
208 typByVal = true;
209 }
210 datumSerialize(prm->value, prm->isnull, typByVal, typLen,
211 start_address);
212 }
213}
214
215/*
216 * Copy a ParamListInfo structure.
217 *
218 * The result is allocated in CurrentMemoryContext.
219 *
220 * Note: the intent of this function is to make a static, self-contained
221 * set of parameter values. If dynamic parameter hooks are present, we
222 * intentionally do not copy them into the result. Rather, we forcibly
223 * instantiate all available parameter values and copy the datum values.
224 */
225ParamListInfo
226RestoreParamList(char **start_address)
227{
228 ParamListInfo paramLI;
229 int nparams;
230
231 memcpy(&nparams, *start_address, sizeof(int));
232 *start_address += sizeof(int);
233
234 paramLI = makeParamList(nparams);
235
236 for (int i = 0; i < nparams; i++)
237 {
238 ParamExternData *prm = &paramLI->params[i];
239
240 /* Read type OID. */
241 memcpy(&prm->ptype, *start_address, sizeof(Oid));
242 *start_address += sizeof(Oid);
243
244 /* Read flags. */
245 memcpy(&prm->pflags, *start_address, sizeof(uint16));
246 *start_address += sizeof(uint16);
247
248 /* Read datum/isnull. */
249 prm->value = datumRestore(start_address, &prm->isnull);
250 }
251
252 return paramLI;
253}
254