]> granicus.if.org Git - postgis/commitdiff
Addition of ST_AddBand(raster, ...) for out-db bands. Ticket #2276
authorBborie Park <bkpark at ucdavis.edu>
Tue, 23 Apr 2013 19:32:06 +0000 (19:32 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Tue, 23 Apr 2013 19:32:06 +0000 (19:32 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@11311 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_raster.xml
raster/rt_core/rt_api.c
raster/rt_core/rt_api.h
raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in
raster/test/regress/rt_addband-post.pl [new file with mode: 0644]
raster/test/regress/rt_addband-pre.pl [new file with mode: 0644]
raster/test/regress/rt_addband.sql
raster/test/regress/rt_addband_expected
regress/run_test.pl

diff --git a/NEWS b/NEWS
index 0a0e3ccd518ae7b164f55a22334d0e637e1e4257..953017829d0fa20dcfe50e93d529958c85b5036c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -79,6 +79,7 @@ PostGIS 2.1.0
   - #2228, TopoJSON output for TopoGeometry (Sandro Santilli / Vizzuality)
   - #2123, ST_FromGDALRaster
   - #613, ST_SetGeoReference with numerical parameters instead of text
+  - #2276, ST_AddBand(raster) variant for out-db bands
 
 * Enhancements *
 
@@ -118,11 +119,12 @@ PostGIS 2.1.0
   - #2148, Addition of coverage_tile constraint for raster
   - #2149, Addition of spatially_unique constraint for raster
   - TopologySummary output now includes unregistered layers and a count
-    of missing TopoGeometry objects from their natural layer.
+           of missing TopoGeometry objects from their natural layer.
   - ST_HillShade(), ST_Aspect() and ST_Slope() have one new optional 
-    parameter to interpolate NODATA pixels before running the operation.
+           parameter to interpolate NODATA pixels before running the
+           operation.
   - Point variant of ST_SetValue(raster) is now a wrapper around geomval 
-    variant of ST_SetValues(rast).
+           variant of ST_SetValues(rast).
   - Proper support for raster band's isnodata flag in core API and loader.
   - Additional default values for parameters of ST_Aspect and ST_HillShade
   - #2178, ST_Summary now advertises presence of known srid with an [S] flag
index b837bd1e6edfc7f2e5876713e7af6caa3ee485d8..f689737b076f04396c4da145417ca0f64b34499b 100644 (file)
@@ -1036,34 +1036,30 @@ WHERE short_name = 'GTiff') As g;
                                <funcsynopsis>
 
                                        <funcprototype>
-                                               <funcdef>raster <function>ST_AddBand</function></funcdef>
-
+                                               <funcdef>(1) raster <function>ST_AddBand</function></funcdef>
                                                <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
                                                <paramdef><type>addbandarg[] </type> <parameter>addbandargset</parameter></paramdef>
                                        </funcprototype>
 
                                        <funcprototype>
-                                               <funcdef>raster <function>ST_AddBand</function></funcdef>
-
+                                               <funcdef>(2) raster <function>ST_AddBand</function></funcdef>
                                                <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>integer </type> <parameter>index</parameter></paramdef>
                                                <paramdef><type>text </type> <parameter>pixeltype</parameter></paramdef>
                                                <paramdef choice="opt"><type>double precision </type> <parameter>initialvalue=0</parameter></paramdef>
                                                <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
                                        </funcprototype>
 
                                        <funcprototype>
-                                               <funcdef>raster <function>ST_AddBand</function></funcdef>
-
+                                               <funcdef>(3) raster <function>ST_AddBand</function></funcdef>
                                                <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
-                                               <paramdef><type>integer </type> <parameter>index</parameter></paramdef>
                                                <paramdef><type>text </type> <parameter>pixeltype</parameter></paramdef>
                                                <paramdef choice="opt"><type>double precision </type> <parameter>initialvalue=0</parameter></paramdef>
                                                <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
                                        </funcprototype>
 
                                        <funcprototype>
-                                               <funcdef>raster <function>ST_AddBand</function></funcdef>
-
+                                               <funcdef>(4) raster <function>ST_AddBand</function></funcdef>
                                                <paramdef><type>raster </type> <parameter>torast</parameter></paramdef>
                                                <paramdef><type>raster </type> <parameter>fromrast</parameter></paramdef>
                                                <paramdef choice="opt"><type>integer </type> <parameter>fromband=1</parameter></paramdef>
@@ -1071,14 +1067,31 @@ WHERE short_name = 'GTiff') As g;
                                        </funcprototype>
 
                                        <funcprototype>
-                                               <funcdef>raster <function>ST_AddBand</function></funcdef>
-
+                                               <funcdef>(5) raster <function>ST_AddBand</function></funcdef>
                                                <paramdef><type>raster </type> <parameter>torast</parameter></paramdef>
                                                <paramdef><type>raster[] </type> <parameter>fromrasts</parameter></paramdef>
                                                <paramdef choice="opt"><type>integer </type> <parameter>fromband=1</parameter></paramdef>
                                                <paramdef choice="opt"><type>integer </type> <parameter>torastindex=at_end</parameter></paramdef>
                                        </funcprototype>
 
+                                       <funcprototype>
+                                               <funcdef>(6) raster <function>ST_AddBand</function></funcdef>
+                                               <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>integer </type> <parameter>index</parameter></paramdef>
+                                               <paramdef><type>text </type> <parameter>outdbfile</parameter></paramdef>
+                                               <paramdef><type>integer[] </type> <parameter>outdbindex</parameter></paramdef>
+                                               <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
+                                       </funcprototype>
+
+                                       <funcprototype>
+                                               <funcdef>(7) raster <function>ST_AddBand</function></funcdef>
+                                               <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>text </type> <parameter>outdbfile</parameter></paramdef>
+                                               <paramdef><type>integer[] </type> <parameter>outdbindex</parameter></paramdef>
+                                               <paramdef choice="opt"><type>integer </type> <parameter>index=at_end</parameter></paramdef>
+                                               <paramdef choice="opt"><type>double precision </type> <parameter>nodataval=NULL</parameter></paramdef>
+                                       </funcprototype>
+
                                </funcsynopsis>
                        </refsynopsisdiv>
 
@@ -1086,21 +1099,27 @@ WHERE short_name = 'GTiff') As g;
                                <title>Description</title> 
 
                                <para>
-                                       Returns a raster with a new band added in given position (index), of given type, of given initial value, and of given nodata value.  If no index is specified, the band is added to the end. If no <varname>fromband</varname> is specified, band 1 is assumed. Pixel type is a string representation of one of the pixel types specified in <xref linkend="RT_ST_BandPixelType" />.  If an existing index is specified all subsequent bands >= that index are incremented by 1. If an initial value greater than the max of the pixel type is specified, then the initial value is set to the highest value allowed by the pixel type. The last version add the <varname>fromband</varname> from <varname>fromrast</varname> raster to <varname>torast</varname> in position <varname>torastindex</varname>.
+                                       Returns a raster with a new band added in given position (index), of given type, of given initial value, and of given nodata value.  If no index is specified, the band is added to the end. If no <varname>fromband</varname> is specified, band 1 is assumed. Pixel type is a string representation of one of the pixel types specified in <xref linkend="RT_ST_BandPixelType" />.  If an existing index is specified all subsequent bands >= that index are incremented by 1. If an initial value greater than the max of the pixel type is specified, then the initial value is set to the highest value allowed by the pixel type.
+                               </para>
+
+                               <para>
+                                       For the variant that takes an array of <xref linkend="addbandarg" /> (Variant 1), a specific addbandarg's index value is relative to the raster at the time when the band described by that addbandarg is being added to the raster.  See the Multiple New Bands example below.
                                </para>
 
                                <para>
-                                       For the version that takes an array of <xref linkend="addbandarg" />, a specific addbandarg's index value is relative to the raster at the time when the band described by that addbandarg is being added to the raster.  See the Multiple New Bands example below.
+                                       For the variant that takes an array of rasters (Variant 5),  if <varname>torast</varname> is NULL then the <varname>fromband</varname> band of each raster in the array is accumulated into a new raster.
                                </para>
 
                                <para>
-                                       For the version that takes an array of bands if <varname>torast</varname> is NULL, then the <varname>fromband</varname> band of each raster in the array is accumulated into a new raster.
+                                       For the variants that take <varname>outdbfile</varname> (Variants 6 and 7), the value must include the full path to the raster file. The file must also be accessible to the postgres server process.
                                </para>
-                               <para>Enhanced: 2.1.0 support addbandarg was introduced.</para>
+
+                               <para>Enhanced: 2.1.0 support for addbandarg added.</para>
+                               <para>Enhanced: 2.1.0 support for new out-db bands added.</para>
                        </refsection> 
 
                        <refsection>
-                               <title>Examples: Single New Band versions</title>
+                               <title>Examples: Single New Band</title>
 
                                <programlisting>
 -- Add another band of type 8 bit unsigned integer with pixels initialized to 200
@@ -1169,10 +1188,6 @@ FROM ST_BandMetadata(
        3 | 32BUI     |          12 | f       | 
        4 | 16BUI     |           2 | f       | 
                                </programlisting>
-                       </refsection>
-
-                       <refsection>
-                               <title>Examples: Multi-Band versions</title>
 
                                <programlisting>
 -- Aggregate the 1st band of a table of like rasters into a single raster 
@@ -1181,9 +1196,32 @@ FROM ST_BandMetadata(
 -- for 8.4 and below it usually works to order your data in a subselect (but not guaranteed)
 -- The resulting raster will have a band for each test_type alphabetical by test_type
 -- For mouse lovers: No mice were harmed in this exercise
-SELECT mouse, ST_AddBand(NULL, array_agg(rast ORDER BY test_type), 1 ) As rast 
-       FROM mice_studies
-                       GROUP BY mouse;
+SELECT
+       mouse,
+       ST_AddBand(NULL, array_agg(rast ORDER BY test_type), 1) As rast 
+FROM mice_studies
+GROUP BY mouse;
+                               </programlisting>
+                       </refsection>
+
+                       <refsection>
+                               <title>Examples: New Out-db band</title>
+                               <programlisting>
+SELECT
+       *
+FROM ST_BandMetadata(
+       ST_AddBand(
+               ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0),
+               '/home/raster/mytestraster.tif'::text, NULL::int[]
+       ),
+       ARRAY[]::integer[]
+);
+
+ bandnum | pixeltype | nodatavalue | isoutdb | path 
+---------+-----------+-------------+---------+------
+       1 | 8BUI      |             | t       | /home/raster/mytestraster.tif
+       2 | 8BUI      |             | t       | /home/raster/mytestraster.tif
+       3 | 8BUI      |             | t       | /home/raster/mytestraster.tif
                                </programlisting>
                        </refsection>
 
index 4e5a7cf90fd9c1dff33182780512b549b849b0ed..6e3a56f9fd3b1060772629b854636da7f125b769 100644 (file)
@@ -367,6 +367,62 @@ rt_util_gdal_supported_sr(const char *srs) {
                return 0;
 }
 
+/**
+ * Get auth name and code
+ *
+ * @param authname: authority organization of code. calling function
+ * is expected to free the memory allocated for value
+ * @param authcode: code assigned by authority organization. calling function
+ * is expected to free the memory allocated for value
+ *
+ * @return ES_NONE on success, ES_ERROR on error
+ */
+rt_errorstate
+rt_util_gdal_sr_auth_info(GDALDatasetH hds, char **authname, char **authcode) {
+       const char *srs = NULL;
+
+       assert(authname != NULL);
+       assert(authcode != NULL);
+
+       *authname = NULL;
+       *authcode = NULL;
+
+       srs = GDALGetProjectionRef(hds);
+       if (srs != NULL && srs[0] != '\0') {
+               OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL);
+
+               if (OSRSetFromUserInput(hSRS, srs) == OGRERR_NONE) {
+                       const char* pszAuthorityName = OSRGetAuthorityName(hSRS, NULL);
+                       const char* pszAuthorityCode = OSRGetAuthorityCode(hSRS, NULL);
+
+                       if (pszAuthorityName != NULL && pszAuthorityCode != NULL) {
+                               *authname = rtalloc(sizeof(char) * (strlen(pszAuthorityName) + 1));
+                               *authcode = rtalloc(sizeof(char) * (strlen(pszAuthorityCode) + 1));
+
+                               if (*authname == NULL || *authcode == NULL) {
+                                       rterror("rt_util_gdal_sr_auth_info: Unable to allocate memory for auth name and code");
+                                       if (*authname != NULL) rtdealloc(*authname);
+                                       if (*authcode != NULL) rtdealloc(*authcode);
+                                       OSRDestroySpatialReference(hSRS);
+                                       return ES_ERROR;
+                               }
+
+                               strncpy(*authname, pszAuthorityName, strlen(pszAuthorityName) + 1);
+                               strncpy(*authcode, pszAuthorityCode, strlen(pszAuthorityCode) + 1);
+                       }
+                       else {
+                               rtinfo("Cound not get auth name and code. The SRS may be custom");
+                               OSRDestroySpatialReference(hSRS);
+                               return ES_NONE;
+                       }
+               }
+
+               OSRDestroySpatialReference(hSRS);
+       }
+
+       return ES_NONE;
+}
+
 /*
        is GDAL configured correctly?
 */
@@ -1663,11 +1719,11 @@ rt_band_load_offline_data(rt_band band) {
        _rast = rt_raster_new(1, 1);
        rt_raster_set_geotransform_matrix(_rast, ogt);
        rt_raster_set_srid(_rast, band->raster->srid);
-       err =rt_raster_same_alignment(band->raster, _rast, &aligned, NULL);
+       err = rt_raster_same_alignment(band->raster, _rast, &aligned, NULL);
        rt_raster_destroy(_rast);
 
        if (err != ES_NONE) {
-               rterror("rt_band_load_offline_data: Could not test alignment of in-db representation of out-db raster");
+               rterror("rt_band_load_offline_data: Could not test alignment of in-db representation of out-db raster");
                GDALClose(hdsSrc);
                return ES_ERROR;
        }
@@ -9146,9 +9202,8 @@ rt_raster_from_gdal_dataset(GDALDatasetH ds) {
        uint32_t height = 0;
        uint32_t numBands = 0;
        int i = 0;
-       int status;
-
-       const char *srs = NULL;
+       char *authname = NULL;
+       char *authcode = NULL;
 
        GDALRasterBandH gdband = NULL;
        GDALDataType gdpixtype = GDT_Unknown;
@@ -9156,7 +9211,7 @@ rt_raster_from_gdal_dataset(GDALDatasetH ds) {
        int32_t idx;
        rt_pixtype pt = PT_END;
        uint32_t ptlen = 0;
-       uint32_t hasnodata = 0;
+       int hasnodata = 0;
        double nodataval;
 
        int x;
@@ -9207,22 +9262,20 @@ rt_raster_from_gdal_dataset(GDALDatasetH ds) {
                gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
 
        /* srid */
-       srs = GDALGetProjectionRef(ds);
-       if (srs != NULL && srs[0] != '\0') {
-               OGRSpatialReferenceH hSRS = OSRNewSpatialReference(NULL);
-               if (OSRSetFromUserInput(hSRS, srs) == OGRERR_NONE) {
-                       const char* pszAuthorityName = OSRGetAuthorityName(hSRS, NULL);
-                       const char* pszAuthorityCode = OSRGetAuthorityCode(hSRS, NULL);
-                       if (
-                               pszAuthorityName != NULL &&
-                               strcmp(pszAuthorityName, "EPSG") == 0 &&
-                               pszAuthorityCode != NULL
-                       ) {
-                               rt_raster_set_srid(rast, atoi(pszAuthorityCode));
-                               RASTER_DEBUGF(3, "New raster's SRID = %d", rast->srid);
-                       }
+       if (rt_util_gdal_sr_auth_info(ds, &authname, &authcode) == ES_NONE) {
+               if (
+                       authname != NULL &&
+                       strcmp(authname, "EPSG") == 0 &&
+                       authcode != NULL
+               ) {
+                       rt_raster_set_srid(rast, atoi(authcode));
+                       RASTER_DEBUGF(3, "New raster's SRID = %d", rast->srid);
                }
-               OSRDestroySpatialReference(hSRS);
+
+               if (authname != NULL)
+                       rtdealloc(authname);
+               if (authcode != NULL)
+                       rtdealloc(authcode);
        }
 
        numBands = GDALGetRasterCount(ds);
@@ -9270,13 +9323,7 @@ rt_raster_from_gdal_dataset(GDALDatasetH ds) {
                RASTER_DEBUGF(3, "GDAL band dimensions (width x height): %d x %d", width, height);
 
                /* nodata */
-               nodataval = GDALGetRasterNoDataValue(gdband, &status);
-               if (!status) {
-                       nodataval = 0;
-                       hasnodata = 0;
-               }
-               else
-                       hasnodata = 1;
+               nodataval = GDALGetRasterNoDataValue(gdband, &hasnodata);
                RASTER_DEBUGF(3, "(hasnodata, nodataval) = (%d, %f)", hasnodata, nodataval);
 
                /* create band object */
index ccc83c2d45e7c489e32db5619a082e4f3c2b2058..b225b1c4c46ea143c232e9f0406354bf36074dee 100644 (file)
@@ -2071,6 +2071,18 @@ rt_util_gdal_convert_sr(const char *srs, int proj4);
 int
 rt_util_gdal_supported_sr(const char *srs);
 
+/**
+ * Get auth name and code
+ *
+ * @param authname: authority organization of code. calling function
+ * is expected to free the memory allocated for value
+ * @param authcode: code assigned by authority organization. calling function
+ * is expected to free the memory allocated for value
+ *
+ * @return ES_NONE on success, ES_ERROR on error
+ */
+rt_errorstate rt_util_gdal_sr_auth_info(GDALDatasetH hds, char **authname, char **authcode);
+
 /*
        is GDAL configured correctly?
 */
index 55b49d70de0b18ab0e676571b1c1869bbd6b5115..7bce5dd4c1f7389ef7aa6d277edb9a37754f70c3 100644 (file)
@@ -286,6 +286,7 @@ Datum RASTER_makeEmpty(PG_FUNCTION_ARGS);
 Datum RASTER_addBand(PG_FUNCTION_ARGS);
 Datum RASTER_copyBand(PG_FUNCTION_ARGS);
 Datum RASTER_addBandRasterArray(PG_FUNCTION_ARGS);
+Datum RASTER_addBandOutDB(PG_FUNCTION_ARGS);
 Datum RASTER_tile(PG_FUNCTION_ARGS);
 
 /* create new raster from existing raster's bands */
@@ -5401,6 +5402,364 @@ Datum RASTER_addBandRasterArray(PG_FUNCTION_ARGS)
        PG_RETURN_NULL();
 }
 
+/**
+ * Add out-db band to the given raster at the given position
+ */
+PG_FUNCTION_INFO_V1(RASTER_addBandOutDB);
+Datum RASTER_addBandOutDB(PG_FUNCTION_ARGS)
+{
+       rt_pgraster *pgraster = NULL;
+       rt_pgraster *pgrtn = NULL;
+
+       rt_raster raster = NULL;
+       rt_band band = NULL;
+       int numbands = 0;
+       int dstnband = 1; /* 1-based */
+       int appendband = FALSE;
+       char *outdbfile = NULL;
+       int *srcnband = NULL; /* 1-based */
+       int numsrcnband = 0;
+       int allbands = FALSE;
+       int hasnodata = FALSE;
+       double nodataval = 0.;
+       uint16_t width = 0;
+       uint16_t height = 0;
+       char *authname = NULL;
+       char *authcode = NULL;
+
+       int i = 0;
+       int j = 0;
+
+       GDALDatasetH hdsOut;
+       GDALRasterBandH hbandOut;
+       GDALDataType gdpixtype;
+
+       rt_pixtype pt = PT_END;
+       double gt[6] = {0.};
+       double ogt[6] = {0.};
+       rt_raster _rast = NULL;
+       int aligned = 0;
+       int err = 0;
+
+       /* destination raster */
+       if (!PG_ARGISNULL(0)) {
+               pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+               /* raster */
+               raster = rt_raster_deserialize(pgraster, FALSE);
+               if (!raster) {
+                       elog(ERROR, "RASTER_addBandOutDB: Could not deserialize destination raster");
+                       PG_FREE_IF_COPY(pgraster, 0);
+                       PG_RETURN_NULL();
+               }
+
+               POSTGIS_RT_DEBUG(4, "destination raster isn't NULL");
+       }
+
+       /* destination band index (1) */
+       if (!PG_ARGISNULL(1))
+               dstnband = PG_GETARG_INT32(1);
+       else
+               appendband = TRUE;
+
+       /* outdb file (2) */
+       if (PG_ARGISNULL(2)) {
+               elog(NOTICE, "Out-db raster file not provided. Returning original raster");
+               if (pgraster != NULL) {
+                       rt_raster_destroy(raster);
+                       PG_RETURN_POINTER(pgraster);
+               }
+               else
+                       PG_RETURN_NULL();
+       }
+       else {
+               outdbfile = text_to_cstring(PG_GETARG_TEXT_P(2));
+               if (!strlen(outdbfile)) {
+                       elog(NOTICE, "Out-db raster file not provided. Returning original raster");
+                       if (pgraster != NULL) {
+                               rt_raster_destroy(raster);
+                               PG_RETURN_POINTER(pgraster);
+                       }
+                       else
+                               PG_RETURN_NULL();
+               }
+       }
+
+       /* outdb band index (3) */
+       if (!PG_ARGISNULL(3)) {
+               ArrayType *array;
+               Oid etype;
+               Datum *e;
+               bool *nulls;
+
+               int16 typlen;
+               bool typbyval;
+               char typalign;
+
+               allbands = FALSE;
+
+               array = PG_GETARG_ARRAYTYPE_P(3);
+               etype = ARR_ELEMTYPE(array);
+               get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
+
+               switch (etype) {
+                       case INT2OID:
+                       case INT4OID:
+                               break;
+                       default:
+                               elog(ERROR, "RASTER_addBandOutDB: Invalid data type for band indexes");
+                               if (pgraster != NULL) {
+                                       rt_raster_destroy(raster);
+                                       PG_FREE_IF_COPY(pgraster, 0);
+                               }
+                               PG_RETURN_NULL();
+                               break;
+               }
+
+               deconstruct_array(array, etype, typlen, typbyval, typalign, &e, &nulls, &numsrcnband);
+
+               srcnband = palloc(sizeof(int) * numsrcnband);
+               if (srcnband == NULL) {
+                       elog(ERROR, "RASTER_addBandOutDB: Unable to allocate memory for band indexes");
+                       if (pgraster != NULL) {
+                               rt_raster_destroy(raster);
+                               PG_FREE_IF_COPY(pgraster, 0);
+                       }
+                       PG_RETURN_NULL();
+               }
+
+               for (i = 0, j = 0; i < numsrcnband; i++) {
+                       if (nulls[i]) continue;
+
+                       switch (etype) {
+                               case INT2OID:
+                                       srcnband[j] = DatumGetInt16(e[i]);
+                                       break;
+                               case INT4OID:
+                                       srcnband[j] = DatumGetInt32(e[i]);
+                                       break;
+                       }
+                       j++;
+               }
+
+               if (j < numsrcnband) {
+                       srcnband = repalloc(srcnband, sizeof(int) * j);
+                       if (srcnband == NULL) {
+                               elog(ERROR, "RASTER_addBandOutDB: Unable to reallocate memory for band indexes");
+                               if (pgraster != NULL) {
+                                       rt_raster_destroy(raster);
+                                       PG_FREE_IF_COPY(pgraster, 0);
+                               }
+                               PG_RETURN_NULL();
+                       }
+
+                       numsrcnband = j;
+               }
+       }
+       else
+               allbands = TRUE;
+
+       /* nodataval (4) */
+       if (!PG_ARGISNULL(4)) {
+               hasnodata = TRUE;
+               nodataval = PG_GETARG_FLOAT8(4);
+       }
+       else
+               hasnodata = FALSE;
+
+       /* validate input */
+
+       /* make sure dstnband is valid */
+       if (raster != NULL) {
+               numbands = rt_raster_get_num_bands(raster);
+               if (!appendband) {
+                       if (dstnband < 1) {
+                               elog(NOTICE, "Invalid band index %d for adding bands. Using band index 1", dstnband);
+                               dstnband = 1;
+                       }
+                       else if (dstnband > numbands) {
+                               elog(NOTICE, "Invalid band index %d for adding bands. Using band index %d", dstnband, numbands);
+                               dstnband = numbands + 1; 
+                       }
+               }
+               else
+                       dstnband = numbands + 1; 
+       }
+
+       /* open outdb raster file */
+       rt_util_gdal_register_all();
+       hdsOut = GDALOpenShared(outdbfile, GA_ReadOnly);
+       if (hdsOut == NULL) {
+               elog(ERROR, "RASTER_addBandOutDB: Could not open out-db file with GDAL");
+               if (pgraster != NULL) {
+                       rt_raster_destroy(raster);
+                       PG_FREE_IF_COPY(pgraster, 0);
+               }
+               PG_RETURN_NULL();
+       }
+
+       /* get offline raster's geotransform */
+       if (GDALGetGeoTransform(hdsOut, ogt) != CE_None) {
+               ogt[0] = 0;
+               ogt[1] = 1;
+               ogt[2] = 0;
+               ogt[3] = 0;
+               ogt[4] = 0;
+               ogt[5] = -1;
+       }
+
+       /* raster doesn't exist, create it now */
+       if (raster == NULL) {
+               raster = rt_raster_new(GDALGetRasterXSize(hdsOut), GDALGetRasterYSize(hdsOut));
+               if (rt_raster_is_empty(raster)) {
+                       elog(ERROR, "RASTER_addBandOutDB: Could not create new raster");
+                       PG_RETURN_NULL();
+               }
+               rt_raster_set_geotransform_matrix(raster, ogt);
+               rt_raster_get_geotransform_matrix(raster, gt);
+
+               if (rt_util_gdal_sr_auth_info(hdsOut, &authname, &authcode) == ES_NONE) {
+                       if (
+                               authname != NULL &&
+                               strcmp(authname, "EPSG") == 0 &&
+                               authcode != NULL
+                       ) {
+                               rt_raster_set_srid(raster, atoi(authcode));
+                       }
+                       else
+                               elog(INFO, "Unknown SRS auth name and code from out-db file. Defaulting SRID of new raster to %d", SRID_UNKNOWN);
+               }
+               else
+                       elog(INFO, "Unable to get SRS auth name and code from out-db file. Defaulting SRID of new raster to %d", SRID_UNKNOWN);
+       }
+
+       /* some raster info */
+       width = rt_raster_get_width(raster);
+       height = rt_raster_get_width(raster);
+
+       /* are rasters aligned? */
+       _rast = rt_raster_new(1, 1);
+       rt_raster_set_geotransform_matrix(_rast, ogt);
+       rt_raster_set_srid(_rast, rt_raster_get_srid(raster));
+       err = rt_raster_same_alignment(raster, _rast, &aligned, NULL);
+       rt_raster_destroy(_rast);
+
+       if (err != ES_NONE) {
+               elog(ERROR, "RASTER_addBandOutDB: Could not test alignment of out-db file");
+               GDALClose(hdsOut);
+               if (raster != NULL)
+                       rt_raster_destroy(raster);
+               if (pgraster != NULL)
+                       PG_FREE_IF_COPY(pgraster, 0);
+               return ES_ERROR;
+       }
+       else if (!aligned)
+               elog(WARNING, "The in-db representation of the out-db raster is not aligned. Band data may be incorrect");
+
+       numbands = GDALGetRasterCount(hdsOut);
+
+       /* build up srcnband */
+       if (allbands) {
+               numsrcnband = numbands;
+               srcnband = palloc(sizeof(int) * numsrcnband);
+               if (srcnband == NULL) {
+                       elog(ERROR, "RASTER_addBandOutDB: Unable to allocate memory for band indexes");
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_FREE_IF_COPY(pgraster, 0);
+                       PG_RETURN_NULL();
+               }
+
+               for (i = 0, j = 1; i < numsrcnband; i++, j++)
+                       srcnband[i] = j;
+       }
+
+       /* check band properties and add band */
+       for (i = 0, j = dstnband - 1; i < numsrcnband; i++, j++) {
+               /* valid index? */
+               if (srcnband[i] < 1 || srcnband[i] > numbands) {
+                       elog(NOTICE, "Out-db file does not have a band at index %d. Returning original raster", srcnband[i]);
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_RETURN_POINTER(pgraster);
+                       else
+                               PG_RETURN_NULL();
+               }
+
+               /* get outdb band */
+               hbandOut = NULL;
+               hbandOut = GDALGetRasterBand(hdsOut, srcnband[i]);
+               if (NULL == hbandOut) {
+                       elog(ERROR, "RASTER_addBandOutDB: Unable to get band %d from GDAL dataset", srcnband[i]);
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_FREE_IF_COPY(pgraster, 0);
+                       PG_RETURN_NULL();
+               }
+
+               /* supported pixel type */
+               gdpixtype = GDALGetRasterDataType(hbandOut);
+               pt = rt_util_gdal_datatype_to_pixtype(gdpixtype);
+               if (pt == PT_END) {
+                       elog(NOTICE, "Pixel type %s of band %d from GDAL dataset is not supported. Returning original raster", GDALGetDataTypeName(gdpixtype), srcnband[i]);
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_RETURN_POINTER(pgraster);
+                       else
+                               PG_RETURN_NULL();
+               }
+
+               /* use out-db band's nodata value if nodataval not already set */
+               if (!hasnodata)
+                       nodataval = GDALGetRasterNoDataValue(hbandOut, &hasnodata);
+
+               /* add band */
+               band = rt_band_new_offline(
+                       width, height,
+                       pt,
+                       hasnodata, nodataval,
+                       srcnband[i] - 1, outdbfile
+               );
+               if (band == NULL) {
+                       elog(ERROR, "RASTER_addBandOutDB: Unable to create new out-db band");
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_FREE_IF_COPY(pgraster, 0);
+                       PG_RETURN_NULL();
+               }
+
+               if (rt_raster_add_band(raster, band, j) < 0) {
+                       elog(ERROR, "RASTER_addBandOutDB: Unable to add new out-db band to raster");
+                       GDALClose(hdsOut);
+                       if (raster != NULL)
+                               rt_raster_destroy(raster);
+                       if (pgraster != NULL)
+                               PG_FREE_IF_COPY(pgraster, 0);
+                       PG_RETURN_NULL();
+               }
+       }
+
+       pgrtn = rt_raster_serialize(raster);
+       rt_raster_destroy(raster);
+       if (pgraster != NULL)
+               PG_FREE_IF_COPY(pgraster, 0);
+       if (!pgrtn)
+               PG_RETURN_NULL();
+
+       SET_VARSIZE(pgrtn, pgrtn->size);
+       PG_RETURN_POINTER(pgrtn);
+}
+
 /**
  * Break up a raster into smaller tiles. SRF function
  */
index fd6e8bd849b870bb92d43876109b525ce154065f..184f10133cd77b88841fc6d1cc1e62d7c93f44da 100644 (file)
@@ -303,6 +303,26 @@ CREATE OR REPLACE FUNCTION st_addband(
        AS 'MODULE_PATHNAME', 'RASTER_addBandRasterArray'
        LANGUAGE 'c' IMMUTABLE;
 
+CREATE OR REPLACE FUNCTION st_addband(
+       rast raster,
+       index int,
+       outdbfile text, outdbindex int[],
+       nodataval double precision DEFAULT NULL
+)
+       RETURNS raster
+       AS 'MODULE_PATHNAME', 'RASTER_addBandOutDB'
+       LANGUAGE 'c' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION st_addband(
+       rast raster,
+       outdbfile text, outdbindex int[],
+       index int DEFAULT NULL,
+       nodataval double precision DEFAULT NULL
+)
+       RETURNS raster
+       AS $$ SELECT ST_AddBand($1, $4, $2, $3, $5) $$
+       LANGUAGE 'sql' IMMUTABLE;
+
 -----------------------------------------------------------------------
 -- Constructor ST_Band
 -----------------------------------------------------------------------
diff --git a/raster/test/regress/rt_addband-post.pl b/raster/test/regress/rt_addband-post.pl
new file mode 100644 (file)
index 0000000..a48c932
--- /dev/null
@@ -0,0 +1,8 @@
+use File::Basename;
+use Cwd 'abs_path';
+
+my $REGDIR = abs_path(dirname($0));
+my $RASTERDIR = abs_path($REGDIR . "/../raster/test/regress");
+
+unlink $RASTERDIR . '/' . $TEST . '-pre.sql';
+unlink $RASTERDIR . '/' . $TEST . '-post.sql';
diff --git a/raster/test/regress/rt_addband-pre.pl b/raster/test/regress/rt_addband-pre.pl
new file mode 100644 (file)
index 0000000..8a05dd3
--- /dev/null
@@ -0,0 +1,54 @@
+use File::Basename;
+use Cwd 'abs_path';
+
+my $REGDIR = abs_path(dirname($0));
+my $RASTERDIR = abs_path($REGDIR . "/../raster/test/regress");
+my $FILERASTER = $RASTERDIR . "/loader/testraster.tif";
+
+my $sql = <<"END";
+DROP TABLE IF EXISTS raster_outdb_template;
+CREATE TABLE raster_outdb_template AS
+SELECT
+       1 AS rid,
+       ST_AddBand(
+               ST_MakeEmptyRaster(90, 90, 0., 0., 1, -1, 0, 0, 0),
+               1, '$FILERASTER'::text, NULL::int[]
+       ) AS rast
+UNION ALL
+SELECT
+       2 AS rid,
+       ST_AddBand(
+               ST_MakeEmptyRaster(90, 90, 0., 0., 1, -1, 0, 0, 0),
+               '$FILERASTER'::text, NULL::int[]
+       ) AS rast
+UNION ALL
+SELECT
+       3 AS rid,
+       ST_AddBand(
+               ST_AddBand(
+                       ST_MakeEmptyRaster(90, 90, 0., 0., 1, -1, 0, 0, 0),
+                       1, '8BUI', 1, 0
+               ),
+               '$FILERASTER'::text, ARRAY[2]::int[]
+       ) AS rast
+UNION ALL
+SELECT
+       4 AS rid,
+       ST_AddBand(
+               ST_AddBand(
+                       ST_MakeEmptyRaster(90, 90, 0., 0., 1, -1, 0, 0, 0),
+                       1, '8BUI', 1, 0
+               ),
+               '$FILERASTER'::text, ARRAY[2]::int[],
+               1,
+               255
+       ) AS rast
+END
+
+open(PRESQL, '>', $RASTERDIR . '/' . $TEST . '-pre.sql');
+print PRESQL $sql;
+close(PRESQL);
+
+open(POSTSQL, '>', $RASTERDIR . '/' . $TEST . '-post.sql');
+print POSTSQL "DROP TABLE IF EXISTS raster_outdb_template;\n";
+close(POSTSQL);
index 569305df25c1b9db3770ea09af2730dc3e4ea666..b932ef4154ea7896adb8b79651a261159cc4c3ed 100644 (file)
@@ -170,3 +170,45 @@ SELECT * FROM ST_BandMetadata(
 
 -- raster array version test
 SELECT (ST_DumpAsPolygons(newrast,3)).val As b3val FROM (SELECT ST_AddBand(NULL, array_agg(rast)) AS newrast FROM (SELECT ST_AsRaster(ST_Buffer(ST_Point(10,10), 34),200,200, '8BUI',i*30) As rast FROM generate_series(1,3) As i ) As foo ) As foofoo;
+
+-- out-db variants
+SELECT
+       1,
+       bandnum,
+       isoutdb,
+       CASE
+               WHEN isoutdb IS TRUE
+                       THEN strpos(path, 'testraster.tif') > 0
+               ELSE NULL
+       END
+FROM ST_BandMetadata((SELECT rast FROM raster_outdb_template WHERE rid = 1), ARRAY[]::int[]);
+SELECT
+       2,
+       bandnum,
+       isoutdb,
+       CASE
+               WHEN isoutdb IS TRUE
+                       THEN strpos(path, 'testraster.tif') > 0
+               ELSE NULL
+       END
+FROM ST_BandMetadata((SELECT rast FROM raster_outdb_template WHERE rid = 2), ARRAY[]::int[]);
+SELECT
+       3,
+       bandnum,
+       isoutdb,
+       CASE
+               WHEN isoutdb IS TRUE
+                       THEN strpos(path, 'testraster.tif') > 0
+               ELSE NULL
+       END
+FROM ST_BandMetadata((SELECT rast FROM raster_outdb_template WHERE rid = 3), ARRAY[]::int[]);
+SELECT
+       4,
+       bandnum,
+       isoutdb,
+       CASE
+               WHEN isoutdb IS TRUE
+                       THEN strpos(path, 'testraster.tif') > 0
+               ELSE NULL
+       END
+FROM ST_BandMetadata((SELECT rast FROM raster_outdb_template WHERE rid = 4), ARRAY[]::int[]);
index 801ce9557bb7db9620dde58ce96d66d726e0c36d..08d765db98e1f95057674bc590a2ffcded8e5f6c 100644 (file)
@@ -108,3 +108,13 @@ NOTICE:  RASTER_copyBand: Could not add band to raster. Returning original raste
 5|64BF|0|f|
 6|2BUI|0|f|
 90
+1|1|t|t
+1|2|t|t
+1|3|t|t
+2|1|t|t
+2|2|t|t
+2|3|t|t
+3|1|f|
+3|2|t|t
+4|1|t|t
+4|2|f|
index 30dc4f887b1ef6b25ab6b75105d89d0a5e021774..40800724d09ab72ed68b8d151f6976bc5dfca9b5 100755 (executable)
@@ -30,11 +30,11 @@ if ( @ARGV < 1 )
 # Global configuration items
 ##################################################################
 
-my $DB = "postgis_reg";
-my $REGDIR = abs_path(dirname($0));
-my $SHP2PGSQL = $REGDIR . "/../loader/shp2pgsql";
-my $PGSQL2SHP = $REGDIR . "/../loader/pgsql2shp";
-my $RASTER2PGSQL = $REGDIR . "/../raster/loader/raster2pgsql";
+our $DB = "postgis_reg";
+our $REGDIR = abs_path(dirname($0));
+our $SHP2PGSQL = $REGDIR . "/../loader/shp2pgsql";
+our $PGSQL2SHP = $REGDIR . "/../loader/pgsql2shp";
+our $RASTER2PGSQL = $REGDIR . "/../raster/loader/raster2pgsql";
 
 
 ##################################################################
@@ -493,10 +493,11 @@ sub eval_file
     my $pl;
     if ( -r $file )
     {
-        open(PL, $file);
-        $pl = <PL>;
-        close(PL);
-        eval($pl);
+        #open(PL, $file);
+        #$pl = <PL>;
+        #close(PL);
+        #eval($pl);
+                               do $file;
     }
 }