summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2005-06-24 00:18:52 +0000
committerTom Lane2005-06-24 00:18:52 +0000
commit9a09248eddf12339677169064c88e4df11e5077f (patch)
treeff29984a029e973b85b2869de2c115399c7c6b07
parentdea41174b205ee592d46c074518b38d97b8b90c2 (diff)
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.
-rw-r--r--contrib/rtree_gist/rtree_gist.c19
-rw-r--r--src/backend/access/common/indexvalid.c14
-rw-r--r--src/backend/access/rtree/rtscan.c25
-rw-r--r--src/backend/access/rtree/rtstrat.c44
-rw-r--r--src/include/access/rtree.h3
-rw-r--r--src/include/access/skey.h3
6 files changed, 75 insertions, 33 deletions
diff --git a/contrib/rtree_gist/rtree_gist.c b/contrib/rtree_gist/rtree_gist.c
index 55a480915fb..f4ce58460fb 100644
--- a/contrib/rtree_gist/rtree_gist.c
+++ b/contrib/rtree_gist/rtree_gist.c
@@ -2,12 +2,12 @@
*
* rtree_gist.c
* 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
- * $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);
/*
- * * 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
*/
if (!(DatumGetPointer(entry->key) != NULL && query))
@@ -509,8 +509,9 @@ gpoly_consistent(PG_FUNCTION_ARGS)
bool result;
/*
- * * if entry is not leaf, use gbox_internal_consistent, * else use
- * gbox_leaf_consistent
+ * Since the operators are marked lossy anyway, we can just use
+ * 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))
PG_RETURN_BOOL(FALSE);
@@ -536,15 +537,19 @@ rtree_internal_consistent(BOX *key,
switch (strategy)
{
case RTLeftStrategyNumber:
+ retval = !DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query)));
+ break;
case RTOverLeftStrategyNumber:
- retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
+ retval = !DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
break;
case RTOverlapStrategyNumber:
retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
break;
case RTOverRightStrategyNumber:
+ retval = !DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query)));
+ break;
case RTRightStrategyNumber:
- retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
+ retval = !DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
break;
case RTSameStrategyNumber:
case RTContainsStrategyNumber:
diff --git a/src/backend/access/common/indexvalid.c b/src/backend/access/common/indexvalid.c
index 2dcea775274..29ee54c3bfe 100644
--- a/src/backend/access/common/indexvalid.c
+++ b/src/backend/access/common/indexvalid.c
@@ -8,7 +8,7 @@
*
*
* 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);
- if (!DatumGetBool(test))
- return false;
+ if (key->sk_flags & SK_NEGATE)
+ {
+ if (DatumGetBool(test))
+ return false;
+ }
+ else
+ {
+ if (!DatumGetBool(test))
+ return false;
+ }
key++;
scanKeySize--;
diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c
index f6656a23b9e..3f9f81befb0 100644
--- a/src/backend/access/rtree/rtscan.c
+++ b/src/backend/access/rtree/rtscan.c
@@ -8,7 +8,7 @@
*
*
* 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
* 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).
+ * 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];
- int_strategy = RTMapToInternalOperator(s->keyData[i].sk_strategy);
- int_oper = get_opclass_member(opclass,
- s->keyData[i].sk_subtype,
- int_strategy);
+ 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]),
- s->keyData[i].sk_flags,
+ int_flags,
attno,
int_strategy,
- s->keyData[i].sk_subtype,
+ subtype,
int_proc,
s->keyData[i].sk_argument);
}
diff --git a/src/backend/access/rtree/rtstrat.c b/src/backend/access/rtree/rtstrat.c
index d5f59fed6e6..c7104c9520c 100644
--- a/src/backend/access/rtree/rtstrat.c
+++ b/src/backend/access/rtree/rtstrat.c
@@ -8,7 +8,7 @@
*
*
* 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.
*
* 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] = {
- RTOverLeftStrategyNumber,
- RTOverLeftStrategyNumber,
- RTOverlapStrategyNumber,
- RTOverRightStrategyNumber,
- RTOverRightStrategyNumber,
- RTContainsStrategyNumber,
- RTContainsStrategyNumber,
- RTOverlapStrategyNumber
+ RTOverRightStrategyNumber, /* left */
+ RTRightStrategyNumber, /* overleft */
+ RTOverlapStrategyNumber, /* overlap */
+ RTLeftStrategyNumber, /* overright */
+ RTOverLeftStrategyNumber, /* right */
+ RTContainsStrategyNumber, /* same */
+ RTContainsStrategyNumber, /* contains */
+ 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);
return RTOperMap[strat - 1];
}
+
+bool
+RTMapToInternalNegate(StrategyNumber strat)
+{
+ Assert(strat > 0 && strat <= RTNStrategies);
+ return RTNegateMap[strat - 1];
+}
diff --git a/src/include/access/rtree.h b/src/include/access/rtree.h
index 14a13f4b3a4..744f116fe37 100644
--- a/src/include/access/rtree.h
+++ b/src/include/access/rtree.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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 */
extern StrategyNumber RTMapToInternalOperator(StrategyNumber strat);
+extern bool RTMapToInternalNegate(StrategyNumber strat);
#endif /* RTREE_H */
diff --git a/src/include/access/skey.h b/src/include/access/skey.h
index a160f7b39eb..61a8e81a835 100644
--- a/src/include/access/skey.h
+++ b/src/include/access/skey.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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 */
#define SK_ISNULL 0x0001 /* sk_argument is NULL */
#define SK_UNARY 0x0002 /* unary operator (currently unsupported) */
+#define SK_NEGATE 0x0004 /* must negate the function result */
/*