mirror of https://github.com/postgres/postgres
returns-set boolean field in Func and Oper nodes. This allows cleaner, more reliable tests for expressions returning sets in the planner and parser. For example, a WHERE clause returning a set is now detected and complained of in the parser, not only at runtime.ecpg_big_bison
parent
f9e4f611a1
commit
3389a110d4
@ -1,243 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* execFlatten.c |
||||
* This file handles the nodes associated with flattening sets in the |
||||
* target list of queries containing functions returning sets. |
||||
* |
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.16 2001/10/28 06:25:43 momjian 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 "executor/execFlatten.h" |
||||
#include "executor/executor.h" |
||||
|
||||
#ifdef SETS_FIXED |
||||
static bool FjoinBumpOuterNodes(TargetEntry *tlist, ExprContext *econtext, |
||||
DatumPtr results, char *nulls); |
||||
#endif |
||||
|
||||
|
||||
Datum |
||||
ExecEvalIter(Iter *iterNode, |
||||
ExprContext *econtext, |
||||
bool *isNull, |
||||
ExprDoneCond *isDone) |
||||
{ |
||||
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, isNull, isDone); |
||||
} |
||||
|
||||
void |
||||
ExecEvalFjoin(TargetEntry *tlist, |
||||
ExprContext *econtext, |
||||
bool *isNullVect, |
||||
ExprDoneCond *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 = ExprMultipleResult; |
||||
|
||||
/*
|
||||
* 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 |
@ -1,27 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* execFlatten.h |
||||
* prototypes for execFlatten.c. |
||||
* |
||||
* |
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: execFlatten.h,v 1.16 2001/11/05 17:46:33 momjian Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef EXECFLATTEN_H |
||||
#define EXECFLATTEN_H |
||||
|
||||
#include "nodes/execnodes.h" |
||||
#include "nodes/parsenodes.h" |
||||
|
||||
|
||||
extern Datum ExecEvalIter(Iter *iterNode, ExprContext *econtext, |
||||
bool *isNull, ExprDoneCond *isDone); |
||||
|
||||
extern void ExecEvalFjoin(TargetEntry *tlist, ExprContext *econtext, |
||||
bool *isNullVect, ExprDoneCond *fj_isDone); |
||||
|
||||
#endif /* EXECFLATTEN_H */ |
Loading…
Reference in new issue