From: Bborie Park Date: Tue, 2 Oct 2012 21:45:41 +0000 (+0000) Subject: Added multi-band support for ST_Union. Ticket is #2021 X-Git-Tag: 2.1.0beta2~597 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=563fb8ac54e6fb28a3f52debdb715074276ceaff;p=postgis Added multi-band support for ST_Union. Ticket is #2021 git-svn-id: http://svn.osgeo.org/postgis/trunk@10360 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/NEWS b/NEWS index d784b4261..50d86e4eb 100644 --- a/NEWS +++ b/NEWS @@ -42,6 +42,7 @@ PostGIS 2.1.0 - #1938, Refactor basic ST_AddBand to add multiple new bands in one call - #1978, wrong answer when calculating length of a closed circular arc (circle) - #1780, support ST_GeoHash for geography + - #2021, Added multi-band support to ST_Union(raster, ...) aggregate function * Fixes * diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml index ca9a67cad..0b344c221 100644 --- a/doc/reference_raster.xml +++ b/doc/reference_raster.xml @@ -233,7 +233,56 @@ VALUES (1, - + + + + unionarg + A composite type used as input into the ST_Union function defining the bands to be processed and behavior of the UNION operation. + + + + Description + + A composite type used as input into the ST_Union function defining the bands to be processed and behavior of the UNION operation. + + + + + nband + integer + + + + 1-based value indicating the band of each input raster to be processed. + + + + + + + uniontype + text + + + + Type of UNION operation. One of defined types as described in . + + + + + + + + + + + See Also + + + + + + @@ -8622,34 +8671,43 @@ UPDATE wind ST_Union - Returns the union of a set of raster tiles into a single raster composed of 1 band. + Returns the union of a set of raster tiles into a single raster composed of 1 or more bands. + raster ST_Union setof raster rast + unionarg[] unionargset raster ST_Union - raster set rast + setof raster rast integer nband raster ST_Union - raster set rast + setof raster rast text uniontype raster ST_Union - raster set rast + setof raster rast integer nband text uniontype @@ -8659,8 +8717,8 @@ UPDATE wind Description - Returns the union of a set of raster tiles into a single raster composed of 1 band. If nband is not specified, band 1 is assumed. The resulting raster's extent is the extent of the whole set. In the case of intersection, the resulting value is defined by uniontype which is one of the following: LAST (default), FIRST, MIN, MAX, COUNT, SUM, MEAN. - + Returns the union of a set of raster tiles into a single raster composed of at least one band. If nband is not specified, band 1 is assumed. The resulting raster's extent is the extent of the whole set. In the case of intersection, the resulting value is defined by uniontype which is one of the following: LAST (default), FIRST, MIN, MAX, COUNT, SUM, MEAN. + Availability: 2.0.0 Enhanced: 2.1.0 Improved Speed (fully C-Based). @@ -8687,9 +8745,9 @@ WHERE ST_Intersects(rast, ST_GeomFromText('LINESTRING(230486 887771, 230500 887 See Also + , , - , - + diff --git a/raster/rt_core/rt_api.c b/raster/rt_core/rt_api.c index 6ef0aacbc..911f4b933 100644 --- a/raster/rt_core/rt_api.c +++ b/raster/rt_core/rt_api.c @@ -2408,6 +2408,8 @@ int rt_band_get_nearest_pixel( double minval = 0; uint32_t count = 0; + int inextent = 0; + assert(NULL != band); assert(NULL != npixels); @@ -2579,6 +2581,7 @@ int rt_band_get_nearest_pixel( else pixval = band->nodataval; RASTER_DEBUGF(4, "NODATA pixel outside band extent: (x, y, val) = (%d, %d, %f)", _x, _y, pixval); + inextent = 0; } else { if (rt_band_get_pixel( @@ -2591,6 +2594,7 @@ int rt_band_get_nearest_pixel( return -1; } RASTER_DEBUGF(4, "Pixel: (x, y, val) = (%d, %d, %f)", _x, _y, pixval); + inextent = 1; } /* use pixval? */ @@ -2619,8 +2623,13 @@ int rt_band_get_nearest_pixel( npixel = &((*npixels)[count - 1]); npixel->x = _x; npixel->y = _y; - npixel->nodata = 0; npixel->value = pixval; + + /* special case for when outside band extent */ + if (!inextent && !band->hasnodata) + npixel->nodata = 1; + else + npixel->nodata = 0; } (*_min)++; @@ -13193,6 +13202,7 @@ rt_raster_iterator( int i = 0; int status = 0; + int inextent = 0; int x = 0; int y = 0; int _x = 0; @@ -13631,19 +13641,21 @@ rt_raster_iterator( return NULL; } + inextent = 1; } /* outside band extent, set to NODATA */ else { + RASTER_DEBUG(4, "Outside band extent, setting value to NODATA"); /* has NODATA, use NODATA */ if (rt_band_get_hasnodata_flag(_param->band[i])) value = rt_band_get_nodata(_param->band[i]); /* no NODATA, use min possible value */ else value = rt_band_get_min_value(_param->band[i]); + inextent = 0; } /* add pixel to neighborhood */ - RASTER_DEBUGF(4, "value: %f", value); status++; if (status > 1) npixels = (rt_pixel) rtrealloc(npixels, sizeof(struct rt_pixel_t) * status); @@ -13667,7 +13679,7 @@ rt_raster_iterator( /* set nodata flag */ if ( - !rt_band_get_hasnodata_flag(_param->band[i]) || ( + (!rt_band_get_hasnodata_flag(_param->band[i]) && inextent) || ( (rt_band_get_hasnodata_flag(_param->band[i]) != FALSE) && ( FLT_NEQ(value, rt_band_get_nodata(_param->band[i])) && (rt_band_clamped_value_is_nodata(_param->band[i], value) != 1) @@ -13676,16 +13688,7 @@ rt_raster_iterator( ) { npixels[status - 1].nodata = 0; } - - /* no pixels in neighborhood */ - /* - if (!status) { - RASTER_DEBUG(3, "no pixels in neighborhood, using empty"); - _param->arg->values[i] = _param->empty.values; - _param->arg->nodata[i] = _param->empty.nodata; - continue; - } - */ + RASTER_DEBUGF(4, "value, nodata: %f, %d", value, npixels[status - 1].nodata); /* convert set of rt_pixel to 2D array */ status = rt_pixel_set_to_array( @@ -13728,10 +13731,18 @@ rt_raster_iterator( } /* burn value to pixel */ - if (!nodata) + status = 0; + if (!nodata) { status = rt_band_set_pixel(rtnband, _x, _y, value); - else if (!hasnodata) + RASTER_DEBUGF(4, "burning pixel (%d, %d) with value: %f", _x, _y, value); + } + else if (!hasnodata) { status = rt_band_set_pixel(rtnband, _x, _y, minval); + RASTER_DEBUGF(4, "burning pixel (%d, %d) with minval: %f", _x, _y, minval); + } + else { + RASTER_DEBUGF(4, "NOT burning pixel (%d, %d)", _x, _y); + } if (status < 0) { rterror("rt_raster_iterator: Unable to set pixel value"); diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 89781714a..e0c9b2cf9 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -3767,6 +3767,7 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS) int distance[2] = {0}; bool exclude_nodata_value = TRUE; double pixval; + int inextent = 0; rt_pixel npixels = NULL; int count; @@ -3889,6 +3890,7 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(pgraster, 0); PG_RETURN_NULL(); } + inextent = 1; } /* outside band extent, set to NODATA */ else { @@ -3898,6 +3900,7 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS) /* no NODATA, use min possible value */ else pixval = rt_band_get_min_value(band); + inextent = 0; } POSTGIS_RT_DEBUGF(4, "pixval: %f", pixval); @@ -3925,7 +3928,7 @@ Datum RASTER_neighborhood(PG_FUNCTION_ARGS) /* set NODATA */ if ( !exclude_nodata_value || - !rt_band_get_hasnodata_flag(band) || ( + (!rt_band_get_hasnodata_flag(band) && inextent) || ( exclude_nodata_value && (rt_band_get_hasnodata_flag(band) != FALSE) && ( FLT_NEQ(pixval, rt_band_get_nodata(band)) && @@ -13553,13 +13556,6 @@ typedef enum { UT_MEAN } rtpg_union_type; -typedef struct { - int numraster; - rt_raster *raster; - - rtpg_union_type uniontype; -} rtpg_union_arg; - /* internal function translating text of UNION type to enum */ static rtpg_union_type rtpg_uniontype_index_from_name(const char *cutype) { assert(cutype && strlen(cutype) > 0); @@ -13582,6 +13578,45 @@ static rtpg_union_type rtpg_uniontype_index_from_name(const char *cutype) { return UT_LAST; } +typedef struct rtpg_union_band_arg_t *rtpg_union_band_arg; +struct rtpg_union_band_arg_t { + int nband; /* source raster's band index, 0-based */ + rtpg_union_type uniontype; + + int numraster; + rt_raster *raster; +}; + +typedef struct rtpg_union_arg_t *rtpg_union_arg; +struct rtpg_union_arg_t { + int numband; /* number of bandargs */ + rtpg_union_band_arg bandarg; +}; + +static void rtpg_union_arg_destroy(rtpg_union_arg arg) { + int i = 0; + int j = 0; + + if (arg->bandarg != NULL) { + for (i = 0; i < arg->numband; i++) { + if (!arg->bandarg[i].numraster) + continue; + + for (j = 0; j < arg->bandarg[i].numraster; j++) { + if (arg->bandarg[i].raster[j] == NULL) + continue; + rt_raster_destroy(arg->bandarg[i].raster[j]); + } + + pfree(arg->bandarg[i].raster); + } + + pfree(arg->bandarg); + } + + pfree(arg); +} + static int rtpg_union_callback( rt_iterator_arg arg, void *userarg, double *value, int *nodata @@ -13608,16 +13643,19 @@ static int rtpg_union_callback( /* both NODATA */ if (arg->nodata[0][0][0] && arg->nodata[1][0][0]) { *nodata = 1; + POSTGIS_RT_DEBUGF(4, "value, nodata = %f, %d", *value, *nodata); return 1; } /* second NODATA */ else if (!arg->nodata[0][0][0] && arg->nodata[1][0][0]) { *value = arg->values[0][0][0]; + POSTGIS_RT_DEBUGF(4, "value, nodata = %f, %d", *value, *nodata); return 1; } /* first NODATA */ else if (arg->nodata[0][0][0] && !arg->nodata[1][0][0]) { *value = arg->values[1][0][0]; + POSTGIS_RT_DEBUGF(4, "value, nodata = %f, %d", *value, *nodata); return 1; } } @@ -13663,6 +13701,9 @@ static int rtpg_union_callback( break; } + POSTGIS_RT_DEBUGF(4, "value, nodata = %f, %d", *value, *nodata); + + return 1; } @@ -13685,6 +13726,9 @@ static int rtpg_union_mean_callback( *value = 0; *nodata = 1; + POSTGIS_RT_DEBUGF(4, "rast0: %f %d", arg->values[0][0][0], arg->nodata[0][0][0]); + POSTGIS_RT_DEBUGF(4, "rast1: %f %d", arg->values[1][0][0], arg->nodata[1][0][0]); + if ( !arg->nodata[0][0][0] && FLT_NEQ(arg->values[0][0][0], 0) && @@ -13694,6 +13738,8 @@ static int rtpg_union_mean_callback( *nodata = 0; } + POSTGIS_RT_DEBUGF(4, "value, nodata = (%f, %d)", *value, *nodata); + return 1; } @@ -13703,7 +13749,8 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) { MemoryContext aggcontext; MemoryContext oldcontext; - rtpg_union_arg *iwr; + rtpg_union_arg iwr = NULL; + int skiparg = 0; rt_pgraster *pgraster = NULL; rt_raster raster = NULL; @@ -13715,6 +13762,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) int hasband[2] = {0}; int i = 0; + int j = 0; rt_iterator itrset; char *utypename = NULL; @@ -13723,6 +13771,8 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) int hasnodata = 1; double nodataval = 0; + POSTGIS_RT_DEBUG(3, "Starting..."); + /* cannot be called directly as this is exclusive aggregate function */ if (!AggCheckCallContext(fcinfo, &aggcontext)) { elog(ERROR, "RASTER_union_transfn: Cannot be called in a non-aggregate context"); @@ -13733,15 +13783,25 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(aggcontext); if (PG_ARGISNULL(0)) { + POSTGIS_RT_DEBUG(3, "Creating state variable"); /* allocate container in aggcontext */ - iwr = (rtpg_union_arg *) palloc(sizeof(rtpg_union_arg)); + iwr = palloc(sizeof(struct rtpg_union_arg_t)); + if (iwr == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for state variable"); + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + iwr->numband = 0; + iwr->bandarg = NULL; - iwr->numraster = 1; - iwr->raster = NULL; - iwr->uniontype = UT_LAST; + skiparg = 0; + } + else { + POSTGIS_RT_DEBUG(3, "State variable already exists"); + iwr = (rtpg_union_arg) PG_GETARG_POINTER(0); + skiparg = 1; } - else - iwr = (rtpg_union_arg *) PG_GETARG_POINTER(0); /* raster arg is NOT NULL */ if (!PG_ARGISNULL(1)) { @@ -13753,8 +13813,7 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) if (raster == NULL) { elog(ERROR, "RASTER_union_transfn: Could not deserialize raster"); - pfree(iwr->raster); - pfree(iwr); + rtpg_union_arg_destroy(iwr); PG_FREE_IF_COPY(pgraster, 1); MemoryContextSwitchTo(oldcontext); @@ -13762,165 +13821,368 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) } } - /* if more than 2 arguments, determine the type of argument 3 */ - /* band number or UNION type */ - if (PG_NARGS() > 2 && !PG_ARGISNULL(2)) { - Oid calltype = get_fn_expr_argtype(fcinfo->flinfo, 3); + /* process additional args if needed */ + if (!skiparg) { + POSTGIS_RT_DEBUGF(4, "PG_NARGS() = %d", (int) PG_NARGS()); - switch (calltype) { - /* UNION type */ - case TEXTOID: - utypename = text_to_cstring(PG_GETARG_TEXT_P(3)); - utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename)); - iwr->uniontype = utype; - break; - case INT2OID: - case INT4OID: - nband = PG_GETARG_INT32(2); - if (nband < 1) { - elog(ERROR, "RASTER_union_transfn: Band number must be greater than zero (1-based)"); + /* if more than 2 arguments, determine the type of argument 3 */ + /* band number, UNION type or unionarg */ + if (PG_NARGS() > 2 && !PG_ARGISNULL(2)) { + Oid calltype = get_fn_expr_argtype(fcinfo->flinfo, 2); - pfree(iwr->raster); - pfree(iwr); - if (raster != NULL) { - rt_raster_destroy(raster); - PG_FREE_IF_COPY(pgraster, 1); + switch (calltype) { + /* UNION type */ + case TEXTOID: + POSTGIS_RT_DEBUG(4, "Processing arg 3 as UNION type"); + utypename = text_to_cstring(PG_GETARG_TEXT_P(2)); + utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename)); + + iwr->numband = 1; + + iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * iwr->numband); + if (iwr->bandarg == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for band information"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); } - MemoryContextSwitchTo(oldcontext); - PG_RETURN_NULL(); + iwr->bandarg[0].uniontype = utype; + iwr->bandarg[0].nband = 0; + + if (iwr->bandarg[0].uniontype == UT_MEAN) + iwr->bandarg[0].numraster = 2; + else + iwr->bandarg[0].numraster = 1; + iwr->bandarg[0].raster = NULL; + break; + /* band number */ + case INT2OID: + case INT4OID: + POSTGIS_RT_DEBUG(4, "Processing arg 3 as band number"); + nband = PG_GETARG_INT32(2); + if (nband < 1) { + elog(ERROR, "RASTER_union_transfn: Band number must be greater than zero (1-based)"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + iwr->numband = 1; + iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * iwr->numband); + if (iwr->bandarg == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for band information"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + iwr->bandarg[0].uniontype = UT_LAST; + iwr->bandarg[0].nband = nband - 1; + + iwr->bandarg[0].numraster = 1; + iwr->bandarg[0].raster = NULL; + break; + /* only other type allowed is unionarg */ + default: { + ArrayType *array; + Oid etype; + Datum *e; + bool *nulls; + int16 typlen; + bool typbyval; + char typalign; + int n = 0; + + HeapTupleHeader tup; + bool isnull; + Datum tupv; + + POSTGIS_RT_DEBUG(4, "Processing arg 3 as unionarg"); + + array = PG_GETARG_ARRAYTYPE_P(2); + etype = ARR_ELEMTYPE(array); + get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign); + + deconstruct_array( + array, + etype, + typlen, typbyval, typalign, + &e, &nulls, &n + ); + + if (!n) { + elog(ERROR, "RASTER_union_transfn: Invalid argument for unionarg"); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + /* prep iwr */ + iwr->numband = n; + iwr->bandarg = palloc(sizeof(struct rtpg_union_band_arg_t) * iwr->numband); + if (iwr->bandarg == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for band information"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + /* process each element */ + for (i = 0; i < n; i++) { + if (nulls[i]) { + iwr->numband--; + continue; + } + + POSTGIS_RT_DEBUGF(4, "Processing unionarg at index %d", i); + + /* each element is a tuple */ + tup = (HeapTupleHeader) DatumGetPointer(e[i]); + if (NULL == tup) { + elog(ERROR, "RASTER_union_transfn: Invalid argument for unionarg"); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + /* first element, bandnum */ + tupv = GetAttributeByName(tup, "nband", &isnull); + if (isnull) { + nband = i + 1; + elog(NOTICE, "First argument (nband) of unionarg is NULL. Assuming nband = %d", nband); + } + else + nband = DatumGetInt32(tupv); + + if (nband < 1) { + elog(ERROR, "RASTER_union_transfn: Band number must be greater than zero (1-based)"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + /* second element, uniontype */ + tupv = GetAttributeByName(tup, "uniontype", &isnull); + if (isnull) { + elog(NOTICE, "Second argument (uniontype) of unionarg is NULL. Assuming uniontype = LAST"); + utype = UT_LAST; + } + else { + utypename = text_to_cstring((text *) DatumGetPointer(tupv)); + utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename)); + } + + iwr->bandarg[i].uniontype = utype; + iwr->bandarg[i].nband = nband - 1; + iwr->bandarg[i].raster = NULL; + + if (utype != UT_MEAN) + iwr->bandarg[i].numraster = 1; + else + iwr->bandarg[i].numraster = 2; + } + + if (iwr->numband < n) { + iwr->bandarg = repalloc(iwr->bandarg, sizeof(struct rtpg_union_band_arg_t) * iwr->numband); + if (iwr->bandarg == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to reallocate memory for band information"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + } + + break; } - break; + } } - } - /* UNION type */ - if (PG_NARGS() > 3 && !PG_ARGISNULL(3)) { - utypename = text_to_cstring(PG_GETARG_TEXT_P(3)); - utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename)); - iwr->uniontype = utype; - } - if (utype == UT_MEAN) - iwr->numraster = 2; + /* UNION type */ + if (PG_NARGS() > 3 && !PG_ARGISNULL(3)) { + utypename = text_to_cstring(PG_GETARG_TEXT_P(3)); + utype = rtpg_uniontype_index_from_name(rtpg_strtoupper(utypename)); + iwr->bandarg[0].uniontype = utype; - /* allocate iwr->raster */ - if (iwr->raster == NULL) { - iwr->raster = (rt_raster *) rtalloc(sizeof(rt_raster) * iwr->numraster); - if (iwr->raster == NULL) { - elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for pointer to raster"); + if (utype == UT_MEAN) + iwr->bandarg[0].numraster = 2; + } - pfree(iwr); - if (raster != NULL) { - rt_raster_destroy(raster); - PG_FREE_IF_COPY(pgraster, 1); + /* allocate space for pointers to rt_raster */ + for (i = 0; i < iwr->numband; i++) { + iwr->bandarg[i].raster = (rt_raster *) rtalloc(sizeof(rt_raster) * iwr->bandarg[i].numraster); + if (iwr->bandarg[i].raster == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for working raster(s)"); + + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); } - MemoryContextSwitchTo(oldcontext); - PG_RETURN_NULL(); + memset(iwr->bandarg[i].raster, 0, sizeof(rt_raster) * iwr->bandarg[i].numraster); } - - memset(iwr->raster, 0, sizeof(rt_raster) * iwr->numraster); } - for (i = 0; i < iwr->numraster; i++) { - /* raster flags */ - isempty[0] = rt_raster_is_empty(iwr->raster[i]); - isempty[1] = rt_raster_is_empty(raster); - if (!isempty[0]) - hasband[0] = rt_raster_has_band(iwr->raster[i], 0); - if (!isempty[1]) - hasband[1] = rt_raster_has_band(raster, nband - 1); + /* init itrset */ + itrset = palloc(sizeof(struct rt_iterator_t) * 2); + if (itrset == NULL) { + elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for iterator arguments"); - /* determine pixtype, hasnodata and nodataval */ - _band = NULL; - if (!isempty[0] && hasband[0]) - _band = rt_raster_get_band(iwr->raster[i], 0); - else if (!isempty[1] && hasband[1]) - _band = rt_raster_get_band(raster, nband - 1); - else { - pixtype = PT_64BF; - hasnodata = 1; - nodataval = rt_pixtype_get_min_value(pixtype); - } - if (_band != NULL) { - pixtype = rt_band_get_pixtype(_band); - hasnodata = rt_band_get_hasnodata_flag(_band); - if (hasnodata) - nodataval = rt_band_get_nodata(_band); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); } - /* UT_MEAN requires two passes, first for UT_COUNT and second for UT_SUM */ - if (iwr->uniontype == UT_MEAN) { - /* first pass, UT_COUNT */ - if (i < 1) - utype = UT_COUNT; - else - utype = UT_SUM; - } + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } - /* force band settings for UT_COUNT */ - if (utype == UT_COUNT) { - pixtype = PT_32BUI; - hasnodata = 0; - nodataval = 0; - } + /* by band to UNION */ + for (i = 0; i < iwr->numband; i++) { - /* build itrset */ - itrset = palloc(sizeof(struct rt_iterator_t) * 2); - if (itrset == NULL) { - elog(ERROR, "RASTER_union_transfn: Unable to allocate memory for iterator arguments"); + /* by raster */ + for (j = 0; j < iwr->bandarg[i].numraster; j++) { + utype = iwr->bandarg[i].uniontype; - pfree(iwr->raster); - pfree(iwr); - if (raster != NULL) { - rt_raster_destroy(raster); - PG_FREE_IF_COPY(pgraster, 1); + /* 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 = rt_band_get_hasnodata_flag(_band); + if (hasnodata) + nodataval = rt_band_get_nodata(_band); + else + nodataval = 0; } - MemoryContextSwitchTo(oldcontext); - PG_RETURN_NULL(); - } + /* UT_MEAN requires two passes, 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; + } - itrset[0].raster = iwr->raster[i]; - itrset[0].nband = 0; - itrset[1].raster = raster; - itrset[1].nband = nband - 1; - - /* pass everything to iterator */ - _raster = rt_raster_iterator( - itrset, 2, - ET_UNION, NULL, - pixtype, - hasnodata, nodataval, - 0, 0, - &utype, - rtpg_union_callback, - &noerr - ); + /* force band settings for UT_COUNT */ + if (utype == UT_COUNT) { + pixtype = PT_32BUI; + hasnodata = 0; + nodataval = 0; + } - /* proactive cleanup */ - pfree(itrset); + POSTGIS_RT_DEBUGF(4, "(pixtype, hasnodata, nodataval) = (%s, %d, %f)", rt_pixtype_name(pixtype), hasnodata, nodataval); - if (!noerr) { - elog(ERROR, "RASTER_union_transfn: Unable to run raster interator function"); + /* 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; - pfree(iwr->raster); - pfree(iwr); - if (raster != NULL) { - rt_raster_destroy(raster); - PG_FREE_IF_COPY(pgraster, 1); + /* pass everything to iterator */ + _raster = rt_raster_iterator( + itrset, 2, + ET_UNION, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + &utype, + rtpg_union_callback, + &noerr + ); + + if (!noerr) { + elog(ERROR, "RASTER_union_transfn: Unable to run raster interator function"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); } - MemoryContextSwitchTo(oldcontext); - PG_RETURN_NULL(); + /* replace working raster */ + if (iwr->bandarg[i].raster[j] != NULL) + rt_raster_destroy(iwr->bandarg[i].raster[j]); + iwr->bandarg[i].raster[j] = _raster; } - - /* replace working raster */ - if (iwr->raster[i] != NULL) - rt_raster_destroy(iwr->raster[i]); - iwr->raster[i] = _raster; } + pfree(itrset); if (raster != NULL) { rt_raster_destroy(raster); PG_FREE_IF_COPY(pgraster, 1); @@ -13929,6 +14191,8 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) /* switch back to local context */ MemoryContextSwitchTo(oldcontext); + POSTGIS_RT_DEBUG(3, "Finished"); + PG_RETURN_POINTER(iwr); } @@ -13936,9 +14200,23 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(RASTER_union_finalfn); Datum RASTER_union_finalfn(PG_FUNCTION_ARGS) { - rtpg_union_arg *iwr; + rtpg_union_arg iwr; + rt_raster _rtn = NULL; + rt_raster _raster = NULL; rt_pgraster *pgraster = NULL; + int i = 0; + int j = 0; + rt_iterator itrset = NULL; + rt_band _band = NULL; + int noerr = 1; + int status = 0; + rt_pixtype pixtype = PT_END; + int hasnodata = 0; + double nodataval = 0; + + POSTGIS_RT_DEBUG(3, "Starting..."); + /* cannot be called directly as this is exclusive aggregate function */ if (!AggCheckCallContext(fcinfo, NULL)) { elog(ERROR, "RASTER_union_finalfn: Cannot be called in a non-aggregate context"); @@ -13949,76 +14227,30 @@ Datum RASTER_union_finalfn(PG_FUNCTION_ARGS) if (PG_ARGISNULL(0)) PG_RETURN_NULL(); - iwr = (rtpg_union_arg *) PG_GETARG_POINTER(0); + iwr = (rtpg_union_arg) PG_GETARG_POINTER(0); - /* all UNION types except UT_MEAN have one raster */ - if (iwr->numraster < 2) { - /* return NULL if raster is NULL */ - if (iwr->raster[0] == NULL) { - pfree(iwr->raster); - pfree(iwr); - PG_RETURN_NULL(); - } - - pgraster = rt_raster_serialize(iwr->raster[0]); - rt_raster_destroy(iwr->raster[0]); - pfree(iwr->raster); - pfree(iwr); + /* init itrset */ + itrset = palloc(sizeof(struct rt_iterator_t) * 2); + if (itrset == NULL) { + elog(ERROR, "RASTER_union_finalfn: Unable to allocate memory for iterator arguments"); + rtpg_union_arg_destroy(iwr); + PG_RETURN_NULL(); } - /* special case for UT_MEAN */ - else { - int i; - /* return NULL if either raster is NULL */ - if (iwr->raster[0] == NULL || iwr->raster[1] == NULL) { - for (i = 0; i < iwr->numraster; i++) { - if (iwr->raster[i] != NULL) - rt_raster_destroy(iwr->raster[i]); - } - pfree(iwr->raster); - pfree(iwr); - PG_RETURN_NULL(); - } + for (i = 0; i < iwr->numband; i++) { + if (iwr->bandarg[i].uniontype == UT_MEAN) { + /* raster containing the SUM is at index 1 */ + _band = rt_raster_get_band(iwr->bandarg[i].raster[1], 0); - /* if second raster is empty, return empty raster */ - if (rt_raster_is_empty(iwr->raster[1])) { - pgraster = rt_raster_serialize(iwr->raster[1]); - - for (i = 0; i < iwr->numraster; i++) - rt_raster_destroy(iwr->raster[i]); - pfree(iwr->raster); - pfree(iwr); - } - else { - rt_iterator itrset; - rt_raster _raster = NULL; - rt_band _band = NULL; - rt_pixtype pixtype; - int hasnodata = 1; - double nodataval = 0; - int noerr = 1; - - _band = rt_raster_get_band(iwr->raster[1], 0); pixtype = rt_band_get_pixtype(_band); hasnodata = rt_band_get_hasnodata_flag(_band); if (hasnodata) nodataval = rt_band_get_nodata(_band); + POSTGIS_RT_DEBUGF(4, "(pixtype, hasnodata, nodataval) = (%s, %d, %f)", rt_pixtype_name(pixtype), hasnodata, nodataval); - /* build itrset */ - itrset = palloc(sizeof(struct rt_iterator_t) * 2); - if (itrset == NULL) { - elog(ERROR, "RASTER_union_finalfn: Unable to allocate memory for iterator arguments"); - - for (i = 0; i < iwr->numraster; i++) - rt_raster_destroy(iwr->raster[i]); - pfree(iwr->raster); - pfree(iwr); - PG_RETURN_NULL(); - } - - itrset[0].raster = iwr->raster[0]; + itrset[0].raster = iwr->bandarg[i].raster[0]; itrset[0].nband = 0; - itrset[1].raster = iwr->raster[1]; + itrset[1].raster = iwr->bandarg[i].raster[1]; itrset[1].nband = 0; /* pass everything to iterator */ @@ -14033,23 +14265,58 @@ Datum RASTER_union_finalfn(PG_FUNCTION_ARGS) &noerr ); - /* proactive cleanup */ - pfree(itrset); - for (i = 0; i < iwr->numraster; i++) - rt_raster_destroy(iwr->raster[i]); - pfree(iwr->raster); - pfree(iwr); - if (!noerr) { elog(ERROR, "RASTER_union_finalfn: Unable to run raster interator function"); + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (_rtn != NULL) + rt_raster_destroy(_rtn); PG_RETURN_NULL(); } + } + else + _raster = iwr->bandarg[i].raster[0]; + + /* first band, _rtn doesn't exist */ + if (i < 1) { + uint32_t bandNums[1] = {0}; + _rtn = rt_raster_from_band(_raster, bandNums, 1); + status = (_rtn == NULL) ? -1 : 0; + } + else + status = rt_raster_copy_band(_rtn, _raster, 0, i); - pgraster = rt_raster_serialize(_raster); + POSTGIS_RT_DEBUG(3, "before destroy"); + + /* destroy source rasters */ + if (iwr->bandarg[i].uniontype == UT_MEAN) rt_raster_destroy(_raster); + + for (j = 0; j < iwr->bandarg[i].numraster; j++) { + if (iwr->bandarg[i].raster[j] == NULL) + continue; + rt_raster_destroy(iwr->bandarg[i].raster[j]); + iwr->bandarg[i].raster[j] = NULL; + } + POSTGIS_RT_DEBUG(3, "after destroy"); + + if (status < 0) { + elog(ERROR, "RASTER_union_finalfn: Unable to add band to final raster"); + rtpg_union_arg_destroy(iwr); + rt_raster_destroy(_rtn); + PG_RETURN_NULL(); } } + /* cleanup */ + pfree(itrset); + rtpg_union_arg_destroy(iwr); + + pgraster = rt_raster_serialize(_rtn); + rt_raster_destroy(_rtn); + + POSTGIS_RT_DEBUG(3, "Finished"); + if (!pgraster) PG_RETURN_NULL(); diff --git a/raster/rt_pg/rtpostgis.sql.in.c b/raster/rt_pg/rtpostgis.sql.in.c index c95bbef71..966efb5d2 100644 --- a/raster/rt_pg/rtpostgis.sql.in.c +++ b/raster/rt_pg/rtpostgis.sql.in.c @@ -4398,18 +4398,35 @@ CREATE OR REPLACE FUNCTION st_intersection( LANGUAGE 'sql' STABLE; ----------------------------------------------------------------------- --- ***NEW*** ST_Union aggregate +-- ST_Union aggregate ----------------------------------------------------------------------- -CREATE OR REPLACE FUNCTION _st_union_transfn(internal, raster, integer, text) - RETURNS internal - AS 'MODULE_PATHNAME', 'RASTER_union_transfn' - LANGUAGE 'c' IMMUTABLE; + +CREATE TYPE unionarg AS ( + nband int, + uniontype text +); CREATE OR REPLACE FUNCTION _st_union_finalfn(internal) RETURNS raster AS 'MODULE_PATHNAME', 'RASTER_union_finalfn' LANGUAGE 'c' IMMUTABLE; +CREATE OR REPLACE FUNCTION _st_union_transfn(internal, raster, unionarg[]) + RETURNS internal + AS 'MODULE_PATHNAME', 'RASTER_union_transfn' + LANGUAGE 'c' IMMUTABLE; + +CREATE AGGREGATE st_union(raster, unionarg[]) ( + SFUNC = _st_union_transfn, + STYPE = internal, + FINALFUNC = _st_union_finalfn +); + +CREATE OR REPLACE FUNCTION _st_union_transfn(internal, raster, integer, text) + RETURNS internal + AS 'MODULE_PATHNAME', 'RASTER_union_transfn' + LANGUAGE 'c' IMMUTABLE; + CREATE AGGREGATE st_union(raster, integer, text) ( SFUNC = _st_union_transfn, STYPE = internal, diff --git a/raster/rt_pg/rtpostgis_drop.sql.in.c b/raster/rt_pg/rtpostgis_drop.sql.in.c index 16ebca816..678439a76 100644 --- a/raster/rt_pg/rtpostgis_drop.sql.in.c +++ b/raster/rt_pg/rtpostgis_drop.sql.in.c @@ -30,6 +30,8 @@ DROP AGGREGATE IF EXISTS ST_Union(raster, text, text); DROP AGGREGATE IF EXISTS ST_Union(raster, text, text, text, double precision); DROP AGGREGATE IF EXISTS ST_Union(raster, text); DROP AGGREGATE IF EXISTS ST_Union(raster, integer); +DROP AGGREGATE IF EXISTS ST_Union(raster, unionarg[]); +DROP AGGREGATE IF EXISTS ST_Union(raster, record[]); DROP AGGREGATE IF EXISTS ST_Union(raster); DROP AGGREGATE IF EXISTS st_samealignment(raster); diff --git a/raster/test/core/testapi.c b/raster/test/core/testapi.c index 9263270f2..305bf4aa3 100644 --- a/raster/test/core/testapi.c +++ b/raster/test/core/testapi.c @@ -7050,6 +7050,22 @@ static void testNearestPixel() { if (rtn) rtdealloc(npixels); + /* band with no NODATA */ + band = addBand(rast, PT_32BUI, 0, 0); + CHECK(band); + + /* 0,0 */ + rtn = rt_band_get_nearest_pixel( + band, + 0, 0, + 0, 0, + 1, + &npixels + ); + CHECK((rtn == 8)); + if (rtn) + rtdealloc(npixels); + deepRelease(rast); } diff --git a/raster/test/regress/rt_neighborhood_expected b/raster/test/regress/rt_neighborhood_expected index 32ef03961..e801c8ae5 100644 --- a/raster/test/regress/rt_neighborhood_expected +++ b/raster/test/regress/rt_neighborhood_expected @@ -1,6 +1,6 @@ NOTICE: table "raster_neighborhood" does not exist, skipping {{NULL,NULL,NULL},{NULL,NULL,1},{NULL,1,1}} -{{0,0,0},{0,0,1},{0,1,1}} +{{NULL,NULL,NULL},{NULL,0,1},{NULL,1,1}} {{NULL,1,1},{1,1,1},{1,NULL,1}} {{1,1,1},{1,1,NULL},{1,1,1}} {{1,1,NULL,1,1},{1,1,1,1,1},{NULL,1,1,NULL,1},{1,1,1,1,1},{1,NULL,1,1,NULL}} diff --git a/raster/test/regress/rt_union.sql b/raster/test/regress/rt_union.sql index b55fd6d8c..367718c1b 100644 --- a/raster/test/regress/rt_union.sql +++ b/raster/test/regress/rt_union.sql @@ -70,5 +70,245 @@ FROM ( ) foo ORDER BY uniontype, y, x; +TRUNCATE raster_union_out; +TRUNCATE raster_union_in; + +INSERT INTO raster_union_in + SELECT 10, ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 11, ST_AddBand(ST_MakeEmptyRaster(2, 2, 2, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 12, ST_AddBand(ST_MakeEmptyRaster(2, 2, 4, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + + SELECT 13, ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, -2, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 14, ST_AddBand(ST_MakeEmptyRaster(2, 2, 2, -2, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 15, ST_AddBand(ST_MakeEmptyRaster(2, 2, 4, -2, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + + SELECT 16, ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, -4, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 17, ST_AddBand(ST_MakeEmptyRaster(2, 2, 2, -4, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 18, ST_AddBand(ST_MakeEmptyRaster(2, 2, 4, -4, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast +; + +INSERT INTO raster_union_out + SELECT + 'LAST', + ST_Union(rast, 1) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'FIRST', + ST_Union(rast, 1, 'FIRST') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MIN', + ST_Union(rast, 1, 'MIN') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MAX', + ST_Union(rast, 1, 'MAX') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'COUNT', + ST_Union(rast, 1, 'COUNT') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'SUM', + ST_Union(rast, 1, 'SUM') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MEAN', + ST_Union(rast, 1, 'mean') AS rast + FROM raster_union_in; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + +TRUNCATE raster_union_out; +TRUNCATE raster_union_in; + +INSERT INTO raster_union_in + SELECT 20, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0), 2, '32BF', 1, -9999) AS rast UNION ALL + SELECT 21, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 1, -1, 1, -1, 0, 0, 0), 1, '8BUI', 2, 0), 2, '32BF', 2, -9999) AS rast +; + +INSERT INTO raster_union_out + SELECT + 'LAST', + ST_Union(rast, 2) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'FIRST', + ST_Union(rast, 2, 'FIRST') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MIN', + ST_Union(rast, 2, 'MIN') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MAX', + ST_Union(rast, 2, 'MAX') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'COUNT', + ST_Union(rast, 2, 'COUNT') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'SUM', + ST_Union(rast, 2, 'SUM') AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MEAN', + ST_Union(rast, 2, 'mean') AS rast + FROM raster_union_in; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + +TRUNCATE raster_union_out; +TRUNCATE raster_union_in; + +INSERT INTO raster_union_in + SELECT 30, ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, NULL) AS rast UNION ALL + SELECT 31, ST_AddBand(ST_MakeEmptyRaster(2, 2, 1, -1, 1, -1, 0, 0, 0), 1, '8BUI', 2, NULL) AS rast +; + +INSERT INTO raster_union_out + SELECT + 'LAST', + ST_Union(rast, 1) AS rast + FROM raster_union_in; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + +TRUNCATE raster_union_out; +TRUNCATE raster_union_in; + +INSERT INTO raster_union_in + SELECT 40, NULL::raster AS rast UNION ALL + SELECT 41, NULL::raster AS rast UNION ALL + SELECT 42, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0), 2, '32BF', 100, -9999) AS rast UNION ALL + SELECT 43, ST_AddBand(ST_AddBand(ST_MakeEmptyRaster(2, 2, 1, -1, 1, -1, 0, 0, 0), 1, '8BUI', 2, 0), 2, '32BF', 200, -9999) AS rast +; + +INSERT INTO raster_union_out + SELECT + 'LAST', + ST_Union(rast, ARRAY[ROW(1, 'LAST'), ROW(2, 'LAST')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'FIRST', + ST_Union(rast, ARRAY[ROW(1, 'FIRST'), ROW(2, 'FIRST')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MIN', + ST_Union(rast, ARRAY[ROW(1, 'MIN'), ROW(2, 'MIN')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MAX', + ST_Union(rast, ARRAY[ROW(1, 'MAX'), ROW(2, 'MAX')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'COUNT', + ST_Union(rast, ARRAY[ROW(1, 'COUNT'), ROW(2, 'COUNT')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'SUM', + ST_Union(rast, ARRAY[ROW(1, 'SUM'), ROW(2, 'SUM')]::unionarg[]) AS rast + FROM raster_union_in; + +INSERT INTO raster_union_out + SELECT + 'MEAN', + ST_Union(rast, ARRAY[ROW(1, 'MEAN'), ROW(2, 'MEAN')]::unionarg[]) AS rast + FROM raster_union_in; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast, 2)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + DROP TABLE IF EXISTS raster_union_in; DROP TABLE IF EXISTS raster_union_out; diff --git a/raster/test/regress/rt_union_expected b/raster/test/regress/rt_union_expected index c3caa1856..72f151440 100644 --- a/raster/test/regress/rt_union_expected +++ b/raster/test/regress/rt_union_expected @@ -40,7 +40,7 @@ MEAN|1|1|1 MEAN|2|1|1 MEAN|3|1| MEAN|1|2|1 -MEAN|2|2|2 +MEAN|2|2|1 MEAN|3|2|2 MEAN|1|3| MEAN|2|3|2 @@ -63,3 +63,453 @@ SUM|3|2|2 SUM|1|3| SUM|2|3|2 SUM|3|3|2 +COUNT|1|1|1 +COUNT|2|1|1 +COUNT|3|1|1 +COUNT|4|1|1 +COUNT|5|1|1 +COUNT|6|1|1 +COUNT|1|2|1 +COUNT|2|2|1 +COUNT|3|2|1 +COUNT|4|2|1 +COUNT|5|2|1 +COUNT|6|2|1 +COUNT|1|3|1 +COUNT|2|3|1 +COUNT|3|3|1 +COUNT|4|3|1 +COUNT|5|3|1 +COUNT|6|3|1 +COUNT|1|4|1 +COUNT|2|4|1 +COUNT|3|4|1 +COUNT|4|4|1 +COUNT|5|4|1 +COUNT|6|4|1 +COUNT|1|5|1 +COUNT|2|5|1 +COUNT|3|5|1 +COUNT|4|5|1 +COUNT|5|5|1 +COUNT|6|5|1 +COUNT|1|6|1 +COUNT|2|6|1 +COUNT|3|6|1 +COUNT|4|6|1 +COUNT|5|6|1 +COUNT|6|6|1 +FIRST|1|1|1 +FIRST|2|1|1 +FIRST|3|1|1 +FIRST|4|1|1 +FIRST|5|1|1 +FIRST|6|1|1 +FIRST|1|2|1 +FIRST|2|2|1 +FIRST|3|2|1 +FIRST|4|2|1 +FIRST|5|2|1 +FIRST|6|2|1 +FIRST|1|3|1 +FIRST|2|3|1 +FIRST|3|3|1 +FIRST|4|3|1 +FIRST|5|3|1 +FIRST|6|3|1 +FIRST|1|4|1 +FIRST|2|4|1 +FIRST|3|4|1 +FIRST|4|4|1 +FIRST|5|4|1 +FIRST|6|4|1 +FIRST|1|5|1 +FIRST|2|5|1 +FIRST|3|5|1 +FIRST|4|5|1 +FIRST|5|5|1 +FIRST|6|5|1 +FIRST|1|6|1 +FIRST|2|6|1 +FIRST|3|6|1 +FIRST|4|6|1 +FIRST|5|6|1 +FIRST|6|6|1 +LAST|1|1|1 +LAST|2|1|1 +LAST|3|1|1 +LAST|4|1|1 +LAST|5|1|1 +LAST|6|1|1 +LAST|1|2|1 +LAST|2|2|1 +LAST|3|2|1 +LAST|4|2|1 +LAST|5|2|1 +LAST|6|2|1 +LAST|1|3|1 +LAST|2|3|1 +LAST|3|3|1 +LAST|4|3|1 +LAST|5|3|1 +LAST|6|3|1 +LAST|1|4|1 +LAST|2|4|1 +LAST|3|4|1 +LAST|4|4|1 +LAST|5|4|1 +LAST|6|4|1 +LAST|1|5|1 +LAST|2|5|1 +LAST|3|5|1 +LAST|4|5|1 +LAST|5|5|1 +LAST|6|5|1 +LAST|1|6|1 +LAST|2|6|1 +LAST|3|6|1 +LAST|4|6|1 +LAST|5|6|1 +LAST|6|6|1 +MAX|1|1|1 +MAX|2|1|1 +MAX|3|1|1 +MAX|4|1|1 +MAX|5|1|1 +MAX|6|1|1 +MAX|1|2|1 +MAX|2|2|1 +MAX|3|2|1 +MAX|4|2|1 +MAX|5|2|1 +MAX|6|2|1 +MAX|1|3|1 +MAX|2|3|1 +MAX|3|3|1 +MAX|4|3|1 +MAX|5|3|1 +MAX|6|3|1 +MAX|1|4|1 +MAX|2|4|1 +MAX|3|4|1 +MAX|4|4|1 +MAX|5|4|1 +MAX|6|4|1 +MAX|1|5|1 +MAX|2|5|1 +MAX|3|5|1 +MAX|4|5|1 +MAX|5|5|1 +MAX|6|5|1 +MAX|1|6|1 +MAX|2|6|1 +MAX|3|6|1 +MAX|4|6|1 +MAX|5|6|1 +MAX|6|6|1 +MEAN|1|1|1 +MEAN|2|1|1 +MEAN|3|1|1 +MEAN|4|1|1 +MEAN|5|1|1 +MEAN|6|1|1 +MEAN|1|2|1 +MEAN|2|2|1 +MEAN|3|2|1 +MEAN|4|2|1 +MEAN|5|2|1 +MEAN|6|2|1 +MEAN|1|3|1 +MEAN|2|3|1 +MEAN|3|3|1 +MEAN|4|3|1 +MEAN|5|3|1 +MEAN|6|3|1 +MEAN|1|4|1 +MEAN|2|4|1 +MEAN|3|4|1 +MEAN|4|4|1 +MEAN|5|4|1 +MEAN|6|4|1 +MEAN|1|5|1 +MEAN|2|5|1 +MEAN|3|5|1 +MEAN|4|5|1 +MEAN|5|5|1 +MEAN|6|5|1 +MEAN|1|6|1 +MEAN|2|6|1 +MEAN|3|6|1 +MEAN|4|6|1 +MEAN|5|6|1 +MEAN|6|6|1 +MIN|1|1|1 +MIN|2|1|1 +MIN|3|1|1 +MIN|4|1|1 +MIN|5|1|1 +MIN|6|1|1 +MIN|1|2|1 +MIN|2|2|1 +MIN|3|2|1 +MIN|4|2|1 +MIN|5|2|1 +MIN|6|2|1 +MIN|1|3|1 +MIN|2|3|1 +MIN|3|3|1 +MIN|4|3|1 +MIN|5|3|1 +MIN|6|3|1 +MIN|1|4|1 +MIN|2|4|1 +MIN|3|4|1 +MIN|4|4|1 +MIN|5|4|1 +MIN|6|4|1 +MIN|1|5|1 +MIN|2|5|1 +MIN|3|5|1 +MIN|4|5|1 +MIN|5|5|1 +MIN|6|5|1 +MIN|1|6|1 +MIN|2|6|1 +MIN|3|6|1 +MIN|4|6|1 +MIN|5|6|1 +MIN|6|6|1 +SUM|1|1|1 +SUM|2|1|1 +SUM|3|1|1 +SUM|4|1|1 +SUM|5|1|1 +SUM|6|1|1 +SUM|1|2|1 +SUM|2|2|1 +SUM|3|2|1 +SUM|4|2|1 +SUM|5|2|1 +SUM|6|2|1 +SUM|1|3|1 +SUM|2|3|1 +SUM|3|3|1 +SUM|4|3|1 +SUM|5|3|1 +SUM|6|3|1 +SUM|1|4|1 +SUM|2|4|1 +SUM|3|4|1 +SUM|4|4|1 +SUM|5|4|1 +SUM|6|4|1 +SUM|1|5|1 +SUM|2|5|1 +SUM|3|5|1 +SUM|4|5|1 +SUM|5|5|1 +SUM|6|5|1 +SUM|1|6|1 +SUM|2|6|1 +SUM|3|6|1 +SUM|4|6|1 +SUM|5|6|1 +SUM|6|6|1 +COUNT|1|1|1 +COUNT|2|1|1 +COUNT|3|1|0 +COUNT|1|2|1 +COUNT|2|2|2 +COUNT|3|2|1 +COUNT|1|3|0 +COUNT|2|3|1 +COUNT|3|3|1 +FIRST|1|1|1 +FIRST|2|1|1 +FIRST|3|1| +FIRST|1|2|1 +FIRST|2|2|1 +FIRST|3|2|2 +FIRST|1|3| +FIRST|2|3|2 +FIRST|3|3|2 +LAST|1|1|1 +LAST|2|1|1 +LAST|3|1| +LAST|1|2|1 +LAST|2|2|2 +LAST|3|2|2 +LAST|1|3| +LAST|2|3|2 +LAST|3|3|2 +MAX|1|1|1 +MAX|2|1|1 +MAX|3|1| +MAX|1|2|1 +MAX|2|2|2 +MAX|3|2|2 +MAX|1|3| +MAX|2|3|2 +MAX|3|3|2 +MEAN|1|1|1 +MEAN|2|1|1 +MEAN|3|1| +MEAN|1|2|1 +MEAN|2|2|1.5 +MEAN|3|2|2 +MEAN|1|3| +MEAN|2|3|2 +MEAN|3|3|2 +MIN|1|1|1 +MIN|2|1|1 +MIN|3|1| +MIN|1|2|1 +MIN|2|2|1 +MIN|3|2|2 +MIN|1|3| +MIN|2|3|2 +MIN|3|3|2 +SUM|1|1|1 +SUM|2|1|1 +SUM|3|1| +SUM|1|2|1 +SUM|2|2|3 +SUM|3|2|2 +SUM|1|3| +SUM|2|3|2 +SUM|3|3|2 +LAST|1|1|1 +LAST|2|1|1 +LAST|3|1|0 +LAST|1|2|1 +LAST|2|2|2 +LAST|3|2|2 +LAST|1|3|0 +LAST|2|3|2 +LAST|3|3|2 +COUNT|1|1|1 +COUNT|2|1|1 +COUNT|3|1|0 +COUNT|1|2|1 +COUNT|2|2|2 +COUNT|3|2|1 +COUNT|1|3|0 +COUNT|2|3|1 +COUNT|3|3|1 +FIRST|1|1|1 +FIRST|2|1|1 +FIRST|3|1| +FIRST|1|2|1 +FIRST|2|2|1 +FIRST|3|2|2 +FIRST|1|3| +FIRST|2|3|2 +FIRST|3|3|2 +LAST|1|1|1 +LAST|2|1|1 +LAST|3|1| +LAST|1|2|1 +LAST|2|2|2 +LAST|3|2|2 +LAST|1|3| +LAST|2|3|2 +LAST|3|3|2 +MAX|1|1|1 +MAX|2|1|1 +MAX|3|1| +MAX|1|2|1 +MAX|2|2|2 +MAX|3|2|2 +MAX|1|3| +MAX|2|3|2 +MAX|3|3|2 +MEAN|1|1|1 +MEAN|2|1|1 +MEAN|3|1| +MEAN|1|2|1 +MEAN|2|2|1 +MEAN|3|2|2 +MEAN|1|3| +MEAN|2|3|2 +MEAN|3|3|2 +MIN|1|1|1 +MIN|2|1|1 +MIN|3|1| +MIN|1|2|1 +MIN|2|2|1 +MIN|3|2|2 +MIN|1|3| +MIN|2|3|2 +MIN|3|3|2 +SUM|1|1|1 +SUM|2|1|1 +SUM|3|1| +SUM|1|2|1 +SUM|2|2|3 +SUM|3|2|2 +SUM|1|3| +SUM|2|3|2 +SUM|3|3|2 +COUNT|1|1|1 +COUNT|2|1|1 +COUNT|3|1|0 +COUNT|1|2|1 +COUNT|2|2|2 +COUNT|3|2|1 +COUNT|1|3|0 +COUNT|2|3|1 +COUNT|3|3|1 +FIRST|1|1|100 +FIRST|2|1|100 +FIRST|3|1| +FIRST|1|2|100 +FIRST|2|2|100 +FIRST|3|2|200 +FIRST|1|3| +FIRST|2|3|200 +FIRST|3|3|200 +LAST|1|1|100 +LAST|2|1|100 +LAST|3|1| +LAST|1|2|100 +LAST|2|2|200 +LAST|3|2|200 +LAST|1|3| +LAST|2|3|200 +LAST|3|3|200 +MAX|1|1|100 +MAX|2|1|100 +MAX|3|1| +MAX|1|2|100 +MAX|2|2|200 +MAX|3|2|200 +MAX|1|3| +MAX|2|3|200 +MAX|3|3|200 +MEAN|1|1|100 +MEAN|2|1|100 +MEAN|3|1| +MEAN|1|2|100 +MEAN|2|2|150 +MEAN|3|2|200 +MEAN|1|3| +MEAN|2|3|200 +MEAN|3|3|200 +MIN|1|1|100 +MIN|2|1|100 +MIN|3|1| +MIN|1|2|100 +MIN|2|2|100 +MIN|3|2|200 +MIN|1|3| +MIN|2|3|200 +MIN|3|3|200 +SUM|1|1|100 +SUM|2|1|100 +SUM|3|1| +SUM|1|2|100 +SUM|2|2|300 +SUM|3|2|200 +SUM|1|3| +SUM|2|3|200 +SUM|3|3|200 diff --git a/utils/create_undef.pl b/utils/create_undef.pl index 80232dd62..4a2a1e5b2 100755 --- a/utils/create_undef.pl +++ b/utils/create_undef.pl @@ -172,7 +172,7 @@ foreach my $agg (@aggs) { print "DROP AGGREGATE IF EXISTS $1 ($2);\n"; } - elsif ( $agg =~ /create aggregate\s*([\w\.]+)\s*\(\s*([\w,\.\s]+)\s*\)/ism ) + elsif ( $agg =~ /create aggregate\s*([\w\.]+)\s*\(\s*([\w,\.\s\[\]]+)\s*\)/ism ) { print "DROP AGGREGATE IF EXISTS $1 ($2);\n"; }