PostGIS  2.5.0beta1dev-r@@SVN_REVISION@@

◆ RASTER_bandmetadata()

Datum RASTER_bandmetadata ( PG_FUNCTION_ARGS  )

Definition at line 471 of file rtpg_band_properties.c.

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

Referenced by RASTER_getBandFileTimestamp().

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