aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/Makefile4
-rw-r--r--src/backend/executor/execAmi.c15
-rw-r--r--src/backend/executor/execMain.c219
-rw-r--r--src/backend/executor/execProcnode.c113
-rw-r--r--src/backend/executor/execTuples.c26
-rw-r--r--src/backend/executor/nodeSubqueryscan.c289
6 files changed, 464 insertions, 202 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index bf329b9306b..f26c35e9e10 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -4,7 +4,7 @@
# Makefile for executor
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.13 2000/08/31 16:09:56 petere Exp $
+# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.14 2000/09/29 18:21:28 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -18,7 +18,7 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \
nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
- nodeTidscan.o
+ nodeSubqueryscan.o nodeTidscan.o
all: SUBSYS.o
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 99d6b7b27be..31ad291236b 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execAmi.c,v 1.51 2000/08/03 19:19:30 tgl Exp $
+ * $Id: execAmi.c,v 1.52 2000/09/29 18:21:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,6 +44,7 @@
#include "executor/nodeSeqscan.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
+#include "executor/nodeSubqueryscan.h"
#include "executor/nodeUnique.h"
static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
@@ -304,6 +305,14 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
break;
+ case T_TidScan:
+ ExecTidReScan((TidScan *) node, exprCtxt, parent);
+ break;
+
+ case T_SubqueryScan:
+ ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
+ break;
+
case T_Material:
ExecMaterialReScan((Material *) node, exprCtxt, parent);
break;
@@ -348,10 +357,6 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanAppend((Append *) node, exprCtxt, parent);
break;
- case T_TidScan:
- ExecTidReScan((TidScan *) node, exprCtxt, parent);
- break;
-
default:
elog(ERROR, "ExecReScan: node type %d not supported",
nodeTag(node));
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index d46e0d30f55..a202da98d2e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.127 2000/09/12 21:06:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.128 2000/09/29 18:21:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -69,13 +69,11 @@ static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
- Plan *plan);
-static void ExecCheckPlanPerms(Plan *plan, CmdType operation,
- int resultRelation, bool resultIsScanned);
-static void ExecCheckRTPerms(List *rangeTable, CmdType operation,
- int resultRelation, bool resultIsScanned);
-static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
- bool isResultRelation, bool resultIsScanned);
+ Plan *plan);
+static void ExecCheckPlanPerms(Plan *plan, List *rangeTable,
+ CmdType operation);
+static void ExecCheckRTPerms(List *rangeTable, CmdType operation);
+static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
/* end of local decls */
@@ -390,51 +388,15 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
static void
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
{
- List *rangeTable = parseTree->rtable;
- int resultRelation = parseTree->resultRelation;
- bool resultIsScanned = false;
- List *lp;
-
- /*
- * If we have a result relation, determine whether the result rel is
- * scanned or merely written. If scanned, we will insist on read
- * permission as well as modify permission.
- *
- * Note: it might look faster to apply rangeTableEntry_used(), but
- * that's not correct since it will trigger on jointree references
- * to the RTE. We only want to know about actual Var nodes.
- */
- if (resultRelation > 0)
- {
- List *qvars = pull_varnos((Node *) parseTree);
-
- resultIsScanned = intMember(resultRelation, qvars);
- freeList(qvars);
- }
-
/*
* Check RTEs in the query's primary rangetable.
*/
- ExecCheckRTPerms(rangeTable, operation, resultRelation, resultIsScanned);
-
- /*
- * Check SELECT FOR UPDATE access rights.
- */
- foreach(lp, parseTree->rowMark)
- {
- RowMark *rm = lfirst(lp);
-
- if (!(rm->info & ROW_ACL_FOR_UPDATE))
- continue;
-
- ExecCheckRTEPerms(rt_fetch(rm->rti, rangeTable),
- CMD_UPDATE, true, false);
- }
+ ExecCheckRTPerms(parseTree->rtable, operation);
/*
* Search for subplans and APPEND nodes to check their rangetables.
*/
- ExecCheckPlanPerms(plan, operation, resultRelation, resultIsScanned);
+ ExecCheckPlanPerms(plan, parseTree->rtable, operation);
}
/*
@@ -447,8 +409,7 @@ ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
* in the query's main rangetable. But at the moment, they're not.
*/
static void
-ExecCheckPlanPerms(Plan *plan, CmdType operation,
- int resultRelation, bool resultIsScanned)
+ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
{
List *subp;
@@ -461,28 +422,37 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
{
SubPlan *subplan = (SubPlan *) lfirst(subp);
- ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
- ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
+ ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
+ ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
}
foreach(subp, plan->subPlan)
{
SubPlan *subplan = (SubPlan *) lfirst(subp);
- ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
- ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
+ ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
+ ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
}
/* Check lower plan nodes */
- ExecCheckPlanPerms(plan->lefttree, operation,
- resultRelation, resultIsScanned);
- ExecCheckPlanPerms(plan->righttree, operation,
- resultRelation, resultIsScanned);
+ ExecCheckPlanPerms(plan->lefttree, rangeTable, operation);
+ ExecCheckPlanPerms(plan->righttree, rangeTable, operation);
/* Do node-type-specific checks */
switch (nodeTag(plan))
{
+ case T_SubqueryScan:
+ {
+ SubqueryScan *scan = (SubqueryScan *) plan;
+ RangeTblEntry *rte;
+
+ /* Recursively check the subquery */
+ rte = rt_fetch(scan->scan.scanrelid, rangeTable);
+ Assert(rte->subquery != NULL);
+ ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
+ break;
+ }
case T_Append:
{
Append *app = (Append *) plan;
@@ -490,43 +460,31 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
if (app->inheritrelid > 0)
{
+ /* Append implements expansion of inheritance */
+ ExecCheckRTPerms(app->inheritrtable, operation);
- /*
- * Append implements expansion of inheritance; all
- * members of inheritrtable list will be plugged into
- * same RTE slot. Therefore, they are either all
- * result relations or none.
- */
- List *rtable;
-
- foreach(rtable, app->inheritrtable)
+ /* Check appended plans w/outer rangetable */
+ foreach(appendplans, app->appendplans)
{
- ExecCheckRTEPerms((RangeTblEntry *) lfirst(rtable),
- operation,
- (app->inheritrelid == resultRelation),
- resultIsScanned);
+ ExecCheckPlanPerms((Plan *) lfirst(appendplans),
+ rangeTable,
+ operation);
}
}
else
{
/* Append implements UNION, which must be a SELECT */
- List *rtables;
+ List *rtables = app->unionrtables;
- foreach(rtables, app->unionrtables)
+ /* Check appended plans with their rangetables */
+ foreach(appendplans, app->appendplans)
{
- ExecCheckRTPerms((List *) lfirst(rtables),
- CMD_SELECT, 0, false);
+ ExecCheckPlanPerms((Plan *) lfirst(appendplans),
+ (List *) lfirst(rtables),
+ CMD_SELECT);
+ rtables = lnext(rtables);
}
}
-
- /* Check appended plans */
- foreach(appendplans, app->appendplans)
- {
- ExecCheckPlanPerms((Plan *) lfirst(appendplans),
- operation,
- resultRelation,
- resultIsScanned);
- }
break;
}
@@ -538,28 +496,17 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
/*
* ExecCheckRTPerms
* Check access permissions for all relations listed in a range table.
- *
- * If resultRelation is not 0, it is the RT index of the relation to be
- * treated as the result relation. All other relations are assumed to be
- * read-only for the query.
*/
static void
-ExecCheckRTPerms(List *rangeTable, CmdType operation,
- int resultRelation, bool resultIsScanned)
+ExecCheckRTPerms(List *rangeTable, CmdType operation)
{
- int rtindex = 0;
List *lp;
foreach(lp, rangeTable)
{
RangeTblEntry *rte = lfirst(lp);
- ++rtindex;
-
- ExecCheckRTEPerms(rte,
- operation,
- (rtindex == resultRelation),
- resultIsScanned);
+ ExecCheckRTEPerms(rte, operation);
}
}
@@ -568,45 +515,48 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation,
* Check access permissions for a single RTE.
*/
static void
-ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
- bool isResultRelation, bool resultIsScanned)
+ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
{
char *relName;
Oid userid;
int32 aclcheck_result;
- if (rte->skipAcl)
- {
-
- /*
- * This happens if the access to this table is due to a view query
- * rewriting - the rewrite handler already checked the permissions
- * against the view owner, so we just skip this entry.
- */
+ /*
+ * If it's a subquery RTE, ignore it --- it will be checked when
+ * ExecCheckPlanPerms finds the SubqueryScan node for it.
+ */
+ if (rte->subquery)
return;
- }
relName = rte->relname;
/*
+ * userid to check as: current user unless we have a setuid indication.
+ *
* Note: GetUserId() is presently fast enough that there's no harm
* in calling it separately for each RTE. If that stops being true,
* we could call it once in ExecCheckQueryPerms and pass the userid
* down from there. But for now, no need for the extra clutter.
*/
- userid = GetUserId();
+ userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
#define CHECK(MODE) pg_aclcheck(relName, userid, MODE)
- if (isResultRelation)
+ if (rte->checkForRead)
{
- if (resultIsScanned)
- {
- aclcheck_result = CHECK(ACL_RD);
- if (aclcheck_result != ACLCHECK_OK)
- elog(ERROR, "%s: %s",
- relName, aclcheck_error_strings[aclcheck_result]);
- }
+ aclcheck_result = CHECK(ACL_RD);
+ if (aclcheck_result != ACLCHECK_OK)
+ elog(ERROR, "%s: %s",
+ relName, aclcheck_error_strings[aclcheck_result]);
+ }
+
+ if (rte->checkForWrite)
+ {
+ /*
+ * Note: write access in a SELECT context means SELECT FOR UPDATE.
+ * Right now we don't distinguish that from true update as far as
+ * permissions checks are concerned.
+ */
switch (operation)
{
case CMD_INSERT:
@@ -615,6 +565,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
if (aclcheck_result != ACLCHECK_OK)
aclcheck_result = CHECK(ACL_WR);
break;
+ case CMD_SELECT:
case CMD_DELETE:
case CMD_UPDATE:
aclcheck_result = CHECK(ACL_WR);
@@ -625,13 +576,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
aclcheck_result = ACLCHECK_OK; /* keep compiler quiet */
break;
}
+ if (aclcheck_result != ACLCHECK_OK)
+ elog(ERROR, "%s: %s",
+ relName, aclcheck_error_strings[aclcheck_result]);
}
- else
- aclcheck_result = CHECK(ACL_RD);
-
- if (aclcheck_result != ACLCHECK_OK)
- elog(ERROR, "%s: %s",
- relName, aclcheck_error_strings[aclcheck_result]);
}
@@ -755,26 +703,23 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
/*
* Have to lock relations selected for update
*/
- estate->es_rowMark = NULL;
- if (parseTree->rowMark != NULL)
+ estate->es_rowMark = NIL;
+ if (parseTree->rowMarks != NIL)
{
List *l;
- foreach(l, parseTree->rowMark)
+ foreach(l, parseTree->rowMarks)
{
- RowMark *rm = lfirst(l);
- Oid relid;
+ Index rti = lfirsti(l);
+ Oid relid = getrelid(rti, rangeTable);
Relation relation;
execRowMark *erm;
- if (!(rm->info & ROW_MARK_FOR_UPDATE))
- continue;
- relid = getrelid(rm->rti, rangeTable);
relation = heap_open(relid, RowShareLock);
erm = (execRowMark *) palloc(sizeof(execRowMark));
erm->relation = relation;
- erm->rti = rm->rti;
- sprintf(erm->resname, "ctid%u", rm->rti);
+ erm->rti = rti;
+ sprintf(erm->resname, "ctid%u", rti);
estate->es_rowMark = lappend(estate->es_rowMark, erm);
}
}
@@ -1097,7 +1042,7 @@ lnext: ;
* ctid!! */
tupleid = &tuple_ctid;
}
- else if (estate->es_rowMark != NULL)
+ else if (estate->es_rowMark != NIL)
{
List *l;
@@ -1115,10 +1060,12 @@ lnext: ;
erm->resname,
&datum,
&isNull))
- elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!", erm->resname);
+ elog(ERROR, "ExecutePlan: NO (junk) `%s' was found!",
+ erm->resname);
if (isNull)
- elog(ERROR, "ExecutePlan: (junk) `%s' is NULL!", erm->resname);
+ elog(ERROR, "ExecutePlan: (junk) `%s' is NULL!",
+ erm->resname);
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
test = heap_mark4update(erm->relation, &tuple, &buffer);
@@ -1625,10 +1572,10 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
rte->relid = RelationGetRelid(rel);
rte->eref = makeNode(Attr);
rte->eref->relname = rte->relname;
- /* inh, inFromCl, skipAcl won't be used, leave them zero */
+ /* other fields won't be used, leave them zero */
/* Set up single-entry range table */
- econtext->ecxt_range_table = lcons(rte, NIL);
+ econtext->ecxt_range_table = makeList1(rte);
estate->es_result_relation_constraints =
(List **) palloc(ncheck * sizeof(List *));
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 8c9970a6fa7..d6a15371311 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.19 2000/08/13 02:50:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.20 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -90,6 +90,7 @@
#include "executor/nodeSeqscan.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
+#include "executor/nodeSubqueryscan.h"
#include "executor/nodeUnique.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
@@ -153,6 +154,15 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitIndexScan((IndexScan *) node, estate, parent);
break;
+ case T_TidScan:
+ result = ExecInitTidScan((TidScan *) node, estate, parent);
+ break;
+
+ case T_SubqueryScan:
+ result = ExecInitSubqueryScan((SubqueryScan *) node, estate,
+ parent);
+ break;
+
/* ----------------
* join nodes
* ----------------
@@ -165,6 +175,14 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
break;
+ case T_Hash:
+ result = ExecInitHash((Hash *) node, estate, parent);
+ break;
+
+ case T_HashJoin:
+ result = ExecInitHashJoin((HashJoin *) node, estate, parent);
+ break;
+
/* ----------------
* materialization nodes
* ----------------
@@ -189,18 +207,6 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitAgg((Agg *) node, estate, parent);
break;
- case T_Hash:
- result = ExecInitHash((Hash *) node, estate, parent);
- break;
-
- case T_HashJoin:
- result = ExecInitHashJoin((HashJoin *) node, estate, parent);
- break;
-
- case T_TidScan:
- result = ExecInitTidScan((TidScan *) node, estate, parent);
- break;
-
default:
elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
result = FALSE;
@@ -272,6 +278,14 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecIndexScan((IndexScan *) node);
break;
+ case T_TidScan:
+ result = ExecTidScan((TidScan *) node);
+ break;
+
+ case T_SubqueryScan:
+ result = ExecSubqueryScan((SubqueryScan *) node);
+ break;
+
/* ----------------
* join nodes
* ----------------
@@ -284,6 +298,14 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecMergeJoin((MergeJoin *) node);
break;
+ case T_Hash:
+ result = ExecHash((Hash *) node);
+ break;
+
+ case T_HashJoin:
+ result = ExecHashJoin((HashJoin *) node);
+ break;
+
/* ----------------
* materialization nodes
* ----------------
@@ -308,18 +330,6 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecAgg((Agg *) node);
break;
- case T_Hash:
- result = ExecHash((Hash *) node);
- break;
-
- case T_HashJoin:
- result = ExecHashJoin((HashJoin *) node);
- break;
-
- case T_TidScan:
- result = ExecTidScan((TidScan *) node);
- break;
-
default:
elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
result = NULL;
@@ -356,6 +366,12 @@ ExecCountSlotsNode(Plan *node)
case T_IndexScan:
return ExecCountSlotsIndexScan((IndexScan *) node);
+ case T_TidScan:
+ return ExecCountSlotsTidScan((TidScan *) node);
+
+ case T_SubqueryScan:
+ return ExecCountSlotsSubqueryScan((SubqueryScan *) node);
+
/* ----------------
* join nodes
* ----------------
@@ -366,6 +382,12 @@ ExecCountSlotsNode(Plan *node)
case T_MergeJoin:
return ExecCountSlotsMergeJoin((MergeJoin *) node);
+ case T_Hash:
+ return ExecCountSlotsHash((Hash *) node);
+
+ case T_HashJoin:
+ return ExecCountSlotsHashJoin((HashJoin *) node);
+
/* ----------------
* materialization nodes
* ----------------
@@ -385,15 +407,6 @@ ExecCountSlotsNode(Plan *node)
case T_Agg:
return ExecCountSlotsAgg((Agg *) node);
- case T_Hash:
- return ExecCountSlotsHash((Hash *) node);
-
- case T_HashJoin:
- return ExecCountSlotsHashJoin((HashJoin *) node);
-
- case T_TidScan:
- return ExecCountSlotsTidScan((TidScan *) node);
-
default:
elog(ERROR, "ExecCountSlotsNode: node not yet supported: %d",
nodeTag(node));
@@ -462,6 +475,14 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndIndexScan((IndexScan *) node);
break;
+ case T_TidScan:
+ ExecEndTidScan((TidScan *) node);
+ break;
+
+ case T_SubqueryScan:
+ ExecEndSubqueryScan((SubqueryScan *) node);
+ break;
+
/* ----------------
* join nodes
* ----------------
@@ -474,6 +495,14 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndMergeJoin((MergeJoin *) node);
break;
+ case T_Hash:
+ ExecEndHash((Hash *) node);
+ break;
+
+ case T_HashJoin:
+ ExecEndHashJoin((HashJoin *) node);
+ break;
+
/* ----------------
* materialization nodes
* ----------------
@@ -498,22 +527,6 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndAgg((Agg *) node);
break;
- /* ----------------
- * XXX add hooks to these
- * ----------------
- */
- case T_Hash:
- ExecEndHash((Hash *) node);
- break;
-
- case T_HashJoin:
- ExecEndHashJoin((HashJoin *) node);
- break;
-
- case T_TidScan:
- ExecEndTidScan((TidScan *) node);
- break;
-
default:
elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
break;
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 05474bc64bc..008105719f3 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.39 2000/09/12 21:06:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.40 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -698,6 +698,22 @@ NodeGetResultTupleSlot(Plan *node)
}
break;
+ case T_TidScan:
+ {
+ CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SubqueryScan:
+ {
+ CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
case T_Material:
{
MaterialState *matstate = ((Material *) node)->matstate;
@@ -762,14 +778,6 @@ NodeGetResultTupleSlot(Plan *node)
}
break;
- case T_TidScan:
- {
- CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
-
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
default:
/* ----------------
* should never get here
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
new file mode 100644
index 00000000000..45f07a08b10
--- /dev/null
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -0,0 +1,289 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeSubqueryscan.c
+ * Support routines for scanning subqueries (subselects in rangetable).
+ *
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.1 2000/09/29 18:21:29 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * ExecSubqueryScan scans a subquery.
+ * ExecSubqueryNext retrieve next tuple in sequential order.
+ * ExecInitSubqueryScan creates and initializes a subqueryscan node.
+ * ExecEndSubqueryScan releases any storage allocated.
+ * ExecSubqueryReScan 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/nodeSubqueryscan.h"
+#include "parser/parsetree.h"
+#include "tcop/pquery.h"
+
+static TupleTableSlot *SubqueryNext(SubqueryScan *node);
+
+/* ----------------------------------------------------------------
+ * Scan Support
+ * ----------------------------------------------------------------
+ */
+/* ----------------------------------------------------------------
+ * SubqueryNext
+ *
+ * This is a workhorse for ExecSubqueryScan
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+SubqueryNext(SubqueryScan *node)
+{
+ SubqueryScanState *subquerystate;
+ EState *estate;
+ ScanDirection direction;
+ int execdir;
+ TupleTableSlot *slot;
+ Const countOne;
+
+ /* ----------------
+ * get information from the estate and scan state
+ * ----------------
+ */
+ estate = node->scan.plan.state;
+ subquerystate = (SubqueryScanState *) node->scan.scanstate;
+ direction = estate->es_direction;
+ execdir = ScanDirectionIsBackward(direction) ? EXEC_BACK : EXEC_FOR;
+ slot = subquerystate->csstate.css_ScanTupleSlot;
+
+ /*
+ * Check if we are evaluating PlanQual for tuple of this relation.
+ * Additional checking is not good, but no other way for now. We could
+ * introduce new nodes for this case and handle SubqueryScan --> NewNode
+ * switching in Init/ReScan plan...
+ */
+ if (estate->es_evTuple != NULL &&
+ estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
+ {
+ ExecClearTuple(slot);
+ if (estate->es_evTupleNull[node->scan.scanrelid - 1])
+ return slot; /* return empty slot */
+
+ /* probably ought to use ExecStoreTuple here... */
+ slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
+ slot->ttc_shouldFree = false;
+
+ /* Flag for the next call that no more tuples */
+ estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
+ return (slot);
+ }
+
+ memset(&countOne, 0, sizeof(countOne));
+ countOne.type = T_Const;
+ countOne.consttype = INT4OID;
+ countOne.constlen = sizeof(int4);
+ countOne.constvalue = Int32GetDatum(1);
+ countOne.constisnull = false;
+ countOne.constbyval = true;
+ countOne.constisset = false;
+ countOne.constiscast = false;
+
+ /* ----------------
+ * get the next tuple from the sub-query
+ * ----------------
+ */
+ slot = ExecutorRun(subquerystate->sss_SubQueryDesc,
+ subquerystate->sss_SubEState,
+ execdir,
+ NULL, /* offset */
+ (Node *) &countOne);
+
+ subquerystate->csstate.css_ScanTupleSlot = slot;
+
+ return slot;
+}
+
+/* ----------------------------------------------------------------
+ * ExecSubqueryScan(node)
+ *
+ * Scans the subquery sequentially and returns the next qualifying
+ * tuple.
+ * It calls the ExecScan() routine and passes it the access method
+ * which retrieve tuples sequentially.
+ *
+ */
+
+TupleTableSlot *
+ExecSubqueryScan(SubqueryScan *node)
+{
+ /* ----------------
+ * use SubqueryNext as access method
+ * ----------------
+ */
+ return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitSubqueryScan
+ * ----------------------------------------------------------------
+ */
+bool
+ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
+{
+ SubqueryScanState *subquerystate;
+ RangeTblEntry *rte;
+
+ /* ----------------
+ * SubqueryScan 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 SubqueryScanState for node
+ * ----------------
+ */
+ subquerystate = makeNode(SubqueryScanState);
+ node->scan.scanstate = (CommonScanState *) subquerystate;
+
+ /* ----------------
+ * Miscellaneous initialization
+ *
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
+
+#define SUBQUERYSCAN_NSLOTS 2
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
+
+ /* ----------------
+ * initialize subquery
+ * ----------------
+ */
+ rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
+ Assert(rte->subquery != NULL);
+
+ subquerystate->sss_SubQueryDesc = CreateQueryDesc(rte->subquery,
+ node->subplan,
+ None);
+ subquerystate->sss_SubEState = CreateExecutorState();
+
+ ExecutorStart(subquerystate->sss_SubQueryDesc,
+ subquerystate->sss_SubEState);
+
+ subquerystate->csstate.css_ScanTupleSlot = NULL;
+ subquerystate->csstate.cstate.cs_TupFromTlist = false;
+
+ /* ----------------
+ * initialize tuple type
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
+ ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
+
+ return TRUE;
+}
+
+int
+ExecCountSlotsSubqueryScan(SubqueryScan *node)
+{
+ /*
+ * The subplan has its own tuple table and must not be counted here!
+ */
+ return ExecCountSlotsNode(outerPlan(node)) +
+ ExecCountSlotsNode(innerPlan(node)) +
+ SUBQUERYSCAN_NSLOTS;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndSubqueryScan
+ *
+ * frees any storage allocated through C routines.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndSubqueryScan(SubqueryScan *node)
+{
+ SubqueryScanState *subquerystate;
+
+ /* ----------------
+ * get information from node
+ * ----------------
+ */
+ subquerystate = (SubqueryScanState *) node->scan.scanstate;
+
+ /* ----------------
+ * Free the projection info and the scan attribute info
+ *
+ * Note: we don't ExecFreeResultType(subquerystate)
+ * 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(&subquerystate->csstate.cstate);
+ ExecFreeExprContext(&subquerystate->csstate.cstate);
+
+ /* ----------------
+ * close down subquery
+ * ----------------
+ */
+ ExecutorEnd(subquerystate->sss_SubQueryDesc,
+ subquerystate->sss_SubEState);
+
+ /* XXX we seem to be leaking the querydesc and sub-EState... */
+
+ subquerystate->csstate.css_ScanTupleSlot = NULL;
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
+}
+
+/* ----------------------------------------------------------------
+ * ExecSubqueryReScan
+ *
+ * Rescans the relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
+{
+ SubqueryScanState *subquerystate;
+ EState *estate;
+
+ subquerystate = (SubqueryScanState *) node->scan.scanstate;
+ estate = node->scan.plan.state;
+
+ /* If this is re-scanning of PlanQual ... */
+ if (estate->es_evTuple != NULL &&
+ estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
+ {
+ estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
+ return;
+ }
+
+ ExecReScan(node->subplan, NULL, NULL);
+ subquerystate->csstate.css_ScanTupleSlot = NULL;
+}