1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Fix caching of foreign-key-checking queries so that when a replan is needed,

we regenerate the SQL query text not merely the plan derived from it.  This
is needed to handle contingencies such as renaming of a table or column
used in an FK.  Pre-8.3, such cases worked despite the lack of replanning
(because the cached plan needn't actually change), so this is a regression.
Per bug #4417 from Benjamin Bihler.
This commit is contained in:
Tom Lane
2008-09-15 23:37:40 +00:00
parent 448950b37b
commit 1cd935609f
5 changed files with 103 additions and 7 deletions

View File

@ -15,7 +15,7 @@
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.109 2008/05/19 04:14:24 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.110 2008/09/15 23:37:39 tgl Exp $
*
* ----------
*/
@ -3615,6 +3615,7 @@ static SPIPlanPtr
ri_FetchPreparedPlan(RI_QueryKey *key)
{
RI_QueryHashEntry *entry;
SPIPlanPtr plan;
/*
* On the first call initialize the hashtable
@ -3630,7 +3631,30 @@ ri_FetchPreparedPlan(RI_QueryKey *key)
HASH_FIND, NULL);
if (entry == NULL)
return NULL;
return entry->plan;
/*
* Check whether the plan is still valid. If it isn't, we don't want
* to simply rely on plancache.c to regenerate it; rather we should
* start from scratch and rebuild the query text too. This is to cover
* cases such as table/column renames. We depend on the plancache
* machinery to detect possible invalidations, though.
*
* CAUTION: this check is only trustworthy if the caller has already
* locked both FK and PK rels.
*/
plan = entry->plan;
if (plan && SPI_plan_is_valid(plan))
return plan;
/*
* Otherwise we might as well flush the cached plan now, to free a
* little memory space before we make a new one.
*/
entry->plan = NULL;
if (plan)
SPI_freeplan(plan);
return NULL;
}
@ -3653,11 +3677,13 @@ ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
ri_InitHashTables();
/*
* Add the new plan.
* Add the new plan. We might be overwriting an entry previously
* found invalid by ri_FetchPreparedPlan.
*/
entry = (RI_QueryHashEntry *) hash_search(ri_query_cache,
(void *) key,
HASH_ENTER, &found);
Assert(!found || entry->plan == NULL);
entry->plan = plan;
}