diff options
author | Teodor Sigaev <teodor@sigaev.ru> | 2006-05-02 11:28:56 +0000 |
---|---|---|
committer | Teodor Sigaev <teodor@sigaev.ru> | 2006-05-02 11:28:56 +0000 |
commit | 8a3631f8d86cdd9b07c577d6e213b1fc824db255 (patch) | |
tree | 40bcee8383d3552cba8f79e50025613fb683a72e /src/backend/access/gin/ginutil.c | |
parent | 427c6b5b984928972e955f4477c6ba64edbb66cc (diff) | |
download | postgresql-8a3631f8d86cdd9b07c577d6e213b1fc824db255.tar.gz postgresql-8a3631f8d86cdd9b07c577d6e213b1fc824db255.zip |
GIN: Generalized Inverted iNdex.
text[], int4[], Tsearch2 support for GIN.
Diffstat (limited to 'src/backend/access/gin/ginutil.c')
-rw-r--r-- | src/backend/access/gin/ginutil.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c new file mode 100644 index 00000000000..b9cb80a6cf1 --- /dev/null +++ b/src/backend/access/gin/ginutil.c @@ -0,0 +1,203 @@ +/*------------------------------------------------------------------------- + * + * ginutil.c + * utilities routines for the postgres inverted index access method. + * + * + * 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/ginutil.c,v 1.1 2006/05/02 11:28:54 teodor 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" + +void +initGinState( GinState *state, Relation index ) { + if ( index->rd_att->natts != 1 ) + elog(ERROR, "numberOfAttributes %d != 1", + index->rd_att->natts); + + state->tupdesc = index->rd_att; + + fmgr_info_copy(&(state->compareFn), + index_getprocinfo(index, 1, GIN_COMPARE_PROC), + CurrentMemoryContext); + fmgr_info_copy(&(state->extractValueFn), + index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC), + CurrentMemoryContext); + fmgr_info_copy(&(state->extractQueryFn), + index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC), + CurrentMemoryContext); + fmgr_info_copy(&(state->consistentFn), + index_getprocinfo(index, 1, GIN_CONSISTENT_PROC), + CurrentMemoryContext); +} + +/* + * Allocate a new page (either by recycling, or by extending the index file) + * The returned buffer is already pinned and exclusive-locked + * Caller is responsible for initializing the page by calling GinInitBuffer + */ + +Buffer +GinNewBuffer(Relation index) { + Buffer buffer; + bool needLock; + + /* First, try to get a page from FSM */ + for(;;) { + BlockNumber blkno = GetFreeIndexPage(&index->rd_node); + if (blkno == InvalidBlockNumber) + break; + + buffer = ReadBuffer(index, blkno); + + /* + * We have to guard against the possibility that someone else already + * recycled this page; the buffer may be locked if so. + */ + if (ConditionalLockBuffer(buffer)) { + Page page = BufferGetPage(buffer); + + if (PageIsNew(page)) + return buffer; /* OK to use, if never initialized */ + + if (GinPageIsDeleted(page)) + return buffer; /* OK to use */ + + LockBuffer(buffer, GIN_UNLOCK); + } + + /* Can't use it, so release buffer and try again */ + ReleaseBuffer(buffer); + } + + /* Must extend the file */ + needLock = !RELATION_IS_LOCAL(index); + if (needLock) + LockRelationForExtension(index, ExclusiveLock); + + buffer = ReadBuffer(index, P_NEW); + LockBuffer(buffer, GIN_EXCLUSIVE); + + if (needLock) + UnlockRelationForExtension(index, ExclusiveLock); + + return buffer; +} + +void +GinInitPage(Page page, uint32 f, Size pageSize) { + GinPageOpaque opaque; + + PageInit(page, pageSize, sizeof(GinPageOpaqueData)); + + opaque = GinPageGetOpaque(page); + memset( opaque, 0, sizeof(GinPageOpaqueData) ); + opaque->flags = f; + opaque->rightlink = InvalidBlockNumber; +} + +void +GinInitBuffer(Buffer b, uint32 f) { + GinInitPage( BufferGetPage(b), f, BufferGetPageSize(b) ); +} + +int +compareEntries(GinState *ginstate, Datum a, Datum b) { + return DatumGetInt32( + FunctionCall2( + &ginstate->compareFn, + a, b + ) + ); +} + +static FmgrInfo* cmpDatumPtr=NULL; +static bool needUnique = FALSE; + +static int +cmpEntries(const void * a, const void * b) { + int res = DatumGetInt32( + FunctionCall2( + cmpDatumPtr, + *(Datum*)a, + *(Datum*)b + ) + ); + + if ( res == 0 ) + needUnique = TRUE; + + return res; +} + +Datum* +extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) { + Datum *entries; + + entries = (Datum*)DatumGetPointer( + FunctionCall2( + &ginstate->extractValueFn, + value, + PointerGetDatum( nentries ) + ) + ); + + if ( entries == NULL ) + *nentries = 0; + + if ( *nentries > 1 ) { + cmpDatumPtr = &ginstate->compareFn; + needUnique = FALSE; + qsort(entries, *nentries, sizeof(Datum), cmpEntries); + } + + return entries; +} + + +Datum* +extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) { + Datum *entries = extractEntriesS(ginstate, value, nentries); + + if ( *nentries>1 && needUnique ) { + Datum *ptr, *res; + + ptr = res = entries; + + while( ptr - entries < *nentries ) { + if ( compareEntries(ginstate, *ptr, *res ) != 0 ) + *(++res) = *ptr++; + else + ptr++; + } + + *nentries = res + 1 - entries; + } + + return entries; +} + +/* + * It's analog of PageGetTempPage(), but copies whole page + */ +Page +GinPageGetCopyPage( Page page ) { + Size pageSize = PageGetPageSize( page ); + Page tmppage; + + tmppage=(Page)palloc( pageSize ); + memcpy( tmppage, page, pageSize ); + + return tmppage; +} |