1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

R-tree is dead ... long live GiST.

This commit is contained in:
Tom Lane
2005-11-07 17:36:47 +00:00
parent 645adf5de8
commit 2a8d3d83ef
46 changed files with 213 additions and 2954 deletions

View File

@@ -1,14 +1,14 @@
#
# Makefile for the access methods module
#
# $PostgreSQL: pgsql/src/backend/access/Makefile,v 1.9 2003/11/29 19:51:39 pgsql Exp $
# $PostgreSQL: pgsql/src/backend/access/Makefile,v 1.10 2005/11/07 17:36:44 tgl Exp $
#
subdir = src/backend/access
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
SUBDIRS := common gist hash heap index nbtree rtree transam
SUBDIRS := common gist hash heap index nbtree transam
SUBDIROBJS := $(SUBDIRS:%=%/SUBSYS.o)
all: SUBSYS.o

View File

@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.3 2005/10/15 02:49:08 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.4 2005/11/07 17:36:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@
#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"
#include "access/skey.h"
#include "utils/geo_decls.h"
@@ -40,6 +40,47 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
* Box ops
**************************************************/
static Datum
rt_box_union(PG_FUNCTION_ARGS)
{
BOX *a = PG_GETARG_BOX_P(0);
BOX *b = PG_GETARG_BOX_P(1);
BOX *n;
n = (BOX *) palloc(sizeof(BOX));
n->high.x = Max(a->high.x, b->high.x);
n->high.y = Max(a->high.y, b->high.y);
n->low.x = Min(a->low.x, b->low.x);
n->low.y = Min(a->low.y, b->low.y);
PG_RETURN_BOX_P(n);
}
static Datum
rt_box_inter(PG_FUNCTION_ARGS)
{
BOX *a = PG_GETARG_BOX_P(0);
BOX *b = PG_GETARG_BOX_P(1);
BOX *n;
n = (BOX *) palloc(sizeof(BOX));
n->high.x = Min(a->high.x, b->high.x);
n->high.y = Min(a->high.y, b->high.y);
n->low.x = Max(a->low.x, b->low.x);
n->low.y = Max(a->low.y, b->low.y);
if (n->high.x < n->low.x || n->high.y < n->low.y)
{
pfree(n);
/* Indicate "no intersection" by returning NULL pointer */
n = NULL;
}
PG_RETURN_BOX_P(n);
}
/*
* The GiST Consistent method for boxes
*
@@ -493,8 +534,6 @@ size_box(Datum dbox)
*
* We can use the same function since all types use bounding boxes as the
* internal-page representation.
*
* This implements the same logic as the rtree internal-page strategy map.
*/
static bool
rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)

View File

@@ -1,31 +0,0 @@
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for access/rtree
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/access/rtree/Makefile,v 1.11 2003/11/29 19:51:40 pgsql Exp $
#
#-------------------------------------------------------------------------
subdir = src/backend/access/rtree
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = rtget.o rtproc.o rtree.o rtscan.o rtstrat.o
all: SUBSYS.o
SUBSYS.o: $(OBJS)
$(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
depend dep:
$(CC) -MM $(CFLAGS) *.c >depend
clean:
rm -f SUBSYS.o $(OBJS)
ifeq (depend,$(wildcard depend))
include depend
endif

View File

@@ -1,281 +0,0 @@
/*-------------------------------------------------------------------------
*
* rtget.c
* fetch tuples from an rtree scan.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtget.c,v 1.37 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/iqual.h"
#include "access/relscan.h"
#include "access/rtree.h"
#include "pgstat.h"
static OffsetNumber findnext(IndexScanDesc s, OffsetNumber n,
ScanDirection dir);
static bool rtnext(IndexScanDesc s, ScanDirection dir);
Datum
rtgettuple(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
RTreeScanOpaque so = (RTreeScanOpaque) s->opaque;
Page page;
OffsetNumber offnum;
/*
* If we've already produced a tuple and the executor has informed us that
* it should be marked "killed", do so now.
*/
if (s->kill_prior_tuple && ItemPointerIsValid(&(s->currentItemData)))
{
offnum = ItemPointerGetOffsetNumber(&(s->currentItemData));
page = BufferGetPage(so->curbuf);
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
SetBufferCommitInfoNeedsSave(so->curbuf);
}
/*
* Get the next tuple that matches the search key; if asked to skip killed
* tuples, find the first non-killed tuple that matches. Return as soon as
* we've run out of matches or we've found an acceptable match.
*/
for (;;)
{
bool res = rtnext(s, dir);
if (res && s->ignore_killed_tuples)
{
offnum = ItemPointerGetOffsetNumber(&(s->currentItemData));
page = BufferGetPage(so->curbuf);
if (ItemIdDeleted(PageGetItemId(page, offnum)))
continue;
}
PG_RETURN_BOOL(res);
}
}
Datum
rtgetmulti(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
RTreeScanOpaque so = (RTreeScanOpaque) s->opaque;
bool res = true;
int32 ntids = 0;
/* XXX generic implementation: loop around guts of rtgettuple */
while (ntids < max_tids)
{
res = rtnext(s, ForwardScanDirection);
if (res && s->ignore_killed_tuples)
{
Page page;
OffsetNumber offnum;
offnum = ItemPointerGetOffsetNumber(&(s->currentItemData));
page = BufferGetPage(so->curbuf);
if (ItemIdDeleted(PageGetItemId(page, offnum)))
continue;
}
if (!res)
break;
tids[ntids] = s->xs_ctup.t_self;
ntids++;
}
*returned_tids = ntids;
PG_RETURN_BOOL(res);
}
static bool
rtnext(IndexScanDesc s, ScanDirection dir)
{
Page p;
OffsetNumber n;
RTreePageOpaque po;
RTreeScanOpaque so;
so = (RTreeScanOpaque) s->opaque;
if (!ItemPointerIsValid(&(s->currentItemData)))
{
/* first call: start at the root */
Assert(BufferIsValid(so->curbuf) == false);
so->curbuf = ReadBuffer(s->indexRelation, P_ROOT);
pgstat_count_index_scan(&s->xs_pgstat_info);
}
p = BufferGetPage(so->curbuf);
po = (RTreePageOpaque) PageGetSpecialPointer(p);
if (!ItemPointerIsValid(&(s->currentItemData)))
{
/* first call: start at first/last offset */
if (ScanDirectionIsForward(dir))
n = FirstOffsetNumber;
else
n = PageGetMaxOffsetNumber(p);
}
else
{
/* go on to the next offset */
n = ItemPointerGetOffsetNumber(&(s->currentItemData));
if (ScanDirectionIsForward(dir))
n = OffsetNumberNext(n);
else
n = OffsetNumberPrev(n);
}
for (;;)
{
IndexTuple it;
RTSTACK *stk;
n = findnext(s, n, dir);
/* no match on this page, so read in the next stack entry */
if (n == InvalidOffsetNumber)
{
/* if out of stack entries, we're done */
if (so->s_stack == NULL)
{
ReleaseBuffer(so->curbuf);
so->curbuf = InvalidBuffer;
return false;
}
stk = so->s_stack;
so->curbuf = ReleaseAndReadBuffer(so->curbuf, s->indexRelation,
stk->rts_blk);
p = BufferGetPage(so->curbuf);
po = (RTreePageOpaque) PageGetSpecialPointer(p);
if (ScanDirectionIsBackward(dir))
n = OffsetNumberPrev(stk->rts_child);
else
n = OffsetNumberNext(stk->rts_child);
so->s_stack = stk->rts_parent;
pfree(stk);
continue;
}
if (po->flags & F_LEAF)
{
ItemPointerSet(&(s->currentItemData),
BufferGetBlockNumber(so->curbuf),
n);
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
s->xs_ctup.t_self = it->t_tid;
return true;
}
else
{
BlockNumber blk;
stk = (RTSTACK *) palloc(sizeof(RTSTACK));
stk->rts_child = n;
stk->rts_blk = BufferGetBlockNumber(so->curbuf);
stk->rts_parent = so->s_stack;
so->s_stack = stk;
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
blk = ItemPointerGetBlockNumber(&(it->t_tid));
/*
* Note that we release the pin on the page as we descend down the
* tree, even though there's a good chance we'll eventually need
* to re-read the buffer later in this scan. This may or may not
* be optimal, but it doesn't seem likely to make a huge
* performance difference either way.
*/
so->curbuf = ReleaseAndReadBuffer(so->curbuf, s->indexRelation, blk);
p = BufferGetPage(so->curbuf);
po = (RTreePageOpaque) PageGetSpecialPointer(p);
if (ScanDirectionIsBackward(dir))
n = PageGetMaxOffsetNumber(p);
else
n = FirstOffsetNumber;
}
}
}
/*
* Return the offset of the next matching index entry. We begin the
* search at offset "n" and search for matches in the direction
* "dir". If no more matching entries are found on the page,
* InvalidOffsetNumber is returned.
*/
static OffsetNumber
findnext(IndexScanDesc s, OffsetNumber n, ScanDirection dir)
{
OffsetNumber maxoff;
IndexTuple it;
RTreePageOpaque po;
RTreeScanOpaque so;
Page p;
so = (RTreeScanOpaque) s->opaque;
p = BufferGetPage(so->curbuf);
maxoff = PageGetMaxOffsetNumber(p);
po = (RTreePageOpaque) PageGetSpecialPointer(p);
/*
* If we modified the index during the scan, we may have a pointer to a
* ghost tuple, before the scan. If this is the case, back up one.
*/
if (so->s_flags & RTS_CURBEFORE)
{
so->s_flags &= ~RTS_CURBEFORE;
n = OffsetNumberPrev(n);
}
while (n >= FirstOffsetNumber && n <= maxoff)
{
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
if (po->flags & F_LEAF)
{
if (index_keytest(it,
RelationGetDescr(s->indexRelation),
s->numberOfKeys, s->keyData))
break;
}
else
{
if (index_keytest(it,
RelationGetDescr(s->indexRelation),
so->s_internalNKey, so->s_internalKey))
break;
}
if (ScanDirectionIsBackward(dir))
n = OffsetNumberPrev(n);
else
n = OffsetNumberNext(n);
}
if (n >= FirstOffsetNumber && n <= maxoff)
return n; /* found a match on this page */
else
return InvalidOffsetNumber; /* no match, go to next page */
}

View File

@@ -1,175 +0,0 @@
/*-------------------------------------------------------------------------
*
* rtproc.c
* pg_amproc entries for rtrees.
*
* NOTE: for largely-historical reasons, the intersection functions should
* return a NULL pointer (*not* an SQL null value) to indicate "no
* intersection". The size functions must be prepared to accept such
* a pointer and return 0. This convention means that only pass-by-reference
* data types can be used as the output of the union and intersection
* routines, but that's not a big problem.
*
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtproc.c,v 1.43 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/geo_decls.h"
Datum
rt_box_union(PG_FUNCTION_ARGS)
{
BOX *a = PG_GETARG_BOX_P(0);
BOX *b = PG_GETARG_BOX_P(1);
BOX *n;
n = (BOX *) palloc(sizeof(BOX));
n->high.x = Max(a->high.x, b->high.x);
n->high.y = Max(a->high.y, b->high.y);
n->low.x = Min(a->low.x, b->low.x);
n->low.y = Min(a->low.y, b->low.y);
PG_RETURN_BOX_P(n);
}
Datum
rt_box_inter(PG_FUNCTION_ARGS)
{
BOX *a = PG_GETARG_BOX_P(0);
BOX *b = PG_GETARG_BOX_P(1);
BOX *n;
n = (BOX *) palloc(sizeof(BOX));
n->high.x = Min(a->high.x, b->high.x);
n->high.y = Min(a->high.y, b->high.y);
n->low.x = Max(a->low.x, b->low.x);
n->low.y = Max(a->low.y, b->low.y);
if (n->high.x < n->low.x || n->high.y < n->low.y)
{
pfree(n);
/* Indicate "no intersection" by returning NULL pointer */
n = NULL;
}
PG_RETURN_BOX_P(n);
}
Datum
rt_box_size(PG_FUNCTION_ARGS)
{
BOX *a = PG_GETARG_BOX_P(0);
/* NB: size is an output argument */
float *size = (float *) PG_GETARG_POINTER(1);
if (a == NULL || a->high.x <= a->low.x || a->high.y <= a->low.y)
*size = 0.0;
else
*size = (float) ((a->high.x - a->low.x) * (a->high.y - a->low.y));
PG_RETURN_VOID();
}
Datum
rt_poly_union(PG_FUNCTION_ARGS)
{
POLYGON *a = PG_GETARG_POLYGON_P(0);
POLYGON *b = PG_GETARG_POLYGON_P(1);
POLYGON *p;
p = (POLYGON *) palloc0(sizeof(POLYGON)); /* zero any holes */
p->size = sizeof(POLYGON);
p->npts = 0;
p->boundbox.high.x = Max(a->boundbox.high.x, b->boundbox.high.x);
p->boundbox.high.y = Max(a->boundbox.high.y, b->boundbox.high.y);
p->boundbox.low.x = Min(a->boundbox.low.x, b->boundbox.low.x);
p->boundbox.low.y = Min(a->boundbox.low.y, b->boundbox.low.y);
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
PG_RETURN_POLYGON_P(p);
}
Datum
rt_poly_inter(PG_FUNCTION_ARGS)
{
POLYGON *a = PG_GETARG_POLYGON_P(0);
POLYGON *b = PG_GETARG_POLYGON_P(1);
POLYGON *p;
p = (POLYGON *) palloc0(sizeof(POLYGON)); /* zero any holes */
p->size = sizeof(POLYGON);
p->npts = 0;
p->boundbox.high.x = Min(a->boundbox.high.x, b->boundbox.high.x);
p->boundbox.high.y = Min(a->boundbox.high.y, b->boundbox.high.y);
p->boundbox.low.x = Max(a->boundbox.low.x, b->boundbox.low.x);
p->boundbox.low.y = Max(a->boundbox.low.y, b->boundbox.low.y);
if (p->boundbox.high.x < p->boundbox.low.x ||
p->boundbox.high.y < p->boundbox.low.y)
{
pfree(p);
/* Indicate "no intersection" by returning NULL pointer */
p = NULL;
}
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
PG_RETURN_POLYGON_P(p);
}
Datum
rt_poly_size(PG_FUNCTION_ARGS)
{
Pointer aptr = PG_GETARG_POINTER(0);
/* NB: size is an output argument */
float *size = (float *) PG_GETARG_POINTER(1);
POLYGON *a;
double xdim,
ydim;
/*
* Can't just use GETARG because of possibility that input is NULL; since
* POLYGON is toastable, GETARG will try to inspect its value
*/
if (aptr == NULL)
{
*size = 0.0;
PG_RETURN_VOID();
}
/* Now safe to apply GETARG */
a = PG_GETARG_POLYGON_P(0);
if (a->boundbox.high.x <= a->boundbox.low.x ||
a->boundbox.high.y <= a->boundbox.low.y)
*size = 0.0;
else
{
xdim = (a->boundbox.high.x - a->boundbox.low.x);
ydim = (a->boundbox.high.y - a->boundbox.low.y);
*size = (float) (xdim * ydim);
}
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(a, 0);
PG_RETURN_VOID();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,493 +0,0 @@
/*-------------------------------------------------------------------------
*
* rtscan.c
* routines to manage scans on index relations
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.60 2005/10/15 02:49:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/rtree.h"
#include "utils/lsyscache.h"
#include "utils/resowner.h"
/* routines defined and used here */
static void rtregscan(IndexScanDesc s);
static void rtdropscan(IndexScanDesc s);
static void rtadjone(IndexScanDesc s, int op, BlockNumber blkno,
OffsetNumber offnum);
static void adjuststack(RTSTACK *stk, BlockNumber blkno);
static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
int op, BlockNumber blkno, OffsetNumber offnum);
/*
* Whenever we start an rtree scan in a backend, we register it in private
* space. Then if the rtree index gets updated, we check all registered
* scans and adjust them if the tuple they point at got moved by the
* update. We only need to do this in private space, because when we update
* an rtree we have a write lock on the tree, so no other process can have
* any locks at all on it. A single transaction can have write and read
* locks on the same object, so that's why we need to handle this case.
*/
typedef struct RTScanListData
{
IndexScanDesc rtsl_scan;
ResourceOwner rtsl_owner;
struct RTScanListData *rtsl_next;
} RTScanListData;
typedef RTScanListData *RTScanList;
/* pointer to list of local scans on rtrees */
static RTScanList RTScans = NULL;
Datum
rtbeginscan(PG_FUNCTION_ARGS)
{
Relation r = (Relation) PG_GETARG_POINTER(0);
int nkeys = PG_GETARG_INT32(1);
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
IndexScanDesc s;
s = RelationGetIndexScan(r, nkeys, key);
rtregscan(s);
PG_RETURN_POINTER(s);
}
Datum
rtrescan(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanKey key = (ScanKey) PG_GETARG_POINTER(1);
RTreeScanOpaque p;
int i;
/*
* Clear all the pointers.
*/
ItemPointerSetInvalid(&s->currentItemData);
ItemPointerSetInvalid(&s->currentMarkData);
p = (RTreeScanOpaque) s->opaque;
if (p != NULL)
{
/* rescan an existing indexscan --- reset state */
freestack(p->s_stack);
freestack(p->s_markstk);
p->s_stack = p->s_markstk = NULL;
p->s_flags = 0x0;
/* drop pins on buffers -- no locks held */
if (BufferIsValid(p->curbuf))
{
ReleaseBuffer(p->curbuf);
p->curbuf = InvalidBuffer;
}
if (BufferIsValid(p->markbuf))
{
ReleaseBuffer(p->markbuf);
p->markbuf = InvalidBuffer;
}
}
else
{
/* initialize opaque data */
p = (RTreeScanOpaque) palloc(sizeof(RTreeScanOpaqueData));
p->s_stack = p->s_markstk = NULL;
p->curbuf = p->markbuf = InvalidBuffer;
p->s_internalNKey = s->numberOfKeys;
p->s_flags = 0x0;
s->opaque = p;
if (s->numberOfKeys > 0)
p->s_internalKey = (ScanKey) palloc(sizeof(ScanKeyData) * s->numberOfKeys);
}
/* Update scan key, if a new one is given */
if (key && s->numberOfKeys > 0)
{
memmove(s->keyData,
key,
s->numberOfKeys * sizeof(ScanKeyData));
/*
* Scans on internal pages use different operators than they do on
* leaf pages. For example, if the user wants all boxes that exactly
* match (x1,y1,x2,y2), then on internal pages we need to find all
* boxes that contain (x1,y1,x2,y2). rtstrat.c knows how to pick the
* opclass member to use for internal pages. In some cases we need to
* negate the result of the opclass member.
*/
for (i = 0; i < s->numberOfKeys; i++)
{
AttrNumber attno = s->keyData[i].sk_attno;
Oid opclass;
Oid subtype;
StrategyNumber orig_strategy;
StrategyNumber int_strategy;
Oid int_oper;
RegProcedure int_proc;
int int_flags;
opclass = s->indexRelation->rd_indclass->values[attno - 1];
subtype = s->keyData[i].sk_subtype;
orig_strategy = s->keyData[i].sk_strategy;
int_strategy = RTMapToInternalOperator(orig_strategy);
int_oper = get_opclass_member(opclass, subtype, int_strategy);
Assert(OidIsValid(int_oper));
int_proc = get_opcode(int_oper);
int_flags = s->keyData[i].sk_flags;
if (RTMapToInternalNegate(orig_strategy))
int_flags |= SK_NEGATE;
ScanKeyEntryInitialize(&(p->s_internalKey[i]),
int_flags,
attno,
int_strategy,
subtype,
int_proc,
s->keyData[i].sk_argument);
}
}
PG_RETURN_VOID();
}
Datum
rtmarkpos(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
RTreeScanOpaque p;
RTSTACK *o,
*n,
*tmp;
s->currentMarkData = s->currentItemData;
p = (RTreeScanOpaque) s->opaque;
if (p->s_flags & RTS_CURBEFORE)
p->s_flags |= RTS_MRKBEFORE;
else
p->s_flags &= ~RTS_MRKBEFORE;
o = NULL;
n = p->s_stack;
/* copy the parent stack from the current item data */
while (n != NULL)
{
tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
tmp->rts_child = n->rts_child;
tmp->rts_blk = n->rts_blk;
tmp->rts_parent = o;
o = tmp;
n = n->rts_parent;
}
freestack(p->s_markstk);
p->s_markstk = o;
/* Update markbuf: make sure to bump ref count on curbuf */
if (BufferIsValid(p->markbuf))
{
ReleaseBuffer(p->markbuf);
p->markbuf = InvalidBuffer;
}
if (BufferIsValid(p->curbuf))
{
IncrBufferRefCount(p->curbuf);
p->markbuf = p->curbuf;
}
PG_RETURN_VOID();
}
Datum
rtrestrpos(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
RTreeScanOpaque p;
RTSTACK *o,
*n,
*tmp;
s->currentItemData = s->currentMarkData;
p = (RTreeScanOpaque) s->opaque;
if (p->s_flags & RTS_MRKBEFORE)
p->s_flags |= RTS_CURBEFORE;
else
p->s_flags &= ~RTS_CURBEFORE;
o = NULL;
n = p->s_markstk;
/* copy the parent stack from the current item data */
while (n != NULL)
{
tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
tmp->rts_child = n->rts_child;
tmp->rts_blk = n->rts_blk;
tmp->rts_parent = o;
o = tmp;
n = n->rts_parent;
}
freestack(p->s_stack);
p->s_stack = o;
/* Update curbuf; be sure to bump ref count on markbuf */
if (BufferIsValid(p->curbuf))
{
ReleaseBuffer(p->curbuf);
p->curbuf = InvalidBuffer;
}
if (BufferIsValid(p->markbuf))
{
IncrBufferRefCount(p->markbuf);
p->curbuf = p->markbuf;
}
PG_RETURN_VOID();
}
Datum
rtendscan(PG_FUNCTION_ARGS)
{
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
RTreeScanOpaque p;
p = (RTreeScanOpaque) s->opaque;
if (p != NULL)
{
freestack(p->s_stack);
freestack(p->s_markstk);
if (BufferIsValid(p->curbuf))
ReleaseBuffer(p->curbuf);
if (BufferIsValid(p->markbuf))
ReleaseBuffer(p->markbuf);
pfree(s->opaque);
}
rtdropscan(s);
PG_RETURN_VOID();
}
static void
rtregscan(IndexScanDesc s)
{
RTScanList l;
l = (RTScanList) palloc(sizeof(RTScanListData));
l->rtsl_scan = s;
l->rtsl_owner = CurrentResourceOwner;
l->rtsl_next = RTScans;
RTScans = l;
}
static void
rtdropscan(IndexScanDesc s)
{
RTScanList l;
RTScanList prev;
prev = NULL;
for (l = RTScans;
l != NULL && l->rtsl_scan != s;
l = l->rtsl_next)
prev = l;
if (l == NULL)
elog(ERROR, "rtree scan list corrupted -- could not find 0x%p",
(void *) s);
if (prev == NULL)
RTScans = l->rtsl_next;
else
prev->rtsl_next = l->rtsl_next;
pfree(l);
}
/*
* ReleaseResources_rtree() --- clean up rtree subsystem resources.
*
* This is here because it needs to touch this module's static var RTScans.
*/
void
ReleaseResources_rtree(void)
{
RTScanList l;
RTScanList prev;
RTScanList next;
/*
* Note: this should be a no-op during normal query shutdown. However, in
* an abort situation ExecutorEnd is not called and so there may be open
* index scans to clean up.
*/
prev = NULL;
for (l = RTScans; l != NULL; l = next)
{
next = l->rtsl_next;
if (l->rtsl_owner == CurrentResourceOwner)
{
if (prev == NULL)
RTScans = next;
else
prev->rtsl_next = next;
pfree(l);
/* prev does not change */
}
else
prev = l;
}
}
void
rtadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum)
{
RTScanList l;
Oid relid;
relid = RelationGetRelid(r);
for (l = RTScans; l != NULL; l = l->rtsl_next)
{
if (RelationGetRelid(l->rtsl_scan->indexRelation) == relid)
rtadjone(l->rtsl_scan, op, blkno, offnum);
}
}
/*
* rtadjone() -- adjust one scan for update.
*
* By here, the scan passed in is on a modified relation. Op tells
* us what the modification is, and blkno and offind tell us what
* block and offset index were affected. This routine checks the
* current and marked positions, and the current and marked stacks,
* to see if any stored location needs to be changed because of the
* update. If so, we make the change here.
*/
static void
rtadjone(IndexScanDesc s,
int op,
BlockNumber blkno,
OffsetNumber offnum)
{
RTreeScanOpaque so;
adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
so = (RTreeScanOpaque) s->opaque;
if (op == RTOP_SPLIT)
{
adjuststack(so->s_stack, blkno);
adjuststack(so->s_markstk, blkno);
}
}
/*
* adjustiptr() -- adjust current and marked item pointers in the scan
*
* Depending on the type of update and the place it happened, we
* need to do nothing, to back up one record, or to start over on
* the same page.
*/
static void
adjustiptr(IndexScanDesc s,
ItemPointer iptr,
int op,
BlockNumber blkno,
OffsetNumber offnum)
{
OffsetNumber curoff;
RTreeScanOpaque so;
if (ItemPointerIsValid(iptr))
{
if (ItemPointerGetBlockNumber(iptr) == blkno)
{
curoff = ItemPointerGetOffsetNumber(iptr);
so = (RTreeScanOpaque) s->opaque;
switch (op)
{
case RTOP_DEL:
/* back up one if we need to */
if (curoff >= offnum)
{
if (curoff > FirstOffsetNumber)
{
/* just adjust the item pointer */
ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
}
else
{
/*
* remember that we're before the current tuple
*/
ItemPointerSet(iptr, blkno, FirstOffsetNumber);
if (iptr == &(s->currentItemData))
so->s_flags |= RTS_CURBEFORE;
else
so->s_flags |= RTS_MRKBEFORE;
}
}
break;
case RTOP_SPLIT:
/* back to start of page on split */
ItemPointerSet(iptr, blkno, FirstOffsetNumber);
if (iptr == &(s->currentItemData))
so->s_flags &= ~RTS_CURBEFORE;
else
so->s_flags &= ~RTS_MRKBEFORE;
break;
default:
elog(ERROR, "unrecognized operation in rtree scan adjust: %d", op);
}
}
}
}
/*
* adjuststack() -- adjust the supplied stack for a split on a page in
* the index we're scanning.
*
* If a page on our parent stack has split, we need to back up to the
* beginning of the page and rescan it. The reason for this is that
* the split algorithm for rtrees doesn't order tuples in any useful
* way on a single page. This means on that a split, we may wind up
* looking at some heap tuples more than once. This is handled in the
* access method update code for heaps; if we've modified the tuple we
* are looking at already in this transaction, we ignore the update
* request.
*/
static void
adjuststack(RTSTACK *stk, BlockNumber blkno)
{
while (stk != NULL)
{
if (stk->rts_blk == blkno)
stk->rts_child = FirstOffsetNumber;
stk = stk->rts_parent;
}
}

View File

@@ -1,79 +0,0 @@
/*-------------------------------------------------------------------------
*
* rtstrat.c
* strategy map data for rtrees.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/rtree/rtstrat.c,v 1.27 2005/06/24 20:53:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/rtree.h"
/*
* Here's something peculiar to rtrees that doesn't apply to most other
* indexing structures: When we're searching a tree for a given value, we
* can't do the same sorts of comparisons on internal node entries as we
* do at leaves. The reason is that if we're looking for (say) all boxes
* that are the same as (0,0,10,10), then we need to find all leaf pages
* that overlap that region. So internally we search for overlap, and at
* the leaf we search for equality.
*
* This array maps leaf search operators to the internal search operators.
*/
static const StrategyNumber RTOperMap[RTNStrategies] = {
RTOverRightStrategyNumber, /* left */
RTRightStrategyNumber, /* overleft */
RTOverlapStrategyNumber, /* overlap */
RTLeftStrategyNumber, /* overright */
RTOverLeftStrategyNumber, /* right */
RTContainsStrategyNumber, /* same */
RTContainsStrategyNumber, /* contains */
RTOverlapStrategyNumber, /* contained-by */
RTAboveStrategyNumber, /* overbelow */
RTOverAboveStrategyNumber, /* below */
RTOverBelowStrategyNumber, /* above */
RTBelowStrategyNumber /* overabove */
};
/*
* We may need to negate the result of the selected operator. (This could
* be avoided by expanding the set of operators required for an opclass.)
*/
static const bool RTNegateMap[RTNStrategies] = {
true, /* left */
true, /* overleft */
false, /* overlap */
true, /* overright */
true, /* right */
false, /* same */
false, /* contains */
false, /* contained-by */
true, /* overbelow */
true, /* below */
true, /* above */
true /* overabove */
};
StrategyNumber
RTMapToInternalOperator(StrategyNumber strat)
{
Assert(strat > 0 && strat <= RTNStrategies);
return RTOperMap[strat - 1];
}
bool
RTMapToInternalNegate(StrategyNumber strat)
{
Assert(strat > 0 && strat <= RTNStrategies);
return RTNegateMap[strat - 1];
}

View File

@@ -3,7 +3,7 @@
*
* Resource managers definition
*
* $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.20 2005/06/14 11:45:14 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.21 2005/11/07 17:36:45 tgl Exp $
*/
#include "postgres.h"
@@ -13,7 +13,6 @@
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/nbtree.h"
#include "access/rtree.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "commands/dbcommands.h"
@@ -36,7 +35,7 @@ const RmgrData RmgrTable[RM_MAX_ID + 1] = {
{"Heap", heap_redo, heap_desc, NULL, NULL},
{"Btree", btree_redo, btree_desc, btree_xlog_startup, btree_xlog_cleanup},
{"Hash", hash_redo, hash_desc, NULL, NULL},
{"Rtree", rtree_redo, rtree_desc, NULL, NULL},
{"Reserved 13", NULL, NULL, NULL, NULL},
{"Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup},
{"Sequence", seq_redo, seq_desc, NULL, NULL}
};

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.134 2005/10/15 02:49:15 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.135 2005/11/07 17:36:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -226,10 +226,27 @@ DefineIndex(RangeVar *heapRelation,
PointerGetDatum(accessMethodName),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
accessMethodName)));
{
/*
* Hack to provide more-or-less-transparent updating of old RTREE
* indexes to GIST: if RTREE is requested and not found, use GIST.
*/
if (strcmp(accessMethodName, "rtree") == 0)
{
ereport(NOTICE,
(errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
accessMethodName = "gist";
tuple = SearchSysCache(AMNAME,
PointerGetDatum(accessMethodName),
0, 0, 0);
}
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
accessMethodName)));
}
accessMethodId = HeapTupleGetOid(tuple);
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.24 2004/12/31 22:01:22 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.25 2005/11/07 17:36:45 tgl Exp $
*
* XXX These are totally bogus. Perhaps someone will make them do
* something reasonable, someday.
@@ -22,19 +22,19 @@
/*
* Selectivity functions for rtrees. These are bogus -- unless we know
* the actual key distribution in the index, we can't make a good prediction
* of the selectivity of these operators.
* Selectivity functions for geometric operators. These are bogus -- unless
* we know the actual key distribution in the index, we can't make a good
* prediction of the selectivity of these operators.
*
* Note: the values used here may look unreasonably small. Perhaps they
* are. For now, we want to make sure that the optimizer will make use
* of an r-tree index if one is available, so the selectivity had better
* of a geometric index if one is available, so the selectivity had better
* be fairly small.
*
* In general, rtrees need to search multiple subtrees in order to guarantee
* In general, GiST needs to search multiple subtrees in order to guarantee
* that all occurrences of the same key have been found. Because of this,
* the estimated cost for scanning the index ought to be higher than the
* output selectivity would indicate. rtcostestimate(), over in selfuncs.c,
* output selectivity would indicate. gistcostestimate(), over in selfuncs.c,
* ought to be adjusted accordingly --- but until we can generate somewhat
* realistic numbers here, it hardly matters...
*/

View File

@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.191 2005/10/15 02:49:29 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.192 2005/11/07 17:36:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4470,24 +4470,6 @@ btcostestimate(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
Datum
rtcostestimate(PG_FUNCTION_ARGS)
{
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(1);
List *indexQuals = (List *) PG_GETARG_POINTER(2);
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(3);
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(4);
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(5);
double *indexCorrelation = (double *) PG_GETARG_POINTER(6);
genericcostestimate(root, index, indexQuals, 0.0,
indexStartupCost, indexTotalCost,
indexSelectivity, indexCorrelation);
PG_RETURN_VOID();
}
Datum
hashcostestimate(PG_FUNCTION_ARGS)
{

View File

@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.14 2005/10/15 02:49:36 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.15 2005/11/07 17:36:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,7 +23,6 @@
#include "utils/resowner.h"
#include "access/gistscan.h"
#include "access/hash.h"
#include "access/rtree.h"
#include "storage/bufmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
@@ -280,7 +279,6 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
/* Clean up index scans too */
ReleaseResources_gist();
ReleaseResources_hash();
ReleaseResources_rtree();
}
/* Let add-on modules get a chance too */