aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/geqo/geqo_eval.c
blob: dd3d6bd5372a11ef5c9f16707da1ed3ab35cb718 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*------------------------------------------------------------------------
 *
 * 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 <math.h>
#include <limits.h>

#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 ... */
}