LCOV - differential code coverage report
Current view: top level - src/backend/parser - parse_param.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 87.9 % 107 94 13 94
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 9 9 9
Baseline: 16@8cea358b128 Branches: 54.1 % 74 40 34 40
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 87.9 % 107 94 13 94
Function coverage date bins:
(240..) days: 100.0 % 9 9 9
Branch coverage date bins:
(240..) days: 54.1 % 74 40 34 40

 Age         Owner                    Branch data    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-2024, 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
  772 peter@eisentraut.org       67                 :CBC        2030 : setup_parse_fixed_parameters(ParseState *pstate,
                                 68                 :                :                              const Oid *paramTypes, int numParams)
                                 69                 :                : {
 5279 tgl@sss.pgh.pa.us          70                 :           2030 :     FixedParamState *parstate = palloc(sizeof(FixedParamState));
                                 71                 :                : 
                                 72                 :           2030 :     parstate->paramTypes = paramTypes;
                                 73                 :           2030 :     parstate->numParams = numParams;
                                 74                 :           2030 :     pstate->p_ref_hook_state = (void *) parstate;
                                 75                 :           2030 :     pstate->p_paramref_hook = fixed_paramref_hook;
                                 76                 :                :     /* no need to use p_coerce_param_hook */
                                 77                 :           2030 : }
                                 78                 :                : 
                                 79                 :                : /*
                                 80                 :                :  * Set up to process a query containing references to variable parameters.
                                 81                 :                :  */
                                 82                 :                : void
  772 peter@eisentraut.org       83                 :           4591 : setup_parse_variable_parameters(ParseState *pstate,
                                 84                 :                :                                 Oid **paramTypes, int *numParams)
                                 85                 :                : {
 5279 tgl@sss.pgh.pa.us          86                 :           4591 :     VarParamState *parstate = palloc(sizeof(VarParamState));
                                 87                 :                : 
                                 88                 :           4591 :     parstate->paramTypes = paramTypes;
                                 89                 :           4591 :     parstate->numParams = numParams;
                                 90                 :           4591 :     pstate->p_ref_hook_state = (void *) parstate;
                                 91                 :           4591 :     pstate->p_paramref_hook = variable_paramref_hook;
                                 92                 :           4591 :     pstate->p_coerce_param_hook = variable_coerce_param_hook;
                                 93                 :           4591 : }
                                 94                 :                : 
                                 95                 :                : /*
                                 96                 :                :  * Transform a ParamRef using fixed parameter types.
                                 97                 :                :  */
                                 98                 :                : static Node *
                                 99                 :           2925 : fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
                                100                 :                : {
                                101                 :           2925 :     FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
                                102                 :           2925 :     int         paramno = pref->number;
                                103                 :                :     Param      *param;
                                104                 :                : 
                                105                 :                :     /* Check parameter number is valid */
 5205                           106   [ +  -  +  - ]:           2925 :     if (paramno <= 0 || paramno > parstate->numParams ||
                                107         [ -  + ]:           2925 :         !OidIsValid(parstate->paramTypes[paramno - 1]))
 5279 tgl@sss.pgh.pa.us         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                 :                : 
 5279 tgl@sss.pgh.pa.us         113                 :CBC        2925 :     param = makeNode(Param);
                                114                 :           2925 :     param->paramkind = PARAM_EXTERN;
                                115                 :           2925 :     param->paramid = paramno;
                                116                 :           2925 :     param->paramtype = parstate->paramTypes[paramno - 1];
                                117                 :           2925 :     param->paramtypmod = -1;
 4775                           118                 :           2925 :     param->paramcollid = get_typcollation(param->paramtype);
 5279                           119                 :           2925 :     param->location = pref->location;
                                120                 :                : 
                                121                 :           2925 :     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                 :           5126 : variable_paramref_hook(ParseState *pstate, ParamRef *pref)
                                132                 :                : {
                                133                 :           5126 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                134                 :           5126 :     int         paramno = pref->number;
                                135                 :                :     Oid        *pptype;
                                136                 :                :     Param      *param;
                                137                 :                : 
                                138                 :                :     /* Check parameter number is in range */
                                139   [ +  -  -  + ]:           5126 :     if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
 5279 tgl@sss.pgh.pa.us         140         [ #  # ]:UBC           0 :         ereport(ERROR,
                                141                 :                :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                142                 :                :                  errmsg("there is no parameter $%d", paramno),
                                143                 :                :                  parser_errposition(pstate, pref->location)));
 5279 tgl@sss.pgh.pa.us         144         [ +  + ]:CBC        5126 :     if (paramno > *parstate->numParams)
                                145                 :                :     {
                                146                 :                :         /* Need to enlarge param array */
                                147         [ +  + ]:           4184 :         if (*parstate->paramTypes)
  519 peter@eisentraut.org      148                 :           1394 :             *parstate->paramTypes = repalloc0_array(*parstate->paramTypes, Oid,
                                149                 :                :                                                     *parstate->numParams, paramno);
                                150                 :                :         else
                                151                 :           2790 :             *parstate->paramTypes = palloc0_array(Oid, paramno);
 5279 tgl@sss.pgh.pa.us         152                 :           4184 :         *parstate->numParams = paramno;
                                153                 :                :     }
                                154                 :                : 
                                155                 :                :     /* Locate param's slot in array */
                                156                 :           5126 :     pptype = &(*parstate->paramTypes)[paramno - 1];
                                157                 :                : 
                                158                 :                :     /* If not seen before, initialize to UNKNOWN type */
                                159         [ +  + ]:           5126 :     if (*pptype == InvalidOid)
                                160                 :           4284 :         *pptype = UNKNOWNOID;
                                161                 :                : 
                                162                 :                :     /*
                                163                 :                :      * If the argument is of type void and it's procedure call, interpret it
                                164                 :                :      * as unknown.  This allows the JDBC driver to not have to distinguish
                                165                 :                :      * function and procedure calls.  See also another component of this hack
                                166                 :                :      * in ParseFuncOrColumn().
                                167                 :                :      */
 1265 peter@eisentraut.org      168   [ -  +  -  - ]:           5126 :     if (*pptype == VOIDOID && pstate->p_expr_kind == EXPR_KIND_CALL_ARGUMENT)
 1265 peter@eisentraut.org      169                 :UBC           0 :         *pptype = UNKNOWNOID;
                                170                 :                : 
 5279 tgl@sss.pgh.pa.us         171                 :CBC        5126 :     param = makeNode(Param);
                                172                 :           5126 :     param->paramkind = PARAM_EXTERN;
                                173                 :           5126 :     param->paramid = paramno;
                                174                 :           5126 :     param->paramtype = *pptype;
                                175                 :           5126 :     param->paramtypmod = -1;
 4775                           176                 :           5126 :     param->paramcollid = get_typcollation(param->paramtype);
 5279                           177                 :           5126 :     param->location = pref->location;
                                178                 :                : 
                                179                 :           5126 :     return (Node *) param;
                                180                 :                : }
                                181                 :                : 
                                182                 :                : /*
                                183                 :                :  * Coerce a Param to a query-requested datatype, in the varparams case.
                                184                 :                :  */
                                185                 :                : static Node *
                                186                 :           4303 : variable_coerce_param_hook(ParseState *pstate, Param *param,
                                187                 :                :                            Oid targetTypeId, int32 targetTypeMod,
                                188                 :                :                            int location)
                                189                 :                : {
                                190   [ +  -  +  + ]:           4303 :     if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
                                191                 :                :     {
                                192                 :                :         /*
                                193                 :                :          * Input is a Param of previously undetermined type, and we want to
                                194                 :                :          * update our knowledge of the Param's type.
                                195                 :                :          */
                                196                 :           4287 :         VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                197                 :           4287 :         Oid        *paramTypes = *parstate->paramTypes;
                                198                 :           4287 :         int         paramno = param->paramid;
                                199                 :                : 
                                200         [ +  - ]:           4287 :         if (paramno <= 0 ||      /* shouldn't happen, but... */
                                201         [ -  + ]:           4287 :             paramno > *parstate->numParams)
 5279 tgl@sss.pgh.pa.us         202         [ #  # ]:UBC           0 :             ereport(ERROR,
                                203                 :                :                     (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                204                 :                :                      errmsg("there is no parameter $%d", paramno),
                                205                 :                :                      parser_errposition(pstate, param->location)));
                                206                 :                : 
 5279 tgl@sss.pgh.pa.us         207         [ +  - ]:CBC        4287 :         if (paramTypes[paramno - 1] == UNKNOWNOID)
                                208                 :                :         {
                                209                 :                :             /* We've successfully resolved the type */
                                210                 :           4287 :             paramTypes[paramno - 1] = targetTypeId;
                                211                 :                :         }
 5279 tgl@sss.pgh.pa.us         212         [ #  # ]:UBC           0 :         else if (paramTypes[paramno - 1] == targetTypeId)
                                213                 :                :         {
                                214                 :                :             /* We previously resolved the type, and it matches */
                                215                 :                :         }
                                216                 :                :         else
                                217                 :                :         {
                                218                 :                :             /* Oops */
                                219         [ #  # ]:              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]),
                                225                 :                :                                format_type_be(targetTypeId)),
                                226                 :                :                      parser_errposition(pstate, param->location)));
                                227                 :                :         }
                                228                 :                : 
 5279 tgl@sss.pgh.pa.us         229                 :CBC        4287 :         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
                                234                 :                :          * 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                 :                :          */
                                238                 :           4287 :         param->paramtypmod = -1;
                                239                 :                : 
                                240                 :                :         /*
                                241                 :                :          * 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                 :                :          */
 4775                           245                 :           4287 :         param->paramcollid = get_typcollation(param->paramtype);
                                246                 :                : 
                                247                 :                :         /* Use the leftmost of the param's and coercion's locations */
 5279                           248         [ +  + ]:           4287 :         if (location >= 0 &&
                                249   [ +  -  -  + ]:            577 :             (param->location < 0 || location < param->location))
 5279 tgl@sss.pgh.pa.us         250                 :UBC           0 :             param->location = location;
                                251                 :                : 
 5279 tgl@sss.pgh.pa.us         252                 :CBC        4287 :         return (Node *) param;
                                253                 :                :     }
                                254                 :                : 
                                255                 :                :     /* Else signal to proceed with normal coercion */
                                256                 :             16 :     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
                                264                 :                :  * were used, nor that all got non-UNKNOWN types assigned.  Caller of parser
                                265                 :                :  * should enforce that if it's important.
                                266                 :                :  */
                                267                 :                : void
                                268                 :           4583 : check_variable_parameters(ParseState *pstate, Query *query)
                                269                 :                : {
                                270                 :           4583 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                271                 :                : 
                                272                 :                :     /* If numParams is zero then no Params were generated, so no work */
                                273         [ +  + ]:           4583 :     if (*parstate->numParams > 0)
                                274                 :           3541 :         (void) query_tree_walker(query,
                                275                 :                :                                  check_parameter_resolution_walker,
                                276                 :                :                                  (void *) pstate, 0);
                                277                 :           4583 : }
                                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
                                282                 :                :  * 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
                                286                 :         107093 : check_parameter_resolution_walker(Node *node, ParseState *pstate)
                                287                 :                : {
                                288         [ +  + ]:         107093 :     if (node == NULL)
                                289                 :          46052 :         return false;
                                290         [ +  + ]:          61041 :     if (IsA(node, Param))
                                291                 :                :     {
                                292                 :           4570 :         Param      *param = (Param *) node;
                                293                 :                : 
                                294         [ +  + ]:           4570 :         if (param->paramkind == PARAM_EXTERN)
                                295                 :                :         {
                                296                 :           4568 :             VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                297                 :           4568 :             int         paramno = param->paramid;
                                298                 :                : 
                                299         [ +  - ]:           4568 :             if (paramno <= 0 || /* shouldn't happen, but... */
                                300         [ -  + ]:           4568 :                 paramno > *parstate->numParams)
 5279 tgl@sss.pgh.pa.us         301         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                302                 :                :                         (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                303                 :                :                          errmsg("there is no parameter $%d", paramno),
                                304                 :                :                          parser_errposition(pstate, param->location)));
                                305                 :                : 
 5279 tgl@sss.pgh.pa.us         306         [ -  + ]:CBC        4568 :             if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
 5279 tgl@sss.pgh.pa.us         307         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                308                 :                :                         (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
                                309                 :                :                          errmsg("could not determine data type of parameter $%d",
                                310                 :                :                                 paramno),
                                311                 :                :                          parser_errposition(pstate, param->location)));
                                312                 :                :         }
 5279 tgl@sss.pgh.pa.us         313                 :CBC        4570 :         return false;
                                314                 :                :     }
                                315         [ +  + ]:          56471 :     if (IsA(node, Query))
                                316                 :                :     {
                                317                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                318                 :             98 :         return query_tree_walker((Query *) node,
                                319                 :                :                                  check_parameter_resolution_walker,
                                320                 :                :                                  (void *) pstate, 0);
                                321                 :                :     }
                                322                 :          56373 :     return expression_tree_walker(node, check_parameter_resolution_walker,
                                323                 :                :                                   (void *) pstate);
                                324                 :                : }
                                325                 :                : 
                                326                 :                : /*
                                327                 :                :  * Check to see if a fully-parsed query tree contains any PARAM_EXTERN Params.
                                328                 :                :  */
                                329                 :                : bool
 4020                           330                 :            272 : query_contains_extern_params(Query *query)
                                331                 :                : {
                                332                 :            272 :     return query_tree_walker(query,
                                333                 :                :                              query_contains_extern_params_walker,
                                334                 :                :                              NULL, 0);
                                335                 :                : }
                                336                 :                : 
                                337                 :                : static bool
                                338                 :           5679 : query_contains_extern_params_walker(Node *node, void *context)
                                339                 :                : {
                                340         [ +  + ]:           5679 :     if (node == NULL)
                                341                 :           3487 :         return false;
                                342         [ -  + ]:           2192 :     if (IsA(node, Param))
                                343                 :                :     {
 4020 tgl@sss.pgh.pa.us         344                 :UBC           0 :         Param      *param = (Param *) node;
                                345                 :                : 
                                346         [ #  # ]:              0 :         if (param->paramkind == PARAM_EXTERN)
                                347                 :              0 :             return true;
                                348                 :              0 :         return false;
                                349                 :                :     }
 4020 tgl@sss.pgh.pa.us         350         [ +  + ]:CBC        2192 :     if (IsA(node, Query))
                                351                 :                :     {
                                352                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                353                 :              9 :         return query_tree_walker((Query *) node,
                                354                 :                :                                  query_contains_extern_params_walker,
                                355                 :                :                                  context, 0);
                                356                 :                :     }
                                357                 :           2183 :     return expression_tree_walker(node, query_contains_extern_params_walker,
                                358                 :                :                                   context);
                                359                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622