OSDN Git Service

Standard pgindent run for 8.1.
[pg-rex/syncrep.git] / 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-2005, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  *
14  * IDENTIFICATION
15  *        $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.37 2005/10/15 02:49:16 momjian Exp $
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  *              ExecScan
31  *
32  *              Scans the relation using the 'access method' indicated and
33  *              returns the next qualifying tuple in the direction specified
34  *              in the global variable ExecDirection.
35  *              The access method returns the next tuple and execScan() is
36  *              responsible for checking the tuple returned against the qual-clause.
37  *
38  *              Conditions:
39  *                -- the "cursor" maintained by the AMI is positioned at the tuple
40  *                       returned previously.
41  *
42  *              Initial States:
43  *                -- the relation indicated is opened for scanning so that the
44  *                       "cursor" is positioned before the first qualifying tuple.
45  * ----------------------------------------------------------------
46  */
47 TupleTableSlot *
48 ExecScan(ScanState *node,
49                  ExecScanAccessMtd accessMtd)   /* function returning a tuple */
50 {
51         ExprContext *econtext;
52         List       *qual;
53         ProjectionInfo *projInfo;
54         ExprDoneCond isDone;
55         TupleTableSlot *resultSlot;
56
57         /*
58          * Fetch data from node
59          */
60         qual = node->ps.qual;
61         projInfo = node->ps.ps_ProjInfo;
62
63         /*
64          * If we have neither a qual to check nor a projection to do, just skip
65          * all the overhead and return the raw scan tuple.
66          */
67         if (!qual && !projInfo)
68                 return (*accessMtd) (node);
69
70         /*
71          * Check to see if we're still projecting out tuples from a previous scan
72          * tuple (because there is a function-returning-set in the projection
73          * expressions).  If so, try to project another one.
74          */
75         if (node->ps.ps_TupFromTlist)
76         {
77                 Assert(projInfo);               /* can't get here if not projecting */
78                 resultSlot = ExecProject(projInfo, &isDone);
79                 if (isDone == ExprMultipleResult)
80                         return resultSlot;
81                 /* Done with that source tuple... */
82                 node->ps.ps_TupFromTlist = false;
83         }
84
85         /*
86          * Reset per-tuple memory context to free any expression evaluation
87          * storage allocated in the previous tuple cycle.  Note this can't happen
88          * until we're done projecting out tuples from a scan tuple.
89          */
90         econtext = node->ps.ps_ExprContext;
91         ResetExprContext(econtext);
92
93         /*
94          * get a tuple from the access method loop until we obtain a tuple which
95          * passes the qualification.
96          */
97         for (;;)
98         {
99                 TupleTableSlot *slot;
100
101                 CHECK_FOR_INTERRUPTS();
102
103                 slot = (*accessMtd) (node);
104
105                 /*
106                  * if the slot returned by the accessMtd contains NULL, then it means
107                  * there is nothing more to scan so we just return an empty slot,
108                  * being careful to use the projection result slot so it has correct
109                  * tupleDesc.
110                  */
111                 if (TupIsNull(slot))
112                 {
113                         if (projInfo)
114                                 return ExecClearTuple(projInfo->pi_slot);
115                         else
116                                 return slot;
117                 }
118
119                 /*
120                  * place the current tuple into the expr context
121                  */
122                 econtext->ecxt_scantuple = slot;
123
124                 /*
125                  * check that the current tuple satisfies the qual-clause
126                  *
127                  * check for non-nil qual here to avoid a function call to ExecQual()
128                  * when the qual is nil ... saves only a few cycles, but they add up
129                  * ...
130                  */
131                 if (!qual || ExecQual(qual, econtext, false))
132                 {
133                         /*
134                          * Found a satisfactory scan tuple.
135                          */
136                         if (projInfo)
137                         {
138                                 /*
139                                  * Form a projection tuple, store it in the result tuple slot
140                                  * and return it --- unless we find we can project no tuples
141                                  * from this scan tuple, in which case continue scan.
142                                  */
143                                 resultSlot = ExecProject(projInfo, &isDone);
144                                 if (isDone != ExprEndResult)
145                                 {
146                                         node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
147                                         return resultSlot;
148                                 }
149                         }
150                         else
151                         {
152                                 /*
153                                  * Here, we aren't projecting, so just return scan tuple.
154                                  */
155                                 return slot;
156                         }
157                 }
158
159                 /*
160                  * Tuple fails qual, so free per-tuple memory and try again.
161                  */
162                 ResetExprContext(econtext);
163         }
164 }
165
166 /*
167  * ExecAssignScanProjectionInfo
168  *              Set up projection info for a scan node, if necessary.
169  *
170  * We can avoid a projection step if the requested tlist exactly matches
171  * the underlying tuple type.  If so, we just set ps_ProjInfo to NULL.
172  * Note that this case occurs not only for simple "SELECT * FROM ...", but
173  * also in most cases where there are joins or other processing nodes above
174  * the scan node, because the planner will preferentially generate a matching
175  * tlist.
176  *
177  * ExecAssignScanType must have been called already.
178  */
179 void
180 ExecAssignScanProjectionInfo(ScanState *node)
181 {
182         Scan       *scan = (Scan *) node->ps.plan;
183
184         if (tlist_matches_tupdesc(&node->ps,
185                                                           scan->plan.targetlist,
186                                                           scan->scanrelid,
187                                                           node->ss_ScanTupleSlot->tts_tupleDescriptor))
188                 node->ps.ps_ProjInfo = NULL;
189         else
190                 ExecAssignProjectionInfo(&node->ps);
191 }
192
193 static bool
194 tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
195 {
196         int                     numattrs = tupdesc->natts;
197         int                     attrno;
198         bool            hasoid;
199         ListCell   *tlist_item = list_head(tlist);
200
201         /* Check the tlist attributes */
202         for (attrno = 1; attrno <= numattrs; attrno++)
203         {
204                 Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
205                 Var                *var;
206
207                 if (tlist_item == NULL)
208                         return false;           /* tlist too short */
209                 var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
210                 if (!var || !IsA(var, Var))
211                         return false;           /* tlist item not a Var */
212                 Assert(var->varno == varno);
213                 Assert(var->varlevelsup == 0);
214                 if (var->varattno != attrno)
215                         return false;           /* out of order */
216                 if (att_tup->attisdropped)
217                         return false;           /* table contains dropped columns */
218                 Assert(var->vartype == att_tup->atttypid);
219                 Assert(var->vartypmod == att_tup->atttypmod);
220
221                 tlist_item = lnext(tlist_item);
222         }
223
224         if (tlist_item)
225                 return false;                   /* tlist too long */
226
227         /*
228          * If the plan context requires a particular hasoid setting, then that has
229          * to match, too.
230          */
231         if (ExecContextForcesOids(ps, &hasoid) &&
232                 hasoid != tupdesc->tdhasoid)
233                 return false;
234
235         return true;
236 }