# Configuration Directives
-
+#---------------------------------------------------------------
+# Set USE_PG72 to 1 for PostgreSQL version >= 7.2
+USE_PG72=0
#---------------------------------------------------------------
# Set USE_PROJ to 1 for Proj4 reprojection support
-USE_PROJ=0
+USE_PROJ=1
#---------------------------------------------------------------
subdir=contrib/postgis
libdir := ${PWD}
endif
-#---------------------------------------------------------------
-# Test the version string and select the correct GiST index
-# bindings.
-ifneq ($(findstring 7.1,$(VERSION)),)
- USE_PG72=0
-else
- USE_PG72=1
-endif
-
-#---------------------------------------------------------------
-# Regression test temporary database.
TEST_DB=geom_regress
#---------------------------------------------------------------
override DLLLIBS := $(BE_DLLLIBS) $(DLLLIBS)
ifeq ($(USE_PG72),1)
- OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o postgis_gist_72.o
+ OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o postgis_gist_72.o postgis_estimate.o
else
- OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o postgis_gist.o
+ OBJS=postgis_debug.o postgis_ops.o postgis_fn.o postgis_inout.o postgis_proj.o postgis_chip.o postgis_transform.o postgis_gist.o
endif
# Add libraries that libpq depends (or might depend) on into the
unsigned char data[1]; //THIS HOLD VARIABLE LENGTH DATA
} WellKnownBinary;
+// --------------------------------------------
+// histogram2d type
+
+// 2d histogram is a bounding box with a bunch of cells in it.
+// The cells will have width (xmax-xmin)/boxesPerSide
+// and height(ymax-ymin)/boxesPerSide
+// The first box is the ll corner's box, the send is directly to the right
+// (row-major).
+//
+// Size of structure is:
+// 4 (size) + 32 (box) + 4 (boxesPerSide) +
+// boxesPerSide*boxesPerSide*4 (data)
+typedef struct histotag
+{
+ int32 size; // postgres variable-length type requirement
+ int boxesPerSide; //boxesPerSide * boxesPerSide = total boxes in grid
+ double avgFeatureArea; // average bbox area of features in this histogram
+ // double will be correctly aligned
+ double xmin,ymin, xmax, ymax; // BOX of area
+ unsigned int value[1]; // variable length # of ints for histogram
+} HISTOGRAM2D;
+
+
//prototypes
Datum WKBtoBYTEA(PG_FUNCTION_ARGS);
+Datum histogram2d_in(PG_FUNCTION_ARGS);
+Datum histogram2d_out(PG_FUNCTION_ARGS);
+Datum create_histogram2d(PG_FUNCTION_ARGS);
+
+Datum build_histogram2d(PG_FUNCTION_ARGS);
+
+Datum geometry2box(PG_FUNCTION_ARGS);
+
+Datum explode_histogram2d(PG_FUNCTION_ARGS);
+Datum estimate_histogram2d(PG_FUNCTION_ARGS);
+
+Datum postgisgistcostestimate(PG_FUNCTION_ARGS);
/*--------------------------------------------------------------------
* Useful floating point utilities and constants.
LANGUAGE 'sql';
+-- need this to define geometry_columns table
+create function histogram2d_in(opaque)
+ RETURNS HISTOGRAM2D
+ AS '@MODULE_FILENAME@'
+ LANGUAGE 'c' with (isstrict);
+
+create function histogram2d_out(opaque)
+ RETURNS opaque
+ AS '@MODULE_FILENAME@'
+ LANGUAGE 'c' with (isstrict);
+
+CREATE TYPE HISTOGRAM2D (
+ alignment = double,
+ internallength = VARIABLE,
+ input = histogram2d_in,
+ output = histogram2d_out,
+ storage = main
+);
+
+
+
+
+--drop function FIX_GEOMETRY_COLUMNS() ;
+--utility function to fixup the geometry_columns table with system table information
+CREATE FUNCTION FIX_GEOMETRY_COLUMNS() returns text
+as
+'
+BEGIN
+ EXECUTE ''update geometry_columns set attrelid = (select pg_class.oid as attrelid from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name), varattnum = (select pg_attribute.attnum from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name)'';
+ RETURN ''GEOMETRY_COLUMNS table is now linked to the system tables'';
+END;
+'
+ LANGUAGE 'plpgsql' ;
+
-- create the table with spatial referencing information in it. spec, section 3.2.1.2
create table spatial_ref_sys (
coord_dimension integer NOT NULL,
srid integer NOT NULL,
type varchar(30) NOT NULL,
+attrelid oid,
+varattnum int,
+stats HISTOGRAM2D,
CONSTRAINT GC_PK primary key ( f_table_catalog,f_table_schema, f_table_name,f_geometry_column)
) ;
-- update the given table/column so that it it all NULLS
- EXECUTE ''update ''||table_name||'' set ''||column_name||''= NULL'';
+ EXECUTE ''update "''||table_name||''" set "''||column_name||''"= NULL'';
-- add = NULL constraint to given table/column
- EXECUTE ''ALTER TABLE ''||table_name||'' ADD CHECK (''||column_name||'' IS NULL)'';
+ EXECUTE ''ALTER TABLE "''||table_name||''" ADD CHECK ("''||column_name||''" IS NULL)'';
RETURN table_name || ''.'' || column_name ||'' effectively removed.'';
return ''fail'';
end if;
- EXECUTE ''ALTER TABLE '' || table_name || '' ADD COLUMN '' || column_name || '' GEOMETRY '';
+ EXECUTE ''ALTER TABLE "'' || table_name || ''" ADD COLUMN "'' || column_name || ''" GEOMETRY '';
EXECUTE ''INSERT INTO geometry_columns VALUES ('' || quote_literal('''') || '','' ||
quote_literal(database_name) || '','' || quote_literal(table_name) || '','' ||
quote_literal(column_name) || '','' ||
new_dim ||'',''||new_srid||'',''||quote_literal(new_type)||'')'';
+ EXECUTE ''update geometry_columns set attrelid = (select pg_class.oid as attrelid from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name), varattnum = (select pg_attribute.attnum from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name)'';
- EXECUTE ''ALTER TABLE '' ||table_name||'' ADD CHECK (SRID('' || column_name ||
- '') = '' || new_srid || '')'' ;
+ EXECUTE ''ALTER TABLE "'' ||table_name||''" ADD CHECK (SRID("'' || column_name ||
+ ''") = '' || new_srid || '')'' ;
IF (not(new_type = ''GEOMETRY'')) THEN
- EXECUTE ''ALTER TABLE '' ||table_name||'' ADD CHECK ( geometrytype(''||column_name||'')=''|| quote_literal(new_type)||'' OR ('' ||column_name ||'') is null)'';
+ EXECUTE ''ALTER TABLE "'' ||table_name||''" ADD CHECK ( geometrytype("''||column_name||''")=''|| quote_literal(new_type)||'' OR ('' ||column_name ||'') is null)'';
END IF;
return ''Geometry column '' || column_name || '' added to table ''
storage= extended
);
+--drop function find_extent(text,text);
+-- FIND_EXTENT(table name,column name)
+CREATE FUNCTION FIND_EXTENT(text,text) returns box3d as
+'
+DECLARE
+ tablename alias for $1;
+ columnname alias for $2;
+ okay boolean;
+ myrec RECORD;
+
+BEGIN
+ FOR myrec IN EXECUTE ''SELECT extent("''||columnname||''") FROM "''||tablename||''"'' LOOP
+ return myrec.extent;
+ END LOOP;
+END;
+'
+LANGUAGE 'plpgsql' with (isstrict);
+--select find_extent('test_data','the_geom');
+--CREATE FUNCTION get_proj4_from_srid(integer) returns text as
+--'SELECT proj4text::text FROM spatial_ref_sys WHERE srid= $1'
+--LANGUAGE 'sql' with (iscachable,isstrict);
+
AS '@MODULE_FILENAME@','CHIP_to_geom'
LANGUAGE 'c' with (isstrict,iscachable);
-
-
CREATE FUNCTION box3d(GEOMETRY)
RETURNS BOX3D
AS '@MODULE_FILENAME@','get_bbox_of_geometry'
LANGUAGE 'c' WITH (iscachable,isstrict);
+
+CREATE FUNCTION box(GEOMETRY)
+ RETURNS BOX
+ AS '@MODULE_FILENAME@','geometry2box'
+ LANGUAGE 'c' WITH (iscachable,isstrict);
+
CREATE FUNCTION geometry(BOX3D)
RETURNS GEOMETRY
AS '@MODULE_FILENAME@','get_geometry_of_bbox'
--- 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';
-
+update pg_type set typdefault = NULL where typname = 'histogram2d';
end TRANSACTION;
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
+ More Info? See the documentation, join the mailing list
(postgis@yahoogroups.com), or see the web page
(http://postgis.refractions.net).
#include "utils/elog.h"
//Norman Vine found this problem for compiling under cygwin
-// it defines BYTE_ORDER and LITTLE_ENDIAN
+// it defines BYTE_ORDER and LITTLE_ENDIAN
#ifdef __CYGWIN__
#include <sys/param.h> // FOR ENDIAN DEFINES
int debug = 0;
-//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)
{
GISTENTRY *entry=(GISTENTRY*)PG_GETARG_POINTER(0);
GISTENTRY *retval;
- if ( entry->leafkey)
+ if ( entry->leafkey)
{
retval = palloc(sizeof(GISTENTRY));
if ( DatumGetPointer(entry->key) != NULL ) {
in = (GEOMETRY*)PG_DETOAST_DATUM( entry->key );
r = convert_box3d_to_box(&in->bvol);
- if ( in != (GEOMETRY*)DatumGetPointer(entry->key) )
+ if ( in != (GEOMETRY*)DatumGetPointer(entry->key) )
{
pfree( in );
}
} else {
gistentryinit(*retval, (Datum) 0, entry->rel, entry->page,
entry->offset, 0,FALSE);
- }
+ }
} else {
retval = entry;
}
static int
compare_KB(const void* a, const void* b) {
- BOX *abox = ((KBsort*)a)->key;
+ BOX *abox = ((KBsort*)a)->key;
BOX *bbox = ((KBsort*)b)->key;
float sa = (abox->high.x - abox->low.x) * (abox->high.y - abox->low.y);
float sb = (bbox->high.x - bbox->low.x) * (bbox->high.y - bbox->low.y);
{
cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[i].key);
if ( allisequal == true && (
- pageunion.high.x != cur->high.x ||
- pageunion.high.y != cur->high.y ||
- pageunion.low.x != cur->low.x ||
- pageunion.low.y != cur->low.y
- ) )
+ pageunion.high.x != cur->high.x ||
+ pageunion.high.y != cur->high.y ||
+ pageunion.low.x != cur->low.x ||
+ pageunion.low.y != cur->low.y
+ ) )
allisequal = false;
-
+
if (pageunion.high.x < cur->high.x)
pageunion.high.x = cur->high.x;
if (pageunion.low.x > cur->low.x)
return 0.0;
}
+
BEGIN TRANSACTION;
+--drop function UPDATE_GEOMETRY_STATS();
+-- UPDATE_GEOMETRY_STATS() -- all tables
+CREATE FUNCTION UPDATE_GEOMETRY_STATS() returns text
+AS
+'
+BEGIN
+ EXECUTE ''update geometry_columns set attrelid = (select pg_class.oid as attrelid from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name), varattnum = (select pg_attribute.attnum from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name)'';
+ execute ''update geometry_columns set stats = (build_histogram2d( create_histogram2d(find_extent(f_table_name,f_geometry_column),40 ),f_table_name::text, f_geometry_column::text)) '';
+ return ''done'';
+END;
+'
+LANGUAGE 'plpgsql' ;
+--select UPDATE_GEOMETRY_STATS();
+
+
+--drop function UPDATE_GEOMETRY_STATS(varchar,varchar);
+-- UPDATE_GEOMETRY_STATS(table name,column name)
+CREATE FUNCTION UPDATE_GEOMETRY_STATS(varchar,varchar) returns text
+AS
+'
+DECLARE
+ tablename alias for $1;
+ columnname alias for $2;
+
+BEGIN
+ EXECUTE ''update geometry_columns set attrelid = (select pg_class.oid as attrelid from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name), varattnum = (select pg_attribute.attnum from pg_class,pg_attribute where relname =geometry_columns.f_table_name::name and pg_attribute.attrelid = pg_class.oid and pg_attribute.attname = geometry_columns.f_geometry_column::name)'';
+ execute ''update geometry_columns set stats = (build_histogram2d( create_histogram2d(find_extent(''|| quote_literal(tablename) || '',''||quote_literal(columnname) ||''),40 ),''|| quote_literal(tablename) || ''::text,''||quote_literal(columnname) ||''::text )) WHERE f_table_name=''|| quote_literal(tablename) || ''and f_geometry_column=''||quote_literal(columnname) ;
+ return ''done'';
+END;
+'
+LANGUAGE 'plpgsql' ;
+--select UPDATE_GEOMETRY_STATS('test_data','the_geom');
+
+
+
+
+--- create_histogram2d(BOX3D, boxesPerSide)
+--- returns a histgram with 0s in all the boxes.
+CREATE FUNCTION create_histogram2d(box3d,int)
+ RETURNS HISTOGRAM2D
+ AS '@MODULE_FILENAME@','create_histogram2d'
+ LANGUAGE 'c' with (isstrict);
+
+
+---- build_histogram2d (HISTOGRAM2D, tablename, columnname)
+CREATE FUNCTION build_histogram2d (HISTOGRAM2D,text,text)
+ RETURNS HISTOGRAM2D
+ AS '@MODULE_FILENAME@','build_histogram2d'
+ LANGUAGE 'c' with (isstrict);
+
+---- explode_histogram2d(HISTOGRAM2D, tablename)
+CREATE FUNCTION explode_histogram2d (HISTOGRAM2D,text)
+ RETURNS HISTOGRAM2D
+ AS '@MODULE_FILENAME@','explode_histogram2d'
+ LANGUAGE 'c' with (isstrict);
+
+---- estimate_histogram2d(HISTOGRAM2D, box)
+CREATE FUNCTION estimate_histogram2d(HISTOGRAM2D,box)
+ RETURNS FLOAT8
+ AS '@MODULE_FILENAME@','estimate_histogram2d'
+ LANGUAGE 'c' with (isstrict);
+
+
+
+create function postgisgistcostestimate(opaque,opaque,opaque,opaque,opaque,opaque,opaque,opaque)
+ RETURNS opaque
+ AS '@MODULE_FILENAME@','postgisgistcostestimate'
+ LANGUAGE 'c' with (isstrict);
+
-------- 7.2 GiST support functions
create function ggeometry_consistent(opaque,GEOMETRY,int4) returns bool
as '@MODULE_FILENAME@' language 'C';
PG_RETURN_POINTER(result);
}
+
+PG_FUNCTION_INFO_V1(geometry2box);
+Datum geometry2box(PG_FUNCTION_ARGS)
+{
+ GEOMETRY *g = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+//elog(NOTICE,"geometry2box - ymax is %.15g",g->bvol.URT.y);
+
+ PG_RETURN_POINTER(convert_box3d_to_box(&g->bvol) );
+
+}
+
+//create_histogram2d(BOX3D, boxesPerSide)
+// returns a histgram with 0s in all the boxes.
+PG_FUNCTION_INFO_V1(create_histogram2d);
+Datum create_histogram2d(PG_FUNCTION_ARGS)
+{
+ BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0);
+ int32 boxesPerSide= PG_GETARG_INT32(1);
+ HISTOGRAM2D *histo;
+ int size,t;
+
+
+ if ( (boxesPerSide <1) || (boxesPerSide >50) )
+ {
+ elog(ERROR,"create_histogram2d - boxesPerSide is too small or big.\n");
+ PG_RETURN_NULL() ;
+ }
+
+
+ size = sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ;
+
+ histo = (HISTOGRAM2D *) palloc (size);
+ histo->size = size;
+
+ histo->xmin = bbox->LLB.x;
+ histo->ymin = bbox->LLB.y;
+
+
+ histo->xmax = bbox->URT.x;
+ histo->ymax = bbox->URT.y;
+
+ histo->avgFeatureArea = 0;
+
+ histo->boxesPerSide = boxesPerSide;
+
+ for (t=0;t<boxesPerSide*boxesPerSide; t++)
+ {
+ histo->value[t] =0;
+ }
+
+ //elog(NOTICE,"create_histogram2d returning");
+
+ PG_RETURN_POINTER(histo);
+
+}
+
+
+//text form of HISTOGRAM2D is:
+// 'HISTOGRAM2D(xmin,ymin,xmax,ymax,boxesPerSide;value[0],value[1],...')
+// note the ";" in the middle (for easy parsing)
+// I dont expect anyone to actually create one by hand
+PG_FUNCTION_INFO_V1(histogram2d_in);
+Datum histogram2d_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ HISTOGRAM2D *histo ;
+ int nitems;
+ double xmin,ymin,xmax,ymax;
+ int boxesPerSide;
+ double avgFeatureArea;
+ char *str2,*str3;
+ long datum;
+
+ int t;
+
+ while (isspace((unsigned char) *str))
+ str++;
+
+ if (strstr(str,"HISTOGRAM2D(") != str)
+ {
+ elog(ERROR,"histogram2d parser - doesnt start with 'HISTOGRAM2D(\n");
+ PG_RETURN_NULL() ;
+ }
+ if (strstr(str,";") == NULL)
+ {
+ elog(ERROR,"histogram2d parser - doesnt have a ; in sring!\n");
+ PG_RETURN_NULL() ;
+ }
+
+ nitems = sscanf(str,"HISTOGRAM2D(%lf,%lf,%lf,%lf,%i,%lf;",&xmin,&ymin,&xmax,&ymax,&boxesPerSide,&avgFeatureArea);
+
+ if (nitems != 6)
+ {
+ elog(ERROR,"histogram2d parser - couldnt parse initial portion of histogram!\n");
+ PG_RETURN_NULL() ;
+ }
+
+ if ( (boxesPerSide > 50) || (boxesPerSide <1) )
+ {
+ elog(ERROR,"histogram2d parser - boxesPerSide is too big or too small\n");
+ PG_RETURN_NULL() ;
+ }
+
+ str2 = strstr(str,";");
+ str2++;
+
+ if (str2[0] ==0)
+ {
+ elog(ERROR,"histogram2d parser - no histogram values\n");
+ PG_RETURN_NULL() ;
+ }
+
+ histo = (HISTOGRAM2D *) palloc (sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 );
+ histo->size = sizeof(HISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ;
+
+ for (t=0;t<boxesPerSide*boxesPerSide;t++)
+ {
+ datum = strtol(str2,&str3,10); // str2=start of int, str3=end of int, base 10
+ // str3 points to "," or ")"
+ if (str3[0] ==0)
+ {
+ elog(ERROR,"histogram2d parser - histogram values prematurely ended!\n");
+ PG_RETURN_NULL() ;
+ }
+ histo->value[t] = (unsigned int) datum;
+ str2= str3+1; //move past the "," or ")"
+ }
+ histo->xmin = xmin;
+ histo->xmax = xmax;
+ histo->ymin = ymin;
+ histo->ymax = ymax;
+ histo->avgFeatureArea = avgFeatureArea;
+ histo->boxesPerSide = boxesPerSide;
+
+ PG_RETURN_POINTER(histo);
+}
+
+
+
+//text version
+PG_FUNCTION_INFO_V1(histogram2d_out);
+Datum histogram2d_out(PG_FUNCTION_ARGS)
+{
+ //char *result;
+ //result = palloc(200);
+ //sprintf(result,"HISTOGRAM2D(0,0,100,100,2;11,22,33,44)");
+ //PG_RETURN_CSTRING(result);
+
+ HISTOGRAM2D *histo = (HISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ char *result;
+ int t;
+ char temp[100];
+ int size;
+
+ size = 26+6*MAX_DIGS_DOUBLE + histo->boxesPerSide*histo->boxesPerSide* (MAX_DIGS_DOUBLE+1);
+ result = palloc(size);
+
+ sprintf(result,"HISTOGRAM2D(%.15g,%.15g,%.15g,%.15g,%i,%.15g;",
+ histo->xmin,histo->ymin,histo->xmax,histo->ymax,histo->boxesPerSide,histo->avgFeatureArea );
+
+ //elog(NOTICE,"so far: %s",result);
+ //elog(NOTICE,"buffsize=%i, size=%i",size,histo->size);
+
+ for (t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
+ {
+ if (t!=((histo->boxesPerSide*histo->boxesPerSide)-1))
+ sprintf(temp,"%u,", histo->value[t]);
+ else
+ sprintf(temp,"%u", histo->value[t]);
+ strcat(result,temp);
+ }
+
+ strcat(result,")");
+ //elog(NOTICE,"about to return string (len=%i): -%s-",strlen(result),result);
+
+ PG_RETURN_CSTRING(result);
+
+}
+