typcache.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 532 行 · 第 1/2 页
C
532 行
/*------------------------------------------------------------------------- * * typcache.c * POSTGRES type cache code * * The type cache exists to speed lookup of certain information about data * types that is not directly available from a type's pg_type row. In * particular, we use a type's default btree opclass, or the default hash * opclass if no btree opclass exists, to determine which operators should * be used for grouping and sorting the type (GROUP BY, ORDER BY ASC/DESC). * * Several seemingly-odd choices have been made to support use of the type * cache by the generic array comparison routines array_eq() and array_cmp(). * Because these routines are used as index support operations, they cannot * leak memory. To allow them to execute efficiently, all information that * either of them would like to re-use across calls is made available in the * type cache. * * Once created, a type cache entry lives as long as the backend does, so * there is no need for a call to release a cache entry. (For present uses, * it would be okay to flush type cache entries at the ends of transactions, * if we needed to reclaim space.) * * There is presently no provision for clearing out a cache entry if the * stored data becomes obsolete. (The code will work if a type acquires * opclasses it didn't have before while a backend runs --- but not if the * definition of an existing opclass is altered.) However, the relcache * doesn't cope with opclasses changing under it, either, so this seems * a low-priority problem. * * We do support clearing the tuple descriptor part of a rowtype's cache * entry, since that may need to change as a consequence of ALTER TABLE. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.27 2008/01/01 19:45:53 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/hash.h"#include "access/heapam.h"#include "access/nbtree.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#include "utils/typcache.h"/* The main type cache hashtable searched by lookup_type_cache */static HTAB *TypeCacheHash = NULL;/* * We use a separate table for storing the definitions of non-anonymous * record types. Once defined, a record type will be remembered for the * life of the backend. Subsequent uses of the "same" record type (where * sameness means equalTupleDescs) will refer to the existing table entry. * * Stored record types are remembered in a linear array of TupleDescs, * which can be indexed quickly with the assigned typmod. There is also * a hash table to speed searches for matching TupleDescs. The hash key * uses just the first N columns' type OIDs, and so we may have multiple * entries with the same hash key. */#define REC_HASH_KEYS 16 /* use this many columns in hash key */typedef struct RecordCacheEntry{ /* the hash lookup key MUST BE FIRST */ Oid hashkey[REC_HASH_KEYS]; /* column type IDs, zero-filled */ /* list of TupleDescs for record types with this hashkey */ List *tupdescs;} RecordCacheEntry;static HTAB *RecordCacheHash = NULL;static TupleDesc *RecordCacheArray = NULL;static int32 RecordCacheArrayLen = 0; /* allocated length of array */static int32 NextRecordTypmod = 0; /* number of entries used *//* * lookup_type_cache * * Fetch the type cache entry for the specified datatype, and make sure that * all the fields requested by bits in 'flags' are valid. * * The result is never NULL --- we will elog() if the passed type OID is * invalid. Note however that we may fail to find one or more of the * requested opclass-dependent fields; the caller needs to check whether * the fields are InvalidOid or not. */TypeCacheEntry *lookup_type_cache(Oid type_id, int flags){ TypeCacheEntry *typentry; bool found; if (TypeCacheHash == NULL) { /* First time through: initialize the hash table */ HASHCTL ctl; if (!CacheMemoryContext) CreateCacheMemoryContext(); MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(TypeCacheEntry); ctl.hash = oid_hash; TypeCacheHash = hash_create("Type information cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); } /* Try to look up an existing entry */ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, (void *) &type_id, HASH_FIND, NULL); if (typentry == NULL) { /* * If we didn't find one, we want to make one. But first look up the * pg_type row, just to make sure we don't make a cache entry for an * invalid type OID. */ HeapTuple tp; Form_pg_type typtup; tp = SearchSysCache(TYPEOID, ObjectIdGetDatum(type_id), 0, 0, 0); if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for type %u", type_id); typtup = (Form_pg_type) GETSTRUCT(tp); if (!typtup->typisdefined) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" is only a shell", NameStr(typtup->typname)))); /* Now make the typcache entry */ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash, (void *) &type_id, HASH_ENTER, &found); Assert(!found); /* it wasn't there a moment ago */ MemSet(typentry, 0, sizeof(TypeCacheEntry)); typentry->type_id = type_id; typentry->typlen = typtup->typlen; typentry->typbyval = typtup->typbyval; typentry->typalign = typtup->typalign; typentry->typtype = typtup->typtype; typentry->typrelid = typtup->typrelid; ReleaseSysCache(tp); } /* If we haven't already found the opclass, try to do so */ if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | TYPECACHE_CMP_PROC | TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO | TYPECACHE_BTREE_OPFAMILY)) && typentry->btree_opf == InvalidOid) { Oid opclass; opclass = GetDefaultOpClass(type_id, BTREE_AM_OID); if (OidIsValid(opclass)) { typentry->btree_opf = get_opclass_family(opclass); typentry->btree_opintype = get_opclass_input_type(opclass); } /* Only care about hash opclass if no btree opclass... */ if (typentry->btree_opf == InvalidOid) { if (typentry->hash_opf == InvalidOid) { opclass = GetDefaultOpClass(type_id, HASH_AM_OID); if (OidIsValid(opclass)) { typentry->hash_opf = get_opclass_family(opclass); typentry->hash_opintype = get_opclass_input_type(opclass); } } } else { /* * If we find a btree opclass where previously we only found a * hash opclass, forget the hash equality operator so we can use * the btree operator instead. */ typentry->eq_opr = InvalidOid; typentry->eq_opr_finfo.fn_oid = InvalidOid; } } /* Look for requested operators and functions */ if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) && typentry->eq_opr == InvalidOid) { if (typentry->btree_opf != InvalidOid) typentry->eq_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTEqualStrategyNumber); if (typentry->eq_opr == InvalidOid && typentry->hash_opf != InvalidOid) typentry->eq_opr = get_opfamily_member(typentry->hash_opf, typentry->hash_opintype, typentry->hash_opintype, HTEqualStrategyNumber); } if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid) { if (typentry->btree_opf != InvalidOid) typentry->lt_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTLessStrategyNumber); } if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid) { if (typentry->btree_opf != InvalidOid) typentry->gt_opr = get_opfamily_member(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTGreaterStrategyNumber); } if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) && typentry->cmp_proc == InvalidOid) { if (typentry->btree_opf != InvalidOid) typentry->cmp_proc = get_opfamily_proc(typentry->btree_opf, typentry->btree_opintype, typentry->btree_opintype, BTORDER_PROC); } /* * Set up fmgr lookup info as requested * * Note: we tell fmgr the finfo structures live in CacheMemoryContext, * which is not quite right (they're really in DynaHashContext) but this * will do for our purposes. */ if ((flags & TYPECACHE_EQ_OPR_FINFO) && typentry->eq_opr_finfo.fn_oid == InvalidOid && typentry->eq_opr != InvalidOid) { Oid eq_opr_func; eq_opr_func = get_opcode(typentry->eq_opr); if (eq_opr_func != InvalidOid) fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo, CacheMemoryContext); } if ((flags & TYPECACHE_CMP_PROC_FINFO) && typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?