diff options
Diffstat (limited to 'src/backend/optimizer/geqo/geqo_eval.c')
-rw-r--r-- | src/backend/optimizer/geqo/geqo_eval.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index 1ed38ebe649..d9a20dafe68 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) @@ -56,7 +59,6 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene) MemoryContext mycontext; MemoryContext oldcxt; RelOptInfo *joinrel; - Path *best_path; Cost fitness; int savelength; struct HTAB *savehash; @@ -100,16 +102,22 @@ geqo_eval(PlannerInfo *root, Gene *tour, int num_gene) /* construct the best path for the given combination of relations */ joinrel = gimme_tree(root, tour, num_gene); - best_path = joinrel->cheapest_total_path; /* - * compute fitness + * compute fitness, if we found a valid join * * XXX geqo does not currently support optimization for partial result * retrieval, nor do we take any cognizance of possible use of * parameterized paths --- how to fix? */ - fitness = best_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 @@ -134,7 +142,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 @@ -147,7 +156,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) @@ -164,9 +176,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; @@ -208,7 +219,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; } |