PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ RASTER_bandmetadata()

Datum RASTER_bandmetadata ( PG_FUNCTION_ARGS  )

Definition at line 473 of file rtpg_band_properties.c.

474 {
475  FuncCallContext *funcctx;
476  TupleDesc tupdesc;
477  int call_cntr;
478  int max_calls;
479 
480  struct bandmetadata {
481  uint32_t bandnum;
482  char *pixeltype;
483  bool hasnodata;
484  double nodataval;
485  bool isoutdb;
486  char *bandpath;
487  uint8_t extbandnum;
488  uint64_t filesize;
489  uint64_t timestamp;
490  };
491  struct bandmetadata *bmd = NULL;
492  struct bandmetadata *bmd2 = NULL;
493 
494  HeapTuple tuple;
495  Datum result;
496 
497  if (SRF_IS_FIRSTCALL()) {
498  MemoryContext oldcontext;
499 
500  rt_pgraster *pgraster = NULL;
501  rt_raster raster = NULL;
502  rt_band band = NULL;
503 
504  ArrayType *array;
505  Oid etype;
506  Datum *e;
507  bool *nulls;
508  int16 typlen;
509  bool typbyval;
510  char typalign;
511  int i = 0;
512  int j = 0;
513  int n = 0;
514 
515  uint32_t numBands;
516  uint32_t idx = 1;
517  uint32_t *bandNums = NULL;
518  const char *chartmp = NULL;
519  size_t charlen;
520  uint8_t extbandnum;
521 
522  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
523 
524  /* create a function context for cross-call persistence */
525  funcctx = SRF_FIRSTCALL_INIT();
526 
527  /* switch to memory context appropriate for multiple function calls */
528  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
529 
530  /* pgraster is null, return null */
531  if (PG_ARGISNULL(0)) {
532  MemoryContextSwitchTo(oldcontext);
533  SRF_RETURN_DONE(funcctx);
534  }
535  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
536 
537  /* raster */
538  raster = rt_raster_deserialize(pgraster, FALSE);
539  if (!raster) {
540  PG_FREE_IF_COPY(pgraster, 0);
541  MemoryContextSwitchTo(oldcontext);
542  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
543  SRF_RETURN_DONE(funcctx);
544  }
545 
546  /* numbands */
547  numBands = rt_raster_get_num_bands(raster);
548  if (numBands < 1) {
549  elog(NOTICE, "Raster provided has no bands");
551  PG_FREE_IF_COPY(pgraster, 0);
552  MemoryContextSwitchTo(oldcontext);
553  SRF_RETURN_DONE(funcctx);
554  }
555 
556  /* band index */
557  array = PG_GETARG_ARRAYTYPE_P(1);
558  etype = ARR_ELEMTYPE(array);
559  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
560 
561  switch (etype) {
562  case INT2OID:
563  case INT4OID:
564  break;
565  default:
567  PG_FREE_IF_COPY(pgraster, 0);
568  MemoryContextSwitchTo(oldcontext);
569  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
570  SRF_RETURN_DONE(funcctx);
571  break;
572  }
573 
574  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
575  &nulls, &n);
576 
577  bandNums = palloc(sizeof(uint32_t) * n);
578  for (i = 0, j = 0; i < n; i++) {
579  if (nulls[i]) continue;
580 
581  switch (etype) {
582  case INT2OID:
583  idx = (uint32_t) DatumGetInt16(e[i]);
584  break;
585  case INT4OID:
586  idx = (uint32_t) DatumGetInt32(e[i]);
587  break;
588  }
589 
590  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
591  if (idx > numBands || idx < 1) {
592  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
593  pfree(bandNums);
595  PG_FREE_IF_COPY(pgraster, 0);
596  MemoryContextSwitchTo(oldcontext);
597  SRF_RETURN_DONE(funcctx);
598  }
599 
600  bandNums[j] = idx;
601  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
602  j++;
603  }
604 
605  if (j < 1) {
606  j = numBands;
607  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
608  for (i = 0; i < j; i++)
609  bandNums[i] = i + 1;
610  }
611  else if (j < n)
612  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
613 
614  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata) * j);
615 
616  for (i = 0; i < j; i++) {
617  band = rt_raster_get_band(raster, bandNums[i] - 1);
618  if (NULL == band) {
619  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
621  PG_FREE_IF_COPY(pgraster, 0);
622  MemoryContextSwitchTo(oldcontext);
623  SRF_RETURN_DONE(funcctx);
624  }
625 
626  /* bandnum */
627  bmd[i].bandnum = bandNums[i];
628 
629  /* pixeltype */
631  charlen = strlen(chartmp) + 1;
632  bmd[i].pixeltype = palloc(sizeof(char) * charlen);
633  strncpy(bmd[i].pixeltype, chartmp, charlen);
634 
635  /* hasnodatavalue */
637  bmd[i].hasnodata = TRUE;
638  else
639  bmd[i].hasnodata = FALSE;
640 
641  /* nodatavalue */
642  if (bmd[i].hasnodata)
643  rt_band_get_nodata(band, &(bmd[i].nodataval));
644  else
645  bmd[i].nodataval = 0;
646 
647  /* out-db path */
648  chartmp = rt_band_get_ext_path(band);
649  if (chartmp) {
650  charlen = strlen(chartmp) + 1;
651  bmd[i].bandpath = palloc(sizeof(char) * charlen);
652  strncpy(bmd[i].bandpath, chartmp, charlen);
653  }
654  else
655  bmd[i].bandpath = NULL;
656 
657  /* isoutdb */
658  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
659 
660  /* out-db bandnum */
661  if (rt_band_get_ext_band_num(band, &extbandnum) == ES_NONE)
662  bmd[i].extbandnum = extbandnum + 1;
663  else
664  bmd[i].extbandnum = 0;
665 
666  bmd[i].filesize = 0;
667  bmd[i].timestamp = 0;
668  if( bmd[i].bandpath && enable_outdb_rasters ) {
669  VSIStatBufL sStat;
670  if( VSIStatL(bmd[i].bandpath, &sStat) == 0 ) {
671  bmd[i].filesize = sStat.st_size;
672  bmd[i].timestamp = sStat.st_mtime;
673  }
674  }
675 
677  }
678 
680  PG_FREE_IF_COPY(pgraster, 0);
681 
682  /* Store needed information */
683  funcctx->user_fctx = bmd;
684 
685  /* total number of tuples to be returned */
686  funcctx->max_calls = j;
687 
688  /* Build a tuple descriptor for our result type */
689  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
690  MemoryContextSwitchTo(oldcontext);
691  ereport(ERROR, (
692  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
693  errmsg(
694  "function returning record called in context "
695  "that cannot accept type record"
696  )
697  ));
698  }
699 
700  BlessTupleDesc(tupdesc);
701  funcctx->tuple_desc = tupdesc;
702 
703  MemoryContextSwitchTo(oldcontext);
704  }
705 
706  /* stuff done on every call of the function */
707  funcctx = SRF_PERCALL_SETUP();
708 
709  call_cntr = funcctx->call_cntr;
710  max_calls = funcctx->max_calls;
711  tupdesc = funcctx->tuple_desc;
712  bmd2 = funcctx->user_fctx;
713 
714  /* do when there is more left to send */
715  if (call_cntr < max_calls) {
716  Datum values[VALUES_LENGTH];
717  bool nulls[VALUES_LENGTH];
718 
719  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
720 
721  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
722  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
723 
724  if (bmd2[call_cntr].hasnodata)
725  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
726  else
727  nulls[2] = TRUE;
728 
729  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
730  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath)) {
731  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
732  values[5] = UInt32GetDatum(bmd2[call_cntr].extbandnum);
733  }
734  else {
735  nulls[4] = TRUE;
736  nulls[5] = TRUE;
737  }
738 
739  if (bmd2[call_cntr].filesize) {
740 #if POSTGIS_PGSQL_VERSION > 95
741  values[6] = UInt64GetDatum(bmd2[call_cntr].filesize);
742  values[7] = UInt64GetDatum(bmd2[call_cntr].timestamp);
743 #else /* POSTGIS_PGSQL_VERSION <= 95 */
744  values[6] = Int64GetDatum(bmd2[call_cntr].filesize);
745  values[7] = Int64GetDatum(bmd2[call_cntr].timestamp);
746 #endif
747  }
748  else {
749  nulls[6] = TRUE;
750  nulls[7] = TRUE;
751  }
752 
753  /* build a tuple */
754  tuple = heap_form_tuple(tupdesc, values, nulls);
755 
756  /* make the tuple into a datum */
757  result = HeapTupleGetDatum(tuple);
758 
759  /* clean up */
760  pfree(bmd2[call_cntr].pixeltype);
761  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
762 
763  SRF_RETURN_NEXT(funcctx, result);
764  }
765  /* do when there is no more left */
766  else {
767  pfree(bmd2);
768  SRF_RETURN_DONE(funcctx);
769  }
770 }
#define TRUE
Definition: dbfopen.c:169
#define FALSE
Definition: dbfopen.c:168
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:363
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
@ ES_NONE
Definition: librtcore.h:180
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:340
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
rt_errorstate rt_band_get_ext_band_num(rt_band band, uint8_t *bandnum)
Return bands' external band number (only valid when rt_band_is_offline returns non-zero).
Definition: rt_band.c:376
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1730
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
band
Definition: ovdump.py:57
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
bool enable_outdb_rasters
Definition: rt_band.c:417
#define VALUES_LENGTH
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
Struct definitions.
Definition: librtcore.h:2250
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79

References ovdump::band, enable_outdb_rasters, ES_NONE, FALSE, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, rt_band_destroy(), rt_band_get_ext_band_num(), 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(), TRUE, and VALUES_LENGTH.

Here is the call graph for this function: