[SCM] PostGIS branch master updated. 3.6.0rc2-618-g63cbf4f06
git at osgeo.org
git at osgeo.org
Thu Jun 18 14:14:14 PDT 2026
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".
The branch, master has been updated
via 63cbf4f069afebe50cb520b7abe6440c898842e9 (commit)
from 96571149829e3a65f8ad7b4c488b8d1ca4666137 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 63cbf4f069afebe50cb520b7abe6440c898842e9
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Fri Jun 19 00:25:55 2026 +0400
raster: fix import, warp, and GDAL log handling
Fix raster behavior covering ST_ReclassExact band ownership, Float16 pixel-line writes, legacy GDAL signed-byte imports, mixed nodata/no-nodata warps, zero-band warp nodata allocation, and GDAL credential-bearing log redaction.
No extension upgrade SQL is required because SQL definitions and catalog-visible objects are unchanged.
Closes https://github.com/postgis/postgis/pull/894
diff --git a/NEWS b/NEWS
index af7656e13..2e4b7cac6 100644
--- a/NEWS
+++ b/NEWS
@@ -104,6 +104,9 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
- #4828, geometry_columns handles NOT VALID SRID checks without errors (Darafei Praliaskouski)
- #6048, [raster] ST_Clip no longer crashes when clipping sparse band
selections (Darafei Praliaskouski)
+ - GH-894, [raster] Fix Float16 import, mixed nodata warping,
+ band replacement cleanup, GDAL credential redaction, and Python
+ GDAL compatibility (Darafei Praliaskouski)
- #5645, Docs: keep code operators ("=>") intact in translated manuals
by enforcing verbatim CSS (Darafei Praliaskouski)
- #5593, Docs: render manual images with GraphicsMagick without temporary files,
diff --git a/raster/rt_core/rt_band.c b/raster/rt_core/rt_band.c
index 2cbe92ead..0fb95d1f8 100644
--- a/raster/rt_core/rt_band.c
+++ b/raster/rt_core/rt_band.c
@@ -1080,6 +1080,12 @@ rt_band_set_pixel_line(
memcpy(ptr, vals, (size_t)size * len);
break;
}
+ case PT_16BF: {
+ uint16_t *ptr = (uint16_t *) data;
+ ptr += offset;
+ memcpy(ptr, vals, (size_t)size * len);
+ break;
+ }
case PT_32BUI: {
uint32_t *ptr = (uint32_t *) data;
ptr += offset;
diff --git a/raster/rt_core/rt_warp.c b/raster/rt_core/rt_warp.c
index f5854fd0f..2cdda3c1e 100644
--- a/raster/rt_core/rt_warp.c
+++ b/raster/rt_core/rt_warp.c
@@ -30,6 +30,8 @@
#include "../../postgis_config.h"
+#include <math.h>
+
#include "librtcore.h"
#include "librtcore_internal.h"
@@ -163,6 +165,9 @@ rt_raster rt_raster_gdal_warp(
char *dst_options[] = {"SUBCLASS=VRTWarpedDataset", NULL};
_rti_warp_arg arg = NULL;
+ int nodata_count = 0;
+ int has_nodata_count = 0;
+
GDALRasterBandH band;
rt_band rtband = NULL;
rt_pixtype pt = PT_END;
@@ -179,8 +184,19 @@ rt_raster rt_raster_gdal_warp(
int ul_user = 0;
rt_raster rast = NULL;
+ rt_raster nodata_src = NULL;
+ rt_raster data_src = NULL;
+ rt_raster nodata_warp = NULL;
+ rt_raster data_warp = NULL;
+ rt_raster src = NULL;
+ uint32_t *nodata_bands = NULL;
+ uint32_t *data_bands = NULL;
+ int *group_index = NULL;
+ int *group_has_nodata = NULL;
int i = 0;
int numBands = 0;
+ int nodata_pos = 0;
+ int data_pos = 0;
int subspatial = 0;
@@ -188,6 +204,155 @@ rt_raster rt_raster_gdal_warp(
assert(NULL != raster);
+ numBands = rt_raster_get_num_bands(raster);
+ for (i = 0; i < numBands; i++)
+ {
+ rtband = rt_raster_get_band(raster, i);
+ if (NULL == rtband)
+ {
+ rterror("rt_raster_gdal_warp: Could not get band %d for checking nodata state", i);
+ return NULL;
+ }
+ if (rt_band_get_hasnodata_flag(rtband) != FALSE)
+ has_nodata_count++;
+ }
+
+ if (has_nodata_count > 0 && has_nodata_count < numBands)
+ {
+ nodata_bands = rtalloc(sizeof(uint32_t) * has_nodata_count);
+ data_bands = rtalloc(sizeof(uint32_t) * (numBands - has_nodata_count));
+ group_index = rtalloc(sizeof(int) * numBands);
+ group_has_nodata = rtalloc(sizeof(int) * numBands);
+ if (nodata_bands == NULL || data_bands == NULL || group_index == NULL || group_has_nodata == NULL)
+ {
+ rterror("rt_raster_gdal_warp: Could not allocate mixed nodata band mapping");
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+ return NULL;
+ }
+
+ for (i = 0; i < numBands; i++)
+ {
+ rtband = rt_raster_get_band(raster, i);
+ if (rt_band_get_hasnodata_flag(rtband) != FALSE)
+ {
+ nodata_bands[nodata_pos] = i;
+ group_index[i] = nodata_pos++;
+ group_has_nodata[i] = 1;
+ }
+ else
+ {
+ data_bands[data_pos] = i;
+ group_index[i] = data_pos++;
+ group_has_nodata[i] = 0;
+ }
+ }
+
+ nodata_src = rt_raster_from_band(raster, nodata_bands, has_nodata_count);
+ data_src = rt_raster_from_band(raster, data_bands, numBands - has_nodata_count);
+ if (nodata_src == NULL || data_src == NULL)
+ {
+ rterror("rt_raster_gdal_warp: Could not split mixed nodata raster");
+ if (nodata_src != NULL)
+ rt_raster_destroy(nodata_src);
+ if (data_src != NULL)
+ rt_raster_destroy(data_src);
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+ return NULL;
+ }
+
+ nodata_warp = rt_raster_gdal_warp(nodata_src,
+ src_srs,
+ dst_srs,
+ scale_x,
+ scale_y,
+ width,
+ height,
+ ul_xw,
+ ul_yw,
+ grid_xw,
+ grid_yw,
+ skew_x,
+ skew_y,
+ resample_alg,
+ max_err);
+ data_warp = rt_raster_gdal_warp(data_src,
+ src_srs,
+ dst_srs,
+ scale_x,
+ scale_y,
+ width,
+ height,
+ ul_xw,
+ ul_yw,
+ grid_xw,
+ grid_yw,
+ skew_x,
+ skew_y,
+ resample_alg,
+ max_err);
+ rt_raster_destroy(nodata_src);
+ rt_raster_destroy(data_src);
+ if (nodata_warp == NULL || data_warp == NULL)
+ {
+ rterror("rt_raster_gdal_warp: Could not warp mixed nodata raster groups");
+ if (nodata_warp != NULL)
+ rt_raster_destroy(nodata_warp);
+ if (data_warp != NULL)
+ rt_raster_destroy(data_warp);
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+ return NULL;
+ }
+
+ rast = rt_raster_clone(nodata_warp, 0);
+ if (rast == NULL)
+ {
+ rterror("rt_raster_gdal_warp: Could not create mixed nodata output raster");
+ rt_raster_destroy(nodata_warp);
+ rt_raster_destroy(data_warp);
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+ return NULL;
+ }
+
+ for (i = 0; i < numBands; i++)
+ {
+ src = group_has_nodata[i] ? nodata_warp : data_warp;
+ if (rt_raster_copy_band(rast, src, group_index[i], i) < 0)
+ {
+ rterror("rt_raster_gdal_warp: Could not merge warped mixed nodata band");
+ rt_raster_destroy(rast);
+ rt_raster_destroy(nodata_warp);
+ rt_raster_destroy(data_warp);
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+ return NULL;
+ }
+ }
+
+ rt_raster_destroy(nodata_warp);
+ rt_raster_destroy(data_warp);
+ rtdealloc(nodata_bands);
+ rtdealloc(data_bands);
+ rtdealloc(group_index);
+ rtdealloc(group_has_nodata);
+
+ RASTER_DEBUG(3, "rt_raster_gdal_warp: done");
+ return rast;
+ }
+
arg = _rti_warp_arg_init();
if (arg == NULL) {
rterror("rt_raster_gdal_warp: Could not initialize internal variables");
@@ -627,7 +792,6 @@ rt_raster rt_raster_gdal_warp(
}
/* add bands */
- numBands = rt_raster_get_num_bands(raster);
for (i = 0; i < numBands; i++) {
rtband = rt_raster_get_band(raster, i);
if (NULL == rtband) {
@@ -656,6 +820,7 @@ rt_raster rt_raster_gdal_warp(
}
if (rt_band_get_hasnodata_flag(rtband) != FALSE) {
+ nodata_count++;
rt_band_get_nodata(rtband, &nodata);
if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
rtwarn("rt_raster_gdal_warp: Could not set nodata value for band %d", i);
@@ -700,10 +865,17 @@ rt_raster rt_raster_gdal_warp(
arg->wopts->hDstDS = arg->dst.ds;
arg->wopts->pfnTransformer = arg->transform.func;
arg->wopts->pTransformerArg = arg->transform.arg.transform;
- arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 2);
+ arg->wopts->papszWarpOptions = (char **) CPLMalloc(sizeof(char *) * 3);
arg->wopts->papszWarpOptions[0] = (char *) CPLMalloc(sizeof(char) * (strlen("INIT_DEST=NO_DATA") + 1));
strcpy(arg->wopts->papszWarpOptions[0], "INIT_DEST=NO_DATA");
- arg->wopts->papszWarpOptions[1] = NULL;
+#if POSTGIS_GDAL_VERSION >= 30302
+ arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=PARTIAL") + 1));
+ strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=PARTIAL");
+#else
+ arg->wopts->papszWarpOptions[1] = (char *) CPLMalloc(sizeof(char) * (strlen("UNIFIED_SRC_NODATA=NO") + 1));
+ strcpy(arg->wopts->papszWarpOptions[1], "UNIFIED_SRC_NODATA=NO");
+#endif
+ arg->wopts->papszWarpOptions[2] = NULL;
/* band mapping */
arg->wopts->nBandCount = numBands;
@@ -712,8 +884,12 @@ rt_raster rt_raster_gdal_warp(
for (i = 0; i < arg->wopts->nBandCount; i++)
arg->wopts->panDstBands[i] = arg->wopts->panSrcBands[i] = i + 1;
- /* nodata mapping */
- {
+ /*
+ * When every band declares nodata, pass the explicit vector to GDAL.
+ * Mixed-band rasters keep their intrinsic per-band nodata metadata; a
+ * synthetic value for bands without nodata can collide with valid pixels.
+ */
+ if (numBands > 0 && nodata_count == numBands) {
arg->wopts->padfSrcNoDataReal = (double *) CPLMalloc(numBands * sizeof(double));
arg->wopts->padfDstNoDataReal = (double *) CPLMalloc(numBands * sizeof(double));
arg->wopts->padfSrcNoDataImag = (double *) CPLMalloc(numBands * sizeof(double));
@@ -735,10 +911,7 @@ rt_raster rt_raster_gdal_warp(
_rti_warp_arg_destroy(arg);
return NULL;
}
- if (!rt_band_get_hasnodata_flag(band))
- arg->wopts->padfSrcNoDataReal[i] = -123456.789;
- else
- rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i]));
+ rt_band_get_nodata(band, &(arg->wopts->padfSrcNoDataReal[i]));
arg->wopts->padfDstNoDataReal[i] = arg->wopts->padfSrcNoDataReal[i];
arg->wopts->padfDstNoDataImag[i] = arg->wopts->padfSrcNoDataImag[i] = 0.0;
}
@@ -775,4 +948,3 @@ rt_raster rt_raster_gdal_warp(
return rast;
}
-
diff --git a/raster/rt_pg/rtpg_gdal.c b/raster/rt_pg/rtpg_gdal.c
index 09b3f51a1..41f357f8c 100644
--- a/raster/rt_pg/rtpg_gdal.c
+++ b/raster/rt_pg/rtpg_gdal.c
@@ -38,6 +38,8 @@
#include <utils/guc.h> /* for ArrayType */
#include <catalog/pg_type.h> /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
#include <utils/memutils.h> /* For TopMemoryContext */
+#include <ctype.h>
+#include <strings.h>
#include "../../postgis_config.h"
@@ -1115,10 +1117,62 @@ static const char* const gdalErrorTypes[gdalErrorTypesSize] =
"AWSSignatureDoesNotMatch"
};
+static void
+rtpg_gdal_redact_message(char *msg)
+{
+ static const struct {
+ const char *text;
+ bool header_value;
+ } sensitive[] = {{"access_key=", false},
+ {"access_token=", false},
+ {"authorization:", true},
+ {"cookie:", true},
+ {"key=", false},
+ {"password=", false},
+ {"secret=", false},
+ {"sig=", false},
+ {"signature=", false},
+ {"token=", false},
+ {"x-amz-credential=", false},
+ {"x-amz-security-token:", true},
+ {"x-amz-security-token=", false}};
+ char *p;
+ size_t i;
+
+ for (p = msg; *p; p++)
+ {
+ for (i = 0; i < sizeof(sensitive) / sizeof(sensitive[0]); i++)
+ {
+ size_t n = strlen(sensitive[i].text);
+ char *v;
+
+ if (strncasecmp(p, sensitive[i].text, n) != 0)
+ continue;
+
+ v = p + n;
+ while (*v && isspace((unsigned char) *v))
+ v++;
+ while (*v && *v != '\r' && *v != '\n' &&
+ (sensitive[i].header_value ||
+ (!isspace((unsigned char)*v) && *v != '&' && *v != ';' && *v != ',')))
+ {
+ *v = 'x';
+ v++;
+ }
+ p = v > p ? v - 1 : p;
+ break;
+ }
+ }
+}
+
static void
ogrErrorHandler(CPLErr eErrClass, int err_no, const char* msg)
{
const char* gdalErrType = "unknown type";
+ char *redacted = pstrdup(msg ? msg : "");
+
+ rtpg_gdal_redact_message(redacted);
+
if (err_no >= 0 && err_no < gdalErrorTypesSize)
{
gdalErrType = gdalErrorTypes[err_no];
@@ -1126,20 +1180,21 @@ ogrErrorHandler(CPLErr eErrClass, int err_no, const char* msg)
switch (eErrClass)
{
case CE_None:
- elog(NOTICE, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ elog(NOTICE, "GDAL %s [%d] %s", gdalErrType, err_no, redacted);
break;
case CE_Debug:
- elog(DEBUG2, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ elog(DEBUG2, "GDAL %s [%d] %s", gdalErrType, err_no, redacted);
break;
case CE_Warning:
- elog(WARNING, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ elog(WARNING, "GDAL %s [%d] %s", gdalErrType, err_no, redacted);
break;
case CE_Failure:
case CE_Fatal:
default:
- elog(ERROR, "GDAL %s [%d] %s", gdalErrType, err_no, msg);
+ elog(ERROR, "GDAL %s [%d] %s", gdalErrType, err_no, redacted);
break;
}
+ pfree(redacted);
return;
}
@@ -1152,4 +1207,3 @@ rtpg_gdal_set_cpl_debug(bool value, void *extra)
CPLSetErrorHandler(value ? ogrErrorHandler : NULL);
CPLSetCurrentErrorHandlerCatchDebug(value);
}
-
diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c
index 865fb3a55..ba34e6323 100644
--- a/raster/rt_pg/rtpg_mapalgebra.c
+++ b/raster/rt_pg/rtpg_mapalgebra.c
@@ -4139,12 +4139,14 @@ Datum RASTER_reclass_exact(PG_FUNCTION_ARGS) {
elog(ERROR, "Band reclassification failed");
/* replace old band with new band */
- if (rt_raster_replace_band(raster, newband, bandnum-1) == NULL) {
+ band = rt_raster_replace_band(raster, newband, bandnum-1);
+ if (band == NULL) {
rt_band_destroy(newband);
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
elog(ERROR, "Could not replace raster band of index %d with reclassified band", bandnum);
}
+ rt_band_destroy(band);
pgrtn = rt_raster_serialize(raster);
rt_raster_destroy(raster);
diff --git a/raster/scripts/python/pixval.py b/raster/scripts/python/pixval.py
index 44c953cd0..79ad14c5a 100755
--- a/raster/scripts/python/pixval.py
+++ b/raster/scripts/python/pixval.py
@@ -31,7 +31,6 @@ import sys
def pt2fmt(pt):
fmttypes = {
gdalc.GDT_Byte: 'B',
- gdalc.GDT_Int8: 'B',
gdalc.GDT_Int16: 'h',
gdalc.GDT_UInt16: 'H',
gdalc.GDT_Int32: 'i',
@@ -39,6 +38,8 @@ def pt2fmt(pt):
gdalc.GDT_Float32: 'f',
gdalc.GDT_Float64: 'f'
}
+ if hasattr(gdalc, 'GDT_Int8'):
+ fmttypes[gdalc.GDT_Int8] = 'b'
if hasattr(gdalc, 'GDT_Float16'):
fmttypes[gdalc.GDT_Float16] = 'e'
return fmttypes.get(pt, 'x')
diff --git a/raster/scripts/python/raster2pgsql.py b/raster/scripts/python/raster2pgsql.py
index 7d227b413..82423568d 100755
--- a/raster/scripts/python/raster2pgsql.py
+++ b/raster/scripts/python/raster2pgsql.py
@@ -214,7 +214,6 @@ def gdt2pt(gdt):
"""Translate GDAL data type to WKT Raster pixel type."""
pixtypes = {
gdalc.GDT_Byte : { 'name': 'PT_8BUI', 'id': 4 },
- gdalc.GDT_Int8 : { 'name': 'PT_8BSI', 'id': 3 },
gdalc.GDT_Int16 : { 'name': 'PT_16BSI', 'id': 5 },
gdalc.GDT_UInt16 : { 'name': 'PT_16BUI', 'id': 6 },
gdalc.GDT_Int32 : { 'name': 'PT_32BSI', 'id': 7 },
@@ -223,6 +222,8 @@ def gdt2pt(gdt):
gdalc.GDT_Float64 : { 'name': 'PT_64BF', 'id': 11 }
}
+ if hasattr(gdalc, 'GDT_Int8'):
+ pixtypes[gdalc.GDT_Int8] = { 'name': 'PT_8BSI', 'id': 3 }
if hasattr(gdalc, 'GDT_Float16'):
pixtypes[gdalc.GDT_Float16] = { 'name': 'PT_16BF', 'id': 9 }
@@ -232,6 +233,26 @@ def gdt2pt(gdt):
return pixtypes.get(gdt, 13)
+def band_is_signed_byte(band):
+ """Return True for legacy GDAL signed-byte bands exposed as GDT_Byte."""
+
+ pixel_type = band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE')
+ return band.DataType == gdalc.GDT_Byte and pixel_type is not None and pixel_type.upper() == 'SIGNEDBYTE'
+
+def band2pt(band):
+ """Translate a GDAL raster band to WKT Raster pixel type."""
+
+ if band_is_signed_byte(band):
+ return { 'name': 'PT_8BSI', 'id': 3 }
+ return gdt2pt(band.DataType)
+
+def band2numpy(band):
+ """Translate a GDAL raster band to NumPy data type."""
+
+ if band_is_signed_byte(band):
+ return numpy.int8
+ return pt2numpy(band.DataType)
+
def pt2numpy(pt):
"""Translate GDAL data type to NumPy data type"""
ptnumpy = {
@@ -243,6 +264,8 @@ def pt2numpy(pt):
gdalc.GDT_Float32: numpy.float32,
gdalc.GDT_Float64: numpy.float64
}
+ if hasattr(gdalc, 'GDT_Int8'):
+ ptnumpy[gdalc.GDT_Int8] = numpy.int8
if hasattr(gdalc, 'GDT_Float16'):
ptnumpy[gdalc.GDT_Float16] = numpy.float16
return ptnumpy.get(pt, numpy.uint8)
@@ -250,6 +273,7 @@ def pt2numpy(pt):
def pt2fmt(pt):
"""Returns binary data type specifier for given pixel type."""
fmttypes = {
+ 3: 'b', # PT_8BSI
4: 'B', # PT_8BUI
5: 'h', # PT_16BSI
6: 'H', # PT_16BUI
@@ -265,6 +289,7 @@ def pt2fmt(pt):
def fmt2printfmt(fmt):
"""Returns printf-like formatter for given binary data type specifier."""
fmttypes = {
+ 'b': '%d', # PT_8BSI
'B': '%d', # PT_8BUI
'h': '%d', # PT_16BSI
'H': '%d', # PT_16BUI
@@ -530,7 +555,7 @@ def collect_pixel_types(ds, band_from, band_to):
pt =[]
for i in range(band_from, band_to):
band = ds.GetRasterBand(i)
- pixel_type = gdt2pt(band.DataType)['name'][3:]
+ pixel_type = band2pt(band)['name'][3:]
pt.append(pixel_type)
return pt
@@ -746,7 +771,7 @@ def wkblify_band_header(options, band):
nodata = 0
# Encode pixel type
- pixtype = gdt2pt(band.DataType)['id']
+ pixtype = band2pt(band)['id']
hexwkb += wkblify('B', pixtype + first4bits)
# Encode nodata value (or Zero, if nodata unavailable)
@@ -805,7 +830,7 @@ def wkblify_band(options, band, level, xoff, yoff, read_block_size, block_size,
# XXX: Use for debugging only
#dump_block_numpy(pixels)
- out_pixels = numpy.zeros((block_size[1], block_size[0]), pt2numpy(band.DataType))
+ out_pixels = numpy.zeros((block_size[1], block_size[0]), band2numpy(band))
logit('MSG: Read valid source:\t%d x %d\n' % (len(pixels[0]), len(pixels)))
logit('MSG: Write into block:\t%d x %d\n' % (len(out_pixels[0]), len(out_pixels)))
diff --git a/raster/test/regress/rt_gdalwarp.sql b/raster/test/regress/rt_gdalwarp.sql
index abee24978..ad5b44638 100644
--- a/raster/test/regress/rt_gdalwarp.sql
+++ b/raster/test/regress/rt_gdalwarp.sql
@@ -887,3 +887,50 @@ SELECT
ST_Metadata(ST_Rescale(rast, 2, 2)) AS rescale,
ST_Metadata(ST_Resize(rast, 0.5, 0.5)) AS resize
FROM foo;
+
+-- Mixed nodata/no-nodata bands keep declared nodata without treating no-nodata NaN as invalid
+WITH src AS (
+ SELECT ST_SetValue(
+ ST_AddBand(
+ ST_SetValue(
+ ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 2, 1, -1, 0, 0, 0), 1, '8BUI', 0, 0),
+ 1, 1, 1, NULL
+ ),
+ 2, '64BF', 'NaN'::float8, NULL
+ ),
+ 2, 1, 1, 'NaN'::float8
+ ) AS rast
+), warped AS (
+ SELECT ST_Resample(rast, 4, 4, NULL, NULL, 0, 0, 'NearestNeighbour', 0) AS rast
+ FROM src
+)
+SELECT
+ ST_Value(rast, 1, 1, 1) IS NULL AS nodata_band_preserved,
+ ST_Value(rast, 1, 1, 1, FALSE) = ST_BandNoDataValue(rast, 1) AS nodata_raw_matches,
+ ST_Value(rast, 2, 1, 1) IS NULL AS nan_band_visible_value,
+ ST_Value(rast, 2, 1, 1, FALSE)::text AS nan_band_raw_value,
+ ST_BandNoDataValue(rast, 2) IS NULL AS nan_band_has_no_nodata
+FROM warped;
+
+WITH base AS (
+ SELECT ST_SetValue(
+ ST_SetValue(
+ ST_SetValue(
+ ST_SetValue(ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 2, 1, -1, 0, 0, 0), 1, '32BF', 0, 0),
+ 1, 1, 1, NULL),
+ 1, 2, 1, 100),
+ 1, 1, 2, 100),
+ 1, 2, 2, 100) AS rast
+), mixed AS (
+ SELECT ST_AddBand(rast, 2, '64BF', 'NaN'::float8, NULL) AS rast
+ FROM base
+), warped AS (
+ SELECT
+ ST_Resample((SELECT rast FROM base), 4, 4, NULL, NULL, 0, 0, 'Bilinear', 0) AS single_rast,
+ ST_Resample(rast, 4, 4, NULL, NULL, 0, 0, 'Bilinear', 0) AS mixed_rast
+ FROM mixed
+)
+SELECT
+ ST_Value(mixed_rast, 1, 2, 1) IS NULL = (ST_Value(single_rast, 1, 2, 1) IS NULL) AS mixed_bilinear_matches,
+ ST_BandNoDataValue(mixed_rast, 2) IS NULL AS mixed_bilinear_keeps_no_nodata
+FROM warped;
diff --git a/raster/test/regress/rt_gdalwarp_expected b/raster/test/regress/rt_gdalwarp_expected
index d6bc47c1f..9b2137743 100644
--- a/raster/test/regress/rt_gdalwarp_expected
+++ b/raster/test/regress/rt_gdalwarp_expected
@@ -107,3 +107,5 @@ NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL War
NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL Warp API
NOTICE: Raster has default geotransform. Adjusting metadata for use of GDAL Warp API
(0,0,5,5,2,-2,0,0,0,1)|(0,0,5,5,2,-2,0,0,0,1)
+t|t|f|NaN|t
+t|t
-----------------------------------------------------------------------
Summary of changes:
NEWS | 3 +
raster/rt_core/rt_band.c | 6 +
raster/rt_core/rt_warp.c | 192 +++++++++++++++++++++++++++++--
raster/rt_pg/rtpg_gdal.c | 64 ++++++++++-
raster/rt_pg/rtpg_mapalgebra.c | 4 +-
raster/scripts/python/pixval.py | 3 +-
raster/scripts/python/raster2pgsql.py | 33 +++++-
raster/test/regress/rt_gdalwarp.sql | 47 ++++++++
raster/test/regress/rt_gdalwarp_expected | 2 +
9 files changed, 333 insertions(+), 21 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list