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