cursor.fix5.diff
text/plain
Filename: cursor.fix5.diff
Type: text/plain
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| nodePortalscan.c | 258 | 0 |
| nodePortalscan.h | 27 | 0 |
| src/backend/commands/command.c | 5 | 42 |
| src/backend/commands/explain.c | 14 | 7 |
| src/backend/executor/execAmi.c | 9 | 0 |
| src/backend/executor/execMain.c | 6 | 5 |
| src/backend/executor/execProcnode.c | 25 | 0 |
| src/backend/executor/Makefile | 2 | 1 |
| src/backend/executor/nodeIndexscan.c | 3 | 1 |
| src/backend/executor/nodeSeqscan.c | 4 | 1 |
| src/backend/executor/nodeSubqueryscan.c | 3 | 2 |
| src/backend/executor/nodeTidscan.c | 3 | 1 |
| src/backend/executor/spi.c | 4 | 43 |
| src/backend/nodes/copyfuncs.c | 37 | 8 |
| src/backend/nodes/equalfuncs.c | 20 | 9 |
| src/backend/nodes/outfuncs.c | 32 | 6 |
| src/backend/nodes/print.c | 15 | 5 |
| src/backend/nodes/readfuncs.c | 28 | 12 |
| src/backend/optimizer/path/allpaths.c | 49 | 5 |
| src/backend/optimizer/path/clausesel.c | 1 | 1 |
| src/backend/optimizer/path/costsize.c | 2 | 2 |
| src/backend/optimizer/plan/createplan.c | 59 | 8 |
| src/backend/optimizer/plan/planner.c | 4 | 2 |
| src/backend/optimizer/plan/setrefs.c | 4 | 0 |
| src/backend/optimizer/prep/preptlist.c | 1 | 1 |
| src/backend/optimizer/prep/prepunion.c | 15 | 7 |
| src/backend/optimizer/util/clauses.c | 8 | 6 |
| src/backend/optimizer/util/pathnode.c | 21 | 0 |
| src/backend/optimizer/util/relnode.c | 23 | 15 |
| src/backend/parser/analyze.c | 30 | 9 |
| src/backend/parser/gram.y | 10 | 2 |
| src/backend/parser/parse_clause.c | 57 | 0 |
| src/backend/parser/parse_func.c | 9 | 2 |
| src/backend/parser/parse_node.c | 23 | 5 |
| src/backend/parser/parse_relation.c | 148 | 19 |
| src/backend/rewrite/rewriteDefine.c | 2 | 2 |
| src/backend/rewrite/rewriteHandler.c | 42 | 17 |
| src/backend/rewrite/rewriteManip.c | 3 | 2 |
| src/backend/utils/adt/ruleutils.c | 27 | 16 |
| src/backend/utils/mmgr/portalmem.c | 117 | 0 |
| src/include/nodes/execnodes.h | 13 | 0 |
| src/include/nodes/nodes.h | 4 | 0 |
| src/include/nodes/parsenodes.h | 48 | 12 |
| src/include/nodes/plannodes.h | 11 | 0 |
| src/include/nodes/relation.h | 12 | 2 |
| src/include/optimizer/pathnode.h | 2 | 0 |
| src/include/parser/parse_relation.h | 4 | 0 |
| src/include/parser/parsetree.h | 2 | 9 |
| src/include/utils/portal.h | 3 | 1 |
Index: src/backend/commands/command.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/commands/command.c,v
retrieving revision 1.142
diff --unified -r1.142 command.c
--- src/backend/commands/command.c 2001/09/07 21:57:53 1.142
+++ src/backend/commands/command.c 2001/09/21 17:32:46
@@ -101,6 +101,7 @@
CommandDest dest)
{
Portal portal;
+ int result;
QueryDesc *queryDesc;
EState *estate;
MemoryContext oldcontext;
@@ -169,48 +170,10 @@
tag,
queryDesc->dest);
- /*
- * 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.66
diff --unified -r1.66 explain.c
--- src/backend/commands/explain.c 2001/09/18 01:59:06 1.66
+++ src/backend/commands/explain.c 2001/09/21 17:32:46
@@ -218,6 +218,9 @@
case T_SeqScan:
pname = "Seq Scan";
break;
+ case T_PortalScan:
+ pname = "Portal Scan";
+ break;
case T_IndexScan:
pname = "Index Scan";
break;
@@ -296,15 +299,16 @@
case T_TidScan:
if (((Scan *) plan)->scanrelid > 0)
{
- RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
+ RangeTblEntry *rte = (RangeTblEntry*)
+ rt_fetch(((Scan *) plan)->scanrelid,
es->rtable);
/* Assume it's on a real relation */
- Assert(rte->relname);
+ Assert( rte->rtetype == RTE_RELATION );
appendStringInfo(str, " on %s",
- 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)
appendStringInfo(str, " %s",
stringStringInfo(rte->eref->relname));
}
@@ -401,12 +405,15 @@
{
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
Plan *subnode = subqueryscan->subplan;
- RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
+
+ RangeTblEntry *rte = (RangeTblEntry *)
+ rt_fetch(subqueryscan->scan.scanrelid,
es->rtable);
+
List *saved_rtable = es->rtable;
- Assert(rte->subquery != NULL);
- es->rtable = rte->subquery->rtable;
+ Assert(rte->rtetype == RTE_SUBSELECT);
+ es->rtable = rte->u.sub.subquery->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
Index: src/backend/executor/Makefile
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/Makefile,v
retrieving revision 1.17
diff --unified -r1.17 Makefile
--- src/backend/executor/Makefile 2001/09/18 01:59:06 1.17
+++ src/backend/executor/Makefile 2001/09/21 17:32:46
@@ -16,7 +16,8 @@
execProcnode.o execQual.o execScan.o execTuples.o \
execUtils.o functions.o instrument.o nodeAppend.o nodeAgg.o nodeHash.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
- nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
+ nodeNestloop.o nodePortalscan.o nodeResult.o nodeSeqscan.o \
+ nodeSetOp.o nodeSort.o \
nodeUnique.o nodeLimit.o nodeGroup.o nodeSubplan.o \
nodeSubqueryscan.o nodeTidscan.o spi.o
Index: src/backend/executor/execAmi.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execAmi.c,v
retrieving revision 1.59
diff --unified -r1.59 execAmi.c
--- src/backend/executor/execAmi.c 2001/09/18 01:59:06 1.59
+++ src/backend/executor/execAmi.c 2001/09/21 17:32:47
@@ -43,6 +43,7 @@
#include "executor/nodeMergejoin.h"
#include "executor/nodeNestloop.h"
#include "executor/nodeResult.h"
+#include "executor/nodePortalscan.h"
#include "executor/nodeSeqscan.h"
#include "executor/nodeSetOp.h"
#include "executor/nodeSort.h"
@@ -186,6 +187,10 @@
state = ((SeqScan *) node)->scanstate;
break;
+ case T_PortalScan:
+ state = ((PortalScan *) node)->scan.scanstate;
+ break;
+
case T_IndexScan:
state = ((IndexScan *) node)->scan.scanstate;
break;
@@ -296,6 +301,10 @@
{
case T_SeqScan:
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
+ break;
+
+ case T_PortalScan:
+ ExecPortalReScan((PortalScan *) node, exprCtxt, parent);
break;
case T_IndexScan:
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.148
diff --unified -r1.148 execMain.c
--- src/backend/executor/execMain.c 2001/09/18 01:59:06 1.148
+++ src/backend/executor/execMain.c 2001/09/21 17:32:47
@@ -345,8 +345,9 @@
/* Recursively check the subquery */
rte = rt_fetch(scan->scan.scanrelid, rangeTable);
- Assert(rte->subquery != NULL);
- ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
+ Assert(rte->rtetype == RTE_SUBSELECT);
+ ExecCheckQueryPerms(operation, rte->u.sub.subquery,
+ scan->subplan);
break;
}
case T_Append:
@@ -400,10 +401,10 @@
* If it's a subquery RTE, ignore it --- it will be checked when
* ExecCheckPlanPerms finds the SubqueryScan node for it.
*/
- if (rte->subquery)
- return;
+ if (!rte->rtetype == RTE_RELATION) return;
- relName = rte->relname;
+
+ relName = rte->u.rel.relname;
/*
* userid to check as: current user unless we have a setuid
Index: src/backend/executor/execProcnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/execProcnode.c,v
retrieving revision 1.27
diff --unified -r1.27 execProcnode.c
--- src/backend/executor/execProcnode.c 2001/09/18 01:59:06 1.27
+++ src/backend/executor/execProcnode.c 2001/09/21 17:32:47
@@ -90,6 +90,7 @@
#include "executor/nodeMaterial.h"
#include "executor/nodeMergejoin.h"
#include "executor/nodeNestloop.h"
+#include "executor/nodePortalscan.h"
#include "executor/nodeResult.h"
#include "executor/nodeSeqscan.h"
#include "executor/nodeSetOp.h"
@@ -168,6 +169,11 @@
parent);
break;
+ case T_PortalScan:
+ result = ExecInitPortalScan((PortalScan *) node, estate,
+ parent);
+ break;
+
/*
* join nodes
*/
@@ -297,6 +303,10 @@
result = ExecSubqueryScan((SubqueryScan *) node);
break;
+ case T_PortalScan:
+ result = ExecPortalScan((PortalScan *) node);
+ break;
+
/*
* join nodes
*/
@@ -392,6 +402,9 @@
case T_SubqueryScan:
return ExecCountSlotsSubqueryScan((SubqueryScan *) node);
+ case T_PortalScan:
+ return ExecCountSlotsPortalScan((PortalScan *) node);
+
/*
* join nodes
*/
@@ -503,6 +516,10 @@
ExecEndSubqueryScan((SubqueryScan *) node);
break;
+ case T_PortalScan:
+ ExecEndPortalScan((PortalScan *) node);
+ break;
+
/*
* join nodes
*/
@@ -635,6 +652,14 @@
case T_SubqueryScan:
{
CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_PortalScan:
+ {
+ CommonScanState *scanstate = ((PortalScan *) node)->scan.scanstate;
slot = scanstate->cstate.cs_ResultTupleSlot;
}
Index: src/backend/executor/nodeIndexscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeIndexscan.c,v
retrieving revision 1.62
diff --unified -r1.62 nodeIndexscan.c
--- src/backend/executor/nodeIndexscan.c 2001/07/15 22:48:17 1.62
+++ src/backend/executor/nodeIndexscan.c 2001/09/21 17:32:47
@@ -988,7 +988,9 @@
*/
relid = node->scan.scanrelid;
rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
+ Assert(rtentry->rtetype == RTE_RELATION);
+
+ reloid = rtentry->u.rel.relid;
ExecOpenScanR(reloid, /* relation */
0, /* nkeys */
Index: src/backend/executor/nodeSeqscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeSeqscan.c,v
retrieving revision 1.31
diff --unified -r1.31 nodeSeqscan.c
--- src/backend/executor/nodeSeqscan.c 2001/07/15 22:48:18 1.31
+++ src/backend/executor/nodeSeqscan.c 2001/09/21 17:32:47
@@ -159,8 +159,11 @@
*/
relid = node->scanrelid;
rangeTable = estate->es_range_table;
+
rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
+ Assert(rtentry->rtetype == RTE_RELATION);
+
+ reloid = rtentry->u.rel.relid;
direction = estate->es_direction;
ExecOpenScanR(reloid, /* relation */
Index: src/backend/executor/nodeSubqueryscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeSubqueryscan.c,v
retrieving revision 1.10
diff --unified -r1.10 nodeSubqueryscan.c
--- src/backend/executor/nodeSubqueryscan.c 2001/09/18 01:59:06 1.10
+++ src/backend/executor/nodeSubqueryscan.c 2001/09/21 17:32:47
@@ -147,12 +147,13 @@
* This should agree with ExecInitSubPlan
*/
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
- Assert(rte->subquery != NULL);
+ Assert(rte->rtetype == RTE_SUBSELECT);
sp_estate = CreateExecutorState();
subquerystate->sss_SubEState = sp_estate;
- sp_estate->es_range_table = rte->subquery->rtable;
+ Assert( PointerIsValid(rte->u.sub.subquery) );
+ sp_estate->es_range_table = rte->u.sub.subquery->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info;
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
sp_estate->es_tupleTable =
Index: src/backend/executor/nodeTidscan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/nodeTidscan.c,v
retrieving revision 1.18
diff --unified -r1.18 nodeTidscan.c
--- src/backend/executor/nodeTidscan.c 2001/06/22 19:16:22 1.18
+++ src/backend/executor/nodeTidscan.c 2001/09/21 17:32:47
@@ -458,9 +458,11 @@
* open the base relation
*/
relid = node->scan.scanrelid;
+
rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
+ Assert(rtentry->rtetype == RTE_RELATION);
+ reloid = rtentry->u.rel.relid;
currentRelation = heap_open(reloid, AccessShareLock);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = 0;
Index: src/backend/executor/spi.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/executor/spi.c,v
retrieving revision 1.57
diff --unified -r1.57 spi.c
--- src/backend/executor/spi.c 2001/08/02 18:08:43 1.57
+++ src/backend/executor/spi.c 2001/09/21 17:32:47
@@ -1135,10 +1135,8 @@
_SPI_cursor_operation(Portal portal, bool forward, int count,
CommandDest dest)
{
- QueryDesc *querydesc;
- EState *estate;
- MemoryContext oldcontext;
- CommandDest olddest;
+ int nrows; /* how many records portal returned */
+
/* Check that the portal is valid */
if (!PortalIsValid(portal))
@@ -1153,46 +1151,9 @@
_SPI_current->processed = 0;
_SPI_current->tuptable = NULL;
- /* Switch to the portals memory context */
- oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- querydesc = PortalGetQueryDesc(portal);
- estate = PortalGetState(portal);
+ nrows = PortalRun ( portal, forward, (long) count, dest, NULL);
- /* 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;
if (dest == SPI && _SPI_checktuples())
elog(FATAL, "SPI_fetch: # of processed tuples check failed");
Index: src/backend/executor/nodePortalscan.c
===================================================================
RCS file: nodePortalscan.c
diff -N nodePortalscan.c
--- /dev/null Fri Sep 21 14:39:51 2001
+++ nodePortalscan.c Fri Sep 21 13:38:15 2001
@@ -0,0 +1,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.156
diff --unified -r1.156 copyfuncs.c
--- src/backend/nodes/copyfuncs.c 2001/09/18 01:59:06 1.156
+++ src/backend/nodes/copyfuncs.c 2001/09/21 17:32:47
@@ -227,6 +227,24 @@
}
/* ----------------
+ * _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;
+}
+
+/* ----------------
* _copyIndexScan
* ----------------
*/
@@ -1105,7 +1123,7 @@
Node_Copy(from, newnode, cheapest_total_path);
newnode->pruneable = from->pruneable;
- newnode->issubquery = from->issubquery;
+ newnode->reltype = from->reltype;
Node_Copy(from, newnode, indexlist);
newnode->pages = from->pages;
newnode->tuples = from->tuples;
@@ -1487,11 +1505,6 @@
_copyRangeTblEntry(RangeTblEntry *from)
{
RangeTblEntry *newnode = makeNode(RangeTblEntry);
-
- if (from->relname)
- newnode->relname = pstrdup(from->relname);
- newnode->relid = from->relid;
- Node_Copy(from, newnode, subquery);
Node_Copy(from, newnode, alias);
Node_Copy(from, newnode, eref);
newnode->inh = from->inh;
@@ -1499,7 +1512,21 @@
newnode->checkForRead = from->checkForRead;
newnode->checkForWrite = from->checkForWrite;
newnode->checkAsUser = from->checkAsUser;
-
+ 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);
+ }
return newnode;
}
@@ -2246,7 +2273,6 @@
newnode->vacuum = from->vacuum;
newnode->full = from->full;
newnode->analyze = from->analyze;
- newnode->freeze = from->freeze;
newnode->verbose = from->verbose;
if (from->vacrel)
newnode->vacrel = pstrdup(from->vacrel);
@@ -2554,6 +2580,9 @@
break;
case T_SeqScan:
retval = _copySeqScan(from);
+ break;
+ case T_PortalScan:
+ retval = _copyPortalScan(from);
break;
case T_IndexScan:
retval = _copyIndexScan(from);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.104
diff --unified -r1.104 equalfuncs.c
--- src/backend/nodes/equalfuncs.c 2001/09/18 01:59:06 1.104
+++ src/backend/nodes/equalfuncs.c 2001/09/21 17:32:47
@@ -1116,8 +1116,6 @@
return false;
if (a->analyze != b->analyze)
return false;
- if (a->freeze != b->freeze)
- return false;
if (a->verbose != b->verbose)
return false;
if (!equalstr(a->vacrel, b->vacrel))
@@ -1599,12 +1597,6 @@
static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{
- if (!equalstr(a->relname, b->relname))
- return false;
- if (a->relid != b->relid)
- return false;
- if (!equal(a->subquery, b->subquery))
- return false;
if (!equal(a->alias, b->alias))
return false;
if (!equal(a->eref, b->eref))
@@ -1619,7 +1611,26 @@
return false;
if (a->checkAsUser != b->checkAsUser)
return false;
-
+ 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);
+ }
return true;
}
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.145
diff --unified -r1.145 outfuncs.c
--- src/backend/nodes/outfuncs.c 2001/08/21 16:36:02 1.145
+++ src/backend/nodes/outfuncs.c 2001/09/21 17:32:47
@@ -504,6 +504,16 @@
}
/*
+ * PortalScan is a subclass of Scan
+ */
+static void
+_outPortalScan(StringInfo str, PortalScan *node)
+{
+ appendStringInfo(str, " PORTALSCAN ");
+ _outPlanInfo(str, (Plan *) node);
+}
+
+/*
* IndexScan is a subclass of Scan
*/
static void
@@ -962,12 +972,7 @@
static void
_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
{
- appendStringInfo(str, " RTE :relname ");
- _outToken(str, node->relname);
- appendStringInfo(str, " :relid %u ",
- node->relid);
- appendStringInfo(str, " :subquery ");
- _outNode(str, node->subquery);
+ appendStringInfo(str, " RTE ");
appendStringInfo(str, " :alias ");
_outNode(str, node->alias);
appendStringInfo(str, " :eref ");
@@ -979,6 +984,24 @@
booltostr(node->checkForRead),
booltostr(node->checkForWrite),
node->checkAsUser);
+ 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);
+ }
}
/*
@@ -1508,6 +1531,9 @@
break;
case T_SeqScan:
_outSeqScan(str, obj);
+ break;
+ case T_PortalScan:
+ _outPortalScan(str, obj);
break;
case T_IndexScan:
_outIndexScan(str, obj);
Index: src/backend/nodes/print.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/print.c,v
retrieving revision 1.47
diff --unified -r1.47 print.c
--- src/backend/nodes/print.c 2001/03/22 03:59:32 1.47
+++ src/backend/nodes/print.c 2001/09/21 17:32:47
@@ -131,12 +131,18 @@
{
RangeTblEntry *rte = lfirst(l);
- if (rte->relname)
+ if (rte->rtetype == RTE_RELATION) {
printf("%d\t%s (%s)\t%u",
- 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) {
printf("%d\t[subquery] (%s)\t",
i, rte->eref->relname);
+ }
+ else if (rte->rtetype == RTE_PORTAL) {
+ printf("%d\t[portal] (%s)\t",
+ i, rte->eref->relname);
+ }
printf("\t%s\t%s\n",
(rte->inh ? "inh" : ""),
(rte->inFromCl ? "inFromCl" : ""));
@@ -300,6 +306,8 @@
return "SCAN";
case T_SeqScan:
return "SEQSCAN";
+ case T_PortalScan:
+ return "PORTALSCAN";
case T_IndexScan:
return "INDEXSCAN";
case T_TidScan:
@@ -360,14 +368,16 @@
RangeTblEntry *rte;
rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
- StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
+ Assert( rte->rtetype == RTE_RELATION);
+ StrNCpy(extraInfo, rte->u.rel.relname, NAMEDATALEN);
}
else if (IsA(p, IndexScan))
{
RangeTblEntry *rte;
rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
- StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
+ Assert( rte->rtetype == RTE_RELATION);
+ StrNCpy(extraInfo, rte->u.rel.relname, NAMEDATALEN);
}
else
extraInfo[0] = '\0';
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/nodes/readfuncs.c,v
retrieving revision 1.112
diff --unified -r1.112 readfuncs.c
--- src/backend/nodes/readfuncs.c 2001/07/03 16:52:48 1.112
+++ src/backend/nodes/readfuncs.c 2001/09/21 17:32:47
@@ -1414,7 +1414,7 @@
* ----------------
*/
static RangeTblEntry *
-_readRangeTblEntry(void)
+_readRangeTblEntry()
{
RangeTblEntry *local_node;
char *token;
@@ -1422,17 +1422,6 @@
local_node = makeNode(RangeTblEntry);
- 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 */
-
token = pg_strtok(&length); /* eat :alias */
local_node->alias = nodeRead(true); /* now read it */
@@ -1459,8 +1448,35 @@
token = pg_strtok(&length); /* get :checkAsUser */
local_node->checkAsUser = atooid(token);
+ 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);
+ }
return local_node;
}
+
/* ----------------
* _readPath
Index: src/backend/optimizer/path/allpaths.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/path/allpaths.c,v
retrieving revision 1.78
diff --unified -r1.78 allpaths.c
--- src/backend/optimizer/path/allpaths.c 2001/07/31 17:56:30 1.78
+++ src/backend/optimizer/path/allpaths.c 2001/09/21 17:32:47
@@ -25,6 +25,7 @@
#include "optimizer/prep.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
+#include "utils/portal.h"
bool enable_geqo = true;
@@ -100,12 +101,46 @@
rti = lfirsti(rel->relids);
rte = rt_fetch(rti, root->rtable);
- if (rel->issubquery)
+ if (rel->reltype == REL_SUBQUERY)
{
+ Assert(rte->rtetype == RTE_SUBSELECT);
/* Subquery --- generate a separate plan for it */
set_subquery_pathlist(root, rel, rti, rte);
}
- 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))
!= NIL)
{
/* Relation is root of an inheritance tree, process specially */
@@ -117,6 +152,9 @@
set_plain_rel_pathlist(root, rel, rte);
}
}
+ else
+ elog(ERROR,"set_base_rel_pathlists: unknown reltype %d", rel->reltype);
+ }
}
/*
@@ -126,6 +164,7 @@
static void
set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
{
+ Assert( rte->rtetype == RTE_RELATION );
/* Mark rel with estimated output rows, width, etc */
set_baserel_size_estimates(root, rel);
@@ -178,10 +217,11 @@
List *inheritlist)
{
int parentRTindex = rti;
- Oid parentOID = rte->relid;
+ Oid parentOID = rte->u.rel.relid;
List *subpaths = NIL;
List *il;
+ Assert( rte->rtetype == RTE_RELATION );
/*
* XXX for now, can't handle inherited expansion of FOR UPDATE; can we
* do better?
@@ -215,7 +255,10 @@
RelOptInfo *childrel;
childrte = rt_fetch(childRTindex, root->rtable);
- childOID = childrte->relid;
+
+ Assert( childrte->rtetype == RTE_RELATION );
+
+ childOID = childrte->u.rel.relid;
/*
* Make a RelOptInfo for the child so we can do planning. Do NOT
@@ -276,7 +319,8 @@
set_subquery_pathlist(Query *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
- Query *subquery = rte->subquery;
+ Query *subquery = rte->u.sub.subquery;
+ Assert(rte->rtetype == RTE_SUBSELECT);
/*
* If there are any restriction clauses that have been attached to the
Index: src/backend/optimizer/path/clausesel.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/path/clausesel.c,v
retrieving revision 1.46
diff --unified -r1.46 clausesel.c
--- src/backend/optimizer/path/clausesel.c 2001/06/25 21:11:43 1.46
+++ src/backend/optimizer/path/clausesel.c 2001/09/21 17:32:47
@@ -384,7 +384,7 @@
{
RangeTblEntry *rte = rt_fetch(var->varno, root->rtable);
- 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
diff --unified -r1.78 costsize.c
--- src/backend/optimizer/path/costsize.c 2001/08/21 16:36:02 1.78
+++ src/backend/optimizer/path/costsize.c 2001/09/21 17:32:47
@@ -110,7 +110,7 @@
/* Should only be applied to base relations */
Assert(length(baserel->relids) == 1);
- Assert(!baserel->issubquery);
+ Assert(baserel->reltype == REL_PLAIN);
if (!enable_seqscan)
startup_cost += disable_cost;
@@ -225,7 +225,7 @@
/* Should only be applied to base relations */
Assert(IsA(baserel, RelOptInfo) &&IsA(index, IndexOptInfo));
Assert(length(baserel->relids) == 1);
- Assert(!baserel->issubquery);
+ Assert(baserel->reltype == REL_PLAIN);
if (!enable_indexscan && !is_injoin)
startup_cost += disable_cost;
Index: src/backend/optimizer/plan/createplan.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/createplan.c,v
retrieving revision 1.109
diff --unified -r1.109 createplan.c
--- src/backend/optimizer/plan/createplan.c 2001/09/21 04:06:04 1.109
+++ src/backend/optimizer/plan/createplan.c 2001/09/21 17:32:47
@@ -43,6 +43,8 @@
List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(Path *best_path,
List *tlist, List *scan_clauses);
+static PortalScan *create_portalscan_plan(Path *best_path,
+ List *tlist, List *scan_clauses);
static NestLoop *create_nestloop_plan(NestPath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
Plan *outer_plan, List *outer_tlist,
@@ -69,6 +71,8 @@
static void copy_path_costsize(Plan *dest, Path *src);
static void copy_plan_costsize(Plan *dest, Plan *src);
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
+static PortalScan *make_portalscan(List *qptlist, List *qpqual,
+ Index scanrelid);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual,
List *indxqualorig,
@@ -117,6 +121,7 @@
case T_SeqScan:
case T_TidScan:
case T_SubqueryScan:
+ case T_PortalScan:
plan = (Plan *) create_scan_plan(root, best_path);
break;
case T_HashJoin:
@@ -198,6 +203,12 @@
scan_clauses);
break;
+ case T_PortalScan:
+ plan = (Scan *) create_portalscan_plan(best_path,
+ tlist,
+ scan_clauses);
+ break;
+
default:
elog(ERROR, "create_scan_plan: unknown node type: %d",
best_path->pathtype);
@@ -348,8 +359,7 @@
Index scan_relid;
/* there should be exactly one base rel involved... */
- Assert(length(best_path->parent->relids) == 1);
- Assert(!best_path->parent->issubquery);
+ Assert(best_path->parent->reltype == REL_PLAIN);
scan_relid = (Index) lfirsti(best_path->parent->relids);
@@ -392,8 +402,7 @@
IndexScan *scan_plan;
/* there should be exactly one base rel involved... */
- Assert(length(best_path->path.parent->relids) == 1);
- Assert(!best_path->path.parent->issubquery);
+ Assert(best_path->path.parent->reltype == REL_PLAIN);
baserelid = lfirsti(best_path->path.parent->relids);
@@ -510,8 +519,7 @@
Index scan_relid;
/* there should be exactly one base rel involved... */
- Assert(length(best_path->path.parent->relids) == 1);
- Assert(!best_path->path.parent->issubquery);
+ Assert(best_path->path.parent->reltype == REL_PLAIN);
scan_relid = (Index) lfirsti(best_path->path.parent->relids);
@@ -540,9 +548,8 @@
Index scan_relid;
/* there should be exactly one base rel involved... */
- Assert(length(best_path->parent->relids) == 1);
/* and it must be a subquery */
- Assert(best_path->parent->issubquery);
+ Assert(best_path->parent->reltype == REL_SUBQUERY);
scan_relid = (Index) lfirsti(best_path->parent->relids);
@@ -554,6 +561,30 @@
return scan_plan;
}
+/*
+ * 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;
+}
+
/*****************************************************************************
*
* JOIN METHODS
@@ -1286,6 +1317,26 @@
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->subplan = subplan;
+ 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;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
Index: src/backend/optimizer/plan/planner.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/planner.c,v
retrieving revision 1.108
diff --unified -r1.108 planner.c
--- src/backend/optimizer/plan/planner.c 2001/06/05 05:26:04 1.108
+++ src/backend/optimizer/plan/planner.c 2001/09/21 17:32:47
@@ -268,7 +268,8 @@
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
RangeTblEntry *rte = rt_fetch(varno, parse->rtable);
- Query *subquery = rte->subquery;
+ Query *subquery = rte->u.sub.subquery;
+
/*
* Is this a subquery RTE, and if so, is the subquery simple
@@ -277,7 +278,8 @@
* Note: even if the subquery itself is simple enough, we can't
* pull it up if there is a reference to its whole tuple result.
*/
- if (subquery && is_simple_subquery(subquery) &&
+ if (rte->rtetype == RTE_SUBSELECT &&
+ is_simple_subquery(subquery) &&
!contain_whole_tuple_var((Node *) parse, varno, 0))
{
int rtoffset;
Index: src/backend/optimizer/plan/setrefs.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/plan/setrefs.c,v
retrieving revision 1.71
diff --unified -r1.71 setrefs.c
--- src/backend/optimizer/plan/setrefs.c 2001/03/22 03:59:37 1.71
+++ src/backend/optimizer/plan/setrefs.c 2001/09/21 17:32:47
@@ -87,6 +87,10 @@
*/
switch (nodeTag(plan))
{
+ case T_PortalScan:
+ fix_expr_references(plan, (Node *) plan->targetlist);
+ fix_expr_references(plan, (Node *) plan->qual);
+ break;
case T_SeqScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
Index: src/backend/optimizer/prep/preptlist.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/prep/preptlist.c,v
retrieving revision 1.43
diff --unified -r1.43 preptlist.c
--- src/backend/optimizer/prep/preptlist.c 2001/09/06 02:07:42 1.43
+++ src/backend/optimizer/prep/preptlist.c 2001/09/21 17:32:47
@@ -58,7 +58,7 @@
{
RangeTblEntry *rte = rt_fetch(result_relation, range_table);
- if (rte->subquery != NULL || rte->relid == InvalidOid)
+ if (rte->rtetype == RTE_SUBSELECT)
elog(ERROR, "preprocess_targetlist: subquery cannot be result relation");
}
Index: src/backend/optimizer/prep/prepunion.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/prep/prepunion.c,v
retrieving revision 1.66
diff --unified -r1.66 prepunion.c
--- src/backend/optimizer/prep/prepunion.c 2001/08/14 17:12:57 1.66
+++ src/backend/optimizer/prep/prepunion.c 2001/09/21 17:32:47
@@ -82,6 +82,7 @@
{
SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
Node *node;
+ RangeTblEntry *rte;
Query *leftmostQuery;
Assert(topop && IsA(topop, SetOperationStmt));
@@ -94,8 +95,11 @@
while (node && IsA(node, SetOperationStmt))
node = ((SetOperationStmt *) node)->larg;
Assert(node && IsA(node, RangeTblRef));
- 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;
+
Assert(leftmostQuery != NULL);
/*
@@ -127,10 +131,11 @@
{
RangeTblRef *rtr = (RangeTblRef *) setOp;
RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable);
- Query *subquery = rte->subquery;
+ Query *subquery = rte->u.sub.subquery;
Plan *subplan,
*plan;
+ Assert(rte->rtetype == RTE_SUBSELECT);
Assert(subquery != NULL);
/*
@@ -555,15 +560,16 @@
expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
{
RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
- Oid parentOID = rte->relid;
+ Oid parentOID = rte->u.rel.relid;
List *inhOIDs;
List *inhRTIs;
List *l;
+ Assert(rte->rtetype == RTE_RELATION);
/* Does RT entry allow inheritance? */
if (!rte->inh)
return NIL;
- Assert(parentOID != InvalidOid && rte->subquery == NULL);
+
/* Always clear the parent's inh flag, see above comments */
rte->inh = false;
/* Fast path for common case of childless table */
@@ -601,8 +607,10 @@
* this point.
*/
childrte = copyObject(rte);
- 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;
parse->rtable = lappend(parse->rtable, childrte);
childRTindex = length(parse->rtable);
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.88
diff --unified -r1.88 clauses.c
--- src/backend/optimizer/util/clauses.c 2001/07/31 20:16:33 1.88
+++ src/backend/optimizer/util/clauses.c 2001/09/21 17:32:47
@@ -1798,8 +1798,8 @@
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
- if (rte->subquery)
- if (walker(rte->subquery, context))
+ if (rte->rtetype == RTE_SUBSELECT)
+ if (walker( rte->u.sub.subquery, context))
return true;
}
}
@@ -2179,15 +2179,17 @@
foreach(rt, query->rtable)
{
- RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+ RangeTblEntry *rte = lfirst(rt);
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT)
{
RangeTblEntry *newrte;
FLATCOPY(newrte, rte, RangeTblEntry);
- 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 *);
rte = newrte;
}
newrt = lappend(newrt, rte);
Index: src/backend/optimizer/util/pathnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/pathnode.c,v
retrieving revision 1.75
diff --unified -r1.75 pathnode.c
--- src/backend/optimizer/util/pathnode.c 2001/07/16 05:06:58 1.75
+++ src/backend/optimizer/util/pathnode.c 2001/09/21 17:32:47
@@ -434,6 +434,27 @@
}
/*
+ * 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;
+}
+
+/*
* create_subqueryscan_path
* Creates a path corresponding to a sequential scan of a subquery,
* returning the pathnode.
Index: src/backend/optimizer/util/relnode.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/optimizer/util/relnode.c,v
retrieving revision 1.33
diff --unified -r1.33 relnode.c
--- src/backend/optimizer/util/relnode.c 2001/05/20 20:28:19 1.33
+++ src/backend/optimizer/util/relnode.c 2001/09/21 17:32:47
@@ -125,7 +125,7 @@
make_base_rel(Query *root, int relid)
{
RelOptInfo *rel = makeNode(RelOptInfo);
- Oid relationObjectId;
+ RangeTblEntry *rte;
rel->relids = makeListi1(relid);
rel->rows = 0;
@@ -135,7 +135,6 @@
rel->cheapest_startup_path = NULL;
rel->cheapest_total_path = NULL;
rel->pruneable = true;
- rel->issubquery = false;
rel->indexlist = NIL;
rel->pages = 0;
rel->tuples = 0;
@@ -146,24 +145,33 @@
rel->joininfo = NIL;
rel->innerjoin = NIL;
- /* 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);
- if (relationObjectId != InvalidOid)
+ if (rte->rtetype == RTE_RELATION)
{
- /* Plain relation --- retrieve statistics from the system catalogs */
- bool indexed;
+ /* Plain relation --- retrieve statistics from the system catalogs */
+ bool indexed;
+ Oid relationObjectId;
- 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);
}
- else
+ else if (rte->rtetype == RTE_SUBSELECT)
{
- /* subquery --- mark it as such for later processing */
- rel->issubquery = true;
+ rel->reltype = REL_SUBQUERY;
}
+ else if (rte->rtetype == RTE_PORTAL)
+ {
+ rel->reltype = REL_PORTAL;
+ }
+ else
+ elog(ERROR, "make_base_rel: Unknown RTE node type %d", nodeTag(rte) );
return rel;
}
@@ -285,6 +293,7 @@
*/
joinrel = makeNode(RelOptInfo);
joinrel->relids = joinrelids;
+ joinrel->reltype = REL_JOIN;
joinrel->rows = 0;
joinrel->width = 0;
joinrel->targetlist = NIL;
@@ -292,7 +301,6 @@
joinrel->cheapest_startup_path = NULL;
joinrel->cheapest_total_path = NULL;
joinrel->pruneable = true;
- joinrel->issubquery = false;
joinrel->indexlist = NIL;
joinrel->pages = 0;
joinrel->tuples = 0;
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.198
diff --unified -r1.198 analyze.c
--- src/backend/parser/analyze.c 2001/09/07 21:57:53 1.198
+++ src/backend/parser/analyze.c 2001/09/21 17:32:47
@@ -169,7 +169,6 @@
{
List *aliaslist = n->aliases;
List *targetList;
-
foreach(targetList, n->query->targetList)
{
TargetEntry *te = (TargetEntry *) lfirst(targetList);
@@ -2018,6 +2017,7 @@
Query *qry = makeNode(Query);
SelectStmt *leftmostSelect;
int leftmostRTI;
+ RangeTblEntry* leftmostRTE;
Query *leftmostQuery;
SetOperationStmt *sostmt;
char *into;
@@ -2093,7 +2093,10 @@
node = ((SetOperationStmt *) node)->larg;
Assert(node && IsA(node, RangeTblRef));
leftmostRTI = ((RangeTblRef *) node)->rtindex;
- 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;
+
Assert(leftmostQuery != NULL);
/*
@@ -2363,10 +2366,11 @@
{
RangeTblRef *rtr = (RangeTblRef *) node;
RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
- Query *selectQuery = rte->subquery;
+ Query *selectQuery = rte->u.sub.subquery;
List *result = NIL;
List *tl;
+ Assert(rte->rtetype == RTE_SUBSELECT);
Assert(selectQuery != NULL);
/* Get types of non-junk columns */
foreach(tl, selectQuery->targetList)
@@ -2875,17 +2879,25 @@
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
++i;
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT)
{
/* FOR UPDATE of subquery is propagated to subquery's rels */
- transformForUpdate(rte->subquery, makeList1(NULL));
+ transformForUpdate( rte->u.sub.subquery, makeList1(NULL));
}
- else
+ else if ( rte->rtetype == RTE_RELATION )
{
if (!intMember(i, rowMarks)) /* avoid duplicates */
rowMarks = lappendi(rowMarks, i);
rte->checkForWrite = true;
}
+ else if ( rte->rtetype == RTE_PORTAL )
+ {
+ /* do nothing */
+ }
+ else
+ {
+ elog(ERROR, "FOR UPDATE: unknown RTE type %d", rte->rtetype);
+ }
}
}
else
@@ -2903,16 +2915,25 @@
++i;
if (strcmp(rte->eref->relname, relname) == 0)
{
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT)
{
/* propagate to subquery */
- transformForUpdate(rte->subquery, makeList1(NULL));
+ transformForUpdate( rte->u.sub.subquery, makeList1(NULL));
}
- else
+ else if (rte->rtetype == RTE_RELATION)
{
if (!intMember(i, rowMarks)) /* avoid duplicates */
rowMarks = lappendi(rowMarks, i);
rte->checkForWrite = true;
+ }
+ else if (rte->rtetype == RTE_PORTAL)
+ {
+ /* do nothing */
+ }
+ else
+ {
+ elog(ERROR, "FOR UPDATE: unknown RTE type %d",
+ rte->rtetype);
}
break;
}
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.252
diff --unified -r2.252 gram.y
--- src/backend/parser/gram.y 2001/09/20 14:20:27 2.252
+++ src/backend/parser/gram.y 2001/09/21 17:32:47
@@ -3732,8 +3732,17 @@
* and joined_table := '(' joined_table ')'. So, we must have the
* redundant-looking productions here instead.
*/
-table_ref: relation_expr
+table_ref:
+ CURSOR relation_name
{
+ PortalRangeVar *n = makeNode(PortalRangeVar);
+ n->portal = $2;
+ n->name = NULL;
+ $$ = (Node *) n;
+ }
+ |
+ relation_expr
+ {
$$ = (Node *) $1;
}
| relation_expr alias_clause
@@ -5600,7 +5609,6 @@
| CREATE { $$ = "create"; }
| CREATEDB { $$ = "createdb"; }
| CREATEUSER { $$ = "createuser"; }
- | CURSOR { $$ = "cursor"; }
| CYCLE { $$ = "cycle"; }
| DATABASE { $$ = "database"; }
| DECLARE { $$ = "declare"; }
Index: src/backend/parser/parse_clause.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_clause.c,v
retrieving revision 1.82
diff --unified -r1.82 parse_clause.c
--- src/backend/parser/parse_clause.c 2001/08/09 18:28:17 1.82
+++ src/backend/parser/parse_clause.c 2001/09/21 17:32:47
@@ -31,6 +31,7 @@
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/portal.h"
#define ORDER_CLAUSE 0
@@ -80,6 +81,7 @@
/*
* The grammar will have produced a list of RangeVars,
+ * FuncRangeVars, PortalRangeVars,
* RangeSubselects, and/or JoinExprs. Transform each one (possibly
* adding entries to the rtable), check for duplicate refnames, and
* then add it to the joinlist and namespace.
@@ -392,6 +394,52 @@
/*
+ * 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;
+}
+
+
+/*
* transformRangeSubselect --- transform a sub-SELECT appearing in FROM
*/
static RangeTblRef *
@@ -480,6 +528,15 @@
RangeTblRef *rtr;
rtr = transformTableEntry(pstate, (RangeVar *) n);
+ *containedRels = makeListi1(rtr->rtindex);
+ return (Node *) rtr;
+ }
+ if (IsA(n, PortalRangeVar))
+ {
+ /* reference to cursor */
+ RangeTblRef *rtr;
+
+ rtr = transformPortalRange(pstate, (PortalRangeVar *) n);
*containedRels = makeListi1(rtr->rtindex);
return (Node *) rtr;
}
Index: src/backend/parser/parse_func.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_func.c,v
retrieving revision 1.110
diff --unified -r1.110 parse_func.c
--- src/backend/parser/parse_func.c 2001/08/09 18:28:18 1.110
+++ src/backend/parser/parse_func.c 2001/09/21 17:32:54
@@ -386,7 +386,14 @@
* signal that the runtime representation will be a pointer
* not an Oid.
*/
- 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)
{
/*
* RTE is a subselect; must fail for lack of a specific type
@@ -407,7 +414,7 @@
}
}
- toid = typenameTypeId(rte->relname);
+ toid = typenameTypeId( rte->u.rel.relname);
/* replace it in the arg list */
lfirst(i) = makeVar(vnum,
Index: src/backend/parser/parse_node.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_node.c,v
retrieving revision 1.55
diff --unified -r1.55 parse_node.c
--- src/backend/parser/parse_node.c 2001/08/09 18:28:18 1.55
+++ src/backend/parser/parse_node.c 2001/09/21 17:32:54
@@ -34,6 +34,7 @@
#include "utils/varbit.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+#include "utils/portal.h"
static bool fitsInFloat(Value *value);
@@ -170,31 +171,44 @@
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
- if (rte->relid != InvalidOid)
+ if (rte->rtetype == RTE_RELATION)
{
/* Plain relation RTE --- get the attribute's type info */
HeapTuple tp;
Form_pg_attribute att_tup;
tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(rte->relid),
+ ObjectIdGetDatum(rte->u.rel.relid),
Int16GetDatum(attrno),
0, 0);
/* this shouldn't happen... */
if (!HeapTupleIsValid(tp))
elog(ERROR, "Relation %s does not have attribute %d",
- rte->relname, attrno);
+ rte->u.rel.relname, attrno);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
vartypeid = att_tup->atttypid;
type_mod = att_tup->atttypmod;
ReleaseSysCache(tp);
}
- 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)
{
/* Subselect RTE --- get type info from subselect's tlist */
List *tlistitem;
- foreach(tlistitem, rte->subquery->targetList)
+ foreach(tlistitem, rte->u.sub.subquery->targetList)
{
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
@@ -208,6 +222,10 @@
if (tlistitem == NIL)
elog(ERROR, "Subquery %s does not have attribute %d",
rte->eref->relname, attrno);
+ }
+ else
+ {
+ elog(ERROR, "make_var: Unknown RTE type");
}
return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
Index: src/backend/parser/parse_relation.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/parser/parse_relation.c,v
retrieving revision 1.56
diff --unified -r1.56 parse_relation.c
--- src/backend/parser/parse_relation.c 2001/08/10 18:57:37 1.56
+++ src/backend/parser/parse_relation.c 2001/09/21 17:32:54
@@ -28,6 +28,7 @@
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
+#include "utils/portal.h"
#include "utils/syscache.h"
@@ -318,7 +319,7 @@
* If the RTE represents a table (not a sub-select), consider system
* column names.
*/
- if (rte->relid != InvalidOid)
+ if (rte->rtetype == RTE_RELATION)
{
/* quick check to see if name could be a system column */
attnum = specialAttNum(colname);
@@ -326,7 +327,7 @@
{
/* now check to see if column actually is defined */
if (SearchSysCacheExists(ATTNUM,
- ObjectIdGetDatum(rte->relid),
+ ObjectIdGetDatum(rte->u.rel.relid),
Int16GetDatum(attnum),
0, 0))
{
@@ -510,9 +511,9 @@
int numaliases;
int varattno;
- rte->relname = relname;
+ rte->rtetype = RTE_RELATION;
+ rte->u.rel.relname = relname;
rte->alias = alias;
- rte->subquery = NULL;
/*
* Get the rel's OID. This access also ensures that we have an
@@ -522,7 +523,7 @@
*/
lockmode = isForUpdate(pstate, relname) ? RowShareLock : AccessShareLock;
rel = heap_openr(relname, lockmode);
- rte->relid = RelationGetRelid(rel);
+ rte->u.rel.relid = RelationGetRelid(rel);
eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
numaliases = length(eref->attrs);
@@ -577,7 +578,75 @@
if (pstate != NULL)
pstate->p_rtable = lappend(pstate->p_rtable, rte);
- 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;
}
/*
@@ -599,9 +668,8 @@
int varattno;
List *tlistitem;
- rte->relname = NULL;
- rte->relid = InvalidOid;
- rte->subquery = subquery;
+ rte->rtetype = RTE_SUBSELECT;
+ rte->u.sub.subquery = subquery;
rte->alias = alias;
eref = copyObject(alias);
@@ -654,7 +722,7 @@
if (pstate != NULL)
pstate->p_rtable = lappend(pstate->p_rtable, rte);
- return rte;
+ return (RangeTblEntry *) rte;
}
/*
@@ -755,14 +823,50 @@
/* Need the RT index of the entry for creating Vars */
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
+
+ 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);
- if (rte->relname)
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
+ }
+ else if (rte->rtetype == RTE_RELATION)
{
/* Ordinary relation RTE */
Relation rel;
int maxattrs;
- rel = heap_openr(rte->relname, AccessShareLock);
+ rel = heap_openr( rte->u.rel.relname, AccessShareLock);
maxattrs = RelationGetNumberOfAttributes(rel);
@@ -800,14 +904,15 @@
heap_close(rel, AccessShareLock);
}
- else
+ else if (rte->rtetype == RTE_SUBSELECT)
{
/* Subquery RTE */
List *aliasp = rte->eref->attrs;
List *tlistitem;
varattno = 0;
- foreach(tlistitem, rte->subquery->targetList)
+ Assert( PointerIsValid(rte->u.sub.subquery) );
+ foreach(tlistitem,rte->u.sub.subquery->targetList)
{
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
@@ -838,6 +943,10 @@
}
}
}
+ else
+ {
+ elog(ERROR, "expandRTE: Unknown RTE type");
+ }
}
/*
@@ -913,11 +1022,11 @@
/* ----------
* get_rte_attribute_name
- * Get an attribute name from a RangeTblEntry
+ * Get an attribute name from a RangeTblEntryRelation
*
* This is unlike get_attname() because we use aliases if available.
* In particular, it will work on an RTE for a subselect, whereas
- * get_attname() only works on real relations.
+ * get_attname() only works on real relations. ??? (below)
*
* "*" is returned if the given attnum is InvalidAttrNumber --- this case
* occurs when a Var represents a whole tuple of a relation.
@@ -926,6 +1035,7 @@
* not guaranteed unique, and may not even have scope across the whole
* query. Cleanest fix would be to add refname/attname to Var nodes and
* just print those, rather than indulging in this hack.
+ *
* ----------
*/
char *
@@ -947,17 +1057,17 @@
* if alias name list is too short (which probably can't happen
* anymore). Neither of these cases is valid for a subselect RTE.
*/
- if (rte->relid == InvalidOid)
+ if (!rte->rtetype == RTE_RELATION)
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
attnum, rte->eref->relname);
/*
* Use the real name of the table's column
*/
- attname = get_attname(rte->relid, attnum);
+ attname = get_attname(rte->u.rel.relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
- attnum, rte->relid);
+ attnum, rte->u.rel.relid);
return attname;
}
@@ -1069,3 +1179,22 @@
pstate->parentParseState != NULL ? " in subquery" : "",
refname);
}
+
+/*
+ * 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
diff --unified -r1.63 rewriteDefine.c
--- src/backend/rewrite/rewriteDefine.c 2001/08/12 21:35:18 1.63
+++ src/backend/rewrite/rewriteDefine.c 2001/09/21 17:32:54
@@ -446,10 +446,10 @@
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
- if (rte->subquery)
+ if ( rte->rtetype == RTE_SUBSELECT )
{
/* Recurse into subquery in FROM */
- setRuleCheckAsUser(rte->subquery, userid);
+ setRuleCheckAsUser( rte->u.sub.subquery, userid);
}
else
rte->checkAsUser = userid;
Index: src/backend/rewrite/rewriteHandler.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/rewrite/rewriteHandler.c,v
retrieving revision 1.97
diff --unified -r1.97 rewriteHandler.c
--- src/backend/rewrite/rewriteHandler.c 2001/07/09 23:50:32 1.97
+++ src/backend/rewrite/rewriteHandler.c 2001/09/21 17:32:55
@@ -265,8 +265,8 @@
bool relIsUsed)
{
Query *rule_action;
- RangeTblEntry *rte,
- *subrte;
+ RangeTblEntry *rte;
+ RangeTblEntry *subrte;
if (length(rule->actions) != 1)
elog(ERROR, "ApplyRetrieveRule: expected just one rule action");
@@ -289,9 +289,20 @@
*/
rte = rt_fetch(rt_index, parsetree->rtable);
- 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;
rte->inh = false; /* must not be set for a subquery */
/*
@@ -299,7 +310,8 @@
* The checks will actually be done against the *OLD* entry therein.
*/
subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
- Assert(subrte->relid == relation->rd_id);
+ Assert( subrte->rtetype == RTE_RELATION );
+ Assert( subrte->u.rel.relid == relation->rd_id);
subrte->checkForRead = rte->checkForRead;
subrte->checkForWrite = rte->checkForWrite;
subrte->checkAsUser = rte->checkAsUser;
@@ -355,10 +367,10 @@
(rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))
continue;
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT )
{
/* FOR UPDATE of subquery is propagated to subquery's rels */
- markQueryForUpdate(rte->subquery, false);
+ markQueryForUpdate( rte->u.sub.subquery, false);
}
else
{
@@ -437,13 +449,23 @@
rte = rt_fetch(rt_index, parsetree->rtable);
/*
+ * 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;
+ }
+
+ /*
* A subquery RTE can't have associated rules, so there's nothing
* to do to this level of the query, but we must recurse into the
* subquery to expand any rule references in it.
*/
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT)
{
- rte->subquery = fireRIRrules(rte->subquery);
+ rte->u.sub.subquery = fireRIRrules(rte->u.sub.subquery);
continue;
}
@@ -459,6 +481,8 @@
if (!relIsUsed && rt_index != parsetree->resultRelation)
continue;
+ /* by now, we should only have plain RTE to deal with */
+ Assert(rte->rtetype == RTE_RELATION);
/*
* This may well be the first access to the relation during the
* current statement (it will be, if this Query was extracted from
@@ -479,7 +503,7 @@
else
lockmode = AccessShareLock;
- rel = heap_openr(rte->relname, lockmode);
+ rel = heap_openr(rte->u.rel.relname, lockmode);
/*
* Check to see if relation's OID matches the RTE. If not, the RTE
@@ -487,9 +511,9 @@
* Eventually we might want to reparse the referencing rule, but
* for now all we can do is punt.
*/
- if (RelationGetRelid(rel) != rte->relid)
+ if (RelationGetRelid(rel) != rte->u.rel.relid)
elog(ERROR, "Relation \"%s\" with OID %u no longer exists",
- rte->relname, rte->relid);
+ rte->u.rel.relname, rte->u.rel.relid);
/*
* Collect the RIR rules that we must apply
@@ -757,6 +781,7 @@
result_relation = parsetree->resultRelation;
Assert(result_relation != 0);
rt_entry = rt_fetch(result_relation, parsetree->rtable);
+ Assert( rt_entry->rtetype == RTE_RELATION );
/*
* This may well be the first access to the result relation during the
@@ -766,7 +791,7 @@
* release it until end of transaction. This protects the rewriter
* and planner against schema changes mid-query.
*/
- rt_entry_relation = heap_openr(rt_entry->relname, RowExclusiveLock);
+ rt_entry_relation = heap_openr(rt_entry->u.rel.relname, RowExclusiveLock);
/*
* Check to see if relation's OID matches the RTE. If not, the RTE
@@ -774,9 +799,9 @@
* Eventually we might want to reparse the referencing rule, but
* for now all we can do is punt.
*/
- if (RelationGetRelid(rt_entry_relation) != rt_entry->relid)
+ if (RelationGetRelid(rt_entry_relation) != rt_entry->u.rel.relid)
elog(ERROR, "Relation \"%s\" with OID %u no longer exists",
- rt_entry->relname, rt_entry->relid);
+ rt_entry->u.rel.relname, rt_entry->u.rel.relid);
/*
* Collect and apply the appropriate rules.
@@ -943,7 +968,7 @@
RangeTblEntry *rte = rt_fetch(query->resultRelation,
query->rtable);
- if (rte->subquery)
+ if (rte->rtetype == RTE_SUBSELECT)
{
switch (query->commandType)
{
Index: src/backend/rewrite/rewriteManip.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/rewrite/rewriteManip.c,v
retrieving revision 1.58
diff --unified -r1.58 rewriteManip.c
--- src/backend/rewrite/rewriteManip.c 2001/09/07 20:52:31 1.58
+++ src/backend/rewrite/rewriteManip.c 2001/09/21 17:32:55
@@ -560,7 +560,8 @@
rtr = (RangeTblRef *) lfirst(parsetree->jointree->fromlist);
Assert(IsA(rtr, RangeTblRef));
selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
- selectquery = selectrte->subquery;
+ Assert( selectrte->rtetype == RTE_SUBSELECT );
+ selectquery = selectrte->u.sub.subquery;
if (!(selectquery && IsA(selectquery, Query) &&
selectquery->commandType == CMD_SELECT))
elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
@@ -571,7 +572,7 @@
"*NEW*") == 0)
{
if (subquery_ptr)
- *subquery_ptr = &(selectrte->subquery);
+ *subquery_ptr = &(selectrte->u.sub.subquery);
return selectquery;
}
elog(ERROR, "getInsertSelectQuery: can't find rule placeholders");
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.82
diff --unified -r1.82 ruleutils.c
--- src/backend/utils/adt/ruleutils.c 2001/08/12 21:35:19 1.82
+++ src/backend/utils/adt/ruleutils.c 2001/09/21 17:32:55
@@ -700,8 +700,9 @@
/* Build a minimal RTE for the rel */
rte = makeNode(RangeTblEntry);
- rte->relname = relname;
- rte->relid = relid;
+ rte->rtetype = RTE_RELATION;
+ rte->u.rel.relname = relname;
+ rte->u.rel.relid = relid;
rte->eref = makeNode(Attr);
rte->eref->relname = relname;
rte->inh = false;
@@ -1162,8 +1163,8 @@
{
RangeTblRef *rtr = (RangeTblRef *) setOp;
RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable);
- Query *subquery = rte->subquery;
-
+ Query *subquery = rte->u.sub.subquery;
+ Assert( rte->rtetype == RTE_SUBSELECT );
Assert(subquery != NULL);
get_query_def(subquery, buf, context->namespaces);
}
@@ -1241,7 +1242,7 @@
get_insert_query_def(Query *query, deparse_context *context)
{
StringInfo buf = context->buf;
- RangeTblEntry *select_rte = NULL;
+ RangeTblEntry *select_rte = NULL; /* rte for underlying SELECT */
RangeTblEntry *rte;
char *sep;
List *l;
@@ -1253,7 +1254,7 @@
foreach(l, query->rtable)
{
rte = (RangeTblEntry *) lfirst(l);
- if (rte->subquery == NULL)
+ if (rte->rtetype != RTE_SUBSELECT)
continue;
if (select_rte)
elog(ERROR, "get_insert_query_def: too many RTEs in INSERT!");
@@ -1264,8 +1265,9 @@
* Start the query with INSERT INTO relname
*/
rte = rt_fetch(query->resultRelation, query->rtable);
+ Assert( rte->rtetype == RTE_RELATION );
appendStringInfo(buf, "INSERT INTO %s",
- quote_identifier(rte->relname));
+ quote_identifier(rte->u.rel.relname));
/* Add the insert-column-names list */
sep = " (";
@@ -1301,7 +1303,7 @@
appendStringInfoChar(buf, ')');
}
else
- get_query_def(select_rte->subquery, buf, NIL);
+ get_query_def(select_rte->u.sub.subquery, buf, NIL);
}
@@ -1321,9 +1323,11 @@
* Start the query with UPDATE relname SET
*/
rte = rt_fetch(query->resultRelation, query->rtable);
+
+ Assert(rte->rtetype == RTE_RELATION);
appendStringInfo(buf, "UPDATE %s%s SET ",
only_marker(rte),
- quote_identifier(rte->relname));
+ quote_identifier(rte->u.rel.relname));
/* Add the comma separated list of 'attname = value' */
sep = "";
@@ -1374,9 +1378,10 @@
* Start the query with DELETE FROM relname
*/
rte = rt_fetch(query->resultRelation, query->rtable);
+ Assert(rte->rtetype == RTE_RELATION);
appendStringInfo(buf, "DELETE FROM %s%s",
only_marker(rte),
- quote_identifier(rte->relname));
+ quote_identifier(rte->u.rel.relname));
/* Add a WHERE clause if given */
if (query->jointree->quals != NULL)
@@ -2425,21 +2430,27 @@
int varno = ((RangeTblRef *) jtnode)->rtindex;
RangeTblEntry *rte = rt_fetch(varno, query->rtable);
- if (rte->relname)
+ if (rte->rtetype == RTE_RELATION)
{
/* Normal relation RTE */
appendStringInfo(buf, "%s%s",
only_marker(rte),
- quote_identifier(rte->relname));
+ quote_identifier( rte->u.rel.relname));
}
- else
+ else if (rte->rtetype == RTE_SUBSELECT)
{
/* Subquery RTE */
- Assert(rte->subquery != NULL);
appendStringInfoChar(buf, '(');
- get_query_def(rte->subquery, buf, context->namespaces);
+ get_query_def( rte->u.sub.subquery, buf, context->namespaces);
appendStringInfoChar(buf, ')');
- }
+ } else if (rte->rtetype == RTE_PORTAL)
+ {
+ appendStringInfo(buf, " CURSOR %s",
+ rte->u.portal.portalname);
+ } else
+ elog(ERROR, "get_from_clause_item: unknown RTE type");
+
+
if (rte->alias != NULL)
{
appendStringInfo(buf, " %s",
Index: src/backend/utils/mmgr/portalmem.c
===================================================================
RCS file: /cvs/pgsql/pgsql/src/backend/utils/mmgr/portalmem.c,v
retrieving revision 1.41
diff --unified -r1.41 portalmem.c
--- src/backend/utils/mmgr/portalmem.c 2001/03/22 04:00:08 1.41
+++ src/backend/utils/mmgr/portalmem.c 2001/09/21 17:32:55
@@ -36,6 +36,8 @@
#include "lib/hasht.h"
#include "utils/memutils.h"
#include "utils/portal.h"
+#include "executor/execdefs.h"
+#include "executor/executor.h"
/* ----------------
* Global state
@@ -150,6 +152,26 @@
}
/*
+ * 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;
+}
+
+/*
* PortalSetQuery
* Attaches a "query" to portal.
*
@@ -225,6 +247,101 @@
PortalHashTableInsert(portal);
return portal;
+}
+
+/* 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
diff --unified -r1.62 execnodes.h
--- src/include/nodes/execnodes.h 2001/07/16 05:07:00 1.62
+++ src/include/nodes/execnodes.h 2001/09/21 17:32:55
@@ -481,6 +481,19 @@
EState *sss_SubEState;
} SubqueryScanState;
+/* ----------------
+ * PortalScanState information
+ *
+ * PortalScanState is used for scanning a portal.
+ *
+ * ----------------
+ */
+typedef struct PortalScanState
+{
+ CommonScanState csstate; /* its first field is NodeTag */
+ struct PortalData * portal;
+} PortalScanState;
+
/* ----------------------------------------------------------------
* Join State Information
* ----------------------------------------------------------------
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.93
diff --unified -r1.93 nodes.h
--- src/include/nodes/nodes.h 2001/07/16 19:12:58 1.93
+++ src/include/nodes/nodes.h 2001/09/21 17:32:55
@@ -49,6 +49,7 @@
T_SubPlan,
T_TidScan,
T_SubqueryScan,
+ T_PortalScan,
/*
* TAGS FOR PRIMITIVE NODES (primnodes.h)
@@ -120,6 +121,7 @@
T_SubqueryScanState,
T_SetOpState,
T_LimitState,
+ T_PortalScanState,
/*
* TAGS FOR MEMORY NODES (memnodes.h)
@@ -222,6 +224,8 @@
T_CaseWhen,
T_FkConstraint,
T_PrivGrantee,
+/* T_FuncRangeVar, */
+ T_PortalRangeVar,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.144
diff --unified -r1.144 parsenodes.h
--- src/include/nodes/parsenodes.h 2001/09/18 01:59:06 1.144
+++ src/include/nodes/parsenodes.h 2001/09/21 17:32:55
@@ -15,7 +15,9 @@
#define PARSENODES_H
#include "nodes/primnodes.h"
+#include "access/tupdesc.h"
+
/*****************************************************************************
* Query Tree
*****************************************************************************/
@@ -890,6 +892,7 @@
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
List *forUpdate; /* FOR UPDATE clause */
+ bool isFunc; /* select * from func(args) */
/*
* These fields are used only in upper-level SelectStmts.
@@ -1182,6 +1185,28 @@
} SortGroupBy;
/*
+ * 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;
+
+/*
* RangeVar - range variable, used in FROM clauses
*/
typedef struct RangeVar
@@ -1288,22 +1313,17 @@
* (This allows rules to act as setuid gateways.)
*--------------------
*/
+typedef enum RTEType {
+ RTE_RELATION,
+ RTE_SUBSELECT,
+ RTE_PORTAL
+} RTEType;
+
typedef struct RangeTblEntry
{
NodeTag type;
-
- /*
- * Fields valid for a plain relation RTE (else NULL/zero):
- */
- char *relname; /* real name of the relation */
- Oid relid; /* OID of the relation */
-
+ RTEType rtetype;
/*
- * Fields valid for a subquery RTE (else NULL):
- */
- Query *subquery; /* the sub-query */
-
- /*
* Fields valid in all RTEs:
*/
Attr *alias; /* user-written alias clause, if any */
@@ -1313,6 +1333,22 @@
bool checkForRead; /* check rel for read access */
bool checkForWrite; /* check rel for write access */
Oid checkAsUser; /* if not zero, check access as this user */
+
+ 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;
} RangeTblEntry;
/*
Index: src/include/nodes/plannodes.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/plannodes.h,v
retrieving revision 1.50
diff --unified -r1.50 plannodes.h
--- src/include/nodes/plannodes.h 2001/09/18 01:59:07 1.50
+++ src/include/nodes/plannodes.h 2001/09/21 17:32:55
@@ -242,6 +242,17 @@
Plan *subplan;
} SubqueryScan;
+/* ----------------
+ * 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;
+
/*
* ==========
* Join nodes
Index: src/include/nodes/relation.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/nodes/relation.h,v
retrieving revision 1.58
diff --unified -r1.58 relation.h
--- src/include/nodes/relation.h 2001/08/21 16:36:06 1.58
+++ src/include/nodes/relation.h 2001/09/21 17:32:55
@@ -129,10 +129,19 @@
*----------
*/
+typedef enum RelOptInfoType {
+ REL_PLAIN,
+ REL_SUBQUERY,
+ REL_JOIN,
+ REL_PORTAL
+} RelOptInfoType;
+
typedef struct RelOptInfo
{
NodeTag type;
+ RelOptInfoType reltype;
+
/* all relations included in this RelOptInfo */
Relids relids; /* integer list of base relids (RT
* indexes) */
@@ -148,11 +157,12 @@
struct Path *cheapest_total_path;
bool pruneable;
- /* information about a base rel (not set for join rels!) */
- bool issubquery;
+ /* Following fields are only for REL_PLAIN */
List *indexlist;
long pages;
double tuples;
+
+ /* following field is only for REL_SUBQUERY */
struct Plan *subplan;
/* used by various scans and joins: */
Index: src/include/optimizer/pathnode.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/optimizer/pathnode.h,v
retrieving revision 1.38
diff --unified -r1.38 pathnode.h
--- src/include/optimizer/pathnode.h 2001/06/05 05:26:05 1.38
+++ src/include/optimizer/pathnode.h 2001/09/21 17:32:55
@@ -15,6 +15,7 @@
#define PATHNODE_H
#include "nodes/relation.h"
+#include "utils/portal.h"
/*
* prototypes for pathnode.c
@@ -35,6 +36,7 @@
extern TidPath *create_tidscan_path(Query *root, RelOptInfo *rel,
List *tideval);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths);
+extern Path *create_portalscan_path(RelOptInfo *rel, Portal portal);
extern Path *create_subqueryscan_path(RelOptInfo *rel);
extern NestPath *create_nestloop_path(Query *root,
Index: src/include/parser/parse_relation.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/parser/parse_relation.h,v
retrieving revision 1.24
diff --unified -r1.24 parse_relation.h
--- src/include/parser/parse_relation.h 2001/08/10 18:57:41 1.24
+++ src/include/parser/parse_relation.h 2001/09/21 17:32:55
@@ -36,6 +36,10 @@
Query *subquery,
Attr *alias,
bool inFromCl);
+extern RangeTblEntry * addRangeTableEntryForPortal(ParseState *pstate,
+ char *portalname,
+ Attr *alias
+ );
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList, bool addToNameSpace);
extern RangeTblEntry *addImplicitRTE(ParseState *pstate, char *relname);
Index: src/include/parser/parsetree.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/parser/parsetree.h,v
retrieving revision 1.13
diff --unified -r1.13 parsetree.h
--- src/include/parser/parsetree.h 2001/01/24 19:43:27 1.13
+++ src/include/parser/parsetree.h 2001/09/21 17:32:55
@@ -36,15 +36,8 @@
#define rt_store(rangetable_index, rangetable, rt) \
set_nth(rangetable, (rangetable_index)-1, rt)
-/*
- * 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);
/*
* Given an RTE and an attribute number, return the appropriate
Index: src/include/utils/portal.h
===================================================================
RCS file: /cvs/pgsql/pgsql/src/include/utils/portal.h,v
retrieving revision 1.28
diff --unified -r1.28 portal.h
--- src/include/utils/portal.h 2001/05/21 14:22:18 1.28
+++ src/include/utils/portal.h 2001/09/21 17:32:55
@@ -63,9 +63,11 @@
extern Portal CreatePortal(char *name);
extern void PortalDrop(Portal *portalP);
extern Portal GetPortalByName(char *name);
+extern TupleDesc GetPortalTupleDescByName(char *name);
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
TupleDesc attinfo, EState *state,
void (*cleanup) (Portal portal));
-
+extern int PortalRun(Portal portal, bool forward,
+ long count, CommandDest dest, TupleTableSlot **tts);
#endif /* PORTAL_H */
Index: src/include/executor/nodePortalscan.h
===================================================================
RCS file: nodePortalscan.h
diff -N nodePortalscan.h
--- /dev/null Fri Sep 21 14:39:51 2001
+++ nodePortalscan.h Fri Sep 21 13:38:30 2001
@@ -0,0 +1,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 */