1 /*-------------------------------------------------------------------------
4 * handle parameters in parser
6 * This code covers two cases that are used within the core backend:
7 * * a fixed list of parameters with known types
8 * * an expandable list of parameters whose types can optionally
9 * be determined from context
10 * In both cases, only explicit $n references (ParamRef nodes) are supported.
12 * Note that other approaches to parameters are possible using the parser
13 * hooks defined in ParseState.
15 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
20 * $PostgreSQL: pgsql/src/backend/parser/parse_param.c,v 2.6 2010/08/19 16:54:43 heikki Exp $
22 *-------------------------------------------------------------------------
29 #include "catalog/pg_type.h"
30 #include "nodes/nodeFuncs.h"
31 #include "parser/parse_param.h"
32 #include "utils/builtins.h"
35 typedef struct FixedParamState
37 Oid *paramTypes; /* array of parameter type OIDs */
38 int numParams; /* number of array entries */
42 * In the varparams case, the caller-supplied OID array (if any) can be
43 * re-palloc'd larger at need. A zero array entry means that parameter number
44 * hasn't been seen, while UNKNOWNOID means the parameter has been used but
45 * its type is not yet known.
47 typedef struct VarParamState
49 Oid **paramTypes; /* array of parameter type OIDs */
50 int *numParams; /* number of array entries */
53 static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref);
54 static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
55 static Node *variable_coerce_param_hook(ParseState *pstate, Param *param,
56 Oid targetTypeId, int32 targetTypeMod,
58 static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
62 * Set up to process a query containing references to fixed parameters.
65 parse_fixed_parameters(ParseState *pstate,
66 Oid *paramTypes, int numParams)
68 FixedParamState *parstate = palloc(sizeof(FixedParamState));
70 parstate->paramTypes = paramTypes;
71 parstate->numParams = numParams;
72 pstate->p_ref_hook_state = (void *) parstate;
73 pstate->p_paramref_hook = fixed_paramref_hook;
74 /* no need to use p_coerce_param_hook */
78 * Set up to process a query containing references to variable parameters.
81 parse_variable_parameters(ParseState *pstate,
82 Oid **paramTypes, int *numParams)
84 VarParamState *parstate = palloc(sizeof(VarParamState));
86 parstate->paramTypes = paramTypes;
87 parstate->numParams = numParams;
88 pstate->p_ref_hook_state = (void *) parstate;
89 pstate->p_paramref_hook = variable_paramref_hook;
90 pstate->p_coerce_param_hook = variable_coerce_param_hook;
94 * Transform a ParamRef using fixed parameter types.
97 fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
99 FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
100 int paramno = pref->number;
103 /* Check parameter number is valid */
104 if (paramno <= 0 || paramno > parstate->numParams ||
105 !OidIsValid(parstate->paramTypes[paramno - 1]))
107 (errcode(ERRCODE_UNDEFINED_PARAMETER),
108 errmsg("there is no parameter $%d", paramno),
109 parser_errposition(pstate, pref->location)));
111 param = makeNode(Param);
112 param->paramkind = PARAM_EXTERN;
113 param->paramid = paramno;
114 param->paramtype = parstate->paramTypes[paramno - 1];
115 param->paramtypmod = -1;
116 param->location = pref->location;
118 return (Node *) param;
122 * Transform a ParamRef using variable parameter types.
124 * The only difference here is we must enlarge the parameter type array
128 variable_paramref_hook(ParseState *pstate, ParamRef *pref)
130 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
131 int paramno = pref->number;
135 /* Check parameter number is in range */
136 if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
138 (errcode(ERRCODE_UNDEFINED_PARAMETER),
139 errmsg("there is no parameter $%d", paramno),
140 parser_errposition(pstate, pref->location)));
141 if (paramno > *parstate->numParams)
143 /* Need to enlarge param array */
144 if (*parstate->paramTypes)
145 *parstate->paramTypes = (Oid *) repalloc(*parstate->paramTypes,
146 paramno * sizeof(Oid));
148 *parstate->paramTypes = (Oid *) palloc(paramno * sizeof(Oid));
149 /* Zero out the previously-unreferenced slots */
150 MemSet(*parstate->paramTypes + *parstate->numParams,
152 (paramno - *parstate->numParams) * sizeof(Oid));
153 *parstate->numParams = paramno;
156 /* Locate param's slot in array */
157 pptype = &(*parstate->paramTypes)[paramno - 1];
159 /* If not seen before, initialize to UNKNOWN type */
160 if (*pptype == InvalidOid)
161 *pptype = UNKNOWNOID;
163 param = makeNode(Param);
164 param->paramkind = PARAM_EXTERN;
165 param->paramid = paramno;
166 param->paramtype = *pptype;
167 param->paramtypmod = -1;
168 param->location = pref->location;
170 return (Node *) param;
174 * Coerce a Param to a query-requested datatype, in the varparams case.
177 variable_coerce_param_hook(ParseState *pstate, Param *param,
178 Oid targetTypeId, int32 targetTypeMod,
181 if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
184 * Input is a Param of previously undetermined type, and we want to
185 * update our knowledge of the Param's type.
187 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
188 Oid *paramTypes = *parstate->paramTypes;
189 int paramno = param->paramid;
191 if (paramno <= 0 || /* shouldn't happen, but... */
192 paramno > *parstate->numParams)
194 (errcode(ERRCODE_UNDEFINED_PARAMETER),
195 errmsg("there is no parameter $%d", paramno),
196 parser_errposition(pstate, param->location)));
198 if (paramTypes[paramno - 1] == UNKNOWNOID)
200 /* We've successfully resolved the type */
201 paramTypes[paramno - 1] = targetTypeId;
203 else if (paramTypes[paramno - 1] == targetTypeId)
205 /* We previously resolved the type, and it matches */
211 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
212 errmsg("inconsistent types deduced for parameter $%d",
214 errdetail("%s versus %s",
215 format_type_be(paramTypes[paramno - 1]),
216 format_type_be(targetTypeId)),
217 parser_errposition(pstate, param->location)));
220 param->paramtype = targetTypeId;
223 * Note: it is tempting here to set the Param's paramtypmod to
224 * targetTypeMod, but that is probably unwise because we have no
225 * infrastructure that enforces that the value delivered for a Param
226 * will match any particular typmod. Leaving it -1 ensures that a
227 * run-time length check/coercion will occur if needed.
229 param->paramtypmod = -1;
231 /* Use the leftmost of the param's and coercion's locations */
233 (param->location < 0 || location < param->location))
234 param->location = location;
236 return (Node *) param;
239 /* Else signal to proceed with normal coercion */
244 * Check for consistent assignment of variable parameters after completion
245 * of parsing with parse_variable_parameters.
247 * Note: this code intentionally does not check that all parameter positions
248 * were used, nor that all got non-UNKNOWN types assigned. Caller of parser
249 * should enforce that if it's important.
252 check_variable_parameters(ParseState *pstate, Query *query)
254 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
256 /* If numParams is zero then no Params were generated, so no work */
257 if (*parstate->numParams > 0)
258 (void) query_tree_walker(query,
259 check_parameter_resolution_walker,
264 * Traverse a fully-analyzed tree to verify that parameter symbols
265 * match their types. We need this because some Params might still
266 * be UNKNOWN, if there wasn't anything to force their coercion,
267 * and yet other instances seen later might have gotten coerced.
270 check_parameter_resolution_walker(Node *node, ParseState *pstate)
274 if (IsA(node, Param))
276 Param *param = (Param *) node;
278 if (param->paramkind == PARAM_EXTERN)
280 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
281 int paramno = param->paramid;
283 if (paramno <= 0 || /* shouldn't happen, but... */
284 paramno > *parstate->numParams)
286 (errcode(ERRCODE_UNDEFINED_PARAMETER),
287 errmsg("there is no parameter $%d", paramno),
288 parser_errposition(pstate, param->location)));
290 if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
292 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
293 errmsg("could not determine data type of parameter $%d",
295 parser_errposition(pstate, param->location)));
299 if (IsA(node, Query))
301 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
302 return query_tree_walker((Query *) node,
303 check_parameter_resolution_walker,
306 return expression_tree_walker(node, check_parameter_resolution_walker,