mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 00:02:04 -04:00
Fix rtree and contrib/rtree_gist search behavior for the 1-D box and
polygon operators (<<, &<, >>, &>). Per ideas originally put forward by andrew@supernews and later rediscovered by moi. This patch just fixes the existing opclasses, and does not add any new behavior as I proposed earlier; that can be sorted out later. In principle this could be back-patched, since it changes only search behavior and not system catalog entries nor rtree index contents. I'm not currently planning to do that, though, since I think it could use more testing.
This commit is contained in:
parent
dea41174b2
commit
9a09248edd
@ -2,12 +2,12 @@
|
|||||||
*
|
*
|
||||||
* rtree_gist.c
|
* rtree_gist.c
|
||||||
* pg_amproc entries for GiSTs over 2-D boxes.
|
* pg_amproc entries for GiSTs over 2-D boxes.
|
||||||
|
*
|
||||||
* This gives R-tree behavior, with Guttman's poly-time split algorithm.
|
* This gives R-tree behavior, with Guttman's poly-time split algorithm.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/contrib/rtree_gist/rtree_gist.c,v 1.12 2005/05/25 21:40:40 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/rtree_gist/rtree_gist.c,v 1.13 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -78,7 +78,7 @@ gbox_consistent(PG_FUNCTION_ARGS)
|
|||||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* * if entry is not leaf, use gbox_internal_consistent, * else use
|
* if entry is not leaf, use rtree_internal_consistent, else use
|
||||||
* gbox_leaf_consistent
|
* gbox_leaf_consistent
|
||||||
*/
|
*/
|
||||||
if (!(DatumGetPointer(entry->key) != NULL && query))
|
if (!(DatumGetPointer(entry->key) != NULL && query))
|
||||||
@ -509,8 +509,9 @@ gpoly_consistent(PG_FUNCTION_ARGS)
|
|||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* * if entry is not leaf, use gbox_internal_consistent, * else use
|
* Since the operators are marked lossy anyway, we can just use
|
||||||
* gbox_leaf_consistent
|
* rtree_internal_consistent even at leaf nodes. (This works
|
||||||
|
* in part because the index entries are bounding Boxes not polygons.)
|
||||||
*/
|
*/
|
||||||
if (!(DatumGetPointer(entry->key) != NULL && query))
|
if (!(DatumGetPointer(entry->key) != NULL && query))
|
||||||
PG_RETURN_BOOL(FALSE);
|
PG_RETURN_BOOL(FALSE);
|
||||||
@ -536,15 +537,19 @@ rtree_internal_consistent(BOX *key,
|
|||||||
switch (strategy)
|
switch (strategy)
|
||||||
{
|
{
|
||||||
case RTLeftStrategyNumber:
|
case RTLeftStrategyNumber:
|
||||||
|
retval = !DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query)));
|
||||||
|
break;
|
||||||
case RTOverLeftStrategyNumber:
|
case RTOverLeftStrategyNumber:
|
||||||
retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
|
retval = !DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
case RTOverlapStrategyNumber:
|
case RTOverlapStrategyNumber:
|
||||||
retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
|
retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
case RTOverRightStrategyNumber:
|
case RTOverRightStrategyNumber:
|
||||||
|
retval = !DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query)));
|
||||||
|
break;
|
||||||
case RTRightStrategyNumber:
|
case RTRightStrategyNumber:
|
||||||
retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
|
retval = !DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
|
||||||
break;
|
break;
|
||||||
case RTSameStrategyNumber:
|
case RTSameStrategyNumber:
|
||||||
case RTContainsStrategyNumber:
|
case RTContainsStrategyNumber:
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/indexvalid.c,v 1.33 2004/12/31 21:59:07 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/indexvalid.c,v 1.34 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -59,8 +59,16 @@ index_keytest(IndexTuple tuple,
|
|||||||
|
|
||||||
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
|
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
|
||||||
|
|
||||||
if (!DatumGetBool(test))
|
if (key->sk_flags & SK_NEGATE)
|
||||||
return false;
|
{
|
||||||
|
if (DatumGetBool(test))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!DatumGetBool(test))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
key++;
|
key++;
|
||||||
scanKeySize--;
|
scanKeySize--;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.58 2005/03/29 00:16:53 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.59 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -125,27 +125,36 @@ rtrescan(PG_FUNCTION_ARGS)
|
|||||||
* Scans on internal pages use different operators than they do on
|
* Scans on internal pages use different operators than they do on
|
||||||
* leaf pages. For example, if the user wants all boxes that
|
* leaf pages. For example, if the user wants all boxes that
|
||||||
* exactly match (x1,y1,x2,y2), then on internal pages we need to
|
* exactly match (x1,y1,x2,y2), then on internal pages we need to
|
||||||
* find all boxes that contain (x1,y1,x2,y2).
|
* 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++)
|
for (i = 0; i < s->numberOfKeys; i++)
|
||||||
{
|
{
|
||||||
AttrNumber attno = s->keyData[i].sk_attno;
|
AttrNumber attno = s->keyData[i].sk_attno;
|
||||||
Oid opclass;
|
Oid opclass;
|
||||||
|
Oid subtype;
|
||||||
|
StrategyNumber orig_strategy;
|
||||||
StrategyNumber int_strategy;
|
StrategyNumber int_strategy;
|
||||||
Oid int_oper;
|
Oid int_oper;
|
||||||
RegProcedure int_proc;
|
RegProcedure int_proc;
|
||||||
|
int int_flags;
|
||||||
|
|
||||||
opclass = s->indexRelation->rd_indclass->values[attno - 1];
|
opclass = s->indexRelation->rd_indclass->values[attno - 1];
|
||||||
int_strategy = RTMapToInternalOperator(s->keyData[i].sk_strategy);
|
subtype = s->keyData[i].sk_subtype;
|
||||||
int_oper = get_opclass_member(opclass,
|
orig_strategy = s->keyData[i].sk_strategy;
|
||||||
s->keyData[i].sk_subtype,
|
int_strategy = RTMapToInternalOperator(orig_strategy);
|
||||||
int_strategy);
|
int_oper = get_opclass_member(opclass, subtype, int_strategy);
|
||||||
|
Assert(OidIsValid(int_oper));
|
||||||
int_proc = get_opcode(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]),
|
ScanKeyEntryInitialize(&(p->s_internalKey[i]),
|
||||||
s->keyData[i].sk_flags,
|
int_flags,
|
||||||
attno,
|
attno,
|
||||||
int_strategy,
|
int_strategy,
|
||||||
s->keyData[i].sk_subtype,
|
subtype,
|
||||||
int_proc,
|
int_proc,
|
||||||
s->keyData[i].sk_argument);
|
s->keyData[i].sk_argument);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/rtree/rtstrat.c,v 1.25 2004/12/31 21:59:26 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/access/rtree/rtstrat.c,v 1.26 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -28,20 +28,31 @@
|
|||||||
* the leaf we search for equality.
|
* the leaf we search for equality.
|
||||||
*
|
*
|
||||||
* This array maps leaf search operators to the internal search operators.
|
* This array maps leaf search operators to the internal search operators.
|
||||||
* We assume the normal ordering on operators:
|
|
||||||
*
|
|
||||||
* left, left-or-overlap, overlap, right-or-overlap, right, same,
|
|
||||||
* contains, contained-by
|
|
||||||
*/
|
*/
|
||||||
static const StrategyNumber RTOperMap[RTNStrategies] = {
|
static const StrategyNumber RTOperMap[RTNStrategies] = {
|
||||||
RTOverLeftStrategyNumber,
|
RTOverRightStrategyNumber, /* left */
|
||||||
RTOverLeftStrategyNumber,
|
RTRightStrategyNumber, /* overleft */
|
||||||
RTOverlapStrategyNumber,
|
RTOverlapStrategyNumber, /* overlap */
|
||||||
RTOverRightStrategyNumber,
|
RTLeftStrategyNumber, /* overright */
|
||||||
RTOverRightStrategyNumber,
|
RTOverLeftStrategyNumber, /* right */
|
||||||
RTContainsStrategyNumber,
|
RTContainsStrategyNumber, /* same */
|
||||||
RTContainsStrategyNumber,
|
RTContainsStrategyNumber, /* contains */
|
||||||
RTOverlapStrategyNumber
|
RTOverlapStrategyNumber /* contained-by */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -51,3 +62,10 @@ RTMapToInternalOperator(StrategyNumber strat)
|
|||||||
Assert(strat > 0 && strat <= RTNStrategies);
|
Assert(strat > 0 && strat <= RTNStrategies);
|
||||||
return RTOperMap[strat - 1];
|
return RTOperMap[strat - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RTMapToInternalNegate(StrategyNumber strat)
|
||||||
|
{
|
||||||
|
Assert(strat > 0 && strat <= RTNStrategies);
|
||||||
|
return RTNegateMap[strat - 1];
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/rtree.h,v 1.39 2005/06/06 17:01:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/access/rtree.h,v 1.40 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -136,5 +136,6 @@ extern void ReleaseResources_rtree(void);
|
|||||||
|
|
||||||
/* rtstrat.c */
|
/* rtstrat.c */
|
||||||
extern StrategyNumber RTMapToInternalOperator(StrategyNumber strat);
|
extern StrategyNumber RTMapToInternalOperator(StrategyNumber strat);
|
||||||
|
extern bool RTMapToInternalNegate(StrategyNumber strat);
|
||||||
|
|
||||||
#endif /* RTREE_H */
|
#endif /* RTREE_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/skey.h,v 1.28 2004/12/31 22:03:21 pgsql Exp $
|
* $PostgreSQL: pgsql/src/include/access/skey.h,v 1.29 2005/06/24 00:18:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -72,6 +72,7 @@ typedef ScanKeyData *ScanKey;
|
|||||||
/* ScanKeyData sk_flags */
|
/* ScanKeyData sk_flags */
|
||||||
#define SK_ISNULL 0x0001 /* sk_argument is NULL */
|
#define SK_ISNULL 0x0001 /* sk_argument is NULL */
|
||||||
#define SK_UNARY 0x0002 /* unary operator (currently unsupported) */
|
#define SK_UNARY 0x0002 /* unary operator (currently unsupported) */
|
||||||
|
#define SK_NEGATE 0x0004 /* must negate the function result */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user