1
0
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:
Bruce Momjian
1997-09-07 05:04:48 +00:00
parent 8fecd4febf
commit 1ccd423235
687 changed files with 150775 additions and 136888 deletions

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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