]> granicus.if.org Git - postgis/commitdiff
- cut the gist indexing-related functions out of postgis_ops.c and put them in postgi...
authorChris Hodgson <chodgson@refractions.net>
Fri, 26 Apr 2002 22:50:06 +0000 (22:50 +0000)
committerChris Hodgson <chodgson@refractions.net>
Fri, 26 Apr 2002 22:50:06 +0000 (22:50 +0000)
- similarly, the sql definitions of the gist functions have been split into their own new sql.in file, with postgis_gist_72.sql.in containing the new postgres >= 7.2 definitions

- the makefile has been updated to compile EITHER postgis_gist.c OR postgis_gist_72.c, and also to process EITHER postgis_gist.sql.in OR postgis_gist_72.sql and add the output to the end of postgis.sql

- in order to compile the gist functions for posgres 7.2 or newer, make sure to point your PGSQL_SRC at the new source directory, and uncomment the line in the makefile which says PG72 = 1 (near the top)

- some functions that were previously in postgis_ops.c were moved to postgis_fn.c, as part of a general cleanup I did when splitting off the gist functions into their own file

- some definitions that were previously in postgis.h (unnecessarily) where removed, as they varied depending on which version of postgis_gist was being used

- also edited the loader/Makefile to clean up properly

git-svn-id: http://svn.osgeo.org/postgis/trunk@140 b70326c6-7e19-0410-871a-916f4a2858ee

Makefile
loader/Makefile
postgis.h
postgis.sql.in
postgis_fn.c
postgis_gist.c [new file with mode: 0644]
postgis_gist.sql.in [new file with mode: 0644]
postgis_gist_72.c [new file with mode: 0644]
postgis_gist_72.sql.in [new file with mode: 0644]
postgis_ops.c

index de0f0eab7d2e649dd2ce9a1f5a3e60c5f5e9e66c..871c6596a3d18f45a008c21599a9f1feebc4f8f6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,25 +16,32 @@ endif
 
 test_db = geom_regress
 
+# set PG72 to 1 for postgres >= 7.2
+#PG72 = 1
+
 # shared library parameters
 NAME=postgis
 SO_MAJOR_VERSION=0
 SO_MINOR_VERSION=7
 
-
 #override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
 # Altered for Cynwin
 override CPPFLAGS := -g  -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"' -DWANT_PROJECTION 
 override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS)
 
-OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o
+# output code and SQL file for postgres >= 7.2 or not?
+ifeq ($(PG72),1)
+       OBJS=postgis_debug.o postgis_ops.o postgis_gist_72.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o
+else
+       OBJS=postgis_debug.o postgis_ops.o postgis_gist.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o
+endif
 
 # Add libraries that libpq depends (or might depend) on into the
 # shared library link.  (The order in which you list them here doesn't
 # matter.)
 SHLIB_LINK = $(filter -L%, $(LDFLAGS)) -lproj
 
-all: all-lib $(NAME).sql $(NAME)_undef.sql loaderdumper
+all: all-lib $(NAME).sql $(NAME).sql $(NAME)_undef.sql loaderdumper
 
 loaderdumper:
        make -C loader
@@ -42,8 +49,13 @@ loaderdumper:
 # Shared library stuff
 include $(top_srcdir)/src/Makefile.shlib
 
-$(NAME).sql: $(NAME).sql.in
-       sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g;s:@POSTGIS_VERSION@:$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION):g' < $< > $@
+$(NAME).sql: $(NAME).sql.in $(NAME)_gist_72.sql.in $(NAME)_gist.sql.in
+       sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g;s:@POSTGIS_VERSION@:$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION):g' < $(NAME).sql.in > $@ 
+       if [ $(PG72) == 1 ]; then \
+               sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g;s:@POSTGIS_VERSION@:$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION):g' < $(NAME)_gist_72.sql.in >> $(NAME).sql; \
+       else \
+               sed -e 's:@MODULE_FILENAME@:$(libdir)/$(shlib):g;s:@POSTGIS_VERSION@:$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION):g' < $(NAME)_gist.sql.in >> $(NAME).sql; \
+       fi
 
 $(NAME)_undef.sql: $(NAME).sql
        perl create_undef.pl $< > $@ 
index d21149aa9200ac334d286e8b2d95055aa07b81f3..2a8e946d8a5d74f55a39ca6a3125a3c1f3446c11 100644 (file)
@@ -27,5 +27,5 @@ shp2pgsql: $(OBJS) shp2pgsql.o
        $(CC) $(CFLAGS) $(OBJS) shp2pgsql.o $(libpq) $(LDFLAGS) $(LIBS) -o $@ 
 
 clean:
-       @rm -f $(OBJS) shp2pgsql pgsql2shp
+       @rm -f $(OBJS) shp2pgsql.o pgsql2shp.o shp2pgsql pgsql2shp
 
index 41893b3e6735aee5ff8fbdf379ed8f8dd0783c59..c458619a5c5272dcd3183acdc11a2c0dae3d2805 100644 (file)
--- a/postgis.h
+++ b/postgis.h
@@ -495,38 +495,6 @@ Datum max_distance(PG_FUNCTION_ARGS);
 Datum collector(PG_FUNCTION_ARGS);
 
 
-//for GIST index
-typedef char* (*BINARY_UNION)(char*, char*, int*);
-typedef float (*SIZE_BOX)(char*);
-typedef Datum (*RDF)(PG_FUNCTION_ARGS);
-
-
-
-
-
-GISTENTRY * ggeometry_compress(PG_FUNCTION_ARGS);
-GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS);
-GIST_SPLITVEC * ggeometry_picksplit(PG_FUNCTION_ARGS);
-bool ggeometry_consistent(PG_FUNCTION_ARGS);
-float * ggeometry_penalty(PG_FUNCTION_ARGS);
-bool * ggeometry_same(PG_FUNCTION_ARGS);
-
-char * ggeometry_binary_union(char *r1, char *r2, int *sizep);
-float size_geometrykey( char *pk );
-
-Datum ggeometry_inter(PG_FUNCTION_ARGS);
-
-/*
-** Common rtree-function (for all ops)
-*/
-char * rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu);
-float * rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb);
-GIST_SPLITVEC * rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb);
-bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy);
-
-
-GISTENTRY * rtree_decompress(PG_FUNCTION_ARGS);
-
 
 
 /*--------------------------------------------------------------------
index dd6176e96909f57c23347c4ce3b678bd2f066550..b9b8de73d7f276c35b9393da9014296014649160 100644 (file)
@@ -742,233 +742,6 @@ CREATE FUNCTION force_collection(GEOMETRY) RETURNS GEOMETRY
         AS '@MODULE_FILENAME@'  LANGUAGE 'c' with (isstrict);
 
 
-
-
--------- GiST support functions
-create function ggeometry_consistent(opaque,GEOMETRY,int4) returns bool 
-as '@MODULE_FILENAME@'   language 'C';
-
-create function ggeometry_compress(opaque) returns opaque 
-as '@MODULE_FILENAME@'  language 'C';
-
-create function ggeometry_penalty(opaque,opaque,opaque) returns opaque 
-as '@MODULE_FILENAME@'   language 'C';
-
-create function ggeometry_picksplit(opaque, opaque) returns opaque 
-as '@MODULE_FILENAME@'   language 'C';
-
-create function ggeometry_union(bytea, opaque) returns opaque 
-as '@MODULE_FILENAME@'   language 'C';
-
-create function ggeometry_same(opaque, opaque, opaque) returns opaque 
-as '@MODULE_FILENAME@'   language 'C';
-
-create function rtree_decompress(opaque) returns opaque
-as '@MODULE_FILENAME@'   language 'C';
---------------------------
-create function postgis_gist_sel(oid, oid, int2, opaque, int4) returns float8 
-as '@MODULE_FILENAME@'   language 'C';
-
------- RTREE support functions
-
-create function geometry_union(GEOMETRY,GEOMETRY) returns GEOMETRY 
-as '@MODULE_FILENAME@'   language 'C';
-create function geometry_inter(GEOMETRY,GEOMETRY) returns GEOMETRY 
-as '@MODULE_FILENAME@'   language 'C';
-create function geometry_size(GEOMETRY,opaque) returns float4 
-as '@MODULE_FILENAME@'   language 'C';
-
----------Create actual operators
-
-CREATE OPERATOR << (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_left,
-   COMMUTATOR = '>>',
-   RESTRICT = positionsel, JOIN = positionjoinsel
-);
-
-CREATE OPERATOR &< (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overleft,
-   COMMUTATOR = '&>',
-   RESTRICT = positionsel, JOIN = positionjoinsel
-);
-
-CREATE OPERATOR && (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overlap,
-   COMMUTATOR = '&&',
-   RESTRICT = postgis_gist_sel, JOIN = positionjoinsel
-);
-
-CREATE OPERATOR &> (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overright,
-   COMMUTATOR = '&<',
-   RESTRICT = positionsel, JOIN = positionjoinsel
-);
-
-CREATE OPERATOR >> (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_right,
-   COMMUTATOR = '<<',
-   RESTRICT = positionsel, JOIN = positionjoinsel
-);
-
-CREATE OPERATOR ~= (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_same,
-   COMMUTATOR = '=', 
-   RESTRICT = eqsel, JOIN = eqjoinsel
-);
-
-
-
-CREATE OPERATOR @ (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contain,
-   COMMUTATOR = '@',
-   RESTRICT = contsel, JOIN = contjoinsel
-);
-
-
-CREATE OPERATOR ~ (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contained,
-   COMMUTATOR = '@',
-   RESTRICT = contsel, JOIN = contjoinsel
-);
-
-CREATE OPERATOR = (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_eq,
-   COMMUTATOR = '=',
-   RESTRICT = contsel, JOIN = contjoinsel
-);
-
-CREATE OPERATOR < (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_lt,
-   COMMUTATOR = '<',
-   RESTRICT = contsel, JOIN = contjoinsel
-);
-
-CREATE OPERATOR > (
-   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_gt,
-   COMMUTATOR = '>',
-   RESTRICT = contsel, JOIN = contjoinsel
-);
-
-
-
-
---- old way = insert into pg_opclass values ('gist_geometry_ops');
-
-INSERT INTO pg_opclass (opcname, opcdeftype)
-   SELECT 'gist_geometry_ops', oid
-   FROM pg_type
-   WHERE typname = 'geometry';
-
---- drop table rt_ops_tmp;
-
-SELECT o.oid AS opoid, o.oprname
-INTO TABLE rt_ops_tmp
-FROM pg_operator o, pg_type t
-WHERE o.oprleft = t.oid 
-   and t.typname = 'geometry';
-
--- box_left
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
-   SELECT am.oid, opcl.oid, c.opoid, 1
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '<<';
-
--- box_overleft
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
-   SELECT am.oid, opcl.oid, c.opoid, 2
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '&<';
-
--- box_overlap
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
-   SELECT am.oid, opcl.oid, c.opoid, 3
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '&&';
-
--- box_overright
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
-   SELECT am.oid, opcl.oid, c.opoid, 4
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '&>';
-
--- box_right
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
-   SELECT am.oid, opcl.oid, c.opoid, 5
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '>>';
-
--- box_same
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
-   SELECT am.oid, opcl.oid, c.opoid, 6
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '~=';
-
--- box_contains
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
-   SELECT am.oid, opcl.oid, c.opoid, 7
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '~';
-
--- box_contained
-INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
-   SELECT am.oid, opcl.oid, c.opoid, 8
-   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
-   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
-      and c.oprname = '@';
-
-DROP table rt_ops_tmp;
-
--- add the entries to amproc for the support methods
--- note the amprocnum numbers associated with each are specific!
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 1
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_consistent';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 2
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_union';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 3
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_compress';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 4
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'rtree_decompress';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 5
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_penalty';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 6
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_picksplit';
-
-INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
-   SELECT am.oid, opcl.oid, pro.oid, 7
-   FROM pg_am am, pg_opclass opcl, pg_proc pro
-   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
-      and proname = 'ggeometry_same';
-
 --- workaround for user defined VARIABLE length datatype default value bug
 update pg_type set typdefault = NULL where  typname = 'wkb';
 update pg_type set typdefault = NULL where  typname = 'geometry';
index ff9fdcb289e0364ca1c6c5bbc26849206fb15b6a..33239eb8f019be9e968f3abda356eac85f59a419 100644 (file)
 #include "access/itup.h"
 #include "access/rtree.h"
 
-
-
-
 #include "fmgr.h"
 
-
 #include "postgis.h"
 #include "utils/elog.h"
 
@@ -2563,4 +2559,53 @@ Datum collector( PG_FUNCTION_ARGS )
        pfree( bbox ); // free bounding box
 
        PG_RETURN_POINTER( result );
-}
\ No newline at end of file
+}
+
+PG_FUNCTION_INFO_V1(box3d_xmin);
+Datum box3d_xmin(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->LLB.x);
+}
+
+PG_FUNCTION_INFO_V1(box3d_ymin);
+Datum box3d_ymin(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->LLB.y);
+}
+
+PG_FUNCTION_INFO_V1(box3d_zmin);
+Datum box3d_zmin(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->LLB.z);
+}
+
+PG_FUNCTION_INFO_V1(box3d_xmax);
+Datum box3d_xmax(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->URT.x);
+}
+
+PG_FUNCTION_INFO_V1(box3d_ymax);
+Datum box3d_ymax(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->URT.y);
+}
+
+PG_FUNCTION_INFO_V1(box3d_zmax);
+Datum box3d_zmax(PG_FUNCTION_ARGS)
+{
+       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
+
+       PG_RETURN_FLOAT8(box1->URT.z);
+}
+
diff --git a/postgis_gist.c b/postgis_gist.c
new file mode 100644 (file)
index 0000000..5225196
--- /dev/null
@@ -0,0 +1,572 @@
+/******************************************************
+ postGIS - geometric types for postgres
+
+ This software is copyrighted (2001).
+ This is free software; you can redistribute it and/or modify
+ it under the GNU General Public Licence.  See the file "COPYING".
+
+ More Info?  See the documentation, join the mailing list 
+ (postgis@yahoogroups.com), or see the web page
+ (http://postgis.refractions.net).
+
+ GiST indexing functions fo pgsql < 7.2
+ ******************************************************/
+
+#include "postgres.h"
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+
+#include "fmgr.h"
+
+#include "postgis.h"
+#include "utils/elog.h"
+
+//Norman Vine found this problem for compiling under cygwin
+//  it defines BYTE_ORDER and LITTLE_ENDIAN 
+
+#ifdef __CYGWIN__
+#include <sys/param.h>       // FOR ENDIAN DEFINES
+#endif
+
+#define SHOW_DIGS_DOUBLE 15
+#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
+
+// #define DEBUG_GIST
+
+
+//for GIST index
+typedef char* (*BINARY_UNION)(char*, char*, int*);
+typedef float (*SIZE_BOX)(char*);
+typedef Datum (*RDF)(PG_FUNCTION_ARGS);
+
+GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS);
+GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS);
+GIST_SPLITVEC * ggeometry_picksplit(PG_FUNCTION_ARGS);
+bool ggeometry_consistent(PG_FUNCTION_ARGS);
+float * ggeometry_penalty(PG_FUNCTION_ARGS);
+bool * ggeometry_same(PG_FUNCTION_ARGS);
+
+char * ggeometry_binary_union(char *r1, char *r2, int *sizep);
+float size_geometrykey( char *pk );
+
+Datum ggeometry_inter(PG_FUNCTION_ARGS);
+
+/*
+** Common rtree-function (for all ops)
+*/
+char * rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu);
+float * rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb);
+GIST_SPLITVEC * rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb);
+bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy);
+
+
+GISTENTRY *rtree_decompress(PG_FUNCTION_ARGS);
+
+
+//restriction in the GiST && operator
+
+Datum postgis_gist_sel(PG_FUNCTION_ARGS)
+{
+        PG_RETURN_FLOAT8(0.000005);
+}
+
+
+BOX    *convert_box3d_to_box(BOX3D *in)
+{
+               BOX     *out = palloc (sizeof (BOX) );
+
+               out->high.x = in->URT.x;
+               out->high.y = in->URT.y;
+
+               out->low.x = in->LLB.x;
+               out->low.y = in->LLB.y;
+
+       return out;
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_compress);
+GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS)
+{
+       GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0);
+       GISTENTRY *retval;
+
+       if ( entry->leafkey) {
+               retval = palloc(sizeof(GISTENTRY));
+               if ( entry->pred ) {
+
+                       GEOMETRY *in;
+                       GEOMETRYKEY *r;
+                       BOX     *thebox;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_compress called on geometry\n");
+#endif
+
+                       in = (GEOMETRY*)PG_DETOAST_DATUM(PointerGetDatum(entry->pred));
+                       r = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
+                       r->size = sizeof(GEOMETRYKEY);
+                       r->SRID = in->SRID;
+                       thebox = convert_box3d_to_box(&in->bvol);
+                       memcpy( (void*)&(r->key), (void*)thebox, sizeof(BOX) );
+                       if ( (char*)in != entry->pred ) 
+                       {
+                               pfree( in );
+                               pfree(thebox);
+                       }
+
+                       gistentryinit(*retval, (char*)r, entry->rel, entry->page,
+                               entry->offset, sizeof(GEOMETRYKEY),FALSE);
+
+               } else {
+                       gistentryinit(*retval, NULL, entry->rel, entry->page,
+                               entry->offset, 0,FALSE);
+               } 
+       } else {
+               retval = entry;
+       }
+       return( retval );
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_consistent);
+bool ggeometry_consistent(PG_FUNCTION_ARGS)
+{
+    GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
+    GEOMETRY *query       = (GEOMETRY*)            PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+    BOX                *thebox;
+    /*
+    ** if entry is not leaf, use gbox_internal_consistent,
+    ** else use gbox_leaf_consistent
+    */
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_consistent called\n");
+#endif
+
+    if ( ! (entry->pred && query) )
+       return FALSE;
+
+       thebox = convert_box3d_to_box( &(query->bvol) );
+
+       if(    ((GEOMETRYKEY *)(entry->pred))->SRID != query->SRID)
+       {
+               elog(ERROR,"Operation on two GEOMETRIES with different SRIDs (ggeometry_consistent)\n");
+               PG_RETURN_BOOL(FALSE);
+       }
+
+    PG_RETURN_BOOL(rtree_internal_consistent((BOX*)&( ((GEOMETRYKEY *)(entry->pred))->key ), 
+               thebox, strategy));
+}
+
+
+PG_FUNCTION_INFO_V1(ggeometry_union);
+GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS)
+{
+       GEOMETRYKEY             *result;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_union called\n");
+#endif
+
+       result = (GEOMETRYKEY*) 
+               rtree_union(
+                       (bytea*) PG_GETARG_POINTER(0),
+                       (int*) PG_GETARG_POINTER(1),
+                       ggeometry_binary_union
+               );
+
+    return result;
+}
+
+
+PG_FUNCTION_INFO_V1(ggeometry_penalty);
+float *ggeometry_penalty(PG_FUNCTION_ARGS)
+{
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_penalty called\n");
+#endif
+
+    return rtree_penalty(
+       (GISTENTRY*) PG_GETARG_POINTER(0),
+       (GISTENTRY*) PG_GETARG_POINTER(1),
+       (float*) PG_GETARG_POINTER(2),
+       ggeometry_binary_union,
+       size_geometrykey
+    );
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_picksplit);
+GIST_SPLITVEC *ggeometry_picksplit(PG_FUNCTION_ARGS)
+{
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_picksplit called\n");
+#endif
+
+
+    return rtree_picksplit(
+       (bytea*)PG_GETARG_POINTER(0),
+       (GIST_SPLITVEC*)PG_GETARG_POINTER(1),
+       sizeof(GEOMETRYKEY),
+       ggeometry_binary_union,
+       ggeometry_inter,
+       size_geometrykey
+    );
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_same);
+bool *ggeometry_same(PG_FUNCTION_ARGS)
+{
+
+  GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0);
+  GEOMETRYKEY *b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1);
+
+  bool *result = (bool*) PG_GETARG_POINTER(2);
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_same called\n");
+#endif
+
+
+  if ( b1 && b2 )
+       *result = DatumGetBool( DirectFunctionCall2( box_same, 
+               PointerGetDatum(&(b1->key)), 
+               PointerGetDatum(&(b2->key))) );
+  else
+       *result = ( b1==NULL && b2==NULL ) ? TRUE : FALSE; 
+  return(result);
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_inter);
+Datum ggeometry_inter(PG_FUNCTION_ARGS) {
+       GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0);
+       GEOMETRYKEY*b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1);
+       char *interd;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_inter called\n");
+#endif
+
+
+       interd = DatumGetPointer(DirectFunctionCall2(
+                       rt_box_inter,
+                       PointerGetDatum( &(b1->key) ),
+                       PointerGetDatum( &(b2->key) )) );
+       
+       if (interd) {
+               GEOMETRYKEY *tmp = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
+               tmp->size = sizeof(GEOMETRYKEY);
+       
+               memcpy( (void*)&(tmp->key), (void*)interd, sizeof(BOX) );
+               tmp->SRID = b1->SRID;
+               pfree( interd );
+               PG_RETURN_POINTER( tmp );
+       } else 
+               PG_RETURN_POINTER( NULL );
+}
+
+char *ggeometry_binary_union(char *r1, char *r2, int *sizep)
+{
+    GEOMETRYKEY *retval;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_binary_union called\n");
+#endif
+
+    if ( ! (r1 && r2) ) {
+       if ( r1 ) {
+               retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
+               memcpy( (void*)retval, (void*)r1, sizeof(GEOMETRYKEY) );
+               *sizep = sizeof(GEOMETRYKEY);
+       } else if ( r2 ) {
+               retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
+               memcpy( (void*)retval, (void*)r2, sizeof(GEOMETRYKEY) );
+               *sizep = sizeof(GEOMETRYKEY);
+       } else {
+               *sizep = 0;
+               retval = NULL;
+       } 
+    } else {
+       BOX *key = (BOX*)DatumGetPointer( DirectFunctionCall2(
+               rt_box_union,
+               PointerGetDatum( &(((GEOMETRYKEY*)r1)->key) ),
+               PointerGetDatum( &(((GEOMETRYKEY*)r2)->key) )) );
+       retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
+       retval->SRID = ((GEOMETRYKEY *) r1)->SRID;
+       memcpy( (void*)&(retval->key), (void*)key, sizeof(BOX) );
+       pfree( key );
+       *sizep = retval->size = sizeof(GEOMETRYKEY);
+    }
+    return (char*)retval;
+}
+
+
+float size_geometrykey( char *pk ) {
+
+#ifdef DEBUG_GIST2
+       printf("GIST: size_geometrykey called\n");
+#endif
+
+    if ( pk ) {
+       float size;
+       DirectFunctionCall2( rt_box_size,
+               PointerGetDatum( &(((GEOMETRYKEY*)pk)->key) ),
+               PointerGetDatum( &size ) );
+       return size;
+    } else
+       return 0.0;
+}
+
+char *rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu)
+{
+    int numranges, i;
+    char *out, *tmp;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: rtree_union called\n");
+#endif
+
+    numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); 
+    tmp = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[0]).pred;
+    out = NULL;
+
+    for (i = 1; i < numranges; i++) {
+       out = (*bu)(tmp, (char *)
+                                (((GISTENTRY *)(VARDATA(entryvec)))[i]).pred,
+                                sizep);
+       if (i > 1 && tmp) pfree(tmp);
+       tmp = out;
+    }
+
+    return(out);
+}
+
+float *rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb)
+{
+    char * ud;
+    float tmp1;
+    int sizep;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: rtree_penalty called\n");
+#endif
+
+
+   
+    ud = (*bu)( origentry->pred, newentry->pred, &sizep );
+    tmp1 = (*sb)( ud ); 
+    if (ud) pfree(ud);
+
+    *result = tmp1 - (*sb)( origentry->pred );
+    return(result);
+}
+
+/*
+** The GiST PickSplit method
+** We use Guttman's poly time split algorithm 
+*/
+GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb)
+{
+    OffsetNumber i, j;
+    char *datum_alpha, *datum_beta;
+    char *datum_l, *datum_r;
+    char *union_d, *union_dl, *union_dr;
+    char *inter_d;
+    bool firsttime;
+    float size_alpha, size_beta, size_union, size_inter;
+    float size_waste, waste;
+    float size_l, size_r;
+    int nbytes;
+    int sizep;
+    OffsetNumber seed_1 = 0, seed_2 = 0;
+    OffsetNumber *left, *right;
+    OffsetNumber maxoff;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: rtree_picsplit called\n");
+#endif
+
+    maxoff = ((VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY)) - 2;
+    nbytes =  (maxoff + 2) * sizeof(OffsetNumber);
+    v->spl_left = (OffsetNumber *) palloc(nbytes);
+    v->spl_right = (OffsetNumber *) palloc(nbytes);
+    
+    firsttime = true;
+    waste = 0.0;
+    
+    for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) {
+       datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred);
+       for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) {
+           datum_beta = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[j].pred);
+           
+           /* compute the wasted space by unioning these guys */
+           /* size_waste = size_union - size_inter; */ 
+           union_d = (*bu)( datum_alpha, datum_beta, &sizep );
+           if ( union_d ) {
+               size_union = (*sb)(union_d);
+               pfree(union_d);
+           } else
+               size_union = 0.0;
+
+           if ( datum_alpha && datum_beta ) {
+               inter_d = DatumGetPointer(DirectFunctionCall2(
+                       interop,
+                       PointerGetDatum( datum_alpha ),
+                       PointerGetDatum( datum_beta )) );
+               if ( inter_d ) {
+                       size_inter = (*sb)(inter_d);
+                       pfree(inter_d);
+               } else 
+                       size_inter = 0.0;
+           } else
+               size_inter = 0.0;
+
+           size_waste = size_union - size_inter;
+           
+           /*
+            *  are these a more promising split that what we've
+            *  already seen?
+            */
+           
+           if (size_waste > waste || firsttime) {
+               waste = size_waste;
+               seed_1 = i;
+               seed_2 = j;
+               firsttime = false;
+           }
+       }
+    }
+    
+    left = v->spl_left;
+    v->spl_nleft = 0;
+    right = v->spl_right;
+    v->spl_nright = 0;
+  
+    if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ) {
+       datum_l = (char*) palloc( keylen );
+       memcpy( (void*)datum_l, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ), keylen );
+    } else 
+       datum_l = NULL; 
+    size_l  = (*sb)( datum_l ); 
+    if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ) {
+       datum_r = (char*) palloc( keylen );
+       memcpy( (void*)datum_r, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ), keylen );
+    } else 
+       datum_r = NULL; 
+    size_r  = (*sb)( datum_r ); 
+    
+    /*
+     *  Now split up the regions between the two seeds.  An important
+     *  property of this split algorithm is that the split vector v
+     *  has the indices of items to be split in order in its left and
+     *  right vectors.  We exploit this property by doing a merge in
+     *  the code that actually splits the page.
+     *
+     *  For efficiency, we also place the new index tuple in this loop.
+     *  This is handled at the very end, when we have placed all the
+     *  existing tuples and i == maxoff + 1.
+     */
+    
+    maxoff = OffsetNumberNext(maxoff);
+    for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
+       
+       /*
+        *  If we've already decided where to place this item, just
+        *  put it on the right list.  Otherwise, we need to figure
+        *  out which page needs the least enlargement in order to
+        *  store the item.
+        */
+       
+       if (i == seed_1) {
+           *left++ = i;
+           v->spl_nleft++;
+           continue;
+       } else if (i == seed_2) {
+           *right++ = i;
+           v->spl_nright++;
+           continue;
+       }
+       
+       /* okay, which page needs least enlargement? */ 
+       datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred);
+       union_dl = (*bu)( datum_l, datum_alpha, &sizep );
+       union_dr = (*bu)( datum_r, datum_alpha, &sizep );
+       size_alpha = (*sb)( union_dl ); 
+       size_beta  = (*sb)( union_dr ); 
+       
+       /* pick which page to add it to */
+       if (size_alpha - size_l < size_beta - size_r) {
+           pfree(datum_l);
+           pfree(union_dr);
+           datum_l = union_dl;
+           size_l = size_alpha;
+           *left++ = i;
+           v->spl_nleft++;
+       } else {
+           pfree(datum_r);
+           pfree(union_dl);
+           datum_r = union_dr;
+           size_r = size_alpha;
+           *right++ = i;
+           v->spl_nright++;
+       }
+    }
+    *left = *right = FirstOffsetNumber;        /* sentinel value, see dosplit() */
+    
+    v->spl_ldatum = datum_l;
+    v->spl_rdatum = datum_r;
+
+    return( v );
+}
+
+
+bool rtree_internal_consistent(BOX *key,
+                       BOX *query,
+                       StrategyNumber strategy)
+{
+    bool retval;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: rtree_internal_consist called\n");
+#endif
+
+    switch(strategy) {
+    case RTLeftStrategyNumber:
+    case RTOverLeftStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overleft, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTOverlapStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTOverRightStrategyNumber:
+    case RTRightStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_right, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTSameStrategyNumber:
+    case RTContainsStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_contain, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTContainedByStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    default:
+      retval = FALSE;
+    }
+    return(retval);
+}
+
+PG_FUNCTION_INFO_V1(rtree_decompress);
+GISTENTRY *rtree_decompress(PG_FUNCTION_ARGS)
+{
+    return((GISTENTRY*)PG_GETARG_POINTER(0));
+}
+
+
diff --git a/postgis_gist.sql.in b/postgis_gist.sql.in
new file mode 100644 (file)
index 0000000..f18f90c
--- /dev/null
@@ -0,0 +1,228 @@
+BEGIN TRANSACTION;
+
+-------- GiST support functions
+create function ggeometry_consistent(opaque,GEOMETRY,int4) returns bool 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function ggeometry_compress(opaque) returns opaque 
+as '@MODULE_FILENAME@'  language 'C';
+
+create function ggeometry_penalty(opaque,opaque,opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function ggeometry_picksplit(opaque, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function ggeometry_union(bytea, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function ggeometry_same(opaque, opaque, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function rtree_decompress(opaque) returns opaque
+as '@MODULE_FILENAME@'   language 'C';
+--------------------------
+create function postgis_gist_sel(oid, oid, int2, opaque, int4) returns float8 
+as '@MODULE_FILENAME@'   language 'C';
+
+------ RTREE support functions
+
+create function geometry_union(GEOMETRY,GEOMETRY) returns GEOMETRY 
+as '@MODULE_FILENAME@'   language 'C';
+create function geometry_inter(GEOMETRY,GEOMETRY) returns GEOMETRY 
+as '@MODULE_FILENAME@'   language 'C';
+create function geometry_size(GEOMETRY,opaque) returns float4 
+as '@MODULE_FILENAME@'   language 'C';
+
+---------Create actual operators
+
+CREATE OPERATOR << (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_left,
+   COMMUTATOR = '>>',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &< (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overleft,
+   COMMUTATOR = '&>',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR && (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overlap,
+   COMMUTATOR = '&&',
+   RESTRICT = postgis_gist_sel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &> (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overright,
+   COMMUTATOR = '&<',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR >> (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_right,
+   COMMUTATOR = '<<',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR ~= (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_same,
+   COMMUTATOR = '=', 
+   RESTRICT = eqsel, JOIN = eqjoinsel
+);
+
+
+
+CREATE OPERATOR @ (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contain,
+   COMMUTATOR = '@',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+
+CREATE OPERATOR ~ (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contained,
+   COMMUTATOR = '@',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR = (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_eq,
+   COMMUTATOR = '=',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR < (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_lt,
+   COMMUTATOR = '<',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR > (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_gt,
+   COMMUTATOR = '>',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+
+
+
+--- old way = insert into pg_opclass values ('gist_geometry_ops');
+
+INSERT INTO pg_opclass (opcname, opcdeftype)
+   SELECT 'gist_geometry_ops', oid
+   FROM pg_type
+   WHERE typname = 'geometry';
+
+--- drop table rt_ops_tmp;
+
+SELECT o.oid AS opoid, o.oprname
+INTO TABLE rt_ops_tmp
+FROM pg_operator o, pg_type t
+WHERE o.oprleft = t.oid 
+   and t.typname = 'geometry';
+
+-- box_left
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
+   SELECT am.oid, opcl.oid, c.opoid, 1
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '<<';
+
+-- box_overleft
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
+   SELECT am.oid, opcl.oid, c.opoid, 2
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&<';
+
+-- box_overlap
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
+   SELECT am.oid, opcl.oid, c.opoid, 3
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&&';
+
+-- box_overright
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
+   SELECT am.oid, opcl.oid, c.opoid, 4
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&>';
+
+-- box_right
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
+   SELECT am.oid, opcl.oid, c.opoid, 5
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '>>';
+
+-- box_same
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) 
+   SELECT am.oid, opcl.oid, c.opoid, 6
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '~=';
+
+-- box_contains
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
+   SELECT am.oid, opcl.oid, c.opoid, 7
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '~';
+
+-- box_contained
+INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy)
+   SELECT am.oid, opcl.oid, c.opoid, 8
+   FROM pg_am am, pg_opclass opcl, rt_ops_tmp c
+   WHERE amname = 'gist' and opcname = 'gist_geometry_ops' 
+      and c.oprname = '@';
+
+DROP table rt_ops_tmp;
+
+-- add the entries to amproc for the support methods
+-- note the amprocnum numbers associated with each are specific!
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 1
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_consistent';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 2
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_union';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 3
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_compress';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 4
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'rtree_decompress';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 5
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_penalty';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 6
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_picksplit';
+
+INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum)
+   SELECT am.oid, opcl.oid, pro.oid, 7
+   FROM pg_am am, pg_opclass opcl, pg_proc pro
+   WHERE  amname = 'gist' and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_same';
+
+END TRANSACTION;
diff --git a/postgis_gist_72.c b/postgis_gist_72.c
new file mode 100644 (file)
index 0000000..8dc1ed7
--- /dev/null
@@ -0,0 +1,542 @@
+/******************************************************
+ postGIS - geometric types for postgres
+
+ This software is copyrighted (2001).
+ This is free software; you can redistribute it and/or modify
+ it under the GNU General Public Licence.  See the file "COPYING".
+
+ More Info?  See the documentation, join the mailing list 
+ (postgis@yahoogroups.com), or see the web page
+ (http://postgis.refractions.net).
+
+ GiST indexing functions for pgsql >= 7.2
+ ******************************************************/
+
+#include "postgres.h"
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+
+#include "fmgr.h"
+
+#include "postgis.h"
+#include "utils/elog.h"
+
+//Norman Vine found this problem for compiling under cygwin
+//  it defines BYTE_ORDER and LITTLE_ENDIAN 
+
+#ifdef __CYGWIN__
+#include <sys/param.h>       // FOR ENDIAN DEFINES
+#endif
+
+#define SHOW_DIGS_DOUBLE 15
+#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
+
+// #define DEBUG_GIST
+
+//for GIST index
+typedef char* (*BINARY_UNION)(char*, char*, int*);
+typedef float (*SIZE_BOX)(char*);
+typedef Datum (*RDF)(PG_FUNCTION_ARGS);
+
+
+BOX *convert_box3d_to_box(BOX3D *in);
+Datum ggeometry_compress(PG_FUNCTION_ARGS);
+Datum ggeometry_consistent(PG_FUNCTION_ARGS);
+bool rtree_internal_consistent(BOX *key, BOX *query,StrategyNumber strategy);
+Datum gbox_union(PG_FUNCTION_ARGS);
+Datum gbox_picksplit(PG_FUNCTION_ARGS);
+Datum gbox_penalty(PG_FUNCTION_ARGS);
+Datum gbox_same(PG_FUNCTION_ARGS);
+static bool gbox_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy);
+static float size_box(Datum box);
+
+
+//restriction in the GiST && operator
+PG_FUNCTION_INFO_V1(postgis_gist_sel);
+Datum postgis_gist_sel(PG_FUNCTION_ARGS)
+{
+        PG_RETURN_FLOAT8(0.000005);
+}
+
+BOX    *convert_box3d_to_box(BOX3D *in)
+{
+               BOX     *out = palloc (sizeof (BOX) );
+
+               out->high.x = in->URT.x;
+               out->high.y = in->URT.y;
+
+               out->low.x = in->LLB.x;
+               out->low.y = in->LLB.y;
+
+       return out;
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_compress);
+Datum ggeometry_compress(PG_FUNCTION_ARGS)
+{
+       GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0);
+       GISTENTRY *retval;
+
+       if ( entry->leafkey) 
+       {
+               retval = palloc(sizeof(GISTENTRY));
+               if ( DatumGetPointer(entry->key) != NULL ) {
+
+                       GEOMETRY *in;
+                       BOX     *r;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_compress called on geometry\n");
+       fflush( stdout );
+#endif
+
+                       in = (GEOMETRY*)PG_DETOAST_DATUM( entry->key );
+                       r = convert_box3d_to_box(&in->bvol);
+                       if ( in != (GEOMETRY*)DatumGetPointer(entry->key) ) 
+                       {
+                               pfree( in );
+                       }
+
+                       gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page,
+                               entry->offset, sizeof(BOX), FALSE);
+
+               } else {
+                       gistentryinit(*retval, (Datum) 0, entry->rel, entry->page,
+                               entry->offset, 0,FALSE);
+               } 
+       } else {
+               retval = entry;
+       }
+       PG_RETURN_POINTER(retval);
+}
+
+PG_FUNCTION_INFO_V1(ggeometry_consistent);
+Datum ggeometry_consistent(PG_FUNCTION_ARGS)
+{
+    GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
+    GEOMETRY *query = (GEOMETRY*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+    BOX                *thebox;
+       bool result;
+    /*
+    ** if entry is not leaf, use gbox_internal_consistent,
+    ** else use gbox_leaf_consistent
+    */
+
+#ifdef DEBUG_GIST2
+       printf("GIST: ggeometry_consistent called\n");
+       fflush( stdout );
+#endif
+
+    if ( ! (DatumGetPointer(entry->key) != NULL && query) )
+               PG_RETURN_BOOL(FALSE);
+
+       thebox = convert_box3d_to_box( &(query->bvol) );
+
+    result = rtree_internal_consistent((BOX *) DatumGetPointer(entry->key), thebox, strategy );
+
+       PG_FREE_IF_COPY(query, 1);
+       PG_RETURN_BOOL(result);
+}
+
+bool rtree_internal_consistent(BOX *key,
+                       BOX *query,
+                       StrategyNumber strategy)
+{
+    bool retval;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: rtree_internal_consist called\n");
+       fflush( stdout );
+#endif
+
+    switch(strategy) {
+    case RTLeftStrategyNumber:
+    case RTOverLeftStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overleft, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTOverlapStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTOverRightStrategyNumber:
+    case RTRightStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_right, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTSameStrategyNumber:
+    case RTContainsStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_contain, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    case RTContainedByStrategyNumber:
+      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
+      break;
+    default:
+      retval = FALSE;
+    }
+    return(retval);
+}
+
+PG_FUNCTION_INFO_V1(rtree_decompress);
+Datum rtree_decompress(PG_FUNCTION_ARGS)
+{
+    PG_RETURN_POINTER(PG_GETARG_POINTER(0));
+}
+
+/*
+** The GiST Union method for boxes
+** returns the minimal bounding box that encloses all the entries in entryvec
+*/
+PG_FUNCTION_INFO_V1(gbox_union);
+Datum gbox_union(PG_FUNCTION_ARGS)
+{
+       bytea      *entryvec = (bytea *) PG_GETARG_POINTER(0);
+       int                *sizep = (int *) PG_GETARG_POINTER(1);
+       int                     numranges,
+                               i;
+       BOX                *cur,
+                          *pageunion;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: gbox_union called\n");
+       fflush( stdout );
+#endif
+
+       numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
+       pageunion = (BOX *) palloc(sizeof(BOX));
+       cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[0].key);
+       memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
+
+       for (i = 1; i < numranges; i++)
+       {
+               cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key);
+               if (pageunion->high.x < cur->high.x)
+                       pageunion->high.x = cur->high.x;
+               if (pageunion->low.x > cur->low.x)
+                       pageunion->low.x = cur->low.x;
+               if (pageunion->high.y < cur->high.y)
+                       pageunion->high.y = cur->high.y;
+               if (pageunion->low.y > cur->low.y)
+                       pageunion->low.y = cur->low.y;
+       }
+       *sizep = sizeof(BOX);
+
+       PG_RETURN_POINTER(pageunion);
+}
+
+/*
+** The GiST Penalty method for boxes
+** As in the R-tree paper, we use change in area as our penalty metric
+*/
+PG_FUNCTION_INFO_V1(gbox_penalty);
+Datum gbox_penalty(PG_FUNCTION_ARGS)
+{
+       GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+       float      *result = (float *) PG_GETARG_POINTER(2);
+       Datum           ud;
+       float           tmp1;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: gbox_penalty called\n");
+       fflush( stdout );
+#endif
+
+       ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key);
+       tmp1 = size_box(ud);
+       if (DatumGetPointer(ud) != NULL)
+               pfree(DatumGetPointer(ud));
+
+       *result = tmp1 - size_box(origentry->key);
+       PG_RETURN_POINTER(result);
+}
+
+/*
+** The GiST PickSplit method
+** New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
+** C.H.Ang and T.C.Tan
+*/
+PG_FUNCTION_INFO_V1(gbox_picksplit);
+Datum gbox_picksplit(PG_FUNCTION_ARGS)
+{
+       bytea      *entryvec = (bytea *) PG_GETARG_POINTER(0);
+       GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+       OffsetNumber i;
+       OffsetNumber *listL,
+                          *listR,
+                          *listB,
+                          *listT;
+       BOX                *unionL,
+                          *unionR,
+                          *unionB,
+                          *unionT;
+       int                     posL,
+                               posR,
+                               posB,
+                               posT;
+       BOX                     pageunion;
+       BOX                *cur;
+       char            direction = ' ';
+       bool            allisequal = true;
+       OffsetNumber maxoff;
+       int                     nbytes;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: gbox_picksplit called\n");
+       fflush( stdout );
+#endif
+
+       posL = posR = posB = posT = 0;
+       maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 1;
+
+       cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[FirstOffsetNumber].key);
+       memcpy((void *) &pageunion, (void *) cur, sizeof(BOX));
+
+       /* find MBR */
+       for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
+       {
+               cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key);
+               if (pageunion.high.x < cur->high.x)
+               {
+                       allisequal = false;
+                       pageunion.high.x = cur->high.x;
+               }
+               if (pageunion.low.x > cur->low.x)
+               {
+                       allisequal = false;
+                       pageunion.low.x = cur->low.x;
+               }
+               if (pageunion.high.y < cur->high.y)
+               {
+                       allisequal = false;
+                       pageunion.high.y = cur->high.y;
+               }
+               if (pageunion.low.y > cur->low.y)
+               {
+                       allisequal = false;
+                       pageunion.low.y = cur->low.y;
+               }
+       }
+
+       nbytes = (maxoff + 2) * sizeof(OffsetNumber);
+       listL = (OffsetNumber *) palloc(nbytes);
+       listR = (OffsetNumber *) palloc(nbytes);
+       unionL = (BOX *) palloc(sizeof(BOX));
+       unionR = (BOX *) palloc(sizeof(BOX));
+       if (allisequal)
+       {
+               cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[OffsetNumberNext(FirstOffsetNumber)].key);
+               if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0)
+               {
+                       v->spl_left = listL;
+                       v->spl_right = listR;
+                       v->spl_nleft = v->spl_nright = 0;
+                       memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX));
+                       memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX));
+
+                       for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+                       {
+                               if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
+                               {
+                                       v->spl_left[v->spl_nleft] = i;
+                                       v->spl_nleft++;
+                               }
+                               else
+                               {
+                                       v->spl_right[v->spl_nright] = i;
+                                       v->spl_nright++;
+                               }
+                       }
+                       v->spl_ldatum = BoxPGetDatum(unionL);
+                       v->spl_rdatum = BoxPGetDatum(unionR);
+
+                       PG_RETURN_POINTER(v);
+               }
+       }
+
+       listB = (OffsetNumber *) palloc(nbytes);
+       listT = (OffsetNumber *) palloc(nbytes);
+       unionB = (BOX *) palloc(sizeof(BOX));
+       unionT = (BOX *) palloc(sizeof(BOX));
+
+#define ADDLIST( list, unionD, pos ) do { \
+       if ( pos ) { \
+               if ( unionD->high.x < cur->high.x ) unionD->high.x      = cur->high.x; \
+               if ( unionD->low.x      > cur->low.x  ) unionD->low.x   = cur->low.x; \
+               if ( unionD->high.y < cur->high.y ) unionD->high.y      = cur->high.y; \
+               if ( unionD->low.y      > cur->low.y  ) unionD->low.y   = cur->low.y; \
+       } else { \
+                       memcpy( (void*)unionD, (void*) cur, sizeof( BOX ) );  \
+       } \
+       list[pos] = i; \
+       (pos)++; \
+} while(0)
+
+       for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+       {
+               cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key);
+               if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)
+                       ADDLIST(listL, unionL, posL);
+               else
+                       ADDLIST(listR, unionR, posR);
+               if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)
+                       ADDLIST(listB, unionB, posB);
+               else
+                       ADDLIST(listT, unionT, posT);
+       }
+
+       /* which split more optimal? */
+
+       if (Max(posL, posR) < Max(posB, posT))
+               direction = 'x';
+       else if (Max(posL, posR) > Max(posB, posT))
+               direction = 'y';
+       else
+       {
+               Datum           interLR = DirectFunctionCall2(rt_box_inter,
+                                                                                                 BoxPGetDatum(unionL),
+                                                                                                 BoxPGetDatum(unionR));
+               Datum           interBT = DirectFunctionCall2(rt_box_inter,
+                                                                                                 BoxPGetDatum(unionB),
+                                                                                                 BoxPGetDatum(unionT));
+               float           sizeLR,
+                                       sizeBT;
+
+               sizeLR = size_box(interLR);
+               sizeBT = size_box(interBT);
+
+               if (sizeLR < sizeBT)
+                       direction = 'x';
+               else
+                       direction = 'y';
+       }
+
+       if (direction == 'x')
+       {
+               pfree(unionB);
+               pfree(listB);
+               pfree(unionT);
+               pfree(listT);
+
+               v->spl_left = listL;
+               v->spl_right = listR;
+               v->spl_nleft = posL;
+               v->spl_nright = posR;
+               v->spl_ldatum = BoxPGetDatum(unionL);
+               v->spl_rdatum = BoxPGetDatum(unionR);
+       }
+       else
+       {
+               pfree(unionR);
+               pfree(listR);
+               pfree(unionL);
+               pfree(listL);
+
+               v->spl_left = listB;
+               v->spl_right = listT;
+               v->spl_nleft = posB;
+               v->spl_nright = posT;
+               v->spl_ldatum = BoxPGetDatum(unionB);
+               v->spl_rdatum = BoxPGetDatum(unionT);
+       }
+
+       PG_RETURN_POINTER(v);
+}
+
+/*
+** Equality method
+*/
+PG_FUNCTION_INFO_V1(gbox_same);
+Datum gbox_same(PG_FUNCTION_ARGS)
+{
+       BOX                *b1 = (BOX *) PG_GETARG_POINTER(0);
+       BOX                *b2 = (BOX *) PG_GETARG_POINTER(1);
+       bool       *result = (bool *) PG_GETARG_POINTER(2);
+
+#ifdef DEBUG_GIST2
+       printf("GIST: gbox_same called\n");
+       fflush( stdout );
+#endif
+
+       if (b1 && b2)
+               *result = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(b1), PointerGetDatum(b2)));
+       else
+               *result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;
+       PG_RETURN_POINTER(result);
+}
+
+/*
+** SUPPORT ROUTINES for boxes
+*/
+static bool
+gbox_leaf_consistent(BOX *key,
+                                        BOX *query,
+                                        StrategyNumber strategy)
+{
+       bool            retval;
+
+#ifdef DEBUG_GIST2
+       printf("GIST: gbox_leaf_consistent called\n");
+       fflush( stdout );
+#endif
+
+       switch (strategy)
+       {
+               case RTLeftStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTOverLeftStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTOverlapStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTOverRightStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTRightStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTSameStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTContainsStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               case RTContainedByStrategyNumber:
+                       retval = DatumGetBool(DirectFunctionCall2(box_contained, PointerGetDatum(key), PointerGetDatum(query)));
+                       break;
+               default:
+                       retval = FALSE;
+       }
+       return (retval);
+}
+
+static float
+size_box(Datum box)
+{
+
+#ifdef DEBUG_GIST2
+       printf("GIST: size_box called\n");
+       fflush( stdout );
+#endif
+
+       if (DatumGetPointer(box) != NULL)
+       {
+               float           size;
+
+               DirectFunctionCall2(rt_box_size,
+                                                       box, PointerGetDatum(&size));
+               return size;
+       }
+       else
+               return 0.0;
+}
+
diff --git a/postgis_gist_72.sql.in b/postgis_gist_72.sql.in
new file mode 100644 (file)
index 0000000..0d7d347
--- /dev/null
@@ -0,0 +1,261 @@
+BEGIN TRANSACTION;
+
+-------- 7.2 GiST support functions
+create function ggeometry_consistent(opaque,GEOMETRY,int4) returns bool 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function ggeometry_compress(opaque) returns opaque 
+as '@MODULE_FILENAME@'  language 'C';
+
+create function gbox_penalty(opaque,opaque,opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function gbox_picksplit(opaque, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function gbox_union(bytea, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function gbox_same(box, box, opaque) returns opaque 
+as '@MODULE_FILENAME@'   language 'C';
+
+create function rtree_decompress(opaque) returns opaque
+as '@MODULE_FILENAME@'   language 'C';
+--------------------------
+create function postgis_gist_sel (opaque, oid,  opaque, int4)  returns float8 
+as '@MODULE_FILENAME@'   language 'C';
+
+------ 7.2 RTREE support functions
+
+create function geometry_union(GEOMETRY,GEOMETRY) returns GEOMETRY 
+as '@MODULE_FILENAME@'   language 'C';
+create function geometry_inter(GEOMETRY,GEOMETRY) returns GEOMETRY 
+as '@MODULE_FILENAME@'   language 'C';
+create function geometry_size(GEOMETRY,opaque) returns float4 
+as '@MODULE_FILENAME@'   language 'C';
+
+---------Create actual operators
+
+CREATE OPERATOR << (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_left,
+   COMMUTATOR = '>>',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &< (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overleft,
+   COMMUTATOR = '&>',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR && (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overlap,
+   COMMUTATOR = '&&',
+   RESTRICT = postgis_gist_sel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &> (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_overright,
+   COMMUTATOR = '&<',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR >> (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_right,
+   COMMUTATOR = '<<',
+   RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR ~= (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_same,
+   COMMUTATOR = '=', 
+   RESTRICT = eqsel, JOIN = eqjoinsel
+);
+
+
+
+CREATE OPERATOR @ (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contain,
+   COMMUTATOR = '@',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+
+CREATE OPERATOR ~ (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_contained,
+   COMMUTATOR = '@',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR = (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_eq,
+   COMMUTATOR = '=',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR < (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_lt,
+   COMMUTATOR = '<',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR > (
+   LEFTARG = GEOMETRY, RIGHTARG = GEOMETRY, PROCEDURE = geometry_gt,
+   COMMUTATOR = '>',
+   RESTRICT = contsel, JOIN = contjoinsel
+);
+
+
+
+
+--- old way = insert into pg_opclass values ('gist_geometry_ops');
+
+INSERT INTO pg_opclass (opcamid, opcname, opcintype, opcdefault, opckeytype)
+    VALUES (
+        (SELECT oid FROM pg_am WHERE amname = 'gist'),
+        'gist_geometry_ops',
+        (SELECT oid FROM pg_type WHERE typname = 'geometry'),
+        true,
+        (SELECT oid FROM pg_type WHERE typname = 'box'));
+
+--- drop table rt_ops_tmp;
+
+SELECT o.oid AS opoid, o.oprname
+INTO TABLE rt_ops_tmp
+FROM pg_operator o, pg_type t
+WHERE o.oprleft = t.oid 
+   and t.typname = 'geometry';
+
+-- poly_left
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) 
+   SELECT opcl.oid, 1, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '<<';
+
+-- poly_overleft
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) 
+   SELECT opcl.oid, 2, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&<';
+
+-- poly_overlap
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) 
+   SELECT opcl.oid, 3, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&&';
+
+-- poly_overright
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) 
+   SELECT opcl.oid, 4, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '&>';
+
+-- poly_right
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
+   SELECT opcl.oid, 5, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '>>';
+
+-- poly_same
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr) 
+   SELECT opcl.oid, 6, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '~=';
+
+-- poly_contains
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
+   SELECT opcl.oid, 7, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '~';
+
+-- poly_contained
+INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
+   SELECT opcl.oid, 8, true, c.opoid
+   FROM pg_opclass opcl, rt_ops_tmp c
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops' 
+      and c.oprname = '@';
+
+DROP table rt_ops_tmp;
+
+-- add the entries to amproc for the support methods
+-- note the amprocnum numbers associated with each are specific!
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 1, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_consistent';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 2, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'gbox_union';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 3, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'ggeometry_compress';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 4, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'rtree_decompress';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 5, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'gbox_penalty';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 6, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'gbox_picksplit';
+
+INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
+   SELECT opcl.oid, 7, pro.oid
+   FROM pg_opclass opcl, pg_proc pro
+   WHERE
+      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
+      and opcname = 'gist_geometry_ops'
+      and proname = 'gbox_same';
+
+END TRANSACTION;
index 46d1d0f8e5b5254d4b2a81dac47b4bd0a9f1a3a1..3267a50b1a0f9fb29921c8d9eda251f791bc1742 100644 (file)
 
  *************************************************************/
 
-
-
 #include "postgres.h"
 
-
 #include <math.h>
 #include <float.h>
 #include <string.h>
 #include "access/itup.h"
 #include "access/rtree.h"
 
-
 #include "fmgr.h"
 
-
 #include "postgis.h"
 #include "utils/elog.h"
 
-
 //Norman Vine found this problem for compiling under cygwin
 //  it defines BYTE_ORDER and LITTLE_ENDIAN 
 
 #include <sys/param.h>       // FOR ENDIAN DEFINES
 #endif
 
-
 #define SHOW_DIGS_DOUBLE 15
 #define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
 
 
-// #define DEBUG_GIST
-// #define DEBUG_GIST2
-
-
-
-PG_FUNCTION_INFO_V1(ggeometry_compress);
-PG_FUNCTION_INFO_V1(ggeometry_union);
-PG_FUNCTION_INFO_V1(ggeometry_picksplit);
-PG_FUNCTION_INFO_V1(ggeometry_consistent);
-PG_FUNCTION_INFO_V1(ggeometry_penalty);
-PG_FUNCTION_INFO_V1(ggeometry_same);
-PG_FUNCTION_INFO_V1(ggeometry_inter);
-PG_FUNCTION_INFO_V1(rtree_decompress);
-
-
-//restriction in the GiST && operator
-
-Datum postgis_gist_sel(PG_FUNCTION_ARGS)
-{
-        PG_RETURN_FLOAT8(0.000005);
-}
-
-
 //given a bvol, make a "fake" geometry that contains it (for indexing)
 GEOMETRY *make_bvol_geometry(BOX3D *box)
 {
@@ -630,8 +600,7 @@ Datum box3d_contain(PG_FUNCTION_ARGS)
        BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
        BOX3D              *box2 = (BOX3D *) PG_GETARG_POINTER(1);
 
-
-bool   result;
+       bool result;
 
        result = FPge(box1->URT.x, box2->URT.x) &&
                                   FPle(box1->LLB.x, box2->LLB.x) &&
@@ -656,12 +625,6 @@ Datum geometry_union(PG_FUNCTION_ARGS)
        GEOMETRY                   *result = (GEOMETRY *) palloc(sizeof(GEOMETRY) );
        BOX3D                           *n;
 
-#ifdef DEBUG_GIST2
-       printf("GIST: geometry_union called\n");
-#endif
-
-
-
        if (geom1->SRID != geom2->SRID)
        {
                elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
@@ -709,10 +672,6 @@ Datum geometry_inter(PG_FUNCTION_ARGS)
                elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
                PG_RETURN_NULL();
        }
-#ifdef DEBUG_GIST2
-       printf("GIST: geometry_inter called\n");
-#endif
-
 
        result->size = sizeof(GEOMETRY);
        result->type = BBOXONLYTYPE;
@@ -722,22 +681,22 @@ Datum geometry_inter(PG_FUNCTION_ARGS)
        result->offsetX = geom1->offsetX;
        result->offsetY = geom1->offsetY;
 
-               result->bvol.URT.x = min(geom1->bvol.URT.x, geom2->bvol.URT.x);
-               result->bvol.URT.y = min(geom1->bvol.URT.y, geom2->bvol.URT.y);
-               result->bvol.URT.z = min(geom1->bvol.URT.z, geom2->bvol.URT.z);
+       result->bvol.URT.x = min(geom1->bvol.URT.x, geom2->bvol.URT.x);
+       result->bvol.URT.y = min(geom1->bvol.URT.y, geom2->bvol.URT.y);
+       result->bvol.URT.z = min(geom1->bvol.URT.z, geom2->bvol.URT.z);
 
-               result->bvol.LLB.x = max(geom1->bvol.LLB.x, geom2->bvol.LLB.x);
-               result->bvol.LLB.y = max(geom1->bvol.LLB.y, geom2->bvol.LLB.y);
-               result->bvol.LLB.z = max(geom1->bvol.LLB.z, geom2->bvol.LLB.z);
+       result->bvol.LLB.x = max(geom1->bvol.LLB.x, geom2->bvol.LLB.x);
+       result->bvol.LLB.y = max(geom1->bvol.LLB.y, geom2->bvol.LLB.y);
+       result->bvol.LLB.z = max(geom1->bvol.LLB.z, geom2->bvol.LLB.z);
 
-        if (result->bvol.URT.x < result->bvol.LLB.x || result->bvol.URT.y < result->bvol.LLB.y)
-        {
-                pfree(result);
-                /* Indicate "no intersection" by returning NULL pointer */
-                result = NULL;
-        }
-         PG_FREE_IF_COPY(geom1, 0);
-        PG_FREE_IF_COPY(geom2, 1);
+    if (result->bvol.URT.x < result->bvol.LLB.x || result->bvol.URT.y < result->bvol.LLB.y)
+    {
+               pfree(result);
+        /* Indicate "no intersection" by returning NULL pointer */
+        result = NULL;
+    }
+       PG_FREE_IF_COPY(geom1, 0);
+    PG_FREE_IF_COPY(geom2, 1);
 
        PG_RETURN_POINTER(result);
 }
@@ -745,596 +704,36 @@ Datum geometry_inter(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(geometry_size);
 Datum geometry_size(PG_FUNCTION_ARGS)
 {
-        Pointer                 aptr = PG_GETARG_POINTER(0);
+       Pointer          aptr = PG_GETARG_POINTER(0);
 
-       float           *size = (float *) PG_GETARG_POINTER(1);
-       GEOMETRY        *a;
+    float              *size = (float *) PG_GETARG_POINTER(1);
+    GEOMETRY           *a;
        float                   xdim,ydim;
 
-
-//printf("entering rt_points3d_size \n");
-#ifdef DEBUG_GIST2
-       printf("GIST: geometry_size called\n");
-#endif
-
-
-        if (aptr == NULL)
-        {
-                *size = 0.0;
+    if (aptr == NULL)
+    {
+        *size = 0.0;
                //printf("      + aprt==null return in 0.0\n");
-                PG_RETURN_VOID();
-        }
-
-               a = (GEOMETRY *)   PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-
-        if (a->bvol.URT.x <= a->bvol.LLB.x ||
-                a->bvol.URT.y <= a->bvol.LLB.y)
-                *size = 0.0;
-        else
-        {
-                xdim = (a->bvol.URT.x - a->bvol.LLB.x);
-                ydim = (a->bvol.URT.y - a->bvol.LLB.y);
-
-                *size = (float) (xdim * ydim);
-        }
-
-               //printf("      + about to return (and free) with %e\n",*size);
-
-        /* Avoid leaking memory when handed toasted input. */
-        PG_FREE_IF_COPY(a, 0);
-
         PG_RETURN_VOID();
-}
-
-
-/******************************************************
- * GiST index requires these functions
- *
- *  ORGININAL used BOXONLYTYPE geomery as index
- *
- *     NEW version uses geo_decs.h BOX (2d) type
- *
- *     Based on;
- *
- *     Taken from http://www.sai.msu.su/~megera/postgres/gist/ 
- *   {Slightley Modified}
- *
- ******************************************************/
-
-BOX    *convert_box3d_to_box(BOX3D *in)
-{
-               BOX     *out = palloc (sizeof (BOX) );
-
-               out->high.x = in->URT.x;
-               out->high.y = in->URT.y;
-
-               out->low.x = in->LLB.x;
-               out->low.y = in->LLB.y;
-
-       return out;
-}
-
-
-
-GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS)
-{
-       GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0);
-       GISTENTRY *retval;
-
-       if ( entry->leafkey) {
-               retval = palloc(sizeof(GISTENTRY));
-               if ( entry->pred ) {
-
-                       GEOMETRY *in;
-                       GEOMETRYKEY *r;
-                       BOX     *thebox;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_compress called on geometry\n");
-#endif
-
-                       in = (GEOMETRY*)PG_DETOAST_DATUM(PointerGetDatum(entry->pred));
-                       r = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
-                       r->size = sizeof(GEOMETRYKEY);
-                       r->SRID = in->SRID;
-                       thebox = convert_box3d_to_box(&in->bvol);
-                       memcpy( (void*)&(r->key), (void*)thebox, sizeof(BOX) );
-                       if ( (char*)in != entry->pred ) 
-                       {
-                               pfree( in );
-                               pfree(thebox);
-                       }
-
-                       gistentryinit(*retval, (char*)r, entry->rel, entry->page,
-                               entry->offset, sizeof(GEOMETRYKEY),FALSE);
-
-               } else {
-                       gistentryinit(*retval, NULL, entry->rel, entry->page,
-                               entry->offset, 0,FALSE);
-               } 
-       } else {
-               retval = entry;
-       }
-       return( retval );
-}
-
-bool ggeometry_consistent(PG_FUNCTION_ARGS)
-{
-    GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
-    GEOMETRY *query       = (GEOMETRY*)            PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
-    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-    BOX                *thebox;
-    /*
-    ** if entry is not leaf, use gbox_internal_consistent,
-    ** else use gbox_leaf_consistent
-    */
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_consistent called\n");
-#endif
-
-    if ( ! (entry->pred && query) )
-       return FALSE;
-
-       thebox = convert_box3d_to_box( &(query->bvol) );
-
-       if(    ((GEOMETRYKEY *)(entry->pred))->SRID != query->SRID)
-       {
-               elog(ERROR,"Operation on two GEOMETRIES with different SRIDs (ggeometry_consistent)\n");
-               PG_RETURN_BOOL(FALSE);
-       }
-
-    PG_RETURN_BOOL(rtree_internal_consistent((BOX*)&( ((GEOMETRYKEY *)(entry->pred))->key ), 
-               thebox, strategy));
-}
-
-
-GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS)
-{
-       GEOMETRYKEY             *result;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_union called\n");
-#endif
-
-       result = (GEOMETRYKEY*) 
-               rtree_union(
-                       (bytea*) PG_GETARG_POINTER(0),
-                       (int*) PG_GETARG_POINTER(1),
-                       ggeometry_binary_union
-               );
-
-    return result;
-}
-
-
-float *ggeometry_penalty(PG_FUNCTION_ARGS)
-{
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_penalty called\n");
-#endif
-
-    return rtree_penalty(
-       (GISTENTRY*) PG_GETARG_POINTER(0),
-       (GISTENTRY*) PG_GETARG_POINTER(1),
-       (float*) PG_GETARG_POINTER(2),
-       ggeometry_binary_union,
-       size_geometrykey
-    );
-}
-
-GIST_SPLITVEC *ggeometry_picksplit(PG_FUNCTION_ARGS)
-{
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_picksplit called\n");
-#endif
-
-
-    return rtree_picksplit(
-       (bytea*)PG_GETARG_POINTER(0),
-       (GIST_SPLITVEC*)PG_GETARG_POINTER(1),
-       sizeof(GEOMETRYKEY),
-       ggeometry_binary_union,
-       ggeometry_inter,
-       size_geometrykey
-    );
-}
-
-bool *ggeometry_same(PG_FUNCTION_ARGS)
-{
-
-
-  GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0);
-  GEOMETRYKEY *b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1);
-
-  bool *result = (bool*) PG_GETARG_POINTER(2);
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_same called\n");
-#endif
-
-
-  if ( b1 && b2 )
-       *result = DatumGetBool( DirectFunctionCall2( box_same, 
-               PointerGetDatum(&(b1->key)), 
-               PointerGetDatum(&(b2->key))) );
-  else
-       *result = ( b1==NULL && b2==NULL ) ? TRUE : FALSE; 
-  return(result);
-}
-
-Datum ggeometry_inter(PG_FUNCTION_ARGS) {
-       GEOMETRYKEY *b1 = (GEOMETRYKEY*) PG_GETARG_POINTER(0);
-       GEOMETRYKEY*b2 = (GEOMETRYKEY*) PG_GETARG_POINTER(1);
-       char *interd;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_inter called\n");
-#endif
-
-
-       interd = DatumGetPointer(DirectFunctionCall2(
-                       rt_box_inter,
-                       PointerGetDatum( &(b1->key) ),
-                       PointerGetDatum( &(b2->key) )) );
-       
-       if (interd) {
-               GEOMETRYKEY *tmp = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
-               tmp->size = sizeof(GEOMETRYKEY);
-       
-               memcpy( (void*)&(tmp->key), (void*)interd, sizeof(BOX) );
-               tmp->SRID = b1->SRID;
-               pfree( interd );
-               PG_RETURN_POINTER( tmp );
-       } else 
-               PG_RETURN_POINTER( NULL );
-}
-
-char *ggeometry_binary_union(char *r1, char *r2, int *sizep)
-{
-    GEOMETRYKEY *retval;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: ggeometry_binary_union called\n");
-#endif
-
-
-
-    if ( ! (r1 && r2) ) {
-       if ( r1 ) {
-               retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
-               memcpy( (void*)retval, (void*)r1, sizeof(GEOMETRYKEY) );
-               *sizep = sizeof(GEOMETRYKEY);
-       } else if ( r2 ) {
-               retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
-               memcpy( (void*)retval, (void*)r2, sizeof(GEOMETRYKEY) );
-               *sizep = sizeof(GEOMETRYKEY);
-       } else {
-               *sizep = 0;
-               retval = NULL;
-       } 
-    } else {
-       BOX *key = (BOX*)DatumGetPointer( DirectFunctionCall2(
-               rt_box_union,
-               PointerGetDatum( &(((GEOMETRYKEY*)r1)->key) ),
-               PointerGetDatum( &(((GEOMETRYKEY*)r2)->key) )) );
-       retval = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) );
-       retval->SRID = ((GEOMETRYKEY *) r1)->SRID;
-       memcpy( (void*)&(retval->key), (void*)key, sizeof(BOX) );
-       pfree( key );
-       *sizep = retval->size = sizeof(GEOMETRYKEY);
     }
-    return (char*)retval;
-}
 
+       a = (GEOMETRY *)   PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 
-float size_geometrykey( char *pk ) {
+    if (a->bvol.URT.x <= a->bvol.LLB.x ||
+        a->bvol.URT.y <= a->bvol.LLB.y)
+        *size = 0.0;
+    else
+    {
+               xdim = (a->bvol.URT.x - a->bvol.LLB.x);
+        ydim = (a->bvol.URT.y - a->bvol.LLB.y);
 
-#ifdef DEBUG_GIST2
-       printf("GIST: size_geometrykey called\n");
-#endif
-
-
-    if ( pk ) {
-       float size;
-       DirectFunctionCall2( rt_box_size,
-               PointerGetDatum( &(((GEOMETRYKEY*)pk)->key) ),
-               PointerGetDatum( &size ) );
-       return size;
-    } else
-       return 0.0;
-}
-
-char *rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu)
-{
-    int numranges, i;
-    char *out, *tmp;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: rtree_union called\n");
-#endif
-
-
-
-    numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); 
-    tmp = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[0]).pred;
-    out = NULL;
-
-    for (i = 1; i < numranges; i++) {
-       out = (*bu)(tmp, (char *)
-                                (((GISTENTRY *)(VARDATA(entryvec)))[i]).pred,
-                                sizep);
-       if (i > 1 && tmp) pfree(tmp);
-       tmp = out;
+        *size = (float) (xdim * ydim);
     }
 
-    return(out);
-}
-
-float *rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, BINARY_UNION bu, SIZE_BOX sb)
-{
-    char * ud;
-    float tmp1;
-    int sizep;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: rtree_penalty called\n");
-#endif
-
-
-   
-    ud = (*bu)( origentry->pred, newentry->pred, &sizep );
-    tmp1 = (*sb)( ud ); 
-    if (ud) pfree(ud);
-
-    *result = tmp1 - (*sb)( origentry->pred );
-    return(result);
-}
-
-/*
-** The GiST PickSplit method
-** We use Guttman's poly time split algorithm 
-*/
-GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb)
-{
-    OffsetNumber i, j;
-    char *datum_alpha, *datum_beta;
-    char *datum_l, *datum_r;
-    char *union_d, *union_dl, *union_dr;
-    char *inter_d;
-    bool firsttime;
-    float size_alpha, size_beta, size_union, size_inter;
-    float size_waste, waste;
-    float size_l, size_r;
-    int nbytes;
-    int sizep;
-    OffsetNumber seed_1 = 0, seed_2 = 0;
-    OffsetNumber *left, *right;
-    OffsetNumber maxoff;
-
-
-#ifdef DEBUG_GIST2
-       printf("GIST: rtree_picsplit called\n");
-#endif
-
+       //printf("      + about to return (and free) with %e\n",*size);
 
-    maxoff = ((VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY)) - 2;
-    nbytes =  (maxoff + 2) * sizeof(OffsetNumber);
-    v->spl_left = (OffsetNumber *) palloc(nbytes);
-    v->spl_right = (OffsetNumber *) palloc(nbytes);
-    
-    firsttime = true;
-    waste = 0.0;
-    
-    for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) {
-       datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred);
-       for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) {
-           datum_beta = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[j].pred);
-           
-           /* compute the wasted space by unioning these guys */
-           /* size_waste = size_union - size_inter; */ 
-           union_d = (*bu)( datum_alpha, datum_beta, &sizep );
-           if ( union_d ) {
-               size_union = (*sb)(union_d);
-               pfree(union_d);
-           } else
-               size_union = 0.0;
-
-           if ( datum_alpha && datum_beta ) {
-               inter_d = DatumGetPointer(DirectFunctionCall2(
-                       interop,
-                       PointerGetDatum( datum_alpha ),
-                       PointerGetDatum( datum_beta )) );
-               if ( inter_d ) {
-                       size_inter = (*sb)(inter_d);
-                       pfree(inter_d);
-               } else 
-                       size_inter = 0.0;
-           } else
-               size_inter = 0.0;
-
-           size_waste = size_union - size_inter;
-           
-           /*
-            *  are these a more promising split that what we've
-            *  already seen?
-            */
-           
-           if (size_waste > waste || firsttime) {
-               waste = size_waste;
-               seed_1 = i;
-               seed_2 = j;
-               firsttime = false;
-           }
-       }
-    }
-    
-    left = v->spl_left;
-    v->spl_nleft = 0;
-    right = v->spl_right;
-    v->spl_nright = 0;
-  
-    if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ) {
-       datum_l = (char*) palloc( keylen );
-       memcpy( (void*)datum_l, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ), keylen );
-    } else 
-       datum_l = NULL; 
-    size_l  = (*sb)( datum_l ); 
-    if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ) {
-       datum_r = (char*) palloc( keylen );
-       memcpy( (void*)datum_r, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ), keylen );
-    } else 
-       datum_r = NULL; 
-    size_r  = (*sb)( datum_r ); 
-    
-    /*
-     *  Now split up the regions between the two seeds.  An important
-     *  property of this split algorithm is that the split vector v
-     *  has the indices of items to be split in order in its left and
-     *  right vectors.  We exploit this property by doing a merge in
-     *  the code that actually splits the page.
-     *
-     *  For efficiency, we also place the new index tuple in this loop.
-     *  This is handled at the very end, when we have placed all the
-     *  existing tuples and i == maxoff + 1.
-     */
-    
-    maxoff = OffsetNumberNext(maxoff);
-    for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
+    /* Avoid leaking memory when handed toasted input. */
+       PG_FREE_IF_COPY(a, 0);
        
-       /*
-        *  If we've already decided where to place this item, just
-        *  put it on the right list.  Otherwise, we need to figure
-        *  out which page needs the least enlargement in order to
-        *  store the item.
-        */
-       
-       if (i == seed_1) {
-           *left++ = i;
-           v->spl_nleft++;
-           continue;
-       } else if (i == seed_2) {
-           *right++ = i;
-           v->spl_nright++;
-           continue;
-       }
-       
-       /* okay, which page needs least enlargement? */ 
-       datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred);
-       union_dl = (*bu)( datum_l, datum_alpha, &sizep );
-       union_dr = (*bu)( datum_r, datum_alpha, &sizep );
-       size_alpha = (*sb)( union_dl ); 
-       size_beta  = (*sb)( union_dr ); 
-       
-       /* pick which page to add it to */
-       if (size_alpha - size_l < size_beta - size_r) {
-           pfree(datum_l);
-           pfree(union_dr);
-           datum_l = union_dl;
-           size_l = size_alpha;
-           *left++ = i;
-           v->spl_nleft++;
-       } else {
-           pfree(datum_r);
-           pfree(union_dl);
-           datum_r = union_dr;
-           size_r = size_alpha;
-           *right++ = i;
-           v->spl_nright++;
-       }
-    }
-    *left = *right = FirstOffsetNumber;        /* sentinel value, see dosplit() */
-    
-    v->spl_ldatum = datum_l;
-    v->spl_rdatum = datum_r;
-
-    return( v );
-}
-
-
-bool rtree_internal_consistent(BOX *key,
-                       BOX *query,
-                       StrategyNumber strategy)
-{
-    bool retval;
-
-#ifdef DEBUG_GIST2
-       printf("GIST: rtree_internal_consist called\n");
-#endif
-
-
-
-    switch(strategy) {
-    case RTLeftStrategyNumber:
-    case RTOverLeftStrategyNumber:
-      retval = DatumGetBool( DirectFunctionCall2( box_overleft, PointerGetDatum(key), PointerGetDatum(query) ) );
-      break;
-    case RTOverlapStrategyNumber:
-      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
-      break;
-    case RTOverRightStrategyNumber:
-    case RTRightStrategyNumber:
-      retval = DatumGetBool( DirectFunctionCall2( box_right, PointerGetDatum(key), PointerGetDatum(query) ) );
-      break;
-    case RTSameStrategyNumber:
-    case RTContainsStrategyNumber:
-      retval = DatumGetBool( DirectFunctionCall2( box_contain, PointerGetDatum(key), PointerGetDatum(query) ) );
-      break;
-    case RTContainedByStrategyNumber:
-      retval = DatumGetBool( DirectFunctionCall2( box_overlap, PointerGetDatum(key), PointerGetDatum(query) ) );
-      break;
-    default:
-      retval = FALSE;
-    }
-    return(retval);
-}
-
-GISTENTRY *rtree_decompress(PG_FUNCTION_ARGS)
-{
-    return((GISTENTRY*)PG_GETARG_POINTER(0));
-}
-
-
-PG_FUNCTION_INFO_V1(box3d_xmin);
-Datum box3d_xmin(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->LLB.x);
-}
-
-PG_FUNCTION_INFO_V1(box3d_ymin);
-Datum box3d_ymin(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->LLB.y);
-}
-PG_FUNCTION_INFO_V1(box3d_zmin);
-Datum box3d_zmin(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->LLB.z);
-}
-PG_FUNCTION_INFO_V1(box3d_xmax);
-Datum box3d_xmax(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->URT.x);
-}
-PG_FUNCTION_INFO_V1(box3d_ymax);
-Datum box3d_ymax(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->URT.y);
-}
-PG_FUNCTION_INFO_V1(box3d_zmax);
-Datum box3d_zmax(PG_FUNCTION_ARGS)
-{
-       BOX3D              *box1 = (BOX3D *) PG_GETARG_POINTER(0);
-
-       PG_RETURN_FLOAT8(box1->URT.z);
+       PG_RETURN_VOID();
 }