88 *
99 *
1010 * 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 $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2424 */
2525#include "postgres.h"
2626
27+ #include "access/heapam.h"
28+ #include "catalog/pg_type.h"
2729#include "executor/execdebug.h"
2830#include "executor/nodeTidscan.h"
29- #include "access/heapam .h"
31+ #include "optimizer/clauses .h"
3032#include "parser/parsetree.h"
33+ #include "utils/array.h"
3134
3235
36+ #define IsCTIDVar (node ) \
37+ ((node) != NULL && \
38+ IsA((node), Var) && \
39+ ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
40+ ((Var *) (node))->varlevelsup == 0)
41+
3342static void TidListCreate (TidScanState * tidstate );
43+ static int itemptr_comparator (const void * a ,const void * b );
3444static TupleTableSlot * TidNext (TidScanState * node );
3545
3646
3747/*
3848 * Compute the list of TIDs to be visited, by evaluating the expressions
3949 * for them.
50+ *
51+ * (The result is actually an array, not a list.)
4052 */
4153static void
4254TidListCreate (TidScanState * tidstate )
4355{
44- List * evalList = tidstate -> tss_tideval ;
56+ List * evalList = tidstate -> tss_tidquals ;
4557ExprContext * econtext = tidstate -> ss .ps .ps_ExprContext ;
4658ItemPointerData * tidList ;
47- int numTids = 0 ;
59+ int numAllocTids ;
60+ int numTids ;
4861ListCell * l ;
4962
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 );
5069tidList = (ItemPointerData * )
51- palloc (list_length (tidstate -> tss_tideval )* sizeof (ItemPointerData ));
70+ palloc (numAllocTids * sizeof (ItemPointerData ));
71+ numTids = 0 ;
5272
5373foreach (l ,evalList )
5474{
75+ ExprState * exstate = (ExprState * )lfirst (l );
76+ Expr * expr = exstate -> expr ;
5577ItemPointer itemptr ;
5678bool isNull ;
5779
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 ))
6481{
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+ }
67111}
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 ;
68177}
69178
70179tidstate -> tss_TidList = tidList ;
71180tidstate -> tss_NumTids = numTids ;
72181tidstate -> tss_TidPtr = -1 ;
73182}
74183
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+
75208/* ----------------------------------------------------------------
76209 *TidNext
77210 *
@@ -94,7 +227,6 @@ TidNext(TidScanState *node)
94227ItemPointerData * tidList ;
95228int numTids ;
96229bool bBackward ;
97- int tidNumber ;
98230
99231/*
100232 * extract necessary information from tid scan node
@@ -143,38 +275,35 @@ TidNext(TidScanState *node)
143275tuple = & (node -> tss_htup );
144276
145277/*
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.
149279 */
150280bBackward = ScanDirectionIsBackward (direction );
151281if (bBackward )
152282{
153- tidNumber = numTids - node -> tss_TidPtr - 1 ;
154- if (tidNumber < 0 )
283+ if (node -> tss_TidPtr < 0 )
155284{
156- tidNumber = 0 ;
285+ /* initialize for backward scan */
157286node -> tss_TidPtr = numTids - 1 ;
158287}
288+ else
289+ node -> tss_TidPtr -- ;
159290}
160291else
161292{
162- if (( tidNumber = node -> tss_TidPtr ) < 0 )
293+ if (node -> tss_TidPtr < 0 )
163294{
164- tidNumber = 0 ;
295+ /* initialize for forward scan */
165296node -> tss_TidPtr = 0 ;
166297}
298+ else
299+ node -> tss_TidPtr ++ ;
167300}
168- while (tidNumber < numTids )
169- {
170- bool slot_is_valid = false;
171301
302+ while (node -> tss_TidPtr >=0 && node -> tss_TidPtr < numTids )
303+ {
172304tuple -> t_self = tidList [node -> tss_TidPtr ];
173305if (heap_fetch (heapRelation ,snapshot ,tuple ,& buffer , false,NULL ))
174306{
175- bool prev_matches = false;
176- int prev_tid ;
177-
178307/*
179308 * store the scanned tuple in the scan tuple slot of the scan
180309 * state. Eventually we will only do this and not return a tuple.
@@ -193,31 +322,13 @@ TidNext(TidScanState *node)
193322 */
194323ReleaseBuffer (buffer );
195324
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 ;
213326}
214- tidNumber ++ ;
327+ /* Bad TID or failed snapshot qual; try next */
215328if (bBackward )
216329node -> tss_TidPtr -- ;
217330else
218331node -> tss_TidPtr ++ ;
219- if (slot_is_valid )
220- return slot ;
221332}
222333
223334/*
@@ -242,8 +353,7 @@ TidNext(TidScanState *node)
242353 *Initial States:
243354 * -- the relation indicated is opened for scanning so that the
244355 * "cursor" is positioned before the first qualifying tuple.
245- * -- tidPtr points to the first tid.
246- * -- state variable ruleFlag = nil.
356+ * -- tidPtr is -1.
247357 * ----------------------------------------------------------------
248358 */
249359TupleTableSlot *
@@ -362,7 +472,6 @@ TidScanState *
362472ExecInitTidScan (TidScan * node ,EState * estate )
363473{
364474TidScanState * tidstate ;
365- List * rangeTable ;
366475RangeTblEntry * rtentry ;
367476Oid relid ;
368477Oid reloid ;
@@ -392,8 +501,8 @@ ExecInitTidScan(TidScan *node, EState *estate)
392501ExecInitExpr ((Expr * )node -> scan .plan .qual ,
393502 (PlanState * )tidstate );
394503
395- tidstate -> tss_tideval = (List * )
396- ExecInitExpr ((Expr * )node -> tideval ,
504+ tidstate -> tss_tidquals = (List * )
505+ ExecInitExpr ((Expr * )node -> tidquals ,
397506 (PlanState * )tidstate );
398507
399508#define TIDSCAN_NSLOTS 2
@@ -411,19 +520,13 @@ ExecInitTidScan(TidScan *node, EState *estate)
411520tidstate -> tss_NumTids = 0 ;
412521tidstate -> tss_TidPtr = -1 ;
413522
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-
420523/*
421524 * open the base relation
422525 *
423526 * We acquire AccessShareLock for the duration of the scan.
424527 */
425528relid = node -> scan .scanrelid ;
426- rtentry = rt_fetch (relid ,rangeTable );
529+ rtentry = rt_fetch (relid ,estate -> es_range_table );
427530reloid = rtentry -> relid ;
428531
429532currentRelation = heap_open (reloid ,AccessShareLock );