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
# 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 $< > $@
$(CC) $(CFLAGS) $(OBJS) shp2pgsql.o $(libpq) $(LDFLAGS) $(LIBS) -o $@
clean:
- @rm -f $(OBJS) shp2pgsql pgsql2shp
+ @rm -f $(OBJS) shp2pgsql.o pgsql2shp.o shp2pgsql pgsql2shp
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);
-
/*--------------------------------------------------------------------
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';
#include "access/itup.h"
#include "access/rtree.h"
-
-
-
#include "fmgr.h"
-
#include "postgis.h"
#include "utils/elog.h"
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);
+}
+
--- /dev/null
+/******************************************************
+ 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));
+}
+
+
--- /dev/null
+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;
--- /dev/null
+/******************************************************
+ 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;
+}
+
--- /dev/null
+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;
*************************************************************/
-
-
#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)
{
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) &&
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");
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;
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);
}
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();
}