execFlatten.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:6k
- /*-------------------------------------------------------------------------
- *
- * execFlatten.c
- * This file handles the nodes associated with flattening sets in the
- * target list of queries containing functions returning sets.
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/executor/execFlatten.c,v 1.9 1999/02/23 07:33:09 thomas Exp $
- *
- *-------------------------------------------------------------------------
- */
- /*
- * 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 "postgres.h"
- #include "nodes/primnodes.h"
- #include "nodes/relation.h"
- #include "nodes/execnodes.h"
- #include "executor/executor.h"
- #include "executor/execFlatten.h"
- #ifdef SETS_FIXED
- static bool FjoinBumpOuterNodes(TargetEntry *tlist, ExprContext *econtext,
- DatumPtr results, char *nulls);
- #endif
- Datum
- ExecEvalIter(Iter *iterNode,
- ExprContext *econtext,
- bool *resultIsNull,
- bool *iterIsDone)
- {
- Node *expression;
- expression = iterNode->iterexpr;
- /*
- * 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(expression, econtext, resultIsNull, iterIsDone);
- }
- void
- ExecEvalFjoin(TargetEntry *tlist,
- ExprContext *econtext,
- bool *isNullVect,
- bool *fj_isDone)
- {
- #ifdef SETS_FIXED
- bool isDone;
- int curNode;
- List *tlistP;
- Fjoin *fjNode = tlist->fjoin;
- DatumPtr resVect = fjNode->fj_results;
- BoolPtr alwaysDone = fjNode->fj_alwaysDone;
- if (fj_isDone)
- *fj_isDone = false;
- /*
- * For the next tuple produced by the plan, we need to re-initialize
- * the Fjoin node.
- */
- if (!fjNode->fj_initialized)
- {
- /*
- * Initialize all of the Outer nodes
- */
- curNode = 1;
- foreach(tlistP, lnext(tlist))
- {
- TargetEntry *tle = lfirst(tlistP);
- resVect[curNode] = ExecEvalIter((Iter *) tle->expr,
- econtext,
- &isNullVect[curNode],
- &isDone);
- if (isDone)
- isNullVect[curNode] = alwaysDone[curNode] = true;
- else
- alwaysDone[curNode] = false;
- curNode++;
- }
- /*
- * Initialize the inner node
- */
- resVect[0] = ExecEvalIter((Iter *) fjNode->fj_innerNode->expr,
- econtext,
- &isNullVect[0],
- &isDone);
- if (isDone)
- isNullVect[0] = alwaysDone[0] = true;
- else
- alwaysDone[0] = false;
- /*
- * Mark the Fjoin as initialized now.
- */
- fjNode->fj_initialized = 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 = fjNode->fj_nNodes - 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 *) fjNode->fj_innerNode->expr,
- 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 *) fjNode->fj_innerNode->expr,
- econtext,
- &isNullVect[0],
- &isDone);
- }
- #endif
- return;
- }
- #ifdef SETS_FIXED
- static bool
- FjoinBumpOuterNodes(TargetEntry *tlist,
- ExprContext *econtext,
- DatumPtr results,
- char *nulls)
- {
- bool funcIsDone = true;
- Fjoin *fjNode = tlist->fjoin;
- char *alwaysDone = fjNode->fj_alwaysDone;
- List *outerList = lnext(tlist);
- List *trailers = lnext(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 != NIL))
- {
- TargetEntry *tle = lfirst(outerList);
- if (alwaysDone[curNode] == true)
- nulls[curNode] = 'n';
- else
- results[curNode] = ExecEvalIter((Iter) tle->expr,
- econtext,
- &nulls[curNode],
- &funcIsDone);
- curNode++;
- outerList = lnext(outerList);
- }
- /*
- * If every function is done, then we are done flattening. Mark the
- * Fjoin node uninitialized, 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)
- {
- TargetEntry *tle = lfirst(trailers);
- if (alwaysDone[trailNode] != true)
- results[trailNode] = ExecEvalIter((Iter) tle->expr,
- econtext,
- &nulls[trailNode],
- &funcIsDone);
- trailNode++;
- trailers = lnext(trailers);
- }
- return false;
- }
- #endif