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

Definition at line 347 of file rtpg_band_properties.c.

References ovdump::band, FALSE, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, 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.

348 {
349  FuncCallContext *funcctx;
350  TupleDesc tupdesc;
351  int call_cntr;
352  int max_calls;
353 
354  struct bandmetadata {
355  uint32_t bandnum;
356  char *pixeltype;
357  bool hasnodata;
358  double nodataval;
359  bool isoutdb;
360  char *bandpath;
361  };
362  struct bandmetadata *bmd = NULL;
363  struct bandmetadata *bmd2 = NULL;
364 
365  HeapTuple tuple;
366  Datum result;
367 
368  if (SRF_IS_FIRSTCALL()) {
369  MemoryContext oldcontext;
370 
371  rt_pgraster *pgraster = NULL;
372  rt_raster raster = NULL;
373  rt_band band = NULL;
374 
375  ArrayType *array;
376  Oid etype;
377  Datum *e;
378  bool *nulls;
379  int16 typlen;
380  bool typbyval;
381  char typalign;
382  int i = 0;
383  int j = 0;
384  int n = 0;
385 
386  uint32_t numBands;
387  uint32_t idx = 1;
388  uint32_t *bandNums = NULL;
389  const char *tmp = NULL;
390 
391  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
392 
393  /* create a function context for cross-call persistence */
394  funcctx = SRF_FIRSTCALL_INIT();
395 
396  /* switch to memory context appropriate for multiple function calls */
397  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
398 
399  /* pgraster is null, return null */
400  if (PG_ARGISNULL(0)) {
401  MemoryContextSwitchTo(oldcontext);
402  SRF_RETURN_DONE(funcctx);
403  }
404  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
405 
406  /* raster */
407  raster = rt_raster_deserialize(pgraster, FALSE);
408  if (!raster) {
409  PG_FREE_IF_COPY(pgraster, 0);
410  MemoryContextSwitchTo(oldcontext);
411  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
412  SRF_RETURN_DONE(funcctx);
413  }
414 
415  /* numbands */
416  numBands = rt_raster_get_num_bands(raster);
417  if (numBands < 1) {
418  elog(NOTICE, "Raster provided has no bands");
419  rt_raster_destroy(raster);
420  PG_FREE_IF_COPY(pgraster, 0);
421  MemoryContextSwitchTo(oldcontext);
422  SRF_RETURN_DONE(funcctx);
423  }
424 
425  /* band index */
426  array = PG_GETARG_ARRAYTYPE_P(1);
427  etype = ARR_ELEMTYPE(array);
428  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
429 
430  switch (etype) {
431  case INT2OID:
432  case INT4OID:
433  break;
434  default:
435  rt_raster_destroy(raster);
436  PG_FREE_IF_COPY(pgraster, 0);
437  MemoryContextSwitchTo(oldcontext);
438  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
439  SRF_RETURN_DONE(funcctx);
440  break;
441  }
442 
443  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
444  &nulls, &n);
445 
446  bandNums = palloc(sizeof(uint32_t) * n);
447  for (i = 0, j = 0; i < n; i++) {
448  if (nulls[i]) continue;
449 
450  switch (etype) {
451  case INT2OID:
452  idx = (uint32_t) DatumGetInt16(e[i]);
453  break;
454  case INT4OID:
455  idx = (uint32_t) DatumGetInt32(e[i]);
456  break;
457  }
458 
459  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
460  if (idx > numBands || idx < 1) {
461  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
462  pfree(bandNums);
463  rt_raster_destroy(raster);
464  PG_FREE_IF_COPY(pgraster, 0);
465  MemoryContextSwitchTo(oldcontext);
466  SRF_RETURN_DONE(funcctx);
467  }
468 
469  bandNums[j] = idx;
470  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
471  j++;
472  }
473 
474  if (j < 1) {
475  j = numBands;
476  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
477  for (i = 0; i < j; i++)
478  bandNums[i] = i + 1;
479  }
480  else if (j < n)
481  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
482 
483  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata) * j);
484 
485  for (i = 0; i < j; i++) {
486  band = rt_raster_get_band(raster, bandNums[i] - 1);
487  if (NULL == band) {
488  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
489  rt_raster_destroy(raster);
490  PG_FREE_IF_COPY(pgraster, 0);
491  MemoryContextSwitchTo(oldcontext);
492  SRF_RETURN_DONE(funcctx);
493  }
494 
495  /* bandnum */
496  bmd[i].bandnum = bandNums[i];
497 
498  /* pixeltype */
500  bmd[i].pixeltype = palloc(sizeof(char) * (strlen(tmp) + 1));
501  strncpy(bmd[i].pixeltype, tmp, strlen(tmp) + 1);
502 
503  /* hasnodatavalue */
504  if (rt_band_get_hasnodata_flag(band))
505  bmd[i].hasnodata = TRUE;
506  else
507  bmd[i].hasnodata = FALSE;
508 
509  /* nodatavalue */
510  if (bmd[i].hasnodata)
511  rt_band_get_nodata(band, &(bmd[i].nodataval));
512  else
513  bmd[i].nodataval = 0;
514 
515  /* path */
516  tmp = rt_band_get_ext_path(band);
517  if (tmp) {
518  bmd[i].bandpath = palloc(sizeof(char) * (strlen(tmp) + 1));
519  strncpy(bmd[i].bandpath, tmp, strlen(tmp) + 1);
520  }
521  else
522  bmd[i].bandpath = NULL;
523 
524  /* isoutdb */
525  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
526 
527  rt_band_destroy(band);
528  }
529 
530  rt_raster_destroy(raster);
531  PG_FREE_IF_COPY(pgraster, 0);
532 
533  /* Store needed information */
534  funcctx->user_fctx = bmd;
535 
536  /* total number of tuples to be returned */
537  funcctx->max_calls = j;
538 
539  /* Build a tuple descriptor for our result type */
540  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
541  MemoryContextSwitchTo(oldcontext);
542  ereport(ERROR, (
543  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
544  errmsg(
545  "function returning record called in context "
546  "that cannot accept type record"
547  )
548  ));
549  }
550 
551  BlessTupleDesc(tupdesc);
552  funcctx->tuple_desc = tupdesc;
553 
554  MemoryContextSwitchTo(oldcontext);
555  }
556 
557  /* stuff done on every call of the function */
558  funcctx = SRF_PERCALL_SETUP();
559 
560  call_cntr = funcctx->call_cntr;
561  max_calls = funcctx->max_calls;
562  tupdesc = funcctx->tuple_desc;
563  bmd2 = funcctx->user_fctx;
564 
565  /* do when there is more left to send */
566  if (call_cntr < max_calls) {
567  int values_length = 5;
568  Datum values[values_length];
569  bool nulls[values_length];
570 
571  memset(nulls, FALSE, sizeof(bool) * values_length);
572 
573  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
574  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
575 
576  if (bmd2[call_cntr].hasnodata)
577  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
578  else
579  nulls[2] = TRUE;
580 
581  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
582  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath))
583  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
584  else
585  nulls[4] = TRUE;
586 
587  /* build a tuple */
588  tuple = heap_form_tuple(tupdesc, values, nulls);
589 
590  /* make the tuple into a datum */
591  result = HeapTupleGetDatum(tuple);
592 
593  /* clean up */
594  pfree(bmd2[call_cntr].pixeltype);
595  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
596 
597  SRF_RETURN_NEXT(funcctx, result);
598  }
599  /* do when there is no more left */
600  else {
601  pfree(bmd2);
602  SRF_RETURN_DONE(funcctx);
603  }
604 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
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:121
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:242
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:57
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1597
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_band.c:265
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:541
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2213
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:498
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:53
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717

Here is the call graph for this function: