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

Definition at line 12848 of file rt_pg.c.

References ovdump::band, FALSE, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, result, rt_band_destroy(), rt_band_get_ext_path(), rt_band_get_hasnodata_flag(), rt_band_get_nodata(), rt_band_get_pixtype(), rt_pixtype_name(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_num_bands(), and TRUE.

12849 {
12850  FuncCallContext *funcctx;
12851  TupleDesc tupdesc;
12852  int call_cntr;
12853  int max_calls;
12854 
12855  struct bandmetadata {
12856  uint32_t bandnum;
12857  char *pixeltype;
12858  bool hasnodata;
12859  double nodataval;
12860  bool isoutdb;
12861  char *bandpath;
12862  };
12863  struct bandmetadata *bmd = NULL;
12864  struct bandmetadata *bmd2 = NULL;
12865 
12866  HeapTuple tuple;
12867  Datum result;
12868 
12869  if (SRF_IS_FIRSTCALL()) {
12870  MemoryContext oldcontext;
12871 
12872  rt_pgraster *pgraster = NULL;
12873  rt_raster raster = NULL;
12874  rt_band band = NULL;
12875 
12876  ArrayType *array;
12877  Oid etype;
12878  Datum *e;
12879  bool *nulls;
12880  int16 typlen;
12881  bool typbyval;
12882  char typalign;
12883  int i = 0;
12884  int j = 0;
12885  int n = 0;
12886 
12887  uint32_t numBands;
12888  uint32_t idx = 1;
12889  uint32_t *bandNums = NULL;
12890  const char *tmp = NULL;
12891 
12892  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
12893 
12894  /* create a function context for cross-call persistence */
12895  funcctx = SRF_FIRSTCALL_INIT();
12896 
12897  /* switch to memory context appropriate for multiple function calls */
12898  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
12899 
12900  /* pgraster is null, return null */
12901  if (PG_ARGISNULL(0)) {
12902  MemoryContextSwitchTo(oldcontext);
12903  SRF_RETURN_DONE(funcctx);
12904  }
12905  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
12906 
12907  /* raster */
12908  raster = rt_raster_deserialize(pgraster, FALSE);
12909  if (!raster) {
12910  PG_FREE_IF_COPY(pgraster, 0);
12911  MemoryContextSwitchTo(oldcontext);
12912  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
12913  SRF_RETURN_DONE(funcctx);
12914  }
12915 
12916  /* numbands */
12917  numBands = rt_raster_get_num_bands(raster);
12918  if (numBands < 1) {
12919  elog(NOTICE, "Raster provided has no bands");
12920  rt_raster_destroy(raster);
12921  PG_FREE_IF_COPY(pgraster, 0);
12922  MemoryContextSwitchTo(oldcontext);
12923  SRF_RETURN_DONE(funcctx);
12924  }
12925 
12926  /* band index */
12927  array = PG_GETARG_ARRAYTYPE_P(1);
12928  etype = ARR_ELEMTYPE(array);
12929  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
12930 
12931  switch (etype) {
12932  case INT2OID:
12933  case INT4OID:
12934  break;
12935  default:
12936  rt_raster_destroy(raster);
12937  PG_FREE_IF_COPY(pgraster, 0);
12938  MemoryContextSwitchTo(oldcontext);
12939  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
12940  SRF_RETURN_DONE(funcctx);
12941  break;
12942  }
12943 
12944  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
12945  &nulls, &n);
12946 
12947  bandNums = palloc(sizeof(uint32_t) * n);
12948  for (i = 0, j = 0; i < n; i++) {
12949  if (nulls[i]) continue;
12950 
12951  switch (etype) {
12952  case INT2OID:
12953  idx = (uint32_t) DatumGetInt16(e[i]);
12954  break;
12955  case INT4OID:
12956  idx = (uint32_t) DatumGetInt32(e[i]);
12957  break;
12958  }
12959 
12960  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
12961  if (idx > numBands || idx < 1) {
12962  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
12963  pfree(bandNums);
12964  rt_raster_destroy(raster);
12965  PG_FREE_IF_COPY(pgraster, 0);
12966  MemoryContextSwitchTo(oldcontext);
12967  SRF_RETURN_DONE(funcctx);
12968  }
12969 
12970  bandNums[j] = idx;
12971  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
12972  j++;
12973  }
12974 
12975  if (j < 1) {
12976  j = numBands;
12977  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
12978  for (i = 0; i < j; i++)
12979  bandNums[i] = i + 1;
12980  }
12981  else if (j < n)
12982  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
12983 
12984  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata) * j);
12985 
12986  for (i = 0; i < j; i++) {
12987  band = rt_raster_get_band(raster, bandNums[i] - 1);
12988  if (NULL == band) {
12989  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
12990  rt_raster_destroy(raster);
12991  PG_FREE_IF_COPY(pgraster, 0);
12992  MemoryContextSwitchTo(oldcontext);
12993  SRF_RETURN_DONE(funcctx);
12994  }
12995 
12996  /* bandnum */
12997  bmd[i].bandnum = bandNums[i];
12998 
12999  /* pixeltype */
13000  tmp = rt_pixtype_name(rt_band_get_pixtype(band));
13001  bmd[i].pixeltype = palloc(sizeof(char) * (strlen(tmp) + 1));
13002  strncpy(bmd[i].pixeltype, tmp, strlen(tmp) + 1);
13003 
13004  /* hasnodatavalue */
13005  if (rt_band_get_hasnodata_flag(band))
13006  bmd[i].hasnodata = TRUE;
13007  else
13008  bmd[i].hasnodata = FALSE;
13009 
13010  /* nodatavalue */
13011  if (bmd[i].hasnodata)
13012  rt_band_get_nodata(band, &(bmd[i].nodataval));
13013  else
13014  bmd[i].nodataval = 0;
13015 
13016  /* path */
13017  tmp = rt_band_get_ext_path(band);
13018  if (tmp) {
13019  bmd[i].bandpath = palloc(sizeof(char) * (strlen(tmp) + 1));
13020  strncpy(bmd[i].bandpath, tmp, strlen(tmp) + 1);
13021  }
13022  else
13023  bmd[i].bandpath = NULL;
13024 
13025  /* isoutdb */
13026  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
13027 
13028  rt_band_destroy(band);
13029  }
13030 
13031  rt_raster_destroy(raster);
13032  PG_FREE_IF_COPY(pgraster, 0);
13033 
13034  /* Store needed information */
13035  funcctx->user_fctx = bmd;
13036 
13037  /* total number of tuples to be returned */
13038  funcctx->max_calls = j;
13039 
13040  /* Build a tuple descriptor for our result type */
13041  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
13042  MemoryContextSwitchTo(oldcontext);
13043  ereport(ERROR, (
13044  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
13045  errmsg(
13046  "function returning record called in context "
13047  "that cannot accept type record"
13048  )
13049  ));
13050  }
13051 
13052  BlessTupleDesc(tupdesc);
13053  funcctx->tuple_desc = tupdesc;
13054 
13055  MemoryContextSwitchTo(oldcontext);
13056  }
13057 
13058  /* stuff done on every call of the function */
13059  funcctx = SRF_PERCALL_SETUP();
13060 
13061  call_cntr = funcctx->call_cntr;
13062  max_calls = funcctx->max_calls;
13063  tupdesc = funcctx->tuple_desc;
13064  bmd2 = funcctx->user_fctx;
13065 
13066  /* do when there is more left to send */
13067  if (call_cntr < max_calls) {
13068  int values_length = 5;
13069  Datum values[values_length];
13070  bool nulls[values_length];
13071 
13072  memset(nulls, FALSE, sizeof(bool) * values_length);
13073 
13074  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
13075  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
13076 
13077  if (bmd2[call_cntr].hasnodata)
13078  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
13079  else
13080  nulls[2] = TRUE;
13081 
13082  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
13083  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath))
13084  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
13085  else
13086  nulls[4] = TRUE;
13087 
13088  /* build a tuple */
13089  tuple = heap_form_tuple(tupdesc, values, nulls);
13090 
13091  /* make the tuple into a datum */
13092  result = HeapTupleGetDatum(tuple);
13093 
13094  /* clean up */
13095  pfree(bmd2[call_cntr].pixeltype);
13096  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
13097 
13098  SRF_RETURN_NEXT(funcctx, result);
13099  }
13100  /* do when there is no more left */
13101  else {
13102  pfree(bmd2);
13103  SRF_RETURN_DONE(funcctx);
13104  }
13105 }
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
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_api.c:1168
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_api.c:1900
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
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rt_pg.h:58
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_api.c:3058
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
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_api.c:2002
const char * rt_band_get_ext_path(rt_band band)
Return band's external path (only valid when rt_band_is_offline returns non-zero).
Definition: rt_api.c:1673

Here is the call graph for this function: