From 598ea2c359ef625f472a2a53b870a1baffa45251 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 17 Feb 2000 03:40:02 +0000
Subject: [PATCH] Finish repairing 6.5's problems with r-tree indexes: create
 appropriate selectivity functions and make the r-tree operators use them. 
 The estimation functions themselves are just stubs, unfortunately, but
 perhaps someday someone will make them compute realistic estimates. Change
 pg_am so that the optimizer can reliably tell the difference between ordered
 and unordered indexes --- before it would think that an r-tree index can be
 scanned in '<<' order, which is not right AFAIK. Repair broken negator links
 for network_sup and related ops. Initdb forced.  This might be my last initdb
 force for 7.0 ... hope so anyway ...

---
 doc/src/sgml/catalogs.sgml                 | 65 +++++++-------
 doc/src/sgml/xindex.sgml                   | 20 +++--
 doc/src/sgml/xoper.sgml                    | 10 +++
 src/backend/optimizer/util/plancat.c       | 37 ++++----
 src/backend/utils/adt/geo_selfuncs.c       | 98 ++++++++++++----------
 src/include/catalog/catversion.h           |  4 +-
 src/include/catalog/pg_am.h                | 66 ++++++++-------
 src/include/catalog/pg_operator.h          | 78 ++++++++---------
 src/include/catalog/pg_proc.h              | 15 +++-
 src/include/utils/geo_decls.h              | 15 +++-
 src/test/regress/expected/create_index.out | 14 +++-
 src/test/regress/sql/create_index.sql      |  8 +-
 12 files changed, 249 insertions(+), 181 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index f4dd09d88a3..e0009a17c29 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,6 +1,6 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.4 2000/02/06 05:09:31 momjian Exp $
+.\" $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.5 2000/02/17 03:39:39 tgl Exp $
 .TH "SYSTEM CATALOGS" INTRO 03/13/94 PostgreSQL PostgreSQL
 .SH "Section 7 - System Catalogs"
 .de LS
@@ -108,38 +108,37 @@ pg_aggregate
 .fi
 .nf M
 pg_am
-    NameData      amname		/* access method name */
-    oid         amowner	/* usesysid of creator */
-    char        amkind		/* - deprecated */
-				/* originally:
-				   h=hashed
-				   o=ordered
-				   s=special */
-    int2        amstrategies	/* total NUMBER of strategies by which
-				   we can traverse/search this AM */
-    int2        amsupport	/* total NUMBER of support functions
-				   that this AM uses */
-    regproc     amgettuple	/* "next valid tuple" function */
-    regproc     aminsert	/* "insert this tuple" function */
-    regproc     amdelete	/* "delete this tuple" function */
-    regproc     amgetattr	/* - deprecated */
-    regproc     amsetlock	/* - deprecated */
-    regproc     amsettid	/* - deprecated */
-    regproc     amfreetuple	/* - deprecated */
-    regproc     ambeginscan	/* "start new scan" function */
-    regproc     amrescan	/* "restart this scan" function */
-    regproc     amendscan	/* "end this scan" function */
-    regproc     ammarkpos	/* "mark current scan position"
-				   function */
-    regproc     amrestrpos	/* "restore marked scan position"
-				   function */
-    regproc     amopen		/* - deprecated */
-    regproc     amclose	/* - deprecated */
-    regproc     ambuild	/* "build new index" function */
-    regproc     amcreate 	/* - deprecated */
-    regproc     amdestroy	/* - deprecated */
-    regproc     amcostestimate	/* estimate cost of an indexscan */
-	
+    NameData    amname          /* access method name */
+    oid         amowner         /* usesysid of creator */
+    int2        amstrategies    /* total NUMBER of strategies by which
+                                   we can traverse/search this AM */
+    int2        amsupport       /* total NUMBER of support functions
+                                   that this AM uses */
+    int2        amorderstrategy /* if this AM has a sort order, the
+                                 * strategy number of the sort operator.
+                                 * Zero if AM is not ordered.
+                                 */
+    regproc     amgettuple      /* "next valid tuple" function */
+    regproc     aminsert        /* "insert this tuple" function */
+    regproc     amdelete        /* "delete this tuple" function */
+    regproc     amgetattr       /* - deprecated */
+    regproc     amsetlock       /* - deprecated */
+    regproc     amsettid        /* - deprecated */
+    regproc     amfreetuple     /* - deprecated */
+    regproc     ambeginscan     /* "start new scan" function */
+    regproc     amrescan        /* "restart this scan" function */
+    regproc     amendscan       /* "end this scan" function */
+    regproc     ammarkpos       /* "mark current scan position"
+                                   function */
+    regproc     amrestrpos      /* "restore marked scan position"
+                                   function */
+    regproc     amopen          /* - deprecated */
+    regproc     amclose         /* - deprecated */
+    regproc     ambuild         /* "build new index" function */
+    regproc     amcreate        /* - deprecated */
+    regproc     amdestroy       /* - deprecated */
+    regproc     amcostestimate  /* estimate cost of an indexscan */
+
 .fi
 .nf M
 pg_amop
diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml
index 608465dd1bc..9fcd9b99dac 100644
--- a/doc/src/sgml/xindex.sgml
+++ b/doc/src/sgml/xindex.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.7 2000/01/24 07:16:49 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xindex.sgml,v 1.8 2000/02/17 03:39:39 tgl Exp $
 Postgres documentation
 -->
 
@@ -51,10 +51,6 @@ Postgres documentation
        <entry>amowner</entry>
        <entry>object id of the owner's instance in pg_user</entry>
       </row>
-      <row>
-       <entry>amkind</entry>
-       <entry>not used at present, but set to 'o' as a place holder</entry>
-      </row>
       <row>
        <entry>amstrategies</entry>
        <entry>number of strategies for this access method (see below)</entry>
@@ -63,6 +59,11 @@ Postgres documentation
        <entry>amsupport</entry>
        <entry>number of support routines for this access method (see below)</entry>
       </row>
+      <row>
+       <entry>amorderstrategy</entry>
+       <entry>zero if the index offers no sort order, otherwise the strategy
+        number of the strategy operator that describes the sort order</entry>
+      </row>
       <row>
        <entry>amgettuple</entry>
       </row>
@@ -217,6 +218,15 @@ SELECT oid FROM pg_am WHERE amname = 'btree';
    method.  The actual routines are listed elsewhere.
   </para>
 
+  <para>
+   By the way, the <filename>amorderstrategy</filename> entry tells whether
+   the access method supports ordered scan.  Zero means it doesn't; if it
+   does, <filename>amorderstrategy</filename> is the number of the strategy
+   routine that corresponds to the ordering operator.  For example, btree
+   has <filename>amorderstrategy</filename> = 1 which is its
+   "less than" strategy number.
+  </para>
+
   <para>
    The next class of interest is pg_opclass.  This class exists only to
    associate a name and default type with an oid.  In pg_amop, every
diff --git a/doc/src/sgml/xoper.sgml b/doc/src/sgml/xoper.sgml
index 45d05b6c3b2..153e365e126 100644
--- a/doc/src/sgml/xoper.sgml
+++ b/doc/src/sgml/xoper.sgml
@@ -265,6 +265,13 @@ SELECT (a + b) AS c FROM test_complex;
     yet.)  If you do not do this, things will still work, but the optimizer's
     estimates won't be as good as they could be.
    </para>
+
+   <para>
+    There are additional selectivity functions designed for geometric
+    operators in src/backend/utils/adt/geo_selfuncs.c: areasel, positionsel,
+    and contsel.  At this writing these are just stubs, but you may want
+    to use them (or even better, improve them) anyway.
+   </para>
    </sect2>
 
    <sect2>
@@ -294,6 +301,9 @@ SELECT (a + b) AS c FROM test_complex;
 	neqjoinsel	for &lt;&gt;
 	scalarltjoinsel	for &lt; or &lt;=
 	scalargtjoinsel	for &gt; or &gt;=
+	areajoinsel	for 2D area-based comparisons
+	positionjoinsel	for 2D position-based comparisons
+	contjoinsel	for 2D containment-based comparisons
     </ProgramListing>
     </para>
    </sect2>
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 8663cdb0241..e3a60c2c7f0 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.47 2000/02/15 20:49:20 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.48 2000/02/17 03:39:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,8 +96,8 @@ find_secondary_indexes(Query *root, Index relid)
 		IndexOptInfo   *info = makeNode(IndexOptInfo);
 		int				i;
 		Relation		indexRelation;
-		uint16			amstrategy;
 		Oid				relam;
+		uint16			amorderstrategy;
 
 		/*
 		 * Need to make these arrays large enough to be sure there is a
@@ -129,37 +129,38 @@ find_secondary_indexes(Query *root, Index relid)
 
 		/* Extract info from the relation descriptor for the index */
 		indexRelation = index_open(index->indexrelid);
-#ifdef notdef
-		/* XXX should iterate through strategies -- but how?  use #1 for now */
-		amstrategy = indexRelation->rd_am->amstrategies;
-#endif	 /* notdef */
-		amstrategy = 1;
 		relam = indexRelation->rd_rel->relam;
 		info->relam = relam;
 		info->pages = indexRelation->rd_rel->relpages;
 		info->tuples = indexRelation->rd_rel->reltuples;
 		info->amcostestimate = index_cost_estimator(indexRelation);
+		amorderstrategy = indexRelation->rd_am->amorderstrategy;
 		index_close(indexRelation);
 
 		/*
-		 * Fetch the ordering operators associated with the index.
-		 *
-		 * XXX what if it's a hash or other unordered index?
+		 * Fetch the ordering operators associated with the index,
+		 * if any.
 		 */
 		MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS+1));
-		for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
+		if (amorderstrategy != 0)
 		{
-			HeapTuple		amopTuple;
+			for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
+			{
+				HeapTuple		amopTuple;
+				Form_pg_amop	amop;
 
-			amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
+				amopTuple =
+					SearchSysCacheTuple(AMOPSTRATEGY,
 										ObjectIdGetDatum(relam),
 										ObjectIdGetDatum(index->indclass[i]),
-										UInt16GetDatum(amstrategy),
+										UInt16GetDatum(amorderstrategy),
 										0);
-			if (!HeapTupleIsValid(amopTuple))
-				elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
-					 relam, index->indclass[i], amstrategy);
-			info->ordering[i] = ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
+				if (!HeapTupleIsValid(amopTuple))
+					elog(ERROR, "find_secondary_indexes: no amop %u %u %d",
+						 relam, index->indclass[i], (int) amorderstrategy);
+				amop = (Form_pg_amop) GETSTRUCT(amopTuple);
+				info->ordering[i] = amop->amopopr;
+			}
 		}
 
 		indexes = lcons(info, indexes);
diff --git a/src/backend/utils/adt/geo_selfuncs.c b/src/backend/utils/adt/geo_selfuncs.c
index 9dd0de0e424..95e594ea0ef 100644
--- a/src/backend/utils/adt/geo_selfuncs.c
+++ b/src/backend/utils/adt/geo_selfuncs.c
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------------------------
  *
- * geo-selfuncs.c
+ * geo_selfuncs.c
  *	  Selectivity routines registered in the operator catalog in the
  *	  "oprrest" and "oprjoin" attributes.
  *
@@ -9,9 +9,10 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.12 2000/01/26 05:57:14 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.13 2000/02/17 03:39:42 tgl Exp $
  *
- *		XXX These are totally bogus.
+ *	XXX These are totally bogus.  Perhaps someone will make them do
+ *	something reasonable, someday.
  *
  *-------------------------------------------------------------------------
  */
@@ -19,17 +20,41 @@
 
 #include "utils/builtins.h"
 
+
+/*
+ *	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.
+ *
+ *	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
+ *	be fairly small.
+ *
+ *	In general, rtrees need 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,
+ *	ought to be adjusted accordingly --- but until we can generate somewhat
+ *	realistic numbers here, it hardly matters...
+ */
+
+
+/*
+ * Selectivity for operators that depend on area, such as "overlap".
+ */
+
 float64
 areasel(Oid opid,
 		Oid relid,
 		AttrNumber attno,
-		char *value,
+		Datum value,
 		int32 flag)
 {
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 4.0;
+	*result = 0.05;
 	return result;
 }
 
@@ -43,81 +68,66 @@ areajoinsel(Oid opid,
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 4.0;
+	*result = 0.05;
 	return result;
 }
 
 /*
- *	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.
+ *	positionsel
  *
- *	In general, rtrees need to search multiple subtrees in order to guarantee
- *	that all occurrences of the same key have been found.  Because of this,
- *	the heuristic selectivity functions we return are higher than they would
- *	otherwise be.
- */
-
-/*
- *	left_sel -- How likely is a box to be strictly left of (right of, above,
- *				below) a given box?
+ * How likely is a box to be strictly left of (right of, above, below)
+ * a given box?
  */
 
-#ifdef NOT_USED
 float64
-leftsel(Oid opid,
-		Oid relid,
-		AttrNumber attno,
-		char *value,
-		int32 flag)
+positionsel(Oid opid,
+			Oid relid,
+			AttrNumber attno,
+			Datum value,
+			int32 flag)
 {
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 6.0;
+	*result = 0.1;
 	return result;
 }
 
-#endif
-
-#ifdef NOT_USED
 float64
-leftjoinsel(Oid opid,
-			Oid relid1,
-			AttrNumber attno1,
-			Oid relid2,
-			AttrNumber attno2)
+positionjoinsel(Oid opid,
+				Oid relid1,
+				AttrNumber attno1,
+				Oid relid2,
+				AttrNumber attno2)
 {
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 6.0;
+	*result = 0.1;
 	return result;
 }
 
-#endif
-
 /*
  *	contsel -- How likely is a box to contain (be contained by) a given box?
+ *
+ * This is a tighter constraint than "overlap", so produce a smaller
+ * estimate than areasel does.
  */
-#ifdef NOT_USED
+
 float64
 contsel(Oid opid,
 		Oid relid,
 		AttrNumber attno,
-		char *value,
+		Datum value,
 		int32 flag)
 {
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 10.0;
+	*result = 0.01;
 	return result;
 }
 
-#endif
-
-#ifdef NOT_USED
 float64
 contjoinsel(Oid opid,
 			Oid relid1,
@@ -128,8 +138,6 @@ contjoinsel(Oid opid,
 	float64		result;
 
 	result = (float64) palloc(sizeof(float64data));
-	*result = 1.0 / 10.0;
+	*result = 0.01;
 	return result;
 }
-
-#endif
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 482b299c55d..b64d62be2bc 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.15 2000/02/16 17:26:06 thomas Exp $
+ * $Id: catversion.h,v 1.16 2000/02/17 03:39:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                          yyyymmddN */
-#define CATALOG_VERSION_NO  200002161
+#define CATALOG_VERSION_NO  200002162
 
 #endif
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index a1e55784b0f..dfebc0e8c8f 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_am.h,v 1.13 2000/01/26 05:57:56 momjian Exp $
+ * $Id: pg_am.h,v 1.14 2000/02/17 03:39:47 tgl Exp $
  *
  * NOTES
  *		the genbki.sh script reads this file and generates .bki
@@ -36,29 +36,33 @@
  */
 CATALOG(pg_am)
 {
-	NameData	amname;
-	int4		amowner;
-	char		amkind;
-	int2		amstrategies;
-	int2		amsupport;
-	regproc		amgettuple;
-	regproc		aminsert;
-	regproc		amdelete;
-	regproc		amgetattr;
-	regproc		amsetlock;
-	regproc		amsettid;
-	regproc		amfreetuple;
-	regproc		ambeginscan;
-	regproc		amrescan;
-	regproc		amendscan;
-	regproc		ammarkpos;
-	regproc		amrestrpos;
-	regproc		amopen;
-	regproc		amclose;
-	regproc		ambuild;
-	regproc		amcreate;
-	regproc		amdestroy;
-	regproc		amcostestimate;
+	NameData	amname;			/* access method name */
+	int4		amowner;		/* usesysid of creator */
+	int2		amstrategies;	/* total NUMBER of strategies by which
+								 * we can traverse/search this AM */
+	int2		amsupport;		/* total NUMBER of support functions
+								 * that this AM uses */
+	int2		amorderstrategy; /* if this AM has a sort order, the
+								  * strategy number of the sort operator.
+								  * Zero if AM is not ordered. */
+	regproc		amgettuple;		/* "next valid tuple" function */
+	regproc		aminsert;		/* "insert this tuple" function */
+	regproc		amdelete;		/* "delete this tuple" function */
+	regproc		amgetattr;		/* - deprecated */
+	regproc		amsetlock;		/* - deprecated */
+	regproc		amsettid;		/* - deprecated */
+	regproc		amfreetuple;	/* - deprecated */
+	regproc		ambeginscan;	/* "start new scan" function */
+	regproc		amrescan;		/* "restart this scan" function */
+	regproc		amendscan;		/* "end this scan" function */
+	regproc		ammarkpos;		/* "mark current scan position" function */
+	regproc		amrestrpos;		/* "restore marked scan position" function */
+	regproc		amopen;			/* - deprecated */
+	regproc		amclose;		/* - deprecated */
+	regproc		ambuild;		/* "build new index" function */
+	regproc		amcreate;		/* - deprecated */
+	regproc		amdestroy;		/* - deprecated */
+	regproc		amcostestimate;	/* estimate cost of an indexscan */
 } FormData_pg_am;
 
 /* ----------------
@@ -75,9 +79,9 @@ typedef FormData_pg_am *Form_pg_am;
 #define Natts_pg_am						23
 #define Anum_pg_am_amname				1
 #define Anum_pg_am_amowner				2
-#define Anum_pg_am_amkind				3
-#define Anum_pg_am_amstrategies			4
-#define Anum_pg_am_amsupport			5
+#define Anum_pg_am_amstrategies			3
+#define Anum_pg_am_amsupport			4
+#define Anum_pg_am_amorderstrategy		5
 #define Anum_pg_am_amgettuple			6
 #define Anum_pg_am_aminsert				7
 #define Anum_pg_am_amdelete				8
@@ -102,15 +106,15 @@ typedef FormData_pg_am *Form_pg_am;
  * ----------------
  */
 
-DATA(insert OID = 402 (  rtree PGUID "o" 8 3 rtgettuple rtinsert rtdelete - - - - rtbeginscan rtrescan rtendscan rtmarkpos rtrestrpos - - rtbuild - - rtcostestimate ));
+DATA(insert OID = 402 (  rtree PGUID 8 3 0 rtgettuple rtinsert rtdelete - - - - rtbeginscan rtrescan rtendscan rtmarkpos rtrestrpos - - rtbuild - - rtcostestimate ));
 DESCR("");
-DATA(insert OID = 403 (  btree PGUID "o" 5 1 btgettuple btinsert btdelete - - - - btbeginscan btrescan btendscan btmarkpos btrestrpos - - btbuild - - btcostestimate ));
+DATA(insert OID = 403 (  btree PGUID 5 1 1 btgettuple btinsert btdelete - - - - btbeginscan btrescan btendscan btmarkpos btrestrpos - - btbuild - - btcostestimate ));
 DESCR("");
 #define BTREE_AM_OID 403
-DATA(insert OID = 405 (  hash PGUID "o"  1 1 hashgettuple hashinsert hashdelete - - - - hashbeginscan hashrescan hashendscan hashmarkpos hashrestrpos - - hashbuild - - hashcostestimate ));
+DATA(insert OID = 405 (  hash PGUID 1 1 0 hashgettuple hashinsert hashdelete - - - - hashbeginscan hashrescan hashendscan hashmarkpos hashrestrpos - - hashbuild - - hashcostestimate ));
 DESCR("");
 #define HASH_AM_OID 405
-DATA(insert OID = 783 (  gist PGUID "o" 100 7 gistgettuple gistinsert gistdelete - - - - gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos - - gistbuild - - gistcostestimate ));
+DATA(insert OID = 783 (  gist PGUID 100 7 0 gistgettuple gistinsert gistdelete - - - - gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos - - gistbuild - - gistcostestimate ));
 DESCR("");
 
 #endif	 /* PG_AM_H */
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index e510c621d02..965c7860e45 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_operator.h,v 1.68 2000/02/16 17:26:07 thomas Exp $
+ * $Id: pg_operator.h,v 1.69 2000/02/17 03:39:48 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -157,31 +157,31 @@ DATA(insert OID = 420 ( "<="	   PGUID 0 b t f  20  23  16  82 419 0 0 int84le sc
 DATA(insert OID = 430 ( ">="	   PGUID 0 b t f  20  23  16  80 418 0 0 int84ge scalargtsel scalargtjoinsel ));
 
 DATA(insert OID = 484 (  "-"	   PGUID 0 l t f   0  20  20   0   0   0   0 int8um - - ));
-DATA(insert OID = 485 (  "<<"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_left - - ));
-DATA(insert OID = 486 (  "&<"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overleft - - ));
-DATA(insert OID = 487 (  "&>"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overright - - ));
-DATA(insert OID = 488 (  ">>"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_right - - ));
-DATA(insert OID = 489 (  "@"	   PGUID 0 b t f 604 604  16 490   0   0   0 poly_contained - - ));
-DATA(insert OID = 490 (  "~"	   PGUID 0 b t f 604 604  16 489   0   0   0 poly_contain - - ));
+DATA(insert OID = 485 (  "<<"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_left positionsel positionjoinsel ));
+DATA(insert OID = 486 (  "&<"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overleft positionsel positionjoinsel ));
+DATA(insert OID = 487 (  "&>"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overright positionsel positionjoinsel ));
+DATA(insert OID = 488 (  ">>"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_right positionsel positionjoinsel ));
+DATA(insert OID = 489 (  "@"	   PGUID 0 b t f 604 604  16 490   0   0   0 poly_contained contsel contjoinsel ));
+DATA(insert OID = 490 (  "~"	   PGUID 0 b t f 604 604  16 489   0   0   0 poly_contain contsel contjoinsel ));
 DATA(insert OID = 491 (  "~="	   PGUID 0 b t f 604 604  16 491   0   0   0 poly_same eqsel eqjoinsel ));
-DATA(insert OID = 492 (  "&&"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overlap - - ));
-DATA(insert OID = 493 (  "<<"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_left - - ));
-DATA(insert OID = 494 (  "&<"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overleft - - ));
-DATA(insert OID = 495 (  "&>"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overright - - ));
-DATA(insert OID = 496 (  ">>"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_right - - ));
-DATA(insert OID = 497 (  "@"	   PGUID 0 b t f 603 603  16 498   0   0   0 box_contained - - ));
-DATA(insert OID = 498 (  "~"	   PGUID 0 b t f 603 603  16 497   0   0   0 box_contain - - ));
+DATA(insert OID = 492 (  "&&"	   PGUID 0 b t f 604 604  16   0   0   0   0 poly_overlap areasel areajoinsel ));
+DATA(insert OID = 493 (  "<<"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_left positionsel positionjoinsel ));
+DATA(insert OID = 494 (  "&<"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overleft positionsel positionjoinsel ));
+DATA(insert OID = 495 (  "&>"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overright positionsel positionjoinsel ));
+DATA(insert OID = 496 (  ">>"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_right positionsel positionjoinsel ));
+DATA(insert OID = 497 (  "@"	   PGUID 0 b t f 603 603  16 498   0   0   0 box_contained contsel contjoinsel ));
+DATA(insert OID = 498 (  "~"	   PGUID 0 b t f 603 603  16 497   0   0   0 box_contain contsel contjoinsel ));
 DATA(insert OID = 499 (  "~="	   PGUID 0 b t f 603 603  16 499   0   0   0 box_same eqsel eqjoinsel ));
-DATA(insert OID = 500 (  "&&"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overlap - - ));
+DATA(insert OID = 500 (  "&&"	   PGUID 0 b t f 603 603  16   0   0   0   0 box_overlap areasel areajoinsel ));
 DATA(insert OID = 501 (  ">="	   PGUID 0 b t f 603 603  16 505 504   0   0 box_ge areasel areajoinsel ));
 DATA(insert OID = 502 (  ">"	   PGUID 0 b t f 603 603  16 504 505   0   0 box_gt areasel areajoinsel ));
 DATA(insert OID = 503 (  "="	   PGUID 0 b t f 603 603  16 503   0 504 504 box_eq eqsel eqjoinsel ));
 DATA(insert OID = 504 (  "<"	   PGUID 0 b t f 603 603  16 502 501   0   0 box_lt areasel areajoinsel ));
 DATA(insert OID = 505 (  "<="	   PGUID 0 b t f 603 603  16 501 502   0   0 box_le areasel areajoinsel ));
-DATA(insert OID = 506 (  ">^"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_above - - ));
-DATA(insert OID = 507 (  "<<"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_left - - ));
-DATA(insert OID = 508 (  ">>"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_right - - ));
-DATA(insert OID = 509 (  "<^"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_below - - ));
+DATA(insert OID = 506 (  ">^"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_above positionsel positionjoinsel ));
+DATA(insert OID = 507 (  "<<"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_left positionsel positionjoinsel ));
+DATA(insert OID = 508 (  ">>"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_right positionsel positionjoinsel ));
+DATA(insert OID = 509 (  "<^"	   PGUID 0 b t f 600 600  16   0   0   0   0 point_below positionsel positionjoinsel ));
 DATA(insert OID = 510 (  "~="	   PGUID 0 b t f 600 600  16 510   0   0   0 point_eq eqsel eqjoinsel ));
 DATA(insert OID = 511 (  "@"	   PGUID 0 b t f 600 603  16   0   0   0   0 on_pb - - ));
 DATA(insert OID = 512 (  "@"	   PGUID 0 b t f 600 602  16 755   0   0   0 on_ppath - - ));
@@ -388,9 +388,9 @@ DATA(insert OID =  796 (  ">="	   PGUID 0 b t f  602  602	 16  795  0 0 0 path_n
 DATA(insert OID =  797 (  "#"	   PGUID 0 l t f	0  602	 23    0  0 0 0 path_npoints - - ));
 DATA(insert OID =  798 (  "?#"	   PGUID 0 b t f  602  602	 16    0  0 0 0 path_inter - - ));
 DATA(insert OID =  799 (  "@-@"    PGUID 0 l t f	0  602	701    0  0 0 0 path_length - - ));
-DATA(insert OID =  800 (  ">^"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_above - - ));
-DATA(insert OID =  801 (  "<^"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_below - - ));
-DATA(insert OID =  802 (  "?#"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_overlap - - ));
+DATA(insert OID =  800 (  ">^"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_above positionsel positionjoinsel ));
+DATA(insert OID =  801 (  "<^"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_below positionsel positionjoinsel ));
+DATA(insert OID =  802 (  "?#"	   PGUID 0 b t f  603  603	 16    0  0 0 0 box_overlap areasel areajoinsel ));
 DATA(insert OID =  803 (  "#"	   PGUID 0 b t f  603  603	603    0  0 0 0 box_intersect - - ));
 DATA(insert OID =  804 (  "+"	   PGUID 0 b t f  603  600	603    0  0 0 0 box_add - - ));
 DATA(insert OID =  805 (  "-"	   PGUID 0 b t f  603  600	603    0  0 0 0 box_sub - - ));
@@ -570,16 +570,16 @@ DATA(insert OID = 1503 (  ">"	  PGUID 0 b t f  718  718	16 1502 1504	0	 0 circle
 DATA(insert OID = 1504 (  "<="	  PGUID 0 b t f  718  718	16 1505 1503	0	 0 circle_le areasel areajoinsel ));
 DATA(insert OID = 1505 (  ">="	  PGUID 0 b t f  718  718	16 1504 1502	0	 0 circle_ge areasel areajoinsel ));
 
-DATA(insert OID = 1506 (  "<<"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_left - - ));
-DATA(insert OID = 1507 (  "&<"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overleft - - ));
-DATA(insert OID = 1508 (  "&>"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overright - - ));
-DATA(insert OID = 1509 (  ">>"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_right - - ));
-DATA(insert OID = 1510 (  "@"	  PGUID 0 b t f  718  718	16 1511    0	0	 0 circle_contained - - ));
-DATA(insert OID = 1511 (  "~"	  PGUID 0 b t f  718  718	16 1510    0	0	 0 circle_contain - - ));
+DATA(insert OID = 1506 (  "<<"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_left positionsel positionjoinsel ));
+DATA(insert OID = 1507 (  "&<"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overleft positionsel positionjoinsel ));
+DATA(insert OID = 1508 (  "&>"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overright positionsel positionjoinsel ));
+DATA(insert OID = 1509 (  ">>"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_right positionsel positionjoinsel ));
+DATA(insert OID = 1510 (  "@"	  PGUID 0 b t f  718  718	16 1511    0	0	 0 circle_contained contsel contjoinsel ));
+DATA(insert OID = 1511 (  "~"	  PGUID 0 b t f  718  718	16 1510    0	0	 0 circle_contain contsel contjoinsel ));
 DATA(insert OID = 1512 (  "~="	  PGUID 0 b t f  718  718	16 1512    0	0	 0 circle_same eqsel eqjoinsel ));
-DATA(insert OID = 1513 (  "&&"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overlap - - ));
-DATA(insert OID = 1514 (  ">^"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_above - - ));
-DATA(insert OID = 1515 (  "<^"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_below - - ));
+DATA(insert OID = 1513 (  "&&"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_overlap areasel areajoinsel ));
+DATA(insert OID = 1514 (  ">^"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_above positionsel positionjoinsel ));
+DATA(insert OID = 1515 (  "<^"	  PGUID 0 b t f  718  718	16	  0    0	0	 0 circle_below positionsel positionjoinsel ));
 
 DATA(insert OID = 1516 (  "+"	  PGUID 0 b t f  718  600  718	  0    0	0	 0 circle_add_pt - - ));
 DATA(insert OID = 1517 (  "-"	  PGUID 0 b t f  718  600  718	  0    0	0	 0 circle_sub_pt - - ));
@@ -652,10 +652,10 @@ DATA(insert OID = 1203 (  "<"	   PGUID 0 b t f 869 869	 16 1205 1206 0 0 network
 DATA(insert OID = 1204 (  "<="	   PGUID 0 b t f 869 869	 16 1206 1205 0 0 network_le scalarltsel scalarltjoinsel ));
 DATA(insert OID = 1205 (  ">"	   PGUID 0 b t f 869 869	 16 1203 1204 0 0 network_gt scalargtsel scalargtjoinsel ));
 DATA(insert OID = 1206 (  ">="	   PGUID 0 b t f 869 869	 16 1204 1203 0 0 network_ge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 931  (  "<<"	   PGUID 0 b t f 869 869	 16 933  934  0 0 network_sub - - ));
-DATA(insert OID = 932  (  "<<="    PGUID 0 b t f 869 869	 16 934  933  0 0 network_subeq - - ));
-DATA(insert OID = 933  (  ">>"	   PGUID 0 b t f 869 869	 16 931  932  0 0 network_sup - - ));
-DATA(insert OID = 934  (  ">>="    PGUID 0 b t f 869 869	 16 932  931  0 0 network_supeq - - ));
+DATA(insert OID = 931  (  "<<"	   PGUID 0 b t f 869 869	 16 933     0 0 0 network_sub - - ));
+DATA(insert OID = 932  (  "<<="    PGUID 0 b t f 869 869	 16 934     0 0 0 network_subeq - - ));
+DATA(insert OID = 933  (  ">>"	   PGUID 0 b t f 869 869	 16 931     0 0 0 network_sup - - ));
+DATA(insert OID = 934  (  ">>="    PGUID 0 b t f 869 869	 16 932     0 0 0 network_supeq - - ));
 
 /* CIDR type */
 DATA(insert OID = 820 (  "="	   PGUID 0 b t f 650 650	 16 820 821 0 0 network_eq eqsel eqjoinsel ));
@@ -664,10 +664,10 @@ DATA(insert OID = 822 (  "<"	   PGUID 0 b t f 650 650	 16 824 825 0 0 network_lt
 DATA(insert OID = 823 (  "<="	   PGUID 0 b t f 650 650	 16 825 824 0 0 network_le scalarltsel scalarltjoinsel ));
 DATA(insert OID = 824 (  ">"	   PGUID 0 b t f 650 650	 16 822 823 0 0 network_gt scalargtsel scalargtjoinsel ));
 DATA(insert OID = 825 (  ">="	   PGUID 0 b t f 650 650	 16 823 822 0 0 network_ge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 826 (  "<<"	   PGUID 0 b t f 650 650	 16 828 1004  0 0 network_sub - - ));
-DATA(insert OID = 827 (  "<<="	   PGUID 0 b t f 650 650	 16 1004 828  0 0 network_subeq - - ));
-DATA(insert OID = 828 (  ">>"	   PGUID 0 b t f 650 650	 16 826  827  0 0 network_sup - - ));
-DATA(insert OID = 1004 ( ">>="	   PGUID 0 b t f 650 650	 16 827  826  0 0 network_supeq - - ));
+DATA(insert OID = 826 (  "<<"	   PGUID 0 b t f 650 650	 16 828   0 0 0 network_sub - - ));
+DATA(insert OID = 827 (  "<<="	   PGUID 0 b t f 650 650	 16 1004  0 0 0 network_subeq - - ));
+DATA(insert OID = 828 (  ">>"	   PGUID 0 b t f 650 650	 16 826   0 0 0 network_sup - - ));
+DATA(insert OID = 1004 ( ">>="	   PGUID 0 b t f 650 650	 16 827   0 0 0 network_supeq - - ));
 
 /* NUMERIC type - OID's 1700-1799 */
 DATA(insert OID = 1752 (  "="	   PGUID 0 b t f 1700 1700	 16 1752 1753 1754 1754 numeric_eq eqsel eqjoinsel ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 64c015fbff2..4fdbaaaf9dd 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.122 2000/02/16 17:26:07 thomas Exp $
+ * $Id: pg_proc.h,v 1.123 2000/02/17 03:39:48 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -293,9 +293,9 @@ DESCR("contained in");
 DATA(insert OID = 138 (  box_center		   PGUID 11 f t t 1 f 600 "603" 100 1 0 100  box_center - ));
 DESCR("center of");
 DATA(insert OID = 139 (  areasel		   PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100  areasel - ));
-DESCR("restriction selectivity for operators on areas");
+DESCR("restriction selectivity for area-comparison operators");
 DATA(insert OID = 140 (  areajoinsel	   PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100	areajoinsel - ));
-DESCR("join selectivity for operators on areas");
+DESCR("join selectivity for area-comparison operators");
 DATA(insert OID = 141 (  int4mul		   PGUID 11 f t t 2 f 23 "23 23" 100 0 0 100  int4mul - ));
 DESCR("multiply");
 DATA(insert OID = 142 (  int4fac		   PGUID 11 f t t 1 f 23 "23" 100 0 0 100  int4fac - ));
@@ -1565,6 +1565,15 @@ DESCR("current transaction time");
 
 /* OIDS 1300 - 1399 */
 
+DATA(insert OID = 1300 (  positionsel		   PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100  positionsel - ));
+DESCR("restriction selectivity for position-comparison operators");
+DATA(insert OID = 1301 (  positionjoinsel	   PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100	positionjoinsel - ));
+DESCR("join selectivity for position-comparison operators");
+DATA(insert OID = 1302 (  contsel		   PGUID 11 f t f 5 f 701 "26 26 21 0 23" 100 0 0 100  contsel - ));
+DESCR("restriction selectivity for containment comparison operators");
+DATA(insert OID = 1303 (  contjoinsel	   PGUID 11 f t f 5 f 701 "26 26 21 26 21" 100 0 0 100	contjoinsel - ));
+DESCR("join selectivity for containment comparison operators");
+
 DATA(insert OID = 1314 (  timestamp_cmp		 PGUID 11 f t f 2 f   23 "1184 1184" 100 0 0 100  timestamp_cmp - ));
 DESCR("less-equal-greater");
 DATA(insert OID = 1315 (  interval_cmp		 PGUID 11 f t f 2 f   23 "1186 1186" 100 0 0 100  interval_cmp - ));
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 24a791dbecf..50745f9008b 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -6,12 +6,13 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geo_decls.h,v 1.24 2000/01/26 05:58:38 momjian Exp $
+ * $Id: geo_decls.h,v 1.25 2000/02/17 03:39:51 tgl Exp $
  *
  * NOTE
  *	  These routines do *not* use the float types from adt/.
  *
  *	  XXX These routines were not written by a numerical analyst.
+ *
  *	  XXX I have made some attempt to flesh out the operators
  *		and data types. There are still some more to do. - tgl 97/04/19
  *
@@ -362,8 +363,16 @@ extern double circle_dt(CIRCLE *circle1, CIRCLE *circle2);
 
 /* geo_selfuncs.c */
 extern float64 areasel(Oid opid, Oid relid, AttrNumber attno,
-		char *value, int32 flag);
+					   Datum value, int32 flag);
 extern float64 areajoinsel(Oid opid, Oid relid1, AttrNumber attno1,
-			Oid relid2, AttrNumber attno2);
+						   Oid relid2, AttrNumber attno2);
+extern float64 positionsel(Oid opid, Oid relid, AttrNumber attno,
+						   Datum value, int32 flag);
+extern float64 positionjoinsel(Oid opid, Oid relid1, AttrNumber attno1,
+							   Oid relid2, AttrNumber attno2);
+extern float64 contsel(Oid opid, Oid relid, AttrNumber attno,
+					   Datum value, int32 flag);
+extern float64 contjoinsel(Oid opid, Oid relid1, AttrNumber attno1,
+						   Oid relid2, AttrNumber attno2);
 
 #endif	 /* GEO_DECLS_H */
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 3b070452e4d..3e727517741 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -47,10 +47,22 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
 -- 
 -- rtrees use a quadratic page-splitting algorithm that takes a
 -- really, really long time.  we don't test all rtree opclasses
--- in the regression test (we check them USING the sequoia 2000
+-- in the regression test (we check them using the sequoia 2000
 -- benchmark).
 --
 CREATE INDEX rect2ind ON fast_emp4000 USING rtree (home_base bigbox_ops);
+-- there's no easy way to check that this command actually is using
+-- the index, unfortunately.  (EXPLAIN would work, but its output
+-- changes too often for me to want to put an EXPLAIN in the test...)
+SELECT * FROM fast_emp4000
+    WHERE home_base @ '(200,200),(2000,1000)'::box
+    ORDER BY home_base USING <<;
+       home_base       
+-----------------------
+ (337,455),(240,359)
+ (1444,403),(1346,344)
+(2 rows)
+
 --
 -- HASH
 --
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 00281765a30..2ebc7ef3c3a 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -70,11 +70,17 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
 -- 
 -- rtrees use a quadratic page-splitting algorithm that takes a
 -- really, really long time.  we don't test all rtree opclasses
--- in the regression test (we check them USING the sequoia 2000
+-- in the regression test (we check them using the sequoia 2000
 -- benchmark).
 --
 CREATE INDEX rect2ind ON fast_emp4000 USING rtree (home_base bigbox_ops);
 
+-- there's no easy way to check that this command actually is using
+-- the index, unfortunately.  (EXPLAIN would work, but its output
+-- changes too often for me to want to put an EXPLAIN in the test...)
+SELECT * FROM fast_emp4000
+    WHERE home_base @ '(200,200),(2000,1000)'::box
+    ORDER BY home_base USING <<;
 
 --
 -- HASH
-- 
GitLab