88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.62 2006/03/05 15:58:20 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.63 2006/04/03 13:44:33 teodor Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2020#include "utils/memutils.h"
2121#include "utils/resowner.h"
2222
23- /* routines defined and used here */
24- static void gistregscan (IndexScanDesc scan );
25- static void gistdropscan (IndexScanDesc scan );
26- static void gistadjone (IndexScanDesc scan ,int op ,BlockNumber blkno ,
27- OffsetNumber offnum ,XLogRecPtr newlsn ,XLogRecPtr oldlsn );
28- static void adjustiptr (IndexScanDesc scan ,ItemPointer iptr ,GISTSearchStack * stk ,
29- int op ,BlockNumber blkno ,OffsetNumber offnum ,XLogRecPtr newlsn ,XLogRecPtr oldlsn );
3023static void gistfreestack (GISTSearchStack * s );
3124
32- /*
33- * Whenever we start a GiST scan in a backend, we register it in
34- * private space. Then if the GiST index gets updated, we check all
35- * registered scans and adjust them if the tuple they point at got
36- * moved by the update. We only need to do this in private space,
37- * because when we update an GiST we have a write lock on the tree, so
38- * no other process can have any locks at all on it. A single
39- * transaction can have write and read locks on the same object, so
40- * that's why we need to handle this case.
41- */
42- typedef struct GISTScanListData
43- {
44- IndexScanDesc gsl_scan ;
45- ResourceOwner gsl_owner ;
46- struct GISTScanListData * gsl_next ;
47- }GISTScanListData ;
48-
49- typedef GISTScanListData * GISTScanList ;
50-
51- /* pointer to list of local scans on GiSTs */
52- static GISTScanList GISTScans = NULL ;
53-
5425Datum
5526gistbeginscan (PG_FUNCTION_ARGS )
5627{
@@ -60,7 +31,6 @@ gistbeginscan(PG_FUNCTION_ARGS)
6031IndexScanDesc scan ;
6132
6233scan = RelationGetIndexScan (r ,nkeys ,key );
63- gistregscan (scan );
6434
6535PG_RETURN_POINTER (scan );
6636}
@@ -254,189 +224,17 @@ gistendscan(PG_FUNCTION_ARGS)
254224pfree (scan -> opaque );
255225}
256226
257-
258- gistdropscan (scan );
259-
260227PG_RETURN_VOID ();
261228}
262229
263- static void
264- gistregscan (IndexScanDesc scan )
265- {
266- GISTScanList l ;
267-
268- l = (GISTScanList )palloc (sizeof (GISTScanListData ));
269- l -> gsl_scan = scan ;
270- l -> gsl_owner = CurrentResourceOwner ;
271- l -> gsl_next = GISTScans ;
272- GISTScans = l ;
273- }
274-
275- static void
276- gistdropscan (IndexScanDesc scan )
277- {
278- GISTScanList l ;
279- GISTScanList prev ;
280-
281- prev = NULL ;
282-
283- for (l = GISTScans ;l != NULL && l -> gsl_scan != scan ;l = l -> gsl_next )
284- prev = l ;
285-
286- if (l == NULL )
287- elog (ERROR ,"GiST scan list corrupted -- could not find 0x%p" ,
288- (void * )scan );
289-
290- if (prev == NULL )
291- GISTScans = l -> gsl_next ;
292- else
293- prev -> gsl_next = l -> gsl_next ;
294-
295- pfree (l );
296- }
297-
298- /*
299- * ReleaseResources_gist() --- clean up gist subsystem resources.
300- *
301- * This is here because it needs to touch this module's static var GISTScans.
302- */
303- void
304- ReleaseResources_gist (void )
305- {
306- GISTScanList l ;
307- GISTScanList prev ;
308- GISTScanList next ;
309-
310- /*
311- * Note: this should be a no-op during normal query shutdown. However, in
312- * an abort situation ExecutorEnd is not called and so there may be open
313- * index scans to clean up.
314- */
315- prev = NULL ;
316-
317- for (l = GISTScans ;l != NULL ;l = next )
318- {
319- next = l -> gsl_next ;
320- if (l -> gsl_owner == CurrentResourceOwner )
321- {
322- if (prev == NULL )
323- GISTScans = next ;
324- else
325- prev -> gsl_next = next ;
326-
327- pfree (l );
328- /* prev does not change */
329- }
330- else
331- prev = l ;
332- }
333- }
334-
335- void
336- gistadjscans (Relation rel ,int op ,BlockNumber blkno ,OffsetNumber offnum ,XLogRecPtr newlsn ,XLogRecPtr oldlsn )
337- {
338- GISTScanList l ;
339- Oid relid ;
340-
341- if (XLogRecPtrIsInvalid (newlsn )|| XLogRecPtrIsInvalid (oldlsn ))
342- return ;
343-
344- relid = RelationGetRelid (rel );
345- for (l = GISTScans ;l != NULL ;l = l -> gsl_next )
346- {
347- if (l -> gsl_scan -> indexRelation -> rd_id == relid )
348- gistadjone (l -> gsl_scan ,op ,blkno ,offnum ,newlsn ,oldlsn );
349- }
350- }
351-
352- /*
353- *gistadjone() -- adjust one scan for update.
354- *
355- *By here, the scan passed in is on a modified relation.Op tells
356- *us what the modification is, and blkno and offind tell us what
357- *block and offset index were affected. This routine checks the
358- *current and marked positions, and the current and marked stacks,
359- *to see if any stored location needs to be changed because of the
360- *update. If so, we make the change here.
361- */
362- static void
363- gistadjone (IndexScanDesc scan ,
364- int op ,
365- BlockNumber blkno ,
366- OffsetNumber offnum ,XLogRecPtr newlsn ,XLogRecPtr oldlsn )
367- {
368- GISTScanOpaque so = (GISTScanOpaque )scan -> opaque ;
369-
370- adjustiptr (scan ,& (scan -> currentItemData ),so -> stack ,op ,blkno ,offnum ,newlsn ,oldlsn );
371- adjustiptr (scan ,& (scan -> currentMarkData ),so -> markstk ,op ,blkno ,offnum ,newlsn ,oldlsn );
372- }
373-
374- /*
375- *adjustiptr() -- adjust current and marked item pointers in the scan
376- *
377- *Depending on the type of update and the place it happened, we
378- *need to do nothing, to back up one record, or to start over on
379- *the same page.
380- */
381- static void
382- adjustiptr (IndexScanDesc scan ,
383- ItemPointer iptr ,GISTSearchStack * stk ,
384- int op ,
385- BlockNumber blkno ,
386- OffsetNumber offnum ,XLogRecPtr newlsn ,XLogRecPtr oldlsn )
387- {
388- OffsetNumber curoff ;
389- GISTScanOpaque so ;
390-
391- if (ItemPointerIsValid (iptr ))
392- {
393- if (ItemPointerGetBlockNumber (iptr )== blkno )
394- {
395- curoff = ItemPointerGetOffsetNumber (iptr );
396- so = (GISTScanOpaque )scan -> opaque ;
397-
398- switch (op )
399- {
400- case GISTOP_DEL :
401- /* back up one if we need to */
402- if (curoff >=offnum && XLByteEQ (stk -> lsn ,oldlsn ))/* the same vesrion of
403- * page */
404- {
405- if (curoff > FirstOffsetNumber )
406- {
407- /* just adjust the item pointer */
408- ItemPointerSet (iptr ,blkno ,OffsetNumberPrev (curoff ));
409- }
410- else
411- {
412- /*
413- * remember that we're before the current tuple
414- */
415- ItemPointerSet (iptr ,blkno ,FirstOffsetNumber );
416- if (iptr == & (scan -> currentItemData ))
417- so -> flags |=GS_CURBEFORE ;
418- else
419- so -> flags |=GS_MRKBEFORE ;
420- }
421- stk -> lsn = newlsn ;
422- }
423- break ;
424- default :
425- elog (ERROR ,"unrecognized GiST scan adjust operation: %d" ,
426- op );
427- }
428- }
429- }
430- }
431-
432230static void
433231gistfreestack (GISTSearchStack * s )
434- {
232+ {
435233while (s != NULL )
436234{
437235GISTSearchStack * p = s -> next ;
438-
439236pfree (s );
440237s = p ;
441238}
442239}
240+