summaryrefslogtreecommitdiffstats
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.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
new file mode 100644
index 0000000..c09f628
--- /dev/null
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -0,0 +1,213 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeSubqueryscan.c
+ * Support routines for scanning subqueries (subselects in rangetable).
+ *
+ * This is just enough different from sublinks (nodeSubplan.c) to mean that
+ * we need two sets of code. Ought to look at trying to unify the cases.
+ *
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/executor/nodeSubqueryscan.c
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * 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.
+ * ExecReScanSubqueryScan rescans the relation
+ *
+ */
+#include "postgres.h"
+
+#include "executor/execdebug.h"
+#include "executor/nodeSubqueryscan.h"
+
+static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
+
+/* ----------------------------------------------------------------
+ * Scan Support
+ * ----------------------------------------------------------------
+ */
+/* ----------------------------------------------------------------
+ * SubqueryNext
+ *
+ * This is a workhorse for ExecSubqueryScan
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+SubqueryNext(SubqueryScanState *node)
+{
+ TupleTableSlot *slot;
+
+ /*
+ * Get the next tuple from the sub-query.
+ */
+ slot = ExecProcNode(node->subplan);
+
+ /*
+ * We just return the subplan's result slot, rather than expending extra
+ * cycles for ExecCopySlot(). (Our own ScanTupleSlot is used only for
+ * EvalPlanQual rechecks.)
+ */
+ return slot;
+}
+
+/*
+ * SubqueryRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
+{
+ /* nothing to check */
+ return true;
+}
+
+/* ----------------------------------------------------------------
+ * ExecSubqueryScan(node)
+ *
+ * Scans the subquery sequentially and returns the next qualifying
+ * tuple.
+ * We call the ExecScan() routine and pass it the appropriate
+ * access method functions.
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecSubqueryScan(PlanState *pstate)
+{
+ SubqueryScanState *node = castNode(SubqueryScanState, pstate);
+
+ return ExecScan(&node->ss,
+ (ExecScanAccessMtd) SubqueryNext,
+ (ExecScanRecheckMtd) SubqueryRecheck);
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitSubqueryScan
+ * ----------------------------------------------------------------
+ */
+SubqueryScanState *
+ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
+{
+ SubqueryScanState *subquerystate;
+
+ /* check for unsupported flags */
+ Assert(!(eflags & EXEC_FLAG_MARK));
+
+ /* SubqueryScan should not have any "normal" children */
+ Assert(outerPlan(node) == NULL);
+ Assert(innerPlan(node) == NULL);
+
+ /*
+ * create state structure
+ */
+ subquerystate = makeNode(SubqueryScanState);
+ subquerystate->ss.ps.plan = (Plan *) node;
+ subquerystate->ss.ps.state = estate;
+ subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * create expression context for node
+ */
+ ExecAssignExprContext(estate, &subquerystate->ss.ps);
+
+ /*
+ * initialize subquery
+ */
+ subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags);
+
+ /*
+ * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo)
+ */
+ ExecInitScanTupleSlot(estate, &subquerystate->ss,
+ ExecGetResultType(subquerystate->subplan),
+ ExecGetResultSlotOps(subquerystate->subplan, NULL));
+
+ /*
+ * The slot used as the scantuple isn't the slot above (outside of EPQ),
+ * but the one from the node below.
+ */
+ subquerystate->ss.ps.scanopsset = true;
+ subquerystate->ss.ps.scanops = ExecGetResultSlotOps(subquerystate->subplan,
+ &subquerystate->ss.ps.scanopsfixed);
+ subquerystate->ss.ps.resultopsset = true;
+ subquerystate->ss.ps.resultops = subquerystate->ss.ps.scanops;
+ subquerystate->ss.ps.resultopsfixed = subquerystate->ss.ps.scanopsfixed;
+
+ /*
+ * Initialize result type and projection.
+ */
+ ExecInitResultTypeTL(&subquerystate->ss.ps);
+ ExecAssignScanProjectionInfo(&subquerystate->ss);
+
+ /*
+ * initialize child expressions
+ */
+ subquerystate->ss.ps.qual =
+ ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate);
+
+ return subquerystate;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndSubqueryScan
+ *
+ * frees any storage allocated through C routines.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndSubqueryScan(SubqueryScanState *node)
+{
+ /*
+ * Free the exprcontext
+ */
+ ExecFreeExprContext(&node->ss.ps);
+
+ /*
+ * clean out the upper tuple table
+ */
+ if (node->ss.ps.ps_ResultTupleSlot)
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+ /*
+ * close down subquery
+ */
+ ExecEndNode(node->subplan);
+}
+
+/* ----------------------------------------------------------------
+ * ExecReScanSubqueryScan
+ *
+ * Rescans the relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecReScanSubqueryScan(SubqueryScanState *node)
+{
+ ExecScanReScan(&node->ss);
+
+ /*
+ * ExecReScan doesn't know about my subplan, so I have to do
+ * changed-parameter signaling myself. This is just as well, because the
+ * subplan has its own memory context in which its chgParam state lives.
+ */
+ if (node->ss.ps.chgParam != NULL)
+ UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
+
+ /*
+ * if chgParam of subnode is not null then plan will be re-scanned by
+ * first ExecProcNode.
+ */
+ if (node->subplan->chgParam == NULL)
+ ExecReScan(node->subplan);
+}