geqo_eval.c 4.5 KB
Newer Older
M
Marc G. Fournier 已提交
1 2
/*------------------------------------------------------------------------
 *
3
 * geqo_eval.c
4
 *	  Routines to evaluate query trees
M
Marc G. Fournier 已提交
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
M
Marc G. Fournier 已提交
8
 *
9
 * $Id: geqo_eval.c,v 1.48 2000/02/15 20:49:14 tgl Exp $
M
Marc G. Fournier 已提交
10 11 12 13 14 15
 *
 *-------------------------------------------------------------------------
 */

/* contributed by:
   =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
16 17 18
   *  Martin Utesch				 * Institute of Automatic Control	   *
   =							 = University of Mining and Technology =
   *  utesch@aut.tu-freiberg.de  * Freiberg, Germany				   *
M
Marc G. Fournier 已提交
19 20 21 22
   =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
 */

#include <math.h>
B
Bruce Momjian 已提交
23 24

#include "postgres.h"
25
#ifdef HAVE_LIMITS_H
26
#include <limits.h>
27
#else
28
#ifdef HAVE_VALUES_H
29 30
#include <values.h>
#endif
31
#endif
M
Marc G. Fournier 已提交
32 33 34

#include "optimizer/cost.h"
#include "optimizer/geqo.h"
35
#include "optimizer/pathnode.h"
B
Bruce Momjian 已提交
36 37 38
#include "optimizer/paths.h"
#include "utils/portal.h"

M
Marc G. Fournier 已提交
39

40 41 42 43 44 45 46
/*
 * Variables set by geqo_eval_startup for use within a single GEQO run
 */
static MemoryContext geqo_eval_context;

/*
 * geqo_eval_startup:
B
Bruce Momjian 已提交
47
 *	 Must be called during geqo_main startup (before geqo_eval may be called)
48 49 50 51 52 53 54 55 56 57 58 59 60
 *
 * The main thing we need to do here is prepare a private memory context for
 * allocation of temp storage used while constructing a path in geqo_eval().
 * Since geqo_eval() will be called many times, we can't afford to let all
 * that memory go unreclaimed until end of statement.  We use a special
 * named portal to hold the context, so that it will be freed even if
 * we abort via elog(ERROR).  The working data is allocated in the portal's
 * heap memory context.
 */
void
geqo_eval_startup(void)
{
#define GEQO_PORTAL_NAME	"<geqo workspace>"
B
Bruce Momjian 已提交
61
	Portal		geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
62

B
Bruce Momjian 已提交
63 64
	if (!PortalIsValid(geqo_portal))
	{
65 66 67 68 69 70 71 72
		/* First time through (within current transaction, that is) */
		geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
		Assert(PortalIsValid(geqo_portal));
	}

	geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
}

73
/*
74
 * geqo_eval
75
 *
M
Marc G. Fournier 已提交
76 77 78
 * Returns cost of a query tree as an individual of the population.
 */
Cost
79
geqo_eval(Query *root, Gene *tour, int num_gene)
M
Marc G. Fournier 已提交
80
{
B
Bruce Momjian 已提交
81 82 83 84
	MemoryContext oldcxt;
	RelOptInfo *joinrel;
	Cost		fitness;
	List	   *savelist;
85 86 87

	/* preserve root->join_rel_list, which gimme_tree changes */
	savelist = root->join_rel_list;
M
Marc G. Fournier 已提交
88

B
Bruce Momjian 已提交
89 90 91 92
	/*
	 * create a temporary allocation context for the path construction
	 * work
	 */
93 94
	oldcxt = MemoryContextSwitchTo(geqo_eval_context);
	StartPortalAllocMode(DefaultAllocMode, 0);
M
Marc G. Fournier 已提交
95

96
	/* construct the best path for the given combination of relations */
97
	joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
M
Marc G. Fournier 已提交
98

99 100 101 102 103 104 105
	/*
	 * compute fitness
	 *
	 * XXX geqo does not currently support optimization for partial
	 * result retrieval --- how to fix?
	 */
	fitness = joinrel->cheapest_total_path->total_cost;
M
Marc G. Fournier 已提交
106

107 108
	/* restore join_rel_list */
	root->join_rel_list = savelist;
M
Marc G. Fournier 已提交
109

110 111 112
	/* release all the memory acquired within gimme_tree */
	EndPortalAllocMode();
	MemoryContextSwitchTo(oldcxt);
M
Marc G. Fournier 已提交
113

114
	return fitness;
M
Marc G. Fournier 已提交
115 116
}

117
/*
B
Bruce Momjian 已提交
118
 * gimme_tree
119 120
 *	  this program presumes that only LEFT-SIDED TREES are considered!
 *
121
 * 'old_rel' is the preceding join
122
 *
M
Marc G. Fournier 已提交
123 124
 * Returns a new join relation incorporating all joins in a left-sided tree.
 */
B
Bruce Momjian 已提交
125
RelOptInfo *
126
gimme_tree(Query *root, Gene *tour, int rel_count, int num_gene, RelOptInfo *old_rel)
M
Marc G. Fournier 已提交
127
{
128
	RelOptInfo *inner_rel;		/* current relation */
129
	int			base_rel_index;
130
	RelOptInfo *new_rel;
M
Marc G. Fournier 已提交
131

132 133
	if (rel_count < num_gene)
	{							/* tree not yet finished */
M
Marc G. Fournier 已提交
134

135 136
		/* tour[0] = 3; tour[1] = 1; tour[2] = 2 */
		base_rel_index = (int) tour[rel_count];
M
Marc G. Fournier 已提交
137

138
		inner_rel = (RelOptInfo *) nth(base_rel_index-1, root->base_rel_list);
139

140 141 142 143 144
		if (rel_count == 0)
		{						/* processing first join with
								 * base_rel_index = (int) tour[0] */
			rel_count++;
			return gimme_tree(root, tour, rel_count, num_gene, inner_rel);
M
Marc G. Fournier 已提交
145
		}
146 147
		else
		{						/* tree main part */
148
			List   *acceptable_rels = lcons(inner_rel, NIL);
149

150 151 152 153 154 155 156 157
			new_rel = make_rels_by_clause_joins(root, old_rel,
												acceptable_rels);
			if (! new_rel)
			{
				new_rel = make_rels_by_clauseless_joins(root, old_rel,
														acceptable_rels);
				if (! new_rel)
					elog(ERROR, "gimme_tree: failed to construct join rel");
M
Marc G. Fournier 已提交
158 159
			}

160
			rel_count++;
161
			Assert(length(new_rel->relids) == rel_count);
M
Marc G. Fournier 已提交
162

163 164
			/* Find and save the cheapest paths for this rel */
			set_cheapest(new_rel);
M
Marc G. Fournier 已提交
165

166
			return gimme_tree(root, tour, rel_count, num_gene, new_rel);
M
Marc G. Fournier 已提交
167 168 169
		}
	}

B
Bruce Momjian 已提交
170
	return old_rel;				/* tree finished ... */
M
Marc G. Fournier 已提交
171
}