diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-10-06 18:23:41 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-10-06 18:23:41 +0000 |
commit | a222a158b08205e89a5e291763c854277906fc8c (patch) | |
tree | d276cba652f98fd08ff7c1af0578ddeee3c39807 /src/backend/utils/cache/syscache.c | |
parent | 4af74cc00751d250d6f3c7b6f28b6f7daae07e1d (diff) | |
download | postgresql-a222a158b08205e89a5e291763c854277906fc8c.tar.gz postgresql-a222a158b08205e89a5e291763c854277906fc8c.zip |
Fix SysCacheGetAttr() to handle the case where the specified syscache has not
been initialized yet. This can happen because there are code paths that call
SysCacheGetAttr() on a tuple originally fetched from a different syscache
(hopefully on the same catalog) than the one specified in the call. It
doesn't seem useful or robust to try to prevent that from happening, so just
improve the function to cope instead. Per bug#2678 from Jeff Trout. The
specific example shown by Jeff is new in 8.1, but to be on the safe side
I'm backpatching 8.0 as well. We could patch 7.x similarly but I think
that's probably overkill, given the lack of evidence of old bugs of this ilk.
Diffstat (limited to 'src/backend/utils/cache/syscache.c')
-rw-r--r-- | src/backend/utils/cache/syscache.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 1ee237fafd9..ecac6f64b28 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.101 2005/10/15 02:49:32 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.101.2.1 2006/10/06 18:23:41 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -494,7 +494,7 @@ InitCatalogCachePhase2(void) Assert(CacheInitialized); for (cacheId = 0; cacheId < SysCacheSize; cacheId++) - InitCatCachePhase2(SysCache[cacheId]); + InitCatCachePhase2(SysCache[cacheId], true); } @@ -691,6 +691,9 @@ SearchSysCacheExistsAttName(Oid relid, const char *attname) * As with heap_getattr(), if the attribute is of a pass-by-reference type * then a pointer into the tuple data area is returned --- the caller must * not modify or pfree the datum! + * + * Note: it is legal to use SysCacheGetAttr() with a cacheId referencing + * a different cache for the same catalog the tuple was fetched from. */ Datum SysCacheGetAttr(int cacheId, HeapTuple tup, @@ -699,15 +702,18 @@ SysCacheGetAttr(int cacheId, HeapTuple tup, { /* * We just need to get the TupleDesc out of the cache entry, and then we - * can apply heap_getattr(). We expect that the cache control data is - * currently valid --- if the caller recently fetched the tuple, then it - * should be. + * can apply heap_getattr(). Normally the cache control data is already + * valid (because the caller recently fetched the tuple via this same + * cache), but there are cases where we have to initialize the cache here. */ - if (cacheId < 0 || cacheId >= SysCacheSize) + if (cacheId < 0 || cacheId >= SysCacheSize || + !PointerIsValid(SysCache[cacheId])) elog(ERROR, "invalid cache id: %d", cacheId); - if (!PointerIsValid(SysCache[cacheId]) || - !PointerIsValid(SysCache[cacheId]->cc_tupdesc)) - elog(ERROR, "missing cache data for cache id %d", cacheId); + if (!PointerIsValid(SysCache[cacheId]->cc_tupdesc)) + { + InitCatCachePhase2(SysCache[cacheId], false); + Assert(PointerIsValid(SysCache[cacheId]->cc_tupdesc)); + } return heap_getattr(tup, attributeNumber, SysCache[cacheId]->cc_tupdesc, |