88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.61 2000/02/18 09:28:53 inoue Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.62 2000/02/21 03:36:49 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
16+
1617#include "access/genam.h"
18+ #include "access/hash.h"
1719#include "access/heapam.h"
1820#include "access/valid.h"
1921#include "catalog/pg_operator.h"
2830static void CatCacheRemoveCTup (CatCache * cache ,Dlelem * e );
2931static Index CatalogCacheComputeHashIndex (struct catcache * cacheInP );
3032static Index CatalogCacheComputeTupleHashIndex (struct catcache * cacheInOutP ,
31- Relation relation ,HeapTuple tuple );
33+ Relation relation ,
34+ HeapTuple tuple );
3235static void CatalogCacheInitializeCache (struct catcache * cache ,
33- Relation relation );
34- static long comphash ( long l , char * v );
36+ Relation relation );
37+ static uint32 cc_hashname ( NameData * n );
3538
3639/* ----------------
3740 *variables, macros and other stuff
@@ -63,14 +66,15 @@ GlobalMemory CacheCxt;/* context in which caches are allocated */
6366/* ----------------
6467 *EQPROC is used in CatalogCacheInitializeCache to find the equality
6568 *functions for system types that are used as cache key fields.
69+ *See also GetCCHashFunc, which should support the same set of types.
6670 *
6771 *XXX this should be replaced by catalog lookups,
6872 *but that seems to pose considerable risk of circularity...
6973 * ----------------
7074 */
7175static const Oid eqproc []= {
7276F_BOOLEQ ,InvalidOid ,F_CHAREQ ,F_NAMEEQ ,InvalidOid ,
73- F_INT2EQ ,F_KEYFIRSTEQ ,F_INT4EQ ,F_OIDEQ ,F_TEXTEQ ,
77+ F_INT2EQ ,F_INT2VECTOREQ ,F_INT4EQ ,F_OIDEQ ,F_TEXTEQ ,
7478F_OIDEQ ,InvalidOid ,InvalidOid ,InvalidOid ,F_OIDVECTOREQ
7579};
7680
@@ -80,6 +84,54 @@ static const Oid eqproc[] = {
8084 *internal support functions
8185 * ----------------------------------------------------------------
8286 */
87+
88+ static CCHashFunc
89+ GetCCHashFunc (Oid keytype )
90+ {
91+ switch (keytype )
92+ {
93+ case BOOLOID :
94+ case CHAROID :
95+ return (CCHashFunc )hashchar ;
96+ case NAMEOID :
97+ return (CCHashFunc )cc_hashname ;
98+ case INT2OID :
99+ return (CCHashFunc )hashint2 ;
100+ case INT2VECTOROID :
101+ return (CCHashFunc )hashint2vector ;
102+ case INT4OID :
103+ return (CCHashFunc )hashint4 ;
104+ case TEXTOID :
105+ return (CCHashFunc )hashtext ;
106+ case REGPROCOID :
107+ case OIDOID :
108+ return (CCHashFunc )hashoid ;
109+ case OIDVECTOROID :
110+ return (CCHashFunc )hashoidvector ;
111+ default :
112+ elog (FATAL ,"GetCCHashFunc: type %u unsupported as catcache key" ,
113+ keytype );
114+ return NULL ;
115+ }
116+ }
117+
118+ static uint32
119+ cc_hashname (NameData * n )
120+ {
121+ /*
122+ * We need our own variant of hashname because we want to accept
123+ * null-terminated C strings as search values for name fields.
124+ * So, we have to make sure the data is correctly padded before
125+ * we compute the hash value.
126+ */
127+ NameData my_n ;
128+
129+ namestrcpy (& my_n ,NameStr (* n ));
130+
131+ return hashname (& my_n );
132+ }
133+
134+
83135/* --------------------------------
84136 *CatalogCacheInitializeCache
85137 * --------------------------------
@@ -190,31 +242,20 @@ CatalogCacheInitializeCache(struct catcache * cache,
190242
191243if (cache -> cc_key [i ]> 0 )
192244{
245+ Oid keytype = tupdesc -> attrs [cache -> cc_key [i ]- 1 ]-> atttypid ;
193246
194- /*
195- * Yoiks. The implementation of the hashing code and the
196- * implementation of int2vector's are at loggerheads. The right
197- * thing to do is to throw out the implementation of int2vector's
198- * altogether; until that happens, we do the right thing here
199- * to guarantee that the hash key generator doesn't try to
200- * dereference an int2 by mistake.
201- */
247+ cache -> cc_hashfunc [i ]= GetCCHashFunc (keytype );
202248
203- if (tupdesc -> attrs [cache -> cc_key [i ]- 1 ]-> atttypid == INT2VECTOROID )
204- cache -> cc_klen [i ]= sizeof (short );
205- else
206- cache -> cc_klen [i ]= tupdesc -> attrs [cache -> cc_key [i ]- 1 ]-> attlen ;
207-
208- cache -> cc_skey [i ].sk_procedure = EQPROC (tupdesc -> attrs [cache -> cc_key [i ]- 1 ]-> atttypid );
249+ /* If GetCCHashFunc liked the type, safe to index into eqproc[] */
250+ cache -> cc_skey [i ].sk_procedure = EQPROC (keytype );
209251
210252fmgr_info (cache -> cc_skey [i ].sk_procedure ,
211253& cache -> cc_skey [i ].sk_func );
212254cache -> cc_skey [i ].sk_nargs = cache -> cc_skey [i ].sk_func .fn_nargs ;
213255
214- CACHE5_elog (DEBUG ,"CatalogCacheInit %s %d %d %x" ,
256+ CACHE4_elog (DEBUG ,"CatalogCacheInit %s %d %x" ,
215257RelationGetRelationName (relation ),
216258i ,
217- tupdesc -> attrs [cache -> cc_key [i ]- 1 ]-> attlen ,
218259cache );
219260}
220261}
@@ -255,94 +296,44 @@ CatalogCacheInitializeCache(struct catcache * cache,
255296MemoryContextSwitchTo (oldcxt );
256297}
257298
258- /* ----------------
259- * comphash
260- *Compute a hash value, somehow.
261- *
262- * XXX explain algorithm here.
263- *
264- * l is length of the attribute value, v
265- * v is the attribute value ("Datum")
266- * ----------------
267- */
268- static long
269- comphash (long l ,char * v )
270- {
271- long i ;
272- NameData n ;
273-
274- CACHE3_elog (DEBUG ,"comphash (%d,%x)" ,l ,v );
275-
276- switch (l )
277- {
278- case 1 :
279- case 2 :
280- case 4 :
281- return (long )v ;
282- }
283-
284- if (l == NAMEDATALEN )
285- {
286-
287- /*
288- * if it's a name, make sure that the values are null-padded.
289- *
290- * Note that this other fixed-length types can also have the same
291- * typelen so this may break them - XXX
292- */
293- namestrcpy (& n ,v );
294- v = NameStr (n );
295- }
296- else if (l < 0 )
297- l = VARSIZE (v );
298-
299- i = 0 ;
300- while (l -- )
301- i += * v ++ ;
302- return i ;
303- }
304-
305299/* --------------------------------
306300 *CatalogCacheComputeHashIndex
307301 * --------------------------------
308302 */
309303static Index
310304CatalogCacheComputeHashIndex (struct catcache * cacheInP )
311305{
312- Index hashIndex ;
306+ uint32 hashIndex = 0 ;
313307
314- hashIndex = 0x0 ;
315- CACHE6_elog (DEBUG ,"CatalogCacheComputeHashIndex %s %d %d %d %x" ,
308+ CACHE4_elog (DEBUG ,"CatalogCacheComputeHashIndex %s %d %x" ,
316309cacheInP -> cc_relname ,
317310cacheInP -> cc_nkeys ,
318- cacheInP -> cc_klen [0 ],
319- cacheInP -> cc_klen [1 ],
320311cacheInP );
321312
322313switch (cacheInP -> cc_nkeys )
323314{
324315case 4 :
325- hashIndex ^=comphash ( cacheInP -> cc_klen [ 3 ],
326- ( char * ) cacheInP -> cc_skey [3 ].sk_argument ) <<9 ;
316+ hashIndex ^=
317+ ( * cacheInP -> cc_hashfunc [ 3 ])( cacheInP -> cc_skey [3 ].sk_argument ) <<9 ;
327318/* FALLTHROUGH */
328319case 3 :
329- hashIndex ^=comphash ( cacheInP -> cc_klen [ 2 ],
330- ( char * ) cacheInP -> cc_skey [2 ].sk_argument ) <<6 ;
320+ hashIndex ^=
321+ ( * cacheInP -> cc_hashfunc [ 2 ])( cacheInP -> cc_skey [2 ].sk_argument ) <<6 ;
331322/* FALLTHROUGH */
332323case 2 :
333- hashIndex ^=comphash ( cacheInP -> cc_klen [ 1 ],
334- ( char * ) cacheInP -> cc_skey [1 ].sk_argument ) <<3 ;
324+ hashIndex ^=
325+ ( * cacheInP -> cc_hashfunc [ 1 ])( cacheInP -> cc_skey [1 ].sk_argument ) <<3 ;
335326/* FALLTHROUGH */
336327case 1 :
337- hashIndex ^=comphash ( cacheInP -> cc_klen [ 0 ],
338- ( char * ) cacheInP -> cc_skey [0 ].sk_argument );
328+ hashIndex ^=
329+ ( * cacheInP -> cc_hashfunc [ 0 ])( cacheInP -> cc_skey [0 ].sk_argument );
339330break ;
340331default :
341332elog (FATAL ,"CCComputeHashIndex: %d cc_nkeys" ,cacheInP -> cc_nkeys );
342333break ;
343334}
344- hashIndex %=cacheInP -> cc_size ;
345- return hashIndex ;
335+ hashIndex %=( uint32 ) cacheInP -> cc_size ;
336+ return ( Index ) hashIndex ;
346337}
347338
348339/* --------------------------------
@@ -645,8 +636,8 @@ do { \
645636cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
646637for (i = 0; i < nkeys; i += 1) \
647638{ \
648- elog(DEBUG, "InitSysCache: key=%dlen=%d skey=[%d %d %d %d]\n", \
649- cp->cc_key[i],cp->cc_klen[i], \
639+ elog(DEBUG, "InitSysCache: key=%d skey=[%d %d %d %d]\n", \
640+ cp->cc_key[i], \
650641 cp->cc_skey[i].sk_flags, \
651642 cp->cc_skey[i].sk_attno, \
652643 cp->cc_skey[i].sk_procedure, \
@@ -742,7 +733,8 @@ InitSysCache(char *relname,
742733cp -> cc_iscanfunc = iScanfuncP ;
743734
744735/* ----------------
745- *initialize the cache's key information
736+ *partially initialize the cache's key information
737+ *CatalogCacheInitializeCache() will do the rest
746738 * ----------------
747739 */
748740for (i = 0 ;i < nkeys ;++ i )
@@ -756,15 +748,7 @@ InitSysCache(char *relname,
756748elog (FATAL ,"InitSysCache: called with %d key[%d]" ,key [i ],i );
757749else
758750{
759- cp -> cc_klen [i ]= sizeof (Oid );
760-
761- /*
762- * ScanKeyEntryData and struct skey are equivalent. It
763- * looks like a move was made to obsolete struct skey, but
764- * it didn't reach this file. Someday we should clean up
765- * this code and consolidate to ScanKeyEntry - mer 10 Nov
766- * 1991
767- */
751+ cp -> cc_hashfunc [i ]= GetCCHashFunc (OIDOID );
768752ScanKeyEntryInitialize (& cp -> cc_skey [i ],
769753 (bits16 )0 ,
770754 (AttrNumber )key [i ],