> > 1. This patch introduces a new "polygon <-> point" operator. That seems
> > useful on its own, with or without this patch.
> 
> Yeah, but exact-knn cant come with no one implementation. But it would
> better come in a separate patch.

I tried to split them.  Separated patches are attached.  I changed
the order of the arguments as point <-> polygon, because point was
the first one on all the others.  Its commutator was required for
the index, so I added it on the second patch.  I also added tests
for the operator.  I think it is ready for committer as a separate
patch.  We can add it to the open CommitFest.

I have made some cosmetic changes on the patches.  I hope they are
useful.

I added support to point <-> circle operator with the same GiST
distance function you added for polygon.  I can change it, if it is not
the right way.

> > 2. I wonder how useful it really is to allow mixing exact and non-exact
> > return values from the distance function. The distance function included in
> > the patch always returns recheck=true. I have a feeling that all other
> > distance function will also always return either true or false.
> 
> For geometrical datatypes recheck variations in consistent methods are also
> very rare (I can't remember any). But imagine opclass for arrays where keys
> have different representation depending on array length. For such opclass
> and knn on similarity recheck flag could be useful.

I also wonder how useful it is.  Your example is convincing, but maybe
setting it index-wide will make the decisions on the framework easier.
For example, how hard would it be to decide if further sorting is
required or not on the planner?

> > 4. (as you mentioned in the other thread: ) It's a modularity violation
> > that you peek into the heap tuple from gist. I think the proper way to do
> > this would be to extend the IndexScan executor node to perform the
> > re-shuffling of tuples that come from the index in wrong order, or perhaps
> > add a new node type for it.
> >
> > Of course that's exactly what your partial sort patch does :-). I haven't
> > looked at that in detail, but I don't think the approach the partial sort
> > patch takes will work here as is. In the KNN-GiST case, the index is
> > returning tuples roughly in the right order, but a tuple that it returns
> > might in reality belong somewhere later in the ordering. In the partial
> > sort patch, the "input stream" of tuples is divided into non-overlapping
> > groups, so that the tuples within the group are not sorted, but the groups
> > are. I think the partial sort case is a special case of the KNN-GiST case,
> > if you consider the lower bound of each tuple to be the leading keys that
> > you don't need to sort.
> 
> Yes. But, for instance btree accesses heap for unique checking. Is really
> it so crimilal? :-)
> This is not only question of a new node or extending existing node. We need
> to teach planner/executor access method can return value of some expression
> which is lower bound of another expression. AFICS now access method can
> return only original indexed datums and TIDs. So, I afraid that enormous
> infrastructure changes are required. And I can hardly imagine what they
> should look like.

Unfortunately, I am not experienced enough to judge your implementation.
As far as I understand the problem is partially sorting rows on
the index scan node.  It can lead the planner to choose non-optimal
plans, because of not taking into account the cost of sorting.
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 54391fd..402ea40 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -2408,36 +2408,42 @@ lseg_interpt(PG_FUNCTION_ARGS)
  **            Routines for position comparisons of differently-typed
  **                            2D objects.
  **
  ***********************************************************************/
 
 /*---------------------------------------------------------------------
  *             dist_
  *                             Minimum distance from one object to another.
  *-------------------------------------------------------------------*/
 
+/*
+ * Distance from a point to a line
+ */
 Datum
 dist_pl(PG_FUNCTION_ARGS)
 {
        Point      *pt = PG_GETARG_POINT_P(0);
        LINE       *line = PG_GETARG_LINE_P(1);
 
        PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
 }
 
 static double
 dist_pl_internal(Point *pt, LINE *line)
 {
        return fabs((line->A * pt->x + line->B * pt->y + line->C) /
                                HYPOT(line->A, line->B));
 }
 
+/*
+ * Distance from a point to a lseg
+ */
 Datum
 dist_ps(PG_FUNCTION_ARGS)
 {
        Point      *pt = PG_GETARG_POINT_P(0);
        LSEG       *lseg = PG_GETARG_LSEG_P(1);
 
        PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
 }
 
 static double
@@ -2487,21 +2493,21 @@ dist_ps_internal(Point *pt, LSEG *lseg)
                result = point_dt(pt, &lseg->p[0]);
                tmpdist = point_dt(pt, &lseg->p[1]);
                if (tmpdist < result)
                        result = tmpdist;
        }
 
        return result;
 }
 
 /*
- ** Distance from a point to a path
+ * Distance from a point to a path
  */
 Datum
 dist_ppath(PG_FUNCTION_ARGS)
 {
        Point      *pt = PG_GETARG_POINT_P(0);
        PATH       *path = PG_GETARG_PATH_P(1);
        float8          result = 0.0;   /* keep compiler quiet */
        bool            have_min = false;
        float8          tmp;
        int                     i;
@@ -2543,37 +2549,42 @@ dist_ppath(PG_FUNCTION_ARGS)
                                {
                                        result = tmp;
                                        have_min = true;
                                }
                        }
                        break;
        }
        PG_RETURN_FLOAT8(result);
 }
 
+/*
+ * Distance from a point to a box
+ */
 Datum
 dist_pb(PG_FUNCTION_ARGS)
 {
        Point      *pt = PG_GETARG_POINT_P(0);
        BOX                *box = PG_GETARG_BOX_P(1);
        float8          result;
        Point      *near;
 
        near = DatumGetPointP(DirectFunctionCall2(close_pb,
                                                                                
          PointPGetDatum(pt),
                                                                                
          BoxPGetDatum(box)));
        result = point_dt(near, pt);
 
        PG_RETURN_FLOAT8(result);
 }
 
-
+/*
+ * Distance from a lseg to a line
+ */
 Datum
 dist_sl(PG_FUNCTION_ARGS)
 {
        LSEG       *lseg = PG_GETARG_LSEG_P(0);
        LINE       *line = PG_GETARG_LINE_P(1);
        float8          result,
                                d2;
 
        if (has_interpt_sl(lseg, line))
                result = 0.0;
@@ -2582,57 +2593,63 @@ dist_sl(PG_FUNCTION_ARGS)
                result = dist_pl_internal(&lseg->p[0], line);
                d2 = dist_pl_internal(&lseg->p[1], line);
                /* XXX shouldn't we take the min not max? */
                if (d2 > result)
                        result = d2;
        }
 
        PG_RETURN_FLOAT8(result);
 }
 
-
+/*
+ * Distance from a lseg to a box
+ */
 Datum
 dist_sb(PG_FUNCTION_ARGS)
 {
        LSEG       *lseg = PG_GETARG_LSEG_P(0);
        BOX                *box = PG_GETARG_BOX_P(1);
        Point      *tmp;
        Datum           result;
 
        tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
                                                                                
         LsegPGetDatum(lseg),
                                                                                
         BoxPGetDatum(box)));
        result = DirectFunctionCall2(dist_pb,
                                                                 
PointPGetDatum(tmp),
                                                                 
BoxPGetDatum(box));
 
        PG_RETURN_DATUM(result);
 }
 
-
+/*
+ * Distance from a line to a box
+ */
 Datum
 dist_lb(PG_FUNCTION_ARGS)
 {
 #ifdef NOT_USED
        LINE       *line = PG_GETARG_LINE_P(0);
        BOX                *box = PG_GETARG_BOX_P(1);
 #endif
 
        /* need to think about this one for a while */
        ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("function \"dist_lb\" not implemented")));
 
        PG_RETURN_NULL();
 }
 
-
+/*
+ * Distance from a circle to a polygon
+ */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
        CIRCLE     *circle = PG_GETARG_CIRCLE_P(0);
        POLYGON    *poly = PG_GETARG_POLYGON_P(1);
        float8          result;
        float8          d;
        int                     i;
        LSEG            seg;
 
@@ -2669,20 +2686,69 @@ dist_cpoly(PG_FUNCTION_ARGS)
                        result = d;
        }
 
        result -= circle->radius;
        if (result < 0)
                result = 0;
 
        PG_RETURN_FLOAT8(result);
 }
 
+/*
+ * Distance from a point to a polygon
+ */
+Datum
+dist_ppoly(PG_FUNCTION_ARGS)
+{
+       Point      *point = PG_GETARG_POINT_P(0);
+       POLYGON    *poly = PG_GETARG_POLYGON_P(1);
+       float8          result;
+       float8          distance;
+       int                     i;
+       LSEG            seg;
+
+       if (point_inside(point, poly->npts, poly->p) != 0)
+       {
+#ifdef GEODEBUG
+               printf("dist_ppoly- point inside of polygon\n");
+#endif
+               PG_RETURN_FLOAT8(0.0);
+       }
+
+       /* initialize distance with segment between first and last points */
+       seg.p[0].x = poly->p[0].x;
+       seg.p[0].y = poly->p[0].y;
+       seg.p[1].x = poly->p[poly->npts - 1].x;
+       seg.p[1].y = poly->p[poly->npts - 1].y;
+       result = dist_ps_internal(point, &seg);
+#ifdef GEODEBUG
+       printf("dist_ppoly- segment 0/n distance is %f\n", result);
+#endif
+
+       /* check distances for other segments */
+       for (i = 0; i < poly->npts - 1; i++)
+       {
+               seg.p[0].x = poly->p[i].x;
+               seg.p[0].y = poly->p[i].y;
+               seg.p[1].x = poly->p[i + 1].x;
+               seg.p[1].y = poly->p[i + 1].y;
+               distance = dist_ps_internal(point, &seg);
+#ifdef GEODEBUG
+               printf("dist_ppoly- segment %d distance is %f\n", i + 1, 
distance);
+#endif
+               if (distance < result)
+                       result = distance;
+       }
+
+       PG_RETURN_FLOAT8(result);
+}
+
 
 /*---------------------------------------------------------------------
  *             interpt_
  *                             Intersection point of objects.
  *                             We choose to ignore the "point" of intersection 
between
  *                               lines and boxes, since there are typically 
two.
  *-------------------------------------------------------------------*/
 
 /* Get intersection point of lseg and line; returns NULL if no intersection */
 static Point *
diff --git a/src/include/catalog/pg_operator.h 
b/src/include/catalog/pg_operator.h
index f8b4a65..c31b8a8 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1009,20 +1009,22 @@ DATA(insert OID = 1518 (  "*"     PGNSP PGUID b f f  
718        600  718          0    0 circle_
 DESCR("multiply");
 DATA(insert OID = 1519 (  "/"    PGNSP PGUID b f f  718        600  718        
  0    0 circle_div_pt - - ));
 DESCR("divide");
 
 DATA(insert OID = 1520 (  "<->"   PGNSP PGUID b f f  718       718  701   1520 
   0 circle_distance - - ));
 DESCR("distance between");
 DATA(insert OID = 1521 (  "#"    PGNSP PGUID l f f  0          604   23        
  0    0 poly_npoints - - ));
 DESCR("number of points");
 DATA(insert OID = 1522 (  "<->"   PGNSP PGUID b f f  600       718  701        
  0    0 dist_pc - - ));
 DESCR("distance between");
+DATA(insert OID = 3591 (  "<->"          PGNSP PGUID b f f      600    604     
 701      0        0 dist_ppoly - - ));
+DESCR("distance between");
 DATA(insert OID = 1523 (  "<->"   PGNSP PGUID b f f  718       604  701        
  0    0 dist_cpoly - - ));
 DESCR("distance between");
 
 /* additional geometric operators - thomas 1997-07-09 */
 DATA(insert OID = 1524 (  "<->"   PGNSP PGUID b f f  628       603  701        
  0  0 dist_lb - - ));
 DESCR("distance between");
 
 DATA(insert OID = 1525 (  "?#"   PGNSP PGUID b f f  601        601 16 1525  0 
lseg_intersect - - ));
 DESCR("intersect");
 DATA(insert OID = 1526 (  "?||"   PGNSP PGUID b f f  601       601 16 1526  0 
lseg_parallel - - ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0af1248..95f0b74 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -806,20 +806,21 @@ DESCR("set bit");
 DATA(insert OID = 749 (  overlay                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 4 0 17 "17 17 23 23" _null_ _null_ _null_ _null_        byteaoverlay 
_null_ _null_ _null_ ));
 DESCR("substitute portion of string");
 DATA(insert OID = 752 (  overlay                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 3 0 17 "17 17 23" _null_ _null_ _null_ _null_   byteaoverlay_no_len 
_null_ _null_ _null_ ));
 DESCR("substitute portion of string");
 
 DATA(insert OID = 725 (  dist_pl                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "600 628" _null_ _null_ _null_ _null_   dist_pl _null_ _null_ 
_null_ ));
 DATA(insert OID = 726 (  dist_lb                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "628 603" _null_ _null_ _null_ _null_   dist_lb _null_ _null_ 
_null_ ));
 DATA(insert OID = 727 (  dist_sl                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "601 628" _null_ _null_ _null_ _null_   dist_sl _null_ _null_ 
_null_ ));
 DATA(insert OID = 728 (  dist_cpoly               PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "718 604" _null_ _null_ _null_ _null_   dist_cpoly _null_ 
_null_ _null_ ));
 DATA(insert OID = 729 (  poly_distance    PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "604 604" _null_ _null_ _null_ _null_   poly_distance _null_ _null_ 
_null_ ));
+DATA(insert OID = 3590 (  dist_ppoly      PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "600 604" _null_ _null_ _null_ _null_   dist_ppoly _null_ _null_ _null_ 
));
 
 DATA(insert OID = 740 (  text_lt                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_lt _null_ _null_ _null_ 
));
 DATA(insert OID = 741 (  text_le                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_le _null_ _null_ _null_ 
));
 DATA(insert OID = 742 (  text_gt                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_gt _null_ _null_ _null_ 
));
 DATA(insert OID = 743 (  text_ge                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_ge _null_ _null_ _null_ 
));
 
 DATA(insert OID = 745 (  current_user     PGNSP PGUID 12 1 0 0 0 f f f f t f s 
0 0 19 "" _null_ _null_ _null_ _null_ current_user _null_ _null_ _null_ ));
 DESCR("current user name");
 DATA(insert OID = 746 (  session_user     PGNSP PGUID 12 1 0 0 0 f f f f t f s 
0 0 19 "" _null_ _null_ _null_ _null_ session_user _null_ _null_ _null_ ));
 DESCR("session user name");
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 60b5d01..91610d8 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -388,20 +388,21 @@ extern Datum circle_contain_pt(PG_FUNCTION_ARGS);
 extern Datum pt_contained_circle(PG_FUNCTION_ARGS);
 extern Datum circle_add_pt(PG_FUNCTION_ARGS);
 extern Datum circle_sub_pt(PG_FUNCTION_ARGS);
 extern Datum circle_mul_pt(PG_FUNCTION_ARGS);
 extern Datum circle_div_pt(PG_FUNCTION_ARGS);
 extern Datum circle_diameter(PG_FUNCTION_ARGS);
 extern Datum circle_radius(PG_FUNCTION_ARGS);
 extern Datum circle_distance(PG_FUNCTION_ARGS);
 extern Datum dist_pc(PG_FUNCTION_ARGS);
 extern Datum dist_cpoly(PG_FUNCTION_ARGS);
+extern Datum dist_ppoly(PG_FUNCTION_ARGS);
 extern Datum circle_center(PG_FUNCTION_ARGS);
 extern Datum cr_circle(PG_FUNCTION_ARGS);
 extern Datum box_circle(PG_FUNCTION_ARGS);
 extern Datum circle_box(PG_FUNCTION_ARGS);
 extern Datum poly_circle(PG_FUNCTION_ARGS);
 extern Datum circle_poly(PG_FUNCTION_ARGS);
 extern Datum circle_area(PG_FUNCTION_ARGS);
 
 /* support routines for the GiST access method (access/gist/gistproc.c) */
 extern Datum gist_box_compress(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/polygon.out 
b/src/test/regress/expected/polygon.out
index b252902..b449e32 100644
--- a/src/test/regress/expected/polygon.out
+++ b/src/test/regress/expected/polygon.out
@@ -271,10 +271,22 @@ SELECT 
'((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && '((3,3),(4,3),(
 -------
  f
 (1 row)
 
 SELECT '((200,800),(800,800),(800,200),(200,200))' &&  
'(1000,1000,0,0)'::polygon AS "true";
  true 
 ------
  t
 (1 row)
 
+-- distance from a point
+SELECT
+       '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
+       '(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
+       '(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
+       '(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
+       '(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
+ on_corner | on_segment | inside |   near_corner   | near_segment 
+-----------+------------+--------+-----------------+--------------
+         0 |          0 |      0 | 1.4142135623731 |          3.2
+(1 row)
+
diff --git a/src/test/regress/sql/polygon.sql b/src/test/regress/sql/polygon.sql
index 2dad566..20a7c36 100644
--- a/src/test/regress/sql/polygon.sql
+++ b/src/test/regress/sql/polygon.sql
@@ -164,10 +164,18 @@ SELECT polygon '(2.0,0.0),(2.0,4.0),(0.0,0.0)' && polygon 
'(3.0,1.0),(3.0,3.0),(
 SELECT '((0,4),(6,4),(1,2),(6,0),(0,0))'::polygon && 
'((2,1),(2,3),(3,3),(3,1))'::polygon AS "true";
 
 --     +--+ *--*
 --     |  | |  |
 --     |  | *--*
 --     |  +----+
 --     |       |
 --     +-------+
 SELECT '((1,4),(1,1),(4,1),(4,2),(2,2),(2,4),(1,4))'::polygon && 
'((3,3),(4,3),(4,4),(3,4),(3,3))'::polygon AS "false";
 SELECT '((200,800),(800,800),(800,200),(200,200))' &&  
'(1000,1000,0,0)'::polygon AS "true";
+
+-- distance from a point
+SELECT
+       '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
+       '(1,1)'::point <-> '((0,0),(2,2),(1,3))'::polygon as on_segment,
+       '(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
+       '(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
+       '(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml
index 0158b17..2cfe9e8 100644
--- a/doc/src/sgml/gist.sgml
+++ b/doc/src/sgml/gist.sgml
@@ -98,20 +98,21 @@
        <literal>&lt;&lt;|</>
        <literal>&lt;@</>
        <literal>@&gt;</>
        <literal>@</>
        <literal>|&amp;&gt;</>
        <literal>|&gt;&gt;</>
        <literal>~</>
        <literal>~=</>
       </entry>
       <entry>
+       <literal>&lt;-&gt;</>
       </entry>
      </row>
      <row>
       <entry><literal>inet_ops</></entry>
       <entry><type>inet</>, <type>cidr</></entry>
       <entry>
        <literal>&amp;&amp;</>
        <literal>&gt;&gt;</>
        <literal>&gt;&gt;=</>
        <literal>&gt;</>
@@ -156,20 +157,21 @@
        <literal>&lt;&lt;|</>
        <literal>&lt;@</>
        <literal>@&gt;</>
        <literal>@</>
        <literal>|&amp;&gt;</>
        <literal>|&gt;&gt;</>
        <literal>~</>
        <literal>~=</>
       </entry>
       <entry>
+       <literal>&lt;-&gt;</>
       </entry>
      </row>
      <row>
       <entry><literal>range_ops</></entry>
       <entry>any range type</entry>
       <entry>
        <literal>&amp;&amp;</>
        <literal>&amp;&gt;</>
        <literal>&amp;&lt;</>
        <literal>&gt;&gt;</>
@@ -200,20 +202,26 @@
        <literal>@@</>
       </entry>
       <entry>
       </entry>
      </row>
     </tbody>
    </tgroup>
   </table>
 
  <para>
+  Currently, ordering by the distance operator <literal>&lt;-&gt;</>
+  is supported only with <literal>point</> by the operator classes
+  of the geometric types.
+ </para>
+
+ <para>
   For historical reasons, the <literal>inet_ops</> operator class is
   not the default class for types <type>inet</> and <type>cidr</>.
   To use it, mention the class name in <command>CREATE INDEX</>,
   for example
 <programlisting>
 CREATE INDEX ON my_table USING gist (my_inet_column inet_ops);
 </programlisting>
  </para>
 
 </sect1>
@@ -759,56 +767,62 @@ my_same(PG_FUNCTION_ARGS)
        so the results must be consistent with the operator's semantics.
        For a leaf index entry the result just represents the distance to
        the index entry; for an internal tree node, the result must be the
        smallest distance that any child entry could have.
       </para>
 
       <para>
         The <acronym>SQL</> declaration of the function must look like this:
 
 <programlisting>
-CREATE OR REPLACE FUNCTION my_distance(internal, data_type, smallint, oid)
+CREATE OR REPLACE FUNCTION my_distance(internal, data_type, smallint, oid, 
internal)
 RETURNS float8
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT;
 </programlisting>
 
         And the matching code in the C module could then follow this skeleton:
 
 <programlisting>
 Datum       my_distance(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(my_distance);
 
 Datum
 my_distance(PG_FUNCTION_ARGS)
 {
     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     data_type  *query = PG_GETARG_DATA_TYPE_P(1);
     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     /* Oid subtype = PG_GETARG_OID(3); */
+    bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     data_type  *key = DatumGetDataType(entry-&gt;key);
     double      retval;
 
     /*
      * determine return value as a function of strategy, key and query.
      */
 
     PG_RETURN_FLOAT8(retval);
 }
 </programlisting>
 
        The arguments to the <function>distance</> function are identical to
-       the arguments of the <function>consistent</> function, except that no
-       recheck flag is used.  The distance to a leaf index entry must always
-       be determined exactly, since there is no way to re-order the tuples
-       once they are returned.  Some approximation is allowed when determining
-       the distance to an internal tree node, so long as the result is never
+       the arguments of the <function>consistent</> function.  When
+       <literal>recheck = true</> then value of distance will
+       be rechecked from heap tuple before tuple is returned.  If
+       <literal>recheck</> flag isn't set then it's true by default for
+       compatibility reasons.  The <literal>recheck</> flag can be used only
+       when ordering operator returns <type>float8</> value comparable with
+       result of <function>distance</> function.  Result of distance function
+       should be never greater than result of ordering operator.
+       Same approximation is allowed when determining the distance to an
+       internal tree node, so long as the result is never
        greater than any child's actual distance.  Thus, for example, distance
        to a bounding box is usually sufficient in geometric applications.  The
        result value can be any finite <type>float8</> value.  (Infinity and
        minus infinity are used internally to handle cases such as nulls, so it
        is not recommended that <function>distance</> functions return these
        values.)
       </para>
 
      </listitem>
     </varlistentry>
diff --git a/src/backend/access/gist/gistget.c 
b/src/backend/access/gist/gistget.c
index 7a8692b..7be050d 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -9,20 +9,21 @@
  *
  * IDENTIFICATION
  *       src/backend/access/gist/gistget.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
+#include "catalog/index.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 
 /*
  * gistindex_keytest() -- does this index tuple satisfy the scan key(s)?
  *
@@ -48,38 +49,41 @@ static bool
 gistindex_keytest(IndexScanDesc scan,
                                  IndexTuple tuple,
                                  Page page,
                                  OffsetNumber offset,
                                  bool *recheck_p)
 {
        GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
        GISTSTATE  *giststate = so->giststate;
        ScanKey         key = scan->keyData;
        int                     keySize = scan->numberOfKeys;
-       double     *distance_p;
+       GISTSearchTreeItemDistance *distance_p;
        Relation        r = scan->indexRelation;
 
        *recheck_p = false;
 
        /*
         * If it's a leftover invalid tuple from pre-9.1, treat it as a match 
with
         * minimum possible distances.  This means we'll always follow it to the
         * referenced page.
         */
        if (GistTupleIsInvalid(tuple))
        {
                int                     i;
 
                if (GistPageIsLeaf(page))               /* shouldn't happen */
                        elog(ERROR, "invalid GiST tuple found on leaf page");
                for (i = 0; i < scan->numberOfOrderBys; i++)
-                       so->distances[i] = -get_float8_infinity();
+               {
+                       so->distances[i].value = -get_float8_infinity();
+                       so->distances[i].recheck = false;
+               }
                return true;
        }
 
        /* Check whether it matches according to the Consistent functions */
        while (keySize > 0)
        {
                Datum           datum;
                bool            isNull;
 
                datum = index_getattr(tuple,
@@ -163,53 +167,56 @@ gistindex_keytest(IndexScanDesc scan,
                bool            isNull;
 
                datum = index_getattr(tuple,
                                                          key->sk_attno,
                                                          giststate->tupdesc,
                                                          &isNull);
 
                if ((key->sk_flags & SK_ISNULL) || isNull)
                {
                        /* Assume distance computes as null and sorts to the 
end */
-                       *distance_p = get_float8_infinity();
+                       distance_p->value = get_float8_infinity();
+                       distance_p->recheck = false;
                }
                else
                {
                        Datum           dist;
                        GISTENTRY       de;
 
                        gistdentryinit(giststate, key->sk_attno - 1, &de,
                                                   datum, r, page, offset,
                                                   FALSE, isNull);
 
                        /*
                         * Call the Distance function to evaluate the distance. 
 The
                         * arguments are the index datum (as a GISTENTRY*), the 
comparison
                         * datum, and the ordering operator's strategy number 
and subtype
                         * from pg_amop.
                         *
                         * (Presently there's no need to pass the subtype since 
it'll
                         * always be zero, but might as well pass it for 
possible future
                         * use.)
                         *
-                        * Note that Distance functions don't get a recheck 
argument. We
-                        * can't tolerate lossy distance calculations on leaf 
tuples;
-                        * there is no opportunity to re-sort the tuples 
afterwards.
+                        * Distance function gets a recheck argument as well as 
consistent
+                        * function.  Distance will be re-calculated from heap 
tuple when
+                        * needed.
                         */
-                       dist = FunctionCall4Coll(&key->sk_func,
+                       distance_p->recheck = false;
+                       dist = FunctionCall5Coll(&key->sk_func,
                                                                         
key->sk_collation,
                                                                         
PointerGetDatum(&de),
                                                                         
key->sk_argument,
                                                                         
Int32GetDatum(key->sk_strategy),
-                                                                        
ObjectIdGetDatum(key->sk_subtype));
+                                                                        
ObjectIdGetDatum(key->sk_subtype),
+                                                                        
PointerGetDatum(&distance_p->recheck));
 
-                       *distance_p = DatumGetFloat8(dist);
+                       distance_p->value = DatumGetFloat8(dist);
                }
 
                key++;
                distance_p++;
                keySize--;
        }
 
        return true;
 }
 
@@ -227,21 +234,21 @@ gistindex_keytest(IndexScanDesc scan,
  * tuples should be reported directly into the bitmap.  If they are NULL,
  * we're doing a plain or ordered indexscan.  For a plain indexscan, heap
  * tuple TIDs are returned into so->pageData[].  For an ordered indexscan,
  * heap tuple TIDs are pushed into individual search queue items.
  *
  * If we detect that the index page has split since we saw its downlink
  * in the parent, we push its new right sibling onto the queue so the
  * sibling will be processed next.
  */
 static void
-gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances,
+gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, 
GISTSearchTreeItemDistance *myDistances,
                         TIDBitmap *tbm, int64 *ntids)
 {
        GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
        Buffer          buffer;
        Page            page;
        GISTPageOpaque opaque;
        OffsetNumber maxoff;
        OffsetNumber i;
        GISTSearchTreeItem *tmpItem = so->tmpTreeItem;
        bool            isNew;
@@ -277,21 +284,21 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem 
*pageItem, double *myDistances,
                /* Create new GISTSearchItem for the right sibling index page */
                item = palloc(sizeof(GISTSearchItem));
                item->next = NULL;
                item->blkno = opaque->rightlink;
                item->data.parentlsn = pageItem->data.parentlsn;
 
                /* Insert it into the queue using same distances as for this 
page */
                tmpItem->head = item;
                tmpItem->lastHeap = NULL;
                memcpy(tmpItem->distances, myDistances,
-                          sizeof(double) * scan->numberOfOrderBys);
+                          sizeof(GISTSearchTreeItemDistance) * 
scan->numberOfOrderBys);
 
                (void) rb_insert(so->queue, (RBNode *) tmpItem, &isNew);
 
                MemoryContextSwitchTo(oldcxt);
        }
 
        so->nPageData = so->curPageData = 0;
 
        /*
         * check all tuples on page
@@ -368,63 +375,166 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem 
*pageItem, double *myDistances,
                                 * only have a shared lock, so we need to get 
the LSN
                                 * atomically.
                                 */
                                item->data.parentlsn = 
BufferGetLSNAtomic(buffer);
                        }
 
                        /* Insert it into the queue using new distance data */
                        tmpItem->head = item;
                        tmpItem->lastHeap = GISTSearchItemIsHeap(*item) ? item 
: NULL;
                        memcpy(tmpItem->distances, so->distances,
-                                  sizeof(double) * scan->numberOfOrderBys);
+                                  sizeof(GISTSearchTreeItemDistance) * 
scan->numberOfOrderBys);
 
                        (void) rb_insert(so->queue, (RBNode *) tmpItem, &isNew);
 
                        MemoryContextSwitchTo(oldcxt);
                }
        }
 
        UnlockReleaseBuffer(buffer);
 }
 
 /*
+ * Do this tree item distance values needs recheck?
+ */
+static bool
+searchTreeItemNeedDistanceRecheck(IndexScanDesc scan, GISTSearchTreeItem *item)
+{
+       int i;
+       for (i = 0; i < scan->numberOfOrderBys; i++)
+       {
+               if (item->distances[i].recheck)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * Recheck distance values of item from heap and reinsert it into RB-tree.
+ */
+static void
+searchTreeItemDistanceRecheck(IndexScanDesc scan, GISTSearchTreeItem *treeItem,
+               GISTSearchItem *item)
+{
+       GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
+       GISTSearchTreeItem *tmpItem = so->tmpTreeItem;
+       Buffer  buffer;
+       bool    got_heap_tuple, all_dead;
+       HeapTupleData tup;
+       Datum   values[INDEX_MAX_KEYS];
+       bool    isnull[INDEX_MAX_KEYS];
+       bool    isNew;
+       int             i;
+
+       /* Get tuple from heap */
+       buffer = ReadBuffer(scan->heapRelation,
+                       ItemPointerGetBlockNumber(&item->data.heap.heapPtr));
+       LockBuffer(buffer, BUFFER_LOCK_SHARE);
+       got_heap_tuple = heap_hot_search_buffer(&item->data.heap.heapPtr,
+                                                                               
        scan->heapRelation,
+                                                                               
        buffer,
+                                                                               
        scan->xs_snapshot,
+                                                                               
        &tup,
+                                                                               
        &all_dead,
+                                                                               
        true);
+       if (!got_heap_tuple)
+       {
+               /*
+                * Tuple not found: it has been deleted from heap.  We don't 
have to
+                * reinsert it into RB-tree.
+                */
+               UnlockReleaseBuffer(buffer);
+               pfree(item);
+               return;
+       }
+
+       /* Calculate index datums */
+       ExecStoreTuple(&tup, so->slot, InvalidBuffer, false);
+       FormIndexDatum(so->indexInfo, so->slot, so->estate, values, isnull);
+
+       /* Prepare new tree item and reinsert it */
+       memcpy(tmpItem, treeItem, GSTIHDRSZ + 
sizeof(GISTSearchTreeItemDistance) *
+                                                                               
  scan->numberOfOrderBys);
+       tmpItem->head = item;
+       tmpItem->lastHeap = item;
+       item->next = NULL;
+       for (i = 0; i < scan->numberOfOrderBys; i++)
+       {
+               if (tmpItem->distances[i].recheck)
+               {
+                       /* Re-calculate lossy distance */
+                       ScanKey key = scan->orderByData + i;
+                       float8  newDistance;
+
+                       tmpItem->distances[i].recheck = false;
+                       if (isnull[key->sk_attno - 1])
+                       {
+                               tmpItem->distances[i].value = 
-get_float8_infinity();
+                               continue;
+                       }
+
+                       newDistance = DatumGetFloat8(
+                               FunctionCall2Coll(&so->orderByRechecks[i],
+                                        key->sk_collation,
+                                        values[key->sk_attno - 1],
+                                        key->sk_argument));
+
+                       tmpItem->distances[i].value = newDistance;
+
+               }
+       }
+       (void) rb_insert(so->queue, (RBNode *) tmpItem, &isNew);
+       UnlockReleaseBuffer(buffer);
+}
+
+/*
  * Extract next item (in order) from search queue
  *
  * Returns a GISTSearchItem or NULL.  Caller must pfree item when done with it.
  *
  * NOTE: on successful return, so->curTreeItem is the GISTSearchTreeItem that
  * contained the result item.  Callers can use so->curTreeItem->distances as
  * the distances value for the item.
  */
 static GISTSearchItem *
-getNextGISTSearchItem(GISTScanOpaque so)
+getNextGISTSearchItem(IndexScanDesc scan)
 {
+       GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
+
        for (;;)
        {
                GISTSearchItem *item;
 
                /* Update curTreeItem if we don't have one */
                if (so->curTreeItem == NULL)
                {
                        so->curTreeItem = (GISTSearchTreeItem *) 
rb_leftmost(so->queue);
                        /* Done when tree is empty */
                        if (so->curTreeItem == NULL)
                                break;
                }
 
                item = so->curTreeItem->head;
                if (item != NULL)
                {
                        /* Delink item from chain */
                        so->curTreeItem->head = item->next;
                        if (item == so->curTreeItem->lastHeap)
                                so->curTreeItem->lastHeap = NULL;
+
+                       /* Recheck distance from heap tuple if needed */
+                       if (GISTSearchItemIsHeap(*item) &&
+                               searchTreeItemNeedDistanceRecheck(scan, 
so->curTreeItem))
+                       {
+                               searchTreeItemDistanceRecheck(scan, 
so->curTreeItem, item);
+                               continue;
+                       }
                        /* Return item; caller is responsible to pfree it */
                        return item;
                }
 
                /* curTreeItem is exhausted, so remove it from rbtree */
                rb_delete(so->queue, (RBNode *) so->curTreeItem);
                so->curTreeItem = NULL;
        }
 
        return NULL;
@@ -434,21 +544,21 @@ getNextGISTSearchItem(GISTScanOpaque so)
  * Fetch next heap tuple in an ordered search
  */
 static bool
 getNextNearest(IndexScanDesc scan)
 {
        GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
        bool            res = false;
 
        do
        {
-               GISTSearchItem *item = getNextGISTSearchItem(so);
+               GISTSearchItem *item = getNextGISTSearchItem(scan);
 
                if (!item)
                        break;
 
                if (GISTSearchItemIsHeap(*item))
                {
                        /* found a heap item at currently minimal distance */
                        scan->xs_ctup.t_self = item->data.heap.heapPtr;
                        scan->xs_recheck = item->data.heap.recheck;
                        res = true;
@@ -514,21 +624,21 @@ gistgettuple(PG_FUNCTION_ARGS)
                                /* continuing to return tuples from a leaf page 
*/
                                scan->xs_ctup.t_self = 
so->pageData[so->curPageData].heapPtr;
                                scan->xs_recheck = 
so->pageData[so->curPageData].recheck;
                                so->curPageData++;
                                PG_RETURN_BOOL(true);
                        }
 
                        /* find and process the next index page */
                        do
                        {
-                               GISTSearchItem *item = 
getNextGISTSearchItem(so);
+                               GISTSearchItem *item = 
getNextGISTSearchItem(scan);
 
                                if (!item)
                                        PG_RETURN_BOOL(false);
 
                                CHECK_FOR_INTERRUPTS();
 
                                /*
                                 * While scanning a leaf page, ItemPointers of 
matching heap
                                 * tuples are stored in so->pageData.  If there 
are any on
                                 * this page, we fall out of the inner "do" and 
loop around to
@@ -566,21 +676,21 @@ gistgetbitmap(PG_FUNCTION_ARGS)
        fakeItem.blkno = GIST_ROOT_BLKNO;
        memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
        gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
 
        /*
         * While scanning a leaf page, ItemPointers of matching heap tuples will
         * be stored directly into tbm, so we don't need to deal with them here.
         */
        for (;;)
        {
-               GISTSearchItem *item = getNextGISTSearchItem(so);
+               GISTSearchItem *item = getNextGISTSearchItem(scan);
 
                if (!item)
                        break;
 
                CHECK_FOR_INTERRUPTS();
 
                gistScanPage(scan, item, so->curTreeItem->distances, tbm, 
&ntids);
 
                pfree(item);
        }
diff --git a/src/backend/access/gist/gistproc.c 
b/src/backend/access/gist/gistproc.c
index db0bec6..fd3546a 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -1091,20 +1091,21 @@ gist_poly_consistent(PG_FUNCTION_ARGS)
         */
        result = rtree_internal_consistent(DatumGetBoxP(entry->key),
                                                                           
&(query->boundbox), strategy);
 
        /* Avoid memory leak if supplied poly is toasted */
        PG_FREE_IF_COPY(query, 1);
 
        PG_RETURN_BOOL(result);
 }
 
+
 /**************************************************
  * Circle ops
  **************************************************/
 
 /*
  * GiST compress for circles: represent a circle by its bounding box
  */
 Datum
 gist_circle_compress(PG_FUNCTION_ARGS)
 {
@@ -1452,10 +1453,44 @@ gist_point_distance(PG_FUNCTION_ARGS)
                                                                           
PG_GETARG_POINT_P(1));
                        break;
                default:
                        elog(ERROR, "unrecognized strategy number: %d", 
strategy);
                        distance = 0.0;         /* keep compiler quiet */
                        break;
        }
 
        PG_RETURN_FLOAT8(distance);
 }
+
+/*
+ * The inexact GiST distance method for geometric types
+ *
+ * Compute lossy distance from point to index entries.  The result is inexact
+ * because index entries are bounding boxes, not the exact shapes of the
+ * indexed geometric types.  We use distance from point to MBR of index entry.
+ * This is correct lower bound estimate of distance from point to indexed
+ * geometric type.
+ */
+Datum
+gist_inexact_distance(PG_FUNCTION_ARGS)
+{
+       GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+       bool       *recheck = (bool *) PG_GETARG_POINTER(4);
+       double          distance;
+       StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
+       *recheck = true;
+
+       switch (strategyGroup)
+       {
+               case PointStrategyNumberGroup:
+                       distance = computeDistance(false,
+                                                                          
DatumGetBoxP(entry->key),
+                                                                          
PG_GETARG_POINT_P(1));
+                       break;
+               default:
+                       elog(ERROR, "unknown strategy number: %d", strategy);
+                       distance = 0.0;         /* keep compiler quiet */
+       }
+
+       PG_RETURN_FLOAT8(distance);
+}
diff --git a/src/backend/access/gist/gistscan.c 
b/src/backend/access/gist/gistscan.c
index 8360b16..9bb8294 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -10,41 +10,54 @@
  * IDENTIFICATION
  *       src/backend/access/gist/gistscan.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/gistscan.h"
 #include "access/relscan.h"
+#include "catalog/index.h"
+#include "executor/executor.h"
+#include "executor/tuptable.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 
 /*
  * RBTree support functions for the GISTSearchTreeItem queue
  */
 
 static int
 GISTSearchTreeItemComparator(const RBNode *a, const RBNode *b, void *arg)
 {
        const GISTSearchTreeItem *sa = (const GISTSearchTreeItem *) a;
        const GISTSearchTreeItem *sb = (const GISTSearchTreeItem *) b;
        IndexScanDesc scan = (IndexScanDesc) arg;
        int                     i;
 
        /* Order according to distance comparison */
        for (i = 0; i < scan->numberOfOrderBys; i++)
        {
-               if (sa->distances[i] != sb->distances[i])
-                       return (sa->distances[i] > sb->distances[i]) ? 1 : -1;
+               const GISTSearchTreeItemDistance distance_a = sa->distances[i];
+               const GISTSearchTreeItemDistance distance_b = sb->distances[i];
+
+               if (distance_a.value != distance_b.value)
+                       return (distance_a.value > distance_b.value) ? 1 : -1;
+
+               /*
+                * Items without recheck can be immediately returned.  So they 
are
+                * placed first.
+                */
+               if (distance_a.recheck != distance_b.recheck)
+                       return distance_a.recheck ? 1 : -1;
        }
 
        return 0;
 }
 
 static void
 GISTSearchTreeItemCombiner(RBNode *existing, const RBNode *newrb, void *arg)
 {
        GISTSearchTreeItem *scurrent = (GISTSearchTreeItem *) existing;
        const GISTSearchTreeItem *snew = (const GISTSearchTreeItem *) newrb;
@@ -76,21 +89,21 @@ GISTSearchTreeItemCombiner(RBNode *existing, const RBNode 
*newrb, void *arg)
                newitem->next = scurrent->lastHeap->next;
                scurrent->lastHeap->next = newitem;
        }
 }
 
 static RBNode *
 GISTSearchTreeItemAllocator(void *arg)
 {
        IndexScanDesc scan = (IndexScanDesc) arg;
 
-       return palloc(GSTIHDRSZ + sizeof(double) * scan->numberOfOrderBys);
+       return palloc(GSTIHDRSZ + sizeof(GISTSearchTreeItemDistance) * 
scan->numberOfOrderBys);
 }
 
 static void
 GISTSearchTreeItemDeleter(RBNode *rb, void *arg)
 {
        pfree(rb);
 }
 
 
 /*
@@ -120,24 +133,36 @@ gistbeginscan(PG_FUNCTION_ARGS)
        oldCxt = MemoryContextSwitchTo(giststate->scanCxt);
 
        /* initialize opaque data */
        so = (GISTScanOpaque) palloc0(sizeof(GISTScanOpaqueData));
        so->giststate = giststate;
        giststate->tempCxt = createTempGistContext();
        so->queue = NULL;
        so->queueCxt = giststate->scanCxt;      /* see gistrescan */
 
        /* workspaces with size dependent on numberOfOrderBys: */
-       so->tmpTreeItem = palloc(GSTIHDRSZ + sizeof(double) * 
scan->numberOfOrderBys);
-       so->distances = palloc(sizeof(double) * scan->numberOfOrderBys);
+       so->tmpTreeItem = palloc(GSTIHDRSZ + sizeof(GISTSearchTreeItemDistance) 
*
+                                                                               
 scan->numberOfOrderBys);
+       so->distances = palloc(sizeof(GISTSearchTreeItemDistance) *
+                                                  scan->numberOfOrderBys);
        so->qual_ok = true;                     /* in case there are zero keys 
*/
 
+       if (scan->numberOfOrderBys > 0)
+       {
+               /* Prepare data structures for distance recheck from heap tuple 
*/
+
+               so->orderByRechecks = (FmgrInfo *)palloc(sizeof(FmgrInfo)
+                                                                               
                        * scan->numberOfOrderBys);
+               so->indexInfo = BuildIndexInfo(scan->indexRelation);
+               so->estate = CreateExecutorState();
+       }
+
        scan->opaque = so;
 
        MemoryContextSwitchTo(oldCxt);
 
        PG_RETURN_POINTER(scan);
 }
 
 Datum
 gistrescan(PG_FUNCTION_ARGS)
 {
@@ -179,23 +204,30 @@ gistrescan(PG_FUNCTION_ARGS)
                                                                                
         ALLOCSET_DEFAULT_MAXSIZE);
                first_time = false;
        }
        else
        {
                /* third or later time through */
                MemoryContextReset(so->queueCxt);
                first_time = false;
        }
 
+       if (scan->numberOfOrderBys > 0 && !so->slot)
+       {
+               /* Prepare heap tuple slot for distance recheck */
+               so->slot = 
MakeSingleTupleTableSlot(RelationGetDescr(scan->heapRelation));
+       }
+
        /* create new, empty RBTree for search queue */
        oldCxt = MemoryContextSwitchTo(so->queueCxt);
-       so->queue = rb_create(GSTIHDRSZ + sizeof(double) * 
scan->numberOfOrderBys,
+       so->queue = rb_create(GSTIHDRSZ + sizeof(GISTSearchTreeItemDistance) *
+                                                                         
scan->numberOfOrderBys,
                                                  GISTSearchTreeItemComparator,
                                                  GISTSearchTreeItemCombiner,
                                                  GISTSearchTreeItemAllocator,
                                                  GISTSearchTreeItemDeleter,
                                                  scan);
        MemoryContextSwitchTo(oldCxt);
 
        so->curTreeItem = NULL;
        so->firstCall = true;
 
@@ -282,20 +314,24 @@ gistrescan(PG_FUNCTION_ARGS)
                {
                        ScanKey         skey = scan->orderByData + i;
                        FmgrInfo   *finfo = 
&(so->giststate->distanceFn[skey->sk_attno - 1]);
 
                        /* Check we actually have a distance function ... */
                        if (!OidIsValid(finfo->fn_oid))
                                elog(ERROR, "missing support function %d for 
attribute %d of index \"%s\"",
                                         GIST_DISTANCE_PROC, skey->sk_attno,
                                         
RelationGetRelationName(scan->indexRelation));
 
+                       /* Copy original sk_func for distance recheck from heap 
tuple */
+                       fmgr_info_copy(&so->orderByRechecks[i], 
&(skey->sk_func),
+                                                  so->giststate->scanCxt);
+
                        fmgr_info_copy(&(skey->sk_func), finfo, 
so->giststate->scanCxt);
 
                        /* Restore prior fn_extra pointers, if not first time */
                        if (!first_time)
                                skey->sk_func.fn_extra = fn_extras[i];
                }
 
                if (!first_time)
                        pfree(fn_extras);
        }
@@ -316,18 +352,21 @@ gistrestrpos(PG_FUNCTION_ARGS)
        elog(ERROR, "GiST does not support mark/restore");
        PG_RETURN_VOID();
 }
 
 Datum
 gistendscan(PG_FUNCTION_ARGS)
 {
        IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
        GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
 
+       if (so->slot)
+               ExecDropSingleTupleTableSlot(so->slot);
+
        /*
         * freeGISTstate is enough to clean up everything made by gistbeginscan,
         * as well as the queueCxt if there is a separate context for it.
         */
        freeGISTstate(so->giststate);
 
        PG_RETURN_VOID();
 }
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 402ea40..c9788e4 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -63,20 +63,21 @@ static int  pair_encode(float8 x, float8 y, char *str);
 static int     pair_count(char *s, char delim);
 static int     path_decode(int opentype, int npts, char *str, int *isopen, 
char **ss, Point *p);
 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 static double box_ar(BOX *box);
 static void box_cn(Point *center, BOX *box);
 static Point *interpt_sl(LSEG *lseg, LINE *line);
 static bool has_interpt_sl(LSEG *lseg, LINE *line);
 static double dist_pl_internal(Point *pt, LINE *line);
 static double dist_ps_internal(Point *pt, LSEG *lseg);
+static float8 dist_ppoly_internal(Point *point, POLYGON *poly);
 static Point *line_interpt_internal(LINE *l1, LINE *l2);
 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
 static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
 
 
 /*
  * Delimiters for input and output strings.
  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, 
respectively.
  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
  */
@@ -2634,20 +2635,52 @@ dist_lb(PG_FUNCTION_ARGS)
 
        /* need to think about this one for a while */
        ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("function \"dist_lb\" not implemented")));
 
        PG_RETURN_NULL();
 }
 
 /*
+ * Distance from a point to a circle
+ */
+Datum
+dist_pc(PG_FUNCTION_ARGS)
+{
+       Point      *point = PG_GETARG_POINT_P(0);
+       CIRCLE     *circle = PG_GETARG_CIRCLE_P(1);
+       float8          result;
+
+       result = point_dt(point, &circle->center) - circle->radius;
+       if (result < 0)
+               result = 0;
+       PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * Distance from a circle to a point
+ */
+Datum
+dist_cpoint(PG_FUNCTION_ARGS)
+{
+       CIRCLE     *circle = PG_GETARG_CIRCLE_P(0);
+       Point      *point = PG_GETARG_POINT_P(1);
+       float8          result;
+
+       result = point_dt(point, &circle->center) - circle->radius;
+       if (result < 0)
+               result = 0;
+       PG_RETURN_FLOAT8(result);
+}
+
+/*
  * Distance from a circle to a polygon
  */
 Datum
 dist_cpoly(PG_FUNCTION_ARGS)
 {
        CIRCLE     *circle = PG_GETARG_CIRCLE_P(0);
        POLYGON    *poly = PG_GETARG_POLYGON_P(1);
        float8          result;
        float8          d;
        int                     i;
@@ -2692,33 +2725,48 @@ dist_cpoly(PG_FUNCTION_ARGS)
 
        PG_RETURN_FLOAT8(result);
 }
 
 /*
  * Distance from a point to a polygon
  */
 Datum
 dist_ppoly(PG_FUNCTION_ARGS)
 {
-       Point      *point = PG_GETARG_POINT_P(0);
-       POLYGON    *poly = PG_GETARG_POLYGON_P(1);
+       PG_RETURN_FLOAT8(dist_ppoly_internal(PG_GETARG_POINT_P(0),
+                                                                               
 PG_GETARG_POLYGON_P(1)));
+}
+
+/*
+ * Distance from a polygon to a point
+ */
+Datum
+dist_polyp(PG_FUNCTION_ARGS)
+{
+       PG_RETURN_FLOAT8(dist_ppoly_internal(PG_GETARG_POINT_P(1),
+                                                                               
 PG_GETARG_POLYGON_P(0)));
+}
+
+static float8
+dist_ppoly_internal(Point *point, POLYGON *poly)
+{
        float8          result;
        float8          distance;
        int                     i;
        LSEG            seg;
 
        if (point_inside(point, poly->npts, poly->p) != 0)
        {
 #ifdef GEODEBUG
                printf("dist_ppoly- point inside of polygon\n");
 #endif
-               PG_RETURN_FLOAT8(0.0);
+               return 0.0;
        }
 
        /* initialize distance with segment between first and last points */
        seg.p[0].x = poly->p[0].x;
        seg.p[0].y = poly->p[0].y;
        seg.p[1].x = poly->p[poly->npts - 1].x;
        seg.p[1].y = poly->p[poly->npts - 1].y;
        result = dist_ps_internal(point, &seg);
 #ifdef GEODEBUG
        printf("dist_ppoly- segment 0/n distance is %f\n", result);
@@ -2732,21 +2780,21 @@ dist_ppoly(PG_FUNCTION_ARGS)
                seg.p[1].x = poly->p[i + 1].x;
                seg.p[1].y = poly->p[i + 1].y;
                distance = dist_ps_internal(point, &seg);
 #ifdef GEODEBUG
                printf("dist_ppoly- segment %d distance is %f\n", i + 1, 
distance);
 #endif
                if (distance < result)
                        result = distance;
        }
 
-       PG_RETURN_FLOAT8(result);
+       return result;
 }
 
 
 /*---------------------------------------------------------------------
  *             interpt_
  *                             Intersection point of objects.
  *                             We choose to ignore the "point" of intersection 
between
  *                               lines and boxes, since there are typically 
two.
  *-------------------------------------------------------------------*/
 
@@ -5091,37 +5139,20 @@ pt_contained_circle(PG_FUNCTION_ARGS)
 {
        Point      *point = PG_GETARG_POINT_P(0);
        CIRCLE     *circle = PG_GETARG_CIRCLE_P(1);
        double          d;
 
        d = point_dt(&circle->center, point);
        PG_RETURN_BOOL(d <= circle->radius);
 }
 
 
-/*             dist_pc -               returns the distance between
- *                                               a point and a circle.
- */
-Datum
-dist_pc(PG_FUNCTION_ARGS)
-{
-       Point      *point = PG_GETARG_POINT_P(0);
-       CIRCLE     *circle = PG_GETARG_CIRCLE_P(1);
-       float8          result;
-
-       result = point_dt(point, &circle->center) - circle->radius;
-       if (result < 0)
-               result = 0;
-       PG_RETURN_FLOAT8(result);
-}
-
-
 /*             circle_center   -               returns the center point of the 
circle.
  */
 Datum
 circle_center(PG_FUNCTION_ARGS)
 {
        CIRCLE     *circle = PG_GETARG_CIRCLE_P(0);
        Point      *result;
 
        result = (Point *) palloc(sizeof(Point));
        result->x = circle->center.x;
diff --git a/src/include/access/gist_private.h 
b/src/include/access/gist_private.h
index 03e9903..6f98583 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -9,21 +9,23 @@
  *
  * src/include/access/gist_private.h
  *
  *-------------------------------------------------------------------------
  */
 #ifndef GIST_PRIVATE_H
 #define GIST_PRIVATE_H
 
 #include "access/gist.h"
 #include "access/itup.h"
+#include "executor/tuptable.h"
 #include "fmgr.h"
+#include "nodes/execnodes.h"
 #include "storage/bufmgr.h"
 #include "storage/buffile.h"
 #include "utils/rbtree.h"
 #include "utils/hsearch.h"
 
 /*
  * Maximum number of "halves" a page can be split into in one operation.
  * Typically a split produces 2 halves, but can be more if keys have very
  * different lengths, or when inserting multiple keys in one operation (as
  * when inserting downlinks to an internal node).  There is no theoretical
@@ -128,55 +130,70 @@ typedef struct GISTSearchItem
        {
                GistNSN         parentlsn;      /* parent page's LSN, if index 
page */
                /* we must store parentlsn to detect whether a split occurred */
                GISTSearchHeapItem heap;        /* heap info, if heap tuple */
        }                       data;
 } GISTSearchItem;
 
 #define GISTSearchItemIsHeap(item)     ((item).blkno == InvalidBlockNumber)
 
 /*
+ * KNN distance item: distance which can be rechecked from heap tuple.
+ */
+typedef struct GISTSearchTreeItemDistance
+{
+       double  value;
+       bool    recheck;
+} GISTSearchTreeItemDistance;
+
+/*
  * Within a GISTSearchTreeItem's chain, heap items always appear before
  * index-page items, since we want to visit heap items first.  lastHeap points
  * to the last heap item in the chain, or is NULL if there are none.
  */
 typedef struct GISTSearchTreeItem
 {
        RBNode          rbnode;                 /* this is an RBTree item */
        GISTSearchItem *head;           /* first chain member */
        GISTSearchItem *lastHeap;       /* last heap-tuple member, if any */
-       double          distances[1];   /* array with numberOfOrderBys entries 
*/
+       GISTSearchTreeItemDistance      distances[1];   /* array with 
numberOfOrderBys entries */
 } GISTSearchTreeItem;
 
 #define GSTIHDRSZ offsetof(GISTSearchTreeItem, distances)
 
 /*
  * GISTScanOpaqueData: private state for a scan of a GiST index
  */
 typedef struct GISTScanOpaqueData
 {
        GISTSTATE  *giststate;          /* index information, see above */
        RBTree     *queue;                      /* queue of unvisited items */
        MemoryContext queueCxt;         /* context holding the queue */
        bool            qual_ok;                /* false if qual can never be 
satisfied */
        bool            firstCall;              /* true until first 
gistgettuple call */
 
        GISTSearchTreeItem *curTreeItem;        /* current queue item, if any */
 
        /* pre-allocated workspace arrays */
        GISTSearchTreeItem *tmpTreeItem;        /* workspace to pass to 
rb_insert */
-       double     *distances;          /* output area for gistindex_keytest */
+       GISTSearchTreeItemDistance *distances; /* output area for 
gistindex_keytest */
 
        /* In a non-ordered search, returnable heap items are stored here: */
        GISTSearchHeapItem pageData[BLCKSZ / sizeof(IndexTupleData)];
        OffsetNumber nPageData;         /* number of valid items in array */
        OffsetNumber curPageData;       /* next item to return */
+
+       /* Data structures for performing recheck of lossy knn distance */
+       FmgrInfo        *orderByRechecks;       /* functions for lossy knn 
distance recheck */
+       IndexInfo       *indexInfo;             /* index info for index tuple 
calculation */
+       TupleTableSlot *slot;           /* heap tuple slot */
+       EState          *estate;                /* executor state for index 
tuple calculation */
 } GISTScanOpaqueData;
 
 typedef GISTScanOpaqueData *GISTScanOpaque;
 
 
 /* XLog stuff */
 
 #define XLOG_GIST_PAGE_UPDATE          0x00
  /* #define XLOG_GIST_NEW_ROOT                  0x20 */        /* not used 
anymore */
 #define XLOG_GIST_PAGE_SPLIT           0x30
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 3ef5a49..dd468f6 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -643,39 +643,41 @@ DATA(insert (     2594   604 604 4 s      487 783 0 ));
 DATA(insert (  2594   604 604 5 s      488 783 0 ));
 DATA(insert (  2594   604 604 6 s      491 783 0 ));
 DATA(insert (  2594   604 604 7 s      490 783 0 ));
 DATA(insert (  2594   604 604 8 s      489 783 0 ));
 DATA(insert (  2594   604 604 9 s      2575 783 0 ));
 DATA(insert (  2594   604 604 10 s 2574 783 0 ));
 DATA(insert (  2594   604 604 11 s 2577 783 0 ));
 DATA(insert (  2594   604 604 12 s 2576 783 0 ));
 DATA(insert (  2594   604 604 13 s 2861 783 0 ));
 DATA(insert (  2594   604 604 14 s 2860 783 0 ));
+DATA(insert (  2594   604 600 15 o 3588 783 1970 ));
 
 /*
  *     gist circle_ops
  */
 
 DATA(insert (  2595   718 718 1 s      1506 783 0 ));
 DATA(insert (  2595   718 718 2 s      1507 783 0 ));
 DATA(insert (  2595   718 718 3 s      1513 783 0 ));
 DATA(insert (  2595   718 718 4 s      1508 783 0 ));
 DATA(insert (  2595   718 718 5 s      1509 783 0 ));
 DATA(insert (  2595   718 718 6 s      1512 783 0 ));
 DATA(insert (  2595   718 718 7 s      1511 783 0 ));
 DATA(insert (  2595   718 718 8 s      1510 783 0 ));
 DATA(insert (  2595   718 718 9 s      2589 783 0 ));
 DATA(insert (  2595   718 718 10 s 1515 783 0 ));
 DATA(insert (  2595   718 718 11 s 1514 783 0 ));
 DATA(insert (  2595   718 718 12 s 2590 783 0 ));
 DATA(insert (  2595   718 718 13 s 2865 783 0 ));
 DATA(insert (  2595   718 718 14 s 2864 783 0 ));
+DATA(insert (  2595   718 600 15 o 3586 783 1970 ));
 
 /*
  * gin array_ops (these anyarray operators are used with all the opclasses
  * of the family)
  */
 DATA(insert (  2745   2277 2277 1 s 2750 2742 0 ));
 DATA(insert (  2745   2277 2277 2 s 2751 2742 0 ));
 DATA(insert (  2745   2277 2277 3 s 2752 2742 0 ));
 DATA(insert (  2745   2277 2277 4 s 1070 2742 0 ));
 
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 10a47df..1149923 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -197,27 +197,29 @@ DATA(insert (     2593   603 603 4 2580 ));
 DATA(insert (  2593   603 603 5 2581 ));
 DATA(insert (  2593   603 603 6 2582 ));
 DATA(insert (  2593   603 603 7 2584 ));
 DATA(insert (  2594   604 604 1 2585 ));
 DATA(insert (  2594   604 604 2 2583 ));
 DATA(insert (  2594   604 604 3 2586 ));
 DATA(insert (  2594   604 604 4 2580 ));
 DATA(insert (  2594   604 604 5 2581 ));
 DATA(insert (  2594   604 604 6 2582 ));
 DATA(insert (  2594   604 604 7 2584 ));
+DATA(insert (  2594   604 604 8 3589 ));
 DATA(insert (  2595   718 718 1 2591 ));
 DATA(insert (  2595   718 718 2 2583 ));
 DATA(insert (  2595   718 718 3 2592 ));
 DATA(insert (  2595   718 718 4 2580 ));
 DATA(insert (  2595   718 718 5 2581 ));
 DATA(insert (  2595   718 718 6 2582 ));
 DATA(insert (  2595   718 718 7 2584 ));
+DATA(insert (  2595   718 718 8 3589 ));
 DATA(insert (  3655   3614 3614 1 3654 ));
 DATA(insert (  3655   3614 3614 2 3651 ));
 DATA(insert (  3655   3614 3614 3 3648 ));
 DATA(insert (  3655   3614 3614 4 3649 ));
 DATA(insert (  3655   3614 3614 5 3653 ));
 DATA(insert (  3655   3614 3614 6 3650 ));
 DATA(insert (  3655   3614 3614 7 3652 ));
 DATA(insert (  3702   3615 3615 1 3701 ));
 DATA(insert (  3702   3615 3615 2 3698 ));
 DATA(insert (  3702   3615 3615 3 3695 ));
diff --git a/src/include/catalog/pg_operator.h 
b/src/include/catalog/pg_operator.h
index c31b8a8..b633665 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1007,23 +1007,27 @@ DATA(insert OID = 1517 (  "-"     PGNSP PGUID b f f  
718        600  718          0    0 circle_
 DESCR("subtract");
 DATA(insert OID = 1518 (  "*"    PGNSP PGUID b f f  718        600  718        
  0    0 circle_mul_pt - - ));
 DESCR("multiply");
 DATA(insert OID = 1519 (  "/"    PGNSP PGUID b f f  718        600  718        
  0    0 circle_div_pt - - ));
 DESCR("divide");
 
 DATA(insert OID = 1520 (  "<->"   PGNSP PGUID b f f  718       718  701   1520 
   0 circle_distance - - ));
 DESCR("distance between");
 DATA(insert OID = 1521 (  "#"    PGNSP PGUID l f f  0          604   23        
  0    0 poly_npoints - - ));
 DESCR("number of points");
-DATA(insert OID = 1522 (  "<->"   PGNSP PGUID b f f  600       718  701        
  0    0 dist_pc - - ));
+DATA(insert OID = 1522 (  "<->"   PGNSP PGUID b f f  600       718  701   3586 
   0 dist_pc - - ));
 DESCR("distance between");
-DATA(insert OID = 3591 (  "<->"          PGNSP PGUID b f f      600    604     
 701      0        0 dist_ppoly - - ));
+DATA(insert OID = 3586 (  "<->"   PGNSP PGUID b f f  718       600  701   1522 
   0 dist_cpoint - - ));
+DESCR("distance between");
+DATA(insert OID = 3591 (  "<->"          PGNSP PGUID b f f  600        604  
701   3588    0 dist_ppoly - - ));
+DESCR("distance between");
+DATA(insert OID = 3588 (  "<->"          PGNSP PGUID b f f  604        600  
701   3591    0 dist_polyp - - ));
 DESCR("distance between");
 DATA(insert OID = 1523 (  "<->"   PGNSP PGUID b f f  718       604  701        
  0    0 dist_cpoly - - ));
 DESCR("distance between");
 
 /* additional geometric operators - thomas 1997-07-09 */
 DATA(insert OID = 1524 (  "<->"   PGNSP PGUID b f f  628       603  701        
  0  0 dist_lb - - ));
 DESCR("distance between");
 
 DATA(insert OID = 1525 (  "?#"   PGNSP PGUID b f f  601        601 16 1525  0 
lseg_intersect - - ));
 DESCR("intersect");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 95f0b74..1b7664e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -807,20 +807,22 @@ DATA(insert OID = 749 (  overlay             PGNSP PGUID 
12 1 0 0 0 f f f f t f i 4 0 17
 DESCR("substitute portion of string");
 DATA(insert OID = 752 (  overlay                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 3 0 17 "17 17 23" _null_ _null_ _null_ _null_   byteaoverlay_no_len 
_null_ _null_ _null_ ));
 DESCR("substitute portion of string");
 
 DATA(insert OID = 725 (  dist_pl                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "600 628" _null_ _null_ _null_ _null_   dist_pl _null_ _null_ 
_null_ ));
 DATA(insert OID = 726 (  dist_lb                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "628 603" _null_ _null_ _null_ _null_   dist_lb _null_ _null_ 
_null_ ));
 DATA(insert OID = 727 (  dist_sl                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "601 628" _null_ _null_ _null_ _null_   dist_sl _null_ _null_ 
_null_ ));
 DATA(insert OID = 728 (  dist_cpoly               PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 701 "718 604" _null_ _null_ _null_ _null_   dist_cpoly _null_ 
_null_ _null_ ));
 DATA(insert OID = 729 (  poly_distance    PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "604 604" _null_ _null_ _null_ _null_   poly_distance _null_ _null_ 
_null_ ));
 DATA(insert OID = 3590 (  dist_ppoly      PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "600 604" _null_ _null_ _null_ _null_   dist_ppoly _null_ _null_ _null_ 
));
+DATA(insert OID = 3587 (  dist_polyp      PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "604 600" _null_ _null_ _null_ _null_   dist_polyp _null_ _null_ _null_ 
));
+DATA(insert OID = 3585 (  dist_cpoint     PGNSP PGUID 12 1 0 0 0 f f f f t f i 
2 0 701 "718 600" _null_ _null_ _null_ _null_   dist_cpoint _null_ _null_ 
_null_ ));
 
 DATA(insert OID = 740 (  text_lt                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_lt _null_ _null_ _null_ 
));
 DATA(insert OID = 741 (  text_le                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_le _null_ _null_ _null_ 
));
 DATA(insert OID = 742 (  text_gt                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_gt _null_ _null_ _null_ 
));
 DATA(insert OID = 743 (  text_ge                  PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ text_ge _null_ _null_ _null_ 
));
 
 DATA(insert OID = 745 (  current_user     PGNSP PGUID 12 1 0 0 0 f f f f t f s 
0 0 19 "" _null_ _null_ _null_ _null_ current_user _null_ _null_ _null_ ));
 DESCR("current user name");
 DATA(insert OID = 746 (  session_user     PGNSP PGUID 12 1 0 0 0 f f f f t f s 
0 0 19 "" _null_ _null_ _null_ _null_ session_user _null_ _null_ _null_ ));
 DESCR("session user name");
@@ -4002,20 +4004,22 @@ DESCR("GiST support");
 DATA(insert OID = 2582 (  gist_box_picksplit   PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_   gist_box_picksplit 
_null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2583 (  gist_box_union               PGNSP PGUID 12 1 0 0 0 
f f f f t f i 2 0 603 "2281 2281" _null_ _null_ _null_ _null_ gist_box_union 
_null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2584 (  gist_box_same                        PGNSP PGUID 12 
1 0 0 0 f f f f t f i 3 0 2281 "603 603 2281" _null_ _null_ _null_ _null_ 
gist_box_same _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2585 (  gist_poly_consistent PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 5 0 16 "2281 604 23 26 2281" _null_ _null_ _null_ _null_   
gist_poly_consistent _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2586 (  gist_poly_compress   PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ gist_poly_compress _null_ 
_null_ _null_ ));
 DESCR("GiST support");
+DATA(insert OID = 3589 (  gist_inexact_distance        PGNSP PGUID 12 1 0 0 0 
f f f f t f i 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_       
gist_inexact_distance _null_ _null_ _null_ ));
+DESCR("GiST support");
 DATA(insert OID = 2591 (  gist_circle_consistent PGNSP PGUID 12 1 0 0 0 f f f 
f t f i 5 0 16 "2281 718 23 26 2281" _null_ _null_ _null_ _null_ 
gist_circle_consistent _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2592 (  gist_circle_compress PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ gist_circle_compress _null_ 
_null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 1030 (  gist_point_compress  PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ gist_point_compress _null_ 
_null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 2179 (  gist_point_consistent PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 5 0 16 "2281 600 23 26 2281" _null_ _null_ _null_ _null_  
gist_point_consistent _null_ _null_ _null_ ));
 DESCR("GiST support");
 DATA(insert OID = 3064 (  gist_point_distance  PGNSP PGUID 12 1 0 0 0 f f f f 
t f i 4 0 701 "2281 600 23 26" _null_ _null_ _null_ _null_       
gist_point_distance _null_ _null_ _null_ ));
 DESCR("GiST support");
diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h
index 91610d8..64f63b2 100644
--- a/src/include/utils/geo_decls.h
+++ b/src/include/utils/geo_decls.h
@@ -387,22 +387,24 @@ extern Datum circle_ge(PG_FUNCTION_ARGS);
 extern Datum circle_contain_pt(PG_FUNCTION_ARGS);
 extern Datum pt_contained_circle(PG_FUNCTION_ARGS);
 extern Datum circle_add_pt(PG_FUNCTION_ARGS);
 extern Datum circle_sub_pt(PG_FUNCTION_ARGS);
 extern Datum circle_mul_pt(PG_FUNCTION_ARGS);
 extern Datum circle_div_pt(PG_FUNCTION_ARGS);
 extern Datum circle_diameter(PG_FUNCTION_ARGS);
 extern Datum circle_radius(PG_FUNCTION_ARGS);
 extern Datum circle_distance(PG_FUNCTION_ARGS);
 extern Datum dist_pc(PG_FUNCTION_ARGS);
+extern Datum dist_cpoint(PG_FUNCTION_ARGS);
 extern Datum dist_cpoly(PG_FUNCTION_ARGS);
 extern Datum dist_ppoly(PG_FUNCTION_ARGS);
+extern Datum dist_polyp(PG_FUNCTION_ARGS);
 extern Datum circle_center(PG_FUNCTION_ARGS);
 extern Datum cr_circle(PG_FUNCTION_ARGS);
 extern Datum box_circle(PG_FUNCTION_ARGS);
 extern Datum circle_box(PG_FUNCTION_ARGS);
 extern Datum poly_circle(PG_FUNCTION_ARGS);
 extern Datum circle_poly(PG_FUNCTION_ARGS);
 extern Datum circle_area(PG_FUNCTION_ARGS);
 
 /* support routines for the GiST access method (access/gist/gistproc.c) */
 extern Datum gist_box_compress(PG_FUNCTION_ARGS);
@@ -412,20 +414,21 @@ extern Datum gist_box_picksplit(PG_FUNCTION_ARGS);
 extern Datum gist_box_consistent(PG_FUNCTION_ARGS);
 extern Datum gist_box_penalty(PG_FUNCTION_ARGS);
 extern Datum gist_box_same(PG_FUNCTION_ARGS);
 extern Datum gist_poly_compress(PG_FUNCTION_ARGS);
 extern Datum gist_poly_consistent(PG_FUNCTION_ARGS);
 extern Datum gist_circle_compress(PG_FUNCTION_ARGS);
 extern Datum gist_circle_consistent(PG_FUNCTION_ARGS);
 extern Datum gist_point_compress(PG_FUNCTION_ARGS);
 extern Datum gist_point_consistent(PG_FUNCTION_ARGS);
 extern Datum gist_point_distance(PG_FUNCTION_ARGS);
+extern Datum gist_inexact_distance(PG_FUNCTION_ARGS);
 
 /* geo_selfuncs.c */
 extern Datum areasel(PG_FUNCTION_ARGS);
 extern Datum areajoinsel(PG_FUNCTION_ARGS);
 extern Datum positionsel(PG_FUNCTION_ARGS);
 extern Datum positionjoinsel(PG_FUNCTION_ARGS);
 extern Datum contsel(PG_FUNCTION_ARGS);
 extern Datum contjoinsel(PG_FUNCTION_ARGS);
 
 #endif   /* GEO_DECLS_H */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to