]> granicus.if.org Git - postgresql/blob - src/backend/executor/execScan.c
Fix inconsistencies in the code
[postgresql] / src / backend / executor / execScan.c
1 /*-------------------------------------------------------------------------
2  *
3  * execScan.c
4  *        This code provides support for generalized relation scans. ExecScan
5  *        is passed a node and a pointer to a function to "do the right thing"
6  *        and return a tuple from the relation. ExecScan then does the tedious
7  *        stuff - checking the qualification and projecting the tuple
8  *        appropriately.
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/execScan.c
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include "postgres.h"
20
21 #include "executor/executor.h"
22 #include "miscadmin.h"
23 #include "utils/memutils.h"
24
25
26
27 /*
28  * ExecScanFetch -- check interrupts & fetch next potential tuple
29  *
30  * This routine is concerned with substituting a test tuple if we are
31  * inside an EvalPlanQual recheck.  If we aren't, just execute
32  * the access method's next-tuple routine.
33  */
34 static inline TupleTableSlot *
35 ExecScanFetch(ScanState *node,
36                           ExecScanAccessMtd accessMtd,
37                           ExecScanRecheckMtd recheckMtd)
38 {
39         EState     *estate = node->ps.state;
40
41         CHECK_FOR_INTERRUPTS();
42
43         if (estate->es_epqTupleSlot != NULL)
44         {
45                 /*
46                  * We are inside an EvalPlanQual recheck.  Return the test tuple if
47                  * one is available, after rechecking any access-method-specific
48                  * conditions.
49                  */
50                 Index           scanrelid = ((Scan *) node->ps.plan)->scanrelid;
51
52                 if (scanrelid == 0)
53                 {
54                         TupleTableSlot *slot = node->ss_ScanTupleSlot;
55
56                         /*
57                          * This is a ForeignScan or CustomScan which has pushed down a
58                          * join to the remote side.  The recheck method is responsible not
59                          * only for rechecking the scan/join quals but also for storing
60                          * the correct tuple in the slot.
61                          */
62                         if (!(*recheckMtd) (node, slot))
63                                 ExecClearTuple(slot);   /* would not be returned by scan */
64                         return slot;
65                 }
66                 else if (estate->es_epqTupleSlot[scanrelid - 1] != NULL)
67                 {
68                         TupleTableSlot *slot = node->ss_ScanTupleSlot;
69
70                         /* Return empty slot if we already returned a tuple */
71                         if (estate->es_epqScanDone[scanrelid - 1])
72                                 return ExecClearTuple(slot);
73                         /* Else mark to remember that we shouldn't return more */
74                         estate->es_epqScanDone[scanrelid - 1] = true;
75
76                         slot = estate->es_epqTupleSlot[scanrelid - 1];
77
78                         /* Return empty slot if we haven't got a test tuple */
79                         if (TupIsNull(slot))
80                                 return NULL;
81
82                         /* Check if it meets the access-method conditions */
83                         if (!(*recheckMtd) (node, slot))
84                                 return ExecClearTuple(slot);    /* would not be returned by
85                                                                                                  * scan */
86
87                         return slot;
88                 }
89         }
90
91         /*
92          * Run the node-type-specific access method function to get the next tuple
93          */
94         return (*accessMtd) (node);
95 }
96
97 /* ----------------------------------------------------------------
98  *              ExecScan
99  *
100  *              Scans the relation using the 'access method' indicated and
101  *              returns the next qualifying tuple.
102  *              The access method returns the next tuple and ExecScan() is
103  *              responsible for checking the tuple returned against the qual-clause.
104  *
105  *              A 'recheck method' must also be provided that can check an
106  *              arbitrary tuple of the relation against any qual conditions
107  *              that are implemented internal to the access method.
108  *
109  *              Conditions:
110  *                -- the "cursor" maintained by the AMI is positioned at the tuple
111  *                       returned previously.
112  *
113  *              Initial States:
114  *                -- the relation indicated is opened for scanning so that the
115  *                       "cursor" is positioned before the first qualifying tuple.
116  * ----------------------------------------------------------------
117  */
118 TupleTableSlot *
119 ExecScan(ScanState *node,
120                  ExecScanAccessMtd accessMtd,   /* function returning a tuple */
121                  ExecScanRecheckMtd recheckMtd)
122 {
123         ExprContext *econtext;
124         ExprState  *qual;
125         ProjectionInfo *projInfo;
126
127         /*
128          * Fetch data from node
129          */
130         qual = node->ps.qual;
131         projInfo = node->ps.ps_ProjInfo;
132         econtext = node->ps.ps_ExprContext;
133
134         /* interrupt checks are in ExecScanFetch */
135
136         /*
137          * If we have neither a qual to check nor a projection to do, just skip
138          * all the overhead and return the raw scan tuple.
139          */
140         if (!qual && !projInfo)
141         {
142                 ResetExprContext(econtext);
143                 return ExecScanFetch(node, accessMtd, recheckMtd);
144         }
145
146         /*
147          * Reset per-tuple memory context to free any expression evaluation
148          * storage allocated in the previous tuple cycle.
149          */
150         ResetExprContext(econtext);
151
152         /*
153          * get a tuple from the access method.  Loop until we obtain a tuple that
154          * passes the qualification.
155          */
156         for (;;)
157         {
158                 TupleTableSlot *slot;
159
160                 slot = ExecScanFetch(node, accessMtd, recheckMtd);
161
162                 /*
163                  * if the slot returned by the accessMtd contains NULL, then it means
164                  * there is nothing more to scan so we just return an empty slot,
165                  * being careful to use the projection result slot so it has correct
166                  * tupleDesc.
167                  */
168                 if (TupIsNull(slot))
169                 {
170                         if (projInfo)
171                                 return ExecClearTuple(projInfo->pi_state.resultslot);
172                         else
173                                 return slot;
174                 }
175
176                 /*
177                  * place the current tuple into the expr context
178                  */
179                 econtext->ecxt_scantuple = slot;
180
181                 /*
182                  * check that the current tuple satisfies the qual-clause
183                  *
184                  * check for non-null qual here to avoid a function call to ExecQual()
185                  * when the qual is null ... saves only a few cycles, but they add up
186                  * ...
187                  */
188                 if (qual == NULL || ExecQual(qual, econtext))
189                 {
190                         /*
191                          * Found a satisfactory scan tuple.
192                          */
193                         if (projInfo)
194                         {
195                                 /*
196                                  * Form a projection tuple, store it in the result tuple slot
197                                  * and return it.
198                                  */
199                                 return ExecProject(projInfo);
200                         }
201                         else
202                         {
203                                 /*
204                                  * Here, we aren't projecting, so just return scan tuple.
205                                  */
206                                 return slot;
207                         }
208                 }
209                 else
210                         InstrCountFiltered1(node, 1);
211
212                 /*
213                  * Tuple fails qual, so free per-tuple memory and try again.
214                  */
215                 ResetExprContext(econtext);
216         }
217 }
218
219 /*
220  * ExecAssignScanProjectionInfo
221  *              Set up projection info for a scan node, if necessary.
222  *
223  * We can avoid a projection step if the requested tlist exactly matches
224  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
225  * Note that this case occurs not only for simple "SELECT * FROM ...", but
226  * also in most cases where there are joins or other processing nodes above
227  * the scan node, because the planner will preferentially generate a matching
228  * tlist.
229  *
230  * The scan slot's descriptor must have been set already.
231  */
232 void
233 ExecAssignScanProjectionInfo(ScanState *node)
234 {
235         Scan       *scan = (Scan *) node->ps.plan;
236         TupleDesc       tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
237
238         ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid);
239 }
240
241 /*
242  * ExecAssignScanProjectionInfoWithVarno
243  *              As above, but caller can specify varno expected in Vars in the tlist.
244  */
245 void
246 ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
247 {
248         TupleDesc       tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
249
250         ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno);
251 }
252
253 /*
254  * ExecScanReScan
255  *
256  * This must be called within the ReScan function of any plan node type
257  * that uses ExecScan().
258  */
259 void
260 ExecScanReScan(ScanState *node)
261 {
262         EState     *estate = node->ps.state;
263
264         /*
265          * We must clear the scan tuple so that observers (e.g., execCurrent.c)
266          * can tell that this plan node is not positioned on a tuple.
267          */
268         ExecClearTuple(node->ss_ScanTupleSlot);
269
270         /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
271         if (estate->es_epqScanDone != NULL)
272         {
273                 Index           scanrelid = ((Scan *) node->ps.plan)->scanrelid;
274
275                 if (scanrelid > 0)
276                         estate->es_epqScanDone[scanrelid - 1] = false;
277                 else
278                 {
279                         Bitmapset  *relids;
280                         int                     rtindex = -1;
281
282                         /*
283                          * If an FDW or custom scan provider has replaced the join with a
284                          * scan, there are multiple RTIs; reset the epqScanDone flag for
285                          * all of them.
286                          */
287                         if (IsA(node->ps.plan, ForeignScan))
288                                 relids = ((ForeignScan *) node->ps.plan)->fs_relids;
289                         else if (IsA(node->ps.plan, CustomScan))
290                                 relids = ((CustomScan *) node->ps.plan)->custom_relids;
291                         else
292                                 elog(ERROR, "unexpected scan node: %d",
293                                          (int) nodeTag(node->ps.plan));
294
295                         while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
296                         {
297                                 Assert(rtindex > 0);
298                                 estate->es_epqScanDone[rtindex - 1] = false;
299                         }
300                 }
301         }
302 }