/* * 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) { MemoryContext mycontext; MemoryContext oldcxt; RelOptInfo *joinrel; Cost fitness; int savelength; struct HTAB *savehash; /* * Create a private memory context that will hold all temp storage * allocated inside gimme_tree(). * * Since geqo_eval() will be called many times, we can't afford to let all * that memory go unreclaimed until end of statement. Note we make the * temp context a child of the planner's normal context, so that it will * be freed even if we abort via ereport(ERROR). */ mycontext = AllocSetContextCreate(CurrentMemoryContext, "GEQO", ALLOCSET_DEFAULT_SIZES); oldcxt = MemoryContextSwitchTo(mycontext); /* * gimme_tree will add entries to root->join_rel_list, which may or may * not already contain some entries. The newly added entries will be * recycled by the MemoryContextDelete below, so we must ensure that the * list is restored to its former state before exiting. We can do this by * truncating the list to its original length. NOTE this assumes that any * added entries are appended at the end! * * We also must take care not to mess up the outer join_rel_hash, if there * is one. We can do this by just temporarily setting the link to NULL. * (If we are dealing with enough join rels, which we very likely are, a * new hash table will get built and used locally.) * * join_rel_level[] shouldn't be in use, so just Assert it isn't. */ savelength = list_length(root->join_rel_list); savehash = root->join_rel_hash; Assert(root->join_rel_level == NULL); root->join_rel_hash = NULL; /* construct the best path for the given combination of relations */ joinrel = gimme_tree(root, tour, num_gene); /* * 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? */ 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 * hashtable if any. */ 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); MemoryContextDelete(mycontext); return fitness; }
/* * geqo_eval * * Returns cost of a query tree as an individual of the population. */ Cost geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata) { MemoryContext mycontext; MemoryContext oldcxt; RelOptInfo *joinrel; Cost fitness; int savelength; struct HTAB *savehash; /* * Because gimme_tree considers both left- and right-sided trees, there is * no difference between a tour (a,b,c,d,...) and a tour (b,a,c,d,...) --- * the same join orders will be considered. To avoid redundant cost * calculations, we simply reject tours where tour[0] > tour[1], assigning * them an artificially bad fitness. * * init_tour() is aware of this rule and so we should never reject a tour * during the initial filling of the pool. It seems difficult to persuade * the recombination logic never to break the rule, however. */ if (num_gene >= 2 && tour[0] > tour[1]) return DBL_MAX; /* * Create a private memory context that will hold all temp storage * allocated inside gimme_tree(). * * Since geqo_eval() will be called many times, we can't afford to let all * that memory go unreclaimed until end of statement. Note we make the * temp context a child of the planner's normal context, so that it will * be freed even if we abort via ereport(ERROR). */ mycontext = AllocSetContextCreate(CurrentMemoryContext, "GEQO", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(mycontext); /* * gimme_tree will add entries to root->join_rel_list, which may or may * not already contain some entries. The newly added entries will be * recycled by the MemoryContextDelete below, so we must ensure that the * list is restored to its former state before exiting. We can do this by * truncating the list to its original length. NOTE this assumes that any * added entries are appended at the end! * * We also must take care not to mess up the outer join_rel_hash, if there * is one. We can do this by just temporarily setting the link to NULL. * (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; evaldata->root->join_rel_hash = NULL; /* construct the best path for the given combination of relations */ joinrel = gimme_tree(tour, num_gene, evaldata); /* * compute fitness * * XXX geqo does not currently support optimization for partial result * retrieval --- how to fix? */ if (joinrel) fitness = joinrel->cheapest_total_path->total_cost; else fitness = DBL_MAX; /* * 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; /* release all the memory acquired within gimme_tree */ MemoryContextSwitchTo(oldcxt); MemoryContextDelete(mycontext); return fitness; }