2323#include "utils/lsyscache.h"
2424#include "utils/memutils.h"
2525
26+ static uint32 TupleHashTableHash (struct tuplehash_hash * tb ,const MinimalTuple tuple );
27+ static int TupleHashTableMatch (struct tuplehash_hash * tb ,const MinimalTuple tuple1 ,const MinimalTuple tuple2 );
2628
27- static TupleHashTable CurTupleHashTable = NULL ;
28-
29- static uint32 TupleHashTableHash (const void * key ,Size keysize );
30- static int TupleHashTableMatch (const void * key1 ,const void * key2 ,
31- Size keysize );
29+ /*
30+ * Define parameters for tuple hash table code generation. The interface is
31+ * *also* declared in execnodes.h (to generate the types, which are externally
32+ * visible).
33+ */
34+ #define SH_PREFIX tuplehash
35+ #define SH_ELEMENT_TYPE TupleHashEntryData
36+ #define SH_KEY_TYPE MinimalTuple
37+ #define SH_KEY firstTuple
38+ #define SH_HASH_KEY (tb ,key ) TupleHashTableHash(tb, key)
39+ #define SH_EQUAL (tb ,a ,b ) TupleHashTableMatch(tb, a, b) == 0
40+ #define SH_SCOPE extern
41+ #define SH_STORE_HASH
42+ #define SH_GET_HASH (tb ,a ) a->hash
43+ #define SH_DEFINE
44+ #include "lib/simplehash.h"
3245
3346
3447/*****************************************************************************
@@ -260,7 +273,7 @@ execTuplesHashPrepare(int numCols,
260273 *eqfunctions: equality comparison functions to use
261274 *hashfunctions: datatype-specific hashing functions to use
262275 *nbuckets: initial estimate of hashtable size
263- *entrysize : size ofeach entry (at least sizeof(TupleHashEntryData))
276+ *additionalsize : size ofdata stored in ->additional
264277 *tablecxt: memory context in which to store table and table entries
265278 *tempcxt: short-lived context for evaluation hash and comparison functions
266279 *
@@ -275,20 +288,19 @@ TupleHashTable
275288BuildTupleHashTable (int numCols ,AttrNumber * keyColIdx ,
276289FmgrInfo * eqfunctions ,
277290FmgrInfo * hashfunctions ,
278- long nbuckets ,Size entrysize ,
291+ long nbuckets ,Size additionalsize ,
279292MemoryContext tablecxt ,MemoryContext tempcxt )
280293{
281294TupleHashTable hashtable ;
282- HASHCTL hash_ctl ;
295+ Size entrysize = sizeof ( TupleHashEntryData ) + additionalsize ;
283296
284297Assert (nbuckets > 0 );
285- Assert (entrysize >=sizeof (TupleHashEntryData ));
286298
287299/* Limit initial table size request to not more than work_mem */
288300nbuckets = Min (nbuckets , (long ) ((work_mem * 1024L ) /entrysize ));
289301
290- hashtable = (TupleHashTable )MemoryContextAlloc ( tablecxt ,
291- sizeof (TupleHashTableData ));
302+ hashtable = (TupleHashTable )
303+ MemoryContextAlloc ( tablecxt , sizeof (TupleHashTableData ));
292304
293305hashtable -> numCols = numCols ;
294306hashtable -> keyColIdx = keyColIdx ;
@@ -302,15 +314,8 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
302314hashtable -> in_hash_funcs = NULL ;
303315hashtable -> cur_eq_funcs = NULL ;
304316
305- MemSet (& hash_ctl ,0 ,sizeof (hash_ctl ));
306- hash_ctl .keysize = sizeof (TupleHashEntryData );
307- hash_ctl .entrysize = entrysize ;
308- hash_ctl .hash = TupleHashTableHash ;
309- hash_ctl .match = TupleHashTableMatch ;
310- hash_ctl .hcxt = tablecxt ;
311- hashtable -> hashtab = hash_create ("TupleHashTable" ,nbuckets ,
312- & hash_ctl ,
313- HASH_ELEM |HASH_FUNCTION |HASH_COMPARE |HASH_CONTEXT );
317+ hashtable -> hashtab = tuplehash_create (tablecxt ,nbuckets );
318+ hashtable -> hashtab -> private = hashtable ;
314319
315320return hashtable ;
316321}
@@ -324,18 +329,17 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
324329 *
325330 * If isnew isn't NULL, then a new entry is created if no existing entry
326331 * matches. On return, *isnew is true if the entry is newly created,
327- * false if it existed already.Any extra space ina new entry has been
328- * zeroed.
332+ * false if it existed already.->additional_data inthe new entry has
333+ *been zeroed.
329334 */
330335TupleHashEntry
331336LookupTupleHashEntry (TupleHashTable hashtable ,TupleTableSlot * slot ,
332337bool * isnew )
333338{
334- TupleHashEntry entry ;
339+ TupleHashEntryData * entry ;
335340MemoryContext oldContext ;
336- TupleHashTable saveCurHT ;
337- TupleHashEntryData dummy ;
338341bool found ;
342+ MinimalTuple key ;
339343
340344/* If first time through, clone the input slot to make table slot */
341345if (hashtable -> tableslot == NULL )
@@ -356,53 +360,37 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
356360/* Need to run the hash functions in short-lived context */
357361oldContext = MemoryContextSwitchTo (hashtable -> tempcxt );
358362
359- /*
360- * Set up data needed by hash and match functions
361- *
362- * We save and restore CurTupleHashTable just in case someone manages to
363- * invoke this code re-entrantly.
364- */
363+ /* set up data needed by hash and match functions */
365364hashtable -> inputslot = slot ;
366365hashtable -> in_hash_funcs = hashtable -> tab_hash_funcs ;
367366hashtable -> cur_eq_funcs = hashtable -> tab_eq_funcs ;
368367
369- saveCurHT = CurTupleHashTable ;
370- CurTupleHashTable = hashtable ;
371-
372- /* Search the hash table */
373- dummy .firstTuple = NULL ;/* flag to reference inputslot */
374- entry = (TupleHashEntry )hash_search (hashtable -> hashtab ,
375- & dummy ,
376- isnew ?HASH_ENTER :HASH_FIND ,
377- & found );
368+ key = NULL ;/* flag to reference inputslot */
378369
379370if (isnew )
380371{
372+ entry = tuplehash_insert (hashtable -> hashtab ,key ,& found );
373+
381374if (found )
382375{
383376/* found pre-existing entry */
384377* isnew = false;
385378}
386379else
387380{
388- /*
389- * created new entry
390- *
391- * Zero any caller-requested space in the entry. (This zaps the
392- * "key data" dynahash.c copied into the new entry, but we don't
393- * care since we're about to overwrite it anyway.)
394- */
395- MemSet (entry ,0 ,hashtable -> entrysize );
396-
397- /* Copy the first tuple into the table context */
381+ /* created new entry */
382+ * isnew = true;
383+ /* zero caller data */
384+ entry -> additional = NULL ;
398385MemoryContextSwitchTo (hashtable -> tablecxt );
386+ /* Copy the first tuple into the table context */
399387entry -> firstTuple = ExecCopySlotMinimalTuple (slot );
400-
401- * isnew = true;
402388}
403389}
404-
405- CurTupleHashTable = saveCurHT ;
390+ else
391+ {
392+ entry = tuplehash_lookup (hashtable -> hashtab ,key );
393+ }
406394
407395MemoryContextSwitchTo (oldContext );
408396
@@ -425,34 +413,19 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
425413{
426414TupleHashEntry entry ;
427415MemoryContext oldContext ;
428- TupleHashTable saveCurHT ;
429- TupleHashEntryData dummy ;
416+ MinimalTuple key ;
430417
431418/* Need to run the hash functions in short-lived context */
432419oldContext = MemoryContextSwitchTo (hashtable -> tempcxt );
433420
434- /*
435- * Set up data needed by hash and match functions
436- *
437- * We save and restore CurTupleHashTable just in case someone manages to
438- * invoke this code re-entrantly.
439- */
421+ /* Set up data needed by hash and match functions */
440422hashtable -> inputslot = slot ;
441423hashtable -> in_hash_funcs = hashfunctions ;
442424hashtable -> cur_eq_funcs = eqfunctions ;
443425
444- saveCurHT = CurTupleHashTable ;
445- CurTupleHashTable = hashtable ;
446-
447426/* Search the hash table */
448- dummy .firstTuple = NULL ;/* flag to reference inputslot */
449- entry = (TupleHashEntry )hash_search (hashtable -> hashtab ,
450- & dummy ,
451- HASH_FIND ,
452- NULL );
453-
454- CurTupleHashTable = saveCurHT ;
455-
427+ key = NULL ;/* flag to reference inputslot */
428+ entry = tuplehash_lookup (hashtable -> hashtab ,key );
456429MemoryContextSwitchTo (oldContext );
457430
458431return entry ;
@@ -468,22 +441,18 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
468441 * This convention avoids the need to materialize virtual input tuples unless
469442 * they actually need to get copied into the table.
470443 *
471- * CurTupleHashTable must be set before calling this, since dynahash.c
472- * doesn't provide any API that would let us get at the hashtable otherwise.
473- *
474444 * Also, the caller must select an appropriate memory context for running
475445 * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.)
476446 */
477447static uint32
478- TupleHashTableHash (const void * key , Size keysize )
448+ TupleHashTableHash (struct tuplehash_hash * tb , const MinimalTuple tuple )
479449{
480- MinimalTuple tuple = ((const TupleHashEntryData * )key )-> firstTuple ;
481- TupleTableSlot * slot ;
482- TupleHashTable hashtable = CurTupleHashTable ;
450+ TupleHashTable hashtable = (TupleHashTable )tb -> private ;
483451int numCols = hashtable -> numCols ;
484452AttrNumber * keyColIdx = hashtable -> keyColIdx ;
485- FmgrInfo * hashfunctions ;
486453uint32 hashkey = 0 ;
454+ TupleTableSlot * slot ;
455+ FmgrInfo * hashfunctions ;
487456int i ;
488457
489458if (tuple == NULL )
@@ -494,8 +463,12 @@ TupleHashTableHash(const void *key, Size keysize)
494463}
495464else
496465{
497- /* Process a tuple already stored in the table */
498- /* (this case never actually occurs in current dynahash.c code) */
466+ /*
467+ * Process a tuple already stored in the table.
468+ *
469+ * (this case never actually occurs due to the way simplehash.h is
470+ * used, as the hash-value is stored in the entries)
471+ */
499472slot = hashtable -> tableslot ;
500473ExecStoreMinimalTuple (tuple ,slot , false);
501474hashfunctions = hashtable -> tab_hash_funcs ;
@@ -530,29 +503,21 @@ TupleHashTableHash(const void *key, Size keysize)
530503 *
531504 * As above, the passed pointers are pointers to TupleHashEntryData.
532505 *
533- * CurTupleHashTable must be set before calling this, since dynahash.c
534- * doesn't provide any API that would let us get at the hashtable otherwise.
535- *
536506 * Also, the caller must select an appropriate memory context for running
537507 * the compare functions. (dynahash.c doesn't change CurrentMemoryContext.)
538508 */
539509static int
540- TupleHashTableMatch (const void * key1 ,const void * key2 , Size keysize )
510+ TupleHashTableMatch (struct tuplehash_hash * tb ,const MinimalTuple tuple1 , const MinimalTuple tuple2 )
541511{
542- MinimalTuple tuple1 = ((const TupleHashEntryData * )key1 )-> firstTuple ;
543-
544- #ifdef USE_ASSERT_CHECKING
545- MinimalTuple tuple2 = ((const TupleHashEntryData * )key2 )-> firstTuple ;
546- #endif
547512TupleTableSlot * slot1 ;
548513TupleTableSlot * slot2 ;
549- TupleHashTable hashtable = CurTupleHashTable ;
514+ TupleHashTable hashtable = ( TupleHashTable ) tb -> private ;
550515
551516/*
552- * We assume thatdynahash.c will only ever call us with the first
517+ * We assume thatsimplehash.h will only ever call us with the first
553518 * argument being an actual table entry, and the second argument being
554519 * LookupTupleHashEntry's dummy TupleHashEntryData. The other direction
555- * could be supported too, but is not currentlyused by dynahash.c .
520+ * could be supported too, but is not currentlyrequired .
556521 */
557522Assert (tuple1 != NULL );
558523slot1 = hashtable -> tableslot ;