mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Get rid of long-since-vestigial Iter node type, in favor of adding a
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.
This commit is contained in:
@ -4,7 +4,7 @@
|
||||
# Makefile for executor
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.18 2002/05/12 20:10:02 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.19 2002/05/12 23:43:02 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -12,7 +12,7 @@ subdir = src/backend/executor
|
||||
top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
|
||||
OBJS = execAmi.o execJunk.o execMain.o \
|
||||
execProcnode.o execQual.o execScan.o execTuples.o \
|
||||
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \
|
||||
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
|
||||
|
@ -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
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.92 2002/05/12 20:10:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.93 2002/05/12 23:43:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -35,7 +35,6 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "executor/execFlatten.h"
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/functions.h"
|
||||
#include "executor/nodeSubplan.h"
|
||||
@ -1336,12 +1335,6 @@ ExecEvalExpr(Node *expression,
|
||||
case T_Param:
|
||||
retDatum = ExecEvalParam((Param *) expression, econtext, isNull);
|
||||
break;
|
||||
case T_Iter:
|
||||
retDatum = ExecEvalIter((Iter *) expression,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
case T_Aggref:
|
||||
retDatum = ExecEvalAggref((Aggref *) expression, econtext, isNull);
|
||||
break;
|
||||
|
Reference in New Issue
Block a user