cursor.fix1.diff

text/plain

Filename: cursor.fix1.diff
Type: text/plain
Part: 0
Message: [PATCH] [LARGE] select * from cursor foo
Index: src/backend/commands/command.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/commands/command.c,v
retrieving revision 1.141
retrieving revision 1.142
diff -r1.141 -r1.142
101a102
> 	int 		result;
170,211c171,174
< 	/*
< 	 * Determine which direction to go in, and check to see if we're
< 	 * already at the end of the available tuples in that direction.  If
< 	 * so, do nothing.	(This check exists because not all plan node types
< 	 * are robust about being called again if they've already returned
< 	 * NULL once.)	If it's OK to do the fetch, call the executor.  Then,
< 	 * update the atStart/atEnd state depending on the number of tuples
< 	 * that were retrieved.
< 	 */
< 	if (forward)
< 	{
< 		if (!portal->atEnd)
< 		{
< 			ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
< 			/*
< 			 *	I use CMD_UPDATE, because no CMD_MOVE or the like
< 			 *	exists, and I would like to provide the same
< 			 *	kind of info as CMD_UPDATE
< 			 */
< 			UpdateCommandInfo(CMD_UPDATE, 0, estate->es_processed);
< 			if (estate->es_processed > 0)
< 				portal->atStart = false;		/* OK to back up now */
< 			if (count <= 0 || (int) estate->es_processed < count)
< 				portal->atEnd = true;	/* we retrieved 'em all */
< 		}
< 	}
< 	else
< 	{
< 		if (!portal->atStart)
< 		{
< 			ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
< 			/*
< 			 *	I use CMD_UPDATE, because no CMD_MOVE or the like
< 			 *	exists, and I would like to provide the same
< 			 *	kind of info as CMD_UPDATE
< 			 */
< 			UpdateCommandInfo(CMD_UPDATE, 0, estate->es_processed);
< 			if (estate->es_processed > 0)
< 				portal->atEnd = false;	/* OK to go forward now */
< 			if (count <= 0 || (int) estate->es_processed < count)
< 				portal->atStart = true; /* we retrieved 'em all */
< 		}
---
> 	result = PortalRun( portal, forward, (long) count, queryDesc->dest, NULL );
> 
>   	if (result > 0) {
> 		UpdateCommandInfo(CMD_UPDATE, 0, result);
Index: src/backend/commands/explain.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/commands/explain.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -r1.65 -r1.66
185a186,188
> 		case T_PortalScan:
> 			pname = "Portal Scan";
> 			break;
264c267,268
< 				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
---
> 				RangeTblEntry *rte = (RangeTblEntry*)
> 							rt_fetch(((Scan *) plan)->scanrelid,
268c272
< 				Assert(rte->relname);
---
> 				Assert( rte->rtetype == RTE_RELATION );
271,272c275,276
< 								 stringStringInfo(rte->relname));
< 				if (strcmp(rte->eref->relname, rte->relname) != 0)
---
> 								 stringStringInfo(rte->u.rel.relname));
> 				if (strcmp(rte->eref->relname, rte->u.rel.relname) != 0)
358c362,364
< 		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
---
> 
> 		RangeTblEntry *rte = (RangeTblEntry *)
> 									rt_fetch(subqueryscan->scan.scanrelid,
359a366
> 
362,363c369,370
< 		Assert(rte->subquery != NULL);
< 		es->rtable = rte->subquery->rtable;
---
> 		Assert(rte->rtetype == RTE_SUBSELECT);
> 		es->rtable = rte->u.sub.subquery->rtable;
Index: src/backend/executor/Makefile
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/Makefile,v
retrieving revision 1.16
retrieving revision 1.17
diff -r1.16 -r1.17
19c19,20
<        nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
---
>        nodeNestloop.o nodePortalscan.o nodeResult.o nodeSeqscan.o \
>        nodeSetOp.o nodeSort.o \
Index: src/backend/executor/execAmi.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execAmi.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -r1.58 -r1.59
44a45
> #include "executor/nodePortalscan.h"
187a189,192
> 		case T_PortalScan:
> 			state = ((PortalScan *) node)->scan.scanstate;
> 			break;
> 
295a301,304
> 			break;
> 
> 		case T_PortalScan:
> 			ExecPortalReScan((PortalScan *) node, exprCtxt, parent);
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.145
retrieving revision 1.146
diff -r1.145 -r1.146
348,349c348,350
< 				Assert(rte->subquery != NULL);
< 				ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
---
> 				Assert(rte->rtetype == RTE_SUBSELECT);
> 				ExecCheckQueryPerms(operation, rte->u.sub.subquery, 
> 									scan->subplan);
403,404c404
< 	if (rte->subquery)
< 		return;
---
> 	if (!rte->rtetype == RTE_RELATION) return;
406c406,407
< 	relName = rte->relname;
---
>     
> 	relName = rte->u.rel.relname;
Index: src/backend/executor/execProcnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execProcnode.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -r1.26 -r1.27
91a92
> #include "executor/nodePortalscan.h"
166a168,172
> 		case T_PortalScan:
> 			result = ExecInitPortalScan((PortalScan *) node, estate,
> 										  parent);
> 			break;
> 
292a299,302
> 		case T_PortalScan:
> 			result = ExecPortalScan((PortalScan *) node);
> 			break;
> 
384a395,397
> 		case T_PortalScan:
> 			return ExecCountSlotsPortalScan((PortalScan *) node);
> 
496a510,513
> 		case T_PortalScan:
> 			ExecEndPortalScan((PortalScan *) node);
> 			break;
> 
625a643,650
> 
> 				slot = scanstate->cstate.cs_ResultTupleSlot;
> 			}
> 			break;
> 
> 		case T_PortalScan:
> 			{
> 				CommonScanState *scanstate = ((PortalScan *) node)->scan.scanstate;
Index: src/backend/executor/nodeIndexscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeIndexscan.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -r1.62 -r1.63
991c991,993
< 	reloid = rtentry->relid;
---
>     Assert(rtentry->rtetype == RTE_RELATION);
> 
> 	reloid = rtentry->u.rel.relid;
Index: src/backend/executor/nodeSeqscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeSeqscan.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -r1.31 -r1.32
161a162
> 
163c164,166
< 	reloid = rtentry->relid;
---
>     Assert(rtentry->rtetype == RTE_RELATION);
> 
> 	reloid = rtentry->u.rel.relid;
Index: src/backend/executor/nodeSubqueryscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeSubqueryscan.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -r1.9 -r1.10
150c150
< 	Assert(rte->subquery != NULL);
---
>     Assert(rte->rtetype == RTE_SUBSELECT);
155c155,156
< 	sp_estate->es_range_table = rte->subquery->rtable;
---
>     Assert( PointerIsValid(rte->u.sub.subquery) );
> 	sp_estate->es_range_table = rte->u.sub.subquery->rtable;
Index: src/backend/executor/nodeTidscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeTidscan.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -r1.18 -r1.19
460a461
> 
462c463
< 	reloid = rtentry->relid;
---
>     Assert(rtentry->rtetype == RTE_RELATION);
463a465
> 	reloid = rtentry->u.rel.relid;
Index: src/backend/executor/spi.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/spi.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -r1.57 -r1.58
1138,1141c1138,1139
<     QueryDesc	   *querydesc;
< 	EState		   *estate;
< 	MemoryContext	oldcontext;
< 	CommandDest		olddest;
---
> 	int nrows; /* how many records portal returned */
> 	
1156,1159c1154
< 	/* Switch to the portals memory context */
< 	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
< 	querydesc  = PortalGetQueryDesc(portal);
< 	estate     = PortalGetState(portal);
---
> 	nrows = PortalRun ( portal, forward, (long) count, dest, NULL);
1161,1195c1156
< 	/* Save the queries command destination and set it to SPI (for fetch) */
< 	/* or None (for move) */
< 	olddest = querydesc->dest;
< 	querydesc->dest = dest;
< 
< 	/* Run the executor like PerformPortalFetch and remember states */
< 	if (forward)
< 	{
< 		if (!portal->atEnd)
< 		{
< 			ExecutorRun(querydesc, estate, EXEC_FOR, (long)count);
< 			_SPI_current->processed = estate->es_processed;
< 			if (estate->es_processed > 0)
< 				portal->atStart = false;
< 			if (count <= 0 || (int) estate->es_processed < count)
< 				portal->atEnd = true;
< 		}
< 	}
< 	else
< 	{
< 		if (!portal->atStart)
< 		{
< 			ExecutorRun(querydesc, estate, EXEC_BACK, (long) count);
< 			_SPI_current->processed = estate->es_processed;
< 			if (estate->es_processed > 0)
< 				portal->atEnd = false;
< 			if (count <= 0 || estate->es_processed < count)
< 				portal->atStart = true;
< 		}
< 	}
< 
< 	/* Restore the old command destination and switch back to callers */
< 	/* memory context */
< 	querydesc->dest = olddest;
< 	MemoryContextSwitchTo(oldcontext);
---
> 	_SPI_current->processed = nrows;
Index: src/backend/executor/nodePortalscan.c
===================================================================
RCS file: nodePortalscan.c
diff -N nodePortalscan.c
0a1,258
> /*-------------------------------------------------------------------------
>  *
>  * nodePortalscan.c
>  *	  Support routines for scanning portals (SELECT * FROM CURSOR FOO).
>  *
>  *
>  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
>  * Portions Copyright (c) 1994, Regents of the University of California
>  *
>  *
>  * IDENTIFICATION
>  *	  $Header$
>  *
>  *-------------------------------------------------------------------------
>  */
> /*
>  * INTERFACE ROUTINES
>  *		ExecPortalScan			scans a portal.
>  *		ExecPortalNext			retrieve next tuple in sequential order.
>  *		ExecInitPortalScan		creates and initializes a portalscan node.
>  *		ExecEndPortalScan			releases any storage allocated.
>  *		ExecPortalReScan			rescans the relation
>  *
>  */
> #include "postgres.h"
> 
> #include "catalog/pg_type.h"
> #include "executor/execdebug.h"
> #include "executor/execdefs.h"
> #include "executor/execdesc.h"
> #include "executor/nodePortalscan.h"
> #include "parser/parsetree.h"
> #include "tcop/pquery.h"
> 
> static TupleTableSlot *PortalNext(PortalScan *node);
> 
> /* ----------------------------------------------------------------
>  *						Scan Support
>  * ----------------------------------------------------------------
>  */
> /* ----------------------------------------------------------------
>  *		PortalNext
>  *
>  *		This is a workhorse for ExecPortalScan
>  * ----------------------------------------------------------------
>  */
> static TupleTableSlot *
> PortalNext(PortalScan *node)
> {
> 	PortalScanState *portalstate;
> 	EState	   *estate;
> 	ScanDirection direction;
> 	TupleTableSlot *slot;
> 	bool 		forward;
> 	Portal		portal;
> 	int 		ntuples;
> 
> 	/*
> 	 * get information from the estate and scan state
> 	 */
> 	estate = node->scan.plan.state;
> 	portalstate = (PortalScanState *) node->scan.scanstate;
> 	direction = estate->es_direction;
> 	forward = ScanDirectionIsForward(direction);
> 	portal = portalstate->portal;
> 
> 	/* 
> 	 * get the next tuple from Portal
> 	 */
> 
> 	ntuples = PortalRun(portal, forward, (long) 1, NULL, &slot);
> 
> 	portalstate->csstate.css_ScanTupleSlot = slot;
> 
> 	return slot;
> }
> 
> /* ----------------------------------------------------------------
>  *		ExecPortalScan(node)
>  *
>  *		Scans the portal sequentially and returns the next qualifying
>  *		tuple.
>  *		It calls the ExecScan() routine and passes it the access method
>  *		which retrieve tuples sequentially.
>  *
>  */
> 
> TupleTableSlot *
> ExecPortalScan(PortalScan *node)
> {
> 	/*
> 	 * use PortalNext as access method
> 	 */
> 	return ExecScan(&node->scan, (ExecScanAccessMtd) PortalNext);
> }
> 
> /* ----------------------------------------------------------------
>  *		ExecInitPortalScan
>  * ----------------------------------------------------------------
>  */
> bool
> ExecInitPortalScan(PortalScan *node, EState *estate, Plan *parent)
> {
> 	PortalScanState *portalstate;
> 	RangeTblEntry *rte;
> 	Portal		portal;
> 
> 	/*
> 	 * PortalScan should not have any "normal" children.
> 	 */
> 	Assert(outerPlan((Plan *) node) == NULL);
> 	Assert(innerPlan((Plan *) node) == NULL);
> 
> 	/*
> 	 * assign the node's execution state
> 	 */
> 	node->scan.plan.state = estate;
> 
> 	/*
> 	 * create new PortalScanState for node
> 	 */
> 	portalstate = makeNode(PortalScanState);
> 	node->scan.scanstate = (CommonScanState *) portalstate;
> 
> 	/*
> 	 * Miscellaneous initialization
> 	 *
> 	 * create expression context for node
> 	 */
> 	ExecAssignExprContext(estate, &portalstate->csstate.cstate);
> 
> #define SUBQUERYSCAN_NSLOTS 1
> 
> 	/*
> 	 * tuple table initialization
> 	 */
> 	ExecInitResultTupleSlot(estate, &portalstate->csstate.cstate);
> 
> 	/*
> 	 * initialize portal
> 	 *
> 	 * This should agree with ExecInitSubPlan
> 	 */
>     rte = rt_fetch( node->scan.scanrelid, estate->es_range_table);
>     Assert(rte->rtetype == RTE_PORTAL);
> 
> 	portalstate->csstate.css_ScanTupleSlot = NULL;
> 	portalstate->csstate.cstate.cs_TupFromTlist = false;
> 
> 	portal = GetPortalByName( rte->u.portal.portalname);
> 	if (!PointerIsValid(portal)) 
> 		elog(ERROR, "InitPortalScan: portal %s disappeared", 
> 						rte->u.portal.portalname);
> 
> 	portalstate->portal = portal;
> 
> 	/*
> 	 * initialize tuple type
> 	 */
> 	ExecAssignResultTypeFromTL((Plan *) node, &portalstate->csstate.cstate);
> 	ExecAssignProjectionInfo((Plan *) node, &portalstate->csstate.cstate);
> 
> 	return TRUE;
> }
> 
> int
> ExecCountSlotsPortalScan(PortalScan *node)
> {
> 	/*
> 	 * The subplan has its own tuple table and must not be counted here!
> 	 */
> 	return ExecCountSlotsNode(outerPlan(node)) +
> 	ExecCountSlotsNode(innerPlan(node)) +
> 	SUBQUERYSCAN_NSLOTS;
> }
> 
> /* ----------------------------------------------------------------
>  *		ExecEndPortalScan
>  *
>  *		frees any storage allocated through C routines.
>  * ----------------------------------------------------------------
>  */
> void
> ExecEndPortalScan(PortalScan *node)
> {
> 	PortalScanState *portalstate;
> 
> 	/*
> 	 * get information from node
> 	 */
> 	portalstate = (PortalScanState *) node->scan.scanstate;
> 
> 	/*
> 	 * Free the projection info and the scan attribute info
> 	 *
> 	 * Note: we don't ExecFreeResultType(portalstate) because the rule
> 	 * manager depends on the tupType returned by ExecMain().  So for now,
> 	 * this is freed at end-transaction time.  -cim 6/2/91
> 	 */
> 	ExecFreeProjectionInfo(&portalstate->csstate.cstate);
> 	ExecFreeExprContext(&portalstate->csstate.cstate);
> 
> 	/*
> 	 * close down portal
> 	 */
>  	/* XXX */
> 
> 	/*
> 	 * clean up portal's tuple table
> 	 */
> 	portalstate->csstate.css_ScanTupleSlot = NULL;
> 
> 	/*
> 	 * clean out the upper tuple table
> 	 */
> 	ExecClearTuple(portalstate->csstate.cstate.cs_ResultTupleSlot);
> }
> 
> /* ----------------------------------------------------------------
>  *		ExecPortalReScan
>  *
>  *		Rescans the relation.
>  * ----------------------------------------------------------------
>  */
> void
> ExecPortalReScan(PortalScan *node, ExprContext *exprCtxt, Plan *parent)
> {
> 	PortalScanState *portalstate;
> 	EState	   *estate;
> 
> 	portalstate = (PortalScanState *) node->scan.scanstate;
> 	estate = node->scan.plan.state;
> 
> 	elog(ERROR, "PortalReScan: Cannot rescan portals");
> 
> 	/*
> 	 * ExecReScan doesn't know about my subplan, so I have to do
> 	 * changed-parameter signaling myself.
> 	 */
> 
> /*
> 	if (node->scan.plan.chgParam != NULL)
> 		SetChangedParamList(node->subplan, node->scan.plan.chgParam);
> */
> 
> 	/*
> 	 * if chgParam of subnode is not null then plan will be re-scanned by
> 	 * first ExecProcNode.
> 	 */
> 
> /*
>  XXX 
> 	if (node->subplan->chgParam == NULL)
> 		ExecReScan(node->subplan, NULL, node->subplan);
> */
> 
> 	portalstate->csstate.css_ScanTupleSlot = NULL;
> }
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.155
retrieving revision 1.156
diff -r1.155 -r1.156
229a230,247
>  *		_copyPortalScan
>  * ----------------
>  */
> static PortalScan *
> _copyPortalScan(PortalScan *from)
> {
> 	PortalScan    *newnode = makeNode(PortalScan);
> 
> 	/*
> 	 * copy node superclass fields
> 	 */
> 	CopyPlanFields((Plan *) from, (Plan *) newnode);
> 	CopyScanFields((Scan *) from, (Scan *) newnode);
> 
> 	return newnode;
> }
> 
> /* ----------------
1108c1126
< 	newnode->issubquery = from->issubquery;
---
> 	newnode->reltype = from->reltype;
1490,1494d1507
< 
< 	if (from->relname)
< 		newnode->relname = pstrdup(from->relname);
< 	newnode->relid = from->relid;
< 	Node_Copy(from, newnode, subquery);
1502c1515,1529
< 
---
> 	newnode->rtetype = from->rtetype;
> 	switch (from->rtetype) {
> 		case RTE_RELATION:
> 			newnode->u.rel.relname = pstrdup(from->u.rel.relname);
> 			newnode->u.rel.relid = from->u.rel.relid;
> 			break;
> 		case RTE_SUBSELECT:
> 			Node_Copy(from, newnode, u.sub.subquery);
> 			break;
> 		case RTE_PORTAL:
> 			newnode->u.portal.portalname = pstrdup(from->u.portal.portalname);
> 			break;
> 		default: 
> 			elog(ERROR, "copyRTE: Unknown rtetype %d", from->rtetype);
> 	}
2249d2275
< 	newnode->freeze = from->freeze;
2555a2582,2584
> 			break;
> 		case T_PortalScan:
> 			retval = _copyPortalScan(from);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.103
retrieving revision 1.104
diff -r1.103 -r1.104
1119,1120d1118
< 	if (a->freeze != b->freeze)
< 		return false;
1600,1605d1597
< 	if (!equalstr(a->relname, b->relname))
< 		return false;
< 	if (a->relid != b->relid)
< 		return false;
< 	if (!equal(a->subquery, b->subquery))
< 		return false;
1620c1612,1631
< 
---
> 	if (a->rtetype != b->rtetype)
> 		return false;
> 	switch (a->rtetype) {
> 		case RTE_RELATION:
> 			if (!equalstr(a->u.rel.relname, b->u.rel.relname))
> 				return false;
> 			if (a->u.rel.relid != b->u.rel.relid)
> 				return false;
> 			break;
> 		case RTE_SUBSELECT:
> 			if (!equal(a->u.sub.subquery, b->u.sub.subquery))
> 				return false;
> 			break;
> 		case RTE_PORTAL:
> 			if (!equalstr(a->u.portal.portalname, b->u.portal.portalname))
> 				return false;
> 			break;
> 		default: 
> 			elog(ERROR, "equalRTE: Unknown rtetype %d", a->rtetype);
> 	}
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.145
retrieving revision 1.146
diff -r1.145 -r1.146
506a507,516
>  *	PortalScan is a subclass of Scan
>  */
> static void
> _outPortalScan(StringInfo str, PortalScan *node)
> {
> 	appendStringInfo(str, " PORTALSCAN ");
> 	_outPlanInfo(str, (Plan *) node);
> }
> 
> /*
965,970c975
< 	appendStringInfo(str, " RTE :relname ");
< 	_outToken(str, node->relname);
< 	appendStringInfo(str, " :relid %u ",
< 					 node->relid);
< 	appendStringInfo(str, " :subquery ");
< 	_outNode(str, node->subquery);
---
> 	appendStringInfo(str, " RTE ");
981a987,1004
> 	appendStringInfo(str, " :rtetype %u ", node->rtetype);
> 	switch (node->rtetype) {
> 		case RTE_RELATION:
> 			appendStringInfo(str, " :relname ");
> 			_outToken(str, node->u.rel.relname);
> 			appendStringInfo(str, " :relid %u ", node->u.rel.relid);
> 			break;
> 		case RTE_SUBSELECT:
> 			appendStringInfo(str, " :subquery ");
> 			_outNode(str, node->u.sub.subquery);
> 			break;
> 		case RTE_PORTAL:
> 			appendStringInfo(str, " :portalname ");
> 			_outToken(str, node->u.portal.portalname);
> 			break;
> 		default: 
> 			elog(ERROR, "outRTE: Unknown rtetype %d", node->rtetype);
> 	}
1510a1534,1536
> 				break;
> 			case T_PortalScan:
> 				_outPortalScan(str, obj);
Index: src/backend/nodes/print.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/print.c,v
retrieving revision 1.47
retrieving revision 1.48
diff -r1.47 -r1.48
134c134
< 		if (rte->relname)
---
> 		if (rte->rtetype == RTE_RELATION) {
136,137c136,138
< 				   i, rte->relname, rte->eref->relname, rte->relid);
< 		else
---
> 				   i, rte->u.rel.relname, rte->eref->relname, rte->u.rel.relid);
> 		}
> 		else if (rte->rtetype == RTE_SUBSELECT) {
139a141,145
> 		}
> 		else if (rte->rtetype == RTE_PORTAL) {
> 			printf("%d\t[portal] (%s)\t",
> 				   i, rte->eref->relname);
> 		}
302a309,310
> 		case T_PortalScan:
> 			return "PORTALSCAN";
363c371,372
< 		StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
---
> 		Assert( rte->rtetype == RTE_RELATION);
> 		StrNCpy(extraInfo, rte->u.rel.relname, NAMEDATALEN);
370c379,380
< 		StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
---
> 		Assert( rte->rtetype == RTE_RELATION);
> 		StrNCpy(extraInfo, rte->u.rel.relname, NAMEDATALEN);
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/readfuncs.c,v
retrieving revision 1.112
retrieving revision 1.113
diff -r1.112 -r1.113
1417c1417
< _readRangeTblEntry(void)
---
> _readRangeTblEntry()
1425,1435d1424
< 	token = pg_strtok(&length); /* eat :relname */
< 	token = pg_strtok(&length); /* get :relname */
< 	local_node->relname = nullable_string(token, length);
< 
< 	token = pg_strtok(&length); /* eat :relid */
< 	token = pg_strtok(&length); /* get :relid */
< 	local_node->relid = atooid(token);
< 
< 	token = pg_strtok(&length); /* eat :subquery */
< 	local_node->subquery = nodeRead(true);		/* now read it */
< 
1461a1451,1476
> 	token = pg_strtok(&length); /* eat :rtetype */
> 	token = pg_strtok(&length); /* get :rtetype */
> 	local_node->rtetype = atoui(token);
> 
> 	switch (local_node->rtetype) {
> 		case RTE_RELATION:
> 			token = pg_strtok(&length); /* eat :relname */
> 			token = pg_strtok(&length); /* get :relname */
> 			local_node->u.rel.relname = nullable_string(token, length);
> 
> 			token = pg_strtok(&length); /* eat :relid */
> 			token = pg_strtok(&length); /* get :relid */
> 			local_node->u.rel.relid = atooid(token);
> 			break;
> 		case RTE_SUBSELECT:
> 			token = pg_strtok(&length); /* eat :subquery */
> 			local_node->u.sub.subquery = nodeRead(true);	/* now read it */
> 			break;
> 		case RTE_PORTAL:
> 			token = pg_strtok(&length); /* eat :portalname */
> 			token = pg_strtok(&length); /* get :portalname */
> 			local_node->u.portal.portalname = nullable_string(token, length);
> 			break;
> 		default: 
> 			elog(ERROR, "readRTE: Unknown rtetype %d", local_node->rtetype);
> 	}
1463a1479
> 
Index: src/backend/optimizer/path/allpaths.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/path/allpaths.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -r1.78 -r1.79
27a28
> #include "utils/portal.h"
103c104
< 		if (rel->issubquery)
---
> 		if (rel->reltype == REL_SUBQUERY) 
104a106
>             Assert(rte->rtetype == RTE_SUBSELECT);
108c110,143
< 		else if ((inheritlist = expand_inherted_rtentry(root, rti, true))
---
> 		else if (rel->reltype == REL_PORTAL) 
> 		{
> 			/* its a portal, considerably simpler case, as portals
> 			   may not have setops or conditions. We only need
> 		       to fill in the cost info from Portal's own Plan */
> 			Portal portal;
> 			QueryDesc *qd; 
> 
> 			Assert(rte->rtetype == RTE_PORTAL);
> 
> 			portal = GetPortalByName(rte->u.portal.portalname);
> 			if (!PointerIsValid(portal)) 
> 				elog(ERROR, "set_base_rel_pathlists: Portal %s disappeared", 
> 					rte->u.portal.portalname);
> 
> 			qd = PortalGetQueryDesc(portal);
> 
> 			/* Copy number of output rows from portal info */
> 			rel->tuples = qd->plantree->plan_rows;
> 
> 			/* Mark rel with estimated output rows, width, etc */
> 			set_baserel_size_estimates(root, rel); 
> 
> 			/* Generate appropriate path */
> 			add_path(rel, create_portalscan_path(rel, portal) );
> 
> 			/* Select cheapest path (pretty easy in this case...) */
> 			set_cheapest(rel);
> 		}
> /* XXX: maybe we can/should determine that a relation is a root of inheritance
>  *      hierarchy earlier and have REL_INH_ROOT reltype?
>  */
> 		else if (rel->reltype == REL_PLAIN)  {
> 			if ((inheritlist = expand_inherted_rtentry(root, rti, true))
119a155,157
> 		else 
> 			elog(ERROR,"set_base_rel_pathlists: unknown reltype %d", rel->reltype);
> 	}
128a167
> 	Assert( rte->rtetype == RTE_RELATION );
181c220
< 	Oid			parentOID = rte->relid;
---
> 	Oid			parentOID = rte->u.rel.relid;
184a224
> 	Assert( rte->rtetype == RTE_RELATION );
218c258,261
< 		childOID = childrte->relid;
---
> 
> 		Assert( childrte->rtetype == RTE_RELATION );
> 
> 		childOID = childrte->u.rel.relid;
279c322,323
< 	Query	   *subquery = rte->subquery;
---
> 	Query	   *subquery = rte->u.sub.subquery;
>     Assert(rte->rtetype == RTE_SUBSELECT);
Index: src/backend/optimizer/path/clausesel.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/path/clausesel.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -r1.46 -r1.47
387c387
< 			if (rte->subquery)
---
> 			if (rte->rtetype == RTE_SUBSELECT)
Index: src/backend/optimizer/path/costsize.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/path/costsize.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -r1.78 -r1.79
113c113
< 	Assert(!baserel->issubquery);
---
> 	Assert(baserel->reltype == REL_PLAIN);
228c228
< 	Assert(!baserel->issubquery);
---
> 	Assert(baserel->reltype == REL_PLAIN);
Index: src/backend/optimizer/plan/createplan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/createplan.c,v
retrieving revision 1.108
retrieving revision 1.109
diff -r1.108 -r1.109
45a46,47
> static PortalScan *create_portalscan_plan(Path *best_path,
> 						 List *tlist, List *scan_clauses);
71a74,75
> static PortalScan *make_portalscan(List *qptlist, List *qpqual, 
> 									Index scanrelid);
119a124
> 		case T_PortalScan:
200a206,211
> 		case T_PortalScan:
> 			plan = (Scan *) create_portalscan_plan(best_path,
> 													 tlist,
> 													 scan_clauses);
> 			break;
> 
351,352c362
< 	Assert(length(best_path->parent->relids) == 1);
< 	Assert(!best_path->parent->issubquery);
---
> 	Assert(best_path->parent->reltype == REL_PLAIN);
395,396c405
< 	Assert(length(best_path->path.parent->relids) == 1);
< 	Assert(!best_path->path.parent->issubquery);
---
> 	Assert(best_path->path.parent->reltype == REL_PLAIN);
513,514c522
< 	Assert(length(best_path->path.parent->relids) == 1);
< 	Assert(!best_path->path.parent->issubquery);
---
> 	Assert(best_path->path.parent->reltype == REL_PLAIN);
543d550
< 	Assert(length(best_path->parent->relids) == 1);
545c552
< 	Assert(best_path->parent->issubquery);
---
> 	Assert(best_path->parent->reltype == REL_SUBQUERY);
556a564,587
> /*
>  * create_portalscan_plan
>  *	 Returns a portalscan plan for the portal scanned by 'best_path'
>  *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
>  */
> static PortalScan *
> create_portalscan_plan(Path *best_path, List *tlist, List *scan_clauses)
> {
> 	PortalScan *scan_plan;
> 	Index		scan_relid;
> 
> 	/* there should be exactly one base rel involved... */
> 	/* and it must be a portal */
> 	Assert(best_path->parent->reltype == REL_PORTAL);
> 
> 	scan_relid = (Index) lfirsti(best_path->parent->relids);
> 
> 	scan_plan = make_portalscan( tlist, scan_clauses, scan_relid );
> 
> 	copy_path_costsize(&scan_plan->scan.plan, best_path);
> 
> 	return scan_plan;
> }
> 
1288a1320,1339
> 	node->scan.scanstate = (CommonScanState *) NULL;
> 
> 	return node;
> }
> 
> PortalScan *
> make_portalscan(List *qptlist,
> 				  List *qpqual,
> 				  Index scanrelid)
> {
> 	PortalScan *node = makeNode(PortalScan);
> 	Plan	   *plan = &node->scan.plan;
> 
> 	/* cost should be inserted by caller */
> 	plan->state = (EState *) NULL;
> 	plan->targetlist = qptlist;
> 	plan->qual = qpqual;
> 	plan->lefttree = NULL;
> 	plan->righttree = NULL;
> 	node->scan.scanrelid = scanrelid;
Index: src/backend/optimizer/plan/planner.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/planner.c,v
retrieving revision 1.108
retrieving revision 1.109
diff -r1.108 -r1.109
271c271,272
< 		Query	   *subquery = rte->subquery;
---
> 		Query	   *subquery = rte->u.sub.subquery;
> 		
280c281,282
< 		if (subquery && is_simple_subquery(subquery) &&
---
> 		if (rte->rtetype == RTE_SUBSELECT && 
>              is_simple_subquery(subquery) &&
Index: src/backend/optimizer/plan/setrefs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/setrefs.c,v
retrieving revision 1.71
retrieving revision 1.72
diff -r1.71 -r1.72
89a90,93
> 		case T_PortalScan:
> 			fix_expr_references(plan, (Node *) plan->targetlist);
> 			fix_expr_references(plan, (Node *) plan->qual);
> 			break;
Index: src/backend/optimizer/prep/preptlist.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/prep/preptlist.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -r1.42 -r1.43
61c61
< 		if (rte->subquery != NULL || rte->relid == InvalidOid)
---
> 		if (rte->rtetype == RTE_SUBSELECT)
Index: src/backend/optimizer/prep/prepunion.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/prep/prepunion.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -r1.66 -r1.67
84a85
> 	RangeTblEntry *rte;
97,98c98,102
< 	leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex,
< 							 parse->rtable)->subquery;
---
> 	rte = rt_fetch(((RangeTblRef *) node)->rtindex, parse->rtable);
> 	Assert(rte && rte->rtetype == RTE_SUBSELECT);
> 
> 	leftmostQuery = rte->u.sub.subquery;
> 
130c134
< 		Query	   *subquery = rte->subquery;
---
> 		Query	   *subquery = rte->u.sub.subquery;
133a138
> 		Assert(rte->rtetype == RTE_SUBSELECT);
558c563
< 	Oid			parentOID = rte->relid;
---
> 	Oid			parentOID = rte->u.rel.relid;
561a567
> 	Assert(rte->rtetype == RTE_RELATION);
566c572
< 	Assert(parentOID != InvalidOid && rte->subquery == NULL);
---
> 
604,605c610,613
< 		childrte->relname = get_rel_name(childOID);
< 		childrte->relid = childOID;
---
> 		Assert(rte->rtetype == RTE_RELATION);
> 		Assert(childrte->rtetype == RTE_RELATION);
> 		childrte->u.rel.relname = get_rel_name(childOID);
> 		childrte->u.rel.relid = childOID;
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.88
retrieving revision 1.89
diff -r1.88 -r1.89
1801,1802c1801,1802
< 			if (rte->subquery)
< 				if (walker(rte->subquery, context))
---
> 			if (rte->rtetype == RTE_SUBSELECT)
> 				if (walker( rte->u.sub.subquery, context))
2182c2182
< 			RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
---
> 			RangeTblEntry *rte = lfirst(rt);
2184c2184
< 			if (rte->subquery)
---
> 			if (rte->rtetype == RTE_SUBSELECT)
2189,2190c2189,2192
< 				CHECKFLATCOPY(newrte->subquery, rte->subquery, Query);
< 				MUTATE(newrte->subquery, newrte->subquery, Query *);
---
> 				CHECKFLATCOPY(newrte->u.sub.subquery, rte->u.sub.subquery, 
> 								Query);
> 				MUTATE(newrte->u.sub.subquery, newrte->u.sub.subquery, 
> 						Query *);
Index: src/backend/optimizer/util/pathnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/pathnode.c,v
retrieving revision 1.75
retrieving revision 1.76
diff -r1.75 -r1.76
436a437,457
>  * create_portalscan_path
>  *	  Creates a path corresponding to a sequential scan of a portal,
>  *	  returning the pathnode.
>  */
> Path *
> create_portalscan_path(RelOptInfo *rel, Portal portal)
> {
> 	Path	   *pathnode = makeNode(Path);
> 
> 	pathnode->pathtype = T_PortalScan;
> 	pathnode->parent = rel;
> 	pathnode->pathkeys = NIL;	/* for now, assume unordered result */
> 
> 	/* just copy the Portal's own cost estimates */
> 	pathnode->startup_cost = portal->queryDesc->plantree->startup_cost;
> 	pathnode->total_cost = portal->queryDesc->plantree->total_cost;
> 
> 	return pathnode;
> }
> 
> /*
Index: src/backend/optimizer/util/relnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/relnode.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -r1.33 -r1.34
128c128
< 	Oid			relationObjectId;
---
> 	RangeTblEntry *rte;
138d137
< 	rel->issubquery = false;
149,150c148,149
< 	/* Check rtable to see if it's a plain relation or a subquery */
< 	relationObjectId = getrelid(relid, root->rtable);
---
>    /* Check rtable to see if what kind of a relation it is */
> 	rte = rt_fetch(relid, root->rtable);
152c151
< 	if (relationObjectId != InvalidOid)
---
> 	if (rte->rtetype == RTE_RELATION)
154,155c153,155
< 		/* Plain relation --- retrieve statistics from the system catalogs */
< 		bool	indexed;
---
> 	    /* Plain relation --- retrieve statistics from the system catalogs */
> 	    bool    indexed;
> 	    Oid     relationObjectId;
157,160c157,163
< 		get_relation_info(relationObjectId,
< 						  &indexed, &rel->pages, &rel->tuples);
< 		if (indexed)
< 			rel->indexlist = find_secondary_indexes(relationObjectId);
---
> 	    rel->reltype = REL_PLAIN;
> 	    relationObjectId = rte->u.rel.relid;
> 
> 	    get_relation_info( relationObjectId,
> 	                      &indexed, &rel->pages, &rel->tuples);
> 	    if (indexed)
> 	        rel->indexlist = find_secondary_indexes(relationObjectId);
162c165
< 	else
---
> 	else if (rte->rtetype == RTE_SUBSELECT)
164,165c167
< 		/* subquery --- mark it as such for later processing */
< 		rel->issubquery = true;
---
> 	    rel->reltype = REL_SUBQUERY;
166a169,174
> 	else if (rte->rtetype == RTE_PORTAL)
> 	{
> 	    rel->reltype = REL_PORTAL;
> 	}
> 	else
> 	    elog(ERROR, "make_base_rel: Unknown RTE node type %d", nodeTag(rte) );
287a296
> 	joinrel->reltype = REL_JOIN;
295d303
< 	joinrel->issubquery = false;
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.197
retrieving revision 1.198
diff -r1.197 -r1.198
172d171
< 
2020a2020
> 	RangeTblEntry* leftmostRTE;
2096c2096,2099
< 	leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
---
> 	leftmostRTE = rt_fetch(leftmostRTI, pstate->p_rtable);
> 	Assert(node && leftmostRTE->rtetype ==  RTE_SUBSELECT);
> 	leftmostQuery = leftmostRTE->u.sub.subquery;
> 
2366c2369
< 		Query	   *selectQuery = rte->subquery;
---
> 		Query	   *selectQuery = rte->u.sub.subquery;
2369a2373
> 		Assert(rte->rtetype == RTE_SUBSELECT);
2878c2882
< 			if (rte->subquery)
---
> 			if (rte->rtetype ==  RTE_SUBSELECT)
2881c2885
< 				transformForUpdate(rte->subquery, makeList1(NULL));
---
> 				transformForUpdate( rte->u.sub.subquery, makeList1(NULL));
2883c2887
< 			else
---
> 			else if ( rte->rtetype == RTE_RELATION )
2888a2893,2900
> 			else if ( rte->rtetype == RTE_PORTAL )
> 			{ 
>                /* do nothing */
> 			}
> 			else 
> 			{
> 				elog(ERROR, "FOR UPDATE: unknown RTE type %d", rte->rtetype);
> 			}
2906c2918
< 					if (rte->subquery)
---
> 					if (rte->rtetype == RTE_SUBSELECT) 
2909c2921
< 						transformForUpdate(rte->subquery, makeList1(NULL));
---
> 						transformForUpdate( rte->u.sub.subquery, makeList1(NULL));
2911c2923
< 					else
---
> 					else if (rte->rtetype == RTE_RELATION)
2915a2928,2936
> 					} 
> 					else if (rte->rtetype == RTE_PORTAL)
> 					{ 
>                			/* do nothing */
> 					}
> 					else 
> 					{
> 						elog(ERROR, "FOR UPDATE: unknown RTE type %d", 
> 								rte->rtetype);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.249
diff -r2.249 gram.y
3726c3726,3735
< table_ref:  relation_expr
---
> table_ref:  
> 		CURSOR relation_name
> 				{
> 					PortalRangeVar *n = makeNode(PortalRangeVar);
> 					n->portal = $2;
> 					n->name = NULL;
> 					$$ = (Node *) n;
> 				}
> 	|
> 		relation_expr
5616d5624
< 		| CURSOR						{ $$ = "cursor"; }
Index: src/backend/parser/parse_clause.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_clause.c,v
retrieving revision 1.82
retrieving revision 1.83
diff -r1.82 -r1.83
33a34
> #include "utils/portal.h"
82a84
>          * FuncRangeVars, PortalRangeVars,
394a397,442
>  * transformPortalRange --- transform FROM CURSOR FOO 
>  */
> static RangeTblRef *
> transformPortalRange(ParseState *pstate, PortalRangeVar *r)
> {
> 	RangeTblEntry *rte;
> 	RangeTblRef *rtr;
> 	Portal      portal;
> 	QueryDesc  *queryDesc;
> 	TupleDesc  tupleDesc;
> 	EState     *estate;
> 	char 	   *portalname;
> 
>     /* look up information for the portal */
>     portalname = r->portal;
> 	portal = GetPortalByName(portalname);
> 	if (!PortalIsValid(portal))
> 		elog(ERROR, "transformPortalRange: portal \"%s\" not found",
> 			portalname);
> 
>     queryDesc = PortalGetQueryDesc(portal);
> 	tupleDesc = PortalGetTupleDesc(portal);
>     estate = PortalGetState(portal); /* XXX: check state ? */
> 
> 	if (queryDesc->operation != CMD_SELECT)
> 		elog(ERROR, "Expected SELECT query from the portal %s", portalname);
> 
> 	/*
> 	 * OK, build an RTE for the subquery.
> 	 */
> 	rte = addRangeTableEntryForPortal(pstate, portalname, r->name);
> 
> 	/*
> 	 * We create a RangeTblRef, but we do not add it to the joinlist or
> 	 * namespace; our caller must do that if appropriate.
> 	 */
> 	rtr = makeNode(RangeTblRef);
> 	/* assume new rte is at end */
> 	rtr->rtindex = length(pstate->p_rtable);
> 	Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
> 
> 	return rtr;
> }
> 
> 
> /*
482a531,539
> 		*containedRels = makeListi1(rtr->rtindex);
> 		return (Node *) rtr;
> 	}
> 	if (IsA(n, PortalRangeVar))
> 	{
> 		/* reference to cursor */
> 		RangeTblRef *rtr;
> 
> 		rtr = transformPortalRange(pstate, (PortalRangeVar *) n);
Index: src/backend/parser/parse_func.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_func.c,v
retrieving revision 1.110
retrieving revision 1.111
diff -r1.110 -r1.111
389c389,396
< 			if (rte->relname == NULL)
---
> 			if (rte->rtetype == RTE_PORTAL)
> 			{ 
>               /* RTE is a portal reference, possible? not supported yet */
> 		 		elog(ERROR, "Cannot pass tuple from portal %s to function %s",
> 						 refname, funcname);
>  			}
> 
> 			if (rte->rtetype == RTE_SUBSELECT)
410c417
< 			toid = typenameTypeId(rte->relname);
---
> 			toid = typenameTypeId( rte->u.rel.relname);
Index: src/backend/parser/parse_node.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_node.c,v
retrieving revision 1.55
retrieving revision 1.56
diff -r1.55 -r1.56
36a37
> #include "utils/portal.h"
173c174
< 	if (rte->relid != InvalidOid)
---
> 	if (rte->rtetype == RTE_RELATION)
180c181
< 							ObjectIdGetDatum(rte->relid),
---
> 							ObjectIdGetDatum(rte->u.rel.relid),
186c187
< 				 rte->relname, attrno);
---
> 				 rte->u.rel.relname, attrno);
192c193,206
< 	else
---
>     else if (rte->rtetype == RTE_PORTAL)
> 	{   /* Portal RTE, get type info from it */
> 		TupleDesc tupleDesc = 
> 			GetPortalTupleDescByName(rte->u.portal.portalname);
> 		Form_pg_attribute att_tup;
> 
> 		Assert( attrno <= (tupleDesc->natts) );
> 
> 		att_tup = tupleDesc->attrs[attrno-1];
> 
> 		vartypeid = att_tup->atttypid;
> 		type_mod = att_tup->atttypmod;
> 	}
> 	else if (rte->rtetype == RTE_SUBSELECT)
197c211
< 		foreach(tlistitem, rte->subquery->targetList)
---
> 		foreach(tlistitem, rte->u.sub.subquery->targetList)
210a225,228
> 	}
>  	else 
> 	{
> 			elog(ERROR, "make_var: Unknown RTE type");
Index: src/backend/parser/parse_relation.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_relation.c,v
retrieving revision 1.56
retrieving revision 1.57
diff -r1.56 -r1.57
30a31
> #include "utils/portal.h"
321c322
< 	if (rte->relid != InvalidOid)
---
> 	if (rte->rtetype == RTE_RELATION)
329c330
< 									 ObjectIdGetDatum(rte->relid),
---
> 									 ObjectIdGetDatum(rte->u.rel.relid),
513c514,515
< 	rte->relname = relname;
---
> 	rte->rtetype = RTE_RELATION;
> 	rte->u.rel.relname = relname;
515d516
< 	rte->subquery = NULL;
525c526
< 	rte->relid = RelationGetRelid(rel);
---
> 	rte->u.rel.relid = RelationGetRelid(rel);
580c581,649
< 	return rte;
---
> 	return (RangeTblEntry *) rte;
> }
> 
> /*
>  * Add an entry for a portal reference or for a function-used-as-table
>  *  to the pstate's range table (p_rtable).
>  *
>  * This is just like addRangeTableEntry() except that it makes a portal RTE.
>  */
> RangeTblEntry *
> addRangeTableEntryForPortal(ParseState *pstate,
> 							char *portalname,
> 						    Attr *alias
> 							)
> {
> 	RangeTblEntry *rte = makeNode(RangeTblEntry);
> 	char	   *refname = alias ? alias->relname : portalname;
> 	Attr	   *eref;
> 	int			maxattrs;
> 	int			numaliases;
> 	int			varattno;
> 	TupleDesc 	tupleDesc;
> 
> 	rte->rtetype = RTE_PORTAL;
> 	rte->u.portal.portalname = portalname;
> 	rte->alias = alias;
> 
> 	eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
> 	numaliases = length(eref->attrs);
> 
> 	/* fill in any unspecified alias columns */
> 	varattno = 0;
> 
> 	tupleDesc = GetPortalTupleDescByName( portalname );
> 	maxattrs = tupleDesc->natts;
> 	if (maxattrs < numaliases)
> 		elog(ERROR, "Portal \"%s\" has %d columns available but %d aliases specified",
> 			 refname, maxattrs, numaliases);
> 
> 	/* fill in any unspecified alias columns */
> 	for (varattno = numaliases; varattno < maxattrs; varattno++)
> 	{
> 		char	   *attrname;
> 
> 		attrname = pstrdup(NameStr(tupleDesc->attrs[varattno]->attname));
> 		eref->attrs = lappend(eref->attrs, makeString(attrname));
> 	}
> 	rte->eref = eref;
> 
> 	/*----------
> 	 * Flags:
> 	 * - this RTE should be expanded to include descendant tables,
> 	 * - this RTE is in the FROM clause,
> 	 * - this RTE should be checked for read/write access rights.
> 	 */
> 	rte->inh = false;
> 	rte->inFromCl = true;
> 	rte->checkForRead = false;
> 	rte->checkForWrite = false;
> 	rte->checkAsUser = InvalidOid;		/* not set-uid by default, either */
> 
> 	/*
> 	 * Add completed RTE to pstate's range table list, but not to join
> 	 * list nor namespace --- caller must do that if appropriate.
> 	 */
> 	if (pstate != NULL)
> 		pstate->p_rtable = lappend(pstate->p_rtable, rte);
> 
> 	return (RangeTblEntry *) rte;
602,604c671,672
< 	rte->relname = NULL;
< 	rte->relid = InvalidOid;
< 	rte->subquery = subquery;
---
> 	rte->rtetype = RTE_SUBSELECT;
> 	rte->u.sub.subquery = subquery;
657c725
< 	return rte;
---
> 	return (RangeTblEntry *) rte;
759c827,863
< 	if (rte->relname)
---
> 	if (rte->rtetype == RTE_PORTAL)
> 	{
> 		/* Portal RTE */
> 		TupleDesc 	td;
> 		int			maxattrs;
>         td = GetPortalTupleDescByName( rte->u.portal.portalname );
> 
> 		maxattrs = td->natts;
> 
> 		for (varattno = 0; varattno < maxattrs; varattno++)
> 		{
> 			Form_pg_attribute attr = td->attrs[varattno];
> 
> 			if (colnames)
> 			{
> 				char	   *label;
> 
> 				if (varattno < length(rte->eref->attrs))
> 					label = strVal(nth(varattno, rte->eref->attrs));
> 				else
> 					label = NameStr(attr->attname);
> 				*colnames = lappend(*colnames, makeString(pstrdup(label)));
> 			}
> 
> 			if (colvars)
> 			{
> 				Var		   *varnode;
> 
> 				varnode = makeVar(rtindex, attr->attnum,
> 								  attr->atttypid, attr->atttypmod,
> 								  sublevels_up);
> 
> 				*colvars = lappend(*colvars, varnode);
> 			}
> 		}
> 	}
> 	else if (rte->rtetype == RTE_RELATION)
765c869
< 		rel = heap_openr(rte->relname, AccessShareLock);
---
> 		rel = heap_openr( rte->u.rel.relname, AccessShareLock);
803c907
< 	else
---
> 	else if (rte->rtetype == RTE_SUBSELECT)
810c914,915
< 		foreach(tlistitem, rte->subquery->targetList)
---
> 		Assert( PointerIsValid(rte->u.sub.subquery) );
> 		foreach(tlistitem,rte->u.sub.subquery->targetList)
840a946,949
>     else 
>     { 
>        elog(ERROR, "expandRTE: Unknown RTE type");
>     }
916c1025
<  *		Get an attribute name from a RangeTblEntry
---
>  *		Get an attribute name from a RangeTblEntryRelation
920c1029
<  * get_attname() only works on real relations.
---
>  * get_attname() only works on real relations. ??? (below)
928a1038
>  *
950c1060
< 	if (rte->relid == InvalidOid)
---
> 	if (!rte->rtetype == RTE_RELATION)
957c1067
< 	attname = get_attname(rte->relid, attnum);
---
> 	attname = get_attname(rte->u.rel.relid, attnum);
960c1070
< 			 attnum, rte->relid);
---
> 			 attnum, rte->u.rel.relid);
1071a1182,1200
> 
> /*
>  *              getrelid
>  *
>  *              Given the range index of a relation, return the corresponding
>  *              relation OID.  Note that InvalidOid will be returned if the
>  *              RTE is for not for a relation. (SubSelect or Portal)
>  */
> 
> /* this used to be a #define */
> Oid getrelid (int rangeindex, List * rangetable) {
> 	RangeTblEntry *rte = rt_fetch(rangeindex, rangetable);
> 	if (rte->rtetype == RTE_RELATION) {
> 		return rte->u.rel.relid;
>  	} else { 
> 		return InvalidOid;
> 	}
> }
> 
Index: src/backend/rewrite/rewriteDefine.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/rewrite/rewriteDefine.c,v
retrieving revision 1.63
retrieving revision 1.64
diff -r1.63 -r1.64
449c449
< 		if (rte->subquery)
---
> 		if ( rte->rtetype == RTE_SUBSELECT )
452c452
< 			setRuleCheckAsUser(rte->subquery, userid);
---
> 			setRuleCheckAsUser( rte->u.sub.subquery, userid);
Index: src/backend/rewrite/rewriteHandler.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/rewrite/rewriteHandler.c,v
retrieving revision 1.97
retrieving revision 1.98
diff -r1.97 -r1.98
268,269c268,269
< 	RangeTblEntry *rte,
< 			   *subrte;
---
> 	RangeTblEntry *rte;
> 	RangeTblEntry *subrte;
292,294c292,305
< 	rte->relname = NULL;
< 	rte->relid = InvalidOid;
< 	rte->subquery = rule_action;
---
> 	/* We have to mutate whatever RTE kind it was into RTESubSelect  */
> 	if ( rte->rtetype == RTE_SUBSELECT ) 
> 	{
> 		/* already was SubSelect, do nothing */
> 	} else if (rte->rtetype == RTE_RELATION) {
> 		/* this may be dangerous, as we are changing the type on the fly,
>            perhaps its a better idea to copy RTE, then mangle it? */
> 
> 		rte->rtetype = RTE_SUBSELECT;
> 	} else {
> 		elog(ERROR, "ApplyRetrieveRule: unknown original RTE type");
>  	}
> 
> 	rte->u.sub.subquery = rule_action;
302c313,314
< 	Assert(subrte->relid == relation->rd_id);
---
> 	Assert( subrte->rtetype == RTE_RELATION );
> 	Assert( subrte->u.rel.relid == relation->rd_id);
358c370
< 		if (rte->subquery)
---
> 		if (rte->rtetype == RTE_SUBSELECT )
361c373
< 			markQueryForUpdate(rte->subquery, false);
---
> 			markQueryForUpdate( rte->u.sub.subquery, false);
439a452,461
> 		 * A portal RTE can't have associated rules, so there's nothing
> 		 * to do to this level of the query.
> 		 */
> 
> 		if (rte->rtetype == RTE_PORTAL)
> 		{
> 			continue;
> 		}
> 
> 		/*
444c466
< 		if (rte->subquery)
---
> 		if (rte->rtetype == RTE_SUBSELECT)
446c468
< 			rte->subquery = fireRIRrules(rte->subquery);
---
> 			rte->u.sub.subquery = fireRIRrules(rte->u.sub.subquery);
461a484,485
> 		/* by now, we should only have plain RTE to deal with */
> 		Assert(rte->rtetype == RTE_RELATION);
482c506
< 		rel = heap_openr(rte->relname, lockmode);
---
> 		rel = heap_openr(rte->u.rel.relname, lockmode);
490c514
< 		if (RelationGetRelid(rel) != rte->relid)
---
> 		if (RelationGetRelid(rel) != rte->u.rel.relid)
492c516
< 				 rte->relname, rte->relid);
---
> 				 rte->u.rel.relname, rte->u.rel.relid);
759a784
> 	Assert( rt_entry->rtetype == RTE_RELATION );
769c794
< 	rt_entry_relation = heap_openr(rt_entry->relname, RowExclusiveLock);
---
> 	rt_entry_relation = heap_openr(rt_entry->u.rel.relname, RowExclusiveLock);
777c802
< 	if (RelationGetRelid(rt_entry_relation) != rt_entry->relid)
---
> 	if (RelationGetRelid(rt_entry_relation) != rt_entry->u.rel.relid)
779c804
< 			 rt_entry->relname, rt_entry->relid);
---
> 			 rt_entry->u.rel.relname, rt_entry->u.rel.relid);
946c971
< 			if (rte->subquery)
---
> 			if (rte->rtetype == RTE_SUBSELECT)
Index: src/backend/rewrite/rewriteManip.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/rewrite/rewriteManip.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -r1.57 -r1.58
563c563,564
< 	selectquery = selectrte->subquery;
---
> 	Assert( selectrte->rtetype == RTE_SUBSELECT );
> 	selectquery = selectrte->u.sub.subquery;
574c575
< 			*subquery_ptr = &(selectrte->subquery);
---
> 			*subquery_ptr = &(selectrte->u.sub.subquery);
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.82
retrieving revision 1.83
diff -r1.82 -r1.83
703,704c703,705
< 	rte->relname = relname;
< 	rte->relid = relid;
---
> 	rte->rtetype = RTE_RELATION;
> 	rte->u.rel.relname = relname;
> 	rte->u.rel.relid = relid;
1165,1166c1166,1167
< 		Query	   *subquery = rte->subquery;
< 
---
> 		Query	   *subquery = rte->u.sub.subquery;
> 		Assert( rte->rtetype == RTE_SUBSELECT );
1244c1245
< 	RangeTblEntry *select_rte = NULL;
---
> 	RangeTblEntry *select_rte = NULL; /* rte for underlying SELECT */
1256c1257
< 		if (rte->subquery == NULL)
---
> 		if (rte->rtetype != RTE_SUBSELECT)
1266a1268
> 	Assert( rte->rtetype == RTE_RELATION );
1268c1270
< 					 quote_identifier(rte->relname));
---
> 					 quote_identifier(rte->u.rel.relname));
1304c1306
< 		get_query_def(select_rte->subquery, buf, NIL);
---
> 		get_query_def(select_rte->u.sub.subquery, buf, NIL);
1323a1326,1327
> 
> 	Assert(rte->rtetype == RTE_RELATION);
1326c1330
< 					 quote_identifier(rte->relname));
---
> 					 quote_identifier(rte->u.rel.relname));
1376a1381
> 	Assert(rte->rtetype == RTE_RELATION);
1379c1384
< 					 quote_identifier(rte->relname));
---
> 					 quote_identifier(rte->u.rel.relname));
2428c2433
< 		if (rte->relname)
---
> 		if (rte->rtetype == RTE_RELATION)
2433c2438
< 							 quote_identifier(rte->relname));
---
> 				 quote_identifier( rte->u.rel.relname));
2435c2440
< 		else
---
> 		else if (rte->rtetype == RTE_SUBSELECT)
2438d2442
< 			Assert(rte->subquery != NULL);
2440c2444
< 			get_query_def(rte->subquery, buf, context->namespaces);
---
> 			get_query_def( rte->u.sub.subquery, buf, context->namespaces);
2442c2446,2453
< 		}
---
> 		} else if (rte->rtetype == RTE_PORTAL) 
> 		{
> 			appendStringInfo(buf, " CURSOR %s",
> 							 rte->u.portal.portalname);
> 		} else 
> 			elog(ERROR, "get_from_clause_item: unknown RTE type");
> 
> 
Index: src/backend/utils/mmgr/portalmem.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/utils/mmgr/portalmem.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -r1.41 -r1.42
38a39,40
> #include "executor/execdefs.h"
> #include "executor/executor.h"
152a155,174
>  * GetPortalTupleDescByName
>  *		Returns a TupleDesc for portal given a portal name.
>  *      elog(ERROR) if it doesn't exist
>  */
> TupleDesc
> GetPortalTupleDescByName(char *name)
> {
> 	Portal		portal;
> 
> 	Assert( PointerIsValid(name) );
> 	PortalHashTableLookup(name, portal);
> 
>     if ( !PointerIsValid( portal ))
> 		elog( ERROR, 
> 				"GetPortalTupleDescByName: portal %s does not exist", name);
> 
> 	return portal->attinfo;
> }
> 
> /*
227a250,344
> }
> 
> /* Run the portal's underlying query for number of records, into dest
>  * properly setting context and atStart/atEnd flags after execution.
>  *
>  * If tts!=NULL, will put result of ExecutorRun into variable pointed by TTS
>  * 
>  * Returns number of records processed.
>  */
> int
> PortalRun(Portal portal, bool forward, long count, CommandDest dest, TupleTableSlot **tts)
> {
> 	QueryDesc  *queryDesc;
> 	EState     *estate;
> 	TupleTableSlot *tts_exec;
> 	bool        faked_desc = false;
> 	bool 		did_fetch = false; /* did we actually try to run executor? */
> 	MemoryContext oldcontext;
> 
> 	if (tts) *tts=NULL;
> 
> 	/*
> 	 * switch into the portal context
> 	 */
> 	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
> 
> 	/*
> 	 * tell the destination to prepare to receive some tuples.
> 	 *
> 	 * If passed CommandDest  is not the same as portal's CommandDest, 
>      * make a temporary QueryDesc with the new destination.
> 	 */
> 	queryDesc = PortalGetQueryDesc(portal);
> 	estate = PortalGetState(portal);
> 
> 	if (dest != queryDesc->dest)
> 	{
> 		QueryDesc  *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
> 
> 		memcpy(qdesc, queryDesc, sizeof(QueryDesc));
> 		qdesc->dest = dest;
> 		queryDesc = qdesc;
> 		faked_desc = true;
> 	}
> 
> 	/*
> 	 * Determine which direction to go in, and check to see if we're
> 	 * already at the end of the available tuples in that direction.  If
> 	 * so, do nothing.	(This check exists because not all plan node types
> 	 * are robust about being called again if they've already returned
> 	 * NULL once.)	If it's OK to do the fetch, call the executor.  Then,
> 	 * update the atStart/atEnd state depending on the number of tuples
> 	 * that were retrieved.
> 	 */
> 	if (forward)
> 	{
> 		if (!portal->atEnd)
> 		{
> 			tts_exec=ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
> 			if (estate->es_processed > 0)
> 				portal->atStart = false;		/* OK to back up now */
> 			if (count <= 0 || (int) estate->es_processed < count)
> 				portal->atEnd = true;	/* we retrieved 'em all */
> 			did_fetch = true;
> 		}
> 	}
> 	else
> 	{
> 		if (!portal->atStart)
> 		{
> 			tts_exec=ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
> 			if (estate->es_processed > 0)
> 				portal->atEnd = false;	/* OK to go forward now */
> 			if (count <= 0 || (int) estate->es_processed < count)
> 				portal->atStart = true; /* we retrieved 'em all */
> 			did_fetch = true;
> 		}
> 	}
> 
> 	/*
> 	 * Clean up and switch back to old context.
> 	 */
> 	if (faked_desc)			/* MOVE */
> 		pfree(queryDesc);
> 
> 	MemoryContextSwitchTo(oldcontext);
> 
> 	/* store what we got from Executor */
> 	if (tts && did_fetch) 
> 		*tts=tts_exec;
> 
> 	/* check whether we actually retrieved records */
> 	if (did_fetch)
> 		return estate->es_processed;
> 	return 0;
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.62
retrieving revision 1.63
diff -r1.62 -r1.63
483a484,496
> /* ----------------
>  *	 PortalScanState information
>  *
>  *		PortalScanState is used for scanning a portal.
>  *
>  * ----------------
>  */
> typedef struct PortalScanState
> {
> 	CommonScanState csstate;	/* its first field is NodeTag */
> 	struct PortalData	   * portal;
> } PortalScanState;
> 
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.93
retrieving revision 1.94
diff -r1.93 -r1.94
51a52
> 	T_PortalScan,
122a124
> 	T_PortalScanState,
224a227,228
> /*	T_FuncRangeVar, */
> 	T_PortalRangeVar, 
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.143
retrieving revision 1.144
diff -r1.143 -r1.144
17a18,19
> #include "access/tupdesc.h"
> 
891a894
> 	bool 	isFunc; 		/* select * from func(args) */
1183a1187,1208
>  * FuncRangeVar - range variable, used in FROM clauses
>  *                select x,y from foo(1) as bar(x,y)
>  */
> typedef struct FuncRangeVar
> {
> 	NodeTag		type;
>   	Node 	*func;
> 	Attr	   *name;	/* optional table alias & column aliases */
> } FuncRangeVar;
> 
> /*
>  * PortalRangeVar - range variable, used in FROM clauses
>  *                select x,y from cursor foo
>  */
> typedef struct PortalRangeVar
> {
> 	NodeTag		type;
>   	char 	*portal;
> 	Attr	*name;			/* optional table alias & column aliases */
> } PortalRangeVar;
> 
> /*
1289a1315,1320
> typedef enum RTEType {
> 	RTE_RELATION,
> 	RTE_SUBSELECT,
> 	RTE_PORTAL
> } RTEType;
> 
1293,1304c1324
< 
< 	/*
< 	 * Fields valid for a plain relation RTE (else NULL/zero):
< 	 */
< 	char	   *relname;		/* real name of the relation */
< 	Oid			relid;			/* OID of the relation */
< 
< 	/*
< 	 * Fields valid for a subquery RTE (else NULL):
< 	 */
< 	Query	   *subquery;		/* the sub-query */
< 
---
>     RTEType 	rtetype;
1314a1335,1350
> 
>     union {
> 		struct  {
> 			/* Fields for a plain relation RTE (rtetype=RTE_RELATION) */
> 			char	   *relname;		/* real name of the relation */
> 			Oid			relid;			/* OID of the relation */
> 		} rel;
>  		struct {
> 			/* Fields for a subquery RTE (rtetype=RTE_SUBSELECT) */
> 			Query	   *subquery;		/* the sub-query */
> 		} sub;
> 		struct { 
>  			/* fields for portal RTE (rtetype=RTE_PORTAL) */
>     		char 		  *portalname;    /* portal's name */
> 		} portal;
>  	} u;
Index: src/include/nodes/plannodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/plannodes.h,v
retrieving revision 1.49
retrieving revision 1.50
diff -r1.49 -r1.50
232a233,243
> /* ----------------
>  *		portal scan node
>  *
>  * PortalScan is for scanning the existing portal. Will need additional 
>  * fields, but currently, its just the Scan.
>  */
> typedef struct PortalScan
> {
> 	Scan		scan;
> } PortalScan;
> 
Index: src/include/nodes/relation.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/relation.h,v
retrieving revision 1.58
retrieving revision 1.59
diff -r1.58 -r1.59
131a132,138
> typedef enum RelOptInfoType {
>   REL_PLAIN, 
>   REL_SUBQUERY,
>   REL_JOIN,
>   REL_PORTAL
> } RelOptInfoType;
> 
135a143,144
> 	RelOptInfoType		reltype;
> 
151,152c160
< 	/* information about a base rel (not set for join rels!) */
< 	bool		issubquery;
---
> 	/* Following fields are only for REL_PLAIN */
155a164,165
> 
> 	/* following field is only for REL_SUBQUERY */
Index: src/include/optimizer/pathnode.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/optimizer/pathnode.h,v
retrieving revision 1.38
retrieving revision 1.39
diff -r1.38 -r1.39
17a18
> #include "utils/portal.h"
37a39
> extern Path *create_portalscan_path(RelOptInfo *rel, Portal portal);
Index: src/include/parser/parse_relation.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/parser/parse_relation.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -r1.24 -r1.25
38a39,42
> extern RangeTblEntry * addRangeTableEntryForPortal(ParseState *pstate,
>                             char *portalname,
>                             Attr *alias
>                             );
Index: src/include/parser/parsetree.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/parser/parsetree.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -r1.13 -r1.14
39,47c39,40
< /*
<  *		getrelid
<  *
<  *		Given the range index of a relation, return the corresponding
<  *		relation OID.  Note that InvalidOid will be returned if the
<  *		RTE is for a sub-select rather than a relation.
<  */
< #define getrelid(rangeindex,rangetable) \
< 	(rt_fetch(rangeindex, rangetable)->relid)
---
> /* getrelid is no longer a #define */
> extern Oid getrelid (int rangeindex, List * rangetable);
Index: src/include/utils/portal.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/utils/portal.h,v
retrieving revision 1.28
retrieving revision 1.29
diff -r1.28 -r1.29
65a66
> extern TupleDesc GetPortalTupleDescByName(char *name);
69c70,71
< 
---
> extern int PortalRun(Portal portal, bool forward, 
> 					long count, CommandDest dest, TupleTableSlot **tts);
Index: src/include/executor/nodePortalscan.h
===================================================================
RCS file: nodePortalscan.h
diff -N nodePortalscan.h
0a1,27
> /*-------------------------------------------------------------------------
>  *
>  * nodePortalscan.h
>  *
>  *
>  *
>  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
>  * Portions Copyright (c) 1994, Regents of the University of California
>  *
>  * $Id$
>  *
>  *-------------------------------------------------------------------------
>  */
> #ifndef NODEPORTALSCAN_H
> #define NODEPORTALSCAN_H
> 
> #include "nodes/plannodes.h"
> 
> extern TupleTableSlot *ExecPortalScan(PortalScan *node);
> extern bool ExecInitPortalScan(PortalScan *node, EState *estate, Plan *parent);
> extern int	ExecCountSlotsPortalScan(PortalScan *node);
> extern void ExecEndPortalScan(PortalScan *node);
> extern void ExecPortalReScan(PortalScan *node, ExprContext *exprCtxt, Plan *parent);
> extern void ExecPortalMarkPos(PortalScan *node);
> extern void ExecPortalRestrPos(PortalScan *node);
> 
> #endif	 /* NODESEQSCAN_H */