]> granicus.if.org Git - postgis/commitdiff
Added multi-band support for ST_Union. Ticket is #2021
authorBborie Park <bkpark at ucdavis.edu>
Tue, 2 Oct 2012 21:45:41 +0000 (21:45 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Tue, 2 Oct 2012 21:45:41 +0000 (21:45 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@10360 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_raster.xml
raster/rt_core/rt_api.c
raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/rt_pg/rtpostgis_drop.sql.in.c
raster/test/core/testapi.c
raster/test/regress/rt_neighborhood_expected
raster/test/regress/rt_union.sql
raster/test/regress/rt_union_expected
utils/create_undef.pl

diff --git a/NEWS b/NEWS
index d784b4261747152e55f876d96ffd0a7842bdf9df..50d86e4ebd8f858024dbd9af4310b132a86aa7a8 100644 (file)
--- 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 *
 
index ca9a67cadf296423cd1125ff67c1e7e9ae109332..0b344c221fa1dd2139cbaff5a34887522c814ba1 100644 (file)
@@ -233,7 +233,56 @@ VALUES (1,
                 <para><xref linkend="RT_ST_Reclass" /></para>
            </refsection>
                </refentry>
-               
+
+               <refentry id="unionarg">
+                       <refnamediv>
+                               <refname>unionarg</refname>
+                               <refpurpose>A composite type used as input into the ST_Union function defining the bands to be processed and behavior of the UNION operation.</refpurpose>
+                       </refnamediv>
+
+                       <refsection>
+                               <title>Description</title>
+                               <para>
+                                       A composite type used as input into the ST_Union function defining the bands to be processed and behavior of the UNION operation.
+
+                                       <variablelist>
+                                               <varlistentry>
+                                                       <term>
+                                                               <parameter>nband </parameter>
+                                                               <type>integer</type>
+                                                       </term>
+                                                       <listitem>
+                                                               <para>
+                                                                       1-based value indicating the band of each input raster to be processed.
+                                                               </para>
+                                                       </listitem>
+                                               </varlistentry>
+
+                                               <varlistentry>
+                                                       <term>
+                                                               <parameter>uniontype </parameter>
+                                                               <type>text</type>
+                                                       </term>
+                                                       <listitem>
+                                                               <para>
+                                               Type of UNION operation. One of defined types as described in <xref linkend="RT_ST_Union" />.
+                                                               </para>
+                                                       </listitem>
+                                               </varlistentry>
+
+                                       </variablelist>
+
+                               </para>
+                       </refsection>
+
+                       <refsection>
+                               <title>See Also</title>
+                               <para>
+                                       <xref linkend="RT_ST_Union" />
+                               </para>
+                       </refsection>
+               </refentry>
+
   </sect1>
 
   <sect1 id="Raster_Management_Functions">
@@ -8622,34 +8671,43 @@ UPDATE wind
                <refentry id="RT_ST_Union">
                        <refnamediv>
                                <refname>ST_Union</refname>
-                               <refpurpose>Returns the union of a set of raster tiles into a single raster composed of 1 band.</refpurpose>
+                               <refpurpose>Returns the union of a set of raster tiles into a single raster composed of 1 or more bands.</refpurpose>
                        </refnamediv>
                
                        <refsynopsisdiv>
+<!-- NOT IMPLEMENTED YET
+                               <funcsynopsis>
+                                 <funcprototype>
+                                               <funcdef>raster <function>ST_Union</function></funcdef>
+                                               <paramdef><type>setof raster </type> <parameter>rast</parameter></paramdef>
+                                 </funcprototype>
+                               </funcsynopsis>
+-->
                                <funcsynopsis>
                                  <funcprototype>
                                                <funcdef>raster <function>ST_Union</function></funcdef>
                                                <paramdef><type>setof raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>unionarg[] </type> <parameter>unionargset</parameter></paramdef>
                                  </funcprototype>
                                </funcsynopsis>
                                <funcsynopsis>
                                  <funcprototype>
                                                <funcdef>raster <function>ST_Union</function></funcdef>
-                                               <paramdef><type>raster set</type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>setof raster</type> <parameter>rast</parameter></paramdef>
                                                <paramdef><type>integer</type> <parameter>nband</parameter></paramdef>
                                  </funcprototype>
                                </funcsynopsis>
                                <funcsynopsis>
                                  <funcprototype>
                                                <funcdef>raster <function>ST_Union</function></funcdef>
-                                               <paramdef><type>raster set</type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>setof raster</type> <parameter>rast</parameter></paramdef>
                                                <paramdef><type>text</type> <parameter>uniontype</parameter></paramdef>
                                  </funcprototype>
                                </funcsynopsis>
                                <funcsynopsis>
                                  <funcprototype>
                                                <funcdef>raster <function>ST_Union</function></funcdef>
-                                               <paramdef><type>raster set</type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>setof raster</type> <parameter>rast</parameter></paramdef>
                                                <paramdef><type>integer</type> <parameter>nband</parameter></paramdef>
                                                <paramdef><type>text</type> <parameter>uniontype</parameter></paramdef>
                                  </funcprototype>
@@ -8659,8 +8717,8 @@ UPDATE wind
                        <refsection>
                                <title>Description</title>
                                
-                               <para>Returns the union of a set of raster tiles into a single raster composed of 1 band.  If <varname>nband</varname> 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 <varname>uniontype</varname> which is one of the following: LAST (default), FIRST, MIN, MAX, COUNT, SUM, MEAN.</para>
-                               
+                               <para>Returns the union of a set of raster tiles into a single raster composed of at least one band.  If <varname>nband</varname> 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 <varname>uniontype</varname> which is one of the following: LAST (default), FIRST, MIN, MAX, COUNT, SUM, MEAN.</para>
+
                                <para>Availability: 2.0.0 </para>
                                <para>Enhanced: 2.1.0 Improved Speed (fully C-Based).</para>
                        </refsection>
@@ -8687,9 +8745,9 @@ WHERE ST_Intersects(rast,  ST_GeomFromText('LINESTRING(230486 887771, 230500 887
                        <refsection>
                                <title>See Also</title>
                                <para>
+                                       <xref linkend="unionarg" />, 
                                        <xref linkend="RT_ST_Envelope" />, 
-                                       <xref linkend="RT_ST_ConvexHull" />, 
-                                       <xref linkend="RT_ST_MapAlgebraExpr2" />
+                                       <xref linkend="RT_ST_ConvexHull" />
                                </para>
                        </refsection>
                </refentry>
index 6ef0aacbc46a6b4c8a0b28680fac2f25c19dc654..911f4b933dbad7770da943f389b23a9365f9ce42 100644 (file)
@@ -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");
 
index 89781714ac00b546a5c9ff1c2174abc8c264a7a6..e0c9b2cf9d318005d22dac6d09d7bce98987efc8 100644 (file)
@@ -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();
 
index c95bbef710058c489672888037492e5dcc218e69..966efb5d27044b7d5e83ea550176516e41aa9925 100644 (file)
@@ -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,
index 16ebca816100bcf15d8900ef4b46d25f114a2030..678439a765e91017d9cf424a97339f6da77efdd5 100644 (file)
@@ -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);
index 9263270f222a120f0e6ce59bedc806725adb5e54..305bf4aa3840199cda7305a548c25268e0aee577 100644 (file)
@@ -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);
 }
 
index 32ef039619c835c579f0124337bc06a865110d8e..e801c8ae55344c602a2a9b2dbee09642b9d230e1 100644 (file)
@@ -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}}
index b55fd6d8c3e387497c40bdc4b5b70665d7336fb0..367718c1b925e6b87fa2400b7e5cb8acc18d0e85 100644 (file)
@@ -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;
index c3caa18564e517a3b6511151948e97d04620042f..72f151440b2ac10988b5eb3b1f3fd170f444349e 100644 (file)
@@ -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
index 80232dd629337a399c898c614728224b0ff5f0c9..4a2a1e5b2344df85ba8af85ed38c1ea4cf7db9c1 100755 (executable)
@@ -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";
        }