/*------------------------------------------------------------------------- * * gistscan.c * routines to manage scans on GiST index relations * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.70 2008/06/19 00:46:03 alvherre Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" #include "access/gist_private.h" #include "access/gistscan.h" #include "access/relscan.h" #include "storage/bufmgr.h" #include "utils/memutils.h" static void gistfreestack(GISTSearchStack *s); Datum gistbeginscan(PG_FUNCTION_ARGS) { Relation r = (Relation) PG_GETARG_POINTER(0); int nkeys = PG_GETARG_INT32(1); ScanKey key = (ScanKey) PG_GETARG_POINTER(2); IndexScanDesc scan; scan = RelationGetIndexScan(r, nkeys, key); PG_RETURN_POINTER(scan); } Datum gistrescan(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ScanKey key = (ScanKey) PG_GETARG_POINTER(1); GISTScanOpaque so; int i; so = (GISTScanOpaque) scan->opaque; if (so != NULL) { /* rescan an existing indexscan --- reset state */ gistfreestack(so->stack); gistfreestack(so->markstk); so->stack = so->markstk = NULL; so->flags = 0x0; /* drop pins on buffers -- no locks held */ if (BufferIsValid(so->curbuf)) { ReleaseBuffer(so->curbuf); so->curbuf = InvalidBuffer; } if (BufferIsValid(so->markbuf)) { ReleaseBuffer(so->markbuf); so->markbuf = InvalidBuffer; } } else { /* initialize opaque data */ so = (GISTScanOpaque) palloc(sizeof(GISTScanOpaqueData)); so->stack = so->markstk = NULL; so->flags = 0x0; so->tempCxt = createTempGistContext(); so->curbuf = so->markbuf = InvalidBuffer; so->giststate = (GISTSTATE *) palloc(sizeof(GISTSTATE)); initGISTstate(so->giststate, scan->indexRelation); scan->opaque = so; } /* * Clear all the pointers. */ ItemPointerSetInvalid(&so->curpos); ItemPointerSetInvalid(&so->markpos); /* Update scan key, if a new one is given */ if (key && scan->numberOfKeys > 0) { memmove(scan->keyData, key, scan->numberOfKeys * sizeof(ScanKeyData)); /* * Modify the scan key so that all the Consistent method is called for * all comparisons. The original operator is passed to the Consistent * function in the form of its strategy number, which is available * from the sk_strategy field, and its subtype from the sk_subtype * field. */ for (i = 0; i < scan->numberOfKeys; i++) scan->keyData[i].sk_func = so->giststate->consistentFn[scan->keyData[i].sk_attno - 1]; } PG_RETURN_VOID(); } Datum gistmarkpos(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so; GISTSearchStack *o, *n, *tmp; so = (GISTScanOpaque) scan->opaque; so->markpos = so->curpos; if (so->flags & GS_CURBEFORE) so->flags |= GS_MRKBEFORE; else so->flags &= ~GS_MRKBEFORE; o = NULL; n = so->stack; /* copy the parent stack from the current item data */ while (n != NULL) { tmp = (GISTSearchStack *) palloc(sizeof(GISTSearchStack)); tmp->lsn = n->lsn; tmp->parentlsn = n->parentlsn; tmp->block = n->block; tmp->next = o; o = tmp; n = n->next; } gistfreestack(so->markstk); so->markstk = o; /* Update markbuf: make sure to bump ref count on curbuf */ if (BufferIsValid(so->markbuf)) { ReleaseBuffer(so->markbuf); so->markbuf = InvalidBuffer; } if (BufferIsValid(so->curbuf)) { IncrBufferRefCount(so->curbuf); so->markbuf = so->curbuf; } PG_RETURN_VOID(); } Datum gistrestrpos(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so; GISTSearchStack *o, *n, *tmp; so = (GISTScanOpaque) scan->opaque; so->curpos = so->markpos; if (so->flags & GS_MRKBEFORE) so->flags |= GS_CURBEFORE; else so->flags &= ~GS_CURBEFORE; o = NULL; n = so->markstk; /* copy the parent stack from the current item data */ while (n != NULL) { tmp = (GISTSearchStack *) palloc(sizeof(GISTSearchStack)); tmp->lsn = n->lsn; tmp->parentlsn = n->parentlsn; tmp->block = n->block; tmp->next = o; o = tmp; n = n->next; } gistfreestack(so->stack); so->stack = o; /* Update curbuf: be sure to bump ref count on markbuf */ if (BufferIsValid(so->curbuf)) { ReleaseBuffer(so->curbuf); so->curbuf = InvalidBuffer; } if (BufferIsValid(so->markbuf)) { IncrBufferRefCount(so->markbuf); so->curbuf = so->markbuf; } PG_RETURN_VOID(); } Datum gistendscan(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GISTScanOpaque so; so = (GISTScanOpaque) scan->opaque; if (so != NULL) { gistfreestack(so->stack); gistfreestack(so->markstk); if (so->giststate != NULL) freeGISTstate(so->giststate); /* drop pins on buffers -- we aren't holding any locks */ if (BufferIsValid(so->curbuf)) ReleaseBuffer(so->curbuf); if (BufferIsValid(so->markbuf)) ReleaseBuffer(so->markbuf); MemoryContextDelete(so->tempCxt); pfree(scan->opaque); } PG_RETURN_VOID(); } static void gistfreestack(GISTSearchStack *s) { while (s != NULL) { GISTSearchStack *p = s->next; pfree(s); s = p; } }