rt_pixtype newpixeltype;
int ret = -1;
Oid oid;
- Datum extraargs;
+ FmgrInfo cbinfo;
+ FunctionCallInfoData cbdata;
Datum tmpnewval;
char * strFromText = NULL;
if ( NULL == newrast ) {
elog(ERROR, "RASTER_mapAlgebraFct: Could not create a new raster. "
"Returning NULL");
+
+ rt_raster_destroy(raster);
+
PG_RETURN_NULL();
}
if (newpixeltype == PT_END) {
elog(ERROR, "RASTER_mapAlgebraFct: Invalid pixeltype. Returning NULL");
+
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
PG_RETURN_NULL();
}
/* Get the name of the callback user function for raster values */
if (PG_ARGISNULL(3)) {
elog(ERROR, "RASTER_mapAlgebraFct: Required function is missing. Returning NULL");
+
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
PG_RETURN_NULL();
}
oid = PG_GETARG_OID(3);
+ if (oid == InvalidOid) {
+ elog(ERROR, "RASTER_mapAlgebraFct: Got invalid function object id. Returning NULL");
- POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFct: Got function oid: %d", oid);
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
+ PG_RETURN_NULL();
+ }
+
+ fmgr_info(oid, &cbinfo);
+
+ /* function cannot return set */
+ if (cbinfo.fn_retset) {
+ elog(ERROR, "RASTER_mapAlgebraFct: Function provided must return double precision not resultset");
+
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
+ PG_RETURN_NULL();
+ }
+ /* function should have correct # of args */
+ else if (cbinfo.fn_nargs != 2) {
+ elog(ERROR, "RASTER_mapAlgebraFct: Function does not have two input parameters");
+
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
+ PG_RETURN_NULL();
+ }
+
+ if (func_volatile(oid) == 'v') {
+ elog(NOTICE, "Function provided is VOLATILE. Unless required and for best performance, function should be IMMUTABLE or STABLE");
+ }
+
+ /* prep function call data */
+#if POSTGIS_PGSQL_VERSION <= 90
+ InitFunctionCallInfoData(cbdata, &cbinfo, 2, InvalidOid, NULL);
+#else
+ InitFunctionCallInfoData(cbdata, &cbinfo, 2, InvalidOid, NULL, NULL);
+#endif
+ memset(cbdata.argnull, FALSE, 2);
+
+ /* check that the function isn't strict if the args are null. */
+ if (PG_ARGISNULL(4)) {
+ if (cbinfo.fn_strict) {
+ elog(ERROR, "RASTER_mapAlgebraFct: Strict callback functions cannot have null parameters");
+
+ rt_raster_destroy(raster);
+ rt_raster_destroy(newrast);
+
+ PG_RETURN_NULL();
+ }
+
+ cbdata.arg[1] = (Datum)NULL;
+ cbdata.argnull[1] = TRUE;
+ }
+ else {
+ cbdata.arg[1] = PG_GETARG_DATUM(4);
+ }
/**
* Optimization: If the raster is only filled with nodata values return
PG_RETURN_POINTER(pgraster);
}
-
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFct: Main computing loop (%d x %d)",
width, height);
- extraargs = PG_GETARG_DATUM(4);
-
for (x = 0; x < width; x++) {
for(y = 0; y < height; y++) {
ret = rt_band_get_pixel(band, x, y, &r);
* We compute a value only for the withdata value pixel since the
* nodata value has already been set by the first optimization
**/
- if (ret != -1 && FLT_NEQ(r, newnodatavalue)) {
+ if (ret != -1) {
+ if (FLT_EQ(r, newnodatavalue)) {
+ if (cbinfo.fn_strict) {
+ POSTGIS_RT_DEBUG(3, "RASTER_mapAlgebraFct: Strict callbacks cannot accept NULL arguments, skipping NODATA cell.");
+ continue;
+ }
+ cbdata.argnull[0] = TRUE;
+ cbdata.arg[0] = (Datum)NULL;
+ }
+ else {
+ cbdata.argnull[0] = FALSE;
+ cbdata.arg[0] = Float8GetDatum(r);
+ }
+
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFct: (%dx%d), r = %f",
x, y, r);
- /* convert r to a datum for OidFunctionCall2 */
- tmpnewval = OidFunctionCall2(oid,Float8GetDatum(r),extraargs);
- newval = DatumGetFloat8(tmpnewval);
+ tmpnewval = FunctionCallInvoke(&cbdata);
+
+ if (cbdata.isnull) {
+ newval = newnodatavalue;
+ }
+ else {
+ newval = DatumGetFloat8(tmpnewval);
+ }
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFct: new value = %f",
newval);
rt_mapalgebrafct.sql \
rt_mapalgebraexpr_2raster.sql \
rt_mapalgebrafct_2raster.sql \
+ create_rt_mapalgebrafctngb_test.sql \
rt_mapalgebrafctngb.sql \
rt_reclass.sql \
rt_resample.sql \
RETURN pixel + 20;
END;
$$
- LANGUAGE 'plpgsql';
+ LANGUAGE 'plpgsql' IMMUTABLE;
CREATE OR REPLACE FUNCTION raster_plus_arg1(pixel FLOAT, VARIADIC args TEXT[])
RETURNS FLOAT AS
RETURN pixel + x;
END;
$$
- LANGUAGE 'plpgsql';
+ LANGUAGE 'plpgsql' IMMUTABLE;
CREATE OR REPLACE FUNCTION raster_polynomial(pixel FLOAT, VARIADIC args TEXT[])
RETURNS FLOAT AS
RETURN m * pixel + b;
END;
$$
- LANGUAGE 'plpgsql';
+ LANGUAGE 'plpgsql' IMMUTABLE;
+
+ CREATE OR REPLACE FUNCTION raster_nullage(pixel FLOAT, VARIADIC args TEXT[])
+ RETURNS FLOAT AS
+ $$
+ BEGIN
+ RETURN NULL;
+ END;
+ $$
+ LANGUAGE 'plpgsql' IMMUTABLE;
--- /dev/null
+--
+-- A simple 'callback' user function that sums up all the values in a neighborhood.
+--
+CREATE OR REPLACE FUNCTION ST_Sum(matrix float[][], nodatamode text, variadic args text[])
+ RETURNS float AS
+ $$
+ DECLARE
+ _matrix float[][];
+ x1 integer;
+ x2 integer;
+ y1 integer;
+ y2 integer;
+ sum float;
+ BEGIN
+ _matrix := matrix;
+ sum := 0;
+ FOR x in array_lower(matrix, 1)..array_upper(matrix, 1) LOOP
+ FOR y in array_lower(matrix, 2)..array_upper(matrix, 2) LOOP
+ IF _matrix[x][y] IS NULL THEN
+ IF nodatamode = 'ignore' THEN
+ _matrix[x][y] := 0;
+ ELSE
+ _matrix[x][y] := nodatamode::float;
+ END IF;
+ END IF;
+ sum := sum + _matrix[x][y];
+ END LOOP;
+ END LOOP;
+ RETURN sum;
+ END;
+ $$
+ LANGUAGE 'plpgsql';
+
+--
+--Test rasters
+--
+CREATE OR REPLACE FUNCTION ST_TestRasterNgb(h integer, w integer, val float8)
+ RETURNS raster AS
+ $$
+ DECLARE
+ BEGIN
+ RETURN ST_AddBand(ST_MakeEmptyRaster(h, w, 0, 0, 1, 1, 0, 0, -1), '32BF', val, -1);
+ END;
+ $$
+ LANGUAGE 'plpgsql';
SELECT ST_Value(rast, 1, 1) + 13, ST_Value(ST_MapAlgebraFct(rast, 1, NULL, 'raster_plus_arg1(float, text[])'::regprocedure, '13'), 1, 1) FROM ST_TestRaster(0, 0, 200) AS rast;
SELECT ST_Value(rast, 1, 1) * 21 + 14, ST_Value(ST_MapAlgebraFct(rast, 1, NULL, 'raster_polynomial(float, text[])'::regprocedure, '21', '14'), 1, 1) FROM ST_TestRaster(0, 0, 300) AS rast;
+
+-- Test null return from a user function = NODATA cell value
+SELECT ST_Value(rast, 1, 1), ST_Value(ST_MapAlgebraFct(rast, 1, NULL, 'raster_nullage(float, text[])'::regprocedure), 1, 1) FROM ST_TestRaster(0, 0, 100) AS rast;
t
|19
|19
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
+NOTICE: Pixel value is null.
|
|19
100|
101|
213|213
6314|6314
+100|
---
--- A simple 'callback' user function that sums up all the values in a neighborhood.
---
-CREATE OR REPLACE FUNCTION ST_Sum(matrix float[][], nodatamode text, variadic args text[])
- RETURNS float AS
- $$
- DECLARE
- _matrix float[][];
- x1 integer;
- x2 integer;
- y1 integer;
- y2 integer;
- sum float;
- BEGIN
- _matrix := matrix;
- sum := 0;
- FOR x in array_lower(matrix, 1)..array_upper(matrix, 1) LOOP
- FOR y in array_lower(matrix, 2)..array_upper(matrix, 2) LOOP
- IF _matrix[x][y] IS NULL THEN
- IF nodatamode = 'ignore' THEN
- _matrix[x][y] := 0;
- ELSE
- _matrix[x][y] := nodatamode::float;
- END IF;
- END IF;
- sum := sum + _matrix[x][y];
- END LOOP;
- END LOOP;
- RETURN sum;
- END;
- $$
- LANGUAGE 'plpgsql';
-
---
---Test rasters
---
-CREATE OR REPLACE FUNCTION ST_TestRasterNgb(h integer, w integer, val float8)
- RETURNS raster AS
- $$
- DECLARE
- BEGIN
- RETURN ST_AddBand(ST_MakeEmptyRaster(h, w, 0, 0, 1, 1, 0, 0, -1), '32BF', val, -1);
- END;
- $$
- LANGUAGE 'plpgsql';
-
-- Tests
-- Test NULL Raster. Should be true.
SELECT ST_MapAlgebraFctNgb(NULL, 1, NULL, 1, 1, 'ST_Sum(float[][], text, text[])'::regprocedure, 'NULL', NULL) IS NULL FROM ST_TestRasterNgb(0, 0, -1) rast;