diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index a77727f5a793802883b7c6de9b28e5a2351d24ed..a61f85c4b4cc30a6a74203b8ed8e7d8cadc6d91d 100644
--- a/src/backend/optimizer/geqo/geqo_eval.c
+++ b/src/backend/optimizer/geqo/geqo_eval.c
@@ -49,6 +49,9 @@ static bool desirable_join(PlannerInfo *root,
  * geqo_eval
  *
  * Returns cost of a query tree as an individual of the population.
+ *
+ * If no legal join order can be extracted from the proposed tour,
+ * returns DBL_MAX.
  */
 Cost
 geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
@@ -101,12 +104,19 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
 	joinrel = gimme_tree(root, tour, num_gene);
 
 	/*
-	 * compute fitness
+	 * compute fitness, if we found a valid join
 	 *
 	 * XXX geqo does not currently support optimization for partial result
 	 * retrieval --- how to fix?
 	 */
-	fitness = joinrel->cheapest_total_path->total_cost;
+	if (joinrel)
+	{
+		Path	   *best_path = joinrel->cheapest_total_path;
+
+		fitness = best_path->total_cost;
+	}
+	else
+		fitness = DBL_MAX;
 
 	/*
 	 * Restore join_rel_list to its former state, and put back original
@@ -131,7 +141,8 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
  *	 'tour' is the proposed join order, of length 'num_gene'
  *
  * Returns a new join relation whose cheapest path is the best plan for
- * this join order.
+ * this join order.  NB: will return NULL if join order is invalid and
+ * we can't modify it into a valid order.
  *
  * The original implementation of this routine always joined in the specified
  * order, and so could only build left-sided plans (and right-sided and
@@ -144,7 +155,10 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene)
  * postpones joins that are illegal or seem unsuitable according to some
  * heuristic rules.  This allows correct bushy plans to be generated at need,
  * and as a nice side-effect it seems to materially improve the quality of the
- * generated plans.
+ * generated plans.  Note however that since it's just a heuristic, it can
+ * still fail in some cases.  (In particular, we might clump together
+ * relations that actually mustn't be joined yet due to LATERAL restrictions;
+ * since there's no provision for un-clumping, this must lead to failure.)
  */
 RelOptInfo *
 gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
@@ -161,9 +175,8 @@ gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
 	 * to; if there is none then it becomes a new clump of its own. When we
 	 * enlarge an existing clump we check to see if it can now be merged with
 	 * any other clumps.  After the tour is all scanned, we forget about the
-	 * heuristics and try to forcibly join any remaining clumps.  Some forced
-	 * joins might still fail due to semantics, but we should always be able
-	 * to find some join order that works.
+	 * heuristics and try to forcibly join any remaining clumps.  If we are
+	 * unable to merge all the clumps into one, fail.
 	 */
 	clumps = NIL;
 
@@ -205,7 +218,7 @@ gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
 
 	/* Did we succeed in forming a single join relation? */
 	if (list_length(clumps) != 1)
-		elog(ERROR, "failed to join all relations together");
+		return NULL;
 
 	return ((Clump *) linitial(clumps))->joinrel;
 }
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index 3dda183e410963b6470dc455087380bbb51c76da..2931251f9127da2416d4dcd22d8629232a7fca07 100644
--- a/src/backend/optimizer/geqo/geqo_main.c
+++ b/src/backend/optimizer/geqo/geqo_main.c
@@ -261,6 +261,9 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 
 	best_rel = gimme_tree(root, best_tour, pool->string_length);
 
+	if (best_rel == NULL)
+		elog(ERROR, "geqo failed to make a valid plan");
+
 	/* DBG: show the query plan */
 #ifdef NOT_USED
 	print_plan(best_plan, root);
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index 0a97328059795203e998bb29628d5c756168c748..7d258017d27711f5295324ca78aa9a8ac1faa2c8 100644
--- a/src/backend/optimizer/geqo/geqo_pool.c
+++ b/src/backend/optimizer/geqo/geqo_pool.c
@@ -92,13 +92,37 @@ random_init_pool(PlannerInfo *root, Pool *pool)
 {
 	Chromosome *chromo = (Chromosome *) pool->data;
 	int			i;
+	int			bad = 0;
 
-	for (i = 0; i < pool->size; i++)
+	/*
+	 * We immediately discard any invalid individuals (those that geqo_eval
+	 * returns DBL_MAX for), thereby not wasting pool space on them.
+	 *
+	 * If we fail to make any valid individuals after 10000 tries, give up;
+	 * this probably means something is broken, and we shouldn't just let
+	 * ourselves get stuck in an infinite loop.
+	 */
+	i = 0;
+	while (i < pool->size)
 	{
 		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
+		{
+			bad++;
+			if (i == 0 && bad >= 10000)
+				elog(ERROR, "geqo failed to make a valid plan");
+		}
 	}
+
+#ifdef GEQO_DEBUG
+	if (bad > 0)
+		elog(DEBUG1, "%d invalid tours found while selecting %d pool entries",
+			 bad, pool->size);
+#endif
 }
 
 /*