PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rtpg_band_properties.c
Go to the documentation of this file.
1/*
2 *
3 * WKTRaster - Raster Types for PostGIS
4 * http://trac.osgeo.org/postgis/wiki/WKTRaster
5 *
6 * Copyright (C) 2011-2013 Regents of the University of California
7 * <bkpark@ucdavis.edu>
8 * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9 * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10 * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11 * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12 * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 *
28 */
29
30// For stat64()
31#define _LARGEFILE64_SOURCE 1
32
33#include <postgres.h>
34#include <fmgr.h>
35#include <funcapi.h>
36#include <utils/builtins.h> /* for text_to_cstring() */
37#include "utils/lsyscache.h" /* for get_typlenbyvalalign */
38#include "utils/array.h" /* for ArrayType */
39#include "catalog/pg_type.h" /* for INT2OID, INT4OID, FLOAT4OID, FLOAT8OID and TEXTOID */
40
41#include "../../postgis_config.h"
42
43
44#include "access/htup_details.h" /* for heap_form_tuple() */
45
46
47#include "rtpostgis.h"
48
49extern bool enable_outdb_rasters;
50
51/* Get all the properties of a raster band */
52Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS);
53Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS);
54Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS);
55Datum RASTER_getBandPath(PG_FUNCTION_ARGS);
56Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS);
57
58/* get raster band's meta data */
59Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
60
61/* Set all the properties of a raster band */
62Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS);
63Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS);
64Datum RASTER_setBandPath(PG_FUNCTION_ARGS);
65Datum RASTER_setBandIndex(PG_FUNCTION_ARGS);
66
72Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS)
73{
74 rt_pgraster *pgraster = NULL;
75 rt_raster raster = NULL;
76 rt_band band = NULL;
77 rt_pixtype pixtype;
78 int32_t bandindex;
79
80 /* Deserialize raster */
81 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
82 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
83
84 /* Index is 1-based */
85 bandindex = PG_GETARG_INT32(1);
86 if ( bandindex < 1 ) {
87 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
88 PG_FREE_IF_COPY(pgraster, 0);
89 PG_RETURN_NULL();
90 }
91
92 raster = rt_raster_deserialize(pgraster, FALSE);
93 if ( ! raster ) {
94 PG_FREE_IF_COPY(pgraster, 0);
95 elog(ERROR, "RASTER_getBandPixelType: Could not deserialize raster");
96 PG_RETURN_NULL();
97 }
98
99 /* Fetch requested band and its pixel type */
100 band = rt_raster_get_band(raster, bandindex - 1);
101 if ( ! band ) {
102 elog(NOTICE, "Could not find raster band of index %d when getting pixel type. Returning NULL", bandindex);
103 rt_raster_destroy(raster);
104 PG_FREE_IF_COPY(pgraster, 0);
105 PG_RETURN_NULL();
106 }
107
108 pixtype = rt_band_get_pixtype(band);
109
110 rt_raster_destroy(raster);
111 PG_FREE_IF_COPY(pgraster, 0);
112
113 PG_RETURN_INT32(pixtype);
114}
115
122Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS)
123{
124 rt_pgraster *pgraster = NULL;
125 rt_raster raster = NULL;
126 rt_band band = NULL;
127 rt_pixtype pixtype;
128 int32_t bandindex;
129 const size_t name_size = 8; /* size of type name */
130 size_t size = 0;
131 char *ptr = NULL;
132 text *result = NULL;
133
134 /* Deserialize raster */
135 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
136 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
137
138 /* Index is 1-based */
139 bandindex = PG_GETARG_INT32(1);
140 if ( bandindex < 1 ) {
141 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
142 PG_FREE_IF_COPY(pgraster, 0);
143 PG_RETURN_NULL();
144 }
145
146 raster = rt_raster_deserialize(pgraster, FALSE);
147 if ( ! raster ) {
148 PG_FREE_IF_COPY(pgraster, 0);
149 elog(ERROR, "RASTER_getBandPixelTypeName: Could not deserialize raster");
150 PG_RETURN_NULL();
151 }
152
153 /* Fetch requested band and its pixel type */
154 band = rt_raster_get_band(raster, bandindex - 1);
155 if ( ! band ) {
156 elog(NOTICE, "Could not find raster band of index %d when getting pixel type name. Returning NULL", bandindex);
157 rt_raster_destroy(raster);
158 PG_FREE_IF_COPY(pgraster, 0);
159 PG_RETURN_NULL();
160 }
161
162 pixtype = rt_band_get_pixtype(band);
163
164 result = palloc(VARHDRSZ + name_size);
165 /* We don't need to check for NULL pointer, because if out of memory, palloc
166 * exit via elog(ERROR). It never returns NULL.
167 */
168
169 memset(VARDATA(result), 0, name_size);
170 ptr = (char *)result + VARHDRSZ;
171 strcpy(ptr, rt_pixtype_name(pixtype));
172
173 size = VARHDRSZ + strlen(ptr);
174 SET_VARSIZE(result, size);
175
176 rt_raster_destroy(raster);
177 PG_FREE_IF_COPY(pgraster, 0);
178
179 PG_RETURN_TEXT_P(result);
180}
181
187Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS)
188{
189 rt_pgraster *pgraster = NULL;
190 rt_raster raster = NULL;
191 rt_band band = NULL;
192 int32_t bandindex;
193 double nodata;
194
195 /* Deserialize raster */
196 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
197 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
198
199 /* Index is 1-based */
200 bandindex = PG_GETARG_INT32(1);
201 if ( bandindex < 1 ) {
202 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
203 PG_FREE_IF_COPY(pgraster, 0);
204 PG_RETURN_NULL();
205 }
206
207 raster = rt_raster_deserialize(pgraster, FALSE);
208 if ( ! raster ) {
209 PG_FREE_IF_COPY(pgraster, 0);
210 elog(ERROR, "RASTER_getBandNoDataValue: Could not deserialize raster");
211 PG_RETURN_NULL();
212 }
213
214 /* Fetch requested band and its nodata value */
215 band = rt_raster_get_band(raster, bandindex - 1);
216 if ( ! band ) {
217 elog(NOTICE, "Could not find raster band of index %d when getting band nodata value. Returning NULL", bandindex);
218 rt_raster_destroy(raster);
219 PG_FREE_IF_COPY(pgraster, 0);
220 PG_RETURN_NULL();
221 }
222
223 if ( ! rt_band_get_hasnodata_flag(band) ) {
224 /* Raster does not have a nodata value set so we return NULL */
225 rt_raster_destroy(raster);
226 PG_FREE_IF_COPY(pgraster, 0);
227 PG_RETURN_NULL();
228 }
229
230 rt_band_get_nodata(band, &nodata);
231
232 rt_raster_destroy(raster);
233 PG_FREE_IF_COPY(pgraster, 0);
234
235 PG_RETURN_FLOAT8(nodata);
236}
237
238
240Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS)
241{
242 rt_pgraster *pgraster = NULL;
243 rt_raster raster = NULL;
244 rt_band band = NULL;
245 int32_t bandindex;
246 bool forcechecking = FALSE;
247 bool bandisnodata = FALSE;
248
249 /* Index is 1-based */
250 bandindex = PG_GETARG_INT32(1);
251 if ( bandindex < 1 ) {
252 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
253 PG_RETURN_NULL();
254 }
255
256 /* Deserialize raster */
257 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
258 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
259
260 raster = rt_raster_deserialize(pgraster, FALSE);
261 if ( ! raster ) {
262 PG_FREE_IF_COPY(pgraster, 0);
263 elog(ERROR, "RASTER_bandIsNoData: Could not deserialize raster");
264 PG_RETURN_NULL();
265 }
266
267 /* Fetch requested band and its nodata value */
268 band = rt_raster_get_band(raster, bandindex - 1);
269 if ( ! band ) {
270 elog(NOTICE, "Could not find raster band of index %d when determining if band is nodata. Returning NULL", bandindex);
271 rt_raster_destroy(raster);
272 PG_FREE_IF_COPY(pgraster, 0);
273 PG_RETURN_NULL();
274 }
275
276 forcechecking = PG_GETARG_BOOL(2);
277
278 bandisnodata = (forcechecking) ?
280
281 rt_raster_destroy(raster);
282 PG_FREE_IF_COPY(pgraster, 0);
283
284 PG_RETURN_BOOL(bandisnodata);
285}
286
291Datum RASTER_getBandPath(PG_FUNCTION_ARGS)
292{
293 rt_pgraster *pgraster = NULL;
294 rt_raster raster = NULL;
295 rt_band band = NULL;
296 int32_t bandindex;
297 const char *bandpath;
298 text *result;
299
300 /* Index is 1-based */
301 bandindex = PG_GETARG_INT32(1);
302 if ( bandindex < 1 ) {
303 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
304 PG_RETURN_NULL();
305 }
306
307 /* Deserialize raster */
308 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
309 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
310
311 raster = rt_raster_deserialize(pgraster, FALSE);
312 if (!raster) {
313 PG_FREE_IF_COPY(pgraster, 0);
314 elog(ERROR, "RASTER_getBandPath: Could not deserialize raster");
315 PG_RETURN_NULL();
316 }
317
318 /* Fetch requested band */
319 band = rt_raster_get_band(raster, bandindex - 1);
320 if (!band) {
321 elog(
322 NOTICE,
323 "Could not find raster band of index %d when getting band path. Returning NULL",
324 bandindex
325 );
326 rt_raster_destroy(raster);
327 PG_FREE_IF_COPY(pgraster, 0);
328 PG_RETURN_NULL();
329 }
330
331 bandpath = rt_band_get_ext_path(band);
332 if (!bandpath) {
333 rt_band_destroy(band);
334 rt_raster_destroy(raster);
335 PG_FREE_IF_COPY(pgraster, 0);
336 PG_RETURN_NULL();
337 }
338
339 result = cstring_to_text(bandpath);
340
341 rt_band_destroy(band);
342 rt_raster_destroy(raster);
343 PG_FREE_IF_COPY(pgraster, 0);
344
345 PG_RETURN_TEXT_P(result);
346}
347
348
353Datum RASTER_getBandFileSize(PG_FUNCTION_ARGS)
354{
355 rt_pgraster *pgraster;
356 rt_raster raster;
357 rt_band band = NULL;
358 int64_t fileSize;
359 int32_t bandindex;
360
361 /* Index is 1-based */
362 bandindex = PG_GETARG_INT32(1);
363 if ( bandindex < 1 ) {
364 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
365 PG_RETURN_NULL();
366 }
367
368 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
369 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
370
371 raster = rt_raster_deserialize(pgraster, FALSE);
372 if ( ! raster ) {
373 PG_FREE_IF_COPY(pgraster, 0);
374 elog(ERROR, "RASTER_getFileSize: Could not deserialize raster");
375 PG_RETURN_NULL();
376 }
377
378 /* Fetch requested band */
379 band = rt_raster_get_band(raster, bandindex - 1);
380 if (!band) {
381 elog(
382 NOTICE,
383 "Could not find raster band of index %d when getting band path. Returning NULL",
384 bandindex
385 );
386 rt_raster_destroy(raster);
387 PG_FREE_IF_COPY(pgraster, 0);
388 PG_RETURN_NULL();
389 }
390
391 if (!rt_band_is_offline(band)) {
392 elog(NOTICE, "Band of index %d is not out-db.", bandindex);
393 rt_band_destroy(band);
394 rt_raster_destroy(raster);
395 PG_FREE_IF_COPY(pgraster, 0);
396 PG_RETURN_NULL();
397 }
398
399 fileSize = rt_band_get_file_size(band);
400
401 rt_band_destroy(band);
402 rt_raster_destroy(raster);
403 PG_FREE_IF_COPY(pgraster, 0);
404
405 PG_RETURN_INT64(fileSize);
406}
407
412Datum RASTER_getBandFileTimestamp(PG_FUNCTION_ARGS)
413{
414 rt_pgraster *pgraster;
415 rt_raster raster;
416 rt_band band = NULL;
417 int64_t fileSize;
418 int32_t bandindex;
419
420 /* Index is 1-based */
421 bandindex = PG_GETARG_INT32(1);
422 if ( bandindex < 1 ) {
423 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
424 PG_RETURN_NULL();
425 }
426
427 if (PG_ARGISNULL(0)) PG_RETURN_NULL();
428 pgraster = (rt_pgraster *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
429
430 raster = rt_raster_deserialize(pgraster, FALSE);
431 if ( ! raster ) {
432 PG_FREE_IF_COPY(pgraster, 0);
433 elog(ERROR, "RASTER_getBandFileTimestamp: Could not deserialize raster");
434 PG_RETURN_NULL();
435 }
436
437 /* Fetch requested band */
438 band = rt_raster_get_band(raster, bandindex - 1);
439 if (!band) {
440 elog(
441 NOTICE,
442 "Could not find raster band of index %d when getting band path. Returning NULL",
443 bandindex
444 );
445 rt_raster_destroy(raster);
446 PG_FREE_IF_COPY(pgraster, 0);
447 PG_RETURN_NULL();
448 }
449
450 if (!rt_band_is_offline(band)) {
451 elog(NOTICE, "Band of index %d is not out-db.", bandindex);
452 rt_band_destroy(band);
453 rt_raster_destroy(raster);
454 PG_FREE_IF_COPY(pgraster, 0);
455 PG_RETURN_NULL();
456 }
457
458 fileSize = rt_band_get_file_timestamp(band);
459
460 rt_band_destroy(band);
461 rt_raster_destroy(raster);
462 PG_FREE_IF_COPY(pgraster, 0);
463
464 PG_RETURN_INT64(fileSize);
465}
466
467#define VALUES_LENGTH 8
468
473Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
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 */
538 raster = rt_raster_deserialize(pgraster, FALSE);
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}
773
778Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
779{
780 rt_pgraster *pgraster = NULL;
781 rt_pgraster *pgrtn = NULL;
782 rt_raster raster = NULL;
783 rt_band band = NULL;
784 double nodata;
785 int32_t bandindex;
786 bool forcechecking = FALSE;
787 bool skipset = FALSE;
788
789 /* Deserialize raster */
790 if (PG_ARGISNULL(0))
791 PG_RETURN_NULL();
792 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
793
794 /* Check index is not NULL or smaller than 1 */
795 if (PG_ARGISNULL(1))
796 bandindex = -1;
797 else
798 bandindex = PG_GETARG_INT32(1);
799 if (bandindex < 1) {
800 elog(NOTICE, "Invalid band index (must use 1-based). Nodata value not set. Returning original raster");
801 skipset = TRUE;
802 }
803
804 raster = rt_raster_deserialize(pgraster, FALSE);
805 if (!raster) {
806 PG_FREE_IF_COPY(pgraster, 0);
807 elog(ERROR, "RASTER_setBandNoDataValue: Could not deserialize raster");
808 PG_RETURN_NULL();
809 }
810
811 if (!skipset) {
812 /* Fetch requested band */
813 band = rt_raster_get_band(raster, bandindex - 1);
814 if (!band) {
815 elog(NOTICE, "Could not find raster band of index %d when setting pixel value. Nodata value not set. Returning original raster", bandindex);
816 }
817 else {
818 if (!PG_ARGISNULL(3))
819 forcechecking = PG_GETARG_BOOL(3);
820
821 if (PG_ARGISNULL(2)) {
822 /* Set the hasnodata flag to FALSE */
824 POSTGIS_RT_DEBUGF(3, "Raster band %d does not have a nodata value", bandindex);
825 }
826 else {
827 /* Get the nodata value */
828 nodata = PG_GETARG_FLOAT8(2);
829
830 /* Set the band's nodata value */
831 rt_band_set_nodata(band, nodata, NULL);
832
833 /* Recheck all pixels if requested */
834 if (forcechecking)
836 }
837 }
838 }
839
840 pgrtn = rt_raster_serialize(raster);
841 rt_raster_destroy(raster);
842 PG_FREE_IF_COPY(pgraster, 0);
843 if (!pgrtn)
844 PG_RETURN_NULL();
845
846 SET_VARSIZE(pgrtn, pgrtn->size);
847 PG_RETURN_POINTER(pgrtn);
848}
849
854Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
855{
856 rt_pgraster *pgraster = NULL;
857 rt_pgraster *pgrtn = NULL;
858 rt_raster raster = NULL;
859 rt_band band = NULL;
860 int32_t bandindex;
861
862 if (PG_ARGISNULL(0))
863 PG_RETURN_NULL();
864 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
865
866 raster = rt_raster_deserialize(pgraster, FALSE);
867 if (!raster) {
868 PG_FREE_IF_COPY(pgraster, 0);
869 elog(ERROR, "RASTER_setBandIsNoData: Could not deserialize raster");
870 PG_RETURN_NULL();
871 }
872
873 /* Check index is not NULL or smaller than 1 */
874 if (PG_ARGISNULL(1))
875 bandindex = -1;
876 else
877 bandindex = PG_GETARG_INT32(1);
878
879 if (bandindex < 1)
880 elog(NOTICE, "Invalid band index (must use 1-based). Isnodata flag not set. Returning original raster");
881 else {
882 /* Fetch requested band */
883 band = rt_raster_get_band(raster, bandindex - 1);
884
885 if (!band)
886 elog(NOTICE, "Could not find raster band of index %d. Isnodata flag not set. Returning original raster", bandindex);
887 else {
888 if (!rt_band_get_hasnodata_flag(band)) {
889 elog(NOTICE, "Band of index %d has no NODATA so cannot be NODATA. Returning original raster", bandindex);
890 }
891 /* Set the band's nodata value */
892 else {
894 }
895 }
896 }
897
898 /* Serialize raster again */
899 pgrtn = rt_raster_serialize(raster);
900 rt_raster_destroy(raster);
901 PG_FREE_IF_COPY(pgraster, 0);
902 if (!pgrtn) PG_RETURN_NULL();
903
904 SET_VARSIZE(pgrtn, pgrtn->size);
905 PG_RETURN_POINTER(pgrtn);
906}
907
912Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
913{
914 rt_pgraster *pgraster = NULL;
915 rt_pgraster *pgrtn = NULL;
916 rt_raster raster = NULL;
917 rt_band band = NULL;
918 int32_t bandindex = 1;
919 const char *outdbpathchar = NULL;
920 int32_t outdbindex = 1;
921 bool forceset = FALSE;
922 rt_band newband = NULL;
923
924 int hasnodata;
925 double nodataval = 0.;
926
927 if (PG_ARGISNULL(0))
928 PG_RETURN_NULL();
929 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
930
931 raster = rt_raster_deserialize(pgraster, FALSE);
932 if (!raster) {
933 PG_FREE_IF_COPY(pgraster, 0);
934 elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
935 PG_RETURN_NULL();
936 }
937
938 /* Check index is not NULL or smaller than 1 */
939 if (!PG_ARGISNULL(1))
940 bandindex = PG_GETARG_INT32(1);
941
942 if (bandindex < 1)
943 elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
944 else {
945 /* Fetch requested band */
946 band = rt_raster_get_band(raster, bandindex - 1);
947
948 if (!band)
949 elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
950 else if (!rt_band_is_offline(band)) {
951 elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
952 }
953 else {
954 /* outdbpath */
955 if (!PG_ARGISNULL(2))
956 outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
957 else
958 outdbpathchar = rt_band_get_ext_path(band);
959
960 /* outdbindex, is 1-based */
961 if (!PG_ARGISNULL(3))
962 outdbindex = PG_GETARG_INT32(3);
963
964 /* force */
965 if (!PG_ARGISNULL(4))
966 forceset = PG_GETARG_BOOL(4);
967
968 hasnodata = rt_band_get_hasnodata_flag(band);
969 if (hasnodata)
970 rt_band_get_nodata(band, &nodataval);
971
973 rt_raster_get_width(raster),
974 rt_raster_get_height(raster),
975 hasnodata,
976 nodataval,
977 outdbindex,
978 outdbpathchar,
979 forceset
980 );
981
982 if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
983 elog(NOTICE, "Cannot change path of band. Returning original raster");
984 else
985 /* old band is in the variable band */
986 rt_band_destroy(band);
987 }
988 }
989
990 /* Serialize raster again */
991 pgrtn = rt_raster_serialize(raster);
992 rt_raster_destroy(raster);
993 PG_FREE_IF_COPY(pgraster, 0);
994 if (!pgrtn) PG_RETURN_NULL();
995
996 SET_VARSIZE(pgrtn, pgrtn->size);
997 PG_RETURN_POINTER(pgrtn);
998}
#define TRUE
Definition dbfopen.c:169
#define FALSE
Definition dbfopen.c:168
void rt_band_set_hasnodata_flag(rt_band band, int flag)
Set hasnodata flag value.
Definition rt_band.c:681
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition rt_band.c:695
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_pixtype
Definition librtcore.h:185
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:714
rt_band rt_raster_replace_band(rt_raster raster, rt_band band, int index)
Replace band at provided index with new band.
Definition rt_raster.c:1493
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:110
uint64_t rt_band_get_file_size(rt_band band)
Return file size in bytes.
Definition rt_band.c:586
int rt_band_check_is_nodata(rt_band band)
Returns TRUE if the band is only nodata values.
Definition rt_band.c:1752
rt_errorstate rt_band_set_nodata(rt_band band, double val, int *converted)
Set nodata value.
Definition rt_band.c:733
@ 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
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:129
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
uint64_t rt_band_get_file_timestamp(rt_band band)
Return file timestamp.
Definition rt_band.c:608
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_band rt_band_new_offline_from_path(uint16_t width, uint16_t height, int hasnodata, double nodataval, uint8_t bandNum, const char *path, int force)
Create an out-db rt_band from path.
Definition rt_band.c:199
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:121
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
int rt_band_is_offline(rt_band band)
Return non-zero if the given band data is on the filesystem.
Definition rt_band.c:329
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
char * text_to_cstring(const text *textptr)
Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS)
Datum RASTER_setBandIndex(PG_FUNCTION_ARGS)
Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(RASTER_getBandPixelType)
Return pixel type of the specified band of raster.
bool enable_outdb_rasters
Definition rt_band.c:417
Datum RASTER_getBandPath(PG_FUNCTION_ARGS)
Datum RASTER_getBandFileTimestamp(PG_FUNCTION_ARGS)
Datum RASTER_getBandFileSize(PG_FUNCTION_ARGS)
Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS)
#define VALUES_LENGTH
Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS)
Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS)
#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