1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +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

@ -35,7 +35,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.30 2009/10/26 02:26:41 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.31 2009/11/04 22:26:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -99,8 +99,8 @@ InitPlanCache(void)
* raw_parse_tree: output of raw_parser()
* query_string: original query text (as of PG 8.4, must not be NULL)
* commandTag: compile-time-constant tag for query, or NULL if empty query
* param_types: array of parameter type OIDs, or NULL if none
* num_params: number of parameters
* param_types: array of fixed parameter type OIDs, or NULL if none
* num_params: number of fixed parameters
* cursor_options: options bitmask that was/will be passed to planner
* stmt_list: list of PlannedStmts/utility stmts, or list of Query trees
* fully_planned: are we caching planner or rewriter output?
@ -156,6 +156,9 @@ CreateCachedPlan(Node *raw_parse_tree,
else
plansource->param_types = NULL;
plansource->num_params = num_params;
/* these can be set later with CachedPlanSetParserHook: */
plansource->parserSetup = NULL;
plansource->parserSetupArg = NULL;
plansource->cursor_options = cursor_options;
plansource->fully_planned = fully_planned;
plansource->fixed_result = fixed_result;
@ -240,6 +243,9 @@ FastCreateCachedPlan(Node *raw_parse_tree,
plansource->commandTag = commandTag; /* no copying needed */
plansource->param_types = param_types;
plansource->num_params = num_params;
/* these can be set later with CachedPlanSetParserHook: */
plansource->parserSetup = NULL;
plansource->parserSetupArg = NULL;
plansource->cursor_options = cursor_options;
plansource->fully_planned = fully_planned;
plansource->fixed_result = fixed_result;
@ -274,6 +280,27 @@ FastCreateCachedPlan(Node *raw_parse_tree,
return plansource;
}
/*
* CachedPlanSetParserHook: set up to use parser callback hooks
*
* Use this when a caller wants to manage parameter information via parser
* callbacks rather than a fixed parameter-types list. Beware that the
* information pointed to by parserSetupArg must be valid for as long as
* the cached plan might be replanned!
*/
void
CachedPlanSetParserHook(CachedPlanSource *plansource,
ParserSetupHook parserSetup,
void *parserSetupArg)
{
/* Must not have specified a fixed parameter-types list */
Assert(plansource->param_types == NULL);
Assert(plansource->num_params == 0);
/* OK, save hook info */
plansource->parserSetup = parserSetup;
plansource->parserSetupArg = parserSetupArg;
}
/*
* StoreCachedPlan: store a built or rebuilt plan into a plancache entry.
*
@ -466,6 +493,7 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
if (!plan)
{
bool snapshot_set = false;
Node *rawtree;
List *slist;
TupleDesc resultDesc;
@ -491,14 +519,19 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
/*
* Run parse analysis and rule rewriting. The parser tends to
* scribble on its input, so we must copy the raw parse tree to
* prevent corruption of the cache. Note that we do not use
* parse_analyze_varparams(), assuming that the caller never wants the
* parameter types to change from the original values.
* prevent corruption of the cache.
*/
slist = pg_analyze_and_rewrite(copyObject(plansource->raw_parse_tree),
plansource->query_string,
plansource->param_types,
plansource->num_params);
rawtree = copyObject(plansource->raw_parse_tree);
if (plansource->parserSetup != NULL)
slist = pg_analyze_and_rewrite_params(rawtree,
plansource->query_string,
plansource->parserSetup,
plansource->parserSetupArg);
else
slist = pg_analyze_and_rewrite(rawtree,
plansource->query_string,
plansource->param_types,
plansource->num_params);
if (plansource->fully_planned)
{