PostGIS 3.7.0dev-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 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");
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}
794
799Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
800{
801 rt_pgraster *pgraster = NULL;
802 rt_pgraster *pgrtn = NULL;
803 rt_raster raster = NULL;
804 rt_band band = NULL;
805 double nodata;
806 int32_t bandindex;
807 bool forcechecking = FALSE;
808 bool skipset = FALSE;
809
810 /* Deserialize raster */
811 if (PG_ARGISNULL(0))
812 PG_RETURN_NULL();
813 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
814
815 /* Check index is not NULL or smaller than 1 */
816 if (PG_ARGISNULL(1))
817 bandindex = -1;
818 else
819 bandindex = PG_GETARG_INT32(1);
820 if (bandindex < 1) {
821 elog(NOTICE, "Invalid band index (must use 1-based). Nodata value not set. Returning original raster");
822 skipset = TRUE;
823 }
824
825 raster = rt_raster_deserialize(pgraster, FALSE);
826 if (!raster) {
827 PG_FREE_IF_COPY(pgraster, 0);
828 elog(ERROR, "RASTER_setBandNoDataValue: Could not deserialize raster");
829 PG_RETURN_NULL();
830 }
831
832 if (!skipset) {
833 /* Fetch requested band */
834 band = rt_raster_get_band(raster, bandindex - 1);
835 if (!band) {
836 elog(NOTICE, "Could not find raster band of index %d when setting pixel value. Nodata value not set. Returning original raster", bandindex);
837 }
838 else {
839 if (!PG_ARGISNULL(3))
840 forcechecking = PG_GETARG_BOOL(3);
841
842 if (PG_ARGISNULL(2)) {
843 /* Set the hasnodata flag to FALSE */
845 POSTGIS_RT_DEBUGF(3, "Raster band %d does not have a nodata value", bandindex);
846 }
847 else {
848 /* Get the nodata value */
849 nodata = PG_GETARG_FLOAT8(2);
850
851 /* Set the band's nodata value */
852 rt_band_set_nodata(band, nodata, NULL);
853
854 /* Recheck all pixels if requested */
855 if (forcechecking)
857 }
858 }
859 }
860
861 pgrtn = rt_raster_serialize(raster);
862 rt_raster_destroy(raster);
863 PG_FREE_IF_COPY(pgraster, 0);
864 if (!pgrtn)
865 PG_RETURN_NULL();
866
867 SET_VARSIZE(pgrtn, pgrtn->size);
868 PG_RETURN_POINTER(pgrtn);
869}
870
875Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
876{
877 rt_pgraster *pgraster = NULL;
878 rt_pgraster *pgrtn = NULL;
879 rt_raster raster = NULL;
880 rt_band band = NULL;
881 int32_t bandindex;
882
883 if (PG_ARGISNULL(0))
884 PG_RETURN_NULL();
885 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
886
887 raster = rt_raster_deserialize(pgraster, FALSE);
888 if (!raster) {
889 PG_FREE_IF_COPY(pgraster, 0);
890 elog(ERROR, "RASTER_setBandIsNoData: Could not deserialize raster");
891 PG_RETURN_NULL();
892 }
893
894 /* Check index is not NULL or smaller than 1 */
895 if (PG_ARGISNULL(1))
896 bandindex = -1;
897 else
898 bandindex = PG_GETARG_INT32(1);
899
900 if (bandindex < 1)
901 elog(NOTICE, "Invalid band index (must use 1-based). Isnodata flag not set. Returning original raster");
902 else {
903 /* Fetch requested band */
904 band = rt_raster_get_band(raster, bandindex - 1);
905
906 if (!band)
907 elog(NOTICE, "Could not find raster band of index %d. Isnodata flag not set. Returning original raster", bandindex);
908 else {
909 if (!rt_band_get_hasnodata_flag(band)) {
910 elog(NOTICE, "Band of index %d has no NODATA so cannot be NODATA. Returning original raster", bandindex);
911 }
912 /* Set the band's nodata value */
913 else {
915 }
916 }
917 }
918
919 /* Serialize raster again */
920 pgrtn = rt_raster_serialize(raster);
921 rt_raster_destroy(raster);
922 PG_FREE_IF_COPY(pgraster, 0);
923 if (!pgrtn) PG_RETURN_NULL();
924
925 SET_VARSIZE(pgrtn, pgrtn->size);
926 PG_RETURN_POINTER(pgrtn);
927}
928
933Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
934{
935 rt_pgraster *pgraster = NULL;
936 rt_pgraster *pgrtn = NULL;
937 rt_raster raster = NULL;
938 rt_band band = NULL;
939 int32_t bandindex = 1;
940 const char *outdbpathchar = NULL;
941 int32_t outdbindex = 1;
942 bool forceset = FALSE;
943 rt_band newband = NULL;
944
945 int hasnodata;
946 double nodataval = 0.;
947
948 if (PG_ARGISNULL(0))
949 PG_RETURN_NULL();
950 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
951
952 raster = rt_raster_deserialize(pgraster, FALSE);
953 if (!raster) {
954 PG_FREE_IF_COPY(pgraster, 0);
955 elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
956 PG_RETURN_NULL();
957 }
958
959 /* Check index is not NULL or smaller than 1 */
960 if (!PG_ARGISNULL(1))
961 bandindex = PG_GETARG_INT32(1);
962
963 if (bandindex < 1)
964 elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
965 else {
966 /* Fetch requested band */
967 band = rt_raster_get_band(raster, bandindex - 1);
968
969 if (!band)
970 elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
971 else if (!rt_band_is_offline(band)) {
972 elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
973 }
974 else {
975 /* outdbpath */
976 if (!PG_ARGISNULL(2))
977 outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
978 else
979 outdbpathchar = rt_band_get_ext_path(band);
980
981 /* outdbindex, is 1-based */
982 if (!PG_ARGISNULL(3))
983 outdbindex = PG_GETARG_INT32(3);
984
985 /* force */
986 if (!PG_ARGISNULL(4))
987 forceset = PG_GETARG_BOOL(4);
988
989 hasnodata = rt_band_get_hasnodata_flag(band);
990 if (hasnodata)
991 rt_band_get_nodata(band, &nodataval);
992
994 rt_raster_get_width(raster),
995 rt_raster_get_height(raster),
996 hasnodata,
997 nodataval,
998 outdbindex,
999 outdbpathchar,
1000 forceset
1001 );
1002
1003 if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
1004 elog(NOTICE, "Cannot change path of band. Returning original raster");
1005 else
1006 /* old band is in the variable band */
1007 rt_band_destroy(band);
1008 }
1009 }
1010
1011 /* Serialize raster again */
1012 pgrtn = rt_raster_serialize(raster);
1013 rt_raster_destroy(raster);
1014 PG_FREE_IF_COPY(pgraster, 0);
1015 if (!pgrtn) PG_RETURN_NULL();
1016
1017 SET_VARSIZE(pgrtn, pgrtn->size);
1018 PG_RETURN_POINTER(pgrtn);
1019}
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
void rt_band_set_hasnodata_flag(rt_band band, int flag)
Set hasnodata flag value.
Definition rt_band.c:840
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition rt_band.c:854
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
rt_pixtype
Definition librtcore.h:188
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:873
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:1404
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:114
uint64_t rt_band_get_file_size(rt_band band)
Return file size in bytes.
Definition rt_band.c:745
int rt_band_check_is_nodata(rt_band band)
Returns TRUE if the band is only nodata values.
Definition rt_band.c:2089
rt_errorstate rt_band_set_nodata(rt_band band, double val, int *converted)
Set nodata value.
Definition rt_band.c:892
@ 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
uint16_t rt_raster_get_height(rt_raster raster)
Definition rt_raster.c:133
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
uint64_t rt_band_get_file_timestamp(rt_band band)
Return file timestamp.
Definition rt_band.c:767
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_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:358
uint16_t rt_raster_get_width(rt_raster raster)
Definition rt_raster.c:125
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:488
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
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:576
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:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition rtpostgis.h:69
Struct definitions.
Definition librtcore.h:2452