/*------------------------------------------------------------------------ * * geqo_eval.c * Routines to evaluate query trees * * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * $Id: geqo_eval.c,v 1.58 2001/03/22 03:59:33 momjian Exp $ * *------------------------------------------------------------------------- */ /* contributed by: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= * Martin Utesch * Institute of Automatic Control * = = University of Mining and Technology = * utesch@aut.tu-freiberg.de * Freiberg, Germany * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= */ #include "postgres.h" #include #include #include "optimizer/geqo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "utils/memutils.h" /* * geqo_eval * * Returns cost of a query tree as an individual of the population. */ Cost geqo_eval(Query *root, List *initial_rels, Gene *tour, int num_gene) { MemoryContext mycontext; MemoryContext oldcxt; RelOptInfo *joinrel; Cost fitness; List *savelist; /* * 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 TransactionCommandContext, so that * it will be freed even if we abort via elog(ERROR). */ mycontext = AllocSetContextCreate(TransactionCommandContext, "GEQO", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(mycontext); /* preserve root->join_rel_list, which gimme_tree changes */ savelist = root->join_rel_list; /* construct the best path for the given combination of relations */ joinrel = gimme_tree(root, initial_rels, tour, num_gene, 0, NULL); /* * compute fitness * * XXX geqo does not currently support optimization for partial result * retrieval --- how to fix? */ fitness = joinrel->cheapest_total_path->total_cost; /* restore join_rel_list */ root->join_rel_list = savelist; /* release all the memory acquired within gimme_tree */ MemoryContextSwitchTo(oldcxt); MemoryContextDelete(mycontext); return fitness; } /* * gimme_tree * this routine considers only LEFT-SIDED TREES! * * 'root' is the Query * 'initial_rels' is the list of initial relations (FROM-list items) * 'tour' is the proposed join order, of length 'num_gene' * 'rel_count' is number of initial_rels items already joined (initially 0) * 'old_rel' is the preceding join (initially NULL) * * Returns a new join relation incorporating all joins in a left-sided tree. */ RelOptInfo * gimme_tree(Query *root, List *initial_rels, Gene *tour, int num_gene, int rel_count, RelOptInfo *old_rel) { RelOptInfo *inner_rel; /* current relation */ int init_rel_index; if (rel_count < num_gene) { /* tree not yet finished */ init_rel_index = (int) tour[rel_count]; inner_rel = (RelOptInfo *) nth(init_rel_index - 1, initial_rels); if (rel_count == 0) { /* processing first join with init_rel_index = (int) tour[0] */ rel_count++; return gimme_tree(root, initial_rels, tour, num_gene, rel_count, inner_rel); } else { /* tree main part */ List *acceptable_rels = makeList1(inner_rel); List *new_rels; RelOptInfo *new_rel; new_rels = make_rels_by_clause_joins(root, old_rel, acceptable_rels); /* Shouldn't get more than one result */ Assert(length(new_rels) <= 1); if (new_rels == NIL) { new_rels = make_rels_by_clauseless_joins(root, old_rel, acceptable_rels); Assert(length(new_rels) <= 1); if (new_rels == NIL) elog(ERROR, "gimme_tree: failed to construct join rel"); } new_rel = (RelOptInfo *) lfirst(new_rels); /* Find and save the cheapest paths for this rel */ set_cheapest(new_rel); /* and recurse... */ rel_count++; return gimme_tree(root, initial_rels, tour, num_gene, rel_count, new_rel); } } return old_rel; /* tree finished ... */ }