PostgreSQL Source Code git master
Loading...
Searching...
No Matches
geqo_eval.c File Reference
#include "postgres.h"
#include <float.h>
#include <limits.h>
#include "optimizer/geqo.h"
#include "optimizer/joininfo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "utils/memutils.h"
Include dependency graph for geqo_eval.c:

Go to the source code of this file.

Data Structures

struct  Clump
 

Functions

static Listmerge_clump (PlannerInfo *root, List *clumps, Clump *new_clump, int num_gene, bool force)
 
static bool desirable_join (PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
 
Cost geqo_eval (PlannerInfo *root, Gene *tour, int num_gene)
 
RelOptInfogimme_tree (PlannerInfo *root, Gene *tour, int num_gene)
 

Function Documentation

◆ desirable_join()

static bool desirable_join ( PlannerInfo root,
RelOptInfo outer_rel,
RelOptInfo inner_rel 
)
static

Definition at line 343 of file geqo_eval.c.

345{
346 /*
347 * Join if there is an applicable join clause, or if there is a join order
348 * restriction forcing these rels to be joined.
349 */
352 return true;
353
354 /* Otherwise postpone the join till later. */
355 return false;
356}
bool have_relevant_joinclause(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition joininfo.c:39
bool have_join_order_restriction(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition joinrels.c:1254
static int fb(int x)
tree ctl root
Definition radixtree.h:1857

References fb(), have_join_order_restriction(), have_relevant_joinclause(), and root.

Referenced by merge_clump().

◆ geqo_eval()

Cost geqo_eval ( PlannerInfo root,
Gene tour,
int  num_gene 
)

Definition at line 56 of file geqo_eval.c.

57{
60 RelOptInfo *joinrel;
62 int savelength;
63 struct HTAB *savehash;
64
65 /*
66 * Create a private memory context that will hold all temp storage
67 * allocated inside gimme_tree().
68 *
69 * Since geqo_eval() will be called many times, we can't afford to let all
70 * that memory go unreclaimed until end of statement. Note we make the
71 * temp context a child of the planner's normal context, so that it will
72 * be freed even if we abort via ereport(ERROR).
73 */
75 "GEQO",
78
79 /*
80 * gimme_tree will add entries to root->join_rel_list, which may or may
81 * not already contain some entries. The newly added entries will be
82 * recycled by the MemoryContextDelete below, so we must ensure that the
83 * list is restored to its former state before exiting. We can do this by
84 * truncating the list to its original length. NOTE this assumes that any
85 * added entries are appended at the end!
86 *
87 * We also must take care not to mess up the outer join_rel_hash, if there
88 * is one. We can do this by just temporarily setting the link to NULL.
89 * (If we are dealing with enough join rels, which we very likely are, a
90 * new hash table will get built and used locally.)
91 *
92 * join_rel_level[] shouldn't be in use, so just Assert it isn't.
93 */
94 savelength = list_length(root->join_rel_list);
95 savehash = root->join_rel_hash;
96 Assert(root->join_rel_level == NULL);
97
98 root->join_rel_hash = NULL;
99
100 /* construct the best path for the given combination of relations */
101 joinrel = gimme_tree(root, tour, num_gene);
102
103 /*
104 * compute fitness, if we found a valid join
105 *
106 * XXX geqo does not currently support optimization for partial result
107 * retrieval, nor do we take any cognizance of possible use of
108 * parameterized paths --- how to fix?
109 */
110 if (joinrel)
111 {
113
115 }
116 else
118
119 /*
120 * Restore join_rel_list to its former state, and put back original
121 * hashtable if any.
122 */
123 root->join_rel_list = list_truncate(root->join_rel_list,
124 savelength);
125 root->join_rel_hash = savehash;
126
127 /* release all the memory acquired within gimme_tree */
130
131 return fitness;
132}
#define Assert(condition)
Definition c.h:873
RelOptInfo * gimme_tree(PlannerInfo *root, Gene *tour, int num_gene)
Definition geqo_eval.c:162
List * list_truncate(List *list, int new_size)
Definition list.c:631
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
double Cost
Definition nodes.h:261
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static int list_length(const List *l)
Definition pg_list.h:152
Cost total_cost
Definition pathnodes.h:1988
struct Path * cheapest_total_path
Definition pathnodes.h:1036

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, RelOptInfo::cheapest_total_path, CurrentMemoryContext, fb(), gimme_tree(), list_length(), list_truncate(), MemoryContextDelete(), MemoryContextSwitchTo(), root, and Path::total_cost.

Referenced by geqo(), and random_init_pool().

◆ gimme_tree()

RelOptInfo * gimme_tree ( PlannerInfo root,
Gene tour,
int  num_gene 
)

Definition at line 162 of file geqo_eval.c.

163{
165 List *clumps;
166 int rel_count;
167
168 /*
169 * Sometimes, a relation can't yet be joined to others due to heuristics
170 * or actual semantic restrictions. We maintain a list of "clumps" of
171 * successfully joined relations, with larger clumps at the front. Each
172 * new relation from the tour is added to the first clump it can be joined
173 * to; if there is none then it becomes a new clump of its own. When we
174 * enlarge an existing clump we check to see if it can now be merged with
175 * any other clumps. After the tour is all scanned, we forget about the
176 * heuristics and try to forcibly join any remaining clumps. If we are
177 * unable to merge all the clumps into one, fail.
178 */
179 clumps = NIL;
180
181 for (rel_count = 0; rel_count < num_gene; rel_count++)
182 {
183 int cur_rel_index;
186
187 /* Get the next input relation */
189 cur_rel = (RelOptInfo *) list_nth(private->initial_rels,
190 cur_rel_index - 1);
191
192 /* Make it into a single-rel clump */
194 cur_clump->joinrel = cur_rel;
195 cur_clump->size = 1;
196
197 /* Merge it into the clumps list, using only desirable joins */
199 }
200
201 if (list_length(clumps) > 1)
202 {
203 /* Force-join the remaining clumps in some legal order */
204 List *fclumps;
205 ListCell *lc;
206
207 fclumps = NIL;
208 foreach(lc, clumps)
209 {
210 Clump *clump = (Clump *) lfirst(lc);
211
213 }
214 clumps = fclumps;
215 }
216
217 /* Did we succeed in forming a single join relation? */
218 if (list_length(clumps) != 1)
219 return NULL;
220
221 return ((Clump *) linitial(clumps))->joinrel;
222}
#define palloc_object(type)
Definition fe_memutils.h:74
static GeqoPrivateData * GetGeqoPrivateData(PlannerInfo *root)
Definition geqo.h:85
static List * merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, int num_gene, bool force)
Definition geqo_eval.c:237
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define linitial(l)
Definition pg_list.h:178
Definition pg_list.h:54

References fb(), GetGeqoPrivateData(), lfirst, linitial, list_length(), list_nth(), merge_clump(), NIL, palloc_object, and root.

Referenced by geqo(), and geqo_eval().

◆ merge_clump()

static List * merge_clump ( PlannerInfo root,
List clumps,
Clump new_clump,
int  num_gene,
bool  force 
)
static

Definition at line 237 of file geqo_eval.c.

239{
240 ListCell *lc;
241 int pos;
242
243 /* Look for a clump that new_clump can join to */
244 foreach(lc, clumps)
245 {
246 Clump *old_clump = (Clump *) lfirst(lc);
247
248 if (force ||
249 desirable_join(root, old_clump->joinrel, new_clump->joinrel))
250 {
251 RelOptInfo *joinrel;
252
253 /*
254 * Construct a RelOptInfo representing the join of these two input
255 * relations. Note that we expect the joinrel not to exist in
256 * root->join_rel_list yet, and so the paths constructed for it
257 * will only include the ones we want.
258 */
259 joinrel = make_join_rel(root,
260 old_clump->joinrel,
261 new_clump->joinrel);
262
263 /* Keep searching if join order is not valid */
264 if (joinrel)
265 {
266 bool is_top_rel = bms_equal(joinrel->relids,
267 root->all_query_rels);
268
269 /* Create paths for partitionwise joins. */
271
272 /*
273 * Except for the topmost scan/join rel, consider gathering
274 * partial paths. We'll do the same for the topmost scan/join
275 * rel once we know the final targetlist (see
276 * grouping_planner).
277 */
278 if (!is_top_rel)
279 generate_useful_gather_paths(root, joinrel, false);
280
281 /* Find and save the cheapest paths for this joinrel */
282 set_cheapest(joinrel);
283
284 /*
285 * Except for the topmost scan/join rel, consider generating
286 * partial aggregation paths for the grouped relation on top
287 * of the paths of this rel. After that, we're done creating
288 * paths for the grouped relation, so run set_cheapest().
289 */
290 if (joinrel->grouped_rel != NULL && !is_top_rel)
291 {
292 RelOptInfo *grouped_rel = joinrel->grouped_rel;
293
294 Assert(IS_GROUPED_REL(grouped_rel));
295
296 generate_grouped_paths(root, grouped_rel, joinrel);
297 set_cheapest(grouped_rel);
298 }
299
300 /* Absorb new clump into old */
301 old_clump->joinrel = joinrel;
302 old_clump->size += new_clump->size;
304
305 /* Remove old_clump from list */
307
308 /*
309 * Recursively try to merge the enlarged old_clump with
310 * others. When no further merge is possible, we'll reinsert
311 * it into the list.
312 */
313 return merge_clump(root, clumps, old_clump, num_gene, force);
314 }
315 }
316 }
317
318 /*
319 * No merging is possible, so add new_clump as an independent clump, in
320 * proper order according to size. We can be fast for the common case
321 * where it has size 1 --- it should always go at the end.
322 */
323 if (clumps == NIL || new_clump->size == 1)
324 return lappend(clumps, new_clump);
325
326 /* Else search for the place to insert it */
327 for (pos = 0; pos < list_length(clumps); pos++)
328 {
329 Clump *old_clump = (Clump *) list_nth(clumps, pos);
330
331 if (new_clump->size > old_clump->size)
332 break; /* new_clump belongs before old_clump */
333 }
335
336 return clumps;
337}
void generate_partitionwise_join_paths(PlannerInfo *root, RelOptInfo *rel)
Definition allpaths.c:4814
void generate_grouped_paths(PlannerInfo *root, RelOptInfo *grouped_rel, RelOptInfo *rel)
Definition allpaths.c:3442
void generate_useful_gather_paths(PlannerInfo *root, RelOptInfo *rel, bool override_rows)
Definition allpaths.c:3325
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:142
static bool desirable_join(PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel)
Definition geqo_eval.c:343
RelOptInfo * make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
Definition joinrels.c:699
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_insert_nth(List *list, int pos, void *datum)
Definition list.c:439
void pfree(void *pointer)
Definition mcxt.c:1616
void set_cheapest(RelOptInfo *parent_rel)
Definition pathnode.c:268
#define IS_GROUPED_REL(rel)
Definition pathnodes.h:1239
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
Relids relids
Definition pathnodes.h:1003
struct RelOptInfo * grouped_rel
Definition pathnodes.h:1146

References Assert, bms_equal(), desirable_join(), fb(), foreach_delete_current, generate_grouped_paths(), generate_partitionwise_join_paths(), generate_useful_gather_paths(), RelOptInfo::grouped_rel, IS_GROUPED_REL, lappend(), lfirst, list_insert_nth(), list_length(), list_nth(), make_join_rel(), merge_clump(), NIL, pfree(), RelOptInfo::relids, root, and set_cheapest().

Referenced by gimme_tree(), and merge_clump().