diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-15 23:12:07 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-03-15 23:12:07 +0000 |
commit | 95f6d2d20921b7c2dbec29bf2706fd9448208aa6 (patch) | |
tree | 21dcb36f9df60546d82d547a7855605be73a771c /src/backend/executor | |
parent | d3ff180163a0c88d7a05e0c865f649e5d8bcd6e1 (diff) | |
download | postgresql-95f6d2d20921b7c2dbec29bf2706fd9448208aa6.tar.gz postgresql-95f6d2d20921b7c2dbec29bf2706fd9448208aa6.zip |
Make use of plancache module for SPI plans. In particular, since plpgsql
uses SPI plans, this finally fixes the ancient gotcha that you can't
drop and recreate a temp table used by a plpgsql function.
Along the way, clean up SPI's API a little bit by declaring SPI plan
pointers as "SPIPlanPtr" instead of "void *". This is cosmetic but
helps to forestall simple programming mistakes. (I have changed some
but not all of the callers to match; there are still some "void *"'s
in contrib and the PL's. This is intentional so that we can see if
anyone's compiler complains about it.)
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/spi.c | 402 |
1 files changed, 282 insertions, 120 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index f538f508ba3..7a34add7105 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.171 2007/03/13 00:33:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.172 2007/03/15 23:12:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,9 +34,9 @@ static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */ static int _SPI_connected = -1; static int _SPI_curid = -1; -static void _SPI_prepare_plan(const char *src, _SPI_plan *plan); +static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan); -static int _SPI_execute_plan(_SPI_plan *plan, +static int _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, long tcount); @@ -48,7 +48,8 @@ static void _SPI_error_callback(void *arg); static void _SPI_cursor_operation(Portal portal, bool forward, long count, DestReceiver *dest); -static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location); +static SPIPlanPtr _SPI_copy_plan(SPIPlanPtr plan, MemoryContext parentcxt); +static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan); static int _SPI_begin_call(bool execmem); static int _SPI_end_call(bool procmem); @@ -306,10 +307,8 @@ SPI_execute(const char *src, bool read_only, long tcount) if (res < 0) return res; - plan.plancxt = NULL; /* doesn't have own context */ - plan.query = src; - plan.nargs = 0; - plan.argtypes = NULL; + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; _SPI_prepare_plan(src, &plan); @@ -330,22 +329,22 @@ SPI_exec(const char *src, long tcount) /* Execute a previously prepared plan */ int -SPI_execute_plan(void *plan, Datum *Values, const char *Nulls, +SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount) { int res; - if (plan == NULL || tcount < 0) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) return SPI_ERROR_ARGUMENT; - if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL) + if (plan->nargs > 0 && Values == NULL) return SPI_ERROR_PARAM; res = _SPI_begin_call(true); if (res < 0) return res; - res = _SPI_execute_plan((_SPI_plan *) plan, + res = _SPI_execute_plan(plan, Values, Nulls, InvalidSnapshot, InvalidSnapshot, read_only, tcount); @@ -356,7 +355,7 @@ SPI_execute_plan(void *plan, Datum *Values, const char *Nulls, /* Obsolete version of SPI_execute_plan */ int -SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount) +SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount) { return SPI_execute_plan(plan, Values, Nulls, false, tcount); } @@ -371,24 +370,24 @@ SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount) * fetching a new snapshot for each query. */ int -SPI_execute_snapshot(void *plan, +SPI_execute_snapshot(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, long tcount) { int res; - if (plan == NULL || tcount < 0) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0) return SPI_ERROR_ARGUMENT; - if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL) + if (plan->nargs > 0 && Values == NULL) return SPI_ERROR_PARAM; res = _SPI_begin_call(true); if (res < 0) return res; - res = _SPI_execute_plan((_SPI_plan *) plan, + res = _SPI_execute_plan(plan, Values, Nulls, snapshot, crosscheck_snapshot, read_only, tcount); @@ -397,11 +396,11 @@ SPI_execute_snapshot(void *plan, return res; } -void * +SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes) { _SPI_plan plan; - _SPI_plan *result; + SPIPlanPtr result; if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL)) { @@ -413,27 +412,28 @@ SPI_prepare(const char *src, int nargs, Oid *argtypes) if (SPI_result < 0) return NULL; - plan.plancxt = NULL; /* doesn't have own context */ - plan.query = src; + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; plan.nargs = nargs; plan.argtypes = argtypes; _SPI_prepare_plan(src, &plan); /* copy plan to procedure context */ - result = _SPI_copy_plan(&plan, _SPI_CPLAN_PROCXT); + result = _SPI_copy_plan(&plan, _SPI_current->procCxt); _SPI_end_call(true); - return (void *) result; + return result; } -void * -SPI_saveplan(void *plan) +SPIPlanPtr +SPI_saveplan(SPIPlanPtr plan) { - _SPI_plan *newplan; + SPIPlanPtr newplan; - if (plan == NULL) + /* We don't currently support copying an already-saved plan */ + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || plan->saved) { SPI_result = SPI_ERROR_ARGUMENT; return NULL; @@ -443,23 +443,36 @@ SPI_saveplan(void *plan) if (SPI_result < 0) return NULL; - newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT); + newplan = _SPI_save_plan(plan); _SPI_curid--; SPI_result = 0; - return (void *) newplan; + return newplan; } int -SPI_freeplan(void *plan) +SPI_freeplan(SPIPlanPtr plan) { - _SPI_plan *spiplan = (_SPI_plan *) plan; - - if (plan == NULL) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) return SPI_ERROR_ARGUMENT; - MemoryContextDelete(spiplan->plancxt); + /* If plancache.c owns the plancache entries, we must release them */ + if (plan->saved) + { + ListCell *lc; + + foreach(lc, plan->plancache_list) + { + CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); + + DropCachedPlan(plansource); + } + } + + /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */ + MemoryContextDelete(plan->plancxt); + return 0; } @@ -819,18 +832,18 @@ SPI_freetuptable(SPITupleTable *tuptable) } - /* * SPI_cursor_open() * * Open a prepared SPI plan as a portal */ Portal -SPI_cursor_open(const char *name, void *plan, +SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only) { - _SPI_plan *spiplan = (_SPI_plan *) plan; + CachedPlanSource *plansource; + CachedPlan *cplan; List *stmt_list; ParamListInfo paramLI; Snapshot snapshot; @@ -842,25 +855,23 @@ SPI_cursor_open(const char *name, void *plan, * Check that the plan is something the Portal code will special-case as * returning one tupleset. */ - if (!SPI_is_cursor_plan(spiplan)) + if (!SPI_is_cursor_plan(plan)) { /* try to give a good error message */ - Node *stmt; - - if (list_length(spiplan->stmt_list_list) != 1) + if (list_length(plan->plancache_list) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot open multi-query plan as cursor"))); - stmt = PortalListGetPrimaryStmt((List *) linitial(spiplan->stmt_list_list)); + plansource = (CachedPlanSource *) linitial(plan->plancache_list); ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), /* translator: %s is name of a SQL command, eg INSERT */ errmsg("cannot open %s query as cursor", - CreateCommandTag(stmt)))); + plansource->commandTag))); } - Assert(list_length(spiplan->stmt_list_list) == 1); - stmt_list = (List *) linitial(spiplan->stmt_list_list); + Assert(list_length(plan->plancache_list) == 1); + plansource = (CachedPlanSource *) linitial(plan->plancache_list); /* Reset SPI result (note we deliberately don't touch lastoid) */ SPI_processed = 0; @@ -880,23 +891,20 @@ SPI_cursor_open(const char *name, void *plan, portal = CreatePortal(name, false, false); } - /* Switch to portal's memory and copy the plans to there */ - oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); - stmt_list = copyObject(stmt_list); - - /* If the plan has parameters, set them up */ - if (spiplan->nargs > 0) + /* If the plan has parameters, copy them into the portal */ + if (plan->nargs > 0) { + oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + - (spiplan->nargs - 1) *sizeof(ParamExternData)); - paramLI->numParams = spiplan->nargs; + (plan->nargs - 1) *sizeof(ParamExternData)); + paramLI->numParams = plan->nargs; - for (k = 0; k < spiplan->nargs; k++) + for (k = 0; k < plan->nargs; k++) { ParamExternData *prm = ¶mLI->params[k]; - prm->ptype = spiplan->argtypes[k]; + prm->ptype = plan->argtypes[k]; prm->pflags = 0; prm->isnull = (Nulls && Nulls[k] == 'n'); if (prm->isnull) @@ -915,21 +923,35 @@ SPI_cursor_open(const char *name, void *plan, paramTypByVal, paramTypLen); } } + MemoryContextSwitchTo(oldcontext); } else paramLI = NULL; + if (plan->saved) + { + /* Replan if needed, and increment plan refcount for portal */ + cplan = RevalidateCachedPlan(plansource, false); + stmt_list = cplan->stmt_list; + } + else + { + /* No replan, but copy the plan into the portal's context */ + oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); + stmt_list = copyObject(plansource->plan->stmt_list); + MemoryContextSwitchTo(oldcontext); + cplan = NULL; /* portal shouldn't depend on cplan */ + } + /* * Set up the portal. */ PortalDefineQuery(portal, NULL, /* no statement name */ - spiplan->query, - CreateCommandTag(PortalListGetPrimaryStmt(stmt_list)), + plansource->query_string, + plansource->commandTag, stmt_list, - NULL); - - MemoryContextSwitchTo(oldcontext); + cplan); /* * Set up options for portal. @@ -1023,28 +1045,29 @@ SPI_cursor_close(Portal portal) * parameter is at index zero. */ Oid -SPI_getargtypeid(void *plan, int argIndex) +SPI_getargtypeid(SPIPlanPtr plan, int argIndex) { - if (plan == NULL || argIndex < 0 || argIndex >= ((_SPI_plan *) plan)->nargs) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || + argIndex < 0 || argIndex >= plan->nargs) { SPI_result = SPI_ERROR_ARGUMENT; return InvalidOid; } - return ((_SPI_plan *) plan)->argtypes[argIndex]; + return plan->argtypes[argIndex]; } /* * Returns the number of arguments for the prepared plan. */ int -SPI_getargcount(void *plan) +SPI_getargcount(SPIPlanPtr plan) { - if (plan == NULL) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) { SPI_result = SPI_ERROR_ARGUMENT; return -1; } - return ((_SPI_plan *) plan)->nargs; + return plan->nargs; } /* @@ -1057,31 +1080,32 @@ SPI_getargcount(void *plan) * plan: A plan previously prepared using SPI_prepare */ bool -SPI_is_cursor_plan(void *plan) +SPI_is_cursor_plan(SPIPlanPtr plan) { - _SPI_plan *spiplan = (_SPI_plan *) plan; + CachedPlanSource *plansource; + CachedPlan *cplan; - if (spiplan == NULL) + if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC) { SPI_result = SPI_ERROR_ARGUMENT; return false; } - if (list_length(spiplan->stmt_list_list) != 1) + if (list_length(plan->plancache_list) != 1) return false; /* not exactly 1 pre-rewrite command */ + plansource = (CachedPlanSource *) linitial(plan->plancache_list); - switch (ChoosePortalStrategy((List *) linitial(spiplan->stmt_list_list))) + if (plan->saved) { - case PORTAL_ONE_SELECT: - case PORTAL_ONE_RETURNING: - case PORTAL_UTIL_SELECT: - /* OK */ - return true; - - case PORTAL_MULTI_QUERY: - /* will not return tuples */ - break; + /* Make sure the plan is up to date */ + cplan = RevalidateCachedPlan(plansource, true); + ReleaseCachedPlan(cplan, true); } + + /* Does it return tuples? */ + if (plansource->resultDesc) + return true; + return false; } @@ -1248,13 +1272,15 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) * * At entry, plan->argtypes and plan->nargs must be valid. * - * Result lists are stored into *plan. + * Results are stored into *plan (specifically, plan->plancache_list). + * Note however that the result trees are all in CurrentMemoryContext + * and need to be copied somewhere to survive. */ static void -_SPI_prepare_plan(const char *src, _SPI_plan *plan) +_SPI_prepare_plan(const char *src, SPIPlanPtr plan) { List *raw_parsetree_list; - List *stmt_list_list; + List *plancache_list; ListCell *list_item; ErrorContextCallback spierrcontext; Oid *argtypes = plan->argtypes; @@ -1282,26 +1308,44 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan) raw_parsetree_list = pg_parse_query(src); /* - * Do parse analysis and rule rewrite for each raw parsetree. - * - * We save the results from each raw parsetree as a separate sublist. - * This allows _SPI_execute_plan() to know where the boundaries between - * original queries fall. + * Do parse analysis and rule rewrite for each raw parsetree, then + * cons up a phony plancache entry for each one. */ - stmt_list_list = NIL; + plancache_list = NIL; foreach(list_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(list_item); - List *query_list; - - query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs); - - stmt_list_list = lappend(stmt_list_list, - pg_plan_queries(query_list, NULL, false)); + List *stmt_list; + CachedPlanSource *plansource; + CachedPlan *cplan; + + /* Need a copyObject here to keep parser from modifying raw tree */ + stmt_list = pg_analyze_and_rewrite(copyObject(parsetree), + src, argtypes, nargs); + stmt_list = pg_plan_queries(stmt_list, NULL, false); + + plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); + cplan = (CachedPlan *) palloc0(sizeof(CachedPlan)); + + plansource->raw_parse_tree = parsetree; + /* cast-away-const here is a bit ugly, but there's no reason to copy */ + plansource->query_string = (char *) src; + plansource->commandTag = CreateCommandTag(parsetree); + plansource->param_types = argtypes; + plansource->num_params = nargs; + plansource->fully_planned = true; + plansource->fixed_result = false; + plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list); + plansource->plan = cplan; + + cplan->stmt_list = stmt_list; + cplan->fully_planned = true; + + plancache_list = lappend(plancache_list, plansource); } - plan->stmt_list_list = stmt_list_list; + plan->plancache_list = plancache_list; /* * Pop the error context stack @@ -1319,7 +1363,7 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan) * tcount: execution tuple-count limit, or 0 for none */ static int -_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, +_SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, long tcount) { @@ -1334,10 +1378,11 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, saveActiveSnapshot = ActiveSnapshot; PG_TRY(); { - ListCell *stmt_list_list_item; + ListCell *lc1; ErrorContextCallback spierrcontext; int nargs = plan->nargs; ParamListInfo paramLI; + CachedPlan *cplan = NULL; /* Convert parameters to form wanted by executor */ if (nargs > 0) @@ -1366,18 +1411,34 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, * Setup error traceback support for ereport() */ spierrcontext.callback = _SPI_error_callback; - spierrcontext.arg = (void *) plan->query; + spierrcontext.arg = NULL; spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; - foreach(stmt_list_list_item, plan->stmt_list_list) + foreach(lc1, plan->plancache_list) { - List *stmt_list = (List *) lfirst(stmt_list_list_item); - ListCell *stmt_list_item; + CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1); + List *stmt_list; + ListCell *lc2; - foreach(stmt_list_item, stmt_list) + spierrcontext.arg = (void *) plansource->query_string; + + if (plan->saved) { - Node *stmt = (Node *) lfirst(stmt_list_item); + /* Replan if needed, and increment plan refcount locally */ + cplan = RevalidateCachedPlan(plansource, true); + stmt_list = cplan->stmt_list; + } + else + { + /* No replan here */ + cplan = NULL; + stmt_list = plansource->plan->stmt_list; + } + + foreach(lc2, stmt_list) + { + Node *stmt = (Node *) lfirst(lc2); bool canSetTag; QueryDesc *qdesc; DestReceiver *dest; @@ -1510,10 +1571,19 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls, goto fail; } } + + /* Done with this plan, so release refcount */ + if (cplan) + ReleaseCachedPlan(cplan, true); + cplan = NULL; } fail: + /* We no longer need the cached plan refcount, if any */ + if (cplan) + ReleaseCachedPlan(cplan, true); + /* * Pop the error context stack */ @@ -1772,22 +1842,18 @@ _SPI_checktuples(void) return failed; } -static _SPI_plan * -_SPI_copy_plan(_SPI_plan *plan, int location) +/* + * Make an "unsaved" copy of the given plan, in a child context of parentcxt. + */ +static SPIPlanPtr +_SPI_copy_plan(SPIPlanPtr plan, MemoryContext parentcxt) { - _SPI_plan *newplan; - MemoryContext oldcxt; + SPIPlanPtr newplan; MemoryContext plancxt; - MemoryContext parentcxt; + MemoryContext oldcxt; + ListCell *lc; - /* Determine correct parent for the plan's memory context */ - if (location == _SPI_CPLAN_PROCXT) - parentcxt = _SPI_current->procCxt; - else if (location == _SPI_CPLAN_TOPCXT) - parentcxt = TopMemoryContext; - else - /* (this case not currently used) */ - parentcxt = CurrentMemoryContext; + Assert(!plan->saved); /* not currently supported */ /* * Create a memory context for the plan. We don't expect the plan to be @@ -1801,10 +1867,11 @@ _SPI_copy_plan(_SPI_plan *plan, int location) oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI plan into its own context */ - newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan)); + newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan)); + newplan->magic = _SPI_PLAN_MAGIC; + newplan->saved = false; + newplan->plancache_list = NIL; newplan->plancxt = plancxt; - newplan->query = pstrdup(plan->query); - newplan->stmt_list_list = (List *) copyObject(plan->stmt_list_list); newplan->nargs = plan->nargs; if (plan->nargs > 0) { @@ -1814,6 +1881,101 @@ _SPI_copy_plan(_SPI_plan *plan, int location) else newplan->argtypes = NULL; + foreach(lc, plan->plancache_list) + { + CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); + CachedPlanSource *newsource; + CachedPlan *cplan; + CachedPlan *newcplan; + + /* Note: we assume we don't need to revalidate the plan */ + cplan = plansource->plan; + + newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); + newcplan = (CachedPlan *) palloc0(sizeof(CachedPlan)); + + newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree); + newsource->query_string = pstrdup(plansource->query_string); + newsource->commandTag = plansource->commandTag; + newsource->param_types = newplan->argtypes; + newsource->num_params = newplan->nargs; + newsource->fully_planned = plansource->fully_planned; + newsource->fixed_result = plansource->fixed_result; + if (plansource->resultDesc) + newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc); + newsource->plan = newcplan; + + newcplan->stmt_list = copyObject(cplan->stmt_list); + newcplan->fully_planned = cplan->fully_planned; + + newplan->plancache_list = lappend(newplan->plancache_list, newsource); + } + + MemoryContextSwitchTo(oldcxt); + + return newplan; +} + +/* + * Make a "saved" copy of the given plan, entrusting everything to plancache.c + */ +static SPIPlanPtr +_SPI_save_plan(SPIPlanPtr plan) +{ + SPIPlanPtr newplan; + MemoryContext plancxt; + MemoryContext oldcxt; + ListCell *lc; + + Assert(!plan->saved); /* not currently supported */ + + /* + * Create a memory context for the plan. We don't expect the plan to be + * very large, so use smaller-than-default alloc parameters. + */ + plancxt = AllocSetContextCreate(CacheMemoryContext, + "SPI Plan", + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); + oldcxt = MemoryContextSwitchTo(plancxt); + + /* Copy the SPI plan into its own context */ + newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan)); + newplan->magic = _SPI_PLAN_MAGIC; + newplan->saved = true; + newplan->plancache_list = NIL; + newplan->plancxt = plancxt; + newplan->nargs = plan->nargs; + if (plan->nargs > 0) + { + newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid)); + memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid)); + } + else + newplan->argtypes = NULL; + + foreach(lc, plan->plancache_list) + { + CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); + CachedPlanSource *newsource; + CachedPlan *cplan; + + /* Note: we assume we don't need to revalidate the plan */ + cplan = plansource->plan; + + newsource = CreateCachedPlan(plansource->raw_parse_tree, + plansource->query_string, + plansource->commandTag, + newplan->argtypes, + newplan->nargs, + cplan->stmt_list, + true, + false); + + newplan->plancache_list = lappend(newplan->plancache_list, newsource); + } + MemoryContextSwitchTo(oldcxt); return newplan; |