PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ RASTER_bandmetadata()

Datum RASTER_bandmetadata ( PG_FUNCTION_ARGS  )

Definition at line 471 of file rtpg_band_properties.c.

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

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: