]> granicus.if.org Git - postgresql/commitdiff
Make hashjoin give the right answer with toasted input data.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Aug 2001 19:50:11 +0000 (19:50 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Aug 2001 19:50:11 +0000 (19:50 +0000)
src/backend/executor/nodeHash.c

index b8cee44fbdf4d4630845b1ceb6d3b50ea87f0e89..f387e5a759fa3dda995660138b355ce7297b0745 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- *     $Id: nodeHash.c,v 1.58 2001/06/11 00:17:07 tgl Exp $
+ *     $Id: nodeHash.c,v 1.59 2001/08/13 19:50:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -533,19 +533,23 @@ ExecHashGetBucket(HashJoinTable hashtable,
        int                     bucketno;
        Datum           keyval;
        bool            isNull;
+       MemoryContext oldContext;
 
        /*
-        * Get the join attribute value of the tuple
-        *
-        * We reset the eval context each time to avoid any possibility of memory
-        * leaks in the hash function.
+        * We reset the eval context each time to reclaim any memory leaked
+        * in the hashkey expression or hashFunc itself.
         */
        ResetExprContext(econtext);
 
-       keyval = ExecEvalExprSwitchContext(hashkey, econtext, &isNull, NULL);
+       oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
        /*
-        * compute the hash function
+        * Get the join attribute value of the tuple
+        */
+       keyval = ExecEvalExpr(hashkey, econtext, &isNull, NULL);
+
+       /*
+        * Compute the hash function
         */
        if (isNull)
                bucketno = 0;
@@ -564,6 +568,8 @@ ExecHashGetBucket(HashJoinTable hashtable,
                printf("hash(%ld) = %d\n", (long) keyval, bucketno);
 #endif
 
+       MemoryContextSwitchTo(oldContext);
+
        return bucketno;
 }
 
@@ -624,17 +630,18 @@ ExecScanHashBucket(HashJoinState *hjstate,
  *             hashFunc
  *
  *             the hash function, copied from Margo
+ *
+ *             XXX this probably ought to be replaced with datatype-specific
+ *             hash functions, such as those already implemented for hash indexes.
  * ----------------------------------------------------------------
  */
 static int
 hashFunc(Datum key, int len, bool byVal)
 {
        unsigned int h = 0;
-       unsigned char *k;
 
        if (byVal)
        {
-
                /*
                 * If it's a by-value data type, use the 'len' least significant
                 * bytes of the Datum value.  This should do the right thing on
@@ -649,22 +656,29 @@ hashFunc(Datum key, int len, bool byVal)
        }
        else
        {
-
                /*
-                * If this is a variable length type, then 'k' points to a "struct
-                * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
+                * If this is a variable length type, then 'key' points to a "struct
+                * varlena" and len == -1.  NOTE: VARSIZE returns the "real" data
                 * length plus the sizeof the "vl_len" attribute of varlena (the
-                * length information). 'k' points to the beginning of the varlena
+                * length information). 'key' points to the beginning of the varlena
                 * struct, so we have to use "VARDATA" to find the beginning of
-                * the "real" data.
+                * the "real" data.  Also, we have to be careful to detoast the
+                * datum if it's toasted.  (We don't worry about freeing the detoasted
+                * copy; that happens for free when the per-tuple memory context
+                * is reset in ExecHashGetBucket.)
                 */
-               if (len == -1)
+               unsigned char *k;
+
+               if (len < 0)
                {
-                       len = VARSIZE(key) - VARHDRSZ;
-                       k = (unsigned char *) VARDATA(key);
+                       struct varlena *vkey = PG_DETOAST_DATUM(key);
+
+                       len = VARSIZE(vkey) - VARHDRSZ;
+                       k = (unsigned char *) VARDATA(vkey);
                }
                else
-                       k = (unsigned char *) key;
+                       k = (unsigned char *) DatumGetPointer(key);
+
                while (len-- > 0)
                        h = (h * PRIME1) ^ (*k++);
        }