Added support to pass pixel positions of both rasters to user function in 2-raster ST_MapAlgebraFct. This provides similar functionality to the keywords described in #1525.

git-svn-id: http://svn.osgeo.org/postgis/trunk@9052 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Bborie Park 2012-02-06 20:53:19 +00:00
parent 86d8c4aeae
commit 90ece61b86
2 changed files with 66 additions and 33 deletions

View file

@ -8438,10 +8438,10 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS)
int hasnodatanodataval = 0;
double nodatanodataval = 0;
Oid ufcnoid = InvalidOid;
FmgrInfo uflinfo;
FunctionCallInfoData ufcinfo;
int ufcnullcount = 0;
Oid ufc_noid = InvalidOid;
FmgrInfo ufl_info;
FunctionCallInfoData ufc_info;
int ufc_nullcount = 0;
int idx = 0;
uint32_t i = 0;
@ -8983,24 +8983,29 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS)
case REGPROCEDUREOID: {
POSTGIS_RT_DEBUG(3, "arg 4 is \"userfunction\"!");
if (!PG_ARGISNULL(4)) {
ufcnullcount = 0;
ufcnoid = PG_GETARG_OID(4);
ufc_nullcount = 0;
ufc_noid = PG_GETARG_OID(4);
/* get function info */
fmgr_info(ufcnoid, &uflinfo);
fmgr_info(ufc_noid, &ufl_info);
/* function cannot return set */
err = 0;
if (uflinfo.fn_retset) {
if (ufl_info.fn_retset) {
elog(ERROR, "RASTER_mapAlgebra2: Function provided must return double precision not resultset");
err = 1;
}
/* function should have correct # of args */
else if (uflinfo.fn_nargs != 3) {
elog(ERROR, "RASTER_mapAlgebra2: Function does not have three input parameters");
else if (ufl_info.fn_nargs < 3 || ufl_info.fn_nargs > 4) {
elog(ERROR, "RASTER_mapAlgebra2: Function provided must have three or four input parameters");
err = 1;
}
/*
TODO: consider adding checks of the userfunction parameters
should be able to use get_fn_expr_argtype() of fmgr.c
*/
if (err) {
for (k = 0; k < set_count; k++) rt_raster_destroy(_rast[k]);
rt_raster_destroy(raster);
@ -9008,25 +9013,29 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
if (func_volatile(ufcnoid) == 'v') {
if (func_volatile(ufc_noid) == '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(ufcinfo, &uflinfo, 3, InvalidOid, NULL);
InitFunctionCallInfoData(ufc_info, &ufl_info, ufl_info.fn_nargs, InvalidOid, NULL);
#else
InitFunctionCallInfoData(ufcinfo, &uflinfo, 3, InvalidOid, NULL, NULL);
InitFunctionCallInfoData(ufc_info, &ufl_info, ufl_info.fn_nargs, InvalidOid, NULL, NULL);
#endif
memset(ufcinfo.argnull, FALSE, 3);
memset(ufc_info.argnull, FALSE, ufl_info.fn_nargs);
if (ufl_info.fn_nargs != 4)
k = 2;
else
k = 3;
if (!PG_ARGISNULL(7)) {
ufcinfo.arg[2] = PG_GETARG_DATUM(7);
ufc_info.arg[k] = PG_GETARG_DATUM(7);
}
else {
ufcinfo.arg[2] = (Datum) NULL;
ufcinfo.argnull[2] = TRUE;
ufcnullcount++;
ufc_info.arg[k] = (Datum) NULL;
ufc_info.argnull[k] = TRUE;
ufc_nullcount++;
}
}
break;
@ -9046,7 +9055,7 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS)
(spi_empty != spi_count) || hasnodatanodataval
)
) || (
(calltype == REGPROCEDUREOID) && (ufcnoid != InvalidOid)
(calltype == REGPROCEDUREOID) && (ufc_noid != InvalidOid)
)) {
for (x = 0; x < dim[0]; x++) {
for (y = 0; y < dim[1]; y++) {
@ -9258,29 +9267,52 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS)
}
} break;
case REGPROCEDUREOID: {
Datum d[4];
ArrayType *a;
/* build fcnarg */
for (i = 0; i < set_count; i++) {
ufcinfo.arg[i] = Float8GetDatum(_pixel[i]);
ufc_info.arg[i] = Float8GetDatum(_pixel[i]);
if (_haspixel[i]) {
ufcinfo.argnull[i] = FALSE;
ufcnullcount--;
ufc_info.argnull[i] = FALSE;
ufc_nullcount--;
}
else {
ufcinfo.argnull[i] = TRUE;
ufcnullcount++;
ufc_info.argnull[i] = TRUE;
ufc_nullcount++;
}
}
/* function is strict and null parameter is passed */
/* http://archives.postgresql.org/pgsql-general/2011-11/msg00424.php */
if (uflinfo.fn_strict && ufcnullcount)
if (ufl_info.fn_strict && ufc_nullcount)
break;
datum = FunctionCallInvoke(&ufcinfo);
/* 4 parameters, add position */
if (ufl_info.fn_nargs == 4) {
/* Datum of 4 element array */
/* array is (x1, y1, x2, y2) */
for (i = 0; i < set_count; i++) {
if (i < 1) {
d[0] = Int32GetDatum(_pos[i][0]);
d[1] = Int32GetDatum(_pos[i][1]);
}
else {
d[2] = Int32GetDatum(_pos[i][0]);
d[3] = Int32GetDatum(_pos[i][1]);
}
}
a = construct_array(d, 4, INT4OID, sizeof(int4), true, 'i');
ufc_info.arg[2] = PointerGetDatum(a);
ufc_info.argnull[2] = FALSE;
}
datum = FunctionCallInvoke(&ufc_info);
/* result is not null*/
if (!ufcinfo.isnull) {
if (!ufc_info.isnull) {
haspixel = 1;
pixel = DatumGetFloat8(datum);
}

View file

@ -55,6 +55,7 @@ DROP FUNCTION IF EXISTS make_test_raster(integer, integer, integer, double preci
CREATE OR REPLACE FUNCTION raster_mapalgebra_intersection(
rast1 double precision,
rast2 double precision,
xy int[],
VARIADIC userargs text[]
)
RETURNS double precision
@ -142,7 +143,7 @@ CREATE OR REPLACE FUNCTION raster_mapalgebra_second(
-- INTERSECTION
INSERT INTO raster_mapalgebra_out
(SELECT r1.rid, r2.rid, 'INTERSECTION', st_mapalgebrafct(
r1.rast, r2.rast, 'raster_mapalgebra_intersection(double precision, double precision, text[])'::regprocedure, '32BF', 'INTERSECTION'
r1.rast, r2.rast, 'raster_mapalgebra_intersection(double precision, double precision, int[], text[])'::regprocedure, '32BF', 'INTERSECTION'
)
FROM raster_mapalgebra r1
JOIN raster_mapalgebra r2
@ -151,7 +152,7 @@ INSERT INTO raster_mapalgebra_out
AND r2.rid BETWEEN 1 AND 9
) UNION ALL (
SELECT r1.rid, r2.rid, 'INTERSECTION', st_mapalgebrafct(
r1.rast, r2.rast, 'raster_mapalgebra_intersection(double precision, double precision, text[])'::regprocedure, '32BF', 'INTERSECTION'
r1.rast, r2.rast, 'raster_mapalgebra_intersection(double precision, double precision, int[], text[])'::regprocedure, '32BF', 'INTERSECTION'
)
FROM raster_mapalgebra r1
JOIN raster_mapalgebra r2
@ -162,21 +163,21 @@ INSERT INTO raster_mapalgebra_out
INSERT INTO raster_mapalgebra_out
SELECT NULL AS rid, rid, 'INTERSECTION', st_mapalgebrafct(
NULL::raster, rast, 'raster_mapalgebra_intersection(double precision, double precision, text[])'::regprocedure, '32BF', 'INTERSECTION'
NULL::raster, rast, 'raster_mapalgebra_intersection(double precision, double precision, int[], text[])'::regprocedure, '32BF', 'INTERSECTION'
)
FROM raster_mapalgebra
;
INSERT INTO raster_mapalgebra_out
SELECT rid, NULL AS rid, 'INTERSECTION', st_mapalgebrafct(
rast, NULL::raster, 'raster_mapalgebra_intersection(double precision, double precision, text[])'::regprocedure, '32BF', 'INTERSECTION'
rast, NULL::raster, 'raster_mapalgebra_intersection(double precision, double precision, int[], text[])'::regprocedure, '32BF', 'INTERSECTION'
)
FROM raster_mapalgebra
;
INSERT INTO raster_mapalgebra_out
SELECT NULL AS rid, NULL AS rid, 'INTERSECTION', st_mapalgebrafct(
NULL::raster, NULL::raster, 'raster_mapalgebra_intersection(double precision, double precision, text[])'::regprocedure, '32BF', 'INTERSECTION'
NULL::raster, NULL::raster, 'raster_mapalgebra_intersection(double precision, double precision, int[], text[])'::regprocedure, '32BF', 'INTERSECTION'
)
;
@ -335,7 +336,7 @@ FROM (
FROM raster_mapalgebra_out
) AS r;
DROP FUNCTION IF EXISTS raster_mapalgebra_intersection(double precision, double precision, VARIADIC text[]);
DROP FUNCTION IF EXISTS raster_mapalgebra_intersection(double precision, double precision, int[], VARIADIC text[]);
DROP FUNCTION IF EXISTS raster_mapalgebra_union(double precision, double precision, VARIADIC text[]);
DROP FUNCTION IF EXISTS raster_mapalgebra_first(double precision, double precision, VARIADIC text[]);
DROP FUNCTION IF EXISTS raster_mapalgebra_second(double precision, double precision, VARIADIC text[]);