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-2019, 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 * |
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 |
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 * |
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 * |
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 subquery |
125 | */ |
126 | subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); |
127 | |
128 | /* |
129 | * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo) |
130 | */ |
131 | ExecInitScanTupleSlot(estate, &subquerystate->ss, |
132 | ExecGetResultType(subquerystate->subplan), |
133 | ExecGetResultSlotOps(subquerystate->subplan, NULL)); |
134 | |
135 | /* |
136 | * The slot used as the scantuple isn't the slot above (outside of EPQ), |
137 | * but the one from the node below. |
138 | */ |
139 | subquerystate->ss.ps.scanopsset = true; |
140 | subquerystate->ss.ps.scanops = ExecGetResultSlotOps(subquerystate->subplan, |
141 | &subquerystate->ss.ps.scanopsfixed); |
142 | subquerystate->ss.ps.resultopsset = true; |
143 | subquerystate->ss.ps.resultops = subquerystate->ss.ps.scanops; |
144 | subquerystate->ss.ps.resultopsfixed = subquerystate->ss.ps.scanopsfixed; |
145 | |
146 | /* |
147 | * Initialize result type and projection. |
148 | */ |
149 | ExecInitResultTypeTL(&subquerystate->ss.ps); |
150 | ExecAssignScanProjectionInfo(&subquerystate->ss); |
151 | |
152 | /* |
153 | * initialize child expressions |
154 | */ |
155 | subquerystate->ss.ps.qual = |
156 | ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate); |
157 | |
158 | return subquerystate; |
159 | } |
160 | |
161 | /* ---------------------------------------------------------------- |
162 | * ExecEndSubqueryScan |
163 | * |
164 | * frees any storage allocated through C routines. |
165 | * ---------------------------------------------------------------- |
166 | */ |
167 | void |
168 | ExecEndSubqueryScan(SubqueryScanState *node) |
169 | { |
170 | /* |
171 | * Free the exprcontext |
172 | */ |
173 | ExecFreeExprContext(&node->ss.ps); |
174 | |
175 | /* |
176 | * clean out the upper tuple table |
177 | */ |
178 | if (node->ss.ps.ps_ResultTupleSlot) |
179 | ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); |
180 | ExecClearTuple(node->ss.ss_ScanTupleSlot); |
181 | |
182 | /* |
183 | * close down subquery |
184 | */ |
185 | ExecEndNode(node->subplan); |
186 | } |
187 | |
188 | /* ---------------------------------------------------------------- |
189 | * ExecReScanSubqueryScan |
190 | * |
191 | * Rescans the relation. |
192 | * ---------------------------------------------------------------- |
193 | */ |
194 | void |
195 | ExecReScanSubqueryScan(SubqueryScanState *node) |
196 | { |
197 | ExecScanReScan(&node->ss); |
198 | |
199 | /* |
200 | * ExecReScan doesn't know about my subplan, so I have to do |
201 | * changed-parameter signaling myself. This is just as well, because the |
202 | * subplan has its own memory context in which its chgParam state lives. |
203 | */ |
204 | if (node->ss.ps.chgParam != NULL) |
205 | UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam); |
206 | |
207 | /* |
208 | * if chgParam of subnode is not null then plan will be re-scanned by |
209 | * first ExecProcNode. |
210 | */ |
211 | if (node->subplan->chgParam == NULL) |
212 | ExecReScan(node->subplan); |
213 | } |
214 | |