88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.7 2003/08/08 21:41:34 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/executor/execGrouping.c,v 1.8 2003/08/19 01:13:40 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2323#include "utils/syscache.h"
2424
2525
26+ static TupleHashTable CurTupleHashTable = NULL ;
27+
28+ static uint32 TupleHashTableHash (const void * key ,Size keysize );
29+ static int TupleHashTableMatch (const void * key1 ,const void * key2 ,
30+ Size keysize );
31+
32+
2633/*****************************************************************************
2734 *Utility routines for grouping tuples together
2835 *****************************************************************************/
@@ -272,7 +279,7 @@ execTuplesHashPrepare(TupleDesc tupdesc,
272279 *numCols, keyColIdx: identify the tuple fields to use as lookup key
273280 *eqfunctions: equality comparison functions to use
274281 *hashfunctions: datatype-specific hashing functions to use
275- *nbuckets:number ofbuckets to make
282+ *nbuckets:initial estimate ofhashtable size
276283 *entrysize: size of each entry (at least sizeof(TupleHashEntryData))
277284 *tablecxt: memory context in which to store table and table entries
278285 *tempcxt: short-lived context for evaluation hash and comparison functions
@@ -290,14 +297,13 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
290297MemoryContext tablecxt ,MemoryContext tempcxt )
291298{
292299TupleHashTable hashtable ;
293- Size tabsize ;
300+ HASHCTL hash_ctl ;
294301
295302Assert (nbuckets > 0 );
296303Assert (entrysize >=sizeof (TupleHashEntryData ));
297304
298- tabsize = sizeof (TupleHashTableData )+
299- (nbuckets - 1 )* sizeof (TupleHashEntry );
300- hashtable = (TupleHashTable )MemoryContextAllocZero (tablecxt ,tabsize );
305+ hashtable = (TupleHashTable )MemoryContextAlloc (tablecxt ,
306+ sizeof (TupleHashTableData ));
301307
302308hashtable -> numCols = numCols ;
303309hashtable -> keyColIdx = keyColIdx ;
@@ -306,7 +312,20 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
306312hashtable -> tablecxt = tablecxt ;
307313hashtable -> tempcxt = tempcxt ;
308314hashtable -> entrysize = entrysize ;
309- hashtable -> nbuckets = nbuckets ;
315+
316+ MemSet (& hash_ctl ,0 ,sizeof (hash_ctl ));
317+ hash_ctl .keysize = sizeof (TupleHashEntryData );
318+ hash_ctl .entrysize = entrysize ;
319+ hash_ctl .hash = TupleHashTableHash ;
320+ hash_ctl .match = TupleHashTableMatch ;
321+ hash_ctl .hcxt = tablecxt ;
322+ hashtable -> hashtab = hash_create ("TupleHashTable" , (long )nbuckets ,
323+ & hash_ctl ,
324+ HASH_ELEM |HASH_FUNCTION |HASH_COMPARE |HASH_CONTEXT );
325+ if (hashtable -> hashtab == NULL )
326+ ereport (ERROR ,
327+ (errcode (ERRCODE_OUT_OF_MEMORY ),
328+ errmsg ("out of memory" )));
310329
311330return hashtable ;
312331}
@@ -327,19 +346,93 @@ TupleHashEntry
327346LookupTupleHashEntry (TupleHashTable hashtable ,TupleTableSlot * slot ,
328347bool * isnew )
329348{
330- int numCols = hashtable -> numCols ;
331- AttrNumber * keyColIdx = hashtable -> keyColIdx ;
332349HeapTuple tuple = slot -> val ;
333350TupleDesc tupdesc = slot -> ttc_tupleDescriptor ;
334- uint32 hashkey = 0 ;
335- int i ;
336- int bucketno ;
337351TupleHashEntry entry ;
338352MemoryContext oldContext ;
353+ TupleHashTable saveCurHT ;
354+ bool found ;
339355
340- /* Need to run the hashfunction in short-lived context */
356+ /* Need to run the hashfunctions in short-lived context */
341357oldContext = MemoryContextSwitchTo (hashtable -> tempcxt );
342358
359+ /*
360+ * Set up data needed by hash and match functions
361+ *
362+ * We save and restore CurTupleHashTable just in case someone manages
363+ * to invoke this code re-entrantly.
364+ */
365+ hashtable -> tupdesc = tupdesc ;
366+ saveCurHT = CurTupleHashTable ;
367+ CurTupleHashTable = hashtable ;
368+
369+ /* Search the hash table */
370+ entry = (TupleHashEntry )hash_search (hashtable -> hashtab ,
371+ & tuple ,
372+ isnew ?HASH_ENTER :HASH_FIND ,
373+ & found );
374+
375+ if (isnew )
376+ {
377+ if (found )
378+ {
379+ /* found pre-existing entry */
380+ * isnew = false;
381+ }
382+ else
383+ {
384+ /* created new entry ... we hope */
385+ if (entry == NULL )
386+ ereport (ERROR ,
387+ (errcode (ERRCODE_OUT_OF_MEMORY ),
388+ errmsg ("out of memory" )));
389+
390+ /*
391+ * Zero any caller-requested space in the entry. (This zaps
392+ * the "key data" dynahash.c copied into the new entry, but
393+ * we don't 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 */
398+ MemoryContextSwitchTo (hashtable -> tablecxt );
399+ entry -> firstTuple = heap_copytuple (tuple );
400+
401+ * isnew = true;
402+ }
403+ }
404+
405+ CurTupleHashTable = saveCurHT ;
406+
407+ MemoryContextSwitchTo (oldContext );
408+
409+ return entry ;
410+ }
411+
412+ /*
413+ * Compute the hash value for a tuple
414+ *
415+ * The passed-in key is a pointer to a HeapTuple pointer -- this is either
416+ * the firstTuple field of a TupleHashEntry struct, or the key value passed
417+ * to hash_search. We ignore the keysize.
418+ *
419+ * CurTupleHashTable must be set before calling this, since dynahash.c
420+ * doesn't provide any API that would let us get at the hashtable otherwise.
421+ *
422+ * Also, the caller must select an appropriate memory context for running
423+ * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.)
424+ */
425+ static uint32
426+ TupleHashTableHash (const void * key ,Size keysize )
427+ {
428+ HeapTuple tuple = * (const HeapTuple * )key ;
429+ TupleHashTable hashtable = CurTupleHashTable ;
430+ int numCols = hashtable -> numCols ;
431+ AttrNumber * keyColIdx = hashtable -> keyColIdx ;
432+ TupleDesc tupdesc = hashtable -> tupdesc ;
433+ uint32 hashkey = 0 ;
434+ int i ;
435+
343436for (i = 0 ;i < numCols ;i ++ )
344437{
345438AttrNumber att = keyColIdx [i ];
@@ -360,72 +453,36 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
360453hashkey ^=hkey ;
361454}
362455}
363- bucketno = hashkey % (uint32 )hashtable -> nbuckets ;
364-
365- for (entry = hashtable -> buckets [bucketno ];
366- entry != NULL ;
367- entry = entry -> next )
368- {
369- /* Quick check using hashkey */
370- if (entry -> hashkey != hashkey )
371- continue ;
372- if (execTuplesMatch (entry -> firstTuple ,
373- tuple ,
374- tupdesc ,
375- numCols ,keyColIdx ,
376- hashtable -> eqfunctions ,
377- hashtable -> tempcxt ))
378- {
379- if (isnew )
380- * isnew = false;
381- MemoryContextSwitchTo (oldContext );
382- return entry ;
383- }
384- }
385-
386- /* Not there, so build a new one if requested */
387- if (isnew )
388- {
389- MemoryContextSwitchTo (hashtable -> tablecxt );
390-
391- entry = (TupleHashEntry )palloc0 (hashtable -> entrysize );
392-
393- entry -> hashkey = hashkey ;
394- entry -> firstTuple = heap_copytuple (tuple );
395-
396- entry -> next = hashtable -> buckets [bucketno ];
397- hashtable -> buckets [bucketno ]= entry ;
398-
399- * isnew = true;
400- }
401-
402- MemoryContextSwitchTo (oldContext );
403456
404- return entry ;
457+ return hashkey ;
405458}
406459
407460/*
408- * Walk through all the entries of a hash table, in no special order.
409- * Returns NULL when no more entries remain.
461+ * See whether two tuples (presumably of the same hash value) match
462+ *
463+ * As above, the passed pointers are pointers to HeapTuple pointers.
410464 *
411- * Iterator state must be initialized with ResetTupleHashIterator() macro.
465+ * CurTupleHashTable must be set before calling this, since dynahash.c
466+ * doesn't provide any API that would let us get at the hashtable otherwise.
467+ *
468+ * Also, the caller must select an appropriate memory context for running
469+ * the compare functions. (dynahash.c doesn't change CurrentMemoryContext.)
412470 */
413- TupleHashEntry
414- ScanTupleHashTable ( TupleHashTable hashtable , TupleHashIterator * state )
471+ static int
472+ TupleHashTableMatch ( const void * key1 , const void * key2 , Size keysize )
415473{
416- TupleHashEntry entry ;
417-
418- entry = state -> next_entry ;
419- while (entry == NULL )
420- {
421- if (state -> next_bucket >=hashtable -> nbuckets )
422- {
423- /* No more entries in hashtable, so done */
424- return NULL ;
425- }
426- entry = hashtable -> buckets [state -> next_bucket ++ ];
427- }
428- state -> next_entry = entry -> next ;
429-
430- return entry ;
474+ HeapTuple tuple1 = * (const HeapTuple * )key1 ;
475+ HeapTuple tuple2 = * (const HeapTuple * )key2 ;
476+ TupleHashTable hashtable = CurTupleHashTable ;
477+
478+ if (execTuplesMatch (tuple1 ,
479+ tuple2 ,
480+ hashtable -> tupdesc ,
481+ hashtable -> numCols ,
482+ hashtable -> keyColIdx ,
483+ hashtable -> eqfunctions ,
484+ hashtable -> tempcxt ))
485+ return 0 ;
486+ else
487+ return 1 ;
431488}