mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
to be just a minor extension of the previous patch that made "x IS NULL" indexable, because we can treat the IS NOT NULL condition as if it were "x < NULL" or "x > NULL" (depending on the index's NULLS FIRST/LAST option), just like IS NULL is treated like "x = NULL". Aside from any possible usefulness in its own right, this is an important improvement for index-optimized MAX/MIN aggregates: it is now reliably possible to get a column's min or max value cheaply, even when there are a lot of nulls cluttering the interesting end of the index.
163 lines
3.7 KiB
C
163 lines
3.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* gistscan.c
|
|
* routines to manage scans on GiST index relations
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.77 2010/01/01 21:53:49 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/genam.h"
|
|
#include "access/gist_private.h"
|
|
#include "access/gistscan.h"
|
|
#include "access/relscan.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "utils/memutils.h"
|
|
|
|
static void gistfreestack(GISTSearchStack *s);
|
|
|
|
Datum
|
|
gistbeginscan(PG_FUNCTION_ARGS)
|
|
{
|
|
Relation r = (Relation) PG_GETARG_POINTER(0);
|
|
int nkeys = PG_GETARG_INT32(1);
|
|
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
|
IndexScanDesc scan;
|
|
|
|
scan = RelationGetIndexScan(r, nkeys, key);
|
|
|
|
PG_RETURN_POINTER(scan);
|
|
}
|
|
|
|
Datum
|
|
gistrescan(PG_FUNCTION_ARGS)
|
|
{
|
|
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
|
ScanKey key = (ScanKey) PG_GETARG_POINTER(1);
|
|
GISTScanOpaque so;
|
|
int i;
|
|
|
|
so = (GISTScanOpaque) scan->opaque;
|
|
if (so != NULL)
|
|
{
|
|
/* rescan an existing indexscan --- reset state */
|
|
gistfreestack(so->stack);
|
|
so->stack = NULL;
|
|
/* drop pins on buffers -- no locks held */
|
|
if (BufferIsValid(so->curbuf))
|
|
{
|
|
ReleaseBuffer(so->curbuf);
|
|
so->curbuf = InvalidBuffer;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* initialize opaque data */
|
|
so = (GISTScanOpaque) palloc(sizeof(GISTScanOpaqueData));
|
|
so->stack = NULL;
|
|
so->tempCxt = createTempGistContext();
|
|
so->curbuf = InvalidBuffer;
|
|
so->giststate = (GISTSTATE *) palloc(sizeof(GISTSTATE));
|
|
initGISTstate(so->giststate, scan->indexRelation);
|
|
|
|
scan->opaque = so;
|
|
}
|
|
|
|
/*
|
|
* Clear all the pointers.
|
|
*/
|
|
ItemPointerSetInvalid(&so->curpos);
|
|
so->nPageData = so->curPageData = 0;
|
|
|
|
so->qual_ok = true;
|
|
|
|
/* Update scan key, if a new one is given */
|
|
if (key && scan->numberOfKeys > 0)
|
|
{
|
|
memmove(scan->keyData, key,
|
|
scan->numberOfKeys * sizeof(ScanKeyData));
|
|
|
|
/*
|
|
* Modify the scan key so that all the Consistent method is called for
|
|
* all comparisons. The original operator is passed to the Consistent
|
|
* function in the form of its strategy number, which is available
|
|
* from the sk_strategy field, and its subtype from the sk_subtype
|
|
* field.
|
|
*
|
|
* Next, if any of keys is a NULL and that key is not marked with
|
|
* SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie,
|
|
* we assume all indexable operators are strict).
|
|
*/
|
|
for (i = 0; i < scan->numberOfKeys; i++)
|
|
{
|
|
ScanKey skey = &(scan->keyData[i]);
|
|
|
|
skey->sk_func = so->giststate->consistentFn[skey->sk_attno - 1];
|
|
|
|
if (skey->sk_flags & SK_ISNULL)
|
|
{
|
|
if (!(skey->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL)))
|
|
so->qual_ok = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
PG_RETURN_VOID();
|
|
}
|
|
|
|
Datum
|
|
gistmarkpos(PG_FUNCTION_ARGS)
|
|
{
|
|
elog(ERROR, "GiST does not support mark/restore");
|
|
PG_RETURN_VOID();
|
|
}
|
|
|
|
Datum
|
|
gistrestrpos(PG_FUNCTION_ARGS)
|
|
{
|
|
elog(ERROR, "GiST does not support mark/restore");
|
|
PG_RETURN_VOID();
|
|
}
|
|
|
|
Datum
|
|
gistendscan(PG_FUNCTION_ARGS)
|
|
{
|
|
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
|
GISTScanOpaque so;
|
|
|
|
so = (GISTScanOpaque) scan->opaque;
|
|
|
|
if (so != NULL)
|
|
{
|
|
gistfreestack(so->stack);
|
|
if (so->giststate != NULL)
|
|
freeGISTstate(so->giststate);
|
|
/* drop pins on buffers -- we aren't holding any locks */
|
|
if (BufferIsValid(so->curbuf))
|
|
ReleaseBuffer(so->curbuf);
|
|
MemoryContextDelete(so->tempCxt);
|
|
pfree(scan->opaque);
|
|
}
|
|
|
|
PG_RETURN_VOID();
|
|
}
|
|
|
|
static void
|
|
gistfreestack(GISTSearchStack *s)
|
|
{
|
|
while (s != NULL)
|
|
{
|
|
GISTSearchStack *p = s->next;
|
|
|
|
pfree(s);
|
|
s = p;
|
|
}
|
|
}
|