]> granicus.if.org Git - postgresql/blob - src/backend/executor/execScan.c
Update copyright via script for 2017
[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-2017, 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 static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
27
28
29 /*
30  * ExecScanFetch -- fetch next potential tuple
31  *
32  * This routine is concerned with substituting a test tuple if we are
33  * inside an EvalPlanQual recheck.  If we aren't, just execute
34  * the access method's next-tuple routine.
35  */
36 static inline TupleTableSlot *
37 ExecScanFetch(ScanState *node,
38                           ExecScanAccessMtd accessMtd,
39                           ExecScanRecheckMtd recheckMtd)
40 {
41         EState     *estate = node->ps.state;
42
43         if (estate->es_epqTuple != 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_epqTupleSet[scanrelid - 1])
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                         /* Return empty slot if we haven't got a test tuple */
77                         if (estate->es_epqTuple[scanrelid - 1] == NULL)
78                                 return ExecClearTuple(slot);
79
80                         /* Store test tuple in the plan node's scan slot */
81                         ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
82                                                    slot, InvalidBuffer, false);
83
84                         /* Check if it meets the access-method conditions */
85                         if (!(*recheckMtd) (node, slot))
86                                 ExecClearTuple(slot);   /* would not be returned by scan */
87
88                         return slot;
89                 }
90         }
91
92         /*
93          * Run the node-type-specific access method function to get the next tuple
94          */
95         return (*accessMtd) (node);
96 }
97
98 /* ----------------------------------------------------------------
99  *              ExecScan
100  *
101  *              Scans the relation using the 'access method' indicated and
102  *              returns the next qualifying tuple in the direction specified
103  *              in the global variable ExecDirection.
104  *              The access method returns the next tuple and ExecScan() is
105  *              responsible for checking the tuple returned against the qual-clause.
106  *
107  *              A 'recheck method' must also be provided that can check an
108  *              arbitrary tuple of the relation against any qual conditions
109  *              that are implemented internal to the access method.
110  *
111  *              Conditions:
112  *                -- the "cursor" maintained by the AMI is positioned at the tuple
113  *                       returned previously.
114  *
115  *              Initial States:
116  *                -- the relation indicated is opened for scanning so that the
117  *                       "cursor" is positioned before the first qualifying tuple.
118  * ----------------------------------------------------------------
119  */
120 TupleTableSlot *
121 ExecScan(ScanState *node,
122                  ExecScanAccessMtd accessMtd,   /* function returning a tuple */
123                  ExecScanRecheckMtd recheckMtd)
124 {
125         ExprContext *econtext;
126         List       *qual;
127         ProjectionInfo *projInfo;
128         ExprDoneCond isDone;
129         TupleTableSlot *resultSlot;
130
131         /*
132          * Fetch data from node
133          */
134         qual = node->ps.qual;
135         projInfo = node->ps.ps_ProjInfo;
136         econtext = node->ps.ps_ExprContext;
137
138         /*
139          * If we have neither a qual to check nor a projection to do, just skip
140          * all the overhead and return the raw scan tuple.
141          */
142         if (!qual && !projInfo)
143         {
144                 ResetExprContext(econtext);
145                 return ExecScanFetch(node, accessMtd, recheckMtd);
146         }
147
148         /*
149          * Check to see if we're still projecting out tuples from a previous scan
150          * tuple (because there is a function-returning-set in the projection
151          * expressions).  If so, try to project another one.
152          */
153         if (node->ps.ps_TupFromTlist)
154         {
155                 Assert(projInfo);               /* can't get here if not projecting */
156                 resultSlot = ExecProject(projInfo, &isDone);
157                 if (isDone == ExprMultipleResult)
158                         return resultSlot;
159                 /* Done with that source tuple... */
160                 node->ps.ps_TupFromTlist = false;
161         }
162
163         /*
164          * Reset per-tuple memory context to free any expression evaluation
165          * storage allocated in the previous tuple cycle.  Note this can't happen
166          * until we're done projecting out tuples from a scan tuple.
167          */
168         ResetExprContext(econtext);
169
170         /*
171          * get a tuple from the access method.  Loop until we obtain a tuple that
172          * passes the qualification.
173          */
174         for (;;)
175         {
176                 TupleTableSlot *slot;
177
178                 CHECK_FOR_INTERRUPTS();
179
180                 slot = ExecScanFetch(node, accessMtd, recheckMtd);
181
182                 /*
183                  * if the slot returned by the accessMtd contains NULL, then it means
184                  * there is nothing more to scan so we just return an empty slot,
185                  * being careful to use the projection result slot so it has correct
186                  * tupleDesc.
187                  */
188                 if (TupIsNull(slot))
189                 {
190                         if (projInfo)
191                                 return ExecClearTuple(projInfo->pi_slot);
192                         else
193                                 return slot;
194                 }
195
196                 /*
197                  * place the current tuple into the expr context
198                  */
199                 econtext->ecxt_scantuple = slot;
200
201                 /*
202                  * check that the current tuple satisfies the qual-clause
203                  *
204                  * check for non-nil qual here to avoid a function call to ExecQual()
205                  * when the qual is nil ... saves only a few cycles, but they add up
206                  * ...
207                  */
208                 if (!qual || ExecQual(qual, econtext, false))
209                 {
210                         /*
211                          * Found a satisfactory scan tuple.
212                          */
213                         if (projInfo)
214                         {
215                                 /*
216                                  * Form a projection tuple, store it in the result tuple slot
217                                  * and return it --- unless we find we can project no tuples
218                                  * from this scan tuple, in which case continue scan.
219                                  */
220                                 resultSlot = ExecProject(projInfo, &isDone);
221                                 if (isDone != ExprEndResult)
222                                 {
223                                         node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
224                                         return resultSlot;
225                                 }
226                         }
227                         else
228                         {
229                                 /*
230                                  * Here, we aren't projecting, so just return scan tuple.
231                                  */
232                                 return slot;
233                         }
234                 }
235                 else
236                         InstrCountFiltered1(node, 1);
237
238                 /*
239                  * Tuple fails qual, so free per-tuple memory and try again.
240                  */
241                 ResetExprContext(econtext);
242         }
243 }
244
245 /*
246  * ExecAssignScanProjectionInfo
247  *              Set up projection info for a scan node, if necessary.
248  *
249  * We can avoid a projection step if the requested tlist exactly matches
250  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
251  * Note that this case occurs not only for simple "SELECT * FROM ...", but
252  * also in most cases where there are joins or other processing nodes above
253  * the scan node, because the planner will preferentially generate a matching
254  * tlist.
255  *
256  * ExecAssignScanType must have been called already.
257  */
258 void
259 ExecAssignScanProjectionInfo(ScanState *node)
260 {
261         Scan       *scan = (Scan *) node->ps.plan;
262
263         ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
264 }
265
266 /*
267  * ExecAssignScanProjectionInfoWithVarno
268  *              As above, but caller can specify varno expected in Vars in the tlist.
269  */
270 void
271 ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
272 {
273         Scan       *scan = (Scan *) node->ps.plan;
274
275         if (tlist_matches_tupdesc(&node->ps,
276                                                           scan->plan.targetlist,
277                                                           varno,
278                                                           node->ss_ScanTupleSlot->tts_tupleDescriptor))
279                 node->ps.ps_ProjInfo = NULL;
280         else
281                 ExecAssignProjectionInfo(&node->ps,
282                                                                  node->ss_ScanTupleSlot->tts_tupleDescriptor);
283 }
284
285 static bool
286 tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
287 {
288         int                     numattrs = tupdesc->natts;
289         int                     attrno;
290         bool            hasoid;
291         ListCell   *tlist_item = list_head(tlist);
292
293         /* Check the tlist attributes */
294         for (attrno = 1; attrno <= numattrs; attrno++)
295         {
296                 Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
297                 Var                *var;
298
299                 if (tlist_item == NULL)
300                         return false;           /* tlist too short */
301                 var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
302                 if (!var || !IsA(var, Var))
303                         return false;           /* tlist item not a Var */
304                 /* if these Asserts fail, planner messed up */
305                 Assert(var->varno == varno);
306                 Assert(var->varlevelsup == 0);
307                 if (var->varattno != attrno)
308                         return false;           /* out of order */
309                 if (att_tup->attisdropped)
310                         return false;           /* table contains dropped columns */
311
312                 /*
313                  * Note: usually the Var's type should match the tupdesc exactly, but
314                  * in situations involving unions of columns that have different
315                  * typmods, the Var may have come from above the union and hence have
316                  * typmod -1.  This is a legitimate situation since the Var still
317                  * describes the column, just not as exactly as the tupdesc does. We
318                  * could change the planner to prevent it, but it'd then insert
319                  * projection steps just to convert from specific typmod to typmod -1,
320                  * which is pretty silly.
321                  */
322                 if (var->vartype != att_tup->atttypid ||
323                         (var->vartypmod != att_tup->atttypmod &&
324                          var->vartypmod != -1))
325                         return false;           /* type mismatch */
326
327                 tlist_item = lnext(tlist_item);
328         }
329
330         if (tlist_item)
331                 return false;                   /* tlist too long */
332
333         /*
334          * If the plan context requires a particular hasoid setting, then that has
335          * to match, too.
336          */
337         if (ExecContextForcesOids(ps, &hasoid) &&
338                 hasoid != tupdesc->tdhasoid)
339                 return false;
340
341         return true;
342 }
343
344 /*
345  * ExecScanReScan
346  *
347  * This must be called within the ReScan function of any plan node type
348  * that uses ExecScan().
349  */
350 void
351 ExecScanReScan(ScanState *node)
352 {
353         EState     *estate = node->ps.state;
354
355         /* Stop projecting any tuples from SRFs in the targetlist */
356         node->ps.ps_TupFromTlist = false;
357
358         /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
359         if (estate->es_epqScanDone != NULL)
360         {
361                 Index           scanrelid = ((Scan *) node->ps.plan)->scanrelid;
362
363                 if (scanrelid > 0)
364                         estate->es_epqScanDone[scanrelid - 1] = false;
365                 else
366                 {
367                         Bitmapset  *relids;
368                         int                     rtindex = -1;
369
370                         /*
371                          * If an FDW or custom scan provider has replaced the join with a
372                          * scan, there are multiple RTIs; reset the epqScanDone flag for
373                          * all of them.
374                          */
375                         if (IsA(node->ps.plan, ForeignScan))
376                                 relids = ((ForeignScan *) node->ps.plan)->fs_relids;
377                         else if (IsA(node->ps.plan, CustomScan))
378                                 relids = ((CustomScan *) node->ps.plan)->custom_relids;
379                         else
380                                 elog(ERROR, "unexpected scan node: %d",
381                                          (int) nodeTag(node->ps.plan));
382
383                         while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
384                         {
385                                 Assert(rtindex > 0);
386                                 estate->es_epqScanDone[rtindex - 1] = false;
387                         }
388                 }
389         }
390 }