aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginutil.c
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2006-05-02 11:28:56 +0000
committerTeodor Sigaev <teodor@sigaev.ru>2006-05-02 11:28:56 +0000
commit8a3631f8d86cdd9b07c577d6e213b1fc824db255 (patch)
tree40bcee8383d3552cba8f79e50025613fb683a72e /src/backend/access/gin/ginutil.c
parent427c6b5b984928972e955f4477c6ba64edbb66cc (diff)
downloadpostgresql-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.c203
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;
+}