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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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...
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user