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 */