PostGIS 3.0.6dev-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 };
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 */
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");
550 rt_raster_destroy(raster);
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:
566 rt_raster_destroy(raster);
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);
594 rt_raster_destroy(raster);
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]);
620 rt_raster_destroy(raster);
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 */
630 chartmp = rt_pixtype_name(rt_band_get_pixtype(band));
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
676 rt_band_destroy(band);
677 }
678
679 rt_raster_destroy(raster);
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 {
741#if POSTGIS_PGSQL_VERSION > 95
742 values[6] = UInt64GetDatum(bmd2[call_cntr].filesize);
743 values[7] = UInt64GetDatum(bmd2[call_cntr].timestamp);
744#else /* POSTGIS_PGSQL_VERSION <= 95 */
745 values[6] = Int64GetDatum(bmd2[call_cntr].filesize);
746 values[7] = Int64GetDatum(bmd2[call_cntr].timestamp);
747#endif
748 }
749 else
750 {
751 nulls[6] = TRUE;
752 nulls[7] = TRUE;
753 }
754
755 /* build a tuple */
756 tuple = heap_form_tuple(tupdesc, values, nulls);
757
758 /* make the tuple into a datum */
759 result = HeapTupleGetDatum(tuple);
760
761 /* clean up */
762 pfree(bmd2[call_cntr].pixeltype);
763 if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
764
765 SRF_RETURN_NEXT(funcctx, result);
766 }
767 /* do when there is no more left */
768 else {
769 pfree(bmd2);
770 SRF_RETURN_DONE(funcctx);
771 }
772}
#define TRUE
Definition dbfopen.c:169
#define FALSE
Definition dbfopen.c:168
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
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:110
@ 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_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
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:381
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:2251

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