17
17
*
18
18
*
19
19
* IDENTIFICATION
20
- * $PostgreSQL: pgsql/src/backend/parser/parse_param.c,v 2.4 2010/02/26 02:00:52 momjian Exp $
20
+ * $PostgreSQL: pgsql/src/backend/parser/parse_param.c,v 2.5 2010/08/18 12:20:15 heikki Exp $
21
21
*
22
22
*-------------------------------------------------------------------------
23
23
*/
@@ -36,6 +36,7 @@ typedef struct FixedParamState
36
36
{
37
37
Oid * paramTypes ; /* array of parameter type OIDs */
38
38
int numParams ; /* number of array entries */
39
+ Oid * unknownParamTypes ; /* resolved types of 'unknown' params */
39
40
} FixedParamState ;
40
41
41
42
/*
@@ -55,6 +56,9 @@ static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
55
56
static Node * variable_coerce_param_hook (ParseState * pstate , Param * param ,
56
57
Oid targetTypeId , int32 targetTypeMod ,
57
58
int location );
59
+ static Node * fixed_coerce_param_hook (ParseState * pstate , Param * param ,
60
+ Oid targetTypeId , int32 targetTypeMod ,
61
+ int location );
58
62
static bool check_parameter_resolution_walker (Node * node , ParseState * pstate );
59
63
60
64
@@ -69,9 +73,10 @@ parse_fixed_parameters(ParseState *pstate,
69
73
70
74
parstate -> paramTypes = paramTypes ;
71
75
parstate -> numParams = numParams ;
76
+ parstate -> unknownParamTypes = NULL ;
72
77
pstate -> p_ref_hook_state = (void * ) parstate ;
73
78
pstate -> p_paramref_hook = fixed_paramref_hook ;
74
- /* no need to use p_coerce_param_hook */
79
+ pstate -> p_coerce_param_hook = fixed_coerce_param_hook ;
75
80
}
76
81
77
82
/*
@@ -170,6 +175,83 @@ variable_paramref_hook(ParseState *pstate, ParamRef *pref)
170
175
return (Node * ) param ;
171
176
}
172
177
178
+ /*
179
+ * Coerce a Param to a query-requested datatype, in the fixed params case.
180
+ *
181
+ * 'unknown' type params are coerced to the type requested, analogous to the
182
+ * coercion of unknown constants performed in coerce_type(). We can't change
183
+ * the param types like we do in the varparams case, so the coercion is done
184
+ * at runtime using CoerceViaIO nodes.
185
+ */
186
+ static Node *
187
+ fixed_coerce_param_hook (ParseState * pstate , Param * param ,
188
+ Oid targetTypeId , int32 targetTypeMode ,
189
+ int location )
190
+ {
191
+ if (param -> paramkind == PARAM_EXTERN && param -> paramtype == UNKNOWNOID )
192
+ {
193
+ FixedParamState * parstate = (FixedParamState * ) pstate -> p_ref_hook_state ;
194
+ Oid * unknownParamTypes = parstate -> unknownParamTypes ;
195
+ int paramno = param -> paramid ;
196
+ CoerceViaIO * iocoerce ;
197
+
198
+ if (paramno <= 0 || /* shouldn't happen, but... */
199
+ paramno > parstate -> numParams )
200
+ ereport (ERROR ,
201
+ (errcode (ERRCODE_UNDEFINED_PARAMETER ),
202
+ errmsg ("there is no parameter $%d" , paramno ),
203
+ parser_errposition (pstate , param -> location )));
204
+
205
+ /* Allocate the array on first use */
206
+ if (unknownParamTypes == NULL )
207
+ {
208
+ unknownParamTypes = palloc0 (parstate -> numParams * sizeof (Oid ));
209
+ parstate -> unknownParamTypes = unknownParamTypes ;
210
+ }
211
+
212
+ /*
213
+ * If the same parameter is used multiple times in the query, make
214
+ * sure it's always resolved to the same type. The code would cope
215
+ * with differing interpretations, but it might lead to surprising
216
+ * results. The varparams code forbids that anyway, so better be
217
+ * consistent.
218
+ */
219
+ if (unknownParamTypes [paramno - 1 ] == InvalidOid )
220
+ {
221
+ /* We've successfully resolved the type */
222
+ unknownParamTypes [paramno - 1 ] = targetTypeId ;
223
+ }
224
+ else if (unknownParamTypes [paramno - 1 ] == targetTypeId )
225
+ {
226
+ /* We previously resolved the type, and it matches */
227
+ }
228
+ else
229
+ {
230
+ /* Ooops */
231
+ ereport (ERROR ,
232
+ (errcode (ERRCODE_AMBIGUOUS_PARAMETER ),
233
+ errmsg ("inconsistent types deduced for parameter $%d" ,
234
+ paramno ),
235
+ errdetail ("%s versus %s" ,
236
+ format_type_be (unknownParamTypes [paramno - 1 ]),
237
+ format_type_be (targetTypeId )),
238
+ parser_errposition (pstate , param -> location )));
239
+ }
240
+
241
+ /* Build a CoerceViaIO node */
242
+ iocoerce = makeNode (CoerceViaIO );
243
+ iocoerce -> arg = (Expr * ) param ;
244
+ iocoerce -> resulttype = targetTypeId ;
245
+ iocoerce -> coerceformat = COERCE_IMPLICIT_CAST ;
246
+ iocoerce -> location = location ;
247
+
248
+ return (Node * ) iocoerce ;
249
+ }
250
+
251
+ /* Else signal to proceed with normal coercion */
252
+ return NULL ;
253
+ }
254
+
173
255
/*
174
256
* Coerce a Param to a query-requested datatype, in the varparams case.
175
257
*/
0 commit comments