00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "postgres.h"
00026
00027 #include <limits.h>
00028
00029 #include "catalog/pg_type.h"
00030 #include "nodes/nodeFuncs.h"
00031 #include "parser/parse_param.h"
00032 #include "utils/builtins.h"
00033 #include "utils/lsyscache.h"
00034
00035
00036 typedef struct FixedParamState
00037 {
00038 Oid *paramTypes;
00039 int numParams;
00040 } FixedParamState;
00041
00042
00043
00044
00045
00046
00047
00048 typedef struct VarParamState
00049 {
00050 Oid **paramTypes;
00051 int *numParams;
00052 } VarParamState;
00053
00054 static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref);
00055 static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref);
00056 static Node *variable_coerce_param_hook(ParseState *pstate, Param *param,
00057 Oid targetTypeId, int32 targetTypeMod,
00058 int location);
00059 static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
00060 static bool query_contains_extern_params_walker(Node *node, void *context);
00061
00062
00063
00064
00065
00066 void
00067 parse_fixed_parameters(ParseState *pstate,
00068 Oid *paramTypes, int numParams)
00069 {
00070 FixedParamState *parstate = palloc(sizeof(FixedParamState));
00071
00072 parstate->paramTypes = paramTypes;
00073 parstate->numParams = numParams;
00074 pstate->p_ref_hook_state = (void *) parstate;
00075 pstate->p_paramref_hook = fixed_paramref_hook;
00076
00077 }
00078
00079
00080
00081
00082 void
00083 parse_variable_parameters(ParseState *pstate,
00084 Oid **paramTypes, int *numParams)
00085 {
00086 VarParamState *parstate = palloc(sizeof(VarParamState));
00087
00088 parstate->paramTypes = paramTypes;
00089 parstate->numParams = numParams;
00090 pstate->p_ref_hook_state = (void *) parstate;
00091 pstate->p_paramref_hook = variable_paramref_hook;
00092 pstate->p_coerce_param_hook = variable_coerce_param_hook;
00093 }
00094
00095
00096
00097
00098 static Node *
00099 fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
00100 {
00101 FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
00102 int paramno = pref->number;
00103 Param *param;
00104
00105
00106 if (paramno <= 0 || paramno > parstate->numParams ||
00107 !OidIsValid(parstate->paramTypes[paramno - 1]))
00108 ereport(ERROR,
00109 (errcode(ERRCODE_UNDEFINED_PARAMETER),
00110 errmsg("there is no parameter $%d", paramno),
00111 parser_errposition(pstate, pref->location)));
00112
00113 param = makeNode(Param);
00114 param->paramkind = PARAM_EXTERN;
00115 param->paramid = paramno;
00116 param->paramtype = parstate->paramTypes[paramno - 1];
00117 param->paramtypmod = -1;
00118 param->paramcollid = get_typcollation(param->paramtype);
00119 param->location = pref->location;
00120
00121 return (Node *) param;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 static Node *
00131 variable_paramref_hook(ParseState *pstate, ParamRef *pref)
00132 {
00133 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
00134 int paramno = pref->number;
00135 Oid *pptype;
00136 Param *param;
00137
00138
00139 if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
00140 ereport(ERROR,
00141 (errcode(ERRCODE_UNDEFINED_PARAMETER),
00142 errmsg("there is no parameter $%d", paramno),
00143 parser_errposition(pstate, pref->location)));
00144 if (paramno > *parstate->numParams)
00145 {
00146
00147 if (*parstate->paramTypes)
00148 *parstate->paramTypes = (Oid *) repalloc(*parstate->paramTypes,
00149 paramno * sizeof(Oid));
00150 else
00151 *parstate->paramTypes = (Oid *) palloc(paramno * sizeof(Oid));
00152
00153 MemSet(*parstate->paramTypes + *parstate->numParams,
00154 0,
00155 (paramno - *parstate->numParams) * sizeof(Oid));
00156 *parstate->numParams = paramno;
00157 }
00158
00159
00160 pptype = &(*parstate->paramTypes)[paramno - 1];
00161
00162
00163 if (*pptype == InvalidOid)
00164 *pptype = UNKNOWNOID;
00165
00166 param = makeNode(Param);
00167 param->paramkind = PARAM_EXTERN;
00168 param->paramid = paramno;
00169 param->paramtype = *pptype;
00170 param->paramtypmod = -1;
00171 param->paramcollid = get_typcollation(param->paramtype);
00172 param->location = pref->location;
00173
00174 return (Node *) param;
00175 }
00176
00177
00178
00179
00180 static Node *
00181 variable_coerce_param_hook(ParseState *pstate, Param *param,
00182 Oid targetTypeId, int32 targetTypeMod,
00183 int location)
00184 {
00185 if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
00186 {
00187
00188
00189
00190
00191 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
00192 Oid *paramTypes = *parstate->paramTypes;
00193 int paramno = param->paramid;
00194
00195 if (paramno <= 0 ||
00196 paramno > *parstate->numParams)
00197 ereport(ERROR,
00198 (errcode(ERRCODE_UNDEFINED_PARAMETER),
00199 errmsg("there is no parameter $%d", paramno),
00200 parser_errposition(pstate, param->location)));
00201
00202 if (paramTypes[paramno - 1] == UNKNOWNOID)
00203 {
00204
00205 paramTypes[paramno - 1] = targetTypeId;
00206 }
00207 else if (paramTypes[paramno - 1] == targetTypeId)
00208 {
00209
00210 }
00211 else
00212 {
00213
00214 ereport(ERROR,
00215 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
00216 errmsg("inconsistent types deduced for parameter $%d",
00217 paramno),
00218 errdetail("%s versus %s",
00219 format_type_be(paramTypes[paramno - 1]),
00220 format_type_be(targetTypeId)),
00221 parser_errposition(pstate, param->location)));
00222 }
00223
00224 param->paramtype = targetTypeId;
00225
00226
00227
00228
00229
00230
00231
00232
00233 param->paramtypmod = -1;
00234
00235
00236
00237
00238
00239
00240 param->paramcollid = get_typcollation(param->paramtype);
00241
00242
00243 if (location >= 0 &&
00244 (param->location < 0 || location < param->location))
00245 param->location = location;
00246
00247 return (Node *) param;
00248 }
00249
00250
00251 return NULL;
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 void
00263 check_variable_parameters(ParseState *pstate, Query *query)
00264 {
00265 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
00266
00267
00268 if (*parstate->numParams > 0)
00269 (void) query_tree_walker(query,
00270 check_parameter_resolution_walker,
00271 (void *) pstate, 0);
00272 }
00273
00274
00275
00276
00277
00278
00279
00280 static bool
00281 check_parameter_resolution_walker(Node *node, ParseState *pstate)
00282 {
00283 if (node == NULL)
00284 return false;
00285 if (IsA(node, Param))
00286 {
00287 Param *param = (Param *) node;
00288
00289 if (param->paramkind == PARAM_EXTERN)
00290 {
00291 VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
00292 int paramno = param->paramid;
00293
00294 if (paramno <= 0 ||
00295 paramno > *parstate->numParams)
00296 ereport(ERROR,
00297 (errcode(ERRCODE_UNDEFINED_PARAMETER),
00298 errmsg("there is no parameter $%d", paramno),
00299 parser_errposition(pstate, param->location)));
00300
00301 if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
00302 ereport(ERROR,
00303 (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
00304 errmsg("could not determine data type of parameter $%d",
00305 paramno),
00306 parser_errposition(pstate, param->location)));
00307 }
00308 return false;
00309 }
00310 if (IsA(node, Query))
00311 {
00312
00313 return query_tree_walker((Query *) node,
00314 check_parameter_resolution_walker,
00315 (void *) pstate, 0);
00316 }
00317 return expression_tree_walker(node, check_parameter_resolution_walker,
00318 (void *) pstate);
00319 }
00320
00321
00322
00323
00324 bool
00325 query_contains_extern_params(Query *query)
00326 {
00327 return query_tree_walker(query,
00328 query_contains_extern_params_walker,
00329 NULL, 0);
00330 }
00331
00332 static bool
00333 query_contains_extern_params_walker(Node *node, void *context)
00334 {
00335 if (node == NULL)
00336 return false;
00337 if (IsA(node, Param))
00338 {
00339 Param *param = (Param *) node;
00340
00341 if (param->paramkind == PARAM_EXTERN)
00342 return true;
00343 return false;
00344 }
00345 if (IsA(node, Query))
00346 {
00347
00348 return query_tree_walker((Query *) node,
00349 query_contains_extern_params_walker,
00350 context, 0);
00351 }
00352 return expression_tree_walker(node, query_contains_extern_params_walker,
00353 context);
00354 }