- #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 *
- #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
<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>
</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>
<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
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
-- 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>
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?
*/
_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;
}
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;
int32_t idx;
rt_pixtype pt = PT_END;
uint32_t ptlen = 0;
- uint32_t hasnodata = 0;
+ int hasnodata = 0;
double nodataval;
int x;
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);
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 */
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?
*/
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 */
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
*/
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
-----------------------------------------------------------------------
--- /dev/null
+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';
--- /dev/null
+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);
-- 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[]);
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|
# 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";
##################################################################
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;
}
}