PostGIS  2.5.1dev-r@@SVN_REVISION@@
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 
49 extern bool enable_outdb_rasters;
50 
51 /* Get all the properties of a raster band */
52 Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS);
53 Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS);
54 Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS);
55 Datum RASTER_getBandPath(PG_FUNCTION_ARGS);
56 Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS);
57 
58 /* get raster band's meta data */
59 Datum RASTER_bandmetadata(PG_FUNCTION_ARGS);
60 
61 /* Set all the properties of a raster band */
62 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS);
63 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS);
64 Datum RASTER_setBandPath(PG_FUNCTION_ARGS);
65 Datum RASTER_setBandIndex(PG_FUNCTION_ARGS);
66 
72 Datum 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 
122 Datum 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 
187 Datum 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 
240 Datum 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 
291 Datum 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 
353 Datum RASTER_getBandFileSize(PG_FUNCTION_ARGS)
354 {
355  rt_pgraster *pgraster;
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 
412 Datum RASTER_getBandFileTimestamp(PG_FUNCTION_ARGS)
413 {
414  rt_pgraster *pgraster;
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 
473 Datum 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 */
636  if (rt_band_get_hasnodata_flag(band))
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 #if POSTGIS_PGSQL_VERSION > 95
741  values[6] = UInt64GetDatum(bmd2[call_cntr].filesize);
742  values[7] = UInt64GetDatum(bmd2[call_cntr].timestamp);
743 #else /* POSTGIS_PGSQL_VERSION <= 95 */
744  values[6] = Int64GetDatum(bmd2[call_cntr].filesize);
745  values[7] = Int64GetDatum(bmd2[call_cntr].timestamp);
746 #endif
747  }
748  else {
749  nulls[6] = TRUE;
750  nulls[7] = TRUE;
751  }
752 
753  /* build a tuple */
754  tuple = heap_form_tuple(tupdesc, values, nulls);
755 
756  /* make the tuple into a datum */
757  result = HeapTupleGetDatum(tuple);
758 
759  /* clean up */
760  pfree(bmd2[call_cntr].pixeltype);
761  if (bmd2[call_cntr].bandpath) pfree(bmd2[call_cntr].bandpath);
762 
763  SRF_RETURN_NEXT(funcctx, result);
764  }
765  /* do when there is no more left */
766  else {
767  pfree(bmd2);
768  SRF_RETURN_DONE(funcctx);
769  }
770 }
771 
776 Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
777 {
778  rt_pgraster *pgraster = NULL;
779  rt_pgraster *pgrtn = NULL;
780  rt_raster raster = NULL;
781  rt_band band = NULL;
782  double nodata;
783  int32_t bandindex;
784  bool forcechecking = FALSE;
785  bool skipset = FALSE;
786 
787  /* Deserialize raster */
788  if (PG_ARGISNULL(0))
789  PG_RETURN_NULL();
790  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
791 
792  /* Check index is not NULL or smaller than 1 */
793  if (PG_ARGISNULL(1))
794  bandindex = -1;
795  else
796  bandindex = PG_GETARG_INT32(1);
797  if (bandindex < 1) {
798  elog(NOTICE, "Invalid band index (must use 1-based). Nodata value not set. Returning original raster");
799  skipset = TRUE;
800  }
801 
802  raster = rt_raster_deserialize(pgraster, FALSE);
803  if (!raster) {
804  PG_FREE_IF_COPY(pgraster, 0);
805  elog(ERROR, "RASTER_setBandNoDataValue: Could not deserialize raster");
806  PG_RETURN_NULL();
807  }
808 
809  if (!skipset) {
810  /* Fetch requested band */
811  band = rt_raster_get_band(raster, bandindex - 1);
812  if (!band) {
813  elog(NOTICE, "Could not find raster band of index %d when setting pixel value. Nodata value not set. Returning original raster", bandindex);
814  }
815  else {
816  if (!PG_ARGISNULL(3))
817  forcechecking = PG_GETARG_BOOL(3);
818 
819  if (PG_ARGISNULL(2)) {
820  /* Set the hasnodata flag to FALSE */
822  POSTGIS_RT_DEBUGF(3, "Raster band %d does not have a nodata value", bandindex);
823  }
824  else {
825  /* Get the nodata value */
826  nodata = PG_GETARG_FLOAT8(2);
827 
828  /* Set the band's nodata value */
829  rt_band_set_nodata(band, nodata, NULL);
830 
831  /* Recheck all pixels if requested */
832  if (forcechecking)
834  }
835  }
836  }
837 
838  pgrtn = rt_raster_serialize(raster);
839  rt_raster_destroy(raster);
840  PG_FREE_IF_COPY(pgraster, 0);
841  if (!pgrtn)
842  PG_RETURN_NULL();
843 
844  SET_VARSIZE(pgrtn, pgrtn->size);
845  PG_RETURN_POINTER(pgrtn);
846 }
847 
852 Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
853 {
854  rt_pgraster *pgraster = NULL;
855  rt_pgraster *pgrtn = NULL;
856  rt_raster raster = NULL;
857  rt_band band = NULL;
858  int32_t bandindex;
859 
860  if (PG_ARGISNULL(0))
861  PG_RETURN_NULL();
862  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
863 
864  raster = rt_raster_deserialize(pgraster, FALSE);
865  if (!raster) {
866  PG_FREE_IF_COPY(pgraster, 0);
867  elog(ERROR, "RASTER_setBandIsNoData: Could not deserialize raster");
868  PG_RETURN_NULL();
869  }
870 
871  /* Check index is not NULL or smaller than 1 */
872  if (PG_ARGISNULL(1))
873  bandindex = -1;
874  else
875  bandindex = PG_GETARG_INT32(1);
876 
877  if (bandindex < 1)
878  elog(NOTICE, "Invalid band index (must use 1-based). Isnodata flag not set. Returning original raster");
879  else {
880  /* Fetch requested band */
881  band = rt_raster_get_band(raster, bandindex - 1);
882 
883  if (!band)
884  elog(NOTICE, "Could not find raster band of index %d. Isnodata flag not set. Returning original raster", bandindex);
885  else {
886  if (!rt_band_get_hasnodata_flag(band)) {
887  elog(NOTICE, "Band of index %d has no NODATA so cannot be NODATA. Returning original raster", bandindex);
888  }
889  /* Set the band's nodata value */
890  else {
891  rt_band_set_isnodata_flag(band, 1);
892  }
893  }
894  }
895 
896  /* Serialize raster again */
897  pgrtn = rt_raster_serialize(raster);
898  rt_raster_destroy(raster);
899  PG_FREE_IF_COPY(pgraster, 0);
900  if (!pgrtn) PG_RETURN_NULL();
901 
902  SET_VARSIZE(pgrtn, pgrtn->size);
903  PG_RETURN_POINTER(pgrtn);
904 }
905 
910 Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
911 {
912  rt_pgraster *pgraster = NULL;
913  rt_pgraster *pgrtn = NULL;
914  rt_raster raster = NULL;
915  rt_band band = NULL;
916  int32_t bandindex = 1;
917  const char *outdbpathchar = NULL;
918  int32_t outdbindex = 1;
919  bool forceset = FALSE;
920  rt_band newband = NULL;
921 
922  int hasnodata;
923  double nodataval = 0.;
924 
925  if (PG_ARGISNULL(0))
926  PG_RETURN_NULL();
927  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
928 
929  raster = rt_raster_deserialize(pgraster, FALSE);
930  if (!raster) {
931  PG_FREE_IF_COPY(pgraster, 0);
932  elog(ERROR, "RASTER_setBandPath: Cannot deserialize raster");
933  PG_RETURN_NULL();
934  }
935 
936  /* Check index is not NULL or smaller than 1 */
937  if (!PG_ARGISNULL(1))
938  bandindex = PG_GETARG_INT32(1);
939 
940  if (bandindex < 1)
941  elog(NOTICE, "Invalid band index (must use 1-based). Returning original raster");
942  else {
943  /* Fetch requested band */
944  band = rt_raster_get_band(raster, bandindex - 1);
945 
946  if (!band)
947  elog(NOTICE, "Cannot find raster band of index %d. Returning original raster", bandindex);
948  else if (!rt_band_is_offline(band)) {
949  elog(NOTICE, "Band of index %d is not out-db. Returning original raster", bandindex);
950  }
951  else {
952  /* outdbpath */
953  if (!PG_ARGISNULL(2))
954  outdbpathchar = text_to_cstring(PG_GETARG_TEXT_P(2));
955  else
956  outdbpathchar = rt_band_get_ext_path(band);
957 
958  /* outdbindex, is 1-based */
959  if (!PG_ARGISNULL(3))
960  outdbindex = PG_GETARG_INT32(3);
961 
962  /* force */
963  if (!PG_ARGISNULL(4))
964  forceset = PG_GETARG_BOOL(4);
965 
966  hasnodata = rt_band_get_hasnodata_flag(band);
967  if (hasnodata)
968  rt_band_get_nodata(band, &nodataval);
969 
971  rt_raster_get_width(raster),
972  rt_raster_get_height(raster),
973  hasnodata,
974  nodataval,
975  outdbindex,
976  outdbpathchar,
977  forceset
978  );
979 
980  if (rt_raster_replace_band(raster, newband, bandindex - 1) == NULL)
981  elog(NOTICE, "Cannot change path of band. Returning original raster");
982  else
983  /* old band is in the variable band */
984  rt_band_destroy(band);
985  }
986  }
987 
988  /* Serialize raster again */
989  pgrtn = rt_raster_serialize(raster);
990  rt_raster_destroy(raster);
991  PG_FREE_IF_COPY(pgraster, 0);
992  if (!pgrtn) PG_RETURN_NULL();
993 
994  SET_VARSIZE(pgrtn, pgrtn->size);
995  PG_RETURN_POINTER(pgrtn);
996 }
char * text_to_cstring(const text *textptr)
PG_FUNCTION_INFO_V1(RASTER_getBandPixelType)
Return pixel type of the specified band of raster.
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
bool enable_outdb_rasters
Definition: rt_band.c:417
uint16_t rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
band
Definition: ovdump.py:57
Datum RASTER_bandmetadata(PG_FUNCTION_ARGS)
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_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
Datum RASTER_getBandPixelTypeName(PG_FUNCTION_ARGS)
rt_errorstate rt_band_set_nodata(rt_band band, double val, int *converted)
Set nodata value.
Definition: rt_band.c:733
Datum RASTER_getBandNoDataValue(PG_FUNCTION_ARGS)
rt_pixtype
Definition: librtcore.h:185
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:340
uint64_t rt_band_get_file_size(rt_band band)
Return file size in bytes.
Definition: rt_band.c:586
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1730
const char * rt_band_get_ext_path(rt_band band)
Return band&#39;s external path (only valid when rt_band_is_offline returns non-zero).
Definition: rt_band.c:363
unsigned int uint32_t
Definition: uthash.h:78
Datum RASTER_getBandPixelType(PG_FUNCTION_ARGS)
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int rt_band_check_is_nodata(rt_band band)
Returns TRUE if the band is only nodata values.
Definition: rt_band.c:1752
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
Datum RASTER_setBandPath(PG_FUNCTION_ARGS)
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
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:1498
Datum RASTER_getBandFileTimestamp(PG_FUNCTION_ARGS)
rt_errorstate rt_band_get_ext_band_num(rt_band band, uint8_t *bandnum)
Return bands&#39; external band number (only valid when rt_band_is_offline returns non-zero).
Definition: rt_band.c:376
void rt_band_set_hasnodata_flag(rt_band band, int flag)
Set hasnodata flag value.
Definition: rt_band.c:681
#define VALUES_LENGTH
Datum RASTER_getBandPath(PG_FUNCTION_ARGS)
Datum RASTER_setBandNoDataValue(PG_FUNCTION_ARGS)
uint16_t rt_raster_get_width(rt_raster raster)
Definition: rt_raster.c:121
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition: rt_band.c:695
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2250
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
uint64_t rt_band_get_file_timestamp(rt_band band)
Return file timestamp.
Definition: rt_band.c:608
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition: rt_band.c:714
Datum RASTER_setBandIsNoData(PG_FUNCTION_ARGS)
Datum RASTER_getBandFileSize(PG_FUNCTION_ARGS)
Datum RASTER_bandIsNoData(PG_FUNCTION_ARGS)
uint16_t rt_raster_get_height(rt_raster raster)
Definition: rt_raster.c:129
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
unsigned char uint8_t
Definition: uthash.h:79
Datum RASTER_setBandIndex(PG_FUNCTION_ARGS)
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:725