Avoid updating inactive_since for invalid replication slots.
[pgsql.git] / src / backend / parser / parse_param.c
blob930921626b6d5ab7911a5732d755433c8e9d109e
1 /*-------------------------------------------------------------------------
3 * parse_param.c
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-2025, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
19 * IDENTIFICATION
20 * src/backend/parser/parse_param.c
22 *-------------------------------------------------------------------------
25 #include "postgres.h"
27 #include <limits.h>
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"
34 #include "utils/memutils.h"
37 typedef struct FixedParamState
39 const Oid *paramTypes; /* array of parameter type OIDs */
40 int numParams; /* number of array entries */
41 } FixedParamState;
44 * In the varparams case, the caller-supplied OID array (if any) can be
45 * re-palloc'd larger at need. A zero array entry means that parameter number
46 * hasn't been seen, while UNKNOWNOID means the parameter has been used but
47 * its type is not yet known.
49 typedef struct VarParamState
51 Oid **paramTypes; /* array of parameter type OIDs */
52 int *numParams; /* number of array entries */
53 } VarParamState;
55 static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref);
56 static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
57 static Node *variable_coerce_param_hook(ParseState *pstate, Param *param,
58 Oid targetTypeId, int32 targetTypeMod,
59 int location);
60 static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
61 static bool query_contains_extern_params_walker(Node *node, void *context);
65 * Set up to process a query containing references to fixed parameters.
67 void
68 setup_parse_fixed_parameters(ParseState *pstate,
69 const Oid *paramTypes, int numParams)
71 FixedParamState *parstate = palloc(sizeof(FixedParamState));
73 parstate->paramTypes = paramTypes;
74 parstate->numParams = numParams;
75 pstate->p_ref_hook_state = parstate;
76 pstate->p_paramref_hook = fixed_paramref_hook;
77 /* no need to use p_coerce_param_hook */
81 * Set up to process a query containing references to variable parameters.
83 void
84 setup_parse_variable_parameters(ParseState *pstate,
85 Oid **paramTypes, int *numParams)
87 VarParamState *parstate = palloc(sizeof(VarParamState));
89 parstate->paramTypes = paramTypes;
90 parstate->numParams = numParams;
91 pstate->p_ref_hook_state = parstate;
92 pstate->p_paramref_hook = variable_paramref_hook;
93 pstate->p_coerce_param_hook = variable_coerce_param_hook;
97 * Transform a ParamRef using fixed parameter types.
99 static Node *
100 fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
102 FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
103 int paramno = pref->number;
104 Param *param;
106 /* Check parameter number is valid */
107 if (paramno <= 0 || paramno > parstate->numParams ||
108 !OidIsValid(parstate->paramTypes[paramno - 1]))
109 ereport(ERROR,
110 (errcode(ERRCODE_UNDEFINED_PARAMETER),
111 errmsg("there is no parameter $%d", paramno),
112 parser_errposition(pstate, pref->location)));
114 param = makeNode(Param);
115 param->paramkind = PARAM_EXTERN;
116 param->paramid = paramno;
117 param->paramtype = parstate->paramTypes[paramno - 1];
118 param->paramtypmod = -1;
119 param->paramcollid = get_typcollation(param->paramtype);
120 param->location = pref->location;
122 return (Node *) param;
126 * Transform a ParamRef using variable parameter types.
128 * The only difference here is we must enlarge the parameter type array
129 * as needed.
131 static Node *
132 variable_paramref_hook(ParseState *pstate, ParamRef *pref)
134 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
135 int paramno = pref->number;
136 Oid *pptype;
137 Param *param;
139 /* Check parameter number is in range */
140 if (paramno <= 0 || paramno > MaxAllocSize / sizeof(Oid))
141 ereport(ERROR,
142 (errcode(ERRCODE_UNDEFINED_PARAMETER),
143 errmsg("there is no parameter $%d", paramno),
144 parser_errposition(pstate, pref->location)));
145 if (paramno > *parstate->numParams)
147 /* Need to enlarge param array */
148 if (*parstate->paramTypes)
149 *parstate->paramTypes = repalloc0_array(*parstate->paramTypes, Oid,
150 *parstate->numParams, paramno);
151 else
152 *parstate->paramTypes = palloc0_array(Oid, paramno);
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;
164 * If the argument is of type void and it's procedure call, interpret it
165 * as unknown. This allows the JDBC driver to not have to distinguish
166 * function and procedure calls. See also another component of this hack
167 * in ParseFuncOrColumn().
169 if (*pptype == VOIDOID && pstate->p_expr_kind == EXPR_KIND_CALL_ARGUMENT)
170 *pptype = UNKNOWNOID;
172 param = makeNode(Param);
173 param->paramkind = PARAM_EXTERN;
174 param->paramid = paramno;
175 param->paramtype = *pptype;
176 param->paramtypmod = -1;
177 param->paramcollid = get_typcollation(param->paramtype);
178 param->location = pref->location;
180 return (Node *) param;
184 * Coerce a Param to a query-requested datatype, in the varparams case.
186 static Node *
187 variable_coerce_param_hook(ParseState *pstate, Param *param,
188 Oid targetTypeId, int32 targetTypeMod,
189 int location)
191 if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
194 * Input is a Param of previously undetermined type, and we want to
195 * update our knowledge of the Param's type.
197 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
198 Oid *paramTypes = *parstate->paramTypes;
199 int paramno = param->paramid;
201 if (paramno <= 0 || /* shouldn't happen, but... */
202 paramno > *parstate->numParams)
203 ereport(ERROR,
204 (errcode(ERRCODE_UNDEFINED_PARAMETER),
205 errmsg("there is no parameter $%d", paramno),
206 parser_errposition(pstate, param->location)));
208 if (paramTypes[paramno - 1] == UNKNOWNOID)
210 /* We've successfully resolved the type */
211 paramTypes[paramno - 1] = targetTypeId;
213 else if (paramTypes[paramno - 1] == targetTypeId)
215 /* We previously resolved the type, and it matches */
217 else
219 /* Oops */
220 ereport(ERROR,
221 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
222 errmsg("inconsistent types deduced for parameter $%d",
223 paramno),
224 errdetail("%s versus %s",
225 format_type_be(paramTypes[paramno - 1]),
226 format_type_be(targetTypeId)),
227 parser_errposition(pstate, param->location)));
230 param->paramtype = targetTypeId;
233 * Note: it is tempting here to set the Param's paramtypmod to
234 * targetTypeMod, but that is probably unwise because we have no
235 * infrastructure that enforces that the value delivered for a Param
236 * will match any particular typmod. Leaving it -1 ensures that a
237 * run-time length check/coercion will occur if needed.
239 param->paramtypmod = -1;
242 * This module always sets a Param's collation to be the default for
243 * its datatype. If that's not what you want, you should be using the
244 * more general parser substitution hooks.
246 param->paramcollid = get_typcollation(param->paramtype);
248 /* Use the leftmost of the param's and coercion's locations */
249 if (location >= 0 &&
250 (param->location < 0 || location < param->location))
251 param->location = location;
253 return (Node *) param;
256 /* Else signal to proceed with normal coercion */
257 return NULL;
261 * Check for consistent assignment of variable parameters after completion
262 * of parsing with parse_variable_parameters.
264 * Note: this code intentionally does not check that all parameter positions
265 * were used, nor that all got non-UNKNOWN types assigned. Caller of parser
266 * should enforce that if it's important.
268 void
269 check_variable_parameters(ParseState *pstate, Query *query)
271 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
273 /* If numParams is zero then no Params were generated, so no work */
274 if (*parstate->numParams > 0)
275 (void) query_tree_walker(query,
276 check_parameter_resolution_walker,
277 pstate, 0);
281 * Traverse a fully-analyzed tree to verify that parameter symbols
282 * match their types. We need this because some Params might still
283 * be UNKNOWN, if there wasn't anything to force their coercion,
284 * and yet other instances seen later might have gotten coerced.
286 static bool
287 check_parameter_resolution_walker(Node *node, ParseState *pstate)
289 if (node == NULL)
290 return false;
291 if (IsA(node, Param))
293 Param *param = (Param *) node;
295 if (param->paramkind == PARAM_EXTERN)
297 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
298 int paramno = param->paramid;
300 if (paramno <= 0 || /* shouldn't happen, but... */
301 paramno > *parstate->numParams)
302 ereport(ERROR,
303 (errcode(ERRCODE_UNDEFINED_PARAMETER),
304 errmsg("there is no parameter $%d", paramno),
305 parser_errposition(pstate, param->location)));
307 if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
308 ereport(ERROR,
309 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
310 errmsg("could not determine data type of parameter $%d",
311 paramno),
312 parser_errposition(pstate, param->location)));
314 return false;
316 if (IsA(node, Query))
318 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
319 return query_tree_walker((Query *) node,
320 check_parameter_resolution_walker,
321 pstate, 0);
323 return expression_tree_walker(node, check_parameter_resolution_walker,
324 pstate);
328 * Check to see if a fully-parsed query tree contains any PARAM_EXTERN Params.
330 bool
331 query_contains_extern_params(Query *query)
333 return query_tree_walker(query,
334 query_contains_extern_params_walker,
335 NULL, 0);
338 static bool
339 query_contains_extern_params_walker(Node *node, void *context)
341 if (node == NULL)
342 return false;
343 if (IsA(node, Param))
345 Param *param = (Param *) node;
347 if (param->paramkind == PARAM_EXTERN)
348 return true;
349 return false;
351 if (IsA(node, Query))
353 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
354 return query_tree_walker((Query *) node,
355 query_contains_extern_params_walker,
356 context, 0);
358 return expression_tree_walker(node, query_contains_extern_params_walker,
359 context);