1717 *
1818 *
1919 * 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 $
2121 *
2222 *-------------------------------------------------------------------------
2323 */
@@ -36,6 +36,7 @@ typedef struct FixedParamState
3636{
3737Oid * paramTypes ;/* array of parameter type OIDs */
3838int numParams ;/* number of array entries */
39+ Oid * unknownParamTypes ;/* resolved types of 'unknown' params */
3940}FixedParamState ;
4041
4142/*
@@ -55,6 +56,9 @@ static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
5556static Node * variable_coerce_param_hook (ParseState * pstate ,Param * param ,
5657Oid targetTypeId ,int32 targetTypeMod ,
5758int location );
59+ static Node * fixed_coerce_param_hook (ParseState * pstate ,Param * param ,
60+ Oid targetTypeId ,int32 targetTypeMod ,
61+ int location );
5862static bool check_parameter_resolution_walker (Node * node ,ParseState * pstate );
5963
6064
@@ -69,9 +73,10 @@ parse_fixed_parameters(ParseState *pstate,
6973
7074parstate -> paramTypes = paramTypes ;
7175parstate -> numParams = numParams ;
76+ parstate -> unknownParamTypes = NULL ;
7277pstate -> p_ref_hook_state = (void * )parstate ;
7378pstate -> 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 ;
7580}
7681
7782/*
@@ -170,6 +175,83 @@ variable_paramref_hook(ParseState *pstate, ParamRef *pref)
170175return (Node * )param ;
171176}
172177
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+
173255/*
174256 * Coerce a Param to a query-requested datatype, in the varparams case.
175257 */