diff options
Diffstat (limited to 'src/backend/utils/cache/typcache.c')
-rw-r--r-- | src/backend/utils/cache/typcache.c | 104 |
1 files changed, 79 insertions, 25 deletions
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index c3f0afa6853..fbeefad7457 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -36,7 +36,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.18 2006/03/05 15:58:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.19 2006/06/16 18:42:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -270,12 +270,16 @@ lookup_type_cache(Oid type_id, int flags) Assert(rel->rd_rel->reltype == typentry->type_id); /* - * Notice that we simply store a link to the relcache's tupdesc. Since - * we are relying on relcache to detect cache flush events, there's - * not a lot of point to maintaining an independent copy. + * Link to the tupdesc and increment its refcount (we assert it's + * a refcounted descriptor). We don't use IncrTupleDescRefCount() + * for this, because the reference mustn't be entered in the current + * resource owner; it can outlive the current query. */ typentry->tupDesc = RelationGetDescr(rel); + Assert(typentry->tupDesc->tdrefcount > 0); + typentry->tupDesc->tdrefcount++; + relation_close(rel, AccessShareLock); } @@ -283,29 +287,13 @@ lookup_type_cache(Oid type_id, int flags) } /* - * lookup_rowtype_tupdesc - * - * Given a typeid/typmod that should describe a known composite type, - * return the tuple descriptor for the type. Will ereport on failure. - * - * Note: returned TupleDesc points to cached copy; caller must copy it - * if intending to scribble on it or keep a reference for a long time. - */ -TupleDesc -lookup_rowtype_tupdesc(Oid type_id, int32 typmod) -{ - return lookup_rowtype_tupdesc_noerror(type_id, typmod, false); -} - -/* - * lookup_rowtype_tupdesc_noerror + * lookup_rowtype_tupdesc_internal --- internal routine to lookup a rowtype * - * As above, but if the type is not a known composite type and noError - * is true, returns NULL instead of ereport'ing. (Note that if a bogus - * type_id is passed, you'll get an ereport anyway.) + * Same API as lookup_rowtype_tupdesc_noerror, but the returned tupdesc + * hasn't had its refcount bumped. */ -TupleDesc -lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError) +static TupleDesc +lookup_rowtype_tupdesc_internal(Oid type_id, int32 typmod, bool noError) { if (type_id != RECORDOID) { @@ -339,6 +327,59 @@ lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError) } } +/* + * lookup_rowtype_tupdesc + * + * Given a typeid/typmod that should describe a known composite type, + * return the tuple descriptor for the type. Will ereport on failure. + * + * Note: on success, we increment the refcount of the returned TupleDesc, + * and log the reference in CurrentResourceOwner. Caller should call + * ReleaseTupleDesc or DecrTupleDescRefCount when done using the tupdesc. + */ +TupleDesc +lookup_rowtype_tupdesc(Oid type_id, int32 typmod) +{ + TupleDesc tupDesc; + + tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, false); + IncrTupleDescRefCount(tupDesc); + return tupDesc; +} + +/* + * lookup_rowtype_tupdesc_noerror + * + * As above, but if the type is not a known composite type and noError + * is true, returns NULL instead of ereport'ing. (Note that if a bogus + * type_id is passed, you'll get an ereport anyway.) + */ +TupleDesc +lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, bool noError) +{ + TupleDesc tupDesc; + + tupDesc = lookup_rowtype_tupdesc_internal(type_id, typmod, noError); + if (tupDesc != NULL) + IncrTupleDescRefCount(tupDesc); + return tupDesc; +} + +/* + * lookup_rowtype_tupdesc_copy + * + * Like lookup_rowtype_tupdesc(), but the returned TupleDesc has been + * copied into the CurrentMemoryContext and is not reference-counted. + */ +TupleDesc +lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod) +{ + TupleDesc tmp; + + tmp = lookup_rowtype_tupdesc_internal(type_id, typmod, false); + return CreateTupleDescCopyConstr(tmp); +} + /* * assign_record_type_typmod @@ -425,6 +466,8 @@ assign_record_type_typmod(TupleDesc tupDesc) /* if fail in subrs, no damage except possibly some wasted memory... */ entDesc = CreateTupleDescCopy(tupDesc); recentry->tupdescs = lcons(entDesc, recentry->tupdescs); + /* mark it as a reference-counted tupdesc */ + entDesc->tdrefcount = 1; /* now it's safe to advance NextRecordTypmod */ newtypmod = NextRecordTypmod++; entDesc->tdtypmod = newtypmod; @@ -456,6 +499,17 @@ flush_rowtype_cache(Oid type_id) HASH_FIND, NULL); if (typentry == NULL) return; /* no matching entry */ + if (typentry->tupDesc == NULL) + return; /* tupdesc hasn't been requested */ + + /* + * Release our refcount and free the tupdesc if none remain. + * (Can't use DecrTupleDescRefCount because this reference is not + * logged in current resource owner.) + */ + Assert(typentry->tupDesc->tdrefcount > 0); + if (--typentry->tupDesc->tdrefcount == 0) + FreeTupleDesc(typentry->tupDesc); typentry->tupDesc = NULL; } |