1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-21 10:42:50 +03:00

Add support for invoking parser callback hooks via SPI and in cached plans.

As proof of concept, modify plpgsql to use the hooks.  plpgsql is still
inserting $n symbols textually, but the "back end" of the parsing process now
goes through the ParamRef hook instead of using a fixed parameter-type array,
and then execution only fetches actually-referenced parameters, using a hook
added to ParamListInfo.

Although there's a lot left to be done in plpgsql, this already cures the
"if (TG_OP = 'INSERT' and NEW.foo ...)"  problem, as illustrated by the
changed regression test.
This commit is contained in:
Tom Lane
2009-11-04 22:26:08 +00:00
parent 48912acc08
commit 9bedd128d6
23 changed files with 1110 additions and 533 deletions

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.11 2009/01/01 17:23:43 momjian Exp $
* $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.12 2009/11/04 22:26:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,7 @@
#include "postgres.h"
#include "nodes/params.h"
#include "parser/parse_param.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
@@ -24,6 +25,11 @@
* Copy a ParamListInfo structure.
*
* The result is allocated in CurrentMemoryContext.
*
* Note: the intent of this function is to make a static, self-contained
* set of parameter values. If dynamic parameter hooks are present, we
* intentionally do not copy them into the result. Rather, we forcibly
* instantiate all available parameter values and copy the datum values.
*/
ParamListInfo
copyParamList(ParamListInfo from)
@@ -40,54 +46,76 @@ copyParamList(ParamListInfo from)
(from->numParams - 1) *sizeof(ParamExternData);
retval = (ParamListInfo) palloc(size);
memcpy(retval, from, size);
retval->paramFetch = NULL;
retval->paramFetchArg = NULL;
retval->parserSetup = NULL;
retval->parserSetupArg = NULL;
retval->numParams = from->numParams;
/*
* Flat-copy is not good enough for pass-by-ref data values, so make a
* pass over the array to copy those.
*/
for (i = 0; i < retval->numParams; i++)
for (i = 0; i < from->numParams; i++)
{
ParamExternData *prm = &retval->params[i];
ParamExternData *oprm = &from->params[i];
ParamExternData *nprm = &retval->params[i];
int16 typLen;
bool typByVal;
if (prm->isnull || !OidIsValid(prm->ptype))
/* give hook a chance in case parameter is dynamic */
if (!OidIsValid(oprm->ptype) && from->paramFetch != NULL)
(*from->paramFetch) (from, i+1);
/* flat-copy the parameter info */
*nprm = *oprm;
/* need datumCopy in case it's a pass-by-reference datatype */
if (nprm->isnull || !OidIsValid(nprm->ptype))
continue;
get_typlenbyval(prm->ptype, &typLen, &typByVal);
prm->value = datumCopy(prm->value, typByVal, typLen);
get_typlenbyval(nprm->ptype, &typLen, &typByVal);
nprm->value = datumCopy(nprm->value, typByVal, typLen);
}
return retval;
}
/*
* Extract an array of parameter type OIDs from a ParamListInfo.
* Set up the parser to treat the given list of run-time parameters
* as available external parameters during parsing of a new query.
*
* The result is allocated in CurrentMemoryContext.
* Note that the parser doesn't actually care about the *values* of the given
* parameters, only about their *types*. Also, the code that originally
* provided the ParamListInfo may have provided a setupHook, which should
* override applying parse_fixed_parameters().
*/
void
getParamListTypes(ParamListInfo params,
Oid **param_types, int *num_params)
setupParserWithParamList(struct ParseState *pstate,
ParamListInfo params)
{
Oid *ptypes;
int i;
if (params == NULL) /* no params, nothing to do */
return;
if (params == NULL || params->numParams <= 0)
/* If there is a parserSetup hook, it gets to do this */
if (params->parserSetup != NULL)
{
*param_types = NULL;
*num_params = 0;
(*params->parserSetup) (pstate, params->parserSetupArg);
return;
}
ptypes = (Oid *) palloc(params->numParams * sizeof(Oid));
*param_types = ptypes;
*num_params = params->numParams;
for (i = 0; i < params->numParams; i++)
/* Else, treat any available parameters as being of fixed type */
if (params->numParams > 0)
{
ParamExternData *prm = &params->params[i];
Oid *ptypes;
int i;
ptypes[i] = prm->ptype;
ptypes = (Oid *) palloc(params->numParams * sizeof(Oid));
for (i = 0; i < params->numParams; i++)
{
ParamExternData *prm = &params->params[i];
/* give hook a chance in case parameter is dynamic */
if (!OidIsValid(prm->ptype) && params->paramFetch != NULL)
(*params->paramFetch) (params, i+1);
ptypes[i] = prm->ptype;
}
parse_fixed_parameters(pstate, ptypes, params->numParams);
}
}