diff --git a/.gitignore b/.gitignore index 6789011420f..0500abd1597 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,9 @@ *.la .libs *.lo +*~ gmon.out -install-sh +/install-sh postgis_svn_revision.h aclocal.m4 autom4te.cache/ @@ -86,6 +87,7 @@ postgis/legacy_gist.sql postgis/legacy_minimal.sql postgis/legacy.sql postgis/postgis.sql +postgis/pipeline_gis.sql postgis/postgis_upgrade.sql* postgis/sfcgal_upgrade.sql* postgis/sqldefines.h @@ -128,11 +130,8 @@ topology/test/load_topology.sql topology/test/topo_predicates.sql topology/test/regress/topogeo_addlinestring_expected topology/topology_drop_after.sql -topology/topology_drop_after.sql.in topology/topology_drop_before.sql -topology/topology_drop_before.sql.in topology/topology.sql -topology/topology.sql.in topology/topology_upgrade.sql* topology/uninstall_topology.sql libpgcommon/Makefile diff --git a/GNUmakefile.in b/GNUmakefile.in index a7492c06d67..a04ecec3db3 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -5,7 +5,7 @@ #----------------------------------------------------- # todo: add all subdirs -SUBDIRS = liblwgeom libpgcommon postgis regress @RASTER@ @TOPOLOGY@ loader utils doc @EXTENSIONS@ +SUBDIRS = liblwgeom libpgcommon postgis regress @RASTER@ @TOPOLOGY@ loader utils @EXTENSIONS@ PERL = @PERL@ @@ -21,11 +21,11 @@ all install uninstall noop clean distclean check: all: postgis_svn_revision.h -install: all comments-install +install: all # comments-install uninstall: docs-uninstall comments-uninstall -clean: docs-clean clean-local +clean: clean-local clean-local: rm -f postgis.sql postgis_upgrade.sql diff --git a/configure.ac b/configure.ac index e3e7c376661..d67532a8cc2 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ dnl * dnl * PostGIS - Spatial Types for PostgreSQL dnl * http://postgis.net dnl * Copyright 2008 Mark Cave-Ayland +dnl * Portions Copyright 2013-2015 PipelineDB dnl * dnl * This is free software; you can redistribute and/or modify it under dnl * the terms of the GNU General Public Licence. See the COPYING file. @@ -162,7 +163,7 @@ dnl dnl Search for xsltproc which is required for building documentation dnl -CAN_BUILD_COMMENTS=yes +CAN_BUILD_COMMENTS=no AC_PATH_PROG([XSLTPROC], [xsltproc], []) if test "x$XSLTPROC" = "x"; then @@ -373,16 +374,16 @@ if test "x$PG_CONFIG" = "xno"; then elif test "x$PG_CONFIG" = "x"; then dnl PG_CONFIG was not specified, so search within the current path - AC_PATH_PROG([PG_CONFIG], [pg_config]) + AC_PATH_PROG([PG_CONFIG], [pipeline-config]) dnl If we couldn't find pg_config, display an error if test "x$PG_CONFIG" = "x"; then - AC_MSG_ERROR([could not find pg_config within the current path. You may need to try re-running configure with a --with-pg_config parameter.]) + AC_MSG_ERROR([could not find pipeline-config within the current path. You may need to try re-running configure with a --with-pg_config parameter.]) fi else dnl PG_CONFIG was specified; display a message to the user if test "x$PG_CONFIG" = "xyes"; then - AC_MSG_ERROR([you must specify a parameter to --with-pgconfig, e.g. --with-pgconfig=/path/to/pg_config]) + AC_MSG_ERROR([you must specify a parameter to --with-pgconfig, e.g. --with-pgconfig=/path/to/pipeline-config]) else if test -f $PG_CONFIG; then AC_MSG_RESULT([Using user-specified pg_config file: $PG_CONFIG]) @@ -1283,9 +1284,6 @@ AC_OUTPUT([GNUmakefile topology/Makefile topology/test/Makefile regress/Makefile - doc/Makefile - doc/Makefile.comments - doc/html/image_src/Makefile utils/Makefile java/jdbc/Makefile $RT_MAKEFILE_LIST]) diff --git a/extensions/address_standardizer/.gitignore b/extensions/address_standardizer/.gitignore new file mode 100644 index 00000000000..d50b8146c1f --- /dev/null +++ b/extensions/address_standardizer/.gitignore @@ -0,0 +1 @@ +/sql diff --git a/extensions/postgis/Makefile.in b/extensions/postgis/Makefile.in index 088c1466633..cf89b2bbf4e 100644 --- a/extensions/postgis/Makefile.in +++ b/extensions/postgis/Makefile.in @@ -37,7 +37,7 @@ ifeq ($(PG91),yes) all: sql/$(EXTENSION)--$(EXTVERSION).sql sql/$(EXTENSION)--unpackaged--$(EXTVERSION).sql sql/$(EXTENSION)--$(EXTVERSION)--$(EXTVERSION)next.sql sql/$(EXTENSION)--$(EXTVERSION)next--$(EXTVERSION).sql sql_minor_upgrade -sql/$(EXTENSION).sql: sql_bits/postgis.sql sql_bits/postgis_comments.sql sql_bits/rtpostgis.sql sql_bits/mark_editable_objects.sql.in sql_bits/raster_comments.sql sql_bits/spatial_ref_sys.sql +sql/$(EXTENSION).sql: sql_bits/postgis.sql sql_bits/postgis_comments.sql sql_bits/rtpostgis.sql sql_bits/mark_editable_objects.sql.in sql_bits/raster_comments.sql sql_bits/spatial_ref_sys.sql sql_bits/pipeline_gis.sql mkdir -p sql echo '\echo Use "CREATE EXTENSION $(EXTENSION)" to load this file. \quit' > $@ cat $^ >> $@ @@ -46,9 +46,9 @@ sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql mkdir -p sql cp $< $@ -sql/$(EXTENSION)--unpackaged--$(EXTVERSION).sql: ../../postgis/postgis.sql ../../raster/rt_pg/rtpostgis.sql ../../utils/create_unpackaged.pl +sql/$(EXTENSION)--unpackaged--$(EXTVERSION).sql: ../../postgis/postgis.sql ../../raster/rt_pg/rtpostgis.sql ../../utils/create_unpackaged.pl ../../postgis/pipeline_gis.sql mkdir -p sql - cat ../../postgis/postgis.sql ../../raster/rt_pg/rtpostgis.sql | $(PERL) ../../utils/create_unpackaged.pl postgis > $@ + cat ../../postgis/postgis.sql ../../raster/rt_pg/rtpostgis.sql ../../postgis/pipeline_gis.sql | $(PERL) ../../utils/create_unpackaged.pl postgis > $@ #this is a cludge to allow upgrading from same SVN to same SVN sql/$(EXTENSION)--$(EXTVERSION)--$(EXTVERSION)next.sql: sql_bits/postgis_raster_upgrade_minor.sql @@ -64,11 +64,14 @@ sql_bits/spatial_ref_sys.sql: ../../spatial_ref_sys.sql sql_bits/postgis.sql: ../../postgis/postgis.sql sed -e 's/BEGIN;//g' -e 's/COMMIT;//g' $< > $@ +sql_bits/pipeline_gis.sql: ../../postgis/pipeline_gis.sql + sed -e 's/BEGIN;//g' -e 's/COMMIT;//g' $< > $@ + ../../doc/postgis_comments.sql: $(MAKE) -C ../../doc comments -sql_bits/postgis_comments.sql: ../../doc/postgis_comments.sql - cp $< $@ +sql_bits/postgis_comments.sql: + touch $@ #strip BEGIN/COMMIT since these are not allowed in extensions sql_bits/rtpostgis.sql: ../../raster/rt_pg/rtpostgis.sql @@ -98,13 +101,13 @@ sql_bits/postgis_upgrade.sql: ../../postgis/postgis_upgrade.sql ../../doc/raster_comments.sql: $(MAKE) -C ../../doc comments -sql_bits/raster_comments.sql: ../../doc/raster_comments.sql - cp $< $@ +sql_bits/raster_comments.sql: + touch $@ #postgis_raster_upgrade_minor.sql is the one that contains both postgis AND raster #TODO: come up with a better name #TODO: what about postgis_drop_after.sql ? where does it fit ?? -sql_bits/postgis_raster_upgrade_minor.sql: ../postgis_extension_helper.sql sql_bits/postgis_upgrade.sql sql_bits/rtpostgis_upgrade.sql ../../doc/raster_comments.sql ../../doc/postgis_comments.sql ../postgis_extension_helper_uninstall.sql +sql_bits/postgis_raster_upgrade_minor.sql: ../postgis_extension_helper.sql sql_bits/postgis_upgrade.sql sql_bits/rtpostgis_upgrade.sql sql_bits/raster_comments.sql sql_bits/postgis_comments.sql ../postgis_extension_helper_uninstall.sql echo '\echo Use "CREATE EXTENSION $(EXTENSION)" to load this file. \quit' > $@ cat $^ >> $@ diff --git a/extensions/postgis_tiger_geocoder/Makefile.in b/extensions/postgis_tiger_geocoder/Makefile.in index 4240c748960..f72ac15d30a 100644 --- a/extensions/postgis_tiger_geocoder/Makefile.in +++ b/extensions/postgis_tiger_geocoder/Makefile.in @@ -129,8 +129,8 @@ sql_bits/add_search_path.sql: sql_bits/add_search_path.sql.in ../../doc/tiger_geocoder_comments.sql: $(MAKE) -C ../../doc comments -sql_bits/tiger_geocoder_comments.sql: ../../doc/tiger_geocoder_comments.sql - cp $< $@ +sql_bits/tiger_geocoder_comments.sql: + touch $@ #grep all lines that start with CREATE OR REPLACE FUNCTION, TRIGGER... #then replace CREATE OR REPLACE .. with ALTER EXTENSION..; diff --git a/extensions/postgis_topology/Makefile.in b/extensions/postgis_topology/Makefile.in index 832d2cc8eb0..4ddda3de0ff 100644 --- a/extensions/postgis_topology/Makefile.in +++ b/extensions/postgis_topology/Makefile.in @@ -55,8 +55,8 @@ sql_bits/topology.sql: ../../topology/topology.sql ../../doc/topology_comments.sql: $(MAKE) -C ../../doc comments -sql_bits/topology_comments.sql: ../../doc/topology_comments.sql - cp $< $@ +sql_bits/topology_comments.sql: + touch $@ sql/$(EXTENSION)--unpackaged--$(EXTVERSION).sql: ../../topology/topology.sql ../../utils/create_unpackaged.pl mkdir -p sql diff --git a/liblwgeom/Makefile.in b/liblwgeom/Makefile.in index 1c4d08e5abc..1dd790a7f03 100644 --- a/liblwgeom/Makefile.in +++ b/liblwgeom/Makefile.in @@ -3,6 +3,7 @@ # * PostGIS - Spatial Types for PostgreSQL # * http://postgis.net # * Copyright 2008 Mark Cave-Ayland +# * Portions Copyright 2013-2015 PipelineDB # * # * This is free software; you can redistribute and/or modify it under # * the terms of the GNU General Public Licence. See the COPYING file. @@ -24,6 +25,9 @@ LIBTOOL = @LIBTOOL@ SOVER = @POSTGIS_MAJOR_VERSION@.@POSTGIS_MINOR_VERSION@.@POSTGIS_MICRO_VERSION@ +PG_CONFIG = @PG_CONFIG@ +LIB_INSTALL_PATH = $(shell $(PG_CONFIG) --libdir) +LIB_INCLUDE_PATH = $(shell $(PG_CONFIG) --includedir) YACC=@YACC@ LEX=@LEX@ @@ -120,8 +124,8 @@ install: install-liblwgeom uninstall: uninstall-liblwgeom install-liblwgeom: liblwgeom.la - $(LIBTOOL) --mode=install $(INSTALL) liblwgeom.la "$(DESTDIR)$(libdir)/liblwgeom.la" - $(INSTALL) liblwgeom.h "$(DESTDIR)$(includedir)/liblwgeom.h" + $(LIBTOOL) --mode=install $(INSTALL) liblwgeom.la "$(LIB_INSTALL_PATH)/liblwgeom.la" + $(INSTALL) -m 0644 liblwgeom.h "$(LIB_INCLUDE_PATH)/liblwgeom.h" uninstall-liblwgeom: $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/liblwgeom.la" diff --git a/postgis/Makefile.in b/postgis/Makefile.in index af0a839901e..a6031599dcd 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -3,6 +3,7 @@ # * PostGIS - Spatial Types for PostgreSQL # * http://postgis.net # * Copyright 2008 Mark Cave-Ayland +# * Portions Copyright 2013-2015 PipelineDB # * # * This is free software; you can redistribute and/or modify it under # * the terms of the GNU General Public Licence. See the COPYING file. @@ -14,11 +15,11 @@ MODULE_big=postgis-@POSTGIS_MAJOR_VERSION@.@POSTGIS_MINOR_VERSION@ MODULEDIR=contrib/$(MODULE_big) # Files to be copied to the contrib/ directory -SQL_built=postgis.sql uninstall_postgis.sql postgis_upgrade.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql +SQL_built=postgis.sql uninstall_postgis.sql postgis_upgrade.sql legacy.sql uninstall_legacy.sql legacy_minimal.sql legacy_gist.sql pipeline_gis.sql DATA=../spatial_ref_sys.sql # SQL objects (files requiring pre-processing) -SQL_objs=postgis.sql legacy.sql legacy_minimal.sql +SQL_objs=postgis.sql legacy.sql legacy_minimal.sql pipeline_gis.sql GEOM_BACKEND_OBJ = lwgeom_geos.o SFCGAL_BACKEND_OBJ = lwgeom_sfcgal.o diff --git a/postgis/lwgeom_accum.c b/postgis/lwgeom_accum.c index 1a09bbd21b1..c4cfb7fb11d 100644 --- a/postgis/lwgeom_accum.c +++ b/postgis/lwgeom_accum.c @@ -2,7 +2,8 @@ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.net - * Copyright 2009 Paul Ramsey + * Portions Copyright 2009 Paul Ramsey + * Portions Copyright 2013-2015 PipelineDB * * This is free software; you can redistribute and/or modify it under * the terms of the GNU General Public Licence. See the COPYING file. @@ -13,6 +14,8 @@ #include "fmgr.h" #include "funcapi.h" #include "access/tupmacs.h" +#include "lib/stringinfo.h" +#include "libpq/pqformat.h" #include "utils/array.h" #include "utils/lsyscache.h" @@ -87,6 +90,79 @@ pgis_abs_out(PG_FUNCTION_ARGS) PG_RETURN_POINTER(NULL); } +/* + * Serializes as pgis_abs + */ +PG_FUNCTION_INFO_V1(pgis_abs_send); +Datum +pgis_abs_send(PG_FUNCTION_ARGS) +{ + pgis_abs *p = (pgis_abs *) PG_GETARG_POINTER(0); + ArrayType *arr = DirectFunctionCall1(arrayaggstatesend, (Datum) p->a); + + PG_RETURN_ARRAYTYPE_P(arr); +} + +/* + * Deserializes a pgis_abs + */ +PG_FUNCTION_INFO_V1(pgis_abs_recv); +Datum +pgis_abs_recv(PG_FUNCTION_ARGS) +{ + MemoryContext context; + MemoryContext old; + pgis_abs *result; + ArrayType *arr; + + if (!AggCheckCallContext(fcinfo, &context)) + context = fcinfo->flinfo->fn_mcxt; + + old = MemoryContextSwitchTo(context); + + arr = (ArrayType *) PG_GETARG_ARRAYTYPE_P_COPY(0); + fcinfo->arg[0] = (Datum) arr; + result = palloc0(sizeof(pgis_abs)); + result->a = (ArrayBuildState *) arrayaggstaterecv(fcinfo); + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(result); +} + +/* + * Combines two pgis_abs transition states into one + */ +PG_FUNCTION_INFO_V1(pgis_geometry_accum_combinefn); +Datum +pgis_geometry_accum_combinefn(PG_FUNCTION_ARGS) +{ + MemoryContext old; + MemoryContext aggcontext; + pgis_abs *state = PG_ARGISNULL(0) ? NULL : (pgis_abs *) PG_GETARG_POINTER(0); + pgis_abs *incoming = (pgis_abs *) PG_GETARG_POINTER(1); + int i; + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + elog(ERROR, "pgis_geometry_accum_combinefn called in non-aggregate context"); + + if (state == NULL) + PG_RETURN_POINTER(incoming); + + old = MemoryContextSwitchTo(aggcontext); + + for (i=0; ia->nelems; i++) + { + state->a = accumArrayResult(state->a, + incoming->a->dvalues[i], incoming->a->dnulls[i], + incoming->a->element_type, aggcontext); + } + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(state); +} + /** ** The transfer function hooks into the PostgreSQL accumArrayResult() ** function (present since 8.0) to build an array in a side memory diff --git a/postgis/lwgeom_box3d.c b/postgis/lwgeom_box3d.c index 73fb7d02248..d87e3b54183 100644 --- a/postgis/lwgeom_box3d.c +++ b/postgis/lwgeom_box3d.c @@ -2,6 +2,8 @@ * * BOX3D IO and conversions * + * Portions Copyright 2013-2015 PipelineDB + * **********************************************************************/ #include "postgres.h" @@ -340,6 +342,31 @@ Datum BOX3D_zmax(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(Max(box->zmin, box->zmax)); } +PG_FUNCTION_INFO_V1(BOX3D_combine_3d); +Datum BOX3D_combine_3d(PG_FUNCTION_ARGS) +{ + BOX3D *state; + BOX3D *incoming = (BOX3D *) PG_GETARG_POINTER(1); + + if (PG_ARGISNULL(0)) + { + if (PG_ARGISNULL(1)) + PG_RETURN_NULL(); + PG_RETURN_POINTER(incoming); + } + + state = (BOX3D *) PG_GETARG_POINTER(0); + + state->xmax = Max(state->xmax, incoming->xmax); + state->ymax = Max(state->ymax, incoming->ymax); + state->zmax = Max(state->zmax, incoming->zmax); + state->xmin = Min(state->xmin, incoming->xmin); + state->ymin = Min(state->ymin, incoming->ymin); + state->zmin = Min(state->zmin, incoming->zmin); + + PG_RETURN_POINTER(state); +} + /** * Used in the ST_Extent and ST_Extent3D aggregates, does not read the * serialized cached bounding box (since that is floating point) diff --git a/postgis/pipeline_gis.sql.in b/postgis/pipeline_gis.sql.in new file mode 100644 index 00000000000..0a2395ef1a7 --- /dev/null +++ b/postgis/pipeline_gis.sql.in @@ -0,0 +1,241 @@ +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- +-- PostGIS - Support for PipelineDB +-- http://postgis.net +-- Copyright 2013-2015 PipelineDB +-- +-- This is free software; you can redistribute and/or modify it under +-- the terms of the GNU General Public Licence v3. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +------------------------------------------------------------------------------- +-- ST_SummaryStatsAgg combiner +------------------------------------------------------------------------------- + +CREATE FUNCTION summarystatssend(internal) + RETURNS bytea + AS '$libdir/rtpostgis-2.2' + LANGUAGE c; + +CREATE FUNCTION summarystatsrecv(bytea) + RETURNS bytea + AS '$libdir/rtpostgis-2.2' + LANGUAGE c; + +CREATE FUNCTION _st_summarystats_combinefn(internal, internal) + RETURNS internal + AS '$libdir/rtpostgis-2.2', 'RASTER_summaryStats_combinefn' + LANGUAGE c; + +-- The transition functions for each transition function's signature all have the same name, +-- so we need to select each one individually in order to properly construct pipeline_combine entries +INSERT INTO pipeline_combine VALUES ( +'_st_summarystats_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_summarystats_transfn' AND pronargs = 5), +'summarystatssend', 'summarystatsrecv', '_st_summarystats_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_summarystats_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_summarystats_transfn' AND pronargs = 4 AND proargtypes[3] = 16), +'summarystatssend', 'summarystatsrecv', '_st_summarystats_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_summarystats_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_summarystats_transfn' AND pronargs = 4 AND proargtypes[3] = 701), +'summarystatssend', 'summarystatsrecv', '_st_summarystats_combinefn', 17); + +------------------------------------------------------------------------------- +-- ST_Union(raster) combiner +------------------------------------------------------------------------------- + +CREATE FUNCTION unionargsend(internal) + RETURNS bytea + AS '$libdir/rtpostgis-2.2' + LANGUAGE c; + +CREATE FUNCTION unionargrecv(bytea) + RETURNS bytea + AS '$libdir/rtpostgis-2.2' + LANGUAGE c; + +CREATE FUNCTION _st_union_combinefn(internal) + RETURNS internal + AS '$libdir/rtpostgis-2.2', 'RASTER_union_combinefn' + LANGUAGE c; + +-- The transition functions for each transition function's signature all have the same name, +-- so we need to select each one individually in order to properly construct pipeline_combine entries +INSERT INTO pipeline_combine VALUES ( +'_st_union_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_union_transfn' AND pronargs = 2), +'unionargsend', 'unionargrecv', '_st_union_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_union_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_union_transfn' AND pronargs = 4), +'unionargsend', 'unionargrecv', '_st_union_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_union_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_union_transfn' AND pronargs = 3 AND proargtypes[2] = 23), +'unionargsend', 'unionargrecv', '_st_union_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_union_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_union_transfn' AND pronargs = 3 AND proargtypes[2] = 25), +'unionargsend', 'unionargrecv', '_st_union_combinefn', 17); + +INSERT INTO pipeline_combine VALUES ( +'_st_union_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_union_transfn' AND pronargs = 3 AND proargtypes[2] NOT IN (23, 25)), +'unionargsend', 'unionargrecv', '_st_union_combinefn', 17); + +------------------------------------------------------------------------------- +-- ST_Extent combiner +------------------------------------------------------------------------------- + +CREATE FUNCTION combine_box3d(internal) + RETURNS box3d + AS 'MODULE_PATHNAME', 'BOX3D_combine_3d' + LANGUAGE c; + +INSERT INTO pipeline_combine VALUES ( +(SELECT oid FROM pg_proc WHERE proname = 'box2d' AND proargtypes[0] = + (SELECT oid FROM pg_type WHERE typname = 'box3d')), +(SELECT oid FROM pg_proc WHERE proname = 'st_combine_bbox' AND prorettype = + (SELECT oid FROM pg_type WHERE typname = 'box3d')), +0, 0, 'combine_box3d', +(SELECT oid FROM pg_type WHERE typname = 'box3d')); + +------------------------------------------------------------------------------- +-- ST_3DExtent combiner +------------------------------------------------------------------------------- + +INSERT INTO pipeline_combine VALUES (0, +(SELECT oid FROM pg_proc WHERE proname = 'st_combine_bbox' AND prorettype = + (SELECT oid FROM pg_type WHERE typname = 'box3d')), +0, 0, 'combine_box3d', +(SELECT oid FROM pg_type WHERE typname = 'box3d')); + +------------------------------------------------------------------------------- +-- ST_Accum combiner +------------------------------------------------------------------------------- + +CREATE FUNCTION pgis_geometry_accum_combinefn(pgis_abs, pgis_abs) + RETURNS pgis_abs + AS 'MODULE_PATHNAME' + LANGUAGE c; + +CREATE FUNCTION pgis_abs_send(anyelement) + RETURNS anyarray + AS 'MODULE_PATHNAME' + LANGUAGE c; + +CREATE FUNCTION pgis_abs_recv(anyarray) + RETURNS pgis_abs + AS 'MODULE_PATHNAME' + LANGUAGE c; + +INSERT INTO pipeline_combine VALUES ( +'pgis_geometry_accum_finalfn', +'pgis_geometry_accum_transfn', +'pgis_abs_send', 'pgis_abs_recv', 'pgis_geometry_accum_combinefn', 2277); + +------------------------------------------------------------------------------- +-- ST_Union(geometry) combiner +------------------------------------------------------------------------------- + +INSERT INTO pipeline_combine VALUES ( +'pgis_geometry_union_finalfn', +'pgis_geometry_accum_transfn', +'pgis_abs_send', 'pgis_abs_recv', 'pgis_geometry_accum_combinefn', 2277); + +------------------------------------------------------------------------------- +-- ST_Collect combiner +------------------------------------------------------------------------------- + +INSERT INTO pipeline_combine VALUES ( +'pgis_geometry_collect_finalfn', +'pgis_geometry_accum_transfn', +'pgis_abs_send', 'pgis_abs_recv', 'pgis_geometry_accum_combinefn', 2277); + +------------------------------------------------------------------------------- +-- ST_Polygonize combiner +------------------------------------------------------------------------------- + +INSERT INTO pipeline_combine VALUES ( +'pgis_geometry_polygonize_finalfn', +'pgis_geometry_accum_transfn', +'pgis_abs_send', 'pgis_abs_recv', 'pgis_geometry_accum_combinefn', 2277); + +------------------------------------------------------------------------------- +-- ST_MakeLine combiner +------------------------------------------------------------------------------- + +INSERT INTO pipeline_combine VALUES ( +'pgis_geometry_makeline_finalfn', +'pgis_geometry_accum_transfn', +'pgis_abs_send', 'pgis_abs_recv', 'pgis_geometry_accum_combinefn', 2277); + +------------------------------------------------------------------------------- +-- ST_CountAgg combiner +------------------------------------------------------------------------------- + +CREATE OR REPLACE FUNCTION _st_countagg_combinefn(state agg_count, incoming agg_count) + RETURNS agg_count + AS $$ + BEGIN + IF state IS NULL THEN + RETURN incoming; + END IF; + + state.count := state.count + incoming.count; + RETURN state; + END + $$ LANGUAGE 'plpgsql' IMMUTABLE; + +-- The transition functions for each transition function's signature all have the same name, +-- so we need to select each one individually in order to properly construct pipeline_combine entries +INSERT INTO pipeline_combine VALUES ( +'_st_countagg_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_countagg_transfn' AND pronargs = 5), +0, 0, '_st_countagg_combinefn', +(SELECT oid FROM pg_type WHERE typname = 'agg_count')); + +INSERT INTO pipeline_combine VALUES ( +'_st_countagg_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_countagg_transfn' AND pronargs = 4), +0, 0, '_st_countagg_combinefn', +(SELECT oid FROM pg_type WHERE typname = 'agg_count')); + +INSERT INTO pipeline_combine VALUES ( +'_st_countagg_finalfn', +(SELECT oid FROM pg_proc WHERE proname = '_st_countagg_transfn' AND pronargs = 3), +0, 0, '_st_countagg_combinefn', +(SELECT oid FROM pg_type WHERE typname = 'agg_count')); + +------------------------------------------------------------------------------- +-- ST_SameAlignment combiner +------------------------------------------------------------------------------- + +CREATE OR REPLACE FUNCTION _st_samealignment_combinefn(state agg_samealignment, incoming agg_samealignment) + RETURNS agg_samealignment + AS $$ + BEGIN + IF state IS NULL THEN + RETURN incoming; + END IF; + + state.aligned := ST_SameAlignment(state.refraster, incoming.refraster); + + RETURN state; + END + $$ LANGUAGE 'plpgsql' IMMUTABLE; + +INSERT INTO pipeline_combine VALUES ( +'_st_samealignment_finalfn', +'_st_samealignment_transfn', +0, 0, '_st_samealignment_combinefn', +(SELECT oid FROM pg_type WHERE typname = 'agg_samealignment')); diff --git a/raster/rt_core/librtcore.h b/raster/rt_core/librtcore.h index 0c33b991718..5274cd859a3 100644 --- a/raster/rt_core/librtcore.h +++ b/raster/rt_core/librtcore.h @@ -11,6 +11,7 @@ * Copyright (C) 2009-2011 Mateusz Loskot * Copyright (C) 2008-2009 Sandro Santilli * Copyright (C) 2013 Nathaneil Hunter Clay * Copyright (C) 2009-2011 Mateusz Loskot * Copyright (C) 2008-2009 Sandro Santilli + * Portions Copyright 2013-2015 PipelineDB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -103,6 +104,7 @@ static void quicksort(double *left, double *right) { * @param cK : number of pixels counted thus far in coverage * @param cM : M component of 1-pass stddev for coverage * @param cQ : Q component of 1-pass stddev for coverage + * @param sum2: sum of the square of each input value, used for combining stddevs * * @return the summary statistics for a band or NULL */ @@ -110,7 +112,7 @@ rt_bandstats rt_band_get_summary_stats( rt_band band, int exclude_nodata_value, double sample, int inc_vals, - uint64_t *cK, double *cM, double *cQ + uint64_t *cK, double *cM, double *cQ, double *sum2 ) { uint32_t x = 0; uint32_t y = 0; @@ -322,6 +324,9 @@ rt_band_get_summary_stats( } } + if (sum2) + *sum2 += pow(value, 2); + /* min/max */ if (stats->count < 1) { stats->count = 1; diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c index 9dd039fcbd2..a93feabd6cd 100644 --- a/raster/rt_pg/rtpg_mapalgebra.c +++ b/raster/rt_pg/rtpg_mapalgebra.c @@ -11,6 +11,7 @@ * Copyright (C) 2009-2011 Mateusz Loskot * Copyright (C) 2008-2009 Sandro Santilli * Copyright (C) 2013 Nathaniel Hunter Clay + * Portions Copyright 2013-2015 PipelineDB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,6 +46,8 @@ #include "rtpostgis.h" #include "rtpg_internal.h" +#include "lib/stringinfo.h" +#include "libpq/pqformat.h" /* n-raster MapAlgebra */ Datum RASTER_nMapAlgebra(PG_FUNCTION_ARGS); @@ -2052,6 +2055,489 @@ static int rtpg_union_noarg(rtpg_union_arg arg, rt_raster raster) { return 1; } +/* + * Serialize a rtpg_union_arg + */ +PG_FUNCTION_INFO_V1(unionargsend); +Datum +unionargsend(PG_FUNCTION_ARGS) +{ + MemoryContext context; + MemoryContext old; + StringInfoData buf; + rtpg_union_arg state = PG_GETARG_POINTER(0); + bytea *result; + int nbytes; + int i; + int j; + + if (!AggCheckCallContext(fcinfo, &context)) + context = fcinfo->flinfo->fn_mcxt; + + old = MemoryContextSwitchTo(context); + + initStringInfo(&buf); + + /* Serialize each band's array of rasters */ + pq_sendint(&buf, state->numband, sizeof(state->numband)); + for (i=0; inumband; i++) + { + pq_sendint(&buf, state->bandarg[i].nband, sizeof(state->bandarg[i].nband)); + pq_sendint(&buf, state->bandarg[i].uniontype, sizeof(state->bandarg[i].uniontype)); + pq_sendint(&buf, state->bandarg[i].numraster, sizeof(state->bandarg[i].numraster)); + + for (j=0; jbandarg[i].numraster; j++) + { + uint32_t size; + rt_raster raster = state->bandarg[i].raster[j]; + uint8_t *bytes = rt_raster_to_wkb(raster, false, &size); + + pq_sendint(&buf, size, sizeof(size)); + pq_sendbytes(&buf, (char *) bytes, size); + } + } + + nbytes = buf.len - buf.cursor; + result = (bytea *) palloc0(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + + pq_copymsgbytes(&buf, VARDATA(result), nbytes); + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(result); +} + +/* + * Deserialize a rtpg_union_arg + */ +PG_FUNCTION_INFO_V1(unionargrecv); +Datum +unionargrecv(PG_FUNCTION_ARGS) +{ + MemoryContext context; + MemoryContext old; + bytea *bytesin; + StringInfoData buf; + rtpg_union_arg result; + int nbytes; + int i; + int j; + int numband; + + if (!AggCheckCallContext(fcinfo, &context)) + context = fcinfo->flinfo->fn_mcxt; + + old = MemoryContextSwitchTo(context); + + bytesin = (bytea *) PG_GETARG_BYTEA_P(0); + nbytes = VARSIZE(bytesin) - VARHDRSZ; + + initStringInfo(&buf); + appendBinaryStringInfo(&buf, VARDATA(bytesin), nbytes); + + numband = pq_getmsgint(&buf, sizeof(int)); + + result = palloc0(sizeof(struct rtpg_union_arg_t)); + result->numband = numband; + result->bandarg = palloc0(numband * sizeof(struct rtpg_union_band_arg_t)); + + /* Read each band's array of rasters */ + for (i=0; inumband; i++) + { + result->bandarg[i].nband = pq_getmsgint(&buf, sizeof(result->bandarg[i].nband)); + result->bandarg[i].uniontype = pq_getmsgint(&buf, sizeof(result->bandarg[i].uniontype)); + result->bandarg[i].numraster = pq_getmsgint(&buf, sizeof(result->bandarg[i].numraster)); + result->bandarg[i].raster = palloc0(result->bandarg[i].numraster * sizeof(rt_raster)); + + for (j=0; jbandarg[i].numraster; j++) + { + uint32_t size = pq_getmsgint(&buf, sizeof(uint32_t)); + const char *raw = pq_getmsgbytes(&buf, size); + + result->bandarg[i].raster[j] = rt_raster_from_wkb((uint8_t *) raw, size); + } + } + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(result); +} + +static void +raster_union(rtpg_union_arg iwr, rt_raster raster) +{ + rt_raster _raster = NULL; + rt_band _band = NULL; + int noerr = 1; + int isempty[2] = {0}; + int hasband[2] = {0}; + double _offset[4] = {0.}; + int nbnodata = 0; /* 1 if adding bands */ + int i = 0; + int j = 0; + int k = 0; + rt_iterator itrset; + rtpg_union_type utype = UT_LAST; + rt_pixtype pixtype = PT_END; + int hasnodata = 1; + double nodataval = 0; + rt_raster iraster = NULL; + rt_band iband = NULL; + int reuserast = 0; + int y = 0; + uint16_t _dim[2] = {0}; + void *vals = NULL; + uint16_t nvals = 0; + + POSTGIS_RT_DEBUG(3, "Starting..."); + + itrset = palloc(sizeof(struct rt_iterator_t) * 2); + + /* by band to UNION */ + for (i = 0; i < iwr->numband; i++) { + + /* by raster */ + for (j = 0; j < iwr->bandarg[i].numraster; j++) { + reuserast = 0; + + /* type of union */ + utype = iwr->bandarg[i].uniontype; + + /* raster flags */ + isempty[0] = rt_raster_is_empty(iwr->bandarg[i].raster[j]); + isempty[1] = rt_raster_is_empty(raster); + + if (!isempty[0]) + hasband[0] = rt_raster_has_band(iwr->bandarg[i].raster[j], 0); + if (!isempty[1]) + hasband[1] = rt_raster_has_band(raster, iwr->bandarg[i].nband); + + /* determine pixtype, hasnodata and nodataval */ + _band = NULL; + if (!isempty[0] && hasband[0]) + _band = rt_raster_get_band(iwr->bandarg[i].raster[j], 0); + else if (!isempty[1] && hasband[1]) + _band = rt_raster_get_band(raster, iwr->bandarg[i].nband); + else { + pixtype = PT_64BF; + hasnodata = 1; + nodataval = rt_pixtype_get_min_value(pixtype); + } + if (_band != NULL) { + pixtype = rt_band_get_pixtype(_band); + hasnodata = 1; + if (rt_band_get_hasnodata_flag(_band)) + rt_band_get_nodata(_band, &nodataval); + else + nodataval = rt_band_get_min_value(_band); + } + + /* UT_MEAN and UT_RANGE require two passes */ + /* UT_MEAN: first for UT_COUNT and second for UT_SUM */ + if (iwr->bandarg[i].uniontype == UT_MEAN) { + /* first pass, UT_COUNT */ + if (j < 1) + utype = UT_COUNT; + else + utype = UT_SUM; + } + /* UT_RANGE: first for UT_MIN and second for UT_MAX */ + else if (iwr->bandarg[i].uniontype == UT_RANGE) { + /* first pass, UT_MIN */ + if (j < 1) + utype = UT_MIN; + else + utype = UT_MAX; + } + + /* force band settings for UT_COUNT */ + if (utype == UT_COUNT) { + pixtype = PT_32BUI; + hasnodata = 0; + nodataval = 0; + } + + POSTGIS_RT_DEBUGF(4, "(pixtype, hasnodata, nodataval) = (%s, %d, %f)", rt_pixtype_name(pixtype), hasnodata, nodataval); + + /* set itrset */ + itrset[0].raster = iwr->bandarg[i].raster[j]; + itrset[0].nband = 0; + itrset[1].raster = raster; + itrset[1].nband = iwr->bandarg[i].nband; + + /* allow use NODATA to replace missing bands */ + if (nbnodata) { + itrset[0].nbnodata = 1; + itrset[1].nbnodata = 1; + } + /* missing bands are not ignored */ + else { + itrset[0].nbnodata = 0; + itrset[1].nbnodata = 0; + } + + /* if rasters AND bands are present, use copy approach */ + if (!isempty[0] && !isempty[1] && hasband[0] && hasband[1]) { + POSTGIS_RT_DEBUG(3, "using line method"); + + /* generate empty out raster */ + if (rt_raster_from_two_rasters( + iwr->bandarg[i].raster[j], raster, + ET_UNION, + &iraster, _offset + ) != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not create internal raster"); + } + POSTGIS_RT_DEBUGF(4, "_offset = %f, %f, %f, %f", + _offset[0], _offset[1], _offset[2], _offset[3]); + + /* rasters are spatially the same? */ + if ( + rt_raster_get_width(iwr->bandarg[i].raster[j]) == rt_raster_get_width(iraster) && + rt_raster_get_height(iwr->bandarg[i].raster[j]) == rt_raster_get_height(iraster) + ) { + double igt[6] = {0}; + double gt[6] = {0}; + + rt_raster_get_geotransform_matrix(iwr->bandarg[i].raster[j], gt); + rt_raster_get_geotransform_matrix(iraster, igt); + + reuserast = rt_util_same_geotransform_matrix(gt, igt); + } + + /* use internal raster */ + if (!reuserast) { + /* create band of same type */ + if (rt_raster_generate_new_band( + iraster, + pixtype, + nodataval, + hasnodata, nodataval, + 0 + ) == -1) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not add new band to internal raster"); + } + iband = rt_raster_get_band(iraster, 0); + + /* copy working raster to output raster */ + _dim[0] = rt_raster_get_width(iwr->bandarg[i].raster[j]); + _dim[1] = rt_raster_get_height(iwr->bandarg[i].raster[j]); + for (y = 0; y < _dim[1]; y++) { + POSTGIS_RT_DEBUGF(4, "Getting pixel line of working raster at (x, y, length) = (0, %d, %d)", y, _dim[0]); + if (rt_band_get_pixel_line( + _band, + 0, y, + _dim[0], + &vals, &nvals + ) != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_band_destroy(iband); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not get pixel line from band of working raster"); + } + + POSTGIS_RT_DEBUGF(4, "Setting pixel line at (x, y, length) = (%d, %d, %d)", (int) _offset[0], (int) _offset[1] + y, nvals); + if (rt_band_set_pixel_line( + iband, + (int) _offset[0], (int) _offset[1] + y, + vals, nvals + ) != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_band_destroy(iband); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not set pixel line to band of internal raster"); + } + } + } + else { + rt_raster_destroy(iraster); + iraster = iwr->bandarg[i].raster[j]; + iband = rt_raster_get_band(iraster, 0); + } + + /* run iterator for extent of input raster */ + noerr = rt_raster_iterator( + itrset, 2, + ET_LAST, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + NULL, + &utype, + rtpg_union_callback, + &_raster + ); + if (noerr != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not run raster iterator function"); + } + + /* with iterator raster, copy data to output raster */ + _band = rt_raster_get_band(_raster, 0); + _dim[0] = rt_raster_get_width(_raster); + _dim[1] = rt_raster_get_height(_raster); + for (y = 0; y < _dim[1]; y++) { + POSTGIS_RT_DEBUGF(4, "Getting pixel line of iterator raster at (x, y, length) = (0, %d, %d)", y, _dim[0]); + if (rt_band_get_pixel_line( + _band, + 0, y, + _dim[0], + &vals, &nvals + ) != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not get pixel line from band of working raster"); + } + + POSTGIS_RT_DEBUGF(4, "Setting pixel line at (x, y, length) = (%d, %d, %d)", (int) _offset[2], (int) _offset[3] + y, nvals); + if (rt_band_set_pixel_line( + iband, + (int) _offset[2], (int) _offset[3] + y, + vals, nvals + ) != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not set pixel line to band of internal raster"); + } + } + + /* free _raster */ + rt_band_destroy(_band); + rt_raster_destroy(_raster); + + /* replace working raster with output raster */ + _raster = iraster; + } + else { + POSTGIS_RT_DEBUG(3, "using pixel method"); + + /* pass everything to iterator */ + noerr = rt_raster_iterator( + itrset, 2, + ET_UNION, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + NULL, + &utype, + rtpg_union_callback, + &_raster + ); + + if (noerr != ES_NONE) { + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + } + + elog(ERROR, "RASTER_union_transfn: Could not run raster iterator function"); + } + } + + /* replace working raster */ + if (iwr->bandarg[i].raster[j] != NULL && !reuserast) { + for (k = rt_raster_get_num_bands(iwr->bandarg[i].raster[j]) - 1; k >= 0; k--) + rt_band_destroy(rt_raster_get_band(iwr->bandarg[i].raster[j], k)); + rt_raster_destroy(iwr->bandarg[i].raster[j]); + } + iwr->bandarg[i].raster[j] = _raster; + } + + } +} + +/* + * Combines two rtpg_union_args into one + */ +PG_FUNCTION_INFO_V1(RASTER_union_combinefn); +Datum RASTER_union_combinefn(PG_FUNCTION_ARGS) +{ + MemoryContext old; + MemoryContext aggcontext; + rtpg_union_arg state = PG_ARGISNULL(0) ? NULL : (rtpg_union_arg) PG_GETARG_POINTER(0); + rtpg_union_arg incoming = (rtpg_union_arg) PG_GETARG_POINTER(1); + int i; + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + elog(ERROR, "_st_union_combinefn called in non-aggregate context"); + + if (state == NULL) + PG_RETURN_POINTER(incoming); + + old = MemoryContextSwitchTo(aggcontext); + + for (i=0; inumband; i++) + { + int j; + for (j=0; jbandarg[i].numraster; j++) + { + raster_union(state, incoming->bandarg[i].raster[j]); + } + } + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(state); +} + /* UNION aggregate transition function */ PG_FUNCTION_INFO_V1(RASTER_union_transfn); Datum RASTER_union_transfn(PG_FUNCTION_ARGS) @@ -4273,7 +4759,7 @@ Datum RASTER_colorMap(PG_FUNCTION_ARGS) if (arg->bandstats == NULL) { POSTGIS_RT_DEBUG(4, "Getting band stats"); - arg->bandstats = rt_band_get_summary_stats(arg->band, 1, 1, 0, NULL, NULL, NULL); + arg->bandstats = rt_band_get_summary_stats(arg->band, 1, 1, 0, NULL, NULL, NULL, NULL); if (arg->bandstats == NULL) { pfree(_element); rtpg_colormap_arg_destroy(arg); diff --git a/raster/rt_pg/rtpg_statistics.c b/raster/rt_pg/rtpg_statistics.c index 7192d7f98ff..98bc90acab4 100644 --- a/raster/rt_pg/rtpg_statistics.c +++ b/raster/rt_pg/rtpg_statistics.c @@ -11,6 +11,7 @@ * Copyright (C) 2009-2011 Pierre Racine * Copyright (C) 2009-2011 Mateusz Loskot * Copyright (C) 2008-2009 Sandro Santilli + * Portions Copyright 2013-2015 PipelineDB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,6 +45,8 @@ #endif #include "rtpostgis.h" +#include "lib/stringinfo.h" +#include "libpq/pqformat.h" /* Get summary stats */ Datum RASTER_summaryStats(PG_FUNCTION_ARGS); @@ -138,7 +141,7 @@ Datum RASTER_summaryStats(PG_FUNCTION_ARGS) } /* we don't need the raw values, hence the zero parameter */ - stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 0, NULL, NULL, NULL); + stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 0, NULL, NULL, NULL, NULL); rt_band_destroy(band); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -373,7 +376,7 @@ Datum RASTER_summaryStatsCoverage(PG_FUNCTION_ARGS) } /* we don't need the raw values, hence the zero parameter */ - stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 0, &cK, &cM, &cQ); + stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 0, &cK, &cM, &cQ, NULL); rt_band_destroy(band); rt_raster_destroy(raster); @@ -546,6 +549,7 @@ rtpg_summarystats_arg_init() { arg->stats->min = 0; arg->stats->max = 0; arg->stats->sum = 0; + arg->stats->sum2 = 0; arg->stats->mean = 0; arg->stats->stddev = -1; arg->stats->values = NULL; @@ -562,6 +566,164 @@ rtpg_summarystats_arg_init() { return arg; } +/* + * Serialize a rtpg_summarystats_arg + */ +PG_FUNCTION_INFO_V1(summarystatssend); +Datum +summarystatssend(PG_FUNCTION_ARGS) +{ + StringInfoData buf; + rtpg_summarystats_arg state = (rtpg_summarystats_arg) PG_GETARG_POINTER(0); + int i; + int nbytes; + int vlen; + bytea *result; + + initStringInfo(&buf); + + pq_sendint64(&buf, state->cK); + pq_sendfloat8(&buf, state->cM); + pq_sendfloat8(&buf, state->cQ); + + pq_sendint(&buf, state->band_index, sizeof(state->band_index)); + pq_sendint(&buf, state->exclude_nodata_value, 1); + pq_sendfloat8(&buf, state->sample); + + pq_sendfloat8(&buf, state->stats->sample); + pq_sendint(&buf, state->stats->count, sizeof(state->stats->count)); + pq_sendfloat8(&buf, state->stats->min); + pq_sendfloat8(&buf, state->stats->max); + pq_sendfloat8(&buf, state->stats->sum); + pq_sendfloat8(&buf, state->stats->sum2); + pq_sendfloat8(&buf, state->stats->mean); + pq_sendfloat8(&buf, state->stats->stddev); + pq_sendint(&buf, state->stats->sorted, sizeof(state->stats->sorted)); + + vlen = state->stats->values == NULL ? 0 : state->stats->count; + pq_sendint(&buf, vlen, sizeof(vlen)); + for (i=0; istats->values[i]); + } + + nbytes = buf.len - buf.cursor; + result = (bytea *) palloc(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + + pq_copymsgbytes(&buf, VARDATA(result), nbytes); + + PG_RETURN_POINTER(result); +} + +/* + * Deserialize a rtpg_summarystats_arg + */ +PG_FUNCTION_INFO_V1(summarystatsrecv); +Datum +summarystatsrecv(PG_FUNCTION_ARGS) +{ + MemoryContext context; + MemoryContext old; + bytea *bytesin; + StringInfoData buf; + rtpg_summarystats_arg result; + int nbytes; + int vlen; + + if (!AggCheckCallContext(fcinfo, &context)) + context = fcinfo->flinfo->fn_mcxt; + + old = MemoryContextSwitchTo(context); + + bytesin = (bytea *) PG_GETARG_BYTEA_P(0); + nbytes = VARSIZE(bytesin) - VARHDRSZ; + + initStringInfo(&buf); + appendBinaryStringInfo(&buf, VARDATA(bytesin), nbytes); + + result = palloc0(sizeof(struct rtpg_summarystats_arg_t)); + + result->cK = pq_getmsgint64(&buf); + result->cM = pq_getmsgfloat8(&buf); + result->cQ = pq_getmsgfloat8(&buf); + + result->band_index = pq_getmsgint(&buf, sizeof(result->band_index)); + result->exclude_nodata_value = pq_getmsgint(&buf, 1); + result->sample = pq_getmsgfloat8(&buf); + + result->stats = palloc0(sizeof(struct rt_bandstats_t)); + result->stats->sample = pq_getmsgfloat8(&buf); + result->stats->count = pq_getmsgint(&buf, sizeof(result->stats->count)); + result->stats->min = pq_getmsgfloat8(&buf); + result->stats->max = pq_getmsgfloat8(&buf); + result->stats->sum = pq_getmsgfloat8(&buf); + result->stats->sum2 = pq_getmsgfloat8(&buf); + result->stats->mean = pq_getmsgfloat8(&buf); + result->stats->stddev = pq_getmsgfloat8(&buf); + result->stats->sorted = pq_getmsgint(&buf, sizeof(result->stats->sorted)); + result->stats->values = NULL; + + vlen = pq_getmsgint(&buf, sizeof(vlen)); + if (vlen > 0) + { + int i; + + result->stats->values = palloc0(vlen * sizeof(double)); + for (i=0; istats->values[i] = pq_getmsgfloat8(&buf); + } + } + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(result); +} + +/* + * Combines two rtpg_summarystats_args into one + */ +PG_FUNCTION_INFO_V1(RASTER_summaryStats_combinefn); +Datum RASTER_summaryStats_combinefn(PG_FUNCTION_ARGS) +{ + MemoryContext old; + MemoryContext aggcontext; + rtpg_summarystats_arg state = PG_ARGISNULL(0) ? NULL : (rtpg_summarystats_arg) PG_GETARG_POINTER(0); + rtpg_summarystats_arg incoming = (rtpg_summarystats_arg) PG_GETARG_POINTER(1); + int n; + double s; + double s2; + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + elog(ERROR, "_summaryStats_combinefn called in non-aggregate context"); + + if (state == NULL) + PG_RETURN_POINTER(incoming); + + old = MemoryContextSwitchTo(aggcontext); + + state->cK += incoming->cK; + state->cQ += incoming->cQ; + state->cM += incoming->cM; + state->stats->sum += incoming->stats->sum; + state->stats->sum2 += incoming->stats->sum2; + state->stats->count += incoming->stats->count; + state->stats->min = Min(state->stats->min, incoming->stats->min); + state->stats->max = Max(state->stats->max, incoming->stats->max); + + n = state->stats->count; + s = state->stats->sum; + s2 = state->stats->sum2; + + /* numerator of final stddev formula's radicand */ + state->cQ = (((n * s2) - s * s) / n); + + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(state); +} + PG_FUNCTION_INFO_V1(RASTER_summaryStats_transfn); Datum RASTER_summaryStats_transfn(PG_FUNCTION_ARGS) { @@ -775,7 +937,7 @@ Datum RASTER_summaryStats_transfn(PG_FUNCTION_ARGS) stats = rt_band_get_summary_stats( band, (int) state->exclude_nodata_value, state->sample, 0, - &(state->cK), &(state->cM), &(state->cQ) + &(state->cK), &(state->cM), &(state->cQ), &(state->stats->sum2) ); rt_band_destroy(band); @@ -1097,7 +1259,7 @@ Datum RASTER_histogram(PG_FUNCTION_ARGS) } /* get stats */ - stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL); + stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL, NULL); rt_band_destroy(band); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); @@ -1562,7 +1724,7 @@ Datum RASTER_histogramCoverage(PG_FUNCTION_ARGS) } /* we need the raw values, hence the non-zero parameter */ - stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL); + stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL, NULL); rt_band_destroy(band); rt_raster_destroy(raster); @@ -1880,7 +2042,7 @@ Datum RASTER_quantile(PG_FUNCTION_ARGS) } /* get stats */ - stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL); + stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL, NULL); rt_band_destroy(band); rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 0); diff --git a/raster/test/cunit/cu_band_stats.c b/raster/test/cunit/cu_band_stats.c index cf153498709..8f358cbd398 100644 --- a/raster/test/cunit/cu_band_stats.c +++ b/raster/test/cunit/cu_band_stats.c @@ -4,6 +4,7 @@ * * Copyright (C) 2012 Regents of the University of California * + * Portions Copyright 2013-2015 PipelineDB * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,7 +61,7 @@ static void test_band_stats() { rt_band_get_nodata(band, &nodata); CU_ASSERT_DOUBLE_EQUAL(nodata, 0, DBL_EPSILON); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0, 1, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0, 1, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); CU_ASSERT_DOUBLE_EQUAL(stats->min, 1, DBL_EPSILON); CU_ASSERT_DOUBLE_EQUAL(stats->max, 198, DBL_EPSILON); @@ -84,7 +85,7 @@ static void test_band_stats() { rtdealloc(stats->values); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.1, 1, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.1, 1, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); quantile = (rt_quantile) rt_band_get_quantiles(stats, NULL, 0, &count); @@ -103,19 +104,19 @@ static void test_band_stats() { rtdealloc(stats->values); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.15, 0, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.15, 0, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.2, 0, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.2, 0, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.25, 0, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 1, 0.25, 0, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 0, 0, 1, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 0, 0, 1, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); CU_ASSERT_DOUBLE_EQUAL(stats->min, 0, DBL_EPSILON); CU_ASSERT_DOUBLE_EQUAL(stats->max, 198, DBL_EPSILON); @@ -127,7 +128,7 @@ static void test_band_stats() { rtdealloc(stats->values); rtdealloc(stats); - stats = (rt_bandstats) rt_band_get_summary_stats(band, 0, 0.1, 1, NULL, NULL, NULL); + stats = (rt_bandstats) rt_band_get_summary_stats(band, 0, 0.1, 1, NULL, NULL, NULL, NULL); CU_ASSERT(stats != NULL); quantile = (rt_quantile) rt_band_get_quantiles(stats, NULL, 0, &count); diff --git a/topology/topology.sql.in b/topology/topology.sql.in index e7601230d69..7cc66547461 100644 --- a/topology/topology.sql.in +++ b/topology/topology.sql.in @@ -6,6 +6,7 @@ -- -- Copyright (C) 2010, 2011 Sandro Santilli -- Copyright (C) 2005 Refractions Research Inc. +-- Portions Copyright 2013-2015 PipelineDB -- -- This is free software; you can redistribute and/or modify it under -- the terms of the GNU General Public Licence. See the COPYING file. @@ -2012,4 +2013,28 @@ CREATE OR REPLACE FUNCTION topology.postgis_topology_scripts_installed() RETURNS -- Make sure topology is in database search path -- SELECT topology.AddToSearchPath('topology'); +------------------------------------------------------------------------------- +-- TopoElementArray_agg combiner +------------------------------------------------------------------------------- + +CREATE OR REPLACE FUNCTION topology.TopoElementArray_combine(state topology.TopoElementArray, incoming topology.TopoElementArray) + RETURNS topology.TopoElementArray + AS $$ + BEGIN + IF state IS NULL THEN + RETURN incoming; + END IF; + + state := state::int[][] || incoming::int[][]; + + RETURN state; + END + $$ LANGUAGE 'plpgsql' IMMUTABLE; + +INSERT INTO pipeline_combine VALUES ( +0, +'topology.TopoElementArray_append', +0, 0, 'topology.TopoElementArray_combine', +(SELECT oid FROM pg_type WHERE typname = 'topoelementarray')); + COMMIT;