OSDN Git Service

Fix rtree and contrib/rtree_gist search behavior for the 1-D box and
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 24 Jun 2005 00:18:52 +0000 (00:18 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 24 Jun 2005 00:18:52 +0000 (00:18 +0000)
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.

contrib/rtree_gist/rtree_gist.c
src/backend/access/common/indexvalid.c
src/backend/access/rtree/rtscan.c
src/backend/access/rtree/rtstrat.c
src/include/access/rtree.h
src/include/access/skey.h

index 55a4809..f4ce584 100644 (file)
@@ -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:
index 2dcea77..29ee54c 100644 (file)
@@ -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--;
index f6656a2..3f9f81b 100644 (file)
@@ -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);
                }
index d5f59fe..c7104c9 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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];
+}
index 14a13f4..744f116 100644 (file)
@@ -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 */
index a160f7b..61a8e81 100644 (file)
@@ -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 */
 
 
 /*