diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index 6d0e0f5..210e1f2 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -195,6 +195,9 @@ static HASHSEGMENT seg_alloc(HTAB *hashp);
 static bool element_alloc(HTAB *hashp, int nelem);
 static bool dir_realloc(HTAB *hashp);
 static bool expand_table(HTAB *hashp);
+static HASHBUCKET get_matched_bucket(HTAB *hashp,
+				   const void *keyPtr, uint32 hashvalue,
+				   HASHBUCKET **prevBucketPtr);
 static HASHBUCKET get_hash_entry(HTAB *hashp);
 static void hdefault(HTAB *hashp);
 static int	choose_nelem_alloc(Size entrysize);
@@ -806,54 +809,15 @@ hash_search_with_hash_value(HTAB *hashp,
 							bool *foundPtr)
 {
 	HASHHDR    *hctl = hashp->hctl;
-	Size		keysize;
-	uint32		bucket;
-	long		segment_num;
-	long		segment_ndx;
-	HASHSEGMENT segp;
 	HASHBUCKET	currBucket;
 	HASHBUCKET *prevBucketPtr;
-	HashCompareFunc match;
 
 #if HASH_STATISTICS
 	hash_accesses++;
 	hctl->accesses++;
 #endif
 
-	/*
-	 * Do the initial lookup
-	 */
-	bucket = calc_bucket(hctl, hashvalue);
-
-	segment_num = bucket >> hashp->sshift;
-	segment_ndx = MOD(bucket, hashp->ssize);
-
-	segp = hashp->dir[segment_num];
-
-	if (segp == NULL)
-		hash_corrupted(hashp);
-
-	prevBucketPtr = &segp[segment_ndx];
-	currBucket = *prevBucketPtr;
-
-	/*
-	 * Follow collision chain looking for matching key
-	 */
-	match = hashp->match;		/* save one fetch in inner loop */
-	keysize = hashp->keysize;	/* ditto */
-
-	while (currBucket != NULL)
-	{
-		if (currBucket->hashvalue == hashvalue &&
-			match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
-			break;
-		prevBucketPtr = &(currBucket->link);
-		currBucket = *prevBucketPtr;
-#if HASH_STATISTICS
-		hash_collisions++;
-		hctl->collisions++;
-#endif
-	}
+	currBucket = get_matched_bucket(hashp, keyPtr, hashvalue, &prevBucketPtr);
 
 	if (foundPtr)
 		*foundPtr = (bool) (currBucket != NULL);
@@ -915,6 +879,31 @@ hash_search_with_hash_value(HTAB *hashp,
 				elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
 					 hashp->tabname);
 
+			/*
+			 * Check if it is time to split a bucket.  Can't split if running
+			 * in partitioned mode, nor if table is the subject of any active
+			 * hash_seq_search scans.  Strange order of these tests is to try
+			 * to check cheaper conditions first.
+			 */
+			if (!IS_PARTITIONED(hctl) &&
+			(hctl->nentries + 1) / (long) (hctl->max_bucket + 1) >= hctl->ffactor &&
+				!has_seq_scans(hashp))
+			{
+				/*
+				 * We do this before allocating a hash entry, because some
+				 * long-lived hash tables like relcache could run into
+				 * trouble in transaction abort clean up if expand_table
+				 * errors out after we allocate an entry that has not been
+				 * filled out.
+				 */
+				expand_table(hashp);
+
+				/*
+				 * Calculate bucket to find the spot to insert the new entry.
+				 */
+				get_matched_bucket(hashp, keyPtr, hashvalue, &prevBucketPtr);
+			}
+
 			currBucket = get_hash_entry(hashp);
 			if (currBucket == NULL)
 			{
@@ -938,27 +927,10 @@ hash_search_with_hash_value(HTAB *hashp,
 
 			/* copy key into record */
 			currBucket->hashvalue = hashvalue;
-			hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);
+			hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, hashp->keysize);
 
 			/* caller is expected to fill the data field on return */
 
-			/*
-			 * Check if it is time to split a bucket.  Can't split if running
-			 * in partitioned mode, nor if table is the subject of any active
-			 * hash_seq_search scans.  Strange order of these tests is to try
-			 * to check cheaper conditions first.
-			 */
-			if (!IS_PARTITIONED(hctl) &&
-			hctl->nentries / (long) (hctl->max_bucket + 1) >= hctl->ffactor &&
-				!has_seq_scans(hashp))
-			{
-				/*
-				 * NOTE: failure to expand table is not a fatal error, it just
-				 * means we have to run at higher fill factor than we wanted.
-				 */
-				expand_table(hashp);
-			}
-
 			return (void *) ELEMENTKEY(currBucket);
 	}
 
@@ -968,6 +940,60 @@ hash_search_with_hash_value(HTAB *hashp,
 }
 
 /*
+ * Get the entry that matches key, with the previous entry in the same bucket.
+ */
+static HASHBUCKET
+get_matched_bucket(HTAB *hashp, const void *keyPtr, uint32 hashvalue,
+				   HASHBUCKET **prevBucketPtr)
+{
+	HASHHDR	   *hctl = hashp->hctl;
+	Size		keysize;
+	uint32		bucket;
+	long		segment_num;
+	long		segment_ndx;
+	HASHSEGMENT	segp;
+	HASHBUCKET	currBucket;
+	HashCompareFunc match;
+
+	/*
+	 * Do the initial lookup
+	 */
+	bucket = calc_bucket(hctl, hashvalue);
+
+	segment_num = bucket >> hashp->sshift;
+	segment_ndx = MOD(bucket, hashp->ssize);
+
+	segp = hashp->dir[segment_num];
+
+	if (segp == NULL)
+		hash_corrupted(hashp);
+
+	*prevBucketPtr = &segp[segment_ndx];
+	currBucket = **prevBucketPtr;
+
+	/*
+	 * Follow collision chain looking for matching key
+	 */
+	match = hashp->match;		/* save one fetch in inner loop */
+	keysize = hashp->keysize;	/* ditto */
+
+	while (currBucket != NULL)
+	{
+		if (currBucket->hashvalue == hashvalue &&
+			match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
+			break;
+		*prevBucketPtr = &(currBucket->link);
+		currBucket = **prevBucketPtr;
+#if HASH_STATISTICS
+		hash_collisions++;
+		hctl->collisions++;
+#endif
+	}
+
+	return currBucket;
+}
+
+/*
  * create a new entry if possible
  */
 static HASHBUCKET