summaryrefslogtreecommitdiff
path: root/src/backend/access/gin
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gin')
-rw-r--r--src/backend/access/gin/ginarrayproc.c41
-rw-r--r--src/backend/access/gin/ginget.c67
2 files changed, 76 insertions, 32 deletions
diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c
index c453cda525..c85399d632 100644
--- a/src/backend/access/gin/ginarrayproc.c
+++ b/src/backend/access/gin/ginarrayproc.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.12 2008/01/01 19:45:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.13 2008/04/14 17:05:33 tgl Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -95,8 +95,9 @@ ginarrayconsistent(PG_FUNCTION_ARGS)
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
- int res,
- i,
+ bool *recheck = (bool *) PG_GETARG_POINTER(3);
+ bool res;
+ int i,
nentries;
/* ARRAYCHECK was already done by previous ginarrayextract call */
@@ -104,25 +105,51 @@ ginarrayconsistent(PG_FUNCTION_ARGS)
switch (strategy)
{
case GinOverlapStrategy:
+ /* result is not lossy */
+ *recheck = false;
+ /* at least one element in check[] is true, so result = true */
+ res = true;
+ break;
case GinContainedStrategy:
+ /* we will need recheck */
+ *recheck = true;
/* at least one element in check[] is true, so result = true */
- res = TRUE;
+ res = true;
break;
case GinContainsStrategy:
+ /* result is not lossy */
+ *recheck = false;
+ /* must have all elements in check[] true */
+ nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
+ res = true;
+ for (i = 0; i < nentries; i++)
+ {
+ if (!check[i])
+ {
+ res = false;
+ break;
+ }
+ }
+ break;
case GinEqualStrategy:
+ /* we will need recheck */
+ *recheck = true;
+ /* must have all elements in check[] true */
nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
- res = TRUE;
+ res = true;
for (i = 0; i < nentries; i++)
+ {
if (!check[i])
{
- res = FALSE;
+ res = false;
break;
}
+ }
break;
default:
elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
strategy);
- res = FALSE;
+ res = false;
}
PG_RETURN_BOOL(res);
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index af38717340..26abaa76af 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.12 2008/04/13 19:18:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.13 2008/04/14 17:05:33 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -343,10 +343,12 @@ entryGetItem(Relation index, GinScanEntry entry)
/*
* Sets key->curItem to new found heap item pointer for one scan key
- * returns isFinished!
+ * Returns isFinished, ie TRUE means we did NOT get a new item pointer!
+ * Also, *keyrecheck is set true if recheck is needed for this scan key.
*/
static bool
-keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
+keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
+ GinScanKey key, bool *keyrecheck)
{
uint32 i;
GinScanEntry entry;
@@ -391,31 +393,36 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey
return TRUE;
}
- if (key->nentries == 1)
- {
- /* we can do not call consistentFn !! */
- key->entryRes[0] = TRUE;
- return FALSE;
- }
+ /*
+ * if key->nentries == 1 then the consistentFn should always succeed,
+ * but we must call it anyway to find out the recheck status.
+ */
/* setting up array for consistentFn */
for (i = 0; i < key->nentries; i++)
{
entry = key->scanEntry + i;
- if (entry->isFinished == FALSE && compareItemPointers(&entry->curItem, &key->curItem) == 0)
+ if (entry->isFinished == FALSE &&
+ compareItemPointers(&entry->curItem, &key->curItem) == 0)
key->entryRes[i] = TRUE;
else
key->entryRes[i] = FALSE;
}
+ /*
+ * Initialize *keyrecheck in case the consistentFn doesn't know it
+ * should set it. The safe assumption in that case is to force
+ * recheck.
+ */
+ *keyrecheck = true;
+
oldCtx = MemoryContextSwitchTo(tempCtx);
- res = DatumGetBool(FunctionCall3(
- &ginstate->consistentFn,
+ res = DatumGetBool(FunctionCall4(&ginstate->consistentFn,
PointerGetDatum(key->entryRes),
UInt16GetDatum(key->strategy),
- key->query
- ));
+ key->query,
+ PointerGetDatum(keyrecheck)));
MemoryContextSwitchTo(oldCtx);
MemoryContextReset(tempCtx);
} while (!res);
@@ -430,24 +437,32 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey
static bool
scanGetItem(IndexScanDesc scan, ItemPointerData *item, bool *recheck)
{
- uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
-
- /* XXX for the moment, treat all GIN operators as lossy */
- *recheck = true;
+ uint32 i;
+ bool keyrecheck;
+
+ /*
+ * We return recheck = true if any of the keyGetItem calls return
+ * keyrecheck = true. Note that because the second loop might advance
+ * some keys, this could theoretically be too conservative. In practice
+ * though, we expect that a consistentFn's recheck result will depend
+ * only on the operator and the query, so for any one key it should
+ * stay the same regardless of advancing to new items. So it's not
+ * worth working harder.
+ */
+ *recheck = false;
ItemPointerSetMin(item);
for (i = 0; i < so->nkeys; i++)
{
GinScanKey key = so->keys + i;
- if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == FALSE)
- {
- if (compareItemPointers(item, &key->curItem) < 0)
- *item = key->curItem;
- }
- else
+ if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx,
+ key, &keyrecheck))
return FALSE; /* finished one of keys */
+ if (compareItemPointers(item, &key->curItem) < 0)
+ *item = key->curItem;
+ *recheck |= keyrecheck;
}
for (i = 1; i <= so->nkeys; i++)
@@ -462,8 +477,10 @@ scanGetItem(IndexScanDesc scan, ItemPointerData *item, bool *recheck)
break;
else if (cmp > 0)
{
- if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
+ if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx,
+ key, &keyrecheck))
return FALSE; /* finished one of keys */
+ *recheck |= keyrecheck;
}
else
{ /* returns to begin */