Refactored ST_MapAlgebraFctNgb to cache userfunction lookup, and accept NULL input and output values.

git-svn-id: http://svn.osgeo.org/postgis/trunk@8183 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
David Zwarg 2011-11-18 20:53:46 +00:00
parent 15c2f240d2
commit 663a3de49e
4 changed files with 103 additions and 12 deletions

View file

@ -8938,7 +8938,8 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
rt_pixtype newpixeltype;
int ret = -1;
Oid oid;
Datum extraargs;
FmgrInfo cbinfo;
FunctionCallInfoData cbdata;
Datum tmpnewval;
ArrayType * neighborDatum;
char * strFromText = NULL;
@ -9126,6 +9127,10 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
if (newpixeltype == PT_END) {
elog(ERROR, "RASTER_mapAlgebraFctNgb: Invalid pixeltype. Returning NULL");
rt_raster_destroy(raster);
rt_raster_destroy(newrast);
PG_RETURN_NULL();
}
@ -9135,12 +9140,73 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
/* Get the name of the callback userfunction */
if (PG_ARGISNULL(5)) {
elog(ERROR, "RASTER_mapAlgebraFctNgb: Required function is missing. Returning NULL");
rt_raster_destroy(raster);
rt_raster_destroy(newrast);
PG_RETURN_NULL();
}
oid = PG_GETARG_OID(5);
if (oid == InvalidOid) {
elog(ERROR, "RASTER_mapAlgebraFctNgb: Got invalid function object id. Returning NULL");
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFctNgb: 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_mapAlgebraFctNgb: Function provided must return double precision not resultset. Returning NULL");
rt_raster_destroy(raster);
rt_raster_destroy(newrast);
PG_RETURN_NULL();
}
/* function should have correct # of args */
else if (cbinfo.fn_nargs != 3) {
elog(ERROR, "RASTER_mapAlgebraFctNgb: Function does not have three input parameters. Returning NULL");
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, 3, InvalidOid, NULL);
#else
InitFunctionCallInfoData(cbdata, &cbinfo, 3, InvalidOid, NULL, NULL);
#endif
memset(cbdata.argnull, FALSE, 3);
/* check that the function isn't strict if the args are null. */
if (PG_ARGISNULL(7)) {
if (cbinfo.fn_strict) {
elog(ERROR, "RASTER_mapAlgebraFctNgb: Strict callback functions cannot have null parameters. Returning NULL");
rt_raster_destroy(raster);
rt_raster_destroy(newrast);
PG_RETURN_NULL();
}
cbdata.arg[2] = (Datum)NULL;
cbdata.argnull[2] = TRUE;
}
else {
cbdata.arg[2] = PG_GETARG_DATUM(7);
}
/**
* Optimization: If the raster is only filled with nodata values return
@ -9281,6 +9347,9 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
SET_VARSIZE(txtCallbackParam, VARSIZE(txtNodataMode));
memcpy((void *)VARDATA(txtCallbackParam), (void *)VARDATA(txtNodataMode), VARSIZE(txtNodataMode) - VARHDRSZ);
/* pass the nodata mode into the user function */
cbdata.arg[1] = CStringGetDatum(txtCallbackParam);
strFromText = text_to_cstring(txtNodataMode);
strFromText = strtoupper(strFromText);
@ -9322,8 +9391,6 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFctNgb: Main computing loop (%d x %d)",
width, height);
extraargs = PG_GETARG_DATUM(7);
/* Allocate room for the neighborhood. */
neighborData = (Datum *)palloc(winwidth * winheight * sizeof(Datum));
neighborNulls = (bool *)palloc(winwidth * winheight * sizeof(bool));
@ -9399,9 +9466,19 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
neighborDatum = construct_md_array((void *)neighborData, neighborNulls, 2, neighborDims, neighborLbs,
FLOAT8OID, typlen, typbyval, typalign);
/* convert neighborData to a datum for OidFunctionCall3 */
tmpnewval = OidFunctionCall3(oid, PointerGetDatum(neighborDatum), CStringGetDatum(txtCallbackParam), extraargs);
/* Assign the neighbor matrix as the first argument to the user function */
cbdata.arg[0] = PointerGetDatum(neighborDatum);
/* Invoke the user function */
tmpnewval = FunctionCallInvoke(&cbdata);
/* Get the return value of the user function */
if (cbdata.isnull) {
newval = newnodatavalue;
}
else {
newval = DatumGetFloat8(tmpnewval);
}
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFctNgb: new value = %f",
newval);
@ -9416,13 +9493,9 @@ Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS)
/* clean up */
POSTGIS_RT_DEBUG(3, "RASTER_mapAlgebraFctNgb: cleaning up memory (neighborNulls)");
pfree(neighborNulls);
POSTGIS_RT_DEBUG(3, "RASTER_mapAlgebraFctNgb: cleaning up memory (neighborData)");
pfree(neighborData);
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFctNgb: cleaning up memory (strFromText = '%s')", strFromText);
pfree(strFromText);
POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraFctNgb: cleaning up memory (txtCallbackFaram)", txtCallbackParam);
pfree(txtCallbackParam);
/* The newrast band has been modified */

View file

@ -29,7 +29,17 @@ CREATE OR REPLACE FUNCTION ST_Sum(matrix float[][], nodatamode text, variadic ar
RETURN sum;
END;
$$
LANGUAGE 'plpgsql';
LANGUAGE 'plpgsql' IMMUTABLE;
CREATE OR REPLACE FUNCTION ST_Nullage(matrix float[][], nodatamode text, VARIADIC args text[])
RETURNS float AS
$$
BEGIN
RETURN NULL;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE;
--
--Test rasters

View file

@ -165,3 +165,10 @@ SELECT
)).*
FROM ST_TestRasterNgb(5, 5, 1) AS rast) AS foo;
-- test a user function that nullifies everything
SELECT
ST_Value(rast, 2, 2) = 2,
ST_Value(
ST_MapAlgebraFctNgb(rast, 1, NULL, 1, 1, 'ST_Nullage(float[][], text, text[])'::regprocedure, 'NULL', NULL), 2, 2
) IS NULL
FROM ST_TestRasterNgb(3, 3, 2) AS rast;

View file

@ -52,3 +52,4 @@ t|t|t
NOTICE: SRID value -1 converted to the officially unknown SRID value 0
NOTICE: SRID value -1 converted to the officially unknown SRID value 0
t|t|t
t|t