postgresql/src/backend/access/gin/ginscan.c

325 lines
7.9 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* ginscan.c
2006-10-04 02:30:14 +02:00
* routines to manage scans inverted 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/gin/ginscan.c,v 1.14 2008/05/16 16:31:01 tgl Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/gin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "utils/memutils.h"
2006-10-04 02:30:14 +02:00
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
2006-10-04 02:30:14 +02:00
fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, bool *partial_matches, uint32 nEntryValues,
StrategyNumber strategy)
2006-10-04 02:30:14 +02:00
{
uint32 i,
j;
key->nentries = nEntryValues;
2006-10-04 02:30:14 +02:00
key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
key->strategy = strategy;
key->query = query;
2006-10-04 02:30:14 +02:00
key->firstCall = TRUE;
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
2006-10-04 02:30:14 +02:00
for (i = 0; i < nEntryValues; i++)
{
key->scanEntry[i].pval = key->entryRes + i;
key->scanEntry[i].entry = entryValues[i];
2006-10-04 02:30:14 +02:00
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;
key->scanEntry[i].isPartialMatch = ( ginstate->canPartialMatch && partial_matches )
? partial_matches[i] : false;
/* link to the equals entry in current scan key */
key->scanEntry[i].master = NULL;
2006-10-04 02:30:14 +02:00
for (j = 0; j < i; j++)
if (compareEntries(ginstate, entryValues[i], entryValues[j]) == 0)
{
key->scanEntry[i].master = key->scanEntry + j;
break;
}
}
}
2006-05-02 17:48:11 +02:00
#ifdef NOT_USED
static void
2006-10-04 02:30:14 +02:00
resetScanKeys(GinScanKey keys, uint32 nkeys)
{
uint32 i,
j;
2006-10-04 02:30:14 +02:00
if (keys == NULL)
return;
2006-10-04 02:30:14 +02:00
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
key->firstCall = TRUE;
2006-10-04 02:30:14 +02:00
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
2006-10-04 02:30:14 +02:00
for (j = 0; j < key->nentries; j++)
{
if (key->scanEntry[j].buffer != InvalidBuffer)
ReleaseBuffer(key->scanEntry[i].buffer);
2006-10-04 02:30:14 +02:00
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;
key->scanEntry[j].partialMatch = NULL;
key->scanEntry[j].partialMatchResult = NULL;
}
}
}
2006-05-02 17:48:11 +02:00
#endif
static void
2006-10-04 02:30:14 +02:00
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
{
uint32 i,
j;
2006-10-04 02:30:14 +02:00
if (keys == NULL)
return;
2006-10-04 02:30:14 +02:00
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
2006-10-04 02:30:14 +02:00
for (j = 0; j < key->nentries; 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 && key->scanEntry[j].partialMatch)
tbm_free(key->scanEntry[j].partialMatch);
}
2006-10-04 02:30:14 +02:00
if (removeRes)
pfree(key->entryRes);
pfree(key->scanEntry);
}
2006-10-04 02:30:14 +02:00
pfree(keys);
}
void
2006-10-04 02:30:14 +02:00
newScanKey(IndexScanDesc scan)
{
ScanKey scankey = scan->keyData;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
2006-10-04 02:30:14 +02:00
int i;
uint32 nkeys = 0;
2006-10-04 02:30:14 +02:00
so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
if (scan->numberOfKeys < 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2006-10-04 02:30:14 +02:00
errmsg("GIN indexes do not support whole-index scans")));
so->isVoidRes = false;
2006-10-04 02:30:14 +02:00
for (i = 0; i < scan->numberOfKeys; i++)
{
Datum *entryValues;
int32 nEntryValues;
bool *partial_matches = NULL;
2006-10-04 02:30:14 +02:00
Assert(scankey[i].sk_attno == 1);
/* XXX can't we treat nulls by just setting isVoidRes? */
/* This would amount to assuming that all GIN operators are strict */
if (scankey[i].sk_flags & SK_ISNULL)
elog(ERROR, "GIN doesn't support NULL as scan key");
entryValues = (Datum *) DatumGetPointer(FunctionCall4(
2006-10-04 02:30:14 +02:00
&so->ginstate.extractQueryFn,
scankey[i].sk_argument,
PointerGetDatum(&nEntryValues),
UInt16GetDatum(scankey[i].sk_strategy),
PointerGetDatum(&partial_matches)));
2007-11-15 22:14:46 +01:00
if (nEntryValues < 0)
{
/*
2007-11-15 22:14:46 +01:00
* extractQueryFn signals that nothing will be found, so we can
* just set isVoidRes flag...
*/
2007-11-15 22:14:46 +01:00
so->isVoidRes = true;
break;
}
/*
* extractQueryFn signals that everything matches
*/
2006-10-04 02:30:14 +02:00
if (entryValues == NULL || nEntryValues == 0)
/* full scan... */
continue;
2006-10-04 02:30:14 +02:00
fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, partial_matches, nEntryValues, scankey[i].sk_strategy);
nkeys++;
}
so->nkeys = nkeys;
if (so->nkeys == 0 && !so->isVoidRes)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2007-11-15 22:14:46 +01:00
errmsg("GIN index does not support search with void query")));
pgstat_count_index_scan(scan->indexRelation);
}
Datum
2006-10-04 02:30:14 +02:00
ginrescan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
2006-10-04 02:30:14 +02:00
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so;
so = (GinScanOpaque) scan->opaque;
2006-10-04 02:30:14 +02:00
if (so == NULL)
{
/* if called from ginbeginscan */
2006-10-04 02:30:14 +02:00
so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
2006-10-04 02:30:14 +02:00
"Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
initGinState(&so->ginstate, scan->indexRelation);
scan->opaque = so;
2006-10-04 02:30:14 +02:00
}
else
{
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
}
2006-10-04 02:30:14 +02:00
so->markPos = so->keys = NULL;
2006-10-04 02:30:14 +02:00
if (scankey && scan->numberOfKeys > 0)
{
memmove(scan->keyData, scankey,
2006-10-04 02:30:14 +02:00
scan->numberOfKeys * sizeof(ScanKeyData));
}
PG_RETURN_VOID();
}
Datum
2006-10-04 02:30:14 +02:00
ginendscan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
2006-10-04 02:30:14 +02:00
GinScanOpaque so = (GinScanOpaque) scan->opaque;
2006-10-04 02:30:14 +02:00
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, bool restart)
2006-10-04 02:30:14 +02:00
{
GinScanKey newkeys;
2006-10-04 02:30:14 +02:00
uint32 i,
j;
newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
memcpy(newkeys, keys, sizeof(GinScanKeyData) * nkeys);
2006-10-04 02:30:14 +02:00
for (i = 0; i < nkeys; i++)
{
newkeys[i].scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * keys[i].nentries);
memcpy(newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries);
2006-10-04 02:30:14 +02:00
for (j = 0; j < keys[i].nentries; j++)
{
if (keys[i].scanEntry[j].buffer != InvalidBuffer)
IncrBufferRefCount(keys[i].scanEntry[j].buffer);
if (keys[i].scanEntry[j].master)
{
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN;
}
if ( restart )
ginrestartentry( &keys[i].scanEntry[j] );
}
}
return newkeys;
}
2006-10-04 02:30:14 +02:00
Datum
ginmarkpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
2006-10-04 02:30:14 +02:00
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->markPos, so->nkeys, FALSE);
so->markPos = copyScanKeys(so->keys, so->nkeys, FALSE);
PG_RETURN_VOID();
}
2006-10-04 02:30:14 +02:00
Datum
ginrestrpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
2006-10-04 02:30:14 +02:00
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->keys, so->nkeys, FALSE);
so->keys = copyScanKeys(so->markPos, so->nkeys, TRUE);
PG_RETURN_VOID();
}