]> granicus.if.org Git - postgis/commitdiff
In preparation of turning the table raster_columns into a view, refactored ST_BandMet...
authorBborie Park <bkpark at ucdavis.edu>
Tue, 29 Nov 2011 23:25:49 +0000 (23:25 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Tue, 29 Nov 2011 23:25:49 +0000 (23:25 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8259 b70326c6-7e19-0410-871a-916f4a2858ee

raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/test/regress/rt_bandmetadata.sql
raster/test/regress/rt_bandmetadata_expected

index 6aaff2cce2df420201d60bb8ea92c012ecfd4667..da5712b301f84e242171e0aae93e2784607ad8de 100644 (file)
@@ -3386,6 +3386,7 @@ Datum RASTER_band(PG_FUNCTION_ARGS)
        int *dims;
        int *lbs;
 
+       uint32_t numBands;
        uint32_t *bandNums;
        uint32 idx = 0;
        int n;
@@ -3409,6 +3410,8 @@ Datum RASTER_band(PG_FUNCTION_ARGS)
        do {
                if (skip) break;
 
+               numBands = rt_raster_get_num_bands(raster);
+
                array = PG_GETARG_ARRAYTYPE_P(1);
                etype = ARR_ELEMTYPE(array);
                get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
@@ -3445,7 +3448,7 @@ Datum RASTER_band(PG_FUNCTION_ARGS)
                        }
 
                        POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
-                       if (idx > pgraster->numBands || idx < 1) {
+                       if (idx > numBands || idx < 1) {
         elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
                                skip = TRUE;
                                break;
@@ -3958,7 +3961,7 @@ Datum RASTER_histogram(PG_FUNCTION_ARGS)
                raster = rt_raster_deserialize(pgraster, FALSE);
                if (!raster) {
                        elog(ERROR, "RASTER_histogram: Could not deserialize raster");
-                       PG_RETURN_NULL();
+                       SRF_RETURN_DONE(funcctx);
                }
 
                /* band index is 1-based */
@@ -7660,133 +7663,248 @@ Datum RASTER_metadata(PG_FUNCTION_ARGS)
 }
 
 /**
- * Get raster band's meta data
+ * Get raster bands' meta data
  */
 PG_FUNCTION_INFO_V1(RASTER_bandmetadata);
 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
 {
-       rt_pgraster *pgraster = NULL;
-       rt_raster raster = NULL;
-       rt_band band = NULL;
+       FuncCallContext *funcctx;
+       TupleDesc tupdesc;
+       int call_cntr;
+       int max_calls;
 
-       uint32_t numBands;
-       uint32_t bandindex = 1;
-       const char *tmp = NULL;
-       char *pixtypename = NULL;
-       bool hasnodatavalue = FALSE;
-       double nodatavalue;
-       char *bandpath = NULL;
-       bool isoutdb = FALSE;
+       struct bandmetadata {
+               uint32_t bandnum;
+               char *pixeltype;
+               bool hasnodata;
+               double nodataval;
+               bool isoutdb;
+               char *bandpath;
+       };
+       struct bandmetadata *bmd = NULL;
+       struct bandmetadata *bmd2 = NULL;
 
-       TupleDesc tupdesc;
        bool *nulls = NULL;
-       int values_length = 5;
+       int values_length = 6;
        Datum values[values_length];
        HeapTuple tuple;
        Datum result;
 
-       POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
+       if (SRF_IS_FIRSTCALL()) {
+               MemoryContext oldcontext;
 
-       /* pgraster is null, return null */
-       if (PG_ARGISNULL(0)) PG_RETURN_NULL();
-       pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               rt_pgraster *pgraster = NULL;
+               rt_raster raster = NULL;
+               rt_band band = NULL;
 
-       /* raster */
-       raster = rt_raster_deserialize(pgraster, FALSE);
-       if (!raster) {
-               elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
-               PG_RETURN_NULL();
-       }
+               ArrayType *array;
+               Oid etype;
+               Datum *e;
+               bool *nulls;
+               int16 typlen;
+               bool typbyval;
+               char typalign;
+               int ndims = 1;
+               int *dims;
+               int *lbs;
+               int i = 0;
+               int j = 0;
+               int n = 0;
 
-       /* numbands */
-       numBands = rt_raster_get_num_bands(raster);
-       if (numBands < 1) {
-               elog(NOTICE, "Raster provided has no bands");
-               rt_raster_destroy(raster);
-               PG_RETURN_NULL();
-       }
+               uint32_t numBands;
+               uint32_t idx = 1;
+               uint32_t *bandNums = NULL;
+               const char *tmp = NULL;
 
-       /* band index */
-       if (!PG_ARGISNULL(1)) {
-               bandindex = PG_GETARG_INT32(1);
-               if (bandindex < 1 || bandindex > numBands) {
-                       elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+               POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
+
+               /* create a function context for cross-call persistence */
+               funcctx = SRF_FIRSTCALL_INIT();
+
+               /* switch to memory context appropriate for multiple function calls */
+               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+               /* pgraster is null, return null */
+               if (PG_ARGISNULL(0)) SRF_RETURN_DONE(funcctx);
+               pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+               /* raster */
+               raster = rt_raster_deserialize(pgraster, FALSE);
+               if (!raster) {
+                       elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
+                       SRF_RETURN_DONE(funcctx);
+               }
+
+               /* numbands */
+               numBands = rt_raster_get_num_bands(raster);
+               if (numBands < 1) {
+                       elog(NOTICE, "Raster provided has no bands");
                        rt_raster_destroy(raster);
-                       PG_RETURN_NULL();
+                       SRF_RETURN_DONE(funcctx);
                }
-       }
 
-       band = rt_raster_get_band(raster, bandindex - 1);
-       if (NULL == band) {
-               elog(NOTICE, "Could not get raster band at index %d", bandindex);
-               rt_raster_destroy(raster);
-               PG_RETURN_NULL();
-       }
+               /* band index */
+               array = PG_GETARG_ARRAYTYPE_P(1);
+               etype = ARR_ELEMTYPE(array);
+               get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
 
-       /* pixeltype */
-       tmp = rt_pixtype_name(rt_band_get_pixtype(band));
-       pixtypename = palloc(sizeof(char) * (strlen(tmp) + 1));
-       strncpy(pixtypename, tmp, strlen(tmp) + 1);
+               switch (etype) {
+                       case INT2OID:
+                       case INT4OID:
+                               break;
+                       default:
+                               elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
+                               rt_raster_destroy(raster);
+                               SRF_RETURN_DONE(funcctx);
+                               break;
+               }
 
-       /* hasnodatavalue */
-       if (rt_band_get_hasnodata_flag(band)) hasnodatavalue = TRUE;
+               ndims = ARR_NDIM(array);
+               dims = ARR_DIMS(array);
+               lbs = ARR_LBOUND(array);
 
-       /* nodatavalue */
-       if (hasnodatavalue)
-               nodatavalue = rt_band_get_nodata(band);
-       else
-               nodatavalue = 0;
+               deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
+                       &nulls, &n);
 
-       /* path */
-       tmp = rt_band_get_ext_path(band);
-       if (tmp) {
-               bandpath = palloc(sizeof(char) * (strlen(tmp) + 1));
-               strncpy(bandpath, tmp, strlen(tmp) + 1);
-       }
+               bandNums = palloc(sizeof(uint32_t) * n);
+               for (i = 0, j = 0; i < n; i++) {
+                       if (nulls[i]) continue;
 
-       /* isoutdb */
-       isoutdb = bandpath ? TRUE : FALSE;
+                       switch (etype) {
+                               case INT2OID:
+                                       idx = (uint32_t) DatumGetInt16(e[i]);
+                                       break;
+                               case INT4OID:
+                                       idx = (uint32_t) DatumGetInt32(e[i]);
+                                       break;
+                       }
 
-       rt_band_destroy(band);
-       rt_raster_destroy(raster);
+                       POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
+                       if (idx > numBands || idx < 1) {
+                               elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
+                               pfree(bandNums);
+                               rt_raster_destroy(raster);
+                               SRF_RETURN_DONE(funcctx);
+                       }
 
-       /* Build a tuple descriptor for our result type */
-       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
-               ereport(ERROR, (
-                       errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                       errmsg(
-                               "function returning record called in context "
-                               "that cannot accept type record"
-                       )
-               ));
+                       bandNums[j] = idx;
+                       POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
+                       j++;
+               }
+
+               if (j < n)
+                       bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
+               bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata) * j);
+
+               for (i = 0; i < j; i++) {
+                       band = rt_raster_get_band(raster, bandNums[i] - 1);
+                       if (NULL == band) {
+                               elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
+                               rt_raster_destroy(raster);
+                               SRF_RETURN_DONE(funcctx);
+                       }
+
+                       /* bandnum */
+                       bmd[i].bandnum = bandNums[i];
+
+                       /* pixeltype */
+                       tmp = rt_pixtype_name(rt_band_get_pixtype(band));
+                       bmd[i].pixeltype = palloc(sizeof(char) * (strlen(tmp) + 1));
+                       strncpy(bmd[i].pixeltype, tmp, strlen(tmp) + 1);
+
+                       /* hasnodatavalue */
+                       if (rt_band_get_hasnodata_flag(band))
+                               bmd[i].hasnodata = TRUE;
+                       else
+                               bmd[i].hasnodata = FALSE;
+
+                       /* nodatavalue */
+                       if (bmd[i].hasnodata)
+                               bmd[i].nodataval = rt_band_get_nodata(band);
+                       else
+                               bmd[i].nodataval = 0;
+
+                       /* path */
+                       tmp = rt_band_get_ext_path(band);
+                       if (tmp) {
+                               bmd[i].bandpath = palloc(sizeof(char) * (strlen(tmp) + 1));
+                               strncpy(bmd[i].bandpath, tmp, strlen(tmp) + 1);
+                       }
+                       else
+                               bmd[i].bandpath = NULL;
+
+                       /* isoutdb */
+                       bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
+
+                       rt_band_destroy(band);
+               }
+
+               rt_raster_destroy(raster);
+
+               /* Store needed information */
+               funcctx->user_fctx = bmd;
+
+               /* total number of tuples to be returned */
+               funcctx->max_calls = j;
+
+               /* Build a tuple descriptor for our result type */
+               if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
+                       ereport(ERROR, (
+                               errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                               errmsg(
+                                       "function returning record called in context "
+                                       "that cannot accept type record"
+                               )
+                       ));
+               }
+
+               BlessTupleDesc(tupdesc);
+               funcctx->tuple_desc = tupdesc;
+
+               MemoryContextSwitchTo(oldcontext);
        }
 
-       BlessTupleDesc(tupdesc);
+       /* stuff done on every call of the function */
+       funcctx = SRF_PERCALL_SETUP();
 
-       nulls = palloc(sizeof(bool) * values_length);
-       memset(nulls, FALSE, values_length);
+       call_cntr = funcctx->call_cntr;
+       max_calls = funcctx->max_calls;
+       tupdesc = funcctx->tuple_desc;
+       bmd2 = funcctx->user_fctx;
 
-       values[0] = CStringGetTextDatum(pixtypename);
-       values[1] = BoolGetDatum(hasnodatavalue);
-       values[2] = Float8GetDatum(nodatavalue);
-       values[3] = BoolGetDatum(isoutdb);
-       if (bandpath && strlen(bandpath))
-               values[4] = CStringGetTextDatum(bandpath);
-       else
-               nulls[4] = TRUE;
+       /* do when there is more left to send */
+       if (call_cntr < max_calls) {
+               nulls = palloc(sizeof(bool) * values_length);
+               memset(nulls, FALSE, values_length);
 
-       /* build a tuple */
-       tuple = heap_form_tuple(tupdesc, values, nulls);
+               values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
+               values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
+               values[2] = BoolGetDatum(bmd2[call_cntr].hasnodata);
+               values[3] = Float8GetDatum(bmd2[call_cntr].nodataval);
+               values[4] = BoolGetDatum(bmd2[call_cntr].isoutdb);
+               if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath))
+                       values[5] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
+               else
+                       nulls[5] = TRUE;
 
-       /* make the tuple into a datum */
-       result = HeapTupleGetDatum(tuple);
+               /* build a tuple */
+               tuple = heap_form_tuple(tupdesc, values, nulls);
 
-       /* clean up */
-       pfree(nulls);
-       pfree(pixtypename);
-       if (bandpath) pfree(bandpath);
+               /* make the tuple into a datum */
+               result = HeapTupleGetDatum(tuple);
 
-       PG_RETURN_DATUM(result);
+               /* clean up */
+               pfree(nulls);
+               pfree(bmd2[call_cntr].pixeltype);
+               if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
+
+               SRF_RETURN_NEXT(funcctx, result);
+       }
+       /* do when there is no more left */
+       else {
+               pfree(bmd2);
+               SRF_RETURN_DONE(funcctx);
+       }
 }
 
 /**
index e5f61f7f1acc273cdeac7aa1b4891644f9db43f4..c61f0ddbf8579ea38d3291dc5dcf0f4871f79c34 100644 (file)
@@ -1837,6 +1837,23 @@ CREATE OR REPLACE FUNCTION st_bandpixeltype(rast raster, band integer DEFAULT 1)
     AS 'MODULE_PATHNAME','RASTER_getBandPixelTypeName'
     LANGUAGE 'C' IMMUTABLE STRICT;
 
+CREATE TYPE bandmetadata AS (
+       bandnum int,
+       pixeltype text,
+       hasnodata boolean,
+       nodatavalue double precision,
+       isoutdb boolean,
+       path text
+);
+
+CREATE OR REPLACE FUNCTION st_bandmetadata(
+       rast raster,
+       VARIADIC band int[]
+)
+       RETURNS SETOF bandmetadata
+       AS 'MODULE_PATHNAME','RASTER_bandmetadata'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
 CREATE OR REPLACE FUNCTION st_bandmetadata(
        rast raster,
        band int DEFAULT 1,
@@ -1846,8 +1863,8 @@ CREATE OR REPLACE FUNCTION st_bandmetadata(
        OUT isoutdb boolean,
        OUT path text
 )
-       AS 'MODULE_PATHNAME','RASTER_bandmetadata'
-       LANGUAGE 'C' IMMUTABLE STRICT;
+       AS $$ SELECT pixeltype, hasnodata, nodatavalue, isoutdb, path FROM st_bandmetadata($1, VARIADIC ARRAY[$2]::int[]) LIMIT 1 $$
+       LANGUAGE 'sql' IMMUTABLE STRICT;
 
 -----------------------------------------------------------------------
 -- Raster Pixel Accessors
index ef4ca754f910df610912c86d02cfe739d14ba838..071f0a016166649c340928e948fffb4b3e4cfccb 100644 (file)
@@ -1,3 +1,38 @@
+CREATE OR REPLACE FUNCTION make_test_raster(
+       width integer DEFAULT 10,
+       height integer DEFAULT 10,
+       ul_x double precision DEFAULT 0,
+       ul_y double precision DEFAULT 0,
+       skew_x double precision DEFAULT 0,
+       skew_y double precision DEFAULT 0,
+       numbands integer DEFAULT 1,
+       autofill boolean DEFAULT FALSE
+)
+       RETURNS raster
+       AS $$
+       DECLARE
+               i int;
+               x int;
+               y int;
+               rast raster;
+       BEGIN
+               rast := ST_MakeEmptyRaster(width, height, ul_x, ul_y, 1, 1, skew_x, skew_y, 0);
+               FOR i IN 1..numbands LOOP
+                       rast := ST_AddBand(rast, i, '8BUI', 0, i);
+
+                       IF autofill IS TRUE THEN
+                               FOR x IN 1..width LOOP
+                                       FOR y IN 1..height LOOP
+                                               rast := ST_SetValue(rast, i, x, y, ((x - 1) * width) + y);
+                                       END LOOP;
+                               END LOOP;
+                       END IF;
+               END LOOP;
+
+               RETURN rast;
+       END;
+       $$ LANGUAGE 'plpgsql';
+
 SELECT
        pixeltype,
        hasnodata,
@@ -5,20 +40,9 @@ SELECT
        isoutdb,
        path
 FROM ST_BandMetaData(
-       ST_SetValue(
-               ST_SetValue(
-                       ST_SetValue(
-                               ST_AddBand(
-                                       ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0,-1)
-                                       , 1, '64BF', 0, 0
-                               )
-                               , 1, 1, 1, -10
-                       )
-                       , 1, 5, 4, 0
-               )
-               , 1, 5, 5, 3.14159
-       )
+       make_test_raster(10, 10, 0, 0, 0, 0)
 );
+
 SELECT
        pixeltype,
        hasnodata,
@@ -26,21 +50,10 @@ SELECT
        isoutdb,
        path
 FROM ST_BandMetaData(
-       ST_SetValue(
-               ST_SetValue(
-                       ST_SetValue(
-                               ST_AddBand(
-                                       ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0,-1)
-                                       , 1, '64BF', 0, 0
-                               )
-                               , 1, 1, 1, -10
-                       )
-                       , 1, 5, 4, 0
-               )
-               , 1, 5, 5, 3.14159
-       ),
-       1
+       make_test_raster(10, 10, 0, 0, 0, 0, 2),
+       2
 );
+
 SELECT
        pixeltype,
        hasnodata,
@@ -48,18 +61,51 @@ SELECT
        isoutdb,
        path
 FROM ST_BandMetaData(
-       ST_SetValue(
-               ST_SetValue(
-                       ST_SetValue(
-                               ST_AddBand(
-                                       ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0,-1)
-                                       , 1, '64BF', 0, 0
-                               )
-                               , 1, 1, 1, -10
-                       )
-                       , 1, 5, 4, 0
-               )
-               , 1, 5, 5, 3.14159
-       ),
-       2
+       make_test_raster(10, 10, 0, 0, 0, 0, 3, TRUE),
+       3
+);
+
+SELECT
+       pixeltype,
+       hasnodata,
+       round(nodatavalue::numeric, 3),
+       isoutdb,
+       path
+FROM ST_BandMetaData(
+       make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
+       4
+);
+
+SELECT
+       pixeltype,
+       hasnodata,
+       round(nodatavalue::numeric, 3),
+       isoutdb,
+       path
+FROM ST_BandMetaData(
+       make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
+       6
+);
+
+SELECT
+       bandnum
+       pixeltype,
+       hasnodata,
+       round(nodatavalue::numeric, 3),
+       isoutdb,
+       path
+FROM ST_BandMetaData(
+       make_test_raster(10, 10, 0, 0, 0, 0, 5, TRUE),
+       1,2,5
+);
+
+DROP FUNCTION IF EXISTS make_test_raster(
+       integer,
+       integer,
+       double precision,
+       double precision,
+       double precision,
+       double precision,
+       integer,
+       boolean
 );
index 4824dbc28b9fe61bd304b7e7b3531f53ff5985db..076218fc7fb2bc485a70e0a1fed6cfebed3d04d2 100644 (file)
@@ -1,4 +1,9 @@
-64BF|t|0.000|f|
-64BF|t|0.000|f|
-NOTICE:  Invalid band index (must use 1-based). Returning NULL
+8BUI|t|1.000|f|
+8BUI|t|2.000|f|
+8BUI|t|3.000|f|
+8BUI|t|4.000|f|
+NOTICE:  Invalid band index: 6. Indices must be 1-based. Returning NULL
 ||||
+1|t|1.000|f|
+2|t|2.000|f|
+5|t|5.000|f|