From: Sandro Santilli Date: Tue, 21 Dec 2004 12:04:42 +0000 (+0000) Subject: Updated geom_accum to create *real* geometry arrays, changed aggregates X-Git-Tag: pgis_1_0_0RC1~133 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01879ac951030ecfef1d2895c0f37bd44318ba0d;p=postgis Updated geom_accum to create *real* geometry arrays, changed aggregates using it accordingly. Fixed collect output type settings, and dropped CR/LF in lwgeom_functions_basic.c git-svn-id: http://svn.osgeo.org/postgis/trunk@1171 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/lwgeom/lwgeom_functions_basic.c b/lwgeom/lwgeom_functions_basic.c index b69b70227..cbfc0de46 100644 --- a/lwgeom/lwgeom_functions_basic.c +++ b/lwgeom/lwgeom_functions_basic.c @@ -14,7 +14,7 @@ #include "lwgeom_pg.h" #include "profile.h" -//#define DEBUG +//#define DEBUG 1 Datum LWGEOM_mem_size(PG_FUNCTION_ARGS); Datum LWGEOM_summary(PG_FUNCTION_ARGS); @@ -1584,8 +1584,13 @@ Datum LWGEOM_collect(PG_FUNCTION_ARGS) PG_RETURN_POINTER(result); } + pglwgeom1 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); pglwgeom2 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + +#ifdef DEBUG + elog(NOTICE, "LWGEOM_collect(%s, %s): call", lwgeom_typename(TYPE_GETTYPE(pglwgeom1->type)), lwgeom_typename(TYPE_GETTYPE(pglwgeom2->type))); +#endif if ( lwgeom_getSRID(pglwgeom1) != lwgeom_getSRID(pglwgeom2) ) { @@ -1598,11 +1603,13 @@ Datum LWGEOM_collect(PG_FUNCTION_ARGS) type1 = TYPE_GETTYPE(lwgeoms[0]->type); type2 = TYPE_GETTYPE(lwgeoms[1]->type); - if ( type1 < 4 ) type1+=3; - if ( type2 < 4 ) type2+=3; - if ( type1 == type2 ) outtype = type1; + if ( type1 == type2 && type1 < 4 ) outtype = type1+3; else outtype = COLLECTIONTYPE; +#ifdef DEBUG + elog(NOTICE, " outtype = %d", outtype); +#endif + outlwg = (LWGEOM *)lwcollection_construct( outtype, lwgeoms[0]->SRID, NULL, 2, lwgeoms); @@ -1635,12 +1642,12 @@ PG_FUNCTION_INFO_V1(LWGEOM_accum); Datum LWGEOM_accum(PG_FUNCTION_ARGS) { ArrayType *array = NULL; - int nelems, nbytes; + int nelems; + int lbs=1; + size_t nbytes, oldsize; Datum datum; PG_LWGEOM *geom; ArrayType *result; - Pointer **pointers; - MemoryContext oldcontext; #ifdef DEBUG elog(NOTICE, "LWGEOM_accum called"); @@ -1655,6 +1662,7 @@ Datum LWGEOM_accum(PG_FUNCTION_ARGS) #endif } else { array = (ArrayType *) PG_DETOAST_DATUM_COPY(datum); + //array = PG_GETARG_ARRAYTYPE_P(0); nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); #ifdef DEBUG elog(NOTICE, "geom_accum: array of nelems=%d", nelems); @@ -1671,16 +1679,9 @@ Datum LWGEOM_accum(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(array); } - /* - * Switch to * flinfo->fcinfo->fn_mcxt - * memory context to be sure both detoasted - * geometry AND array of pointers to it - * last till the call to unite_finalfunc. - */ - oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - /* Make a DETOASTED copy of input geometry */ - geom = (PG_LWGEOM *)PG_DETOAST_DATUM_COPY(datum); + geom = (PG_LWGEOM *)PG_DETOAST_DATUM(datum); + /* * Might use a more optimized version instead of lwrealloc'ing @@ -1688,32 +1689,65 @@ Datum LWGEOM_accum(PG_FUNCTION_ARGS) * --strk(TODO); */ ++nelems; - nbytes = ARR_OVERHEAD(1) + sizeof(Pointer *) * nelems; - if ( ! array ) { + if ( nelems == 1 || ! array ) { + nbytes = ARR_OVERHEAD(1)+INTALIGN(geom->size); +#ifdef DEBUG + elog(NOTICE, "geom_accum: adding %p (nelems=%d; nbytes=%d)", + geom, nelems, nbytes); +#endif result = (ArrayType *) lwalloc(nbytes); + if ( ! result ) + { + elog(ERROR, "Out of virtual memory"); + PG_RETURN_NULL(); + } +#ifdef DEBUG + elog(NOTICE, " %d bytes allocated for array (%d of header, %lu of geom, elemtype: %ld)", nbytes, ARR_OVERHEAD(1), INTALIGN(geom->size), get_fn_expr_argtype(fcinfo->flinfo, 1)); +#endif result->size = nbytes; result->ndim = 1; - *((int *) ARR_DIMS(result)) = nelems; + result->elemtype = get_fn_expr_argtype(fcinfo->flinfo, 1); + memcpy(ARR_DIMS(result), &nelems, sizeof(int)); + memcpy(ARR_LBOUND(result), &lbs, sizeof(int)); + memcpy(ARR_DATA_PTR(result), geom, geom->size); #ifdef DEBUG - elog(NOTICE, "geom_accum: adding %p (nelems=%d)", geom, nelems); + elog(NOTICE, " %d bytes memcopied", geom->size); #endif } else { + oldsize = array->size; + nbytes = oldsize + INTALIGN(geom->size); +#ifdef DEBUG + elog(NOTICE, "geom_accum: old array size: %d, adding %d bytes (nelems=%d; nbytes=%lu)", array->size, INTALIGN(geom->size), nelems, nbytes); +#endif result = (ArrayType *) lwrealloc(array, nbytes); + if ( ! result ) + { + elog(ERROR, "Out of virtual memory"); + PG_RETURN_NULL(); + } +#ifdef DEBUG + elog(NOTICE, " %d bytes allocated for array", nbytes); +#endif + +#ifdef DEBUG + elog(NOTICE, " array start @ %p", result); + elog(NOTICE, " ARR_DATA_PTR @ %p (%d)", + ARR_DATA_PTR(result), (char *)ARR_DATA_PTR(result)-(char *)result); + elog(NOTICE, " next element @ %p", (char *)result+oldsize); +#endif result->size = nbytes; - result->ndim = 1; - *((int *) ARR_DIMS(result)) = nelems; + memcpy(ARR_DIMS(result), &nelems, sizeof(int)); #ifdef DEBUG - elog(NOTICE, "geom_accum: adding %p (nelems=%d)", geom, nelems); + elog(NOTICE, " writing next element starting @ %p", + result+oldsize); #endif + memcpy((char *)result+oldsize, geom, geom->size); } - pointers = (Pointer **)ARR_DATA_PTR(result); - pointers[nelems-1] = (Pointer *)geom; - - /* Go back to previous memory context */ - MemoryContextSwitchTo(oldcontext); - +#ifdef DEBUG + elog(NOTICE, " returning"); +#endif PG_RETURN_ARRAYTYPE_P(result); @@ -1734,13 +1768,14 @@ Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS) Datum datum; ArrayType *array; int nelems; - PG_LWGEOM **geoms; + //PG_LWGEOM **geoms; PG_LWGEOM *result=NULL; LWGEOM **lwgeoms, *outlwg; size_t size; unsigned int outtype; int i; - int SRID; + int SRID=-1; + size_t offset; #ifdef DEBUG elog(NOTICE, "LWGEOM_collect_garray called"); @@ -1759,6 +1794,12 @@ Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS) /* Get actual ArrayType */ array = (ArrayType *) PG_DETOAST_DATUM(datum); +#ifdef DEBUG + elog(NOTICE, " array is %d-bytes in size, %d w/out header", + array->size, array->size-ARR_OVERHEAD(ARR_NDIM(array))); +#endif + + /* Get number of geometries in array */ nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); @@ -1773,25 +1814,29 @@ Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } - /* Get pointer to GEOMETRY pointers array */ - geoms = (PG_LWGEOM **)ARR_DATA_PTR(array); - - /* Get first geometry SRID */ - SRID = lwgeom_getSRID(geoms[0]); - /* * Deserialize all geometries in array into the lwgeoms pointers * array. Check input types to form output type. */ lwgeoms = palloc(sizeof(LWGEOM *)*nelems); outtype = 0; + offset = 0; for (i=0; itype); - lwgeoms[i] = lwgeom_deserialize(SERIALIZED_FORM(geoms[i])); + PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); + offset += INTALIGN(geom->size); + + unsigned int intype = TYPE_GETTYPE(geom->type); + lwgeoms[i] = lwgeom_deserialize(SERIALIZED_FORM(geom)); +#ifdef DEBUG + elog(NOTICE, "LWGEOM_collect_garray: geom %d deserialized", i); +#endif // Check SRID homogeneity - if ( i ) { + if ( ! i ) { + /* Get first geometry SRID */ + SRID = lwgeoms[i]->SRID; + } else { if ( lwgeoms[i]->SRID != SRID ) { elog(ERROR, @@ -1806,7 +1851,7 @@ Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS) // Output type not initialized if ( ! outtype ) { // Input is single, make multi - if ( outtype < 4 ) outtype = intype+3; + if ( intype < 4 ) outtype = intype+3; // Input is multi, make collection else outtype = COLLECTIONTYPE; } @@ -1820,6 +1865,10 @@ Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS) } +#ifdef DEBUG + elog(NOTICE, "LWGEOM_collect_garray: outtype = %d", outtype); +#endif + outlwg = (LWGEOM *)lwcollection_construct( outtype, SRID, NULL, nelems, lwgeoms); @@ -1897,13 +1946,14 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) Datum datum; ArrayType *array; int nelems; - PG_LWGEOM **geoms; PG_LWGEOM *result=NULL; LWPOINT **lwpoints; LWGEOM *outlwg; size_t size; unsigned int npoints; int i; + size_t offset; + int SRID=-1; #ifdef DEBUG elog(NOTICE, "LWGEOM_makeline_garray called"); @@ -1940,9 +1990,6 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } - /* Get pointer to GEOMETRY pointers array */ - geoms = (PG_LWGEOM **)ARR_DATA_PTR(array); - /* * Deserialize all point geometries in array into the * lwpoints pointers array. @@ -1952,11 +1999,30 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) // possibly more then required lwpoints = palloc(sizeof(LWGEOM *)*nelems); npoints = 0; + offset = 0; for (i=0; itype) != POINTTYPE ) continue; + PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); + offset += INTALIGN(geom->size); + + if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) continue; + lwpoints[npoints++] = - lwpoint_deserialize(SERIALIZED_FORM(geoms[i])); + lwpoint_deserialize(SERIALIZED_FORM(geom)); + + // Check SRID homogeneity + if ( npoints == 1 ) { + /* Get first geometry SRID */ + SRID = lwpoints[npoints-1]->SRID; + } else { + if ( lwpoints[npoints-1]->SRID != SRID ) + { + elog(ERROR, + "Operation on mixed SRID geometries"); + PG_RETURN_NULL(); + } + } + #ifdef DEBUG elog(NOTICE, "LWGEOM_makeline_garray: element %d deserialized", i); @@ -1974,7 +2040,7 @@ Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS) elog(NOTICE, "LWGEOM_makeline_garray: point elements: %d", npoints); #endif - outlwg = (LWGEOM *)lwline_from_lwpointarray(-1, npoints, lwpoints); + outlwg = (LWGEOM *)lwline_from_lwpointarray(SRID, npoints, lwpoints); size = lwgeom_serialize_size(outlwg); //lwnotice("lwgeom_serialize_size returned %d", size); diff --git a/lwgeom/lwgeom_geos.c b/lwgeom/lwgeom_geos.c index bfa3580c8..35c0c8c49 100644 --- a/lwgeom/lwgeom_geos.c +++ b/lwgeom/lwgeom_geos.c @@ -154,9 +154,10 @@ Datum unite_garray(PG_FUNCTION_ARGS) ArrayType *array; int is3d = 0; int nelems, i; - PG_LWGEOM **geoms, *result, *pgis_geom; - Geometry *g1, *g2, *geos_result; - int SRID; + PG_LWGEOM *result, *pgis_geom; + Geometry *g1, *g2, *geos_result=NULL; + int SRID=-1; + size_t offset; #ifdef DEBUG static int call=1; #endif @@ -180,38 +181,52 @@ Datum unite_garray(PG_FUNCTION_ARGS) if ( nelems == 0 ) PG_RETURN_NULL(); - geoms = (PG_LWGEOM **)ARR_DATA_PTR(array); - /* One-element union is the element itself */ - if ( nelems == 1 ) PG_RETURN_POINTER(geoms[0]); + if ( nelems == 1 ) PG_RETURN_POINTER((PG_LWGEOM *)(ARR_DATA_PTR(array))); /* Ok, we really need geos now ;) */ initGEOS(MAXIMUM_ALIGNOF); - if ( TYPE_NDIMS(geoms[0]->type) > 2 ) is3d = 1; - SRID = lwgeom_getSRID(geoms[0]); - geos_result = POSTGIS2GEOS(geoms[0]); - pfree(geoms[0]); - for (i=1; isize); + + pgis_geom = geom; + +#ifdef DEBUG + elog(NOTICE, "geom %d @ %p", i, geom); +#endif + + // Check is3d flag + if ( TYPE_NDIMS(geom->type) > 2 ) is3d = 1; + + // Check SRID homogeneity and initialize geos result + if ( ! i ) { - elog(ERROR, "geomunion: operation on mixed SRID geometries"); - PG_RETURN_NULL(); + geos_result = POSTGIS2GEOS(geom); + SRID = lwgeom_getSRID(geom); +#ifdef DEBUG + elog(NOTICE, "first geom is a %s", lwgeom_typename(TYPE_GETTYPE(geom->type))); +#endif + continue; + } + else + { + if ( SRID != lwgeom_getSRID(geom) ) + { + elog(ERROR, + "Operation on mixed SRID geometries"); + PG_RETURN_NULL(); + } } g1 = POSTGIS2GEOS(pgis_geom); - /* - * If we free this memory now we'll have - * more space for the growing result geometry. - * We don't need it anyway. - */ - pfree(pgis_geom); #ifdef DEBUG - elog(NOTICE, "unite_garray(%d): adding geom %d to union", - call, i); + elog(NOTICE, "unite_garray(%d): adding geom %d to union (%s)", + call, i, lwgeom_typename(TYPE_GETTYPE(geom->type))); #endif g2 = GEOSUnion(g1,geos_result); @@ -2328,10 +2343,11 @@ Datum GEOS_polygonize_garray(PG_FUNCTION_ARGS) ArrayType *array; int is3d = 0; unsigned int nelems, i; - PG_LWGEOM **geoms, *result; + PG_LWGEOM *result; Geometry *geos_result; Geometry **vgeoms; int SRID=-1; + size_t offset; #ifdef DEBUG static int call=1; #endif @@ -2355,23 +2371,24 @@ Datum GEOS_polygonize_garray(PG_FUNCTION_ARGS) if ( nelems == 0 ) PG_RETURN_NULL(); - geoms = (PG_LWGEOM **)ARR_DATA_PTR(array); - /* Ok, we really need geos now ;) */ initGEOS(MAXIMUM_ALIGNOF); vgeoms = palloc(sizeof(Geometry *)*nelems); + offset = 0; for (i=0; itype) > 2 ) is3d = 1; - vgeoms[i] = POSTGIS2GEOS(geoms[i]); + PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); + offset += INTALIGN(geom->size); + + vgeoms[i] = POSTGIS2GEOS(geom); if ( ! i ) { - SRID = lwgeom_getSRID(geoms[i]); + SRID = lwgeom_getSRID(geom); } else { - if ( SRID != lwgeom_getSRID(geoms[i]) ) + if ( SRID != lwgeom_getSRID(geom) ) { elog(ERROR, "polygonize: operation on mixed SRID geometries"); PG_RETURN_NULL(); diff --git a/lwgeom/lwgeom_ogc.c b/lwgeom/lwgeom_ogc.c index ac57facc6..92cd4c445 100644 --- a/lwgeom/lwgeom_ogc.c +++ b/lwgeom/lwgeom_ogc.c @@ -736,7 +736,7 @@ Datum LWGEOM_asText(PG_FUNCTION_ARGS) char *result_cstring; int len; char *result,*loc_wkt; - char *semicolonLoc; + //char *semicolonLoc; init_pg_func();