aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSubqueryscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeSubqueryscan.c')
-rw-r--r--src/backend/executor/nodeSubqueryscan.c289
1 files changed, 289 insertions, 0 deletions
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;
+}