From: Paul Ramsey Date: Fri, 4 Oct 2019 18:25:46 +0000 (+0000) Subject: Restore ST_Union() aggregate signature and re-work X-Git-Tag: 3.0.0rc1~26 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=75a044c6141b64ed3357e766cdb48f7b40bd4867;p=postgis Restore ST_Union() aggregate signature and re-work performance/size enhancement to continue to avoid using Array type during ST_Union(), hopefully avoiding Array size limitations. git-svn-id: http://svn.osgeo.org/postgis/trunk@17856 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/lwgeom_accum.c b/postgis/lwgeom_accum.c index ddd5ed3f6..950274375 100644 --- a/postgis/lwgeom_accum.c +++ b/postgis/lwgeom_accum.c @@ -37,12 +37,12 @@ #include "lwgeom_geos.h" #include "lwgeom_pg.h" #include "lwgeom_transform.h" +#include "lwgeom_accum.h" /* Local prototypes */ Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1); Datum PGISDirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2); Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS); -Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS); Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS); Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS); Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS); @@ -58,49 +58,22 @@ Datum cluster_within_distance_garray(PG_FUNCTION_ARGS); Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS); -/** @file -** Versions of PostgreSQL < 8.4 perform array accumulation internally using -** pass by value, which is very slow working with large/many geometries. -** Hence PostGIS currently implements its own aggregate for building -** geometry arrays using pass by reference, which is significantly faster and -** similar to the method used in PostgreSQL 8.4. -** -** Hence we can revert this to the original aggregate functions from 1.3 at -** whatever point PostgreSQL 8.4 becomes the minimum version we support :) -*/ - - -/** -** To pass the internal ArrayBuildState pointer between the -** transfn and finalfn we need to wrap it into a custom type first, -** the pgis_abs type in our case. The extra "data" member can optionally -** be used to pass an additional constant argument to a finalizer function. -*/ - -typedef struct -{ - ArrayBuildState *a; - Datum data; -} -pgis_abs; - - /** -** The transfer function hooks into the PostgreSQL accumArrayResult() -** function (present since 8.0) to build an array in a side memory -** context. +** The transfer function builds a List of LWGEOM* allocated +** in the aggregate memory context. The pgis_accum_finalfn +** converts that List into a Pg Array. */ PG_FUNCTION_INFO_V1(pgis_geometry_accum_transfn); Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS) { - Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); - MemoryContext aggcontext; - ArrayBuildState *state; - pgis_abs *p; - Datum elem; + MemoryContext aggcontext, old; + CollectionBuildState *state; + LWGEOM *geom = NULL; + GSERIALIZED *gser = NULL; + Datum argType = get_fn_expr_argtype(fcinfo->flinfo, 1); - if (arg1_typeid == InvalidOid) + if (argType == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); @@ -114,52 +87,64 @@ pgis_geometry_accum_transfn(PG_FUNCTION_ARGS) if ( PG_ARGISNULL(0) ) { - MemoryContext old = MemoryContextSwitchTo(aggcontext); - p = (pgis_abs*) palloc(sizeof(pgis_abs)); - p->a = NULL; - p->data = (Datum) NULL; - - if (PG_NARGS() == 3) - { - Datum argument = PG_GETARG_DATUM(2); - Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, 2); + int n = ((PG_NARGS()-2) <= CollectionBuildStateDataSize) ? (PG_NARGS()-2) : CollectionBuildStateDataSize; - p->data = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid)); + state = MemoryContextAlloc(aggcontext, sizeof(CollectionBuildState)); + state->geoms = NULL; + state->geomOid = argType; + for (int i = 0; i < n; i++) + { + Datum argument = PG_GETARG_DATUM(i+2); + Oid dataOid = get_fn_expr_argtype(fcinfo->flinfo, i+2); + state->data[i] = datumCopy(argument, get_typbyval(dataOid), get_typlen(dataOid)); } - MemoryContextSwitchTo(old); } else { - p = (pgis_abs*) PG_GETARG_POINTER(0); + state = (CollectionBuildState*) PG_GETARG_POINTER(0); } - state = p->a; - elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1); - state = accumArrayResult(state, - elem, - PG_ARGISNULL(1), - arg1_typeid, - aggcontext); - p->a = state; - - PG_RETURN_POINTER(p); -} + if (!PG_ARGISNULL(1)) + gser = PG_GETARG_GSERIALIZED_P(1); + /* Take a copy of the geometry into the aggregate context */ + old = MemoryContextSwitchTo(aggcontext); + if (gser) + geom = lwgeom_clone_deep(lwgeom_from_gserialized(gser)); + + /* Initialize or append to list as necessary */ + if (state->geoms) + state->geoms = lappend(state->geoms, geom); + else + state->geoms = list_make1(geom); -Datum pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, FunctionCallInfo fcinfo); + MemoryContextSwitchTo(old); + + PG_RETURN_POINTER(state); +} + + +Datum pgis_accum_finalfn(CollectionBuildState *state, MemoryContext mctx, FunctionCallInfo fcinfo); /** -** The final function rescues the built array from the side memory context -** using the PostgreSQL built-in function makeMdArrayResult +** The final function reads the List of LWGEOM* from the aggregate +** memory context and constructs an Array using construct_md_array() */ Datum -pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, __attribute__((__unused__)) FunctionCallInfo fcinfo) +pgis_accum_finalfn(CollectionBuildState *state, MemoryContext mctx, __attribute__((__unused__)) FunctionCallInfo fcinfo) { + ListCell *l; + size_t nelems = 0; + Datum *elems; + bool *nulls; + int16 elmlen; + bool elmbyval; + char elmalign; + size_t i = 0; + ArrayType *arr; int dims[1]; - int lbs[1]; - ArrayBuildState *state; - Datum result; + int lbs[1] = {1}; /* cannot be called directly because of internal-type argument */ Assert(fcinfo->context && @@ -167,11 +152,40 @@ pgis_accum_finalfn(pgis_abs *p, MemoryContext mctx, __attribute__((__unused__)) IsA(fcinfo->context, WindowAggState)) ); - state = p->a; - dims[0] = state->nelems; - lbs[0] = 1; - result = makeMdArrayResult(state, 1, dims, lbs, mctx, false); - return result; + /* Retrieve geometry type metadata */ + get_typlenbyvalalign(state->geomOid, &elmlen, &elmbyval, &elmalign); + nelems = list_length(state->geoms); + + /* Build up an array, because that's what we pass to all the */ + /* specific final functions */ + elems = palloc(nelems * sizeof(Datum)); + nulls = palloc(nelems * sizeof(bool)); + + foreach (l, state->geoms) + { + LWGEOM *geom = (LWGEOM*)(lfirst(l)); + Datum elem = (Datum)0; + bool isNull = true; + if (geom) + { + GSERIALIZED *gser = geometry_serialize(geom); + elem = PointerGetDatum(gser); + isNull = false; + } + elems[i] = elem; + nulls[i] = isNull; + i++; + + if (i >= nelems) + break; + } + + /* Turn element array into PgSQL array */ + dims[0] = nelems; + arr = construct_md_array(elems, nulls, 1, dims, lbs, state->geomOid, + elmlen, elmbyval, elmalign); + + return PointerGetDatum(arr); } /** @@ -182,14 +196,14 @@ PG_FUNCTION_INFO_V1(pgis_geometry_collect_finalfn); Datum pgis_geometry_collect_finalfn(PG_FUNCTION_ARGS) { - pgis_abs *p; + CollectionBuildState *p; Datum result = 0; Datum geometry_array = 0; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); /* returns null iff no input values */ - p = (pgis_abs*) PG_GETARG_POINTER(0); + p = (CollectionBuildState*) PG_GETARG_POINTER(0); geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array ); @@ -208,14 +222,14 @@ PG_FUNCTION_INFO_V1(pgis_geometry_polygonize_finalfn); Datum pgis_geometry_polygonize_finalfn(PG_FUNCTION_ARGS) { - pgis_abs *p; + CollectionBuildState *p; Datum result = 0; Datum geometry_array = 0; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); /* returns null iff no input values */ - p = (pgis_abs*) PG_GETARG_POINTER(0); + p = (CollectionBuildState*) PG_GETARG_POINTER(0); geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); result = PGISDirectFunctionCall1( polygonize_garray, geometry_array ); @@ -233,14 +247,14 @@ PG_FUNCTION_INFO_V1(pgis_geometry_makeline_finalfn); Datum pgis_geometry_makeline_finalfn(PG_FUNCTION_ARGS) { - pgis_abs *p; + CollectionBuildState *p; Datum result = 0; Datum geometry_array = 0; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); /* returns null iff no input values */ - p = (pgis_abs*) PG_GETARG_POINTER(0); + p = (CollectionBuildState*) PG_GETARG_POINTER(0); geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array ); @@ -258,14 +272,14 @@ PG_FUNCTION_INFO_V1(pgis_geometry_clusterintersecting_finalfn); Datum pgis_geometry_clusterintersecting_finalfn(PG_FUNCTION_ARGS) { - pgis_abs *p; + CollectionBuildState *p; Datum result = 0; Datum geometry_array = 0; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); - p = (pgis_abs*) PG_GETARG_POINTER(0); + p = (CollectionBuildState*) PG_GETARG_POINTER(0); geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); result = PGISDirectFunctionCall1( clusterintersecting_garray, geometry_array ); if (!result) @@ -282,23 +296,23 @@ PG_FUNCTION_INFO_V1(pgis_geometry_clusterwithin_finalfn); Datum pgis_geometry_clusterwithin_finalfn(PG_FUNCTION_ARGS) { - pgis_abs *p; + CollectionBuildState *p; Datum result = 0; Datum geometry_array = 0; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); - p = (pgis_abs*) PG_GETARG_POINTER(0); + p = (CollectionBuildState*) PG_GETARG_POINTER(0); - if (!p->data) + if (!p->data[0]) { elog(ERROR, "Tolerance not defined"); PG_RETURN_NULL(); } geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); - result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data); + result = PGISDirectFunctionCall2( cluster_within_distance_garray, geometry_array, p->data[0]); if (!result) PG_RETURN_NULL(); diff --git a/postgis/lwgeom_accum.h b/postgis/lwgeom_accum.h new file mode 100644 index 000000000..c500d6785 --- /dev/null +++ b/postgis/lwgeom_accum.h @@ -0,0 +1,44 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.net + * + * PostGIS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * PostGIS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with PostGIS. If not, see . + * + ********************************************************************** + * + * Copyright (c) 2019, Paul Ramsey + * + **********************************************************************/ + +#ifndef _LWGEOM_ACCUM_H +#define _LWGEOM_ACCUM_H 1 + +/** +** To pass the internal state of our collection between the +** transfn and finalfn we need to wrap it into a custom type first, +** the CollectionBuildState type in our case. The extra "data" member +** can optionally be used to pass additional constant +** arguments to a finalizer function. +*/ +#define CollectionBuildStateDataSize 2 +typedef struct CollectionBuildState +{ + List *geoms; /* collected geometries */ + Datum data[CollectionBuildStateDataSize]; + Oid geomOid; +} CollectionBuildState; + + +#endif /* _LWGEOM_ACCUM_H */ diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c index f91f7054d..828421625 100644 --- a/postgis/lwgeom_geos.c +++ b/postgis/lwgeom_geos.c @@ -27,6 +27,8 @@ #include "../postgis_config.h" +#include "float.h" /* for DBL_DIG */ + /* PostgreSQL */ #include "postgres.h" #include "funcapi.h" @@ -34,17 +36,15 @@ #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/numeric.h" - #include "access/htup_details.h" - /* PostGIS */ #include "lwgeom_functions_analytic.h" /* for point_in_polygon */ #include "lwgeom_geos.h" #include "liblwgeom.h" #include "lwgeom_rtree.h" #include "lwgeom_geos_prepared.h" -#include "float.h" /* for DBL_DIG */ +#include "lwgeom_accum.h" /* Return NULL on GEOS error @@ -107,6 +107,7 @@ Datum ST_BuildArea(PG_FUNCTION_ARGS); Datum ST_DelaunayTriangles(PG_FUNCTION_ARGS); Datum pgis_union_geometry_array(PG_FUNCTION_ARGS); +Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS); /* ** Prototypes end @@ -505,135 +506,62 @@ Datum pgis_union_geometry_array(PG_FUNCTION_ARGS) PG_RETURN_POINTER(gser_out); } -typedef struct UnionBuildState -{ - MemoryContext mcontext; /* where all the temp stuff is kept */ - GEOSGeometry **geoms; /* collected GEOS geometries*/ - int empty_type; - uint32_t alen; /* allocated length of above arrays */ - uint32_t ngeoms; /* number of valid entries in above arrays */ - int32_t srid; - bool is3d; -} UnionBuildState; -PG_FUNCTION_INFO_V1(pgis_geometry_union_transfn); -Datum pgis_geometry_union_transfn(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(pgis_geometry_union_finalfn); +Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS) { - MemoryContext aggcontext; - MemoryContext old; - UnionBuildState *state; - GSERIALIZED *gser_in; - uint32_t curgeom; - GEOSGeometry *g; - - if (!AggCheckCallContext(fcinfo, &aggcontext)) - { - /* cannot be called directly because of dummy-type argument */ - elog(ERROR, "%s called in non-aggregate context", __func__); - aggcontext = NULL; /* keep compiler quiet */ - } - - if (!PG_ARGISNULL(0)) - { - state = (UnionBuildState *)PG_GETARG_POINTER(0); - } - else - { - old = MemoryContextSwitchTo(aggcontext); - state = (UnionBuildState *)palloc(sizeof(UnionBuildState)); - - state->mcontext = aggcontext; - state->alen = 10; - state->ngeoms = 0; - state->geoms = palloc(sizeof(GEOSGeometry *) * state->alen); - state->is3d = false; - state->srid = 0; - state->empty_type = 0; + CollectionBuildState *state; + ListCell *l; + LWGEOM **geoms; + GSERIALIZED *gser_out; + size_t ngeoms = 0; + int empty_type = 0; + bool first = true; + int32_t srid = SRID_UNKNOWN; + int has_z = LW_FALSE; - initGEOS(lwpgnotice, lwgeom_geos_error); + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); /* returns null iff no input values */ - MemoryContextSwitchTo(old); - }; + state = (CollectionBuildState *)PG_GETARG_POINTER(0); + geoms = palloc(list_length(state->geoms) * sizeof(LWGEOM*)); - /* do we have geometry to push? */ - if (!PG_ARGISNULL(1)) + /* Read contents of list into an array of only non-null values */ + foreach (l, state->geoms) { - old = MemoryContextSwitchTo(state->mcontext); - gser_in = PG_GETARG_GSERIALIZED_P_COPY(1); - MemoryContextSwitchTo(old); - - if (state->ngeoms > 0) - { - if (state->srid != gserialized_get_srid(gser_in)) - for (curgeom = 0; curgeom < state->ngeoms; curgeom++) - GEOSGeom_destroy(state->geoms[curgeom]); - - gserialized_error_if_srid_mismatch_reference(gser_in, state->srid, __func__); - } - - if (!gserialized_is_empty(gser_in)) + LWGEOM *geom = (LWGEOM*)(lfirst(l)); + if (geom) { - if (state->ngeoms == 0) - { - state->srid = gserialized_get_srid(gser_in); - state->is3d = gserialized_has_z(gser_in); - } - - old = MemoryContextSwitchTo(state->mcontext); - g = POSTGIS2GEOS(gser_in); - MemoryContextSwitchTo(old); - - if (!g) + if (!lwgeom_is_empty(geom)) { - for (curgeom = 0; curgeom < state->ngeoms; curgeom++) - GEOSGeom_destroy(state->geoms[curgeom]); - HANDLE_GEOS_ERROR("One of the geometries in the set could not be converted to GEOS"); + geoms[ngeoms++] = geom; + if (first) + { + srid = lwgeom_get_srid(geom); + has_z = lwgeom_has_z(geom); + first = false; + } } - - curgeom = state->ngeoms; - state->ngeoms++; - - if (state->ngeoms > state->alen) + else { - old = MemoryContextSwitchTo(state->mcontext); - state->alen *= 2; - state->geoms = repalloc(state->geoms, sizeof(GEOSGeometry *) * state->alen); - MemoryContextSwitchTo(old); + int type = lwgeom_get_type(geom); + empty_type = type > empty_type ? type : empty_type; } - - state->geoms[curgeom] = g; - } - else - { - int gser_type = gserialized_get_type(gser_in); - if (gser_type > state->empty_type) - state->empty_type = gser_type; } } - PG_RETURN_POINTER(state); -} - -PG_FUNCTION_INFO_V1(pgis_geometry_union_finalfn); -Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS) -{ - UnionBuildState *state; - GSERIALIZED *gser_out = NULL; - GEOSGeometry *g = NULL; - GEOSGeometry *g_union = NULL; - - if (PG_ARGISNULL(0)) - PG_RETURN_NULL(); /* returns null iff no input values */ - - state = (UnionBuildState *)PG_GETARG_POINTER(0); - /* - ** Take our GEOS geometries and turn them into a GEOS collection, + ** Take our array of LWGEOM* and turn it into a GEOS collection, ** then pass that into cascaded union. */ - if (state->ngeoms > 0) + if (ngeoms > 0) { - g = GEOSGeom_createCollection(GEOS_GEOMETRYCOLLECTION, state->geoms, state->ngeoms); + GEOSGeometry *g = NULL; + GEOSGeometry *g_union = NULL; + LWCOLLECTION* col = lwcollection_construct(COLLECTIONTYPE, srid, NULL, ngeoms, geoms); + + initGEOS(lwpgnotice, lwgeom_geos_error); + g = LWGEOM2GEOS((LWGEOM*)col, LW_FALSE); if (!g) HANDLE_GEOS_ERROR("Could not create GEOS COLLECTION from geometry array"); @@ -642,17 +570,17 @@ Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS) if (!g_union) HANDLE_GEOS_ERROR("GEOSUnaryUnion"); - GEOSSetSRID(g_union, state->srid); - gser_out = GEOS2POSTGIS(g_union, state->is3d); + GEOSSetSRID(g_union, srid); + gser_out = GEOS2POSTGIS(g_union, has_z); GEOSGeom_destroy(g_union); } /* No real geometries in our array, any empties? */ else { /* If it was only empties, we'll return the largest type number */ - if (state->empty_type > 0) + if (empty_type > 0) PG_RETURN_POINTER( - geometry_serialize(lwgeom_construct_empty(state->empty_type, state->srid, state->is3d, 0))); + geometry_serialize(lwgeom_construct_empty(empty_type, srid, has_z, 0))); /* Nothing but NULL, returns NULL */ else @@ -668,6 +596,8 @@ Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS) PG_RETURN_POINTER(gser_out); } + + /** * @example ST_UnaryUnion {@link #geomunion} SELECT ST_UnaryUnion( * 'POLYGON((0 0, 10 0, 0 10, 10 10, 0 0))' diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 1dc1b1ea5..26d82ee30 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -3835,12 +3835,6 @@ CREATE OR REPLACE FUNCTION pgis_geometry_accum_transfn(internal, geometry, float AS 'MODULE_PATHNAME' LANGUAGE 'c' _PARALLEL; --- Availability: 3.0.0 -CREATE OR REPLACE FUNCTION pgis_geometry_union_transfn(internal, geometry) - RETURNS internal - AS 'MODULE_PATHNAME' - LANGUAGE 'c' _PARALLEL; - -- Availability: 1.4.0 -- Changed: 2.5.0 use 'internal' transfer type CREATE OR REPLACE FUNCTION pgis_geometry_union_finalfn(internal) @@ -3894,9 +3888,8 @@ CREATE OR REPLACE FUNCTION ST_Union (geometry[]) -- we don't want to force drop of this agg since its often used in views -- parallel handling dealt with in postgis_after_upgrade.sql -- Changed: 2.5.0 use 'internal' stype --- Changed: 3.0.0 transfn now converts to GEOS CREATE AGGREGATE ST_Union (geometry) ( - sfunc = pgis_geometry_union_transfn, + sfunc = pgis_geometry_accum_transfn, stype = internal, #if POSTGIS_PGSQL_VERSION >= 96 parallel = safe, diff --git a/postgis/postgis_after_upgrade.sql b/postgis/postgis_after_upgrade.sql index fc46e1c49..2c0fb94fb 100644 --- a/postgis/postgis_after_upgrade.sql +++ b/postgis/postgis_after_upgrade.sql @@ -227,6 +227,8 @@ DROP FUNCTION IF EXISTS st_combine_bbox(box3d, geometry); DROP FUNCTION IF EXISTS st_combine_bbox(box2d, geometry); DROP FUNCTION IF EXISTS st_distance_sphere(geometry, geometry); +-- dev function 3.0 cycle +DROP FUNCTION IF EXISTS pgis_geometry_union_transfn(internal, geometry); -- pgis_abs type was increased from 8 bytes in 2.1 to 16 bytes in 2.2 -- See #3460 diff --git a/postgis/postgis_before_upgrade.sql b/postgis/postgis_before_upgrade.sql index 4f5b0c347..02ff21306 100644 --- a/postgis/postgis_before_upgrade.sql +++ b/postgis/postgis_before_upgrade.sql @@ -198,7 +198,6 @@ DROP FUNCTION IF EXISTS st_askml(geography, integer); -- Does not conflict -- This signature was superseeded DROP FUNCTION IF EXISTS st_buffer(geometry, double precision); -- Does not conflict - -- FUNCTION ST_CurveToLine changed to add defaults in 2.5 -- These signatures were superseeded DROP FUNCTION IF EXISTS ST_CurveToLine(geometry, integer); -- Does not conflict diff --git a/regress/run_test.pl b/regress/run_test.pl index 1a6d4e739..9fdc1aa65 100755 --- a/regress/run_test.pl +++ b/regress/run_test.pl @@ -299,6 +299,25 @@ sub create_upgrade_test_objects exit(1); } + $query = "insert into upgrade_test(g1,g2) values "; + $query .= "('POINT(0 0)', 'LINESTRING(0 0, 1 1)'), "; + $query .= "('POINT(1 0)', 'LINESTRING(0 1, 1 1)');"; + my $ret = sql($query); + unless ( $ret =~ /^INSERT/ ) { + `dropdb $DB`; + print "\nSomething went wrong populating upgrade_test table: $ret.\n"; + exit(1); + } + + my $query = "create view upgrade_view_test as "; + $query .= "select st_union(g1) from upgrade_test;"; + my $ret = sql($query); + unless ( $ret =~ /^CREATE/ ) { + `dropdb $DB`; + print "\nSomething went wrong creating upgrade_view_test view: $ret.\n"; + exit(1); + } + if ( $OPT_WITH_RASTER ) { $query = "insert into upgrade_test(r) "; @@ -328,6 +347,13 @@ sub drop_upgrade_test_objects { # TODO: allow passing the "upgrade-cleanup" script via commandline + my $ret = sql("drop view upgrade_view_test;"); + unless ( $ret =~ /^DROP/ ) { + `dropdb $DB`; + print "\nSomething went wrong dropping spatial view: $ret.\n"; + exit(1); + } + my $ret = sql("drop table upgrade_test;"); unless ( $ret =~ /^DROP/ ) { `dropdb $DB`;