From 2dc9e5b59b3244f14497f551a25e2f76e46b5138 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Sun, 10 Dec 2017 20:03:16 +0100
Subject: [PATCH 1/3] use random seed for hash table

---
 src/backend/executor/execGrouping.c |  9 ++++++---
 src/backend/executor/nodeHash.c     |  2 +-
 src/backend/executor/nodeSubplan.c  |  3 ++-
 src/backend/utils/cache/lsyscache.c | 13 ++++++++++---
 src/include/nodes/execnodes.h       |  1 +
 src/include/utils/lsyscache.h       |  3 ++-
 6 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 07c8852..eb0a1e8 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -249,7 +249,8 @@ execTuplesHashPrepare(int numCols,
 
 		eq_function = get_opcode(eq_opr);
 		if (!get_op_hash_functions(eq_opr,
-								   &left_hash_function, &right_hash_function))
+								   &left_hash_function, &right_hash_function,
+								   true))
 			elog(ERROR, "could not find hash function for hash operator %u",
 				 eq_opr);
 		/* We're not supporting cross-type cases here */
@@ -316,6 +317,7 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
 	hashtable->inputslot = NULL;
 	hashtable->in_hash_funcs = NULL;
 	hashtable->cur_eq_funcs = NULL;
+	hashtable->hash_seed = random();
 
 	/*
 	 * If parallelism is in use, even if the master backend is performing the
@@ -504,8 +506,9 @@ TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple)
 		{
 			uint32		hkey;
 
-			hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i],
-												attr));
+			hkey = DatumGetUInt32(FunctionCall2(&hashfunctions[i],
+												attr,
+												Int32GetDatum(hashtable->hash_seed)));
 			hashkey ^= hkey;
 		}
 	}
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 6fe5d69..38f4909 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -326,7 +326,7 @@ ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
 		Oid			left_hashfn;
 		Oid			right_hashfn;
 
-		if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
+		if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn, false))
 			elog(ERROR, "could not find hash function for hash operator %u",
 				 hashop);
 		fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]);
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index a93fbf6..5645a71 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -860,7 +860,8 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 
 			/* Lookup the associated hash functions */
 			if (!get_op_hash_functions(opexpr->opno,
-									   &left_hashfn, &right_hashfn))
+									   &left_hashfn, &right_hashfn,
+									   false))
 				elog(ERROR, "could not find hash function for hash operator %u",
 					 opexpr->opno);
 			fmgr_info(left_hashfn, &sstate->lhs_hash_funcs[i - 1]);
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 5211360..f71aff2 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -505,11 +505,18 @@ get_compatible_hash_operators(Oid opno,
  */
 bool
 get_op_hash_functions(Oid opno,
-					  RegProcedure *lhs_procno, RegProcedure *rhs_procno)
+					  RegProcedure *lhs_procno, RegProcedure *rhs_procno,
+					  bool extended)
 {
 	bool		result = false;
 	CatCList   *catlist;
 	int			i;
+	int16		procnum;
+
+	if (extended)
+		procnum = HASHEXTENDED_PROC;
+	else
+		procnum = HASHSTANDARD_PROC;
 
 	/* Ensure output args are initialized on failure */
 	if (lhs_procno)
@@ -542,7 +549,7 @@ get_op_hash_functions(Oid opno,
 				*lhs_procno = get_opfamily_proc(aform->amopfamily,
 												aform->amoplefttype,
 												aform->amoplefttype,
-												HASHSTANDARD_PROC);
+												procnum);
 				if (!OidIsValid(*lhs_procno))
 					continue;
 				/* Matching LHS found, done if caller doesn't want RHS */
@@ -564,7 +571,7 @@ get_op_hash_functions(Oid opno,
 				*rhs_procno = get_opfamily_proc(aform->amopfamily,
 												aform->amoprighttype,
 												aform->amoprighttype,
-												HASHSTANDARD_PROC);
+												procnum);
 				if (!OidIsValid(*rhs_procno))
 				{
 					/* Forget any LHS function from this opfamily */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1a35c5c..54bd336 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -619,6 +619,7 @@ typedef struct TupleHashTableData
 	FmgrInfo   *in_hash_funcs;	/* hash functions for input datatype(s) */
 	FmgrInfo   *cur_eq_funcs;	/* equality functions for input vs. table */
 	uint32		hash_iv;		/* hash-function IV */
+	uint32		hash_seed;		/* seed for randomized hashing */
 }			TupleHashTableData;
 
 typedef tuplehash_iterator TupleHashIterator;
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index b316cc5..c6f3080 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -78,7 +78,8 @@ extern List *get_mergejoin_opfamilies(Oid opno);
 extern bool get_compatible_hash_operators(Oid opno,
 							  Oid *lhs_opno, Oid *rhs_opno);
 extern bool get_op_hash_functions(Oid opno,
-					  RegProcedure *lhs_procno, RegProcedure *rhs_procno);
+					  RegProcedure *lhs_procno, RegProcedure *rhs_procno,
+					  bool extended);
 extern List *get_op_btree_interpretation(Oid opno);
 extern bool equality_ops_are_compatible(Oid opno1, Oid opno2);
 extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype,
-- 
2.9.5

