PostGIS  2.1.10dev-r@@SVN_REVISION@@
Datum RASTER_valueCount ( PG_FUNCTION_ARGS  )

Definition at line 9890 of file rt_pg.c.

References ovdump::band, genraster::count, FALSE, POSTGIS_RT_DEBUGF, rtrowdump::raster, result, rt_band_destroy(), rt_band_get_value_count(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_num_bands(), TRUE, and genraster::value.

9890  {
9891  FuncCallContext *funcctx;
9892  TupleDesc tupdesc;
9893 
9894  int i;
9895  rt_valuecount vcnts;
9896  rt_valuecount vcnts2;
9897  int call_cntr;
9898  int max_calls;
9899 
9900  /* first call of function */
9901  if (SRF_IS_FIRSTCALL()) {
9902  MemoryContext oldcontext;
9903 
9904  rt_pgraster *pgraster = NULL;
9905  rt_raster raster = NULL;
9906  rt_band band = NULL;
9907  int32_t bandindex = 0;
9908  int num_bands = 0;
9909  bool exclude_nodata_value = TRUE;
9910  double *search_values = NULL;
9911  uint32_t search_values_count = 0;
9912  double roundto = 0;
9913  uint32_t count;
9914 
9915  int j;
9916  int n;
9917 
9918  ArrayType *array;
9919  Oid etype;
9920  Datum *e;
9921  bool *nulls;
9922  int16 typlen;
9923  bool typbyval;
9924  char typalign;
9925 
9926  /* create a function context for cross-call persistence */
9927  funcctx = SRF_FIRSTCALL_INIT();
9928 
9929  /* switch to memory context appropriate for multiple function calls */
9930  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
9931 
9932  /* pgraster is null, return nothing */
9933  if (PG_ARGISNULL(0)) {
9934  MemoryContextSwitchTo(oldcontext);
9935  SRF_RETURN_DONE(funcctx);
9936  }
9937  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
9938 
9939  raster = rt_raster_deserialize(pgraster, FALSE);
9940  if (!raster) {
9941  PG_FREE_IF_COPY(pgraster, 0);
9942  MemoryContextSwitchTo(oldcontext);
9943  elog(ERROR, "RASTER_valueCount: Could not deserialize raster");
9944  SRF_RETURN_DONE(funcctx);
9945  }
9946 
9947  /* band index is 1-based */
9948  bandindex = PG_GETARG_INT32(1);
9949  num_bands = rt_raster_get_num_bands(raster);
9950  if (bandindex < 1 || bandindex > num_bands) {
9951  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
9952  rt_raster_destroy(raster);
9953  PG_FREE_IF_COPY(pgraster, 0);
9954  MemoryContextSwitchTo(oldcontext);
9955  SRF_RETURN_DONE(funcctx);
9956  }
9957 
9958  /* exclude_nodata_value flag */
9959  if (!PG_ARGISNULL(2))
9960  exclude_nodata_value = PG_GETARG_BOOL(2);
9961 
9962  /* search values */
9963  if (!PG_ARGISNULL(3)) {
9964  array = PG_GETARG_ARRAYTYPE_P(3);
9965  etype = ARR_ELEMTYPE(array);
9966  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
9967 
9968  switch (etype) {
9969  case FLOAT4OID:
9970  case FLOAT8OID:
9971  break;
9972  default:
9973  rt_raster_destroy(raster);
9974  PG_FREE_IF_COPY(pgraster, 0);
9975  MemoryContextSwitchTo(oldcontext);
9976  elog(ERROR, "RASTER_valueCount: Invalid data type for values");
9977  SRF_RETURN_DONE(funcctx);
9978  break;
9979  }
9980 
9981  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
9982  &nulls, &n);
9983 
9984  search_values = palloc(sizeof(double) * n);
9985  for (i = 0, j = 0; i < n; i++) {
9986  if (nulls[i]) continue;
9987 
9988  switch (etype) {
9989  case FLOAT4OID:
9990  search_values[j] = (double) DatumGetFloat4(e[i]);
9991  break;
9992  case FLOAT8OID:
9993  search_values[j] = (double) DatumGetFloat8(e[i]);
9994  break;
9995  }
9996 
9997  POSTGIS_RT_DEBUGF(5, "search_values[%d] = %f", j, search_values[j]);
9998  j++;
9999  }
10000  search_values_count = j;
10001 
10002  if (j < 1) {
10003  pfree(search_values);
10004  search_values = NULL;
10005  }
10006  }
10007 
10008  /* roundto */
10009  if (!PG_ARGISNULL(4)) {
10010  roundto = PG_GETARG_FLOAT8(4);
10011  if (roundto < 0.) roundto = 0;
10012  }
10013 
10014  /* get band */
10015  band = rt_raster_get_band(raster, bandindex - 1);
10016  if (!band) {
10017  elog(NOTICE, "Could not find band at index %d. Returning NULL", bandindex);
10018  rt_raster_destroy(raster);
10019  PG_FREE_IF_COPY(pgraster, 0);
10020  MemoryContextSwitchTo(oldcontext);
10021  SRF_RETURN_DONE(funcctx);
10022  }
10023 
10024  /* get counts of values */
10025  vcnts = rt_band_get_value_count(band, (int) exclude_nodata_value, search_values, search_values_count, roundto, NULL, &count);
10026  rt_band_destroy(band);
10027  rt_raster_destroy(raster);
10028  PG_FREE_IF_COPY(pgraster, 0);
10029  if (NULL == vcnts || !count) {
10030  elog(NOTICE, "Could not count the values for band at index %d", bandindex);
10031  MemoryContextSwitchTo(oldcontext);
10032  SRF_RETURN_DONE(funcctx);
10033  }
10034 
10035  POSTGIS_RT_DEBUGF(3, "%d value counts returned", count);
10036 
10037  /* Store needed information */
10038  funcctx->user_fctx = vcnts;
10039 
10040  /* total number of tuples to be returned */
10041  funcctx->max_calls = count;
10042 
10043  /* Build a tuple descriptor for our result type */
10044  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
10045  ereport(ERROR, (
10046  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10047  errmsg(
10048  "function returning record called in context "
10049  "that cannot accept type record"
10050  )
10051  ));
10052  }
10053 
10054  BlessTupleDesc(tupdesc);
10055  funcctx->tuple_desc = tupdesc;
10056 
10057  MemoryContextSwitchTo(oldcontext);
10058  }
10059 
10060  /* stuff done on every call of the function */
10061  funcctx = SRF_PERCALL_SETUP();
10062 
10063  call_cntr = funcctx->call_cntr;
10064  max_calls = funcctx->max_calls;
10065  tupdesc = funcctx->tuple_desc;
10066  vcnts2 = funcctx->user_fctx;
10067 
10068  /* do when there is more left to send */
10069  if (call_cntr < max_calls) {
10070  int values_length = 3;
10071  Datum values[values_length];
10072  bool nulls[values_length];
10073  HeapTuple tuple;
10074  Datum result;
10075 
10076  POSTGIS_RT_DEBUGF(3, "Result %d", call_cntr);
10077 
10078  memset(nulls, FALSE, sizeof(bool) * values_length);
10079 
10080  values[0] = Float8GetDatum(vcnts2[call_cntr].value);
10081  values[1] = UInt32GetDatum(vcnts2[call_cntr].count);
10082  values[2] = Float8GetDatum(vcnts2[call_cntr].percent);
10083 
10084  /* build a tuple */
10085  tuple = heap_form_tuple(tupdesc, values, nulls);
10086 
10087  /* make the tuple into a datum */
10088  result = HeapTupleGetDatum(tuple);
10089 
10090  SRF_RETURN_NEXT(funcctx, result);
10091  }
10092  /* do when there is no more left */
10093  else {
10094  pfree(vcnts2);
10095  SRF_RETURN_DONE(funcctx);
10096  }
10097 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_api.c:5677
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_api.c:5387
tuple band
Definition: ovdump.py:57
tuple raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:123
char ** result
Definition: liblwgeom.h:218
int count
Definition: genraster.py:57
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_api.c:1650
rt_band rt_raster_get_band(rt_raster raster, int n)
Return Nth band, or NULL if unavailable.
Definition: rt_api.c:5686
#define FALSE
Definition: dbfopen.c:169
Struct definitions.
Definition: rt_api.h:2175
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rt_pg.h:62
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_api.c:8350
#define TRUE
Definition: dbfopen.c:170
rt_valuecount rt_band_get_value_count(rt_band band, int exclude_nodata_value, double *search_values, uint32_t search_values_count, double roundto, uint32_t *rtn_total, uint32_t *rtn_count)
Count the number of times provided value(s) occur in the band.
Definition: rt_api.c:4750

Here is the call graph for this function: