LCOV - differential code coverage report
Current view: top level - src/backend/parser - parse_param.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 87.9 % 107 94 13 94
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 9 9 9
Baseline: lcov-20250906-005545-baseline Branches: 54.1 % 74 40 34 40
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 2 2 2
(360..) days: 87.6 % 105 92 13 92
Function coverage date bins:
(360..) days: 100.0 % 9 9 9
Branch coverage date bins:
(360..) 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-2025, 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                 :                : #include "utils/memutils.h"
                                 35                 :                : 
                                 36                 :                : 
                                 37                 :                : typedef struct FixedParamState
                                 38                 :                : {
                                 39                 :                :     const Oid  *paramTypes;     /* array of parameter type OIDs */
                                 40                 :                :     int         numParams;      /* number of array entries */
                                 41                 :                : } FixedParamState;
                                 42                 :                : 
                                 43                 :                : /*
                                 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.
                                 48                 :                :  */
                                 49                 :                : typedef struct VarParamState
                                 50                 :                : {
                                 51                 :                :     Oid       **paramTypes;     /* array of parameter type OIDs */
                                 52                 :                :     int        *numParams;      /* number of array entries */
                                 53                 :                : } VarParamState;
                                 54                 :                : 
                                 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);
                                 62                 :                : 
                                 63                 :                : 
                                 64                 :                : /*
                                 65                 :                :  * Set up to process a query containing references to fixed parameters.
                                 66                 :                :  */
                                 67                 :                : void
 1282 peter@eisentraut.org       68                 :CBC        1961 : setup_parse_fixed_parameters(ParseState *pstate,
                                 69                 :                :                              const Oid *paramTypes, int numParams)
                                 70                 :                : {
 5789 tgl@sss.pgh.pa.us          71                 :           1961 :     FixedParamState *parstate = palloc(sizeof(FixedParamState));
                                 72                 :                : 
                                 73                 :           1961 :     parstate->paramTypes = paramTypes;
                                 74                 :           1961 :     parstate->numParams = numParams;
  282 peter@eisentraut.org       75                 :           1961 :     pstate->p_ref_hook_state = parstate;
 5789 tgl@sss.pgh.pa.us          76                 :           1961 :     pstate->p_paramref_hook = fixed_paramref_hook;
                                 77                 :                :     /* no need to use p_coerce_param_hook */
                                 78                 :           1961 : }
                                 79                 :                : 
                                 80                 :                : /*
                                 81                 :                :  * Set up to process a query containing references to variable parameters.
                                 82                 :                :  */
                                 83                 :                : void
 1282 peter@eisentraut.org       84                 :           5210 : setup_parse_variable_parameters(ParseState *pstate,
                                 85                 :                :                                 Oid **paramTypes, int *numParams)
                                 86                 :                : {
 5789 tgl@sss.pgh.pa.us          87                 :           5210 :     VarParamState *parstate = palloc(sizeof(VarParamState));
                                 88                 :                : 
                                 89                 :           5210 :     parstate->paramTypes = paramTypes;
                                 90                 :           5210 :     parstate->numParams = numParams;
  282 peter@eisentraut.org       91                 :           5210 :     pstate->p_ref_hook_state = parstate;
 5789 tgl@sss.pgh.pa.us          92                 :           5210 :     pstate->p_paramref_hook = variable_paramref_hook;
                                 93                 :           5210 :     pstate->p_coerce_param_hook = variable_coerce_param_hook;
                                 94                 :           5210 : }
                                 95                 :                : 
                                 96                 :                : /*
                                 97                 :                :  * Transform a ParamRef using fixed parameter types.
                                 98                 :                :  */
                                 99                 :                : static Node *
                                100                 :           2826 : fixed_paramref_hook(ParseState *pstate, ParamRef *pref)
                                101                 :                : {
                                102                 :           2826 :     FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
                                103                 :           2826 :     int         paramno = pref->number;
                                104                 :                :     Param      *param;
                                105                 :                : 
                                106                 :                :     /* Check parameter number is valid */
 5715                           107   [ +  -  +  - ]:           2826 :     if (paramno <= 0 || paramno > parstate->numParams ||
                                108         [ -  + ]:           2826 :         !OidIsValid(parstate->paramTypes[paramno - 1]))
 5789 tgl@sss.pgh.pa.us         109         [ #  # ]:UBC           0 :         ereport(ERROR,
                                110                 :                :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                111                 :                :                  errmsg("there is no parameter $%d", paramno),
                                112                 :                :                  parser_errposition(pstate, pref->location)));
                                113                 :                : 
 5789 tgl@sss.pgh.pa.us         114                 :CBC        2826 :     param = makeNode(Param);
                                115                 :           2826 :     param->paramkind = PARAM_EXTERN;
                                116                 :           2826 :     param->paramid = paramno;
                                117                 :           2826 :     param->paramtype = parstate->paramTypes[paramno - 1];
                                118                 :           2826 :     param->paramtypmod = -1;
 5285                           119                 :           2826 :     param->paramcollid = get_typcollation(param->paramtype);
 5789                           120                 :           2826 :     param->location = pref->location;
                                121                 :                : 
                                122                 :           2826 :     return (Node *) param;
                                123                 :                : }
                                124                 :                : 
                                125                 :                : /*
                                126                 :                :  * Transform a ParamRef using variable parameter types.
                                127                 :                :  *
                                128                 :                :  * The only difference here is we must enlarge the parameter type array
                                129                 :                :  * as needed.
                                130                 :                :  */
                                131                 :                : static Node *
                                132                 :           5756 : variable_paramref_hook(ParseState *pstate, ParamRef *pref)
                                133                 :                : {
                                134                 :           5756 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                135                 :           5756 :     int         paramno = pref->number;
                                136                 :                :     Oid        *pptype;
                                137                 :                :     Param      *param;
                                138                 :                : 
                                139                 :                :     /* Check parameter number is in range */
  431 peter@eisentraut.org      140   [ +  -  -  + ]:           5756 :     if (paramno <= 0 || paramno > MaxAllocSize / sizeof(Oid))
 5789 tgl@sss.pgh.pa.us         141         [ #  # ]:UBC           0 :         ereport(ERROR,
                                142                 :                :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                143                 :                :                  errmsg("there is no parameter $%d", paramno),
                                144                 :                :                  parser_errposition(pstate, pref->location)));
 5789 tgl@sss.pgh.pa.us         145         [ +  + ]:CBC        5756 :     if (paramno > *parstate->numParams)
                                146                 :                :     {
                                147                 :                :         /* Need to enlarge param array */
                                148         [ +  + ]:           4510 :         if (*parstate->paramTypes)
 1029 peter@eisentraut.org      149                 :           1457 :             *parstate->paramTypes = repalloc0_array(*parstate->paramTypes, Oid,
                                150                 :                :                                                     *parstate->numParams, paramno);
                                151                 :                :         else
                                152                 :           3053 :             *parstate->paramTypes = palloc0_array(Oid, paramno);
 5789 tgl@sss.pgh.pa.us         153                 :           4510 :         *parstate->numParams = paramno;
                                154                 :                :     }
                                155                 :                : 
                                156                 :                :     /* Locate param's slot in array */
                                157                 :           5756 :     pptype = &(*parstate->paramTypes)[paramno - 1];
                                158                 :                : 
                                159                 :                :     /* If not seen before, initialize to UNKNOWN type */
                                160         [ +  + ]:           5756 :     if (*pptype == InvalidOid)
                                161                 :           4620 :         *pptype = UNKNOWNOID;
                                162                 :                : 
                                163                 :                :     /*
                                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().
                                168                 :                :      */
 1775 peter@eisentraut.org      169   [ -  +  -  - ]:           5756 :     if (*pptype == VOIDOID && pstate->p_expr_kind == EXPR_KIND_CALL_ARGUMENT)
 1775 peter@eisentraut.org      170                 :UBC           0 :         *pptype = UNKNOWNOID;
                                171                 :                : 
 5789 tgl@sss.pgh.pa.us         172                 :CBC        5756 :     param = makeNode(Param);
                                173                 :           5756 :     param->paramkind = PARAM_EXTERN;
                                174                 :           5756 :     param->paramid = paramno;
                                175                 :           5756 :     param->paramtype = *pptype;
                                176                 :           5756 :     param->paramtypmod = -1;
 5285                           177                 :           5756 :     param->paramcollid = get_typcollation(param->paramtype);
 5789                           178                 :           5756 :     param->location = pref->location;
                                179                 :                : 
                                180                 :           5756 :     return (Node *) param;
                                181                 :                : }
                                182                 :                : 
                                183                 :                : /*
                                184                 :                :  * Coerce a Param to a query-requested datatype, in the varparams case.
                                185                 :                :  */
                                186                 :                : static Node *
                                187                 :           4665 : variable_coerce_param_hook(ParseState *pstate, Param *param,
                                188                 :                :                            Oid targetTypeId, int32 targetTypeMod,
                                189                 :                :                            int location)
                                190                 :                : {
                                191   [ +  -  +  + ]:           4665 :     if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
                                192                 :                :     {
                                193                 :                :         /*
                                194                 :                :          * Input is a Param of previously undetermined type, and we want to
                                195                 :                :          * update our knowledge of the Param's type.
                                196                 :                :          */
                                197                 :           4623 :         VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                198                 :           4623 :         Oid        *paramTypes = *parstate->paramTypes;
                                199                 :           4623 :         int         paramno = param->paramid;
                                200                 :                : 
                                201         [ +  - ]:           4623 :         if (paramno <= 0 ||      /* shouldn't happen, but... */
                                202         [ -  + ]:           4623 :             paramno > *parstate->numParams)
 5789 tgl@sss.pgh.pa.us         203         [ #  # ]:UBC           0 :             ereport(ERROR,
                                204                 :                :                     (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                205                 :                :                      errmsg("there is no parameter $%d", paramno),
                                206                 :                :                      parser_errposition(pstate, param->location)));
                                207                 :                : 
 5789 tgl@sss.pgh.pa.us         208         [ +  - ]:CBC        4623 :         if (paramTypes[paramno - 1] == UNKNOWNOID)
                                209                 :                :         {
                                210                 :                :             /* We've successfully resolved the type */
                                211                 :           4623 :             paramTypes[paramno - 1] = targetTypeId;
                                212                 :                :         }
 5789 tgl@sss.pgh.pa.us         213         [ #  # ]:UBC           0 :         else if (paramTypes[paramno - 1] == targetTypeId)
                                214                 :                :         {
                                215                 :                :             /* We previously resolved the type, and it matches */
                                216                 :                :         }
                                217                 :                :         else
                                218                 :                :         {
                                219                 :                :             /* Oops */
                                220         [ #  # ]:              0 :             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)));
                                228                 :                :         }
                                229                 :                : 
 5789 tgl@sss.pgh.pa.us         230                 :CBC        4623 :         param->paramtype = targetTypeId;
                                231                 :                : 
                                232                 :                :         /*
                                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.
                                238                 :                :          */
                                239                 :           4623 :         param->paramtypmod = -1;
                                240                 :                : 
                                241                 :                :         /*
                                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.
                                245                 :                :          */
 5285                           246                 :           4623 :         param->paramcollid = get_typcollation(param->paramtype);
                                247                 :                : 
                                248                 :                :         /* Use the leftmost of the param's and coercion's locations */
 5789                           249         [ +  + ]:           4623 :         if (location >= 0 &&
                                250   [ +  -  -  + ]:            614 :             (param->location < 0 || location < param->location))
 5789 tgl@sss.pgh.pa.us         251                 :UBC           0 :             param->location = location;
                                252                 :                : 
 5789 tgl@sss.pgh.pa.us         253                 :CBC        4623 :         return (Node *) param;
                                254                 :                :     }
                                255                 :                : 
                                256                 :                :     /* Else signal to proceed with normal coercion */
                                257                 :             42 :     return NULL;
                                258                 :                : }
                                259                 :                : 
                                260                 :                : /*
                                261                 :                :  * Check for consistent assignment of variable parameters after completion
                                262                 :                :  * of parsing with parse_variable_parameters.
                                263                 :                :  *
                                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.
                                267                 :                :  */
                                268                 :                : void
                                269                 :           5202 : check_variable_parameters(ParseState *pstate, Query *query)
                                270                 :                : {
                                271                 :           5202 :     VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                272                 :                : 
                                273                 :                :     /* If numParams is zero then no Params were generated, so no work */
                                274         [ +  + ]:           5202 :     if (*parstate->numParams > 0)
                                275                 :           3951 :         (void) query_tree_walker(query,
                                276                 :                :                                  check_parameter_resolution_walker,
                                277                 :                :                                  pstate, 0);
                                278                 :           5202 : }
                                279                 :                : 
                                280                 :                : /*
                                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.
                                285                 :                :  */
                                286                 :                : static bool
                                287                 :         122437 : check_parameter_resolution_walker(Node *node, ParseState *pstate)
                                288                 :                : {
                                289         [ +  + ]:         122437 :     if (node == NULL)
                                290                 :          51116 :         return false;
                                291         [ +  + ]:          71321 :     if (IsA(node, Param))
                                292                 :                :     {
                                293                 :           5204 :         Param      *param = (Param *) node;
                                294                 :                : 
                                295         [ +  + ]:           5204 :         if (param->paramkind == PARAM_EXTERN)
                                296                 :                :         {
                                297                 :           5199 :             VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
                                298                 :           5199 :             int         paramno = param->paramid;
                                299                 :                : 
                                300         [ +  - ]:           5199 :             if (paramno <= 0 || /* shouldn't happen, but... */
                                301         [ -  + ]:           5199 :                 paramno > *parstate->numParams)
 5789 tgl@sss.pgh.pa.us         302         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                303                 :                :                         (errcode(ERRCODE_UNDEFINED_PARAMETER),
                                304                 :                :                          errmsg("there is no parameter $%d", paramno),
                                305                 :                :                          parser_errposition(pstate, param->location)));
                                306                 :                : 
 5789 tgl@sss.pgh.pa.us         307         [ -  + ]:CBC        5199 :             if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
 5789 tgl@sss.pgh.pa.us         308         [ #  # ]:UBC           0 :                 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)));
                                313                 :                :         }
 5789 tgl@sss.pgh.pa.us         314                 :CBC        5204 :         return false;
                                315                 :                :     }
                                316         [ +  + ]:          66117 :     if (IsA(node, Query))
                                317                 :                :     {
                                318                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                319                 :            105 :         return query_tree_walker((Query *) node,
                                320                 :                :                                  check_parameter_resolution_walker,
                                321                 :                :                                  pstate, 0);
                                322                 :                :     }
                                323                 :          66012 :     return expression_tree_walker(node, check_parameter_resolution_walker,
                                324                 :                :                                   pstate);
                                325                 :                : }
                                326                 :                : 
                                327                 :                : /*
                                328                 :                :  * Check to see if a fully-parsed query tree contains any PARAM_EXTERN Params.
                                329                 :                :  */
                                330                 :                : bool
 4530                           331                 :            281 : query_contains_extern_params(Query *query)
                                332                 :                : {
                                333                 :            281 :     return query_tree_walker(query,
                                334                 :                :                              query_contains_extern_params_walker,
                                335                 :                :                              NULL, 0);
                                336                 :                : }
                                337                 :                : 
                                338                 :                : static bool
                                339                 :           5913 : query_contains_extern_params_walker(Node *node, void *context)
                                340                 :                : {
                                341         [ +  + ]:           5913 :     if (node == NULL)
                                342                 :           3615 :         return false;
                                343         [ -  + ]:           2298 :     if (IsA(node, Param))
                                344                 :                :     {
 4530 tgl@sss.pgh.pa.us         345                 :UBC           0 :         Param      *param = (Param *) node;
                                346                 :                : 
                                347         [ #  # ]:              0 :         if (param->paramkind == PARAM_EXTERN)
                                348                 :              0 :             return true;
                                349                 :              0 :         return false;
                                350                 :                :     }
 4530 tgl@sss.pgh.pa.us         351         [ +  + ]:CBC        2298 :     if (IsA(node, Query))
                                352                 :                :     {
                                353                 :                :         /* Recurse into RTE subquery or not-yet-planned sublink subquery */
                                354                 :              9 :         return query_tree_walker((Query *) node,
                                355                 :                :                                  query_contains_extern_params_walker,
                                356                 :                :                                  context, 0);
                                357                 :                :     }
                                358                 :           2289 :     return expression_tree_walker(node, query_contains_extern_params_walker,
                                359                 :                :                                   context);
                                360                 :                : }
        

Generated by: LCOV version 2.4-beta