Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1b794d3

Browse files
committed
Fix hash_update_hash_key() to handle same-bucket case correctly.
Original coding would corrupt the hashtable if the item being updated was at the end of its bucket chain and the new hash key hashed to that same bucket. Diagnosis and fix by Heikki Linnakangas.
1 parent 3f4b174 commit 1b794d3

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

src/backend/utils/hash/dynahash.c

+19-8
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ hash_update_hash_key(HTAB *hashp,
10221022
uint32 newhashvalue;
10231023
Size keysize;
10241024
uint32 bucket;
1025+
uint32 newbucket;
10251026
long segment_num;
10261027
long segment_ndx;
10271028
HASHSEGMENT segp;
@@ -1078,10 +1079,10 @@ hash_update_hash_key(HTAB *hashp,
10781079
*/
10791080
newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
10801081

1081-
bucket = calc_bucket(hctl, newhashvalue);
1082+
newbucket = calc_bucket(hctl, newhashvalue);
10821083

1083-
segment_num = bucket >> hashp->sshift;
1084-
segment_ndx = MOD(bucket, hashp->ssize);
1084+
segment_num = newbucket >> hashp->sshift;
1085+
segment_ndx = MOD(newbucket, hashp->ssize);
10851086

10861087
segp = hashp->dir[segment_num];
10871088

@@ -1115,12 +1116,22 @@ hash_update_hash_key(HTAB *hashp,
11151116

11161117
currBucket = existingElement;
11171118

1118-
/* OK to remove record from old hash bucket's chain. */
1119-
*oldPrevPtr = currBucket->link;
1119+
/*
1120+
* If old and new hash values belong to the same bucket, we need not
1121+
* change any chain links, and indeed should not since this simplistic
1122+
* update will corrupt the list if currBucket is the last element. (We
1123+
* cannot fall out earlier, however, since we need to scan the bucket to
1124+
* check for duplicate keys.)
1125+
*/
1126+
if (bucket != newbucket)
1127+
{
1128+
/* OK to remove record from old hash bucket's chain. */
1129+
*oldPrevPtr = currBucket->link;
11201130

1121-
/* link into new hashbucket chain */
1122-
*prevBucketPtr = currBucket;
1123-
currBucket->link = NULL;
1131+
/* link into new hashbucket chain */
1132+
*prevBucketPtr = currBucket;
1133+
currBucket->link = NULL;
1134+
}
11241135

11251136
/* copy new key into record */
11261137
currBucket->hashvalue = newhashvalue;

0 commit comments

Comments
 (0)