home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: /private/postgres/src/executor/RCS/ex_flatten.c,v 1.7 1992/07/13 10:19:46 hong Exp $
- *
- * This file handles the nodes associated with flattening sets in the
- * target list of queries containing functions returning sets.
- *
- * ExecEvalIter() -
- * Iterate through the all return tuples/base types from a function one
- * at time (i.e. one per ExecEvalIter call). Not really needed for
- * postquel functions, but for reasons of orthogonality, these nodes
- * exist above pq functions as well as c functions.
- *
- * ExecEvalFjoin() -
- * Given N Iter nodes return a vector of all combinations of results
- * one at a time (i.e. one result vector per ExecEvalFjoin call). This
- * node does the actual flattening work.
- */
-
- #include "tmp/postgres.h"
- #include "nodes/primnodes.h"
- #include "nodes/relation.h"
- #include "nodes/execnodes.h"
- #include "parser/parsetree.h"
- #include "executor/flatten.h"
-
- Datum
- ExecEvalIter(iterNode, econtext, resultIsNull, iterIsDone)
- Iter iterNode;
- ExprContext econtext;
- bool *iterIsDone;
- bool *resultIsNull;
- {
- List expression;
-
- expression = get_iterexpr(iterNode);
-
- /*
- * Really Iter nodes are only needed for C functions, postquel function
- * by their nature return 1 result at a time. For now we are only worrying
- * about postquel functions, c functions will come later.
- */
- return ExecEvalExpr((Node)expression, econtext, resultIsNull, iterIsDone);
- }
-
- void
- ExecEvalFjoin(tlist, econtext, isNullVect, fj_isDone)
- List tlist;
- ExprContext econtext;
- bool *isNullVect;
- bool *fj_isDone;
- {
- bool isDone;
- int curNode;
- List tlistP;
- Fjoin fjNode = (Fjoin)CAR(tlist);
- DatumPtr resVect = get_fj_results(fjNode);
- BoolPtr alwaysDone = get_fj_alwaysDone(fjNode);
-
- if (fj_isDone) *fj_isDone = false;
- /*
- * For the next tuple produced by the plan, we need to re-initialize
- * the Fjoin node.
- */
- if (!get_fj_initialized(fjNode))
- {
- /*
- * Initialize all of the Outer nodes
- */
- curNode = 1;
- foreach(tlistP, CDR(tlist))
- {
- List tle = CAR(tlistP);
-
- resVect[curNode] = ExecEvalIter((Iter)tl_expr(tle),
- econtext,
- &isNullVect[curNode],
- &isDone);
- if (isDone)
- isNullVect[curNode] = alwaysDone[curNode] = true;
- else
- alwaysDone[curNode] = false;
-
- curNode++;
- }
-
- /*
- * Initialize the inner node
- */
- resVect[0] = ExecEvalIter((Iter)tl_expr(get_fj_innerNode(fjNode)),
- econtext,
- &isNullVect[0],
- &isDone);
- if (isDone)
- isNullVect[0] = alwaysDone[0] = true;
- else
- alwaysDone[0] = false;
-
- /*
- * Mark the Fjoin as initialized now.
- */
- set_fj_initialized(fjNode, true);
-
- /*
- * If the inner node is always done, then we are done for now
- */
- if (isDone)
- return;
- }
- else
- {
- /*
- * If we're already initialized, all we need to do is get the
- * next inner result and pair it up with the existing outer node
- * result vector. Watch out for the degenerate case, where the
- * inner node never returns results.
- */
-
- /*
- * Fill in nulls for every function that is always done.
- */
- for (curNode=get_fj_nNodes(fjNode)-1; curNode >= 0; curNode--)
- isNullVect[curNode] = alwaysDone[curNode];
-
- if (alwaysDone[0] == true)
- {
- *fj_isDone = FjoinBumpOuterNodes(tlist,
- econtext,
- resVect,
- isNullVect);
- return;
- }
- else
- resVect[0] = ExecEvalIter((Iter)tl_expr(get_fj_innerNode(fjNode)),
- econtext,
- &isNullVect[0],
- &isDone);
- }
-
- /*
- * if the inner node is done
- */
- if (isDone)
- {
- *fj_isDone = FjoinBumpOuterNodes(tlist,
- econtext,
- resVect,
- isNullVect);
- if (*fj_isDone)
- return;
-
- resVect[0] = ExecEvalIter((Iter)tl_expr(get_fj_innerNode(fjNode)),
- econtext,
- &isNullVect[0],
- &isDone);
-
- }
- return;
- }
-
- bool
- FjoinBumpOuterNodes(tlist, econtext, results, nulls)
- List tlist;
- ExprContext econtext;
- DatumPtr results;
- String nulls;
- {
- bool funcIsDone = true;
- Fjoin fjNode = (Fjoin)CAR(tlist);
- String alwaysDone = get_fj_alwaysDone(fjNode);
- List outerList = CDR(tlist);
- List trailers = CDR(tlist);
- int trailNode = 1;
- int curNode = 1;
-
- /*
- * Run through list of functions until we get to one that isn't yet
- * done returning values. Watch out for funcs that are always done.
- */
- while ((funcIsDone == true) && (outerList != LispNil))
- {
- if (alwaysDone[curNode] == true)
- nulls[curNode] = 'n';
- else
- results[curNode] = ExecEvalIter((Iter)tl_expr(CAR(outerList)),
- econtext,
- &nulls[curNode],
- &funcIsDone);
- curNode++;
- outerList = CDR(outerList);
- }
-
- /*
- * If every function is done, then we are done flattening.
- * Mark the Fjoin node unitialized, it is time to get the
- * next tuple from the plan and redo all of the flattening.
- */
- if (funcIsDone)
- {
- set_fj_initialized(fjNode, false);
- return (true);
- }
-
- /*
- * We found a function that wasn't done. Now re-run every function
- * before it. As usual watch out for functions that are always done.
- */
- trailNode = 1;
- while (trailNode != curNode-1)
- {
- if (alwaysDone[trailNode] != true)
- results[trailNode] = ExecEvalIter((Iter)tl_expr(CAR(trailers)),
- econtext,
- &nulls[trailNode],
- &funcIsDone);
- trailNode++;
- trailers = CDR(trailers);
- }
- return false;
- }
-