mirror of
https://github.com/postgres/postgres.git
synced 2025-06-25 01:02:05 +03:00
Massive commit to run PGINDENT on all *.c and *.h files.
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* allpaths.c--
|
||||
* Routines to find possible search paths for processing a query
|
||||
* Routines to find possible search paths for processing a query
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.10 1997/06/10 07:55:45 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.11 1997/09/07 04:43:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -34,226 +34,245 @@
|
||||
#include "optimizer/geqo.h"
|
||||
|
||||
#ifdef GEQO
|
||||
bool _use_geqo_ = true;
|
||||
bool _use_geqo_ = true;
|
||||
|
||||
#else
|
||||
bool _use_geqo_ = false;
|
||||
bool _use_geqo_ = false;
|
||||
|
||||
#endif
|
||||
int32 _use_geqo_rels_ = GEQO_RELS;
|
||||
int32 _use_geqo_rels_ = GEQO_RELS;
|
||||
|
||||
|
||||
static void find_rel_paths(Query *root, List *rels);
|
||||
static List *find_join_paths(Query *root, List *outer_rels, int levels_left);
|
||||
static void find_rel_paths(Query * root, List * rels);
|
||||
static List *find_join_paths(Query * root, List * outer_rels, int levels_left);
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-paths--
|
||||
* Finds all possible access paths for executing a query, returning the
|
||||
* top level list of relation entries.
|
||||
*
|
||||
* Finds all possible access paths for executing a query, returning the
|
||||
* top level list of relation entries.
|
||||
*
|
||||
* 'rels' is the list of single relation entries appearing in the query
|
||||
*/
|
||||
List *
|
||||
find_paths(Query *root, List *rels)
|
||||
List *
|
||||
find_paths(Query * root, List * rels)
|
||||
{
|
||||
int levels_left;
|
||||
int levels_left;
|
||||
|
||||
/*
|
||||
* Set the number of join (not nesting) levels yet to be processed.
|
||||
*/
|
||||
levels_left = length(rels);
|
||||
|
||||
if (levels_left <= 0)
|
||||
return NIL;
|
||||
|
||||
/*
|
||||
* Find the base relation paths.
|
||||
*/
|
||||
find_rel_paths(root, rels);
|
||||
|
||||
if (levels_left <= 1) {
|
||||
/*
|
||||
* Unsorted single relation, no more processing is required.
|
||||
* Set the number of join (not nesting) levels yet to be processed.
|
||||
*/
|
||||
return (rels);
|
||||
}else {
|
||||
/*
|
||||
* this means that joins or sorts are required.
|
||||
* set selectivities of clauses that have not been set
|
||||
* by an index.
|
||||
*/
|
||||
set_rest_relselec(root, rels);
|
||||
levels_left = length(rels);
|
||||
|
||||
return(find_join_paths(root, rels, levels_left-1));
|
||||
}
|
||||
if (levels_left <= 0)
|
||||
return NIL;
|
||||
|
||||
/*
|
||||
* Find the base relation paths.
|
||||
*/
|
||||
find_rel_paths(root, rels);
|
||||
|
||||
if (levels_left <= 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* Unsorted single relation, no more processing is required.
|
||||
*/
|
||||
return (rels);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* this means that joins or sorts are required. set selectivities
|
||||
* of clauses that have not been set by an index.
|
||||
*/
|
||||
set_rest_relselec(root, rels);
|
||||
|
||||
return (find_join_paths(root, rels, levels_left - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-rel-paths--
|
||||
* Finds all paths available for scanning each relation entry in
|
||||
* 'rels'. Sequential scan and any available indices are considered
|
||||
* if possible(indices are not considered for lower nesting levels).
|
||||
* All unique paths are attached to the relation's 'pathlist' field.
|
||||
*
|
||||
* MODIFIES: rels
|
||||
* Finds all paths available for scanning each relation entry in
|
||||
* 'rels'. Sequential scan and any available indices are considered
|
||||
* if possible(indices are not considered for lower nesting levels).
|
||||
* All unique paths are attached to the relation's 'pathlist' field.
|
||||
*
|
||||
* MODIFIES: rels
|
||||
*/
|
||||
static void
|
||||
find_rel_paths(Query *root, List *rels)
|
||||
find_rel_paths(Query * root, List * rels)
|
||||
{
|
||||
List *temp;
|
||||
Rel *rel;
|
||||
List *lastpath;
|
||||
|
||||
foreach(temp, rels) {
|
||||
List *sequential_scan_list;
|
||||
List *rel_index_scan_list;
|
||||
List *or_index_scan_list;
|
||||
List *temp;
|
||||
Rel *rel;
|
||||
List *lastpath;
|
||||
|
||||
rel = (Rel *)lfirst(temp);
|
||||
sequential_scan_list = lcons(create_seqscan_path(rel),
|
||||
NIL);
|
||||
foreach(temp, rels)
|
||||
{
|
||||
List *sequential_scan_list;
|
||||
List *rel_index_scan_list;
|
||||
List *or_index_scan_list;
|
||||
|
||||
rel_index_scan_list =
|
||||
find_index_paths(root,
|
||||
rel,
|
||||
find_relation_indices(root,rel),
|
||||
rel->clauseinfo,
|
||||
rel->joininfo);
|
||||
rel = (Rel *) lfirst(temp);
|
||||
sequential_scan_list = lcons(create_seqscan_path(rel),
|
||||
NIL);
|
||||
|
||||
or_index_scan_list =
|
||||
create_or_index_paths(root, rel, rel->clauseinfo);
|
||||
rel_index_scan_list =
|
||||
find_index_paths(root,
|
||||
rel,
|
||||
find_relation_indices(root, rel),
|
||||
rel->clauseinfo,
|
||||
rel->joininfo);
|
||||
|
||||
rel->pathlist = add_pathlist(rel,
|
||||
sequential_scan_list,
|
||||
append(rel_index_scan_list,
|
||||
or_index_scan_list));
|
||||
|
||||
/* The unordered path is always the last in the list.
|
||||
* If it is not the cheapest path, prune it.
|
||||
*/
|
||||
lastpath = rel->pathlist;
|
||||
while(lnext(lastpath)!=NIL)
|
||||
lastpath=lnext(lastpath);
|
||||
prune_rel_path(rel, (Path*)lfirst(lastpath));
|
||||
/*
|
||||
* if there is a qualification of sequential scan the selec.
|
||||
* value is not set -- so set it explicitly -- Sunita
|
||||
*/
|
||||
set_rest_selec(root, rel->clauseinfo);
|
||||
rel->size = compute_rel_size(rel);
|
||||
rel->width = compute_rel_width(rel);
|
||||
}
|
||||
return;
|
||||
or_index_scan_list =
|
||||
create_or_index_paths(root, rel, rel->clauseinfo);
|
||||
|
||||
rel->pathlist = add_pathlist(rel,
|
||||
sequential_scan_list,
|
||||
append(rel_index_scan_list,
|
||||
or_index_scan_list));
|
||||
|
||||
/*
|
||||
* The unordered path is always the last in the list. If it is not
|
||||
* the cheapest path, prune it.
|
||||
*/
|
||||
lastpath = rel->pathlist;
|
||||
while (lnext(lastpath) != NIL)
|
||||
lastpath = lnext(lastpath);
|
||||
prune_rel_path(rel, (Path *) lfirst(lastpath));
|
||||
|
||||
/*
|
||||
* if there is a qualification of sequential scan the selec. value
|
||||
* is not set -- so set it explicitly -- Sunita
|
||||
*/
|
||||
set_rest_selec(root, rel->clauseinfo);
|
||||
rel->size = compute_rel_size(rel);
|
||||
rel->width = compute_rel_width(rel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-join-paths--
|
||||
* Find all possible joinpaths for a query by successively finding ways
|
||||
* to join single relations into join relations.
|
||||
* Find all possible joinpaths for a query by successively finding ways
|
||||
* to join single relations into join relations.
|
||||
*
|
||||
* if BushyPlanFlag is set, bushy tree plans will be generated:
|
||||
* Find all possible joinpaths(bushy trees) for a query by systematically
|
||||
* finding ways to join relations(both original and derived) together.
|
||||
*
|
||||
* 'outer-rels' is the current list of relations for which join paths
|
||||
* are to be found, i.e., he current list of relations that
|
||||
* have already been derived.
|
||||
* if BushyPlanFlag is set, bushy tree plans will be generated:
|
||||
* Find all possible joinpaths(bushy trees) for a query by systematically
|
||||
* finding ways to join relations(both original and derived) together.
|
||||
*
|
||||
* 'outer-rels' is the current list of relations for which join paths
|
||||
* are to be found, i.e., he current list of relations that
|
||||
* have already been derived.
|
||||
* 'levels-left' is the current join level being processed, where '1' is
|
||||
* the "last" level
|
||||
*
|
||||
* the "last" level
|
||||
*
|
||||
* Returns the final level of join relations, i.e., the relation that is
|
||||
* the result of joining all the original relations togehter.
|
||||
*/
|
||||
static List *
|
||||
find_join_paths(Query *root, List *outer_rels, int levels_left)
|
||||
static List *
|
||||
find_join_paths(Query * root, List * outer_rels, int levels_left)
|
||||
{
|
||||
List *x;
|
||||
List *new_rels;
|
||||
Rel *rel;
|
||||
List *x;
|
||||
List *new_rels;
|
||||
Rel *rel;
|
||||
|
||||
/*******************************************
|
||||
* genetic query optimizer entry point *
|
||||
* <utesch@aut.tu-freiberg.de> *
|
||||
*******************************************/
|
||||
/*******************************************
|
||||
* genetic query optimizer entry point *
|
||||
* <utesch@aut.tu-freiberg.de> *
|
||||
*******************************************/
|
||||
|
||||
if ( (_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_ )
|
||||
return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */
|
||||
if ((_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_)
|
||||
return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */
|
||||
|
||||
/*******************************************
|
||||
* rest will be deprecated in case of GEQO *
|
||||
*******************************************/
|
||||
/*******************************************
|
||||
* rest will be deprecated in case of GEQO *
|
||||
*******************************************/
|
||||
|
||||
/*
|
||||
* Determine all possible pairs of relations to be joined at this level.
|
||||
* Determine paths for joining these relation pairs and modify 'new-rels'
|
||||
* accordingly, then eliminate redundant join relations.
|
||||
*/
|
||||
new_rels = find_join_rels(root, outer_rels);
|
||||
/*
|
||||
* Determine all possible pairs of relations to be joined at this
|
||||
* level. Determine paths for joining these relation pairs and modify
|
||||
* 'new-rels' accordingly, then eliminate redundant join relations.
|
||||
*/
|
||||
new_rels = find_join_rels(root, outer_rels);
|
||||
|
||||
find_all_join_paths(root, new_rels);
|
||||
find_all_join_paths(root, new_rels);
|
||||
|
||||
new_rels = prune_joinrels(new_rels);
|
||||
new_rels = prune_joinrels(new_rels);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** for each expensive predicate in each path in each distinct rel,
|
||||
** consider doing pullup -- JMH
|
||||
*/
|
||||
if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
|
||||
foreach(x, new_rels)
|
||||
xfunc_trypullup((Rel*)lfirst(x));
|
||||
#if 0
|
||||
|
||||
/*
|
||||
* * for each expensive predicate in each path in each distinct rel, *
|
||||
* consider doing pullup -- JMH
|
||||
*/
|
||||
if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
|
||||
foreach(x, new_rels)
|
||||
xfunc_trypullup((Rel *) lfirst(x));
|
||||
#endif
|
||||
|
||||
prune_rel_paths(new_rels);
|
||||
prune_rel_paths(new_rels);
|
||||
|
||||
if(BushyPlanFlag) {
|
||||
/*
|
||||
* In case of bushy trees
|
||||
* if there is still a join between a join relation and another
|
||||
* relation, add a new joininfo that involves the join relation
|
||||
* to the joininfo list of the other relation
|
||||
*/
|
||||
add_new_joininfos(root, new_rels,outer_rels);
|
||||
}
|
||||
if (BushyPlanFlag)
|
||||
{
|
||||
|
||||
foreach(x, new_rels) {
|
||||
rel = (Rel*)lfirst(x);
|
||||
if ( rel->size <= 0 )
|
||||
rel->size = compute_rel_size(rel);
|
||||
rel->width = compute_rel_width(rel);
|
||||
/*
|
||||
* In case of bushy trees if there is still a join between a join
|
||||
* relation and another relation, add a new joininfo that involves
|
||||
* the join relation to the joininfo list of the other relation
|
||||
*/
|
||||
add_new_joininfos(root, new_rels, outer_rels);
|
||||
}
|
||||
|
||||
foreach(x, new_rels)
|
||||
{
|
||||
rel = (Rel *) lfirst(x);
|
||||
if (rel->size <= 0)
|
||||
rel->size = compute_rel_size(rel);
|
||||
rel->width = compute_rel_width(rel);
|
||||
|
||||
/*#define OPTIMIZER_DEBUG*/
|
||||
#ifdef OPTIMIZER_DEBUG
|
||||
printf("levels left: %d\n", levels_left);
|
||||
debug_print_rel(root, rel);
|
||||
#endif
|
||||
}
|
||||
printf("levels left: %d\n", levels_left);
|
||||
debug_print_rel(root, rel);
|
||||
#endif
|
||||
}
|
||||
|
||||
if(BushyPlanFlag) {
|
||||
/*
|
||||
* prune rels that have been completely incorporated into
|
||||
* new join rels
|
||||
*/
|
||||
outer_rels = prune_oldrels(outer_rels);
|
||||
/*
|
||||
* merge join rels if then contain the same list of base rels
|
||||
*/
|
||||
outer_rels = merge_joinrels(new_rels,outer_rels);
|
||||
root->join_relation_list_ = outer_rels;
|
||||
}
|
||||
else {
|
||||
root->join_relation_list_ = new_rels;
|
||||
}
|
||||
if (BushyPlanFlag)
|
||||
{
|
||||
|
||||
if(levels_left == 1) {
|
||||
if(BushyPlanFlag)
|
||||
return(final_join_rels(outer_rels));
|
||||
/*
|
||||
* prune rels that have been completely incorporated into new join
|
||||
* rels
|
||||
*/
|
||||
outer_rels = prune_oldrels(outer_rels);
|
||||
|
||||
/*
|
||||
* merge join rels if then contain the same list of base rels
|
||||
*/
|
||||
outer_rels = merge_joinrels(new_rels, outer_rels);
|
||||
root->join_relation_list_ = outer_rels;
|
||||
}
|
||||
else
|
||||
return(new_rels);
|
||||
} else {
|
||||
if(BushyPlanFlag)
|
||||
return(find_join_paths(root, outer_rels, levels_left - 1));
|
||||
{
|
||||
root->join_relation_list_ = new_rels;
|
||||
}
|
||||
|
||||
if (levels_left == 1)
|
||||
{
|
||||
if (BushyPlanFlag)
|
||||
return (final_join_rels(outer_rels));
|
||||
else
|
||||
return (new_rels);
|
||||
}
|
||||
else
|
||||
return(find_join_paths(root, new_rels, levels_left - 1));
|
||||
}
|
||||
{
|
||||
if (BushyPlanFlag)
|
||||
return (find_join_paths(root, outer_rels, levels_left - 1));
|
||||
else
|
||||
return (find_join_paths(root, new_rels, levels_left - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -262,115 +281,147 @@ find_join_paths(Query *root, List *outer_rels, int levels_left)
|
||||
|
||||
#ifdef OPTIMIZER_DEBUG
|
||||
static void
|
||||
print_joinclauses(Query *root, List *clauses)
|
||||
print_joinclauses(Query * root, List * clauses)
|
||||
{
|
||||
List *l;
|
||||
extern void print_expr(Node *expr, List *rtable); /* in print.c */
|
||||
List *l;
|
||||
extern void print_expr(Node * expr, List * rtable); /* in print.c */
|
||||
|
||||
foreach(l, clauses) {
|
||||
CInfo *c = lfirst(l);
|
||||
foreach(l, clauses)
|
||||
{
|
||||
CInfo *c = lfirst(l);
|
||||
|
||||
print_expr((Node*)c->clause, root->rtable);
|
||||
if (lnext(l)) printf(" ");
|
||||
}
|
||||
print_expr((Node *) c->clause, root->rtable);
|
||||
if (lnext(l))
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_path(Query *root, Path *path, int indent)
|
||||
print_path(Query * root, Path * path, int indent)
|
||||
{
|
||||
char *ptype = NULL;
|
||||
JoinPath *jp;
|
||||
bool join = false;
|
||||
int i;
|
||||
char *ptype = NULL;
|
||||
JoinPath *jp;
|
||||
bool join = false;
|
||||
int i;
|
||||
|
||||
for(i=0; i < indent; i++)
|
||||
printf("\t");
|
||||
|
||||
switch(nodeTag(path)) {
|
||||
case T_Path:
|
||||
ptype = "SeqScan"; join=false; break;
|
||||
case T_IndexPath:
|
||||
ptype = "IdxScan"; join=false; break;
|
||||
case T_JoinPath:
|
||||
ptype = "Nestloop"; join=true; break;
|
||||
case T_MergePath:
|
||||
ptype = "MergeJoin"; join=true; break;
|
||||
case T_HashPath:
|
||||
ptype = "HashJoin"; join=true; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (join) {
|
||||
int size = path->parent->size;
|
||||
jp = (JoinPath*)path;
|
||||
printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
|
||||
switch(nodeTag(path)) {
|
||||
case T_MergePath:
|
||||
case T_HashPath:
|
||||
for(i=0; i < indent+1; i++)
|
||||
for (i = 0; i < indent; i++)
|
||||
printf("\t");
|
||||
printf(" clauses=(");
|
||||
print_joinclauses(root,
|
||||
((JoinPath*)path)->pathclauseinfo);
|
||||
printf(")\n");
|
||||
|
||||
if (nodeTag(path)==T_MergePath) {
|
||||
MergePath *mp = (MergePath*)path;
|
||||
if (mp->outersortkeys || mp->innersortkeys) {
|
||||
for(i=0; i < indent+1; i++)
|
||||
printf("\t");
|
||||
printf(" sortouter=%d sortinner=%d\n",
|
||||
((mp->outersortkeys)?1:0),
|
||||
((mp->innersortkeys)?1:0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
switch (nodeTag(path))
|
||||
{
|
||||
case T_Path:
|
||||
ptype = "SeqScan";
|
||||
join = false;
|
||||
break;
|
||||
case T_IndexPath:
|
||||
ptype = "IdxScan";
|
||||
join = false;
|
||||
break;
|
||||
case T_JoinPath:
|
||||
ptype = "Nestloop";
|
||||
join = true;
|
||||
break;
|
||||
case T_MergePath:
|
||||
ptype = "MergeJoin";
|
||||
join = true;
|
||||
break;
|
||||
case T_HashPath:
|
||||
ptype = "HashJoin";
|
||||
join = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
print_path(root, jp->outerjoinpath, indent+1);
|
||||
print_path(root, jp->innerjoinpath, indent+1);
|
||||
} else {
|
||||
int size = path->parent->size;
|
||||
int relid = lfirsti(path->parent->relids);
|
||||
printf("%s(%d) size=%d cost=%f",
|
||||
ptype, relid, size, path->path_cost);
|
||||
if (join)
|
||||
{
|
||||
int size = path->parent->size;
|
||||
|
||||
if (nodeTag(path)==T_IndexPath) {
|
||||
List *k, *l;
|
||||
jp = (JoinPath *) path;
|
||||
printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
|
||||
switch (nodeTag(path))
|
||||
{
|
||||
case T_MergePath:
|
||||
case T_HashPath:
|
||||
for (i = 0; i < indent + 1; i++)
|
||||
printf("\t");
|
||||
printf(" clauses=(");
|
||||
print_joinclauses(root,
|
||||
((JoinPath *) path)->pathclauseinfo);
|
||||
printf(")\n");
|
||||
|
||||
printf(" keys=");
|
||||
foreach (k, path->keys) {
|
||||
printf("(");
|
||||
foreach (l, lfirst(k)) {
|
||||
Var *var = lfirst(l);
|
||||
printf("%d.%d", var->varnoold, var->varoattno);
|
||||
if (lnext(l)) printf(", ");
|
||||
if (nodeTag(path) == T_MergePath)
|
||||
{
|
||||
MergePath *mp = (MergePath *) path;
|
||||
|
||||
if (mp->outersortkeys || mp->innersortkeys)
|
||||
{
|
||||
for (i = 0; i < indent + 1; i++)
|
||||
printf("\t");
|
||||
printf(" sortouter=%d sortinner=%d\n",
|
||||
((mp->outersortkeys) ? 1 : 0),
|
||||
((mp->innersortkeys) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf(")");
|
||||
if (lnext(k)) printf(", ");
|
||||
}
|
||||
print_path(root, jp->outerjoinpath, indent + 1);
|
||||
print_path(root, jp->innerjoinpath, indent + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = path->parent->size;
|
||||
int relid = lfirsti(path->parent->relids);
|
||||
|
||||
printf("%s(%d) size=%d cost=%f",
|
||||
ptype, relid, size, path->path_cost);
|
||||
|
||||
if (nodeTag(path) == T_IndexPath)
|
||||
{
|
||||
List *k,
|
||||
*l;
|
||||
|
||||
printf(" keys=");
|
||||
foreach(k, path->keys)
|
||||
{
|
||||
printf("(");
|
||||
foreach(l, lfirst(k))
|
||||
{
|
||||
Var *var = lfirst(l);
|
||||
|
||||
printf("%d.%d", var->varnoold, var->varoattno);
|
||||
if (lnext(l))
|
||||
printf(", ");
|
||||
}
|
||||
printf(")");
|
||||
if (lnext(k))
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debug_print_rel(Query *root, Rel *rel)
|
||||
static void
|
||||
debug_print_rel(Query * root, Rel * rel)
|
||||
{
|
||||
List *l;
|
||||
List *l;
|
||||
|
||||
printf("(");
|
||||
foreach(l, rel->relids) {
|
||||
printf("%d ", lfirsti(l));
|
||||
}
|
||||
printf("): size=%d width=%d\n", rel->size, rel->width);
|
||||
printf("(");
|
||||
foreach(l, rel->relids)
|
||||
{
|
||||
printf("%d ", lfirsti(l));
|
||||
}
|
||||
printf("): size=%d width=%d\n", rel->size, rel->width);
|
||||
|
||||
printf("\tpath list:\n");
|
||||
foreach (l, rel->pathlist) {
|
||||
print_path(root, lfirst(l), 1);
|
||||
}
|
||||
printf("\tcheapest path:\n");
|
||||
print_path(root, rel->cheapestpath, 1);
|
||||
printf("\tpath list:\n");
|
||||
foreach(l, rel->pathlist)
|
||||
{
|
||||
print_path(root, lfirst(l), 1);
|
||||
}
|
||||
printf("\tcheapest path:\n");
|
||||
print_path(root, rel->cheapestpath, 1);
|
||||
}
|
||||
#endif /* OPTIMIZER_DEBUG */
|
||||
|
||||
#endif /* OPTIMIZER_DEBUG */
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* clausesel.c--
|
||||
* Routines to compute and set clause selectivities
|
||||
* Routines to compute and set clause selectivities
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.2 1997/09/07 04:43:31 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -23,7 +23,7 @@
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/plancat.h"
|
||||
|
||||
#include "parser/parsetree.h" /* for getrelid() */
|
||||
#include "parser/parsetree.h" /* for getrelid() */
|
||||
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
@ -31,301 +31,353 @@
|
||||
#include "utils/elog.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
|
||||
static Cost compute_selec(Query * root, List * clauses, List * or_selectivities);
|
||||
|
||||
/****************************************************************************
|
||||
* ROUTINES TO SET CLAUSE SELECTIVITIES
|
||||
* ROUTINES TO SET CLAUSE SELECTIVITIES
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
/*
|
||||
* set_clause_selectivities -
|
||||
* Sets the selectivity field for each of clause in 'clauseinfo-list'
|
||||
* to 'new-selectivity'. If the selectivity has already been set, reset
|
||||
* it only if the new one is better.
|
||||
*
|
||||
* Sets the selectivity field for each of clause in 'clauseinfo-list'
|
||||
* to 'new-selectivity'. If the selectivity has already been set, reset
|
||||
* it only if the new one is better.
|
||||
*
|
||||
* Returns nothing of interest.
|
||||
*
|
||||
*/
|
||||
void
|
||||
set_clause_selectivities(List *clauseinfo_list, Cost new_selectivity)
|
||||
set_clause_selectivities(List * clauseinfo_list, Cost new_selectivity)
|
||||
{
|
||||
List *temp;
|
||||
CInfo *clausenode;
|
||||
Cost cost_clause;
|
||||
List *temp;
|
||||
CInfo *clausenode;
|
||||
Cost cost_clause;
|
||||
|
||||
foreach (temp,clauseinfo_list) {
|
||||
clausenode = (CInfo*)lfirst(temp);
|
||||
cost_clause = clausenode->selectivity;
|
||||
if ( FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) {
|
||||
clausenode->selectivity = new_selectivity;
|
||||
foreach(temp, clauseinfo_list)
|
||||
{
|
||||
clausenode = (CInfo *) lfirst(temp);
|
||||
cost_clause = clausenode->selectivity;
|
||||
if (FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause)
|
||||
{
|
||||
clausenode->selectivity = new_selectivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* product_selec -
|
||||
* Multiplies the selectivities of each clause in 'clauseinfo-list'.
|
||||
*
|
||||
* Multiplies the selectivities of each clause in 'clauseinfo-list'.
|
||||
*
|
||||
* Returns a flonum corresponding to the selectivity of 'clauseinfo-list'.
|
||||
*/
|
||||
Cost
|
||||
product_selec(List *clauseinfo_list)
|
||||
product_selec(List * clauseinfo_list)
|
||||
{
|
||||
Cost result = 1.0;
|
||||
if (clauseinfo_list!=NIL) {
|
||||
List *xclausenode = NIL;
|
||||
Cost temp;
|
||||
Cost result = 1.0;
|
||||
|
||||
foreach(xclausenode,clauseinfo_list) {
|
||||
temp = ((CInfo *)lfirst(xclausenode))->selectivity;
|
||||
result = result * temp;
|
||||
if (clauseinfo_list != NIL)
|
||||
{
|
||||
List *xclausenode = NIL;
|
||||
Cost temp;
|
||||
|
||||
foreach(xclausenode, clauseinfo_list)
|
||||
{
|
||||
temp = ((CInfo *) lfirst(xclausenode))->selectivity;
|
||||
result = result * temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* set_rest_relselec -
|
||||
* Scans through clauses on each relation and assigns a selectivity to
|
||||
* those clauses that haven't been assigned a selectivity by an index.
|
||||
*
|
||||
* Scans through clauses on each relation and assigns a selectivity to
|
||||
* those clauses that haven't been assigned a selectivity by an index.
|
||||
*
|
||||
* Returns nothing of interest.
|
||||
* MODIFIES: selectivities of the various rel's clauseinfo
|
||||
* slots.
|
||||
* slots.
|
||||
*/
|
||||
void
|
||||
set_rest_relselec(Query *root, List *rel_list)
|
||||
set_rest_relselec(Query * root, List * rel_list)
|
||||
{
|
||||
Rel *rel;
|
||||
List *x;
|
||||
Rel *rel;
|
||||
List *x;
|
||||
|
||||
foreach (x,rel_list) {
|
||||
rel = (Rel*)lfirst(x);
|
||||
set_rest_selec(root, rel->clauseinfo);
|
||||
}
|
||||
foreach(x, rel_list)
|
||||
{
|
||||
rel = (Rel *) lfirst(x);
|
||||
set_rest_selec(root, rel->clauseinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* set_rest_selec -
|
||||
* Sets the selectivity fields for those clauses within a single
|
||||
* relation's 'clauseinfo-list' that haven't already been set.
|
||||
*
|
||||
* Sets the selectivity fields for those clauses within a single
|
||||
* relation's 'clauseinfo-list' that haven't already been set.
|
||||
*
|
||||
* Returns nothing of interest.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void
|
||||
set_rest_selec(Query *root, List *clauseinfo_list)
|
||||
set_rest_selec(Query * root, List * clauseinfo_list)
|
||||
{
|
||||
List *temp = NIL;
|
||||
CInfo *clausenode = (CInfo*)NULL;
|
||||
Cost cost_clause;
|
||||
|
||||
foreach (temp,clauseinfo_list) {
|
||||
clausenode = (CInfo*)lfirst(temp);
|
||||
cost_clause = clausenode->selectivity;
|
||||
List *temp = NIL;
|
||||
CInfo *clausenode = (CInfo *) NULL;
|
||||
Cost cost_clause;
|
||||
|
||||
/*
|
||||
* Check to see if the selectivity of this clause or any 'or'
|
||||
* subclauses (if any) haven't been set yet.
|
||||
*/
|
||||
if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) {
|
||||
clausenode->selectivity =
|
||||
compute_clause_selec(root,
|
||||
(Node*)clausenode->clause,
|
||||
lcons(makeFloat(cost_clause), NIL));
|
||||
foreach(temp, clauseinfo_list)
|
||||
{
|
||||
clausenode = (CInfo *) lfirst(temp);
|
||||
cost_clause = clausenode->selectivity;
|
||||
|
||||
/*
|
||||
* Check to see if the selectivity of this clause or any 'or'
|
||||
* subclauses (if any) haven't been set yet.
|
||||
*/
|
||||
if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause))
|
||||
{
|
||||
clausenode->selectivity =
|
||||
compute_clause_selec(root,
|
||||
(Node *) clausenode->clause,
|
||||
lcons(makeFloat(cost_clause), NIL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ROUTINES TO COMPUTE SELECTIVITIES
|
||||
* ROUTINES TO COMPUTE SELECTIVITIES
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute_clause_selec -
|
||||
* Given a clause, this routine will compute the selectivity of the
|
||||
* clause by calling 'compute_selec' with the appropriate parameters
|
||||
* and possibly use that return value to compute the real selectivity
|
||||
* of a clause.
|
||||
*
|
||||
* Given a clause, this routine will compute the selectivity of the
|
||||
* clause by calling 'compute_selec' with the appropriate parameters
|
||||
* and possibly use that return value to compute the real selectivity
|
||||
* of a clause.
|
||||
*
|
||||
* 'or-selectivities' are selectivities that have already been assigned
|
||||
* to subclauses of an 'or' clause.
|
||||
*
|
||||
* to subclauses of an 'or' clause.
|
||||
*
|
||||
* Returns a flonum corresponding to the clause selectivity.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
|
||||
compute_clause_selec(Query * root, Node * clause, List * or_selectivities)
|
||||
{
|
||||
if (!is_opclause (clause)) {
|
||||
/* if it's not an operator clause, then it is a boolean clause -jolly*/
|
||||
/*
|
||||
* Boolean variables get a selectivity of 1/2.
|
||||
*/
|
||||
return(0.1);
|
||||
} else if (not_clause (clause)) {
|
||||
/*
|
||||
* 'not' gets "1.0 - selectivity-of-inner-clause".
|
||||
*/
|
||||
return (1.000000 - compute_selec(root,
|
||||
lcons(get_notclausearg((Expr*)clause),
|
||||
NIL),
|
||||
or_selectivities));
|
||||
} else if (or_clause(clause)) {
|
||||
/*
|
||||
* Both 'or' and 'and' clauses are evaluated as described in
|
||||
* (compute_selec).
|
||||
*/
|
||||
return (compute_selec(root,
|
||||
((Expr*)clause)->args, or_selectivities));
|
||||
} else {
|
||||
return(compute_selec(root,
|
||||
lcons(clause,NIL),or_selectivities));
|
||||
}
|
||||
if (!is_opclause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* if it's not an operator clause, then it is a boolean clause
|
||||
* -jolly
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boolean variables get a selectivity of 1/2.
|
||||
*/
|
||||
return (0.1);
|
||||
}
|
||||
else if (not_clause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* 'not' gets "1.0 - selectivity-of-inner-clause".
|
||||
*/
|
||||
return (1.000000 - compute_selec(root,
|
||||
lcons(get_notclausearg((Expr *) clause),
|
||||
NIL),
|
||||
or_selectivities));
|
||||
}
|
||||
else if (or_clause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* Both 'or' and 'and' clauses are evaluated as described in
|
||||
* (compute_selec).
|
||||
*/
|
||||
return (compute_selec(root,
|
||||
((Expr *) clause)->args, or_selectivities));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (compute_selec(root,
|
||||
lcons(clause, NIL), or_selectivities));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* compute_selec -
|
||||
* Computes the selectivity of a clause.
|
||||
*
|
||||
* If there is more than one clause in the argument 'clauses', then the
|
||||
* desired selectivity is that of an 'or' clause. Selectivities for an
|
||||
* 'or' clause such as (OR a b) are computed by finding the selectivity
|
||||
* of a (s1) and b (s2) and computing s1+s2 - s1*s2.
|
||||
*
|
||||
* In addition, if the clause is an 'or' clause, individual selectivities
|
||||
* may have already been assigned by indices to subclauses. These values
|
||||
* are contained in the list 'or-selectivities'.
|
||||
*
|
||||
/*
|
||||
* compute_selec -
|
||||
* Computes the selectivity of a clause.
|
||||
*
|
||||
* If there is more than one clause in the argument 'clauses', then the
|
||||
* desired selectivity is that of an 'or' clause. Selectivities for an
|
||||
* 'or' clause such as (OR a b) are computed by finding the selectivity
|
||||
* of a (s1) and b (s2) and computing s1+s2 - s1*s2.
|
||||
*
|
||||
* In addition, if the clause is an 'or' clause, individual selectivities
|
||||
* may have already been assigned by indices to subclauses. These values
|
||||
* are contained in the list 'or-selectivities'.
|
||||
*
|
||||
* Returns the clause selectivity as a flonum.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static Cost
|
||||
compute_selec(Query *root, List *clauses, List *or_selectivities)
|
||||
static Cost
|
||||
compute_selec(Query * root, List * clauses, List * or_selectivities)
|
||||
{
|
||||
Cost s1 = 0;
|
||||
List *clause = lfirst(clauses);
|
||||
Cost s1 = 0;
|
||||
List *clause = lfirst(clauses);
|
||||
|
||||
if (clauses==NULL) {
|
||||
s1 = 1.0;
|
||||
} else if (IsA(clause,Param)) {
|
||||
/* XXX How're we handling this before?? -ay */
|
||||
s1 = 1.0;
|
||||
} else if (IsA(clause,Const)) {
|
||||
s1 = ((bool) ((Const*) clause)->constvalue) ? 1.0 : 0.0;
|
||||
} else if (IsA(clause,Var)) {
|
||||
Oid relid = getrelid(((Var*)clause)->varno,
|
||||
root->rtable);
|
||||
if (clauses == NULL)
|
||||
{
|
||||
s1 = 1.0;
|
||||
}
|
||||
else if (IsA(clause, Param))
|
||||
{
|
||||
/* XXX How're we handling this before?? -ay */
|
||||
s1 = 1.0;
|
||||
}
|
||||
else if (IsA(clause, Const))
|
||||
{
|
||||
s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
|
||||
}
|
||||
else if (IsA(clause, Var))
|
||||
{
|
||||
Oid relid = getrelid(((Var *) clause)->varno,
|
||||
root->rtable);
|
||||
|
||||
/*
|
||||
* we have a bool Var. This is exactly equivalent to the clause:
|
||||
* reln.attribute = 't' so we compute the selectivity as if that
|
||||
* is what we have. The magic #define constants are a hack. I
|
||||
* didn't want to have to do system cache look ups to find out all
|
||||
* of that info.
|
||||
*/
|
||||
|
||||
s1 = restriction_selectivity(EqualSelectivityProcedure,
|
||||
BooleanEqualOperator,
|
||||
relid,
|
||||
((Var *) clause)->varoattno,
|
||||
"t",
|
||||
_SELEC_CONSTANT_RIGHT_);
|
||||
}
|
||||
else if (or_selectivities)
|
||||
{
|
||||
/* If s1 has already been assigned by an index, use that value. */
|
||||
List *this_sel = lfirst(or_selectivities);
|
||||
|
||||
s1 = floatVal(this_sel);
|
||||
}
|
||||
else if (is_funcclause((Node *) clause))
|
||||
{
|
||||
/* this isn't an Oper, it's a Func!! */
|
||||
|
||||
/*
|
||||
* * This is not an operator, so we guess at the selectivity. *
|
||||
* THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE * ABLE
|
||||
* TO HAVE SELECTIVITIES THEMSELVES. * -- JMH 7/9/92
|
||||
*/
|
||||
s1 = 0.1;
|
||||
}
|
||||
else if (NumRelids((Node *) clause) == 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* ...otherwise, calculate s1 from 'clauses'. The clause is not a
|
||||
* join clause, since there is only one relid in the clause. The
|
||||
* clause selectivity will be based on the operator selectivity
|
||||
* and operand values.
|
||||
*/
|
||||
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||
RegProcedure oprrest = get_oprrest(opno);
|
||||
Oid relid;
|
||||
int relidx;
|
||||
AttrNumber attno;
|
||||
Datum constval;
|
||||
int flag;
|
||||
|
||||
get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
|
||||
relid = getrelid(relidx, root->rtable);
|
||||
|
||||
/*
|
||||
* if the oprrest procedure is missing for whatever reason, use a
|
||||
* selectivity of 0.5
|
||||
*/
|
||||
if (!oprrest)
|
||||
s1 = (Cost) (0.5);
|
||||
else if (attno == InvalidAttrNumber)
|
||||
{
|
||||
|
||||
/*
|
||||
* attno can be Invalid if the clause had a function in it,
|
||||
* i.e. WHERE myFunc(f) = 10
|
||||
*/
|
||||
/* this should be FIXED somehow to use function selectivity */
|
||||
s1 = (Cost) (0.5);
|
||||
}
|
||||
else
|
||||
s1 = (Cost) restriction_selectivity(oprrest,
|
||||
opno,
|
||||
relid,
|
||||
attno,
|
||||
(char *) constval,
|
||||
flag);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* The clause must be a join clause. The clause selectivity will
|
||||
* be based on the relations to be scanned and the attributes they
|
||||
* are to be joined on.
|
||||
*/
|
||||
Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
|
||||
RegProcedure oprjoin = get_oprjoin(opno);
|
||||
int relid1,
|
||||
relid2;
|
||||
AttrNumber attno1,
|
||||
attno2;
|
||||
|
||||
get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
|
||||
relid1 = getrelid(relid1, root->rtable);
|
||||
relid2 = getrelid(relid2, root->rtable);
|
||||
|
||||
/*
|
||||
* if the oprjoin procedure is missing for whatever reason, use a
|
||||
* selectivity of 0.5
|
||||
*/
|
||||
if (!oprjoin)
|
||||
s1 = (Cost) (0.5);
|
||||
else
|
||||
s1 = (Cost) join_selectivity(oprjoin,
|
||||
opno,
|
||||
relid1,
|
||||
attno1,
|
||||
relid2,
|
||||
attno2);
|
||||
}
|
||||
|
||||
/*
|
||||
* we have a bool Var. This is exactly equivalent to the clause:
|
||||
* reln.attribute = 't'
|
||||
* so we compute the selectivity as if that is what we have. The
|
||||
* magic #define constants are a hack. I didn't want to have to
|
||||
* do system cache look ups to find out all of that info.
|
||||
* A null clause list eliminates no tuples, so return a selectivity of
|
||||
* 1.0. If there is only one clause, the selectivity is not that of
|
||||
* an 'or' clause, but rather that of the single clause.
|
||||
*/
|
||||
|
||||
s1 = restriction_selectivity(EqualSelectivityProcedure,
|
||||
BooleanEqualOperator,
|
||||
relid,
|
||||
((Var*)clause)->varoattno,
|
||||
"t",
|
||||
_SELEC_CONSTANT_RIGHT_);
|
||||
} else if (or_selectivities) {
|
||||
/* If s1 has already been assigned by an index, use that value. */
|
||||
List *this_sel = lfirst(or_selectivities);
|
||||
|
||||
s1 = floatVal(this_sel);
|
||||
} else if (is_funcclause((Node*)clause)) {
|
||||
/* this isn't an Oper, it's a Func!! */
|
||||
/*
|
||||
** This is not an operator, so we guess at the selectivity.
|
||||
** THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE
|
||||
** ABLE TO HAVE SELECTIVITIES THEMSELVES.
|
||||
** -- JMH 7/9/92
|
||||
*/
|
||||
s1 = 0.1;
|
||||
} else if (NumRelids((Node*) clause) == 1) {
|
||||
/* ...otherwise, calculate s1 from 'clauses'.
|
||||
* The clause is not a join clause, since there is
|
||||
* only one relid in the clause. The clause
|
||||
* selectivity will be based on the operator
|
||||
* selectivity and operand values.
|
||||
*/
|
||||
Oid opno = ((Oper*)((Expr*)clause)->oper)->opno;
|
||||
RegProcedure oprrest = get_oprrest(opno);
|
||||
Oid relid;
|
||||
int relidx;
|
||||
AttrNumber attno;
|
||||
Datum constval;
|
||||
int flag;
|
||||
|
||||
get_relattval((Node*)clause, &relidx, &attno, &constval, &flag);
|
||||
relid = getrelid(relidx, root->rtable);
|
||||
|
||||
/* if the oprrest procedure is missing for whatever reason,
|
||||
use a selectivity of 0.5*/
|
||||
if (!oprrest)
|
||||
s1 = (Cost) (0.5);
|
||||
if (length(clauses) < 2)
|
||||
{
|
||||
return (s1);
|
||||
}
|
||||
else
|
||||
if (attno == InvalidAttrNumber) {
|
||||
/* attno can be Invalid if the clause had a function in it,
|
||||
i.e. WHERE myFunc(f) = 10 */
|
||||
/* this should be FIXED somehow to use function selectivity */
|
||||
s1 = (Cost) (0.5);
|
||||
} else
|
||||
s1 = (Cost) restriction_selectivity(oprrest,
|
||||
opno,
|
||||
relid,
|
||||
attno,
|
||||
(char *)constval,
|
||||
flag);
|
||||
{
|
||||
/* Compute selectivity of the 'or'ed subclauses. */
|
||||
/* Added check for taking lnext(NIL). -- JMH 3/9/92 */
|
||||
Cost s2;
|
||||
|
||||
} else {
|
||||
/* The clause must be a join clause. The clause
|
||||
* selectivity will be based on the relations to be
|
||||
* scanned and the attributes they are to be joined
|
||||
* on.
|
||||
*/
|
||||
Oid opno = ((Oper*)((Expr*)clause)->oper)->opno;
|
||||
RegProcedure oprjoin = get_oprjoin (opno);
|
||||
int relid1, relid2;
|
||||
AttrNumber attno1, attno2;
|
||||
|
||||
get_rels_atts((Node*)clause, &relid1, &attno1, &relid2, &attno2);
|
||||
relid1 = getrelid(relid1, root->rtable);
|
||||
relid2 = getrelid(relid2, root->rtable);
|
||||
|
||||
/* if the oprjoin procedure is missing for whatever reason,
|
||||
use a selectivity of 0.5*/
|
||||
if (!oprjoin)
|
||||
s1 = (Cost) (0.5);
|
||||
else
|
||||
s1 = (Cost) join_selectivity(oprjoin,
|
||||
opno,
|
||||
relid1,
|
||||
attno1,
|
||||
relid2,
|
||||
attno2);
|
||||
}
|
||||
|
||||
/* A null clause list eliminates no tuples, so return a selectivity
|
||||
* of 1.0. If there is only one clause, the selectivity is not
|
||||
* that of an 'or' clause, but rather that of the single clause.
|
||||
*/
|
||||
|
||||
if (length (clauses) < 2) {
|
||||
return(s1);
|
||||
} else {
|
||||
/* Compute selectivity of the 'or'ed subclauses. */
|
||||
/* Added check for taking lnext(NIL). -- JMH 3/9/92 */
|
||||
Cost s2;
|
||||
|
||||
if (or_selectivities != NIL)
|
||||
s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
|
||||
else
|
||||
s2 = compute_selec(root, lnext(clauses), NIL);
|
||||
return(s1 + s2 - s1 * s2);
|
||||
}
|
||||
if (or_selectivities != NIL)
|
||||
s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
|
||||
else
|
||||
s2 = compute_selec(root, lnext(clauses), NIL);
|
||||
return (s1 + s2 - s1 * s2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* costsize.c--
|
||||
* Routines to compute (and set) relation sizes and path costs
|
||||
* Routines to compute (and set) relation sizes and path costs
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.16 1997/08/19 21:31:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.17 1997/09/07 04:43:33 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -17,15 +17,15 @@
|
||||
|
||||
#include <math.h>
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
# ifndef MAXINT
|
||||
# define MAXINT INT_MAX
|
||||
# endif
|
||||
#include <limits.h>
|
||||
#ifndef MAXINT
|
||||
#define MAXINT INT_MAX
|
||||
#endif
|
||||
#else
|
||||
# ifdef HAVE_VALUES_H
|
||||
# include <values.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_VALUES_H
|
||||
#include <values.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <utils/lsyscache.h>
|
||||
#include "nodes/relation.h"
|
||||
@ -35,77 +35,81 @@
|
||||
#include "optimizer/keys.h"
|
||||
#include "optimizer/tlist.h"
|
||||
|
||||
#include "storage/bufmgr.h" /* for BLCKSZ */
|
||||
#include "storage/bufmgr.h" /* for BLCKSZ */
|
||||
|
||||
extern int NBuffers;
|
||||
extern int NBuffers;
|
||||
|
||||
static int compute_attribute_width(TargetEntry *tlistentry);
|
||||
static double base_log(double x, double b);
|
||||
static int compute_targetlist_width(List *targetlist);
|
||||
static int compute_attribute_width(TargetEntry * tlistentry);
|
||||
static double base_log(double x, double b);
|
||||
static int compute_targetlist_width(List * targetlist);
|
||||
|
||||
int _disable_cost_ = 30000000;
|
||||
|
||||
bool _enable_seqscan_ = true;
|
||||
bool _enable_indexscan_ = true;
|
||||
bool _enable_sort_ = true;
|
||||
bool _enable_hash_ = true;
|
||||
bool _enable_nestloop_ = true;
|
||||
bool _enable_mergesort_ = true;
|
||||
bool _enable_hashjoin_ = true;
|
||||
int _disable_cost_ = 30000000;
|
||||
|
||||
Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
|
||||
Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
|
||||
bool _enable_seqscan_ = true;
|
||||
bool _enable_indexscan_ = true;
|
||||
bool _enable_sort_ = true;
|
||||
bool _enable_hash_ = true;
|
||||
bool _enable_nestloop_ = true;
|
||||
bool _enable_mergesort_ = true;
|
||||
bool _enable_hashjoin_ = true;
|
||||
|
||||
/*
|
||||
Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
|
||||
Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
|
||||
|
||||
/*
|
||||
* cost_seqscan--
|
||||
* Determines and returns the cost of scanning a relation sequentially.
|
||||
* If the relation is a temporary to be materialized from a query
|
||||
* embedded within a data field (determined by 'relid' containing an
|
||||
* attribute reference), then a predetermined constant is returned (we
|
||||
* have NO IDEA how big the result of a POSTQUEL procedure is going to
|
||||
* be).
|
||||
*
|
||||
* disk = p
|
||||
* cpu = *CPU-PAGE-WEIGHT* * t
|
||||
*
|
||||
* Determines and returns the cost of scanning a relation sequentially.
|
||||
* If the relation is a temporary to be materialized from a query
|
||||
* embedded within a data field (determined by 'relid' containing an
|
||||
* attribute reference), then a predetermined constant is returned (we
|
||||
* have NO IDEA how big the result of a POSTQUEL procedure is going to
|
||||
* be).
|
||||
*
|
||||
* disk = p
|
||||
* cpu = *CPU-PAGE-WEIGHT* * t
|
||||
*
|
||||
* 'relid' is the relid of the relation to be scanned
|
||||
* 'relpages' is the number of pages in the relation to be scanned
|
||||
* (as determined from the system catalogs)
|
||||
* (as determined from the system catalogs)
|
||||
* 'reltuples' is the number of tuples in the relation to be scanned
|
||||
*
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
cost_seqscan(int relid, int relpages, int reltuples)
|
||||
{
|
||||
Cost temp = 0;
|
||||
Cost temp = 0;
|
||||
|
||||
if ( !_enable_seqscan_ )
|
||||
temp += _disable_cost_;
|
||||
if (!_enable_seqscan_)
|
||||
temp += _disable_cost_;
|
||||
|
||||
if (relid < 0) {
|
||||
/*
|
||||
* cost of sequentially scanning a materialized temporary relation
|
||||
*/
|
||||
temp += _TEMP_SCAN_COST_;
|
||||
} else {
|
||||
temp += relpages;
|
||||
temp += _cpu_page_wight_ * reltuples;
|
||||
}
|
||||
Assert(temp >= 0);
|
||||
return(temp);
|
||||
if (relid < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* cost of sequentially scanning a materialized temporary relation
|
||||
*/
|
||||
temp += _TEMP_SCAN_COST_;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += relpages;
|
||||
temp += _cpu_page_wight_ * reltuples;
|
||||
}
|
||||
Assert(temp >= 0);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* cost_index--
|
||||
* Determines and returns the cost of scanning a relation using an index.
|
||||
*
|
||||
* disk = expected-index-pages + expected-data-pages
|
||||
* cpu = *CPU-PAGE-WEIGHT* *
|
||||
* (expected-index-tuples + expected-data-tuples)
|
||||
*
|
||||
* Determines and returns the cost of scanning a relation using an index.
|
||||
*
|
||||
* disk = expected-index-pages + expected-data-pages
|
||||
* cpu = *CPU-PAGE-WEIGHT* *
|
||||
* (expected-index-tuples + expected-data-tuples)
|
||||
*
|
||||
* 'indexid' is the index OID
|
||||
* 'expected-indexpages' is the number of index pages examined in the scan
|
||||
* 'selec' is the selectivity of the index
|
||||
@ -113,100 +117,102 @@ cost_seqscan(int relid, int relpages, int reltuples)
|
||||
* 'reltuples' is the number of tuples in the main relation
|
||||
* 'indexpages' is the number of pages in the index relation
|
||||
* 'indextuples' is the number of tuples in the index relation
|
||||
*
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
cost_index(Oid indexid,
|
||||
int expected_indexpages,
|
||||
Cost selec,
|
||||
int relpages,
|
||||
int reltuples,
|
||||
int indexpages,
|
||||
int indextuples,
|
||||
bool is_injoin)
|
||||
int expected_indexpages,
|
||||
Cost selec,
|
||||
int relpages,
|
||||
int reltuples,
|
||||
int indexpages,
|
||||
int indextuples,
|
||||
bool is_injoin)
|
||||
{
|
||||
Cost temp;
|
||||
double temp2;
|
||||
Cost temp;
|
||||
double temp2;
|
||||
|
||||
temp = (Cost) 0;
|
||||
temp = (Cost) 0;
|
||||
|
||||
if (!_enable_indexscan_ && !is_injoin)
|
||||
temp += _disable_cost_;
|
||||
if (!_enable_indexscan_ && !is_injoin)
|
||||
temp += _disable_cost_;
|
||||
|
||||
/* expected index relation pages */
|
||||
temp += expected_indexpages;
|
||||
/* expected index relation pages */
|
||||
temp += expected_indexpages;
|
||||
|
||||
/* expected base relation pages */
|
||||
temp2 = ( reltuples == 0 ) ? (double)0 : (double)relpages/reltuples;
|
||||
temp2 = temp2 * (double)selec * indextuples;
|
||||
temp += Min (relpages, (int)ceil (temp2));
|
||||
/* expected base relation pages */
|
||||
temp2 = (reltuples == 0) ? (double) 0 : (double) relpages / reltuples;
|
||||
temp2 = temp2 * (double) selec *indextuples;
|
||||
|
||||
/* per index tuples */
|
||||
temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
|
||||
temp += Min(relpages, (int) ceil(temp2));
|
||||
|
||||
/* per heap tuples */
|
||||
temp = temp + (_cpu_page_wight_ * selec * reltuples);
|
||||
/* per index tuples */
|
||||
temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
|
||||
|
||||
Assert(temp >= 0);
|
||||
return(temp);
|
||||
/* per heap tuples */
|
||||
temp = temp + (_cpu_page_wight_ * selec * reltuples);
|
||||
|
||||
Assert(temp >= 0);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* cost_sort--
|
||||
* Determines and returns the cost of sorting a relation by considering
|
||||
* 1. the cost of doing an external sort: XXX this is probably too low
|
||||
* disk = (p lg p)
|
||||
* cpu = *CPU-PAGE-WEIGHT* * (t lg t)
|
||||
* 2. the cost of reading the sort result into memory (another seqscan)
|
||||
* unless 'noread' is set
|
||||
*
|
||||
* Determines and returns the cost of sorting a relation by considering
|
||||
* 1. the cost of doing an external sort: XXX this is probably too low
|
||||
* disk = (p lg p)
|
||||
* cpu = *CPU-PAGE-WEIGHT* * (t lg t)
|
||||
* 2. the cost of reading the sort result into memory (another seqscan)
|
||||
* unless 'noread' is set
|
||||
*
|
||||
* 'keys' is a list of sort keys
|
||||
* 'tuples' is the number of tuples in the relation
|
||||
* 'width' is the average tuple width in bytes
|
||||
* 'noread' is a flag indicating that the sort result can remain on disk
|
||||
* (i.e., the sort result is the result relation)
|
||||
*
|
||||
* (i.e., the sort result is the result relation)
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
cost_sort(List *keys, int tuples, int width, bool noread)
|
||||
cost_sort(List * keys, int tuples, int width, bool noread)
|
||||
{
|
||||
Cost temp = 0;
|
||||
int npages = page_size (tuples,width);
|
||||
Cost pages = (Cost)npages;
|
||||
Cost numTuples = tuples;
|
||||
|
||||
if ( !_enable_sort_ )
|
||||
temp += _disable_cost_ ;
|
||||
if (tuples == 0 || keys==NULL)
|
||||
Cost temp = 0;
|
||||
int npages = page_size(tuples, width);
|
||||
Cost pages = (Cost) npages;
|
||||
Cost numTuples = tuples;
|
||||
|
||||
if (!_enable_sort_)
|
||||
temp += _disable_cost_;
|
||||
if (tuples == 0 || keys == NULL)
|
||||
{
|
||||
Assert(temp >= 0);
|
||||
return(temp);
|
||||
Assert(temp >= 0);
|
||||
return (temp);
|
||||
}
|
||||
temp += pages * base_log((double)pages, (double)2.0);
|
||||
temp += pages * base_log((double) pages, (double) 2.0);
|
||||
|
||||
/*
|
||||
* could be base_log(pages, NBuffers), but we are only doing 2-way merges
|
||||
*/
|
||||
temp += _cpu_page_wight_ *
|
||||
numTuples * base_log((double)pages,(double)2.0);
|
||||
/*
|
||||
* could be base_log(pages, NBuffers), but we are only doing 2-way
|
||||
* merges
|
||||
*/
|
||||
temp += _cpu_page_wight_ *
|
||||
numTuples * base_log((double) pages, (double) 2.0);
|
||||
|
||||
if( !noread )
|
||||
temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples);
|
||||
Assert(temp >= 0);
|
||||
if (!noread)
|
||||
temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples);
|
||||
Assert(temp >= 0);
|
||||
|
||||
return(temp);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* cost_result--
|
||||
* Determines and returns the cost of writing a relation of 'tuples'
|
||||
* tuples of 'width' bytes out to a result relation.
|
||||
*
|
||||
* Determines and returns the cost of writing a relation of 'tuples'
|
||||
* tuples of 'width' bytes out to a result relation.
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*/
|
||||
@ -214,257 +220,273 @@ cost_sort(List *keys, int tuples, int width, bool noread)
|
||||
Cost
|
||||
cost_result(int tuples, int width)
|
||||
{
|
||||
Cost temp =0;
|
||||
temp = temp + page_size(tuples,width);
|
||||
temp = temp + _cpu_page_wight_ * tuples;
|
||||
Assert(temp >= 0);
|
||||
return(temp);
|
||||
Cost temp = 0;
|
||||
|
||||
temp = temp + page_size(tuples, width);
|
||||
temp = temp + _cpu_page_wight_ * tuples;
|
||||
Assert(temp >= 0);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
/*
|
||||
* cost_nestloop--
|
||||
* Determines and returns the cost of joining two relations using the
|
||||
* nested loop algorithm.
|
||||
*
|
||||
* Determines and returns the cost of joining two relations using the
|
||||
* nested loop algorithm.
|
||||
*
|
||||
* 'outercost' is the (disk+cpu) cost of scanning the outer relation
|
||||
* 'innercost' is the (disk+cpu) cost of scanning the inner relation
|
||||
* 'outertuples' is the number of tuples in the outer relation
|
||||
*
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
cost_nestloop(Cost outercost,
|
||||
Cost innercost,
|
||||
int outertuples,
|
||||
int innertuples,
|
||||
int outerpages,
|
||||
bool is_indexjoin)
|
||||
Cost innercost,
|
||||
int outertuples,
|
||||
int innertuples,
|
||||
int outerpages,
|
||||
bool is_indexjoin)
|
||||
{
|
||||
Cost temp =0;
|
||||
Cost temp = 0;
|
||||
|
||||
if ( !_enable_nestloop_ )
|
||||
temp += _disable_cost_;
|
||||
temp += outercost;
|
||||
temp += outertuples * innercost;
|
||||
Assert(temp >= 0);
|
||||
if (!_enable_nestloop_)
|
||||
temp += _disable_cost_;
|
||||
temp += outercost;
|
||||
temp += outertuples * innercost;
|
||||
Assert(temp >= 0);
|
||||
|
||||
return(temp);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* cost_mergesort--
|
||||
* 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
|
||||
* outer and inner relations
|
||||
* 'outersortkeys' and 'innersortkeys' are lists of the keys to be used
|
||||
* to sort the outer and inner relations
|
||||
* 'outertuples' and 'innertuples' are the number of tuples in the outer
|
||||
* and inner relations
|
||||
* 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
|
||||
* of the tuples of the outer and inner relations
|
||||
*
|
||||
* 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
|
||||
* outer and inner relations
|
||||
* 'outersortkeys' and 'innersortkeys' are lists of the keys to be used
|
||||
* to sort the outer and inner relations
|
||||
* 'outertuples' and 'innertuples' are the number of tuples in the outer
|
||||
* and inner relations
|
||||
* 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
|
||||
* of the tuples of the outer and inner relations
|
||||
*
|
||||
* Returns a flonum.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Cost
|
||||
cost_mergesort(Cost outercost,
|
||||
Cost innercost,
|
||||
List *outersortkeys,
|
||||
List *innersortkeys,
|
||||
int outersize,
|
||||
int innersize,
|
||||
int outerwidth,
|
||||
int innerwidth)
|
||||
Cost innercost,
|
||||
List * outersortkeys,
|
||||
List * innersortkeys,
|
||||
int outersize,
|
||||
int innersize,
|
||||
int outerwidth,
|
||||
int innerwidth)
|
||||
{
|
||||
Cost temp = 0;
|
||||
Cost temp = 0;
|
||||
|
||||
if ( !_enable_mergesort_ )
|
||||
temp += _disable_cost_;
|
||||
|
||||
temp += outercost;
|
||||
temp += innercost;
|
||||
temp += cost_sort(outersortkeys,outersize,outerwidth,false);
|
||||
temp += cost_sort(innersortkeys,innersize,innerwidth,false);
|
||||
temp += _cpu_page_wight_ * (outersize + innersize);
|
||||
Assert(temp >= 0);
|
||||
if (!_enable_mergesort_)
|
||||
temp += _disable_cost_;
|
||||
|
||||
return(temp);
|
||||
temp += outercost;
|
||||
temp += innercost;
|
||||
temp += cost_sort(outersortkeys, outersize, outerwidth, false);
|
||||
temp += cost_sort(innersortkeys, innersize, innerwidth, false);
|
||||
temp += _cpu_page_wight_ * (outersize + innersize);
|
||||
Assert(temp >= 0);
|
||||
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/*
|
||||
* cost_hashjoin-- XXX HASH
|
||||
* 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
|
||||
* outer and inner relations
|
||||
* 'outerkeys' and 'innerkeys' are lists of the keys to be used
|
||||
* to hash the outer and inner relations
|
||||
* 'outersize' and 'innersize' are the number of tuples in the outer
|
||||
* and inner relations
|
||||
* 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
|
||||
* of the tuples of the outer and inner relations
|
||||
*
|
||||
/*
|
||||
* cost_hashjoin-- XXX HASH
|
||||
* 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
|
||||
* outer and inner relations
|
||||
* 'outerkeys' and 'innerkeys' are lists of the keys to be used
|
||||
* to hash the outer and inner relations
|
||||
* 'outersize' and 'innersize' are the number of tuples in the outer
|
||||
* and inner relations
|
||||
* 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
|
||||
* of the tuples of the outer and inner relations
|
||||
*
|
||||
* Returns a flonum.
|
||||
*/
|
||||
Cost
|
||||
cost_hashjoin(Cost outercost,
|
||||
Cost innercost,
|
||||
List *outerkeys,
|
||||
List *innerkeys,
|
||||
int outersize,
|
||||
int innersize,
|
||||
int outerwidth,
|
||||
int innerwidth)
|
||||
Cost innercost,
|
||||
List * outerkeys,
|
||||
List * innerkeys,
|
||||
int outersize,
|
||||
int innersize,
|
||||
int outerwidth,
|
||||
int innerwidth)
|
||||
{
|
||||
Cost temp = 0;
|
||||
int outerpages = page_size (outersize,outerwidth);
|
||||
int innerpages = page_size (innersize,innerwidth);
|
||||
int nrun = ceil((double)outerpages/(double)NBuffers);
|
||||
Cost temp = 0;
|
||||
int outerpages = page_size(outersize, outerwidth);
|
||||
int innerpages = page_size(innersize, innerwidth);
|
||||
int nrun = ceil((double) outerpages / (double) NBuffers);
|
||||
|
||||
if (outerpages < innerpages)
|
||||
return _disable_cost_;
|
||||
if ( !_enable_hashjoin_ )
|
||||
temp += _disable_cost_;
|
||||
/*
|
||||
temp += outercost + (nrun + 1) * innercost;
|
||||
*
|
||||
* the innercost shouldn't be used it. Instead the
|
||||
* cost of hashing the innerpath should be used
|
||||
*
|
||||
* ASSUME innercost is 1 for now -- a horrible hack
|
||||
* - jolly
|
||||
temp += outercost + (nrun + 1);
|
||||
*
|
||||
* But we must add innercost to result. - vadim 04/24/97
|
||||
*/
|
||||
temp += outercost + innercost + (nrun + 1);
|
||||
if (outerpages < innerpages)
|
||||
return _disable_cost_;
|
||||
if (!_enable_hashjoin_)
|
||||
temp += _disable_cost_;
|
||||
|
||||
temp += _cpu_page_wight_ * (outersize + nrun * innersize);
|
||||
Assert(temp >= 0);
|
||||
/*
|
||||
* temp += outercost + (nrun + 1) * innercost;
|
||||
*
|
||||
* the innercost shouldn't be used it. Instead the cost of hashing the
|
||||
* innerpath should be used
|
||||
*
|
||||
* ASSUME innercost is 1 for now -- a horrible hack - jolly temp +=
|
||||
* outercost + (nrun + 1);
|
||||
*
|
||||
* But we must add innercost to result. - vadim 04/24/97
|
||||
*/
|
||||
temp += outercost + innercost + (nrun + 1);
|
||||
|
||||
return(temp);
|
||||
temp += _cpu_page_wight_ * (outersize + nrun * innersize);
|
||||
Assert(temp >= 0);
|
||||
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute-rel-size--
|
||||
* Computes the size of each relation in 'rel-list' (after applying
|
||||
* restrictions), by multiplying the selectivity of each restriction
|
||||
* by the original size of the relation.
|
||||
*
|
||||
* Sets the 'size' field for each relation entry with this computed size.
|
||||
*
|
||||
* Computes the size of each relation in 'rel-list' (after applying
|
||||
* restrictions), by multiplying the selectivity of each restriction
|
||||
* by the original size of the relation.
|
||||
*
|
||||
* Sets the 'size' field for each relation entry with this computed size.
|
||||
*
|
||||
* Returns the size.
|
||||
*/
|
||||
int compute_rel_size(Rel *rel)
|
||||
int
|
||||
compute_rel_size(Rel * rel)
|
||||
{
|
||||
Cost temp;
|
||||
int temp1;
|
||||
Cost temp;
|
||||
int temp1;
|
||||
|
||||
temp = rel->tuples * product_selec(rel->clauseinfo);
|
||||
Assert(temp >= 0);
|
||||
if (temp >= (MAXINT - 1)) {
|
||||
temp1 = MAXINT;
|
||||
} else {
|
||||
temp1 = ceil((double) temp);
|
||||
}
|
||||
Assert(temp1 >= 0);
|
||||
Assert(temp1 <= MAXINT);
|
||||
return(temp1);
|
||||
temp = rel->tuples * product_selec(rel->clauseinfo);
|
||||
Assert(temp >= 0);
|
||||
if (temp >= (MAXINT - 1))
|
||||
{
|
||||
temp1 = MAXINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp1 = ceil((double) temp);
|
||||
}
|
||||
Assert(temp1 >= 0);
|
||||
Assert(temp1 <= MAXINT);
|
||||
return (temp1);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute-rel-width--
|
||||
* Computes the width in bytes of a tuple from 'rel'.
|
||||
*
|
||||
* Computes the width in bytes of a tuple from 'rel'.
|
||||
*
|
||||
* Returns the width of the tuple as a fixnum.
|
||||
*/
|
||||
int
|
||||
compute_rel_width(Rel *rel)
|
||||
compute_rel_width(Rel * rel)
|
||||
{
|
||||
return (compute_targetlist_width(get_actual_tlist(rel->targetlist)));
|
||||
return (compute_targetlist_width(get_actual_tlist(rel->targetlist)));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute-targetlist-width--
|
||||
* Computes the width in bytes of a tuple made from 'targetlist'.
|
||||
*
|
||||
* Computes the width in bytes of a tuple made from 'targetlist'.
|
||||
*
|
||||
* Returns the width of the tuple as a fixnum.
|
||||
*/
|
||||
static int
|
||||
compute_targetlist_width(List *targetlist)
|
||||
compute_targetlist_width(List * targetlist)
|
||||
{
|
||||
List *temp_tl;
|
||||
int tuple_width = 0;
|
||||
List *temp_tl;
|
||||
int tuple_width = 0;
|
||||
|
||||
foreach (temp_tl, targetlist) {
|
||||
tuple_width = tuple_width +
|
||||
compute_attribute_width(lfirst(temp_tl));
|
||||
}
|
||||
return(tuple_width);
|
||||
foreach(temp_tl, targetlist)
|
||||
{
|
||||
tuple_width = tuple_width +
|
||||
compute_attribute_width(lfirst(temp_tl));
|
||||
}
|
||||
return (tuple_width);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute-attribute-width--
|
||||
* Given a target list entry, find the size in bytes of the attribute.
|
||||
*
|
||||
* If a field is variable-length, it is assumed to be at least the size
|
||||
* of a TID field.
|
||||
*
|
||||
* Given a target list entry, find the size in bytes of the attribute.
|
||||
*
|
||||
* If a field is variable-length, it is assumed to be at least the size
|
||||
* of a TID field.
|
||||
*
|
||||
* Returns the width of the attribute as a fixnum.
|
||||
*/
|
||||
static int
|
||||
compute_attribute_width(TargetEntry *tlistentry)
|
||||
compute_attribute_width(TargetEntry * tlistentry)
|
||||
{
|
||||
int width = get_typlen(tlistentry->resdom->restype);
|
||||
if (width < 0)
|
||||
return(_DEFAULT_ATTRIBUTE_WIDTH_);
|
||||
else
|
||||
return(width);
|
||||
int width = get_typlen(tlistentry->resdom->restype);
|
||||
|
||||
if (width < 0)
|
||||
return (_DEFAULT_ATTRIBUTE_WIDTH_);
|
||||
else
|
||||
return (width);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* compute-joinrel-size--
|
||||
* Computes the size of the join relation 'joinrel'.
|
||||
*
|
||||
* Computes the size of the join relation 'joinrel'.
|
||||
*
|
||||
* Returns a fixnum.
|
||||
*/
|
||||
int
|
||||
compute_joinrel_size(JoinPath *joinpath)
|
||||
compute_joinrel_size(JoinPath * joinpath)
|
||||
{
|
||||
Cost temp = 1.0;
|
||||
int temp1 = 0;
|
||||
Cost temp = 1.0;
|
||||
int temp1 = 0;
|
||||
|
||||
temp *= ((Path*)joinpath->outerjoinpath)->parent->size;
|
||||
temp *= ((Path*)joinpath->innerjoinpath)->parent->size;
|
||||
|
||||
temp = temp * product_selec(joinpath->pathclauseinfo);
|
||||
if (temp >= (MAXINT -1)) {
|
||||
temp1 = MAXINT;
|
||||
} else {
|
||||
/* should be ceil here, we don't want joinrel size's of one, do we? */
|
||||
temp1 = ceil((double)temp);
|
||||
}
|
||||
Assert(temp1 >= 0);
|
||||
temp *= ((Path *) joinpath->outerjoinpath)->parent->size;
|
||||
temp *= ((Path *) joinpath->innerjoinpath)->parent->size;
|
||||
|
||||
return(temp1);
|
||||
temp = temp * product_selec(joinpath->pathclauseinfo);
|
||||
if (temp >= (MAXINT - 1))
|
||||
{
|
||||
temp1 = MAXINT;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* should be ceil here, we don't want joinrel size's of one, do
|
||||
* we?
|
||||
*/
|
||||
temp1 = ceil((double) temp);
|
||||
}
|
||||
Assert(temp1 >= 0);
|
||||
|
||||
return (temp1);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* page-size--
|
||||
* Returns an estimate of the number of pages covered by a given
|
||||
* number of tuples of a given width (size in bytes).
|
||||
* Returns an estimate of the number of pages covered by a given
|
||||
* number of tuples of a given width (size in bytes).
|
||||
*/
|
||||
int page_size(int tuples, int width)
|
||||
int
|
||||
page_size(int tuples, int width)
|
||||
{
|
||||
int temp =0;
|
||||
int temp = 0;
|
||||
|
||||
temp = ceil((double)(tuples * (width + sizeof(HeapTupleData)))
|
||||
/ BLCKSZ);
|
||||
Assert(temp >= 0);
|
||||
return(temp);
|
||||
temp = ceil((double) (tuples * (width + sizeof(HeapTupleData)))
|
||||
/ BLCKSZ);
|
||||
Assert(temp >= 0);
|
||||
return (temp);
|
||||
}
|
||||
|
||||
static double
|
||||
base_log(double x, double b)
|
||||
{
|
||||
return(log(x)/log(b));
|
||||
return (log(x) / log(b));
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hashutils.c--
|
||||
* Utilities for finding applicable merge clauses and pathkeys
|
||||
* Utilities for finding applicable merge clauses and pathkeys
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.2 1997/09/07 04:43:34 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,101 +20,109 @@
|
||||
#include "optimizer/clauses.h"
|
||||
|
||||
|
||||
static HInfo *match_hashop_hashinfo(Oid hashop, List *hashinfo_list);
|
||||
static HInfo *match_hashop_hashinfo(Oid hashop, List * hashinfo_list);
|
||||
|
||||
/*
|
||||
/*
|
||||
* group-clauses-by-hashop--
|
||||
* If a join clause node in 'clauseinfo-list' is hashjoinable, store
|
||||
* it within a hashinfo node containing other clause nodes with the same
|
||||
* hash operator.
|
||||
*
|
||||
* If a join clause node in 'clauseinfo-list' is hashjoinable, store
|
||||
* it within a hashinfo node containing other clause nodes with the same
|
||||
* hash operator.
|
||||
*
|
||||
* 'clauseinfo-list' is the list of clauseinfo nodes
|
||||
* 'inner-relid' is the relid of the inner join relation
|
||||
*
|
||||
*
|
||||
* Returns the new list of hashinfo nodes.
|
||||
*
|
||||
*
|
||||
*/
|
||||
List *
|
||||
group_clauses_by_hashop(List *clauseinfo_list,
|
||||
int inner_relid)
|
||||
List *
|
||||
group_clauses_by_hashop(List * clauseinfo_list,
|
||||
int inner_relid)
|
||||
{
|
||||
List *hashinfo_list = NIL;
|
||||
CInfo *clauseinfo = (CInfo*)NULL;
|
||||
List *i = NIL;
|
||||
Oid hashjoinop = 0;
|
||||
|
||||
foreach (i,clauseinfo_list) {
|
||||
clauseinfo = (CInfo*)lfirst(i);
|
||||
hashjoinop = clauseinfo->hashjoinoperator;
|
||||
|
||||
/*
|
||||
* Create a new hashinfo node and add it to 'hashinfo-list' if one
|
||||
* does not yet exist for this hash operator.
|
||||
*/
|
||||
if (hashjoinop ) {
|
||||
HInfo *xhashinfo = (HInfo*)NULL;
|
||||
Expr *clause = clauseinfo->clause;
|
||||
Var *leftop = get_leftop(clause);
|
||||
Var *rightop = get_rightop(clause);
|
||||
JoinKey *keys = (JoinKey*)NULL;
|
||||
|
||||
xhashinfo =
|
||||
match_hashop_hashinfo(hashjoinop,hashinfo_list);
|
||||
|
||||
if (inner_relid == leftop->varno){
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = rightop;
|
||||
keys->inner = leftop;
|
||||
} else {
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = leftop;
|
||||
keys->inner = rightop;
|
||||
}
|
||||
|
||||
if (xhashinfo==NULL) {
|
||||
xhashinfo = makeNode(HInfo);
|
||||
xhashinfo->hashop = hashjoinop;
|
||||
List *hashinfo_list = NIL;
|
||||
CInfo *clauseinfo = (CInfo *) NULL;
|
||||
List *i = NIL;
|
||||
Oid hashjoinop = 0;
|
||||
|
||||
xhashinfo->jmethod.jmkeys = NIL;
|
||||
xhashinfo->jmethod.clauses = NIL;
|
||||
foreach(i, clauseinfo_list)
|
||||
{
|
||||
clauseinfo = (CInfo *) lfirst(i);
|
||||
hashjoinop = clauseinfo->hashjoinoperator;
|
||||
|
||||
/* XXX was push */
|
||||
hashinfo_list = lappend(hashinfo_list,xhashinfo);
|
||||
hashinfo_list = nreverse(hashinfo_list);
|
||||
}
|
||||
/*
|
||||
* Create a new hashinfo node and add it to 'hashinfo-list' if one
|
||||
* does not yet exist for this hash operator.
|
||||
*/
|
||||
if (hashjoinop)
|
||||
{
|
||||
HInfo *xhashinfo = (HInfo *) NULL;
|
||||
Expr *clause = clauseinfo->clause;
|
||||
Var *leftop = get_leftop(clause);
|
||||
Var *rightop = get_rightop(clause);
|
||||
JoinKey *keys = (JoinKey *) NULL;
|
||||
|
||||
xhashinfo->jmethod.clauses =
|
||||
lcons(clause, xhashinfo->jmethod.clauses);
|
||||
xhashinfo =
|
||||
match_hashop_hashinfo(hashjoinop, hashinfo_list);
|
||||
|
||||
xhashinfo->jmethod.jmkeys =
|
||||
lcons(keys, xhashinfo->jmethod.jmkeys);
|
||||
if (inner_relid == leftop->varno)
|
||||
{
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = rightop;
|
||||
keys->inner = leftop;
|
||||
}
|
||||
else
|
||||
{
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = leftop;
|
||||
keys->inner = rightop;
|
||||
}
|
||||
|
||||
if (xhashinfo == NULL)
|
||||
{
|
||||
xhashinfo = makeNode(HInfo);
|
||||
xhashinfo->hashop = hashjoinop;
|
||||
|
||||
xhashinfo->jmethod.jmkeys = NIL;
|
||||
xhashinfo->jmethod.clauses = NIL;
|
||||
|
||||
/* XXX was push */
|
||||
hashinfo_list = lappend(hashinfo_list, xhashinfo);
|
||||
hashinfo_list = nreverse(hashinfo_list);
|
||||
}
|
||||
|
||||
xhashinfo->jmethod.clauses =
|
||||
lcons(clause, xhashinfo->jmethod.clauses);
|
||||
|
||||
xhashinfo->jmethod.jmkeys =
|
||||
lcons(keys, xhashinfo->jmethod.jmkeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(hashinfo_list);
|
||||
return (hashinfo_list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* match-hashop-hashinfo--
|
||||
* Searches the list 'hashinfo-list' for a hashinfo node whose hash op
|
||||
* field equals 'hashop'.
|
||||
*
|
||||
* Searches the list 'hashinfo-list' for a hashinfo node whose hash op
|
||||
* field equals 'hashop'.
|
||||
*
|
||||
* Returns the node if it exists.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static HInfo *
|
||||
match_hashop_hashinfo(Oid hashop, List *hashinfo_list)
|
||||
static HInfo *
|
||||
match_hashop_hashinfo(Oid hashop, List * hashinfo_list)
|
||||
{
|
||||
Oid key = 0;
|
||||
HInfo *xhashinfo = (HInfo*)NULL;
|
||||
List *i = NIL;
|
||||
|
||||
foreach( i, hashinfo_list) {
|
||||
xhashinfo = (HInfo*)lfirst(i);
|
||||
key = xhashinfo->hashop;
|
||||
if (hashop == key) { /* found */
|
||||
return(xhashinfo); /* should be a hashinfo node ! */
|
||||
Oid key = 0;
|
||||
HInfo *xhashinfo = (HInfo *) NULL;
|
||||
List *i = NIL;
|
||||
|
||||
foreach(i, hashinfo_list)
|
||||
{
|
||||
xhashinfo = (HInfo *) lfirst(i);
|
||||
key = xhashinfo->hashop;
|
||||
if (hashop == key)
|
||||
{ /* found */
|
||||
return (xhashinfo); /* should be a hashinfo node ! */
|
||||
}
|
||||
}
|
||||
}
|
||||
return((HInfo*)NIL);
|
||||
return ((HInfo *) NIL);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* joinrels.c--
|
||||
* Routines to determine which relations should be joined
|
||||
* Routines to determine which relations should be joined
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.4 1997/06/05 09:33:52 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.5 1997/09/07 04:43:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,467 +24,508 @@
|
||||
#include "optimizer/pathnode.h"
|
||||
|
||||
#ifdef USE_RIGHT_SIDED_PLANS
|
||||
bool _use_right_sided_plans_ = true;
|
||||
bool _use_right_sided_plans_ = true;
|
||||
|
||||
#else
|
||||
bool _use_right_sided_plans_ = false;
|
||||
bool _use_right_sided_plans_ = false;
|
||||
|
||||
#endif
|
||||
|
||||
static List *find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list);
|
||||
static List *find_clauseless_joins(Rel *outer_rel, List *inner_rels);
|
||||
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 set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel,
|
||||
JInfo *jinfo);
|
||||
static List *find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list);
|
||||
static List *find_clauseless_joins(Rel * outer_rel, List * inner_rels);
|
||||
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
|
||||
set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel,
|
||||
JInfo * jinfo);
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-join-rels--
|
||||
* Find all possible joins for each of the outer join relations in
|
||||
* 'outer-rels'. A rel node is created for each possible join relation,
|
||||
* and the resulting list of nodes is returned. If at all possible, only
|
||||
* those relations for which join clauses exist are considered. If none
|
||||
* of these exist for a given relation, all remaining possibilities are
|
||||
* considered.
|
||||
*
|
||||
* Find all possible joins for each of the outer join relations in
|
||||
* 'outer-rels'. A rel node is created for each possible join relation,
|
||||
* and the resulting list of nodes is returned. If at all possible, only
|
||||
* those relations for which join clauses exist are considered. If none
|
||||
* of these exist for a given relation, all remaining possibilities are
|
||||
* considered.
|
||||
*
|
||||
* 'outer-rels' is the list of rel nodes
|
||||
*
|
||||
*
|
||||
* Returns a list of rel nodes corresponding to the new join relations.
|
||||
*/
|
||||
List *
|
||||
find_join_rels(Query *root, List *outer_rels)
|
||||
List *
|
||||
find_join_rels(Query * root, List * outer_rels)
|
||||
{
|
||||
List *joins = NIL;
|
||||
List *join_list = NIL;
|
||||
List *r = NIL;
|
||||
|
||||
foreach(r, outer_rels) {
|
||||
Rel *outer_rel = (Rel *)lfirst(r);
|
||||
List *joins = NIL;
|
||||
List *join_list = NIL;
|
||||
List *r = NIL;
|
||||
|
||||
if(!(joins = find_clause_joins(root, outer_rel,outer_rel->joininfo)))
|
||||
if (BushyPlanFlag)
|
||||
joins = find_clauseless_joins(outer_rel,outer_rels);
|
||||
else
|
||||
joins = find_clauseless_joins(outer_rel,root->base_relation_list_);
|
||||
foreach(r, outer_rels)
|
||||
{
|
||||
Rel *outer_rel = (Rel *) lfirst(r);
|
||||
|
||||
join_list = nconc(join_list, joins);
|
||||
}
|
||||
if (!(joins = find_clause_joins(root, outer_rel, outer_rel->joininfo)))
|
||||
if (BushyPlanFlag)
|
||||
joins = find_clauseless_joins(outer_rel, outer_rels);
|
||||
else
|
||||
joins = find_clauseless_joins(outer_rel, root->base_relation_list_);
|
||||
|
||||
return(join_list);
|
||||
join_list = nconc(join_list, joins);
|
||||
}
|
||||
|
||||
return (join_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-clause-joins--
|
||||
* Determines whether joins can be performed between an outer relation
|
||||
* 'outer-rel' and those relations within 'outer-rel's joininfo nodes
|
||||
* (i.e., relations that participate in join clauses that 'outer-rel'
|
||||
* participates in). This is possible if all but one of the relations
|
||||
* contained within the join clauses of the joininfo node are already
|
||||
* contained within 'outer-rel'.
|
||||
* Determines whether joins can be performed between an outer relation
|
||||
* 'outer-rel' and those relations within 'outer-rel's joininfo nodes
|
||||
* (i.e., relations that participate in join clauses that 'outer-rel'
|
||||
* participates in). This is possible if all but one of the relations
|
||||
* contained within the join clauses of the joininfo node are already
|
||||
* contained within 'outer-rel'.
|
||||
*
|
||||
* 'outer-rel' is the relation entry for the outer relation
|
||||
* 'joininfo-list' is a list of join clauses which 'outer-rel'
|
||||
* participates in
|
||||
*
|
||||
* 'joininfo-list' is a list of join clauses which 'outer-rel'
|
||||
* participates in
|
||||
*
|
||||
* Returns a list of new join relations.
|
||||
*/
|
||||
static List *
|
||||
find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list)
|
||||
static List *
|
||||
find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list)
|
||||
{
|
||||
List *join_list = NIL;
|
||||
List *i = NIL;
|
||||
|
||||
foreach (i, joininfo_list) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(i);
|
||||
Rel *rel;
|
||||
List *join_list = NIL;
|
||||
List *i = NIL;
|
||||
|
||||
if(!joininfo->inactive) {
|
||||
List *other_rels = joininfo->otherrels;
|
||||
foreach(i, joininfo_list)
|
||||
{
|
||||
JInfo *joininfo = (JInfo *) lfirst(i);
|
||||
Rel *rel;
|
||||
|
||||
if(other_rels != NIL) {
|
||||
if(length(other_rels) == 1) {
|
||||
rel = init_join_rel(outer_rel,
|
||||
get_base_rel(root, lfirsti(other_rels)),
|
||||
joininfo);
|
||||
/* how about right-sided plan ? */
|
||||
if ( _use_right_sided_plans_ &&
|
||||
length (outer_rel->relids) > 1 )
|
||||
{
|
||||
if (rel != NULL)
|
||||
join_list = lappend(join_list, rel);
|
||||
rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)),
|
||||
outer_rel,
|
||||
joininfo);
|
||||
}
|
||||
} else if (BushyPlanFlag) {
|
||||
rel = init_join_rel(outer_rel,
|
||||
get_join_rel(root, other_rels),
|
||||
joininfo);
|
||||
} else {
|
||||
rel = NULL;
|
||||
if (!joininfo->inactive)
|
||||
{
|
||||
List *other_rels = joininfo->otherrels;
|
||||
|
||||
if (other_rels != NIL)
|
||||
{
|
||||
if (length(other_rels) == 1)
|
||||
{
|
||||
rel = init_join_rel(outer_rel,
|
||||
get_base_rel(root, lfirsti(other_rels)),
|
||||
joininfo);
|
||||
/* how about right-sided plan ? */
|
||||
if (_use_right_sided_plans_ &&
|
||||
length(outer_rel->relids) > 1)
|
||||
{
|
||||
if (rel != NULL)
|
||||
join_list = lappend(join_list, rel);
|
||||
rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)),
|
||||
outer_rel,
|
||||
joininfo);
|
||||
}
|
||||
}
|
||||
else if (BushyPlanFlag)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (rel != NULL)
|
||||
join_list = lappend(join_list, rel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(join_list);
|
||||
return (join_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* find-clauseless-joins--
|
||||
* Given an outer relation 'outer-rel' and a list of inner relations
|
||||
* 'inner-rels', create a join relation between 'outer-rel' and each
|
||||
* member of 'inner-rels' that isn't already included in 'outer-rel'.
|
||||
*
|
||||
* Given an outer relation 'outer-rel' and a list of inner relations
|
||||
* 'inner-rels', create a join relation between 'outer-rel' and each
|
||||
* member of 'inner-rels' that isn't already included in 'outer-rel'.
|
||||
*
|
||||
* Returns a list of new join relations.
|
||||
*/
|
||||
static List *
|
||||
find_clauseless_joins(Rel *outer_rel, List *inner_rels)
|
||||
static List *
|
||||
find_clauseless_joins(Rel * outer_rel, List * inner_rels)
|
||||
{
|
||||
Rel *inner_rel;
|
||||
List *t_list = NIL;
|
||||
List *temp_node = NIL;
|
||||
List *i = NIL;
|
||||
|
||||
foreach (i, inner_rels) {
|
||||
inner_rel = (Rel *)lfirst(i);
|
||||
if(nonoverlap_rels(inner_rel, outer_rel)) {
|
||||
temp_node = lcons(init_join_rel(outer_rel,
|
||||
inner_rel,
|
||||
(JInfo*)NULL),
|
||||
NIL);
|
||||
t_list = nconc(t_list,temp_node);
|
||||
}
|
||||
}
|
||||
Rel *inner_rel;
|
||||
List *t_list = NIL;
|
||||
List *temp_node = NIL;
|
||||
List *i = NIL;
|
||||
|
||||
return(t_list);
|
||||
foreach(i, inner_rels)
|
||||
{
|
||||
inner_rel = (Rel *) lfirst(i);
|
||||
if (nonoverlap_rels(inner_rel, outer_rel))
|
||||
{
|
||||
temp_node = lcons(init_join_rel(outer_rel,
|
||||
inner_rel,
|
||||
(JInfo *) NULL),
|
||||
NIL);
|
||||
t_list = nconc(t_list, temp_node);
|
||||
}
|
||||
}
|
||||
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* init-join-rel--
|
||||
* Creates and initializes a new join relation.
|
||||
*
|
||||
* Creates and initializes a new join relation.
|
||||
*
|
||||
* 'outer-rel' and 'inner-rel' are relation nodes for the relations to be
|
||||
* joined
|
||||
* joined
|
||||
* 'joininfo' is the joininfo node(join clause) containing both
|
||||
* 'outer-rel' and 'inner-rel', if any exists
|
||||
*
|
||||
* '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)
|
||||
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;
|
||||
Rel *joinrel = makeNode(Rel);
|
||||
List *joinrel_joininfo_list = NIL;
|
||||
List *new_outer_tlist;
|
||||
List *new_inner_tlist;
|
||||
|
||||
joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists? -ay */
|
||||
lcons(inner_rel->relids, NIL));
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
|
||||
|
||||
return(joinrel);
|
||||
joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists?
|
||||
* -ay */
|
||||
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;
|
||||
|
||||
set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
|
||||
|
||||
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'.
|
||||
*
|
||||
* 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
|
||||
* join relation
|
||||
* 'first-resdomno' is the resdom number to use for the first created
|
||||
* target list entry
|
||||
*
|
||||
* target list entry
|
||||
*
|
||||
* Returns the new target list.
|
||||
*/
|
||||
static List *
|
||||
new_join_tlist(List *tlist,
|
||||
List *other_relids,
|
||||
int first_resdomno)
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
return(t_list);
|
||||
|
||||
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.
|
||||
* 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
|
||||
* '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
|
||||
*
|
||||
* '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)
|
||||
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) {
|
||||
List *or;
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
List *current_joininfo_list = NIL;
|
||||
List *new_otherrels = NIL;
|
||||
JInfo *other_joininfo = (JInfo *) NULL;
|
||||
List *xjoininfo = NIL;
|
||||
|
||||
new_otherrels = joininfo->otherrels;
|
||||
foreach (or, new_otherrels)
|
||||
foreach(xjoininfo, joininfo_list)
|
||||
{
|
||||
if ( intMember (lfirsti(or), join_relids) )
|
||||
new_otherrels = lremove ((void*)lfirst(or), new_otherrels);
|
||||
}
|
||||
joininfo->otherrels = new_otherrels;
|
||||
if ( new_otherrels != NIL )
|
||||
{
|
||||
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);
|
||||
List *or;
|
||||
JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
new_otherrels = joininfo->otherrels;
|
||||
foreach(or, new_otherrels)
|
||||
{
|
||||
if (intMember(lfirsti(or), join_relids))
|
||||
new_otherrels = lremove((void *) lfirst(or), new_otherrels);
|
||||
}
|
||||
joininfo->otherrels = new_otherrels;
|
||||
if (new_otherrels != NIL)
|
||||
{
|
||||
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);
|
||||
|
||||
return(current_joininfo_list);
|
||||
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.
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
add_new_joininfos(Query *root, List *joinrels, List *outerrels)
|
||||
add_new_joininfos(Query * root, List * joinrels, List * outerrels)
|
||||
{
|
||||
List *xjoinrel = NIL;
|
||||
List *xrelid = NIL;
|
||||
List *xrel = NIL;
|
||||
List *xjoininfo = NIL;
|
||||
|
||||
foreach(xjoinrel, joinrels) {
|
||||
Rel *joinrel = (Rel *)lfirst(xjoinrel);
|
||||
foreach(xrelid, joinrel->relids) {
|
||||
Relid relid = (Relid)lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
add_superrels(rel,joinrel);
|
||||
}
|
||||
}
|
||||
foreach(xjoinrel, joinrels) {
|
||||
Rel *joinrel = (Rel *)lfirst(xjoinrel);
|
||||
List *xjoinrel = NIL;
|
||||
List *xrelid = NIL;
|
||||
List *xrel = NIL;
|
||||
List *xjoininfo = NIL;
|
||||
|
||||
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(xjoinrel, joinrels)
|
||||
{
|
||||
Rel *joinrel = (Rel *) lfirst(xjoinrel);
|
||||
|
||||
foreach(xrelid, other_rels) {
|
||||
Relid relid = (Relid)lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
List *super_rels = rel->superrels;
|
||||
List *xsuper_rel = NIL;
|
||||
JInfo *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(xrelid, joinrel->relids)
|
||||
{
|
||||
Relid relid = (Relid) lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
add_superrels(rel, joinrel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach(xrel, outerrels) {
|
||||
Rel *rel = (Rel *)lfirst(xrel);
|
||||
rel->superrels = NIL;
|
||||
}
|
||||
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)
|
||||
{
|
||||
Relid relid = (Relid) lfirst(xrelid);
|
||||
Rel *rel = get_join_rel(root, relid);
|
||||
List *super_rels = rel->superrels;
|
||||
List *xsuper_rel = NIL;
|
||||
JInfo *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 = (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.
|
||||
* 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.
|
||||
*/
|
||||
List *
|
||||
final_join_rels(List *join_rel_list)
|
||||
List *
|
||||
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;
|
||||
List *xrel = NIL;
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (xjoininfo, rel->joininfo) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if (joininfo->otherrels != NIL) {
|
||||
final = false;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (final) {
|
||||
temp = lcons(rel, NIL);
|
||||
t_list = nconc(t_list, temp);
|
||||
}
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* add_superrels--
|
||||
* add rel to the temporary property list superrels.
|
||||
* add rel to the temporary property list superrels.
|
||||
*
|
||||
* 'rel' a rel node
|
||||
* 'super-rel' rel node of a join relation that includes rel
|
||||
@ -492,60 +533,69 @@ final_join_rels(List *join_rel_list)
|
||||
* Modifies the superrels field of rel
|
||||
*/
|
||||
static void
|
||||
add_superrels(Rel *rel, Rel *super_rel)
|
||||
add_superrels(Rel * rel, Rel * super_rel)
|
||||
{
|
||||
rel->superrels = lappend(rel->superrels, super_rel);
|
||||
rel->superrels = lappend(rel->superrels, super_rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* nonoverlap-rels--
|
||||
* test if two join relations overlap, i.e., includes the same
|
||||
* relation.
|
||||
* 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)
|
||||
static bool
|
||||
nonoverlap_rels(Rel * rel1, Rel * rel2)
|
||||
{
|
||||
return(nonoverlap_sets(rel1->relids, rel2->relids));
|
||||
return (nonoverlap_sets(rel1->relids, rel2->relids));
|
||||
}
|
||||
|
||||
static bool
|
||||
nonoverlap_sets(List *s1, List *s2)
|
||||
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);
|
||||
List *x = NIL;
|
||||
|
||||
foreach(x, s1)
|
||||
{
|
||||
int e = lfirsti(x);
|
||||
|
||||
if (intMember(e, s2))
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
static void
|
||||
set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel, JInfo *jinfo)
|
||||
set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel, JInfo * jinfo)
|
||||
{
|
||||
int ntuples;
|
||||
float selec;
|
||||
int ntuples;
|
||||
float selec;
|
||||
|
||||
/* voodoo magic. but better than a size of 0. I have no idea why
|
||||
we didn't set the size before. -ay 2/95 */
|
||||
if (jinfo==NULL) {
|
||||
/* worst case: the cartesian product */
|
||||
ntuples = outer_rel->tuples * inner_rel->tuples;
|
||||
} else {
|
||||
selec = product_selec(jinfo->jinfoclauseinfo);
|
||||
/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */
|
||||
ntuples = outer_rel->tuples * inner_rel->tuples * selec;
|
||||
}
|
||||
|
||||
/* I bet sizes less than 1 will screw up optimization so
|
||||
make the best case 1 instead of 0 - jolly*/
|
||||
if (ntuples < 1)
|
||||
ntuples = 1;
|
||||
/*
|
||||
* voodoo magic. but better than a size of 0. I have no idea why we
|
||||
* didn't set the size before. -ay 2/95
|
||||
*/
|
||||
if (jinfo == NULL)
|
||||
{
|
||||
/* worst case: the cartesian product */
|
||||
ntuples = outer_rel->tuples * inner_rel->tuples;
|
||||
}
|
||||
else
|
||||
{
|
||||
selec = product_selec(jinfo->jinfoclauseinfo);
|
||||
/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */
|
||||
ntuples = outer_rel->tuples * inner_rel->tuples * selec;
|
||||
}
|
||||
|
||||
joinrel->tuples = ntuples;
|
||||
/*
|
||||
* I bet sizes less than 1 will screw up optimization so make the best
|
||||
* case 1 instead of 0 - jolly
|
||||
*/
|
||||
if (ntuples < 1)
|
||||
ntuples = 1;
|
||||
|
||||
joinrel->tuples = ntuples;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* joinutils.c--
|
||||
* Utilities for matching and building join and path keys
|
||||
* Utilities for matching and building join and path keys
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.2 1997/09/07 04:43:42 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,407 +26,440 @@
|
||||
#include "optimizer/ordering.h"
|
||||
|
||||
|
||||
static int match_pathkey_joinkeys(List *pathkey, List *joinkeys,
|
||||
int which_subkey);
|
||||
static bool every_func(List *joinkeys, List *pathkey,
|
||||
int which_subkey);
|
||||
static List *new_join_pathkey(List *subkeys,
|
||||
List *considered_subkeys, List *join_rel_tlist,
|
||||
List *joinclauses);
|
||||
static List *new_matching_subkeys(Var *subkey, List *considered_subkeys,
|
||||
List *join_rel_tlist, List *joinclauses);
|
||||
static int
|
||||
match_pathkey_joinkeys(List * pathkey, List * joinkeys,
|
||||
int which_subkey);
|
||||
static bool
|
||||
every_func(List * joinkeys, List * pathkey,
|
||||
int which_subkey);
|
||||
static List *
|
||||
new_join_pathkey(List * subkeys,
|
||||
List * considered_subkeys, List * join_rel_tlist,
|
||||
List * joinclauses);
|
||||
static List *
|
||||
new_matching_subkeys(Var * subkey, List * considered_subkeys,
|
||||
List * join_rel_tlist, List * joinclauses);
|
||||
|
||||
/****************************************************************************
|
||||
* KEY COMPARISONS
|
||||
* KEY COMPARISONS
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
/*
|
||||
* match-pathkeys-joinkeys--
|
||||
* Attempts to match the keys of a path against the keys of join clauses.
|
||||
* This is done by looking for a matching join key in 'joinkeys' for
|
||||
* every path key in the list 'pathkeys'. If there is a matching join key
|
||||
* (not necessarily unique) for every path key, then the list of
|
||||
* corresponding join keys and join clauses are returned in the order in
|
||||
* which the keys matched the path keys.
|
||||
*
|
||||
* Attempts to match the keys of a path against the keys of join clauses.
|
||||
* This is done by looking for a matching join key in 'joinkeys' for
|
||||
* every path key in the list 'pathkeys'. If there is a matching join key
|
||||
* (not necessarily unique) for every path key, then the list of
|
||||
* corresponding join keys and join clauses are returned in the order in
|
||||
* which the keys matched the path keys.
|
||||
*
|
||||
* 'pathkeys' is a list of path keys:
|
||||
* ( ( (var) (var) ... ) ( (var) ... ) )
|
||||
* ( ( (var) (var) ... ) ( (var) ... ) )
|
||||
* 'joinkeys' is a list of join keys:
|
||||
* ( (outer inner) (outer inner) ... )
|
||||
* ( (outer inner) (outer inner) ... )
|
||||
* 'joinclauses' is a list of clauses corresponding to the join keys in
|
||||
* 'joinkeys'
|
||||
* 'joinkeys'
|
||||
* 'which-subkey' is a flag that selects the desired subkey of a join key
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* Returns the join keys and corresponding join clauses in a list if all
|
||||
* of the path keys were matched:
|
||||
* (
|
||||
* ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) )
|
||||
* ( clause0 ... clauseN )
|
||||
* )
|
||||
* (
|
||||
* ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) )
|
||||
* ( clause0 ... clauseN )
|
||||
* )
|
||||
* and nil otherwise.
|
||||
*
|
||||
*
|
||||
* Returns a list of matched join keys and a list of matched join clauses
|
||||
* in matchedJoinClausesPtr. - ay 11/94
|
||||
*/
|
||||
List *
|
||||
match_pathkeys_joinkeys(List *pathkeys,
|
||||
List *joinkeys,
|
||||
List *joinclauses,
|
||||
int which_subkey,
|
||||
List **matchedJoinClausesPtr)
|
||||
List *
|
||||
match_pathkeys_joinkeys(List * pathkeys,
|
||||
List * joinkeys,
|
||||
List * joinclauses,
|
||||
int which_subkey,
|
||||
List ** matchedJoinClausesPtr)
|
||||
{
|
||||
List *matched_joinkeys = NIL;
|
||||
List *matched_joinclauses = NIL;
|
||||
List *pathkey = NIL;
|
||||
List *i = NIL;
|
||||
int matched_joinkey_index = -1;
|
||||
|
||||
foreach(i, pathkeys) {
|
||||
pathkey = lfirst(i);
|
||||
matched_joinkey_index =
|
||||
match_pathkey_joinkeys(pathkey, joinkeys, which_subkey);
|
||||
|
||||
if (matched_joinkey_index != -1 ) {
|
||||
List *xjoinkey = nth(matched_joinkey_index,joinkeys);
|
||||
List *joinclause = nth(matched_joinkey_index,joinclauses);
|
||||
|
||||
/* XXX was "push" function */
|
||||
matched_joinkeys = lappend(matched_joinkeys,xjoinkey);
|
||||
matched_joinkeys = nreverse(matched_joinkeys);
|
||||
|
||||
matched_joinclauses = lappend(matched_joinclauses,joinclause);
|
||||
matched_joinclauses = nreverse(matched_joinclauses);
|
||||
joinkeys = LispRemove(xjoinkey,joinkeys);
|
||||
} else {
|
||||
return(NIL);
|
||||
}
|
||||
|
||||
}
|
||||
if(matched_joinkeys==NULL ||
|
||||
length(matched_joinkeys) != length(pathkeys)) {
|
||||
return NIL;
|
||||
}
|
||||
List *matched_joinkeys = NIL;
|
||||
List *matched_joinclauses = NIL;
|
||||
List *pathkey = NIL;
|
||||
List *i = NIL;
|
||||
int matched_joinkey_index = -1;
|
||||
|
||||
*matchedJoinClausesPtr = nreverse(matched_joinclauses);
|
||||
return (nreverse(matched_joinkeys));
|
||||
foreach(i, pathkeys)
|
||||
{
|
||||
pathkey = lfirst(i);
|
||||
matched_joinkey_index =
|
||||
match_pathkey_joinkeys(pathkey, joinkeys, which_subkey);
|
||||
|
||||
if (matched_joinkey_index != -1)
|
||||
{
|
||||
List *xjoinkey = nth(matched_joinkey_index, joinkeys);
|
||||
List *joinclause = nth(matched_joinkey_index, joinclauses);
|
||||
|
||||
/* XXX was "push" function */
|
||||
matched_joinkeys = lappend(matched_joinkeys, xjoinkey);
|
||||
matched_joinkeys = nreverse(matched_joinkeys);
|
||||
|
||||
matched_joinclauses = lappend(matched_joinclauses, joinclause);
|
||||
matched_joinclauses = nreverse(matched_joinclauses);
|
||||
joinkeys = LispRemove(xjoinkey, joinkeys);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (NIL);
|
||||
}
|
||||
|
||||
}
|
||||
if (matched_joinkeys == NULL ||
|
||||
length(matched_joinkeys) != length(pathkeys))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
*matchedJoinClausesPtr = nreverse(matched_joinclauses);
|
||||
return (nreverse(matched_joinkeys));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* match-pathkey-joinkeys--
|
||||
* Returns the 0-based index into 'joinkeys' of the first joinkey whose
|
||||
* outer or inner subkey matches any subkey of 'pathkey'.
|
||||
* Returns the 0-based index into 'joinkeys' of the first joinkey whose
|
||||
* outer or inner subkey matches any subkey of 'pathkey'.
|
||||
*/
|
||||
static int
|
||||
match_pathkey_joinkeys(List *pathkey,
|
||||
List *joinkeys,
|
||||
int which_subkey)
|
||||
match_pathkey_joinkeys(List * pathkey,
|
||||
List * joinkeys,
|
||||
int which_subkey)
|
||||
{
|
||||
Var *path_subkey;
|
||||
int pos;
|
||||
List *i = NIL;
|
||||
List *x = NIL;
|
||||
JoinKey *jk;
|
||||
|
||||
foreach(i, pathkey) {
|
||||
path_subkey = (Var *)lfirst(i);
|
||||
pos = 0;
|
||||
foreach(x, joinkeys) {
|
||||
jk = (JoinKey*)lfirst(x);
|
||||
if(var_equal(path_subkey,
|
||||
extract_subkey(jk, which_subkey)))
|
||||
return(pos);
|
||||
pos++;
|
||||
Var *path_subkey;
|
||||
int pos;
|
||||
List *i = NIL;
|
||||
List *x = NIL;
|
||||
JoinKey *jk;
|
||||
|
||||
foreach(i, pathkey)
|
||||
{
|
||||
path_subkey = (Var *) lfirst(i);
|
||||
pos = 0;
|
||||
foreach(x, joinkeys)
|
||||
{
|
||||
jk = (JoinKey *) lfirst(x);
|
||||
if (var_equal(path_subkey,
|
||||
extract_subkey(jk, which_subkey)))
|
||||
return (pos);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(-1); /* no index found */
|
||||
return (-1); /* no index found */
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* match-paths-joinkeys--
|
||||
* Attempts to find a path in 'paths' whose keys match a set of join
|
||||
* keys 'joinkeys'. To match,
|
||||
* 1. the path node ordering must equal 'ordering'.
|
||||
* 2. each subkey of a given path must match(i.e., be(var_equal) to) the
|
||||
* appropriate subkey of the corresponding join key in 'joinkeys',
|
||||
* i.e., the Nth path key must match its subkeys against the subkey of
|
||||
* the Nth join key in 'joinkeys'.
|
||||
*
|
||||
* 'joinkeys' is the list of key pairs to which the path keys must be
|
||||
* matched
|
||||
* Attempts to find a path in 'paths' whose keys match a set of join
|
||||
* keys 'joinkeys'. To match,
|
||||
* 1. the path node ordering must equal 'ordering'.
|
||||
* 2. each subkey of a given path must match(i.e., be(var_equal) to) the
|
||||
* appropriate subkey of the corresponding join key in 'joinkeys',
|
||||
* i.e., the Nth path key must match its subkeys against the subkey of
|
||||
* the Nth join key in 'joinkeys'.
|
||||
*
|
||||
* 'joinkeys' is the list of key pairs to which the path keys must be
|
||||
* matched
|
||||
* 'ordering' is the ordering of the(outer) path to which 'joinkeys'
|
||||
* must correspond
|
||||
* must correspond
|
||||
* 'paths' is a list of(inner) paths which are to be matched against
|
||||
* each join key in 'joinkeys'
|
||||
* each join key in 'joinkeys'
|
||||
* 'which-subkey' is a flag that selects the desired subkey of a join key
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* Returns the matching path node if one exists, nil otherwise.
|
||||
*/
|
||||
static bool
|
||||
every_func(List *joinkeys, List *pathkey, int which_subkey)
|
||||
static bool
|
||||
every_func(List * joinkeys, List * pathkey, int which_subkey)
|
||||
{
|
||||
JoinKey *xjoinkey;
|
||||
Var *temp;
|
||||
Var *tempkey = NULL;
|
||||
bool found = false;
|
||||
List *i = NIL;
|
||||
List *j = NIL;
|
||||
|
||||
foreach(i,joinkeys) {
|
||||
xjoinkey = (JoinKey*)lfirst(i);
|
||||
found = false;
|
||||
foreach(j,pathkey) {
|
||||
temp = (Var*)lfirst((List*)lfirst(j));
|
||||
if(temp == NULL) continue;
|
||||
tempkey = extract_subkey(xjoinkey,which_subkey);
|
||||
if(var_equal(tempkey, temp)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
JoinKey *xjoinkey;
|
||||
Var *temp;
|
||||
Var *tempkey = NULL;
|
||||
bool found = false;
|
||||
List *i = NIL;
|
||||
List *j = NIL;
|
||||
|
||||
foreach(i, joinkeys)
|
||||
{
|
||||
xjoinkey = (JoinKey *) lfirst(i);
|
||||
found = false;
|
||||
foreach(j, pathkey)
|
||||
{
|
||||
temp = (Var *) lfirst((List *) lfirst(j));
|
||||
if (temp == NULL)
|
||||
continue;
|
||||
tempkey = extract_subkey(xjoinkey, which_subkey);
|
||||
if (var_equal(tempkey, temp))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == false)
|
||||
return (false);
|
||||
}
|
||||
if(found == false)
|
||||
return(false);
|
||||
}
|
||||
return(found);
|
||||
return (found);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* match_paths_joinkeys -
|
||||
* find the cheapest path that matches the join keys
|
||||
* find the cheapest path that matches the join keys
|
||||
*/
|
||||
Path *
|
||||
match_paths_joinkeys(List *joinkeys,
|
||||
PathOrder *ordering,
|
||||
List *paths,
|
||||
int which_subkey)
|
||||
Path *
|
||||
match_paths_joinkeys(List * joinkeys,
|
||||
PathOrder * ordering,
|
||||
List * paths,
|
||||
int which_subkey)
|
||||
{
|
||||
Path *matched_path = NULL ;
|
||||
bool key_match = false;
|
||||
List *i = NIL;
|
||||
Path *matched_path = NULL;
|
||||
bool key_match = false;
|
||||
List *i = NIL;
|
||||
|
||||
foreach(i,paths) {
|
||||
Path *path = (Path*)lfirst(i);
|
||||
foreach(i, paths)
|
||||
{
|
||||
Path *path = (Path *) lfirst(i);
|
||||
|
||||
key_match = every_func(joinkeys, path->keys, which_subkey);
|
||||
|
||||
if (equal_path_path_ordering(ordering,
|
||||
&path->p_ordering) &&
|
||||
length(joinkeys) == length(path->keys) &&
|
||||
key_match) {
|
||||
key_match = every_func(joinkeys, path->keys, which_subkey);
|
||||
|
||||
if (matched_path) {
|
||||
if (path->path_cost < matched_path->path_cost)
|
||||
matched_path = path;
|
||||
} else {
|
||||
matched_path = path;
|
||||
}
|
||||
if (equal_path_path_ordering(ordering,
|
||||
&path->p_ordering) &&
|
||||
length(joinkeys) == length(path->keys) &&
|
||||
key_match)
|
||||
{
|
||||
|
||||
if (matched_path)
|
||||
{
|
||||
if (path->path_cost < matched_path->path_cost)
|
||||
matched_path = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
matched_path = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return matched_path;
|
||||
return matched_path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* extract-path-keys--
|
||||
* Builds a subkey list for a path by pulling one of the subkeys from
|
||||
* a list of join keys 'joinkeys' and then finding the var node in the
|
||||
* target list 'tlist' that corresponds to that subkey.
|
||||
*
|
||||
* Builds a subkey list for a path by pulling one of the subkeys from
|
||||
* a list of join keys 'joinkeys' and then finding the var node in the
|
||||
* target list 'tlist' that corresponds to that subkey.
|
||||
*
|
||||
* 'joinkeys' is a list of join key pairs
|
||||
* 'tlist' is a relation target list
|
||||
* 'which-subkey' is a flag that selects the desired subkey of a join key
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* in 'joinkeys'
|
||||
*
|
||||
* Returns a list of pathkeys: ((tlvar1)(tlvar2)...(tlvarN)).
|
||||
* [I've no idea why they have to be list of lists. Should be fixed. -ay 12/94]
|
||||
*/
|
||||
List *
|
||||
extract_path_keys(List *joinkeys,
|
||||
List *tlist,
|
||||
int which_subkey)
|
||||
List *
|
||||
extract_path_keys(List * joinkeys,
|
||||
List * tlist,
|
||||
int which_subkey)
|
||||
{
|
||||
List *pathkeys = NIL;
|
||||
List *jk;
|
||||
|
||||
foreach(jk, joinkeys) {
|
||||
JoinKey *jkey = (JoinKey*)lfirst(jk);
|
||||
Var *var, *key;
|
||||
List *p;
|
||||
List *pathkeys = NIL;
|
||||
List *jk;
|
||||
|
||||
/*
|
||||
* find the right Var in the target list for this key
|
||||
*/
|
||||
var = (Var*)extract_subkey(jkey, which_subkey);
|
||||
key = (Var*)matching_tlvar(var, tlist);
|
||||
foreach(jk, joinkeys)
|
||||
{
|
||||
JoinKey *jkey = (JoinKey *) lfirst(jk);
|
||||
Var *var,
|
||||
*key;
|
||||
List *p;
|
||||
|
||||
/*
|
||||
* include it in the pathkeys list if we haven't already done so
|
||||
*/
|
||||
foreach(p, pathkeys) {
|
||||
Var *pkey = lfirst((List*)lfirst(p)); /* XXX fix me */
|
||||
if (key == pkey)
|
||||
break;
|
||||
/*
|
||||
* find the right Var in the target list for this key
|
||||
*/
|
||||
var = (Var *) extract_subkey(jkey, which_subkey);
|
||||
key = (Var *) matching_tlvar(var, tlist);
|
||||
|
||||
/*
|
||||
* include it in the pathkeys list if we haven't already done so
|
||||
*/
|
||||
foreach(p, pathkeys)
|
||||
{
|
||||
Var *pkey = lfirst((List *) lfirst(p)); /* XXX fix me */
|
||||
|
||||
if (key == pkey)
|
||||
break;
|
||||
}
|
||||
if (p != NIL)
|
||||
continue; /* key already in pathkeys */
|
||||
|
||||
pathkeys =
|
||||
lappend(pathkeys, lcons(key, NIL));
|
||||
}
|
||||
if (p!=NIL)
|
||||
continue; /* key already in pathkeys */
|
||||
|
||||
pathkeys =
|
||||
lappend(pathkeys, lcons(key,NIL));
|
||||
}
|
||||
return(pathkeys);
|
||||
return (pathkeys);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* NEW PATHKEY FORMATION
|
||||
* NEW PATHKEY FORMATION
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
/*
|
||||
* new-join-pathkeys--
|
||||
* Find the path keys for a join relation by finding all vars in the list
|
||||
* of join clauses 'joinclauses' such that:
|
||||
* (1) the var corresponding to the outer join relation is a
|
||||
* key on the outer path
|
||||
* (2) the var appears in the target list of the join relation
|
||||
* In other words, add to each outer path key the inner path keys that
|
||||
* are required for qualification.
|
||||
*
|
||||
* Find the path keys for a join relation by finding all vars in the list
|
||||
* of join clauses 'joinclauses' such that:
|
||||
* (1) the var corresponding to the outer join relation is a
|
||||
* key on the outer path
|
||||
* (2) the var appears in the target list of the join relation
|
||||
* In other words, add to each outer path key the inner path keys that
|
||||
* are required for qualification.
|
||||
*
|
||||
* 'outer-pathkeys' is the list of the outer path's path keys
|
||||
* 'join-rel-tlist' is the target list of the join relation
|
||||
* 'joinclauses' is the list of restricting join clauses
|
||||
*
|
||||
* Returns the list of new path keys.
|
||||
*
|
||||
*
|
||||
* Returns the list of new path keys.
|
||||
*
|
||||
*/
|
||||
List *
|
||||
new_join_pathkeys(List *outer_pathkeys,
|
||||
List *join_rel_tlist,
|
||||
List *joinclauses)
|
||||
{
|
||||
List *outer_pathkey = NIL;
|
||||
List *t_list = NIL;
|
||||
List *x;
|
||||
List *i = NIL;
|
||||
|
||||
foreach(i, outer_pathkeys) {
|
||||
outer_pathkey = lfirst(i);
|
||||
x = new_join_pathkey(outer_pathkey, NIL,
|
||||
join_rel_tlist,joinclauses);
|
||||
if (x!=NIL) {
|
||||
t_list = lappend(t_list, x);
|
||||
}
|
||||
}
|
||||
return(t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-join-pathkey--
|
||||
* Finds new vars that become subkeys due to qualification clauses that
|
||||
* contain any previously considered subkeys. These new subkeys plus the
|
||||
* subkeys from 'subkeys' form a new pathkey for the join relation.
|
||||
*
|
||||
* Note that each returned subkey is the var node found in
|
||||
* 'join-rel-tlist' rather than the joinclause var node.
|
||||
*
|
||||
* 'subkeys' is a list of subkeys for which matching subkeys are to be
|
||||
* found
|
||||
* 'considered-subkeys' is the current list of all subkeys corresponding
|
||||
* to a given pathkey
|
||||
*
|
||||
* Returns a new pathkey(list of subkeys).
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
new_join_pathkey(List *subkeys,
|
||||
List *considered_subkeys,
|
||||
List *join_rel_tlist,
|
||||
List *joinclauses)
|
||||
List *
|
||||
new_join_pathkeys(List * outer_pathkeys,
|
||||
List * join_rel_tlist,
|
||||
List * joinclauses)
|
||||
{
|
||||
List *t_list = NIL;
|
||||
Var *subkey;
|
||||
List *i = NIL;
|
||||
List *matched_subkeys = NIL;
|
||||
Expr *tlist_key = (Expr*)NULL;
|
||||
List *newly_considered_subkeys = NIL;
|
||||
|
||||
foreach (i, subkeys) {
|
||||
subkey = (Var *)lfirst(i);
|
||||
if(subkey == NULL)
|
||||
break; /* XXX something is wrong */
|
||||
matched_subkeys =
|
||||
new_matching_subkeys(subkey,considered_subkeys,
|
||||
join_rel_tlist,joinclauses);
|
||||
tlist_key = matching_tlvar(subkey,join_rel_tlist);
|
||||
newly_considered_subkeys = NIL;
|
||||
|
||||
if (tlist_key) {
|
||||
if(!member(tlist_key, matched_subkeys))
|
||||
newly_considered_subkeys = lcons(tlist_key,
|
||||
matched_subkeys);
|
||||
}
|
||||
else {
|
||||
newly_considered_subkeys = matched_subkeys;
|
||||
}
|
||||
|
||||
considered_subkeys =
|
||||
append(considered_subkeys, newly_considered_subkeys);
|
||||
List *outer_pathkey = NIL;
|
||||
List *t_list = NIL;
|
||||
List *x;
|
||||
List *i = NIL;
|
||||
|
||||
t_list = nconc(t_list,newly_considered_subkeys);
|
||||
}
|
||||
return(t_list);
|
||||
foreach(i, outer_pathkeys)
|
||||
{
|
||||
outer_pathkey = lfirst(i);
|
||||
x = new_join_pathkey(outer_pathkey, NIL,
|
||||
join_rel_tlist, joinclauses);
|
||||
if (x != NIL)
|
||||
{
|
||||
t_list = lappend(t_list, x);
|
||||
}
|
||||
}
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* new-join-pathkey--
|
||||
* Finds new vars that become subkeys due to qualification clauses that
|
||||
* contain any previously considered subkeys. These new subkeys plus the
|
||||
* subkeys from 'subkeys' form a new pathkey for the join relation.
|
||||
*
|
||||
* Note that each returned subkey is the var node found in
|
||||
* 'join-rel-tlist' rather than the joinclause var node.
|
||||
*
|
||||
* 'subkeys' is a list of subkeys for which matching subkeys are to be
|
||||
* found
|
||||
* 'considered-subkeys' is the current list of all subkeys corresponding
|
||||
* to a given pathkey
|
||||
*
|
||||
* Returns a new pathkey(list of subkeys).
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
new_join_pathkey(List * subkeys,
|
||||
List * considered_subkeys,
|
||||
List * join_rel_tlist,
|
||||
List * joinclauses)
|
||||
{
|
||||
List *t_list = NIL;
|
||||
Var *subkey;
|
||||
List *i = NIL;
|
||||
List *matched_subkeys = NIL;
|
||||
Expr *tlist_key = (Expr *) NULL;
|
||||
List *newly_considered_subkeys = NIL;
|
||||
|
||||
foreach(i, subkeys)
|
||||
{
|
||||
subkey = (Var *) lfirst(i);
|
||||
if (subkey == NULL)
|
||||
break; /* XXX something is wrong */
|
||||
matched_subkeys =
|
||||
new_matching_subkeys(subkey, considered_subkeys,
|
||||
join_rel_tlist, joinclauses);
|
||||
tlist_key = matching_tlvar(subkey, join_rel_tlist);
|
||||
newly_considered_subkeys = NIL;
|
||||
|
||||
if (tlist_key)
|
||||
{
|
||||
if (!member(tlist_key, matched_subkeys))
|
||||
newly_considered_subkeys = lcons(tlist_key,
|
||||
matched_subkeys);
|
||||
}
|
||||
else
|
||||
{
|
||||
newly_considered_subkeys = matched_subkeys;
|
||||
}
|
||||
|
||||
considered_subkeys =
|
||||
append(considered_subkeys, newly_considered_subkeys);
|
||||
|
||||
t_list = nconc(t_list, newly_considered_subkeys);
|
||||
}
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-matching-subkeys--
|
||||
* Returns a list of new subkeys:
|
||||
* (1) which are not listed in 'considered-subkeys'
|
||||
* (2) for which the "other" variable in some clause in 'joinclauses' is
|
||||
* 'subkey'
|
||||
* (3) which are mentioned in 'join-rel-tlist'
|
||||
*
|
||||
* Note that each returned subkey is the var node found in
|
||||
* 'join-rel-tlist' rather than the joinclause var node.
|
||||
*
|
||||
* Returns a list of new subkeys:
|
||||
* (1) which are not listed in 'considered-subkeys'
|
||||
* (2) for which the "other" variable in some clause in 'joinclauses' is
|
||||
* 'subkey'
|
||||
* (3) which are mentioned in 'join-rel-tlist'
|
||||
*
|
||||
* Note that each returned subkey is the var node found in
|
||||
* 'join-rel-tlist' rather than the joinclause var node.
|
||||
*
|
||||
* 'subkey' is the var node for which we are trying to find matching
|
||||
* clauses
|
||||
*
|
||||
* clauses
|
||||
*
|
||||
* Returns a list of new subkeys.
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
new_matching_subkeys(Var *subkey,
|
||||
List *considered_subkeys,
|
||||
List *join_rel_tlist,
|
||||
List *joinclauses)
|
||||
static List *
|
||||
new_matching_subkeys(Var * subkey,
|
||||
List * considered_subkeys,
|
||||
List * join_rel_tlist,
|
||||
List * joinclauses)
|
||||
{
|
||||
Expr *joinclause = NULL;
|
||||
List *t_list = NIL;
|
||||
List *temp = NIL;
|
||||
List *i = NIL;
|
||||
Expr *tlist_other_var = (Expr *)NULL;
|
||||
|
||||
foreach(i,joinclauses) {
|
||||
joinclause = lfirst(i);
|
||||
tlist_other_var =
|
||||
matching_tlvar(other_join_clause_var(subkey,joinclause),
|
||||
join_rel_tlist);
|
||||
|
||||
if(tlist_other_var &&
|
||||
!(member(tlist_other_var,considered_subkeys))) {
|
||||
Expr *joinclause = NULL;
|
||||
List *t_list = NIL;
|
||||
List *temp = NIL;
|
||||
List *i = NIL;
|
||||
Expr *tlist_other_var = (Expr *) NULL;
|
||||
|
||||
/* XXX was "push" function */
|
||||
considered_subkeys = lappend(considered_subkeys,
|
||||
tlist_other_var);
|
||||
foreach(i, joinclauses)
|
||||
{
|
||||
joinclause = lfirst(i);
|
||||
tlist_other_var =
|
||||
matching_tlvar(other_join_clause_var(subkey, joinclause),
|
||||
join_rel_tlist);
|
||||
|
||||
/* considered_subkeys = nreverse(considered_subkeys);
|
||||
XXX -- I am not sure of this. */
|
||||
|
||||
temp = lcons(tlist_other_var, NIL);
|
||||
t_list = nconc(t_list,temp);
|
||||
}
|
||||
}
|
||||
return(t_list);
|
||||
if (tlist_other_var &&
|
||||
!(member(tlist_other_var, considered_subkeys)))
|
||||
{
|
||||
|
||||
/* XXX was "push" function */
|
||||
considered_subkeys = lappend(considered_subkeys,
|
||||
tlist_other_var);
|
||||
|
||||
/*
|
||||
* considered_subkeys = nreverse(considered_subkeys); XXX -- I
|
||||
* am not sure of this.
|
||||
*/
|
||||
|
||||
temp = lcons(tlist_other_var, NIL);
|
||||
t_list = nconc(t_list, temp);
|
||||
}
|
||||
}
|
||||
return (t_list);
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* mergeutils.c--
|
||||
* Utilities for finding applicable merge clauses and pathkeys
|
||||
* Utilities for finding applicable merge clauses and pathkeys
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.2 1997/09/07 04:43:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -21,102 +21,110 @@
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/ordering.h"
|
||||
|
||||
/*
|
||||
/*
|
||||
* group-clauses-by-order--
|
||||
* If a join clause node in 'clauseinfo-list' is mergesortable, store
|
||||
* it within a mergeinfo node containing other clause nodes with the same
|
||||
* mergesort ordering.
|
||||
*
|
||||
* If a join clause node in 'clauseinfo-list' is mergesortable, store
|
||||
* it within a mergeinfo node containing other clause nodes with the same
|
||||
* mergesort ordering.
|
||||
*
|
||||
* 'clauseinfo-list' is the list of clauseinfo nodes
|
||||
* 'inner-relid' is the relid of the inner join relation
|
||||
*
|
||||
*
|
||||
* Returns the new list of mergeinfo nodes.
|
||||
*
|
||||
*
|
||||
*/
|
||||
List *
|
||||
group_clauses_by_order(List *clauseinfo_list,
|
||||
int inner_relid)
|
||||
List *
|
||||
group_clauses_by_order(List * clauseinfo_list,
|
||||
int inner_relid)
|
||||
{
|
||||
List *mergeinfo_list = NIL;
|
||||
List *xclauseinfo = NIL;
|
||||
|
||||
foreach (xclauseinfo, clauseinfo_list) {
|
||||
CInfo *clauseinfo = (CInfo *)lfirst(xclauseinfo);
|
||||
MergeOrder *merge_ordering = clauseinfo->mergesortorder;
|
||||
|
||||
if (merge_ordering) {
|
||||
/*
|
||||
* Create a new mergeinfo node and add it to
|
||||
* 'mergeinfo-list' if one does not yet exist for this
|
||||
* merge ordering.
|
||||
*/
|
||||
PathOrder p_ordering;
|
||||
MInfo *xmergeinfo;
|
||||
Expr *clause = clauseinfo->clause;
|
||||
Var *leftop = get_leftop (clause);
|
||||
Var *rightop = get_rightop (clause);
|
||||
JoinKey *keys;
|
||||
List *mergeinfo_list = NIL;
|
||||
List *xclauseinfo = NIL;
|
||||
|
||||
p_ordering.ordtype = MERGE_ORDER;
|
||||
p_ordering.ord.merge = merge_ordering;
|
||||
xmergeinfo =
|
||||
match_order_mergeinfo(&p_ordering, mergeinfo_list);
|
||||
if (inner_relid == leftop->varno) {
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = rightop;
|
||||
keys->inner = leftop;
|
||||
} else {
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = leftop;
|
||||
keys->inner = rightop;
|
||||
}
|
||||
|
||||
if (xmergeinfo==NULL) {
|
||||
xmergeinfo = makeNode(MInfo);
|
||||
foreach(xclauseinfo, clauseinfo_list)
|
||||
{
|
||||
CInfo *clauseinfo = (CInfo *) lfirst(xclauseinfo);
|
||||
MergeOrder *merge_ordering = clauseinfo->mergesortorder;
|
||||
|
||||
xmergeinfo->m_ordering = merge_ordering;
|
||||
mergeinfo_list = lcons(xmergeinfo,
|
||||
mergeinfo_list);
|
||||
}
|
||||
|
||||
((JoinMethod *)xmergeinfo)->clauses =
|
||||
lcons(clause,
|
||||
((JoinMethod *)xmergeinfo)->clauses);
|
||||
((JoinMethod *)xmergeinfo)->jmkeys =
|
||||
lcons(keys,
|
||||
((JoinMethod *)xmergeinfo)->jmkeys);
|
||||
if (merge_ordering)
|
||||
{
|
||||
|
||||
/*
|
||||
* Create a new mergeinfo node and add it to 'mergeinfo-list'
|
||||
* if one does not yet exist for this merge ordering.
|
||||
*/
|
||||
PathOrder p_ordering;
|
||||
MInfo *xmergeinfo;
|
||||
Expr *clause = clauseinfo->clause;
|
||||
Var *leftop = get_leftop(clause);
|
||||
Var *rightop = get_rightop(clause);
|
||||
JoinKey *keys;
|
||||
|
||||
p_ordering.ordtype = MERGE_ORDER;
|
||||
p_ordering.ord.merge = merge_ordering;
|
||||
xmergeinfo =
|
||||
match_order_mergeinfo(&p_ordering, mergeinfo_list);
|
||||
if (inner_relid == leftop->varno)
|
||||
{
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = rightop;
|
||||
keys->inner = leftop;
|
||||
}
|
||||
else
|
||||
{
|
||||
keys = makeNode(JoinKey);
|
||||
keys->outer = leftop;
|
||||
keys->inner = rightop;
|
||||
}
|
||||
|
||||
if (xmergeinfo == NULL)
|
||||
{
|
||||
xmergeinfo = makeNode(MInfo);
|
||||
|
||||
xmergeinfo->m_ordering = merge_ordering;
|
||||
mergeinfo_list = lcons(xmergeinfo,
|
||||
mergeinfo_list);
|
||||
}
|
||||
|
||||
((JoinMethod *) xmergeinfo)->clauses =
|
||||
lcons(clause,
|
||||
((JoinMethod *) xmergeinfo)->clauses);
|
||||
((JoinMethod *) xmergeinfo)->jmkeys =
|
||||
lcons(keys,
|
||||
((JoinMethod *) xmergeinfo)->jmkeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(mergeinfo_list);
|
||||
return (mergeinfo_list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* match-order-mergeinfo--
|
||||
* Searches the list 'mergeinfo-list' for a mergeinfo node whose order
|
||||
* field equals 'ordering'.
|
||||
*
|
||||
* Searches the list 'mergeinfo-list' for a mergeinfo node whose order
|
||||
* field equals 'ordering'.
|
||||
*
|
||||
* Returns the node if it exists.
|
||||
*
|
||||
*
|
||||
*/
|
||||
MInfo *
|
||||
match_order_mergeinfo(PathOrder *ordering, List *mergeinfo_list)
|
||||
MInfo *
|
||||
match_order_mergeinfo(PathOrder * ordering, List * mergeinfo_list)
|
||||
{
|
||||
MergeOrder *xmergeorder;
|
||||
List *xmergeinfo = NIL;
|
||||
MergeOrder *xmergeorder;
|
||||
List *xmergeinfo = NIL;
|
||||
|
||||
foreach(xmergeinfo, mergeinfo_list) {
|
||||
MInfo *mergeinfo = (MInfo*)lfirst(xmergeinfo);
|
||||
foreach(xmergeinfo, mergeinfo_list)
|
||||
{
|
||||
MInfo *mergeinfo = (MInfo *) lfirst(xmergeinfo);
|
||||
|
||||
xmergeorder = mergeinfo->m_ordering;
|
||||
xmergeorder = mergeinfo->m_ordering;
|
||||
|
||||
if ((ordering->ordtype==MERGE_ORDER &&
|
||||
equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) ||
|
||||
(ordering->ordtype==SORTOP_ORDER &&
|
||||
equal_path_merge_ordering(ordering->ord.sortop, xmergeorder))) {
|
||||
if ((ordering->ordtype == MERGE_ORDER &&
|
||||
equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) ||
|
||||
(ordering->ordtype == SORTOP_ORDER &&
|
||||
equal_path_merge_ordering(ordering->ord.sortop, xmergeorder)))
|
||||
{
|
||||
|
||||
return (mergeinfo);
|
||||
return (mergeinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return((MInfo*) NIL);
|
||||
return ((MInfo *) NIL);
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* orindxpath.c--
|
||||
* Routines to find index paths that match a set of 'or' clauses
|
||||
* Routines to find index paths that match a set of 'or' clauses
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.2 1997/09/07 04:43:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -31,241 +31,267 @@
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
|
||||
static void best_or_subclause_indices(Query *root, Rel *rel, List *subclauses,
|
||||
List *indices, List *examined_indexids, Cost subcost, List *selectivities,
|
||||
List **indexids, Cost *cost, List **selecs);
|
||||
static void best_or_subclause_index(Query *root, Rel *rel, Expr *subclause,
|
||||
List *indices, int *indexid, Cost *cost, Cost *selec);
|
||||
static void
|
||||
best_or_subclause_indices(Query * root, Rel * rel, List * subclauses,
|
||||
List * indices, List * examined_indexids, Cost subcost, List * selectivities,
|
||||
List ** indexids, Cost * cost, List ** selecs);
|
||||
static void
|
||||
best_or_subclause_index(Query * root, Rel * rel, Expr * subclause,
|
||||
List * indices, int *indexid, Cost * cost, Cost * selec);
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* create-or-index-paths--
|
||||
* Creates index paths for indices that match 'or' clauses.
|
||||
*
|
||||
* Creates index paths for indices that match 'or' clauses.
|
||||
*
|
||||
* 'rel' is the relation entry for which the paths are to be defined on
|
||||
* 'clauses' is the list of available restriction clause nodes
|
||||
*
|
||||
*
|
||||
* Returns a list of these index path nodes.
|
||||
*
|
||||
*
|
||||
*/
|
||||
List *
|
||||
create_or_index_paths(Query *root,
|
||||
Rel *rel, List *clauses)
|
||||
List *
|
||||
create_or_index_paths(Query * root,
|
||||
Rel * rel, List * clauses)
|
||||
{
|
||||
List *t_list = NIL;
|
||||
|
||||
if (clauses != NIL) {
|
||||
CInfo *clausenode = (CInfo *) (lfirst (clauses));
|
||||
|
||||
/* Check to see if this clause is an 'or' clause, and, if so,
|
||||
* whether or not each of the subclauses within the 'or' clause has
|
||||
* been matched by an index (the 'Index field was set in
|
||||
* (match_or) if no index matches a given subclause, one of the
|
||||
* lists of index nodes returned by (get_index) will be 'nil').
|
||||
*/
|
||||
if (valid_or_clause(clausenode) &&
|
||||
clausenode->indexids) {
|
||||
List *temp = NIL;
|
||||
List *index_list = NIL;
|
||||
bool index_flag = true;
|
||||
|
||||
index_list = clausenode->indexids;
|
||||
foreach(temp,index_list) {
|
||||
if (!temp)
|
||||
index_flag = false;
|
||||
}
|
||||
if (index_flag) { /* used to be a lisp every function */
|
||||
IndexPath *pathnode = makeNode(IndexPath);
|
||||
List *indexids;
|
||||
Cost cost;
|
||||
List *selecs;
|
||||
List *t_list = NIL;
|
||||
|
||||
best_or_subclause_indices(root,
|
||||
rel,
|
||||
clausenode->clause->args,
|
||||
clausenode->indexids,
|
||||
NIL,
|
||||
(Cost)0,
|
||||
NIL,
|
||||
&indexids,
|
||||
&cost,
|
||||
&selecs);
|
||||
|
||||
pathnode->path.pathtype = T_IndexScan;
|
||||
pathnode->path.parent = rel;
|
||||
pathnode->indexqual =
|
||||
lcons(clausenode,NIL);
|
||||
pathnode->indexid = indexids;
|
||||
pathnode->path.path_cost = cost;
|
||||
|
||||
/* copy clauseinfo list into path for expensive
|
||||
function processing -- JMH, 7/7/92 */
|
||||
pathnode->path.locclauseinfo =
|
||||
set_difference(clauses,
|
||||
copyObject((Node*)
|
||||
rel->clauseinfo));
|
||||
|
||||
#if 0 /* fix xfunc */
|
||||
/* add in cost for expensive functions! -- JMH, 7/7/92 */
|
||||
if (XfuncMode != XFUNC_OFF) {
|
||||
((Path*)pathnode)->path_cost +=
|
||||
xfunc_get_path_cost((Path)pathnode);
|
||||
if (clauses != NIL)
|
||||
{
|
||||
CInfo *clausenode = (CInfo *) (lfirst(clauses));
|
||||
|
||||
/*
|
||||
* Check to see if this clause is an 'or' clause, and, if so,
|
||||
* whether or not each of the subclauses within the 'or' clause
|
||||
* has been matched by an index (the 'Index field was set in
|
||||
* (match_or) if no index matches a given subclause, one of the
|
||||
* lists of index nodes returned by (get_index) will be 'nil').
|
||||
*/
|
||||
if (valid_or_clause(clausenode) &&
|
||||
clausenode->indexids)
|
||||
{
|
||||
List *temp = NIL;
|
||||
List *index_list = NIL;
|
||||
bool index_flag = true;
|
||||
|
||||
index_list = clausenode->indexids;
|
||||
foreach(temp, index_list)
|
||||
{
|
||||
if (!temp)
|
||||
index_flag = false;
|
||||
}
|
||||
if (index_flag)
|
||||
{ /* used to be a lisp every function */
|
||||
IndexPath *pathnode = makeNode(IndexPath);
|
||||
List *indexids;
|
||||
Cost cost;
|
||||
List *selecs;
|
||||
|
||||
best_or_subclause_indices(root,
|
||||
rel,
|
||||
clausenode->clause->args,
|
||||
clausenode->indexids,
|
||||
NIL,
|
||||
(Cost) 0,
|
||||
NIL,
|
||||
&indexids,
|
||||
&cost,
|
||||
&selecs);
|
||||
|
||||
pathnode->path.pathtype = T_IndexScan;
|
||||
pathnode->path.parent = rel;
|
||||
pathnode->indexqual =
|
||||
lcons(clausenode, NIL);
|
||||
pathnode->indexid = indexids;
|
||||
pathnode->path.path_cost = cost;
|
||||
|
||||
/*
|
||||
* copy clauseinfo list into path for expensive function
|
||||
* processing -- JMH, 7/7/92
|
||||
*/
|
||||
pathnode->path.locclauseinfo =
|
||||
set_difference(clauses,
|
||||
copyObject((Node *)
|
||||
rel->clauseinfo));
|
||||
|
||||
#if 0 /* fix xfunc */
|
||||
/* add in cost for expensive functions! -- JMH, 7/7/92 */
|
||||
if (XfuncMode != XFUNC_OFF)
|
||||
{
|
||||
((Path *) pathnode)->path_cost +=
|
||||
xfunc_get_path_cost((Path) pathnode);
|
||||
}
|
||||
#endif
|
||||
clausenode->selectivity = (Cost) floatVal(selecs);
|
||||
t_list =
|
||||
lcons(pathnode,
|
||||
create_or_index_paths(root, rel, lnext(clauses)));
|
||||
}
|
||||
else
|
||||
{
|
||||
t_list = create_or_index_paths(root, rel, lnext(clauses));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
clausenode->selectivity = (Cost)floatVal(selecs);
|
||||
t_list =
|
||||
lcons(pathnode,
|
||||
create_or_index_paths(root, rel,lnext(clauses)));
|
||||
} else {
|
||||
t_list = create_or_index_paths(root, rel,lnext(clauses));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* best-or-subclause-indices--
|
||||
* Determines the best index to be used in conjunction with each subclause
|
||||
* of an 'or' clause and the cost of scanning a relation using these
|
||||
* indices. The cost is the sum of the individual index costs.
|
||||
*
|
||||
* Determines the best index to be used in conjunction with each subclause
|
||||
* of an 'or' clause and the cost of scanning a relation using these
|
||||
* indices. The cost is the sum of the individual index costs.
|
||||
*
|
||||
* 'rel' is the node of the relation on which the index is defined
|
||||
* 'subclauses' are the subclauses of the 'or' clause
|
||||
* 'indices' are those index nodes that matched subclauses of the 'or'
|
||||
* clause
|
||||
* 'examined-indexids' is a list of those index ids to be used with
|
||||
* subclauses that have already been examined
|
||||
* clause
|
||||
* 'examined-indexids' is a list of those index ids to be used with
|
||||
* subclauses that have already been examined
|
||||
* 'subcost' is the cost of using the indices in 'examined-indexids'
|
||||
* 'selectivities' is a list of the selectivities of subclauses that
|
||||
* have already been examined
|
||||
*
|
||||
* have already been examined
|
||||
*
|
||||
* Returns a list of the indexids, cost, and selectivities of each
|
||||
* subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
|
||||
* 'cost' is a flonum, and 's' is a flonum.
|
||||
*/
|
||||
static void
|
||||
best_or_subclause_indices(Query *root,
|
||||
Rel *rel,
|
||||
List *subclauses,
|
||||
List *indices,
|
||||
List *examined_indexids,
|
||||
Cost subcost,
|
||||
List *selectivities,
|
||||
List **indexids, /* return value */
|
||||
Cost *cost, /* return value */
|
||||
List **selecs) /* return value */
|
||||
best_or_subclause_indices(Query * root,
|
||||
Rel * rel,
|
||||
List * subclauses,
|
||||
List * indices,
|
||||
List * examined_indexids,
|
||||
Cost subcost,
|
||||
List * selectivities,
|
||||
List ** indexids, /* return value */
|
||||
Cost * cost, /* return value */
|
||||
List ** selecs) /* return value */
|
||||
{
|
||||
if (subclauses==NIL) {
|
||||
*indexids = nreverse(examined_indexids);
|
||||
*cost = subcost;
|
||||
*selecs = nreverse(selectivities);
|
||||
} else {
|
||||
int best_indexid;
|
||||
Cost best_cost;
|
||||
Cost best_selec;
|
||||
|
||||
best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
|
||||
&best_indexid, &best_cost, &best_selec);
|
||||
|
||||
best_or_subclause_indices(root,
|
||||
rel,
|
||||
lnext(subclauses),
|
||||
lnext(indices),
|
||||
lconsi(best_indexid, examined_indexids),
|
||||
subcost + best_cost,
|
||||
lcons(makeFloat(best_selec), selectivities),
|
||||
indexids,
|
||||
cost,
|
||||
selecs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (subclauses == NIL)
|
||||
{
|
||||
*indexids = nreverse(examined_indexids);
|
||||
*cost = subcost;
|
||||
*selecs = nreverse(selectivities);
|
||||
}
|
||||
else
|
||||
{
|
||||
int best_indexid;
|
||||
Cost best_cost;
|
||||
Cost best_selec;
|
||||
|
||||
/*
|
||||
best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
|
||||
&best_indexid, &best_cost, &best_selec);
|
||||
|
||||
best_or_subclause_indices(root,
|
||||
rel,
|
||||
lnext(subclauses),
|
||||
lnext(indices),
|
||||
lconsi(best_indexid, examined_indexids),
|
||||
subcost + best_cost,
|
||||
lcons(makeFloat(best_selec), selectivities),
|
||||
indexids,
|
||||
cost,
|
||||
selecs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* best-or-subclause-index--
|
||||
* Determines which is the best index to be used with a subclause of
|
||||
* an 'or' clause by estimating the cost of using each index and selecting
|
||||
* the least expensive.
|
||||
*
|
||||
* Determines which is the best index to be used with a subclause of
|
||||
* an 'or' clause by estimating the cost of using each index and selecting
|
||||
* the least expensive.
|
||||
*
|
||||
* 'rel' is the node of the relation on which the index is defined
|
||||
* 'subclause' is the subclause
|
||||
* 'indices' is a list of index nodes that match the subclause
|
||||
*
|
||||
*
|
||||
* Returns a list (index-id index-subcost index-selectivity)
|
||||
* (a fixnum, a fixnum, and a flonum respectively).
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
best_or_subclause_index(Query *root,
|
||||
Rel *rel,
|
||||
Expr *subclause,
|
||||
List *indices,
|
||||
int *retIndexid, /* return value */
|
||||
Cost *retCost, /* return value */
|
||||
Cost *retSelec) /* return value */
|
||||
best_or_subclause_index(Query * root,
|
||||
Rel * rel,
|
||||
Expr * subclause,
|
||||
List * indices,
|
||||
int *retIndexid, /* return value */
|
||||
Cost * retCost, /* return value */
|
||||
Cost * retSelec) /* return value */
|
||||
{
|
||||
if (indices != NIL) {
|
||||
Datum value;
|
||||
int flag = 0;
|
||||
Cost subcost;
|
||||
Rel *index = (Rel *)lfirst (indices);
|
||||
AttrNumber attno = (get_leftop (subclause))->varattno ;
|
||||
Oid opno = ((Oper*)subclause->oper)->opno;
|
||||
bool constant_on_right = non_null((Expr*)get_rightop(subclause));
|
||||
float npages, selec;
|
||||
int subclause_indexid;
|
||||
Cost subclause_cost;
|
||||
Cost subclause_selec;
|
||||
|
||||
if(constant_on_right) {
|
||||
value = ((Const*)get_rightop (subclause))->constvalue;
|
||||
} else {
|
||||
value = NameGetDatum("");
|
||||
}
|
||||
if(constant_on_right) {
|
||||
flag = (_SELEC_IS_CONSTANT_ ||_SELEC_CONSTANT_RIGHT_);
|
||||
} else {
|
||||
flag = _SELEC_CONSTANT_RIGHT_;
|
||||
}
|
||||
index_selectivity(lfirsti(index->relids),
|
||||
index->classlist,
|
||||
lconsi(opno,NIL),
|
||||
getrelid(lfirsti(rel->relids),
|
||||
root->rtable),
|
||||
lconsi(attno,NIL),
|
||||
lconsi(value,NIL),
|
||||
lconsi(flag,NIL),
|
||||
1,
|
||||
&npages,
|
||||
&selec);
|
||||
|
||||
subcost = cost_index((Oid) lfirsti(index->relids),
|
||||
(int)npages,
|
||||
(Cost)selec,
|
||||
rel->pages,
|
||||
rel->tuples,
|
||||
index->pages,
|
||||
index->tuples,
|
||||
false);
|
||||
best_or_subclause_index(root,
|
||||
rel,
|
||||
subclause,
|
||||
lnext(indices),
|
||||
&subclause_indexid,
|
||||
&subclause_cost,
|
||||
&subclause_selec);
|
||||
if (indices != NIL)
|
||||
{
|
||||
Datum value;
|
||||
int flag = 0;
|
||||
Cost subcost;
|
||||
Rel *index = (Rel *) lfirst(indices);
|
||||
AttrNumber attno = (get_leftop(subclause))->varattno;
|
||||
Oid opno = ((Oper *) subclause->oper)->opno;
|
||||
bool constant_on_right = non_null((Expr *) get_rightop(subclause));
|
||||
float npages,
|
||||
selec;
|
||||
int subclause_indexid;
|
||||
Cost subclause_cost;
|
||||
Cost subclause_selec;
|
||||
|
||||
if (subclause_indexid==0 || subcost < subclause_cost) {
|
||||
*retIndexid = lfirsti(index->relids);
|
||||
*retCost = subcost;
|
||||
*retSelec = selec;
|
||||
} else {
|
||||
*retIndexid = 0;
|
||||
*retCost = 0.0;
|
||||
*retSelec = 0.0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
if (constant_on_right)
|
||||
{
|
||||
value = ((Const *) get_rightop(subclause))->constvalue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = NameGetDatum("");
|
||||
}
|
||||
if (constant_on_right)
|
||||
{
|
||||
flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = _SELEC_CONSTANT_RIGHT_;
|
||||
}
|
||||
index_selectivity(lfirsti(index->relids),
|
||||
index->classlist,
|
||||
lconsi(opno, NIL),
|
||||
getrelid(lfirsti(rel->relids),
|
||||
root->rtable),
|
||||
lconsi(attno, NIL),
|
||||
lconsi(value, NIL),
|
||||
lconsi(flag, NIL),
|
||||
1,
|
||||
&npages,
|
||||
&selec);
|
||||
|
||||
subcost = cost_index((Oid) lfirsti(index->relids),
|
||||
(int) npages,
|
||||
(Cost) selec,
|
||||
rel->pages,
|
||||
rel->tuples,
|
||||
index->pages,
|
||||
index->tuples,
|
||||
false);
|
||||
best_or_subclause_index(root,
|
||||
rel,
|
||||
subclause,
|
||||
lnext(indices),
|
||||
&subclause_indexid,
|
||||
&subclause_cost,
|
||||
&subclause_selec);
|
||||
|
||||
if (subclause_indexid == 0 || subcost < subclause_cost)
|
||||
{
|
||||
*retIndexid = lfirsti(index->relids);
|
||||
*retCost = subcost;
|
||||
*retSelec = selec;
|
||||
}
|
||||
else
|
||||
{
|
||||
*retIndexid = 0;
|
||||
*retCost = 0.0;
|
||||
*retSelec = 0.0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* prune.c--
|
||||
* Routines to prune redundant paths and relations
|
||||
* Routines to prune redundant paths and relations
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.3 1997/06/10 07:55:47 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.4 1997/09/07 04:43:49 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,181 +24,199 @@
|
||||
#include "utils/elog.h"
|
||||
|
||||
|
||||
static List *prune_joinrel(Rel *rel, List *other_rels);
|
||||
static List *prune_joinrel(Rel * rel, List * other_rels);
|
||||
|
||||
/*
|
||||
/*
|
||||
* prune-joinrels--
|
||||
* Removes any redundant relation entries from a list of rel nodes
|
||||
* 'rel-list'.
|
||||
*
|
||||
* Returns the resulting list.
|
||||
*
|
||||
* Removes any redundant relation entries from a list of rel nodes
|
||||
* 'rel-list'.
|
||||
*
|
||||
* Returns the resulting list.
|
||||
*
|
||||
*/
|
||||
List *prune_joinrels(List *rel_list)
|
||||
List *
|
||||
prune_joinrels(List * rel_list)
|
||||
{
|
||||
List *temp_list = NIL;
|
||||
List *temp_list = NIL;
|
||||
|
||||
if (rel_list != NIL) {
|
||||
temp_list = lcons(lfirst(rel_list),
|
||||
prune_joinrels(prune_joinrel((Rel*)lfirst(rel_list),
|
||||
lnext(rel_list))));
|
||||
}
|
||||
return(temp_list);
|
||||
if (rel_list != NIL)
|
||||
{
|
||||
temp_list = lcons(lfirst(rel_list),
|
||||
prune_joinrels(prune_joinrel((Rel *) lfirst(rel_list),
|
||||
lnext(rel_list))));
|
||||
}
|
||||
return (temp_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* prune-joinrel--
|
||||
* Prunes those relations from 'other-rels' that are redundant with
|
||||
* 'rel'. A relation is redundant if it is built up of the same
|
||||
* relations as 'rel'. Paths for the redundant relation are merged into
|
||||
* the pathlist of 'rel'.
|
||||
*
|
||||
* Prunes those relations from 'other-rels' that are redundant with
|
||||
* 'rel'. A relation is redundant if it is built up of the same
|
||||
* relations as 'rel'. Paths for the redundant relation are merged into
|
||||
* the pathlist of 'rel'.
|
||||
*
|
||||
* Returns a list of non-redundant relations, and sets the pathlist field
|
||||
* of 'rel' appropriately.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
prune_joinrel(Rel *rel, List *other_rels)
|
||||
static List *
|
||||
prune_joinrel(Rel * rel, List * other_rels)
|
||||
{
|
||||
List *i = NIL;
|
||||
List *t_list = NIL;
|
||||
List *temp_node = NIL;
|
||||
Rel *other_rel = (Rel *)NULL;
|
||||
|
||||
foreach(i, other_rels) {
|
||||
other_rel = (Rel*)lfirst(i);
|
||||
if(same(rel->relids, other_rel->relids)) {
|
||||
rel->pathlist = add_pathlist(rel,
|
||||
rel->pathlist,
|
||||
other_rel->pathlist);
|
||||
t_list = nconc(t_list, NIL); /* XXX is this right ? */
|
||||
} else {
|
||||
temp_node = lcons(other_rel, NIL);
|
||||
t_list = nconc(t_list,temp_node);
|
||||
}
|
||||
}
|
||||
return(t_list);
|
||||
List *i = NIL;
|
||||
List *t_list = NIL;
|
||||
List *temp_node = NIL;
|
||||
Rel *other_rel = (Rel *) NULL;
|
||||
|
||||
foreach(i, other_rels)
|
||||
{
|
||||
other_rel = (Rel *) lfirst(i);
|
||||
if (same(rel->relids, other_rel->relids))
|
||||
{
|
||||
rel->pathlist = add_pathlist(rel,
|
||||
rel->pathlist,
|
||||
other_rel->pathlist);
|
||||
t_list = nconc(t_list, NIL); /* XXX is this right ? */
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_node = lcons(other_rel, NIL);
|
||||
t_list = nconc(t_list, temp_node);
|
||||
}
|
||||
}
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* prune-rel-paths--
|
||||
* For each relation entry in 'rel-list' (which corresponds to a join
|
||||
* relation), set pointers to the unordered path and cheapest paths
|
||||
* (if the unordered path isn't the cheapest, it is pruned), and
|
||||
* reset the relation's size field to reflect the join.
|
||||
*
|
||||
* For each relation entry in 'rel-list' (which corresponds to a join
|
||||
* relation), set pointers to the unordered path and cheapest paths
|
||||
* (if the unordered path isn't the cheapest, it is pruned), and
|
||||
* reset the relation's size field to reflect the join.
|
||||
*
|
||||
* Returns nothing of interest.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void
|
||||
prune_rel_paths(List *rel_list)
|
||||
prune_rel_paths(List * rel_list)
|
||||
{
|
||||
List *x = NIL;
|
||||
List *y = NIL;
|
||||
Path *path = NULL;
|
||||
Rel *rel = (Rel*)NULL;
|
||||
JoinPath *cheapest = (JoinPath*)NULL;
|
||||
|
||||
foreach(x, rel_list) {
|
||||
rel = (Rel*)lfirst(x);
|
||||
rel->size = 0;
|
||||
foreach(y, rel->pathlist) {
|
||||
path = (Path*)lfirst(y);
|
||||
List *x = NIL;
|
||||
List *y = NIL;
|
||||
Path *path = NULL;
|
||||
Rel *rel = (Rel *) NULL;
|
||||
JoinPath *cheapest = (JoinPath *) NULL;
|
||||
|
||||
if(!path->p_ordering.ord.sortop) {
|
||||
break;
|
||||
}
|
||||
foreach(x, rel_list)
|
||||
{
|
||||
rel = (Rel *) lfirst(x);
|
||||
rel->size = 0;
|
||||
foreach(y, rel->pathlist)
|
||||
{
|
||||
path = (Path *) lfirst(y);
|
||||
|
||||
if (!path->p_ordering.ord.sortop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
cheapest = (JoinPath *) prune_rel_path(rel, path);
|
||||
if (IsA_JoinPath(cheapest))
|
||||
{
|
||||
rel->size = compute_joinrel_size(cheapest);
|
||||
}
|
||||
else
|
||||
elog(WARN, "non JoinPath called");
|
||||
}
|
||||
cheapest = (JoinPath*)prune_rel_path(rel, path);
|
||||
if (IsA_JoinPath(cheapest))
|
||||
{
|
||||
rel->size = compute_joinrel_size(cheapest);
|
||||
}
|
||||
else
|
||||
elog(WARN, "non JoinPath called");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* prune-rel-path--
|
||||
* Compares the unordered path for a relation with the cheapest path. If
|
||||
* the unordered path is not cheapest, it is pruned.
|
||||
*
|
||||
* Resets the pointers in 'rel' for unordered and cheapest paths.
|
||||
*
|
||||
* Compares the unordered path for a relation with the cheapest path. If
|
||||
* the unordered path is not cheapest, it is pruned.
|
||||
*
|
||||
* Resets the pointers in 'rel' for unordered and cheapest paths.
|
||||
*
|
||||
* Returns the cheapest path.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Path *
|
||||
prune_rel_path(Rel *rel, Path *unorderedpath)
|
||||
Path *
|
||||
prune_rel_path(Rel * rel, Path * unorderedpath)
|
||||
{
|
||||
Path *cheapest = set_cheapest(rel, rel->pathlist);
|
||||
|
||||
/* don't prune if not pruneable -- JMH, 11/23/92 */
|
||||
if(unorderedpath != cheapest
|
||||
&& rel->pruneable) {
|
||||
|
||||
rel->unorderedpath = (Path *)NULL;
|
||||
rel->pathlist = lremove(unorderedpath, rel->pathlist);
|
||||
} else {
|
||||
rel->unorderedpath = (Path *)unorderedpath;
|
||||
}
|
||||
|
||||
return(cheapest);
|
||||
Path *cheapest = set_cheapest(rel, rel->pathlist);
|
||||
|
||||
/* don't prune if not pruneable -- JMH, 11/23/92 */
|
||||
if (unorderedpath != cheapest
|
||||
&& rel->pruneable)
|
||||
{
|
||||
|
||||
rel->unorderedpath = (Path *) NULL;
|
||||
rel->pathlist = lremove(unorderedpath, rel->pathlist);
|
||||
}
|
||||
else
|
||||
{
|
||||
rel->unorderedpath = (Path *) unorderedpath;
|
||||
}
|
||||
|
||||
return (cheapest);
|
||||
}
|
||||
|
||||
/*
|
||||
* merge-joinrels--
|
||||
* Given two lists of rel nodes that are already
|
||||
* pruned, merge them into one pruned rel node list
|
||||
* Given two lists of rel nodes that are already
|
||||
* pruned, merge them into one pruned rel node list
|
||||
*
|
||||
* 'rel-list1' and
|
||||
* 'rel-list2' are the rel node lists
|
||||
*
|
||||
* Returns one pruned rel node list
|
||||
*/
|
||||
List *
|
||||
merge_joinrels(List *rel_list1, List *rel_list2)
|
||||
List *
|
||||
merge_joinrels(List * rel_list1, List * rel_list2)
|
||||
{
|
||||
List *xrel = NIL;
|
||||
|
||||
foreach(xrel,rel_list1) {
|
||||
Rel *rel = (Rel*)lfirst(xrel);
|
||||
rel_list2 = prune_joinrel(rel,rel_list2);
|
||||
}
|
||||
return(append(rel_list1, rel_list2));
|
||||
List *xrel = NIL;
|
||||
|
||||
foreach(xrel, rel_list1)
|
||||
{
|
||||
Rel *rel = (Rel *) lfirst(xrel);
|
||||
|
||||
rel_list2 = prune_joinrel(rel, rel_list2);
|
||||
}
|
||||
return (append(rel_list1, rel_list2));
|
||||
}
|
||||
|
||||
/*
|
||||
* prune_oldrels--
|
||||
* If all the joininfo's in a rel node are inactive,
|
||||
* that means that this node has been joined into
|
||||
* other nodes in all possible ways, therefore
|
||||
* this node can be discarded. If not, it will cause
|
||||
* extra complexity of the optimizer.
|
||||
* If all the joininfo's in a rel node are inactive,
|
||||
* that means that this node has been joined into
|
||||
* other nodes in all possible ways, therefore
|
||||
* this node can be discarded. If not, it will cause
|
||||
* extra complexity of the optimizer.
|
||||
*
|
||||
* old_rels is a list of rel nodes
|
||||
*
|
||||
*
|
||||
* Returns a new list of rel nodes
|
||||
*/
|
||||
List *prune_oldrels(List *old_rels)
|
||||
List *
|
||||
prune_oldrels(List * old_rels)
|
||||
{
|
||||
Rel *rel;
|
||||
List *joininfo_list, *xjoininfo;
|
||||
|
||||
if(old_rels == NIL)
|
||||
return(NIL);
|
||||
|
||||
rel = (Rel*)lfirst(old_rels);
|
||||
joininfo_list = rel->joininfo;
|
||||
if(joininfo_list == NIL)
|
||||
return (lcons(rel, prune_oldrels(lnext(old_rels))));
|
||||
Rel *rel;
|
||||
List *joininfo_list,
|
||||
*xjoininfo;
|
||||
|
||||
foreach(xjoininfo, joininfo_list) {
|
||||
JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
|
||||
if(!joininfo->inactive)
|
||||
return (lcons(rel, prune_oldrels(lnext(old_rels))));
|
||||
}
|
||||
return(prune_oldrels(lnext(old_rels)));
|
||||
if (old_rels == NIL)
|
||||
return (NIL);
|
||||
|
||||
rel = (Rel *) lfirst(old_rels);
|
||||
joininfo_list = rel->joininfo;
|
||||
if (joininfo_list == NIL)
|
||||
return (lcons(rel, prune_oldrels(lnext(old_rels))));
|
||||
|
||||
foreach(xjoininfo, joininfo_list)
|
||||
{
|
||||
JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
|
||||
|
||||
if (!joininfo->inactive)
|
||||
return (lcons(rel, prune_oldrels(lnext(old_rels))));
|
||||
}
|
||||
return (prune_oldrels(lnext(old_rels)));
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user