diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 3b527a7ecbd51f034a927b74d70387e85d296264..a86ba6089a49395d072dc5fb99fddfd78569512a 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.221 2009/07/03 19:14:25 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.222 2009/07/16 20:55:44 tgl Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -2149,7 +2149,23 @@ archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"'  # Windows
        </para>
       </listitem>
      </varlistentry>
-     
+
+     <varlistentry id="guc-geqo-seed" xreflabel="geqo_seed">
+      <term><varname>geqo_seed</varname> (<type>floating point</type>)</term>
+      <indexterm>
+       <primary><varname>geqo_seed</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Controls the initial value of the random number generator used
+        by GEQO to select random paths through the join order search space.
+        The value can range from zero (the default) to one.  Varying the
+        value changes the set of join paths explored, and may result in a
+        better or worse best path being found.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
      <sect2 id="runtime-config-query-other">
diff --git a/doc/src/sgml/geqo.sgml b/doc/src/sgml/geqo.sgml
index 2f680762c13bb45c3b85bbba5c43011de112eb4b..97961272a4ae97150f6d1518b34d40523cf25a04 100644
--- a/doc/src/sgml/geqo.sgml
+++ b/doc/src/sgml/geqo.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.40 2007/07/21 04:02:41 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/geqo.sgml,v 1.41 2009/07/16 20:55:44 tgl Exp $ -->
 
  <chapter id="geqo">
   <chapterinfo>
@@ -49,7 +49,7 @@
     methods</firstterm> (e.g., nested loop, hash join, merge join in
     <productname>PostgreSQL</productname>) to process individual joins
     and a diversity of <firstterm>indexes</firstterm> (e.g.,
-    B-tree, hash, GiST and GIN in <productname>PostgreSQL</productname>) as 
+    B-tree, hash, GiST and GIN in <productname>PostgreSQL</productname>) as
     access paths for relations.
    </para>
 
@@ -88,8 +88,7 @@
 
    <para>
     The genetic algorithm (<acronym>GA</acronym>) is a heuristic optimization method which
-    operates through
-    nondeterministic, randomized search. The set of possible solutions for the
+    operates through randomized search. The set of possible solutions for the
     optimization problem is considered as a
     <firstterm>population</firstterm> of <firstterm>individuals</firstterm>.
     The degree of adaptation of an individual to its environment is specified
@@ -116,7 +115,7 @@
     According to the <systemitem class="resource">comp.ai.genetic</> <acronym>FAQ</acronym> it cannot be stressed too
     strongly that a <acronym>GA</acronym> is not a pure random search for a solution to a
     problem. A <acronym>GA</acronym> uses stochastic processes, but the result is distinctly
-    non-random (better than random). 
+    non-random (better than random).
    </para>
 
    <figure id="geqo-diagram">
@@ -260,9 +259,13 @@
    <para>
     This process is inherently nondeterministic, because of the randomized
     choices made during both the initial population selection and subsequent
-    <quote>mutation</> of the best candidates.  Hence different plans may
-    be selected from one run to the next, resulting in varying run time
-    and varying output row order.
+    <quote>mutation</> of the best candidates.  To avoid surprising changes
+    of the selected plan, each run of the GEQO algorithm restarts its
+    random number generator with the current <xref linkend="guc-geqo-seed">
+    parameter setting.  As long as <varname>geqo_seed</> and the other
+    GEQO parameters are kept fixed, the same plan will be generated for a
+    given query (and other planner inputs such as statistics).  To experiment
+    with different search paths, try changing <varname>geqo_seed</>.
    </para>
 
   </sect2>
@@ -330,7 +333,7 @@
       url="news://comp.ai.genetic"></ulink>)
      </para>
     </listitem>
-   
+
     <listitem>
      <para>
       <ulink url="http://www.red3d.com/cwr/evolve.html">
diff --git a/src/backend/optimizer/geqo/Makefile b/src/backend/optimizer/geqo/Makefile
index becc95f2ef4378b6fb2bd4f7d231a18c8debfc93..9ccfd9e60c85934e5c1da1494f6cc0864770912d 100644
--- a/src/backend/optimizer/geqo/Makefile
+++ b/src/backend/optimizer/geqo/Makefile
@@ -5,7 +5,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/backend/optimizer/geqo/Makefile,v 1.20 2008/02/19 10:30:07 petere Exp $
+# $PostgreSQL: pgsql/src/backend/optimizer/geqo/Makefile,v 1.21 2009/07/16 20:55:44 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,7 +14,7 @@ top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS =	geqo_copy.o geqo_eval.o geqo_main.o geqo_misc.o \
-	geqo_mutation.o geqo_pool.o geqo_recombination.o \
+	geqo_mutation.o geqo_pool.o geqo_random.o geqo_recombination.o \
 	geqo_selection.o \
 	geqo_erx.o geqo_pmx.o geqo_cx.o geqo_px.o geqo_ox1.o geqo_ox2.o
 
diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c
index 8e4aab214d6af73e3dbed04d36afca00de2d247f..1c7498c959ca0b851c036be47f83f7ce9fecd485 100644
--- a/src/backend/optimizer/geqo/geqo_copy.c
+++ b/src/backend/optimizer/geqo/geqo_copy.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_copy.c,v 1.19 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_copy.c,v 1.20 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,8 @@
  *
  */
 void
-geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length)
+geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2,
+		  int string_length)
 {
 	int			i;
 
diff --git a/src/backend/optimizer/geqo/geqo_cx.c b/src/backend/optimizer/geqo/geqo_cx.c
index 616ff41fb9734fe7a37c419adc943713b37675f0..9f3dfe216e0c49686e9086a3102c21cd25f1fc82 100644
--- a/src/backend/optimizer/geqo/geqo_cx.c
+++ b/src/backend/optimizer/geqo/geqo_cx.c
@@ -6,7 +6,7 @@
 *	 CX operator according to Oliver et al
 *	 (Proc 2nd Int'l Conf on GA's)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_cx.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_cx.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -44,7 +44,8 @@
  *	 cycle crossover
  */
 int
-cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+cx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
+   int num_gene, City *city_table)
 {
 
 	int			i,
@@ -62,7 +63,7 @@ cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 	}
 
 	/* choose random cycle starting position */
-	start_pos = geqo_randint(num_gene - 1, 0);
+	start_pos = geqo_randint(root, num_gene - 1, 0);
 
 	/* child inherits first city  */
 	offspring[start_pos] = tour1[start_pos];
diff --git a/src/backend/optimizer/geqo/geqo_erx.c b/src/backend/optimizer/geqo/geqo_erx.c
index 9c7a34258582d08f421780c7e9ca72bd1de95ff8..45effbdad95c93cc1ddf6800860ee9ddcc15cfec 100644
--- a/src/backend/optimizer/geqo/geqo_erx.c
+++ b/src/backend/optimizer/geqo/geqo_erx.c
@@ -3,7 +3,7 @@
 * geqo_erx.c
 *	 edge recombination crossover [ER]
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_erx.c,v 1.20 2005/10/15 02:49:19 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_erx.c,v 1.21 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -36,11 +36,11 @@
 #include "optimizer/geqo_random.h"
 
 
-static int	gimme_edge(Gene gene1, Gene gene2, Edge *edge_table);
-static void remove_gene(Gene gene, Edge edge, Edge *edge_table);
-static Gene gimme_gene(Edge edge, Edge *edge_table);
+static int	gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table);
+static void remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table);
+static Gene gimme_gene(PlannerInfo *root, Edge edge, Edge *edge_table);
 
-static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene);
+static Gene edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene);
 
 
 /* alloc_edge_table
@@ -50,7 +50,7 @@ static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene);
  */
 
 Edge *
-alloc_edge_table(int num_gene)
+alloc_edge_table(PlannerInfo *root, int num_gene)
 {
 	Edge	   *edge_table;
 
@@ -70,7 +70,7 @@ alloc_edge_table(int num_gene)
  *
  */
 void
-free_edge_table(Edge *edge_table)
+free_edge_table(PlannerInfo *root, Edge *edge_table)
 {
 	pfree(edge_table);
 }
@@ -89,7 +89,8 @@ free_edge_table(Edge *edge_table)
  *
  */
 float
-gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
+gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
+				 int num_gene, Edge *edge_table)
 {
 	int			i,
 				index1,
@@ -121,11 +122,11 @@ gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
 		 * twice per edge
 		 */
 
-		edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table);
-		gimme_edge(tour1[index2], tour1[index1], edge_table);
+		edge_total += gimme_edge(root, tour1[index1], tour1[index2], edge_table);
+		gimme_edge(root, tour1[index2], tour1[index1], edge_table);
 
-		edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table);
-		gimme_edge(tour2[index2], tour2[index1], edge_table);
+		edge_total += gimme_edge(root, tour2[index1], tour2[index2], edge_table);
+		gimme_edge(root, tour2[index2], tour2[index1], edge_table);
 	}
 
 	/* return average number of edges per index */
@@ -147,7 +148,7 @@ gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
  *			  0 if edge was already registered and edge_table is unchanged
  */
 static int
-gimme_edge(Gene gene1, Gene gene2, Edge *edge_table)
+gimme_edge(PlannerInfo *root, Gene gene1, Gene gene2, Edge *edge_table)
 {
 	int			i;
 	int			edges;
@@ -189,13 +190,13 @@ gimme_edge(Gene gene1, Gene gene2, Edge *edge_table)
  *
  */
 int
-gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
+gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene, int num_gene)
 {
 	int			i;
 	int			edge_failures = 0;
 
-	new_gene[0] = (Gene) geqo_randint(num_gene, 1);		/* choose int between 1
-														 * and num_gene */
+	/* choose int between 1 and num_gene */
+	new_gene[0] = (Gene) geqo_randint(root, num_gene, 1);
 
 	for (i = 1; i < num_gene; i++)
 	{
@@ -204,18 +205,18 @@ gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
 		 * table
 		 */
 
-		remove_gene(new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);
+		remove_gene(root, new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);
 
 		/* find destination for the newly entered point */
 
 		if (edge_table[new_gene[i - 1]].unused_edges > 0)
-			new_gene[i] = gimme_gene(edge_table[(int) new_gene[i - 1]], edge_table);
+			new_gene[i] = gimme_gene(root, edge_table[(int) new_gene[i - 1]], edge_table);
 
 		else
 		{						/* cope with fault */
 			edge_failures++;
 
-			new_gene[i] = edge_failure(new_gene, i - 1, edge_table, num_gene);
+			new_gene[i] = edge_failure(root, new_gene, i - 1, edge_table, num_gene);
 		}
 
 		/* mark this node as incorporated */
@@ -235,7 +236,7 @@ gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene)
  *
  */
 static void
-remove_gene(Gene gene, Edge edge, Edge *edge_table)
+remove_gene(PlannerInfo *root, Gene gene, Edge edge, Edge *edge_table)
 {
 	int			i,
 				j;
@@ -277,7 +278,7 @@ remove_gene(Gene gene, Edge edge, Edge *edge_table)
  *
  */
 static Gene
-gimme_gene(Edge edge, Edge *edge_table)
+gimme_gene(PlannerInfo *root, Edge edge, Edge *edge_table)
 {
 	int			i;
 	Gene		friend;
@@ -340,7 +341,7 @@ gimme_gene(Edge edge, Edge *edge_table)
 
 
 	/* random decision of the possible candidates to use */
-	rand_decision = (int) geqo_randint(minimum_count - 1, 0);
+	rand_decision = geqo_randint(root, minimum_count - 1, 0);
 
 
 	for (i = 0; i < edge.unused_edges; i++)
@@ -368,7 +369,7 @@ gimme_gene(Edge edge, Edge *edge_table)
  *
  */
 static Gene
-edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
+edge_failure(PlannerInfo *root, Gene *gene, int index, Edge *edge_table, int num_gene)
 {
 	int			i;
 	Gene		fail_gene = gene[index];
@@ -401,7 +402,7 @@ edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
 	if (four_count != 0)
 	{
 
-		rand_decision = (int) geqo_randint(four_count - 1, 0);
+		rand_decision = geqo_randint(root, four_count - 1, 0);
 
 		for (i = 1; i <= num_gene; i++)
 		{
@@ -423,7 +424,7 @@ edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene)
 	else if (remaining_edges != 0)
 	{
 		/* random decision of the gene with remaining edges */
-		rand_decision = (int) geqo_randint(remaining_edges - 1, 0);
+		rand_decision = geqo_randint(root, remaining_edges - 1, 0);
 
 		for (i = 1; i <= num_gene; i++)
 		{
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index 392cfc5aa318c399077866a9512701a1330fa168..226d64a94d96a7b36ed6f3ea53ff43159ecf50c6 100644
--- a/src/backend/optimizer/geqo/geqo_eval.c
+++ b/src/backend/optimizer/geqo/geqo_eval.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.88 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.89 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,7 @@ static bool desirable_join(PlannerInfo *root,
  * Returns cost of a query tree as an individual of the population.
  */
 Cost
-geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
+geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
 {
 	MemoryContext mycontext;
 	MemoryContext oldcxt;
@@ -94,13 +94,13 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 	 * (If we are dealing with enough join rels, which we very likely are, a
 	 * new hash table will get built and used locally.)
 	 */
-	savelength = list_length(evaldata->root->join_rel_list);
-	savehash = evaldata->root->join_rel_hash;
+	savelength = list_length(root->join_rel_list);
+	savehash = root->join_rel_hash;
 
-	evaldata->root->join_rel_hash = NULL;
+	root->join_rel_hash = NULL;
 
 	/* construct the best path for the given combination of relations */
-	joinrel = gimme_tree(tour, num_gene, evaldata);
+	joinrel = gimme_tree(root, tour, num_gene);
 
 	/*
 	 * compute fitness
@@ -117,9 +117,9 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 	 * Restore join_rel_list to its former state, and put back original
 	 * hashtable if any.
 	 */
-	evaldata->root->join_rel_list = list_truncate(evaldata->root->join_rel_list,
-												  savelength);
-	evaldata->root->join_rel_hash = savehash;
+	root->join_rel_list = list_truncate(root->join_rel_list,
+										savelength);
+	root->join_rel_hash = savehash;
 
 	/* release all the memory acquired within gimme_tree */
 	MemoryContextSwitchTo(oldcxt);
@@ -134,7 +134,6 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
  *	  order.
  *
  *	 'tour' is the proposed join order, of length 'num_gene'
- *	 'evaldata' contains the context we need
  *
  * Returns a new join relation whose cheapest path is the best plan for
  * this join order.  NB: will return NULL if join order is invalid.
@@ -153,8 +152,9 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
  * plans.
  */
 RelOptInfo *
-gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
+gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
 {
+	GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
 	RelOptInfo **stack;
 	int			stack_depth;
 	RelOptInfo *joinrel;
@@ -193,7 +193,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 
 		/* Get the next input relation and push it */
 		cur_rel_index = (int) tour[rel_count];
-		stack[stack_depth] = (RelOptInfo *) list_nth(evaldata->initial_rels,
+		stack[stack_depth] = (RelOptInfo *) list_nth(private->initial_rels,
 													 cur_rel_index - 1);
 		stack_depth++;
 
@@ -211,7 +211,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 			 * have exhausted the input, the heuristics can't prevent popping.
 			 */
 			if (rel_count < num_gene - 1 &&
-				!desirable_join(evaldata->root, outer_rel, inner_rel))
+				!desirable_join(root, outer_rel, inner_rel))
 				break;
 
 			/*
@@ -220,7 +220,7 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
 			 * root->join_rel_list yet, and so the paths constructed for it
 			 * will only include the ones we want.
 			 */
-			joinrel = make_join_rel(evaldata->root, outer_rel, inner_rel);
+			joinrel = make_join_rel(root, outer_rel, inner_rel);
 
 			/* Can't pop stack here if join order is not valid */
 			if (!joinrel)
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index 08b5b1a44db23dfc235bce0ceab21d5f459bb3b7..824ae7b610817bc96e73aac1e14049ceb1fb4bc8 100644
--- a/src/backend/optimizer/geqo/geqo_main.c
+++ b/src/backend/optimizer/geqo/geqo_main.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.56 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.57 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,9 @@
 #include <math.h>
 
 #include "optimizer/geqo_misc.h"
+#include "optimizer/geqo_mutation.h"
 #include "optimizer/geqo_pool.h"
+#include "optimizer/geqo_random.h"
 #include "optimizer/geqo_selection.h"
 
 
@@ -38,6 +40,7 @@ int			Geqo_effort;
 int			Geqo_pool_size;
 int			Geqo_generations;
 double		Geqo_selection_bias;
+double		Geqo_seed;
 
 
 static int	gimme_pool_size(int nr_rel);
@@ -63,7 +66,7 @@ static int	gimme_number_generations(int pool_size);
 RelOptInfo *
 geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 {
-	GeqoEvalData evaldata;
+	GeqoPrivateData private;
 	int			generation;
 	Chromosome *momma;
 	Chromosome *daddy;
@@ -88,9 +91,12 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 	int			mutations = 0;
 #endif
 
-/* set up evaldata */
-	evaldata.root = root;
-	evaldata.initial_rels = initial_rels;
+/* set up private information */
+	root->join_search_private = (void *) &private;
+	private.initial_rels = initial_rels;
+
+/* initialize private number generator */
+	geqo_set_seed(root, Geqo_seed);
 
 /* set GA parameters */
 	pool_size = gimme_pool_size(number_of_rels);
@@ -98,13 +104,13 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 	status_interval = 10;
 
 /* allocate genetic pool memory */
-	pool = alloc_pool(pool_size, number_of_rels);
+	pool = alloc_pool(root, pool_size, number_of_rels);
 
 /* random initialization of the pool */
-	random_init_pool(pool, &evaldata);
+	random_init_pool(root, pool);
 
 /* sort the pool according to cheapest path as fitness */
-	sort_pool(pool);			/* we have to do it only one time, since all
+	sort_pool(root, pool);		/* we have to do it only one time, since all
 								 * kids replace the worst individuals in
 								 * future (-> geqo_pool.c:spread_chromo ) */
 
@@ -116,49 +122,49 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 #endif
 
 /* allocate chromosome momma and daddy memory */
-	momma = alloc_chromo(pool->string_length);
-	daddy = alloc_chromo(pool->string_length);
+	momma = alloc_chromo(root, pool->string_length);
+	daddy = alloc_chromo(root, pool->string_length);
 
 #if defined (ERX)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using edge recombination crossover [ERX]");
 #endif
 /* allocate edge table memory */
-	edge_table = alloc_edge_table(pool->string_length);
+	edge_table = alloc_edge_table(root, pool->string_length);
 #elif defined(PMX)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using partially matched crossover [PMX]");
 #endif
 /* allocate chromosome kid memory */
-	kid = alloc_chromo(pool->string_length);
+	kid = alloc_chromo(root, pool->string_length);
 #elif defined(CX)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using cycle crossover [CX]");
 #endif
 /* allocate city table memory */
-	kid = alloc_chromo(pool->string_length);
-	city_table = alloc_city_table(pool->string_length);
+	kid = alloc_chromo(root, pool->string_length);
+	city_table = alloc_city_table(root, pool->string_length);
 #elif defined(PX)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using position crossover [PX]");
 #endif
 /* allocate city table memory */
-	kid = alloc_chromo(pool->string_length);
-	city_table = alloc_city_table(pool->string_length);
+	kid = alloc_chromo(root, pool->string_length);
+	city_table = alloc_city_table(root, pool->string_length);
 #elif defined(OX1)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using order crossover [OX1]");
 #endif
 /* allocate city table memory */
-	kid = alloc_chromo(pool->string_length);
-	city_table = alloc_city_table(pool->string_length);
+	kid = alloc_chromo(root, pool->string_length);
+	city_table = alloc_city_table(root, pool->string_length);
 #elif defined(OX2)
 #ifdef GEQO_DEBUG
 	elog(DEBUG2, "using order crossover [OX2]");
 #endif
 /* allocate city table memory */
-	kid = alloc_chromo(pool->string_length);
-	city_table = alloc_city_table(pool->string_length);
+	kid = alloc_chromo(root, pool->string_length);
+	city_table = alloc_city_table(root, pool->string_length);
 #endif
 
 
@@ -168,45 +174,45 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 	for (generation = 0; generation < number_generations; generation++)
 	{
 		/* SELECTION: using linear bias function */
-		geqo_selection(momma, daddy, pool, Geqo_selection_bias);
+		geqo_selection(root, momma, daddy, pool, Geqo_selection_bias);
 
 #if defined (ERX)
 		/* EDGE RECOMBINATION CROSSOVER */
-		difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table);
+		difference = gimme_edge_table(root, momma->string, daddy->string, pool->string_length, edge_table);
 
 		kid = momma;
 
 		/* are there any edge failures ? */
-		edge_failures += gimme_tour(edge_table, kid->string, pool->string_length);
+		edge_failures += gimme_tour(root, edge_table, kid->string, pool->string_length);
 #elif defined(PMX)
 		/* PARTIALLY MATCHED CROSSOVER */
-		pmx(momma->string, daddy->string, kid->string, pool->string_length);
+		pmx(root, momma->string, daddy->string, kid->string, pool->string_length);
 #elif defined(CX)
 		/* CYCLE CROSSOVER */
-		cycle_diffs = cx(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+		cycle_diffs = cx(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 		/* mutate the child */
 		if (cycle_diffs == 0)
 		{
 			mutations++;
-			geqo_mutation(kid->string, pool->string_length);
+			geqo_mutation(root, kid->string, pool->string_length);
 		}
 #elif defined(PX)
 		/* POSITION CROSSOVER */
-		px(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+		px(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 #elif defined(OX1)
 		/* ORDER CROSSOVER */
-		ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+		ox1(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 #elif defined(OX2)
 		/* ORDER CROSSOVER */
-		ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+		ox2(root, momma->string, daddy->string, kid->string, pool->string_length, city_table);
 #endif
 
 
 		/* EVALUATE FITNESS */
-		kid->worth = geqo_eval(kid->string, pool->string_length, &evaldata);
+		kid->worth = geqo_eval(root, kid->string, pool->string_length);
 
 		/* push the kid into the wilderness of life according to its worth */
-		spread_chromo(kid, pool);
+		spread_chromo(root, kid, pool);
 
 
 #ifdef GEQO_DEBUG
@@ -249,7 +255,7 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 	 */
 	best_tour = (Gene *) pool->data[0].string;
 
-	best_rel = gimme_tree(best_tour, pool->string_length, &evaldata);
+	best_rel = gimme_tree(root, best_tour, pool->string_length);
 
 	if (best_rel == NULL)
 		elog(ERROR, "failed to make a valid plan");
@@ -260,28 +266,31 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 #endif
 
 	/* ... free memory stuff */
-	free_chromo(momma);
-	free_chromo(daddy);
+	free_chromo(root, momma);
+	free_chromo(root, daddy);
 
 #if defined (ERX)
-	free_edge_table(edge_table);
+	free_edge_table(root, edge_table);
 #elif defined(PMX)
-	free_chromo(kid);
+	free_chromo(root, kid);
 #elif defined(CX)
-	free_chromo(kid);
-	free_city_table(city_table);
+	free_chromo(root, kid);
+	free_city_table(root, city_table);
 #elif defined(PX)
-	free_chromo(kid);
-	free_city_table(city_table);
+	free_chromo(root, kid);
+	free_city_table(root, city_table);
 #elif defined(OX1)
-	free_chromo(kid);
-	free_city_table(city_table);
+	free_chromo(root, kid);
+	free_city_table(root, city_table);
 #elif defined(OX2)
-	free_chromo(kid);
-	free_city_table(city_table);
+	free_chromo(root, kid);
+	free_city_table(root, city_table);
 #endif
 
-	free_pool(pool);
+	free_pool(root, pool);
+
+	/* ... clear root pointer to our private storage */
+	root->join_search_private = NULL;
 
 	return best_rel;
 }
diff --git a/src/backend/optimizer/geqo/geqo_mutation.c b/src/backend/optimizer/geqo/geqo_mutation.c
index 946eb117e3dd3c6653ff4bbae82be822e1a334ed..bd527324f5ac1cd0f688c95b4f220f8d5fc8c5f1 100644
--- a/src/backend/optimizer/geqo/geqo_mutation.c
+++ b/src/backend/optimizer/geqo/geqo_mutation.c
@@ -4,7 +4,7 @@
 *
 *	 TSP mutation routines
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_mutation.c,v 1.9 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_mutation.c,v 1.10 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -36,21 +36,21 @@
 #include "optimizer/geqo_random.h"
 
 void
-geqo_mutation(Gene *tour, int num_gene)
+geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene)
 {
 	int			swap1;
 	int			swap2;
-	int			num_swaps = geqo_randint(num_gene / 3, 0);
+	int			num_swaps = geqo_randint(root, num_gene / 3, 0);
 	Gene		temp;
 
 
 	while (num_swaps > 0)
 	{
-		swap1 = geqo_randint(num_gene - 1, 0);
-		swap2 = geqo_randint(num_gene - 1, 0);
+		swap1 = geqo_randint(root, num_gene - 1, 0);
+		swap2 = geqo_randint(root, num_gene - 1, 0);
 
 		while (swap1 == swap2)
-			swap2 = geqo_randint(num_gene - 1, 0);
+			swap2 = geqo_randint(root, num_gene - 1, 0);
 
 		temp = tour[swap1];
 		tour[swap1] = tour[swap2];
diff --git a/src/backend/optimizer/geqo/geqo_ox1.c b/src/backend/optimizer/geqo/geqo_ox1.c
index 268194e295cbfd888a1ef7f759c45beb943aa8a8..d11d3cd9c396b966094dff7dbc74b7d6705d7c7f 100644
--- a/src/backend/optimizer/geqo/geqo_ox1.c
+++ b/src/backend/optimizer/geqo/geqo_ox1.c
@@ -6,7 +6,7 @@
 *	 OX1 operator according to Davis
 *	 (Proc Int'l Joint Conf on AI)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox1.c,v 1.9 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox1.c,v 1.10 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,8 @@
  *	 position crossover
  */
 void
-ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox1(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
+	City *city_table)
 {
 	int			left,
 				right,
@@ -56,8 +57,8 @@ ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 		city_table[k].used = 0;
 
 	/* select portion to copy from tour1 */
-	left = geqo_randint(num_gene - 1, 0);
-	right = geqo_randint(num_gene - 1, 0);
+	left = geqo_randint(root, num_gene - 1, 0);
+	right = geqo_randint(root, num_gene - 1, 0);
 
 	if (left > right)
 	{
diff --git a/src/backend/optimizer/geqo/geqo_ox2.c b/src/backend/optimizer/geqo/geqo_ox2.c
index 0c31cccae52ba01b07b4c75ac85b9cdbb3edba21..48ed359a630a62f3eb881856fb3e84b28debd92f 100644
--- a/src/backend/optimizer/geqo/geqo_ox2.c
+++ b/src/backend/optimizer/geqo/geqo_ox2.c
@@ -6,7 +6,7 @@
 *	 OX2 operator according to Syswerda
 *	 (The Genetic Algorithms Handbook, ed L Davis)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox2.c,v 1.10 2004/10/07 15:21:52 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_ox2.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,7 @@
  *	 position crossover
  */
 void
-ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox2(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 {
 	int			k,
 				j,
@@ -60,12 +60,12 @@ ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 	}
 
 	/* determine the number of positions to be inherited from tour1  */
-	num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);
+	num_positions = geqo_randint(root, 2 * num_gene / 3, num_gene / 3);
 
 	/* make a list of selected cities */
 	for (k = 0; k < num_positions; k++)
 	{
-		pos = geqo_randint(num_gene - 1, 0);
+		pos = geqo_randint(root, num_gene - 1, 0);
 		city_table[pos].select_list = (int) tour1[pos];
 		city_table[(int) tour1[pos]].used = 1;	/* mark used */
 	}
diff --git a/src/backend/optimizer/geqo/geqo_pmx.c b/src/backend/optimizer/geqo/geqo_pmx.c
index dc52b731523e4a8054e4e8bcf5374889829ac9b1..a1f3d1019ec87f1e5e576e63012170b8efc56869 100644
--- a/src/backend/optimizer/geqo/geqo_pmx.c
+++ b/src/backend/optimizer/geqo/geqo_pmx.c
@@ -6,7 +6,7 @@
 *	 PMX operator according to Goldberg & Lingle
 *	 (Proc Int'l Conf on GA's)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pmx.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pmx.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,7 @@
  *	 partially matched crossover
  */
 void
-pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
+pmx(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
 {
 	int		   *failed = (int *) palloc((num_gene + 1) * sizeof(int));
 	int		   *from = (int *) palloc((num_gene + 1) * sizeof(int));
@@ -71,8 +71,8 @@ pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
 	}
 
 /* locate crossover points */
-	left = geqo_randint(num_gene - 1, 0);
-	right = geqo_randint(num_gene - 1, 0);
+	left = geqo_randint(root, num_gene - 1, 0);
+	right = geqo_randint(root, num_gene - 1, 0);
 
 	if (left > right)
 	{
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index 7562d2ee0b31aa5fdfcd3440d8ee5eae8e620ff9..26137272f70888556a6ce2643750e74651328f57 100644
--- a/src/backend/optimizer/geqo/geqo_pool.c
+++ b/src/backend/optimizer/geqo/geqo_pool.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.33 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.34 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,7 @@ static int	compare(const void *arg1, const void *arg2);
  *		allocates memory for GA pool
  */
 Pool *
-alloc_pool(int pool_size, int string_length)
+alloc_pool(PlannerInfo *root, int pool_size, int string_length)
 {
 	Pool	   *new_pool;
 	Chromosome *chromo;
@@ -66,7 +66,7 @@ alloc_pool(int pool_size, int string_length)
  *		deallocates memory for GA pool
  */
 void
-free_pool(Pool *pool)
+free_pool(PlannerInfo *root, Pool *pool)
 {
 	Chromosome *chromo;
 	int			i;
@@ -88,7 +88,7 @@ free_pool(Pool *pool)
  *		initialize genetic pool
  */
 void
-random_init_pool(Pool *pool, GeqoEvalData *evaldata)
+random_init_pool(PlannerInfo *root, Pool *pool)
 {
 	Chromosome *chromo = (Chromosome *) pool->data;
 	int			i;
@@ -105,10 +105,9 @@ random_init_pool(Pool *pool, GeqoEvalData *evaldata)
 	i = 0;
 	while (i < pool->size)
 	{
-		init_tour(chromo[i].string, pool->string_length);
-		pool->data[i].worth = geqo_eval(chromo[i].string,
-										pool->string_length,
-										evaldata);
+		init_tour(root, chromo[i].string, pool->string_length);
+		pool->data[i].worth = geqo_eval(root, chromo[i].string,
+										pool->string_length);
 		if (pool->data[i].worth < DBL_MAX)
 			i++;
 		else
@@ -133,7 +132,7 @@ random_init_pool(Pool *pool, GeqoEvalData *evaldata)
  *	 maybe you have to change compare() for different ordering ...
  */
 void
-sort_pool(Pool *pool)
+sort_pool(PlannerInfo *root, Pool *pool)
 {
 	qsort(pool->data, pool->size, sizeof(Chromosome), compare);
 }
@@ -160,7 +159,7 @@ compare(const void *arg1, const void *arg2)
  *	  allocates a chromosome and string space
  */
 Chromosome *
-alloc_chromo(int string_length)
+alloc_chromo(PlannerInfo *root, int string_length)
 {
 	Chromosome *chromo;
 
@@ -174,7 +173,7 @@ alloc_chromo(int string_length)
  *	  deallocates a chromosome and string space
  */
 void
-free_chromo(Chromosome *chromo)
+free_chromo(PlannerInfo *root, Chromosome *chromo)
 {
 	pfree(chromo->string);
 	pfree(chromo);
@@ -185,7 +184,7 @@ free_chromo(Chromosome *chromo)
  *	 assumes best->worst = smallest->largest
  */
 void
-spread_chromo(Chromosome *chromo, Pool *pool)
+spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool)
 {
 	int			top,
 				mid,
@@ -247,7 +246,7 @@ spread_chromo(Chromosome *chromo, Pool *pool)
 	 * copy new gene into pool storage; always replace worst gene in pool
 	 */
 
-	geqo_copy(&pool->data[pool->size - 1], chromo, pool->string_length);
+	geqo_copy(root, &pool->data[pool->size - 1], chromo, pool->string_length);
 
 	swap_chromo.string = pool->data[pool->size - 1].string;
 	swap_chromo.worth = pool->data[pool->size - 1].worth;
diff --git a/src/backend/optimizer/geqo/geqo_px.c b/src/backend/optimizer/geqo/geqo_px.c
index 8b6732b72247604a8fd1279c9aaa566ceab673ba..674529313a2be378536fed4aa28ed4bfc6c37b20 100644
--- a/src/backend/optimizer/geqo/geqo_px.c
+++ b/src/backend/optimizer/geqo/geqo_px.c
@@ -6,7 +6,7 @@
 *	 PX operator according to Syswerda
 *	 (The Genetic Algorithms Handbook, L Davis, ed)
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_px.c,v 1.10 2003/11/29 22:39:49 pgsql Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_px.c,v 1.11 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -43,7 +43,8 @@
  *	 position crossover
  */
 void
-px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene,
+   City *city_table)
 {
 
 	int			num_positions;
@@ -57,12 +58,12 @@ px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
 		city_table[i].used = 0;
 
 	/* choose random positions that will be inherited directly from parent */
-	num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);
+	num_positions = geqo_randint(root, 2 * num_gene / 3, num_gene / 3);
 
 	/* choose random position */
 	for (i = 0; i < num_positions; i++)
 	{
-		pos = geqo_randint(num_gene - 1, 0);
+		pos = geqo_randint(root, num_gene - 1, 0);
 
 		offspring[pos] = tour1[pos];	/* transfer cities to child */
 		city_table[(int) tour1[pos]].used = 1;	/* mark city used */
diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c
new file mode 100644
index 0000000000000000000000000000000000000000..025407e2d3983263401d56af86f1ec97661253a7
--- /dev/null
+++ b/src/backend/optimizer/geqo/geqo_random.c
@@ -0,0 +1,40 @@
+/*------------------------------------------------------------------------
+ *
+ * geqo_random.c
+ *	   random number generator
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_random.c,v 1.1 2009/07/16 20:55:44 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "optimizer/geqo_random.h"
+
+
+void
+geqo_set_seed(PlannerInfo *root, double seed)
+{
+	GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+
+	/*
+	 * XXX. This seeding algorithm could certainly be improved - but
+	 * it is not critical to do so.
+	 */
+	memset(private->random_state, 0, sizeof(private->random_state));
+	memcpy(private->random_state,
+		   &seed,
+		   Min(sizeof(private->random_state), sizeof(seed)));
+}
+
+double
+geqo_rand(PlannerInfo *root)
+{
+	GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
+
+	return erand48(private->random_state);
+}
diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c
index c73e5b2a79e4c3b806e56b462b284e510066ff9e..ebdd220383940e5fff8653cfb2af5250a8556397 100644
--- a/src/backend/optimizer/geqo/geqo_recombination.c
+++ b/src/backend/optimizer/geqo/geqo_recombination.c
@@ -3,7 +3,7 @@
 * geqo_recombination.c
 *	 misc recombination procedures
 *
-* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.15 2005/10/15 02:49:19 momjian Exp $
+* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.16 2009/07/16 20:55:44 tgl Exp $
 *
 *-------------------------------------------------------------------------
 */
@@ -35,7 +35,7 @@
  *	 and the procedure repeated.
  */
 void
-init_tour(Gene *tour, int num_gene)
+init_tour(PlannerInfo *root, Gene *tour, int num_gene)
 {
 	Gene	   *tmp;
 	int			remainder;
@@ -53,7 +53,7 @@ init_tour(Gene *tour, int num_gene)
 	for (i = 0; i < num_gene; i++)
 	{
 		/* choose value between 0 and remainder inclusive */
-		next = (int) geqo_randint(remainder, 0);
+		next = geqo_randint(root, remainder, 0);
 		/* output that element of the tmp array */
 		tour[i] = tmp[next];
 		/* and delete it */
@@ -81,7 +81,7 @@ init_tour(Gene *tour, int num_gene)
  *	 allocate memory for city table
  */
 City *
-alloc_city_table(int num_gene)
+alloc_city_table(PlannerInfo *root, int num_gene)
 {
 	City	   *city_table;
 
@@ -99,7 +99,7 @@ alloc_city_table(int num_gene)
  *	  deallocate memory of city table
  */
 void
-free_city_table(City *city_table)
+free_city_table(PlannerInfo *root, City *city_table)
 {
 	pfree(city_table);
 }
diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c
index 3febca3c36fb62c847a96cee5052ca606b411d0d..0ba8941c22e05818bc5c36dc28f18299cf0f2aa3 100644
--- a/src/backend/optimizer/geqo/geqo_selection.c
+++ b/src/backend/optimizer/geqo/geqo_selection.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_selection.c,v 1.24 2009/01/01 17:23:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_selection.c,v 1.25 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,7 @@
 #include "optimizer/geqo_random.h"
 #include "optimizer/geqo_selection.h"
 
-static int	linear(int max, double bias);
+static int	linear(PlannerInfo *root, int max, double bias);
 
 
 /*
@@ -51,22 +51,23 @@ static int	linear(int max, double bias);
  *	 first and second genes are selected from the pool
  */
 void
-geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias)
+geqo_selection(PlannerInfo *root, Chromosome *momma, Chromosome *daddy,
+			   Pool *pool, double bias)
 {
 	int			first,
 				second;
 
-	first = linear(pool->size, bias);
-	second = linear(pool->size, bias);
+	first = linear(root, pool->size, bias);
+	second = linear(root, pool->size, bias);
 
 	if (pool->size > 1)
 	{
 		while (first == second)
-			second = linear(pool->size, bias);
+			second = linear(root, pool->size, bias);
 	}
 
-	geqo_copy(momma, &pool->data[first], pool->string_length);
-	geqo_copy(daddy, &pool->data[second], pool->string_length);
+	geqo_copy(root, momma, &pool->data[first], pool->string_length);
+	geqo_copy(root, daddy, &pool->data[second], pool->string_length);
 }
 
 /*
@@ -74,12 +75,13 @@ geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias)
  *	  generates random integer between 0 and input max number
  *	  using input linear bias
  *
+ *	  bias is y-intercept of linear distribution
+ *
  *	  probability distribution function is: f(x) = bias - 2(bias - 1)x
  *			 bias = (prob of first rule) / (prob of middle rule)
  */
 static int
-linear(int pool_size, double bias)		/* bias is y-intercept of linear
-										 * distribution */
+linear(PlannerInfo *root, int pool_size, double bias)
 {
 	double		index;			/* index between 0 and pop_size */
 	double		max = (double) pool_size;
@@ -95,7 +97,7 @@ linear(int pool_size, double bias)		/* bias is y-intercept of linear
 	{
 		double		sqrtval;
 
-		sqrtval = (bias * bias) - 4.0 * (bias - 1.0) * geqo_rand();
+		sqrtval = (bias * bias) - 4.0 * (bias - 1.0) * geqo_rand(root);
 		if (sqrtval > 0.0)
 			sqrtval = sqrt(sqrtval);
 		index = max * (bias - sqrtval) / 2.0 / (bias - 1.0);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2944249a6924e349f43b2a2b2438bddafc0e9155..f3b42da99b15de7284ec901f1835ad437d64aba2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.507 2009/07/16 06:33:44 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.508 2009/07/16 20:55:44 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2026,6 +2026,14 @@ static struct config_real ConfigureNamesReal[] =
 		DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS,
 		MAX_GEQO_SELECTION_BIAS, NULL, NULL
 	},
+	{
+		{"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
+			gettext_noop("GEQO: seed for random path selection."),
+			NULL
+		},
+		&Geqo_seed,
+		0.0, 0.0, 1.0, NULL, NULL
+	},
 
 	{
 		{"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES,
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c1b888c0d4663088fbd3f40f6949316a5583c13f..e50d7a44f7b839d101ed1384fb1f0ce4972de7d5 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -213,6 +213,7 @@
 #geqo_pool_size = 0			# selects default based on effort
 #geqo_generations = 0			# selects default based on effort
 #geqo_selection_bias = 2.0		# range 1.5-2.0
+#geqo_seed = 0.0			# range 0.0-1.0
 
 # - Other Planner Options -
 
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 7eb15dbeecd74b88e94f30c19c649795ca6b610e..4432252a72f3abf47bb3c270e8f259fa830f162a 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.173 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.174 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -192,6 +192,9 @@ typedef struct PlannerInfo
 	/* These fields are used only when hasRecursion is true: */
 	int			wt_param_id;	/* PARAM_EXEC ID for the work table */
 	struct Plan *non_recursive_plan;	/* plan for non-recursive term */
+
+	/* optional private data for join_search_hook, e.g., GEQO */
+	void	   *join_search_private;
 } PlannerInfo;
 
 
diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h
index fc06006fd3b4ec5afffec345d38943ba573ea9c1..39226a7c7c98690037016d6c9d3c800c9a90cfa6 100644
--- a/src/include/optimizer/geqo.h
+++ b/src/include/optimizer/geqo.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo.h,v 1.44 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo.h,v 1.45 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,7 +46,7 @@
 /*
  * Configuration options
  *
- * If you change these, update backend/utils/misc/postgresql.sample.conf
+ * If you change these, update backend/utils/misc/postgresql.conf.sample
  */
 extern int	Geqo_effort;		/* 1 .. 10, knob for adjustment of defaults */
 
@@ -64,16 +64,17 @@ extern double Geqo_selection_bias;
 #define MIN_GEQO_SELECTION_BIAS 1.5
 #define MAX_GEQO_SELECTION_BIAS 2.0
 
+extern double Geqo_seed;		/* 0 .. 1 */
+
 
 /*
- * Data structure to encapsulate information needed for building plan trees
- * (i.e., geqo_eval and gimme_tree).
+ * Private state for a GEQO run --- accessible via root->join_search_private
  */
 typedef struct
 {
-	PlannerInfo *root;			/* the query we are planning */
-	List	   *initial_rels;	/* the base relations */
-} GeqoEvalData;
+	List	   *initial_rels;			/* the base relations we are joining */
+	unsigned short random_state[3];		/* state for erand48() */
+} GeqoPrivateData;
 
 
 /* routines in geqo_main.c */
@@ -81,8 +82,7 @@ extern RelOptInfo *geqo(PlannerInfo *root,
 	 int number_of_rels, List *initial_rels);
 
 /* routines in geqo_eval.c */
-extern Cost geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata);
-extern RelOptInfo *gimme_tree(Gene *tour, int num_gene,
-		   GeqoEvalData *evaldata);
+extern Cost geqo_eval(PlannerInfo *root, Gene *tour, int num_gene);
+extern RelOptInfo *gimme_tree(PlannerInfo *root, Gene *tour, int num_gene);
 
 #endif   /* GEQO_H */
diff --git a/src/include/optimizer/geqo_copy.h b/src/include/optimizer/geqo_copy.h
index 53293c4916114ee4fc2a77923c01b6c5b0fd47a5..582de22e6c3395487b3ef9296b7480fc1418935d 100644
--- a/src/include/optimizer/geqo_copy.h
+++ b/src/include/optimizer/geqo_copy.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_copy.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_copy.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,9 @@
 #ifndef GEQO_COPY_H
 #define GEQO_COPY_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_copy(Chromosome *chromo1, Chromosome *chromo2, int string_length);
+
+extern void geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2, int string_length);
 
 #endif   /* GEQO_COPY_H */
diff --git a/src/include/optimizer/geqo_mutation.h b/src/include/optimizer/geqo_mutation.h
index 430797c3707cef28c5787afe134dddea1e42afe5..559c35218db8f4608b97d1a0af666eebfd34b4be 100644
--- a/src/include/optimizer/geqo_mutation.h
+++ b/src/include/optimizer/geqo_mutation.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_mutation.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_mutation.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,9 @@
 #ifndef GEQO_MUTATION_H
 #define GEQO_MUTATION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_mutation(Gene *tour, int num_gene);
+
+extern void geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene);
 
 #endif   /* GEQO_MUTATION_H */
diff --git a/src/include/optimizer/geqo_pool.h b/src/include/optimizer/geqo_pool.h
index 282b2c2c5b73c27992d67a414f64ff2ec45be302..277b144ebd06a1e1da070e28835f1450487713d1 100644
--- a/src/include/optimizer/geqo_pool.h
+++ b/src/include/optimizer/geqo_pool.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_pool.h,v 1.25 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_pool.h,v 1.26 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,15 +26,15 @@
 #include "optimizer/geqo.h"
 
 
-extern Pool *alloc_pool(int pool_size, int string_length);
-extern void free_pool(Pool *pool);
+extern Pool *alloc_pool(PlannerInfo *root, int pool_size, int string_length);
+extern void free_pool(PlannerInfo *root, Pool *pool);
 
-extern void random_init_pool(Pool *pool, GeqoEvalData *evaldata);
-extern Chromosome *alloc_chromo(int string_length);
-extern void free_chromo(Chromosome *chromo);
+extern void random_init_pool(PlannerInfo *root, Pool *pool);
+extern Chromosome *alloc_chromo(PlannerInfo *root, int string_length);
+extern void free_chromo(PlannerInfo *root, Chromosome *chromo);
 
-extern void spread_chromo(Chromosome *chromo, Pool *pool);
+extern void spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool);
 
-extern void sort_pool(Pool *pool);
+extern void sort_pool(PlannerInfo *root, Pool *pool);
 
 #endif   /* GEQO_POOL_H */
diff --git a/src/include/optimizer/geqo_random.h b/src/include/optimizer/geqo_random.h
index 327989b5fb8bdba91e22bfd264255833ba4abdf5..cb1f60fa34e9b9706d00d58aac4db850c9169334 100644
--- a/src/include/optimizer/geqo_random.h
+++ b/src/include/optimizer/geqo_random.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_random.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_random.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,13 +26,16 @@
 
 #include <math.h>
 
-/* geqo_rand returns a random float value between 0 and 1 inclusive */
+#include "optimizer/geqo.h"
 
-#define geqo_rand() ((double) random() / (double) MAX_RANDOM_VALUE)
 
-/* geqo_randint returns integer value between lower and upper inclusive */
+extern void geqo_set_seed(PlannerInfo *root, double seed);
 
-#define geqo_randint(upper,lower) \
-	( (int) floor( geqo_rand()*(((upper)-(lower))+0.999999) ) + (lower) )
+/* geqo_rand returns a random float value between 0 and 1 inclusive */
+extern double geqo_rand(PlannerInfo *root);
+
+/* geqo_randint returns integer value between lower and upper inclusive */
+#define geqo_randint(root, upper, lower) \
+	( (int) floor( geqo_rand(root)*(((upper)-(lower))+0.999999) ) + (lower) )
 
 #endif   /* GEQO_RANDOM_H */
diff --git a/src/include/optimizer/geqo_recombination.h b/src/include/optimizer/geqo_recombination.h
index 264560f1128f5f1d08f1fd9dfaf039e7f9c0f7df..456783865065d9440577afa458ccfc64c13d37e7 100644
--- a/src/include/optimizer/geqo_recombination.h
+++ b/src/include/optimizer/geqo_recombination.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_recombination.h,v 1.20 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_recombination.h,v 1.21 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,9 +24,10 @@
 #ifndef GEQO_RECOMBINATION_H
 #define GEQO_RECOMBINATION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void init_tour(Gene *tour, int num_gene);
+
+extern void init_tour(PlannerInfo *root, Gene *tour, int num_gene);
 
 
 /* edge recombination crossover [ERX] */
@@ -38,12 +39,14 @@ typedef struct Edge
 	int			unused_edges;
 } Edge;
 
-extern Edge *alloc_edge_table(int num_gene);
-extern void free_edge_table(Edge *edge_table);
+extern Edge *alloc_edge_table(PlannerInfo *root, int num_gene);
+extern void free_edge_table(PlannerInfo *root, Edge *edge_table);
 
-extern float gimme_edge_table(Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table);
+extern float gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2,
+							  int num_gene, Edge *edge_table);
 
-extern int	gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene);
+extern int	gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene,
+					   int num_gene);
 
 
 /* partially matched crossover [PMX] */
@@ -51,7 +54,9 @@ extern int	gimme_tour(Edge *edge_table, Gene *new_gene, int num_gene);
 #define DAD 1					/* indicator for gene from dad */
 #define MOM 0					/* indicator for gene from mom */
 
-extern void pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene);
+extern void pmx(PlannerInfo *root,
+				Gene *tour1, Gene *tour2,
+				Gene *offspring, int num_gene);
 
 
 typedef struct City
@@ -62,19 +67,23 @@ typedef struct City
 	int			select_list;
 } City;
 
-extern City *alloc_city_table(int num_gene);
-extern void free_city_table(City *city_table);
+extern City *alloc_city_table(PlannerInfo *root, int num_gene);
+extern void free_city_table(PlannerInfo *root, City *city_table);
 
 /* cycle crossover [CX] */
-extern int	cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table);
+extern int	cx(PlannerInfo *root, Gene *tour1, Gene *tour2,
+			   Gene *offspring, int num_gene, City *city_table);
 
 /* position crossover [PX] */
-extern void px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table);
+extern void px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring,
+			   int num_gene, City *city_table);
 
 /* order crossover [OX1] according to Davis */
-extern void ox1(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);
+extern void ox1(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring,
+				int num_gene, City *city_table);
 
 /* order crossover [OX2] according to Syswerda */
-extern void ox2(Gene *mom, Gene *dad, Gene *offspring, int num_gene, City *city_table);
+extern void ox2(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring,
+				int num_gene, City *city_table);
 
 #endif   /* GEQO_RECOMBINATION_H */
diff --git a/src/include/optimizer/geqo_selection.h b/src/include/optimizer/geqo_selection.h
index e37a92b554efba81b586a94888b3f220957204c1..166ba475350cc1c706c6b7c7d61cb0af0c6b0bc7 100644
--- a/src/include/optimizer/geqo_selection.h
+++ b/src/include/optimizer/geqo_selection.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/geqo_selection.h,v 1.21 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/geqo_selection.h,v 1.22 2009/07/16 20:55:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,8 +23,11 @@
 #ifndef GEQO_SELECTION_H
 #define GEQO_SELECTION_H
 
-#include "optimizer/geqo_gene.h"
+#include "optimizer/geqo.h"
 
-extern void geqo_selection(Chromosome *momma, Chromosome *daddy, Pool *pool, double bias);
+
+extern void geqo_selection(PlannerInfo *root,
+						   Chromosome *momma, Chromosome *daddy,
+						   Pool *pool, double bias);
 
 #endif   /* GEQO_SELECTION_H */