aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/xfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/xfunc.c')
-rw-r--r--src/backend/optimizer/path/xfunc.c2192
1 files changed, 1170 insertions, 1022 deletions
diff --git a/src/backend/optimizer/path/xfunc.c b/src/backend/optimizer/path/xfunc.c
index 3e3ee650f94..36135d4a823 100644
--- a/src/backend/optimizer/path/xfunc.c
+++ b/src/backend/optimizer/path/xfunc.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* xfunc.c--
- * Utility routines to handle expensive function optimization.
- * Includes xfunc_trypullup(), which attempts early pullup of predicates
- * to allow for maximal pruning.
- *
+ * Utility routines to handle expensive function optimization.
+ * Includes xfunc_trypullup(), which attempts early pullup of predicates
+ * to allow for maximal pruning.
+ *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.3 1997/02/14 04:15:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.4 1997/09/07 04:43:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for MAXFLOAT on most systems */
+#include <math.h> /* for MAXFLOAT on most systems */
-#include <values.h> /* for MAXFLOAT on SunOS */
+#include <values.h> /* for MAXFLOAT on SunOS */
#include <string.h>
#include "postgres.h"
@@ -40,82 +40,96 @@
#include "lib/lispsort.h"
#include "access/heapam.h"
#include "tcop/dest.h"
-#include "storage/buf_internals.h" /* for NBuffers */
-#include "optimizer/tlist.h" /* for get_expr */
+#include "storage/buf_internals.h" /* for NBuffers */
+#include "optimizer/tlist.h" /* for get_expr */
#define ever ; 1 ;
/* local funcs */
-static int xfunc_card_unreferenced(Query *queryInfo,
- Expr *clause, Relid referenced); */
+static int
+xfunc_card_unreferenced(Query * queryInfo,
+ Expr * clause, Relid referenced);
+
+*/
/*
** xfunc_trypullup --
-** Preliminary pullup of predicates, to allow for maximal pruning.
+** Preliminary pullup of predicates, to allow for maximal pruning.
** Given a relation, check each of its paths and see if you can
** pullup clauses from its inner and outer.
*/
-void xfunc_trypullup(Rel rel)
+void
+xfunc_trypullup(Rel rel)
{
- LispValue y; /* list ptr */
- CInfo maxcinfo; /* The CInfo to pull up, as calculated by
- xfunc_shouldpull() */
- JoinPath curpath; /* current path in list */
- int progress; /* has progress been made this time through? */
- int clausetype;
-
- do {
- progress = false; /* no progress yet in this iteration */
- foreach(y, get_pathlist(rel)) {
- curpath = (JoinPath)lfirst(y);
-
- /*
- ** for each operand, attempt to pullup predicates until first
- ** failure.
- */
- for(ever) {
- /* No, the following should NOT be '==' !! */
- if (clausetype =
- xfunc_shouldpull((Path)get_innerjoinpath(curpath),
- curpath, INNER, &maxcinfo)) {
-
- xfunc_pullup((Path)get_innerjoinpath(curpath),
- curpath, maxcinfo, INNER, clausetype);
- progress = true;
- }else
- break;
- }
- for(ever) {
-
- /* No, the following should NOT be '==' !! */
- if (clausetype =
- xfunc_shouldpull((Path)get_outerjoinpath(curpath),
- curpath, OUTER, &maxcinfo)) {
-
- xfunc_pullup((Path)get_outerjoinpath(curpath),
- curpath, maxcinfo, OUTER, clausetype);
- progress = true;
- }else
- break;
- }
-
- /*
- ** make sure the unpruneable flag bubbles up, i.e.
- ** if anywhere below us in the path pruneable is false,
- ** then pruneable should be false here
- */
- if (get_pruneable(get_parent(curpath)) &&
- (!get_pruneable(get_parent
- ((Path)get_innerjoinpath(curpath))) ||
- !get_pruneable(get_parent((Path)
- get_outerjoinpath(curpath))))) {
-
- set_pruneable(get_parent(curpath),false);
- progress = true;
- }
- }
- } while(progress);
+ LispValue y; /* list ptr */
+ CInfo maxcinfo; /* The CInfo to pull up, as calculated by
+ * xfunc_shouldpull() */
+ JoinPath curpath; /* current path in list */
+ int progress; /* has progress been made this time
+ * through? */
+ int clausetype;
+
+ do
+ {
+ progress = false; /* no progress yet in this iteration */
+ foreach(y, get_pathlist(rel))
+ {
+ curpath = (JoinPath) lfirst(y);
+
+ /*
+ * * for each operand, attempt to pullup predicates until
+ * first * failure.
+ */
+ for (ever)
+ {
+ /* No, the following should NOT be '==' !! */
+ if (clausetype =
+ xfunc_shouldpull((Path) get_innerjoinpath(curpath),
+ curpath, INNER, &maxcinfo))
+ {
+
+ xfunc_pullup((Path) get_innerjoinpath(curpath),
+ curpath, maxcinfo, INNER, clausetype);
+ progress = true;
+ }
+ else
+ break;
+ }
+ for (ever)
+ {
+
+ /* No, the following should NOT be '==' !! */
+ if (clausetype =
+ xfunc_shouldpull((Path) get_outerjoinpath(curpath),
+ curpath, OUTER, &maxcinfo))
+ {
+
+ xfunc_pullup((Path) get_outerjoinpath(curpath),
+ curpath, maxcinfo, OUTER, clausetype);
+ progress = true;
+ }
+ else
+ break;
+ }
+
+ /*
+ * * make sure the unpruneable flag bubbles up, i.e. * if
+ * anywhere below us in the path pruneable is false, * then
+ * pruneable should be false here
+ */
+ if (get_pruneable(get_parent(curpath)) &&
+ (!get_pruneable(get_parent
+ ((Path) get_innerjoinpath(curpath))) ||
+ !get_pruneable(get_parent((Path)
+ get_outerjoinpath(curpath)))))
+ {
+
+ set_pruneable(get_parent(curpath), false);
+ progress = true;
+ }
+ }
+ } while (progress);
}
/*
@@ -128,108 +142,123 @@ void xfunc_trypullup(Rel rel)
** we'd better set the unpruneable flag. -- JMH, 11/11/92
**
** Returns: 0 if nothing left to pullup
- ** XFUNC_LOCPRD if a local predicate is to be pulled up
- ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up
+ ** XFUNC_LOCPRD if a local predicate is to be pulled up
+ ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up
*/
-int xfunc_shouldpull(Query* queryInfo,
- Path childpath,
- JoinPath parentpath,
- int whichchild,
- CInfo *maxcinfopt) /* Out: pointer to clause to pullup */
+int
+xfunc_shouldpull(Query * queryInfo,
+ Path childpath,
+ JoinPath parentpath,
+ int whichchild,
+ CInfo * maxcinfopt) /* Out: pointer to clause to
+ * pullup */
{
- LispValue clauselist, tmplist; /* lists of clauses */
- CInfo maxcinfo; /* clause to pullup */
- LispValue primjoinclause /* primary join clause */
+ LispValue clauselist,
+ tmplist; /* lists of clauses */
+ CInfo maxcinfo; /* clause to pullup */
+ LispValue primjoinclause /* primary join clause */
= xfunc_primary_join(parentpath);
- Cost tmprank, maxrank = (-1 * MAXFLOAT); /* ranks of clauses */
- Cost joinselec = 0; /* selectivity of the join predicate */
- Cost joincost = 0; /* join cost + primjoinclause cost */
- int retval = XFUNC_LOCPRD;
-
- clauselist = get_locclauseinfo(childpath);
-
- if (clauselist != LispNil) {
- /* find local predicate with maximum rank */
- for (tmplist = clauselist,
- maxcinfo = (CInfo) lfirst(tmplist),
- maxrank = xfunc_rank(get_clause(maxcinfo));
- tmplist != LispNil;
- tmplist = lnext(tmplist)) {
-
- if ((tmprank = xfunc_rank(get_clause((CInfo)lfirst(tmplist))))
- > maxrank) {
- maxcinfo = (CInfo) lfirst(tmplist);
- maxrank = tmprank;
- }
+ Cost tmprank,
+ maxrank = (-1 * MAXFLOAT); /* ranks of clauses */
+ Cost joinselec = 0; /* selectivity of the join
+ * predicate */
+ Cost joincost = 0; /* join cost + primjoinclause cost */
+ int retval = XFUNC_LOCPRD;
+
+ clauselist = get_locclauseinfo(childpath);
+
+ if (clauselist != LispNil)
+ {
+ /* find local predicate with maximum rank */
+ for (tmplist = clauselist,
+ maxcinfo = (CInfo) lfirst(tmplist),
+ maxrank = xfunc_rank(get_clause(maxcinfo));
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ {
+
+ if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ > maxrank)
+ {
+ maxcinfo = (CInfo) lfirst(tmplist);
+ maxrank = tmprank;
+ }
+ }
}
- }
-
- /*
- ** If child is a join path, and there are multiple join clauses,
- ** see if any join clause has even higher rank than the highest
- ** local predicate
- */
- if (is_join(childpath) && xfunc_num_join_clauses((JoinPath)childpath) > 1)
- for (tmplist = get_pathclauseinfo((JoinPath)childpath);
- tmplist != LispNil;
- tmplist = lnext(tmplist)) {
-
- if (tmplist != LispNil &&
- (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
- > maxrank) {
- maxcinfo = (CInfo) lfirst(tmplist);
- maxrank = tmprank;
- retval = XFUNC_JOINPRD;
- }
- }
- if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */
- return(0);
-
- /*
- ** Pullup over join if clause is higher rank than join, or if
- ** join is nested loop and current path is inner child (note that
- ** restrictions on the inner of a nested loop don't buy you anything --
- ** you still have to scan the entire inner relation each time).
- ** Note that the cost of a secondary join clause is only what's
- ** calculated by xfunc_expense(), since the actual joining
- ** (i.e. the usual path_cost) is paid for by the primary join clause.
- */
- if (primjoinclause != LispNil) {
- joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil);
- joincost = xfunc_join_expense(parentpath, whichchild);
-
- if (XfuncMode == XFUNC_PULLALL ||
- (XfuncMode != XFUNC_WAIT &&
- ((joincost != 0 &&
- (maxrank = xfunc_rank(get_clause(maxcinfo))) >
- ((joinselec - 1.0) / joincost))
- || (joincost == 0 && joinselec < 1)
- || (!is_join(childpath)
- && (whichchild == INNER)
- && IsA(parentpath,JoinPath)
- && !IsA(parentpath,HashPath)
- && !IsA(parentpath,MergePath))))) {
-
- *maxcinfopt = maxcinfo;
- return(retval);
-
- }else if (maxrank != -(MAXFLOAT)) {
- /*
- ** we've left an expensive restriction below a join. Since
- ** we may pullup this restriction in predmig.c, we'd best
- ** set the Rel of this join to be unpruneable
- */
- set_pruneable(get_parent(parentpath), false);
- /* and fall through */
+
+ /*
+ * * If child is a join path, and there are multiple join clauses, *
+ * see if any join clause has even higher rank than the highest *
+ * local predicate
+ */
+ if (is_join(childpath) && xfunc_num_join_clauses((JoinPath) childpath) > 1)
+ for (tmplist = get_pathclauseinfo((JoinPath) childpath);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ {
+
+ if (tmplist != LispNil &&
+ (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ > maxrank)
+ {
+ maxcinfo = (CInfo) lfirst(tmplist);
+ maxrank = tmprank;
+ retval = XFUNC_JOINPRD;
+ }
+ }
+ if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */
+ return (0);
+
+ /*
+ * * Pullup over join if clause is higher rank than join, or if * join
+ * is nested loop and current path is inner child (note that *
+ * restrictions on the inner of a nested loop don't buy you anything
+ * -- * you still have to scan the entire inner relation each time). *
+ * Note that the cost of a secondary join clause is only what's *
+ * calculated by xfunc_expense(), since the actual joining * (i.e. the
+ * usual path_cost) is paid for by the primary join clause.
+ */
+ if (primjoinclause != LispNil)
+ {
+ joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil);
+ joincost = xfunc_join_expense(parentpath, whichchild);
+
+ if (XfuncMode == XFUNC_PULLALL ||
+ (XfuncMode != XFUNC_WAIT &&
+ ((joincost != 0 &&
+ (maxrank = xfunc_rank(get_clause(maxcinfo))) >
+ ((joinselec - 1.0) / joincost))
+ || (joincost == 0 && joinselec < 1)
+ || (!is_join(childpath)
+ && (whichchild == INNER)
+ && IsA(parentpath, JoinPath)
+ && !IsA(parentpath, HashPath)
+ && !IsA(parentpath, MergePath)))))
+ {
+
+ *maxcinfopt = maxcinfo;
+ return (retval);
+
+ }
+ else if (maxrank != -(MAXFLOAT))
+ {
+
+ /*
+ * * we've left an expensive restriction below a join. Since *
+ * we may pullup this restriction in predmig.c, we'd best *
+ * set the Rel of this join to be unpruneable
+ */
+ set_pruneable(get_parent(parentpath), false);
+ /* and fall through */
+ }
}
- }
- return(0);
+ return (0);
}
/*
** xfunc_pullup --
- ** move clause from child pathnode to parent pathnode. This operation
+ ** move clause from child pathnode to parent pathnode. This operation
** makes the child pathnode produce a larger relation than it used to.
** This means that we must construct a new Rel just for the childpath,
** although this Rel will not be added to the list of Rels to be joined up
@@ -238,101 +267,111 @@ int xfunc_shouldpull(Query* queryInfo,
**
** Now returns a pointer to the new pulled-up CInfo. -- JMH, 11/18/92
*/
-CInfo xfunc_pullup(Query* queryInfo,
- Path childpath,
- JoinPath parentpath,
- CInfo cinfo, /* clause to pull up */
- int whichchild,/* whether child is INNER or OUTER of join */
- int clausetype)/* whether clause to pull is join or local */
+CInfo
+xfunc_pullup(Query * queryInfo,
+ Path childpath,
+ JoinPath parentpath,
+ CInfo cinfo, /* clause to pull up */
+ int whichchild, /* whether child is INNER or OUTER of join */
+ int clausetype) /* whether clause to pull is join or local */
{
- Path newkid;
- Rel newrel;
- Cost pulled_selec;
- Cost cost;
- CInfo newinfo;
-
- /* remove clause from childpath */
- newkid = (Path)copyObject((Node)childpath);
- if (clausetype == XFUNC_LOCPRD) {
- set_locclauseinfo(newkid,
- xfunc_LispRemove((LispValue)cinfo,
- (List)get_locclauseinfo(newkid)));
- }else {
- set_pathclauseinfo
- ((JoinPath)newkid,
- xfunc_LispRemove((LispValue)cinfo,
- (List)get_pathclauseinfo((JoinPath)newkid)));
- }
-
- /*
- ** give the new child path its own Rel node that reflects the
- ** lack of the pulled-up predicate
- */
- pulled_selec = compute_clause_selec(queryInfo,
- get_clause(cinfo), LispNil);
- xfunc_copyrel(get_parent(newkid), &newrel);
- set_parent(newkid, newrel);
- set_pathlist(newrel, lcons(newkid, NIL));
- set_unorderedpath(newrel, (PathPtr)newkid);
- set_cheapestpath(newrel, (PathPtr)newkid);
- set_size(newrel,
- (Count)((Cost)get_size(get_parent(childpath)) / pulled_selec));
-
- /*
- ** fix up path cost of newkid. To do this we subtract away all the
- ** xfunc_costs of childpath, then recompute the xfunc_costs of newkid
- */
- cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath);
- Assert(cost >= 0);
- set_path_cost(newkid, cost);
- cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid);
- set_path_cost(newkid, cost);
-
- /*
- ** We copy the cinfo, since it may appear in other plans, and we're going
- ** to munge it. -- JMH, 7/22/92
- */
- newinfo = (CInfo)copyObject((Node)cinfo);
-
- /*
- ** Fix all vars in the clause
- ** to point to the right varno and varattno in parentpath
- */
- xfunc_fixvars(get_clause(newinfo), newrel, whichchild);
-
- /* add clause to parentpath, and fix up its cost. */
- set_locclauseinfo(parentpath,
- lispCons((LispValue)newinfo,
- (LispValue)get_locclauseinfo(parentpath)));
- /* put new childpath into the path tree */
- if (whichchild == INNER) {
- set_innerjoinpath(parentpath, (pathPtr)newkid);
- }else {
- set_outerjoinpath(parentpath, (pathPtr)newkid);
- }
-
- /*
- ** recompute parentpath cost from scratch -- the cost
- ** of the join method has changed
- */
- cost = xfunc_total_path_cost(parentpath);
- set_path_cost(parentpath, cost);
-
- return(newinfo);
+ Path newkid;
+ Rel newrel;
+ Cost pulled_selec;
+ Cost cost;
+ CInfo newinfo;
+
+ /* remove clause from childpath */
+ newkid = (Path) copyObject((Node) childpath);
+ if (clausetype == XFUNC_LOCPRD)
+ {
+ set_locclauseinfo(newkid,
+ xfunc_LispRemove((LispValue) cinfo,
+ (List) get_locclauseinfo(newkid)));
+ }
+ else
+ {
+ set_pathclauseinfo
+ ((JoinPath) newkid,
+ xfunc_LispRemove((LispValue) cinfo,
+ (List) get_pathclauseinfo((JoinPath) newkid)));
+ }
+
+ /*
+ * * give the new child path its own Rel node that reflects the * lack
+ * of the pulled-up predicate
+ */
+ pulled_selec = compute_clause_selec(queryInfo,
+ get_clause(cinfo), LispNil);
+ xfunc_copyrel(get_parent(newkid), &newrel);
+ set_parent(newkid, newrel);
+ set_pathlist(newrel, lcons(newkid, NIL));
+ set_unorderedpath(newrel, (PathPtr) newkid);
+ set_cheapestpath(newrel, (PathPtr) newkid);
+ set_size(newrel,
+ (Count) ((Cost) get_size(get_parent(childpath)) / pulled_selec));
+
+ /*
+ * * fix up path cost of newkid. To do this we subtract away all the *
+ * xfunc_costs of childpath, then recompute the xfunc_costs of newkid
+ */
+ cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath);
+ Assert(cost >= 0);
+ set_path_cost(newkid, cost);
+ cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid);
+ set_path_cost(newkid, cost);
+
+ /*
+ * * We copy the cinfo, since it may appear in other plans, and we're
+ * going * to munge it. -- JMH, 7/22/92
+ */
+ newinfo = (CInfo) copyObject((Node) cinfo);
+
+ /*
+ * * Fix all vars in the clause * to point to the right varno and
+ * varattno in parentpath
+ */
+ xfunc_fixvars(get_clause(newinfo), newrel, whichchild);
+
+ /* add clause to parentpath, and fix up its cost. */
+ set_locclauseinfo(parentpath,
+ lispCons((LispValue) newinfo,
+ (LispValue) get_locclauseinfo(parentpath)));
+ /* put new childpath into the path tree */
+ if (whichchild == INNER)
+ {
+ set_innerjoinpath(parentpath, (pathPtr) newkid);
+ }
+ else
+ {
+ set_outerjoinpath(parentpath, (pathPtr) newkid);
+ }
+
+ /*
+ * * recompute parentpath cost from scratch -- the cost * of the join
+ * method has changed
+ */
+ cost = xfunc_total_path_cost(parentpath);
+ set_path_cost(parentpath, cost);
+
+ return (newinfo);
}
/*
- ** calculate (selectivity-1)/cost.
+ ** calculate (selectivity-1)/cost.
*/
-Cost xfunc_rank(Query *queryInfo,LispValue clause)
+Cost
+xfunc_rank(Query * queryInfo, LispValue clause)
{
- Cost selec = compute_clause_selec(queryInfo, clause, LispNil);
- Cost cost = xfunc_expense(queryInfo,clause);
-
- if (cost == 0)
- if (selec > 1) return(MAXFLOAT);
- else return(-(MAXFLOAT));
- return((selec - 1)/cost);
+ Cost selec = compute_clause_selec(queryInfo, clause, LispNil);
+ Cost cost = xfunc_expense(queryInfo, clause);
+
+ if (cost == 0)
+ if (selec > 1)
+ return (MAXFLOAT);
+ else
+ return (-(MAXFLOAT));
+ return ((selec - 1) / cost);
}
/*
@@ -340,91 +379,99 @@ Cost xfunc_rank(Query *queryInfo,LispValue clause)
** by the cardinalities of all the base relations of the query that are *not*
** referenced in the clause.
*/
-Cost xfunc_expense(Query* queryInfo, clause)
- LispValue clause;
+Cost
+xfunc_expense(Query * queryInfo, clause)
+LispValue clause;
{
- Cost cost = xfunc_local_expense(clause);
-
- if (cost)
+ Cost cost = xfunc_local_expense(clause);
+
+ if (cost)
{
- Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil);
- if (card)
- cost /= card;
+ Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil);
+
+ if (card)
+ cost /= card;
}
-
- return(cost);
+
+ return (cost);
}
/*
** xfunc_join_expense --
** Find global expense of a join clause
*/
-Cost xfunc_join_expense(Query *queryInfo, JoinPath path, int whichchild)
+Cost
+xfunc_join_expense(Query * queryInfo, JoinPath path, int whichchild)
{
- LispValue primjoinclause = xfunc_primary_join(path);
-
- /*
- ** the second argument to xfunc_card_unreferenced reflects all the
- ** relations involved in the join clause, i.e. all the relids in the Rel
- ** of the join clause
- */
- Count card = 0;
- Cost cost = xfunc_expense_per_tuple(path, whichchild);
-
- card = xfunc_card_unreferenced(queryInfo,
- primjoinclause,
- get_relids(get_parent(path)));
- if (primjoinclause)
- cost += xfunc_local_expense(primjoinclause);
-
- if (card) cost /= card;
-
- return(cost);
+ LispValue primjoinclause = xfunc_primary_join(path);
+
+ /*
+ * * the second argument to xfunc_card_unreferenced reflects all the *
+ * relations involved in the join clause, i.e. all the relids in the
+ * Rel * of the join clause
+ */
+ Count card = 0;
+ Cost cost = xfunc_expense_per_tuple(path, whichchild);
+
+ card = xfunc_card_unreferenced(queryInfo,
+ primjoinclause,
+ get_relids(get_parent(path)));
+ if (primjoinclause)
+ cost += xfunc_local_expense(primjoinclause);
+
+ if (card)
+ cost /= card;
+
+ return (cost);
}
/*
** Recursively find the per-tuple expense of a clause. See
** xfunc_func_expense for more discussion.
*/
-Cost xfunc_local_expense(LispValue clause)
+Cost
+xfunc_local_expense(LispValue clause)
{
- Cost cost = 0; /* running expense */
- LispValue tmpclause;
-
- /* First handle the base case */
- if (IsA(clause,Const) || IsA(clause,Var) || IsA(clause,Param))
- return(0);
- /* now other stuff */
- else if (IsA(clause,Iter))
- /* Too low. Should multiply by the expected number of iterations. */
- return(xfunc_local_expense(get_iterexpr((Iter)clause)));
- else if (IsA(clause,ArrayRef))
- return(xfunc_local_expense(get_refexpr((ArrayRef)clause)));
- else if (fast_is_clause(clause))
- return(xfunc_func_expense((LispValue)get_op(clause),
- (LispValue)get_opargs(clause)));
- else if (fast_is_funcclause(clause))
- return(xfunc_func_expense((LispValue)get_function(clause),
- (LispValue)get_funcargs(clause)));
- else if (fast_not_clause(clause))
- return(xfunc_local_expense(lsecond(clause)));
- else if (fast_or_clause(clause)) {
- /* find cost of evaluating each disjunct */
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- cost += xfunc_local_expense(lfirst(tmpclause));
- return(cost);
- }else {
- elog(WARN, "Clause node of undetermined type");
- return(-1);
- }
+ Cost cost = 0; /* running expense */
+ LispValue tmpclause;
+
+ /* First handle the base case */
+ if (IsA(clause, Const) || IsA(clause, Var) || IsA(clause, Param))
+ return (0);
+ /* now other stuff */
+ else if (IsA(clause, Iter))
+ /* Too low. Should multiply by the expected number of iterations. */
+ return (xfunc_local_expense(get_iterexpr((Iter) clause)));
+ else if (IsA(clause, ArrayRef))
+ return (xfunc_local_expense(get_refexpr((ArrayRef) clause)));
+ else if (fast_is_clause(clause))
+ return (xfunc_func_expense((LispValue) get_op(clause),
+ (LispValue) get_opargs(clause)));
+ else if (fast_is_funcclause(clause))
+ return (xfunc_func_expense((LispValue) get_function(clause),
+ (LispValue) get_funcargs(clause)));
+ else if (fast_not_clause(clause))
+ return (xfunc_local_expense(lsecond(clause)));
+ else if (fast_or_clause(clause))
+ {
+ /* find cost of evaluating each disjunct */
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ cost += xfunc_local_expense(lfirst(tmpclause));
+ return (cost);
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return (-1);
+ }
}
/*
** xfunc_func_expense --
** given a Func or Oper and its args, find its expense.
** Note: in Stonebraker's SIGMOD '91 paper, he uses a more complicated metric
- ** than the one here. We can ignore the expected number of tuples for
+ ** than the one here. We can ignore the expected number of tuples for
** our calculations; we just need the per-tuple expense. But he also
** proposes components to take into account the costs of accessing disk and
** archive. We didn't adopt that scheme here; eventually the vacuum
@@ -434,268 +481,323 @@ Cost xfunc_local_expense(LispValue clause)
** accessing secondary or tertiary storage, since we don't have sufficient
** stats to do it right.
*/
-Cost xfunc_func_expense(LispValue node, LispValue args)
+Cost
+xfunc_func_expense(LispValue node, LispValue args)
{
- HeapTuple tupl; /* the pg_proc tuple for each function */
- Form_pg_proc proc; /* a data structure to hold the pg_proc tuple */
- int width = 0; /* byte width of the field referenced by each clause */
- RegProcedure funcid; /* ID of function associate with node */
- Cost cost = 0; /* running expense */
- LispValue tmpclause;
- LispValue operand; /* one operand of an operator */
-
- if (IsA(node,Oper)) {
- /* don't trust the opid in the Oper node. Use the opno. */
- if (!(funcid = get_opcode(get_opno((Oper)node))))
- elog(WARN, "Oper's function is undefined");
- }else {
- funcid = get_funcid((Func)node);
- }
-
- /* look up tuple in cache */
- tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d", funcid);
- proc = (Form_pg_proc) GETSTRUCT(tupl);
-
- /*
- ** if it's a Postquel function, its cost is stored in the
- ** associated plan.
- */
- if (proc->prolang == SQLlanguageId) {
- LispValue tmpplan;
- List planlist;
-
- if (IsA(node,Oper) || get_func_planlist((Func)node) == LispNil) {
- Oid *argOidVect; /* vector of argtypes */
- char *pq_src; /* text of PQ function */
- int nargs; /* num args to PQ function */
- QueryTreeList *queryTree_list; /* dummy variable */
-
- /*
- ** plan the function, storing it in the Func node for later
- ** use by the executor.
- */
- pq_src = (char *) textout(&(proc->prosrc));
- nargs = proc->pronargs;
- if (nargs > 0)
- argOidVect = proc->proargtypes;
- planlist = (List)pg_plan(pq_src, argOidVect, nargs,
- &parseTree_list, None);
- if (IsA(node,Func))
- set_func_planlist((Func)node, planlist);
-
- }else {/* plan has been cached inside the Func node already */
- planlist = get_func_planlist((Func)node);
+ HeapTuple tupl; /* the pg_proc tuple for each function */
+ Form_pg_proc proc; /* a data structure to hold the pg_proc
+ * tuple */
+ int width = 0; /* byte width of the field referenced by
+ * each clause */
+ RegProcedure funcid; /* ID of function associate with node */
+ Cost cost = 0; /* running expense */
+ LispValue tmpclause;
+ LispValue operand; /* one operand of an operator */
+
+ if (IsA(node, Oper))
+ {
+ /* don't trust the opid in the Oper node. Use the opno. */
+ if (!(funcid = get_opcode(get_opno((Oper) node))))
+ elog(WARN, "Oper's function is undefined");
}
-
- /*
- ** Return the sum of the costs of the plans (the PQ function
- ** may have many queries in its body).
- */
- foreach(tmpplan, planlist)
- cost += get_cost((Plan)lfirst(tmpplan));
- return(cost);
- }else { /* it's a C function */
+ else
+ {
+ funcid = get_funcid((Func) node);
+ }
+
+ /* look up tuple in cache */
+ tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d", funcid);
+ proc = (Form_pg_proc) GETSTRUCT(tupl);
+
/*
- ** find the cost of evaluating the function's arguments
- ** and the width of the operands
+ * * if it's a Postquel function, its cost is stored in the *
+ * associated plan.
*/
- for (tmpclause = args; tmpclause != LispNil;
- tmpclause = lnext(tmpclause)) {
-
- if ((operand = lfirst(tmpclause)) != LispNil) {
- cost += xfunc_local_expense(operand);
- width += xfunc_width(operand);
- }
+ if (proc->prolang == SQLlanguageId)
+ {
+ LispValue tmpplan;
+ List planlist;
+
+ if (IsA(node, Oper) || get_func_planlist((Func) node) == LispNil)
+ {
+ Oid *argOidVect; /* vector of argtypes */
+ char *pq_src; /* text of PQ function */
+ int nargs; /* num args to PQ function */
+ QueryTreeList *queryTree_list; /* dummy variable */
+
+ /*
+ * * plan the function, storing it in the Func node for later *
+ * use by the executor.
+ */
+ pq_src = (char *) textout(&(proc->prosrc));
+ nargs = proc->pronargs;
+ if (nargs > 0)
+ argOidVect = proc->proargtypes;
+ planlist = (List) pg_plan(pq_src, argOidVect, nargs,
+ &parseTree_list, None);
+ if (IsA(node, Func))
+ set_func_planlist((Func) node, planlist);
+
+ }
+ else
+ { /* plan has been cached inside the Func
+ * node already */
+ planlist = get_func_planlist((Func) node);
+ }
+
+ /*
+ * * Return the sum of the costs of the plans (the PQ function *
+ * may have many queries in its body).
+ */
+ foreach(tmpplan, planlist)
+ cost += get_cost((Plan) lfirst(tmpplan));
+ return (cost);
+ }
+ else
+ { /* it's a C function */
+
+ /*
+ * * find the cost of evaluating the function's arguments * and
+ * the width of the operands
+ */
+ for (tmpclause = args; tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ {
+
+ if ((operand = lfirst(tmpclause)) != LispNil)
+ {
+ cost += xfunc_local_expense(operand);
+ width += xfunc_width(operand);
+ }
+ }
+
+ /*
+ * * when stats become available, add in cost of accessing
+ * secondary * and tertiary storage here.
+ */
+ return (cost +
+ (Cost) proc->propercall_cpu +
+ (Cost) proc->properbyte_cpu * (Cost) proc->probyte_pct / 100.00 *
+ (Cost) width
+
+ /*
+ * Pct_of_obj_in_mem DISK_COST * proc->probyte_pct/100.00 * width
+ * Pct_of_obj_on_disk + ARCH_COST * proc->probyte_pct/100.00 *
+ * width Pct_of_obj_on_arch
+ */
+ );
}
-
- /*
- ** when stats become available, add in cost of accessing secondary
- ** and tertiary storage here.
- */
- return(cost +
- (Cost)proc->propercall_cpu +
- (Cost)proc->properbyte_cpu * (Cost)proc->probyte_pct/100.00 *
- (Cost)width
- /*
- * Pct_of_obj_in_mem
- DISK_COST * proc->probyte_pct/100.00 * width
- * Pct_of_obj_on_disk +
- ARCH_COST * proc->probyte_pct/100.00 * width
- * Pct_of_obj_on_arch
- */
- );
- }
}
-/*
+/*
** xfunc_width --
** recursively find the width of a expression
*/
-int xfunc_width(LispValue clause)
+int
+xfunc_width(LispValue clause)
{
- Relation rd; /* Relation Descriptor */
- HeapTuple tupl; /* structure to hold a cached tuple */
- TypeTupleForm type; /* structure to hold a type tuple */
- int retval = 0;
-
- if (IsA(clause,Const)) {
- /* base case: width is the width of this constant */
- retval = get_constlen((Const) clause);
- goto exit;
- }else if (IsA(clause,ArrayRef)) {
- /* base case: width is width of the refelem within the array */
- retval = get_refelemlength((ArrayRef)clause);
- goto exit;
- }else if (IsA(clause,Var)) {
- /* base case: width is width of this attribute */
- tupl = SearchSysCacheTuple(TYPOID,
- PointerGetDatum(get_vartype((Var)clause)),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for type %d",
- get_vartype((Var)clause));
- type = (TypeTupleForm) GETSTRUCT(tupl);
- if (get_varattno((Var)clause) == 0) {
- /* clause is a tuple. Get its width */
- rd = heap_open(type->typrelid);
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- }else {
- /* attribute is a base type */
- retval = type->typlen;
+ Relation rd; /* Relation Descriptor */
+ HeapTuple tupl; /* structure to hold a cached tuple */
+ TypeTupleForm type; /* structure to hold a type tuple */
+ int retval = 0;
+
+ if (IsA(clause, Const))
+ {
+ /* base case: width is the width of this constant */
+ retval = get_constlen((Const) clause);
+ goto exit;
}
- goto exit;
- }else if (IsA(clause,Param)) {
- if (typeid_get_relid(get_paramtype((Param)clause))) {
- /* Param node returns a tuple. Find its width */
- rd = heap_open(typeid_get_relid(get_paramtype((Param)clause)));
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- }else if (get_param_tlist((Param)clause) != LispNil) {
- /* Param node projects a complex type */
- Assert(length(get_param_tlist((Param)clause)) == 1); /* sanity */
- retval =
- xfunc_width((LispValue)
- get_expr(lfirst(get_param_tlist((Param)clause))));
- }else {
- /* Param node returns a base type */
- retval = tlen(get_id_type(get_paramtype((Param)clause)));
+ else if (IsA(clause, ArrayRef))
+ {
+ /* base case: width is width of the refelem within the array */
+ retval = get_refelemlength((ArrayRef) clause);
+ goto exit;
}
- goto exit;
- }else if (IsA(clause,Iter)) {
- /*
- ** An Iter returns a setof things, so return the width of a single
- ** thing.
- ** Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET FIXED,
- ** SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!!
- ** This whole Iter business is bogus, anyway.
- */
- retval = xfunc_width(get_iterexpr((Iter)clause));
- goto exit;
- }else if (fast_is_clause(clause)) {
- /*
- ** get function associated with this Oper, and treat this as
- ** a Func
- */
- tupl = SearchSysCacheTuple(OPROID,
- ObjectIdGetDatum(get_opno((Oper)get_op(clause))),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d",
- get_opno((Oper)get_op(clause)));
- return(xfunc_func_width
- ((RegProcedure)(((OperatorTupleForm)(GETSTRUCT(tupl)))->oprcode),
- (LispValue)get_opargs(clause)));
- }else if (fast_is_funcclause(clause)) {
- Func func = (Func)get_function(clause);
- if (get_func_tlist(func) != LispNil) {
- /* this function has a projection on it. Get the length
- of the projected attribute */
- Assert(length(get_func_tlist(func)) == 1); /* sanity */
- retval =
- xfunc_width((LispValue)
- get_expr(lfirst(get_func_tlist(func))));
- goto exit;
- }else {
- return(xfunc_func_width((RegProcedure)get_funcid(func),
- (LispValue)get_funcargs(clause)));
+ else if (IsA(clause, Var))
+ {
+ /* base case: width is width of this attribute */
+ tupl = SearchSysCacheTuple(TYPOID,
+ PointerGetDatum(get_vartype((Var) clause)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for type %d",
+ get_vartype((Var) clause));
+ type = (TypeTupleForm) GETSTRUCT(tupl);
+ if (get_varattno((Var) clause) == 0)
+ {
+ /* clause is a tuple. Get its width */
+ rd = heap_open(type->typrelid);
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ }
+ else
+ {
+ /* attribute is a base type */
+ retval = type->typlen;
+ }
+ goto exit;
+ }
+ else if (IsA(clause, Param))
+ {
+ if (typeid_get_relid(get_paramtype((Param) clause)))
+ {
+ /* Param node returns a tuple. Find its width */
+ rd = heap_open(typeid_get_relid(get_paramtype((Param) clause)));
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ }
+ else if (get_param_tlist((Param) clause) != LispNil)
+ {
+ /* Param node projects a complex type */
+ Assert(length(get_param_tlist((Param) clause)) == 1); /* sanity */
+ retval =
+ xfunc_width((LispValue)
+ get_expr(lfirst(get_param_tlist((Param) clause))));
+ }
+ else
+ {
+ /* Param node returns a base type */
+ retval = tlen(get_id_type(get_paramtype((Param) clause)));
+ }
+ goto exit;
+ }
+ else if (IsA(clause, Iter))
+ {
+
+ /*
+ * * An Iter returns a setof things, so return the width of a
+ * single * thing. * Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET
+ * FIXED, * SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! *
+ * This whole Iter business is bogus, anyway.
+ */
+ retval = xfunc_width(get_iterexpr((Iter) clause));
+ goto exit;
+ }
+ else if (fast_is_clause(clause))
+ {
+
+ /*
+ * * get function associated with this Oper, and treat this as * a
+ * Func
+ */
+ tupl = SearchSysCacheTuple(OPROID,
+ ObjectIdGetDatum(get_opno((Oper) get_op(clause))),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d",
+ get_opno((Oper) get_op(clause)));
+ return (xfunc_func_width
+ ((RegProcedure) (((OperatorTupleForm) (GETSTRUCT(tupl)))->oprcode),
+ (LispValue) get_opargs(clause)));
+ }
+ else if (fast_is_funcclause(clause))
+ {
+ Func func = (Func) get_function(clause);
+
+ if (get_func_tlist(func) != LispNil)
+ {
+
+ /*
+ * this function has a projection on it. Get the length of
+ * the projected attribute
+ */
+ Assert(length(get_func_tlist(func)) == 1); /* sanity */
+ retval =
+ xfunc_width((LispValue)
+ get_expr(lfirst(get_func_tlist(func))));
+ goto exit;
+ }
+ else
+ {
+ return (xfunc_func_width((RegProcedure) get_funcid(func),
+ (LispValue) get_funcargs(clause)));
+ }
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return (-1);
}
- }else {
- elog(WARN, "Clause node of undetermined type");
- return(-1);
- }
-
- exit:
- if (retval == -1)
- retval = VARLEN_DEFAULT;
- return(retval);
+
+exit:
+ if (retval == -1)
+ retval = VARLEN_DEFAULT;
+ return (retval);
}
/*
** xfunc_card_unreferenced:
- ** find all relations not referenced in clause, and multiply their
- ** cardinalities. Ignore relation of cardinality 0.
+ ** find all relations not referenced in clause, and multiply their
+ ** cardinalities. Ignore relation of cardinality 0.
** User may pass in referenced list, if they know it (useful
** for joins).
*/
-static Count
-xfunc_card_unreferenced(Query *queryInfo,
- LispValue clause, Relid referenced)
+static Count
+xfunc_card_unreferenced(Query * queryInfo,
+ LispValue clause, Relid referenced)
{
- Relid unreferenced, allrelids = LispNil;
- LispValue temp;
-
- /* find all relids of base relations referenced in query */
- foreach (temp,queryInfo->base_relation_list_)
+ Relid unreferenced,
+ allrelids = LispNil;
+ LispValue temp;
+
+ /* find all relids of base relations referenced in query */
+ foreach(temp, queryInfo->base_relation_list_)
{
- Assert(lnext(get_relids((Rel)lfirst(temp))) == LispNil);
- allrelids = lappend(allrelids,
- lfirst(get_relids((Rel)lfirst(temp))));
+ Assert(lnext(get_relids((Rel) lfirst(temp))) == LispNil);
+ allrelids = lappend(allrelids,
+ lfirst(get_relids((Rel) lfirst(temp))));
}
-
- /* find all relids referenced in query but not in clause */
- if (!referenced)
- referenced = xfunc_find_references(clause);
- unreferenced = set_difference(allrelids, referenced);
-
- return(xfunc_card_product(unreferenced));
+
+ /* find all relids referenced in query but not in clause */
+ if (!referenced)
+ referenced = xfunc_find_references(clause);
+ unreferenced = set_difference(allrelids, referenced);
+
+ return (xfunc_card_product(unreferenced));
}
/*
- ** xfunc_card_product
+ ** xfunc_card_product
** multiple together cardinalities of a list relations.
*/
-Count xfunc_card_product(Query *queryInfo, Relid relids)
+Count
+xfunc_card_product(Query * queryInfo, Relid relids)
{
- LispValue cinfonode;
- LispValue temp;
- Rel currel;
- Cost tuples;
- Count retval = 0;
-
- foreach(temp,relids) {
- currel = get_rel(lfirst(temp));
- tuples = get_tuples(currel);
-
- if (tuples) { /* not of cardinality 0 */
- /* factor in the selectivity of all zero-cost clauses */
- foreach (cinfonode, get_clauseinfo(currel)) {
- if (!xfunc_expense(queryInfo,get_clause((CInfo)lfirst(cinfonode))))
- tuples *=
- compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(cinfonode)),
- LispNil);
- }
-
- if (retval == 0) retval = tuples;
- else retval *= tuples;
+ LispValue cinfonode;
+ LispValue temp;
+ Rel currel;
+ Cost tuples;
+ Count retval = 0;
+
+ foreach(temp, relids)
+ {
+ currel = get_rel(lfirst(temp));
+ tuples = get_tuples(currel);
+
+ if (tuples)
+ { /* not of cardinality 0 */
+ /* factor in the selectivity of all zero-cost clauses */
+ foreach(cinfonode, get_clauseinfo(currel))
+ {
+ if (!xfunc_expense(queryInfo, get_clause((CInfo) lfirst(cinfonode))))
+ tuples *=
+ compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(cinfonode)),
+ LispNil);
+ }
+
+ if (retval == 0)
+ retval = tuples;
+ else
+ retval *= tuples;
+ }
}
- }
- if (retval == 0) retval = 1; /* saves caller from dividing by zero */
- return(retval);
+ if (retval == 0)
+ retval = 1; /* saves caller from dividing by zero */
+ return (retval);
}
@@ -703,48 +805,60 @@ Count xfunc_card_product(Query *queryInfo, Relid relids)
** xfunc_find_references:
** Traverse a clause and find all relids referenced in the clause.
*/
-List xfunc_find_references(LispValue clause)
+List
+xfunc_find_references(LispValue clause)
{
- List retval = (List)LispNil;
- LispValue tmpclause;
-
- /* Base cases */
- if (IsA(clause,Var))
- return(lispCons(lfirst(get_varid((Var)clause)), LispNil));
- else if (IsA(clause,Const) || IsA(clause,Param))
- return((List)LispNil);
-
- /* recursion */
- else if (IsA(clause,Iter))
- /* Too low. Should multiply by the expected number of iterations. maybe */
- return(xfunc_find_references(get_iterexpr((Iter)clause)));
- else if (IsA(clause,ArrayRef))
- return(xfunc_find_references(get_refexpr((ArrayRef)clause)));
- else if (fast_is_clause(clause)) {
- /* string together result of all operands of Oper */
- for (tmpclause = (LispValue)get_opargs(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else if (fast_is_funcclause(clause)) {
- /* string together result of all args of Func */
- for (tmpclause = (LispValue)get_funcargs(clause);
- tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else if (fast_not_clause(clause))
- return(xfunc_find_references(lsecond(clause)));
- else if (fast_or_clause(clause)) {
- /* string together result of all operands of OR */
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else {
- elog(WARN, "Clause node of undetermined type");
- return((List)LispNil);
- }
+ List retval = (List) LispNil;
+ LispValue tmpclause;
+
+ /* Base cases */
+ if (IsA(clause, Var))
+ return (lispCons(lfirst(get_varid((Var) clause)), LispNil));
+ else if (IsA(clause, Const) || IsA(clause, Param))
+ return ((List) LispNil);
+
+ /* recursion */
+ else if (IsA(clause, Iter))
+
+ /*
+ * Too low. Should multiply by the expected number of iterations.
+ * maybe
+ */
+ return (xfunc_find_references(get_iterexpr((Iter) clause)));
+ else if (IsA(clause, ArrayRef))
+ return (xfunc_find_references(get_refexpr((ArrayRef) clause)));
+ else if (fast_is_clause(clause))
+ {
+ /* string together result of all operands of Oper */
+ for (tmpclause = (LispValue) get_opargs(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else if (fast_is_funcclause(clause))
+ {
+ /* string together result of all args of Func */
+ for (tmpclause = (LispValue) get_funcargs(clause);
+ tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else if (fast_not_clause(clause))
+ return (xfunc_find_references(lsecond(clause)));
+ else if (fast_or_clause(clause))
+ {
+ /* string together result of all operands of OR */
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return ((List) LispNil);
+ }
}
/*
@@ -753,212 +867,219 @@ List xfunc_find_references(LispValue clause)
** min rank Hash or Merge clause, while for Nested Loop it's the
** min rank pathclause
*/
-LispValue xfunc_primary_join(JoinPath pathnode)
+LispValue
+xfunc_primary_join(JoinPath pathnode)
{
- LispValue joinclauselist = get_pathclauseinfo(pathnode);
- CInfo mincinfo;
- LispValue tmplist;
- LispValue minclause = LispNil;
- Cost minrank, tmprank;
-
- if (IsA(pathnode,MergePath))
+ LispValue joinclauselist = get_pathclauseinfo(pathnode);
+ CInfo mincinfo;
+ LispValue tmplist;
+ LispValue minclause = LispNil;
+ Cost minrank,
+ tmprank;
+
+ if (IsA(pathnode, MergePath))
{
- for(tmplist = get_path_mergeclauses((MergePath)pathnode),
- minclause = lfirst(tmplist),
- minrank = xfunc_rank(minclause);
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(lfirst(tmplist)))
- < minrank)
- {
- minrank = tmprank;
- minclause = lfirst(tmplist);
- }
- return(minclause);
+ for (tmplist = get_path_mergeclauses((MergePath) pathnode),
+ minclause = lfirst(tmplist),
+ minrank = xfunc_rank(minclause);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(lfirst(tmplist)))
+ < minrank)
+ {
+ minrank = tmprank;
+ minclause = lfirst(tmplist);
+ }
+ return (minclause);
}
- else if (IsA(pathnode,HashPath))
+ else if (IsA(pathnode, HashPath))
{
- for(tmplist = get_path_hashclauses((HashPath)pathnode),
- minclause = lfirst(tmplist),
- minrank = xfunc_rank(minclause);
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(lfirst(tmplist)))
- < minrank)
- {
- minrank = tmprank;
- minclause = lfirst(tmplist);
- }
- return(minclause);
+ for (tmplist = get_path_hashclauses((HashPath) pathnode),
+ minclause = lfirst(tmplist),
+ minrank = xfunc_rank(minclause);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(lfirst(tmplist)))
+ < minrank)
+ {
+ minrank = tmprank;
+ minclause = lfirst(tmplist);
+ }
+ return (minclause);
}
-
- /* if we drop through, it's nested loop join */
- if (joinclauselist == LispNil)
- return(LispNil);
-
- for(tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist),
- minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)));
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
- < minrank)
- {
- minrank = tmprank;
- mincinfo = (CInfo) lfirst(tmplist);
- }
- return((LispValue)get_clause(mincinfo));
+
+ /* if we drop through, it's nested loop join */
+ if (joinclauselist == LispNil)
+ return (LispNil);
+
+ for (tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist),
+ minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)));
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ < minrank)
+ {
+ minrank = tmprank;
+ mincinfo = (CInfo) lfirst(tmplist);
+ }
+ return ((LispValue) get_clause(mincinfo));
}
/*
** xfunc_get_path_cost
** get the expensive function costs of the path
*/
-Cost xfunc_get_path_cost(Query *queryInfo, Path pathnode)
+Cost
+xfunc_get_path_cost(Query * queryInfo, Path pathnode)
{
- Cost cost = 0;
- LispValue tmplist;
- Cost selec = 1.0;
-
- /*
- ** first add in the expensive local function costs.
- ** We ensure that the clauses are sorted by rank, so that we
- ** know (via selectivities) the number of tuples that will be checked
- ** by each function. If we're not doing any optimization of expensive
- ** functions, we don't sort.
- */
- if (XfuncMode != XFUNC_OFF)
- set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode),
- xfunc_cinfo_compare));
- for(tmplist = get_locclauseinfo(pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ Cost cost = 0;
+ LispValue tmplist;
+ Cost selec = 1.0;
+
+ /*
+ * * first add in the expensive local function costs. * We ensure that
+ * the clauses are sorted by rank, so that we * know (via
+ * selectivities) the number of tuples that will be checked * by each
+ * function. If we're not doing any optimization of expensive *
+ * functions, we don't sort.
+ */
+ if (XfuncMode != XFUNC_OFF)
+ set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode),
+ xfunc_cinfo_compare));
+ for (tmplist = get_locclauseinfo(pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist)))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(tmplist)),
- LispNil);
+ cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist)))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(tmplist)),
+ LispNil);
}
-
- /*
- ** Now add in any node-specific expensive function costs.
- ** Again, we must ensure that the clauses are sorted by rank.
- */
- if (IsA(pathnode,JoinPath))
+
+ /*
+ * * Now add in any node-specific expensive function costs. * Again,
+ * we must ensure that the clauses are sorted by rank.
+ */
+ if (IsA(pathnode, JoinPath))
{
- if (XfuncMode != XFUNC_OFF)
- set_pathclauseinfo((JoinPath)pathnode, lisp_qsort
- (get_pathclauseinfo((JoinPath)pathnode),
- xfunc_cinfo_compare));
- for(tmplist = get_pathclauseinfo((JoinPath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_pathclauseinfo((JoinPath) pathnode, lisp_qsort
+ (get_pathclauseinfo((JoinPath) pathnode),
+ xfunc_cinfo_compare));
+ for (tmplist = get_pathclauseinfo((JoinPath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist)))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(tmplist)),
- LispNil);
+ cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist)))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(tmplist)),
+ LispNil);
}
}
- if (IsA(pathnode,HashPath))
+ if (IsA(pathnode, HashPath))
{
- if (XfuncMode != XFUNC_OFF)
- set_path_hashclauses
- ((HashPath)pathnode,
- lisp_qsort(get_path_hashclauses((HashPath)pathnode),
- xfunc_clause_compare));
- for(tmplist = get_path_hashclauses((HashPath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_path_hashclauses
+ ((HashPath) pathnode,
+ lisp_qsort(get_path_hashclauses((HashPath) pathnode),
+ xfunc_clause_compare));
+ for (tmplist = get_path_hashclauses((HashPath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(lfirst(tmplist))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- lfirst(tmplist), LispNil);
+ cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ lfirst(tmplist), LispNil);
}
}
- if (IsA(pathnode,MergePath))
+ if (IsA(pathnode, MergePath))
{
- if (XfuncMode != XFUNC_OFF)
- set_path_mergeclauses
- ((MergePath)pathnode,
- lisp_qsort(get_path_mergeclauses((MergePath)pathnode),
- xfunc_clause_compare));
- for(tmplist = get_path_mergeclauses((MergePath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_path_mergeclauses
+ ((MergePath) pathnode,
+ lisp_qsort(get_path_mergeclauses((MergePath) pathnode),
+ xfunc_clause_compare));
+ for (tmplist = get_path_mergeclauses((MergePath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(lfirst(tmplist))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- lfirst(tmplist), LispNil);
+ cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ lfirst(tmplist), LispNil);
}
}
- Assert(cost >= 0);
- return(cost);
+ Assert(cost >= 0);
+ return (cost);
}
/*
- ** Recalculate the cost of a path node. This includes the basic cost of the
+ ** Recalculate the cost of a path node. This includes the basic cost of the
** node, as well as the cost of its expensive functions.
** We need to do this to the parent after pulling a clause from a child into a
** parent. Thus we should only be calling this function on JoinPaths.
*/
-Cost xfunc_total_path_cost(JoinPath pathnode)
+Cost
+xfunc_total_path_cost(JoinPath pathnode)
{
- Cost cost = xfunc_get_path_cost((Path)pathnode);
-
- Assert(IsA(pathnode,JoinPath));
- if (IsA(pathnode,MergePath))
+ Cost cost = xfunc_get_path_cost((Path) pathnode);
+
+ Assert(IsA(pathnode, JoinPath));
+ if (IsA(pathnode, MergePath))
{
- MergePath mrgnode = (MergePath)pathnode;
- cost += cost_mergesort(get_path_cost((Path)get_outerjoinpath(mrgnode)),
- get_path_cost((Path)get_innerjoinpath(mrgnode)),
- get_outersortkeys(mrgnode),
- get_innersortkeys(mrgnode),
- get_tuples(get_parent((Path)get_outerjoinpath
- (mrgnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (mrgnode))),
- get_width(get_parent((Path)get_outerjoinpath
- (mrgnode))),
- get_width(get_parent((Path)get_innerjoinpath
- (mrgnode))));
- Assert(cost >= 0);
- return(cost);
+ MergePath mrgnode = (MergePath) pathnode;
+
+ cost += cost_mergesort(get_path_cost((Path) get_outerjoinpath(mrgnode)),
+ get_path_cost((Path) get_innerjoinpath(mrgnode)),
+ get_outersortkeys(mrgnode),
+ get_innersortkeys(mrgnode),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (mrgnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (mrgnode))),
+ get_width(get_parent((Path) get_outerjoinpath
+ (mrgnode))),
+ get_width(get_parent((Path) get_innerjoinpath
+ (mrgnode))));
+ Assert(cost >= 0);
+ return (cost);
}
- else if (IsA(pathnode,HashPath))
+ else if (IsA(pathnode, HashPath))
{
- HashPath hashnode = (HashPath)pathnode;
- cost += cost_hashjoin(get_path_cost((Path)get_outerjoinpath(hashnode)),
- get_path_cost((Path)get_innerjoinpath(hashnode)),
- get_outerhashkeys(hashnode),
- get_innerhashkeys(hashnode),
- get_tuples(get_parent((Path)get_outerjoinpath
- (hashnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (hashnode))),
- get_width(get_parent((Path)get_outerjoinpath
- (hashnode))),
- get_width(get_parent((Path)get_innerjoinpath
- (hashnode))));
- Assert (cost >= 0);
- return(cost);
+ HashPath hashnode = (HashPath) pathnode;
+
+ cost += cost_hashjoin(get_path_cost((Path) get_outerjoinpath(hashnode)),
+ get_path_cost((Path) get_innerjoinpath(hashnode)),
+ get_outerhashkeys(hashnode),
+ get_innerhashkeys(hashnode),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (hashnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (hashnode))),
+ get_width(get_parent((Path) get_outerjoinpath
+ (hashnode))),
+ get_width(get_parent((Path) get_innerjoinpath
+ (hashnode))));
+ Assert(cost >= 0);
+ return (cost);
}
- else /* Nested Loop Join */
+ else
+/* Nested Loop Join */
{
- cost += cost_nestloop(get_path_cost((Path)get_outerjoinpath(pathnode)),
- get_path_cost((Path)get_innerjoinpath(pathnode)),
- get_tuples(get_parent((Path)get_outerjoinpath
- (pathnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (pathnode))),
- get_pages(get_parent((Path)get_outerjoinpath
- (pathnode))),
- IsA(get_innerjoinpath(pathnode),IndexPath));
- Assert(cost >= 0);
- return(cost);
+ cost += cost_nestloop(get_path_cost((Path) get_outerjoinpath(pathnode)),
+ get_path_cost((Path) get_innerjoinpath(pathnode)),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (pathnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (pathnode))),
+ get_pages(get_parent((Path) get_outerjoinpath
+ (pathnode))),
+ IsA(get_innerjoinpath(pathnode), IndexPath));
+ Assert(cost >= 0);
+ return (cost);
}
}
@@ -967,7 +1088,7 @@ Cost xfunc_total_path_cost(JoinPath pathnode)
** xfunc_expense_per_tuple --
** return the expense of the join *per-tuple* of the input relation.
** The cost model here is that a join costs
- ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n
+ ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n
**
** We treat the l and m terms by considering them to be like restrictions
** constrained to be right under the join. Thus the cost per inner and
@@ -975,138 +1096,146 @@ Cost xfunc_total_path_cost(JoinPath pathnode)
**
** The cost per tuple of outer is k + l/referenced(inner). Cost per tuple
** of inner is k + m/referenced(outer).
- ** The constants k, l, m and n depend on the join method. Measures here are
+ ** The constants k, l, m and n depend on the join method. Measures here are
** based on the costs in costsize.c, with fudging for HashJoin and Sorts to
** make it fit our model (the 'q' in HashJoin results in a
** card(outer)/card(inner) term, and sorting results in a log term.
-
+
*/
-Cost xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
+Cost
+xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
{
- Rel outerrel = get_parent((Path)get_outerjoinpath(joinnode));
- Rel innerrel = get_parent((Path)get_innerjoinpath(joinnode));
- Count outerwidth = get_width(outerrel);
- Count outers_per_page = ceil(BLCKSZ/(outerwidth + sizeof(HeapTupleData)));
-
- if (IsA(joinnode,HashPath))
+ Rel outerrel = get_parent((Path) get_outerjoinpath(joinnode));
+ Rel innerrel = get_parent((Path) get_innerjoinpath(joinnode));
+ Count outerwidth = get_width(outerrel);
+ Count outers_per_page = ceil(BLCKSZ / (outerwidth + sizeof(HeapTupleData)));
+
+ if (IsA(joinnode, HashPath))
{
- if (whichchild == INNER)
- return((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers);
- else
- return(((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers)
- + _CPU_PAGE_WEIGHT_
- / xfunc_card_product(get_relids(innerrel)));
+ if (whichchild == INNER)
+ return ((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers);
+ else
+ return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers)
+ + _CPU_PAGE_WEIGHT_
+ / xfunc_card_product(get_relids(innerrel)));
}
- else if (IsA(joinnode,MergePath))
+ else if (IsA(joinnode, MergePath))
{
- /* assumes sort exists, and costs one (I/O + CPU) per tuple */
- if (whichchild == INNER)
- return((2*_CPU_PAGE_WEIGHT_ + 1)
- / xfunc_card_product(get_relids(outerrel)));
- else
- return((2*_CPU_PAGE_WEIGHT_ + 1)
- / xfunc_card_product(get_relids(innerrel)));
+ /* assumes sort exists, and costs one (I/O + CPU) per tuple */
+ if (whichchild == INNER)
+ return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ / xfunc_card_product(get_relids(outerrel)));
+ else
+ return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ / xfunc_card_product(get_relids(innerrel)));
}
- else /* nestloop */
+ else
+/* nestloop */
{
- Assert(IsA(joinnode,JoinPath));
- return(_CPU_PAGE_WEIGHT_);
+ Assert(IsA(joinnode, JoinPath));
+ return (_CPU_PAGE_WEIGHT_);
}
}
/*
** xfunc_fixvars --
- ** After pulling up a clause, we must walk its expression tree, fixing Var
+ ** After pulling up a clause, we must walk its expression tree, fixing Var
** nodes to point to the correct varno (either INNER or OUTER, depending
- ** on which child the clause was pulled from), and the right varattno in the
+ ** on which child the clause was pulled from), and the right varattno in the
** target list of the child's former relation. If the target list of the
** child Rel does not contain the attribute we need, we add it.
*/
-void xfunc_fixvars(LispValue clause, /* clause being pulled up */
- Rel rel, /* rel it's being pulled from */
- int varno) /* whether rel is INNER or OUTER of join */
+void
+xfunc_fixvars(LispValue clause, /* clause being pulled up */
+ Rel rel, /* rel it's being pulled from */
+ int varno) /* whether rel is INNER or OUTER of join */
{
- LispValue tmpclause; /* temporary variable */
- TargetEntry *tle; /* tlist member corresponding to var */
-
-
- if (IsA(clause,Const) || IsA(clause,Param)) return;
- else if (IsA(clause,Var))
+ LispValue tmpclause; /* temporary variable */
+ TargetEntry *tle; /* tlist member corresponding to var */
+
+
+ if (IsA(clause, Const) || IsA(clause, Param))
+ return;
+ else if (IsA(clause, Var))
{
- /* here's the meat */
- tle = tlistentry_member((Var)clause, get_targetlist(rel));
- if (tle == LispNil)
+ /* here's the meat */
+ tle = tlistentry_member((Var) clause, get_targetlist(rel));
+ if (tle == LispNil)
{
- /*
- ** The attribute we need is not in the target list,
- ** so we have to add it.
- **
- */
- add_tl_element(rel, (Var)clause);
- tle = tlistentry_member((Var)clause, get_targetlist(rel));
+
+ /*
+ * * The attribute we need is not in the target list, * so we
+ * have to add it. *
+ *
+ */
+ add_tl_element(rel, (Var) clause);
+ tle = tlistentry_member((Var) clause, get_targetlist(rel));
}
- set_varno(((Var)clause), varno);
- set_varattno(((Var)clause), get_resno(get_resdom(get_entry(tle))));
+ set_varno(((Var) clause), varno);
+ set_varattno(((Var) clause), get_resno(get_resdom(get_entry(tle))));
}
- else if (IsA(clause,Iter))
- xfunc_fixvars(get_iterexpr((Iter)clause), rel, varno);
- else if (fast_is_clause(clause))
+ else if (IsA(clause, Iter))
+ xfunc_fixvars(get_iterexpr((Iter) clause), rel, varno);
+ else if (fast_is_clause(clause))
{
- xfunc_fixvars(lfirst(lnext(clause)), rel, varno);
- xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno);
+ xfunc_fixvars(lfirst(lnext(clause)), rel, varno);
+ xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno);
}
- else if (fast_is_funcclause(clause))
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- xfunc_fixvars(lfirst(tmpclause), rel, varno);
- else if (fast_not_clause(clause))
- xfunc_fixvars(lsecond(clause), rel, varno);
- else if (fast_or_clause(clause))
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- xfunc_fixvars(lfirst(tmpclause), rel, varno);
- else
+ else if (fast_is_funcclause(clause))
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ xfunc_fixvars(lfirst(tmpclause), rel, varno);
+ else if (fast_not_clause(clause))
+ xfunc_fixvars(lsecond(clause), rel, varno);
+ else if (fast_or_clause(clause))
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ xfunc_fixvars(lfirst(tmpclause), rel, varno);
+ else
{
- elog(WARN, "Clause node of undetermined type");
+ elog(WARN, "Clause node of undetermined type");
}
}
/*
** Comparison function for lisp_qsort() on a list of CInfo's.
- ** arg1 and arg2 should really be of type (CInfo *).
+ ** arg1 and arg2 should really be of type (CInfo *).
*/
-int xfunc_cinfo_compare(void *arg1, void *arg2)
+int
+xfunc_cinfo_compare(void *arg1, void *arg2)
{
- CInfo info1 = *(CInfo *) arg1;
- CInfo info2 = *(CInfo *) arg2;
-
- LispValue clause1 = (LispValue) get_clause(info1),
- clause2 = (LispValue) get_clause(info2);
-
- return(xfunc_clause_compare((void *) &clause1, (void *) &clause2));
+ CInfo info1 = *(CInfo *) arg1;
+ CInfo info2 = *(CInfo *) arg2;
+
+ LispValue clause1 = (LispValue) get_clause(info1),
+ clause2 = (LispValue) get_clause(info2);
+
+ return (xfunc_clause_compare((void *) &clause1, (void *) &clause2));
}
/*
- ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two
+ ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two
** clauses based on expense/(1 - selectivity)
** arg1 and arg2 are really pointers to clauses.
*/
-int xfunc_clause_compare(void *arg1, void *arg2)
+int
+xfunc_clause_compare(void *arg1, void *arg2)
{
- LispValue clause1 = *(LispValue *) arg1;
- LispValue clause2 = *(LispValue *) arg2;
- Cost rank1, /* total xfunc rank of clause1 */
- rank2; /* total xfunc rank of clause2 */
-
- rank1 = xfunc_rank(clause1);
- rank2 = xfunc_rank(clause2);
-
- if ( rank1 < rank2)
- return(-1);
- else if (rank1 == rank2)
- return(0);
- else return(1);
+ LispValue clause1 = *(LispValue *) arg1;
+ LispValue clause2 = *(LispValue *) arg2;
+ Cost rank1, /* total xfunc rank of clause1 */
+ rank2; /* total xfunc rank of clause2 */
+
+ rank1 = xfunc_rank(clause1);
+ rank2 = xfunc_rank(clause2);
+
+ if (rank1 < rank2)
+ return (-1);
+ else if (rank1 == rank2)
+ return (0);
+ else
+ return (1);
}
/*
@@ -1115,58 +1244,62 @@ int xfunc_clause_compare(void *arg1, void *arg2)
** (this assumes the predicates have been converted to Conjunctive NF)
** Modifies the clause list!
*/
-void xfunc_disjunct_sort(LispValue clause_list)
+void
+xfunc_disjunct_sort(LispValue clause_list)
{
- LispValue temp;
-
- foreach(temp, clause_list)
- if(or_clause(lfirst(temp)))
- lnext(lfirst(temp)) =
- lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);
+ LispValue temp;
+
+ foreach(temp, clause_list)
+ if (or_clause(lfirst(temp)))
+ lnext(lfirst(temp)) =
+ lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);
}
/*
- ** xfunc_disjunct_compare: comparison function for qsort() that compares two
+ ** xfunc_disjunct_compare: comparison function for qsort() that compares two
** disjuncts based on cost/selec.
** arg1 and arg2 are really pointers to disjuncts
*/
-int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2)
+int
+xfunc_disjunct_compare(Query * queryInfo, void *arg1, void *arg2)
{
- LispValue disjunct1 = *(LispValue *) arg1;
- LispValue disjunct2 = *(LispValue *) arg2;
- Cost cost1, /* total cost of disjunct1 */
- cost2, /* total cost of disjunct2 */
- selec1,
- selec2;
- Cost rank1, rank2;
-
- cost1 = xfunc_expense(queryInfo, disjunct1);
- cost2 = xfunc_expense(queryInfo, disjunct2);
- selec1 = compute_clause_selec(queryInfo,
- disjunct1, LispNil);
- selec2 = compute_clause_selec(queryInfo,
- disjunct2, LispNil);
-
- if (selec1 == 0)
- rank1 = MAXFLOAT;
- else if (cost1 == 0)
- rank1 = 0;
- else
- rank1 = cost1/selec1;
-
- if (selec2 == 0)
- rank2 = MAXFLOAT;
- else if (cost2 == 0)
- rank2 = 0;
- else
- rank2 = cost2/selec2;
-
- if ( rank1 < rank2)
- return(-1);
- else if (rank1 == rank2)
- return(0);
- else return(1);
+ LispValue disjunct1 = *(LispValue *) arg1;
+ LispValue disjunct2 = *(LispValue *) arg2;
+ Cost cost1, /* total cost of disjunct1 */
+ cost2, /* total cost of disjunct2 */
+ selec1,
+ selec2;
+ Cost rank1,
+ rank2;
+
+ cost1 = xfunc_expense(queryInfo, disjunct1);
+ cost2 = xfunc_expense(queryInfo, disjunct2);
+ selec1 = compute_clause_selec(queryInfo,
+ disjunct1, LispNil);
+ selec2 = compute_clause_selec(queryInfo,
+ disjunct2, LispNil);
+
+ if (selec1 == 0)
+ rank1 = MAXFLOAT;
+ else if (cost1 == 0)
+ rank1 = 0;
+ else
+ rank1 = cost1 / selec1;
+
+ if (selec2 == 0)
+ rank2 = MAXFLOAT;
+ else if (cost2 == 0)
+ rank2 = 0;
+ else
+ rank2 = cost2 / selec2;
+
+ if (rank1 < rank2)
+ return (-1);
+ else if (rank1 == rank2)
+ return (0);
+ else
+ return (1);
}
/* ------------------------ UTILITY FUNCTIONS ------------------------------- */
@@ -1174,182 +1307,197 @@ int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2)
** xfunc_func_width --
** Given a function OID and operands, find the width of the return value.
*/
-int xfunc_func_width(RegProcedure funcid, LispValue args)
+int
+xfunc_func_width(RegProcedure funcid, LispValue args)
{
- Relation rd; /* Relation Descriptor */
- HeapTuple tupl; /* structure to hold a cached tuple */
- Form_pg_proc proc; /* structure to hold the pg_proc tuple */
- TypeTupleForm type; /* structure to hold the pg_type tuple */
- LispValue tmpclause;
- int retval;
-
- /* lookup function and find its return type */
- Assert(RegProcedureIsValid(funcid));
- tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d", funcid);
- proc = (Form_pg_proc) GETSTRUCT(tupl);
-
- /* if function returns a tuple, get the width of that */
- if (typeid_get_relid(proc->prorettype))
+ Relation rd; /* Relation Descriptor */
+ HeapTuple tupl; /* structure to hold a cached tuple */
+ Form_pg_proc proc; /* structure to hold the pg_proc tuple */
+ TypeTupleForm type; /* structure to hold the pg_type tuple */
+ LispValue tmpclause;
+ int retval;
+
+ /* lookup function and find its return type */
+ Assert(RegProcedureIsValid(funcid));
+ tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d", funcid);
+ proc = (Form_pg_proc) GETSTRUCT(tupl);
+
+ /* if function returns a tuple, get the width of that */
+ if (typeid_get_relid(proc->prorettype))
{
- rd = heap_open(typeid_get_relid(proc->prorettype));
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- goto exit;
+ rd = heap_open(typeid_get_relid(proc->prorettype));
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ goto exit;
}
- else /* function returns a base type */
+ else
+/* function returns a base type */
{
- tupl = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(proc->prorettype),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for type %d", proc->prorettype);
- type = (TypeTupleForm) GETSTRUCT(tupl);
- /* if the type length is known, return that */
- if (type->typlen != -1)
+ tupl = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(proc->prorettype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for type %d", proc->prorettype);
+ type = (TypeTupleForm) GETSTRUCT(tupl);
+ /* if the type length is known, return that */
+ if (type->typlen != -1)
{
- retval = type->typlen;
- goto exit;
+ retval = type->typlen;
+ goto exit;
}
- else /* estimate the return size */
+ else
+/* estimate the return size */
{
- /* find width of the function's arguments */
- for (tmpclause = args; tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval += xfunc_width(lfirst(tmpclause));
- /* multiply by outin_ratio */
- retval = (int)(proc->prooutin_ratio/100.0 * retval);
- goto exit;
+ /* find width of the function's arguments */
+ for (tmpclause = args; tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval += xfunc_width(lfirst(tmpclause));
+ /* multiply by outin_ratio */
+ retval = (int) (proc->prooutin_ratio / 100.0 * retval);
+ goto exit;
}
}
- exit:
- return(retval);
+exit:
+ return (retval);
}
/*
** xfunc_tuple_width --
- ** Return the sum of the lengths of all the attributes of a given relation
+ ** Return the sum of the lengths of all the attributes of a given relation
*/
-int xfunc_tuple_width(Relation rd)
+int
+xfunc_tuple_width(Relation rd)
{
- int i;
- int retval = 0;
- TupleDesc tdesc = RelationGetTupleDescriptor(rd);
-
- for (i = 0; i < tdesc->natts; i++)
+ int i;
+ int retval = 0;
+ TupleDesc tdesc = RelationGetTupleDescriptor(rd);
+
+ for (i = 0; i < tdesc->natts; i++)
{
- if (tdesc->attrs[i]->attlen != -1)
- retval += tdesc->attrs[i]->attlen;
- else retval += VARLEN_DEFAULT;
+ if (tdesc->attrs[i]->attlen != -1)
+ retval += tdesc->attrs[i]->attlen;
+ else
+ retval += VARLEN_DEFAULT;
}
-
- return(retval);
+
+ return (retval);
}
/*
** xfunc_num_join_clauses --
** Find the number of join clauses associated with this join path
*/
-int xfunc_num_join_clauses(JoinPath path)
+int
+xfunc_num_join_clauses(JoinPath path)
{
- int num = length(get_pathclauseinfo(path));
- if (IsA(path,MergePath))
- return(num + length(get_path_mergeclauses((MergePath)path)));
- else if (IsA(path,HashPath))
- return(num + length(get_path_hashclauses((HashPath)path)));
- else return(num);
+ int num = length(get_pathclauseinfo(path));
+
+ if (IsA(path, MergePath))
+ return (num + length(get_path_mergeclauses((MergePath) path)));
+ else if (IsA(path, HashPath))
+ return (num + length(get_path_hashclauses((HashPath) path)));
+ else
+ return (num);
}
/*
** xfunc_LispRemove --
** Just like LispRemove, but it whines if the item to be removed ain't there
*/
-LispValue xfunc_LispRemove(LispValue foo, List bar)
+LispValue
+xfunc_LispRemove(LispValue foo, List bar)
{
- LispValue temp = LispNil;
- LispValue result = LispNil;
- int sanity = false;
-
- for (temp = bar; !null(temp); temp = lnext(temp))
- if (! equal((Node)(foo),(Node)(lfirst(temp))) )
- {
- result = lappend(result,lfirst(temp));
- }
- else sanity = true; /* found a matching item to remove! */
-
- if (!sanity)
- elog(WARN, "xfunc_LispRemove: didn't find a match!");
-
- return(result);
+ LispValue temp = LispNil;
+ LispValue result = LispNil;
+ int sanity = false;
+
+ for (temp = bar; !null(temp); temp = lnext(temp))
+ if (!equal((Node) (foo), (Node) (lfirst(temp))))
+ {
+ result = lappend(result, lfirst(temp));
+ }
+ else
+ sanity = true; /* found a matching item to remove! */
+
+ if (!sanity)
+ elog(WARN, "xfunc_LispRemove: didn't find a match!");
+
+ return (result);
}
#define Node_Copy(a, b, c, d) \
- if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \
- return false; \
- }
+ if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \
+ return false; \
+ }
/*
** xfunc_copyrel --
** Just like _copyRel, but doesn't copy the paths
*/
-bool xfunc_copyrel(Rel from, Rel *to)
+bool
+xfunc_copyrel(Rel from, Rel * to)
{
- Rel newnode;
- Pointer (*alloc)() = palloc;
-
- /* COPY_CHECKARGS() */
- if (to == NULL)
- {
- return false;
- }
-
- /* COPY_CHECKNULL() */
- if (from == NULL)
+ Rel newnode;
+
+ Pointer(*alloc) () = palloc;
+
+ /* COPY_CHECKARGS() */
+ if (to == NULL)
+ {
+ return false;
+ }
+
+ /* COPY_CHECKNULL() */
+ if (from == NULL)
{
- (*to) = NULL;
- return true;
- }
-
- /* COPY_NEW(c) */
- newnode = (Rel)(*alloc)(classSize(Rel));
- if (newnode == NULL)
- {
- return false;
- }
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyNodeFields((Node)from, (Node)newnode, alloc);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, alloc, relids);
-
- newnode->indexed = from->indexed;
- newnode->pages = from->pages;
- newnode->tuples = from->tuples;
- newnode->size = from->size;
- newnode->width = from->width;
-
- Node_Copy(from, newnode, alloc, targetlist);
- /* No!!!! Node_Copy(from, newnode, alloc, pathlist);
- Node_Copy(from, newnode, alloc, unorderedpath);
- Node_Copy(from, newnode, alloc, cheapestpath); */
-#if 0 /* can't use Node_copy now. 2/95 -ay */
- Node_Copy(from, newnode, alloc, classlist);
- Node_Copy(from, newnode, alloc, indexkeys);
- Node_Copy(from, newnode, alloc, ordering);
+ (*to) = NULL;
+ return true;
+ }
+
+ /* COPY_NEW(c) */
+ newnode = (Rel) (*alloc) (classSize(Rel));
+ if (newnode == NULL)
+ {
+ return false;
+ }
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyNodeFields((Node) from, (Node) newnode, alloc);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, alloc, relids);
+
+ newnode->indexed = from->indexed;
+ newnode->pages = from->pages;
+ newnode->tuples = from->tuples;
+ newnode->size = from->size;
+ newnode->width = from->width;
+
+ Node_Copy(from, newnode, alloc, targetlist);
+
+ /*
+ * No!!!! Node_Copy(from, newnode, alloc, pathlist);
+ * Node_Copy(from, newnode, alloc, unorderedpath); Node_Copy(from,
+ * newnode, alloc, cheapestpath);
+ */
+#if 0 /* can't use Node_copy now. 2/95 -ay */
+ Node_Copy(from, newnode, alloc, classlist);
+ Node_Copy(from, newnode, alloc, indexkeys);
+ Node_Copy(from, newnode, alloc, ordering);
#endif
- Node_Copy(from, newnode, alloc, clauseinfo);
- Node_Copy(from, newnode, alloc, joininfo);
- Node_Copy(from, newnode, alloc, innerjoin);
- Node_Copy(from, newnode, alloc, superrels);
-
- (*to) = newnode;
- return true;
+ Node_Copy(from, newnode, alloc, clauseinfo);
+ Node_Copy(from, newnode, alloc, joininfo);
+ Node_Copy(from, newnode, alloc, innerjoin);
+ Node_Copy(from, newnode, alloc, superrels);
+
+ (*to) = newnode;
+ return true;
}