Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Functions

parse_param.c File Reference

#include "postgres.h"
#include <limits.h>
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_param.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
Include dependency graph for parse_param.c:

Go to the source code of this file.

Data Structures

struct  FixedParamState
struct  VarParamState

Typedefs

typedef struct FixedParamState FixedParamState
typedef struct VarParamState VarParamState

Functions

static Nodefixed_paramref_hook (ParseState *pstate, ParamRef *pref)
static Nodevariable_paramref_hook (ParseState *pstate, ParamRef *pref)
static Nodevariable_coerce_param_hook (ParseState *pstate, Param *param, Oid targetTypeId, int32 targetTypeMod, int location)
static bool check_parameter_resolution_walker (Node *node, ParseState *pstate)
static bool query_contains_extern_params_walker (Node *node, void *context)
void parse_fixed_parameters (ParseState *pstate, Oid *paramTypes, int numParams)
void parse_variable_parameters (ParseState *pstate, Oid **paramTypes, int *numParams)
void check_variable_parameters (ParseState *pstate, Query *query)
bool query_contains_extern_params (Query *query)

Typedef Documentation

typedef struct VarParamState VarParamState

Function Documentation

static bool check_parameter_resolution_walker ( Node node,
ParseState pstate 
) [static]

Definition at line 281 of file parse_param.c.

References ereport, errcode(), errmsg(), ERROR, expression_tree_walker(), IsA, Param::location, NULL, VarParamState::numParams, ParseState::p_ref_hook_state, PARAM_EXTERN, Param::paramid, Param::paramkind, Param::paramtype, VarParamState::paramTypes, parser_errposition(), and query_tree_walker().

Referenced by check_variable_parameters().

{
    if (node == NULL)
        return false;
    if (IsA(node, Param))
    {
        Param      *param = (Param *) node;

        if (param->paramkind == PARAM_EXTERN)
        {
            VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
            int         paramno = param->paramid;

            if (paramno <= 0 || /* shouldn't happen, but... */
                paramno > *parstate->numParams)
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_PARAMETER),
                         errmsg("there is no parameter $%d", paramno),
                         parser_errposition(pstate, param->location)));

            if (param->paramtype != (*parstate->paramTypes)[paramno - 1])
                ereport(ERROR,
                        (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
                     errmsg("could not determine data type of parameter $%d",
                            paramno),
                         parser_errposition(pstate, param->location)));
        }
        return false;
    }
    if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        return query_tree_walker((Query *) node,
                                 check_parameter_resolution_walker,
                                 (void *) pstate, 0);
    }
    return expression_tree_walker(node, check_parameter_resolution_walker,
                                  (void *) pstate);
}

void check_variable_parameters ( ParseState pstate,
Query query 
)

Definition at line 263 of file parse_param.c.

References check_parameter_resolution_walker(), VarParamState::numParams, ParseState::p_ref_hook_state, and query_tree_walker().

Referenced by parse_analyze_varparams().

{
    VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;

    /* If numParams is zero then no Params were generated, so no work */
    if (*parstate->numParams > 0)
        (void) query_tree_walker(query,
                                 check_parameter_resolution_walker,
                                 (void *) pstate, 0);
}

static Node * fixed_paramref_hook ( ParseState pstate,
ParamRef pref 
) [static]

Definition at line 99 of file parse_param.c.

References ereport, errcode(), errmsg(), ERROR, get_typcollation(), ParamRef::location, makeNode, ParamRef::number, FixedParamState::numParams, OidIsValid, ParseState::p_ref_hook_state, FixedParamState::paramTypes, and parser_errposition().

{
    FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state;
    int         paramno = pref->number;
    Param      *param;

    /* Check parameter number is valid */
    if (paramno <= 0 || paramno > parstate->numParams ||
        !OidIsValid(parstate->paramTypes[paramno - 1]))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_PARAMETER),
                 errmsg("there is no parameter $%d", paramno),
                 parser_errposition(pstate, pref->location)));

    param = makeNode(Param);
    param->paramkind = PARAM_EXTERN;
    param->paramid = paramno;
    param->paramtype = parstate->paramTypes[paramno - 1];
    param->paramtypmod = -1;
    param->paramcollid = get_typcollation(param->paramtype);
    param->location = pref->location;

    return (Node *) param;
}

void parse_fixed_parameters ( ParseState pstate,
Oid paramTypes,
int  numParams 
)

Definition at line 67 of file parse_param.c.

References FixedParamState::numParams, ParseState::p_paramref_hook, ParseState::p_ref_hook_state, palloc(), and FixedParamState::paramTypes.

Referenced by parse_analyze().

{
    FixedParamState *parstate = palloc(sizeof(FixedParamState));

    parstate->paramTypes = paramTypes;
    parstate->numParams = numParams;
    pstate->p_ref_hook_state = (void *) parstate;
    pstate->p_paramref_hook = fixed_paramref_hook;
    /* no need to use p_coerce_param_hook */
}

void parse_variable_parameters ( ParseState pstate,
Oid **  paramTypes,
int *  numParams 
)

Definition at line 83 of file parse_param.c.

References VarParamState::numParams, ParseState::p_coerce_param_hook, ParseState::p_paramref_hook, ParseState::p_ref_hook_state, palloc(), and VarParamState::paramTypes.

Referenced by parse_analyze_varparams().

{
    VarParamState *parstate = palloc(sizeof(VarParamState));

    parstate->paramTypes = paramTypes;
    parstate->numParams = numParams;
    pstate->p_ref_hook_state = (void *) parstate;
    pstate->p_paramref_hook = variable_paramref_hook;
    pstate->p_coerce_param_hook = variable_coerce_param_hook;
}

bool query_contains_extern_params ( Query query  ) 
static bool query_contains_extern_params_walker ( Node node,
void *  context 
) [static]

Definition at line 333 of file parse_param.c.

References expression_tree_walker(), IsA, NULL, PARAM_EXTERN, Param::paramkind, and query_tree_walker().

Referenced by query_contains_extern_params().

{
    if (node == NULL)
        return false;
    if (IsA(node, Param))
    {
        Param      *param = (Param *) node;

        if (param->paramkind == PARAM_EXTERN)
            return true;
        return false;
    }
    if (IsA(node, Query))
    {
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        return query_tree_walker((Query *) node,
                                 query_contains_extern_params_walker,
                                 context, 0);
    }
    return expression_tree_walker(node, query_contains_extern_params_walker,
                                  context);
}

static Node * variable_coerce_param_hook ( ParseState pstate,
Param param,
Oid  targetTypeId,
int32  targetTypeMod,
int  location 
) [static]

Definition at line 181 of file parse_param.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), get_typcollation(), Param::location, VarParamState::numParams, ParseState::p_ref_hook_state, PARAM_EXTERN, Param::paramcollid, Param::paramid, Param::paramkind, Param::paramtype, VarParamState::paramTypes, Param::paramtypmod, parser_errposition(), and UNKNOWNOID.

{
    if (param->paramkind == PARAM_EXTERN && param->paramtype == UNKNOWNOID)
    {
        /*
         * Input is a Param of previously undetermined type, and we want to
         * update our knowledge of the Param's type.
         */
        VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
        Oid        *paramTypes = *parstate->paramTypes;
        int         paramno = param->paramid;

        if (paramno <= 0 ||     /* shouldn't happen, but... */
            paramno > *parstate->numParams)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_PARAMETER),
                     errmsg("there is no parameter $%d", paramno),
                     parser_errposition(pstate, param->location)));

        if (paramTypes[paramno - 1] == UNKNOWNOID)
        {
            /* We've successfully resolved the type */
            paramTypes[paramno - 1] = targetTypeId;
        }
        else if (paramTypes[paramno - 1] == targetTypeId)
        {
            /* We previously resolved the type, and it matches */
        }
        else
        {
            /* Ooops */
            ereport(ERROR,
                    (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
                     errmsg("inconsistent types deduced for parameter $%d",
                            paramno),
                     errdetail("%s versus %s",
                               format_type_be(paramTypes[paramno - 1]),
                               format_type_be(targetTypeId)),
                     parser_errposition(pstate, param->location)));
        }

        param->paramtype = targetTypeId;

        /*
         * Note: it is tempting here to set the Param's paramtypmod to
         * targetTypeMod, but that is probably unwise because we have no
         * infrastructure that enforces that the value delivered for a Param
         * will match any particular typmod.  Leaving it -1 ensures that a
         * run-time length check/coercion will occur if needed.
         */
        param->paramtypmod = -1;

        /*
         * This module always sets a Param's collation to be the default for
         * its datatype.  If that's not what you want, you should be using the
         * more general parser substitution hooks.
         */
        param->paramcollid = get_typcollation(param->paramtype);

        /* Use the leftmost of the param's and coercion's locations */
        if (location >= 0 &&
            (param->location < 0 || location < param->location))
            param->location = location;

        return (Node *) param;
    }

    /* Else signal to proceed with normal coercion */
    return NULL;
}

static Node * variable_paramref_hook ( ParseState pstate,
ParamRef pref 
) [static]

Definition at line 131 of file parse_param.c.

References ereport, errcode(), errmsg(), ERROR, get_typcollation(), InvalidOid, ParamRef::location, makeNode, MemSet, ParamRef::number, VarParamState::numParams, ParseState::p_ref_hook_state, palloc(), VarParamState::paramTypes, parser_errposition(), and repalloc().

{
    VarParamState *parstate = (VarParamState *) pstate->p_ref_hook_state;
    int         paramno = pref->number;
    Oid        *pptype;
    Param      *param;

    /* Check parameter number is in range */
    if (paramno <= 0 || paramno > INT_MAX / sizeof(Oid))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_PARAMETER),
                 errmsg("there is no parameter $%d", paramno),
                 parser_errposition(pstate, pref->location)));
    if (paramno > *parstate->numParams)
    {
        /* Need to enlarge param array */
        if (*parstate->paramTypes)
            *parstate->paramTypes = (Oid *) repalloc(*parstate->paramTypes,
                                                     paramno * sizeof(Oid));
        else
            *parstate->paramTypes = (Oid *) palloc(paramno * sizeof(Oid));
        /* Zero out the previously-unreferenced slots */
        MemSet(*parstate->paramTypes + *parstate->numParams,
               0,
               (paramno - *parstate->numParams) * sizeof(Oid));
        *parstate->numParams = paramno;
    }

    /* Locate param's slot in array */
    pptype = &(*parstate->paramTypes)[paramno - 1];

    /* If not seen before, initialize to UNKNOWN type */
    if (*pptype == InvalidOid)
        *pptype = UNKNOWNOID;

    param = makeNode(Param);
    param->paramkind = PARAM_EXTERN;
    param->paramid = paramno;
    param->paramtype = *pptype;
    param->paramtypmod = -1;
    param->paramcollid = get_typcollation(param->paramtype);
    param->location = pref->location;

    return (Node *) param;
}