8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.44 2005/11/25 04:24:48 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.45 2005/11/26 22:14:56 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
24
24
*/
25
25
#include "postgres.h"
26
26
27
+ #include "access/heapam.h"
28
+ #include "catalog/pg_type.h"
27
29
#include "executor/execdebug.h"
28
30
#include "executor/nodeTidscan.h"
29
- #include "access/heapam .h"
31
+ #include "optimizer/clauses .h"
30
32
#include "parser/parsetree.h"
33
+ #include "utils/array.h"
31
34
32
35
36
+ #define IsCTIDVar (node ) \
37
+ ((node) != NULL && \
38
+ IsA((node), Var) && \
39
+ ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
40
+ ((Var *) (node))->varlevelsup == 0)
41
+
33
42
static void TidListCreate (TidScanState * tidstate );
43
+ static int itemptr_comparator (const void * a , const void * b );
34
44
static TupleTableSlot * TidNext (TidScanState * node );
35
45
36
46
37
47
/*
38
48
* Compute the list of TIDs to be visited, by evaluating the expressions
39
49
* for them.
50
+ *
51
+ * (The result is actually an array, not a list.)
40
52
*/
41
53
static void
42
54
TidListCreate (TidScanState * tidstate )
43
55
{
44
- List * evalList = tidstate -> tss_tideval ;
56
+ List * evalList = tidstate -> tss_tidquals ;
45
57
ExprContext * econtext = tidstate -> ss .ps .ps_ExprContext ;
46
58
ItemPointerData * tidList ;
47
- int numTids = 0 ;
59
+ int numAllocTids ;
60
+ int numTids ;
48
61
ListCell * l ;
49
62
63
+ /*
64
+ * We initialize the array with enough slots for the case that all
65
+ * quals are simple OpExprs. If there's any ScalarArrayOpExprs,
66
+ * we may have to enlarge the array.
67
+ */
68
+ numAllocTids = list_length (evalList );
50
69
tidList = (ItemPointerData * )
51
- palloc (list_length (tidstate -> tss_tideval ) * sizeof (ItemPointerData ));
70
+ palloc (numAllocTids * sizeof (ItemPointerData ));
71
+ numTids = 0 ;
52
72
53
73
foreach (l , evalList )
54
74
{
75
+ ExprState * exstate = (ExprState * ) lfirst (l );
76
+ Expr * expr = exstate -> expr ;
55
77
ItemPointer itemptr ;
56
78
bool isNull ;
57
79
58
- itemptr = (ItemPointer )
59
- DatumGetPointer (ExecEvalExprSwitchContext (lfirst (l ),
60
- econtext ,
61
- & isNull ,
62
- NULL ));
63
- if (!isNull && itemptr && ItemPointerIsValid (itemptr ))
80
+ if (is_opclause (expr ))
64
81
{
65
- tidList [numTids ] = * itemptr ;
66
- numTids ++ ;
82
+ FuncExprState * fexstate = (FuncExprState * ) exstate ;
83
+ Node * arg1 ;
84
+ Node * arg2 ;
85
+
86
+ arg1 = get_leftop (expr );
87
+ arg2 = get_rightop (expr );
88
+ if (IsCTIDVar (arg1 ))
89
+ exstate = (ExprState * ) lsecond (fexstate -> args );
90
+ else if (IsCTIDVar (arg2 ))
91
+ exstate = (ExprState * ) linitial (fexstate -> args );
92
+ else
93
+ elog (ERROR , "could not identify CTID variable" );
94
+
95
+ itemptr = (ItemPointer )
96
+ DatumGetPointer (ExecEvalExprSwitchContext (exstate ,
97
+ econtext ,
98
+ & isNull ,
99
+ NULL ));
100
+ if (!isNull && ItemPointerIsValid (itemptr ))
101
+ {
102
+ if (numTids >= numAllocTids )
103
+ {
104
+ numAllocTids *= 2 ;
105
+ tidList = (ItemPointerData * )
106
+ repalloc (tidList ,
107
+ numAllocTids * sizeof (ItemPointerData ));
108
+ }
109
+ tidList [numTids ++ ] = * itemptr ;
110
+ }
67
111
}
112
+ else if (expr && IsA (expr , ScalarArrayOpExpr ))
113
+ {
114
+ ScalarArrayOpExprState * saexstate = (ScalarArrayOpExprState * ) exstate ;
115
+ Datum arraydatum ;
116
+ ArrayType * itemarray ;
117
+ Datum * ipdatums ;
118
+ bool * ipnulls ;
119
+ int ndatums ;
120
+ int i ;
121
+
122
+ exstate = (ExprState * ) lsecond (saexstate -> fxprstate .args );
123
+ arraydatum = ExecEvalExprSwitchContext (exstate ,
124
+ econtext ,
125
+ & isNull ,
126
+ NULL );
127
+ if (isNull )
128
+ continue ;
129
+ itemarray = DatumGetArrayTypeP (arraydatum );
130
+ deconstruct_array (itemarray ,
131
+ TIDOID , SizeOfIptrData , false, 's' ,
132
+ & ipdatums , & ipnulls , & ndatums );
133
+ if (numTids + ndatums > numAllocTids )
134
+ {
135
+ numAllocTids = numTids + ndatums ;
136
+ tidList = (ItemPointerData * )
137
+ repalloc (tidList ,
138
+ numAllocTids * sizeof (ItemPointerData ));
139
+ }
140
+ for (i = 0 ; i < ndatums ; i ++ )
141
+ {
142
+ if (!ipnulls [i ])
143
+ {
144
+ itemptr = (ItemPointer ) DatumGetPointer (ipdatums [i ]);
145
+ if (ItemPointerIsValid (itemptr ))
146
+ tidList [numTids ++ ] = * itemptr ;
147
+ }
148
+ }
149
+ pfree (ipdatums );
150
+ pfree (ipnulls );
151
+ }
152
+ else
153
+ elog (ERROR , "could not identify CTID expression" );
154
+ }
155
+
156
+ /*
157
+ * Sort the array of TIDs into order, and eliminate duplicates.
158
+ * Eliminating duplicates is necessary since we want OR semantics
159
+ * across the list. Sorting makes it easier to detect duplicates,
160
+ * and as a bonus ensures that we will visit the heap in the most
161
+ * efficient way.
162
+ */
163
+ if (numTids > 1 )
164
+ {
165
+ int lastTid ;
166
+ int i ;
167
+
168
+ qsort ((void * ) tidList , numTids , sizeof (ItemPointerData ),
169
+ itemptr_comparator );
170
+ lastTid = 0 ;
171
+ for (i = 1 ; i < numTids ; i ++ )
172
+ {
173
+ if (!ItemPointerEquals (& tidList [lastTid ], & tidList [i ]))
174
+ tidList [++ lastTid ] = tidList [i ];
175
+ }
176
+ numTids = lastTid + 1 ;
68
177
}
69
178
70
179
tidstate -> tss_TidList = tidList ;
71
180
tidstate -> tss_NumTids = numTids ;
72
181
tidstate -> tss_TidPtr = -1 ;
73
182
}
74
183
184
+ /*
185
+ * qsort comparator for ItemPointerData items
186
+ */
187
+ static int
188
+ itemptr_comparator (const void * a , const void * b )
189
+ {
190
+ const ItemPointerData * ipa = (const ItemPointerData * ) a ;
191
+ const ItemPointerData * ipb = (const ItemPointerData * ) b ;
192
+ BlockNumber ba = ItemPointerGetBlockNumber (ipa );
193
+ BlockNumber bb = ItemPointerGetBlockNumber (ipb );
194
+ OffsetNumber oa = ItemPointerGetOffsetNumber (ipa );
195
+ OffsetNumber ob = ItemPointerGetOffsetNumber (ipb );
196
+
197
+ if (ba < bb )
198
+ return -1 ;
199
+ if (ba > bb )
200
+ return 1 ;
201
+ if (oa < ob )
202
+ return -1 ;
203
+ if (oa > ob )
204
+ return 1 ;
205
+ return 0 ;
206
+ }
207
+
75
208
/* ----------------------------------------------------------------
76
209
* TidNext
77
210
*
@@ -94,7 +227,6 @@ TidNext(TidScanState *node)
94
227
ItemPointerData * tidList ;
95
228
int numTids ;
96
229
bool bBackward ;
97
- int tidNumber ;
98
230
99
231
/*
100
232
* extract necessary information from tid scan node
@@ -143,38 +275,35 @@ TidNext(TidScanState *node)
143
275
tuple = & (node -> tss_htup );
144
276
145
277
/*
146
- * ok, now that we have what we need, fetch an tid tuple. if scanning this
147
- * tid succeeded then return the appropriate heap tuple.. else return
148
- * NULL.
278
+ * Initialize or advance scan position, depending on direction.
149
279
*/
150
280
bBackward = ScanDirectionIsBackward (direction );
151
281
if (bBackward )
152
282
{
153
- tidNumber = numTids - node -> tss_TidPtr - 1 ;
154
- if (tidNumber < 0 )
283
+ if (node -> tss_TidPtr < 0 )
155
284
{
156
- tidNumber = 0 ;
285
+ /* initialize for backward scan */
157
286
node -> tss_TidPtr = numTids - 1 ;
158
287
}
288
+ else
289
+ node -> tss_TidPtr -- ;
159
290
}
160
291
else
161
292
{
162
- if (( tidNumber = node -> tss_TidPtr ) < 0 )
293
+ if (node -> tss_TidPtr < 0 )
163
294
{
164
- tidNumber = 0 ;
295
+ /* initialize for forward scan */
165
296
node -> tss_TidPtr = 0 ;
166
297
}
298
+ else
299
+ node -> tss_TidPtr ++ ;
167
300
}
168
- while (tidNumber < numTids )
169
- {
170
- bool slot_is_valid = false;
171
301
302
+ while (node -> tss_TidPtr >= 0 && node -> tss_TidPtr < numTids )
303
+ {
172
304
tuple -> t_self = tidList [node -> tss_TidPtr ];
173
305
if (heap_fetch (heapRelation , snapshot , tuple , & buffer , false, NULL ))
174
306
{
175
- bool prev_matches = false;
176
- int prev_tid ;
177
-
178
307
/*
179
308
* store the scanned tuple in the scan tuple slot of the scan
180
309
* state. Eventually we will only do this and not return a tuple.
@@ -193,31 +322,13 @@ TidNext(TidScanState *node)
193
322
*/
194
323
ReleaseBuffer (buffer );
195
324
196
- /*
197
- * We must check to see if the current tuple would have been
198
- * matched by an earlier tid, so we don't double report it.
199
- */
200
- for (prev_tid = 0 ; prev_tid < node -> tss_TidPtr ;
201
- prev_tid ++ )
202
- {
203
- if (ItemPointerEquals (& tidList [prev_tid ], & tuple -> t_self ))
204
- {
205
- prev_matches = true;
206
- break ;
207
- }
208
- }
209
- if (!prev_matches )
210
- slot_is_valid = true;
211
- else
212
- ExecClearTuple (slot );
325
+ return slot ;
213
326
}
214
- tidNumber ++ ;
327
+ /* Bad TID or failed snapshot qual; try next */
215
328
if (bBackward )
216
329
node -> tss_TidPtr -- ;
217
330
else
218
331
node -> tss_TidPtr ++ ;
219
- if (slot_is_valid )
220
- return slot ;
221
332
}
222
333
223
334
/*
@@ -242,8 +353,7 @@ TidNext(TidScanState *node)
242
353
* Initial States:
243
354
* -- the relation indicated is opened for scanning so that the
244
355
* "cursor" is positioned before the first qualifying tuple.
245
- * -- tidPtr points to the first tid.
246
- * -- state variable ruleFlag = nil.
356
+ * -- tidPtr is -1.
247
357
* ----------------------------------------------------------------
248
358
*/
249
359
TupleTableSlot *
@@ -362,7 +472,6 @@ TidScanState *
362
472
ExecInitTidScan (TidScan * node , EState * estate )
363
473
{
364
474
TidScanState * tidstate ;
365
- List * rangeTable ;
366
475
RangeTblEntry * rtentry ;
367
476
Oid relid ;
368
477
Oid reloid ;
@@ -392,8 +501,8 @@ ExecInitTidScan(TidScan *node, EState *estate)
392
501
ExecInitExpr ((Expr * ) node -> scan .plan .qual ,
393
502
(PlanState * ) tidstate );
394
503
395
- tidstate -> tss_tideval = (List * )
396
- ExecInitExpr ((Expr * ) node -> tideval ,
504
+ tidstate -> tss_tidquals = (List * )
505
+ ExecInitExpr ((Expr * ) node -> tidquals ,
397
506
(PlanState * ) tidstate );
398
507
399
508
#define TIDSCAN_NSLOTS 2
@@ -411,19 +520,13 @@ ExecInitTidScan(TidScan *node, EState *estate)
411
520
tidstate -> tss_NumTids = 0 ;
412
521
tidstate -> tss_TidPtr = -1 ;
413
522
414
- /*
415
- * get the range table and direction information from the execution state
416
- * (these are needed to open the relations).
417
- */
418
- rangeTable = estate -> es_range_table ;
419
-
420
523
/*
421
524
* open the base relation
422
525
*
423
526
* We acquire AccessShareLock for the duration of the scan.
424
527
*/
425
528
relid = node -> scan .scanrelid ;
426
- rtentry = rt_fetch (relid , rangeTable );
529
+ rtentry = rt_fetch (relid , estate -> es_range_table );
427
530
reloid = rtentry -> relid ;
428
531
429
532
currentRelation = heap_open (reloid , AccessShareLock );
0 commit comments