12
12
*
13
13
*
14
14
* IDENTIFICATION
15
- * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
15
+ * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.23 2003/02/03 15:07:07 tgl Exp $
16
16
*
17
17
*-------------------------------------------------------------------------
18
18
*/
19
19
#include "postgres.h"
20
20
21
- #include <sys/file.h>
22
-
23
21
#include "executor/executor.h"
24
22
#include "miscadmin.h"
25
23
#include "utils/memutils.h"
26
24
27
25
26
+ static bool tlist_matches_tupdesc (List * tlist , Index varno , TupleDesc tupdesc );
27
+
28
+
28
29
/* ----------------------------------------------------------------
29
30
* ExecScan
30
31
*
@@ -50,6 +51,7 @@ ExecScan(ScanState *node,
50
51
EState * estate ;
51
52
ExprContext * econtext ;
52
53
List * qual ;
54
+ ProjectionInfo * projInfo ;
53
55
ExprDoneCond isDone ;
54
56
TupleTableSlot * resultSlot ;
55
57
@@ -59,6 +61,7 @@ ExecScan(ScanState *node,
59
61
estate = node -> ps .state ;
60
62
econtext = node -> ps .ps_ExprContext ;
61
63
qual = node -> ps .qual ;
64
+ projInfo = node -> ps .ps_ProjInfo ;
62
65
63
66
/*
64
67
* Check to see if we're still projecting out tuples from a previous
@@ -67,7 +70,8 @@ ExecScan(ScanState *node,
67
70
*/
68
71
if (node -> ps .ps_TupFromTlist )
69
72
{
70
- resultSlot = ExecProject (node -> ps .ps_ProjInfo , & isDone );
73
+ Assert (projInfo ); /* can't get here if not projecting */
74
+ resultSlot = ExecProject (projInfo , & isDone );
71
75
if (isDone == ExprMultipleResult )
72
76
return resultSlot ;
73
77
/* Done with that source tuple... */
@@ -101,10 +105,13 @@ ExecScan(ScanState *node,
101
105
*/
102
106
if (TupIsNull (slot ))
103
107
{
104
- return ExecStoreTuple (NULL ,
105
- node -> ps .ps_ProjInfo -> pi_slot ,
106
- InvalidBuffer ,
107
- true);
108
+ if (projInfo )
109
+ return ExecStoreTuple (NULL ,
110
+ projInfo -> pi_slot ,
111
+ InvalidBuffer ,
112
+ true);
113
+ else
114
+ return slot ;
108
115
}
109
116
110
117
/*
@@ -123,16 +130,27 @@ ExecScan(ScanState *node,
123
130
{
124
131
/*
125
132
* Found a satisfactory scan tuple.
126
- *
127
- * Form a projection tuple, store it in the result tuple slot and
128
- * return it --- unless we find we can project no tuples from
129
- * this scan tuple, in which case continue scan.
130
133
*/
131
- resultSlot = ExecProject (node -> ps .ps_ProjInfo , & isDone );
132
- if (isDone != ExprEndResult )
134
+ if (projInfo )
133
135
{
134
- node -> ps .ps_TupFromTlist = (isDone == ExprMultipleResult );
135
- return resultSlot ;
136
+ /*
137
+ * Form a projection tuple, store it in the result tuple slot
138
+ * and return it --- unless we find we can project no tuples
139
+ * from this scan tuple, in which case continue scan.
140
+ */
141
+ resultSlot = ExecProject (projInfo , & isDone );
142
+ if (isDone != ExprEndResult )
143
+ {
144
+ node -> ps .ps_TupFromTlist = (isDone == ExprMultipleResult );
145
+ return resultSlot ;
146
+ }
147
+ }
148
+ else
149
+ {
150
+ /*
151
+ * Here, we aren't projecting, so just return scan tuple.
152
+ */
153
+ return slot ;
136
154
}
137
155
}
138
156
@@ -142,3 +160,61 @@ ExecScan(ScanState *node,
142
160
ResetExprContext (econtext );
143
161
}
144
162
}
163
+
164
+ /*
165
+ * ExecAssignScanProjectionInfo
166
+ * Set up projection info for a scan node, if necessary.
167
+ *
168
+ * We can avoid a projection step if the requested tlist exactly matches
169
+ * the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
170
+ * Note that this case occurs not only for simple "SELECT * FROM ...", but
171
+ * also in most cases where there are joins or other processing nodes above
172
+ * the scan node, because the planner will preferentially generate a matching
173
+ * tlist.
174
+ *
175
+ * ExecAssignScanType must have been called already.
176
+ */
177
+ void
178
+ ExecAssignScanProjectionInfo (ScanState * node )
179
+ {
180
+ Scan * scan = (Scan * ) node -> ps .plan ;
181
+
182
+ if (tlist_matches_tupdesc (scan -> plan .targetlist ,
183
+ scan -> scanrelid ,
184
+ node -> ss_ScanTupleSlot -> ttc_tupleDescriptor ))
185
+ node -> ps .ps_ProjInfo = NULL ;
186
+ else
187
+ ExecAssignProjectionInfo (& node -> ps );
188
+ }
189
+
190
+ static bool
191
+ tlist_matches_tupdesc (List * tlist , Index varno , TupleDesc tupdesc )
192
+ {
193
+ int numattrs = tupdesc -> natts ;
194
+ int attrno ;
195
+
196
+ for (attrno = 1 ; attrno <= numattrs ; attrno ++ )
197
+ {
198
+ Form_pg_attribute att_tup = tupdesc -> attrs [attrno - 1 ];
199
+ Var * var ;
200
+
201
+ if (tlist == NIL )
202
+ return false; /* tlist too short */
203
+ var = (Var * ) ((TargetEntry * ) lfirst (tlist ))-> expr ;
204
+ if (!var || !IsA (var , Var ))
205
+ return false; /* tlist item not a Var */
206
+ Assert (var -> varno == varno );
207
+ if (var -> varattno != attrno )
208
+ return false; /* out of order */
209
+ Assert (var -> vartype == att_tup -> atttypid );
210
+ Assert (var -> vartypmod == att_tup -> atttypmod );
211
+ Assert (var -> varlevelsup == 0 );
212
+
213
+ tlist = lnext (tlist );
214
+ }
215
+
216
+ if (tlist )
217
+ return false; /* tlist too long */
218
+
219
+ return true;
220
+ }
0 commit comments