77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 *
10- * $Id: nodeHash.c,v 1.56 2001/03/22 06:16:12 momjian Exp $
10+ * $Id: nodeHash.c,v 1.56.2.1 2001/08/13 19:54:00 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -507,19 +507,23 @@ ExecHashGetBucket(HashJoinTable hashtable,
507507 int bucketno ;
508508 Datum keyval ;
509509 bool isNull ;
510+ MemoryContext oldContext ;
510511
511512 /*
512- * Get the join attribute value of the tuple
513- *
514- * We reset the eval context each time to avoid any possibility of memory
515- * leaks in the hash function.
513+ * We reset the eval context each time to reclaim any memory leaked
514+ * in the hashkey expression or hashFunc itself.
516515 */
517516 ResetExprContext (econtext );
518517
519- keyval = ExecEvalExprSwitchContext ( hashkey , econtext , & isNull , NULL );
518+ oldContext = MemoryContextSwitchTo ( econtext -> ecxt_per_tuple_memory );
520519
521520 /*
522- * compute the hash function
521+ * Get the join attribute value of the tuple
522+ */
523+ keyval = ExecEvalExpr (hashkey , econtext , & isNull , NULL );
524+
525+ /*
526+ * Compute the hash function
523527 */
524528 if (isNull )
525529 bucketno = 0 ;
@@ -538,6 +542,8 @@ ExecHashGetBucket(HashJoinTable hashtable,
538542 printf ("hash(%ld) = %d\n" , (long ) keyval , bucketno );
539543#endif
540544
545+ MemoryContextSwitchTo (oldContext );
546+
541547 return bucketno ;
542548}
543549
@@ -598,17 +604,18 @@ ExecScanHashBucket(HashJoinState *hjstate,
598604 * hashFunc
599605 *
600606 * the hash function, copied from Margo
607+ *
608+ * XXX this probably ought to be replaced with datatype-specific
609+ * hash functions, such as those already implemented for hash indexes.
601610 * ----------------------------------------------------------------
602611 */
603612static int
604613hashFunc (Datum key , int len , bool byVal )
605614{
606615 unsigned int h = 0 ;
607- unsigned char * k ;
608616
609617 if (byVal )
610618 {
611-
612619 /*
613620 * If it's a by-value data type, use the 'len' least significant
614621 * bytes of the Datum value. This should do the right thing on
@@ -623,22 +630,29 @@ hashFunc(Datum key, int len, bool byVal)
623630 }
624631 else
625632 {
626-
627633 /*
628- * If this is a variable length type, then 'k ' points to a "struct
629- * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
634+ * If this is a variable length type, then 'key ' points to a "struct
635+ * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
630636 * length plus the sizeof the "vl_len" attribute of varlena (the
631- * length information). 'k ' points to the beginning of the varlena
637+ * length information). 'key ' points to the beginning of the varlena
632638 * struct, so we have to use "VARDATA" to find the beginning of
633- * the "real" data.
639+ * the "real" data. Also, we have to be careful to detoast the
640+ * datum if it's toasted. (We don't worry about freeing the detoasted
641+ * copy; that happens for free when the per-tuple memory context
642+ * is reset in ExecHashGetBucket.)
634643 */
635- if (len == -1 )
644+ unsigned char * k ;
645+
646+ if (len < 0 )
636647 {
637- len = VARSIZE (key ) - VARHDRSZ ;
638- k = (unsigned char * ) VARDATA (key );
648+ struct varlena * vkey = PG_DETOAST_DATUM (key );
649+
650+ len = VARSIZE (vkey ) - VARHDRSZ ;
651+ k = (unsigned char * ) VARDATA (vkey );
639652 }
640653 else
641- k = (unsigned char * ) key ;
654+ k = (unsigned char * ) DatumGetPointer (key );
655+
642656 while (len -- > 0 )
643657 h = (h * PRIME1 ) ^ (* k ++ );
644658 }
0 commit comments