Commit 3389a110 authored by Tom Lane's avatar Tom Lane

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.
parent f9e4f611
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.198 2002/05/03 04:11:08 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.199 2002/05/12 23:43:02 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "parser/parse_target.h" #include "parser/parse_target.h"
...@@ -1626,9 +1627,7 @@ AddRelationRawConstraints(Relation rel, ...@@ -1626,9 +1627,7 @@ AddRelationRawConstraints(Relation rel,
/* /*
* Make sure it yields a boolean result. * Make sure it yields a boolean result.
*/ */
if (exprType(expr) != BOOLOID) expr = coerce_to_boolean(expr, "CHECK");
elog(ERROR, "CHECK constraint expression '%s' does not yield boolean result",
ccname);
/* /*
* Make sure no outside relations are referred to. * Make sure no outside relations are referred to.
...@@ -1764,6 +1763,12 @@ cookDefault(ParseState *pstate, ...@@ -1764,6 +1763,12 @@ cookDefault(ParseState *pstate,
if (contain_var_clause(expr)) if (contain_var_clause(expr))
elog(ERROR, "cannot use column references in DEFAULT clause"); elog(ERROR, "cannot use column references in DEFAULT clause");
/*
* It can't return a set either.
*/
if (expression_returns_set(expr))
elog(ERROR, "DEFAULT clause must not return a set");
/* /*
* No subplans or aggregates, either... * No subplans or aggregates, either...
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.12 2002/04/27 21:24:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.13 2002/05/12 23:43:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/parse.h" #include "parser/parse.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
...@@ -2461,9 +2462,7 @@ AlterTableAddConstraint(Oid myrelid, ...@@ -2461,9 +2462,7 @@ AlterTableAddConstraint(Oid myrelid,
/* /*
* Make sure it yields a boolean result. * Make sure it yields a boolean result.
*/ */
if (exprType(expr) != BOOLOID) expr = coerce_to_boolean(expr, "CHECK");
elog(ERROR, "CHECK '%s' does not yield boolean result",
name);
/* /*
* Make sure no outside relations are * Make sure no outside relations are
...@@ -2473,6 +2472,14 @@ AlterTableAddConstraint(Oid myrelid, ...@@ -2473,6 +2472,14 @@ AlterTableAddConstraint(Oid myrelid,
elog(ERROR, "Only relation '%s' can be referenced in CHECK", elog(ERROR, "Only relation '%s' can be referenced in CHECK",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
/*
* No subplans or aggregates, either...
*/
if (contain_subplans(expr))
elog(ERROR, "cannot use subselect in CHECK constraint expression");
if (contain_agg_clause(expr))
elog(ERROR, "cannot use aggregate function in CHECK constraint expression");
/* /*
* Might as well try to reduce any * Might as well try to reduce any
* constant expressions. * constant expressions.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Makefile for executor # Makefile for executor
# #
# IDENTIFICATION # 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 ...@@ -12,7 +12,7 @@ subdir = src/backend/executor
top_builddir = ../../.. top_builddir = ../../..
include $(top_builddir)/src/Makefile.global 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 \ execProcnode.o execQual.o execScan.o execTuples.o \
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \ execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
......
/*-------------------------------------------------------------------------
*
* 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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -35,7 +35,6 @@
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "executor/execFlatten.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "executor/functions.h" #include "executor/functions.h"
#include "executor/nodeSubplan.h" #include "executor/nodeSubplan.h"
...@@ -1336,12 +1335,6 @@ ExecEvalExpr(Node *expression, ...@@ -1336,12 +1335,6 @@ ExecEvalExpr(Node *expression,
case T_Param: case T_Param:
retDatum = ExecEvalParam((Param *) expression, econtext, isNull); retDatum = ExecEvalParam((Param *) expression, econtext, isNull);
break; break;
case T_Iter:
retDatum = ExecEvalIter((Iter *) expression,
econtext,
isNull,
isDone);
break;
case T_Aggref: case T_Aggref:
retDatum = ExecEvalAggref((Aggref *) expression, econtext, isNull); retDatum = ExecEvalAggref((Aggref *) expression, econtext, isNull);
break; break;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.183 2002/05/12 20:10:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.184 2002/05/12 23:43:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -764,6 +764,7 @@ _copyOper(Oper *from) ...@@ -764,6 +764,7 @@ _copyOper(Oper *from)
newnode->opno = from->opno; newnode->opno = from->opno;
newnode->opid = from->opid; newnode->opid = from->opid;
newnode->opresulttype = from->opresulttype; newnode->opresulttype = from->opresulttype;
newnode->opretset = from->opretset;
/* Do not copy the run-time state, if any */ /* Do not copy the run-time state, if any */
newnode->op_fcache = NULL; newnode->op_fcache = NULL;
...@@ -852,7 +853,8 @@ _copyFunc(Func *from) ...@@ -852,7 +853,8 @@ _copyFunc(Func *from)
* copy remainder of node * copy remainder of node
*/ */
newnode->funcid = from->funcid; newnode->funcid = from->funcid;
newnode->functype = from->functype; newnode->funcresulttype = from->funcresulttype;
newnode->funcretset = from->funcretset;
/* Do not copy the run-time state, if any */ /* Do not copy the run-time state, if any */
newnode->func_fcache = NULL; newnode->func_fcache = NULL;
...@@ -1433,17 +1435,6 @@ _copyJoinInfo(JoinInfo *from) ...@@ -1433,17 +1435,6 @@ _copyJoinInfo(JoinInfo *from)
return newnode; return newnode;
} }
static Iter *
_copyIter(Iter *from)
{
Iter *newnode = makeNode(Iter);
Node_Copy(from, newnode, iterexpr);
newnode->itertype = from->itertype;
return newnode;
}
static Stream * static Stream *
_copyStream(Stream *from) _copyStream(Stream *from)
{ {
...@@ -2729,9 +2720,6 @@ copyObject(void *from) ...@@ -2729,9 +2720,6 @@ copyObject(void *from)
case T_ArrayRef: case T_ArrayRef:
retval = _copyArrayRef(from); retval = _copyArrayRef(from);
break; break;
case T_Iter:
retval = _copyIter(from);
break;
case T_FieldSelect: case T_FieldSelect:
retval = _copyFieldSelect(from); retval = _copyFieldSelect(from);
break; break;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.131 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.132 2002/05/12 23:43:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -130,6 +130,8 @@ _equalOper(Oper *a, Oper *b) ...@@ -130,6 +130,8 @@ _equalOper(Oper *a, Oper *b)
return false; return false;
if (a->opresulttype != b->opresulttype) if (a->opresulttype != b->opresulttype)
return false; return false;
if (a->opretset != b->opretset)
return false;
/* /*
* We do not examine opid or op_fcache, since these are logically * We do not examine opid or op_fcache, since these are logically
...@@ -139,7 +141,8 @@ _equalOper(Oper *a, Oper *b) ...@@ -139,7 +141,8 @@ _equalOper(Oper *a, Oper *b)
* (Besides, op_fcache is executor state, which we don't check --- see * (Besides, op_fcache is executor state, which we don't check --- see
* notes at head of file.) * notes at head of file.)
* *
* It's probably not really necessary to check opresulttype either... * It's probably not really necessary to check opresulttype or opretset,
* either...
*/ */
return true; return true;
...@@ -210,7 +213,9 @@ _equalFunc(Func *a, Func *b) ...@@ -210,7 +213,9 @@ _equalFunc(Func *a, Func *b)
{ {
if (a->funcid != b->funcid) if (a->funcid != b->funcid)
return false; return false;
if (a->functype != b->functype) if (a->funcresulttype != b->funcresulttype)
return false;
if (a->funcretset != b->funcretset)
return false; return false;
/* Note we do not look at func_fcache; see notes for _equalOper */ /* Note we do not look at func_fcache; see notes for _equalOper */
...@@ -538,12 +543,6 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b) ...@@ -538,12 +543,6 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
return true; return true;
} }
static bool
_equalIter(Iter *a, Iter *b)
{
return equal(a->iterexpr, b->iterexpr);
}
static bool static bool
_equalStream(Stream *a, Stream *b) _equalStream(Stream *a, Stream *b)
{ {
...@@ -1884,9 +1883,6 @@ equal(void *a, void *b) ...@@ -1884,9 +1883,6 @@ equal(void *a, void *b)
case T_ArrayRef: case T_ArrayRef:
retval = _equalArrayRef(a, b); retval = _equalArrayRef(a, b);
break; break;
case T_Iter:
retval = _equalIter(a, b);
break;
case T_RelabelType: case T_RelabelType:
retval = _equalRelabelType(a, b); retval = _equalRelabelType(a, b);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.31 2002/04/16 23:08:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.32 2002/05/12 23:43:02 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -56,13 +56,15 @@ makeSimpleA_Expr(int oper, const char *name, ...@@ -56,13 +56,15 @@ makeSimpleA_Expr(int oper, const char *name,
Oper * Oper *
makeOper(Oid opno, makeOper(Oid opno,
Oid opid, Oid opid,
Oid opresulttype) Oid opresulttype,
bool opretset)
{ {
Oper *oper = makeNode(Oper); Oper *oper = makeNode(Oper);
oper->opno = opno; oper->opno = opno;
oper->opid = opid; oper->opid = opid;
oper->opresulttype = opresulttype; oper->opresulttype = opresulttype;
oper->opretset = opretset;
oper->op_fcache = NULL; oper->op_fcache = NULL;
return oper; return oper;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.158 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.159 2002/05/12 23:43:02 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -850,9 +850,11 @@ _outArrayRef(StringInfo str, ArrayRef *node) ...@@ -850,9 +850,11 @@ _outArrayRef(StringInfo str, ArrayRef *node)
static void static void
_outFunc(StringInfo str, Func *node) _outFunc(StringInfo str, Func *node)
{ {
appendStringInfo(str, " FUNC :funcid %u :functype %u ", appendStringInfo(str,
" FUNC :funcid %u :funcresulttype %u :funcretset %s ",
node->funcid, node->funcid,
node->functype); node->funcresulttype,
booltostr(node->funcretset));
} }
/* /*
...@@ -862,10 +864,11 @@ static void ...@@ -862,10 +864,11 @@ static void
_outOper(StringInfo str, Oper *node) _outOper(StringInfo str, Oper *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" OPER :opno %u :opid %u :opresulttype %u ", " OPER :opno %u :opid %u :opresulttype %u :opretset %s ",
node->opno, node->opno,
node->opid, node->opid,
node->opresulttype); node->opresulttype,
booltostr(node->opretset));
} }
/* /*
...@@ -1246,13 +1249,6 @@ _outDatum(StringInfo str, Datum value, int typlen, bool typbyval) ...@@ -1246,13 +1249,6 @@ _outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
} }
} }
static void
_outIter(StringInfo str, Iter *node)
{
appendStringInfo(str, " ITER :iterexpr ");
_outNode(str, node->iterexpr);
}
static void static void
_outStream(StringInfo str, Stream *node) _outStream(StringInfo str, Stream *node)
{ {
...@@ -1731,9 +1727,6 @@ _outNode(StringInfo str, void *obj) ...@@ -1731,9 +1727,6 @@ _outNode(StringInfo str, void *obj)
case T_JoinInfo: case T_JoinInfo:
_outJoinInfo(str, obj); _outJoinInfo(str, obj);
break; break;
case T_Iter:
_outIter(str, obj);
break;
case T_Stream: case T_Stream:
_outStream(str, obj); _outStream(str, obj);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.121 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.122 2002/05/12 23:43:02 tgl Exp $
* *
* NOTES * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -1083,9 +1083,13 @@ _readFunc(void) ...@@ -1083,9 +1083,13 @@ _readFunc(void)
token = pg_strtok(&length); /* now read it */ token = pg_strtok(&length); /* now read it */
local_node->funcid = atooid(token); local_node->funcid = atooid(token);
token = pg_strtok(&length); /* get :functype */ token = pg_strtok(&length); /* get :funcresulttype */
token = pg_strtok(&length); /* now read it */ token = pg_strtok(&length); /* now read it */
local_node->functype = atooid(token); local_node->funcresulttype = atooid(token);
token = pg_strtok(&length); /* get :funcretset */
token = pg_strtok(&length); /* now read it */
local_node->funcretset = strtobool(token);
local_node->func_fcache = NULL; local_node->func_fcache = NULL;
...@@ -1119,6 +1123,10 @@ _readOper(void) ...@@ -1119,6 +1123,10 @@ _readOper(void)
token = pg_strtok(&length); /* now read it */ token = pg_strtok(&length); /* now read it */
local_node->opresulttype = atooid(token); local_node->opresulttype = atooid(token);
token = pg_strtok(&length); /* get :opretset */
token = pg_strtok(&length); /* now read it */
local_node->opretset = strtobool(token);
local_node->op_fcache = NULL; local_node->op_fcache = NULL;
return local_node; return local_node;
...@@ -1991,26 +1999,6 @@ _readJoinInfo(void) ...@@ -1991,26 +1999,6 @@ _readJoinInfo(void)
return local_node; return local_node;
} }
/* ----------------
* _readIter()
*
* ----------------
*/
static Iter *
_readIter(void)
{
Iter *local_node;
char *token;
int length;
local_node = makeNode(Iter);
token = pg_strtok(&length); /* eat :iterexpr */
local_node->iterexpr = nodeRead(true); /* now read it */
return local_node;
}
/* ---------------- /* ----------------
* parsePlanString * parsePlanString
...@@ -2124,8 +2112,6 @@ parsePlanString(void) ...@@ -2124,8 +2112,6 @@ parsePlanString(void)
return_value = _readRestrictInfo(); return_value = _readRestrictInfo();
else if (length == 8 && strncmp(token, "JOININFO", length) == 0) else if (length == 8 && strncmp(token, "JOININFO", length) == 0)
return_value = _readJoinInfo(); return_value = _readJoinInfo();
else if (length == 4 && strncmp(token, "ITER", length) == 0)
return_value = _readIter();
else if (length == 5 && strncmp(token, "QUERY", length) == 0) else if (length == 5 && strncmp(token, "QUERY", length) == 0)
return_value = _readQuery(); return_value = _readQuery();
else if (length == 6 && strncmp(token, "NOTIFY", length) == 0) else if (length == 6 && strncmp(token, "NOTIFY", length) == 0)
......
...@@ -42,7 +42,8 @@ base rels of the query. ...@@ -42,7 +42,8 @@ base rels of the query.
Possible Paths for a primitive table relation include plain old sequential Possible Paths for a primitive table relation include plain old sequential
scan, plus index scans for any indexes that exist on the table. A subquery scan, plus index scans for any indexes that exist on the table. A subquery
base relation just has one Path, a "SubqueryScan" path (which links to the base relation just has one Path, a "SubqueryScan" path (which links to the
subplan that was built by a recursive invocation of the planner). subplan that was built by a recursive invocation of the planner). Likewise
a function-RTE base relation has only one possible Path.
Joins always occur using two RelOptInfos. One is outer, the other inner. Joins always occur using two RelOptInfos. One is outer, the other inner.
Outers drive lookups of values in the inner. In a nested loop, lookups of Outers drive lookups of values in the inner. In a nested loop, lookups of
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.84 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.85 2002/05/12 23:43:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -312,8 +312,8 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel, ...@@ -312,8 +312,8 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel,
* checking that seems more work than it's worth. In any case, a * checking that seems more work than it's worth. In any case, a
* plain DISTINCT is safe to push down past.) * plain DISTINCT is safe to push down past.)
* *
* 3. If the subquery has any ITER nodes (ie, functions returning sets) * 3. If the subquery has any functions returning sets in its target list,
* in its target list, we do not push down any quals, since the quals * we do not push down any quals, since the quals
* might refer to those tlist items, which would mean we'd introduce * might refer to those tlist items, which would mean we'd introduce
* functions-returning-sets into the subquery's WHERE/HAVING quals. * functions-returning-sets into the subquery's WHERE/HAVING quals.
* (It'd be sufficient to not push down quals that refer to those * (It'd be sufficient to not push down quals that refer to those
...@@ -333,7 +333,7 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel, ...@@ -333,7 +333,7 @@ set_subquery_pathlist(Query *root, RelOptInfo *rel,
subquery->limitOffset == NULL && subquery->limitOffset == NULL &&
subquery->limitCount == NULL && subquery->limitCount == NULL &&
!has_distinct_on_clause(subquery) && !has_distinct_on_clause(subquery) &&
!contain_iter_clause((Node *) subquery->targetList)) !expression_returns_set((Node *) subquery->targetList))
{ {
/* OK to consider pushing down individual quals */ /* OK to consider pushing down individual quals */
List *upperrestrictlist = NIL; List *upperrestrictlist = NIL;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.116 2002/04/16 23:08:10 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.117 2002/05/12 23:43:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1316,7 +1316,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause) ...@@ -1316,7 +1316,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
*/ */
test_oper = makeOper(test_op, /* opno */ test_oper = makeOper(test_op, /* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
BOOLOID); /* opresulttype */ BOOLOID, /* opresulttype */
false); /* opretset */
replace_opid(test_oper); replace_opid(test_oper);
test_expr = make_opclause(test_oper, test_expr = make_opclause(test_oper,
(Var *) clause_const, (Var *) clause_const,
...@@ -2020,7 +2021,7 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -2020,7 +2021,7 @@ prefix_quals(Var *leftop, Oid expr_op,
if (oproid == InvalidOid) if (oproid == InvalidOid)
elog(ERROR, "prefix_quals: no = operator for type %u", datatype); elog(ERROR, "prefix_quals: no = operator for type %u", datatype);
con = string_to_const(prefix, datatype); con = string_to_const(prefix, datatype);
op = makeOper(oproid, InvalidOid, BOOLOID); op = makeOper(oproid, InvalidOid, BOOLOID, false);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = makeList1(expr); result = makeList1(expr);
return result; return result;
...@@ -2035,7 +2036,7 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -2035,7 +2036,7 @@ prefix_quals(Var *leftop, Oid expr_op,
if (oproid == InvalidOid) if (oproid == InvalidOid)
elog(ERROR, "prefix_quals: no >= operator for type %u", datatype); elog(ERROR, "prefix_quals: no >= operator for type %u", datatype);
con = string_to_const(prefix, datatype); con = string_to_const(prefix, datatype);
op = makeOper(oproid, InvalidOid, BOOLOID); op = makeOper(oproid, InvalidOid, BOOLOID, false);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = makeList1(expr); result = makeList1(expr);
...@@ -2051,7 +2052,7 @@ prefix_quals(Var *leftop, Oid expr_op, ...@@ -2051,7 +2052,7 @@ prefix_quals(Var *leftop, Oid expr_op,
if (oproid == InvalidOid) if (oproid == InvalidOid)
elog(ERROR, "prefix_quals: no < operator for type %u", datatype); elog(ERROR, "prefix_quals: no < operator for type %u", datatype);
con = string_to_const(greaterstr, datatype); con = string_to_const(greaterstr, datatype);
op = makeOper(oproid, InvalidOid, BOOLOID); op = makeOper(oproid, InvalidOid, BOOLOID, false);
expr = make_opclause(op, leftop, (Var *) con); expr = make_opclause(op, leftop, (Var *) con);
result = lappend(result, expr); result = lappend(result, expr);
pfree(greaterstr); pfree(greaterstr);
...@@ -2116,7 +2117,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) ...@@ -2116,7 +2117,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
opr1right = network_scan_first(rightop); opr1right = network_scan_first(rightop);
op = makeOper(opr1oid, InvalidOid, BOOLOID); op = makeOper(opr1oid, InvalidOid, BOOLOID, false);
expr = make_opclause(op, leftop, expr = make_opclause(op, leftop,
(Var *) makeConst(datatype, -1, opr1right, (Var *) makeConst(datatype, -1, opr1right,
false, false, false, false)); false, false, false, false));
...@@ -2131,7 +2132,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) ...@@ -2131,7 +2132,7 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
opr2right = network_scan_last(rightop); opr2right = network_scan_last(rightop);
op = makeOper(opr2oid, InvalidOid, BOOLOID); op = makeOper(opr2oid, InvalidOid, BOOLOID, false);
expr = make_opclause(op, leftop, expr = make_opclause(op, leftop,
(Var *) makeConst(datatype, -1, opr2right, (Var *) makeConst(datatype, -1, opr2right,
false, false, false, false)); false, false, false, false));
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.37 2002/03/12 00:51:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.38 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -518,7 +518,8 @@ build_index_pathkeys(Query *root, ...@@ -518,7 +518,8 @@ build_index_pathkeys(Query *root,
List *funcargs = NIL; List *funcargs = NIL;
funcnode->funcid = index->indproc; funcnode->funcid = index->indproc;
funcnode->functype = get_func_rettype(index->indproc); funcnode->funcresulttype = get_func_rettype(index->indproc);
funcnode->funcretset = false; /* can never be a set */
funcnode->func_fcache = NULL; funcnode->func_fcache = NULL;
while (*indexkeys != 0) while (*indexkeys != 0)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.69 2002/04/28 19:54:28 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.70 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -764,9 +764,10 @@ process_implied_equality(Query *root, Node *item1, Node *item2, ...@@ -764,9 +764,10 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
clause = makeNode(Expr); clause = makeNode(Expr);
clause->typeOid = BOOLOID; clause->typeOid = BOOLOID;
clause->opType = OP_EXPR; clause->opType = OP_EXPR;
clause->oper = (Node *) makeOper(oprid(eq_operator), /* opno */ clause->oper = (Node *) makeOper(oprid(eq_operator),/* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
BOOLOID); /* operator result type */ BOOLOID, /* opresulttype */
false); /* opretset */
clause->args = makeList2(item1, item2); clause->args = makeList2(item1, item2);
ReleaseSysCache(eq_operator); ReleaseSysCache(eq_operator);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.116 2002/04/28 19:54:28 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.117 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -498,7 +498,7 @@ is_simple_subquery(Query *subquery) ...@@ -498,7 +498,7 @@ is_simple_subquery(Query *subquery)
* set-returning functions into places where they mustn't go, * set-returning functions into places where they mustn't go,
* such as quals of higher queries. * such as quals of higher queries.
*/ */
if (contain_iter_clause((Node *) subquery->targetList)) if (expression_returns_set((Node *) subquery->targetList))
return false; return false;
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.30 2001/10/25 05:49:33 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.31 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -502,7 +502,8 @@ push_nots(Expr *qual) ...@@ -502,7 +502,8 @@ push_nots(Expr *qual)
{ {
Oper *op = (Oper *) makeOper(negator, Oper *op = (Oper *) makeOper(negator,
InvalidOid, InvalidOid,
oper->opresulttype); oper->opresulttype,
oper->opretset);
return make_opclause(op, get_leftop(qual), get_rightop(qual)); return make_opclause(op, get_leftop(qual), get_rightop(qual));
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.98 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.99 2002/05/12 23:43:03 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -47,7 +47,7 @@ typedef struct ...@@ -47,7 +47,7 @@ typedef struct
static bool contain_agg_clause_walker(Node *node, void *context); static bool contain_agg_clause_walker(Node *node, void *context);
static bool pull_agg_clause_walker(Node *node, List **listptr); static bool pull_agg_clause_walker(Node *node, List **listptr);
static bool contain_iter_clause_walker(Node *node, void *context); static bool expression_returns_set_walker(Node *node, void *context);
static bool contain_subplans_walker(Node *node, void *context); static bool contain_subplans_walker(Node *node, void *context);
static bool pull_subplans_walker(Node *node, List **listptr); static bool pull_subplans_walker(Node *node, List **listptr);
static bool check_subplans_for_ungrouped_vars_walker(Node *node, static bool check_subplans_for_ungrouped_vars_walker(Node *node,
...@@ -74,7 +74,7 @@ make_clause(int type, Node *oper, List *args) ...@@ -74,7 +74,7 @@ make_clause(int type, Node *oper, List *args)
expr->typeOid = ((Oper *) oper)->opresulttype; expr->typeOid = ((Oper *) oper)->opresulttype;
break; break;
case FUNC_EXPR: case FUNC_EXPR:
expr->typeOid = ((Func *) oper)->functype; expr->typeOid = ((Func *) oper)->funcresulttype;
break; break;
default: default:
elog(ERROR, "make_clause: unsupported type %d", type); elog(ERROR, "make_clause: unsupported type %d", type);
...@@ -195,7 +195,7 @@ make_funcclause(Func *func, List *funcargs) ...@@ -195,7 +195,7 @@ make_funcclause(Func *func, List *funcargs)
{ {
Expr *expr = makeNode(Expr); Expr *expr = makeNode(Expr);
expr->typeOid = func->functype; expr->typeOid = func->funcresulttype;
expr->opType = FUNC_EXPR; expr->opType = FUNC_EXPR;
expr->oper = (Node *) func; expr->oper = (Node *) func;
expr->args = funcargs; expr->args = funcargs;
...@@ -453,36 +453,61 @@ pull_agg_clause_walker(Node *node, List **listptr) ...@@ -453,36 +453,61 @@ pull_agg_clause_walker(Node *node, List **listptr)
/***************************************************************************** /*****************************************************************************
* Iter clause manipulation * Support for expressions returning sets
*****************************************************************************/ *****************************************************************************/
/* /*
* contain_iter_clause * expression_returns_set
* Recursively search for Iter nodes within a clause. * Test whethe an expression returns a set result.
* *
* Returns true if any Iter found. * Because we use expression_tree_walker(), this can also be applied to
* * whole targetlists; it'll produce TRUE if any one of the tlist items
* XXX Iter is a crock. It'd be better to look directly at each function * returns a set.
* or operator to see if it can return a set. However, that would require
* a lot of extra cycles as things presently stand. The return-type info
* for function and operator nodes should be extended to include whether
* the return is a set.
*/ */
bool bool
contain_iter_clause(Node *clause) expression_returns_set(Node *clause)
{ {
return contain_iter_clause_walker(clause, NULL); return expression_returns_set_walker(clause, NULL);
} }
static bool static bool
contain_iter_clause_walker(Node *node, void *context) expression_returns_set_walker(Node *node, void *context)
{ {
if (node == NULL) if (node == NULL)
return false; return false;
if (IsA(node, Iter)) if (IsA(node, Expr))
return true; /* abort the tree traversal and return {
* true */ Expr *expr = (Expr *) node;
return expression_tree_walker(node, contain_iter_clause_walker, context);
switch (expr->opType)
{
case OP_EXPR:
if (((Oper *) expr->oper)->opretset)
return true;
/* else fall through to check args */
break;
case FUNC_EXPR:
if (((Func *) expr->oper)->funcretset)
return true;
/* else fall through to check args */
break;
case OR_EXPR:
case AND_EXPR:
case NOT_EXPR:
/* Booleans can't return a set, so no need to recurse */
return false;
case SUBPLAN_EXPR:
/* Subplans can't presently return sets either */
return false;
}
}
/* Avoid recursion for some other cases that can't return a set */
if (IsA(node, Aggref))
return false;
if (IsA(node, SubLink))
return false;
return expression_tree_walker(node, expression_returns_set_walker,
context);
} }
/***************************************************************************** /*****************************************************************************
...@@ -1043,7 +1068,8 @@ CommuteClause(Expr *clause) ...@@ -1043,7 +1068,8 @@ CommuteClause(Expr *clause)
commu = makeOper(optup->t_data->t_oid, commu = makeOper(optup->t_data->t_oid,
commuTup->oprcode, commuTup->oprcode,
commuTup->oprresult); commuTup->oprresult,
((Oper *) clause->oper)->opretset);
ReleaseSysCache(optup); ReleaseSysCache(optup);
...@@ -1073,8 +1099,7 @@ CommuteClause(Expr *clause) ...@@ -1073,8 +1099,7 @@ CommuteClause(Expr *clause)
* results even with constant inputs, "nextval()" being the classic * results even with constant inputs, "nextval()" being the classic
* example. Functions that are not marked "immutable" in pg_proc * example. Functions that are not marked "immutable" in pg_proc
* will not be pre-evaluated here, although we will reduce their * will not be pre-evaluated here, although we will reduce their
* arguments as far as possible. Functions that are the arguments * arguments as far as possible.
* of Iter nodes are also not evaluated.
* *
* We assume that the tree has already been type-checked and contains * We assume that the tree has already been type-checked and contains
* only operators and functions that are reasonable to try to execute. * only operators and functions that are reasonable to try to execute.
...@@ -1398,37 +1423,6 @@ eval_const_expressions_mutator(Node *node, void *context) ...@@ -1398,37 +1423,6 @@ eval_const_expressions_mutator(Node *node, void *context)
newcase->defresult = defresult; newcase->defresult = defresult;
return (Node *) newcase; return (Node *) newcase;
} }
if (IsA(node, Iter))
{
/*
* The argument of an Iter is normally a function call. We must
* not try to eliminate the function, but we can try to simplify
* its arguments. If, by chance, the arg is NOT a function then
* we go ahead and try to simplify it (by falling into
* expression_tree_mutator). Is that the right thing?
*/
Iter *iter = (Iter *) node;
if (is_funcclause(iter->iterexpr))
{
Expr *func = (Expr *) iter->iterexpr;
Expr *newfunc;
Iter *newiter;
newfunc = makeNode(Expr);
newfunc->typeOid = func->typeOid;
newfunc->opType = func->opType;
newfunc->oper = func->oper;
newfunc->args = (List *)
expression_tree_mutator((Node *) func->args,
eval_const_expressions_mutator,
(void *) context);
newiter = makeNode(Iter);
newiter->iterexpr = (Node *) newfunc;
newiter->itertype = iter->itertype;
return (Node *) newiter;
}
}
/* /*
* For any node type not handled above, we recurse using * For any node type not handled above, we recurse using
...@@ -1501,8 +1495,9 @@ simplify_op_or_func(Expr *expr, List *args) ...@@ -1501,8 +1495,9 @@ simplify_op_or_func(Expr *expr, List *args)
* Get the function procedure's OID and look to see whether it is * Get the function procedure's OID and look to see whether it is
* marked immutable. * marked immutable.
* *
* XXX would it be better to take the result type from the pg_proc tuple, * Note we take the result type from the Oper or Func node, not the
* rather than the Oper or Func node? * pg_proc tuple; probably necessary for binary-compatibility cases.
*
*/ */
if (expr->opType == OP_EXPR) if (expr->opType == OP_EXPR)
{ {
...@@ -1517,7 +1512,7 @@ simplify_op_or_func(Expr *expr, List *args) ...@@ -1517,7 +1512,7 @@ simplify_op_or_func(Expr *expr, List *args)
Func *func = (Func *) expr->oper; Func *func = (Func *) expr->oper;
funcid = func->funcid; funcid = func->funcid;
result_typeid = func->functype; result_typeid = func->funcresulttype;
} }
/* /*
...@@ -1747,8 +1742,6 @@ expression_tree_walker(Node *node, ...@@ -1747,8 +1742,6 @@ expression_tree_walker(Node *node,
break; break;
case T_Aggref: case T_Aggref:
return walker(((Aggref *) node)->target, context); return walker(((Aggref *) node)->target, context);
case T_Iter:
return walker(((Iter *) node)->iterexpr, context);
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *aref = (ArrayRef *) node; ArrayRef *aref = (ArrayRef *) node;
...@@ -2083,16 +2076,6 @@ expression_tree_mutator(Node *node, ...@@ -2083,16 +2076,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode; return (Node *) newnode;
} }
break; break;
case T_Iter:
{
Iter *iter = (Iter *) node;
Iter *newnode;
FLATCOPY(newnode, iter, Iter);
MUTATE(newnode->iterexpr, iter->iterexpr, Node *);
return (Node *) newnode;
}
break;
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *arrayref = (ArrayRef *) node; ArrayRef *arrayref = (ArrayRef *) node;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.91 2002/05/12 20:10:04 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.92 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -285,14 +285,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) ...@@ -285,14 +285,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
*/ */
result = transformExpr(pstate, result); result = transformExpr(pstate, result);
/* result = coerce_to_boolean(result, "JOIN/USING");
* We expect the result to yield bool directly, otherwise complain. We
* could try coerce_to_boolean() here, but it seems likely that an "="
* operator that doesn't return bool is wrong anyway.
*/
if (exprType(result) != BOOLOID)
elog(ERROR, "JOIN/USING clause must return type boolean, not type %s",
format_type_be(exprType(result)));
return result; return result;
} /* transformJoinUsingClause() */ } /* transformJoinUsingClause() */
...@@ -326,9 +319,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, ...@@ -326,9 +319,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
/* This part is just like transformWhereClause() */ /* This part is just like transformWhereClause() */
result = transformExpr(pstate, j->quals); result = transformExpr(pstate, j->quals);
if (!coerce_to_boolean(pstate, &result)) result = coerce_to_boolean(result, "JOIN/ON");
elog(ERROR, "JOIN/ON clause must return type boolean, not type %s",
format_type_be(exprType(result)));
pstate->p_namespace = save_namespace; pstate->p_namespace = save_namespace;
...@@ -486,14 +477,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) ...@@ -486,14 +477,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
elog(ERROR, "cannot use subselect in FROM function expression"); elog(ERROR, "cannot use subselect in FROM function expression");
/* /*
* Remove any Iter nodes added by parse_func.c. We oughta get rid of * Insist we have a bare function call (explain.c is the only place
* Iter completely ...
*/
while (funcexpr && IsA(funcexpr, Iter))
funcexpr = ((Iter *) funcexpr)->iterexpr;
/*
* Insist we now have a bare function call (explain.c is the only place
* that depends on this, I think). If this fails, it's probably because * that depends on this, I think). If this fails, it's probably because
* transformExpr interpreted the function notation as a type coercion. * transformExpr interpreted the function notation as a type coercion.
*/ */
...@@ -947,9 +931,7 @@ transformWhereClause(ParseState *pstate, Node *clause) ...@@ -947,9 +931,7 @@ transformWhereClause(ParseState *pstate, Node *clause)
qual = transformExpr(pstate, clause); qual = transformExpr(pstate, clause);
if (!coerce_to_boolean(pstate, &qual)) qual = coerce_to_boolean(qual, "WHERE");
elog(ERROR, "WHERE clause must return type boolean, not type %s",
format_type_be(exprType(qual)));
return qual; return qual;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.71 2002/04/25 02:56:55 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.72 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -313,26 +313,37 @@ coerce_type_typmod(ParseState *pstate, Node *node, ...@@ -313,26 +313,37 @@ coerce_type_typmod(ParseState *pstate, Node *node,
/* coerce_to_boolean() /* coerce_to_boolean()
* Coerce an argument of a construct that requires boolean input * Coerce an argument of a construct that requires boolean input
* (AND, OR, NOT, etc). * (AND, OR, NOT, etc). Also check that input is not a set.
* *
* If successful, update *pnode to be the transformed argument (if any * Returns the possibly-transformed node tree.
* transformation is needed), and return TRUE. If fail, return FALSE.
* (The caller must check for FALSE and emit a suitable error message.)
*/ */
bool Node *
coerce_to_boolean(ParseState *pstate, Node **pnode) coerce_to_boolean(Node *node, const char *constructName)
{ {
Oid inputTypeId = exprType(*pnode); Oid inputTypeId = exprType(node);
Oid targetTypeId; Oid targetTypeId;
if (inputTypeId == BOOLOID) if (inputTypeId != BOOLOID)
return true; /* no work */ {
targetTypeId = BOOLOID; targetTypeId = BOOLOID;
if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false)) if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
return false; /* fail, but let caller choose error msg */ {
*pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1, /* translator: first %s is name of a SQL construct, eg WHERE */
elog(ERROR, "Argument of %s must be type boolean, not type %s",
constructName, format_type_be(inputTypeId));
}
node = coerce_type(NULL, node, inputTypeId, targetTypeId, -1,
false); false);
return true; }
if (expression_returns_set(node))
{
/* translator: %s is name of a SQL construct, eg WHERE */
elog(ERROR, "Argument of %s must not be a set function",
constructName);
}
return node;
} }
...@@ -782,7 +793,8 @@ build_func_call(Oid funcid, Oid rettype, List *args) ...@@ -782,7 +793,8 @@ build_func_call(Oid funcid, Oid rettype, List *args)
funcnode = makeNode(Func); funcnode = makeNode(Func);
funcnode->funcid = funcid; funcnode->funcid = funcid;
funcnode->functype = rettype; funcnode->funcresulttype = rettype;
funcnode->funcretset = false; /* only possible case here */
funcnode->func_fcache = NULL; funcnode->func_fcache = NULL;
expr = makeNode(Expr); expr = makeNode(Expr);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.116 2002/04/28 00:49:12 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.117 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "parser/parse_target.h" #include "parser/parse_target.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -230,15 +231,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -230,15 +231,8 @@ transformExpr(ParseState *pstate, Node *expr)
a->rexpr); a->rexpr);
Expr *expr = makeNode(Expr); Expr *expr = makeNode(Expr);
if (!coerce_to_boolean(pstate, &lexpr)) lexpr = coerce_to_boolean(lexpr, "AND");
elog(ERROR, "left-hand side of AND is type '%s', not '%s'", rexpr = coerce_to_boolean(rexpr, "AND");
format_type_be(exprType(lexpr)),
format_type_be(BOOLOID));
if (!coerce_to_boolean(pstate, &rexpr))
elog(ERROR, "right-hand side of AND is type '%s', not '%s'",
format_type_be(exprType(rexpr)),
format_type_be(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = AND_EXPR; expr->opType = AND_EXPR;
...@@ -254,15 +248,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -254,15 +248,8 @@ transformExpr(ParseState *pstate, Node *expr)
a->rexpr); a->rexpr);
Expr *expr = makeNode(Expr); Expr *expr = makeNode(Expr);
if (!coerce_to_boolean(pstate, &lexpr)) lexpr = coerce_to_boolean(lexpr, "OR");
elog(ERROR, "left-hand side of OR is type '%s', not '%s'", rexpr = coerce_to_boolean(rexpr, "OR");
format_type_be(exprType(lexpr)),
format_type_be(BOOLOID));
if (!coerce_to_boolean(pstate, &rexpr))
elog(ERROR, "right-hand side of OR is type '%s', not '%s'",
format_type_be(exprType(rexpr)),
format_type_be(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = OR_EXPR; expr->opType = OR_EXPR;
...@@ -276,10 +263,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -276,10 +263,7 @@ transformExpr(ParseState *pstate, Node *expr)
a->rexpr); a->rexpr);
Expr *expr = makeNode(Expr); Expr *expr = makeNode(Expr);
if (!coerce_to_boolean(pstate, &rexpr)) rexpr = coerce_to_boolean(rexpr, "NOT");
elog(ERROR, "argument to NOT is type '%s', not '%s'",
format_type_be(exprType(rexpr)),
format_type_be(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = NOT_EXPR; expr->opType = NOT_EXPR;
...@@ -426,9 +410,15 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -426,9 +410,15 @@ transformExpr(ParseState *pstate, Node *expr)
opname, typeidTypeName(opform->oprresult), opname, typeidTypeName(opform->oprresult),
typeidTypeName(BOOLOID)); typeidTypeName(BOOLOID));
if (get_func_retset(opform->oprcode))
elog(ERROR, "'%s' must not return a set"
" to be used with quantified predicate subquery",
opname);
newop = makeOper(oprid(optup), /* opno */ newop = makeOper(oprid(optup), /* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
opform->oprresult); opform->oprresult,
false);
sublink->oper = lappend(sublink->oper, newop); sublink->oper = lappend(sublink->oper, newop);
ReleaseSysCache(optup); ReleaseSysCache(optup);
} }
...@@ -467,8 +457,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -467,8 +457,7 @@ transformExpr(ParseState *pstate, Node *expr)
} }
neww->expr = transformExpr(pstate, warg); neww->expr = transformExpr(pstate, warg);
if (!coerce_to_boolean(pstate, &neww->expr)) neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN");
elog(ERROR, "WHEN clause must have a boolean result");
/* /*
* result is NULL for NULLIF() construct - thomas * result is NULL for NULLIF() construct - thomas
...@@ -553,11 +542,6 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -553,11 +542,6 @@ transformExpr(ParseState *pstate, Node *expr)
case T_BooleanTest: case T_BooleanTest:
{ {
BooleanTest *b = (BooleanTest *) expr; BooleanTest *b = (BooleanTest *) expr;
b->arg = transformExpr(pstate, b->arg);
if (!coerce_to_boolean(pstate, &b->arg))
{
const char *clausename; const char *clausename;
switch (b->booltesttype) switch (b->booltesttype)
...@@ -586,9 +570,10 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -586,9 +570,10 @@ transformExpr(ParseState *pstate, Node *expr)
clausename = NULL; /* keep compiler quiet */ clausename = NULL; /* keep compiler quiet */
} }
elog(ERROR, "Argument of %s must be boolean", b->arg = transformExpr(pstate, b->arg);
clausename);
} b->arg = coerce_to_boolean(b->arg, clausename);
result = expr; result = expr;
break; break;
} }
...@@ -833,12 +818,6 @@ exprType(Node *expr) ...@@ -833,12 +818,6 @@ exprType(Node *expr)
switch (nodeTag(expr)) switch (nodeTag(expr))
{ {
case T_Func:
type = ((Func *) expr)->functype;
break;
case T_Iter:
type = ((Iter *) expr)->itertype;
break;
case T_Var: case T_Var:
type = ((Var *) expr)->vartype; type = ((Var *) expr)->vartype;
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.128 2002/05/12 20:10:04 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.129 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -280,7 +280,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -280,7 +280,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
Func *funcnode = makeNode(Func); Func *funcnode = makeNode(Func);
funcnode->funcid = funcid; funcnode->funcid = funcid;
funcnode->functype = rettype; funcnode->funcresulttype = rettype;
funcnode->funcretset = retset;
funcnode->func_fcache = NULL; funcnode->func_fcache = NULL;
expr->typeOid = rettype; expr->typeOid = rettype;
...@@ -289,21 +290,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -289,21 +290,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
expr->args = fargs; expr->args = fargs;
retval = (Node *) expr; retval = (Node *) expr;
/*
* if the function returns a set of values, then we need to iterate
* over all the returned values in the executor, so we stick an iter
* node here. if it returns a singleton, then we don't need the iter
* node.
*/
if (retset)
{
Iter *iter = makeNode(Iter);
iter->itertype = rettype;
iter->iterexpr = retval;
retval = (Node *) iter;
}
} }
else else
{ {
...@@ -1186,26 +1172,6 @@ ParseComplexProjection(ParseState *pstate, ...@@ -1186,26 +1172,6 @@ ParseComplexProjection(ParseState *pstate,
*/ */
switch (nodeTag(first_arg)) switch (nodeTag(first_arg))
{ {
case T_Iter:
{
Iter *iter = (Iter *) first_arg;
/*
* If it's an Iter, we stick the FieldSelect
* *inside* the Iter --- this is klugy, but necessary
* because ExecTargetList() currently does the right thing
* only when the Iter node is at the top level of a
* targetlist item.
*
* XXX Iter should go away altogether...
*/
fselect = setup_field_select(iter->iterexpr,
funcname, argrelid);
iter->iterexpr = (Node *) fselect;
iter->itertype = fselect->resulttype;
return (Node *) iter;
break;
}
case T_Var: case T_Var:
{ {
Var *var = (Var *) first_arg; Var *var = (Var *) first_arg;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.64 2002/05/01 19:26:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.65 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -135,7 +135,8 @@ make_op(List *opname, Node *ltree, Node *rtree) ...@@ -135,7 +135,8 @@ make_op(List *opname, Node *ltree, Node *rtree)
newop = makeOper(oprid(tup), /* opno */ newop = makeOper(oprid(tup), /* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
opform->oprresult); /* operator result type */ opform->oprresult, /* opresulttype */
get_func_retset(opform->oprcode)); /* opretset */
result = makeNode(Expr); result = makeNode(Expr);
result->typeOid = opform->oprresult; result->typeOid = opform->oprresult;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.103 2002/05/12 20:10:04 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.104 2002/05/12 23:43:03 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -1673,10 +1673,6 @@ get_rule_expr(Node *node, deparse_context *context) ...@@ -1673,10 +1673,6 @@ get_rule_expr(Node *node, deparse_context *context)
get_agg_expr((Aggref *) node, context); get_agg_expr((Aggref *) node, context);
break; break;
case T_Iter:
get_rule_expr(((Iter *) node)->iterexpr, context);
break;
case T_ArrayRef: case T_ArrayRef:
{ {
ArrayRef *aref = (ArrayRef *) node; ArrayRef *aref = (ArrayRef *) node;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.72 2002/04/30 01:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.73 2002/05/12 23:43:03 tgl Exp $
* *
* NOTES * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -612,6 +612,27 @@ get_func_rettype(Oid funcid) ...@@ -612,6 +612,27 @@ get_func_rettype(Oid funcid)
return result; return result;
} }
/*
* get_func_retset
* Given procedure id, return the function's proretset flag.
*/
bool
get_func_retset(Oid funcid)
{
HeapTuple tp;
bool result;
tp = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "Function OID %u does not exist", funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
ReleaseSysCache(tp);
return result;
}
/* /*
* func_volatile * func_volatile
* Given procedure id, return the function's provolatile flag. * Given procedure id, return the function's provolatile flag.
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.130 2002/05/12 20:10:04 tgl Exp $ * $Id: catversion.h,v 1.131 2002/05/12 23:43:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200205121 #define CATALOG_VERSION_NO 200205122
#endif #endif
/*-------------------------------------------------------------------------
*
* 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 */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: makefuncs.h,v 1.35 2002/04/16 23:08:12 tgl Exp $ * $Id: makefuncs.h,v 1.36 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,7 +23,8 @@ extern A_Expr *makeSimpleA_Expr(int oper, const char *name, ...@@ -23,7 +23,8 @@ extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
extern Oper *makeOper(Oid opno, extern Oper *makeOper(Oid opno,
Oid opid, Oid opid,
Oid opresulttype); Oid opresulttype,
bool opretset);
extern Var *makeVar(Index varno, extern Var *makeVar(Index varno,
AttrNumber varattno, AttrNumber varattno,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: nodes.h,v 1.106 2002/05/12 20:10:04 tgl Exp $ * $Id: nodes.h,v 1.107 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,7 +66,6 @@ typedef enum NodeTag ...@@ -66,7 +66,6 @@ typedef enum NodeTag
T_Func, T_Func,
T_FieldSelect, T_FieldSelect,
T_ArrayRef, T_ArrayRef,
T_Iter,
T_RelabelType, T_RelabelType,
T_RangeTblRef, T_RangeTblRef,
T_FromExpr, T_FromExpr,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: primnodes.h,v 1.62 2002/05/12 20:10:05 tgl Exp $ * $Id: primnodes.h,v 1.63 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -151,12 +151,51 @@ typedef struct Expr ...@@ -151,12 +151,51 @@ typedef struct Expr
{ {
NodeTag type; NodeTag type;
Oid typeOid; /* oid of the type of this expression */ Oid typeOid; /* oid of the type of this expression */
OpType opType; /* type of this expression */ OpType opType; /* kind of expression */
Node *oper; /* operator node if needed (Oper, Func, or Node *oper; /* operator node if needed (Oper, Func, or
* SubPlan) */ * SubPlan) */
List *args; /* arguments to this expression */ List *args; /* arguments to this expression */
} Expr; } Expr;
/*
* Oper - Expr subnode for an OP_EXPR
*
* NOTE: in the good old days 'opno' used to be both (or either, or
* neither) the pg_operator oid, and/or the pg_proc oid depending
* on the postgres module in question (parser->pg_operator,
* executor->pg_proc, planner->both), the mood of the programmer,
* and the phase of the moon (rumors that it was also depending on the day
* of the week are probably false). To make things even more postgres-like
* (i.e. a mess) some comments were referring to 'opno' using the name
* 'opid'. Anyway, now we have two separate fields, and of course that
* immediately removes all bugs from the code... [ sp :-) ].
*
* Note also that opid is not necessarily filled in immediately on creation
* of the node. The planner makes sure it is valid before passing the node
* tree to the executor, but during parsing/planning opid is typically 0.
*/
typedef struct Oper
{
NodeTag type;
Oid opno; /* PG_OPERATOR OID of the operator */
Oid opid; /* PG_PROC OID of underlying function */
Oid opresulttype; /* PG_TYPE OID of result value */
bool opretset; /* true if operator returns set */
FunctionCachePtr op_fcache; /* runtime state, else NULL */
} Oper;
/*
* Func - Expr subnode for a FUNC_EXPR
*/
typedef struct Func
{
NodeTag type;
Oid funcid; /* PG_PROC OID of the function */
Oid funcresulttype; /* PG_TYPE OID of result value */
bool funcretset; /* true if function returns set */
FunctionCachePtr func_fcache; /* runtime state, or NULL */
} Func;
/* /*
* Var * Var
* *
...@@ -196,37 +235,6 @@ typedef struct Var ...@@ -196,37 +235,6 @@ typedef struct Var
AttrNumber varoattno; /* original value of varattno */ AttrNumber varoattno; /* original value of varattno */
} Var; } Var;
/*--------------------
* Oper
*
* NOTE: in the good old days 'opno' used to be both (or either, or
* neither) the pg_operator oid, and/or the pg_proc oid depending
* on the postgres module in question (parser->pg_operator,
* executor->pg_proc, planner->both), the mood of the programmer,
* and the phase of the moon (rumors that it was also depending on the day
* of the week are probably false). To make things even more postgres-like
* (i.e. a mess) some comments were referring to 'opno' using the name
* 'opid'. Anyway, now we have two separate fields, and of course that
* immediately removes all bugs from the code... [ sp :-) ].
*
* Note also that opid is not necessarily filled in immediately on creation
* of the node. The planner makes sure it is valid before passing the node
* tree to the executor, but during parsing/planning opid is typically 0.
*--------------------
*/
typedef struct Oper
{
NodeTag type;
Oid opno; /* PG_OPERATOR OID of the operator */
Oid opid; /* PG_PROC OID for the operator's
* underlying function */
Oid opresulttype;
/* PG_TYPE OID of the operator's return value */
FunctionCachePtr op_fcache;
/* runtime state while running the function */
} Oper;
/* /*
* Const * Const
*/ */
...@@ -283,39 +291,6 @@ typedef struct Param ...@@ -283,39 +291,6 @@ typedef struct Param
Oid paramtype; /* PG_TYPE OID of the parameter's value */ Oid paramtype; /* PG_TYPE OID of the parameter's value */
} Param; } Param;
/*
* Func
*/
typedef struct Func
{
NodeTag type;
Oid funcid; /* PG_PROC OID of the function */
Oid functype; /* PG_TYPE OID of the function's return
* value */
FunctionCachePtr func_fcache;
/*
* runtime state while running this function. Where we are in the
* execution of the function if it returns more than one value, etc.
* See utils/fcache.h
*/
} Func;
/* ----------------
* Iter
* can anyone explain what this is for? Seems to have something to do
* with evaluation of functions that return sets...
* ----------------
*/
typedef struct Iter
{
NodeTag type;
Node *iterexpr;
Oid itertype; /* type of the iter expr (use for type
* checking) */
} Iter;
/* /*
* Aggref * Aggref
*/ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: clauses.h,v 1.51 2002/04/05 00:31:35 tgl Exp $ * $Id: clauses.h,v 1.52 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -42,7 +42,7 @@ extern List *make_ands_implicit(Expr *clause); ...@@ -42,7 +42,7 @@ extern List *make_ands_implicit(Expr *clause);
extern bool contain_agg_clause(Node *clause); extern bool contain_agg_clause(Node *clause);
extern List *pull_agg_clause(Node *clause); extern List *pull_agg_clause(Node *clause);
extern bool contain_iter_clause(Node *clause); extern bool expression_returns_set(Node *clause);
extern bool contain_subplans(Node *clause); extern bool contain_subplans(Node *clause);
extern List *pull_subplans(Node *clause); extern List *pull_subplans(Node *clause);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_coerce.h,v 1.42 2002/04/11 20:00:15 tgl Exp $ * $Id: parse_coerce.h,v 1.43 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,7 +45,7 @@ extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, ...@@ -45,7 +45,7 @@ extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
extern Node *coerce_type_typmod(ParseState *pstate, Node *node, extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
Oid targetTypeId, int32 atttypmod); Oid targetTypeId, int32 atttypmod);
extern bool coerce_to_boolean(ParseState *pstate, Node **pnode); extern Node *coerce_to_boolean(Node *node, const char *constructName);
extern Oid select_common_type(List *typeids, const char *context); extern Oid select_common_type(List *typeids, const char *context);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node, extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: lsyscache.h,v 1.51 2002/04/30 01:26:26 tgl Exp $ * $Id: lsyscache.h,v 1.52 2002/05/12 23:43:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,6 +39,7 @@ extern RegProcedure get_oprrest(Oid opno); ...@@ -39,6 +39,7 @@ extern RegProcedure get_oprrest(Oid opno);
extern RegProcedure get_oprjoin(Oid opno); extern RegProcedure get_oprjoin(Oid opno);
extern char *get_func_name(Oid funcid); extern char *get_func_name(Oid funcid);
extern Oid get_func_rettype(Oid funcid); extern Oid get_func_rettype(Oid funcid);
extern bool get_func_retset(Oid funcid);
extern char func_volatile(Oid funcid); extern char func_volatile(Oid funcid);
extern Oid get_relname_relid(const char *relname, Oid relnamespace); extern Oid get_relname_relid(const char *relname, Oid relnamespace);
extern char *get_rel_name(Oid relid); extern char *get_rel_name(Oid relid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment