1 /*-------------------------------------------------------------------------
2 *
3 * nodeSubqueryscan.c
4 * Support routines for scanning subqueries (subselects in rangetable).
5 *
6 * This is just enough different from sublinks (nodeSubplan.c) to mean that
7 * we need two sets of code. Ought to look at trying to unify the cases.
8 *
9 *
10 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
12 *
13 *
14 * IDENTIFICATION
15 * src/backend/executor/nodeSubqueryscan.c
16 *
17 *-------------------------------------------------------------------------
18 */
19 /*
20 * INTERFACE ROUTINES
21 * ExecSubqueryScan scans a subquery.
22 * ExecSubqueryNext retrieve next tuple in sequential order.
23 * ExecInitSubqueryScan creates and initializes a subqueryscan node.
24 * ExecEndSubqueryScan releases any storage allocated.
25 * ExecReScanSubqueryScan rescans the relation
26 *
27 */
28 #include "postgres.h"
29
30 #include "executor/execdebug.h"
31 #include "executor/nodeSubqueryscan.h"
32
33 static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
34
35 /* ----------------------------------------------------------------
36 * Scan Support
37 * ----------------------------------------------------------------
38 */
39 /* ----------------------------------------------------------------
40 * SubqueryNext
41 *
42 * This is a workhorse for ExecSubqueryScan
43 * ----------------------------------------------------------------
44 */
45 static TupleTableSlot *
SubqueryNext(SubqueryScanState * node)46 SubqueryNext(SubqueryScanState *node)
47 {
48 TupleTableSlot *slot;
49
50 /*
51 * Get the next tuple from the sub-query.
52 */
53 slot = ExecProcNode(node->subplan);
54
55 /*
56 * We just return the subplan's result slot, rather than expending extra
57 * cycles for ExecCopySlot(). (Our own ScanTupleSlot is used only for
58 * EvalPlanQual rechecks.)
59 */
60 return slot;
61 }
62
63 /*
64 * SubqueryRecheck -- access method routine to recheck a tuple in EvalPlanQual
65 */
66 static bool
SubqueryRecheck(SubqueryScanState * node,TupleTableSlot * slot)67 SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
68 {
69 /* nothing to check */
70 return true;
71 }
72
73 /* ----------------------------------------------------------------
74 * ExecSubqueryScan(node)
75 *
76 * Scans the subquery sequentially and returns the next qualifying
77 * tuple.
78 * We call the ExecScan() routine and pass it the appropriate
79 * access method functions.
80 * ----------------------------------------------------------------
81 */
82 static TupleTableSlot *
ExecSubqueryScan(PlanState * pstate)83 ExecSubqueryScan(PlanState *pstate)
84 {
85 SubqueryScanState *node = castNode(SubqueryScanState, pstate);
86
87 return ExecScan(&node->ss,
88 (ExecScanAccessMtd) SubqueryNext,
89 (ExecScanRecheckMtd) SubqueryRecheck);
90 }
91
92 /* ----------------------------------------------------------------
93 * ExecInitSubqueryScan
94 * ----------------------------------------------------------------
95 */
96 SubqueryScanState *
ExecInitSubqueryScan(SubqueryScan * node,EState * estate,int eflags)97 ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
98 {
99 SubqueryScanState *subquerystate;
100
101 /* check for unsupported flags */
102 Assert(!(eflags & EXEC_FLAG_MARK));
103
104 /* SubqueryScan should not have any "normal" children */
105 Assert(outerPlan(node) == NULL);
106 Assert(innerPlan(node) == NULL);
107
108 /*
109 * create state structure
110 */
111 subquerystate = makeNode(SubqueryScanState);
112 subquerystate->ss.ps.plan = (Plan *) node;
113 subquerystate->ss.ps.state = estate;
114 subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
115
116 /*
117 * Miscellaneous initialization
118 *
119 * create expression context for node
120 */
121 ExecAssignExprContext(estate, &subquerystate->ss.ps);
122
123 /*
124 * initialize child expressions
125 */
126 subquerystate->ss.ps.qual =
127 ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate);
128
129 /*
130 * tuple table initialization
131 */
132 ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
133 ExecInitScanTupleSlot(estate, &subquerystate->ss);
134
135 /*
136 * initialize subquery
137 */
138 subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags);
139
140 /*
141 * Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
142 */
143 ExecAssignScanType(&subquerystate->ss,
144 ExecGetResultType(subquerystate->subplan));
145
146 /*
147 * Initialize result tuple type and projection info.
148 */
149 ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
150 ExecAssignScanProjectionInfo(&subquerystate->ss);
151
152 return subquerystate;
153 }
154
155 /* ----------------------------------------------------------------
156 * ExecEndSubqueryScan
157 *
158 * frees any storage allocated through C routines.
159 * ----------------------------------------------------------------
160 */
161 void
ExecEndSubqueryScan(SubqueryScanState * node)162 ExecEndSubqueryScan(SubqueryScanState *node)
163 {
164 /*
165 * Free the exprcontext
166 */
167 ExecFreeExprContext(&node->ss.ps);
168
169 /*
170 * clean out the upper tuple table
171 */
172 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
173 ExecClearTuple(node->ss.ss_ScanTupleSlot);
174
175 /*
176 * close down subquery
177 */
178 ExecEndNode(node->subplan);
179 }
180
181 /* ----------------------------------------------------------------
182 * ExecReScanSubqueryScan
183 *
184 * Rescans the relation.
185 * ----------------------------------------------------------------
186 */
187 void
ExecReScanSubqueryScan(SubqueryScanState * node)188 ExecReScanSubqueryScan(SubqueryScanState *node)
189 {
190 ExecScanReScan(&node->ss);
191
192 /*
193 * ExecReScan doesn't know about my subplan, so I have to do
194 * changed-parameter signaling myself. This is just as well, because the
195 * subplan has its own memory context in which its chgParam state lives.
196 */
197 if (node->ss.ps.chgParam != NULL)
198 UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
199
200 /*
201 * if chgParam of subnode is not null then plan will be re-scanned by
202 * first ExecProcNode.
203 */
204 if (node->subplan->chgParam == NULL)
205 ExecReScan(node->subplan);
206 }
207