]> granicus.if.org Git - postgis/commitdiff
Add ST_CountAgg(). Ticket #2567
authorBborie Park <bkpark at ucdavis.edu>
Sun, 15 Dec 2013 19:24:35 +0000 (19:24 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Sun, 15 Dec 2013 19:24:35 +0000 (19:24 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@12161 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
doc/reference_raster.xml
raster/rt_pg/rtpostgis.sql.in
raster/rt_pg/rtpostgis_drop.sql.in
raster/test/regress/rt_count.sql
raster/test/regress/rt_count_expected

diff --git a/NEWS b/NEWS
index 9309047f443e3af0f4b595ab82fd2b546aebd86b..acf5cbf9ff495d3600f07173460d450e9b55d38b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,10 +5,12 @@ PostGIS 2.2.0
 
   - #2565, ST_SummaryStats(tablename, rastercolumn, ...) uses
            ST_SummaryStatsAgg()
+  - #2567, ST_Count(tablename, rastercolumn, ...) uses ST_CountAgg()
 
  * Deprecated signatures *
 
   - #2565, ST_SummaryStats(tablename, rastercolumn, ...)
+  - #2567, ST_Count(tablename, rastercolumn, ...)
 
  * New Features *
 
@@ -18,6 +20,7 @@ PostGIS 2.2.0
     variable GDAL_DATA
   - #2397, read encoding info automatically in shapefile loader
   - #2565, ST_SummaryStatsAgg()
+  - #2567, ST_CountAgg()
 
  * Enhancements *
 
index f9bc5f03a7811966fe8a10141d8eb91a54b9f76f..7bbeb9bde82ab5d8313c8b4dfd075a045586084a 100644 (file)
@@ -6593,6 +6593,7 @@ select st_bandisnodata(rast, 1) from dummy_rast where rid = 1; -- Expected true
        
        <sect1 id="RasterBand_Stats">
            <title>Raster Band Statistics and Analytics</title>
+
                <refentry id="RT_ST_Count">
                        <refnamediv>
                                <refname>ST_Count</refname>
@@ -6634,6 +6635,13 @@ select st_bandisnodata(rast, 1) from dummy_rast where rid = 1; -- Expected true
                                <para>Returns the number of pixels in a given band of a raster or raster coverage.  If no band is specified <varname>nband</varname> defaults to 1. </para> 
                                <note><para>If <varname>exclude_nodata_value</varname> is set to true, will only count pixels with value not equal to the <varname>nodata</varname> value of the raster. Set <varname>exclude_nodata_value</varname> to false to get count all pixels</para></note>
                                <para>Availability: 2.0.0 </para>
+
+                               <warning>
+                                       <para>
+                                               The ST_Count(rastertable, rastercolumn, ...) variants are deprecated as of 2.2.0. Use <xref linkend="RT_ST_CountAgg" /> instead.
+                                       </para>
+                               </warning>
+
                        </refsection>
                                
                        <refsection>
@@ -6653,7 +6661,104 @@ rid | exclude_nodata | include_nodata
 
                        <refsection>
                                <title>See Also</title>
-                               <para><xref linkend="RT_ST_SetBandNoDataValue" /></para>
+                               <para>
+                                       <xref linkend="RT_ST_CountAgg" />, 
+                                       <xref linkend="RT_ST_SummaryStats" />, 
+                                       <xref linkend="RT_ST_SetBandNoDataValue" />
+                               </para>
+                       </refsection>
+               </refentry>
+               
+         <refentry id="RT_ST_CountAgg">
+                       <refnamediv>
+                               <refname>ST_CountAgg</refname>
+                               <refpurpose>
+                                       Aggregate. Returns the number of pixels in a given band of a set of rasters. If no band is specified defaults to band 1. If exclude_nodata_value is set to true, will only count pixels that are not equal to the NODATA value.
+                               </refpurpose>
+                       </refnamediv>
+               
+                       <refsynopsisdiv>
+                               <funcsynopsis>
+                                       <funcprototype>
+                                               <funcdef>bigint <function>ST_CountAgg</function></funcdef>
+                                               <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>integer </type> <parameter>nband</parameter></paramdef>
+                                               <paramdef><type>boolean </type> <parameter>exclude_nodata_value</parameter></paramdef>
+                                               <paramdef><type>double precision </type> <parameter>sample_percent</parameter></paramdef>
+                                       </funcprototype>
+
+                                       <funcprototype>
+                                               <funcdef>bigint <function>ST_CountAgg</function></funcdef>
+                                               <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>integer </type> <parameter>nband</parameter></paramdef>
+                                               <paramdef><type>boolean </type> <parameter>exclude_nodata_value</parameter></paramdef>
+                                       </funcprototype>
+
+                                       <funcprototype>
+                                               <funcdef>bigint <function>ST_CountAgg</function></funcdef>
+                                               <paramdef><type>raster </type> <parameter>rast</parameter></paramdef>
+                                               <paramdef><type>boolean </type> <parameter>exclude_nodata_value</parameter></paramdef>
+                                       </funcprototype>
+
+                               </funcsynopsis>
+                       </refsynopsisdiv>
+               
+                       <refsection>
+                               <title>Description</title>
+                               
+                               <para>Returns the number of pixels in a given band of a set of rasters.  If no band is specified <varname>nband</varname> defaults to 1.</para> 
+                               <para>
+                                       If <varname>exclude_nodata_value</varname> is set to true, will only count pixels with value not equal to the <varname>NODATA</varname> value of the raster. Set <varname>exclude_nodata_value</varname> to false to get count all pixels
+                               </para>
+                               <para>By default will sample all pixels. To get faster response, set <varname>sample_percent</varname> to value between zero (0) and one (1)</para>
+
+                               <para>Availability: 2.2.0 </para>
+                       </refsection>
+                               
+                       <refsection>
+                               <title>Examples</title>
+                               <programlisting>
+WITH foo AS (
+       SELECT
+               rast.rast
+       FROM (
+               SELECT ST_SetValue(
+                       ST_SetValue(
+                               ST_SetValue(
+                                       ST_AddBand(
+                                               ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0,0)
+                                               , 1, '64BF', 0, 0
+                                       )
+                                       , 1, 1, 1, -10
+                               )
+                               , 1, 5, 4, 0
+                       )
+                       , 1, 5, 5, 3.14159
+               ) AS rast
+       ) AS rast
+       FULL JOIN (
+               SELECT generate_series(1, 10) AS id
+       ) AS id
+               ON 1 = 1
+)
+SELECT
+       ST_CountAgg(rast, 1, TRUE)
+FROM foo;
+
+ st_countagg 
+-------------
+          20
+(1 row)
+                               </programlisting>       
+                       </refsection>
+
+                       <refsection>
+                               <title>See Also</title>
+                               <para>
+                                       <xref linkend="RT_ST_Count" />, 
+                                       <xref linkend="RT_ST_SummaryStats" />, 
+                                       <xref linkend="RT_ST_SetBandNoDataValue" />
+                               </para>
                        </refsection>
                </refentry>
                
index 16c03fd592d68922d807295296da281f57f63836..d50ab37e32ade2c4a368e54a32c65f4a5042ab62 100644 (file)
@@ -551,7 +551,7 @@ CREATE OR REPLACE FUNCTION _st_summarystats(
                stats summarystats;
        BEGIN
                EXECUTE 'SELECT (stats).* FROM (SELECT ST_SummaryStatsAgg('
-                       || $2 || ', '
+                       || quote_ident($2) || ', '
                        || $3 || ', '
                        || $4 || ', '
                        || $5 || ') AS stats '
@@ -620,10 +620,10 @@ CREATE OR REPLACE FUNCTION st_approxsummarystats(
        AS $$ SELECT _st_summarystats($1, $2, 1, TRUE, $3) $$
        LANGUAGE 'sql' STABLE STRICT;
 
-
 -----------------------------------------------------------------------
 -- ST_Count and ST_ApproxCount
 -----------------------------------------------------------------------
+
 CREATE OR REPLACE FUNCTION _st_count(rast raster, nband int DEFAULT 1, exclude_nodata_value boolean DEFAULT TRUE, sample_percent double precision DEFAULT 1)
        RETURNS bigint
        AS $$
@@ -670,69 +670,190 @@ CREATE OR REPLACE FUNCTION st_approxcount(rast raster, sample_percent double pre
        AS $$ SELECT _st_count($1, 1, TRUE, $2) $$
        LANGUAGE 'sql' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION _st_count(rastertable text, rastercolumn text, nband integer DEFAULT 1, exclude_nodata_value boolean DEFAULT TRUE, sample_percent double precision DEFAULT 1)
+-----------------------------------------------------------------------
+-- ST_CountAgg
+-----------------------------------------------------------------------
+
+CREATE TYPE agg_count AS (
+       count bigint,
+       nband integer,
+       exclude_nodata_value boolean,
+       sample_percent double precision
+);
+
+CREATE OR REPLACE FUNCTION _st_countagg_finalfn(agg agg_count)
        RETURNS bigint
        AS $$
-       DECLARE
-               curs refcursor;
+       BEGIN
+               IF agg IS NULL THEN
+                       RAISE EXCEPTION 'Cannot count coverage';
+               END IF;
 
-               ctable text;
-               ccolumn text;
-               rast raster;
+               RETURN agg.count;
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
 
-               rtn bigint;
-               tmp bigint;
+CREATE OR REPLACE FUNCTION __st_countagg_transfn(
+       agg agg_count,
+       rast raster,
+       nband integer DEFAULT 1, exclude_nodata_value boolean DEFAULT TRUE,
+       sample_percent double precision DEFAULT 1
+)
+       RETURNS agg_count
+       AS $$
+       DECLARE
+               _count bigint;
+               rtn_agg agg_count;
        BEGIN
-               -- nband
-               IF nband < 1 THEN
-                       RAISE WARNING 'Invalid band index (must use 1-based). Returning NULL';
-                       RETURN NULL;
-               END IF;
 
-               -- sample percent
-               IF sample_percent < 0 OR sample_percent > 1 THEN
-                       RAISE WARNING 'Invalid sample percentage (must be between 0 and 1). Returning NULL';
-                       RETURN NULL;
+               -- only process parameter args once
+               IF agg IS NULL THEN
+                       rtn_agg.count := 0;
+
+                       IF nband < 1 THEN
+                               RAISE EXCEPTION 'Band index must be greater than zero (1-based)';
+                       ELSE
+                               rtn_agg.nband := nband;
+                       END IF;
+
+                       IF exclude_nodata_value IS FALSE THEN
+                               rtn_agg.exclude_nodata_value := FALSE;
+                       ELSE
+                               rtn_agg.exclude_nodata_value := TRUE;
+                       END IF;
+
+                       IF sample_percent < 0. OR sample_percent > 1. THEN
+                               RAISE EXCEPTION 'Sample percent must be between zero and one';
+                       ELSE
+                               rtn_agg.sample_percent := sample_percent;
+                       END IF;
+               ELSE
+                       rtn_agg := agg;
                END IF;
 
-               -- exclude_nodata_value IS TRUE
-               IF exclude_nodata_value IS TRUE THEN
-                       SELECT count INTO rtn FROM _st_summarystats($1, $2, $3, $4, $5);
-                       RETURN rtn;
+               IF rast IS NOT NULL THEN
+                       IF rtn_agg.exclude_nodata_value IS FALSE THEN
+                               SELECT width * height INTO _count FROM ST_Metadata(rast);
+                       ELSE
+                               SELECT count INTO _count FROM _st_summarystats(
+                                       rast,
+                                       rtn_agg.nband, rtn_agg.exclude_nodata_value,
+                                       rtn_agg.sample_percent
+                               );
+                       END IF;
                END IF;
 
-               -- clean rastertable and rastercolumn
-               ctable := quote_ident(rastertable);
-               ccolumn := quote_ident(rastercolumn);
+               rtn_agg.count := rtn_agg.count + _count;
+               RETURN rtn_agg;
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
 
-               BEGIN
-                       OPEN curs FOR EXECUTE 'SELECT '
-                                       || ccolumn
-                                       || ' FROM '
-                                       || ctable
-                                       || ' WHERE '
-                                       || ccolumn
-                                       || ' IS NOT NULL';
-               EXCEPTION
-                       WHEN OTHERS THEN
-                               RAISE WARNING 'Invalid table or column name. Returning NULL';
-                               RETURN NULL;
-               END;
+CREATE OR REPLACE FUNCTION _st_countagg_transfn(
+       agg agg_count,
+       rast raster,
+       nband integer, exclude_nodata_value boolean,
+       sample_percent double precision
+)
+       RETURNS agg_count
+       AS $$
+       DECLARE
+               rtn_agg agg_count;
+       BEGIN
+               rtn_agg := __st_countagg_transfn(
+                       agg,
+                       rast,
+                       nband, exclude_nodata_value,
+                       sample_percent
+               );
+               RETURN rtn_agg;
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
 
-               rtn := 0;
-               LOOP
-                       FETCH curs INTO rast;
-                       EXIT WHEN NOT FOUND;
+CREATE AGGREGATE st_countagg(
+       raster,
+       integer, boolean,
+       double precision
+) (
+       SFUNC = _st_countagg_transfn,
+       STYPE = agg_count,
+       FINALFUNC = _st_countagg_finalfn
+);
 
-                       SELECT (width * height) INTO tmp FROM ST_Metadata(rast);
-                       rtn := rtn + tmp;
-               END LOOP;
+CREATE OR REPLACE FUNCTION _st_countagg_transfn(
+       agg agg_count,
+       rast raster,
+       nband integer, exclude_nodata_value boolean
+)
+       RETURNS agg_count
+       AS $$
+       DECLARE
+               rtn_agg agg_count;
+       BEGIN
+               rtn_agg := __st_countagg_transfn(
+                       agg,
+                       rast,
+                       nband, exclude_nodata_value,
+                       1
+               );
+               RETURN rtn_agg;
+       END;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
 
-               CLOSE curs;
+CREATE AGGREGATE st_countagg(
+       raster,
+       integer, boolean
+) (
+       SFUNC = _st_countagg_transfn,
+       STYPE = agg_count,
+       FINALFUNC = _st_countagg_finalfn
+);
 
-               RETURN rtn;
+CREATE OR REPLACE FUNCTION _st_countagg_transfn(
+       agg agg_count,
+       rast raster,
+       exclude_nodata_value boolean
+)
+       RETURNS agg_count
+       AS $$
+       DECLARE
+               rtn_agg agg_count;
+       BEGIN
+               rtn_agg := __st_countagg_transfn(
+                       agg,
+                       rast,
+                       1, exclude_nodata_value,
+                       1
+               );
+               RETURN rtn_agg;
        END;
-       $$ LANGUAGE 'plpgsql' STABLE STRICT;
+       $$ LANGUAGE 'plpgsql' IMMUTABLE;
+
+CREATE AGGREGATE st_countagg(raster, boolean) (
+       SFUNC = _st_countagg_transfn,
+       STYPE = agg_count,
+       FINALFUNC = _st_countagg_finalfn
+);
+
+-----------------------------------------------------------------------
+-- ST_Count for table
+-----------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION _st_count(rastertable text, rastercolumn text, nband integer DEFAULT 1, exclude_nodata_value boolean DEFAULT TRUE, sample_percent double precision DEFAULT 1)
+       RETURNS bigint
+       AS $$
+       DECLARE
+               count bigint;
+       BEGIN
+               EXECUTE 'SELECT ST_CountAgg('
+                       || quote_ident($2) || ', '
+                       || $3 || ', '
+                       || $4 || ', '
+                       || $5 || ') '
+                       || 'FROM ' || quote_ident($1)
+               INTO count;
+               RETURN count;
+       END;
+       $$ LANGUAGE 'plpgsql' STABLE STRICT;
 
 CREATE OR REPLACE FUNCTION st_count(rastertable text, rastercolumn text, nband int DEFAULT 1, exclude_nodata_value boolean DEFAULT TRUE)
        RETURNS bigint
@@ -767,6 +888,7 @@ CREATE OR REPLACE FUNCTION st_approxcount(rastertable text, rastercolumn text, s
 -----------------------------------------------------------------------
 -- ST_Histogram and ST_ApproxHistogram
 -----------------------------------------------------------------------
+
 -- Cannot be strict as "width", "min" and "max" can be NULL
 CREATE OR REPLACE FUNCTION _st_histogram(
        rast raster, nband int DEFAULT 1,
index 86f7118389d7b5bd82acfa61534ec2d97fb97d5a..5f20ab1ab22ef5753a84020322d2ac16c6ec17ad 100644 (file)
@@ -511,3 +511,8 @@ DROP FUNCTION IF EXISTS _st_slope4ma(float8[], text, text[]);
 DROP AGGREGATE IF EXISTS ST_SummaryStatsAgg(raster, integer, boolean, double precision);
 DROP AGGREGATE IF EXISTS ST_SummaryStatsAgg(raster, boolean, double precision);
 DROP AGGREGATE IF EXISTS ST_SummaryStatsAgg(raster, integer, boolean);
+
+-- drop aggregates
+DROP AGGREGATE IF EXISTS ST_CountAgg(raster, integer, boolean, double precision);
+DROP AGGREGATE IF EXISTS ST_CountAgg(raster, integer, boolean);
+DROP AGGREGATE IF EXISTS ST_CountAgg(raster, boolean);
index 39f7bd89485c6ce575763e740b42a199d3c78991..5c0c22be7918633ddd375e0643c80654cf20f8fa 100644 (file)
@@ -90,4 +90,24 @@ SELECT ST_Count('test', 'rast', 1, FALSE);
 SELECT ST_Count('test', 'rast', 1);
 SELECT ST_Count('test', 'rast', FALSE);
 SELECT ST_Count('test', 'rast');
+
+SELECT ST_CountAgg(rast, 1, TRUE, 1) FROM test;
+SELECT ST_CountAgg(rast, 1, TRUE, 0) FROM test;
+SELECT ST_CountAgg(rast, 1, FALSE, 1) FROM test;
+SELECT ST_CountAgg(rast, 1, FALSE, 0) FROM test;
+SELECT ST_CountAgg(rast, 1, TRUE) FROM test;
+SELECT ST_CountAgg(rast, 1, FALSE) FROM test;
+SELECT ST_CountAgg(rast, TRUE) FROM test;
+SELECT ST_CountAgg(rast, FALSE) FROM test;
+
+SAVEPOINT test;
+SELECT ST_CountAgg(rast, 2, TRUE) FROM test;
+ROLLBACK TO SAVEPOINT test;
+RELEASE SAVEPOINT test;
+
+SAVEPOINT test;
+SELECT ST_CountAgg(rast, 1, TRUE, 2) FROM test;
+ROLLBACK TO SAVEPOINT test;
+RELEASE SAVEPOINT test;
+
 ROLLBACK;
index 5e8f6c68994a1cf471a8fc2a2be763560d006165..11c5664a16d8361d30e755e48026f04a78daa26c 100644 (file)
@@ -8,4 +8,29 @@ BEGIN
 20
 1000
 20
+20
+20
+1000
+1000
+20
+1000
+20
+1000
+SAVEPOINT
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+COMMIT
+RELEASE
+SAVEPOINT
+ERROR:  Sample percent must be between zero and one
+COMMIT
+RELEASE
 COMMIT