77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 *
10- *$Id: nodeHash.c,v 1.58 2001/06/11 00:17:07 tgl Exp $
10+ *$Id: nodeHash.c,v 1.59 2001/08/13 19:50:11 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -533,19 +533,23 @@ ExecHashGetBucket(HashJoinTable hashtable,
533533int bucketno ;
534534Datum keyval ;
535535bool isNull ;
536+ MemoryContext oldContext ;
536537
537538/*
538- * Get the join attribute value of the tuple
539- *
540- * We reset the eval context each time to avoid any possibility of memory
541- * leaks in the hash function.
539+ * We reset the eval context each time to reclaim any memory leaked
540+ * in the hashkey expression or hashFunc itself.
542541 */
543542ResetExprContext (econtext );
544543
545- keyval = ExecEvalExprSwitchContext ( hashkey , econtext , & isNull , NULL );
544+ oldContext = MemoryContextSwitchTo ( econtext -> ecxt_per_tuple_memory );
546545
547546/*
548- * compute the hash function
547+ * Get the join attribute value of the tuple
548+ */
549+ keyval = ExecEvalExpr (hashkey ,econtext ,& isNull ,NULL );
550+
551+ /*
552+ * Compute the hash function
549553 */
550554if (isNull )
551555bucketno = 0 ;
@@ -564,6 +568,8 @@ ExecHashGetBucket(HashJoinTable hashtable,
564568printf ("hash(%ld) = %d\n" , (long )keyval ,bucketno );
565569#endif
566570
571+ MemoryContextSwitchTo (oldContext );
572+
567573return bucketno ;
568574}
569575
@@ -624,17 +630,18 @@ ExecScanHashBucket(HashJoinState *hjstate,
624630 *hashFunc
625631 *
626632 *the hash function, copied from Margo
633+ *
634+ *XXX this probably ought to be replaced with datatype-specific
635+ *hash functions, such as those already implemented for hash indexes.
627636 * ----------------------------------------------------------------
628637 */
629638static int
630639hashFunc (Datum key ,int len ,bool byVal )
631640{
632641unsignedint h = 0 ;
633- unsignedchar * k ;
634642
635643if (byVal )
636644{
637-
638645/*
639646 * If it's a by-value data type, use the 'len' least significant
640647 * bytes of the Datum value. This should do the right thing on
@@ -649,22 +656,29 @@ hashFunc(Datum key, int len, bool byVal)
649656}
650657else
651658{
652-
653659/*
654- * If this is a variable length type, then 'k ' points to a "struct
655- * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
660+ * If this is a variable length type, then 'key ' points to a "struct
661+ * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
656662 * length plus the sizeof the "vl_len" attribute of varlena (the
657- * length information). 'k ' points to the beginning of the varlena
663+ * length information). 'key ' points to the beginning of the varlena
658664 * struct, so we have to use "VARDATA" to find the beginning of
659- * the "real" data.
665+ * the "real" data. Also, we have to be careful to detoast the
666+ * datum if it's toasted. (We don't worry about freeing the detoasted
667+ * copy; that happens for free when the per-tuple memory context
668+ * is reset in ExecHashGetBucket.)
660669 */
661- if (len == -1 )
670+ unsignedchar * k ;
671+
672+ if (len < 0 )
662673{
663- len = VARSIZE (key )- VARHDRSZ ;
664- k = (unsignedchar * )VARDATA (key );
674+ struct varlena * vkey = PG_DETOAST_DATUM (key );
675+
676+ len = VARSIZE (vkey )- VARHDRSZ ;
677+ k = (unsignedchar * )VARDATA (vkey );
665678}
666679else
667- k = (unsignedchar * )key ;
680+ k = (unsignedchar * )DatumGetPointer (key );
681+
668682while (len -- > 0 )
669683h = (h * PRIME1 ) ^ (* k ++ );
670684}