diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/executor/execFlatten.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/executor/execFlatten.c')
-rw-r--r-- | src/backend/executor/execFlatten.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/backend/executor/execFlatten.c b/src/backend/executor/execFlatten.c new file mode 100644 index 00000000000..646c571506e --- /dev/null +++ b/src/backend/executor/execFlatten.c @@ -0,0 +1,236 @@ +/*------------------------------------------------------------------------- + * + * 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: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.1.1.1 1996/07/09 06:21:24 scrappy 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" + +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; +} + +bool +FjoinBumpOuterNodes(TargetEntry *tlist, + ExprContext *econtext, + DatumPtr results, + char *nulls) +{ +#ifdef SETS_FIXED + 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 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) + { + 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 + return false; +} |