Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ef71375

Browse files
committed
Coerce 'unknown' type parameters to the right type in the fixed-params
parse_analyze() function. That case occurs e.g with PL/pgSQL EXECUTE ... USING 'stringconstant'. The coercion with a CoerceViaIO node. The result is similar to the coercion via input function performed for unknown constants in coerce_type(), except that this happens at runtime. Backpatch to 9.0. The issue is present in 8.4 as well, but the coerce param hook infrastructure this patch relies on was introduced in 9.0. Given the lack of user reports and harmlessness of the bug, it's not worth attempting a different fix just for 8.4.
1 parent 9a8d15b commit ef71375

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

src/backend/parser/parse_param.c

+84-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
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
{
3737
Oid *paramTypes; /* array of parameter type OIDs */
3838
int 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);
5556
static Node *variable_coerce_param_hook(ParseState *pstate, Param *param,
5657
Oid targetTypeId, int32 targetTypeMod,
5758
int location);
59+
static Node *fixed_coerce_param_hook(ParseState *pstate, Param *param,
60+
Oid targetTypeId, int32 targetTypeMod,
61+
int location);
5862
static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
5963

6064

@@ -69,9 +73,10 @@ parse_fixed_parameters(ParseState *pstate,
6973

7074
parstate->paramTypes = paramTypes;
7175
parstate->numParams = numParams;
76+
parstate->unknownParamTypes = NULL;
7277
pstate->p_ref_hook_state = (void *) parstate;
7378
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;
7580
}
7681

7782
/*
@@ -170,6 +175,83 @@ variable_paramref_hook(ParseState *pstate, ParamRef *pref)
170175
return (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
*/

0 commit comments

Comments
 (0)