]> granicus.if.org Git - postgis/commitdiff
Rewrote ST_BandMetaData to use a C function instead of sequential calls for the metad...
authorBborie Park <bkpark at ucdavis.edu>
Fri, 10 Jun 2011 15:19:03 +0000 (15:19 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Fri, 10 Jun 2011 15:19:03 +0000 (15:19 +0000)
Associated ticket #1012

git-svn-id: http://svn.osgeo.org/postgis/trunk@7357 b70326c6-7e19-0410-871a-916f4a2858ee

raster/rt_pg/rt_pg.c
raster/rt_pg/rtpostgis.sql.in.c
raster/test/regress/Makefile.in
raster/test/regress/rt_bandmetadata.sql [new file with mode: 0644]
raster/test/regress/rt_bandmetadata_expected [new file with mode: 0644]
raster/test/regress/rt_metadata.sql [new file with mode: 0644]
raster/test/regress/rt_metadata_expected [new file with mode: 0644]

index b9ef3a9436eb50df3030c5ebf2e6fde102453430..5710284244b5d855f2c37a19ef611c2e95e2d64f 100644 (file)
@@ -225,6 +225,9 @@ Datum RASTER_transform(PG_FUNCTION_ARGS);
 /* get raster's meta data */
 Datum RASTER_metadata(PG_FUNCTION_ARGS);
 
+/* get raster band's meta data */
+Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
+
 /* Replace function taken from
  * http://ubuntuforums.org/showthread.php?s=aa6f015109fd7e4c7e30d2fd8b717497&t=141670&page=3
  */
@@ -4955,7 +4958,8 @@ Datum RASTER_transform(PG_FUNCTION_ARGS)
  * Get raster's meta data
  */
 PG_FUNCTION_INFO_V1(RASTER_metadata);
-Datum RASTER_metadata(PG_FUNCTION_ARGS) {
+Datum RASTER_metadata(PG_FUNCTION_ARGS)
+{
        rt_pgraster *pgraster = NULL;
        rt_raster raster = NULL;
 
@@ -5127,6 +5131,172 @@ Datum RASTER_metadata(PG_FUNCTION_ARGS) {
        PG_RETURN_DATUM(result);
 }
 
+/**
+ * Get raster band's 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;
+
+       TupleDesc tupdesc;
+       AttInMetadata *attinmeta;
+
+       uint32_t numBands;
+       uint32_t bandindex = 1;
+       const char *pixtypename = NULL;
+       bool hasnodatavalue = FALSE;
+       double nodatavalue;
+       const char *bandpath = NULL;
+       bool isoutdb = FALSE;
+
+       int i = 0;
+       char **values = NULL;
+       int values_length = 5;
+       HeapTuple tuple;
+       Datum result;
+
+       POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
+
+       /* pgraster is null, return null */
+       if (PG_ARGISNULL(0)) PG_RETURN_NULL();
+       pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+       /* raster */
+       /* TODO: can be optimized to only detoast the header! */
+       raster = rt_raster_deserialize(pgraster);
+       if (!raster) {
+               elog(ERROR, "RASTER_transform: Could not deserialize raster");
+               PG_RETURN_NULL();
+       }
+
+       /* 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();
+       }
+
+       /* 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");
+                       rt_raster_destroy(raster);
+                       PG_RETURN_NULL();
+               }
+       }
+
+       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();
+       }
+
+       /* pixeltype */
+       pixtypename = rt_pixtype_name(rt_band_get_pixtype(band));
+
+       /* hasnodatavalue */
+       if (rt_band_get_hasnodata_flag(band)) hasnodatavalue = TRUE;
+
+       /* nodatavalue */
+       nodatavalue = rt_band_get_nodata(band);
+
+       /* path */
+       bandpath = rt_band_get_ext_path(band);
+
+       /* isoutdb */
+       isoutdb = bandpath ? TRUE : FALSE;
+
+       rt_band_destroy(band);
+       rt_raster_destroy(raster);
+       PG_FREE_IF_COPY(pgraster, 0);
+
+       /* 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"
+                       )
+               ));
+       }
+
+       /*
+        * generate attribute metadata needed later to produce tuples from raw
+        * C strings
+        */
+       attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+       /*
+        * Prepare a values array for building the returned tuple.
+        * This should be an array of C strings which will
+        * be processed later by the type input functions.
+        */
+       values = (char **) palloc(values_length * sizeof(char *));
+
+       values[0] = (char *) palloc(sizeof(char) * (strlen(pixtypename) + 1));
+       values[1] = (char *) palloc(sizeof(char) * (MAX_INT_CHARLEN + 1));
+       values[2] = (char *) palloc(sizeof(char) * (MAX_DBL_CHARLEN + 1));
+       values[3] = (char *) palloc(sizeof(char) * (MAX_INT_CHARLEN + 1));
+       if (bandpath)
+               values[4] = (char *) palloc(sizeof(char) * (strlen(bandpath) + 1));
+       else
+               values[4] = NULL;
+
+       snprintf(
+               values[0],
+               sizeof(char) * (strlen(pixtypename) + 1),
+               "%s",
+               pixtypename
+       );
+       snprintf(
+               values[1],
+               sizeof(char) * (MAX_INT_CHARLEN + 1),
+               "%d",
+               hasnodatavalue
+       );
+       snprintf(
+               values[2],
+               sizeof(char) * (MAX_DBL_CHARLEN + 1),
+               "%f",
+               nodatavalue
+       );
+       snprintf(
+               values[3],
+               sizeof(char) * (MAX_INT_CHARLEN + 1),
+               "%d",
+               isoutdb
+       );
+       if (bandpath) {
+               snprintf(
+                       values[4],
+                       sizeof(char) * (strlen(bandpath) + 1),
+                       "%s",
+                       bandpath
+               );
+       }
+
+       /* build a tuple */
+       tuple = BuildTupleFromCStrings(attinmeta, values);
+
+       /* make the tuple into a datum */
+       result = HeapTupleGetDatum(tuple);
+
+       /* clean up */
+       for (i = 0; i < values_length; i++) {
+               if (NULL != values[i]) pfree(values[i]);
+       }
+       pfree(values);
+
+       PG_RETURN_DATUM(result);
+}
+
 /* ---------------------------------------------------------------- */
 /*  Memory allocation / error reporting hooks                       */
 /* ---------------------------------------------------------------- */
index 39c05a95107c6ee19323382f5e006d8133b51c24..ff735094b4a1452c1a0a6e98d0f38ad3336e888f 100644 (file)
@@ -1837,36 +1837,17 @@ CREATE OR REPLACE FUNCTION st_bandpixeltype(raster)
     AS $$ SELECT st_bandpixeltype($1, 1) $$
     LANGUAGE SQL IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION st_bandmetadata(rast raster,
-                                           band int,
-                                           OUT pixeltype text,
-                                           OUT hasnodatavalue boolean,
-                                           OUT nodatavalue float4,
-                                           OUT isoutdb boolean,
-                                           OUT path text)
-    AS $$
-    SELECT st_bandpixeltype($1, $2),
-       st_bandnodatavalue($1, $2) IS NOT NULL,
-       st_bandnodatavalue($1, $2),
-       st_bandpath($1, $2) IS NOT NULL,
-       st_bandpath($1, $2)
-    $$
-    LANGUAGE SQL IMMUTABLE STRICT;
-
-CREATE OR REPLACE FUNCTION st_bandmetadata(rast raster,
-                                           OUT pixeltype text,
-                                           OUT hasnodatavalue boolean,
-                                           OUT nodatavalue float4,
-                                           OUT isoutdb boolean,
-                                           OUT path text)
-    AS $$
-    SELECT st_bandpixeltype($1, 1),
-       st_bandnodatavalue($1, 1) IS NOT NULL,
-       st_bandnodatavalue($1, 1),
-       st_bandpath($1, 1) IS NOT NULL,
-       st_bandpath($1, 1)
-    $$
-    LANGUAGE SQL IMMUTABLE STRICT;
+CREATE OR REPLACE FUNCTION st_bandmetadata(
+       rast raster,
+       band int DEFAULT 1,
+       OUT pixeltype text,
+       OUT hasnodatavalue boolean,
+       OUT nodatavalue float4,
+       OUT isoutdb boolean,
+       OUT path text
+)
+       AS 'MODULE_PATHNAME','RASTER_bandmetadata'
+       LANGUAGE 'C' IMMUTABLE STRICT;
 
 -----------------------------------------------------------------------
 -- Raster Pixel Accessors
index b99f8a1089abe86b7551d45c1afd36f93a7a5116..187a270483dad0ea302c6d89ad5ccd65997d84f9 100644 (file)
@@ -61,6 +61,7 @@ TEST_PROPS = \
        create_rt_empty_raster_test.sql \
        rt_isempty.sql \
        rt_hasnoband.sql \
+       rt_metadata.sql \
        $(NULL)
 
 TEST_BANDPROPS = \
@@ -77,6 +78,7 @@ TEST_BANDPROPS = \
        rt_quantile.sql \
        rt_valuecount.sql \
        rt_valuepercent.sql \
+       rt_bandmetadata.sql \
        $(NULL)
 
 TEST_PIXEL = \
diff --git a/raster/test/regress/rt_bandmetadata.sql b/raster/test/regress/rt_bandmetadata.sql
new file mode 100644 (file)
index 0000000..222de30
--- /dev/null
@@ -0,0 +1,47 @@
+SELECT * 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
+       )
+);
+SELECT * 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
+);
+SELECT * 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
+);
diff --git a/raster/test/regress/rt_bandmetadata_expected b/raster/test/regress/rt_bandmetadata_expected
new file mode 100644 (file)
index 0000000..0aa4386
--- /dev/null
@@ -0,0 +1,4 @@
+64BF|t|0|f|
+64BF|t|0|f|
+NOTICE:  Invalid band index (must use 1-based). Returning NULL
+||||
diff --git a/raster/test/regress/rt_metadata.sql b/raster/test/regress/rt_metadata.sql
new file mode 100644 (file)
index 0000000..62e885e
--- /dev/null
@@ -0,0 +1,6 @@
+SELECT * FROM ST_MetaData(
+       ST_AddBand(
+               ST_MakeEmptyRaster(10, 10, 10, 10, 2, 2, 0, 0,-1)
+               , 1, '64BF', 0, 0
+       )
+);
diff --git a/raster/test/regress/rt_metadata_expected b/raster/test/regress/rt_metadata_expected
new file mode 100644 (file)
index 0000000..a51807b
--- /dev/null
@@ -0,0 +1 @@
+10|10|10|10|2|2|0|0|-1|1