PostGIS  3.4.0dev-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  bool isnullband;
491  };
492  struct bandmetadata *bmd = NULL;
493  struct bandmetadata *bmd2 = NULL;
494 
495  HeapTuple tuple;
496  Datum result;
497 
498  if (SRF_IS_FIRSTCALL()) {
499  MemoryContext oldcontext;
500 
501  rt_pgraster *pgraster = NULL;
502  rt_raster raster = NULL;
503  rt_band band = NULL;
504 
505  ArrayType *array;
506  Oid etype;
507  Datum *e;
508  bool *nulls;
509  int16 typlen;
510  bool typbyval;
511  char typalign;
512  int i = 0;
513  int j = 0;
514  int n = 0;
515 
516  uint32_t numBands;
517  uint32_t idx = 1;
518  uint32_t *bandNums = NULL;
519  const char *chartmp = NULL;
520  size_t charlen;
521  uint8_t extbandnum;
522 
523  POSTGIS_RT_DEBUG(3, "RASTER_bandmetadata: Starting");
524 
525  /* create a function context for cross-call persistence */
526  funcctx = SRF_FIRSTCALL_INIT();
527 
528  /* switch to memory context appropriate for multiple function calls */
529  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
530 
531  /* Build a tuple descriptor for our result type */
532  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
533  MemoryContextSwitchTo(oldcontext);
534  ereport(ERROR, (
535  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
536  errmsg(
537  "function returning record called in context "
538  "that cannot accept type record"
539  )
540  ));
541  }
542 
543  BlessTupleDesc(tupdesc);
544  funcctx->tuple_desc = tupdesc;
545 
546  /* pgraster is null, return null */
547  if (PG_ARGISNULL(0)) {
548  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
549  bmd->isnullband = TRUE;
550  funcctx->user_fctx = bmd;
551  funcctx->max_calls = 1;
552  MemoryContextSwitchTo(oldcontext);
553  goto PER_CALL;
554  }
555  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
556 
557  /* raster */
558  raster = rt_raster_deserialize(pgraster, FALSE);
559  if (!raster) {
560  PG_FREE_IF_COPY(pgraster, 0);
561  MemoryContextSwitchTo(oldcontext);
562  elog(ERROR, "RASTER_bandmetadata: Could not deserialize raster");
563  SRF_RETURN_DONE(funcctx);
564  }
565 
566  /* numbands */
567  numBands = rt_raster_get_num_bands(raster);
568  if (numBands < 1) {
569  elog(NOTICE, "Raster provided has no bands");
571  PG_FREE_IF_COPY(pgraster, 0);
572  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
573  bmd->isnullband = TRUE;
574  funcctx->user_fctx = bmd;
575  funcctx->max_calls = 1;
576  MemoryContextSwitchTo(oldcontext);
577  goto PER_CALL;
578  }
579 
580  /* band index */
581  array = PG_GETARG_ARRAYTYPE_P(1);
582  etype = ARR_ELEMTYPE(array);
583  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
584 
585  switch (etype) {
586  case INT2OID:
587  case INT4OID:
588  break;
589  default:
591  PG_FREE_IF_COPY(pgraster, 0);
592  MemoryContextSwitchTo(oldcontext);
593  elog(ERROR, "RASTER_bandmetadata: Invalid data type for band number(s)");
594  SRF_RETURN_DONE(funcctx);
595  break;
596  }
597 
598  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
599  &nulls, &n);
600 
601  bandNums = palloc(sizeof(uint32_t) * n);
602  for (i = 0, j = 0; i < n; i++) {
603  if (nulls[i]) continue;
604 
605  switch (etype) {
606  case INT2OID:
607  idx = (uint32_t) DatumGetInt16(e[i]);
608  break;
609  case INT4OID:
610  idx = (uint32_t) DatumGetInt32(e[i]);
611  break;
612  }
613 
614  POSTGIS_RT_DEBUGF(3, "band idx (before): %d", idx);
615  if (idx > numBands || idx < 1) {
616  elog(NOTICE, "Invalid band index: %d. Indices must be 1-based. Returning NULL", idx);
617  pfree(bandNums);
619  PG_FREE_IF_COPY(pgraster, 0);
620  bmd = (struct bandmetadata *) palloc(sizeof(struct bandmetadata));
621  bmd->isnullband = TRUE;
622  funcctx->user_fctx = bmd;
623  funcctx->max_calls = 1;
624  MemoryContextSwitchTo(oldcontext);
625  goto PER_CALL;
626  }
627 
628  bandNums[j] = idx;
629  POSTGIS_RT_DEBUGF(3, "bandNums[%d] = %d", j, bandNums[j]);
630  j++;
631  }
632 
633  if (j < 1) {
634  j = numBands;
635  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
636  for (i = 0; i < j; i++)
637  bandNums[i] = i + 1;
638  }
639  else if (j < n)
640  bandNums = repalloc(bandNums, sizeof(uint32_t) * j);
641 
642  bmd = (struct bandmetadata *) palloc0(sizeof(struct bandmetadata) * j);
643 
644  for (i = 0; i < j; i++) {
645  band = rt_raster_get_band(raster, bandNums[i] - 1);
646  if (NULL == band) {
647  elog(NOTICE, "Could not get raster band at index %d", bandNums[i]);
649  PG_FREE_IF_COPY(pgraster, 0);
650  bmd[0].isnullband = TRUE;
651  funcctx->user_fctx = bmd;
652  funcctx->max_calls = 1;
653  MemoryContextSwitchTo(oldcontext);
654  goto PER_CALL;
655  }
656 
657  /* bandnum */
658  bmd[i].bandnum = bandNums[i];
659 
660  /* pixeltype */
662  charlen = strlen(chartmp) + 1;
663  bmd[i].pixeltype = palloc(sizeof(char) * charlen);
664  strncpy(bmd[i].pixeltype, chartmp, charlen);
665 
666  /* hasnodatavalue */
668  bmd[i].hasnodata = TRUE;
669  else
670  bmd[i].hasnodata = FALSE;
671 
672  /* nodatavalue */
673  if (bmd[i].hasnodata)
674  rt_band_get_nodata(band, &(bmd[i].nodataval));
675  else
676  bmd[i].nodataval = 0;
677 
678  /* out-db path */
679  chartmp = rt_band_get_ext_path(band);
680  if (chartmp) {
681  charlen = strlen(chartmp) + 1;
682  bmd[i].bandpath = palloc(sizeof(char) * charlen);
683  strncpy(bmd[i].bandpath, chartmp, charlen);
684  }
685  else
686  bmd[i].bandpath = NULL;
687 
688  /* isoutdb */
689  bmd[i].isoutdb = bmd[i].bandpath ? TRUE : FALSE;
690 
691  /* out-db bandnum */
692  if (rt_band_get_ext_band_num(band, &extbandnum) == ES_NONE)
693  bmd[i].extbandnum = extbandnum + 1;
694  else
695  bmd[i].extbandnum = 0;
696 
697  bmd[i].filesize = 0;
698  bmd[i].timestamp = 0;
699  if( bmd[i].bandpath && enable_outdb_rasters ) {
700  VSIStatBufL sStat;
701  if( VSIStatL(bmd[i].bandpath, &sStat) == 0 ) {
702  bmd[i].filesize = sStat.st_size;
703  bmd[i].timestamp = sStat.st_mtime;
704  }
705  }
706 
708  }
709 
711  PG_FREE_IF_COPY(pgraster, 0);
712 
713  /* Store needed information */
714  funcctx->user_fctx = bmd;
715 
716  /* total number of tuples to be returned */
717  funcctx->max_calls = j;
718 
719  MemoryContextSwitchTo(oldcontext);
720  }
721 
722  PER_CALL:
723 
724  /* stuff done on every call of the function */
725  funcctx = SRF_PERCALL_SETUP();
726 
727  call_cntr = funcctx->call_cntr;
728  max_calls = funcctx->max_calls;
729  tupdesc = funcctx->tuple_desc;
730  bmd2 = funcctx->user_fctx;
731 
732  /* do when there is more left to send */
733  if (call_cntr < max_calls) {
734  Datum values[VALUES_LENGTH];
735  bool nulls[VALUES_LENGTH];
736 
737  if (bmd2[0].isnullband) {
738  int i;
739  for (i = 0; i < VALUES_LENGTH; i++)
740  nulls[i] = TRUE;
741  result = HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls));
742  SRF_RETURN_NEXT(funcctx, result);
743  }
744 
745  memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
746 
747  values[0] = UInt32GetDatum(bmd2[call_cntr].bandnum);
748  values[1] = CStringGetTextDatum(bmd2[call_cntr].pixeltype);
749 
750  if (bmd2[call_cntr].hasnodata)
751  values[2] = Float8GetDatum(bmd2[call_cntr].nodataval);
752  else
753  nulls[2] = TRUE;
754 
755  values[3] = BoolGetDatum(bmd2[call_cntr].isoutdb);
756  if (bmd2[call_cntr].bandpath && strlen(bmd2[call_cntr].bandpath)) {
757  values[4] = CStringGetTextDatum(bmd2[call_cntr].bandpath);
758  values[5] = UInt32GetDatum(bmd2[call_cntr].extbandnum);
759  }
760  else {
761  nulls[4] = TRUE;
762  nulls[5] = TRUE;
763  }
764 
765  if (bmd2[call_cntr].filesize)
766  {
767  values[6] = UInt64GetDatum(bmd2[call_cntr].filesize);
768  values[7] = UInt64GetDatum(bmd2[call_cntr].timestamp);
769  }
770  else
771  {
772  nulls[6] = TRUE;
773  nulls[7] = TRUE;
774  }
775 
776  /* build a tuple */
777  tuple = heap_form_tuple(tupdesc, values, nulls);
778 
779  /* make the tuple into a datum */
780  result = HeapTupleGetDatum(tuple);
781 
782  /* clean up */
783  pfree(bmd2[call_cntr].pixeltype);
784  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
785 
786  SRF_RETURN_NEXT(funcctx, result);
787  }
788  /* do when there is no more left */
789  else {
790  pfree(bmd2);
791  SRF_RETURN_DONE(funcctx);
792  }
793 }
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:262
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
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:86
@ ES_NONE
Definition: librtcore.h:182
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:376
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:1887
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:385
band
Definition: ovdump.py:58
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:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:69
Struct definitions.
Definition: librtcore.h:2403

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