[SCM] PostGIS branch master updated. 3.6.0rc2-650-ga401974f9
git at osgeo.org
git at osgeo.org
Sun Jun 21 11:53:22 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 a401974f93be7586b3c7dbe9f7d686f3cad16061 (commit)
from 1b74f201374035483b1d9e53f0fa4d981349f78b (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 a401974f93be7586b3c7dbe9f7d686f3cad16061
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Sun Jun 21 22:40:45 2026 +0400
Move raster st_sum4ma callback to C
Replace the PL/pgSQL two-dimensional st_sum4ma callback with a C implementation while preserving nodata handling, including lazy replacement-value casting for wrapper-provided modes.
Closes #4678
Closes https://github.com/postgis/postgis/pull/1098
diff --git a/NEWS b/NEWS
index 2f67dfa1e..0f1dba4e5 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
to open shapefile sidecar files (Darafei Praliaskouski)
- #3158, Move geometry and geography typmod bit helpers out of the
public liblwgeom header (Darafei Praliaskouski)
+ - #4678, [raster] Move st_sum4ma neighborhood callback to C
+ (Darafei Praliaskouski)
- #2116, [raster] Add ST_Value nearest-neighbor boundary options
(Darafei Praliaskouski)
- #2804, #4315, [raster] Support two-argument ST_MapAlgebra callbacks
diff --git a/raster/rt_pg/rtpg_mapalgebra.c b/raster/rt_pg/rtpg_mapalgebra.c
index 36aad8f02..601c795e6 100644
--- a/raster/rt_pg/rtpg_mapalgebra.c
+++ b/raster/rt_pg/rtpg_mapalgebra.c
@@ -38,6 +38,7 @@
#include <utils/lsyscache.h> /* for get_typlenbyvalalign */
#include <utils/array.h> /* for ArrayType */
#include <utils/builtins.h> /* for cstring_to_text */
+#include <utils/float.h> /* for float8in */
#include <catalog/pg_type.h> /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
#include <executor/executor.h> /* for GetAttributeByName */
@@ -71,6 +72,7 @@ Datum RASTER_mapAlgebraFct(PG_FUNCTION_ARGS);
/* one-raster neighborhood MapAlgebra */
Datum RASTER_mapAlgebraFctNgb(PG_FUNCTION_ARGS);
+Datum RASTER_sum4ma(PG_FUNCTION_ARGS);
/* two-raster MapAlgebra */
Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS);
@@ -79,6 +81,89 @@ Datum RASTER_mapAlgebra2(PG_FUNCTION_ARGS);
/* n-raster MapAlgebra */
/* ---------------------------------------------------------------- */
+/*
+ * Neighborhood callback for one-raster map algebra that implements ST_Sum4ma.
+ * The callback receives the moving-window values as a PostgreSQL float8 array
+ * and returns their sum. NULL cells follow the historical PL/pgSQL contract:
+ * a NULL nodata mode makes the result NULL, "ignore" skips NULL cells, and any
+ * other mode is interpreted as the numeric replacement value. The replacement
+ * mode is cast only when a NULL cell is actually encountered so wrapper-provided
+ * modes such as "NULL" and "value" remain valid for all-non-NULL windows.
+ */
+PG_FUNCTION_INFO_V1(RASTER_sum4ma);
+Datum
+RASTER_sum4ma(PG_FUNCTION_ARGS)
+{
+ ArrayType *matrix;
+ Datum *values;
+ bool *nulls;
+ int nitems;
+ int i;
+ double sum = 0;
+ char *nodatamode = NULL;
+ bool ignore_nodata = false;
+ bool has_nodata_replacement = false;
+ double nodata_replacement = 0;
+
+ if (PG_ARGISNULL(0))
+ ereport(
+ ERROR,
+ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("st_sum4ma: matrix argument must not be NULL")));
+
+ if (!PG_ARGISNULL(1))
+ {
+ nodatamode = text_to_cstring(PG_GETARG_TEXT_PP(1));
+ if (strcmp(nodatamode, "ignore") == 0)
+ ignore_nodata = true;
+ }
+
+ matrix = PG_GETARG_ARRAYTYPE_P(0);
+ if (ARR_NDIM(matrix) < 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("st_sum4ma: matrix argument must have at least 2 dimensions")));
+
+ deconstruct_array(matrix, FLOAT8OID, sizeof(float8), FLOAT8PASSBYVAL, 'd', &values, &nulls, &nitems);
+
+ for (i = 0; i < nitems; i++)
+ {
+ if (nulls[i])
+ {
+ if (ignore_nodata)
+ continue;
+ if (!nodatamode)
+ {
+ pfree(nulls);
+ pfree(values);
+ PG_FREE_IF_COPY(matrix, 0);
+ PG_RETURN_NULL();
+ }
+
+ /*
+ * Match the PL/pgSQL callback: wrapper-provided modes such as
+ * "NULL" and "value" are only cast when a NULL cell is present.
+ */
+ if (!has_nodata_replacement)
+ {
+ nodata_replacement =
+ DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(nodatamode)));
+ has_nodata_replacement = true;
+ }
+ sum += nodata_replacement;
+ }
+ else
+ sum += DatumGetFloat8(values[i]);
+ }
+
+ if (nodatamode)
+ pfree(nodatamode);
+ pfree(nulls);
+ pfree(values);
+ PG_FREE_IF_COPY(matrix, 0);
+
+ PG_RETURN_FLOAT8(sum);
+}
+
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in
index 96bb55ed8..aa09a7357 100644
--- a/raster/rt_pg/rtpostgis.sql.in
+++ b/raster/rt_pg/rtpostgis.sql.in
@@ -2541,30 +2541,9 @@ CREATE OR REPLACE FUNCTION st_min4ma(matrix float[][], nodatamode text, variadic
LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION st_sum4ma(matrix float[][], nodatamode text, variadic args text[])
- RETURNS float AS
- $$
- DECLARE
- _matrix float[][];
- 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' IMMUTABLE PARALLEL SAFE;
+ RETURNS float
+ AS 'MODULE_PATHNAME', 'RASTER_sum4ma'
+ LANGUAGE 'c' IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION st_mean4ma(matrix float[][], nodatamode text, variadic args text[])
RETURNS float AS
diff --git a/raster/test/regress/rt_4ma.sql b/raster/test/regress/rt_4ma.sql
index 1a3b214f3..57798b735 100644
--- a/raster/test/regress/rt_4ma.sql
+++ b/raster/test/regress/rt_4ma.sql
@@ -78,5 +78,20 @@ SELECT
FROM raster_value_arrays
ORDER BY id;
+SELECT
+ 'sum4ma.nodata',
+ st_sum4ma(ARRAY[[1::double precision, NULL, 3]], NULL, VARIADIC NULL::text[]) IS NULL,
+ st_sum4ma(ARRAY[[1::double precision, NULL, 3]], 'ignore', VARIADIC NULL::text[]),
+ st_sum4ma(ARRAY[[1::double precision, NULL, 3]], '-8', VARIADIC NULL::text[]);
+
+SELECT
+ 'sum4ma.mode.no-null',
+ st_sum4ma(ARRAY[[1::double precision, 2, 3]], 'NULL', VARIADIC NULL::text[]),
+ st_sum4ma(ARRAY[[1::double precision, 2, 3]], 'value', VARIADIC NULL::text[]);
+
+SELECT
+ 'sum4ma.runtime-3d',
+ st_sum4ma('{{{1,2,3},{4,5,6}}}'::double precision[][], NULL, VARIADIC NULL::text[]);
+
DROP TABLE IF EXISTS raster_value_arrays;
DROP FUNCTION IF EXISTS make_value_array(integer, integer, double precision, double precision, text);
diff --git a/raster/test/regress/rt_4ma_expected b/raster/test/regress/rt_4ma_expected
index d6ec1c2b2..c91079c10 100644
--- a/raster/test/regress/rt_4ma_expected
+++ b/raster/test/regress/rt_4ma_expected
@@ -15,3 +15,6 @@ NOTICE: table "raster_value_arrays" does not exist, skipping
16|{{{1,3.1,5.2},{NULL,NULL,11.5},{13.6,NULL,NULL}}}|5.000000|13.600000|6.880000|1.000000|12.600000|5.435715|34.400000
17|{{{NULL,3.14,NULL},{NULL,12.56,NULL},{NULL,NULL,25.12}}}|3.000000|25.120000|13.606667|3.140000|21.980000|11.027318|40.820000
18|{{{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,9}}}|1.000000|9.000000|9.000000|9.000000|0.000000||9.000000
+sum4ma.nodata|t|4|-4
+sum4ma.mode.no-null|6|6
+sum4ma.runtime-3d|21
-----------------------------------------------------------------------
Summary of changes:
NEWS | 2 +
raster/rt_pg/rtpg_mapalgebra.c | 85 +++++++++++++++++++++++++++++++++++++
raster/rt_pg/rtpostgis.sql.in | 27 ++----------
raster/test/regress/rt_4ma.sql | 15 +++++++
raster/test/regress/rt_4ma_expected | 3 ++
5 files changed, 108 insertions(+), 24 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list