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-2011, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
20 * src/backend/parser/parse_param.c
22 *-------------------------------------------------------------------------
29 #include "catalog/pg_type.h"
30 #include "nodes/nodeFuncs.h"
31 #include "parser/parse_param.h"
32 #include "utils/builtins.h"
33 #include "utils/lsyscache.h"
36 typedef struct FixedParamState
38 Oid *paramTypes; /* array of parameter type OIDs */
39 int numParams; /* number of array entries */
43 * In the varparams case, the caller-supplied OID array (if any) can be
44 * re-palloc'd larger at need. A zero array entry means that parameter number
45 * hasn't been seen, while UNKNOWNOID means the parameter has been used but
46 * its type is not yet known.
48 typedef struct VarParamState
50 Oid **paramTypes; /* array of parameter type OIDs */
51 int *numParams; /* number of array entries */
54 static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref);
55 static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
56 static Node *variable_coerce_param_hook(ParseState *pstate, Param *param,
57 Oid targetTypeId, int32 targetTypeMod,
59 static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
63 * Set up to process a query containing references to fixed parameters.
66 parse_fixed_parameters(ParseState *pstate,
67 Oid *paramTypes, int numParams)
69 FixedParamState *parstate = palloc(sizeof(FixedParamState));
71 parstate->paramTypes = paramTypes;
72 parstate->numParams = numParams;
73 pstate->p_ref_hook_state = (void *) parstate;
74 pstate->p_paramref_hook = fixed_paramref_hook;
75 /* no need to use p_coerce_param_hook */
79 * Set up to process a query containing references to variable parameters.
82 parse_variable_parameters(ParseState *pstate,
83 Oid **paramTypes, int *numParams)
85 VarParamState *parstate = palloc(sizeof(VarParamState));
87 parstate->paramTypes = paramTypes;
88 parstate->numParams = numParams;
89 pstate->p_ref_hook_state = (void *) parstate;
90 pstate->p_paramref_hook = variable_paramref_hook;
91 pstate->p_coerce_param_hook = variable_coerce_param_hook;
95 * Transform a ParamRef using fixed parameter types.
98 fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
100 FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
101 int paramno = pref->number;
104 /* Check parameter number is valid */
105 if (paramno <= 0 || paramno > parstate->numParams ||
106 !OidIsValid(parstate->paramTypes[paramno - 1]))
108 (errcode(ERRCODE_UNDEFINED_PARAMETER),
109 errmsg("there is no parameter $%d", paramno),
110 parser_errposition(pstate, pref->location)));
112 param = makeNode(Param);
113 param->paramkind = PARAM_EXTERN;
114 param->paramid = paramno;
115 param->paramtype = parstate->paramTypes[paramno - 1];
116 param->paramtypmod = -1;
117 param->paramcollation = get_typcollation(param->paramtype);
118 param->location = pref->location;
120 return (Node *) param;
124 * Transform a ParamRef using variable parameter types.
126 * The only difference here is we must enlarge the parameter type array
130 variable_paramref_hook(ParseState *pstate, ParamRef *pref)
132 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
133 int paramno = pref->number;
137 /* Check parameter number is in range */
138 if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
140 (errcode(ERRCODE_UNDEFINED_PARAMETER),
141 errmsg("there is no parameter $%d", paramno),
142 parser_errposition(pstate, pref->location)));
143 if (paramno > *parstate->numParams)
145 /* Need to enlarge param array */
146 if (*parstate->paramTypes)
147 *parstate->paramTypes = (Oid *) repalloc(*parstate->paramTypes,
148 paramno * sizeof(Oid));
150 *parstate->paramTypes = (Oid *) palloc(paramno * sizeof(Oid));
151 /* Zero out the previously-unreferenced slots */
152 MemSet(*parstate->paramTypes + *parstate->numParams,
154 (paramno - *parstate->numParams) * sizeof(Oid));
155 *parstate->numParams = paramno;
158 /* Locate param's slot in array */
159 pptype = &(*parstate->paramTypes)[paramno - 1];
161 /* If not seen before, initialize to UNKNOWN type */
162 if (*pptype == InvalidOid)
163 *pptype = UNKNOWNOID;
165 param = makeNode(Param);
166 param->paramkind = PARAM_EXTERN;
167 param->paramid = paramno;
168 param->paramtype = *pptype;
169 param->paramtypmod = -1;
170 param->paramcollation = get_typcollation(param->paramtype);
171 param->location = pref->location;
173 return (Node *) param;
177 * Coerce a Param to a query-requested datatype, in the varparams case.
180 variable_coerce_param_hook(ParseState *pstate, Param *param,
181 Oid targetTypeId, int32 targetTypeMod,
184 if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
187 * Input is a Param of previously undetermined type, and we want to
188 * update our knowledge of the Param's type.
190 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
191 Oid *paramTypes = *parstate->paramTypes;
192 int paramno = param->paramid;
194 if (paramno <= 0 || /* shouldn't happen, but... */
195 paramno > *parstate->numParams)
197 (errcode(ERRCODE_UNDEFINED_PARAMETER),
198 errmsg("there is no parameter $%d", paramno),
199 parser_errposition(pstate, param->location)));
201 if (paramTypes[paramno - 1] == UNKNOWNOID)
203 /* We've successfully resolved the type */
204 paramTypes[paramno - 1] = targetTypeId;
206 else if (paramTypes[paramno - 1] == targetTypeId)
208 /* We previously resolved the type, and it matches */
214 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
215 errmsg("inconsistent types deduced for parameter $%d",
217 errdetail("%s versus %s",
218 format_type_be(paramTypes[paramno - 1]),
219 format_type_be(targetTypeId)),
220 parser_errposition(pstate, param->location)));
223 param->paramtype = targetTypeId;
226 * Note: it is tempting here to set the Param's paramtypmod to
227 * targetTypeMod, but that is probably unwise because we have no
228 * infrastructure that enforces that the value delivered for a Param
229 * will match any particular typmod. Leaving it -1 ensures that a
230 * run-time length check/coercion will occur if needed.
232 param->paramtypmod = -1;
234 /* Use the leftmost of the param's and coercion's locations */
236 (param->location < 0 || location < param->location))
237 param->location = location;
239 return (Node *) param;
242 /* Else signal to proceed with normal coercion */
247 * Check for consistent assignment of variable parameters after completion
248 * of parsing with parse_variable_parameters.
250 * Note: this code intentionally does not check that all parameter positions
251 * were used, nor that all got non-UNKNOWN types assigned. Caller of parser
252 * should enforce that if it's important.
255 check_variable_parameters(ParseState *pstate, Query *query)
257 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
259 /* If numParams is zero then no Params were generated, so no work */
260 if (*parstate->numParams > 0)
261 (void) query_tree_walker(query,
262 check_parameter_resolution_walker,
267 * Traverse a fully-analyzed tree to verify that parameter symbols
268 * match their types. We need this because some Params might still
269 * be UNKNOWN, if there wasn't anything to force their coercion,
270 * and yet other instances seen later might have gotten coerced.
273 check_parameter_resolution_walker(Node *node, ParseState *pstate)
277 if (IsA(node, Param))
279 Param *param = (Param *) node;
281 if (param->paramkind == PARAM_EXTERN)
283 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
284 int paramno = param->paramid;
286 if (paramno <= 0 || /* shouldn't happen, but... */
287 paramno > *parstate->numParams)
289 (errcode(ERRCODE_UNDEFINED_PARAMETER),
290 errmsg("there is no parameter $%d", paramno),
291 parser_errposition(pstate, param->location)));
293 if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
295 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
296 errmsg("could not determine data type of parameter $%d",
298 parser_errposition(pstate, param->location)));
302 if (IsA(node, Query))
304 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
305 return query_tree_walker((Query *) node,
306 check_parameter_resolution_walker,
309 return expression_tree_walker(node, check_parameter_resolution_walker,