Fix rtree and contrib/rtree_gist search behavior for the 1-D box and
authorTom Lane
Fri, 24 Jun 2005 00:18:52 +0000 (00:18 +0000)
committerTom Lane
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 55a480915fbd0fb03487843da027826684888183..f4ce58460fbeee1fec02d0f324f4d23ecf5dbb4d 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 2dcea775274a9005f8522ed0ffe38ecccdb42df1..29ee54c3bfea1f3d81304866b7cca3819fd68fdc 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 f6656a23b9ec8cb3d3ca885d818e7ff7879f5b15..3f9f81befb0f70231262912660bea0249ae79326 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 d5f59fed6e6b2d3f30ee4acddc216ed3e1a0f995..c7104c9520ce26934046995bb509eb8d693d8959 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 14a13f4b3a4148f0463325881178777f7f76c9fa..744f116fe37470e2964874a82e84b1fea08b4643 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 a160f7b39eb24bd6f3e384c1498d5a7f41af1022..61a8e81a835f0adf2d564cebe4745dd839f748c0 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 */
 
 
 /*