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 | */ |
31 | ParamListInfo |
32 | makeParamList(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 | */ |
62 | ParamListInfo |
63 | copyParamList(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 | */ |
102 | Size |
103 | EstimateParamListSpace(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 = ¶mLI->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 | */ |
162 | void |
163 | SerializeParamList(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 = ¶mLI->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 | */ |
225 | ParamListInfo |
226 | RestoreParamList(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 = ¶mLI->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 | |