predmig.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:22k
- /*-------------------------------------------------------------------------
- *
- * predmig.c
- *
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/_deadcode/predmig.c,v 1.4 1999/05/25 22:41:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
- /*
- ** DESCRIPTION
- ** 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
- ** 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
- ** 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
- ** 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
- ** optimizer and/or cause the system to run out of memory.
- ** -- JMH, 11/13/92
- */
- #include "nodes/pg_list.h"
- #include "nodes/nodes.h"
- #include "nodes/primnodes.h"
- #include "nodes/relation.h"
- #include "utils/palloc.h"
- #include "utils/elog.h"
- #include "optimizer/xfunc.h"
- #include "optimizer/pathnode.h"
- #include "optimizer/internal.h"
- #include "optimizer/cost.h"
- #include "optimizer/keys.h"
- #include "optimizer/tlist.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(RestrictInfo restrictinfo, 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);
- /* ----------------- MAIN FUNCTIONS ------------------------ */
- /*
- ** xfunc_do_predmig
- ** wrapper for Predicate Migration. It calls xfunc_predmig until no
- ** more progress is made.
- ** return value says if any changes were ever made.
- */
- 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;
- }
- /*
- ** 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
- ** "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)
- {
- 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(ERROR, "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, (RestrictInfo) 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);
- }
- 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);
- }
- /* 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,
- ** call xfunc_llel_chains on the substream from root to that node.
- */
- static bool
- xfunc_series_llel(Stream stream)
- {
- 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;
- }
- 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.
- ** 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
- ** following bottom, and try to pull them up as far as possible.
- */
- 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))
- {
- 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 (get_downstream(tmpstream))
- pathstream = (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream));
- }
- /* 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.
- */
- 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)
- {
- 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;
- }
- /*
- ** 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
- ** require the original stream, which maintains pointers to all the path
- ** nodes. We use the original stream to find out what joins are
- ** above the clause.
- */
- static bool
- xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
- {
- RestrictInfo restrictinfo = 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) != restrictinfo;
- orignode = (Stream) get_downstream(orignode))
- /* empty body in for loop */ ;
- if (!orignode)
- elog(ERROR, "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!");
- #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;
- restrictinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)),
- (JoinPath) get_pathptr(upjoin),
- restrictinfo,
- whichchild,
- get_clausetype(orignode));
- set_pathptr(pullme, get_pathptr(upjoin));
- /* pullme has been moved into locrestrictinfo */
- 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))
- set_pathptr
- (temp, (pathPtr)
- get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
- set_pathptr
- (temp,
- (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
- }
- else
- {
- 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)));
- }
- progress = true;
- }
- if (!progress)
- elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
- return progress;
- }
- /*
- ** xfunc_form_groups
- ** A group is a pair of stream nodes a,b such that a is constrained to
- ** precede b (for instance if a and b are both joins), but rank(a) > rank(b).
- ** In such a situation, Monma and Sidney prove that no clauses should end
- ** up between a and b, and therefore we may treat them as a group, with
- ** selectivity equal to the product of their selectivities, and cost
- ** 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
- ** the same groupcost and groupsel (since they're in the same group!)
- */
- 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))
- {
- /* 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)))
- {
- set_groupsel(temp,
- compute_clause_selec(queryInfo,
- primjoin, NIL));
- }
- else
- set_groupsel(temp, 1.0);
- }
- 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_groupup(temp, false);
- }
- /* make passes upwards, forming groups */
- do
- {
- 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 &&
- /* 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))
- {
- 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);
- }
- /* ------------------- UTILITY FUNCTIONS ------------------------- */
- /*
- ** xfunc_free_stream
- ** walk down a stream and pfree it
- */
- 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);
- }
- }
- /*
- ** xfunc_add<_clauses
- ** 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)
- {
- Stream topnode = current;
- LispValue temp;
- LispValue primjoin;
- /* first add in the local clauses */
- foreach(temp, get_loc_restrictinfo((Path) get_pathptr(current)))
- {
- topnode = xfunc_streaminsert((RestrictInfo) lfirst(temp), topnode,
- XFUNC_LOCPRD);
- }
- /* and add in the join clauses */
- if (IsA(get_pathptr(current), JoinPath))
- {
- primjoin = xfunc_primary_join((JoinPath) get_pathptr(current));
- foreach(temp, get_pathrestrictinfo((JoinPath) get_pathptr(current)))
- {
- if (!equal(get_clause((RestrictInfo) lfirst(temp)), primjoin))
- topnode = xfunc_streaminsert((RestrictInfo) lfirst(temp), topnode,
- XFUNC_JOINPRD);
- }
- }
- return topnode;
- }
- /*
- ** xfunc_setup_group
- ** 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)
- {
- 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
- {
- set_groupcost(temp, get_groupcost(node));
- set_groupsel(temp, get_groupsel(node));
- }
- }
- }
- /*
- ** xfunc_streaminsert
- ** Make a new Stream node to hold clause, and insert it above current.
- ** Return new node.
- */
- static Stream
- xfunc_streaminsert(RestrictInfo restrictinfo,
- 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, restrictinfo);
- 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
- ** join nodes.
- */
- 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)))));
- }
- /*
- ** 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)
- {
- 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)
- {
- 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;
- }
- /*
- ** xfunc_stream_qsort
- ** 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)
- {
- 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 */
- 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[0], (StreamPtr) bottom);
- if (bottom)
- set_upstream(bottom, (StreamPtr) nodearray[0]);
- Assert(xfunc_check_stream(output));
- return output;
- }
- /*
- ** xfunc_stream_compare
- ** comparison function for xfunc_stream_qsort.
- ** 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)
- {
- 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 (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
- return -1;
- else
- return 1;
- }
- 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;
- }
- else if (!is_clause(stream1) && is_clause(stream2))
- {
- /* stream2 is a restriction over stream1: never push down */
- return -1;
- }
- }
- }
- /* ------------------ 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)
- {
- 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)
- {
- elog(ERROR, "bad pointers in stream");
- return false;
- }
- if (!is_clause(temp))
- {
- if ((tmp = xfunc_num_relids(temp)) >= numrelids)
- {
- elog(ERROR, "Joins got reordered!");
- return false;
- }
- numrelids = tmp;
- }
- }
- return true;
- }
- /*
- ** xfunc_in_stream
- ** check if node is in 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;
- }