diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/Makefile | 4 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 15 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 219 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 113 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 26 | ||||
-rw-r--r-- | src/backend/executor/nodeSubqueryscan.c | 289 |
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; +} |