/*------------------------------------------------------------------------- * * ginscan.c * routines to manage scans inverted index relations * * * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.2 2006/05/02 15:48:11 tgl Exp $ *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" #include "access/gin.h" #include "access/heapam.h" #include "catalog/index.h" #include "miscadmin.h" #include "storage/freespace.h" #include "utils/memutils.h" Datum ginbeginscan(PG_FUNCTION_ARGS) { Relation rel = (Relation) PG_GETARG_POINTER(0); int keysz = PG_GETARG_INT32(1); ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2); IndexScanDesc scan; scan = RelationGetIndexScan(rel, keysz, scankey); PG_RETURN_POINTER(scan); } static void fillScanKey( GinState *ginstate, GinScanKey key, Datum query, Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy ) { uint32 i,j; key->nentries = nEntryValues; key->entryRes = (bool*)palloc0( sizeof(bool) * nEntryValues ); key->scanEntry = (GinScanEntry) palloc( sizeof(GinScanEntryData) * nEntryValues ); key->strategy = strategy; key->query = query; key->firstCall= TRUE; ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber ); for(i=0; iscanEntry[i].pval = key->entryRes + i; key->scanEntry[i].entry = entryValues[i]; ItemPointerSet( &(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber ); key->scanEntry[i].offset = InvalidOffsetNumber; key->scanEntry[i].buffer = InvalidBuffer; key->scanEntry[i].list = NULL; key->scanEntry[i].nlist = 0; /* link to the equals entry in current scan key */ key->scanEntry[i].master = NULL; for( j=0; jscanEntry[i].master = key->scanEntry + j; break; } } } #ifdef NOT_USED static void resetScanKeys(GinScanKey keys, uint32 nkeys) { uint32 i, j; if ( keys == NULL ) return; for(i=0;ifirstCall = TRUE; ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber ); for(j=0;jnentries;j++) { if ( key->scanEntry[j].buffer != InvalidBuffer ) ReleaseBuffer( key->scanEntry[i].buffer ); ItemPointerSet( &(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber ); key->scanEntry[j].offset = InvalidOffsetNumber; key->scanEntry[j].buffer = InvalidBuffer; key->scanEntry[j].list = NULL; key->scanEntry[j].nlist = 0; } } } #endif static void freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) { uint32 i, j; if ( keys == NULL ) return; for(i=0;inentries;j++) { if ( key->scanEntry[j].buffer != InvalidBuffer ) ReleaseBuffer( key->scanEntry[j].buffer ); if ( removeRes && key->scanEntry[j].list ) pfree(key->scanEntry[j].list); } if ( removeRes ) pfree(key->entryRes); pfree(key->scanEntry); } pfree(keys); } void newScanKey( IndexScanDesc scan ) { ScanKey scankey = scan->keyData; GinScanOpaque so = (GinScanOpaque) scan->opaque; int i; uint32 nkeys = 0; so->keys = (GinScanKey) palloc( scan->numberOfKeys * sizeof(GinScanKeyData) ); for(i=0; inumberOfKeys; i++) { Datum* entryValues; uint32 nEntryValues; if ( scankey[i].sk_flags & SK_ISNULL ) elog(ERROR, "Gin doesn't support NULL as scan key"); Assert( scankey[i].sk_attno == 1 ); entryValues = (Datum*)DatumGetPointer( FunctionCall3( &so->ginstate.extractQueryFn, scankey[i].sk_argument, PointerGetDatum( &nEntryValues ), UInt16GetDatum(scankey[i].sk_strategy) ) ); if ( entryValues==NULL || nEntryValues == 0 ) /* full scan... */ continue; fillScanKey( &so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument, entryValues, nEntryValues, scankey[i].sk_strategy ); nkeys++; } so->nkeys = nkeys; if ( so->nkeys == 0 ) elog(ERROR, "Gin doesn't support full scan due to it's awful inefficiency"); } Datum ginrescan(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); GinScanOpaque so; so = (GinScanOpaque) scan->opaque; if ( so == NULL ) { /* if called from ginbeginscan */ so = (GinScanOpaque)palloc( sizeof(GinScanOpaqueData) ); so->tempCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin scan temporary context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); initGinState(&so->ginstate, scan->indexRelation); scan->opaque = so; } else { freeScanKeys(so->keys, so->nkeys, TRUE); freeScanKeys(so->markPos, so->nkeys, FALSE); } so->markPos=so->keys=NULL; if ( scankey && scan->numberOfKeys > 0 ) { memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } PG_RETURN_VOID(); } Datum ginendscan(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GinScanOpaque so = (GinScanOpaque) scan->opaque; if ( so != NULL ) { freeScanKeys(so->keys, so->nkeys, TRUE); freeScanKeys(so->markPos, so->nkeys, FALSE); MemoryContextDelete(so->tempCtx); pfree(so); } PG_RETURN_VOID(); } static GinScanKey copyScanKeys( GinScanKey keys, uint32 nkeys ) { GinScanKey newkeys; uint32 i, j; newkeys = (GinScanKey)palloc( sizeof(GinScanKeyData) * nkeys ); memcpy( newkeys, keys, sizeof(GinScanKeyData) * nkeys ); for(i=0;iopaque; freeScanKeys(so->markPos, so->nkeys, FALSE); so->markPos = copyScanKeys( so->keys, so->nkeys ); PG_RETURN_VOID(); } Datum ginrestrpos(PG_FUNCTION_ARGS) { IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GinScanOpaque so = (GinScanOpaque) scan->opaque; freeScanKeys(so->keys, so->nkeys, FALSE); so->keys = copyScanKeys( so->markPos, so->nkeys ); PG_RETURN_VOID(); }