aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/predmig.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/predmig.c')
-rw-r--r--src/backend/optimizer/path/predmig.c1064
1 files changed, 557 insertions, 507 deletions
diff --git a/src/backend/optimizer/path/predmig.c b/src/backend/optimizer/path/predmig.c
index 241ab4a12d7..c302af3b581 100644
--- a/src/backend/optimizer/path/predmig.c
+++ b/src/backend/optimizer/path/predmig.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* predmig.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.2 1996/10/23 07:14:41 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.3 1997/09/07 04:43:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,23 +16,23 @@
** Main Routines to handle Predicate Migration (i.e. correct optimization
** of queries with expensive functions.)
**
-** The reasoning behind some of these algorithms is rather detailed.
-** Have a look at Sequoia Tech Report 92/13 for more info. Also
+** The reasoning behind some of these algorithms is rather detailed.
+** Have a look at Sequoia Tech Report 92/13 for more info. Also
** see Monma and Sidney's paper "Sequencing with Series-Parallel
** Precedence Constraints", in "Mathematics of Operations Research",
** volume 4 (1979), pp. 215-224.
**
-** The main thing that this code does that wasn't handled in xfunc.c is
+** The main thing that this code does that wasn't handled in xfunc.c is
** it considers the possibility that two joins in a stream may not
** be ordered by ascending rank -- in such a scenario, it may be optimal
** to pullup more restrictions than we did via xfunc_try_pullup.
**
-** This code in some sense generalizes xfunc_try_pullup; if you
+** This code in some sense generalizes xfunc_try_pullup; if you
** run postgres -x noprune, you'll turn off xfunc_try_pullup, and this
** code will do everything that xfunc_try_pullup would have, and maybe
-** more. However, this results in no pruning, which may slow down the
+** more. However, this results in no pruning, which may slow down the
** optimizer and/or cause the system to run out of memory.
-** -- JMH, 11/13/92
+** -- JMH, 11/13/92
*/
#include "nodes/pg_list.h"
@@ -49,331 +49,350 @@
#include "optimizer/tlist.h"
#include "lib/qsort.h"
-#define is_clause(node) (get_cinfo(node)) /* a stream node represents a
- clause (not a join) iff it
- has a non-NULL cinfo field */
-
-static void xfunc_predmig(JoinPath pathnode, Stream streamroot,
- Stream laststream, bool *progressp);
-static bool xfunc_series_llel(Stream stream);
-static bool xfunc_llel_chains(Stream root, Stream bottom);
-static Stream xfunc_complete_stream(Stream stream);
-static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme,
- JoinPath joinpath);
-static void xfunc_form_groups(Stream root, Stream bottom);
-static void xfunc_free_stream(Stream root);
-static Stream xfunc_add_clauses(Stream current);
-static void xfunc_setup_group(Stream node, Stream bottom);
-static Stream xfunc_streaminsert(CInfo clauseinfo, Stream current,
- int clausetype);
-static int xfunc_num_relids(Stream node);
+#define is_clause(node) (get_cinfo(node)) /* a stream node
+ * represents a clause
+ * (not a join) iff it has
+ * a non-NULL cinfo field */
+
+static void
+xfunc_predmig(JoinPath pathnode, Stream streamroot,
+ Stream laststream, bool * progressp);
+static bool xfunc_series_llel(Stream stream);
+static bool xfunc_llel_chains(Stream root, Stream bottom);
+static Stream xfunc_complete_stream(Stream stream);
+static bool
+xfunc_prdmig_pullup(Stream origstream, Stream pullme,
+ JoinPath joinpath);
+static void xfunc_form_groups(Stream root, Stream bottom);
+static void xfunc_free_stream(Stream root);
+static Stream xfunc_add_clauses(Stream current);
+static void xfunc_setup_group(Stream node, Stream bottom);
+static Stream
+xfunc_streaminsert(CInfo clauseinfo, Stream current,
+ int clausetype);
+static int xfunc_num_relids(Stream node);
static StreamPtr xfunc_get_downjoin(Stream node);
static StreamPtr xfunc_get_upjoin(Stream node);
-static Stream xfunc_stream_qsort(Stream root, Stream bottom);
-static int xfunc_stream_compare(void *arg1, void *arg2);
-static bool xfunc_check_stream(Stream node);
-static bool xfunc_in_stream(Stream node, Stream stream);
+static Stream xfunc_stream_qsort(Stream root, Stream bottom);
+static int xfunc_stream_compare(void *arg1, void *arg2);
+static bool xfunc_check_stream(Stream node);
+static bool xfunc_in_stream(Stream node, Stream stream);
-/* ----------------- MAIN FUNCTIONS ------------------------ */
+/* ----------------- MAIN FUNCTIONS ------------------------ */
/*
** xfunc_do_predmig
-** wrapper for Predicate Migration. It calls xfunc_predmig until no
+** wrapper for Predicate Migration. It calls xfunc_predmig until no
** more progress is made.
-** return value says if any changes were ever made.
+** return value says if any changes were ever made.
*/
-bool xfunc_do_predmig(Path root)
+bool
+xfunc_do_predmig(Path root)
{
- bool progress, changed = false;
-
- if (is_join(root))
- do
- {
- progress = false;
- Assert(IsA(root,JoinPath));
- xfunc_predmig((JoinPath)root, (Stream)NULL, (Stream)NULL,
- &progress);
- if (changed && progress)
- elog(DEBUG, "Needed to do a second round of predmig!\n");
- if (progress) changed = true;
- } while (progress);
- return(changed);
+ bool progress,
+ changed = false;
+
+ if (is_join(root))
+ do
+ {
+ progress = false;
+ Assert(IsA(root, JoinPath));
+ xfunc_predmig((JoinPath) root, (Stream) NULL, (Stream) NULL,
+ &progress);
+ if (changed && progress)
+ elog(DEBUG, "Needed to do a second round of predmig!\n");
+ if (progress)
+ changed = true;
+ } while (progress);
+ return (changed);
}
/*
** xfunc_predmig
- ** The main routine for Predicate Migration. It traverses a join tree,
- ** and for each root-to-leaf path in the plan tree it constructs a
+ ** The main routine for Predicate Migration. It traverses a join tree,
+ ** and for each root-to-leaf path in the plan tree it constructs a
** "Stream", which it passes to xfunc_series_llel for optimization.
** Destructively modifies the join tree (via predicate pullup).
*/
static void
-xfunc_predmig(JoinPath pathnode, /* root of the join tree */
- Stream streamroot,
- Stream laststream, /* for recursive calls -- these are
- the root of the stream under
- construction, and the lowest node
- created so far */
- bool *progressp)
+xfunc_predmig(JoinPath pathnode,/* root of the join tree */
+ Stream streamroot,
+ Stream laststream,/* for recursive calls -- these are the
+ * root of the stream under construction,
+ * and the lowest node created so far */
+ bool * progressp)
{
- Stream newstream;
-
- /*
- ** traverse the join tree dfs-style, constructing a stream as you go.
- ** When you hit a scan node, pass the stream off to xfunc_series_llel.
- */
-
- /* sanity check */
- if ((!streamroot && laststream) ||
- (streamroot && !laststream))
- elog(WARN, "called xfunc_predmig with bad inputs");
- if (streamroot) Assert(xfunc_check_stream(streamroot));
-
- /* add path node to stream */
- newstream = RMakeStream();
- if (!streamroot)
- streamroot = newstream;
- set_upstream(newstream, (StreamPtr)laststream);
- if (laststream)
- set_downstream(laststream, (StreamPtr)newstream);
- set_downstream(newstream, (StreamPtr)NULL);
- set_pathptr(newstream, (pathPtr)pathnode);
- set_cinfo(newstream, (CInfo)NULL);
- set_clausetype(newstream, XFUNC_UNKNOWN);
-
- /* base case: we're at a leaf, call xfunc_series_llel */
- if (!is_join(pathnode))
+ Stream newstream;
+
+ /*
+ * * traverse the join tree dfs-style, constructing a stream as you
+ * go. * When you hit a scan node, pass the stream off to
+ * xfunc_series_llel.
+ */
+
+ /* sanity check */
+ if ((!streamroot && laststream) ||
+ (streamroot && !laststream))
+ elog(WARN, "called xfunc_predmig with bad inputs");
+ if (streamroot)
+ Assert(xfunc_check_stream(streamroot));
+
+ /* add path node to stream */
+ newstream = RMakeStream();
+ if (!streamroot)
+ streamroot = newstream;
+ set_upstream(newstream, (StreamPtr) laststream);
+ if (laststream)
+ set_downstream(laststream, (StreamPtr) newstream);
+ set_downstream(newstream, (StreamPtr) NULL);
+ set_pathptr(newstream, (pathPtr) pathnode);
+ set_cinfo(newstream, (CInfo) NULL);
+ set_clausetype(newstream, XFUNC_UNKNOWN);
+
+ /* base case: we're at a leaf, call xfunc_series_llel */
+ if (!is_join(pathnode))
{
- /* form a fleshed-out copy of the stream */
- Stream fullstream = xfunc_complete_stream(streamroot);
-
- /* sort it via series-llel */
- if (xfunc_series_llel(fullstream))
- *progressp = true;
-
- /* free up the copy */
- xfunc_free_stream(fullstream);
+ /* form a fleshed-out copy of the stream */
+ Stream fullstream = xfunc_complete_stream(streamroot);
+
+ /* sort it via series-llel */
+ if (xfunc_series_llel(fullstream))
+ *progressp = true;
+
+ /* free up the copy */
+ xfunc_free_stream(fullstream);
}
- else
+ else
{
- /* visit left child */
- xfunc_predmig((JoinPath)get_outerjoinpath(pathnode),
- streamroot, newstream, progressp);
-
- /* visit right child */
- xfunc_predmig((JoinPath)get_innerjoinpath(pathnode),
- streamroot, newstream, progressp);
+ /* visit left child */
+ xfunc_predmig((JoinPath) get_outerjoinpath(pathnode),
+ streamroot, newstream, progressp);
+
+ /* visit right child */
+ xfunc_predmig((JoinPath) get_innerjoinpath(pathnode),
+ streamroot, newstream, progressp);
}
-
- /* remove this node */
- if (get_upstream(newstream))
- set_downstream((Stream)get_upstream(newstream), (StreamPtr)NULL);
- pfree(newstream);
+
+ /* remove this node */
+ if (get_upstream(newstream))
+ set_downstream((Stream) get_upstream(newstream), (StreamPtr) NULL);
+ pfree(newstream);
}
/*
** xfunc_series_llel
** A flavor of Monma and Sidney's Series-Parallel algorithm.
- ** Traverse stream downwards. When you find a node with restrictions on it,
+ ** Traverse stream downwards. When you find a node with restrictions on it,
** call xfunc_llel_chains on the substream from root to that node.
*/
-static bool xfunc_series_llel(Stream stream)
+static bool
+xfunc_series_llel(Stream stream)
{
- Stream temp, next;
- bool progress = false;
-
- for (temp = stream; temp != (Stream)NULL; temp = next)
+ Stream temp,
+ next;
+ bool progress = false;
+
+ for (temp = stream; temp != (Stream) NULL; temp = next)
{
- next = (Stream)xfunc_get_downjoin(temp);
- /*
- ** if there are restrictions/secondary join clauses above this
- ** node, call xfunc_llel_chains
- */
- if (get_upstream(temp) && is_clause((Stream)get_upstream(temp)))
- if (xfunc_llel_chains(stream, temp))
- progress = true;
+ next = (Stream) xfunc_get_downjoin(temp);
+
+ /*
+ * * if there are restrictions/secondary join clauses above this *
+ * node, call xfunc_llel_chains
+ */
+ if (get_upstream(temp) && is_clause((Stream) get_upstream(temp)))
+ if (xfunc_llel_chains(stream, temp))
+ progress = true;
}
- return(progress);
+ return (progress);
}
/*
** xfunc_llel_chains
** A flavor of Monma and Sidney's Parallel Chains algorithm.
** Given a stream which has been well-ordered except for its lowermost
- ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate.
+ ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate.
** What that means here is to form groups in the chain above the lowest
- ** join node above bottom inclusive, and then take all the restrictions
+ ** join node above bottom inclusive, and then take all the restrictions
** following bottom, and try to pull them up as far as possible.
*/
-static bool xfunc_llel_chains(Stream root, Stream bottom)
+static bool
+xfunc_llel_chains(Stream root, Stream bottom)
{
- bool progress = false;
- Stream origstream;
- Stream tmpstream, pathstream;
- Stream rootcopy = root;
-
- Assert(xfunc_check_stream(root));
-
- /* xfunc_prdmig_pullup will need an unmodified copy of the stream */
- origstream = (Stream)copyObject((Node)root);
-
- /* form groups among ill-ordered nodes */
- xfunc_form_groups(root, bottom);
-
- /* sort chain by rank */
- Assert(xfunc_in_stream(bottom, root));
- rootcopy = xfunc_stream_qsort(root, bottom);
-
- /*
- ** traverse sorted stream -- if any restriction has moved above a join,
- ** we must pull it up in the plan. That is, make plan tree
- ** reflect order of sorted stream.
- */
- for (tmpstream = rootcopy,
- pathstream = (Stream)xfunc_get_downjoin(rootcopy);
- tmpstream != (Stream)NULL && pathstream != (Stream)NULL;
- tmpstream = (Stream)get_downstream(tmpstream))
+ bool progress = false;
+ Stream origstream;
+ Stream tmpstream,
+ pathstream;
+ Stream rootcopy = root;
+
+ Assert(xfunc_check_stream(root));
+
+ /* xfunc_prdmig_pullup will need an unmodified copy of the stream */
+ origstream = (Stream) copyObject((Node) root);
+
+ /* form groups among ill-ordered nodes */
+ xfunc_form_groups(root, bottom);
+
+ /* sort chain by rank */
+ Assert(xfunc_in_stream(bottom, root));
+ rootcopy = xfunc_stream_qsort(root, bottom);
+
+ /*
+ * * traverse sorted stream -- if any restriction has moved above a
+ * join, * we must pull it up in the plan. That is, make plan tree *
+ * reflect order of sorted stream.
+ */
+ for (tmpstream = rootcopy,
+ pathstream = (Stream) xfunc_get_downjoin(rootcopy);
+ tmpstream != (Stream) NULL && pathstream != (Stream) NULL;
+ tmpstream = (Stream) get_downstream(tmpstream))
{
- if (is_clause(tmpstream)
- && get_pathptr(pathstream) != get_pathptr(tmpstream))
+ if (is_clause(tmpstream)
+ && get_pathptr(pathstream) != get_pathptr(tmpstream))
{
- /*
- ** If restriction moved above a Join after sort, we pull it
- ** up in the join plan.
- ** If restriction moved down, we ignore it.
- ** This is because Joey's Sequoia paper proves that
- ** restrictions should never move down. If this
- ** one were moved down, it would violate "semantic correctness",
- ** i.e. it would be lower than the attributes it references.
- */
- Assert(xfunc_num_relids(pathstream)>xfunc_num_relids(tmpstream));
- progress =
- xfunc_prdmig_pullup(origstream, tmpstream,
- (JoinPath)get_pathptr(pathstream));
+
+ /*
+ * * If restriction moved above a Join after sort, we pull it *
+ * up in the join plan. * If restriction moved down, we
+ * ignore it. * This is because Joey's Sequoia paper proves
+ * that * restrictions should never move down. If this * one
+ * were moved down, it would violate "semantic correctness", *
+ * i.e. it would be lower than the attributes it references.
+ */
+ Assert(xfunc_num_relids(pathstream) > xfunc_num_relids(tmpstream));
+ progress =
+ xfunc_prdmig_pullup(origstream, tmpstream,
+ (JoinPath) get_pathptr(pathstream));
}
- if (get_downstream(tmpstream))
- pathstream =
- (Stream)xfunc_get_downjoin((Stream)get_downstream(tmpstream));
+ if (get_downstream(tmpstream))
+ pathstream =
+ (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream));
}
-
- /* free up origstream */
- xfunc_free_stream(origstream);
- return(progress);
+
+ /* free up origstream */
+ xfunc_free_stream(origstream);
+ return (progress);
}
/*
** xfunc_complete_stream --
** Given a stream composed of join nodes only, make a copy containing the
- ** join nodes along with the associated restriction nodes.
+ ** join nodes along with the associated restriction nodes.
*/
-static Stream xfunc_complete_stream(Stream stream)
+static Stream
+xfunc_complete_stream(Stream stream)
{
- Stream tmpstream, copystream, curstream = (Stream)NULL;
-
- copystream = (Stream)copyObject((Node)stream);
- Assert(xfunc_check_stream(copystream));
-
- curstream = copystream;
- Assert(!is_clause(curstream));
-
- /* curstream = (Stream)xfunc_get_downjoin(curstream); */
-
- while(curstream != (Stream)NULL)
+ Stream tmpstream,
+ copystream,
+ curstream = (Stream) NULL;
+
+ copystream = (Stream) copyObject((Node) stream);
+ Assert(xfunc_check_stream(copystream));
+
+ curstream = copystream;
+ Assert(!is_clause(curstream));
+
+ /* curstream = (Stream)xfunc_get_downjoin(curstream); */
+
+ while (curstream != (Stream) NULL)
{
- xfunc_add_clauses(curstream);
- curstream = (Stream)xfunc_get_downjoin(curstream);
+ xfunc_add_clauses(curstream);
+ curstream = (Stream) xfunc_get_downjoin(curstream);
}
-
- /* find top of stream and return it */
- for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr)NULL;
- tmpstream = (Stream)get_upstream(tmpstream))
- /* no body in for loop */;
-
- return(tmpstream);
+
+ /* find top of stream and return it */
+ for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr) NULL;
+ tmpstream = (Stream) get_upstream(tmpstream))
+ /* no body in for loop */ ;
+
+ return (tmpstream);
}
/*
** xfunc_prdmig_pullup
** pullup a clause in a path above joinpath. Since the JoinPath tree
- ** doesn't have upward pointers, it's difficult to deal with. Thus we
+ ** doesn't have upward pointers, it's difficult to deal with. Thus we
** require the original stream, which maintains pointers to all the path
- ** nodes. We use the original stream to find out what joins are
+ ** nodes. We use the original stream to find out what joins are
** above the clause.
*/
-static bool
+static bool
xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
{
- CInfo clauseinfo = get_cinfo(pullme);
- bool progress = false;
- Stream upjoin, orignode, temp;
- int whichchild;
-
- /* find node in origstream that contains clause */
- for (orignode = origstream;
- orignode != (Stream) NULL
- && get_cinfo(orignode) != clauseinfo;
- orignode = (Stream)get_downstream(orignode))
- /* empty body in for loop */ ;
- if (!orignode)
- elog(WARN, "Didn't find matching node in original stream");
-
-
- /* pull up this node as far as it should go */
- for (upjoin = (Stream)xfunc_get_upjoin(orignode);
- upjoin != (Stream)NULL
- && (JoinPath)get_pathptr((Stream)xfunc_get_downjoin(upjoin))
- != joinpath;
- upjoin = (Stream)xfunc_get_upjoin(upjoin))
+ CInfo clauseinfo = get_cinfo(pullme);
+ bool progress = false;
+ Stream upjoin,
+ orignode,
+ temp;
+ int whichchild;
+
+ /* find node in origstream that contains clause */
+ for (orignode = origstream;
+ orignode != (Stream) NULL
+ && get_cinfo(orignode) != clauseinfo;
+ orignode = (Stream) get_downstream(orignode))
+ /* empty body in for loop */ ;
+ if (!orignode)
+ elog(WARN, "Didn't find matching node in original stream");
+
+
+ /* pull up this node as far as it should go */
+ for (upjoin = (Stream) xfunc_get_upjoin(orignode);
+ upjoin != (Stream) NULL
+ && (JoinPath) get_pathptr((Stream) xfunc_get_downjoin(upjoin))
+ != joinpath;
+ upjoin = (Stream) xfunc_get_upjoin(upjoin))
{
-#ifdef DEBUG
- elog(DEBUG, "pulling up in xfunc_predmig_pullup!");
+#ifdef DEBUG
+ elog(DEBUG, "pulling up in xfunc_predmig_pullup!");
#endif
- /* move clause up in path */
- if (get_pathptr((Stream)get_downstream(upjoin))
- == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin)))
- whichchild = OUTER;
- else whichchild = INNER;
- clauseinfo = xfunc_pullup((Path)get_pathptr((Stream)get_downstream(upjoin)),
- (JoinPath)get_pathptr(upjoin),
- clauseinfo,
- whichchild,
- get_clausetype(orignode));
- set_pathptr(pullme, get_pathptr(upjoin));
- /* pullme has been moved into locclauseinfo */
- set_clausetype(pullme, XFUNC_LOCPRD);
-
- /*
- ** xfunc_pullup makes new path nodes for children of
- ** get_pathptr(current). We must modify the stream nodes to point
- ** to these path nodes
- */
- if (whichchild == OUTER)
+ /* move clause up in path */
+ if (get_pathptr((Stream) get_downstream(upjoin))
+ == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)))
+ whichchild = OUTER;
+ else
+ whichchild = INNER;
+ clauseinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)),
+ (JoinPath) get_pathptr(upjoin),
+ clauseinfo,
+ whichchild,
+ get_clausetype(orignode));
+ set_pathptr(pullme, get_pathptr(upjoin));
+ /* pullme has been moved into locclauseinfo */
+ set_clausetype(pullme, XFUNC_LOCPRD);
+
+ /*
+ * * xfunc_pullup makes new path nodes for children of *
+ * get_pathptr(current). We must modify the stream nodes to point *
+ * to these path nodes
+ */
+ if (whichchild == OUTER)
{
- for(temp = (Stream)get_downstream(upjoin); is_clause(temp);
- temp = (Stream)get_downstream(temp))
+ for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ set_pathptr
+ (temp, (pathPtr)
+ get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
set_pathptr
- (temp, (pathPtr)
- get_outerjoinpath((JoinPath)get_pathptr(upjoin)));
- set_pathptr
- (temp,
- (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin)));
+ (temp,
+ (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
}
- else
+ else
{
- for(temp = (Stream)get_downstream(upjoin); is_clause(temp);
- temp = (Stream)get_downstream(temp))
+ for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ set_pathptr
+ (temp, (pathPtr)
+ get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
set_pathptr
- (temp, (pathPtr)
- get_innerjoinpath((JoinPath)get_pathptr(upjoin)));
- set_pathptr
- (temp, (pathPtr)
- get_innerjoinpath((JoinPath)get_pathptr(upjoin)));
+ (temp, (pathPtr)
+ get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
}
- progress = true;
+ progress = true;
}
- if (!progress)
- elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
- return(progress);
+ if (!progress)
+ elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
+ return (progress);
}
/*
@@ -386,143 +405,151 @@ xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
** equal to the cost of the first plus the selectivity of the first times the
** cost of the second. We define each node to be in a group by itself,
** and then repeatedly find adjacent groups which are ordered by descending
- ** rank, and make larger groups. You know that two adjacent nodes are in a
- ** group together if the lower has groupup set to true. They will both have
+ ** rank, and make larger groups. You know that two adjacent nodes are in a
+ ** group together if the lower has groupup set to true. They will both have
** the same groupcost and groupsel (since they're in the same group!)
*/
-static void xfunc_form_groups(Query* queryInfo, Stream root, Stream bottom)
+static void
+xfunc_form_groups(Query * queryInfo, Stream root, Stream bottom)
{
- Stream temp, parent;
- int lowest = xfunc_num_relids((Stream)xfunc_get_upjoin(bottom));
- bool progress;
- LispValue primjoin;
- int whichchild;
-
- if (!lowest) return; /* no joins in stream, so no groups */
-
- /* initialize groups to be single nodes */
- for (temp = root;
- temp != (Stream)NULL && temp != bottom;
- temp = (Stream)get_downstream(temp))
+ Stream temp,
+ parent;
+ int lowest = xfunc_num_relids((Stream) xfunc_get_upjoin(bottom));
+ bool progress;
+ LispValue primjoin;
+ int whichchild;
+
+ if (!lowest)
+ return; /* no joins in stream, so no groups */
+
+ /* initialize groups to be single nodes */
+ for (temp = root;
+ temp != (Stream) NULL && temp != bottom;
+ temp = (Stream) get_downstream(temp))
{
- /* if a Join node */
- if (!is_clause(temp))
+ /* if a Join node */
+ if (!is_clause(temp))
{
- if (get_pathptr((Stream)get_downstream(temp))
- == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(temp)))
- whichchild = OUTER;
- else whichchild = INNER;
- set_groupcost(temp,
- xfunc_join_expense((JoinPath)get_pathptr(temp),
- whichchild));
- if (primjoin = xfunc_primary_join((JoinPath)get_pathptr(temp)))
+ if (get_pathptr((Stream) get_downstream(temp))
+ == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(temp)))
+ whichchild = OUTER;
+ else
+ whichchild = INNER;
+ set_groupcost(temp,
+ xfunc_join_expense((JoinPath) get_pathptr(temp),
+ whichchild));
+ if (primjoin = xfunc_primary_join((JoinPath) get_pathptr(temp)))
{
- set_groupsel(temp,
- compute_clause_selec(queryInfo,
- primjoin, NIL));
+ set_groupsel(temp,
+ compute_clause_selec(queryInfo,
+ primjoin, NIL));
}
- else
+ else
{
- set_groupsel(temp,1.0);
+ set_groupsel(temp, 1.0);
}
}
- else /* a restriction, or 2-ary join pred */
+ else
+/* a restriction, or 2-ary join pred */
{
- set_groupcost(temp,
- xfunc_expense(queryInfo,
- get_clause(get_cinfo(temp))));
- set_groupsel(temp,
- compute_clause_selec(queryInfo,
- get_clause(get_cinfo(temp)),
- NIL));
+ set_groupcost(temp,
+ xfunc_expense(queryInfo,
+ get_clause(get_cinfo(temp))));
+ set_groupsel(temp,
+ compute_clause_selec(queryInfo,
+ get_clause(get_cinfo(temp)),
+ NIL));
}
- set_groupup(temp,false);
+ set_groupup(temp, false);
}
-
- /* make passes upwards, forming groups */
- do
+
+ /* make passes upwards, forming groups */
+ do
{
- progress = false;
- for (temp = (Stream)get_upstream(bottom);
- temp != (Stream)NULL;
- temp = (Stream)get_upstream(temp))
+ progress = false;
+ for (temp = (Stream) get_upstream(bottom);
+ temp != (Stream) NULL;
+ temp = (Stream) get_upstream(temp))
{
- /* check for grouping with node upstream */
- if (!get_groupup(temp) && /* not already grouped */
- (parent = (Stream)get_upstream(temp)) != (Stream)NULL &&
+ /* check for grouping with node upstream */
+ if (!get_groupup(temp) && /* not already grouped */
+ (parent = (Stream) get_upstream(temp)) != (Stream) NULL &&
/* temp is a join or temp is the top of a group */
- (is_join((Path)get_pathptr(temp)) ||
- get_downstream(temp) &&
- get_groupup((Stream)get_downstream(temp))) &&
- get_grouprank(parent) < get_grouprank(temp))
+ (is_join((Path) get_pathptr(temp)) ||
+ get_downstream(temp) &&
+ get_groupup((Stream) get_downstream(temp))) &&
+ get_grouprank(parent) < get_grouprank(temp))
{
- progress = true; /* we formed a new group */
- set_groupup(temp,true);
- set_groupcost(temp,
- get_groupcost(temp) +
- get_groupsel(temp) * get_groupcost(parent));
- set_groupsel(temp,get_groupsel(temp) * get_groupsel(parent));
-
- /* fix costs and sels of all members of group */
- xfunc_setup_group(temp, bottom);
+ progress = true;/* we formed a new group */
+ set_groupup(temp, true);
+ set_groupcost(temp,
+ get_groupcost(temp) +
+ get_groupsel(temp) * get_groupcost(parent));
+ set_groupsel(temp, get_groupsel(temp) * get_groupsel(parent));
+
+ /* fix costs and sels of all members of group */
+ xfunc_setup_group(temp, bottom);
}
}
- } while(progress);
+ } while (progress);
}
-/* ------------------- UTILITY FUNCTIONS ------------------------- */
+/* ------------------- UTILITY FUNCTIONS ------------------------- */
/*
** xfunc_free_stream --
** walk down a stream and pfree it
*/
-static void xfunc_free_stream(Stream root)
+static void
+xfunc_free_stream(Stream root)
{
- Stream cur, next;
-
- Assert(xfunc_check_stream(root));
-
- if (root != (Stream)NULL)
- for (cur = root; cur != (Stream)NULL; cur = next)
- {
- next = (Stream)get_downstream(cur);
- pfree(cur);
- }
+ Stream cur,
+ next;
+
+ Assert(xfunc_check_stream(root));
+
+ if (root != (Stream) NULL)
+ for (cur = root; cur != (Stream) NULL; cur = next)
+ {
+ next = (Stream) get_downstream(cur);
+ pfree(cur);
+ }
}
/*
** xfunc_add<_clauses
- ** find any clauses above current, and insert them into stream as
+ ** find any clauses above current, and insert them into stream as
** appropriate. Return uppermost clause inserted, or current if none.
*/
-static Stream xfunc_add_clauses(Stream current)
+static Stream
+xfunc_add_clauses(Stream current)
{
- Stream topnode = current;
- LispValue temp;
- LispValue primjoin;
-
- /* first add in the local clauses */
- foreach(temp, get_locclauseinfo((Path)get_pathptr(current)))
+ Stream topnode = current;
+ LispValue temp;
+ LispValue primjoin;
+
+ /* first add in the local clauses */
+ foreach(temp, get_locclauseinfo((Path) get_pathptr(current)))
{
- topnode =
- xfunc_streaminsert((CInfo)lfirst(temp), topnode,
- XFUNC_LOCPRD);
+ topnode =
+ xfunc_streaminsert((CInfo) lfirst(temp), topnode,
+ XFUNC_LOCPRD);
}
-
- /* and add in the join clauses */
- if (IsA(get_pathptr(current),JoinPath))
+
+ /* and add in the join clauses */
+ if (IsA(get_pathptr(current), JoinPath))
{
- primjoin = xfunc_primary_join((JoinPath)get_pathptr(current));
- foreach(temp, get_pathclauseinfo((JoinPath)get_pathptr(current)))
+ primjoin = xfunc_primary_join((JoinPath) get_pathptr(current));
+ foreach(temp, get_pathclauseinfo((JoinPath) get_pathptr(current)))
{
- if (!equal(get_clause((CInfo)lfirst(temp)), primjoin))
- topnode =
- xfunc_streaminsert((CInfo)lfirst(temp), topnode,
- XFUNC_JOINPRD);
+ if (!equal(get_clause((CInfo) lfirst(temp)), primjoin))
+ topnode =
+ xfunc_streaminsert((CInfo) lfirst(temp), topnode,
+ XFUNC_JOINPRD);
}
}
- return(topnode);
+ return (topnode);
}
@@ -531,33 +558,36 @@ static Stream xfunc_add_clauses(Stream current)
** find all elements of stream that are grouped with node and are above
** bottom, and set their groupcost and groupsel to be the same as node's.
*/
-static void xfunc_setup_group(Stream node, Stream bottom)
+static void
+xfunc_setup_group(Stream node, Stream bottom)
{
- Stream temp;
-
- if (node != bottom)
- /* traverse downwards */
- for (temp = (Stream)get_downstream(node);
- temp != (Stream)NULL && temp != bottom;
- temp = (Stream)get_downstream(temp))
- {
- if (!get_groupup(temp)) break;
- else
- {
- set_groupcost(temp, get_groupcost(node));
- set_groupsel(temp, get_groupsel(node));
- }
- }
-
- /* traverse upwards */
- for (temp = (Stream)get_upstream(node); temp != (Stream)NULL;
- temp = (Stream)get_upstream(temp))
+ Stream temp;
+
+ if (node != bottom)
+ /* traverse downwards */
+ for (temp = (Stream) get_downstream(node);
+ temp != (Stream) NULL && temp != bottom;
+ temp = (Stream) get_downstream(temp))
+ {
+ if (!get_groupup(temp))
+ break;
+ else
+ {
+ set_groupcost(temp, get_groupcost(node));
+ set_groupsel(temp, get_groupsel(node));
+ }
+ }
+
+ /* traverse upwards */
+ for (temp = (Stream) get_upstream(node); temp != (Stream) NULL;
+ temp = (Stream) get_upstream(temp))
{
- if (!get_groupup((Stream)get_downstream(temp))) break;
- else
+ if (!get_groupup((Stream) get_downstream(temp)))
+ break;
+ else
{
- set_groupcost(temp, get_groupcost(node));
- set_groupsel(temp, get_groupsel(node));
+ set_groupcost(temp, get_groupcost(node));
+ set_groupsel(temp, get_groupsel(node));
}
}
}
@@ -568,70 +598,75 @@ static void xfunc_setup_group(Stream node, Stream bottom)
** Make a new Stream node to hold clause, and insert it above current.
** Return new node.
*/
-static Stream
+static Stream
xfunc_streaminsert(CInfo clauseinfo,
- Stream current,
- int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */
+ Stream current,
+ int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */
{
- Stream newstream = RMakeStream();
- set_upstream(newstream, get_upstream(current));
- if (get_upstream(current))
- set_downstream((Stream)(get_upstream(current)), (StreamPtr)newstream);
- set_upstream(current, (StreamPtr)newstream);
- set_downstream(newstream, (StreamPtr)current);
- set_pathptr(newstream, get_pathptr(current));
- set_cinfo(newstream, clauseinfo);
- set_clausetype(newstream, clausetype);
- return(newstream);
+ Stream newstream = RMakeStream();
+
+ set_upstream(newstream, get_upstream(current));
+ if (get_upstream(current))
+ set_downstream((Stream) (get_upstream(current)), (StreamPtr) newstream);
+ set_upstream(current, (StreamPtr) newstream);
+ set_downstream(newstream, (StreamPtr) current);
+ set_pathptr(newstream, get_pathptr(current));
+ set_cinfo(newstream, clauseinfo);
+ set_clausetype(newstream, clausetype);
+ return (newstream);
}
/*
** Given a Stream node, find the number of relids referenced in the pathnode
** associated with the stream node. The number of relids gives a unique
- ** ordering on the joins in a stream, which we use to compare the height of
+ ** ordering on the joins in a stream, which we use to compare the height of
** join nodes.
*/
-static int xfunc_num_relids(Stream node)
+static int
+xfunc_num_relids(Stream node)
{
- if (!node || !IsA(get_pathptr(node),JoinPath))
- return(0);
- else return(length
- (get_relids(get_parent((JoinPath)get_pathptr(node)))));
+ if (!node || !IsA(get_pathptr(node), JoinPath))
+ return (0);
+ else
+ return (length
+ (get_relids(get_parent((JoinPath) get_pathptr(node)))));
}
-/*
+/*
** xfunc_get_downjoin --
** Given a stream node, find the next lowest node which points to a
** join predicate or a scan node.
*/
-static StreamPtr xfunc_get_downjoin(Stream node)
+static StreamPtr
+xfunc_get_downjoin(Stream node)
{
- Stream temp;
-
- if (!is_clause(node)) /* if this is a join */
- node = (Stream)get_downstream(node);
- for (temp = node; temp && is_clause(temp);
- temp = (Stream)get_downstream(temp))
- /* empty body in for loop */ ;
-
- return((StreamPtr)temp);
+ Stream temp;
+
+ if (!is_clause(node)) /* if this is a join */
+ node = (Stream) get_downstream(node);
+ for (temp = node; temp && is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ /* empty body in for loop */ ;
+
+ return ((StreamPtr) temp);
}
/*
** xfunc_get_upjoin --
** same as above, but upwards.
*/
-static StreamPtr xfunc_get_upjoin(Stream node)
+static StreamPtr
+xfunc_get_upjoin(Stream node)
{
- Stream temp;
-
- if (!is_clause(node)) /* if this is a join */
- node = (Stream)get_upstream(node);
- for (temp = node; temp && is_clause(temp);
- temp = (Stream)get_upstream(temp))
- /* empty body in for loop */ ;
-
- return((StreamPtr)temp);
+ Stream temp;
+
+ if (!is_clause(node)) /* if this is a join */
+ node = (Stream) get_upstream(node);
+ for (temp = node; temp && is_clause(temp);
+ temp = (Stream) get_upstream(temp))
+ /* empty body in for loop */ ;
+
+ return ((StreamPtr) temp);
}
/*
@@ -639,43 +674,46 @@ static StreamPtr xfunc_get_upjoin(Stream node)
** Given a stream, sort by group rank the elements in the stream from the
** node "bottom" up. DESTRUCTIVELY MODIFIES STREAM! Returns new root.
*/
-static Stream xfunc_stream_qsort(Stream root, Stream bottom)
+static Stream
+xfunc_stream_qsort(Stream root, Stream bottom)
{
- int i;
- size_t num;
- Stream *nodearray, output;
- Stream tmp;
-
- /* find size of list */
- for (num = 0, tmp = root; tmp != bottom;
- tmp = (Stream)get_downstream(tmp))
- num ++;
- if (num <= 1) return (root);
-
- /* copy elements of the list into an array */
- nodearray = (Stream *) palloc(num * sizeof(Stream));
-
- for (tmp = root, i = 0; tmp != bottom;
- tmp = (Stream)get_downstream(tmp), i++)
- nodearray[i] = tmp;
-
- /* sort the array */
- pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare);
-
- /* paste together the array elements */
- output = nodearray[num - 1];
- set_upstream(output, (StreamPtr)NULL);
- for (i = num - 2; i >= 0; i--)
+ int i;
+ size_t num;
+ Stream *nodearray,
+ output;
+ Stream tmp;
+
+ /* find size of list */
+ for (num = 0, tmp = root; tmp != bottom;
+ tmp = (Stream) get_downstream(tmp))
+ num++;
+ if (num <= 1)
+ return (root);
+
+ /* copy elements of the list into an array */
+ nodearray = (Stream *) palloc(num * sizeof(Stream));
+
+ for (tmp = root, i = 0; tmp != bottom;
+ tmp = (Stream) get_downstream(tmp), i++)
+ nodearray[i] = tmp;
+
+ /* sort the array */
+ pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare);
+
+ /* paste together the array elements */
+ output = nodearray[num - 1];
+ set_upstream(output, (StreamPtr) NULL);
+ for (i = num - 2; i >= 0; i--)
{
- set_downstream(nodearray[i+1], (StreamPtr)nodearray[i]);
- set_upstream(nodearray[i], (StreamPtr)nodearray[i+1]);
+ set_downstream(nodearray[i + 1], (StreamPtr) nodearray[i]);
+ set_upstream(nodearray[i], (StreamPtr) nodearray[i + 1]);
}
- set_downstream(nodearray[0], (StreamPtr)bottom);
- if (bottom)
- set_upstream(bottom, (StreamPtr)nodearray[0]);
-
- Assert(xfunc_check_stream(output));
- return(output);
+ set_downstream(nodearray[0], (StreamPtr) bottom);
+ if (bottom)
+ set_upstream(bottom, (StreamPtr) nodearray[0]);
+
+ Assert(xfunc_check_stream(output));
+ return (output);
}
/*
@@ -684,90 +722,102 @@ static Stream xfunc_stream_qsort(Stream root, Stream bottom)
** Compare nodes by group rank. If group ranks are equal, ensure that
** join nodes appear in same order as in plan tree.
*/
-static int xfunc_stream_compare(void *arg1, void *arg2)
+static int
+xfunc_stream_compare(void *arg1, void *arg2)
{
- Stream stream1 = *(Stream *) arg1;
- Stream stream2 = *(Stream *) arg2;
- Cost rank1, rank2;
-
- rank1 = get_grouprank(stream1);
- rank2 = get_grouprank(stream2);
-
- if (rank1 > rank2) return(1);
- else if (rank1 < rank2) return(-1);
- else
+ Stream stream1 = *(Stream *) arg1;
+ Stream stream2 = *(Stream *) arg2;
+ Cost rank1,
+ rank2;
+
+ rank1 = get_grouprank(stream1);
+ rank2 = get_grouprank(stream2);
+
+ if (rank1 > rank2)
+ return (1);
+ else if (rank1 < rank2)
+ return (-1);
+ else
{
- if (is_clause(stream1) && is_clause(stream2))
- return(0); /* doesn't matter what order if both are restrictions */
- else if (!is_clause(stream1) && !is_clause(stream2))
+ if (is_clause(stream1) && is_clause(stream2))
+ return (0); /* doesn't matter what order if both are
+ * restrictions */
+ else if (!is_clause(stream1) && !is_clause(stream2))
{
- if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
- return(-1);
- else return(1);
+ if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
+ return (-1);
+ else
+ return (1);
}
- else if (is_clause(stream1) && !is_clause(stream2))
+ else if (is_clause(stream1) && !is_clause(stream2))
{
- if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2))
- /* stream1 is a restriction over stream2 */
- return(1);
- else return(-1);
+ if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2))
+ /* stream1 is a restriction over stream2 */
+ return (1);
+ else
+ return (-1);
}
- else if (!is_clause(stream1) && is_clause(stream2))
+ else if (!is_clause(stream1) && is_clause(stream2))
{
- /* stream2 is a restriction over stream1: never push down */
- return(-1);
+ /* stream2 is a restriction over stream1: never push down */
+ return (-1);
}
}
}
-/* ------------------ DEBUGGING ROUTINES ---------------------------- */
+/* ------------------ DEBUGGING ROUTINES ---------------------------- */
/*
** Make sure all pointers in stream make sense. Make sure no joins are
** out of order.
*/
-static bool xfunc_check_stream(Stream node)
+static bool
+xfunc_check_stream(Stream node)
{
- Stream temp;
- int numrelids, tmp;
-
- /* set numrelids higher than max */
- if (!is_clause(node))
- numrelids = xfunc_num_relids(node) + 1;
- else if (xfunc_get_downjoin(node))
- numrelids = xfunc_num_relids((Stream)xfunc_get_downjoin(node)) + 1;
- else numrelids = 1;
-
- for (temp = node; get_downstream(temp); temp = (Stream)get_downstream(temp))
+ Stream temp;
+ int numrelids,
+ tmp;
+
+ /* set numrelids higher than max */
+ if (!is_clause(node))
+ numrelids = xfunc_num_relids(node) + 1;
+ else if (xfunc_get_downjoin(node))
+ numrelids = xfunc_num_relids((Stream) xfunc_get_downjoin(node)) + 1;
+ else
+ numrelids = 1;
+
+ for (temp = node; get_downstream(temp); temp = (Stream) get_downstream(temp))
{
- if ((Stream)get_upstream((Stream)get_downstream(temp)) != temp)
+ if ((Stream) get_upstream((Stream) get_downstream(temp)) != temp)
{
- elog(WARN, "bad pointers in stream");
- return(false);
+ elog(WARN, "bad pointers in stream");
+ return (false);
}
- if (!is_clause(temp))
+ if (!is_clause(temp))
{
- if ((tmp = xfunc_num_relids(temp)) >= numrelids)
+ if ((tmp = xfunc_num_relids(temp)) >= numrelids)
{
- elog(WARN, "Joins got reordered!");
- return(false);
+ elog(WARN, "Joins got reordered!");
+ return (false);
}
- numrelids = tmp;
+ numrelids = tmp;
}
}
-
- return(true);
+
+ return (true);
}
/*
** xfunc_in_stream
** check if node is in stream
*/
-static bool xfunc_in_stream(Stream node, Stream stream)
+static bool
+xfunc_in_stream(Stream node, Stream stream)
{
- Stream temp;
-
- for (temp = stream; temp; temp = (Stream)get_downstream(temp))
- if (temp == node) return(1);
- return(0);
+ Stream temp;
+
+ for (temp = stream; temp; temp = (Stream) get_downstream(temp))
+ if (temp == node)
+ return (1);
+ return (0);
}