mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
GIN: Generalized Inverted iNdex.
text[], int4[], Tsearch2 support for GIN.
This commit is contained in:
203
src/backend/access/gin/ginutil.c
Normal file
203
src/backend/access/gin/ginutil.c
Normal file
@ -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;
|
||||
}
|
Reference in New Issue
Block a user