PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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 */
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");
570 rt_raster_destroy(raster);
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:
590 rt_raster_destroy(raster);
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);
618 rt_raster_destroy(raster);
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]);
648 rt_raster_destroy(raster);
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 */
661 chartmp = rt_pixtype_name(rt_band_get_pixtype(band));
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
707 rt_band_destroy(band);
708 }
709
710 rt_raster_destroy(raster);
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:267
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:114
@ ES_NONE
Definition librtcore.h:182
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition rt_band.c:499
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:535
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition rt_band.c:790
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:522
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
bool enable_outdb_rasters
Definition rt_band.c:576
#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:2452

References enable_outdb_rasters, ES_NONE, FALSE, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, 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: