Index: src/backend/executor/nodeHash.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/nodeHash.c,v
retrieving revision 1.116
diff -c -r1.116 nodeHash.c
*** src/backend/executor/nodeHash.c	1 Jan 2008 19:45:49 -0000	1.116
--- src/backend/executor/nodeHash.c	24 Nov 2008 12:32:13 -0000
***************
*** 54,59 ****
--- 54,165 ----
  }
  
  /* ----------------------------------------------------------------
+ *		isAMostCommonValue
+ *
+ *		is the value one of the most common key values?
+ *  ----------------------------------------------------------------
+ */
+ bool isAMostCommonValue(HashJoinTable hashtable, uint32 hashvalue, int *partitionNumber)
+ {
+ 	int bucket = hashvalue & (hashtable->nMostCommonTuplePartitionHashBuckets - 1);
+ 
+ 	while (hashtable->mostCommonTuplePartition[bucket].hashvalue != 0
+ 		&& hashtable->mostCommonTuplePartition[bucket].hashvalue != hashvalue)
+ 	{
+ 		bucket = (bucket + 1) & (hashtable->nMostCommonTuplePartitionHashBuckets - 1);
+ 	}
+ 
+ 	if (!hashtable->mostCommonTuplePartition[bucket].frozen && hashtable->mostCommonTuplePartition[bucket].hashvalue == hashvalue)
+ 	{
+ 		*partitionNumber = bucket;
+ 		return true;
+ 	}
+ 
+ 	/* must have run into an empty slot which means this is not an MCV*/
+ 	*partitionNumber = MCV_INVALID_PARTITION;
+ 	return false;
+ }
+ 
+ /*
+ *	freezeNextMCVPartiton
+ *
+ *	flush the tuples of the next MCV partition by pushing them into the main hashtable
+ */
+ bool freezeNextMCVPartiton(HashJoinTable hashtable) {
+ 	int partitionToFlush = hashtable->nMostCommonTuplePartitions - 1 - hashtable->nMostCommonTuplePartitionsFlushed;
+ 	if (partitionToFlush < 0)
+ 		return false;
+ 	else
+ 	{
+ 
+ 		int		bucketno;
+ 		int		batchno;
+ 		uint32		hashvalue;
+ 		HashJoinTuple hashTuple;
+ 		HashJoinTuple nextHashTuple;
+ 		HashJoinMostCommonValueTuplePartition *partition;
+ 		MinimalTuple mintuple;
+ 
+ 		partition = hashtable->flushOrderedMostCommonTuplePartition[partitionToFlush];
+ 		hashvalue = partition->hashvalue;
+ 
+ 		Assert(hashvalue != 0);
+ 
+ 		hashTuple = partition->tuples;
+ 
+ 		ExecHashGetBucketAndBatch(hashtable, hashvalue,
+ 								  &bucketno, &batchno);
+ 
+ 		while (hashTuple != NULL)
+ 		{
+ 			/* decide whether to put the tuples in the hash table or a temp file */
+ 			if (batchno == hashtable->curbatch)
+ 			{
+ 				/* put the tuples in hash table */
+ 				nextHashTuple = hashTuple->next;
+ 
+ 				hashTuple->next = hashtable->buckets[bucketno];
+ 				hashtable->buckets[bucketno] = hashTuple;
+ 				
+ 				hashTuple = nextHashTuple;
+ 				hashtable->totalTuples++;
+ 				hashtable->mostCommonTuplesStored--;
+ 				
+ 				if (hashtable->spaceUsed > hashtable->spaceAllowed)
+ 				{
+ 					ExecHashIncreaseNumBatches(hashtable);
+ 					/* likely changed due to increase in batches */
+ 					ExecHashGetBucketAndBatch(hashtable, hashvalue,
+ 						&bucketno, &batchno);
+ 				}
+ 			}
+ 			else
+ 			{
+ 				/* put the tuples into a temp file for later batches */
+ 				Assert(batchno > hashtable->curbatch);
+ 				mintuple = HJTUPLE_MINTUPLE(hashTuple);
+ 				ExecHashJoinSaveTuple(mintuple,
+ 									  hashvalue,
+ 									  &hashtable->innerBatchFile[batchno]);
+ 				hashtable->spaceUsed -= HJTUPLE_OVERHEAD + mintuple->t_len;
+ 				nextHashTuple = hashTuple->next;
+ 				pfree(hashTuple);
+ 				hashTuple = nextHashTuple;
+ 				hashtable->inTupIOs++;
+ 				hashtable->totalTuples++;
+ 				hashtable->mostCommonTuplesStored--;
+ 			}
+ 		}
+ 
+ 		partition->frozen = true;
+ 		partition->tuples = NULL;
+ 		hashtable->nMostCommonTuplePartitionsFlushed++;
+ 
+ 		return true;
+ 	}
+ }
+ 
+ /* ----------------------------------------------------------------
   *		MultiExecHash
   *
   *		build hash table for hashjoin, doing partitioning if more
***************
*** 69,74 ****
--- 175,182 ----
  	TupleTableSlot *slot;
  	ExprContext *econtext;
  	uint32		hashvalue;
+ 	MinimalTuple mintuple;
+ 	int partitionNumber;
  
  	/* must provide our own instrumentation support */
  	if (node->ps.instrument)
***************
*** 99,106 ****
  		if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false, false,
  								 &hashvalue))
  		{
! 			ExecHashTableInsert(hashtable, slot, hashvalue);
! 			hashtable->totalTuples += 1;
  		}
  	}
  
--- 207,240 ----
  		if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false, false,
  								 &hashvalue))
  		{
! 			partitionNumber = MCV_INVALID_PARTITION;
! 
! 			if (hashtable->usingMostCommonValues && isAMostCommonValue(hashtable, hashvalue, &partitionNumber))
! 			{
! 				HashJoinTuple hashTuple;
! 				int			hashTupleSize;
! 				
! 				mintuple = ExecFetchSlotMinimalTuple(slot);
! 				hashTupleSize = HJTUPLE_OVERHEAD + mintuple->t_len;
! 				hashTuple = (HashJoinTuple) palloc(hashTupleSize);
! 				hashTuple->hashvalue = hashvalue;
! 				memcpy(HJTUPLE_MINTUPLE(hashTuple), mintuple, mintuple->t_len);
! 
! 				hashTuple->next = hashtable->mostCommonTuplePartition[partitionNumber].tuples;
! 				hashtable->mostCommonTuplePartition[partitionNumber].tuples = hashTuple;
! 				
! 				hashtable->spaceUsed += hashTupleSize;
! 				
! 				hashtable->mostCommonTuplesStored++;
! 				
! 				while (hashtable->spaceUsed > hashtable->spaceAllowed && freezeNextMCVPartiton(hashtable)) {}
! 			}
! 
! 			if (partitionNumber == MCV_INVALID_PARTITION)
! 			{
! 				ExecHashTableInsert(hashtable, slot, hashvalue);
! 				hashtable->totalTuples += 1;
! 			}
  		}
  	}
  
***************
*** 461,466 ****
--- 595,606 ----
  			BufFileClose(hashtable->outerBatchFile[i]);
  	}
  
+ 	if (hashtable->usingMostCommonValues)
+ 	{
+ 		pfree(hashtable->mostCommonTuplePartition);
+ 		pfree(hashtable->flushOrderedMostCommonTuplePartition);
+ 	}
+ 
  	/* Release working memory (batchCxt is a child, so it goes away too) */
  	MemoryContextDelete(hashtable->hashCxt);
  
***************
*** 798,803 ****
--- 938,1005 ----
  }
  
  /*
+  * ExecScanHashMostCommonTuples
+  *		scan a hash bucket for matches to the current outer tuple
+  *
+  * The current outer tuple must be stored in econtext->ecxt_outertuple.
+  */
+ HashJoinTuple
+ ExecScanHashMostCommonTuples(HashJoinState *hjstate,
+ 				   ExprContext *econtext)
+ {
+ 	List	   *hjclauses = hjstate->hashclauses;
+ 	HashJoinTable hashtable = hjstate->hj_HashTable;
+ 	HashJoinTuple hashTuple = hjstate->hj_CurTuple;
+ 	uint32		hashvalue = hjstate->hj_CurHashValue;
+ 
+ 	/*
+ 	 * hj_CurTuple is NULL to start scanning a new bucket, or the address of
+ 	 * the last tuple returned from the current bucket.
+ 	 */
+ 	if (hashTuple == NULL)
+ 	{
+ 		//painstakingly make sure this is a valid partition index
+ 		Assert(hjstate->hj_OuterTupleMostCommonValuePartition > MCV_INVALID_PARTITION);
+ 		Assert(hjstate->hj_OuterTupleMostCommonValuePartition < hashtable->nMostCommonTuplePartitionHashBuckets);
+ 		Assert(hashtable->mostCommonTuplePartition[hjstate->hj_OuterTupleMostCommonValuePartition].hashvalue != 0);
+ 
+ 		hashTuple = hashtable->mostCommonTuplePartition[hjstate->hj_OuterTupleMostCommonValuePartition].tuples;
+ 	}
+ 	else
+ 		hashTuple = hashTuple->next;
+ 
+ 	while (hashTuple != NULL)
+ 	{
+ 		if (hashTuple->hashvalue == hashvalue)
+ 		{
+ 			TupleTableSlot *inntuple;
+ 
+ 			/* insert hashtable's tuple into exec slot so ExecQual sees it */
+ 			inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
+ 											 hjstate->hj_HashTupleSlot,
+ 											 false);	/* do not pfree */
+ 			econtext->ecxt_innertuple = inntuple;
+ 
+ 			/* reset temp memory each time to avoid leaks from qual expr */
+ 			ResetExprContext(econtext);
+ 
+ 			if (ExecQual(hjclauses, econtext, false))
+ 			{
+ 				hjstate->hj_CurTuple = hashTuple;
+ 				return hashTuple;
+ 			}
+ 		}
+ 
+ 		hashTuple = hashTuple->next;
+ 	}
+ 
+ 	/*
+ 	 * no match
+ 	 */
+ 	return NULL;
+ }
+ 
+ /*
   * ExecScanHashBucket
   *		scan a hash bucket for matches to the current outer tuple
   *
Index: src/backend/executor/nodeHashjoin.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v
retrieving revision 1.96
diff -c -r1.96 nodeHashjoin.c
*** src/backend/executor/nodeHashjoin.c	23 Oct 2008 14:34:34 -0000	1.96
--- src/backend/executor/nodeHashjoin.c	24 Nov 2008 12:35:29 -0000
***************
*** 20,25 ****
--- 20,30 ----
  #include "executor/nodeHash.h"
  #include "executor/nodeHashjoin.h"
  #include "utils/memutils.h"
+ #include "optimizer/cost.h"
+ #include "utils/syscache.h"
+ #include "utils/lsyscache.h"
+ #include "parser/parsetree.h"
+ #include "catalog/pg_statistic.h"
  
  
  /* Returns true for JOIN_LEFT and JOIN_ANTI jointypes */
***************
*** 34,39 ****
--- 39,149 ----
  						  TupleTableSlot *tupleSlot);
  static int	ExecHashJoinNewBatch(HashJoinState *hjstate);
  
+ /*
+ *          getMostCommonValues
+ *
+ *          
+ */
+ void getMostCommonValues(EState *estate, HashJoinState *hjstate)
+ {
+ 	HeapTupleData *statsTuple;
+ 	FuncExprState *clause;
+ 	ExprState *argstate;
+ 	Var *variable;
+ 
+ 	Datum	   *values;
+ 	int			nvalues;
+ 	float4	   *numbers;
+ 	int			nnumbers;
+ 
+ 	Oid relid;
+ 	AttrNumber relattnum;
+ 	Oid atttype;
+ 	int32 atttypmod;
+ 
+ 	int i;
+ 
+ 	//is it a join on more than one key?
+ 	if (hjstate->hashclauses->length != 1)
+ 		return; //histojoin is not defined for more than one join key so run away
+ 
+ 	//make sure the outer node is a seq scan on a base relation otherwise we cant get MCVs at the moment and should not bother trying
+ 	if (outerPlanState(hjstate)->type != T_SeqScanState)
+ 		return;
+ 	
+ 	//grab the relation object id of the outer relation
+ 	relid = getrelid(((SeqScan *) ((SeqScanState *) outerPlanState(hjstate))->ps.plan)->scanrelid, estate->es_range_table);
+ 	clause = (FuncExprState *) lfirst(list_head(hjstate->hashclauses));
+ 	argstate = (ExprState *) lfirst(list_head(clause->args));
+ 	variable = (Var *) argstate->expr;
+ 
+ 	//grab the necessary properties of the join variable
+ 	relattnum = variable->varattno;
+ 	atttype = variable->vartype;
+ 	atttypmod = variable->vartypmod;
+ 
+ 	statsTuple = SearchSysCache(STATRELATT,
+ 		ObjectIdGetDatum(relid),
+ 		Int16GetDatum(relattnum),
+ 		0, 0);
+ 
+ 	if (HeapTupleIsValid(statsTuple))
+ 	{
+ 		if (get_attstatsslot(statsTuple,
+ 			atttype, atttypmod,
+ 			STATISTIC_KIND_MCV, InvalidOid,
+ 			&values, &nvalues,
+ 			&numbers, &nnumbers))
+ 		{
+ 			HashJoinTable hashtable;
+ 			FmgrInfo   *hashfunctions;
+ 			//MCV Partitions is an open addressing hashtable with a power of 2 size greater than the number of MCV values
+ 			int nbuckets = 2;
+ 			uint32 collisionsWhileHashing = 0;
+ 			while (nbuckets <= nvalues)
+ 			{
+ 				nbuckets <<= 1;
+ 			}
+ 			//use two more bit just to help avoid collisions
+ 			nbuckets <<= 2;
+ 
+ 			hashtable = hjstate->hj_HashTable;
+ 			hashtable->usingMostCommonValues = true;
+ 			hashtable->nMostCommonTuplePartitionHashBuckets = nbuckets;
+ 			hashtable->mostCommonTuplePartition = palloc0(nbuckets * sizeof(HashJoinMostCommonValueTuplePartition));
+ 			hashtable->flushOrderedMostCommonTuplePartition = palloc0(nvalues * sizeof(HashJoinMostCommonValueTuplePartition*));
+ 			hashfunctions = hashtable->outer_hashfunctions;
+ 
+ 			//create the partitions
+ 			for (i = 0; i < nvalues; i++)
+ 			{
+ 				uint32 hashvalue = DatumGetUInt32(FunctionCall1(&hashfunctions[0], values[i]));
+ 				int bucket = hashvalue & (nbuckets - 1);
+ 
+ 				while (hashtable->mostCommonTuplePartition[bucket].hashvalue != 0
+ 					&& hashtable->mostCommonTuplePartition[bucket].hashvalue != hashvalue)
+ 				{
+ 					bucket = (bucket + 1) & (nbuckets - 1);
+ 					collisionsWhileHashing++;
+ 				}
+ 
+ 				//leave partition alone if it has the same hashvalue as current MCV.  we only want one partition per hashvalue
+ 				if (hashtable->mostCommonTuplePartition[bucket].hashvalue != hashvalue)
+ 				{
+ 					hashtable->mostCommonTuplePartition[bucket].tuples = NULL;
+ 					hashtable->mostCommonTuplePartition[bucket].hashvalue = hashvalue;
+ 					hashtable->mostCommonTuplePartition[bucket].frozen = false;
+ +					hashtable->flushOrderedMostCommonTuplePartition[hashtable->nMostCommonTuplePartitions] = &hashtable->mostCommonTuplePartition[bucket];
+ 					hashtable->nMostCommonTuplePartitions++;
+ 				}
+ 			}
+ 
+ 			free_attstatsslot(atttype, values, nvalues, numbers, nnumbers);
+ 		}
+ 
+ 		ReleaseSysCache(statsTuple);
+ 	}
+ }
  
  /* ----------------------------------------------------------------
   *		ExecHashJoin
***************
*** 146,151 ****
--- 256,271 ----
  		hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan,
  										node->hj_HashOperators);
  		node->hj_HashTable = hashtable;
+ 		
+ 		hashtable->usingMostCommonValues = false;
+ 		hashtable->nMostCommonTuplePartitions = 0;
+ 		hashtable->nMostCommonTuplePartitionHashBuckets = 0;
+ 		hashtable->mostCommonTuplesStored = 0;
+ 		hashtable->mostCommonTuplePartition = NULL;
+ 		hashtable->nMostCommonTuplePartitionsFlushed = 0;
+ 
+ 		if (hashtable->nbatch > 1 && enable_hashjoin_usestatmcvs)
+ 			getMostCommonValues(estate, node);
  
  		/*
  		 * execute the Hash node, to build the hash table
***************
*** 157,163 ****
  		 * If the inner relation is completely empty, and we're not doing an
  		 * outer join, we can quit without scanning the outer relation.
  		 */
! 		if (hashtable->totalTuples == 0 && !HASHJOIN_IS_OUTER(node))
  			return NULL;
  
  		/*
--- 277,283 ----
  		 * If the inner relation is completely empty, and we're not doing an
  		 * outer join, we can quit without scanning the outer relation.
  		 */
! 		if (hashtable->totalTuples == 0 && hashtable->mostCommonTuplesStored == 0 && !HASHJOIN_IS_OUTER(node))
  			return NULL;
  
  		/*
***************
*** 205,227 ****
  			ExecHashGetBucketAndBatch(hashtable, hashvalue,
  									  &node->hj_CurBucketNo, &batchno);
  			node->hj_CurTuple = NULL;
! 
! 			/*
! 			 * Now we've got an outer tuple and the corresponding hash bucket,
! 			 * but this tuple may not belong to the current batch.
! 			 */
! 			if (batchno != hashtable->curbatch)
  			{
  				/*
! 				 * Need to postpone this outer tuple to a later batch. Save it
! 				 * in the corresponding outer-batch file.
  				 */
! 				Assert(batchno > hashtable->curbatch);
! 				ExecHashJoinSaveTuple(ExecFetchSlotMinimalTuple(outerTupleSlot),
! 									  hashvalue,
! 									  &hashtable->outerBatchFile[batchno]);
! 				node->hj_NeedNewOuter = true;
! 				continue;		/* loop around for a new outer tuple */
  			}
  		}
  
--- 325,353 ----
  			ExecHashGetBucketAndBatch(hashtable, hashvalue,
  									  &node->hj_CurBucketNo, &batchno);
  			node->hj_CurTuple = NULL;
! 			
! 			node->hj_OuterTupleMostCommonValuePartition = MCV_INVALID_PARTITION;
! 			
! 			
! 			if (!(hashtable->usingMostCommonValues && isAMostCommonValue(hashtable, hashvalue, &node->hj_OuterTupleMostCommonValuePartition)))
  			{
  				/*
! 				 * Now we've got an outer tuple and the corresponding hash bucket,
! 				 * but this tuple may not belong to the current batch.
  				 */
! 				if (batchno != hashtable->curbatch)
! 				{
! 					/*
! 					 * Need to postpone this outer tuple to a later batch. Save it
! 					 * in the corresponding outer-batch file.
! 					 */
! 					Assert(batchno > hashtable->curbatch);
! 					ExecHashJoinSaveTuple(ExecFetchSlotMinimalTuple(outerTupleSlot),
! 										  hashvalue,
! 										  &hashtable->outerBatchFile[batchno]);
! 					node->hj_NeedNewOuter = true;
! 					continue;		/* loop around for a new outer tuple */
! 				}
  			}
  		}
  
***************
*** 230,236 ****
  		 */
  		for (;;)
  		{
! 			curtuple = ExecScanHashBucket(node, econtext);
  			if (curtuple == NULL)
  				break;			/* out of matches */
  
--- 356,369 ----
  		 */
  		for (;;)
  		{
! 			if (node->hj_OuterTupleMostCommonValuePartition != MCV_INVALID_PARTITION)
! 			{
! 				curtuple = ExecScanHashMostCommonTuples(node, econtext);
! 			}
! 			else
! 			{
! 				curtuple = ExecScanHashBucket(node, econtext);
! 			}
  			if (curtuple == NULL)
  				break;			/* out of matches */
  
Index: src/backend/optimizer/path/costsize.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v
retrieving revision 1.201
diff -c -r1.201 costsize.c
*** src/backend/optimizer/path/costsize.c	22 Nov 2008 22:47:05 -0000	1.201
--- src/backend/optimizer/path/costsize.c	24 Nov 2008 12:15:00 -0000
***************
*** 109,114 ****
--- 109,116 ----
  bool		enable_mergejoin = true;
  bool		enable_hashjoin = true;
  
+ bool		enable_hashjoin_usestatmcvs = true;
+ 
  typedef struct
  {
  	PlannerInfo *root;
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.481
diff -c -r1.481 guc.c
*** src/backend/utils/misc/guc.c	21 Nov 2008 20:14:27 -0000	1.481
--- src/backend/utils/misc/guc.c	24 Nov 2008 12:15:05 -0000
***************
*** 636,641 ****
--- 636,649 ----
  		true, NULL, NULL
  	},
  	{
+ 		{"enable_hashjoin_usestatmcvs", PGC_USERSET, QUERY_TUNING_METHOD,
+ 			gettext_noop("Enables the hash join's use of the MCVs stored in pg_statistic."),
+ 			NULL
+ 		},
+ 		&enable_hashjoin_usestatmcvs,
+ 		true, NULL, NULL
+ 	},
+ 	{
  		{"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
  			gettext_noop("Enables the planner to use constraints to optimize queries."),
  			gettext_noop("Child table scans will be skipped if their "
Index: src/include/executor/hashjoin.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/executor/hashjoin.h,v
retrieving revision 1.48
diff -c -r1.48 hashjoin.h
*** src/include/executor/hashjoin.h	1 Jan 2008 19:45:57 -0000	1.48
--- src/include/executor/hashjoin.h	24 Nov 2008 12:40:18 -0000
***************
*** 72,77 ****
--- 72,85 ----
  #define HJTUPLE_MINTUPLE(hjtup)  \
  	((MinimalTuple) ((char *) (hjtup) + HJTUPLE_OVERHEAD))
  
+ typedef struct HashJoinMostCommonValueTuplePartition
+ {
+ 	uint32 hashvalue;
+ 	bool frozen;
+ 	HashJoinTuple tuples;
+ } HashJoinMostCommonValueTuplePartition;
+ 
+ #define MCV_INVALID_PARTITION -1
  
  typedef struct HashJoinTableData
  {
***************
*** 116,121 ****
--- 124,137 ----
  
  	MemoryContext hashCxt;		/* context for whole-hash-join storage */
  	MemoryContext batchCxt;		/* context for this-batch-only storage */
+ 	
+ 	bool usingMostCommonValues;
+ 	HashJoinMostCommonValueTuplePartition *mostCommonTuplePartition;
+ 	HashJoinMostCommonValueTuplePartition **flushOrderedMostCommonTuplePartition;
+ 	int nMostCommonTuplePartitionHashBuckets;
+ 	int nMostCommonTuplePartitions;
+ 	int nMostCommonTuplePartitionsFlushed;
+ 	uint32 mostCommonTuplesStored;
  } HashJoinTableData;
  
  #endif   /* HASHJOIN_H */
Index: src/include/executor/nodeHash.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/executor/nodeHash.h,v
retrieving revision 1.45
diff -c -r1.45 nodeHash.h
*** src/include/executor/nodeHash.h	1 Jan 2008 19:45:57 -0000	1.45
--- src/include/executor/nodeHash.h	30 Sep 2008 20:31:35 -0000
***************
*** 45,48 ****
--- 45,51 ----
  						int *numbuckets,
  						int *numbatches);
  
+ extern HashJoinTuple ExecScanHashMostCommonTuples(HashJoinState *hjstate, ExprContext *econtext);
+ extern bool isAMostCommonValue(HashJoinTable hashtable, uint32 hashvalue, int *partitionNumber);
+ 
  #endif   /* NODEHASH_H */
Index: src/include/executor/nodeHashjoin.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/executor/nodeHashjoin.h,v
retrieving revision 1.37
diff -c -r1.37 nodeHashjoin.h
*** src/include/executor/nodeHashjoin.h	1 Jan 2008 19:45:57 -0000	1.37
--- src/include/executor/nodeHashjoin.h	30 Sep 2008 20:32:05 -0000
***************
*** 26,29 ****
--- 26,31 ----
  extern void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
  					  BufFile **fileptr);
  
+ extern void getMostCommonValues(EState *estate, HashJoinState *hjstate);
+ 
  #endif   /* NODEHASHJOIN_H */
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.196
diff -c -r1.196 execnodes.h
*** src/include/nodes/execnodes.h	16 Nov 2008 17:34:28 -0000	1.196
--- src/include/nodes/execnodes.h	17 Nov 2008 20:05:27 -0000
***************
*** 1392,1397 ****
--- 1392,1398 ----
  	bool		hj_NeedNewOuter;
  	bool		hj_MatchedOuter;
  	bool		hj_OuterNotEmpty;
+ 	int		hj_OuterTupleMostCommonValuePartition;
  } HashJoinState;
  
  
Index: src/include/optimizer/cost.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/optimizer/cost.h,v
retrieving revision 1.93
diff -c -r1.93 cost.h
*** src/include/optimizer/cost.h	4 Oct 2008 21:56:55 -0000	1.93
--- src/include/optimizer/cost.h	7 Oct 2008 18:31:42 -0000
***************
*** 52,57 ****
--- 52,58 ----
  extern bool enable_nestloop;
  extern bool enable_mergejoin;
  extern bool enable_hashjoin;
+ extern bool enable_hashjoin_usestatmcvs;
  extern bool constraint_exclusion;
  
  extern double clamp_row_est(double nrows);
