LCOV - differential code coverage report
Current view: top level - src/backend/parser - parse_param.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 87.9 % 107 94 2 8 3 4 31 2 57 6 32 3
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 9 9 5 1 3 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (240..) days: 87.6 % 105 92 2 8 3 4 31 57 6 32
Function coverage date bins:
(240..) days: 64.3 % 14 9 5 1 3 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * parse_param.c
                                  4                 :  *    handle parameters in parser
                                  5                 :  *
                                  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.
                                 11                 :  *
                                 12                 :  * Note that other approaches to parameters are possible using the parser
                                 13                 :  * hooks defined in ParseState.
                                 14                 :  *
                                 15                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 16                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 17                 :  *
                                 18                 :  *
                                 19                 :  * IDENTIFICATION
                                 20                 :  *    src/backend/parser/parse_param.c
                                 21                 :  *
                                 22                 :  *-------------------------------------------------------------------------
                                 23                 :  */
                                 24                 : 
                                 25                 : #include "postgres.h"
                                 26                 : 
                                 27                 : #include <limits.h>
                                 28                 : 
                                 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                 : 
                                 35                 : 
                                 36                 : typedef struct FixedParamState
                                 37                 : {
                                 38                 :     const Oid  *paramTypes;     /* array of parameter type OIDs */
                                 39                 :     int         numParams;      /* number of array entries */
                                 40                 : } FixedParamState;
                                 41                 : 
                                 42                 : /*
                                 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.
                                 47                 :  */
                                 48                 : typedef struct VarParamState
                                 49                 : {
                                 50                 :     Oid       **paramTypes;     /* array of parameter type OIDs */
                                 51                 :     int        *numParams;      /* number of array entries */
                                 52                 : } VarParamState;
                                 53                 : 
                                 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,
                                 58                 :                                         int location);
                                 59                 : static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
                                 60                 : static bool query_contains_extern_params_walker(Node *node, void *context);
                                 61                 : 
                                 62                 : 
                                 63                 : /*
                                 64                 :  * Set up to process a query containing references to fixed parameters.
                                 65                 :  */
                                 66                 : void
  401 peter                      67 CBC        1781 : setup_parse_fixed_parameters(ParseState *pstate,
                                 68                 :                              const Oid *paramTypes, int numParams)
                                 69                 : {
 4908 tgl                        70            1781 :     FixedParamState *parstate = palloc(sizeof(FixedParamState));
                                 71                 : 
                                 72            1781 :     parstate->paramTypes = paramTypes;
                                 73            1781 :     parstate->numParams = numParams;
                                 74            1781 :     pstate->p_ref_hook_state = (void *) parstate;
                                 75            1781 :     pstate->p_paramref_hook = fixed_paramref_hook;
                                 76                 :     /* no need to use p_coerce_param_hook */
                                 77            1781 : }
                                 78                 : 
                                 79                 : /*
                                 80                 :  * Set up to process a query containing references to variable parameters.
                                 81                 :  */
                                 82                 : void
  401 peter                      83            4506 : setup_parse_variable_parameters(ParseState *pstate,
                                 84                 :                                 Oid **paramTypes, int *numParams)
                                 85                 : {
 4908 tgl                        86            4506 :     VarParamState *parstate = palloc(sizeof(VarParamState));
                                 87                 : 
                                 88            4506 :     parstate->paramTypes = paramTypes;
                                 89            4506 :     parstate->numParams = numParams;
                                 90            4506 :     pstate->p_ref_hook_state = (void *) parstate;
                                 91            4506 :     pstate->p_paramref_hook = variable_paramref_hook;
                                 92            4506 :     pstate->p_coerce_param_hook = variable_coerce_param_hook;
                                 93            4506 : }
                                 94                 : 
                                 95                 : /*
                                 96                 :  * Transform a ParamRef using fixed parameter types.
                                 97                 :  */
                                 98                 : static Node *
                                 99            2340 : fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
                                100                 : {
                                101            2340 :     FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
                                102            2340 :     int         paramno = pref->number;
                                103                 :     Param      *param;
                                104                 : 
                                105                 :     /* Check parameter number is valid */
 4834                           106            2340 :     if (paramno <= 0 || paramno > parstate->numParams ||
                                107            2340 :         !OidIsValid(parstate->paramTypes[paramno - 1]))
 4908 tgl                       108 UBC           0 :         ereport(ERROR,
                                109                 :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                110                 :                  errmsg("there is no parameter $%d", paramno),
                                111                 :                  parser_errposition(pstate, pref->location)));
                                112                 : 
 4908 tgl                       113 CBC        2340 :     param = makeNode(Param);
                                114            2340 :     param->paramkind = PARAM_EXTERN;
                                115            2340 :     param->paramid = paramno;
                                116            2340 :     param->paramtype = parstate->paramTypes[paramno - 1];
                                117            2340 :     param->paramtypmod = -1;
 4404                           118            2340 :     param->paramcollid = get_typcollation(param->paramtype);
 4908                           119            2340 :     param->location = pref->location;
                                120                 : 
                                121            2340 :     return (Node *) param;
                                122                 : }
                                123                 : 
                                124                 : /*
                                125                 :  * Transform a ParamRef using variable parameter types.
                                126                 :  *
                                127                 :  * The only difference here is we must enlarge the parameter type array
                                128                 :  * as needed.
                                129                 :  */
                                130                 : static Node *
                                131           75019 : variable_paramref_hook(ParseState *pstate, ParamRef *pref)
                                132                 : {
                                133           75019 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                134           75019 :     int         paramno = pref->number;
                                135                 :     Oid        *pptype;
                                136                 :     Param      *param;
                                137                 : 
                                138                 :     /* Check parameter number is in range */
                                139           75019 :     if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
 4908 tgl                       140 UBC           0 :         ereport(ERROR,
                                141                 :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                142                 :                  errmsg("there is no parameter $%d", paramno),
                                143                 :                  parser_errposition(pstate, pref->location)));
 4908 tgl                       144 CBC       75019 :     if (paramno > *parstate->numParams)
                                145                 :     {
                                146                 :         /* Need to enlarge param array */
                                147           74149 :         if (*parstate->paramTypes)
  148 peter                     148 GNC       71366 :             *parstate->paramTypes = repalloc0_array(*parstate->paramTypes, Oid,
                                149                 :                                                     *parstate->numParams, paramno);
                                150                 :         else
                                151            2783 :             *parstate->paramTypes = palloc0_array(Oid, paramno);
 4908 tgl                       152 CBC       74149 :         *parstate->numParams = paramno;
                                153                 :     }
                                154                 : 
 4908 tgl                       155 ECB             :     /* Locate param's slot in array */
 4908 tgl                       156 CBC       75019 :     pptype = &(*parstate->paramTypes)[paramno - 1];
                                157                 : 
                                158                 :     /* If not seen before, initialize to UNKNOWN type */
 4908 tgl                       159 GIC       75019 :     if (*pptype == InvalidOid)
                                160           74249 :         *pptype = UNKNOWNOID;
                                161                 : 
                                162                 :     /*
                                163                 :      * If the argument is of type void and it's procedure call, interpret it
  894 peter                     164 ECB             :      * as unknown.  This allows the JDBC driver to not have to distinguish
  894 peter                     165 EUB             :      * function and procedure calls.  See also another component of this hack
                                166                 :      * in ParseFuncOrColumn().
  894 peter                     167 ECB             :      */
  894 peter                     168 CBC       75019 :     if (*pptype == VOIDOID && pstate->p_expr_kind == EXPR_KIND_CALL_ARGUMENT)
  894 peter                     169 LBC           0 :         *pptype = UNKNOWNOID;
  894 peter                     170 ECB             : 
 4908 tgl                       171 CBC       75019 :     param = makeNode(Param);
                                172           75019 :     param->paramkind = PARAM_EXTERN;
                                173           75019 :     param->paramid = paramno;
 4908 tgl                       174 GIC       75019 :     param->paramtype = *pptype;
 4908 tgl                       175 CBC       75019 :     param->paramtypmod = -1;
 4404 tgl                       176 GIC       75019 :     param->paramcollid = get_typcollation(param->paramtype);
 4908                           177           75019 :     param->location = pref->location;
                                178                 : 
                                179           75019 :     return (Node *) param;
                                180                 : }
                                181                 : 
 4908 tgl                       182 ECB             : /*
                                183                 :  * Coerce a Param to a query-requested datatype, in the varparams case.
                                184                 :  */
                                185                 : static Node *
 4908 tgl                       186 CBC       74262 : variable_coerce_param_hook(ParseState *pstate, Param *param,
                                187                 :                            Oid targetTypeId, int32 targetTypeMod,
                                188                 :                            int location)
                                189                 : {
 4908 tgl                       190 GIC       74262 :     if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
                                191                 :     {
 4908 tgl                       192 ECB             :         /*
                                193                 :          * Input is a Param of previously undetermined type, and we want to
                                194                 :          * update our knowledge of the Param's type.
                                195                 :          */
 4908 tgl                       196 CBC       74252 :         VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                197           74252 :         Oid        *paramTypes = *parstate->paramTypes;
 4908 tgl                       198 GBC       74252 :         int         paramno = param->paramid;
                                199                 : 
 4908 tgl                       200 GIC       74252 :         if (paramno <= 0 ||      /* shouldn't happen, but... */
                                201           74252 :             paramno > *parstate->numParams)
 4908 tgl                       202 UIC           0 :             ereport(ERROR,
 4908 tgl                       203 ECB             :                     (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                204                 :                      errmsg("there is no parameter $%d", paramno),
                                205                 :                      parser_errposition(pstate, param->location)));
                                206                 : 
 4908 tgl                       207 GIC       74252 :         if (paramTypes[paramno - 1] == UNKNOWNOID)
 4908 tgl                       208 EUB             :         {
                                209                 :             /* We've successfully resolved the type */
 4908 tgl                       210 GIC       74252 :             paramTypes[paramno - 1] = targetTypeId;
                                211                 :         }
 4908 tgl                       212 UIC           0 :         else if (paramTypes[paramno - 1] == targetTypeId)
                                213                 :         {
                                214                 :             /* We previously resolved the type, and it matches */
 4908 tgl                       215 EUB             :         }
                                216                 :         else
                                217                 :         {
                                218                 :             /* Oops */
 4908 tgl                       219 UIC           0 :             ereport(ERROR,
                                220                 :                     (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
                                221                 :                      errmsg("inconsistent types deduced for parameter $%d",
                                222                 :                             paramno),
                                223                 :                      errdetail("%s versus %s",
                                224                 :                                format_type_be(paramTypes[paramno - 1]),
 4908 tgl                       225 ECB             :                                format_type_be(targetTypeId)),
                                226                 :                      parser_errposition(pstate, param->location)));
                                227                 :         }
                                228                 : 
 4908 tgl                       229 GIC       74252 :         param->paramtype = targetTypeId;
                                230                 : 
                                231                 :         /*
                                232                 :          * Note: it is tempting here to set the Param's paramtypmod to
                                233                 :          * targetTypeMod, but that is probably unwise because we have no
 4908 tgl                       234 ECB             :          * infrastructure that enforces that the value delivered for a Param
                                235                 :          * will match any particular typmod.  Leaving it -1 ensures that a
                                236                 :          * run-time length check/coercion will occur if needed.
                                237                 :          */
 4908 tgl                       238 GIC       74252 :         param->paramtypmod = -1;
                                239                 : 
                                240                 :         /*
 4399 tgl                       241 ECB             :          * This module always sets a Param's collation to be the default for
                                242                 :          * its datatype.  If that's not what you want, you should be using the
                                243                 :          * more general parser substitution hooks.
                                244                 :          */
 4404 tgl                       245 CBC       74252 :         param->paramcollid = get_typcollation(param->paramtype);
 4404 tgl                       246 EUB             : 
                                247                 :         /* Use the leftmost of the param's and coercion's locations */
 4908 tgl                       248 CBC       74252 :         if (location >= 0 &&
 4908 tgl                       249 GIC         576 :             (param->location < 0 || location < param->location))
 4908 tgl                       250 UIC           0 :             param->location = location;
                                251                 : 
 4908 tgl                       252 CBC       74252 :         return (Node *) param;
                                253                 :     }
                                254                 : 
                                255                 :     /* Else signal to proceed with normal coercion */
 4908 tgl                       256 GIC          10 :     return NULL;
                                257                 : }
                                258                 : 
                                259                 : /*
                                260                 :  * Check for consistent assignment of variable parameters after completion
                                261                 :  * of parsing with parse_variable_parameters.
                                262                 :  *
                                263                 :  * Note: this code intentionally does not check that all parameter positions
 3260 bruce                     264 ECB             :  * were used, nor that all got non-UNKNOWN types assigned.  Caller of parser
                                265                 :  * should enforce that if it's important.
 4908 tgl                       266                 :  */
                                267                 : void
 4908 tgl                       268 GIC        4499 : check_variable_parameters(ParseState *pstate, Query *query)
 4908 tgl                       269 ECB             : {
 4908 tgl                       270 CBC        4499 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                271                 : 
                                272                 :     /* If numParams is zero then no Params were generated, so no work */
                                273            4499 :     if (*parstate->numParams > 0)
 4908 tgl                       274 GIC        3474 :         (void) query_tree_walker(query,
                                275                 :                                  check_parameter_resolution_walker,
                                276                 :                                  (void *) pstate, 0);
                                277            4499 : }
                                278                 : 
                                279                 : /*
                                280                 :  * Traverse a fully-analyzed tree to verify that parameter symbols
                                281                 :  * match their types.  We need this because some Params might still
 4908 tgl                       282 ECB             :  * be UNKNOWN, if there wasn't anything to force their coercion,
                                283                 :  * and yet other instances seen later might have gotten coerced.
                                284                 :  */
                                285                 : static bool
 4908 tgl                       286 CBC      239420 : check_parameter_resolution_walker(Node *node, ParseState *pstate)
                                287                 : {
                                288          239420 :     if (node == NULL)
 4908 tgl                       289 GIC       41556 :         return false;
 4908 tgl                       290 CBC      197864 :     if (IsA(node, Param))
                                291                 :     {
                                292           74464 :         Param      *param = (Param *) node;
 4908 tgl                       293 ECB             : 
 4908 tgl                       294 GIC       74464 :         if (param->paramkind == PARAM_EXTERN)
 4908 tgl                       295 ECB             :         {
 4908 tgl                       296 CBC       74462 :             VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
 4908 tgl                       297 GBC       74462 :             int         paramno = param->paramid;
                                298                 : 
 4908 tgl                       299 GIC       74462 :             if (paramno <= 0 || /* shouldn't happen, but... */
                                300           74462 :                 paramno > *parstate->numParams)
 4908 tgl                       301 UIC           0 :                 ereport(ERROR,
 4908 tgl                       302 ECB             :                         (errcode(ERRCODE_UNDEFINED_PARAMETER),
 4908 tgl                       303 EUB             :                          errmsg("there is no parameter $%d", paramno),
                                304                 :                          parser_errposition(pstate, param->location)));
                                305                 : 
 4908 tgl                       306 GIC       74462 :             if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
 4908 tgl                       307 UIC           0 :                 ereport(ERROR,
                                308                 :                         (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
 2118 tgl                       309 ECB             :                          errmsg("could not determine data type of parameter $%d",
                                310                 :                                 paramno),
 4908                           311                 :                          parser_errposition(pstate, param->location)));
                                312                 :         }
 4908 tgl                       313 GIC       74464 :         return false;
 4908 tgl                       314 ECB             :     }
 4908 tgl                       315 GIC      123400 :     if (IsA(node, Query))
                                316                 :     {
                                317                 :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
 4908 tgl                       318 CBC          97 :         return query_tree_walker((Query *) node,
                                319                 :                                  check_parameter_resolution_walker,
                                320                 :                                  (void *) pstate, 0);
                                321                 :     }
 4908 tgl                       322 GIC      123303 :     return expression_tree_walker(node, check_parameter_resolution_walker,
                                323                 :                                   (void *) pstate);
                                324                 : }
                                325                 : 
 3649 tgl                       326 ECB             : /*
                                327                 :  * Check to see if a fully-parsed query tree contains any PARAM_EXTERN Params.
                                328                 :  */
                                329                 : bool
 3649 tgl                       330 GIC         265 : query_contains_extern_params(Query *query)
                                331                 : {
                                332             265 :     return query_tree_walker(query,
                                333                 :                              query_contains_extern_params_walker,
 3649 tgl                       334 ECB             :                              NULL, 0);
                                335                 : }
                                336                 : 
                                337                 : static bool
 3649 tgl                       338 CBC        5283 : query_contains_extern_params_walker(Node *node, void *context)
                                339                 : {
 3649 tgl                       340 GBC        5283 :     if (node == NULL)
 3649 tgl                       341 GIC        3131 :         return false;
 3649 tgl                       342 GBC        2152 :     if (IsA(node, Param))
 3649 tgl                       343 EUB             :     {
 3649 tgl                       344 UBC           0 :         Param      *param = (Param *) node;
                                345                 : 
 3649 tgl                       346 LBC           0 :         if (param->paramkind == PARAM_EXTERN)
 3649 tgl                       347 UIC           0 :             return true;
                                348               0 :         return false;
 3649 tgl                       349 ECB             :     }
 3649 tgl                       350 GIC        2152 :     if (IsA(node, Query))
                                351                 :     {
                                352                 :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
 3649 tgl                       353 CBC           9 :         return query_tree_walker((Query *) node,
                                354                 :                                  query_contains_extern_params_walker,
                                355                 :                                  context, 0);
                                356                 :     }
 3649 tgl                       357 GIC        2143 :     return expression_tree_walker(node, query_contains_extern_params_walker,
                                358                 :                                   context);
                                359                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a