<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
- <funcdef>record <function>ST_BandMetaData</function></funcdef>
- <paramdef><type>raster </type><parameter>rast</parameter></paramdef>
- <paramdef choice="opt"><type>integer </type><parameter>bandnum=1</parameter></paramdef>
+ <funcdef>(1) record <function>ST_BandMetaData</function></funcdef>
+ <paramdef><type>raster </type><parameter>rast</parameter></paramdef>
+ <paramdef choice="opt"><type>integer </type><parameter>band=1</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>(2) record <function>ST_BandMetaData</function></funcdef>
+ <paramdef><type>raster </type><parameter>rast</parameter></paramdef>
+ <paramdef choice="opt"><type>integer[] </type><parameter>band</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsection>
<title>Description</title>
- <para>Returns basic meta data about a raster band. Columns returned
- pixeltype | nodatavalue | isoutdb | path.
+ <para>Returns basic meta data about a raster band. Columns returned: pixeltype, nodatavalue, isoutdb, path, outdbbandnum.
</para>
<note>
- <para>
- If raster contains no bands then an error is thrown.
- </para>
+ <para>
+ If raster contains no bands then an error is thrown.
+ </para>
+ </note>
+
+ <note>
+ <para>
+ If band has no NODATA value, nodatavalue are NULL.
+ </para>
</note>
<note>
- <para>
- If band has no NODATA value, nodatavalue will be NULL.
- </para>
+ <para>
+ If isoutdb is False, path and outdbbandnum are NULL.
+ </para>
</note>
</refsection>
<refsection>
- <title>Examples</title>
+ <title>Examples: Variant 1</title>
- <programlisting>SELECT rid, (foo.md).*
- FROM (SELECT rid, ST_BandMetaData(rast,1) As md
-FROM dummy_rast WHERE rid=2) As foo;
+ <programlisting>
+WITH foo AS (
+ SELECT
+ ST_AddBand(NULL::raster, '/home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif', NULL::int[]) AS rast
+)
+SELECT
+ *
+FROM ST_BandMetadata(
+ (SELECT rast FROM foo),
+ ARRAY[1,3,2]::int[]
+);
- rid | pixeltype | nodatavalue | isoutdb | path
------+-----------+----------------+-------------+---------+------
- 2 | 8BUI | 0 | f |
+ bandnum | pixeltype | nodatavalue | isoutdb | path | outdbbandnum
+---------+-----------+-------------+---------+--------------------------------------------------------------------------------+--------------
+ 1 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1
+ 3 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 3
+ 2 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 2
</programlisting>
+
+ </refsection>
+
+ <refsection>
+ <title>Examples: Variant 2</title>
+
+ <programlisting>
+SELECT
+ rid,
+ (foo.md).*
+FROM (
+ SELECT
+ rid,
+ ST_BandMetaData(rast, 1) AS md
+ FROM dummy_rast
+ WHERE rid=2
+) As foo;
+
+ rid | pixeltype | nodatavalue | isoutdb | path | outdbbandnum
+-----+-----------+---- --------+---------+------+--------------
+ 2 | 8BUI | 0 | f | |
+ </programlisting>
+
</refsection>
<!-- Optionally add a "See Also" section -->
linkend="RT_ST_BandIsNoData"/></para>
</refsection>
</refentry>
+
+ <refentry id="RT_ST_SetBandPath">
+ <refnamediv>
+ <refname>ST_SetBandPath</refname>
+ <refpurpose>Update the external path and band number of an out-db band</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>raster <function>ST_SetBandPath</function></funcdef>
+ <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+ <paramdef><type>integer </type> <parameter>band</parameter></paramdef>
+ <paramdef><type>text </type> <parameter>outdbpath</parameter></paramdef>
+ <paramdef><type>integer </type> <parameter>outdbindex</parameter></paramdef>
+ <paramdef choice="opt"><type>boolean </type> <parameter>force=false</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Updates an out-db band's external raster file path and external band number.</para>
+
+ <note>
+ <para>
+ If <varname>force</varname> is set to true, no tests are done to ensure compatibility (e.g. alignment, pixel support) between the external raster file and the PostGIS raster. This mode is intended for file system changes where the external raster resides.
+ </para>
+ </note>
+
+ <note>
+ <para>
+ Internally, this method replaces the PostGIS raster's band at index <varname>band</varname> with a new band instead of updating the existing path information.
+ </para>
+ </note>
+
+ <para>Availability: 2.5.0</para>
+ </refsection>
+
+ <refsection>
+ <title>Examples</title>
+ <programlisting>
+WITH foo AS (
+ SELECT
+ ST_AddBand(NULL::raster, '/home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif', NULL::int[]) AS rast
+)
+SELECT
+ 1 AS query,
+ *
+FROM ST_BandMetadata(
+ (SELECT rast FROM foo),
+ ARRAY[1,3,2]::int[]
+)
+UNION ALL
+SELECT
+ 2,
+ *
+FROM ST_BandMetadata(
+ (
+ SELECT
+ <emphasis role="strong">ST_SetBandPath(
+ rast,
+ 2,
+ '/home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected2.tif',
+ 1
+ )</emphasis> AS rast
+ FROM foo
+ ),
+ ARRAY[1,3,2]::int[]
+)
+ORDER BY 1, 2;
+
+ query | bandnum | pixeltype | nodatavalue | isoutdb | path | outdbbandnum
+-------+---------+-----------+-------------+---------+---------------------------------------------------------------------------------+--------------
+ 1 | 1 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1
+ 1 | 2 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 2
+ 1 | 3 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 3
+ 2 | 1 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1
+<emphasis role="strong"> 2 | 2 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected2.tif | 1</emphasis>
+ 2 | 3 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 3
+ </programlisting>
+ </refsection>
+
+ <refsection>
+ <title>See Also</title>
+ <para>
+ <xref linkend="RT_ST_BandMetaData" />,
+ <xref linkend="RT_ST_SetBandIndex" />
+ </para>
+ </refsection>
+
+ </refentry>
+
+ <refentry id="RT_ST_SetBandIndex">
+ <refnamediv>
+ <refname>ST_SetBandIndex</refname>
+ <refpurpose>Update the external band number of an out-db band</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>raster <function>ST_SetBandIndex</function></funcdef>
+ <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+ <paramdef><type>integer </type> <parameter>band</parameter></paramdef>
+ <paramdef><type>integer </type> <parameter>outdbindex</parameter></paramdef>
+ <paramdef choice="opt"><type>boolean </type> <parameter>force=false</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Updates an out-db band's external band number. This does not touch the external raster file associated with the out-db band</para>
+
+ <note>
+ <para>
+ If <varname>force</varname> is set to true, no tests are done to ensure compatibility (e.g. alignment, pixel support) between the external raster file and the PostGIS raster. This mode is intended for where bands are moved around in the external raster file.
+ </para>
+ </note>
+
+ <note>
+ <para>
+ Internally, this method replaces the PostGIS raster's band at index <varname>band</varname> with a new band instead of updating the existing path information.
+ </para>
+ </note>
+
+ <para>Availability: 2.5.0</para>
+ </refsection>
+
+ <refsection>
+ <title>Examples</title>
+ <programlisting>
+WITH foo AS (
+ SELECT
+ ST_AddBand(NULL::raster, '/home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif', NULL::int[]) AS rast
+)
+SELECT
+ 1 AS query,
+ *
+FROM ST_BandMetadata(
+ (SELECT rast FROM foo),
+ ARRAY[1,3,2]::int[]
+)
+UNION ALL
+SELECT
+ 2,
+ *
+FROM ST_BandMetadata(
+ (
+ SELECT
+ <emphasis role="strong">ST_SetBandIndex(
+ rast,
+ 2,
+ 1
+ )</emphasis> AS rast
+ FROM foo
+ ),
+ ARRAY[1,3,2]::int[]
+)
+ORDER BY 1, 2;
+
+ query | bandnum | pixeltype | nodatavalue | isoutdb | path | outdbbandnum
+-------+---------+-----------+-------------+---------+---------------------------------------------------------------------------------+--------------
+ 1 | 1 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1
+ 1 | 2 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 2
+ 1 | 3 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 3
+ 2 | 1 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1
+<emphasis role="strong"> 2 | 2 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 1</emphasis>
+ 2 | 3 | 8BUI | | t | /home/pele/devel/geo/postgis-git/raster/test/regress/loader/Projected.tif | 3
+ </programlisting>
+ </refsection>
+
+ <refsection>
+ <title>See Also</title>
+ <para>
+ <xref linkend="RT_ST_BandMetaData" />,
+ <xref linkend="RT_ST_SetBandPath" />
+ </para>
+ </refsection>
+
+ </refentry>
+
</sect1>
<sect1 id="RasterBand_Stats">
uint8_t bandNum, const char* path
);
+/**
+ * Create an out-db rt_band from path
+ *
+ * @param width : number of pixel columns
+ * @param height : number of pixel rows
+ * @param hasnodata : indicates if the band has nodata value
+ * @param nodataval : the nodata value, will be appropriately
+ * @param bandNum : 1-based band number in the external file
+ * to associate this band with.
+ * @param path : NULL-terminated path string pointing to the file
+ * containing band data. The string will NOT be
+ * copied, ownership is left to caller which is
+ * responsible to keep it allocated for the whole
+ * lifetime of the returned rt_band.
+ * @param force : if True, ignore all validation checks
+ *
+ * @return an rt_band, or 0 on failure
+ */
+rt_band
+rt_band_new_offline_from_path(
+ uint16_t width,
+ uint16_t height,
+ int hasnodata,
+ double nodataval,
+ uint8_t bandNum,
+ const char* path,
+ int force
+);
+
/**
* Create a new band duplicated from source band. Memory is allocated
* for band path (if band is offline) or band data (if band is online).
* WKTRaster - Raster Types for PostGIS
* http://trac.osgeo.org/postgis/wiki/WKTRaster
*
+ * Copyright (C) 2018 Bborie Park <dustymugs@gmail.com>
* Copyright (C) 2011-2013 Regents of the University of California
* <bkpark@ucdavis.edu>
* Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
return band;
}
+/**
+ * Create an out-db rt_band from path
+ *
+ * @param width : number of pixel columns
+ * @param height : number of pixel rows
+ * @param hasnodata : indicates if the band has nodata value
+ * @param nodataval : the nodata value, will be appropriately
+ * @param bandNum : 1-based band number in the external file
+ * to associate this band with.
+ * @param path : NULL-terminated path string pointing to the file
+ * containing band data. The string will NOT be
+ * copied, ownership is left to caller which is
+ * responsible to keep it allocated for the whole
+ * lifetime of the returned rt_band.
+ * @param force : if True, ignore all validation checks
+ *
+ * @return an rt_band, or 0 on failure
+ */
+rt_band
+rt_band_new_offline_from_path(
+ uint16_t width,
+ uint16_t height,
+ int hasnodata,
+ double nodataval,
+ uint8_t bandNum,
+ const char* path,
+ int force
+) {
+ GDALDatasetH hdsSrc = NULL;
+ int nband = 0;
+ GDALRasterBandH hbandSrc = NULL;
+
+ GDALDataType gdpixtype;
+ rt_pixtype pt = PT_END;
+
+ /* open outdb raster file */
+ rt_util_gdal_register_all(0);
+ hdsSrc = rt_util_gdal_open(path, GA_ReadOnly, 1);
+ if (hdsSrc == NULL && !force) {
+ rterror("rt_band_new_offline_from_path: Cannot open offline raster: %s", path);
+ return NULL;
+ }
+
+ nband = GDALGetRasterCount(hdsSrc);
+ if (!nband && !force) {
+ rterror("rt_band_new_offline_from_path: No bands found in offline raster: %s", path);
+ GDALClose(hdsSrc);
+ return NULL;
+ }
+ /* bandNum is 1-based */
+ else if (bandNum > nband && !force) {
+ rterror(
+ "rt_band_new_offline_from_path: Specified band %d not found in offline raster: %s",
+ bandNum,
+ path
+ );
+ GDALClose(hdsSrc);
+ return NULL;
+ }
+
+ hbandSrc = GDALGetRasterBand(hdsSrc, bandNum);
+ if (hbandSrc == NULL && !force) {
+ rterror(
+ "rt_band_new_offline_from_path: Cannot get band %d from GDAL dataset",
+ bandNum
+ );
+ GDALClose(hdsSrc);
+ return NULL;
+ }
+
+ gdpixtype = GDALGetRasterDataType(hbandSrc);
+ pt = rt_util_gdal_datatype_to_pixtype(gdpixtype);
+ if (pt == PT_END && !force) {
+ rterror(
+ "rt_band_new_offline_from_path: Unsupported pixel type %s of band %d from GDAL dataset",
+ GDALGetDataTypeName(gdpixtype),
+ bandNum
+ );
+ GDALClose(hdsSrc);
+ return NULL;
+ }
+
+ /* use out-db band's nodata value if nodataval not already set */
+ if (!hasnodata)
+ nodataval = GDALGetRasterNoDataValue(hbandSrc, &hasnodata);
+
+ GDALClose(hdsSrc);
+
+ return rt_band_new_offline(
+ width, height,
+ pt,
+ hasnodata, nodataval,
+ bandNum - 1, path
+ );
+}
+
/**
* Create a new band duplicated from source band. Memory is allocated
* for band path (if band is offline) or band data (if band is online).
int
rt_band_is_offline(rt_band band) {
-
- assert(NULL != band);
-
-
- return band->offline ? 1 : 0;
+ assert(NULL != band);
+ return band->offline ? 1 : 0;
}
/**
int nband = 0;
VRTDatasetH hdsDst = NULL;
VRTSourcedRasterBandH hbandDst = NULL;
- double gt[6] = {0.};
double ogt[6] = {0};
double offset[2] = {0};
rt_util_gdal_register_all(0);
hdsSrc = rt_util_gdal_open(band->data.offline.path, GA_ReadOnly, 1);
- /*
- hdsSrc = rt_util_gdal_open(band->data.offline.path, GA_ReadOnly, 0);
- */
if (hdsSrc == NULL) {
rterror("rt_band_load_offline_data: Cannot open offline raster: %s", band->data.offline.path);
return ES_ERROR;
return ES_ERROR;
}
- /* get raster's geotransform */
- rt_raster_get_geotransform_matrix(band->raster, gt);
- RASTER_DEBUGF(3, "Raster geotransform (%f, %f, %f, %f, %f, %f)",
- gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
-
/* get offline raster's geotransform */
if (GDALGetGeoTransform(hdsSrc, ogt) != CE_None) {
RASTER_DEBUG(4, "Using default geotransform matrix (0, 1, 0, 0, 0, -1)");
/* create VRT dataset */
hdsDst = VRTCreate(band->width, band->height);
- GDALSetGeoTransform(hdsDst, gt);
+ GDALSetGeoTransform(hdsDst, ogt);
/*
GDALSetDescription(hdsDst, "/tmp/offline.vrt");
*/
#include <postgres.h>
#include <fmgr.h>
#include <funcapi.h>
-#include <utils/builtins.h>
+#include <utils/builtins.h> /* for text_to_cstring() */
#include "utils/lsyscache.h" /* for get_typlenbyvalalign */
#include "utils/array.h" /* for ArrayType */
#include "catalog/pg_type.h" /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
/* Set all the properties of a raster band */
Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS);
Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS);
+Datum RASTER_setBandPath(PG_FUNCTION_ARGS);
+Datum RASTER_setBandIndex(PG_FUNCTION_ARGS);
/**
* Return pixel type of the specified band of raster.
double nodataval;
bool isoutdb;
char *bandpath;
+ uint8_t extbandnum;
};
struct bandmetadata *bmd = NULL;
struct bandmetadata *bmd2 = NULL;
uint32_t numBands;
uint32_t idx = 1;
uint32_t *bandNums = NULL;
- const char *tmp = NULL;
+ const char *chartmp = NULL;
+ size_t charlen;
+ uint8_t extbandnum;
POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
bmd[i].bandnum = bandNums[i];
/* pixeltype */
- tmp = rt_pixtype_name(rt_band_get_pixtype(band));
- bmd[i].pixeltype = palloc(sizeof(char) * (strlen(tmp) + 1));
- strncpy(bmd[i].pixeltype, tmp, strlen(tmp) + 1);
+ chartmp = rt_pixtype_name(rt_band_get_pixtype(band));
+ charlen = strlen(chartmp) + 1;
+ bmd[i].pixeltype = palloc(sizeof(char) * charlen);
+ strncpy(bmd[i].pixeltype, chartmp, charlen);
/* hasnodatavalue */
if (rt_band_get_hasnodata_flag(band))
else
bmd[i].nodataval = 0;
- /* path */
- tmp = rt_band_get_ext_path(band);
- if (tmp) {
- bmd[i].bandpath = palloc(sizeof(char) * (strlen(tmp) + 1));
- strncpy(bmd[i].bandpath, tmp, strlen(tmp) + 1);
+ /* out-db path */
+ chartmp = rt_band_get_ext_path(band);
+ if (chartmp) {
+ charlen = strlen(chartmp) + 1;
+ bmd[i].bandpath = palloc(sizeof(char) * charlen);
+ strncpy(bmd[i].bandpath, chartmp, charlen);
}
else
bmd[i].bandpath = NULL;
/* isoutdb */
bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
+ /* out-db bandnum */
+ if (rt_band_get_ext_band_num(band, &extbandnum) == ES_NONE)
+ bmd[i].extbandnum = extbandnum + 1;
+ else
+ bmd[i].extbandnum = 0;
+
rt_band_destroy(band);
}
/* do when there is more left to send */
if (call_cntr < max_calls) {
- int values_length = 5;
+ int values_length = 6;
Datum values[values_length];
bool nulls[values_length];
nulls[2] = TRUE;
values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
- if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath))
+ if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath)) {
values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
- else
+ values[5] = UInt32GetDatum(bmd2[call_cntr].extbandnum);
+ }
+ else {
nulls[4] = TRUE;
+ nulls[5] = TRUE;
+ }
/* build a tuple */
tuple = heap_form_tuple(tupdesc, values, nulls);
PG_RETURN_POINTER(pgrtn);
}
+/**
+ * Set flag indicating that the entire band is NODATA
+ */
PG_FUNCTION_INFO_V1(RASTER_setBandIsNoData);
Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
{
PG_RETURN_POINTER(pgrtn);
}
+/**
+ * Set the path value of an out-db band
+ */
+PG_FUNCTION_INFO_V1(RASTER_setBandPath);
+Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
+{
+ rt_pgraster *pgraster = NULL;
+ rt_pgraster *pgrtn = NULL;
+ rt_raster raster = NULL;
+ rt_band band = NULL;
+ int32_t bandindex = 1;
+ const char *outdbpathchar = NULL;
+ int32_t outdbindex = 1;
+ bool forceset = FALSE;
+ rt_band newband = NULL;
+
+ int hasnodata;
+ double nodataval = 0.;
+
+ if (PG_ARGISNULL(0))
+ PG_RETURN_NULL();
+ pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+ raster = rt_raster_deserialize(pgraster, FALSE);
+ if (!raster) {
+ PG_FREE_IF_COPY(pgraster, 0);
+ elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
+ PG_RETURN_NULL();
+ }
+
+ /* Check index is not NULL or smaller than 1 */
+ if (!PG_ARGISNULL(1))
+ bandindex = PG_GETARG_INT32(1);
+
+ if (bandindex < 1)
+ elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
+ else {
+ /* Fetch requested band */
+ band = rt_raster_get_band(raster, bandindex - 1);
+
+ if (!band)
+ elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
+ else if (!rt_band_is_offline(band)) {
+ elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
+ }
+ else {
+ /* outdbpath */
+ if (!PG_ARGISNULL(2))
+ outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
+ else
+ outdbpathchar = rt_band_get_ext_path(band);
+
+ /* outdbindex, is 1-based */
+ if (!PG_ARGISNULL(3))
+ outdbindex = PG_GETARG_INT32(3);
+
+ /* force */
+ if (!PG_ARGISNULL(4))
+ forceset = PG_GETARG_BOOL(4);
+
+ hasnodata = rt_band_get_hasnodata_flag(band);
+ if (hasnodata)
+ rt_band_get_nodata(band, &nodataval);
+
+ newband = rt_band_new_offline_from_path(
+ rt_raster_get_width(raster),
+ rt_raster_get_height(raster),
+ hasnodata,
+ nodataval,
+ outdbindex,
+ outdbpathchar,
+ forceset
+ );
+
+ if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
+ elog(NOTICE, "Cannot change path of band. Returning original raster");
+ else
+ /* old band is in the variable band */
+ rt_band_destroy(band);
+ }
+ }
+
+ /* Serialize raster again */
+ pgrtn = rt_raster_serialize(raster);
+ rt_raster_destroy(raster);
+ PG_FREE_IF_COPY(pgraster, 0);
+ if (!pgrtn) PG_RETURN_NULL();
+
+ SET_VARSIZE(pgrtn, pgrtn->size);
+ PG_RETURN_POINTER(pgrtn);
+}
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;
raster = rt_raster_deserialize(pgraster, FALSE);
if (!raster) {
PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not deserialize destination raster");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot deserialize destination raster");
PG_RETURN_NULL();
}
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
}
- elog(ERROR, "RASTER_addBandOutDB: Could not allocate memory for band indexes");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot allocate memory for band indexes");
PG_RETURN_NULL();
}
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
}
- elog(ERROR, "RASTER_addBandOutDB: Could not reallocate memory for band indexes");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot reallocate memory for band indexes");
PG_RETURN_NULL();
}
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
}
- elog(ERROR, "RASTER_addBandOutDB: Could not open out-db file with GDAL");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot open out-db file with GDAL");
PG_RETURN_NULL();
}
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");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot 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 (
elog(INFO, "Unknown SRS auth name and code from out-db file. Defaulting SRID of new raster to %d", SRID_UNKNOWN);
}
else
- elog(INFO, "Could not get SRS auth name and code from out-db file. Defaulting SRID of new raster to %d", SRID_UNKNOWN);
+ elog(INFO, "Cannot get SRS auth name and code from out-db file. Defaulting SRID of new raster to %d", SRID_UNKNOWN);
}
/* some raster info */
rt_raster_destroy(raster);
if (pgraster != NULL)
PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not test alignment of out-db file");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot test alignment of out-db file");
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;
+ numsrcnband = GDALGetRasterCount(hdsOut);
+ GDALClose(hdsOut);
+
srcnband = palloc(sizeof(int) * numsrcnband);
if (srcnband == NULL) {
- GDALClose(hdsOut);
if (raster != NULL)
rt_raster_destroy(raster);
if (pgraster != NULL)
PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not allocate memory for band indexes");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot allocate memory for band indexes");
PG_RETURN_NULL();
}
for (i = 0, j = 1; i < numsrcnband; i++, j++)
srcnband[i] = j;
}
+ else
+ GDALClose(hdsOut);
- /* check band properties and add band */
+ /* 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) {
- GDALClose(hdsOut);
- if (raster != NULL)
- rt_raster_destroy(raster);
- if (pgraster != NULL)
- PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not get band %d from GDAL dataset", srcnband[i]);
- 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(
+ /* create band with path */
+ band = rt_band_new_offline_from_path(
width, height,
- pt,
hasnodata, nodataval,
- srcnband[i] - 1, outdbfile
+ srcnband[i], outdbfile,
+ FALSE
);
if (band == NULL) {
- GDALClose(hdsOut);
if (raster != NULL)
rt_raster_destroy(raster);
if (pgraster != NULL)
PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not create new out-db band");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot create new out-db band");
PG_RETURN_NULL();
}
+ /* add band */
if (rt_raster_add_band(raster, band, j) < 0) {
- GDALClose(hdsOut);
if (raster != NULL)
rt_raster_destroy(raster);
if (pgraster != NULL)
PG_FREE_IF_COPY(pgraster, 0);
- elog(ERROR, "RASTER_addBandOutDB: Could not add new out-db band to raster");
+ elog(ERROR, "RASTER_addBandOutDB: Cannot add new out-db band to raster");
PG_RETURN_NULL();
}
}
OUT pixeltype text,
OUT nodatavalue double precision,
OUT isoutdb boolean,
- OUT path text
+ OUT path text,
+ OUT outdbbandnum integer
)
AS 'MODULE_PATHNAME','RASTER_bandmetadata'
LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
OUT pixeltype text,
OUT nodatavalue double precision,
OUT isoutdb boolean,
- OUT path text
+ OUT path text,
+ OUT outdbbandnum integer
)
- AS $$ SELECT pixeltype, nodatavalue, isoutdb, path FROM @extschema@.ST_BandMetaData($1, ARRAY[$2]::int[]) LIMIT 1 $$
+ AS $$ SELECT pixeltype, nodatavalue, isoutdb, path, outdbbandnum FROM @extschema@.ST_BandMetaData($1, ARRAY[$2]::int[]) LIMIT 1 $$
LANGUAGE 'sql' IMMUTABLE STRICT _PARALLEL;
-----------------------------------------------------------------------
AS 'MODULE_PATHNAME', 'RASTER_setBandIsNoData'
LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+-- This function can not be STRICT, because outdbpath can be NULL
+CREATE OR REPLACE FUNCTION st_setbandpath(rast raster, band integer, outdbpath text, outdbindex integer, force boolean DEFAULT FALSE)
+ RETURNS raster
+ AS 'MODULE_PATHNAME', 'RASTER_setBandPath'
+ LANGUAGE 'c' IMMUTABLE _PARALLEL;
+
+CREATE OR REPLACE FUNCTION st_setbandindex(rast raster, band integer, outdbindex integer, force boolean DEFAULT FALSE)
+ RETURNS raster
+ AS $$ SELECT @extschema@.ST_SetBandPath($1, $2, NULL, $3, $4) $$
+ LANGUAGE 'sql' IMMUTABLE STRICT _PARALLEL;
+
-----------------------------------------------------------------------
-- Raster Pixel Editors
-----------------------------------------------------------------------
END IF;
END;
$$;
+
+-- 2.5.0 signature changed
+DROP FUNCTION IF EXISTS st_bandmetadata(raster, int[]);
+DROP FUNCTION IF EXISTS st_bandmetadata(raster, int);
* PostGIS Raster - Raster Types for PostGIS
* http://trac.osgeo.org/postgis/wiki/WKTRaster
*
+ * Copyright (C) 2018 Bborie Park <dustymugs@gmail.com>
* Copyright (C) 2012 Regents of the University of California
* <bkpark@ucdavis.edu>
*
cu_free_raster(rast);
}
+static void test_band_new_offline_from_path() {
+ rt_band band = NULL;
+ int width = 10;
+ int height = 10;
+ char *path = "../regress/loader/testraster.tif";
+ uint8_t extband = 0;
+
+ /* offline band */
+ band = rt_band_new_offline_from_path(
+ width, height,
+ 0, 0,
+ 2, path,
+ FALSE
+ );
+ CU_ASSERT(band != NULL);
+
+ /* isoffline */
+ CU_ASSERT(rt_band_is_offline(band));
+
+ /* ext path */
+ CU_ASSERT_STRING_EQUAL(rt_band_get_ext_path(band), path);
+
+ /* ext band number */
+ CU_ASSERT_EQUAL(rt_band_get_ext_band_num(band, &extband), ES_NONE);
+ CU_ASSERT_EQUAL(extband, 1);
+
+ /* test rt_band_check_is_nodata */
+ CU_ASSERT_EQUAL(rt_band_check_is_nodata(band), FALSE);
+
+ /* dimensions */
+ CU_ASSERT_EQUAL(rt_band_get_width(band), width);
+ CU_ASSERT_EQUAL(rt_band_get_height(band), height);
+
+ rt_band_destroy(band);
+}
+
/* register tests */
void band_basics_suite_setup(void);
void band_basics_suite_setup(void)
PG_ADD_TEST(suite, test_band_pixtype_32BF);
PG_ADD_TEST(suite, test_band_pixtype_64BF);
PG_ADD_TEST(suite, test_band_get_pixel_line);
+ PG_ADD_TEST(suite, test_band_new_offline_from_path);
}
rt_neighborhood \
rt_nearestvalue \
rt_pixelofvalue \
- rt_polygon
+ rt_polygon \
+ rt_setbandpath
TEST_UTILITY = \
rt_utility \
NOTICE: RASTER_copyBand: Could not add band to raster. Returning original raster.
1234.5678
1234.567|255
-1|4BUI|0|f|
-2|8BUI|0|f|
-3|16BUI|0|f|
-4|32BUI|0|f|
-5|64BF|0|f|
-1|2BUI|0|f|
-2|4BUI|0|f|
-3|8BUI|0|f|
-4|16BUI|0|f|
-5|32BUI|0|f|
-6|64BF|0|f|
-1|4BUI|0|f|
-2|8BUI|0|f|
-3|16BUI|0|f|
-4|32BUI|0|f|
-5|64BF|0|f|
-6|2BUI|0|f|
+1|4BUI|0|f||
+2|8BUI|0|f||
+3|16BUI|0|f||
+4|32BUI|0|f||
+5|64BF|0|f||
+1|2BUI|0|f||
+2|4BUI|0|f||
+3|8BUI|0|f||
+4|16BUI|0|f||
+5|32BUI|0|f||
+6|64BF|0|f||
+1|4BUI|0|f||
+2|8BUI|0|f||
+3|16BUI|0|f||
+4|32BUI|0|f||
+5|64BF|0|f||
+6|2BUI|0|f||
90
1|1|t|t
1|2|t|t
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
ST_SetBandNoDataValue(make_test_raster(10, 10, 0, 0, 0, 0), NULL)
);
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0)
);
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 2),
2
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 3, TRUE),
3
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
4
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
6
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
ARRAY[1,2,5]
pixeltype,
round(nodatavalue::numeric, 3),
isoutdb,
- path
+ path,
+ outdbbandnum
FROM ST_BandMetaData(
make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
ARRAY[]::int[]
-8BUI||f|
-8BUI|1.000|f|
-8BUI|2.000|f|
-8BUI|3.000|f|
-8BUI|4.000|f|
+8BUI||f||
+8BUI|1.000|f||
+8BUI|2.000|f||
+8BUI|3.000|f||
+8BUI|4.000|f||
NOTICE: Invalid band index: 6. Indices must be 1-based. Returning NULL
-|||
-1|1.000|f|
-2|2.000|f|
-5|5.000|f|
-1|1.000|f|
-2|2.000|f|
-3|3.000|f|
-4|4.000|f|
-5|5.000|f|
+||||
+1|1.000|f||
+2|2.000|f||
+5|5.000|f||
+1|1.000|f||
+2|2.000|f||
+3|3.000|f||
+4|4.000|f||
+5|5.000|f||
NOTICE: value = {{{200,200,NULL},{200,200,NULL},{NULL,NULL,NULL}}}
NOTICE: pos = [0:1][1:2]={{2,2},{2,2}}
NOTICE: userargs = <NULL>
-3|(0,0,0,0,1,-1,0,0,0,0)|(,,,)|
-4|(1,-1,2,2,1,-1,0,0,0,1)|(8BUI,0,f,)|255
+3|(0,0,0,0,1,-1,0,0,0,0)|(,,,,)|
+4|(1,-1,2,2,1,-1,0,0,0,1)|(8BUI,0,f,,)|255
NOTICE: value = {{{NULL,NULL,NULL},{NULL,1,1},{NULL,1,1}}}
NOTICE: pos = [0:1][1:2]={{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{1,1,2},{1,1,2},{10,10,20}}}
NOTICE: pos = [0:1][1:2]={{2,2},{2,2}}
NOTICE: userargs = <NULL>
-NOTICE: record = (10,"(0,0,2,2,1,-1,0,0,0,1)","(32BUI,0,f,)",255)
+NOTICE: record = (10,"(0,0,2,2,1,-1,0,0,0,1)","(32BUI,0,f,,)",255)
NOTICE: value = {{{1,2,2},{10,20,20},{10,20,20}}}
NOTICE: pos = [0:1][1:2]={{1,1},{3,3}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{20,20,30},{20,20,30},{200,200,300}}}
NOTICE: pos = [0:1][1:2]={{2,2},{4,4}}
NOTICE: userargs = <NULL>
-NOTICE: record = (14,"(2,-2,2,2,1,-1,0,0,0,1)","(32BUI,0,f,)",255)
+NOTICE: record = (14,"(2,-2,2,2,1,-1,0,0,0,1)","(32BUI,0,f,,)",255)
NOTICE: value = {{{10,20,20},{100,200,200},{100,200,200}}}
NOTICE: pos = [0:1][1:2]={{1,1},{3,3}}
NOTICE: userargs = {1000}
NOTICE: value = {{{200,200,300},{200,200,300},{NULL,NULL,NULL}}}
NOTICE: pos = [0:1][1:2]={{2,2},{4,4}}
NOTICE: userargs = {1000}
-NOTICE: record = (17,"(2,-4,2,2,1,-1,0,0,0,1)","(32BUI,0,f,)",1000)
+NOTICE: record = (17,"(2,-4,2,2,1,-1,0,0,0,1)","(32BUI,0,f,,)",1000)
NOTICE: value = {{{1}},{{2}}}
NOTICE: pos = [0:2][1:2]={{1,1},{2,2},{1,1}}
NOTICE: userargs = <NULL>
-20|21|(1,-1,1,1,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|(1,-1,1,1,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: Raster provided has no bands
-20|22|(0,0,0,0,0,0,0,0,0,0)|(,,,)
+20|22|(0,0,0,0,0,0,0,0,0,0)|(,,,,)
NOTICE: value = {{{2}},{{3}}}
NOTICE: pos = [0:2][1:2]={{1,1},{1,2},{2,1}}
NOTICE: userargs = <NULL>
-21|22|(1,-2,1,1,1,-1,0,0,0,1)|(16BUI,0,f,)
+21|22|(1,-2,1,1,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{1}},{{NULL}}}
NOTICE: pos = [0:2][1:2]={{1,1},{1,1},{0,0}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{NULL}},{{2}}}
NOTICE: pos = [0:2][1:2]={{3,3},{3,3},{2,2}}
NOTICE: userargs = <NULL>
-20|21|(0,0,3,3,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|(0,0,3,3,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{1}},{{NULL}}}
NOTICE: pos = [0:2][1:2]={{1,1},{1,1},{1,-1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{NULL}},{{3}}}
NOTICE: pos = [0:2][1:2]={{2,4},{2,4},{2,2}}
NOTICE: userargs = <NULL>
-20|22|(0,0,2,4,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|22|(0,0,2,4,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{1}},{{NULL}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{0,0},{1,-1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{NULL}},{{NULL}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{3,4},{3,4},{2,3},{3,2}}
NOTICE: userargs = <NULL>
-20|21|22|(0,0,3,4,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|22|(0,0,3,4,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{1}},{{NULL}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{0,0},{1,-1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{1}},{{2}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{2,2},{2,2},{1,1},{2,0}}
NOTICE: userargs = <NULL>
-20|21|22|(0,0,2,2,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|22|(0,0,2,2,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{1}},{{2}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{1,1},{2,2},{1,1},{2,0}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{NULL}},{{2}},{{NULL}}}
NOTICE: pos = [0:3][1:2]={{2,2},{3,3},{2,2},{3,1}}
NOTICE: userargs = <NULL>
-20|21|22|(1,-1,2,2,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|22|(1,-1,2,2,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{NULL}},{{NULL}},{{3}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,3},{0,2},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{NULL}},{{NULL}},{{3}}}
NOTICE: pos = [0:3][1:2]={{2,2},{2,4},{1,3},{2,2}}
NOTICE: userargs = <NULL>
-20|21|22|(0,-2,2,2,1,-1,0,0,0,1)|(16BUI,0,f,)
+20|21|22|(0,-2,2,2,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: Raster provided has no bands
-20|21|22|(0,0,0,0,0,0,0,0,0,0)|(,,,)
+20|21|22|(0,0,0,0,0,0,0,0,0,0)|(,,,,)
NOTICE: value = {{{1}},{{10}},{{100}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{1}},{{10}},{{100}}}
NOTICE: pos = [0:3][1:2]={{2,2},{2,2},{2,2},{2,2}}
NOTICE: userargs = <NULL>
-30|(0,0,2,2,1,-1,0,0,0,1)|(16BUI,0,f,)
+30|(0,0,2,2,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{100}},{{1}},{{100}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{100}},{{1}},{{100}}}
NOTICE: pos = [0:3][1:2]={{2,2},{2,2},{2,2},{2,2}}
NOTICE: userargs = <NULL>
-30|(0,0,2,2,1,-1,0,0,0,1)|(32BUI,0,f,)
+30|(0,0,2,2,1,-1,0,0,0,1)|(32BUI,0,f,,)
NOTICE: value = {{{20}},{{20}}}
NOTICE: pos = [0:2][1:2]={{1,1},{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{20}},{{20}}}
NOTICE: pos = [0:2][1:2]={{2,2},{2,2},{2,2}}
NOTICE: userargs = <NULL>
-31|(0,1,2,2,1,-1,0,0,0,1)|(16BUI,0,f,)
+31|(0,1,2,2,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{10}},{{2}},{{20}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{1,2},{1,2}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{10}},{{2}},{{20}}}
NOTICE: pos = [0:3][1:2]={{2,1},{2,1},{2,2},{2,2}}
NOTICE: userargs = <NULL>
-30|31|(0,0,2,1,1,-1,0,0,0,1)|(16BUI,0,f,)
+30|31|(0,0,2,1,1,-1,0,0,0,1)|(16BUI,0,f,,)
NOTICE: value = {{{100}},{{1}},{{100}}}
NOTICE: pos = [0:3][1:2]={{1,1},{1,1},{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{100}},{{1}},{{100}}}
NOTICE: pos = [0:3][1:2]={{2,2},{2,2},{2,2},{2,2}}
NOTICE: userargs = <NULL>
-30|(0,0,2,2,1,-1,0,0,0,1)|(32BUI,0,f,)
+30|(0,0,2,2,1,-1,0,0,0,1)|(32BUI,0,f,,)
NOTICE: value = {{{10}}}
NOTICE: pos = [0:1][1:2]={{1,1},{1,1}}
NOTICE: userargs = <NULL>
NOTICE: value = {{{10}}}
NOTICE: pos = [0:1][1:2]={{2,2},{2,2}}
NOTICE: userargs = <NULL>
-30|(0,0,2,2,1,-1,0,0,0,1)|(8BUI,0,f,)
+30|(0,0,2,2,1,-1,0,0,0,1)|(8BUI,0,f,,)
NOTICE: value = {{{1}}}
NOTICE: pos = [0:1][1:2]={{1,1},{1,1}}
NOTICE: userargs = {}
--- /dev/null
+SET postgis.gdal_enabled_drivers = 'GTiff';
+SET postgis.enable_outdb_rasters = true;
+
+(
+SELECT
+ 1,
+ bandnum,
+ isoutdb,
+ CASE
+ WHEN isoutdb IS TRUE
+ THEN strpos(path, 'testraster.tif') > 0
+ ELSE NULL
+ END,
+ outdbbandnum
+FROM ST_BandMetadata((SELECT rast FROM raster_outdb_template WHERE rid = 1), ARRAY[]::int[])
+UNION ALL
+SELECT
+ 2,
+ bandnum,
+ isoutdb,
+ CASE
+ WHEN isoutdb IS TRUE
+ THEN strpos(path, 'testraster.tif') > 0
+ ELSE NULL
+ END,
+ outdbbandnum
+FROM ST_BandMetadata((SELECT ST_SetBandIndex(rast, 1, 2) FROM raster_outdb_template WHERE rid = 1), ARRAY[]::int[])
+)
+ORDER BY 1, 2;
--- /dev/null
+1|1|t|t|1
+1|2|t|t|2
+1|3|t|t|3
+2|1|t|t|2
+2|2|t|t|2
+2|3|t|t|3