mirror of
https://github.com/postgres/postgres.git
synced 2025-11-15 03:41:20 +03:00
Merge in GEQO Optimizer
From: "Martin S. Utesch" <utesch@aut.tu-freiberg.de>
This commit is contained in:
667
src/backend/optimizer/geqo/geqo_eval.c
Normal file
667
src/backend/optimizer/geqo/geqo_eval.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/*------------------------------------------------------------------------
|
||||
*
|
||||
* geqo_eval.c--
|
||||
* Routines to evaluate query trees
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: geqo_eval.c,v 1.1 1997/02/19 12:57:01 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* contributed by:
|
||||
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||
* Martin Utesch * Institute of Automatic Control *
|
||||
= = University of Mining and Technology =
|
||||
* utesch@aut.tu-freiberg.de * Freiberg, Germany *
|
||||
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#ifdef WIN32
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#define MAXINT INT_MAX
|
||||
#else
|
||||
# if defined(PORTNAME_BSD44_derived) || \
|
||||
defined(PORTNAME_bsdi) || \
|
||||
defined(PORTNAME_bsdi_2_1)
|
||||
# include <machine/limits.h>
|
||||
# define MAXINT INT_MAX
|
||||
# else
|
||||
# include <values.h>
|
||||
# endif /* !PORTNAME_BSD44_derived */
|
||||
#endif /* WIN32 */
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "nodes/primnodes.h"
|
||||
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
#include "optimizer/internal.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
|
||||
#include "optimizer/geqo_gene.h"
|
||||
#include "optimizer/geqo.h"
|
||||
#include "optimizer/geqo_paths.h"
|
||||
|
||||
|
||||
static List *gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel);
|
||||
static Rel *gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel);
|
||||
static Rel *init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo);
|
||||
static List *new_join_tlist(List *tlist, List *other_relids, int first_resdomno);
|
||||
static List *new_joininfo_list(List *joininfo_list, List *join_relids);
|
||||
static void add_superrels(Rel *rel, Rel *super_rel);
|
||||
static bool nonoverlap_rels(Rel *rel1, Rel *rel2);
|
||||
static bool nonoverlap_sets(List *s1, List *s2);
|
||||
static void geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel);
|
||||
|
||||
static void geqo_add_new_joininfos(Query *root, List *joinrels, List *outerrels);
|
||||
static List *geqo_final_join_rels(List *join_rel_list);
|
||||
|
||||
|
||||
/*
|
||||
* geqo_eval--
|
||||
*
|
||||
* Returns cost of a query tree as an individual of the population.
|
||||
*/
|
||||
Cost
|
||||
geqo_eval (Query *root, Gene *tour, int num_gene)
|
||||
{
|
||||
Rel *joinrel;
|
||||
Cost fitness;
|
||||
List *temp;
|
||||
|
||||
|
||||
/* remember root->join_relation_list_ ... */
|
||||
/* because root->join_relation_list_ will be changed during the following */
|
||||
temp = listCopy(root->join_relation_list_);
|
||||
|
||||
/* joinrel is readily processed query tree -- left-sided ! */
|
||||
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
|
||||
|
||||
/* compute fitness */
|
||||
fitness = (Cost) joinrel->cheapestpath->path_cost;
|
||||
|
||||
root->join_relation_list_ = listCopy(temp);
|
||||
|
||||
pfree(joinrel);
|
||||
freeList(temp);
|
||||
|
||||
return(fitness);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* gimme-tree --
|
||||
* this program presumes that only LEFT-SIDED TREES are considered!
|
||||
*
|
||||
* 'outer_rel' is the preceeding join
|
||||
*
|
||||
* Returns a new join relation incorporating all joins in a left-sided tree.
|
||||
*/
|
||||
Rel *
|
||||
gimme_tree (Query *root, Gene *tour, int rel_count, int num_gene, Rel *outer_rel)
|
||||
{
|
||||
Rel *inner_rel; /* current relation */
|
||||
int relid;
|
||||
|
||||
List *new_rels = NIL;
|
||||
Rel *new_rel = NULL;
|
||||
|
||||
if (rel_count < num_gene ) { /* tree not yet finished */
|
||||
|
||||
/* tour[0] = 3; tour[1] = 1; tour[2] = 2 */
|
||||
relid = (int) tour[rel_count];
|
||||
inner_rel = (Rel *) get_base_rel(root, relid);
|
||||
|
||||
if (rel_count == 0) { /* processing first join with relid = (int) tour[0] */
|
||||
rel_count++;
|
||||
return gimme_tree(root, tour, rel_count, num_gene, inner_rel);
|
||||
}
|
||||
else { /* tree main part */
|
||||
|
||||
if(!(new_rels = gimme_clause_joins(root, outer_rel,inner_rel))) {
|
||||
if (BushyPlanFlag) {
|
||||
new_rels = lcons(gimme_clauseless_join(outer_rel,outer_rel),NIL); /* ??? MAU */
|
||||
}
|
||||
else {
|
||||
new_rels = lcons(gimme_clauseless_join(outer_rel,inner_rel),NIL);
|
||||
}
|
||||
}
|
||||
|
||||
/* process new_rel->pathlist */
|
||||
find_all_join_paths(root, new_rels);
|
||||
|
||||
/* prune new_rels */
|
||||
/* MAU: is this necessary? */
|
||||
/* what's the matter if more than one new rel is left till now? */
|
||||
/* joinrels in newrels with different ordering of relids are not possible */
|
||||
if (length(new_rels) > 1) new_rels = geqo_prune_rels(new_rels);
|
||||
|
||||
if (length(new_rels) > 1) { /* should never be reached ... */
|
||||
elog(DEBUG,"gimme_tree: still %d relations left", length(new_rels));
|
||||
}
|
||||
|
||||
/* get essential new relation */
|
||||
new_rel = (Rel *) lfirst(new_rels);
|
||||
rel_count++;
|
||||
|
||||
/* process new_rel->cheapestpath, new_rel->unorderedpath */
|
||||
geqo_rel_paths(new_rel);
|
||||
|
||||
/* processing of other new_rel attributes */
|
||||
new_rel->size = compute_rel_size(new_rel);
|
||||
new_rel->width = compute_rel_width(new_rel);
|
||||
|
||||
root->join_relation_list_ = lcons(new_rel, NIL);
|
||||
|
||||
return gimme_tree(root, tour, rel_count, num_gene, new_rel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (outer_rel); /* tree finished ... */
|
||||
}
|
||||
|
||||
/*
|
||||
* gimme-clause-joins--
|
||||
*
|
||||
* 'outer-rel' is the relation entry for the outer relation
|
||||
* 'inner-rel' is the relation entry for the inner relation
|
||||
*
|
||||
* Returns a list of new join relations.
|
||||
*/
|
||||
|
||||
static List *
|
||||
gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel)
|
||||
{
|
||||
List *join_list = NIL;
|
||||
List *i = NIL;
|
||||
List *joininfo_list = (List *) outer_rel->joininfo;
|
||||
|
||||
foreach (i, joininfo_list) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(i);
|
||||
Rel *rel = NULL;
|
||||
|
||||
if(!joininfo->inactive) {
|
||||
List *other_rels = (List *)joininfo->otherrels;
|
||||
|
||||
if(other_rels != NIL) {
|
||||
if( (length(other_rels) == 1) ) {
|
||||
|
||||
if( same(other_rels, inner_rel->relids) ) { /* look if inner_rel is it...*/
|
||||
rel = init_join_rel(outer_rel, inner_rel, joininfo);
|
||||
}
|
||||
}
|
||||
else if (BushyPlanFlag) { /* ?!? MAU */
|
||||
rel = init_join_rel(outer_rel, get_join_rel(root, other_rels), joininfo);
|
||||
}
|
||||
else {
|
||||
rel = NULL;
|
||||
}
|
||||
|
||||
if (rel != NULL)
|
||||
join_list = lappend(join_list, rel);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(join_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* gimme-clauseless-join--
|
||||
* Given an outer relation 'outer-rel' and an inner relation
|
||||
* 'inner-rel', create a join relation between 'outer-rel' and 'inner-rel'
|
||||
*
|
||||
* Returns a new join relation.
|
||||
*/
|
||||
|
||||
static Rel *
|
||||
gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel)
|
||||
{
|
||||
return(init_join_rel(outer_rel, inner_rel, (JInfo*)NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* init-join-rel--
|
||||
* Creates and initializes a new join relation.
|
||||
*
|
||||
* 'outer-rel' and 'inner-rel' are relation nodes for the relations to be
|
||||
* joined
|
||||
* 'joininfo' is the joininfo node(join clause) containing both
|
||||
* 'outer-rel' and 'inner-rel', if any exists
|
||||
*
|
||||
* Returns the new join relation node.
|
||||
*/
|
||||
static Rel *
|
||||
init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo)
|
||||
{
|
||||
Rel *joinrel = makeNode(Rel);
|
||||
List *joinrel_joininfo_list = NIL;
|
||||
List *new_outer_tlist;
|
||||
List *new_inner_tlist;
|
||||
|
||||
/*
|
||||
* Create a new tlist by removing irrelevant elements from both
|
||||
* tlists of the outer and inner join relations and then merging
|
||||
* the results together.
|
||||
*/
|
||||
new_outer_tlist =
|
||||
new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */
|
||||
inner_rel->relids, 1);
|
||||
new_inner_tlist =
|
||||
new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */
|
||||
outer_rel->relids,
|
||||
length(new_outer_tlist) + 1);
|
||||
|
||||
joinrel->relids = NIL;
|
||||
joinrel->indexed = false;
|
||||
joinrel->pages = 0;
|
||||
joinrel->tuples = 0;
|
||||
joinrel->width = 0;
|
||||
/* joinrel->targetlist = NIL;*/
|
||||
joinrel->pathlist = NIL;
|
||||
joinrel->unorderedpath = (Path *)NULL;
|
||||
joinrel->cheapestpath = (Path *)NULL;
|
||||
joinrel->pruneable = true;
|
||||
joinrel->classlist = NULL;
|
||||
joinrel->relam = InvalidOid;
|
||||
joinrel->ordering = NULL;
|
||||
joinrel->clauseinfo = NIL;
|
||||
joinrel->joininfo = NULL;
|
||||
joinrel->innerjoin = NIL;
|
||||
joinrel->superrels = NIL;
|
||||
|
||||
joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));
|
||||
|
||||
new_outer_tlist = nconc(new_outer_tlist,new_inner_tlist);
|
||||
joinrel->targetlist = new_outer_tlist;
|
||||
|
||||
if (joininfo) {
|
||||
joinrel->clauseinfo = joininfo->jinfoclauseinfo;
|
||||
if (BushyPlanFlag) joininfo->inactive = true;
|
||||
}
|
||||
|
||||
joinrel_joininfo_list =
|
||||
new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo),
|
||||
intAppend(outer_rel->relids, inner_rel->relids));
|
||||
|
||||
joinrel->joininfo = joinrel_joininfo_list;
|
||||
|
||||
geqo_joinrel_size(joinrel, outer_rel, inner_rel);
|
||||
|
||||
return(joinrel);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-join-tlist--
|
||||
* Builds a join relations's target list by keeping those elements that
|
||||
* will be in the final target list and any other elements that are still
|
||||
* needed for future joins. For a target list entry to still be needed
|
||||
* for future joins, its 'joinlist' field must not be empty after removal
|
||||
* of all relids in 'other-relids'.
|
||||
*
|
||||
* 'tlist' is the target list of one of the join relations
|
||||
* 'other-relids' is a list of relids contained within the other
|
||||
* join relation
|
||||
* 'first-resdomno' is the resdom number to use for the first created
|
||||
* target list entry
|
||||
*
|
||||
* Returns the new target list.
|
||||
*/
|
||||
static List *
|
||||
new_join_tlist(List *tlist,
|
||||
List *other_relids,
|
||||
int first_resdomno)
|
||||
{
|
||||
int resdomno = first_resdomno - 1;
|
||||
TargetEntry *xtl = NULL;
|
||||
List *temp_node = NIL;
|
||||
List *t_list = NIL;
|
||||
List *i = NIL;
|
||||
List *join_list = NIL;
|
||||
bool in_final_tlist =false;
|
||||
|
||||
|
||||
foreach(i,tlist) {
|
||||
xtl= lfirst(i);
|
||||
in_final_tlist = (join_list==NIL);
|
||||
if( in_final_tlist) {
|
||||
resdomno += 1;
|
||||
temp_node =
|
||||
lcons(create_tl_element(get_expr(xtl),
|
||||
resdomno),
|
||||
NIL);
|
||||
t_list = nconc(t_list,temp_node);
|
||||
}
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-joininfo-list--
|
||||
* Builds a join relation's joininfo list by checking for join clauses
|
||||
* which still need to used in future joins involving this relation. A
|
||||
* join clause is still needed if there are still relations in the clause
|
||||
* not contained in the list of relations comprising this join relation.
|
||||
* New joininfo nodes are only created and added to
|
||||
* 'current-joininfo-list' if a node for a particular join hasn't already
|
||||
* been created.
|
||||
*
|
||||
* 'current-joininfo-list' contains a list of those joininfo nodes that
|
||||
* have already been built
|
||||
* 'joininfo-list' is the list of join clauses involving this relation
|
||||
* 'join-relids' is a list of relids corresponding to the relations
|
||||
* currently being joined
|
||||
*
|
||||
* Returns a list of joininfo nodes, new and old.
|
||||
*/
|
||||
static List *
|
||||
new_joininfo_list(List *joininfo_list, List *join_relids)
|
||||
{
|
||||
List *current_joininfo_list = NIL;
|
||||
List *new_otherrels = NIL;
|
||||
JInfo *other_joininfo = (JInfo*)NULL;
|
||||
List *xjoininfo = NIL;
|
||||
|
||||
foreach (xjoininfo, joininfo_list) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
|
||||
new_otherrels = joininfo->otherrels;
|
||||
if (nonoverlap_sets(new_otherrels,join_relids)) {
|
||||
other_joininfo = joininfo_member(new_otherrels,
|
||||
current_joininfo_list);
|
||||
if(other_joininfo) {
|
||||
other_joininfo->jinfoclauseinfo =
|
||||
(List*)LispUnion(joininfo->jinfoclauseinfo,
|
||||
other_joininfo->jinfoclauseinfo);
|
||||
}else {
|
||||
other_joininfo = makeNode(JInfo);
|
||||
|
||||
other_joininfo->otherrels =
|
||||
joininfo->otherrels;
|
||||
other_joininfo->jinfoclauseinfo =
|
||||
joininfo->jinfoclauseinfo;
|
||||
other_joininfo->mergesortable =
|
||||
joininfo->mergesortable;
|
||||
other_joininfo->hashjoinable =
|
||||
joininfo->hashjoinable;
|
||||
other_joininfo->inactive = false;
|
||||
|
||||
current_joininfo_list = lcons(other_joininfo,
|
||||
current_joininfo_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(current_joininfo_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* add-new-joininfos--
|
||||
* For each new join relation, create new joininfos that
|
||||
* use the join relation as inner relation, and add
|
||||
* the new joininfos to those rel nodes that still
|
||||
* have joins with the join relation.
|
||||
*
|
||||
* 'joinrels' is a list of join relations.
|
||||
*
|
||||
* Modifies the joininfo field of appropriate rel nodes.
|
||||
*/
|
||||
static void
|
||||
geqo_add_new_joininfos(Query *root, List *joinrels, List *outerrels)
|
||||
{
|
||||
List *xjoinrel = NIL;
|
||||
List *xrelid = NIL;
|
||||
List *xrel = NIL;
|
||||
List *xjoininfo = NIL;
|
||||
|
||||
Rel *rel;
|
||||
List *relids;
|
||||
|
||||
List *super_rels;
|
||||
List *xsuper_rel = NIL;
|
||||
JInfo *new_joininfo;
|
||||
|
||||
foreach(xjoinrel, joinrels) {
|
||||
Rel *joinrel = (Rel *)lfirst(xjoinrel);
|
||||
foreach(xrelid, joinrel->relids) {
|
||||
/* length(joinrel->relids) should always be greater that 1, because of *JOIN* */
|
||||
/* ! BUG BUG !
|
||||
Relid relid = (Relid)lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
*/
|
||||
|
||||
/*
|
||||
if ( (root->join_relation_list_) != NIL ) {
|
||||
rel = get_join_rel(root, xrelid);
|
||||
}
|
||||
else {
|
||||
rel = get_base_rel(root, lfirsti(xrelid));
|
||||
}
|
||||
*/
|
||||
|
||||
/* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
|
||||
/*
|
||||
relids = lconsi(lfirsti(xrelid), NIL);
|
||||
rel = rel_member(relids, outerrels);
|
||||
*/
|
||||
|
||||
relids = lconsi(lfirsti(xrelid), NIL);
|
||||
rel = rel_member(relids, root->base_relation_list_);
|
||||
|
||||
add_superrels(rel,joinrel);
|
||||
}
|
||||
}
|
||||
foreach(xjoinrel, joinrels) {
|
||||
Rel *joinrel = (Rel *)lfirst(xjoinrel);
|
||||
|
||||
foreach(xjoininfo, joinrel->joininfo) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
List *other_rels = joininfo->otherrels;
|
||||
List *clause_info = joininfo->jinfoclauseinfo;
|
||||
bool mergesortable = joininfo->mergesortable;
|
||||
bool hashjoinable = joininfo->hashjoinable;
|
||||
|
||||
foreach(xrelid, other_rels) {
|
||||
/* ! BUG BUG !
|
||||
Relid relid = (Relid)lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
*/
|
||||
|
||||
/*
|
||||
if ( (root->join_relation_list_) != NIL ) {
|
||||
rel = get_join_rel(root, xrelid);
|
||||
}
|
||||
else {
|
||||
rel = get_base_rel(root, lfirsti(xrelid));
|
||||
}
|
||||
*/
|
||||
|
||||
/* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
|
||||
/*
|
||||
relids = lconsi(lfirsti(xrelid), NIL);
|
||||
rel = rel_member(relids, outerrels);
|
||||
*/
|
||||
|
||||
relids = lconsi(lfirsti(xrelid), NIL);
|
||||
rel = rel_member(relids, root->base_relation_list_);
|
||||
|
||||
super_rels = rel->superrels;
|
||||
new_joininfo = makeNode(JInfo);
|
||||
|
||||
new_joininfo->otherrels = joinrel->relids;
|
||||
new_joininfo->jinfoclauseinfo = clause_info;
|
||||
new_joininfo->mergesortable = mergesortable;
|
||||
new_joininfo->hashjoinable = hashjoinable;
|
||||
new_joininfo->inactive = false;
|
||||
rel->joininfo =
|
||||
lappend(rel->joininfo, new_joininfo);
|
||||
|
||||
foreach(xsuper_rel, super_rels) {
|
||||
Rel *super_rel = (Rel *)lfirst(xsuper_rel);
|
||||
|
||||
if( nonoverlap_rels(super_rel,joinrel) ) {
|
||||
List *new_relids = super_rel->relids;
|
||||
JInfo *other_joininfo =
|
||||
joininfo_member(new_relids,
|
||||
joinrel->joininfo);
|
||||
|
||||
if (other_joininfo) {
|
||||
other_joininfo->jinfoclauseinfo =
|
||||
(List*)LispUnion(clause_info,
|
||||
other_joininfo->jinfoclauseinfo);
|
||||
} else {
|
||||
JInfo *new_joininfo = makeNode(JInfo);
|
||||
|
||||
new_joininfo->otherrels = new_relids;
|
||||
new_joininfo->jinfoclauseinfo = clause_info;
|
||||
new_joininfo->mergesortable = mergesortable;
|
||||
new_joininfo->hashjoinable = hashjoinable;
|
||||
new_joininfo->inactive = false;
|
||||
joinrel->joininfo =
|
||||
lappend(joinrel->joininfo,
|
||||
new_joininfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach(xrel, outerrels) {
|
||||
rel = (Rel *)lfirst(xrel);
|
||||
rel->superrels = NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* final-join-rels--
|
||||
* Find the join relation that includes all the original
|
||||
* relations, i.e. the final join result.
|
||||
*
|
||||
* 'join-rel-list' is a list of join relations.
|
||||
*
|
||||
* Returns the list of final join relations.
|
||||
*/
|
||||
static List *
|
||||
geqo_final_join_rels(List *join_rel_list)
|
||||
{
|
||||
List *xrel = NIL;
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
/*
|
||||
* find the relations that has no further joins,
|
||||
* i.e., its joininfos all have otherrels nil.
|
||||
*/
|
||||
foreach(xrel,join_rel_list) {
|
||||
Rel *rel = (Rel *)lfirst(xrel);
|
||||
List *xjoininfo = NIL;
|
||||
bool final = true;
|
||||
|
||||
foreach (xjoininfo, rel->joininfo) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
|
||||
if (joininfo->otherrels != NIL) {
|
||||
final = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (final) {
|
||||
temp = lcons(rel, NIL);
|
||||
t_list = nconc(t_list, temp);
|
||||
}
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_superrels--
|
||||
* add rel to the temporary property list superrels.
|
||||
*
|
||||
* 'rel' a rel node
|
||||
* 'super-rel' rel node of a join relation that includes rel
|
||||
*
|
||||
* Modifies the superrels field of rel
|
||||
*/
|
||||
static void
|
||||
add_superrels(Rel *rel, Rel *super_rel)
|
||||
{
|
||||
rel->superrels = lappend(rel->superrels, super_rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* nonoverlap-rels--
|
||||
* test if two join relations overlap, i.e., includes the same
|
||||
* relation.
|
||||
*
|
||||
* 'rel1' and 'rel2' are two join relations
|
||||
*
|
||||
* Returns non-nil if rel1 and rel2 do not overlap.
|
||||
*/
|
||||
static bool
|
||||
nonoverlap_rels(Rel *rel1, Rel *rel2)
|
||||
{
|
||||
return(nonoverlap_sets(rel1->relids, rel2->relids));
|
||||
}
|
||||
|
||||
static bool
|
||||
nonoverlap_sets(List *s1, List *s2)
|
||||
{
|
||||
List *x = NIL;
|
||||
|
||||
foreach(x,s1) {
|
||||
int e = lfirsti(x);
|
||||
if(intMember(e,s2))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* geqo_joinrel_size--
|
||||
* compute estimate for join relation tuples, even for
|
||||
* long join queries; so get logarithm of size when MAXINT overflow;
|
||||
*/
|
||||
static void
|
||||
geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel)
|
||||
{
|
||||
Cost temp;
|
||||
int ntuples;
|
||||
|
||||
temp = (Cost) inner_rel->tuples * (Cost) outer_rel->tuples; /* cartesian product */
|
||||
|
||||
if (joinrel->clauseinfo) {
|
||||
temp = temp * product_selec(joinrel->clauseinfo);
|
||||
}
|
||||
|
||||
if (temp >= (MAXINT -1)) {
|
||||
ntuples = ceil( geqo_log((double)temp, (double) GEQO_LOG_BASE) );
|
||||
}
|
||||
else {
|
||||
ntuples = ceil((double)temp);
|
||||
}
|
||||
|
||||
if (ntuples < 1) ntuples = 1; /* make the best case 1 instead of 0 */
|
||||
|
||||
joinrel->tuples = ntuples;
|
||||
}
|
||||
|
||||
double
|
||||
geqo_log(double x, double b)
|
||||
{
|
||||
return(log(x)/log(b));
|
||||
}
|
||||
Reference in New Issue
Block a user